1 //========================================================================
5 // Copyright 1996-2003 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);
833 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
834 if (freetypeControl != fontRastNone) {
835 font = tryGetFTFont(xref, gfxFont, m11, m12, m21, m22);
845 // search for a display font mapping
847 if (gfxFont->isCIDFont()) {
848 if (((GfxCIDFont *)gfxFont)->getCollection()) {
850 getDisplayCIDFont(gfxFont->getName(),
851 ((GfxCIDFont *)gfxFont)->getCollection());
853 // this error (no CMap file) was already reported by GfxFont
857 if (gfxFont->getName()) {
858 dfp = globalParams->getDisplayFont(gfxFont->getName());
862 font = tryGetFont(xref, dfp, gfxFont, m11, m12, m21, m22,
863 m11, m12, m21, m22, gFalse);
866 // substitute a font (8-bit fonts only)
867 if (!font && !gfxFont->isCIDFont()) {
869 // choose a substitute font
870 if (gfxFont->isFixedWidth()) {
872 } else if (gfxFont->isSerif()) {
877 if (gfxFont->isBold()) {
880 if (gfxFont->isItalic()) {
883 substName = new GString(xOutSubstFonts[index].name);
885 // adjust the font matrix -- compare the width of 'm' in the
886 // original font and the substituted font
891 for (code = 0; code < 256; ++code) {
892 if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
893 name[0] == 'm' && name[1] == '\0') {
898 w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
899 w2 = xOutSubstFonts[index].mWidth;
900 if (gfxFont->getType() == fontType3) {
901 // This is a hack which makes it possible to substitute for some
902 // Type 3 fonts. The problem is that it's impossible to know what
903 // the base coordinate system used in the font is without actually
904 // rendering the font. This code tries to guess by looking at the
905 // width of the character 'm' (which breaks if the font is a
906 // subset that doesn't contain 'm').
907 if (w1 > 0 && (w1 > 1.1 * w2 || w1 < 0.9 * w2)) {
914 fm = gfxFont->getFontMatrix();
915 v = (fm[0] == 0) ? 1 : (fm[3] / fm[0]);
918 } else if (!gfxFont->isSymbolic()) {
919 // if real font is substantially narrower than substituted
920 // font, reduce the font size accordingly
921 if (w1 > 0.01 && w1 < 0.9 * w2) {
930 dfp = globalParams->getDisplayFont(substName);
933 // this should never happen since GlobalParams sets up default
934 // mappings for the Base-14 fonts
935 error(-1, "Couldn't find a font for '%s'",
936 gfxFont->getName()->getCString());
939 font = tryGetFont(xref, dfp, gfxFont, m11, m12, m21, m22,
940 m11New, m12New, m21New, m22New, gTrue);
946 // This will happen if the user specifies a bogus font in the
947 // config file (a non-existent font file or a font that requires a
948 // rasterizer that is disabled or wasn't built in), or if a CID
949 // font has no associated font in the config file.
950 if (gfxFont->isCIDFont()) {
951 error(-1, "Couldn't find a font for the '%s' character collection",
952 ((GfxCIDFont *)gfxFont)->getCollection()->getCString());
954 error(-1, "Couldn't find a font for '%s'",
956 gfxFont->getName()->getCString() : "[unnamed]");
961 // insert font in cache
962 if (nFonts == xOutFontCacheSize) {
964 delete fonts[nFonts];
966 for (j = nFonts; j > 0; --j) {
967 fonts[j] = fonts[j-1];
975 XOutputFont *XOutputFontCache::tryGetFont(XRef *xref, DisplayFontParam *dfp,
977 double m11Orig, double m12Orig,
978 double m21Orig, double m22Orig,
979 double m11, double m12,
980 double m21, double m22,
986 // create the new font
990 font = tryGetServerFont(dfp->x.xlfd, dfp->x.encoding, gfxFont,
991 m11Orig, m12Orig, m21Orig, m22Orig,
997 if (t1libControl != fontRastNone && !gfxFont->isCIDFont()) {
998 font = tryGetT1FontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont,
999 m11Orig, m12Orig, m21Orig, m22Orig,
1000 m11, m12, m21, m22, subst);
1003 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1005 if (freetypeControl != fontRastNone) {
1006 font = tryGetFTFontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont,
1007 m11Orig, m12Orig, m21Orig, m22Orig,
1008 m11, m12, m21, m22, gFalse, subst);
1012 #if !((FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)) || defined(HAVE_T1LIB_H))
1013 error(-1, "Config file specifies a Type 1 font,");
1014 error(-1, "but xpdf was not built with t1lib or FreeType2 support");
1019 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1020 if (freetypeControl != fontRastNone) {
1021 font = tryGetFTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont,
1022 m11Orig, m12Orig, m21Orig, m22Orig,
1023 m11, m12, m21, m22, gFalse, subst);
1026 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1027 if (freetypeControl != fontRastNone) {
1028 font = tryGetTTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont,
1029 m11Orig, m12Orig, m21Orig, m22Orig,
1030 m11, m12, m21, m22, subst);
1033 #if !(HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1034 error(-1, "Config file specifies a TrueType font,");
1035 error(-1, "but xpdf was not built with FreeType support");
1045 XOutputFont *XOutputFontCache::tryGetT1Font(XRef *xref,
1047 double m11, double m12,
1048 double m21, double m22) {
1050 XOutputT1FontFile *xFontFile;
1058 Object refObj, strObj;
1062 // check the already available font files
1063 id = gfxFont->getID();
1064 for (i = 0; i < t1FontFiles->getLength(); ++i) {
1065 xFontFile = (XOutputT1FontFile *)t1FontFiles->get(i);
1066 if (xFontFile->num == id->num && xFontFile->gen == id->gen &&
1067 !xFontFile->subst) {
1068 font = new XOutputT1Font(id, xFontFile->fontFile,
1070 m11, m12, m21, m22, display, xOut);
1071 if (!font->isOk()) {
1079 // check for an embedded font
1080 if (gfxFont->getEmbeddedFontID(&embRef)) {
1082 // create the font file
1084 if (!openTempFile(&fileName, &f, "wb", NULL)) {
1085 error(-1, "Couldn't create temporary Type 1 font file");
1088 if (gfxFont->getType() == fontType1C) {
1089 if (!(fontBuf = gfxFont->readEmbFontFile(xref, &fontLen))) {
1093 ff = new Type1CFontFile(fontBuf, fontLen);
1099 ff->convertToType1(outputToFile, f);
1102 } else { // fontType1
1103 refObj.initRef(embRef.num, embRef.gen);
1104 refObj.fetch(xref, &strObj);
1106 strObj.streamReset();
1107 while ((c = strObj.streamGetChar()) != EOF) {
1110 strObj.streamClose();
1116 font = tryGetT1FontFromFile(xref, fileName, gTrue, gfxFont,
1118 m11, m12, m21, m22, gFalse);
1120 // on systems with Unix hard link semantics, this will remove the
1121 // last link to the temp file
1122 unlink(fileName->getCString());
1126 // check for an external font file
1127 } else if ((fileName = gfxFont->getExtFontFile())) {
1128 font = tryGetT1FontFromFile(xref, fileName, gFalse, gfxFont,
1130 m11, m12, m21, m22, gFalse);
1139 XOutputFont *XOutputFontCache::tryGetT1FontFromFile(XRef *xref,
1147 double m11, double m12,
1148 double m21, double m22,
1151 T1FontFile *fontFile;
1154 // create the t1lib font file
1155 fontFile = new T1FontFile(t1Engine, fileName->getCString(),
1156 ((Gfx8BitFont *)gfxFont)->getEncoding(),
1157 gfxFont->getFontBBox());
1158 if (!fontFile->isOk()) {
1159 error(-1, "Couldn't create t1lib font from '%s'",
1160 fileName->getCString());
1163 unlink(fileName->getCString());
1169 id = gfxFont->getID();
1170 t1FontFiles->append(new XOutputT1FontFile(id->num, id->gen,
1172 deleteFile ? fileName->copy()
1173 : (GString *)NULL));
1176 font = new XOutputT1Font(gfxFont->getID(), fontFile,
1177 m11Orig, m12Orig, m21Orig, m22Orig,
1178 m11, m12, m21, m22, display, xOut);
1179 if (!font->isOk()) {
1185 #endif // HAVE_T1LIB_H
1187 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1188 XOutputFont *XOutputFontCache::tryGetFTFont(XRef *xref,
1190 double m11, double m12,
1191 double m21, double m22) {
1193 XOutputFTFontFile *xFontFile;
1198 #if 1 //~ need this until FT can handle fonts with missing tables
1201 TrueTypeFontFile *ff;
1203 Object refObj, strObj;
1207 // check the already available font files
1208 id = gfxFont->getID();
1209 for (i = 0; i < ftFontFiles->getLength(); ++i) {
1210 xFontFile = (XOutputFTFontFile *)ftFontFiles->get(i);
1211 if (xFontFile->num == id->num && xFontFile->gen == id->gen &&
1212 !xFontFile->subst) {
1213 font = new XOutputFTFont(id, xFontFile->fontFile,
1215 m11, m12, m21, m22, display, xOut);
1216 if (!font->isOk()) {
1224 // check for an embedded font
1225 if (gfxFont->getEmbeddedFontID(&embRef)) {
1227 // create the font file
1229 if (!openTempFile(&fileName, &f, "wb", NULL)) {
1230 error(-1, "Couldn't create temporary TrueType font file");
1233 #if 1 //~ need this until FT can handle fonts with missing tables
1234 if (gfxFont->getType() == fontTrueType ||
1235 gfxFont->getType() == fontCIDType2) {
1236 if (!(fontBuf = gfxFont->readEmbFontFile(xref, &fontLen))) {
1240 ff = new TrueTypeFontFile(fontBuf, fontLen);
1245 refObj.initRef(embRef.num, embRef.gen);
1246 refObj.fetch(xref, &strObj);
1248 strObj.streamReset();
1249 while ((c = strObj.streamGetChar()) != EOF) {
1252 strObj.streamClose();
1256 refObj.initRef(embRef.num, embRef.gen);
1257 refObj.fetch(xref, &strObj);
1259 strObj.streamReset();
1260 while ((c = strObj.streamGetChar()) != EOF) {
1263 strObj.streamClose();
1269 font = tryGetFTFontFromFile(xref, fileName, gTrue, gfxFont,
1271 m11, m12, m21, m22, gTrue, gFalse);
1273 // on systems with Unix hard link semantics, this will remove the
1274 // last link to the temp file
1275 unlink(fileName->getCString());
1279 // check for an external font file
1280 } else if ((fileName = gfxFont->getExtFontFile())) {
1281 font = tryGetFTFontFromFile(xref, fileName, gFalse, gfxFont,
1283 m11, m12, m21, m22, gFalse, gFalse);
1292 XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref,
1300 double m11, double m12,
1301 double m21, double m22,
1305 FTFontFile *fontFile;
1308 // create the FreeType font file
1309 if (gfxFont->isCIDFont()) {
1310 if (gfxFont->getType() == fontCIDType2) {
1311 fontFile = new FTFontFile(ftEngine, fileName->getCString(),
1312 ((GfxCIDFont *)gfxFont)->getCIDToGID(),
1313 ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(),
1315 } else { // fontCIDType0, fontCIDType0C
1316 fontFile = new FTFontFile(ftEngine, fileName->getCString(), embedded);
1319 fontFile = new FTFontFile(ftEngine, fileName->getCString(),
1320 ((Gfx8BitFont *)gfxFont)->getEncoding(),
1321 ((Gfx8BitFont *)gfxFont)->getHasEncoding(),
1322 ((Gfx8BitFont *)gfxFont)->isSymbolic());
1324 if (!fontFile->isOk()) {
1325 error(-1, "Couldn't create FreeType font from '%s'",
1326 fileName->getCString());
1329 unlink(fileName->getCString());
1335 id = gfxFont->getID();
1336 ftFontFiles->append(new XOutputFTFontFile(id->num, id->gen,
1338 deleteFile ? fileName->copy()
1339 : (GString *)NULL));
1342 font = new XOutputFTFont(gfxFont->getID(), fontFile,
1343 m11Orig, m12Orig, m21Orig, m22Orig,
1344 m11, m12, m21, m22, display, xOut);
1345 if (!font->isOk()) {
1351 #endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1353 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1354 XOutputFont *XOutputFontCache::tryGetTTFont(XRef *xref,
1356 double m11, double m12,
1357 double m21, double m22) {
1359 XOutputTTFontFile *xFontFile;
1364 Object refObj, strObj;
1368 // check the already available font files
1369 id = gfxFont->getID();
1371 for (i = 0; i < ttFontFiles->getLength(); ++i) {
1372 xFontFile = (XOutputTTFontFile *)ttFontFiles->get(i);
1373 if (xFontFile->num == id->num && xFontFile->gen == id->gen &&
1374 !xFontFile->subst) {
1375 font = new XOutputTTFont(id, xFontFile->fontFile,
1377 m11, m12, m21, m22, display, xOut);
1378 if (!font->isOk()) {
1386 // check for an embedded font
1387 if (gfxFont->getEmbeddedFontID(&embRef)) {
1389 // create the font file
1391 if (!openTempFile(&fileName, &f, "wb", NULL)) {
1392 error(-1, "Couldn't create temporary TrueType font file");
1395 refObj.initRef(embRef.num, embRef.gen);
1396 refObj.fetch(xref, &strObj);
1398 strObj.streamReset();
1399 while ((c = strObj.streamGetChar()) != EOF) {
1402 strObj.streamClose();
1407 font = tryGetTTFontFromFile(xref, fileName, gTrue, gfxFont,
1409 m11, m12, m21, m22, gFalse);
1411 // on systems with Unix hard link semantics, this will remove the
1412 // last link to the temp file
1413 unlink(fileName->getCString());
1417 } else if ((fileName = gfxFont->getExtFontFile())) {
1418 font = tryGetTTFontFromFile(xref, fileName, gFalse, gfxFont,
1420 m11, m12, m21, m22, gFalse);
1429 XOutputFont *XOutputFontCache::tryGetTTFontFromFile(XRef *xref,
1437 double m11, double m12,
1438 double m21, double m22,
1441 TTFontFile *fontFile;
1444 // create the FreeType font file
1445 if (gfxFont->isCIDFont()) {
1447 fontFile = new TTFontFile(ttEngine, fileName->getCString(),
1448 ((GfxCIDFont *)gfxFont)->getCIDToGID(),
1449 ((GfxCIDFont *)gfxFont)->getCIDToGIDLen());
1451 fontFile = new TTFontFile(ttEngine, fileName->getCString(),
1452 ((Gfx8BitFont *)gfxFont)->getEncoding(),
1453 ((Gfx8BitFont *)gfxFont)->getHasEncoding());
1455 if (!fontFile->isOk()) {
1456 error(-1, "Couldn't create FreeType font from '%s'",
1457 fileName->getCString());
1460 unlink(fileName->getCString());
1466 id = gfxFont->getID();
1467 ttFontFiles->append(new XOutputTTFontFile(id->num, id->gen,
1469 deleteFile ? fileName->copy()
1470 : (GString *)NULL));
1473 font = new XOutputTTFont(gfxFont->getID(), fontFile,
1474 m11Orig, m12Orig, m21Orig, m22Orig,
1475 m11, m12, m21, m22, display, xOut);
1476 if (!font->isOk()) {
1482 #endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1484 XOutputFont *XOutputFontCache::tryGetServerFont(GString *xlfd,
1485 GString *encodingName,
1487 double m11Orig, double m12Orig,
1488 double m21Orig, double m22Orig,
1489 double m11, double m12,
1490 double m21, double m22) {
1493 CharCodeToUnicode *ctu;
1495 uMap = globalParams->getUnicodeMap(encodingName);
1496 if (gfxFont->isCIDFont()) {
1497 ctu = ((GfxCIDFont *)gfxFont)->getToUnicode();
1498 font = new XOutputServer16BitFont(gfxFont->getID(), xlfd, uMap, ctu,
1499 m11Orig, m12Orig, m21Orig, m22Orig,
1504 ctu = ((Gfx8BitFont *)gfxFont)->getToUnicode();
1505 font = new XOutputServer8BitFont(gfxFont->getID(), xlfd, uMap, ctu,
1506 m11Orig, m12Orig, m21Orig, m22Orig,
1512 if (!font->isOk()) {
1519 //------------------------------------------------------------------------
1521 //------------------------------------------------------------------------
1523 struct T3FontCacheTag {
1525 Gushort mru; // valid bit (0x8000) and MRU index
1526 double wx, wy; // untransformed glyph metrics
1532 T3FontCache(Ref *fontID, double m11A, double m12A,
1533 double m21A, double m22A,
1534 int glyphXA, int glyphYA, int glyphWA, int glyphHA,
1535 Display *displayA, Visual *visual, Guint depth,
1538 GBool matches(Ref *idA, double m11A, double m12A,
1539 double m21A, double m22A)
1540 { return fontID.num == idA->num && fontID.gen == idA->gen &&
1541 m11 == m11A && m12 == m12A && m21 == m21A && m22 == m22A; }
1543 Ref fontID; // PDF font ID
1544 double m11, m12, m21, m22; // transform matrix
1545 int glyphX, glyphY; // pixel offset of glyph pixmaps
1546 int glyphW, glyphH; // size of glyph pixmaps, in pixels
1547 int glyphSize; // size of glyph pixmaps, in bytes
1548 int cacheSets; // number of sets in cache
1549 int cacheAssoc; // cache associativity (glyphs per set)
1550 Guchar *cacheData; // glyph pixmap cache
1551 T3FontCacheTag *cacheTags; // cache tags, i.e., char codes
1557 T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A,
1558 double m21A, double m22A,
1559 int glyphXA, int glyphYA, int glyphWA, int glyphHA,
1560 Display *displayA, Visual *visual, Guint depth,
1561 Pixmap origPixmap) {
1573 glyphSize = glyphW * glyphH;
1575 if (glyphSize <= 256) {
1577 } else if (glyphSize <= 512) {
1579 } else if (glyphSize <= 1024) {
1584 cacheData = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize);
1585 cacheTags = (T3FontCacheTag *)gmalloc(cacheSets * cacheAssoc *
1586 sizeof(T3FontCacheTag));
1587 for (i = 0; i < cacheSets * cacheAssoc; ++i) {
1588 cacheTags[i].mru = i & (cacheAssoc - 1);
1591 pixmap = XCreatePixmap(display, origPixmap, glyphW, glyphH, depth);
1592 image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL,
1593 glyphW, glyphH, 8, 0);
1594 image->data = (char *)gmalloc(glyphH * image->bytes_per_line);
1597 T3FontCache::~T3FontCache() {
1600 XFreePixmap(display, pixmap);
1603 XDestroyImage(image);
1606 struct T3GlyphStack {
1611 T3FontCacheTag *cacheTag;
1617 int origPixmapW, origPixmapH;
1621 Region origClipRegion;
1622 double origCTM4, origCTM5;
1623 double wx, wy; // untransformed glyph metrics
1627 //------------------------------------------------------------------------
1629 //------------------------------------------------------------------------
1631 XOutputDev::XOutputDev(Display *displayA, int screenNumA,
1632 Visual *visualA, Colormap colormapA,
1633 GBool reverseVideoA, unsigned long paperColorA,
1634 GBool installCmap, int rgbCubeSize,
1636 XVisualInfo visualTempl;
1637 XVisualInfo *visualList;
1648 // display / screen / visual / colormap
1650 screenNum = screenNumA;
1652 colormap = colormapA;
1655 pixmapW = pixmapH = 0;
1657 // check for TrueColor visual
1658 if (forceDepth != 0) {
1660 trueColor = depth >= 16;
1662 visualTempl.visualid = XVisualIDFromVisual(visual);
1663 visualList = XGetVisualInfo(display, VisualIDMask,
1664 &visualTempl, &nVisuals);
1666 // this shouldn't happen
1667 XFree((XPointer)visualList);
1668 visualList = XGetVisualInfo(display, VisualNoMask, &visualTempl,
1671 depth = visualList->depth;
1672 if (visualList->c_class == TrueColor) {
1674 for (mask = visualList->red_mask, rShift = 0;
1675 mask && !(mask & 1);
1676 mask >>= 1, ++rShift) ;
1678 for (mask = visualList->green_mask, gShift = 0;
1679 mask && !(mask & 1);
1680 mask >>= 1, ++gShift) ;
1682 for (mask = visualList->blue_mask, bShift = 0;
1683 mask && !(mask & 1);
1684 mask >>= 1, ++bShift) ;
1689 XFree((XPointer)visualList);
1692 // allocate a color cube
1694 redMap[BlackPixel(display, screenNum) & 0xff] = 0;
1695 redMap[WhitePixel(display, screenNum) & 0xff] = 1;
1697 // set colors in private colormap
1699 for (numColors = 6; numColors >= 2; --numColors) {
1700 m = numColors * numColors * numColors;
1701 if (XAllocColorCells(display, colormap, False, NULL, 0, colors, m)) {
1705 if (numColors >= 2) {
1706 m = numColors * numColors * numColors;
1707 xcolors = (XColor *)gmalloc(m * sizeof(XColor));
1709 for (r = 0; r < numColors; ++r) {
1710 for (g = 0; g < numColors; ++g) {
1711 for (b = 0; b < numColors; ++b) {
1712 xcolors[n].pixel = colors[n];
1713 xcolors[n].red = (r * 65535) / (numColors - 1);
1714 xcolors[n].green = (g * 65535) / (numColors - 1);
1715 xcolors[n].blue = (b * 65535) / (numColors - 1);
1716 xcolors[n].flags = DoRed | DoGreen | DoBlue;
1717 redMap[xcolors[n].pixel & 0xff] = xcolors[n].red / 65535.0;
1722 XStoreColors(display, colormap, xcolors, m);
1726 colors[0] = BlackPixel(display, screenNum);
1727 colors[1] = WhitePixel(display, screenNum);
1730 // allocate colors in shared colormap
1732 if (rgbCubeSize > maxRGBCube) {
1733 rgbCubeSize = maxRGBCube;
1736 for (numColors = rgbCubeSize; numColors >= 2; --numColors) {
1739 for (r = 0; r < numColors && ok; ++r) {
1740 for (g = 0; g < numColors && ok; ++g) {
1741 for (b = 0; b < numColors && ok; ++b) {
1743 colors[n] = BlackPixel(display, screenNum);
1744 redMap[colors[n] & 0xff] = 0;
1747 xcolor.red = (r * 65535) / (numColors - 1);
1748 xcolor.green = (g * 65535) / (numColors - 1);
1749 xcolor.blue = (b * 65535) / (numColors - 1);
1750 if (XAllocColor(display, colormap, &xcolor)) {
1751 colors[n++] = xcolor.pixel;
1752 redMap[xcolor.pixel & 0xff] = xcolor.red / 65535.0;
1763 XFreeColors(display, colormap, &colors[1], n-1, 0);
1767 colors[0] = BlackPixel(display, screenNum);
1768 colors[1] = WhitePixel(display, screenNum);
1774 reverseVideo = reverseVideoA;
1775 paperColor = paperColorA;
1777 // set up the font cache and fonts
1780 needFontUpdate = gFalse;
1781 fontCache = new XOutputFontCache(display, depth, this,
1782 globalParams->getT1libControl(),
1783 globalParams->getFreeTypeControl());
1785 t3GlyphStack = NULL;
1787 // empty state stack
1790 // create text object
1791 text = new TextPage(gFalse);
1794 XOutputDev::~XOutputDev() {
1798 for (i = 0; i < nT3Fonts; ++i) {
1799 delete t3FontCache[i];
1804 void XOutputDev::startDoc(XRef *xrefA) {
1808 fontCache->startDoc(screenNum, visual, colormap, trueColor, rMul, gMul, bMul,
1809 rShift, gShift, bShift, colors, numColors);
1810 for (i = 0; i < nT3Fonts; ++i) {
1811 delete t3FontCache[i];
1816 void XOutputDev::startPage(int pageNum, GfxState *state) {
1820 // default line flatness
1824 gcValues.foreground = BlackPixel(display, screenNum);
1825 gcValues.background = WhitePixel(display, screenNum);
1826 gcValues.line_width = 0;
1827 gcValues.line_style = LineSolid;
1828 strokeGC = XCreateGC(display, pixmap,
1829 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
1831 fillGC = XCreateGC(display, pixmap,
1832 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
1834 gcValues.foreground = paperColor;
1835 paperGC = XCreateGC(display, pixmap,
1836 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
1839 // initialize clip region
1840 clipRegion = XCreateRegion();
1841 rect.x = rect.y = 0;
1842 rect.width = pixmapW;
1843 rect.height = pixmapH;
1844 XUnionRectWithRegion(&rect, clipRegion, clipRegion);
1845 XSetRegion(display, strokeGC, clipRegion);
1846 XSetRegion(display, fillGC, clipRegion);
1853 XFillRectangle(display, pixmap, paperGC, 0, 0, pixmapW, pixmapH);
1855 // clear text object
1856 text->startPage(state);
1859 void XOutputDev::endPage() {
1862 text->coalesce(gTrue);
1864 // clear state stack, free all GCs, free the clip region
1868 XFreeGC(display, s->strokeGC);
1869 XFreeGC(display, s->fillGC);
1870 XDestroyRegion(s->clipRegion);
1873 XFreeGC(display, strokeGC);
1874 XFreeGC(display, fillGC);
1875 XFreeGC(display, paperGC);
1876 XDestroyRegion(clipRegion);
1879 void XOutputDev::drawLink(Link *link, Catalog *catalog) {
1880 double x1, y1, x2, y2, w;
1885 link->getBorder(&x1, &y1, &x2, &y2, &w);
1890 XSetForeground(display, strokeGC, findColor(&rgb));
1891 XSetLineAttributes(display, strokeGC, xoutRound(w),
1892 LineSolid, CapRound, JoinRound);
1893 cvtUserToDev(x1, y1, &x, &y);
1894 points[0].x = points[4].x = x;
1895 points[0].y = points[4].y = y;
1896 cvtUserToDev(x2, y1, &x, &y);
1899 cvtUserToDev(x2, y2, &x, &y);
1902 cvtUserToDev(x1, y2, &x, &y);
1905 XDrawLines(display, pixmap, strokeGC, points, 5, CoordModeOrigin);
1909 void XOutputDev::saveState(GfxState *state) {
1913 // save current state
1914 s = new XOutputState;
1915 s->strokeGC = strokeGC;
1917 s->clipRegion = clipRegion;
1919 // push onto state stack
1923 // create a new current state by copying
1924 strokeGC = XCreateGC(display, pixmap, 0, &values);
1925 XCopyGC(display, s->strokeGC, 0xffffffff, strokeGC);
1926 fillGC = XCreateGC(display, pixmap, 0, &values);
1927 XCopyGC(display, s->fillGC, 0xffffffff, fillGC);
1928 clipRegion = XCreateRegion();
1929 XUnionRegion(s->clipRegion, clipRegion, clipRegion);
1930 XSetRegion(display, strokeGC, clipRegion);
1931 XSetRegion(display, fillGC, clipRegion);
1934 void XOutputDev::restoreState(GfxState *state) {
1938 // kill current state
1939 XFreeGC(display, strokeGC);
1940 XFreeGC(display, fillGC);
1941 XDestroyRegion(clipRegion);
1944 flatness = state->getFlatness();
1945 strokeGC = save->strokeGC;
1946 fillGC = save->fillGC;
1947 clipRegion = save->clipRegion;
1948 XSetRegion(display, strokeGC, clipRegion);
1949 XSetRegion(display, fillGC, clipRegion);
1956 // we'll need to restore the font
1957 needFontUpdate = gTrue;
1961 void XOutputDev::updateAll(GfxState *state) {
1962 updateLineAttrs(state, gTrue);
1963 updateFlatness(state);
1964 updateMiterLimit(state);
1965 updateFillColor(state);
1966 updateStrokeColor(state);
1967 needFontUpdate = gTrue;
1970 void XOutputDev::updateCTM(GfxState *state, double m11, double m12,
1971 double m21, double m22, double m31, double m32) {
1972 updateLineAttrs(state, gTrue);
1975 void XOutputDev::updateLineDash(GfxState *state) {
1976 updateLineAttrs(state, gTrue);
1979 void XOutputDev::updateFlatness(GfxState *state) {
1980 flatness = state->getFlatness();
1983 void XOutputDev::updateLineJoin(GfxState *state) {
1984 updateLineAttrs(state, gFalse);
1987 void XOutputDev::updateLineCap(GfxState *state) {
1988 updateLineAttrs(state, gFalse);
1992 void XOutputDev::updateMiterLimit(GfxState *state) {
1995 void XOutputDev::updateLineWidth(GfxState *state) {
1996 updateLineAttrs(state, gFalse);
1999 void XOutputDev::updateLineAttrs(GfxState *state, GBool updateDash) {
2002 double *dashPattern;
2008 width = state->getTransformedLineWidth();
2009 switch (state->getLineCap()) {
2010 case 0: cap = CapButt; break;
2011 case 1: cap = CapRound; break;
2012 case 2: cap = CapProjecting; break;
2014 error(-1, "Bad line cap style (%d)", state->getLineCap());
2018 switch (state->getLineJoin()) {
2019 case 0: join = JoinMiter; break;
2020 case 1: join = JoinRound; break;
2021 case 2: join = JoinBevel; break;
2023 error(-1, "Bad line join style (%d)", state->getLineJoin());
2027 state->getLineDash(&dashPattern, &dashLength, &dashStart);
2028 #if 1 //~ work around a bug in XFree86 (???)
2029 if (dashLength > 0 && cap == CapProjecting) {
2033 XSetLineAttributes(display, strokeGC, xoutRound(width),
2034 dashLength > 0 ? LineOnOffDash : LineSolid,
2036 if (updateDash && dashLength > 0) {
2037 if (dashLength > 20)
2039 for (i = 0; i < dashLength; ++i) {
2040 dashList[i] = xoutRound(state->transformWidth(dashPattern[i]));
2041 if (dashList[i] == 0)
2044 XSetDashes(display, strokeGC, xoutRound(dashStart), dashList, dashLength);
2048 void XOutputDev::updateFillColor(GfxState *state) {
2051 state->getFillRGB(&rgb);
2057 XSetForeground(display, fillGC, findColor(&rgb));
2060 void XOutputDev::updateStrokeColor(GfxState *state) {
2063 state->getStrokeRGB(&rgb);
2069 XSetForeground(display, strokeGC, findColor(&rgb));
2072 void XOutputDev::updateFont(GfxState *state) {
2073 double m11, m12, m21, m22;
2075 needFontUpdate = gFalse;
2077 text->updateFont(state);
2079 if (!(gfxFont = state->getFont())) {
2083 if (gfxFont->getType() == fontType3) {
2087 state->getFontTransMat(&m11, &m12, &m21, &m22);
2088 m11 *= state->getHorizScaling();
2089 m12 *= state->getHorizScaling();
2090 font = fontCache->getFont(xref, gfxFont, m11, m12, m21, m22);
2092 font->updateGC(fillGC);
2093 font->updateGC(strokeGC);
2097 void XOutputDev::stroke(GfxState *state) {
2100 int n, size, numPoints, i, j;
2103 n = convertPath(state, &points, &size, &numPoints, &lengths, gFalse);
2105 // draw each subpath
2107 for (i = 0; i < n; ++i) {
2108 XDrawLines(display, pixmap, strokeGC, points + j, lengths[i],
2113 // free points and lengths arrays
2114 if (points != tmpPoints)
2116 if (lengths != tmpLengths)
2120 void XOutputDev::fill(GfxState *state) {
2121 doFill(state, WindingRule);
2124 void XOutputDev::eoFill(GfxState *state) {
2125 doFill(state, EvenOddRule);
2129 // X doesn't color the pixels on the right-most and bottom-most
2130 // borders of a polygon. This means that one-pixel-thick polygons
2131 // are not colored at all. I think this is supposed to be a
2132 // feature, but I can't figure out why. So after it fills a
2133 // polygon, it also draws lines around the border. This is done
2134 // only for single-component polygons, since it's not very
2135 // compatible with the compound polygon kludge (see convertPath()).
2137 void XOutputDev::doFill(GfxState *state, int rule) {
2140 int n, size, numPoints, i, j;
2143 XSetFillRule(display, fillGC, rule);
2145 // transform points, build separate polygons
2146 n = convertPath(state, &points, &size, &numPoints, &lengths, gTrue);
2150 for (i = 0; i < n; ++i) {
2151 XFillPolygon(display, pixmap, fillGC, points + j, lengths[i],
2152 Complex, CoordModeOrigin);
2153 if (state->getPath()->getNumSubpaths() == 1) {
2154 XDrawLines(display, pixmap, fillGC, points + j, lengths[i],
2157 j += lengths[i] + 1;
2160 // free points and lengths arrays
2161 if (points != tmpPoints)
2163 if (lengths != tmpLengths)
2167 void XOutputDev::clip(GfxState *state) {
2168 doClip(state, WindingRule);
2171 void XOutputDev::eoClip(GfxState *state) {
2172 doClip(state, EvenOddRule);
2175 void XOutputDev::doClip(GfxState *state, int rule) {
2176 Region region, region2;
2179 int n, size, numPoints, i, j;
2181 // transform points, build separate polygons
2182 n = convertPath(state, &points, &size, &numPoints, &lengths, gTrue);
2184 // construct union of subpath regions
2185 // (XPolygonRegion chokes if there aren't at least three points --
2186 // this happens if the PDF file does moveto/closepath/clip, which
2187 // sets an empty clipping region)
2188 if (lengths[0] > 2) {
2189 region = XPolygonRegion(points, lengths[0], rule);
2191 region = XCreateRegion();
2194 for (i = 1; i < n; ++i) {
2195 if (lengths[i] > 2) {
2196 region2 = XPolygonRegion(points + j, lengths[i], rule);
2198 region2 = XCreateRegion();
2200 XUnionRegion(region2, region, region);
2201 XDestroyRegion(region2);
2202 j += lengths[i] + 1;
2205 // intersect region with clipping region
2206 XIntersectRegion(region, clipRegion, clipRegion);
2207 XDestroyRegion(region);
2208 XSetRegion(display, strokeGC, clipRegion);
2209 XSetRegion(display, fillGC, clipRegion);
2211 // free points and lengths arrays
2212 if (points != tmpPoints)
2214 if (lengths != tmpLengths)
2219 // Transform points in the path and convert curves to line segments.
2220 // Builds a set of subpaths and returns the number of subpaths.
2221 // If <fillHack> is set, close any unclosed subpaths and activate a
2222 // kludge for polygon fills: First, it divides up the subpaths into
2223 // non-overlapping polygons by simply comparing bounding rectangles.
2224 // Then it connects subaths within a single compound polygon to a single
2225 // point so that X can fill the polygon (sort of).
2227 int XOutputDev::convertPath(GfxState *state, XPoint **points, int *size,
2228 int *numPoints, int **lengths, GBool fillHack) {
2230 BoundingRect *rects;
2232 int n, i, ii, j, k, k0;
2234 // get path and number of subpaths
2235 path = state->getPath();
2236 n = path->getNumSubpaths();
2238 // allocate lengths array
2239 if (n < numTmpSubpaths)
2240 *lengths = tmpLengths;
2242 *lengths = (int *)gmalloc(n * sizeof(int));
2244 // allocate bounding rectangles array
2246 if (n < numTmpSubpaths)
2249 rects = (BoundingRect *)gmalloc(n * sizeof(BoundingRect));
2255 *points = tmpPoints;
2256 *size = numTmpPoints;
2258 for (i = 0; i < n; ++i) {
2260 // transform the points
2262 convertSubpath(state, path->getSubpath(i), points, size, numPoints);
2264 // construct bounding rectangle
2266 rects[i].xMin = rects[i].xMax = (*points)[j].x;
2267 rects[i].yMin = rects[i].yMax = (*points)[j].y;
2268 for (k = j + 1; k < *numPoints; ++k) {
2269 if ((*points)[k].x < rects[i].xMin)
2270 rects[i].xMin = (*points)[k].x;
2271 else if ((*points)[k].x > rects[i].xMax)
2272 rects[i].xMax = (*points)[k].x;
2273 if ((*points)[k].y < rects[i].yMin)
2274 rects[i].yMin = (*points)[k].y;
2275 else if ((*points)[k].y > rects[i].yMax)
2276 rects[i].yMax = (*points)[k].y;
2280 // close subpath if necessary
2281 if (fillHack && ((*points)[*numPoints-1].x != (*points)[j].x ||
2282 (*points)[*numPoints-1].y != (*points)[j].y)) {
2283 addPoint(points, size, numPoints, (*points)[j].x, (*points)[j].y);
2286 // length of this subpath
2287 (*lengths)[i] = *numPoints - j;
2289 // leave an extra point for compound fill hack
2291 addPoint(points, size, numPoints, 0, 0);
2294 // kludge: munge any points that are *way* out of bounds - these can
2295 // crash certain (buggy) X servers
2296 for (i = 0; i < *numPoints; ++i) {
2297 if ((*points)[i].x < -pixmapW) {
2298 (*points)[i].x = -pixmapW;
2299 } else if ((*points)[i].x > 2 * pixmapW) {
2300 (*points)[i].x = 2 * pixmapW;
2302 if ((*points)[i].y < -pixmapH) {
2303 (*points)[i].y = -pixmapH;
2304 } else if ((*points)[i].y > 2 * pixmapH) {
2305 (*points)[i].y = 2 * pixmapH;
2309 // combine compound polygons
2314 // start with subpath i
2316 (*lengths)[j] = (*lengths)[i];
2318 (*points)[k + (*lengths)[i]] = (*points)[k0];
2319 k += (*lengths)[i] + 1;
2322 // combine overlapping polygons
2325 // look for the first subsequent subpath, if any, which overlaps
2326 for (ii = i; ii < n; ++ii) {
2327 if (rects[ii].xMax > rects[i].xMin &&
2328 rects[ii].xMin < rects[i].xMax &&
2329 rects[ii].yMax > rects[i].yMin &&
2330 rects[ii].yMin < rects[i].yMax) {
2335 // if there is an overlap, combine the polygons
2337 for (; i <= ii; ++i) {
2338 if (rects[i].xMin < rect.xMin)
2339 rect.xMin = rects[j].xMin;
2340 if (rects[i].xMax > rect.xMax)
2341 rect.xMax = rects[j].xMax;
2342 if (rects[i].yMin < rect.yMin)
2343 rect.yMin = rects[j].yMin;
2344 if (rects[i].yMax > rect.yMax)
2345 rect.yMax = rects[j].yMax;
2346 (*lengths)[j] += (*lengths)[i] + 1;
2347 (*points)[k + (*lengths)[i]] = (*points)[k0];
2348 k += (*lengths)[i] + 1;
2351 } while (ii < n && i < n);
2356 // free bounding rectangles
2357 if (rects != tmpRects)
2367 // Transform points in a single subpath and convert curves to line
2370 void XOutputDev::convertSubpath(GfxState *state, GfxSubpath *subpath,
2371 XPoint **points, int *size, int *n) {
2372 double x0, y0, x1, y1, x2, y2, x3, y3;
2375 m = subpath->getNumPoints();
2378 if (i >= 1 && subpath->getCurve(i)) {
2379 state->transform(subpath->getX(i-1), subpath->getY(i-1), &x0, &y0);
2380 state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1);
2381 state->transform(subpath->getX(i+1), subpath->getY(i+1), &x2, &y2);
2382 state->transform(subpath->getX(i+2), subpath->getY(i+2), &x3, &y3);
2383 doCurve(points, size, n, x0, y0, x1, y1, x2, y2, x3, y3);
2386 state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1);
2387 addPoint(points, size, n, xoutRound(x1), xoutRound(y1));
2394 // Subdivide a Bezier curve. This uses floating point to avoid
2395 // propagating rounding errors. (The curves look noticeably more
2396 // jagged with integer arithmetic.)
2398 void XOutputDev::doCurve(XPoint **points, int *size, int *n,
2399 double x0, double y0, double x1, double y1,
2400 double x2, double y2, double x3, double y3) {
2401 double x[(1<<maxCurveSplits)+1][3];
2402 double y[(1<<maxCurveSplits)+1][3];
2403 int next[1<<maxCurveSplits];
2405 double xx1, yy1, xx2, yy2;
2406 double dx, dy, mx, my, d1, d2;
2407 double xl0, yl0, xl1, yl1, xl2, yl2;
2408 double xr0, yr0, xr1, yr1, xr2, yr2, xr3, yr3;
2412 flat = (double)(flatness * flatness);
2418 p2 = 1<<maxCurveSplits;
2419 x[p1][0] = x0; y[p1][0] = y0;
2420 x[p1][1] = x1; y[p1][1] = y1;
2421 x[p1][2] = x2; y[p1][2] = y2;
2422 x[p2][0] = x3; y[p2][0] = y3;
2425 while (p1 < (1<<maxCurveSplits)) {
2428 xl0 = x[p1][0]; yl0 = y[p1][0];
2429 xx1 = x[p1][1]; yy1 = y[p1][1];
2430 xx2 = x[p1][2]; yy2 = y[p1][2];
2432 xr3 = x[p2][0]; yr3 = y[p2][0];
2434 // compute distances from control points to midpoint of the
2435 // straight line (this is a bit of a hack, but it's much faster
2436 // than computing the actual distances to the line)
2437 mx = (xl0 + xr3) * 0.5;
2438 my = (yl0 + yr3) * 0.5;
2446 // if curve is flat enough, or no more divisions allowed then
2447 // add the straight line segment
2448 if (p2 - p1 <= 1 || (d1 <= flat && d2 <= flat)) {
2449 addPoint(points, size, n, xoutRound(xr3), xoutRound(yr3));
2452 // otherwise, subdivide the curve
2454 xl1 = (xl0 + xx1) * 0.5;
2455 yl1 = (yl0 + yy1) * 0.5;
2456 xh = (xx1 + xx2) * 0.5;
2457 yh = (yy1 + yy2) * 0.5;
2458 xl2 = (xl1 + xh) * 0.5;
2459 yl2 = (yl1 + yh) * 0.5;
2460 xr2 = (xx2 + xr3) * 0.5;
2461 yr2 = (yy2 + yr3) * 0.5;
2462 xr1 = (xh + xr2) * 0.5;
2463 yr1 = (yh + yr2) * 0.5;
2464 xr0 = (xl2 + xr1) * 0.5;
2465 yr0 = (yl2 + yr1) * 0.5;
2467 // add the new subdivision points
2469 x[p1][1] = xl1; y[p1][1] = yl1;
2470 x[p1][2] = xl2; y[p1][2] = yl2;
2472 x[p3][0] = xr0; y[p3][0] = yr0;
2473 x[p3][1] = xr1; y[p3][1] = yr1;
2474 x[p3][2] = xr2; y[p3][2] = yr2;
2481 // Add a point to the points array. (This would use a generic resizable
2482 // array type if C++ supported parameterized types in some reasonable
2483 // way -- templates are a disgusting kludge.)
2485 void XOutputDev::addPoint(XPoint **points, int *size, int *k, int x, int y) {
2488 if (*points == tmpPoints) {
2489 *points = (XPoint *)gmalloc(*size * sizeof(XPoint));
2490 memcpy(*points, tmpPoints, *k * sizeof(XPoint));
2492 *points = (XPoint *)grealloc(*points, *size * sizeof(XPoint));
2495 (*points)[*k].x = x;
2496 (*points)[*k].y = y;
2500 void XOutputDev::beginString(GfxState *state, GString *s) {
2501 text->beginWord(state, state->getCurX(), state->getCurY());
2504 void XOutputDev::endString(GfxState *state) {
2508 void XOutputDev::drawChar(GfxState *state, double x, double y,
2509 double dx, double dy,
2510 double originX, double originY,
2511 CharCode code, Unicode *u, int uLen) {
2513 double x1, y1, dx1, dy1;
2515 double saveCurX, saveCurY;
2519 if (needFontUpdate) {
2523 text->addChar(state, x, y, dx, dy, code, u, uLen);
2529 // check for invisible text -- this is used by Acrobat Capture
2530 render = state->getRender();
2531 if ((render & 3) == 3) {
2537 state->transform(x, y, &x1, &y1);
2538 state->transformDelta(dx, dy, &dx1, &dy1);
2541 if (!(render & 1)) {
2542 state->getFillRGB(&rgb);
2548 font->drawChar(state, pixmap, pixmapW, pixmapH, fillGC, &rgb,
2549 x1, y1, dx1, dy1, code, u, uLen);
2553 if ((render & 3) == 1 || (render & 3) == 2) {
2554 if (font->hasGetCharPath()) {
2555 saveCurX = state->getCurX();
2556 saveCurY = state->getCurY();
2557 ctm = state->getCTM();
2558 memcpy(saveCTM, ctm, 6 * sizeof(double));
2559 state->setCTM(1, 0, 0, 1, x1, y1);
2560 font->getCharPath(state, code, u, uLen);
2563 state->setCTM(saveCTM[0], saveCTM[1], saveCTM[2], saveCTM[3],
2564 saveCTM[4], saveCTM[5]);
2565 state->moveTo(saveCurX, saveCurY);
2567 // can't stroke the outline, so just fill it using the stroke
2569 state->getStrokeRGB(&rgb);
2575 font->drawChar(state, pixmap, pixmapW, pixmapH, strokeGC, &rgb,
2576 x1, y1, dx1, dy1, code, u, uLen);
2580 #if 0 //~ unimplemented: clipping to char path
2587 GBool XOutputDev::beginType3Char(GfxState *state,
2588 CharCode code, Unicode *u, int uLen) {
2592 T3FontCache *t3Font;
2594 double x1, y1, xMin, yMin, xMax, yMax, xt, yt;
2597 if (needFontUpdate) {
2603 fontID = gfxFont->getID();
2604 ctm = state->getCTM();
2605 state->transform(0, 0, &xt, &yt);
2607 // is it the first (MRU) font in the cache?
2608 if (!(nT3Fonts > 0 &&
2609 t3FontCache[0]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3]))) {
2611 // is the font elsewhere in the cache?
2612 for (i = 1; i < nT3Fonts; ++i) {
2613 if (t3FontCache[i]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3])) {
2614 t3Font = t3FontCache[i];
2615 for (j = i; j > 0; --j) {
2616 t3FontCache[j] = t3FontCache[j - 1];
2618 t3FontCache[0] = t3Font;
2622 if (i >= nT3Fonts) {
2624 // create new entry in the font cache
2625 if (nT3Fonts == xOutT3FontCacheSize) {
2626 delete t3FontCache[nT3Fonts - 1];
2629 for (j = nT3Fonts; j > 0; --j) {
2630 t3FontCache[j] = t3FontCache[j - 1];
2633 bbox = gfxFont->getFontBBox();
2634 if (bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0) {
2635 // broken bounding box -- just take a guess
2641 state->transform(bbox[0], bbox[1], &x1, &y1);
2644 state->transform(bbox[0], bbox[3], &x1, &y1);
2647 } else if (x1 > xMax) {
2652 } else if (y1 > yMax) {
2655 state->transform(bbox[2], bbox[1], &x1, &y1);
2658 } else if (x1 > xMax) {
2663 } else if (y1 > yMax) {
2666 state->transform(bbox[2], bbox[3], &x1, &y1);
2669 } else if (x1 > xMax) {
2674 } else if (y1 > yMax) {
2678 t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3],
2679 (int)floor(xMin - xt),
2680 (int)floor(yMin - yt),
2681 (int)ceil(xMax) - (int)floor(xMin) + 3,
2682 (int)ceil(yMax) - (int)floor(yMin) + 3,
2683 display, visual, depth, pixmap);
2686 t3Font = t3FontCache[0];
2688 // is the glyph in the cache?
2689 i = (code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc;
2690 for (j = 0; j < t3Font->cacheAssoc; ++j) {
2691 if ((t3Font->cacheTags[i+j].mru & 0x8000) &&
2692 t3Font->cacheTags[i+j].code == code) {
2693 state->getFillRGB(&color);
2695 color.r = 1 - color.r;
2696 color.g = 1 - color.g;
2697 color.b = 1 - color.b;
2699 text->addChar(state, 0, 0,
2700 t3Font->cacheTags[i+j].wx, t3Font->cacheTags[i+j].wy,
2702 drawType3Glyph(t3Font, &t3Font->cacheTags[i+j],
2703 t3Font->cacheData + (i+j) * t3Font->glyphSize,
2709 // push a new Type 3 glyph record
2710 t3gs = new T3GlyphStack();
2711 t3gs->next = t3GlyphStack;
2712 t3GlyphStack = t3gs;
2713 t3GlyphStack->cacheable = gFalse;
2714 t3GlyphStack->code = code;
2715 t3GlyphStack->cache = t3Font;
2716 t3GlyphStack->cacheIdx = i;
2717 t3GlyphStack->x = xt;
2718 t3GlyphStack->y = yt;
2719 t3GlyphStack->u = u;
2720 t3GlyphStack->uLen = uLen;
2725 void XOutputDev::endType3Char(GfxState *state) {
2734 if (t3GlyphStack->cacheable) {
2735 image = t3GlyphStack->cache->image;
2736 XGetSubImage(display, pixmap, 0, 0,
2737 t3GlyphStack->cache->glyphW, t3GlyphStack->cache->glyphH,
2738 (1 << depth) - 1, ZPixmap, image, 0, 0);
2739 p = t3GlyphStack->cacheData;
2740 for (y = 0; y < t3GlyphStack->cache->glyphH; ++y) {
2741 for (x = 0; x < t3GlyphStack->cache->glyphW; ++x) {
2742 pixel = XGetPixel(image, x, y);
2744 alpha = (double)((pixel >> rShift) & rMul) / (double)rMul;
2746 alpha = redMap[pixel & 0xff];
2750 } else if (alpha <= 0.4) {
2752 } else if (alpha <= 0.6) {
2754 } else if (alpha <= 0.8) {
2761 XDestroyRegion(clipRegion);
2762 XFreeGC(display, strokeGC);
2763 XFreeGC(display, fillGC);
2764 pixmapW = t3GlyphStack->origPixmapW;
2765 pixmapH = t3GlyphStack->origPixmapH;
2766 pixmap = t3GlyphStack->origPixmap;
2767 strokeGC = t3GlyphStack->origStrokeGC;
2768 fillGC = t3GlyphStack->origFillGC;
2769 clipRegion = t3GlyphStack->origClipRegion;
2770 drawType3Glyph(t3GlyphStack->cache,
2771 t3GlyphStack->cacheTag, t3GlyphStack->cacheData,
2772 t3GlyphStack->x, t3GlyphStack->y, &t3GlyphStack->color);
2773 // the CTM must be restored here in order for TextPage::addChar to
2775 ctm = state->getCTM();
2776 state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
2777 t3GlyphStack->origCTM4, t3GlyphStack->origCTM5);
2779 text->addChar(state, 0, 0, t3GlyphStack->wx, t3GlyphStack->wy,
2780 t3GlyphStack->code, t3GlyphStack->u, t3GlyphStack->uLen);
2781 t3gs = t3GlyphStack;
2782 t3GlyphStack = t3gs->next;
2786 void XOutputDev::drawType3Glyph(T3FontCache *t3Font,
2787 T3FontCacheTag *tag, Guchar *data,
2788 double x, double y, GfxRGB *color) {
2795 int x0, y0, w0, h0, x1, y1;
2798 // compute: (x0,y0) = position in destination pixmap
2799 // (x1,y1) = position in the XImage
2800 // (w0,h0) = size of XImage transfer
2801 x0 = xoutRound(x + t3Font->glyphX);
2802 y0 = xoutRound(y + t3Font->glyphY);
2805 w0 = t3Font->glyphW;
2806 h0 = t3Font->glyphH;
2812 if (x0 + w0 > pixmapW) {
2823 if (y0 + h0 > pixmapH) {
2830 image = t3Font->image;
2831 XGetSubImage(display, pixmap, x0, y0, w0, h0,
2832 (1 << depth) - 1, ZPixmap, image, x1, y1);
2833 xcolor.pixel = XGetPixel(image, t3Font->glyphW / 2, t3Font->glyphH / 2);
2834 XQueryColor(display, colormap, &xcolor);
2835 bg.r = xcolor.red / 65535.0;
2836 bg.g = xcolor.green / 65535.0;
2837 bg.b = xcolor.blue / 65535.0;
2838 rgb.r = 0.25 * (color->r + 3 * bg.r);
2839 rgb.g = 0.25 * (color->g + 3 * bg.g);
2840 rgb.b = 0.25 * (color->b + 3 * bg.b);
2841 map[1] = findColor(&rgb);
2842 rgb.r = 0.5 * (color->r + bg.r);
2843 rgb.g = 0.5 * (color->g + bg.g);
2844 rgb.b = 0.5 * (color->b + bg.b);
2845 map[2] = findColor(&rgb);
2846 rgb.r = 0.25 * (3 * color->r + bg.r);
2847 rgb.g = 0.25 * (3 * color->g + bg.g);
2848 rgb.b = 0.25 * (3 * color->b + bg.b);
2849 map[3] = findColor(&rgb);
2850 map[4] = findColor(color);
2852 for (iy = 0; iy < t3Font->glyphH; ++iy) {
2853 for (ix = 0; ix < t3Font->glyphW; ++ix) {
2856 XPutPixel(image, ix, iy, map[pixel]);
2860 XPutImage(display, pixmap, fillGC, image, x1, y1, x0, y0, w0, h0);
2863 void XOutputDev::type3D0(GfxState *state, double wx, double wy) {
2864 t3GlyphStack->wx = wx;
2865 t3GlyphStack->wy = wy;
2868 void XOutputDev::type3D1(GfxState *state, double wx, double wy,
2869 double llx, double lly, double urx, double ury) {
2874 T3FontCache *t3Font;
2875 double xt, yt, xMin, xMax, yMin, yMax, x1, y1;
2878 t3Font = t3GlyphStack->cache;
2879 t3GlyphStack->wx = wx;
2880 t3GlyphStack->wy = wy;
2882 // check for a valid bbox
2883 state->transform(0, 0, &xt, &yt);
2884 state->transform(llx, lly, &x1, &y1);
2887 state->transform(llx, ury, &x1, &y1);
2890 } else if (x1 > xMax) {
2895 } else if (y1 > yMax) {
2898 state->transform(urx, lly, &x1, &y1);
2901 } else if (x1 > xMax) {
2906 } else if (y1 > yMax) {
2909 state->transform(urx, ury, &x1, &y1);
2912 } else if (x1 > xMax) {
2917 } else if (y1 > yMax) {
2920 if (xMin - xt < t3Font->glyphX ||
2921 yMin - yt < t3Font->glyphY ||
2922 xMax - xt > t3Font->glyphX + t3Font->glyphW ||
2923 yMax - yt > t3Font->glyphY + t3Font->glyphH) {
2924 error(-1, "Bad bounding box in Type 3 glyph");
2928 // allocate a cache entry
2929 t3GlyphStack->cacheable = gTrue;
2930 i = t3GlyphStack->cacheIdx;
2931 for (j = 0; j < t3Font->cacheAssoc; ++j) {
2932 if ((t3Font->cacheTags[i+j].mru & 0x7fff) == t3Font->cacheAssoc - 1) {
2933 t3Font->cacheTags[i+j].mru = 0x8000;
2934 t3Font->cacheTags[i+j].code = t3GlyphStack->code;
2935 t3GlyphStack->cacheTag = &t3Font->cacheTags[i+j];
2936 t3GlyphStack->cacheData = t3Font->cacheData + (i+j) * t3Font->glyphSize;
2938 ++t3Font->cacheTags[i+j].mru;
2941 t3GlyphStack->cacheTag->wx = wx;
2942 t3GlyphStack->cacheTag->wy = wy;
2944 // prepare to rasterize the glyph
2945 //~ do we need to handle both fill and stroke color?
2946 state->getFillRGB(&t3GlyphStack->color);
2948 t3GlyphStack->color.r = 1 - t3GlyphStack->color.r;
2949 t3GlyphStack->color.g = 1 - t3GlyphStack->color.g;
2950 t3GlyphStack->color.b = 1 - t3GlyphStack->color.b;
2952 fgColor.c[0] = reverseVideo ? 1 : 0;
2953 state->setFillColorSpace(new GfxDeviceGrayColorSpace());
2954 state->setFillColor(&fgColor);
2955 state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
2956 state->setStrokeColor(&fgColor);
2957 t3GlyphStack->origPixmapW = pixmapW;
2958 t3GlyphStack->origPixmapH = pixmapH;
2959 t3GlyphStack->origPixmap = pixmap;
2960 t3GlyphStack->origStrokeGC = strokeGC;
2961 t3GlyphStack->origFillGC = fillGC;
2962 t3GlyphStack->origClipRegion = clipRegion;
2963 pixmapW = t3GlyphStack->cache->glyphW;
2964 pixmapH = t3GlyphStack->cache->glyphH;
2965 pixmap = t3GlyphStack->cache->pixmap;
2966 gcValues.foreground = BlackPixel(display, screenNum);
2967 gcValues.background = WhitePixel(display, screenNum);
2968 gcValues.line_width = 0;
2969 gcValues.line_style = LineSolid;
2970 strokeGC = XCreateGC(display, pixmap,
2971 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
2973 updateLineAttrs(state, gTrue);
2974 gcValues.foreground = WhitePixel(display, screenNum);
2975 fillGC = XCreateGC(display, pixmap,
2976 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
2978 XFillRectangle(display, pixmap, fillGC, 0, 0, pixmapW, pixmapH);
2979 XSetForeground(display, fillGC, BlackPixel(display, screenNum));
2980 clipRegion = XCreateRegion();
2981 rect.x = rect.y = 0;
2982 rect.width = pixmapW;
2983 rect.height = pixmapH;
2984 XUnionRectWithRegion(&rect, clipRegion, clipRegion);
2985 XSetRegion(display, strokeGC, clipRegion);
2986 XSetRegion(display, fillGC, clipRegion);
2987 ctm = state->getCTM();
2988 t3GlyphStack->origCTM4 = ctm[4];
2989 t3GlyphStack->origCTM5 = ctm[5];
2990 state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
2991 -t3GlyphStack->cache->glyphX, -t3GlyphStack->cache->glyphY);
2994 inline Gulong XOutputDev::findColor(GfxRGB *x, GfxRGB *err) {
3000 r = xoutRound(x->r * rMul);
3001 g = xoutRound(x->g * gMul);
3002 b = xoutRound(x->b * bMul);
3003 pixel = ((Gulong)r << rShift) +
3004 ((Gulong)g << gShift) +
3005 ((Gulong)b << bShift);
3006 err->r = x->r - (double)r / rMul;
3007 err->g = x->g - (double)g / gMul;
3008 err->b = x->b - (double)b / bMul;
3009 } else if (numColors == 1) {
3010 gray = 0.299 * x->r + 0.587 * x->g + 0.114 * x->b;
3023 r = xoutRound(x->r * (numColors - 1));
3024 g = xoutRound(x->g * (numColors - 1));
3025 b = xoutRound(x->b * (numColors - 1));
3026 pixel = colors[(r * numColors + g) * numColors + b];
3027 err->r = x->r - (double)r / (numColors - 1);
3028 err->g = x->g - (double)g / (numColors - 1);
3029 err->b = x->b - (double)b / (numColors - 1);
3034 Gulong XOutputDev::findColor(GfxRGB *rgb) {
3040 r = xoutRound(rgb->r * rMul);
3041 g = xoutRound(rgb->g * gMul);
3042 b = xoutRound(rgb->b * bMul);
3043 pixel = ((Gulong)r << rShift) +
3044 ((Gulong)g << gShift) +
3045 ((Gulong)b << bShift);
3046 } else if (numColors == 1) {
3047 gray = 0.299 * rgb->r + 0.587 * rgb->g + 0.114 * rgb->b;
3053 r = xoutRound(rgb->r * (numColors - 1));
3054 g = xoutRound(rgb->g * (numColors - 1));
3055 b = xoutRound(rgb->b * (numColors - 1));
3056 #if 0 // this makes things worse as often as better
3057 // even a very light color shouldn't map to white
3058 if (r == numColors - 1 && g == numColors - 1 && b == numColors - 1) {
3059 if (color->getR() < 0.95)
3061 if (color->getG() < 0.95)
3063 if (color->getB() < 0.95)
3067 pixel = colors[(r * numColors + g) * numColors + b];
3072 void XOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
3073 int width, int height, GBool invert,
3075 ImageStream *imgStr;
3079 double xScale, yScale, xShear, yShear;
3080 int tx, ty, scaledWidth, scaledHeight, xSign, ySign;
3081 int ulx, uly, llx, lly, urx, ury, lrx, lry;
3082 int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
3083 int bx0, by0, bx1, by1, bw, bh;
3084 int cx0, cy0, cx1, cy1, cw, ch;
3085 int yp, yq, yt, yStep, lastYStep;
3086 int xp, xq, xt, xStep, xSrc;
3094 double r0, g0, b0, r1, g1, b1;
3097 int x, y, x1, y1, x2, y2;
3100 // get CTM, check for singular matrix
3101 ctm = state->getCTM();
3102 if (fabs(ctm[0] * ctm[3] - ctm[1] * ctm[2]) < 0.000001) {
3103 error(-1, "Singular CTM in drawImage");
3105 j = height * ((width + 7) / 8);
3107 for (i = 0; i < j; ++i) {
3115 // compute scale, shear, rotation, translation parameters
3116 rot = fabs(ctm[1]) > fabs(ctm[0]);
3119 yScale = -ctm[2] + (ctm[0] * ctm[3]) / ctm[1];
3120 xShear = ctm[3] / yScale;
3121 yShear = -ctm[0] / ctm[1];
3124 yScale = -ctm[3] + (ctm[1] * ctm[2]) / ctm[0];
3125 xShear = -ctm[2] / yScale;
3126 yShear = ctm[1] / ctm[0];
3128 tx = xoutRound(ctm[2] + ctm[4]);
3129 ty = xoutRound(ctm[3] + ctm[5]);
3130 // use ceil() to avoid gaps between "striped" images
3131 scaledWidth = (int)ceil(fabs(xScale));
3132 xSign = (xScale < 0) ? -1 : 1;
3133 scaledHeight = (int)ceil(fabs(yScale));
3134 ySign = (yScale < 0) ? -1 : 1;
3136 // compute corners in device space
3139 urx1 = xSign * (scaledWidth - 1);
3140 ury1 = xoutRound(yShear * urx1);
3141 llx1 = xoutRound(xShear * ySign * (scaledHeight - 1));
3142 lly1 = ySign * (scaledHeight - 1) + xoutRound(yShear * llx1);
3143 lrx1 = xSign * (scaledWidth - 1) +
3144 xoutRound(xShear * ySign * (scaledHeight - 1));
3145 lry1 = ySign * (scaledHeight - 1) + xoutRound(yShear * lrx1);
3147 ulx = tx + uly1; uly = ty - ulx1;
3148 urx = tx + ury1; ury = ty - urx1;
3149 llx = tx + lly1; lly = ty - llx1;
3150 lrx = tx + lry1; lry = ty - lrx1;
3152 ulx = tx + ulx1; uly = ty + uly1;
3153 urx = tx + urx1; ury = ty + ury1;
3154 llx = tx + llx1; lly = ty + lly1;
3155 lrx = tx + lrx1; lry = ty + lry1;
3159 // (bx0, by0) = upper-left corner
3160 // (bx1, by1) = lower-right corner
3162 bx0 = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
3163 : (llx < lrx) ? llx : lrx
3164 : (urx < llx) ? (urx < lrx) ? urx : lrx
3165 : (llx < lrx) ? llx : lrx;
3166 bx1 = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
3167 : (llx > lrx) ? llx : lrx
3168 : (urx > llx) ? (urx > lrx) ? urx : lrx
3169 : (llx > lrx) ? llx : lrx;
3170 by0 = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
3171 : (lly < lry) ? lly : lry
3172 : (ury < lly) ? (ury < lry) ? ury : lry
3173 : (lly < lry) ? lly : lry;
3174 by1 = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
3175 : (lly > lry) ? lly : lry
3176 : (ury > lly) ? (ury > lry) ? ury : lry
3177 : (lly > lry) ? lly : lry;
3181 // Bounding box clipped to pixmap, i.e., "valid" rectangle:
3182 // (cx0, cy0) = upper-left corner of valid rectangle in Pixmap
3183 // (cx1, cy1) = upper-left corner of valid rectangle in XImage
3184 // (cw, ch) = size of valid rectangle
3185 // These values will be used to transfer the XImage from/to the
3187 cw = (bx1 >= pixmapW) ? pixmapW - bx0 : bw;
3196 ch = (by1 >= pixmapH) ? pixmapH - by0 : bh;
3206 // check for tiny (zero width or height) images
3207 // and off-page images
3208 if (scaledWidth <= 0 || scaledHeight <= 0 || cw <= 0 || ch <= 0) {
3210 j = height * ((width + 7) / 8);
3212 for (i = 0; i < j; ++i) {
3220 // compute Bresenham parameters for x and y scaling
3221 yp = height / scaledHeight;
3222 yq = height % scaledHeight;
3223 xp = width / scaledWidth;
3224 xq = width % scaledWidth;
3226 // allocate pixel buffer
3227 pixBuf = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar));
3229 // allocate XImage and read from page pixmap
3230 image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, bw, bh, 8, 0);
3231 image->data = (char *)gmalloc(bh * image->bytes_per_line);
3232 XGetSubImage(display, pixmap, cx0, cy0, cw, ch, (1 << depth) - 1, ZPixmap,
3236 state->getFillRGB(&rgb);
3246 // initialize background color
3247 // (the specific pixel value doesn't matter here, as long as
3248 // r1,g1,b1 correspond correctly to lastPixel)
3249 xcolor.pixel = lastPixel = 0;
3250 XQueryColor(display, colormap, &xcolor);
3251 r1 = (double)xcolor.red / 65535.0;
3252 g1 = (double)xcolor.green / 65535.0;
3253 b1 = (double)xcolor.blue / 65535.0;
3255 // initialize the image stream
3256 imgStr = new ImageStream(str, width, 1, 1);
3259 // init y scale Bresenham
3263 for (y = 0; y < scaledHeight; ++y) {
3265 // y scale Bresenham
3268 if (yt >= scaledHeight) {
3273 // read row(s) from image
3274 n = (yp > 0) ? yStep : lastYStep;
3277 for (i = 0; i < n; ++i) {
3278 memcpy(p, imgStr->getLine(), width);
3280 for (j = 0; j < width; ++j) {
3289 // init x scale Bresenham
3293 for (x = 0; x < scaledWidth; ++x) {
3295 // x scale Bresenham
3298 if (xt >= scaledWidth) {
3304 x1 = xSign * x + xoutRound(xShear * ySign * y);
3307 y1 = ySign * y + xoutRound(yShear * x1);
3318 // compute the filtered pixel at (x,y) after the
3319 // x and y scaling operations
3320 n = yStep > 0 ? yStep : 1;
3321 m = xStep > 0 ? xStep : 1;
3324 for (i = 0; i < n; ++i) {
3325 for (j = 0; j < m; ++j) {
3331 // x scale Bresenham
3334 // blend image pixel with background
3335 alpha = (double)imgPix / (double)(n * m);
3336 xcolor.pixel = XGetPixel(image, tx + x2 - bx0, ty + y2 - by0);
3337 if (xcolor.pixel != lastPixel) {
3338 XQueryColor(display, colormap, &xcolor);
3339 r1 = (double)xcolor.red / 65535.0;
3340 g1 = (double)xcolor.green / 65535.0;
3341 b1 = (double)xcolor.blue / 65535.0;
3342 lastPixel = xcolor.pixel;
3344 rgb2.r = r0 * (1 - alpha) + r1 * alpha;
3345 rgb2.g = g0 * (1 - alpha) + g1 * alpha;
3346 rgb2.b = b0 * (1 - alpha) + b1 * alpha;
3347 pix = findColor(&rgb2);
3350 XPutPixel(image, tx + x2 - bx0, ty + y2 - by0, pix);
3354 // blit the image into the pixmap
3355 XPutImage(display, pixmap, fillGC, image, cx1, cy1, cx0, cy0, cw, ch);
3362 XDestroyImage(image);
3365 void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
3366 int width, int height, GfxImageColorMap *colorMap,
3367 int *maskColors, GBool inlineImg) {
3368 ImageStream *imgStr;
3370 int nComps, nVals, nBits;
3374 double xScale, yScale, xShear, yShear;
3375 int tx, ty, scaledWidth, scaledHeight, xSign, ySign;
3376 int ulx, uly, llx, lly, urx, ury, lrx, lry;
3377 int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
3378 int bx0, by0, bx1, by1, bw, bh;
3379 int cx0, cy0, cx1, cy1, cw, ch;
3380 int yp, yq, yt, yStep, lastYStep;
3381 int xp, xq, xt, xStep, xSrc;
3384 Guchar pixBuf2[gfxColorMaxComps];
3385 GfxRGB color2, err, errRight;
3387 double r0, g0, b0, alpha, mul;
3392 GfxRGB oneBitRGB[2];
3393 int x, y, x1, y1, x2, y2;
3397 nComps = colorMap->getNumPixelComps();
3398 nVals = width * nComps;
3399 nBits = colorMap->getBits();
3400 dither = nComps > 1 || nBits > 1;
3402 // get CTM, check for singular matrix
3403 ctm = state->getCTM();
3404 if (fabs(ctm[0] * ctm[3] - ctm[1] * ctm[2]) < 0.000001) {
3405 error(-1, "Singular CTM in drawImage");
3408 j = height * ((nVals * nBits + 7) / 8);
3409 for (i = 0; i < j; ++i) {
3417 // compute scale, shear, rotation, translation parameters
3418 rot = fabs(ctm[1]) > fabs(ctm[0]);
3421 yScale = -ctm[2] + (ctm[0] * ctm[3]) / ctm[1];
3422 xShear = ctm[3] / yScale;
3423 yShear = -ctm[0] / ctm[1];
3426 yScale = -ctm[3] + (ctm[1] * ctm[2]) / ctm[0];
3427 xShear = -ctm[2] / yScale;
3428 yShear = ctm[1] / ctm[0];
3430 tx = xoutRound(ctm[2] + ctm[4]);
3431 ty = xoutRound(ctm[3] + ctm[5]);
3433 // this is the right edge which needs to be (left + width - 1)
3437 // this is the bottom edge which needs to be (top + height - 1)
3440 // use ceil() to avoid gaps between "striped" images
3441 scaledWidth = (int)ceil(fabs(xScale));
3442 xSign = (xScale < 0) ? -1 : 1;
3443 scaledHeight = (int)ceil(fabs(yScale));
3444 ySign = (yScale < 0) ? -1 : 1;
3446 // compute corners in device space
3449 urx1 = xSign * (scaledWidth - 1);
3450 ury1 = xoutRound(yShear * urx1);
3451 llx1 = xoutRound(xShear * ySign * (scaledHeight - 1));
3452 lly1 = ySign * (scaledHeight - 1) + xoutRound(yShear * llx1);
3453 lrx1 = xSign * (scaledWidth - 1) +
3454 xoutRound(xShear * ySign * (scaledHeight - 1));
3455 lry1 = ySign * (scaledHeight - 1) + xoutRound(yShear * lrx1);
3457 ulx = tx + uly1; uly = ty - ulx1;
3458 urx = tx + ury1; ury = ty - urx1;
3459 llx = tx + lly1; lly = ty - llx1;
3460 lrx = tx + lry1; lry = ty - lrx1;
3462 ulx = tx + ulx1; uly = ty + uly1;
3463 urx = tx + urx1; ury = ty + ury1;
3464 llx = tx + llx1; lly = ty + lly1;
3465 lrx = tx + lrx1; lry = ty + lry1;
3469 // (bx0, by0) = upper-left corner
3470 // (bx1, by1) = lower-right corner
3472 bx0 = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
3473 : (llx < lrx) ? llx : lrx
3474 : (urx < llx) ? (urx < lrx) ? urx : lrx
3475 : (llx < lrx) ? llx : lrx;
3476 bx1 = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
3477 : (llx > lrx) ? llx : lrx
3478 : (urx > llx) ? (urx > lrx) ? urx : lrx
3479 : (llx > lrx) ? llx : lrx;
3480 by0 = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
3481 : (lly < lry) ? lly : lry
3482 : (ury < lly) ? (ury < lry) ? ury : lry
3483 : (lly < lry) ? lly : lry;
3484 by1 = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
3485 : (lly > lry) ? lly : lry
3486 : (ury > lly) ? (ury > lry) ? ury : lry
3487 : (lly > lry) ? lly : lry;
3491 // Bounding box clipped to pixmap, i.e., "valid" rectangle:
3492 // (cx0, cy0) = upper-left corner of valid rectangle in Pixmap
3493 // (cx1, cy1) = upper-left corner of valid rectangle in XImage
3494 // (cw, ch) = size of valid rectangle
3495 // These values will be used to transfer the XImage from/to the
3497 cw = (bx1 >= pixmapW) ? pixmapW - bx0 : bw;
3506 ch = (by1 >= pixmapH) ? pixmapH - by0 : bh;
3516 // check for tiny (zero width or height) images
3517 // and off-page images
3518 if (scaledWidth <= 0 || scaledHeight <= 0 || cw <= 0 || ch <= 0) {
3521 j = height * ((nVals * nBits + 7) / 8);
3522 for (i = 0; i < j; ++i)
3529 // compute Bresenham parameters for x and y scaling
3530 yp = height / scaledHeight;
3531 yq = height % scaledHeight;
3532 xp = width / scaledWidth;
3533 xq = width % scaledWidth;
3535 // allocate pixel buffer
3536 pixBuf = (GfxRGB *)gmalloc((yp + 1) * width * sizeof(GfxRGB));
3538 alphaBuf = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar));
3544 image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, bw, bh, 8, 0);
3545 image->data = (char *)gmalloc(bh * image->bytes_per_line);
3547 // if the transform is anything other than a 0/90/180/270 degree
3548 // rotation/flip, or if there is color key masking, read the
3549 // backgound pixmap to fill in the corners
3550 if (!((ulx == llx && uly == ury) ||
3551 (uly == lly && ulx == urx)) ||
3553 XGetSubImage(display, pixmap, cx0, cy0, cw, ch, (1 << depth) - 1, ZPixmap,
3557 // allocate error diffusion accumulators
3559 errDown = (GfxRGB *)gmalloc(bw * sizeof(GfxRGB));
3560 for (j = 0; j < bw; ++j) {
3561 errDown[j].r = errDown[j].g = errDown[j].b = 0;
3567 // optimize the one-bit-deep image case
3568 if ((oneBitMode = nComps == 1 && nBits == 1)) {
3570 colorMap->getRGB(pixBuf2, &oneBitRGB[0]);
3572 colorMap->getRGB(pixBuf2, &oneBitRGB[1]);
3575 // initialize the image stream
3576 imgStr = new ImageStream(str, width, nComps, nBits);
3579 // init y scale Bresenham
3583 for (y = 0; y < scaledHeight; ++y) {
3585 // initialize error diffusion accumulator
3586 errRight.r = errRight.g = errRight.b = 0;
3588 // y scale Bresenham
3591 if (yt >= scaledHeight) {
3596 // read row(s) from image
3597 n = (yp > 0) ? yStep : lastYStep;
3601 for (i = 0; i < n; ++i) {
3602 p2 = imgStr->getLine();
3603 for (j = 0; j < width; ++j) {
3605 *p = oneBitRGB[*p2];
3607 colorMap->getRGB(p2, p);
3612 for (k = 0; k < nComps; ++k) {
3613 if (p2[k] < maskColors[2*k] ||
3614 p2[k] > maskColors[2*k]) {
3627 // init x scale Bresenham
3631 for (x = 0; x < scaledWidth; ++x) {
3633 // x scale Bresenham
3636 if (xt >= scaledWidth) {
3642 x1 = xSign * x + xoutRound(xShear * ySign * y);
3645 y1 = ySign * y + xoutRound(yShear * x1);
3656 // compute the filtered pixel at (x,y) after the
3657 // x and y scaling operations
3658 n = yStep > 0 ? yStep : 1;
3659 m = xStep > 0 ? xStep : 1;
3662 q = alphaBuf ? alphaBuf + xSrc : (Guchar *)NULL;
3664 for (i = 0; i < n; ++i) {
3665 for (j = 0; j < m; ++j) {
3676 mul = 1 / (double)(n * m);
3682 // x scale Bresenham
3687 color2.r = r0 + errRight.r + errDown[tx + x2 - bx0].r;
3690 } else if (color2.r < 0) {
3693 color2.g = g0 + errRight.g + errDown[tx + x2 - bx0].g;
3696 } else if (color2.g < 0) {
3699 color2.b = b0 + errRight.b + errDown[tx + x2 - bx0].b;
3702 } else if (color2.b < 0) {
3705 pix = findColor(&color2, &err);
3706 errRight.r = errDown[tx + x2 - bx0].r = err.r / 2;
3707 errRight.g = errDown[tx + x2 - bx0].g = err.g / 2;
3708 errRight.b = errDown[tx + x2 - bx0].b = err.b / 2;
3713 pix = findColor(&color2, &err);
3717 //~ this should do a blend when 0 < alpha < 1
3719 XPutPixel(image, tx + x2 - bx0, ty + y2 - by0, pix);
3724 // blit the image into the pixmap
3725 XPutImage(display, pixmap, fillGC, image, cx1, cy1, cx0, cy0, cw, ch);
3735 XDestroyImage(image);
3739 GBool XOutputDev::findText(Unicode *s, int len, GBool top, GBool bottom,
3740 int *xMin, int *yMin, int *xMax, int *yMax) {
3741 double xMin1, yMin1, xMax1, yMax1;
3743 xMin1 = (double)*xMin;
3744 yMin1 = (double)*yMin;
3745 xMax1 = (double)*xMax;
3746 yMax1 = (double)*yMax;
3747 if (text->findText(s, len, top, bottom, &xMin1, &yMin1, &xMax1, &yMax1)) {
3748 *xMin = xoutRound(xMin1);
3749 *xMax = xoutRound(xMax1);
3750 *yMin = xoutRound(yMin1);
3751 *yMax = xoutRound(yMax1);
3757 GString *XOutputDev::getText(int xMin, int yMin, int xMax, int yMax) {
3758 return text->getText((double)xMin, (double)yMin,
3759 (double)xMax, (double)yMax);