1 //========================================================================
5 // Copyright 1996-2002 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
31 #include "UnicodeMap.h"
32 #include "CharCodeToUnicode.h"
35 #include "TextOutputDev.h"
36 #include "XOutputDev.h"
40 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
43 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
48 #if (__VMS_VER < 70000000)
49 extern "C" int unlink(char *filename);
53 #ifdef XlibSpecificationRelease
54 #if XlibSpecificationRelease < 5
55 typedef char *XPointer;
58 typedef char *XPointer;
61 //------------------------------------------------------------------------
62 // Constants and macros
63 //------------------------------------------------------------------------
65 #define xoutRound(x) ((int)(x + 0.5))
67 #define maxCurveSplits 6 // max number of splits when recursively
68 // drawing Bezier curves
70 //------------------------------------------------------------------------
72 //------------------------------------------------------------------------
74 struct XOutFontSubst {
79 // index: {symbolic:12, fixed:8, serif:4, sans-serif:0} + bold*2 + italic
80 static XOutFontSubst xOutSubstFonts[16] = {
82 {"Helvetica-Oblique", 0.833},
83 {"Helvetica-Bold", 0.889},
84 {"Helvetica-BoldOblique", 0.889},
85 {"Times-Roman", 0.788},
86 {"Times-Italic", 0.722},
87 {"Times-Bold", 0.833},
88 {"Times-BoldItalic", 0.778},
90 {"Courier-Oblique", 0.600},
91 {"Courier-Bold", 0.600},
92 {"Courier-BoldOblique", 0.600},
99 //------------------------------------------------------------------------
101 static void outputToFile(void *stream, char *data, int len) {
102 fwrite(data, 1, len, (FILE *)stream);
105 //------------------------------------------------------------------------
107 //------------------------------------------------------------------------
109 XOutputFont::XOutputFont(Ref *idA, double m11OrigA, double m12OrigA,
110 double m21OrigA, double m22OrigA,
111 double m11A, double m12A, double m21A, double m22A,
112 Display *displayA, XOutputDev *xOutA) {
126 XOutputFont::~XOutputFont() {
129 void XOutputFont::getCharPath(GfxState *state,
130 CharCode c, Unicode *u, int ulen) {
134 //------------------------------------------------------------------------
136 //------------------------------------------------------------------------
138 XOutputT1Font::XOutputT1Font(Ref *idA, T1FontFile *fontFileA,
139 double m11OrigA, double m12OrigA,
140 double m21OrigA, double m22OrigA,
141 double m11A, double m12A,
142 double m21A, double m22A,
143 Display *displayA, XOutputDev *xOutA):
144 XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA,
145 m11A, m12A, m21A, m22A, displayA, xOutA)
149 fontFile = fontFileA;
151 // create the transformed instance
156 font = new T1Font(fontFile, matrix);
159 XOutputT1Font::~XOutputT1Font() {
165 GBool XOutputT1Font::isOk() {
169 void XOutputT1Font::updateGC(GC gc) {
172 void XOutputT1Font::drawChar(GfxState *state, Pixmap pixmap, int w, int h,
174 double x, double y, double dx, double dy,
175 CharCode c, Unicode *u, int uLen) {
176 font->drawChar(pixmap, w, h, gc, xoutRound(x), xoutRound(y),
177 (int)(rgb->r * 65535), (int)(rgb->g * 65535),
178 (int)(rgb->b * 65535), c, u[0]);
181 void XOutputT1Font::getCharPath(GfxState *state,
182 CharCode c, Unicode *u, int uLen) {
183 font->getCharPath(c, u[0], state);
185 #endif // HAVE_T1LIB_H
187 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
188 //------------------------------------------------------------------------
190 //------------------------------------------------------------------------
192 XOutputFTFont::XOutputFTFont(Ref *idA, FTFontFile *fontFileA,
193 double m11OrigA, double m12OrigA,
194 double m21OrigA, double m22OrigA,
195 double m11A, double m12A,
196 double m21A, double m22A,
197 Display *displayA, XOutputDev *xOutA):
198 XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA,
199 m11A, m12A, m21A, m22A, displayA, xOutA)
203 fontFile = fontFileA;
205 // create the transformed instance
210 font = new FTFont(fontFile, matrix);
213 XOutputFTFont::~XOutputFTFont() {
219 GBool XOutputFTFont::isOk() {
223 void XOutputFTFont::updateGC(GC gc) {
226 void XOutputFTFont::drawChar(GfxState *state, Pixmap pixmap, int w, int h,
228 double x, double y, double dx, double dy,
229 CharCode c, Unicode *u, int uLen) {
230 font->drawChar(pixmap, w, h, gc, xoutRound(x), xoutRound(y),
231 (int)(rgb->r * 65535), (int)(rgb->g * 65535),
232 (int)(rgb->b * 65535), c, uLen > 0 ? u[0] : 0);
235 void XOutputFTFont::getCharPath(GfxState *state,
236 CharCode c, Unicode *u, int uLen) {
237 font->getCharPath(c, u[0], state);
239 #endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
241 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
242 //------------------------------------------------------------------------
244 //------------------------------------------------------------------------
246 XOutputTTFont::XOutputTTFont(Ref *idA, TTFontFile *fontFileA,
247 double m11OrigA, double m12OrigA,
248 double m21OrigA, double m22OrigA,
249 double m11A, double m12A,
250 double m21A, double m22A,
251 Display *displayA, XOutputDev *xOutA):
252 XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA,
253 m11A, m12A, m21A, m22A, displayA, xOutA)
257 fontFile = fontFileA;
259 // create the transformed instance
264 font = new TTFont(fontFile, matrix);
267 XOutputTTFont::~XOutputTTFont() {
273 GBool XOutputTTFont::isOk() {
277 void XOutputTTFont::updateGC(GC gc) {
280 void XOutputTTFont::drawChar(GfxState *state, Pixmap pixmap, int w, int h,
282 double x, double y, double dx, double dy,
283 CharCode c, Unicode *u, int uLen) {
284 font->drawChar(pixmap, w, h, gc, xoutRound(x), xoutRound(y),
285 (int)(rgb->r * 65535), (int)(rgb->g * 65535),
286 (int)(rgb->b * 65535), c, u[0]);
288 #endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
290 //------------------------------------------------------------------------
291 // XOutputServer8BitFont
292 //------------------------------------------------------------------------
294 // Copy <fmt>, substituting <val> for one occurrence of "%s", into
296 static void stringSubst(char *buf, int bufSize, char *fmt, char *val) {
303 if (p[0] == '%' && p[1] == 's') {
305 while (*q && i < bufSize - 1) {
310 if (i < bufSize - 1) {
319 XOutputServer8BitFont::XOutputServer8BitFont(Ref *idA, GString *xlfdFmt,
321 CharCodeToUnicode *fontUMap,
322 double m11OrigA, double m12OrigA,
323 double m21OrigA, double m22OrigA,
324 double m11A, double m12A,
325 double m21A, double m22A,
328 XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA,
329 m11A, m12A, m21A, m22A, displayA, xOutA)
331 double size, ntm11, ntm12, ntm21, ntm22;
334 char fontName[500], fontSize[100];
339 // compute size and normalized transform matrix
340 size = sqrt(m21*m21 + m22*m22);
346 // try to get a rotated font?
347 rotated = !(ntm11 > 0 && ntm22 > 0 &&
348 fabs(ntm11 / ntm22 - 1) < 0.2 &&
349 fabs(ntm12) < 0.01 &&
352 // open X font -- if font is not found (which means the server can't
353 // scale fonts), try progressively smaller and then larger sizes
354 startSize = (int)size;
356 sprintf(fontSize, "[%s%0.2f %s%0.2f %s%0.2f %s%0.2f]",
357 ntm11<0 ? "~" : "", fabs(ntm11 * size),
358 ntm12<0 ? "~" : "", fabs(ntm12 * size),
359 ntm21<0 ? "~" : "", fabs(ntm21 * size),
360 ntm22<0 ? "~" : "", fabs(ntm22 * size));
362 sprintf(fontSize, "%d", startSize);
364 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize);
365 xFont = XLoadQueryFont(display, fontName);
367 for (sz = startSize; sz >= startSize/2 && sz >= 1; --sz) {
368 sprintf(fontSize, "%d", sz);
369 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize);
370 if ((xFont = XLoadQueryFont(display, fontName)))
374 for (sz = startSize + 1; sz < startSize + 10; ++sz) {
375 sprintf(fontSize, "%d", sz);
376 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(),
378 if ((xFont = XLoadQueryFont(display, fontName))) {
383 sprintf(fontSize, "%d", startSize);
384 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(),
386 error(-1, "Failed to open font: '%s'", fontName);
392 // Construct char code map.
394 for (i = 0; i < 256; ++i) {
395 if (fontUMap->mapToUnicode((CID)i, &u, 1) == 1 &&
396 xUMap->mapUnicode(u, &buf, 1) == 1) {
404 XOutputServer8BitFont::~XOutputServer8BitFont() {
406 XFreeFont(display, xFont);
410 GBool XOutputServer8BitFont::isOk() {
411 return xFont != NULL;
414 void XOutputServer8BitFont::updateGC(GC gc) {
415 XSetFont(display, gc, xFont->fid);
418 void XOutputServer8BitFont::drawChar(GfxState *state, Pixmap pixmap,
419 int w, int h, GC gc, GfxRGB *rgb,
420 double x, double y, double dx, double dy,
421 CharCode c, Unicode *u, int uLen) {
430 XDrawString(display, pixmap, gc, xoutRound(x), xoutRound(y), buf, 1);
432 // substituted character, using more than one character
434 for (i = 0; i < uLen; ++i) {
435 n += xUMap->mapUnicode(u[i], buf, sizeof(buf));
441 for (i = 0; i < uLen; ++i) {
442 m = xUMap->mapUnicode(u[i], buf, sizeof(buf));
443 for (j = 0; j < m; ++j) {
444 XDrawString(display, pixmap, gc,
445 xoutRound(x + k*dx1), xoutRound(y + k*dy1),
454 //------------------------------------------------------------------------
455 // XOutputServer16BitFont
456 //------------------------------------------------------------------------
458 XOutputServer16BitFont::XOutputServer16BitFont(Ref *idA, GString *xlfdFmt,
460 CharCodeToUnicode *fontUMap,
465 double m11A, double m12A,
466 double m21A, double m22A,
469 XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA,
470 m11A, m12A, m21A, m22A, displayA, xOutA)
472 double size, ntm11, ntm12, ntm21, ntm22;
475 char fontName[500], fontSize[100];
480 // compute size and normalized transform matrix
481 size = sqrt(m21*m21 + m22*m22);
487 // try to get a rotated font?
488 rotated = !(ntm11 > 0 && ntm22 > 0 &&
489 fabs(ntm11 / ntm22 - 1) < 0.2 &&
490 fabs(ntm12) < 0.01 &&
493 // open X font -- if font is not found (which means the server can't
494 // scale fonts), try progressively smaller and then larger sizes
495 startSize = (int)size;
497 sprintf(fontSize, "[%s%0.2f %s%0.2f %s%0.2f %s%0.2f]",
498 ntm11<0 ? "~" : "", fabs(ntm11 * size),
499 ntm12<0 ? "~" : "", fabs(ntm12 * size),
500 ntm21<0 ? "~" : "", fabs(ntm21 * size),
501 ntm22<0 ? "~" : "", fabs(ntm22 * size));
503 sprintf(fontSize, "%d", startSize);
505 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize);
506 xFont = XLoadQueryFont(display, fontName);
508 for (sz = startSize; sz >= startSize/2 && sz >= 1; --sz) {
509 sprintf(fontSize, "%d", sz);
510 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize);
511 if ((xFont = XLoadQueryFont(display, fontName)))
515 for (sz = startSize + 1; sz < startSize + 10; ++sz) {
516 sprintf(fontSize, "%d", sz);
517 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(),
519 if ((xFont = XLoadQueryFont(display, fontName))) {
524 sprintf(fontSize, "%d", startSize);
525 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(),
527 error(-1, "Failed to open font: '%s'", fontName);
534 XOutputServer16BitFont::~XOutputServer16BitFont() {
537 XFreeFont(display, xFont);
541 GBool XOutputServer16BitFont::isOk() {
542 return xFont != NULL;
545 void XOutputServer16BitFont::updateGC(GC gc) {
546 XSetFont(display, gc, xFont->fid);
549 void XOutputServer16BitFont::drawChar(GfxState *state, Pixmap pixmap,
550 int w, int h, GC gc, GfxRGB *rgb,
551 double x, double y, double dx, double dy,
552 CharCode c, Unicode *u, int uLen) {
559 for (i = 0; i < uLen; ++i) {
560 n += xUMap->mapUnicode(u[i], buf, sizeof(buf));
566 for (i = 0; i < uLen; ++i) {
567 m = xUMap->mapUnicode(u[i], buf, sizeof(buf));
568 for (j = 0; j+1 < m; j += 2) {
571 XDrawString16(display, pixmap, gc,
572 xoutRound(x + k*dx1), xoutRound(y + k*dy1),
578 // some PDF files use CID 0, which is .notdef, so just ignore it
579 error(-1, "Unknown character (CID=%d Unicode=%04x)",
580 c, uLen > 0 ? u[0] : (Unicode)0);
584 //------------------------------------------------------------------------
586 //------------------------------------------------------------------------
589 XOutputT1FontFile::~XOutputT1FontFile() {
592 unlink(tmpFileName->getCString());
598 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
599 XOutputFTFontFile::~XOutputFTFontFile() {
602 unlink(tmpFileName->getCString());
608 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
609 XOutputTTFontFile::~XOutputTTFontFile() {
612 unlink(tmpFileName->getCString());
618 XOutputFontCache::XOutputFontCache(Display *displayA, Guint depthA,
620 FontRastControl t1libControlA,
621 FontRastControl freetypeControlA) {
628 t1libControl = t1libControlA;
631 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
634 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
637 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
638 freetypeControl = freetypeControlA;
644 XOutputFontCache::~XOutputFontCache() {
648 void XOutputFontCache::startDoc(int screenNum, Visual *visual,
649 Colormap colormap, GBool trueColor,
650 int rMul, int gMul, int bMul,
651 int rShift, int gShift, int bShift,
652 Gulong *colors, int numColors) {
657 if (t1libControl != fontRastNone) {
658 t1Engine = new T1FontEngine(display, visual, depth, colormap,
659 t1libControl == fontRastAALow ||
660 t1libControl == fontRastAAHigh,
661 t1libControl == fontRastAAHigh);
662 if (t1Engine->isOk()) {
664 t1Engine->useTrueColor(rMul, rShift, gMul, gShift, bMul, bShift);
666 t1Engine->useColorCube(colors, numColors);
673 #endif // HAVE_T1LIB_H
675 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
676 if (freetypeControl != fontRastNone) {
677 ftEngine = new FTFontEngine(display, visual, depth, colormap,
678 freetypeControl == fontRastAALow ||
679 freetypeControl == fontRastAAHigh);
680 if (ftEngine->isOk()) {
682 ftEngine->useTrueColor(rMul, rShift, gMul, gShift, bMul, bShift);
684 ftEngine->useColorCube(colors, numColors);
691 #endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
693 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
694 if (freetypeControl != fontRastNone) {
695 ttEngine = new TTFontEngine(display, visual, depth, colormap,
696 freetypeControl == fontRastAALow ||
697 freetypeControl == fontRastAAHigh);
698 if (ttEngine->isOk()) {
700 ttEngine->useTrueColor(rMul, rShift, gMul, gShift, bMul, bShift);
702 ttEngine->useColorCube(colors, numColors);
709 #endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
712 void XOutputFontCache::delFonts() {
715 for (i = 0; i < nFonts; ++i) {
720 // delete Type 1 font files
721 deleteGList(t1FontFiles, XOutputT1FontFile);
727 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
728 // delete FreeType font files
729 deleteGList(ftFontFiles, XOutputFTFontFile);
735 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
736 // delete TrueType fonts
737 deleteGList(ttFontFiles, XOutputTTFontFile);
744 void XOutputFontCache::clear() {
747 for (i = 0; i < xOutFontCacheSize; ++i) {
753 // clear Type 1 font files
754 t1FontFiles = new GList();
757 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
758 // clear FreeType font cache
759 ftFontFiles = new GList();
762 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
763 // clear TrueType font cache
764 ttFontFiles = new GList();
768 XOutputFont *XOutputFontCache::getFont(XRef *xref, GfxFont *gfxFont,
769 double m11, double m12,
770 double m21, double m22) {
772 DisplayFontParam *dfp;
774 double m11New, m12New, m21New, m22New;
782 // is it the most recently used font?
783 if (nFonts > 0 && fonts[0]->matches(gfxFont->getID(), m11, m12, m21, m22)) {
787 // is it in the cache?
788 for (i = 1; i < nFonts; ++i) {
789 if (fonts[i]->matches(gfxFont->getID(), m11, m12, m21, m22)) {
791 for (j = i; j > 0; --j) {
792 fonts[j] = fonts[j-1];
799 // try for a cached FontFile, an embedded font, or an external font
802 switch (gfxFont->getType()) {
806 if (t1libControl != fontRastNone) {
807 font = tryGetT1Font(xref, gfxFont, m11, m12, m21, m22);
810 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
812 if (freetypeControl != fontRastNone) {
813 font = tryGetFTFont(xref, gfxFont, m11, m12, m21, m22);
820 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
821 if (freetypeControl != fontRastNone) {
822 font = tryGetFTFont(xref, gfxFont, m11, m12, m21, m22);
825 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
826 if (freetypeControl != fontRastNone) {
827 font = tryGetTTFont(xref, gfxFont, m11, m12, m21, m22);
832 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
833 if (freetypeControl != fontRastNone) {
834 font = tryGetFTFont(xref, gfxFont, m11, m12, m21, m22);
844 // search for a display font mapping
846 if (gfxFont->isCIDFont()) {
847 if (((GfxCIDFont *)gfxFont)->getCollection()) {
849 getDisplayCIDFont(gfxFont->getName(),
850 ((GfxCIDFont *)gfxFont)->getCollection());
852 // this error (no CMap file) was already reported by GfxFont
856 if (gfxFont->getName()) {
857 dfp = globalParams->getDisplayFont(gfxFont->getName());
861 font = tryGetFont(xref, dfp, gfxFont, m11, m12, m21, m22,
862 m11, m12, m21, m22, gFalse);
865 // substitute a font (8-bit fonts only)
866 if (!font && !gfxFont->isCIDFont()) {
868 // choose a substitute font
869 if (gfxFont->isFixedWidth()) {
871 } else if (gfxFont->isSerif()) {
876 if (gfxFont->isBold()) {
879 if (gfxFont->isItalic()) {
882 substName = new GString(xOutSubstFonts[index].name);
884 // adjust the font matrix -- compare the width of 'm' in the
885 // original font and the substituted font
890 for (code = 0; code < 256; ++code) {
891 if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
892 name[0] == 'm' && name[1] == '\0') {
897 w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
898 w2 = xOutSubstFonts[index].mWidth;
899 if (gfxFont->getType() == fontType3) {
900 // This is a hack which makes it possible to substitute for some
901 // Type 3 fonts. The problem is that it's impossible to know what
902 // the base coordinate system used in the font is without actually
903 // rendering the font. This code tries to guess by looking at the
904 // width of the character 'm' (which breaks if the font is a
905 // subset that doesn't contain 'm').
906 if (w1 > 0 && (w1 > 1.1 * w2 || w1 < 0.9 * w2)) {
913 fm = gfxFont->getFontMatrix();
914 v = (fm[0] == 0) ? 1 : (fm[3] / fm[0]);
917 } else if (!gfxFont->isSymbolic()) {
918 // if real font is substantially narrower than substituted
919 // font, reduce the font size accordingly
920 if (w1 > 0.01 && w1 < 0.9 * w2) {
929 dfp = globalParams->getDisplayFont(substName);
932 // this should never happen since GlobalParams sets up default
933 // mappings for the Base-14 fonts
934 error(-1, "Couldn't find a font for '%s'",
935 gfxFont->getName()->getCString());
938 font = tryGetFont(xref, dfp, gfxFont, m11, m12, m21, m22,
939 m11New, m12New, m21New, m22New, gTrue);
945 // This will happen if the user specifies a bogus font in the
946 // config file (a non-existent font file or a font that requires a
947 // rasterizer that is disabled or wasn't built in), or if a CID
948 // font has no associated font in the config file.
949 if (gfxFont->isCIDFont()) {
950 error(-1, "Couldn't find a font for the '%s' character collection",
951 ((GfxCIDFont *)gfxFont)->getCollection()->getCString());
953 error(-1, "Couldn't find a font for '%s'",
955 gfxFont->getName()->getCString() : "[unnamed]");
960 // insert font in cache
961 if (nFonts == xOutFontCacheSize) {
963 delete fonts[nFonts];
965 for (j = nFonts; j > 0; --j) {
966 fonts[j] = fonts[j-1];
974 XOutputFont *XOutputFontCache::tryGetFont(XRef *xref, DisplayFontParam *dfp,
976 double m11Orig, double m12Orig,
977 double m21Orig, double m22Orig,
978 double m11, double m12,
979 double m21, double m22,
985 // create the new font
989 font = tryGetServerFont(dfp->x.xlfd, dfp->x.encoding, gfxFont,
990 m11Orig, m12Orig, m21Orig, m22Orig,
996 if (t1libControl != fontRastNone) {
997 font = tryGetT1FontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont,
998 m11Orig, m12Orig, m21Orig, m22Orig,
999 m11, m12, m21, m22, subst);
1002 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1004 if (freetypeControl != fontRastNone) {
1005 font = tryGetFTFontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont,
1006 m11Orig, m12Orig, m21Orig, m22Orig,
1007 m11, m12, m21, m22, subst);
1011 #if !((FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)) || defined(HAVE_T1LIB_H))
1012 error(-1, "Config file specifies a Type 1 font,");
1013 error(-1, "but xpdf was not built with t1lib or FreeType2 support");
1018 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1019 if (freetypeControl != fontRastNone) {
1020 font = tryGetFTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont,
1021 m11Orig, m12Orig, m21Orig, m22Orig,
1022 m11, m12, m21, m22, subst);
1025 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1026 if (freetypeControl != fontRastNone) {
1027 font = tryGetTTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont,
1028 m11Orig, m12Orig, m21Orig, m22Orig,
1029 m11, m12, m21, m22, subst);
1032 #if !(HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1033 error(-1, "Config file specifies a TrueType font,");
1034 error(-1, "but xpdf was not built with FreeType support");
1044 XOutputFont *XOutputFontCache::tryGetT1Font(XRef *xref,
1046 double m11, double m12,
1047 double m21, double m22) {
1049 XOutputT1FontFile *xFontFile;
1057 Object refObj, strObj;
1061 // check the already available font files
1062 id = gfxFont->getID();
1063 for (i = 0; i < t1FontFiles->getLength(); ++i) {
1064 xFontFile = (XOutputT1FontFile *)t1FontFiles->get(i);
1065 if (xFontFile->num == id->num && xFontFile->gen == id->gen &&
1066 !xFontFile->subst) {
1067 font = new XOutputT1Font(id, xFontFile->fontFile,
1069 m11, m12, m21, m22, display, xOut);
1070 if (!font->isOk()) {
1078 // check for an embedded font
1079 if (gfxFont->getEmbeddedFontID(&embRef)) {
1081 // create the font file
1083 if (!openTempFile(&fileName, &f, "wb", NULL)) {
1084 error(-1, "Couldn't create temporary Type 1 font file");
1087 if (gfxFont->getType() == fontType1C) {
1088 if (!(fontBuf = gfxFont->readEmbFontFile(xref, &fontLen))) {
1092 ff = new Type1CFontFile(fontBuf, fontLen);
1093 ff->convertToType1(outputToFile, f);
1096 } else { // fontType1
1097 refObj.initRef(embRef.num, embRef.gen);
1098 refObj.fetch(xref, &strObj);
1100 strObj.streamReset();
1101 while ((c = strObj.streamGetChar()) != EOF) {
1104 strObj.streamClose();
1110 font = tryGetT1FontFromFile(xref, fileName, gTrue, gfxFont,
1112 m11, m12, m21, m22, gFalse);
1114 // on systems with Unix hard link semantics, this will remove the
1115 // last link to the temp file
1116 unlink(fileName->getCString());
1120 // check for an external font file
1121 } else if ((fileName = gfxFont->getExtFontFile())) {
1122 font = tryGetT1FontFromFile(xref, fileName, gFalse, gfxFont,
1124 m11, m12, m21, m22, gFalse);
1133 XOutputFont *XOutputFontCache::tryGetT1FontFromFile(XRef *xref,
1141 double m11, double m12,
1142 double m21, double m22,
1145 T1FontFile *fontFile;
1148 // create the t1lib font file
1149 fontFile = new T1FontFile(t1Engine, fileName->getCString(),
1150 ((Gfx8BitFont *)gfxFont)->getEncoding(),
1151 gfxFont->getFontBBox());
1152 if (!fontFile->isOk()) {
1153 error(-1, "Couldn't create t1lib font from '%s'",
1154 fileName->getCString());
1157 unlink(fileName->getCString());
1163 id = gfxFont->getID();
1164 t1FontFiles->append(new XOutputT1FontFile(id->num, id->gen,
1166 deleteFile ? fileName->copy()
1167 : (GString *)NULL));
1170 font = new XOutputT1Font(gfxFont->getID(), fontFile,
1171 m11Orig, m12Orig, m21Orig, m22Orig,
1172 m11, m12, m21, m22, display, xOut);
1173 if (!font->isOk()) {
1179 #endif // HAVE_T1LIB_H
1181 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1182 XOutputFont *XOutputFontCache::tryGetFTFont(XRef *xref,
1184 double m11, double m12,
1185 double m21, double m22) {
1187 XOutputFTFontFile *xFontFile;
1192 #if 1 //~ need this until FT can handle fonts with missing tables
1195 TrueTypeFontFile *ff;
1197 Object refObj, strObj;
1201 // check the already available font files
1202 id = gfxFont->getID();
1203 for (i = 0; i < ftFontFiles->getLength(); ++i) {
1204 xFontFile = (XOutputFTFontFile *)ftFontFiles->get(i);
1205 if (xFontFile->num == id->num && xFontFile->gen == id->gen &&
1206 !xFontFile->subst) {
1207 font = new XOutputFTFont(id, xFontFile->fontFile,
1209 m11, m12, m21, m22, display, xOut);
1210 if (!font->isOk()) {
1218 // check for an embedded font
1219 if (gfxFont->getEmbeddedFontID(&embRef)) {
1221 // create the font file
1223 if (!openTempFile(&fileName, &f, "wb", NULL)) {
1224 error(-1, "Couldn't create temporary TrueType font file");
1227 #if 1 //~ need this until FT can handle fonts with missing tables
1228 if (gfxFont->getType() == fontTrueType ||
1229 gfxFont->getType() == fontCIDType2) {
1230 if (!(fontBuf = gfxFont->readEmbFontFile(xref, &fontLen))) {
1234 ff = new TrueTypeFontFile(fontBuf, fontLen);
1239 refObj.initRef(embRef.num, embRef.gen);
1240 refObj.fetch(xref, &strObj);
1242 strObj.streamReset();
1243 while ((c = strObj.streamGetChar()) != EOF) {
1246 strObj.streamClose();
1250 refObj.initRef(embRef.num, embRef.gen);
1251 refObj.fetch(xref, &strObj);
1253 strObj.streamReset();
1254 while ((c = strObj.streamGetChar()) != EOF) {
1257 strObj.streamClose();
1263 font = tryGetFTFontFromFile(xref, fileName, gTrue, gfxFont,
1265 m11, m12, m21, m22, gFalse);
1267 // on systems with Unix hard link semantics, this will remove the
1268 // last link to the temp file
1269 unlink(fileName->getCString());
1273 // check for an external font file
1274 } else if ((fileName = gfxFont->getExtFontFile())) {
1275 font = tryGetFTFontFromFile(xref, fileName, gFalse, gfxFont,
1277 m11, m12, m21, m22, gFalse);
1286 XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref,
1294 double m11, double m12,
1295 double m21, double m22,
1298 FTFontFile *fontFile;
1301 // create the FreeType font file
1302 if (gfxFont->isCIDFont()) {
1303 if (gfxFont->getType() == fontCIDType2) {
1304 fontFile = new FTFontFile(ftEngine, fileName->getCString(),
1305 ((GfxCIDFont *)gfxFont)->getCIDToGID(),
1306 ((GfxCIDFont *)gfxFont)->getCIDToGIDLen());
1307 } else { // fontCIDType0C
1308 fontFile = new FTFontFile(ftEngine, fileName->getCString());
1311 fontFile = new FTFontFile(ftEngine, fileName->getCString(),
1312 ((Gfx8BitFont *)gfxFont)->getEncoding(),
1313 ((Gfx8BitFont *)gfxFont)->getHasEncoding());
1315 if (!fontFile->isOk()) {
1316 error(-1, "Couldn't create FreeType font from '%s'",
1317 fileName->getCString());
1320 unlink(fileName->getCString());
1326 id = gfxFont->getID();
1327 ftFontFiles->append(new XOutputFTFontFile(id->num, id->gen,
1329 deleteFile ? fileName->copy()
1330 : (GString *)NULL));
1333 font = new XOutputFTFont(gfxFont->getID(), fontFile,
1334 m11Orig, m12Orig, m21Orig, m22Orig,
1335 m11, m12, m21, m22, display, xOut);
1336 if (!font->isOk()) {
1342 #endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1344 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1345 XOutputFont *XOutputFontCache::tryGetTTFont(XRef *xref,
1347 double m11, double m12,
1348 double m21, double m22) {
1350 XOutputTTFontFile *xFontFile;
1355 Object refObj, strObj;
1359 // check the already available font files
1360 id = gfxFont->getID();
1362 for (i = 0; i < ttFontFiles->getLength(); ++i) {
1363 xFontFile = (XOutputTTFontFile *)ttFontFiles->get(i);
1364 if (xFontFile->num == id->num && xFontFile->gen == id->gen &&
1365 !xFontFile->subst) {
1366 font = new XOutputTTFont(id, xFontFile->fontFile,
1368 m11, m12, m21, m22, display, xOut);
1369 if (!font->isOk()) {
1377 // check for an embedded font
1378 if (gfxFont->getEmbeddedFontID(&embRef)) {
1380 // create the font file
1382 if (!openTempFile(&fileName, &f, "wb", NULL)) {
1383 error(-1, "Couldn't create temporary TrueType font file");
1386 refObj.initRef(embRef.num, embRef.gen);
1387 refObj.fetch(xref, &strObj);
1389 strObj.streamReset();
1390 while ((c = strObj.streamGetChar()) != EOF) {
1393 strObj.streamClose();
1398 font = tryGetTTFontFromFile(xref, fileName, gTrue, gfxFont,
1400 m11, m12, m21, m22, gFalse);
1402 // on systems with Unix hard link semantics, this will remove the
1403 // last link to the temp file
1404 unlink(fileName->getCString());
1408 } else if ((fileName = gfxFont->getExtFontFile())) {
1409 font = tryGetTTFontFromFile(xref, fileName, gFalse, gfxFont,
1411 m11, m12, m21, m22, gFalse);
1420 XOutputFont *XOutputFontCache::tryGetTTFontFromFile(XRef *xref,
1428 double m11, double m12,
1429 double m21, double m22,
1432 TTFontFile *fontFile;
1435 // create the FreeType font file
1436 if (gfxFont->isCIDFont()) {
1438 fontFile = new TTFontFile(ttEngine, fileName->getCString(),
1439 ((GfxCIDFont *)gfxFont)->getCIDToGID(),
1440 ((GfxCIDFont *)gfxFont)->getCIDToGIDLen());
1442 fontFile = new TTFontFile(ttEngine, fileName->getCString(),
1443 ((Gfx8BitFont *)gfxFont)->getEncoding(),
1444 ((Gfx8BitFont *)gfxFont)->getHasEncoding());
1446 if (!fontFile->isOk()) {
1447 error(-1, "Couldn't create FreeType font from '%s'",
1448 fileName->getCString());
1451 unlink(fileName->getCString());
1457 id = gfxFont->getID();
1458 ttFontFiles->append(new XOutputTTFontFile(id->num, id->gen,
1460 deleteFile ? fileName->copy()
1461 : (GString *)NULL));
1464 font = new XOutputTTFont(gfxFont->getID(), fontFile,
1465 m11Orig, m12Orig, m21Orig, m22Orig,
1466 m11, m12, m21, m22, display, xOut);
1467 if (!font->isOk()) {
1473 #endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1475 XOutputFont *XOutputFontCache::tryGetServerFont(GString *xlfd,
1476 GString *encodingName,
1478 double m11Orig, double m12Orig,
1479 double m21Orig, double m22Orig,
1480 double m11, double m12,
1481 double m21, double m22) {
1484 CharCodeToUnicode *ctu;
1486 uMap = globalParams->getUnicodeMap(encodingName);
1487 if (gfxFont->isCIDFont()) {
1488 ctu = ((GfxCIDFont *)gfxFont)->getToUnicode();
1489 font = new XOutputServer16BitFont(gfxFont->getID(), xlfd, uMap, ctu,
1490 m11Orig, m12Orig, m21Orig, m22Orig,
1495 ctu = ((Gfx8BitFont *)gfxFont)->getToUnicode();
1496 font = new XOutputServer8BitFont(gfxFont->getID(), xlfd, uMap, ctu,
1497 m11Orig, m12Orig, m21Orig, m22Orig,
1503 if (!font->isOk()) {
1510 //------------------------------------------------------------------------
1512 //------------------------------------------------------------------------
1514 struct T3FontCacheTag {
1516 Gushort mru; // valid bit (0x8000) and MRU index
1517 double wx, wy; // untransformed glyph metrics
1523 T3FontCache(Ref *fontID, double m11A, double m12A,
1524 double m21A, double m22A,
1525 int glyphXA, int glyphYA, int glyphWA, int glyphHA,
1526 Display *displayA, Visual *visual, Guint depth,
1529 GBool matches(Ref *idA, double m11A, double m12A,
1530 double m21A, double m22A)
1531 { return fontID.num == idA->num && fontID.gen == idA->gen &&
1532 m11 == m11A && m12 == m12A && m21 == m21A && m22 == m22A; }
1534 Ref fontID; // PDF font ID
1535 double m11, m12, m21, m22; // transform matrix
1536 int glyphX, glyphY; // pixel offset of glyph pixmaps
1537 int glyphW, glyphH; // size of glyph pixmaps, in pixels
1538 int glyphSize; // size of glyph pixmaps, in bytes
1539 int cacheSets; // number of sets in cache
1540 int cacheAssoc; // cache associativity (glyphs per set)
1541 Guchar *cacheData; // glyph pixmap cache
1542 T3FontCacheTag *cacheTags; // cache tags, i.e., char codes
1548 T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A,
1549 double m21A, double m22A,
1550 int glyphXA, int glyphYA, int glyphWA, int glyphHA,
1551 Display *displayA, Visual *visual, Guint depth,
1552 Pixmap origPixmap) {
1564 glyphSize = glyphW * glyphH;
1566 if (glyphSize <= 256) {
1568 } else if (glyphSize <= 512) {
1570 } else if (glyphSize <= 1024) {
1575 cacheData = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize);
1576 cacheTags = (T3FontCacheTag *)gmalloc(cacheSets * cacheAssoc *
1577 sizeof(T3FontCacheTag));
1578 for (i = 0; i < cacheSets * cacheAssoc; ++i) {
1579 cacheTags[i].mru = i & (cacheAssoc - 1);
1582 pixmap = XCreatePixmap(display, origPixmap, glyphW, glyphH, depth);
1583 image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL,
1584 glyphW, glyphH, 8, 0);
1585 image->data = (char *)gmalloc(glyphH * image->bytes_per_line);
1588 T3FontCache::~T3FontCache() {
1591 XFreePixmap(display, pixmap);
1594 XDestroyImage(image);
1597 struct T3GlyphStack {
1602 T3FontCacheTag *cacheTag;
1608 int origPixmapW, origPixmapH;
1612 Region origClipRegion;
1613 double origCTM4, origCTM5;
1614 double wx, wy; // untransformed glyph metrics
1618 //------------------------------------------------------------------------
1620 //------------------------------------------------------------------------
1622 XOutputDev::XOutputDev(Display *displayA, int screenNumA,
1623 Visual *visualA, Colormap colormapA,
1624 GBool reverseVideoA, unsigned long paperColorA,
1625 GBool installCmap, int rgbCubeSize,
1627 XVisualInfo visualTempl;
1628 XVisualInfo *visualList;
1639 // display / screen / visual / colormap
1641 screenNum = screenNumA;
1643 colormap = colormapA;
1646 pixmapW = pixmapH = 0;
1648 // check for TrueColor visual
1649 if (forceDepth != 0) {
1651 trueColor = depth >= 16;
1653 visualTempl.visualid = XVisualIDFromVisual(visual);
1654 visualList = XGetVisualInfo(display, VisualIDMask,
1655 &visualTempl, &nVisuals);
1657 // this shouldn't happen
1658 XFree((XPointer)visualList);
1659 visualList = XGetVisualInfo(display, VisualNoMask, &visualTempl,
1662 depth = visualList->depth;
1663 if (visualList->c_class == TrueColor) {
1665 for (mask = visualList->red_mask, rShift = 0;
1666 mask && !(mask & 1);
1667 mask >>= 1, ++rShift) ;
1669 for (mask = visualList->green_mask, gShift = 0;
1670 mask && !(mask & 1);
1671 mask >>= 1, ++gShift) ;
1673 for (mask = visualList->blue_mask, bShift = 0;
1674 mask && !(mask & 1);
1675 mask >>= 1, ++bShift) ;
1680 XFree((XPointer)visualList);
1683 // allocate a color cube
1685 redMap[BlackPixel(display, screenNum) & 0xff] = 0;
1686 redMap[WhitePixel(display, screenNum) & 0xff] = 1;
1688 // set colors in private colormap
1690 for (numColors = 6; numColors >= 2; --numColors) {
1691 m = numColors * numColors * numColors;
1692 if (XAllocColorCells(display, colormap, False, NULL, 0, colors, m)) {
1696 if (numColors >= 2) {
1697 m = numColors * numColors * numColors;
1698 xcolors = (XColor *)gmalloc(m * sizeof(XColor));
1700 for (r = 0; r < numColors; ++r) {
1701 for (g = 0; g < numColors; ++g) {
1702 for (b = 0; b < numColors; ++b) {
1703 xcolors[n].pixel = colors[n];
1704 xcolors[n].red = (r * 65535) / (numColors - 1);
1705 xcolors[n].green = (g * 65535) / (numColors - 1);
1706 xcolors[n].blue = (b * 65535) / (numColors - 1);
1707 xcolors[n].flags = DoRed | DoGreen | DoBlue;
1708 redMap[xcolors[n].pixel & 0xff] = xcolors[n].red / 65535.0;
1713 XStoreColors(display, colormap, xcolors, m);
1717 colors[0] = BlackPixel(display, screenNum);
1718 colors[1] = WhitePixel(display, screenNum);
1721 // allocate colors in shared colormap
1723 if (rgbCubeSize > maxRGBCube) {
1724 rgbCubeSize = maxRGBCube;
1727 for (numColors = rgbCubeSize; numColors >= 2; --numColors) {
1730 for (r = 0; r < numColors && ok; ++r) {
1731 for (g = 0; g < numColors && ok; ++g) {
1732 for (b = 0; b < numColors && ok; ++b) {
1734 colors[n] = BlackPixel(display, screenNum);
1735 redMap[colors[n] & 0xff] = 0;
1738 xcolor.red = (r * 65535) / (numColors - 1);
1739 xcolor.green = (g * 65535) / (numColors - 1);
1740 xcolor.blue = (b * 65535) / (numColors - 1);
1741 if (XAllocColor(display, colormap, &xcolor)) {
1742 colors[n++] = xcolor.pixel;
1743 redMap[xcolor.pixel & 0xff] = xcolor.red / 65535.0;
1754 XFreeColors(display, colormap, &colors[1], n-1, 0);
1758 colors[0] = BlackPixel(display, screenNum);
1759 colors[1] = WhitePixel(display, screenNum);
1765 reverseVideo = reverseVideoA;
1766 paperColor = paperColorA;
1768 // set up the font cache and fonts
1771 fontCache = new XOutputFontCache(display, depth, this,
1772 globalParams->getT1libControl(),
1773 globalParams->getFreeTypeControl());
1775 t3GlyphStack = NULL;
1777 // empty state stack
1780 // create text object
1781 text = new TextPage(gFalse);
1784 XOutputDev::~XOutputDev() {
1788 for (i = 0; i < nT3Fonts; ++i) {
1789 delete t3FontCache[i];
1794 void XOutputDev::startDoc(XRef *xrefA) {
1798 fontCache->startDoc(screenNum, visual, colormap, trueColor, rMul, gMul, bMul,
1799 rShift, gShift, bShift, colors, numColors);
1800 for (i = 0; i < nT3Fonts; ++i) {
1801 delete t3FontCache[i];
1806 void XOutputDev::startPage(int pageNum, GfxState *state) {
1810 // default line flatness
1814 gcValues.foreground = BlackPixel(display, screenNum);
1815 gcValues.background = WhitePixel(display, screenNum);
1816 gcValues.line_width = 0;
1817 gcValues.line_style = LineSolid;
1818 strokeGC = XCreateGC(display, pixmap,
1819 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
1821 fillGC = XCreateGC(display, pixmap,
1822 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
1824 gcValues.foreground = paperColor;
1825 paperGC = XCreateGC(display, pixmap,
1826 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
1829 // initialize clip region
1830 clipRegion = XCreateRegion();
1831 rect.x = rect.y = 0;
1832 rect.width = pixmapW;
1833 rect.height = pixmapH;
1834 XUnionRectWithRegion(&rect, clipRegion, clipRegion);
1835 XSetRegion(display, strokeGC, clipRegion);
1836 XSetRegion(display, fillGC, clipRegion);
1843 XFillRectangle(display, pixmap, paperGC, 0, 0, pixmapW, pixmapH);
1845 // clear text object
1849 void XOutputDev::endPage() {
1854 // clear state stack, free all GCs, free the clip region
1858 XFreeGC(display, s->strokeGC);
1859 XFreeGC(display, s->fillGC);
1860 XDestroyRegion(s->clipRegion);
1863 XFreeGC(display, strokeGC);
1864 XFreeGC(display, fillGC);
1865 XFreeGC(display, paperGC);
1866 XDestroyRegion(clipRegion);
1869 void XOutputDev::drawLink(Link *link, Catalog *catalog) {
1870 double x1, y1, x2, y2, w;
1875 link->getBorder(&x1, &y1, &x2, &y2, &w);
1880 XSetForeground(display, strokeGC, findColor(&rgb));
1881 XSetLineAttributes(display, strokeGC, xoutRound(w),
1882 LineSolid, CapRound, JoinRound);
1883 cvtUserToDev(x1, y1, &x, &y);
1884 points[0].x = points[4].x = x;
1885 points[0].y = points[4].y = y;
1886 cvtUserToDev(x2, y1, &x, &y);
1889 cvtUserToDev(x2, y2, &x, &y);
1892 cvtUserToDev(x1, y2, &x, &y);
1895 XDrawLines(display, pixmap, strokeGC, points, 5, CoordModeOrigin);
1899 void XOutputDev::saveState(GfxState *state) {
1903 // save current state
1904 s = new XOutputState;
1905 s->strokeGC = strokeGC;
1907 s->clipRegion = clipRegion;
1909 // push onto state stack
1913 // create a new current state by copying
1914 strokeGC = XCreateGC(display, pixmap, 0, &values);
1915 XCopyGC(display, s->strokeGC, 0xffffffff, strokeGC);
1916 fillGC = XCreateGC(display, pixmap, 0, &values);
1917 XCopyGC(display, s->fillGC, 0xffffffff, fillGC);
1918 clipRegion = XCreateRegion();
1919 XUnionRegion(s->clipRegion, clipRegion, clipRegion);
1920 XSetRegion(display, strokeGC, clipRegion);
1921 XSetRegion(display, fillGC, clipRegion);
1924 void XOutputDev::restoreState(GfxState *state) {
1928 // kill current state
1929 XFreeGC(display, strokeGC);
1930 XFreeGC(display, fillGC);
1931 XDestroyRegion(clipRegion);
1934 flatness = state->getFlatness();
1935 strokeGC = save->strokeGC;
1936 fillGC = save->fillGC;
1937 clipRegion = save->clipRegion;
1938 XSetRegion(display, strokeGC, clipRegion);
1939 XSetRegion(display, fillGC, clipRegion);
1948 void XOutputDev::updateAll(GfxState *state) {
1949 updateLineAttrs(state, gTrue);
1950 updateFlatness(state);
1951 updateMiterLimit(state);
1952 updateFillColor(state);
1953 updateStrokeColor(state);
1957 void XOutputDev::updateCTM(GfxState *state, double m11, double m12,
1958 double m21, double m22, double m31, double m32) {
1959 updateLineAttrs(state, gTrue);
1962 void XOutputDev::updateLineDash(GfxState *state) {
1963 updateLineAttrs(state, gTrue);
1966 void XOutputDev::updateFlatness(GfxState *state) {
1967 flatness = state->getFlatness();
1970 void XOutputDev::updateLineJoin(GfxState *state) {
1971 updateLineAttrs(state, gFalse);
1974 void XOutputDev::updateLineCap(GfxState *state) {
1975 updateLineAttrs(state, gFalse);
1979 void XOutputDev::updateMiterLimit(GfxState *state) {
1982 void XOutputDev::updateLineWidth(GfxState *state) {
1983 updateLineAttrs(state, gFalse);
1986 void XOutputDev::updateLineAttrs(GfxState *state, GBool updateDash) {
1989 double *dashPattern;
1995 width = state->getTransformedLineWidth();
1996 switch (state->getLineCap()) {
1997 case 0: cap = CapButt; break;
1998 case 1: cap = CapRound; break;
1999 case 2: cap = CapProjecting; break;
2001 error(-1, "Bad line cap style (%d)", state->getLineCap());
2005 switch (state->getLineJoin()) {
2006 case 0: join = JoinMiter; break;
2007 case 1: join = JoinRound; break;
2008 case 2: join = JoinBevel; break;
2010 error(-1, "Bad line join style (%d)", state->getLineJoin());
2014 state->getLineDash(&dashPattern, &dashLength, &dashStart);
2015 #if 1 //~ work around a bug in XFree86 (???)
2016 if (dashLength > 0 && cap == CapProjecting) {
2020 XSetLineAttributes(display, strokeGC, xoutRound(width),
2021 dashLength > 0 ? LineOnOffDash : LineSolid,
2023 if (updateDash && dashLength > 0) {
2024 if (dashLength > 20)
2026 for (i = 0; i < dashLength; ++i) {
2027 dashList[i] = xoutRound(state->transformWidth(dashPattern[i]));
2028 if (dashList[i] == 0)
2031 XSetDashes(display, strokeGC, xoutRound(dashStart), dashList, dashLength);
2035 void XOutputDev::updateFillColor(GfxState *state) {
2038 state->getFillRGB(&rgb);
2044 XSetForeground(display, fillGC, findColor(&rgb));
2047 void XOutputDev::updateStrokeColor(GfxState *state) {
2050 state->getStrokeRGB(&rgb);
2056 XSetForeground(display, strokeGC, findColor(&rgb));
2059 void XOutputDev::updateFont(GfxState *state) {
2060 double m11, m12, m21, m22;
2062 text->updateFont(state);
2064 if (!(gfxFont = state->getFont())) {
2068 if (gfxFont->getType() == fontType3) {
2072 state->getFontTransMat(&m11, &m12, &m21, &m22);
2073 m11 *= state->getHorizScaling();
2074 m12 *= state->getHorizScaling();
2075 font = fontCache->getFont(xref, gfxFont, m11, m12, m21, m22);
2077 font->updateGC(fillGC);
2078 font->updateGC(strokeGC);
2082 void XOutputDev::stroke(GfxState *state) {
2085 int n, size, numPoints, i, j;
2088 n = convertPath(state, &points, &size, &numPoints, &lengths, gFalse);
2090 // draw each subpath
2092 for (i = 0; i < n; ++i) {
2093 XDrawLines(display, pixmap, strokeGC, points + j, lengths[i],
2098 // free points and lengths arrays
2099 if (points != tmpPoints)
2101 if (lengths != tmpLengths)
2105 void XOutputDev::fill(GfxState *state) {
2106 doFill(state, WindingRule);
2109 void XOutputDev::eoFill(GfxState *state) {
2110 doFill(state, EvenOddRule);
2114 // X doesn't color the pixels on the right-most and bottom-most
2115 // borders of a polygon. This means that one-pixel-thick polygons
2116 // are not colored at all. I think this is supposed to be a
2117 // feature, but I can't figure out why. So after it fills a
2118 // polygon, it also draws lines around the border. This is done
2119 // only for single-component polygons, since it's not very
2120 // compatible with the compound polygon kludge (see convertPath()).
2122 void XOutputDev::doFill(GfxState *state, int rule) {
2125 int n, size, numPoints, i, j;
2128 XSetFillRule(display, fillGC, rule);
2130 // transform points, build separate polygons
2131 n = convertPath(state, &points, &size, &numPoints, &lengths, gTrue);
2135 for (i = 0; i < n; ++i) {
2136 XFillPolygon(display, pixmap, fillGC, points + j, lengths[i],
2137 Complex, CoordModeOrigin);
2138 if (state->getPath()->getNumSubpaths() == 1) {
2139 XDrawLines(display, pixmap, fillGC, points + j, lengths[i],
2142 j += lengths[i] + 1;
2145 // free points and lengths arrays
2146 if (points != tmpPoints)
2148 if (lengths != tmpLengths)
2152 void XOutputDev::clip(GfxState *state) {
2153 doClip(state, WindingRule);
2156 void XOutputDev::eoClip(GfxState *state) {
2157 doClip(state, EvenOddRule);
2160 void XOutputDev::doClip(GfxState *state, int rule) {
2161 Region region, region2;
2164 int n, size, numPoints, i, j;
2166 // transform points, build separate polygons
2167 n = convertPath(state, &points, &size, &numPoints, &lengths, gTrue);
2169 // construct union of subpath regions
2170 // (XPolygonRegion chokes if there aren't at least three points --
2171 // this happens if the PDF file does moveto/closepath/clip, which
2172 // sets an empty clipping region)
2173 if (lengths[0] > 2) {
2174 region = XPolygonRegion(points, lengths[0], rule);
2176 region = XCreateRegion();
2179 for (i = 1; i < n; ++i) {
2180 if (lengths[i] > 2) {
2181 region2 = XPolygonRegion(points + j, lengths[i], rule);
2183 region2 = XCreateRegion();
2185 XUnionRegion(region2, region, region);
2186 XDestroyRegion(region2);
2187 j += lengths[i] + 1;
2190 // intersect region with clipping region
2191 XIntersectRegion(region, clipRegion, clipRegion);
2192 XDestroyRegion(region);
2193 XSetRegion(display, strokeGC, clipRegion);
2194 XSetRegion(display, fillGC, clipRegion);
2196 // free points and lengths arrays
2197 if (points != tmpPoints)
2199 if (lengths != tmpLengths)
2204 // Transform points in the path and convert curves to line segments.
2205 // Builds a set of subpaths and returns the number of subpaths.
2206 // If <fillHack> is set, close any unclosed subpaths and activate a
2207 // kludge for polygon fills: First, it divides up the subpaths into
2208 // non-overlapping polygons by simply comparing bounding rectangles.
2209 // Then it connects subaths within a single compound polygon to a single
2210 // point so that X can fill the polygon (sort of).
2212 int XOutputDev::convertPath(GfxState *state, XPoint **points, int *size,
2213 int *numPoints, int **lengths, GBool fillHack) {
2215 BoundingRect *rects;
2217 int n, i, ii, j, k, k0;
2219 // get path and number of subpaths
2220 path = state->getPath();
2221 n = path->getNumSubpaths();
2223 // allocate lengths array
2224 if (n < numTmpSubpaths)
2225 *lengths = tmpLengths;
2227 *lengths = (int *)gmalloc(n * sizeof(int));
2229 // allocate bounding rectangles array
2231 if (n < numTmpSubpaths)
2234 rects = (BoundingRect *)gmalloc(n * sizeof(BoundingRect));
2240 *points = tmpPoints;
2241 *size = numTmpPoints;
2243 for (i = 0; i < n; ++i) {
2245 // transform the points
2247 convertSubpath(state, path->getSubpath(i), points, size, numPoints);
2249 // construct bounding rectangle
2251 rects[i].xMin = rects[i].xMax = (*points)[j].x;
2252 rects[i].yMin = rects[i].yMax = (*points)[j].y;
2253 for (k = j + 1; k < *numPoints; ++k) {
2254 if ((*points)[k].x < rects[i].xMin)
2255 rects[i].xMin = (*points)[k].x;
2256 else if ((*points)[k].x > rects[i].xMax)
2257 rects[i].xMax = (*points)[k].x;
2258 if ((*points)[k].y < rects[i].yMin)
2259 rects[i].yMin = (*points)[k].y;
2260 else if ((*points)[k].y > rects[i].yMax)
2261 rects[i].yMax = (*points)[k].y;
2265 // close subpath if necessary
2266 if (fillHack && ((*points)[*numPoints-1].x != (*points)[j].x ||
2267 (*points)[*numPoints-1].y != (*points)[j].y)) {
2268 addPoint(points, size, numPoints, (*points)[j].x, (*points)[j].y);
2271 // length of this subpath
2272 (*lengths)[i] = *numPoints - j;
2274 // leave an extra point for compound fill hack
2276 addPoint(points, size, numPoints, 0, 0);
2279 // kludge: munge any points that are *way* out of bounds - these can
2280 // crash certain (buggy) X servers
2281 for (i = 0; i < *numPoints; ++i) {
2282 if ((*points)[i].x < -pixmapW) {
2283 (*points)[i].x = -pixmapW;
2284 } else if ((*points)[i].x > 2 * pixmapW) {
2285 (*points)[i].x = 2 * pixmapW;
2287 if ((*points)[i].y < -pixmapH) {
2288 (*points)[i].y = -pixmapH;
2289 } else if ((*points)[i].y > 2 * pixmapH) {
2290 (*points)[i].y = 2 * pixmapH;
2294 // combine compound polygons
2299 // start with subpath i
2301 (*lengths)[j] = (*lengths)[i];
2303 (*points)[k + (*lengths)[i]] = (*points)[k0];
2304 k += (*lengths)[i] + 1;
2307 // combine overlapping polygons
2310 // look for the first subsequent subpath, if any, which overlaps
2311 for (ii = i; ii < n; ++ii) {
2312 if (rects[ii].xMax > rects[i].xMin &&
2313 rects[ii].xMin < rects[i].xMax &&
2314 rects[ii].yMax > rects[i].yMin &&
2315 rects[ii].yMin < rects[i].yMax) {
2320 // if there is an overlap, combine the polygons
2322 for (; i <= ii; ++i) {
2323 if (rects[i].xMin < rect.xMin)
2324 rect.xMin = rects[j].xMin;
2325 if (rects[i].xMax > rect.xMax)
2326 rect.xMax = rects[j].xMax;
2327 if (rects[i].yMin < rect.yMin)
2328 rect.yMin = rects[j].yMin;
2329 if (rects[i].yMax > rect.yMax)
2330 rect.yMax = rects[j].yMax;
2331 (*lengths)[j] += (*lengths)[i] + 1;
2332 (*points)[k + (*lengths)[i]] = (*points)[k0];
2333 k += (*lengths)[i] + 1;
2336 } while (ii < n && i < n);
2341 // free bounding rectangles
2342 if (rects != tmpRects)
2352 // Transform points in a single subpath and convert curves to line
2355 void XOutputDev::convertSubpath(GfxState *state, GfxSubpath *subpath,
2356 XPoint **points, int *size, int *n) {
2357 double x0, y0, x1, y1, x2, y2, x3, y3;
2360 m = subpath->getNumPoints();
2363 if (i >= 1 && subpath->getCurve(i)) {
2364 state->transform(subpath->getX(i-1), subpath->getY(i-1), &x0, &y0);
2365 state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1);
2366 state->transform(subpath->getX(i+1), subpath->getY(i+1), &x2, &y2);
2367 state->transform(subpath->getX(i+2), subpath->getY(i+2), &x3, &y3);
2368 doCurve(points, size, n, x0, y0, x1, y1, x2, y2, x3, y3);
2371 state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1);
2372 addPoint(points, size, n, xoutRound(x1), xoutRound(y1));
2379 // Subdivide a Bezier curve. This uses floating point to avoid
2380 // propagating rounding errors. (The curves look noticeably more
2381 // jagged with integer arithmetic.)
2383 void XOutputDev::doCurve(XPoint **points, int *size, int *n,
2384 double x0, double y0, double x1, double y1,
2385 double x2, double y2, double x3, double y3) {
2386 double x[(1<<maxCurveSplits)+1][3];
2387 double y[(1<<maxCurveSplits)+1][3];
2388 int next[1<<maxCurveSplits];
2390 double xx1, yy1, xx2, yy2;
2391 double dx, dy, mx, my, d1, d2;
2392 double xl0, yl0, xl1, yl1, xl2, yl2;
2393 double xr0, yr0, xr1, yr1, xr2, yr2, xr3, yr3;
2397 flat = (double)(flatness * flatness);
2403 p2 = 1<<maxCurveSplits;
2404 x[p1][0] = x0; y[p1][0] = y0;
2405 x[p1][1] = x1; y[p1][1] = y1;
2406 x[p1][2] = x2; y[p1][2] = y2;
2407 x[p2][0] = x3; y[p2][0] = y3;
2410 while (p1 < (1<<maxCurveSplits)) {
2413 xl0 = x[p1][0]; yl0 = y[p1][0];
2414 xx1 = x[p1][1]; yy1 = y[p1][1];
2415 xx2 = x[p1][2]; yy2 = y[p1][2];
2417 xr3 = x[p2][0]; yr3 = y[p2][0];
2419 // compute distances from control points to midpoint of the
2420 // straight line (this is a bit of a hack, but it's much faster
2421 // than computing the actual distances to the line)
2422 mx = (xl0 + xr3) * 0.5;
2423 my = (yl0 + yr3) * 0.5;
2431 // if curve is flat enough, or no more divisions allowed then
2432 // add the straight line segment
2433 if (p2 - p1 <= 1 || (d1 <= flat && d2 <= flat)) {
2434 addPoint(points, size, n, xoutRound(xr3), xoutRound(yr3));
2437 // otherwise, subdivide the curve
2439 xl1 = (xl0 + xx1) * 0.5;
2440 yl1 = (yl0 + yy1) * 0.5;
2441 xh = (xx1 + xx2) * 0.5;
2442 yh = (yy1 + yy2) * 0.5;
2443 xl2 = (xl1 + xh) * 0.5;
2444 yl2 = (yl1 + yh) * 0.5;
2445 xr2 = (xx2 + xr3) * 0.5;
2446 yr2 = (yy2 + yr3) * 0.5;
2447 xr1 = (xh + xr2) * 0.5;
2448 yr1 = (yh + yr2) * 0.5;
2449 xr0 = (xl2 + xr1) * 0.5;
2450 yr0 = (yl2 + yr1) * 0.5;
2452 // add the new subdivision points
2454 x[p1][1] = xl1; y[p1][1] = yl1;
2455 x[p1][2] = xl2; y[p1][2] = yl2;
2457 x[p3][0] = xr0; y[p3][0] = yr0;
2458 x[p3][1] = xr1; y[p3][1] = yr1;
2459 x[p3][2] = xr2; y[p3][2] = yr2;
2466 // Add a point to the points array. (This would use a generic resizable
2467 // array type if C++ supported parameterized types in some reasonable
2468 // way -- templates are a disgusting kludge.)
2470 void XOutputDev::addPoint(XPoint **points, int *size, int *k, int x, int y) {
2473 if (*points == tmpPoints) {
2474 *points = (XPoint *)gmalloc(*size * sizeof(XPoint));
2475 memcpy(*points, tmpPoints, *k * sizeof(XPoint));
2477 *points = (XPoint *)grealloc(*points, *size * sizeof(XPoint));
2480 (*points)[*k].x = x;
2481 (*points)[*k].y = y;
2485 void XOutputDev::beginString(GfxState *state, GString *s) {
2486 text->beginString(state, state->getCurX(), state->getCurY());
2489 void XOutputDev::endString(GfxState *state) {
2493 void XOutputDev::drawChar(GfxState *state, double x, double y,
2494 double dx, double dy,
2495 double originX, double originY,
2496 CharCode code, Unicode *u, int uLen) {
2498 double x1, y1, dx1, dy1;
2500 double saveCurX, saveCurY;
2504 text->addChar(state, x, y, dx, dy, u, uLen);
2510 // check for invisible text -- this is used by Acrobat Capture
2511 render = state->getRender();
2512 if ((render & 3) == 3) {
2518 state->transform(x, y, &x1, &y1);
2519 state->transformDelta(dx, dy, &dx1, &dy1);
2522 if (!(render & 1)) {
2523 state->getFillRGB(&rgb);
2529 font->drawChar(state, pixmap, pixmapW, pixmapH, fillGC, &rgb,
2530 x1, y1, dx1, dy1, code, u, uLen);
2534 if ((render & 3) == 1 || (render & 3) == 2) {
2535 if (font->hasGetCharPath()) {
2536 saveCurX = state->getCurX();
2537 saveCurY = state->getCurY();
2538 ctm = state->getCTM();
2539 memcpy(saveCTM, ctm, 6 * sizeof(double));
2540 state->setCTM(1, 0, 0, 1, x1, y1);
2541 font->getCharPath(state, code, u, uLen);
2544 state->setCTM(saveCTM[0], saveCTM[1], saveCTM[2], saveCTM[3],
2545 saveCTM[4], saveCTM[5]);
2546 state->moveTo(saveCurX, saveCurY);
2548 // can't stroke the outline, so just fill it using the stroke
2550 state->getStrokeRGB(&rgb);
2556 font->drawChar(state, pixmap, pixmapW, pixmapH, strokeGC, &rgb,
2557 x1, y1, dx1, dy1, code, u, uLen);
2561 #if 0 //~ unimplemented: clipping to char path
2568 GBool XOutputDev::beginType3Char(GfxState *state,
2569 CharCode code, Unicode *u, int uLen) {
2573 T3FontCache *t3Font;
2575 double x1, y1, xMin, yMin, xMax, yMax, xt, yt;
2581 fontID = gfxFont->getID();
2582 ctm = state->getCTM();
2583 state->transform(0, 0, &xt, &yt);
2585 // is it the first (MRU) font in the cache?
2586 if (!(nT3Fonts > 0 &&
2587 t3FontCache[0]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3]))) {
2589 // is the font elsewhere in the cache?
2590 for (i = 1; i < nT3Fonts; ++i) {
2591 if (t3FontCache[i]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3])) {
2592 t3Font = t3FontCache[i];
2593 for (j = i; j > 0; --j) {
2594 t3FontCache[j] = t3FontCache[j - 1];
2596 t3FontCache[0] = t3Font;
2600 if (i >= nT3Fonts) {
2602 // create new entry in the font cache
2603 if (nT3Fonts == xOutT3FontCacheSize) {
2604 delete t3FontCache[nT3Fonts - 1];
2607 for (j = nT3Fonts; j > 0; --j) {
2608 t3FontCache[j] = t3FontCache[j - 1];
2611 bbox = gfxFont->getFontBBox();
2612 if (bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0) {
2613 // broken bounding box -- just take a guess
2619 state->transform(bbox[0], bbox[1], &x1, &y1);
2622 state->transform(bbox[0], bbox[3], &x1, &y1);
2625 } else if (x1 > xMax) {
2630 } else if (y1 > yMax) {
2633 state->transform(bbox[2], bbox[1], &x1, &y1);
2636 } else if (x1 > xMax) {
2641 } else if (y1 > yMax) {
2644 state->transform(bbox[2], bbox[3], &x1, &y1);
2647 } else if (x1 > xMax) {
2652 } else if (y1 > yMax) {
2656 t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3],
2657 (int)floor(xMin - xt),
2658 (int)floor(yMin - yt),
2659 (int)ceil(xMax) - (int)floor(xMin) + 3,
2660 (int)ceil(yMax) - (int)floor(yMin) + 3,
2661 display, visual, depth, pixmap);
2664 t3Font = t3FontCache[0];
2666 // is the glyph in the cache?
2667 i = (code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc;
2668 for (j = 0; j < t3Font->cacheAssoc; ++j) {
2669 if ((t3Font->cacheTags[i+j].mru & 0x8000) &&
2670 t3Font->cacheTags[i+j].code == code) {
2671 state->getFillRGB(&color);
2673 color.r = 1 - color.r;
2674 color.g = 1 - color.g;
2675 color.b = 1 - color.b;
2677 text->addChar(state, 0, 0,
2678 t3Font->cacheTags[i+j].wx, t3Font->cacheTags[i+j].wy,
2680 drawType3Glyph(t3Font, &t3Font->cacheTags[i+j],
2681 t3Font->cacheData + (i+j) * t3Font->glyphSize,
2687 // push a new Type 3 glyph record
2688 t3gs = new T3GlyphStack();
2689 t3gs->next = t3GlyphStack;
2690 t3GlyphStack = t3gs;
2691 t3GlyphStack->cacheable = gFalse;
2692 t3GlyphStack->code = code;
2693 t3GlyphStack->cache = t3Font;
2694 t3GlyphStack->cacheIdx = i;
2695 t3GlyphStack->x = xt;
2696 t3GlyphStack->y = yt;
2697 t3GlyphStack->u = u;
2698 t3GlyphStack->uLen = uLen;
2703 void XOutputDev::endType3Char(GfxState *state) {
2712 if (t3GlyphStack->cacheable) {
2713 image = t3GlyphStack->cache->image;
2714 XGetSubImage(display, pixmap, 0, 0,
2715 t3GlyphStack->cache->glyphW, t3GlyphStack->cache->glyphH,
2716 (1 << depth) - 1, ZPixmap, image, 0, 0);
2717 p = t3GlyphStack->cacheData;
2718 for (y = 0; y < t3GlyphStack->cache->glyphH; ++y) {
2719 for (x = 0; x < t3GlyphStack->cache->glyphW; ++x) {
2720 pixel = XGetPixel(image, x, y);
2722 alpha = (double)((pixel >> rShift) & rMul) / (double)rMul;
2724 alpha = redMap[pixel & 0xff];
2728 } else if (alpha <= 0.4) {
2730 } else if (alpha <= 0.6) {
2732 } else if (alpha <= 0.8) {
2739 XDestroyRegion(clipRegion);
2740 XFreeGC(display, strokeGC);
2741 XFreeGC(display, fillGC);
2742 pixmapW = t3GlyphStack->origPixmapW;
2743 pixmapH = t3GlyphStack->origPixmapH;
2744 pixmap = t3GlyphStack->origPixmap;
2745 strokeGC = t3GlyphStack->origStrokeGC;
2746 fillGC = t3GlyphStack->origFillGC;
2747 clipRegion = t3GlyphStack->origClipRegion;
2748 drawType3Glyph(t3GlyphStack->cache,
2749 t3GlyphStack->cacheTag, t3GlyphStack->cacheData,
2750 t3GlyphStack->x, t3GlyphStack->y, &t3GlyphStack->color);
2751 // the CTM must be restored here in order for TextPage::addChar to
2753 ctm = state->getCTM();
2754 state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
2755 t3GlyphStack->origCTM4, t3GlyphStack->origCTM5);
2757 text->addChar(state, 0, 0, t3GlyphStack->wx, t3GlyphStack->wy,
2758 t3GlyphStack->u, t3GlyphStack->uLen);
2759 t3gs = t3GlyphStack;
2760 t3GlyphStack = t3gs->next;
2764 void XOutputDev::drawType3Glyph(T3FontCache *t3Font,
2765 T3FontCacheTag *tag, Guchar *data,
2766 double x, double y, GfxRGB *color) {
2773 int x0, y0, w0, h0, x1, y1;
2776 // compute: (x0,y0) = position in destination pixmap
2777 // (x1,y1) = position in the XImage
2778 // (w0,h0) = size of XImage transfer
2779 x0 = xoutRound(x + t3Font->glyphX);
2780 y0 = xoutRound(y + t3Font->glyphY);
2783 w0 = t3Font->glyphW;
2784 h0 = t3Font->glyphH;
2790 if (x0 + w0 > pixmapW) {
2801 if (y0 + h0 > pixmapH) {
2808 image = t3Font->image;
2809 XGetSubImage(display, pixmap, x0, y0, w0, h0,
2810 (1 << depth) - 1, ZPixmap, image, x1, y1);
2811 xcolor.pixel = XGetPixel(image, t3Font->glyphW / 2, t3Font->glyphH / 2);
2812 XQueryColor(display, colormap, &xcolor);
2813 bg.r = xcolor.red / 65535.0;
2814 bg.g = xcolor.green / 65535.0;
2815 bg.b = xcolor.blue / 65535.0;
2816 rgb.r = 0.25 * (color->r + 3 * bg.r);
2817 rgb.g = 0.25 * (color->g + 3 * bg.g);
2818 rgb.b = 0.25 * (color->b + 3 * bg.b);
2819 map[1] = findColor(&rgb);
2820 rgb.r = 0.5 * (color->r + bg.r);
2821 rgb.g = 0.5 * (color->g + bg.g);
2822 rgb.b = 0.5 * (color->b + bg.b);
2823 map[2] = findColor(&rgb);
2824 rgb.r = 0.25 * (3 * color->r + bg.r);
2825 rgb.g = 0.25 * (3 * color->g + bg.g);
2826 rgb.b = 0.25 * (3 * color->b + bg.b);
2827 map[3] = findColor(&rgb);
2828 map[4] = findColor(color);
2830 for (iy = 0; iy < t3Font->glyphH; ++iy) {
2831 for (ix = 0; ix < t3Font->glyphW; ++ix) {
2834 XPutPixel(image, ix, iy, map[pixel]);
2838 XPutImage(display, pixmap, fillGC, image, x1, y1, x0, y0, w0, h0);
2841 void XOutputDev::type3D0(GfxState *state, double wx, double wy) {
2842 t3GlyphStack->wx = wx;
2843 t3GlyphStack->wy = wy;
2846 void XOutputDev::type3D1(GfxState *state, double wx, double wy,
2847 double llx, double lly, double urx, double ury) {
2852 T3FontCache *t3Font;
2855 // allocate a cache entry
2856 t3GlyphStack->cacheable = gTrue;
2857 t3Font = t3GlyphStack->cache;
2858 i = t3GlyphStack->cacheIdx;
2859 for (j = 0; j < t3Font->cacheAssoc; ++j) {
2860 if ((t3Font->cacheTags[i+j].mru & 0x7fff) == t3Font->cacheAssoc - 1) {
2861 t3Font->cacheTags[i+j].mru = 0x8000;
2862 t3Font->cacheTags[i+j].code = t3GlyphStack->code;
2863 t3GlyphStack->cacheTag = &t3Font->cacheTags[i+j];
2864 t3GlyphStack->cacheData = t3Font->cacheData + (i+j) * t3Font->glyphSize;
2866 ++t3Font->cacheTags[i+j].mru;
2869 t3GlyphStack->wx = wx;
2870 t3GlyphStack->wy = wy;
2871 t3GlyphStack->cacheTag->wx = wx;
2872 t3GlyphStack->cacheTag->wy = wy;
2874 // prepare to rasterize the glyph
2875 //~ do we need to handle both fill and stroke color?
2876 state->getFillRGB(&t3GlyphStack->color);
2878 t3GlyphStack->color.r = 1 - t3GlyphStack->color.r;
2879 t3GlyphStack->color.g = 1 - t3GlyphStack->color.g;
2880 t3GlyphStack->color.b = 1 - t3GlyphStack->color.b;
2882 fgColor.c[0] = reverseVideo ? 1 : 0;
2883 state->setFillColorSpace(new GfxDeviceGrayColorSpace());
2884 state->setFillColor(&fgColor);
2885 state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
2886 state->setStrokeColor(&fgColor);
2887 t3GlyphStack->origPixmapW = pixmapW;
2888 t3GlyphStack->origPixmapH = pixmapH;
2889 t3GlyphStack->origPixmap = pixmap;
2890 t3GlyphStack->origStrokeGC = strokeGC;
2891 t3GlyphStack->origFillGC = fillGC;
2892 t3GlyphStack->origClipRegion = clipRegion;
2893 pixmapW = t3GlyphStack->cache->glyphW;
2894 pixmapH = t3GlyphStack->cache->glyphH;
2895 pixmap = t3GlyphStack->cache->pixmap;
2896 gcValues.foreground = BlackPixel(display, screenNum);
2897 gcValues.background = WhitePixel(display, screenNum);
2898 gcValues.line_width = 0;
2899 gcValues.line_style = LineSolid;
2900 strokeGC = XCreateGC(display, pixmap,
2901 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
2903 updateLineAttrs(state, gTrue);
2904 gcValues.foreground = WhitePixel(display, screenNum);
2905 fillGC = XCreateGC(display, pixmap,
2906 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
2908 XFillRectangle(display, pixmap, fillGC, 0, 0, pixmapW, pixmapH);
2909 XSetForeground(display, fillGC, BlackPixel(display, screenNum));
2910 clipRegion = XCreateRegion();
2911 rect.x = rect.y = 0;
2912 rect.width = pixmapW;
2913 rect.height = pixmapH;
2914 XUnionRectWithRegion(&rect, clipRegion, clipRegion);
2915 XSetRegion(display, strokeGC, clipRegion);
2916 XSetRegion(display, fillGC, clipRegion);
2917 ctm = state->getCTM();
2918 t3GlyphStack->origCTM4 = ctm[4];
2919 t3GlyphStack->origCTM5 = ctm[5];
2920 state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
2921 -t3GlyphStack->cache->glyphX, -t3GlyphStack->cache->glyphY);
2924 inline Gulong XOutputDev::findColor(GfxRGB *x, GfxRGB *err) {
2930 r = xoutRound(x->r * rMul);
2931 g = xoutRound(x->g * gMul);
2932 b = xoutRound(x->b * bMul);
2933 pixel = ((Gulong)r << rShift) +
2934 ((Gulong)g << gShift) +
2935 ((Gulong)b << bShift);
2936 err->r = x->r - (double)r / rMul;
2937 err->g = x->g - (double)g / gMul;
2938 err->b = x->b - (double)b / bMul;
2939 } else if (numColors == 1) {
2940 gray = 0.299 * x->r + 0.587 * x->g + 0.114 * x->b;
2953 r = xoutRound(x->r * (numColors - 1));
2954 g = xoutRound(x->g * (numColors - 1));
2955 b = xoutRound(x->b * (numColors - 1));
2956 pixel = colors[(r * numColors + g) * numColors + b];
2957 err->r = x->r - (double)r / (numColors - 1);
2958 err->g = x->g - (double)g / (numColors - 1);
2959 err->b = x->b - (double)b / (numColors - 1);
2964 Gulong XOutputDev::findColor(GfxRGB *rgb) {
2970 r = xoutRound(rgb->r * rMul);
2971 g = xoutRound(rgb->g * gMul);
2972 b = xoutRound(rgb->b * bMul);
2973 pixel = ((Gulong)r << rShift) +
2974 ((Gulong)g << gShift) +
2975 ((Gulong)b << bShift);
2976 } else if (numColors == 1) {
2977 gray = 0.299 * rgb->r + 0.587 * rgb->g + 0.114 * rgb->b;
2983 r = xoutRound(rgb->r * (numColors - 1));
2984 g = xoutRound(rgb->g * (numColors - 1));
2985 b = xoutRound(rgb->b * (numColors - 1));
2986 #if 0 // this makes things worse as often as better
2987 // even a very light color shouldn't map to white
2988 if (r == numColors - 1 && g == numColors - 1 && b == numColors - 1) {
2989 if (color->getR() < 0.95)
2991 if (color->getG() < 0.95)
2993 if (color->getB() < 0.95)
2997 pixel = colors[(r * numColors + g) * numColors + b];
3002 void XOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
3003 int width, int height, GBool invert,
3005 ImageStream *imgStr;
3009 double xScale, yScale, xShear, yShear;
3010 int tx, ty, scaledWidth, scaledHeight, xSign, ySign;
3011 int ulx, uly, llx, lly, urx, ury, lrx, lry;
3012 int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
3013 int bx0, by0, bx1, by1, bw, bh;
3014 int cx0, cy0, cx1, cy1, cw, ch;
3015 int yp, yq, yt, yStep, lastYStep;
3016 int xp, xq, xt, xStep, xSrc;
3024 double r0, g0, b0, r1, g1, b1;
3027 int x, y, x1, y1, x2, y2;
3030 // get CTM, check for singular matrix
3031 ctm = state->getCTM();
3032 if (fabs(ctm[0] * ctm[3] - ctm[1] * ctm[2]) < 0.000001) {
3033 error(-1, "Singular CTM in drawImage");
3035 j = height * ((width + 7) / 8);
3037 for (i = 0; i < j; ++i) {
3045 // compute scale, shear, rotation, translation parameters
3046 rot = fabs(ctm[1]) > fabs(ctm[0]);
3049 yScale = -ctm[2] + (ctm[0] * ctm[3]) / ctm[1];
3050 xShear = ctm[3] / yScale;
3051 yShear = -ctm[0] / ctm[1];
3054 yScale = -ctm[3] + (ctm[1] * ctm[2]) / ctm[0];
3055 xShear = -ctm[2] / yScale;
3056 yShear = ctm[1] / ctm[0];
3058 tx = xoutRound(ctm[2] + ctm[4]);
3059 ty = xoutRound(ctm[3] + ctm[5]);
3060 // use ceil() to avoid gaps between "striped" images
3061 scaledWidth = (int)ceil(fabs(xScale));
3062 xSign = (xScale < 0) ? -1 : 1;
3063 scaledHeight = (int)ceil(fabs(yScale));
3064 ySign = (yScale < 0) ? -1 : 1;
3066 // compute corners in device space
3069 urx1 = xSign * (scaledWidth - 1);
3070 ury1 = xoutRound(yShear * urx1);
3071 llx1 = xoutRound(xShear * ySign * (scaledHeight - 1));
3072 lly1 = ySign * (scaledHeight - 1) + xoutRound(yShear * llx1);
3073 lrx1 = xSign * (scaledWidth - 1) +
3074 xoutRound(xShear * ySign * (scaledHeight - 1));
3075 lry1 = ySign * (scaledHeight - 1) + xoutRound(yShear * lrx1);
3077 ulx = tx + uly1; uly = ty - ulx1;
3078 urx = tx + ury1; ury = ty - urx1;
3079 llx = tx + lly1; lly = ty - llx1;
3080 lrx = tx + lry1; lry = ty - lrx1;
3082 ulx = tx + ulx1; uly = ty + uly1;
3083 urx = tx + urx1; ury = ty + ury1;
3084 llx = tx + llx1; lly = ty + lly1;
3085 lrx = tx + lrx1; lry = ty + lry1;
3089 // (bx0, by0) = upper-left corner
3090 // (bx1, by1) = lower-right corner
3092 bx0 = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
3093 : (llx < lrx) ? llx : lrx
3094 : (urx < llx) ? (urx < lrx) ? urx : lrx
3095 : (llx < lrx) ? llx : lrx;
3096 bx1 = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
3097 : (llx > lrx) ? llx : lrx
3098 : (urx > llx) ? (urx > lrx) ? urx : lrx
3099 : (llx > lrx) ? llx : lrx;
3100 by0 = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
3101 : (lly < lry) ? lly : lry
3102 : (ury < lly) ? (ury < lry) ? ury : lry
3103 : (lly < lry) ? lly : lry;
3104 by1 = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
3105 : (lly > lry) ? lly : lry
3106 : (ury > lly) ? (ury > lry) ? ury : lry
3107 : (lly > lry) ? lly : lry;
3111 // Bounding box clipped to pixmap, i.e., "valid" rectangle:
3112 // (cx0, cy0) = upper-left corner of valid rectangle in Pixmap
3113 // (cx1, cy1) = upper-left corner of valid rectangle in XImage
3114 // (cw, ch) = size of valid rectangle
3115 // These values will be used to transfer the XImage from/to the
3117 cw = (bx1 >= pixmapW) ? pixmapW - bx0 : bw;
3126 ch = (by1 >= pixmapH) ? pixmapH - by0 : bh;
3136 // check for tiny (zero width or height) images
3137 // and off-page images
3138 if (scaledWidth <= 0 || scaledHeight <= 0 || cw <= 0 || ch <= 0) {
3140 j = height * ((width + 7) / 8);
3142 for (i = 0; i < j; ++i) {
3150 // compute Bresenham parameters for x and y scaling
3151 yp = height / scaledHeight;
3152 yq = height % scaledHeight;
3153 xp = width / scaledWidth;
3154 xq = width % scaledWidth;
3156 // allocate pixel buffer
3157 pixBuf = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar));
3159 // allocate XImage and read from page pixmap
3160 image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, bw, bh, 8, 0);
3161 image->data = (char *)gmalloc(bh * image->bytes_per_line);
3162 XGetSubImage(display, pixmap, cx0, cy0, cw, ch, (1 << depth) - 1, ZPixmap,
3166 state->getFillRGB(&rgb);
3176 // initialize background color
3177 // (the specific pixel value doesn't matter here, as long as
3178 // r1,g1,b1 correspond correctly to lastPixel)
3179 xcolor.pixel = lastPixel = 0;
3180 XQueryColor(display, colormap, &xcolor);
3181 r1 = (double)xcolor.red / 65535.0;
3182 g1 = (double)xcolor.green / 65535.0;
3183 b1 = (double)xcolor.blue / 65535.0;
3185 // initialize the image stream
3186 imgStr = new ImageStream(str, width, 1, 1);
3189 // init y scale Bresenham
3193 for (y = 0; y < scaledHeight; ++y) {
3195 // y scale Bresenham
3198 if (yt >= scaledHeight) {
3203 // read row(s) from image
3204 n = (yp > 0) ? yStep : lastYStep;
3207 for (i = 0; i < n; ++i) {
3208 memcpy(p, imgStr->getLine(), width);
3210 for (j = 0; j < width; ++j) {
3219 // init x scale Bresenham
3223 for (x = 0; x < scaledWidth; ++x) {
3225 // x scale Bresenham
3228 if (xt >= scaledWidth) {
3234 x1 = xSign * x + xoutRound(xShear * ySign * y);
3237 y1 = ySign * y + xoutRound(yShear * x1);
3248 // compute the filtered pixel at (x,y) after the
3249 // x and y scaling operations
3250 n = yStep > 0 ? yStep : 1;
3251 m = xStep > 0 ? xStep : 1;
3254 for (i = 0; i < n; ++i) {
3255 for (j = 0; j < m; ++j) {
3261 // x scale Bresenham
3264 // blend image pixel with background
3265 alpha = (double)imgPix / (double)(n * m);
3266 xcolor.pixel = XGetPixel(image, tx + x2 - bx0, ty + y2 - by0);
3267 if (xcolor.pixel != lastPixel) {
3268 XQueryColor(display, colormap, &xcolor);
3269 r1 = (double)xcolor.red / 65535.0;
3270 g1 = (double)xcolor.green / 65535.0;
3271 b1 = (double)xcolor.blue / 65535.0;
3272 lastPixel = xcolor.pixel;
3274 rgb2.r = r0 * (1 - alpha) + r1 * alpha;
3275 rgb2.g = g0 * (1 - alpha) + g1 * alpha;
3276 rgb2.b = b0 * (1 - alpha) + b1 * alpha;
3277 pix = findColor(&rgb2);
3280 XPutPixel(image, tx + x2 - bx0, ty + y2 - by0, pix);
3284 // blit the image into the pixmap
3285 XPutImage(display, pixmap, fillGC, image, cx1, cy1, cx0, cy0, cw, ch);
3292 XDestroyImage(image);
3295 void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
3296 int width, int height, GfxImageColorMap *colorMap,
3297 int *maskColors, GBool inlineImg) {
3298 ImageStream *imgStr;
3300 int nComps, nVals, nBits;
3304 double xScale, yScale, xShear, yShear;
3305 int tx, ty, scaledWidth, scaledHeight, xSign, ySign;
3306 int ulx, uly, llx, lly, urx, ury, lrx, lry;
3307 int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
3308 int bx0, by0, bx1, by1, bw, bh;
3309 int cx0, cy0, cx1, cy1, cw, ch;
3310 int yp, yq, yt, yStep, lastYStep;
3311 int xp, xq, xt, xStep, xSrc;
3314 Guchar pixBuf2[gfxColorMaxComps];
3315 GfxRGB color2, err, errRight;
3317 double r0, g0, b0, alpha, mul;
3322 GfxRGB oneBitRGB[2];
3323 int x, y, x1, y1, x2, y2;
3327 nComps = colorMap->getNumPixelComps();
3328 nVals = width * nComps;
3329 nBits = colorMap->getBits();
3330 dither = nComps > 1 || nBits > 1;
3332 // get CTM, check for singular matrix
3333 ctm = state->getCTM();
3334 if (fabs(ctm[0] * ctm[3] - ctm[1] * ctm[2]) < 0.000001) {
3335 error(-1, "Singular CTM in drawImage");
3338 j = height * ((nVals * nBits + 7) / 8);
3339 for (i = 0; i < j; ++i) {
3347 // compute scale, shear, rotation, translation parameters
3348 rot = fabs(ctm[1]) > fabs(ctm[0]);
3351 yScale = -ctm[2] + (ctm[0] * ctm[3]) / ctm[1];
3352 xShear = ctm[3] / yScale;
3353 yShear = -ctm[0] / ctm[1];
3356 yScale = -ctm[3] + (ctm[1] * ctm[2]) / ctm[0];
3357 xShear = -ctm[2] / yScale;
3358 yShear = ctm[1] / ctm[0];
3360 tx = xoutRound(ctm[2] + ctm[4]);
3361 ty = xoutRound(ctm[3] + ctm[5]);
3363 // this is the right edge which needs to be (left + width - 1)
3367 // this is the bottom edge which needs to be (top + height - 1)
3370 // use ceil() to avoid gaps between "striped" images
3371 scaledWidth = (int)ceil(fabs(xScale));
3372 xSign = (xScale < 0) ? -1 : 1;
3373 scaledHeight = (int)ceil(fabs(yScale));
3374 ySign = (yScale < 0) ? -1 : 1;
3376 // compute corners in device space
3379 urx1 = xSign * (scaledWidth - 1);
3380 ury1 = xoutRound(yShear * urx1);
3381 llx1 = xoutRound(xShear * ySign * (scaledHeight - 1));
3382 lly1 = ySign * (scaledHeight - 1) + xoutRound(yShear * llx1);
3383 lrx1 = xSign * (scaledWidth - 1) +
3384 xoutRound(xShear * ySign * (scaledHeight - 1));
3385 lry1 = ySign * (scaledHeight - 1) + xoutRound(yShear * lrx1);
3387 ulx = tx + uly1; uly = ty - ulx1;
3388 urx = tx + ury1; ury = ty - urx1;
3389 llx = tx + lly1; lly = ty - llx1;
3390 lrx = tx + lry1; lry = ty - lrx1;
3392 ulx = tx + ulx1; uly = ty + uly1;
3393 urx = tx + urx1; ury = ty + ury1;
3394 llx = tx + llx1; lly = ty + lly1;
3395 lrx = tx + lrx1; lry = ty + lry1;
3399 // (bx0, by0) = upper-left corner
3400 // (bx1, by1) = lower-right corner
3402 bx0 = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
3403 : (llx < lrx) ? llx : lrx
3404 : (urx < llx) ? (urx < lrx) ? urx : lrx
3405 : (llx < lrx) ? llx : lrx;
3406 bx1 = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
3407 : (llx > lrx) ? llx : lrx
3408 : (urx > llx) ? (urx > lrx) ? urx : lrx
3409 : (llx > lrx) ? llx : lrx;
3410 by0 = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
3411 : (lly < lry) ? lly : lry
3412 : (ury < lly) ? (ury < lry) ? ury : lry
3413 : (lly < lry) ? lly : lry;
3414 by1 = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
3415 : (lly > lry) ? lly : lry
3416 : (ury > lly) ? (ury > lry) ? ury : lry
3417 : (lly > lry) ? lly : lry;
3421 // Bounding box clipped to pixmap, i.e., "valid" rectangle:
3422 // (cx0, cy0) = upper-left corner of valid rectangle in Pixmap
3423 // (cx1, cy1) = upper-left corner of valid rectangle in XImage
3424 // (cw, ch) = size of valid rectangle
3425 // These values will be used to transfer the XImage from/to the
3427 cw = (bx1 >= pixmapW) ? pixmapW - bx0 : bw;
3436 ch = (by1 >= pixmapH) ? pixmapH - by0 : bh;
3446 // check for tiny (zero width or height) images
3447 // and off-page images
3448 if (scaledWidth <= 0 || scaledHeight <= 0 || cw <= 0 || ch <= 0) {
3451 j = height * ((nVals * nBits + 7) / 8);
3452 for (i = 0; i < j; ++i)
3459 // compute Bresenham parameters for x and y scaling
3460 yp = height / scaledHeight;
3461 yq = height % scaledHeight;
3462 xp = width / scaledWidth;
3463 xq = width % scaledWidth;
3465 // allocate pixel buffer
3466 pixBuf = (GfxRGB *)gmalloc((yp + 1) * width * sizeof(GfxRGB));
3468 alphaBuf = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar));
3474 image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, bw, bh, 8, 0);
3475 image->data = (char *)gmalloc(bh * image->bytes_per_line);
3477 // if the transform is anything other than a 0/90/180/270 degree
3478 // rotation/flip, or if there is color key masking, read the
3479 // backgound pixmap to fill in the corners
3480 if (!((ulx == llx && uly == ury) ||
3481 (uly == lly && ulx == urx)) ||
3483 XGetSubImage(display, pixmap, cx0, cy0, cw, ch, (1 << depth) - 1, ZPixmap,
3487 // allocate error diffusion accumulators
3489 errDown = (GfxRGB *)gmalloc(bw * sizeof(GfxRGB));
3490 for (j = 0; j < bw; ++j) {
3491 errDown[j].r = errDown[j].g = errDown[j].b = 0;
3497 // optimize the one-bit-deep image case
3498 if ((oneBitMode = nComps == 1 && nBits == 1)) {
3500 colorMap->getRGB(pixBuf2, &oneBitRGB[0]);
3502 colorMap->getRGB(pixBuf2, &oneBitRGB[1]);
3505 // initialize the image stream
3506 imgStr = new ImageStream(str, width, nComps, nBits);
3509 // init y scale Bresenham
3513 for (y = 0; y < scaledHeight; ++y) {
3515 // initialize error diffusion accumulator
3516 errRight.r = errRight.g = errRight.b = 0;
3518 // y scale Bresenham
3521 if (yt >= scaledHeight) {
3526 // read row(s) from image
3527 n = (yp > 0) ? yStep : lastYStep;
3531 for (i = 0; i < n; ++i) {
3532 p2 = imgStr->getLine();
3533 for (j = 0; j < width; ++j) {
3535 *p = oneBitRGB[*p2];
3537 colorMap->getRGB(p2, p);
3542 for (k = 0; k < nComps; ++k) {
3543 if (p2[k] < maskColors[2*k] ||
3544 p2[k] > maskColors[2*k]) {
3557 // init x scale Bresenham
3561 for (x = 0; x < scaledWidth; ++x) {
3563 // x scale Bresenham
3566 if (xt >= scaledWidth) {
3572 x1 = xSign * x + xoutRound(xShear * ySign * y);
3575 y1 = ySign * y + xoutRound(yShear * x1);
3586 // compute the filtered pixel at (x,y) after the
3587 // x and y scaling operations
3588 n = yStep > 0 ? yStep : 1;
3589 m = xStep > 0 ? xStep : 1;
3592 q = alphaBuf ? alphaBuf + xSrc : (Guchar *)NULL;
3594 for (i = 0; i < n; ++i) {
3595 for (j = 0; j < m; ++j) {
3606 mul = 1 / (double)(n * m);
3612 // x scale Bresenham
3617 color2.r = r0 + errRight.r + errDown[tx + x2 - bx0].r;
3620 } else if (color2.r < 0) {
3623 color2.g = g0 + errRight.g + errDown[tx + x2 - bx0].g;
3626 } else if (color2.g < 0) {
3629 color2.b = b0 + errRight.b + errDown[tx + x2 - bx0].b;
3632 } else if (color2.b < 0) {
3635 pix = findColor(&color2, &err);
3636 errRight.r = errDown[tx + x2 - bx0].r = err.r / 2;
3637 errRight.g = errDown[tx + x2 - bx0].g = err.g / 2;
3638 errRight.b = errDown[tx + x2 - bx0].b = err.b / 2;
3643 pix = findColor(&color2, &err);
3647 //~ this should do a blend when 0 < alpha < 1
3649 XPutPixel(image, tx + x2 - bx0, ty + y2 - by0, pix);
3654 // blit the image into the pixmap
3655 XPutImage(display, pixmap, fillGC, image, cx1, cy1, cx0, cy0, cw, ch);
3665 XDestroyImage(image);
3669 GBool XOutputDev::findText(Unicode *s, int len, GBool top, GBool bottom,
3670 int *xMin, int *yMin, int *xMax, int *yMax) {
3671 double xMin1, yMin1, xMax1, yMax1;
3673 xMin1 = (double)*xMin;
3674 yMin1 = (double)*yMin;
3675 xMax1 = (double)*xMax;
3676 yMax1 = (double)*yMax;
3677 if (text->findText(s, len, top, bottom, &xMin1, &yMin1, &xMax1, &yMax1)) {
3678 *xMin = xoutRound(xMin1);
3679 *xMax = xoutRound(xMax1);
3680 *yMin = xoutRound(yMin1);
3681 *yMax = xoutRound(yMax1);
3687 GString *XOutputDev::getText(int xMin, int yMin, int xMax, int yMax) {
3688 return text->getText((double)xMin, (double)yMin,
3689 (double)xMax, (double)yMax);