1 //========================================================================
5 // Copyright 1996-2002 Glyph & Cog, LLC
7 //========================================================================
10 #pragma implementation
30 #include "UnicodeMap.h"
31 #include "CharCodeToUnicode.h"
34 #include "TextOutputDev.h"
35 #include "XOutputDev.h"
39 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
42 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
47 #if (__VMS_VER < 70000000)
48 extern "C" int unlink(char *filename);
52 #ifdef XlibSpecificationRelease
53 #if XlibSpecificationRelease < 5
54 typedef char *XPointer;
57 typedef char *XPointer;
60 //------------------------------------------------------------------------
61 // Constants and macros
62 //------------------------------------------------------------------------
64 #define xoutRound(x) ((int)(x + 0.5))
66 #define maxCurveSplits 6 // max number of splits when recursively
67 // drawing Bezier curves
69 //------------------------------------------------------------------------
71 //------------------------------------------------------------------------
73 struct XOutFontSubst {
78 // index: {symbolic:12, fixed:8, serif:4, sans-serif:0} + bold*2 + italic
79 static XOutFontSubst xOutSubstFonts[16] = {
81 {"Helvetica-Oblique", 0.833},
82 {"Helvetica-Bold", 0.889},
83 {"Helvetica-BoldOblique", 0.889},
84 {"Times-Roman", 0.788},
85 {"Times-Italic", 0.722},
86 {"Times-Bold", 0.833},
87 {"Times-BoldItalic", 0.778},
89 {"Courier-Oblique", 0.600},
90 {"Courier-Bold", 0.600},
91 {"Courier-BoldOblique", 0.600},
98 //------------------------------------------------------------------------
100 //------------------------------------------------------------------------
102 XOutputFont::XOutputFont(Ref *idA, double m11OrigA, double m12OrigA,
103 double m21OrigA, double m22OrigA,
104 double m11A, double m12A, double m21A, double m22A,
105 Display *displayA, XOutputDev *xOutA) {
119 XOutputFont::~XOutputFont() {
122 void XOutputFont::getCharPath(GfxState *state,
123 CharCode c, Unicode *u, int ulen) {
127 //------------------------------------------------------------------------
129 //------------------------------------------------------------------------
131 XOutputT1Font::XOutputT1Font(Ref *idA, T1FontFile *fontFileA,
132 double m11OrigA, double m12OrigA,
133 double m21OrigA, double m22OrigA,
134 double m11A, double m12A,
135 double m21A, double m22A,
136 Display *displayA, XOutputDev *xOutA):
137 XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA,
138 m11A, m12A, m21A, m22A, displayA, xOutA)
142 fontFile = fontFileA;
144 // create the transformed instance
149 font = new T1Font(fontFile, matrix);
152 XOutputT1Font::~XOutputT1Font() {
158 GBool XOutputT1Font::isOk() {
162 void XOutputT1Font::updateGC(GC gc) {
165 void XOutputT1Font::drawChar(GfxState *state, Pixmap pixmap, int w, int h,
167 double x, double y, double dx, double dy,
168 CharCode c, Unicode *u, int uLen) {
169 font->drawChar(pixmap, w, h, gc, xoutRound(x), xoutRound(y),
170 (int)(rgb->r * 65535), (int)(rgb->g * 65535),
171 (int)(rgb->b * 65535), c, u[0]);
174 void XOutputT1Font::getCharPath(GfxState *state,
175 CharCode c, Unicode *u, int uLen) {
176 font->getCharPath(c, u[0], state);
178 #endif // HAVE_T1LIB_H
180 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
181 //------------------------------------------------------------------------
183 //------------------------------------------------------------------------
185 XOutputFTFont::XOutputFTFont(Ref *idA, FTFontFile *fontFileA,
186 double m11OrigA, double m12OrigA,
187 double m21OrigA, double m22OrigA,
188 double m11A, double m12A,
189 double m21A, double m22A,
190 Display *displayA, XOutputDev *xOutA):
191 XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA,
192 m11A, m12A, m21A, m22A, displayA, xOutA)
196 fontFile = fontFileA;
198 // create the transformed instance
203 font = new FTFont(fontFile, matrix);
206 XOutputFTFont::~XOutputFTFont() {
212 GBool XOutputFTFont::isOk() {
216 void XOutputFTFont::updateGC(GC gc) {
219 void XOutputFTFont::drawChar(GfxState *state, Pixmap pixmap, int w, int h,
221 double x, double y, double dx, double dy,
222 CharCode c, Unicode *u, int uLen) {
223 font->drawChar(pixmap, w, h, gc, xoutRound(x), xoutRound(y),
224 (int)(rgb->r * 65535), (int)(rgb->g * 65535),
225 (int)(rgb->b * 65535), c, uLen > 0 ? u[0] : 0);
228 void XOutputFTFont::getCharPath(GfxState *state,
229 CharCode c, Unicode *u, int uLen) {
230 font->getCharPath(c, u[0], state);
232 #endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
234 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
235 //------------------------------------------------------------------------
237 //------------------------------------------------------------------------
239 XOutputTTFont::XOutputTTFont(Ref *idA, TTFontFile *fontFileA,
240 double m11OrigA, double m12OrigA,
241 double m21OrigA, double m22OrigA,
242 double m11A, double m12A,
243 double m21A, double m22A,
244 Display *displayA, XOutputDev *xOutA):
245 XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA,
246 m11A, m12A, m21A, m22A, displayA, xOutA)
250 fontFile = fontFileA;
252 // create the transformed instance
257 font = new TTFont(fontFile, matrix);
260 XOutputTTFont::~XOutputTTFont() {
266 GBool XOutputTTFont::isOk() {
270 void XOutputTTFont::updateGC(GC gc) {
273 void XOutputTTFont::drawChar(GfxState *state, Pixmap pixmap, int w, int h,
275 double x, double y, double dx, double dy,
276 CharCode c, Unicode *u, int uLen) {
277 font->drawChar(pixmap, w, h, gc, xoutRound(x), xoutRound(y),
278 (int)(rgb->r * 65535), (int)(rgb->g * 65535),
279 (int)(rgb->b * 65535), c, u[0]);
281 #endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
283 //------------------------------------------------------------------------
284 // XOutputServer8BitFont
285 //------------------------------------------------------------------------
287 // Copy <fmt>, substituting <val> for one occurrence of "%s", into
289 static void stringSubst(char *buf, int bufSize, char *fmt, char *val) {
296 if (p[0] == '%' && p[1] == 's') {
298 while (*q && i < bufSize - 1) {
303 if (i < bufSize - 1) {
312 XOutputServer8BitFont::XOutputServer8BitFont(Ref *idA, GString *xlfdFmt,
314 CharCodeToUnicode *fontUMap,
315 double m11OrigA, double m12OrigA,
316 double m21OrigA, double m22OrigA,
317 double m11A, double m12A,
318 double m21A, double m22A,
321 XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA,
322 m11A, m12A, m21A, m22A, displayA, xOutA)
324 double size, ntm11, ntm12, ntm21, ntm22;
327 char fontName[500], fontSize[100];
332 // compute size and normalized transform matrix
333 size = sqrt(m21*m21 + m22*m22);
339 // try to get a rotated font?
340 rotated = !(ntm11 > 0 && ntm22 > 0 &&
341 fabs(ntm11 / ntm22 - 1) < 0.2 &&
342 fabs(ntm12) < 0.01 &&
345 // open X font -- if font is not found (which means the server can't
346 // scale fonts), try progressively smaller and then larger sizes
347 startSize = (int)size;
349 sprintf(fontSize, "[%s%0.2f %s%0.2f %s%0.2f %s%0.2f]",
350 ntm11<0 ? "~" : "", fabs(ntm11 * size),
351 ntm12<0 ? "~" : "", fabs(ntm12 * size),
352 ntm21<0 ? "~" : "", fabs(ntm21 * size),
353 ntm22<0 ? "~" : "", fabs(ntm22 * size));
355 sprintf(fontSize, "%d", startSize);
357 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize);
358 xFont = XLoadQueryFont(display, fontName);
360 for (sz = startSize; sz >= startSize/2 && sz >= 1; --sz) {
361 sprintf(fontSize, "%d", sz);
362 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize);
363 if ((xFont = XLoadQueryFont(display, fontName)))
367 for (sz = startSize + 1; sz < startSize + 10; ++sz) {
368 sprintf(fontSize, "%d", sz);
369 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(),
371 if ((xFont = XLoadQueryFont(display, fontName))) {
376 sprintf(fontSize, "%d", startSize);
377 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(),
379 error(-1, "Failed to open font: '%s'", fontName);
385 // Construct char code map.
387 for (i = 0; i < 256; ++i) {
388 if (fontUMap->mapToUnicode((CID)i, &u, 1) == 1 &&
389 xUMap->mapUnicode(u, &buf, 1) == 1) {
397 XOutputServer8BitFont::~XOutputServer8BitFont() {
399 XFreeFont(display, xFont);
403 GBool XOutputServer8BitFont::isOk() {
404 return xFont != NULL;
407 void XOutputServer8BitFont::updateGC(GC gc) {
408 XSetFont(display, gc, xFont->fid);
411 void XOutputServer8BitFont::drawChar(GfxState *state, Pixmap pixmap,
412 int w, int h, GC gc, GfxRGB *rgb,
413 double x, double y, double dx, double dy,
414 CharCode c, Unicode *u, int uLen) {
423 XDrawString(display, pixmap, gc, xoutRound(x), xoutRound(y), buf, 1);
425 // substituted character, using more than one character
427 for (i = 0; i < uLen; ++i) {
428 n += xUMap->mapUnicode(u[i], buf, sizeof(buf));
434 for (i = 0; i < uLen; ++i) {
435 m = xUMap->mapUnicode(u[i], buf, sizeof(buf));
436 for (j = 0; j < m; ++j) {
437 XDrawString(display, pixmap, gc,
438 xoutRound(x + k*dx1), xoutRound(y + k*dy1),
447 //------------------------------------------------------------------------
448 // XOutputServer16BitFont
449 //------------------------------------------------------------------------
451 XOutputServer16BitFont::XOutputServer16BitFont(Ref *idA, GString *xlfdFmt,
453 CharCodeToUnicode *fontUMap,
458 double m11A, double m12A,
459 double m21A, double m22A,
462 XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA,
463 m11A, m12A, m21A, m22A, displayA, xOutA)
465 double size, ntm11, ntm12, ntm21, ntm22;
468 char fontName[500], fontSize[100];
473 // compute size and normalized transform matrix
474 size = sqrt(m21*m21 + m22*m22);
480 // try to get a rotated font?
481 rotated = !(ntm11 > 0 && ntm22 > 0 &&
482 fabs(ntm11 / ntm22 - 1) < 0.2 &&
483 fabs(ntm12) < 0.01 &&
486 // open X font -- if font is not found (which means the server can't
487 // scale fonts), try progressively smaller and then larger sizes
488 startSize = (int)size;
490 sprintf(fontSize, "[%s%0.2f %s%0.2f %s%0.2f %s%0.2f]",
491 ntm11<0 ? "~" : "", fabs(ntm11 * size),
492 ntm12<0 ? "~" : "", fabs(ntm12 * size),
493 ntm21<0 ? "~" : "", fabs(ntm21 * size),
494 ntm22<0 ? "~" : "", fabs(ntm22 * size));
496 sprintf(fontSize, "%d", startSize);
498 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize);
499 xFont = XLoadQueryFont(display, fontName);
501 for (sz = startSize; sz >= startSize/2 && sz >= 1; --sz) {
502 sprintf(fontSize, "%d", sz);
503 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize);
504 if ((xFont = XLoadQueryFont(display, fontName)))
508 for (sz = startSize + 1; sz < startSize + 10; ++sz) {
509 sprintf(fontSize, "%d", sz);
510 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(),
512 if ((xFont = XLoadQueryFont(display, fontName))) {
517 sprintf(fontSize, "%d", startSize);
518 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(),
520 error(-1, "Failed to open font: '%s'", fontName);
527 XOutputServer16BitFont::~XOutputServer16BitFont() {
530 XFreeFont(display, xFont);
534 GBool XOutputServer16BitFont::isOk() {
535 return xFont != NULL;
538 void XOutputServer16BitFont::updateGC(GC gc) {
539 XSetFont(display, gc, xFont->fid);
542 void XOutputServer16BitFont::drawChar(GfxState *state, Pixmap pixmap,
543 int w, int h, GC gc, GfxRGB *rgb,
544 double x, double y, double dx, double dy,
545 CharCode c, Unicode *u, int uLen) {
552 for (i = 0; i < uLen; ++i) {
553 n += xUMap->mapUnicode(u[i], buf, sizeof(buf));
559 for (i = 0; i < uLen; ++i) {
560 m = xUMap->mapUnicode(u[i], buf, sizeof(buf));
561 for (j = 0; j+1 < m; j += 2) {
564 XDrawString16(display, pixmap, gc,
565 xoutRound(x + k*dx1), xoutRound(y + k*dy1),
571 // some PDF files use CID 0, which is .notdef, so just ignore it
572 error(-1, "Unknown character (CID=%d Unicode=%04x)",
573 c, uLen > 0 ? u[0] : (Unicode)0);
577 //------------------------------------------------------------------------
579 //------------------------------------------------------------------------
582 XOutputT1FontFile::~XOutputT1FontFile() {
587 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
588 XOutputFTFontFile::~XOutputFTFontFile() {
593 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
594 XOutputTTFontFile::~XOutputTTFontFile() {
599 XOutputFontCache::XOutputFontCache(Display *displayA, Guint depthA,
601 FontRastControl t1libControlA,
602 FontRastControl freetypeControlA) {
609 t1libControl = t1libControlA;
612 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
615 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
618 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
619 freetypeControl = freetypeControlA;
625 XOutputFontCache::~XOutputFontCache() {
629 void XOutputFontCache::startDoc(int screenNum, Colormap colormap,
631 int rMul, int gMul, int bMul,
632 int rShift, int gShift, int bShift,
633 Gulong *colors, int numColors) {
638 if (t1libControl != fontRastNone) {
639 t1Engine = new T1FontEngine(display, DefaultVisual(display, screenNum),
641 t1libControl == fontRastAALow ||
642 t1libControl == fontRastAAHigh,
643 t1libControl == fontRastAAHigh);
644 if (t1Engine->isOk()) {
646 t1Engine->useTrueColor(rMul, rShift, gMul, gShift, bMul, bShift);
648 t1Engine->useColorCube(colors, numColors);
655 #endif // HAVE_T1LIB_H
657 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
658 if (freetypeControl != fontRastNone) {
659 ftEngine = new FTFontEngine(display, DefaultVisual(display, screenNum),
661 freetypeControl == fontRastAALow ||
662 freetypeControl == fontRastAAHigh);
663 if (ftEngine->isOk()) {
665 ftEngine->useTrueColor(rMul, rShift, gMul, gShift, bMul, bShift);
667 ftEngine->useColorCube(colors, numColors);
674 #endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
676 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
677 if (freetypeControl != fontRastNone) {
678 ttEngine = new TTFontEngine(display, DefaultVisual(display, screenNum),
680 freetypeControl == fontRastAALow ||
681 freetypeControl == fontRastAAHigh);
682 if (ttEngine->isOk()) {
684 ttEngine->useTrueColor(rMul, rShift, gMul, gShift, bMul, bShift);
686 ttEngine->useColorCube(colors, numColors);
693 #endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
696 void XOutputFontCache::delFonts() {
699 for (i = 0; i < nFonts; ++i) {
704 // delete Type 1 font files
705 deleteGList(t1FontFiles, XOutputT1FontFile);
711 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
712 // delete FreeType font files
713 deleteGList(ftFontFiles, XOutputFTFontFile);
719 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
720 // delete TrueType fonts
721 deleteGList(ttFontFiles, XOutputTTFontFile);
728 void XOutputFontCache::clear() {
731 for (i = 0; i < xOutFontCacheSize; ++i) {
737 // clear Type 1 font files
738 t1FontFiles = new GList();
741 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
742 // clear FreeType font cache
743 ftFontFiles = new GList();
746 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
747 // clear TrueType font cache
748 ttFontFiles = new GList();
752 XOutputFont *XOutputFontCache::getFont(XRef *xref, GfxFont *gfxFont,
753 double m11, double m12,
754 double m21, double m22) {
756 DisplayFontParam *dfp;
758 double m11New, m12New, m21New, m22New;
766 // is it the most recently used font?
767 if (nFonts > 0 && fonts[0]->matches(gfxFont->getID(), m11, m12, m21, m22)) {
771 // is it in the cache?
772 for (i = 1; i < nFonts; ++i) {
773 if (fonts[i]->matches(gfxFont->getID(), m11, m12, m21, m22)) {
775 for (j = i; j > 0; --j) {
776 fonts[j] = fonts[j-1];
783 // try for a cached FontFile, an embedded font, or an external font
786 switch (gfxFont->getType()) {
790 if (t1libControl != fontRastNone) {
791 font = tryGetT1Font(xref, gfxFont, m11, m12, m21, m22);
794 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
796 if (freetypeControl != fontRastNone) {
797 font = tryGetFTFont(xref, gfxFont, m11, m12, m21, m22);
804 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
805 if (freetypeControl != fontRastNone) {
806 font = tryGetFTFont(xref, gfxFont, m11, m12, m21, m22);
809 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
810 if (freetypeControl != fontRastNone) {
811 font = tryGetTTFont(xref, gfxFont, m11, m12, m21, m22);
816 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
817 if (freetypeControl != fontRastNone) {
818 font = tryGetFTFont(xref, gfxFont, m11, m12, m21, m22);
828 // search for a display font mapping
830 if (gfxFont->isCIDFont()) {
831 if (((GfxCIDFont *)gfxFont)->getCollection()) {
833 getDisplayCIDFont(gfxFont->getName(),
834 ((GfxCIDFont *)gfxFont)->getCollection());
836 // this error (no CMap file) was already reported by GfxFont
840 if (gfxFont->getName()) {
841 dfp = globalParams->getDisplayFont(gfxFont->getName());
845 font = tryGetFont(xref, dfp, gfxFont, m11, m12, m21, m22,
846 m11, m12, m21, m22, gFalse);
849 // substitute a font (8-bit fonts only)
850 if (!font && !gfxFont->isCIDFont()) {
852 // choose a substitute font
853 if (gfxFont->isFixedWidth()) {
855 } else if (gfxFont->isSerif()) {
860 if (gfxFont->isBold()) {
863 if (gfxFont->isItalic()) {
866 substName = new GString(xOutSubstFonts[index].name);
868 // adjust the font matrix -- compare the width of 'm' in the
869 // original font and the substituted font
874 for (code = 0; code < 256; ++code) {
875 if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
876 name[0] == 'm' && name[1] == '\0') {
881 w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
882 w2 = xOutSubstFonts[index].mWidth;
883 if (gfxFont->getType() == fontType3) {
884 // This is a hack which makes it possible to substitute for some
885 // Type 3 fonts. The problem is that it's impossible to know what
886 // the base coordinate system used in the font is without actually
887 // rendering the font. This code tries to guess by looking at the
888 // width of the character 'm' (which breaks if the font is a
889 // subset that doesn't contain 'm').
890 if (w1 > 0 && (w1 > 1.1 * w2 || w1 < 0.9 * w2)) {
897 fm = gfxFont->getFontMatrix();
898 v = (fm[0] == 0) ? 1 : (fm[3] / fm[0]);
901 } else if (!gfxFont->isSymbolic()) {
902 // if real font is substantially narrower than substituted
903 // font, reduce the font size accordingly
904 if (w1 > 0.01 && w1 < 0.9 * w2) {
913 dfp = globalParams->getDisplayFont(substName);
916 // this should never happen since GlobalParams sets up default
917 // mappings for the Base-14 fonts
918 error(-1, "Couldn't find a font for '%s'",
919 gfxFont->getName()->getCString());
922 font = tryGetFont(xref, dfp, gfxFont, m11, m12, m21, m22,
923 m11New, m12New, m21New, m22New, gTrue);
929 // This will happen if the user specifies a bogus font in the
930 // config file (a non-existent font file or a font that requires a
931 // rasterizer that is disabled or wasn't built in), or if a CID
932 // font has no associated font in the config file.
933 if (gfxFont->isCIDFont()) {
934 error(-1, "Couldn't find a font for the '%s' character collection",
935 ((GfxCIDFont *)gfxFont)->getCollection()->getCString());
937 error(-1, "Couldn't find a font for '%s'",
939 gfxFont->getName()->getCString() : "[unnamed]");
944 // insert font in cache
945 if (nFonts == xOutFontCacheSize) {
947 delete fonts[nFonts];
949 for (j = nFonts; j > 0; --j) {
950 fonts[j] = fonts[j-1];
958 XOutputFont *XOutputFontCache::tryGetFont(XRef *xref, DisplayFontParam *dfp,
960 double m11Orig, double m12Orig,
961 double m21Orig, double m22Orig,
962 double m11, double m12,
963 double m21, double m22,
969 // create the new font
973 font = tryGetServerFont(dfp->x.xlfd, dfp->x.encoding, gfxFont,
974 m11Orig, m12Orig, m21Orig, m22Orig,
980 if (t1libControl != fontRastNone) {
981 font = tryGetT1FontFromFile(xref, dfp->t1.fileName, gfxFont,
982 m11Orig, m12Orig, m21Orig, m22Orig,
983 m11, m12, m21, m22, subst);
986 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
988 if (freetypeControl != fontRastNone) {
989 font = tryGetFTFontFromFile(xref, dfp->t1.fileName, gfxFont,
990 m11Orig, m12Orig, m21Orig, m22Orig,
991 m11, m12, m21, m22, subst);
995 #if !((FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)) || defined(HAVE_T1LIB_H))
996 error(-1, "Config file specifies a Type 1 font,");
997 error(-1, "but xpdf was not built with t1lib or FreeType2 support");
1002 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1003 if (freetypeControl != fontRastNone) {
1004 font = tryGetFTFontFromFile(xref, dfp->tt.fileName, gfxFont,
1005 m11Orig, m12Orig, m21Orig, m22Orig,
1006 m11, m12, m21, m22, subst);
1009 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1010 if (freetypeControl != fontRastNone) {
1011 font = tryGetTTFontFromFile(xref, dfp->tt.fileName, gfxFont,
1012 m11Orig, m12Orig, m21Orig, m22Orig,
1013 m11, m12, m21, m22, subst);
1016 #if !(HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1017 error(-1, "Config file specifies a TrueType font,");
1018 error(-1, "but xpdf was not built with FreeType support");
1028 XOutputFont *XOutputFontCache::tryGetT1Font(XRef *xref,
1030 double m11, double m12,
1031 double m21, double m22) {
1033 XOutputT1FontFile *xFontFile;
1041 Object refObj, strObj;
1045 // check the already available font files
1046 id = gfxFont->getID();
1047 for (i = 0; i < t1FontFiles->getLength(); ++i) {
1048 xFontFile = (XOutputT1FontFile *)t1FontFiles->get(i);
1049 if (xFontFile->num == id->num && xFontFile->gen == id->gen &&
1050 !xFontFile->subst) {
1051 font = new XOutputT1Font(id, xFontFile->fontFile,
1053 m11, m12, m21, m22, display, xOut);
1054 if (!font->isOk()) {
1062 // check for an embedded font
1063 if (gfxFont->getEmbeddedFontID(&embRef)) {
1065 // create the font file
1067 if (!openTempFile(&fileName, &f, "wb", NULL)) {
1068 error(-1, "Couldn't create temporary Type 1 font file");
1071 if (gfxFont->getType() == fontType1C) {
1072 if (!(fontBuf = gfxFont->readEmbFontFile(xref, &fontLen))) {
1076 ff = new Type1CFontFile(fontBuf, fontLen);
1077 ff->convertToType1(f);
1080 } else { // fontType1
1081 refObj.initRef(embRef.num, embRef.gen);
1082 refObj.fetch(xref, &strObj);
1084 strObj.streamReset();
1085 while ((c = strObj.streamGetChar()) != EOF) {
1088 strObj.streamClose();
1094 font = tryGetT1FontFromFile(xref, fileName, gfxFont,
1096 m11, m12, m21, m22, gFalse);
1098 // remove the temporary file
1099 unlink(fileName->getCString());
1102 // check for an external font file
1103 } else if ((fileName = gfxFont->getExtFontFile())) {
1104 font = tryGetT1FontFromFile(xref, fileName, gfxFont,
1106 m11, m12, m21, m22, gFalse);
1115 XOutputFont *XOutputFontCache::tryGetT1FontFromFile(XRef *xref,
1122 double m11, double m12,
1123 double m21, double m22,
1126 T1FontFile *fontFile;
1129 // create the t1lib font file
1130 fontFile = new T1FontFile(t1Engine, fileName->getCString(),
1131 ((Gfx8BitFont *)gfxFont)->getEncoding(),
1132 gfxFont->getFontBBox());
1133 if (!fontFile->isOk()) {
1134 error(-1, "Couldn't create t1lib font from '%s'",
1135 fileName->getCString());
1141 id = gfxFont->getID();
1142 t1FontFiles->append(new XOutputT1FontFile(id->num, id->gen,
1146 font = new XOutputT1Font(gfxFont->getID(), fontFile,
1147 m11Orig, m12Orig, m21Orig, m22Orig,
1148 m11, m12, m21, m22, display, xOut);
1149 if (!font->isOk()) {
1155 #endif // HAVE_T1LIB_H
1157 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1158 XOutputFont *XOutputFontCache::tryGetFTFont(XRef *xref,
1160 double m11, double m12,
1161 double m21, double m22) {
1163 XOutputFTFontFile *xFontFile;
1168 #if 1 //~ need this until FT can handle fonts with missing tables
1171 TrueTypeFontFile *ff;
1173 Object refObj, strObj;
1177 // check the already available font files
1178 id = gfxFont->getID();
1179 for (i = 0; i < ftFontFiles->getLength(); ++i) {
1180 xFontFile = (XOutputFTFontFile *)ftFontFiles->get(i);
1181 if (xFontFile->num == id->num && xFontFile->gen == id->gen &&
1182 !xFontFile->subst) {
1183 font = new XOutputFTFont(id, xFontFile->fontFile,
1185 m11, m12, m21, m22, display, xOut);
1186 if (!font->isOk()) {
1194 // check for an embedded font
1195 if (gfxFont->getEmbeddedFontID(&embRef)) {
1197 // create the font file
1199 if (!openTempFile(&fileName, &f, "wb", NULL)) {
1200 error(-1, "Couldn't create temporary TrueType font file");
1203 #if 1 //~ need this until FT can handle fonts with missing tables
1204 if (gfxFont->getType() == fontTrueType ||
1205 gfxFont->getType() == fontCIDType2) {
1206 if (!(fontBuf = gfxFont->readEmbFontFile(xref, &fontLen))) {
1210 ff = new TrueTypeFontFile(fontBuf, fontLen);
1215 refObj.initRef(embRef.num, embRef.gen);
1216 refObj.fetch(xref, &strObj);
1218 strObj.streamReset();
1219 while ((c = strObj.streamGetChar()) != EOF) {
1222 strObj.streamClose();
1226 refObj.initRef(embRef.num, embRef.gen);
1227 refObj.fetch(xref, &strObj);
1229 strObj.streamReset();
1230 while ((c = strObj.streamGetChar()) != EOF) {
1233 strObj.streamClose();
1239 font = tryGetFTFontFromFile(xref, fileName, gfxFont,
1241 m11, m12, m21, m22, gFalse);
1243 // remove the temporary file
1244 unlink(fileName->getCString());
1247 // check for an external font file
1248 } else if ((fileName = gfxFont->getExtFontFile())) {
1249 font = tryGetFTFontFromFile(xref, fileName, gfxFont,
1251 m11, m12, m21, m22, gFalse);
1260 XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref,
1267 double m11, double m12,
1268 double m21, double m22,
1271 FTFontFile *fontFile;
1274 // create the FreeType font file
1275 if (gfxFont->isCIDFont()) {
1276 if (gfxFont->getType() == fontCIDType2) {
1277 fontFile = new FTFontFile(ftEngine, fileName->getCString(),
1278 ((GfxCIDFont *)gfxFont)->getCIDToGID(),
1279 ((GfxCIDFont *)gfxFont)->getCIDToGIDLen());
1280 } else { // fontCIDType0C
1281 fontFile = new FTFontFile(ftEngine, fileName->getCString());
1284 fontFile = new FTFontFile(ftEngine, fileName->getCString(),
1285 ((Gfx8BitFont *)gfxFont)->getEncoding(),
1286 ((Gfx8BitFont *)gfxFont)->getHasEncoding());
1288 if (!fontFile->isOk()) {
1289 error(-1, "Couldn't create FreeType font from '%s'",
1290 fileName->getCString());
1296 id = gfxFont->getID();
1297 ftFontFiles->append(new XOutputFTFontFile(id->num, id->gen,
1301 font = new XOutputFTFont(gfxFont->getID(), fontFile,
1302 m11Orig, m12Orig, m21Orig, m22Orig,
1303 m11, m12, m21, m22, display, xOut);
1304 if (!font->isOk()) {
1310 #endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1312 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1313 XOutputFont *XOutputFontCache::tryGetTTFont(XRef *xref,
1315 double m11, double m12,
1316 double m21, double m22) {
1318 XOutputTTFontFile *xFontFile;
1323 Object refObj, strObj;
1327 // check the already available font files
1328 id = gfxFont->getID();
1330 for (i = 0; i < ttFontFiles->getLength(); ++i) {
1331 xFontFile = (XOutputTTFontFile *)ttFontFiles->get(i);
1332 if (xFontFile->num == id->num && xFontFile->gen == id->gen &&
1333 !xFontFile->subst) {
1334 font = new XOutputTTFont(id, xFontFile->fontFile,
1336 m11, m12, m21, m22, display, xOut);
1337 if (!font->isOk()) {
1345 // check for an embedded font
1346 if (gfxFont->getEmbeddedFontID(&embRef)) {
1348 // create the font file
1350 if (!openTempFile(&fileName, &f, "wb", NULL)) {
1351 error(-1, "Couldn't create temporary TrueType font file");
1354 refObj.initRef(embRef.num, embRef.gen);
1355 refObj.fetch(xref, &strObj);
1357 strObj.streamReset();
1358 while ((c = strObj.streamGetChar()) != EOF) {
1361 strObj.streamClose();
1366 font = tryGetTTFontFromFile(xref, fileName, gfxFont,
1368 m11, m12, m21, m22, gFalse);
1370 // remove the temporary file
1371 unlink(fileName->getCString());
1374 } else if ((fileName = gfxFont->getExtFontFile())) {
1375 font = tryGetTTFontFromFile(xref, fileName, gfxFont,
1377 m11, m12, m21, m22, gFalse);
1386 XOutputFont *XOutputFontCache::tryGetTTFontFromFile(XRef *xref,
1393 double m11, double m12,
1394 double m21, double m22,
1397 TTFontFile *fontFile;
1400 // create the FreeType font file
1401 if (gfxFont->isCIDFont()) {
1403 fontFile = new TTFontFile(ttEngine, fileName->getCString(),
1404 ((GfxCIDFont *)gfxFont)->getCIDToGID(),
1405 ((GfxCIDFont *)gfxFont)->getCIDToGIDLen());
1407 fontFile = new TTFontFile(ttEngine, fileName->getCString(),
1408 ((Gfx8BitFont *)gfxFont)->getEncoding(),
1409 ((Gfx8BitFont *)gfxFont)->getHasEncoding());
1411 if (!fontFile->isOk()) {
1412 error(-1, "Couldn't create FreeType font from '%s'",
1413 fileName->getCString());
1419 id = gfxFont->getID();
1420 ttFontFiles->append(new XOutputTTFontFile(id->num, id->gen,
1424 font = new XOutputTTFont(gfxFont->getID(), fontFile,
1425 m11Orig, m12Orig, m21Orig, m22Orig,
1426 m11, m12, m21, m22, display, xOut);
1427 if (!font->isOk()) {
1433 #endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
1435 XOutputFont *XOutputFontCache::tryGetServerFont(GString *xlfd,
1436 GString *encodingName,
1438 double m11Orig, double m12Orig,
1439 double m21Orig, double m22Orig,
1440 double m11, double m12,
1441 double m21, double m22) {
1444 CharCodeToUnicode *ctu;
1446 uMap = globalParams->getUnicodeMap(encodingName);
1447 if (gfxFont->isCIDFont()) {
1448 ctu = ((GfxCIDFont *)gfxFont)->getToUnicode();
1449 font = new XOutputServer16BitFont(gfxFont->getID(), xlfd, uMap, ctu,
1450 m11Orig, m12Orig, m21Orig, m22Orig,
1455 ctu = ((Gfx8BitFont *)gfxFont)->getToUnicode();
1456 font = new XOutputServer8BitFont(gfxFont->getID(), xlfd, uMap, ctu,
1457 m11Orig, m12Orig, m21Orig, m22Orig,
1463 if (!font->isOk()) {
1470 //------------------------------------------------------------------------
1472 //------------------------------------------------------------------------
1474 struct T3FontCacheTag {
1476 Gushort mru; // valid bit (0x8000) and MRU index
1477 double wx, wy; // untransformed glyph metrics
1483 T3FontCache(Ref *fontID, double m11A, double m12A,
1484 double m21A, double m22A,
1485 int glyphXA, int glyphYA, int glyphWA, int glyphHA,
1486 Display *displayA, Visual *visual, Guint depth,
1489 GBool matches(Ref *idA, double m11A, double m12A,
1490 double m21A, double m22A)
1491 { return fontID.num == idA->num && fontID.gen == idA->gen &&
1492 m11 == m11A && m12 == m12A && m21 == m21A && m22 == m22A; }
1494 Ref fontID; // PDF font ID
1495 double m11, m12, m21, m22; // transform matrix
1496 int glyphX, glyphY; // pixel offset of glyph pixmaps
1497 int glyphW, glyphH; // size of glyph pixmaps, in pixels
1498 int glyphSize; // size of glyph pixmaps, in bytes
1499 int cacheSets; // number of sets in cache
1500 int cacheAssoc; // cache associativity (glyphs per set)
1501 Guchar *cacheData; // glyph pixmap cache
1502 T3FontCacheTag *cacheTags; // cache tags, i.e., char codes
1508 T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A,
1509 double m21A, double m22A,
1510 int glyphXA, int glyphYA, int glyphWA, int glyphHA,
1511 Display *displayA, Visual *visual, Guint depth,
1512 Pixmap origPixmap) {
1524 glyphSize = glyphW * glyphH;
1526 if (glyphSize <= 256) {
1528 } else if (glyphSize <= 512) {
1530 } else if (glyphSize <= 1024) {
1535 cacheData = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize);
1536 cacheTags = (T3FontCacheTag *)gmalloc(cacheSets * cacheAssoc *
1537 sizeof(T3FontCacheTag));
1538 for (i = 0; i < cacheSets * cacheAssoc; ++i) {
1539 cacheTags[i].mru = i & (cacheAssoc - 1);
1542 pixmap = XCreatePixmap(display, origPixmap, glyphW, glyphH, depth);
1543 image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL,
1544 glyphW, glyphH, 8, 0);
1545 image->data = (char *)gmalloc(glyphH * image->bytes_per_line);
1548 T3FontCache::~T3FontCache() {
1551 XFreePixmap(display, pixmap);
1554 XDestroyImage(image);
1557 struct T3GlyphStack {
1562 T3FontCacheTag *cacheTag;
1568 int origPixmapW, origPixmapH;
1572 Region origClipRegion;
1573 double wx, wy; // untransformed glyph metrics
1577 //------------------------------------------------------------------------
1579 //------------------------------------------------------------------------
1581 XOutputDev::XOutputDev(Display *displayA, Pixmap pixmapA, Guint depthA,
1582 Colormap colormapA, GBool reverseVideoA,
1583 unsigned long paperColor, GBool installCmap,
1585 XVisualInfo visualTempl;
1586 XVisualInfo *visualList;
1592 int r, g, b, n, m, i;
1597 // get display/pixmap info
1599 screenNum = DefaultScreen(display);
1602 colormap = colormapA;
1604 // check for TrueColor visual
1607 depth = DefaultDepth(display, screenNum);
1608 visualList = XGetVisualInfo(display, 0, &visualTempl, &nVisuals);
1609 for (i = 0; i < nVisuals; ++i) {
1610 if (visualList[i].visual == DefaultVisual(display, screenNum)) {
1611 if (visualList[i].c_class == TrueColor) {
1613 for (mask = visualList[i].red_mask, rShift = 0;
1614 mask && !(mask & 1);
1615 mask >>= 1, ++rShift) ;
1617 for (mask = visualList[i].green_mask, gShift = 0;
1618 mask && !(mask & 1);
1619 mask >>= 1, ++gShift) ;
1621 for (mask = visualList[i].blue_mask, bShift = 0;
1622 mask && !(mask & 1);
1623 mask >>= 1, ++bShift) ;
1629 XFree((XPointer)visualList);
1632 // allocate a color cube
1634 redMap[BlackPixel(display, screenNum) & 0xff] = 0;
1635 redMap[WhitePixel(display, screenNum) & 0xff] = 1;
1637 // set colors in private colormap
1639 for (numColors = 6; numColors >= 2; --numColors) {
1640 m = numColors * numColors * numColors;
1641 if (XAllocColorCells(display, colormap, False, NULL, 0, colors, m)) {
1645 if (numColors >= 2) {
1646 m = numColors * numColors * numColors;
1647 xcolors = (XColor *)gmalloc(m * sizeof(XColor));
1649 for (r = 0; r < numColors; ++r) {
1650 for (g = 0; g < numColors; ++g) {
1651 for (b = 0; b < numColors; ++b) {
1652 xcolors[n].pixel = colors[n];
1653 xcolors[n].red = (r * 65535) / (numColors - 1);
1654 xcolors[n].green = (g * 65535) / (numColors - 1);
1655 xcolors[n].blue = (b * 65535) / (numColors - 1);
1656 xcolors[n].flags = DoRed | DoGreen | DoBlue;
1657 redMap[xcolors[n].pixel & 0xff] = xcolors[n].red / 65535.0;
1662 XStoreColors(display, colormap, xcolors, m);
1666 colors[0] = BlackPixel(display, screenNum);
1667 colors[1] = WhitePixel(display, screenNum);
1670 // allocate colors in shared colormap
1672 if (rgbCubeSize > maxRGBCube) {
1673 rgbCubeSize = maxRGBCube;
1676 for (numColors = rgbCubeSize; numColors >= 2; --numColors) {
1679 for (r = 0; r < numColors && ok; ++r) {
1680 for (g = 0; g < numColors && ok; ++g) {
1681 for (b = 0; b < numColors && ok; ++b) {
1683 colors[n] = BlackPixel(display, screenNum);
1684 redMap[colors[n] & 0xff] = 0;
1687 xcolor.red = (r * 65535) / (numColors - 1);
1688 xcolor.green = (g * 65535) / (numColors - 1);
1689 xcolor.blue = (b * 65535) / (numColors - 1);
1690 if (XAllocColor(display, colormap, &xcolor)) {
1691 colors[n++] = xcolor.pixel;
1692 redMap[xcolor.pixel & 0xff] = xcolor.red / 65535.0;
1703 XFreeColors(display, colormap, &colors[1], n-1, 0);
1707 colors[0] = BlackPixel(display, screenNum);
1708 colors[1] = WhitePixel(display, screenNum);
1713 // reverse video mode
1714 reverseVideo = reverseVideoA;
1717 gcValues.foreground = BlackPixel(display, screenNum);
1718 gcValues.background = WhitePixel(display, screenNum);
1719 gcValues.line_width = 0;
1720 gcValues.line_style = LineSolid;
1721 strokeGC = XCreateGC(display, pixmap,
1722 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
1724 fillGC = XCreateGC(display, pixmap,
1725 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
1727 gcValues.foreground = paperColor;
1728 paperGC = XCreateGC(display, pixmap,
1729 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
1732 // no clip region yet
1735 // set up the font cache and fonts
1738 fontCache = new XOutputFontCache(display, depth, this,
1739 globalParams->getT1libControl(),
1740 globalParams->getFreeTypeControl());
1742 t3GlyphStack = NULL;
1744 // empty state stack
1747 // create text object
1748 text = new TextPage(gFalse);
1751 XOutputDev::~XOutputDev() {
1755 for (i = 0; i < nT3Fonts; ++i) {
1756 delete t3FontCache[i];
1758 XFreeGC(display, strokeGC);
1759 XFreeGC(display, fillGC);
1760 XFreeGC(display, paperGC);
1762 XDestroyRegion(clipRegion);
1767 void XOutputDev::startDoc(XRef *xrefA) {
1771 fontCache->startDoc(screenNum, colormap, trueColor, rMul, gMul, bMul,
1772 rShift, gShift, bShift, colors, numColors);
1773 for (i = 0; i < nT3Fonts; ++i) {
1774 delete t3FontCache[i];
1779 void XOutputDev::startPage(int pageNum, GfxState *state) {
1784 // clear state stack
1788 XFreeGC(display, s->strokeGC);
1789 XFreeGC(display, s->fillGC);
1790 XDestroyRegion(s->clipRegion);
1795 // default line flatness
1799 gcValues.foreground = BlackPixel(display, screenNum);
1800 gcValues.background = WhitePixel(display, screenNum);
1801 gcValues.line_width = 0;
1802 gcValues.line_style = LineSolid;
1803 XChangeGC(display, strokeGC,
1804 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
1806 XChangeGC(display, fillGC,
1807 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
1810 // clear clipping region
1812 XDestroyRegion(clipRegion);
1813 clipRegion = XCreateRegion();
1814 rect.x = rect.y = 0;
1815 rect.width = pixmapW;
1816 rect.height = pixmapH;
1817 XUnionRectWithRegion(&rect, clipRegion, clipRegion);
1818 XSetRegion(display, strokeGC, clipRegion);
1819 XSetRegion(display, fillGC, clipRegion);
1826 XFillRectangle(display, pixmap, paperGC, 0, 0, pixmapW, pixmapH);
1828 // clear text object
1832 void XOutputDev::endPage() {
1836 void XOutputDev::drawLink(Link *link, Catalog *catalog) {
1837 double x1, y1, x2, y2, w;
1842 link->getBorder(&x1, &y1, &x2, &y2, &w);
1847 XSetForeground(display, strokeGC, findColor(&rgb));
1848 XSetLineAttributes(display, strokeGC, xoutRound(w),
1849 LineSolid, CapRound, JoinRound);
1850 cvtUserToDev(x1, y1, &x, &y);
1851 points[0].x = points[4].x = x;
1852 points[0].y = points[4].y = y;
1853 cvtUserToDev(x2, y1, &x, &y);
1856 cvtUserToDev(x2, y2, &x, &y);
1859 cvtUserToDev(x1, y2, &x, &y);
1862 XDrawLines(display, pixmap, strokeGC, points, 5, CoordModeOrigin);
1866 void XOutputDev::saveState(GfxState *state) {
1870 // save current state
1871 s = new XOutputState;
1872 s->strokeGC = strokeGC;
1874 s->clipRegion = clipRegion;
1876 // push onto state stack
1880 // create a new current state by copying
1881 strokeGC = XCreateGC(display, pixmap, 0, &values);
1882 XCopyGC(display, s->strokeGC, 0xffffffff, strokeGC);
1883 fillGC = XCreateGC(display, pixmap, 0, &values);
1884 XCopyGC(display, s->fillGC, 0xffffffff, fillGC);
1885 clipRegion = XCreateRegion();
1886 XUnionRegion(s->clipRegion, clipRegion, clipRegion);
1887 XSetRegion(display, strokeGC, clipRegion);
1888 XSetRegion(display, fillGC, clipRegion);
1891 void XOutputDev::restoreState(GfxState *state) {
1895 // kill current state
1896 XFreeGC(display, strokeGC);
1897 XFreeGC(display, fillGC);
1898 XDestroyRegion(clipRegion);
1901 flatness = state->getFlatness();
1902 strokeGC = save->strokeGC;
1903 fillGC = save->fillGC;
1904 clipRegion = save->clipRegion;
1905 XSetRegion(display, strokeGC, clipRegion);
1906 XSetRegion(display, fillGC, clipRegion);
1915 void XOutputDev::updateAll(GfxState *state) {
1916 updateLineAttrs(state, gTrue);
1917 updateFlatness(state);
1918 updateMiterLimit(state);
1919 updateFillColor(state);
1920 updateStrokeColor(state);
1924 void XOutputDev::updateCTM(GfxState *state, double m11, double m12,
1925 double m21, double m22, double m31, double m32) {
1926 updateLineAttrs(state, gTrue);
1929 void XOutputDev::updateLineDash(GfxState *state) {
1930 updateLineAttrs(state, gTrue);
1933 void XOutputDev::updateFlatness(GfxState *state) {
1934 flatness = state->getFlatness();
1937 void XOutputDev::updateLineJoin(GfxState *state) {
1938 updateLineAttrs(state, gFalse);
1941 void XOutputDev::updateLineCap(GfxState *state) {
1942 updateLineAttrs(state, gFalse);
1946 void XOutputDev::updateMiterLimit(GfxState *state) {
1949 void XOutputDev::updateLineWidth(GfxState *state) {
1950 updateLineAttrs(state, gFalse);
1953 void XOutputDev::updateLineAttrs(GfxState *state, GBool updateDash) {
1956 double *dashPattern;
1962 width = state->getTransformedLineWidth();
1963 switch (state->getLineCap()) {
1964 case 0: cap = CapButt; break;
1965 case 1: cap = CapRound; break;
1966 case 2: cap = CapProjecting; break;
1968 error(-1, "Bad line cap style (%d)", state->getLineCap());
1972 switch (state->getLineJoin()) {
1973 case 0: join = JoinMiter; break;
1974 case 1: join = JoinRound; break;
1975 case 2: join = JoinBevel; break;
1977 error(-1, "Bad line join style (%d)", state->getLineJoin());
1981 state->getLineDash(&dashPattern, &dashLength, &dashStart);
1982 #if 1 //~ work around a bug in XFree86 (???)
1983 if (dashLength > 0 && cap == CapProjecting) {
1987 XSetLineAttributes(display, strokeGC, xoutRound(width),
1988 dashLength > 0 ? LineOnOffDash : LineSolid,
1990 if (updateDash && dashLength > 0) {
1991 if (dashLength > 20)
1993 for (i = 0; i < dashLength; ++i) {
1994 dashList[i] = xoutRound(state->transformWidth(dashPattern[i]));
1995 if (dashList[i] == 0)
1998 XSetDashes(display, strokeGC, xoutRound(dashStart), dashList, dashLength);
2002 void XOutputDev::updateFillColor(GfxState *state) {
2005 state->getFillRGB(&rgb);
2011 XSetForeground(display, fillGC, findColor(&rgb));
2014 void XOutputDev::updateStrokeColor(GfxState *state) {
2017 state->getStrokeRGB(&rgb);
2023 XSetForeground(display, strokeGC, findColor(&rgb));
2026 void XOutputDev::updateFont(GfxState *state) {
2027 double m11, m12, m21, m22;
2029 if (!(gfxFont = state->getFont())) {
2033 if (gfxFont->getType() == fontType3) {
2037 state->getFontTransMat(&m11, &m12, &m21, &m22);
2038 m11 *= state->getHorizScaling();
2039 m12 *= state->getHorizScaling();
2040 font = fontCache->getFont(xref, gfxFont, m11, m12, m21, m22);
2042 font->updateGC(fillGC);
2043 font->updateGC(strokeGC);
2046 text->updateFont(state);
2049 void XOutputDev::stroke(GfxState *state) {
2052 int n, size, numPoints, i, j;
2055 n = convertPath(state, &points, &size, &numPoints, &lengths, gFalse);
2057 // draw each subpath
2059 for (i = 0; i < n; ++i) {
2060 XDrawLines(display, pixmap, strokeGC, points + j, lengths[i],
2065 // free points and lengths arrays
2066 if (points != tmpPoints)
2068 if (lengths != tmpLengths)
2072 void XOutputDev::fill(GfxState *state) {
2073 doFill(state, WindingRule);
2076 void XOutputDev::eoFill(GfxState *state) {
2077 doFill(state, EvenOddRule);
2081 // X doesn't color the pixels on the right-most and bottom-most
2082 // borders of a polygon. This means that one-pixel-thick polygons
2083 // are not colored at all. I think this is supposed to be a
2084 // feature, but I can't figure out why. So after it fills a
2085 // polygon, it also draws lines around the border. This is done
2086 // only for single-component polygons, since it's not very
2087 // compatible with the compound polygon kludge (see convertPath()).
2089 void XOutputDev::doFill(GfxState *state, int rule) {
2092 int n, size, numPoints, i, j;
2095 XSetFillRule(display, fillGC, rule);
2097 // transform points, build separate polygons
2098 n = convertPath(state, &points, &size, &numPoints, &lengths, gTrue);
2102 for (i = 0; i < n; ++i) {
2103 XFillPolygon(display, pixmap, fillGC, points + j, lengths[i],
2104 Complex, CoordModeOrigin);
2105 if (state->getPath()->getNumSubpaths() == 1) {
2106 XDrawLines(display, pixmap, fillGC, points + j, lengths[i],
2109 j += lengths[i] + 1;
2112 // free points and lengths arrays
2113 if (points != tmpPoints)
2115 if (lengths != tmpLengths)
2119 void XOutputDev::clip(GfxState *state) {
2120 doClip(state, WindingRule);
2123 void XOutputDev::eoClip(GfxState *state) {
2124 doClip(state, EvenOddRule);
2127 void XOutputDev::doClip(GfxState *state, int rule) {
2128 Region region, region2;
2131 int n, size, numPoints, i, j;
2133 // transform points, build separate polygons
2134 n = convertPath(state, &points, &size, &numPoints, &lengths, gTrue);
2136 // construct union of subpath regions
2137 // (XPolygonRegion chokes if there aren't at least three points --
2138 // this happens if the PDF file does moveto/closepath/clip, which
2139 // sets an empty clipping region)
2140 if (lengths[0] > 2) {
2141 region = XPolygonRegion(points, lengths[0], rule);
2143 region = XCreateRegion();
2146 for (i = 1; i < n; ++i) {
2147 if (lengths[i] > 2) {
2148 region2 = XPolygonRegion(points + j, lengths[i], rule);
2150 region2 = XCreateRegion();
2152 XUnionRegion(region2, region, region);
2153 XDestroyRegion(region2);
2154 j += lengths[i] + 1;
2157 // intersect region with clipping region
2158 XIntersectRegion(region, clipRegion, clipRegion);
2159 XDestroyRegion(region);
2160 XSetRegion(display, strokeGC, clipRegion);
2161 XSetRegion(display, fillGC, clipRegion);
2163 // free points and lengths arrays
2164 if (points != tmpPoints)
2166 if (lengths != tmpLengths)
2171 // Transform points in the path and convert curves to line segments.
2172 // Builds a set of subpaths and returns the number of subpaths.
2173 // If <fillHack> is set, close any unclosed subpaths and activate a
2174 // kludge for polygon fills: First, it divides up the subpaths into
2175 // non-overlapping polygons by simply comparing bounding rectangles.
2176 // Then it connects subaths within a single compound polygon to a single
2177 // point so that X can fill the polygon (sort of).
2179 int XOutputDev::convertPath(GfxState *state, XPoint **points, int *size,
2180 int *numPoints, int **lengths, GBool fillHack) {
2182 BoundingRect *rects;
2184 int n, i, ii, j, k, k0;
2186 // get path and number of subpaths
2187 path = state->getPath();
2188 n = path->getNumSubpaths();
2190 // allocate lengths array
2191 if (n < numTmpSubpaths)
2192 *lengths = tmpLengths;
2194 *lengths = (int *)gmalloc(n * sizeof(int));
2196 // allocate bounding rectangles array
2198 if (n < numTmpSubpaths)
2201 rects = (BoundingRect *)gmalloc(n * sizeof(BoundingRect));
2207 *points = tmpPoints;
2208 *size = numTmpPoints;
2210 for (i = 0; i < n; ++i) {
2212 // transform the points
2214 convertSubpath(state, path->getSubpath(i), points, size, numPoints);
2216 // construct bounding rectangle
2218 rects[i].xMin = rects[i].xMax = (*points)[j].x;
2219 rects[i].yMin = rects[i].yMax = (*points)[j].y;
2220 for (k = j + 1; k < *numPoints; ++k) {
2221 if ((*points)[k].x < rects[i].xMin)
2222 rects[i].xMin = (*points)[k].x;
2223 else if ((*points)[k].x > rects[i].xMax)
2224 rects[i].xMax = (*points)[k].x;
2225 if ((*points)[k].y < rects[i].yMin)
2226 rects[i].yMin = (*points)[k].y;
2227 else if ((*points)[k].y > rects[i].yMax)
2228 rects[i].yMax = (*points)[k].y;
2232 // close subpath if necessary
2233 if (fillHack && ((*points)[*numPoints-1].x != (*points)[j].x ||
2234 (*points)[*numPoints-1].y != (*points)[j].y)) {
2235 addPoint(points, size, numPoints, (*points)[j].x, (*points)[j].y);
2238 // length of this subpath
2239 (*lengths)[i] = *numPoints - j;
2241 // leave an extra point for compound fill hack
2243 addPoint(points, size, numPoints, 0, 0);
2246 // kludge: munge any points that are *way* out of bounds - these can
2247 // crash certain (buggy) X servers
2248 for (i = 0; i < *numPoints; ++i) {
2249 if ((*points)[i].x < -pixmapW) {
2250 (*points)[i].x = -pixmapW;
2251 } else if ((*points)[i].x > 2 * pixmapW) {
2252 (*points)[i].x = 2 * pixmapW;
2254 if ((*points)[i].y < -pixmapH) {
2255 (*points)[i].y = -pixmapH;
2256 } else if ((*points)[i].y > 2 * pixmapH) {
2257 (*points)[i].y = 2 * pixmapH;
2261 // combine compound polygons
2266 // start with subpath i
2268 (*lengths)[j] = (*lengths)[i];
2270 (*points)[k + (*lengths)[i]] = (*points)[k0];
2271 k += (*lengths)[i] + 1;
2274 // combine overlapping polygons
2277 // look for the first subsequent subpath, if any, which overlaps
2278 for (ii = i; ii < n; ++ii) {
2279 if (rects[ii].xMax > rects[i].xMin &&
2280 rects[ii].xMin < rects[i].xMax &&
2281 rects[ii].yMax > rects[i].yMin &&
2282 rects[ii].yMin < rects[i].yMax) {
2287 // if there is an overlap, combine the polygons
2289 for (; i <= ii; ++i) {
2290 if (rects[i].xMin < rect.xMin)
2291 rect.xMin = rects[j].xMin;
2292 if (rects[i].xMax > rect.xMax)
2293 rect.xMax = rects[j].xMax;
2294 if (rects[i].yMin < rect.yMin)
2295 rect.yMin = rects[j].yMin;
2296 if (rects[i].yMax > rect.yMax)
2297 rect.yMax = rects[j].yMax;
2298 (*lengths)[j] += (*lengths)[i] + 1;
2299 (*points)[k + (*lengths)[i]] = (*points)[k0];
2300 k += (*lengths)[i] + 1;
2303 } while (ii < n && i < n);
2308 // free bounding rectangles
2309 if (rects != tmpRects)
2319 // Transform points in a single subpath and convert curves to line
2322 void XOutputDev::convertSubpath(GfxState *state, GfxSubpath *subpath,
2323 XPoint **points, int *size, int *n) {
2324 double x0, y0, x1, y1, x2, y2, x3, y3;
2327 m = subpath->getNumPoints();
2330 if (i >= 1 && subpath->getCurve(i)) {
2331 state->transform(subpath->getX(i-1), subpath->getY(i-1), &x0, &y0);
2332 state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1);
2333 state->transform(subpath->getX(i+1), subpath->getY(i+1), &x2, &y2);
2334 state->transform(subpath->getX(i+2), subpath->getY(i+2), &x3, &y3);
2335 doCurve(points, size, n, x0, y0, x1, y1, x2, y2, x3, y3);
2338 state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1);
2339 addPoint(points, size, n, xoutRound(x1), xoutRound(y1));
2346 // Subdivide a Bezier curve. This uses floating point to avoid
2347 // propagating rounding errors. (The curves look noticeably more
2348 // jagged with integer arithmetic.)
2350 void XOutputDev::doCurve(XPoint **points, int *size, int *n,
2351 double x0, double y0, double x1, double y1,
2352 double x2, double y2, double x3, double y3) {
2353 double x[(1<<maxCurveSplits)+1][3];
2354 double y[(1<<maxCurveSplits)+1][3];
2355 int next[1<<maxCurveSplits];
2357 double xx1, yy1, xx2, yy2;
2358 double dx, dy, mx, my, d1, d2;
2359 double xl0, yl0, xl1, yl1, xl2, yl2;
2360 double xr0, yr0, xr1, yr1, xr2, yr2, xr3, yr3;
2364 flat = (double)(flatness * flatness);
2370 p2 = 1<<maxCurveSplits;
2371 x[p1][0] = x0; y[p1][0] = y0;
2372 x[p1][1] = x1; y[p1][1] = y1;
2373 x[p1][2] = x2; y[p1][2] = y2;
2374 x[p2][0] = x3; y[p2][0] = y3;
2377 while (p1 < (1<<maxCurveSplits)) {
2380 xl0 = x[p1][0]; yl0 = y[p1][0];
2381 xx1 = x[p1][1]; yy1 = y[p1][1];
2382 xx2 = x[p1][2]; yy2 = y[p1][2];
2384 xr3 = x[p2][0]; yr3 = y[p2][0];
2386 // compute distances from control points to midpoint of the
2387 // straight line (this is a bit of a hack, but it's much faster
2388 // than computing the actual distances to the line)
2389 mx = (xl0 + xr3) * 0.5;
2390 my = (yl0 + yr3) * 0.5;
2398 // if curve is flat enough, or no more divisions allowed then
2399 // add the straight line segment
2400 if (p2 - p1 <= 1 || (d1 <= flat && d2 <= flat)) {
2401 addPoint(points, size, n, xoutRound(xr3), xoutRound(yr3));
2404 // otherwise, subdivide the curve
2406 xl1 = (xl0 + xx1) * 0.5;
2407 yl1 = (yl0 + yy1) * 0.5;
2408 xh = (xx1 + xx2) * 0.5;
2409 yh = (yy1 + yy2) * 0.5;
2410 xl2 = (xl1 + xh) * 0.5;
2411 yl2 = (yl1 + yh) * 0.5;
2412 xr2 = (xx2 + xr3) * 0.5;
2413 yr2 = (yy2 + yr3) * 0.5;
2414 xr1 = (xh + xr2) * 0.5;
2415 yr1 = (yh + yr2) * 0.5;
2416 xr0 = (xl2 + xr1) * 0.5;
2417 yr0 = (yl2 + yr1) * 0.5;
2419 // add the new subdivision points
2421 x[p1][1] = xl1; y[p1][1] = yl1;
2422 x[p1][2] = xl2; y[p1][2] = yl2;
2424 x[p3][0] = xr0; y[p3][0] = yr0;
2425 x[p3][1] = xr1; y[p3][1] = yr1;
2426 x[p3][2] = xr2; y[p3][2] = yr2;
2433 // Add a point to the points array. (This would use a generic resizable
2434 // array type if C++ supported parameterized types in some reasonable
2435 // way -- templates are a disgusting kludge.)
2437 void XOutputDev::addPoint(XPoint **points, int *size, int *k, int x, int y) {
2440 if (*points == tmpPoints) {
2441 *points = (XPoint *)gmalloc(*size * sizeof(XPoint));
2442 memcpy(*points, tmpPoints, *k * sizeof(XPoint));
2444 *points = (XPoint *)grealloc(*points, *size * sizeof(XPoint));
2447 (*points)[*k].x = x;
2448 (*points)[*k].y = y;
2452 void XOutputDev::beginString(GfxState *state, GString *s) {
2453 text->beginString(state);
2456 void XOutputDev::endString(GfxState *state) {
2460 void XOutputDev::drawChar(GfxState *state, double x, double y,
2461 double dx, double dy,
2462 double originX, double originY,
2463 CharCode code, Unicode *u, int uLen) {
2465 double x1, y1, dx1, dy1;
2467 double saveCurX, saveCurY;
2471 text->addChar(state, x, y, dx, dy, u, uLen);
2477 // check for invisible text -- this is used by Acrobat Capture
2478 render = state->getRender();
2479 if ((render & 3) == 3) {
2485 state->transform(x, y, &x1, &y1);
2486 state->transformDelta(dx, dy, &dx1, &dy1);
2489 if (!(render & 1)) {
2490 state->getFillRGB(&rgb);
2496 font->drawChar(state, pixmap, pixmapW, pixmapH, fillGC, &rgb,
2497 x1, y1, dx1, dy1, code, u, uLen);
2501 if ((render & 3) == 1 || (render & 3) == 2) {
2502 if (font->hasGetCharPath()) {
2503 saveCurX = state->getCurX();
2504 saveCurY = state->getCurY();
2505 ctm = state->getCTM();
2506 memcpy(saveCTM, ctm, 6 * sizeof(double));
2507 state->setCTM(1, 0, 0, 1, x1, y1);
2508 font->getCharPath(state, code, u, uLen);
2511 state->setCTM(saveCTM[0], saveCTM[1], saveCTM[2], saveCTM[3],
2512 saveCTM[4], saveCTM[5]);
2513 state->moveTo(saveCurX, saveCurY);
2515 // can't stroke the outline, so just fill it using the stroke
2517 state->getStrokeRGB(&rgb);
2523 font->drawChar(state, pixmap, pixmapW, pixmapH, strokeGC, &rgb,
2524 x1, y1, dx1, dy1, code, u, uLen);
2528 #if 0 //~ unimplemented: clipping to char path
2535 GBool XOutputDev::beginType3Char(GfxState *state,
2536 CharCode code, Unicode *u, int uLen) {
2540 T3FontCache *t3Font;
2542 double x1, y1, xMin, yMin, xMax, yMax, xt, yt;
2548 fontID = gfxFont->getID();
2549 ctm = state->getCTM();
2550 state->transform(0, 0, &xt, &yt);
2552 // is it the first (MRU) font in the cache?
2553 if (!(nT3Fonts > 0 &&
2554 t3FontCache[0]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3]))) {
2556 // is the font elsewhere in the cache?
2557 for (i = 1; i < nT3Fonts; ++i) {
2558 if (t3FontCache[i]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3])) {
2559 t3Font = t3FontCache[i];
2560 for (j = i; j > 0; --j) {
2561 t3FontCache[j] = t3FontCache[j - 1];
2563 t3FontCache[0] = t3Font;
2567 if (i >= nT3Fonts) {
2569 // create new entry in the font cache
2570 if (nT3Fonts == xOutT3FontCacheSize) {
2571 delete t3FontCache[nT3Fonts - 1];
2574 for (j = nT3Fonts; j > 0; --j) {
2575 t3FontCache[j] = t3FontCache[j - 1];
2578 bbox = gfxFont->getFontBBox();
2579 if (bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0) {
2580 // broken bounding box -- just take a guess
2586 state->transform(bbox[0], bbox[1], &x1, &y1);
2589 state->transform(bbox[0], bbox[3], &x1, &y1);
2592 } else if (x1 > xMax) {
2597 } else if (y1 > yMax) {
2600 state->transform(bbox[2], bbox[1], &x1, &y1);
2603 } else if (x1 > xMax) {
2608 } else if (y1 > yMax) {
2611 state->transform(bbox[2], bbox[3], &x1, &y1);
2614 } else if (x1 > xMax) {
2619 } else if (y1 > yMax) {
2623 t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3],
2624 (int)floor(xMin - xt),
2625 (int)floor(yMin - yt),
2626 (int)ceil(xMax) - (int)floor(xMin) + 3,
2627 (int)ceil(yMax) - (int)floor(yMin) + 3,
2629 DefaultVisual(display, screenNum),
2633 t3Font = t3FontCache[0];
2635 // is the glyph in the cache?
2636 i = (code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc;
2637 for (j = 0; j < t3Font->cacheAssoc; ++j) {
2638 if ((t3Font->cacheTags[i+j].mru & 0x8000) &&
2639 t3Font->cacheTags[i+j].code == code) {
2640 state->getFillRGB(&color);
2642 color.r = 1 - color.r;
2643 color.g = 1 - color.g;
2644 color.b = 1 - color.b;
2646 text->addChar(state, 0, 0,
2647 t3Font->cacheTags[i+j].wx, t3Font->cacheTags[i+j].wy,
2649 drawType3Glyph(t3Font, &t3Font->cacheTags[i+j],
2650 t3Font->cacheData + (i+j) * t3Font->glyphSize,
2656 // push a new Type 3 glyph record
2657 t3gs = new T3GlyphStack();
2658 t3gs->next = t3GlyphStack;
2659 t3GlyphStack = t3gs;
2660 t3GlyphStack->cacheable = gFalse;
2661 t3GlyphStack->code = code;
2662 t3GlyphStack->cache = t3Font;
2663 t3GlyphStack->cacheIdx = i;
2664 t3GlyphStack->x = xt;
2665 t3GlyphStack->y = yt;
2666 t3GlyphStack->u = u;
2667 t3GlyphStack->uLen = uLen;
2672 void XOutputDev::endType3Char(GfxState *state) {
2680 if (t3GlyphStack->cacheable) {
2681 image = t3GlyphStack->cache->image;
2682 XGetSubImage(display, pixmap, 0, 0,
2683 t3GlyphStack->cache->glyphW, t3GlyphStack->cache->glyphH,
2684 (1 << depth) - 1, ZPixmap, image, 0, 0);
2685 p = t3GlyphStack->cacheData;
2686 for (y = 0; y < t3GlyphStack->cache->glyphH; ++y) {
2687 for (x = 0; x < t3GlyphStack->cache->glyphW; ++x) {
2688 pixel = XGetPixel(image, x, y);
2690 alpha = (double)((pixel >> rShift) & rMul) / (double)rMul;
2692 alpha = redMap[pixel & 0xff];
2696 } else if (alpha <= 0.4) {
2698 } else if (alpha <= 0.6) {
2700 } else if (alpha <= 0.8) {
2707 XDestroyRegion(clipRegion);
2708 XFreeGC(display, strokeGC);
2709 XFreeGC(display, fillGC);
2710 pixmapW = t3GlyphStack->origPixmapW;
2711 pixmapH = t3GlyphStack->origPixmapH;
2712 pixmap = t3GlyphStack->origPixmap;
2713 strokeGC = t3GlyphStack->origStrokeGC;
2714 fillGC = t3GlyphStack->origFillGC;
2715 clipRegion = t3GlyphStack->origClipRegion;
2716 drawType3Glyph(t3GlyphStack->cache,
2717 t3GlyphStack->cacheTag, t3GlyphStack->cacheData,
2718 t3GlyphStack->x, t3GlyphStack->y, &t3GlyphStack->color);
2720 text->addChar(state, 0, 0, t3GlyphStack->wx, t3GlyphStack->wy,
2721 t3GlyphStack->u, t3GlyphStack->uLen);
2722 t3gs = t3GlyphStack;
2723 t3GlyphStack = t3gs->next;
2727 void XOutputDev::drawType3Glyph(T3FontCache *t3Font,
2728 T3FontCacheTag *tag, Guchar *data,
2729 double x, double y, GfxRGB *color) {
2736 int x0, y0, w0, h0, x1, y1;
2739 // compute: (x0,y0) = position in destination pixmap
2740 // (x1,y1) = position in the XImage
2741 // (w0,h0) = size of XImage transfer
2742 x0 = xoutRound(x + t3Font->glyphX);
2743 y0 = xoutRound(y + t3Font->glyphY);
2746 w0 = t3Font->glyphW;
2747 h0 = t3Font->glyphH;
2753 if (x0 + w0 > pixmapW) {
2764 if (y0 + h0 > pixmapH) {
2771 image = t3Font->image;
2772 XGetSubImage(display, pixmap, x0, y0, w0, h0,
2773 (1 << depth) - 1, ZPixmap, image, x1, y1);
2774 xcolor.pixel = XGetPixel(image, t3Font->glyphW / 2, t3Font->glyphH / 2);
2775 XQueryColor(display, colormap, &xcolor);
2776 bg.r = xcolor.red / 65535.0;
2777 bg.g = xcolor.green / 65535.0;
2778 bg.b = xcolor.blue / 65535.0;
2779 rgb.r = 0.25 * (color->r + 3 * bg.r);
2780 rgb.g = 0.25 * (color->g + 3 * bg.g);
2781 rgb.b = 0.25 * (color->b + 3 * bg.b);
2782 map[1] = findColor(&rgb);
2783 rgb.r = 0.5 * (color->r + bg.r);
2784 rgb.g = 0.5 * (color->g + bg.g);
2785 rgb.b = 0.5 * (color->b + bg.b);
2786 map[2] = findColor(&rgb);
2787 rgb.r = 0.25 * (3 * color->r + bg.r);
2788 rgb.g = 0.25 * (3 * color->g + bg.g);
2789 rgb.b = 0.25 * (3 * color->b + bg.b);
2790 map[3] = findColor(&rgb);
2791 map[4] = findColor(color);
2793 for (iy = 0; iy < t3Font->glyphH; ++iy) {
2794 for (ix = 0; ix < t3Font->glyphW; ++ix) {
2797 XPutPixel(image, ix, iy, map[pixel]);
2801 XPutImage(display, pixmap, fillGC, image, x1, y1, x0, y0, w0, h0);
2804 void XOutputDev::type3D0(GfxState *state, double wx, double wy) {
2805 t3GlyphStack->wx = wx;
2806 t3GlyphStack->wy = wy;
2809 void XOutputDev::type3D1(GfxState *state, double wx, double wy,
2810 double llx, double lly, double urx, double ury) {
2815 T3FontCache *t3Font;
2818 // allocate a cache entry
2819 t3GlyphStack->cacheable = gTrue;
2820 t3Font = t3GlyphStack->cache;
2821 i = t3GlyphStack->cacheIdx;
2822 for (j = 0; j < t3Font->cacheAssoc; ++j) {
2823 if ((t3Font->cacheTags[i+j].mru & 0x7fff) == t3Font->cacheAssoc - 1) {
2824 t3Font->cacheTags[i+j].mru = 0x8000;
2825 t3Font->cacheTags[i+j].code = t3GlyphStack->code;
2826 t3GlyphStack->cacheTag = &t3Font->cacheTags[i+j];
2827 t3GlyphStack->cacheData = t3Font->cacheData + (i+j) * t3Font->glyphSize;
2829 ++t3Font->cacheTags[i+j].mru;
2832 t3GlyphStack->wx = wx;
2833 t3GlyphStack->wy = wy;
2834 t3GlyphStack->cacheTag->wx = wx;
2835 t3GlyphStack->cacheTag->wy = wy;
2837 // prepare to rasterize the glyph
2838 //~ do we need to handle both fill and stroke color?
2839 state->getFillRGB(&t3GlyphStack->color);
2841 t3GlyphStack->color.r = 1 - t3GlyphStack->color.r;
2842 t3GlyphStack->color.g = 1 - t3GlyphStack->color.g;
2843 t3GlyphStack->color.b = 1 - t3GlyphStack->color.b;
2845 fgColor.c[0] = reverseVideo ? 1 : 0;
2846 state->setFillColorSpace(new GfxDeviceGrayColorSpace());
2847 state->setFillColor(&fgColor);
2848 state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
2849 state->setStrokeColor(&fgColor);
2850 t3GlyphStack->origPixmapW = pixmapW;
2851 t3GlyphStack->origPixmapH = pixmapH;
2852 t3GlyphStack->origPixmap = pixmap;
2853 t3GlyphStack->origStrokeGC = strokeGC;
2854 t3GlyphStack->origFillGC = fillGC;
2855 t3GlyphStack->origClipRegion = clipRegion;
2856 pixmapW = t3GlyphStack->cache->glyphW;
2857 pixmapH = t3GlyphStack->cache->glyphH;
2858 pixmap = t3GlyphStack->cache->pixmap;
2859 gcValues.foreground = BlackPixel(display, screenNum);
2860 gcValues.background = WhitePixel(display, screenNum);
2861 gcValues.line_width = 0;
2862 gcValues.line_style = LineSolid;
2863 strokeGC = XCreateGC(display, pixmap,
2864 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
2866 updateLineAttrs(state, gTrue);
2867 gcValues.foreground = WhitePixel(display, screenNum);
2868 fillGC = XCreateGC(display, pixmap,
2869 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
2871 XFillRectangle(display, pixmap, fillGC, 0, 0, pixmapW, pixmapH);
2872 XSetForeground(display, fillGC, BlackPixel(display, screenNum));
2873 clipRegion = XCreateRegion();
2874 rect.x = rect.y = 0;
2875 rect.width = pixmapW;
2876 rect.height = pixmapH;
2877 XUnionRectWithRegion(&rect, clipRegion, clipRegion);
2878 XSetRegion(display, strokeGC, clipRegion);
2879 XSetRegion(display, fillGC, clipRegion);
2880 ctm = state->getCTM();
2881 state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
2882 -t3GlyphStack->cache->glyphX, -t3GlyphStack->cache->glyphY);
2885 inline Gulong XOutputDev::findColor(GfxRGB *x, GfxRGB *err) {
2891 r = xoutRound(x->r * rMul);
2892 g = xoutRound(x->g * gMul);
2893 b = xoutRound(x->b * bMul);
2894 pixel = ((Gulong)r << rShift) +
2895 ((Gulong)g << gShift) +
2896 ((Gulong)b << bShift);
2897 err->r = x->r - (double)r / rMul;
2898 err->g = x->g - (double)g / gMul;
2899 err->b = x->b - (double)b / bMul;
2900 } else if (numColors == 1) {
2901 gray = 0.299 * x->r + 0.587 * x->g + 0.114 * x->b;
2914 r = xoutRound(x->r * (numColors - 1));
2915 g = xoutRound(x->g * (numColors - 1));
2916 b = xoutRound(x->b * (numColors - 1));
2917 pixel = colors[(r * numColors + g) * numColors + b];
2918 err->r = x->r - (double)r / (numColors - 1);
2919 err->g = x->g - (double)g / (numColors - 1);
2920 err->b = x->b - (double)b / (numColors - 1);
2925 Gulong XOutputDev::findColor(GfxRGB *rgb) {
2931 r = xoutRound(rgb->r * rMul);
2932 g = xoutRound(rgb->g * gMul);
2933 b = xoutRound(rgb->b * bMul);
2934 pixel = ((Gulong)r << rShift) +
2935 ((Gulong)g << gShift) +
2936 ((Gulong)b << bShift);
2937 } else if (numColors == 1) {
2938 gray = 0.299 * rgb->r + 0.587 * rgb->g + 0.114 * rgb->b;
2944 r = xoutRound(rgb->r * (numColors - 1));
2945 g = xoutRound(rgb->g * (numColors - 1));
2946 b = xoutRound(rgb->b * (numColors - 1));
2947 #if 0 // this makes things worse as often as better
2948 // even a very light color shouldn't map to white
2949 if (r == numColors - 1 && g == numColors - 1 && b == numColors - 1) {
2950 if (color->getR() < 0.95)
2952 if (color->getG() < 0.95)
2954 if (color->getB() < 0.95)
2958 pixel = colors[(r * numColors + g) * numColors + b];
2963 void XOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
2964 int width, int height, GBool invert,
2966 ImageStream *imgStr;
2970 double xScale, yScale, xShear, yShear;
2971 int tx, ty, scaledWidth, scaledHeight, xSign, ySign;
2972 int ulx, uly, llx, lly, urx, ury, lrx, lry;
2973 int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
2974 int bx0, by0, bx1, by1, bw, bh;
2975 int cx0, cy0, cx1, cy1, cw, ch;
2976 int yp, yq, yt, yStep, lastYStep;
2977 int xp, xq, xt, xStep, xSrc;
2985 double r0, g0, b0, r1, g1, b1;
2988 int x, y, x1, y1, x2, y2;
2991 // get CTM, check for singular matrix
2992 ctm = state->getCTM();
2993 if (fabs(ctm[0] * ctm[3] - ctm[1] * ctm[2]) < 0.000001) {
2994 error(-1, "Singular CTM in drawImage");
2996 j = height * ((width + 7) / 8);
2998 for (i = 0; i < j; ++i) {
3006 // compute scale, shear, rotation, translation parameters
3007 rot = fabs(ctm[1]) > fabs(ctm[0]);
3010 yScale = -ctm[2] + (ctm[0] * ctm[3]) / ctm[1];
3011 xShear = ctm[3] / yScale;
3012 yShear = -ctm[0] / ctm[1];
3015 yScale = -ctm[3] + (ctm[1] * ctm[2]) / ctm[0];
3016 xShear = -ctm[2] / yScale;
3017 yShear = ctm[1] / ctm[0];
3019 tx = xoutRound(ctm[2] + ctm[4]);
3020 ty = xoutRound(ctm[3] + ctm[5]);
3021 // use ceil() to avoid gaps between "striped" images
3022 scaledWidth = (int)ceil(fabs(xScale));
3023 xSign = (xScale < 0) ? -1 : 1;
3024 scaledHeight = (int)ceil(fabs(yScale));
3025 ySign = (yScale < 0) ? -1 : 1;
3027 // compute corners in device space
3030 urx1 = xSign * (scaledWidth - 1);
3031 ury1 = xoutRound(yShear * urx1);
3032 llx1 = xoutRound(xShear * ySign * (scaledHeight - 1));
3033 lly1 = ySign * (scaledHeight - 1) + xoutRound(yShear * llx1);
3034 lrx1 = xSign * (scaledWidth - 1) +
3035 xoutRound(xShear * ySign * (scaledHeight - 1));
3036 lry1 = ySign * (scaledHeight - 1) + xoutRound(yShear * lrx1);
3038 ulx = tx + uly1; uly = ty - ulx1;
3039 urx = tx + ury1; ury = ty - urx1;
3040 llx = tx + lly1; lly = ty - llx1;
3041 lrx = tx + lry1; lry = ty - lrx1;
3043 ulx = tx + ulx1; uly = ty + uly1;
3044 urx = tx + urx1; ury = ty + ury1;
3045 llx = tx + llx1; lly = ty + lly1;
3046 lrx = tx + lrx1; lry = ty + lry1;
3050 // (bx0, by0) = upper-left corner
3051 // (bx1, by1) = lower-right corner
3053 bx0 = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
3054 : (llx < lrx) ? llx : lrx
3055 : (urx < llx) ? (urx < lrx) ? urx : lrx
3056 : (llx < lrx) ? llx : lrx;
3057 bx1 = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
3058 : (llx > lrx) ? llx : lrx
3059 : (urx > llx) ? (urx > lrx) ? urx : lrx
3060 : (llx > lrx) ? llx : lrx;
3061 by0 = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
3062 : (lly < lry) ? lly : lry
3063 : (ury < lly) ? (ury < lry) ? ury : lry
3064 : (lly < lry) ? lly : lry;
3065 by1 = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
3066 : (lly > lry) ? lly : lry
3067 : (ury > lly) ? (ury > lry) ? ury : lry
3068 : (lly > lry) ? lly : lry;
3072 // Bounding box clipped to pixmap, i.e., "valid" rectangle:
3073 // (cx0, cy0) = upper-left corner of valid rectangle in Pixmap
3074 // (cx1, cy1) = upper-left corner of valid rectangle in XImage
3075 // (cw, ch) = size of valid rectangle
3076 // These values will be used to transfer the XImage from/to the
3078 cw = (bx1 >= pixmapW) ? pixmapW - bx0 : bw;
3087 ch = (by1 >= pixmapH) ? pixmapH - by0 : bh;
3097 // check for tiny (zero width or height) images
3098 // and off-page images
3099 if (scaledWidth <= 0 || scaledHeight <= 0 || cw <= 0 || ch <= 0) {
3101 j = height * ((width + 7) / 8);
3103 for (i = 0; i < j; ++i) {
3111 // compute Bresenham parameters for x and y scaling
3112 yp = height / scaledHeight;
3113 yq = height % scaledHeight;
3114 xp = width / scaledWidth;
3115 xq = width % scaledWidth;
3117 // allocate pixel buffer
3118 pixBuf = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar));
3120 // allocate XImage and read from page pixmap
3121 image = XCreateImage(display, DefaultVisual(display, screenNum),
3122 depth, ZPixmap, 0, NULL, bw, bh, 8, 0);
3123 image->data = (char *)gmalloc(bh * image->bytes_per_line);
3124 XGetSubImage(display, pixmap, cx0, cy0, cw, ch, (1 << depth) - 1, ZPixmap,
3128 state->getFillRGB(&rgb);
3138 // initialize background color
3139 // (the specific pixel value doesn't matter here, as long as
3140 // r1,g1,b1 correspond correctly to lastPixel)
3141 xcolor.pixel = lastPixel = 0;
3142 XQueryColor(display, colormap, &xcolor);
3143 r1 = (double)xcolor.red / 65535.0;
3144 g1 = (double)xcolor.green / 65535.0;
3145 b1 = (double)xcolor.blue / 65535.0;
3147 // initialize the image stream
3148 imgStr = new ImageStream(str, width, 1, 1);
3151 // init y scale Bresenham
3155 for (y = 0; y < scaledHeight; ++y) {
3157 // y scale Bresenham
3160 if (yt >= scaledHeight) {
3165 // read row(s) from image
3166 n = (yp > 0) ? yStep : lastYStep;
3169 for (i = 0; i < n; ++i) {
3170 for (j = 0; j < width; ++j) {
3171 imgStr->getPixel(p);
3181 // init x scale Bresenham
3185 for (x = 0; x < scaledWidth; ++x) {
3187 // x scale Bresenham
3190 if (xt >= scaledWidth) {
3196 x1 = xSign * x + xoutRound(xShear * ySign * y);
3199 y1 = ySign * y + xoutRound(yShear * x1);
3210 // compute the filtered pixel at (x,y) after the
3211 // x and y scaling operations
3212 n = yStep > 0 ? yStep : 1;
3213 m = xStep > 0 ? xStep : 1;
3216 for (i = 0; i < n; ++i) {
3217 for (j = 0; j < m; ++j) {
3223 // x scale Bresenham
3226 // blend image pixel with background
3227 alpha = (double)imgPix / (double)(n * m);
3228 xcolor.pixel = XGetPixel(image, tx + x2 - bx0, ty + y2 - by0);
3229 if (xcolor.pixel != lastPixel) {
3230 XQueryColor(display, colormap, &xcolor);
3231 r1 = (double)xcolor.red / 65535.0;
3232 g1 = (double)xcolor.green / 65535.0;
3233 b1 = (double)xcolor.blue / 65535.0;
3234 lastPixel = xcolor.pixel;
3236 rgb2.r = r0 * (1 - alpha) + r1 * alpha;
3237 rgb2.g = g0 * (1 - alpha) + g1 * alpha;
3238 rgb2.b = b0 * (1 - alpha) + b1 * alpha;
3239 pix = findColor(&rgb2);
3242 XPutPixel(image, tx + x2 - bx0, ty + y2 - by0, pix);
3246 // blit the image into the pixmap
3247 XPutImage(display, pixmap, fillGC, image, cx1, cy1, cx0, cy0, cw, ch);
3254 XDestroyImage(image);
3257 void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
3258 int width, int height, GfxImageColorMap *colorMap,
3259 int *maskColors, GBool inlineImg) {
3260 ImageStream *imgStr;
3262 int nComps, nVals, nBits;
3266 double xScale, yScale, xShear, yShear;
3267 int tx, ty, scaledWidth, scaledHeight, xSign, ySign;
3268 int ulx, uly, llx, lly, urx, ury, lrx, lry;
3269 int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
3270 int bx0, by0, bx1, by1, bw, bh;
3271 int cx0, cy0, cx1, cy1, cw, ch;
3272 int yp, yq, yt, yStep, lastYStep;
3273 int xp, xq, xt, xStep, xSrc;
3276 Guchar pixBuf2[gfxColorMaxComps];
3277 GfxRGB color2, err, errRight;
3279 double r0, g0, b0, alpha, mul;
3284 GfxRGB oneBitRGB[2];
3285 int x, y, x1, y1, x2, y2;
3289 nComps = colorMap->getNumPixelComps();
3290 nVals = width * nComps;
3291 nBits = colorMap->getBits();
3292 dither = nComps > 1 || nBits > 1;
3294 // get CTM, check for singular matrix
3295 ctm = state->getCTM();
3296 if (fabs(ctm[0] * ctm[3] - ctm[1] * ctm[2]) < 0.000001) {
3297 error(-1, "Singular CTM in drawImage");
3300 j = height * ((nVals * nBits + 7) / 8);
3301 for (i = 0; i < j; ++i) {
3309 // compute scale, shear, rotation, translation parameters
3310 rot = fabs(ctm[1]) > fabs(ctm[0]);
3313 yScale = -ctm[2] + (ctm[0] * ctm[3]) / ctm[1];
3314 xShear = ctm[3] / yScale;
3315 yShear = -ctm[0] / ctm[1];
3318 yScale = -ctm[3] + (ctm[1] * ctm[2]) / ctm[0];
3319 xShear = -ctm[2] / yScale;
3320 yShear = ctm[1] / ctm[0];
3322 tx = xoutRound(ctm[2] + ctm[4]);
3323 ty = xoutRound(ctm[3] + ctm[5]);
3324 // use ceil() to avoid gaps between "striped" images
3325 scaledWidth = (int)ceil(fabs(xScale));
3326 xSign = (xScale < 0) ? -1 : 1;
3327 scaledHeight = (int)ceil(fabs(yScale));
3328 ySign = (yScale < 0) ? -1 : 1;
3330 // compute corners in device space
3333 urx1 = xSign * (scaledWidth - 1);
3334 ury1 = xoutRound(yShear * urx1);
3335 llx1 = xoutRound(xShear * ySign * (scaledHeight - 1));
3336 lly1 = ySign * (scaledHeight - 1) + xoutRound(yShear * llx1);
3337 lrx1 = xSign * (scaledWidth - 1) +
3338 xoutRound(xShear * ySign * (scaledHeight - 1));
3339 lry1 = ySign * (scaledHeight - 1) + xoutRound(yShear * lrx1);
3341 ulx = tx + uly1; uly = ty - ulx1;
3342 urx = tx + ury1; ury = ty - urx1;
3343 llx = tx + lly1; lly = ty - llx1;
3344 lrx = tx + lry1; lry = ty - lrx1;
3346 ulx = tx + ulx1; uly = ty + uly1;
3347 urx = tx + urx1; ury = ty + ury1;
3348 llx = tx + llx1; lly = ty + lly1;
3349 lrx = tx + lrx1; lry = ty + lry1;
3353 // (bx0, by0) = upper-left corner
3354 // (bx1, by1) = lower-right corner
3356 bx0 = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
3357 : (llx < lrx) ? llx : lrx
3358 : (urx < llx) ? (urx < lrx) ? urx : lrx
3359 : (llx < lrx) ? llx : lrx;
3360 bx1 = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
3361 : (llx > lrx) ? llx : lrx
3362 : (urx > llx) ? (urx > lrx) ? urx : lrx
3363 : (llx > lrx) ? llx : lrx;
3364 by0 = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
3365 : (lly < lry) ? lly : lry
3366 : (ury < lly) ? (ury < lry) ? ury : lry
3367 : (lly < lry) ? lly : lry;
3368 by1 = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
3369 : (lly > lry) ? lly : lry
3370 : (ury > lly) ? (ury > lry) ? ury : lry
3371 : (lly > lry) ? lly : lry;
3375 // Bounding box clipped to pixmap, i.e., "valid" rectangle:
3376 // (cx0, cy0) = upper-left corner of valid rectangle in Pixmap
3377 // (cx1, cy1) = upper-left corner of valid rectangle in XImage
3378 // (cw, ch) = size of valid rectangle
3379 // These values will be used to transfer the XImage from/to the
3381 cw = (bx1 >= pixmapW) ? pixmapW - bx0 : bw;
3390 ch = (by1 >= pixmapH) ? pixmapH - by0 : bh;
3400 // check for tiny (zero width or height) images
3401 // and off-page images
3402 if (scaledWidth <= 0 || scaledHeight <= 0 || cw <= 0 || ch <= 0) {
3405 j = height * ((nVals * nBits + 7) / 8);
3406 for (i = 0; i < j; ++i)
3413 // compute Bresenham parameters for x and y scaling
3414 yp = height / scaledHeight;
3415 yq = height % scaledHeight;
3416 xp = width / scaledWidth;
3417 xq = width % scaledWidth;
3419 // allocate pixel buffer
3420 pixBuf = (GfxRGB *)gmalloc((yp + 1) * width * sizeof(GfxRGB));
3422 alphaBuf = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar));
3428 image = XCreateImage(display, DefaultVisual(display, screenNum),
3429 depth, ZPixmap, 0, NULL, bw, bh, 8, 0);
3430 image->data = (char *)gmalloc(bh * image->bytes_per_line);
3432 // if the transform is anything other than a 0/90/180/270 degree
3433 // rotation/flip, or if there is color key masking, read the
3434 // backgound pixmap to fill in the corners
3435 if (!((ulx == llx && uly == ury) ||
3436 (uly == lly && ulx == urx)) ||
3438 XGetSubImage(display, pixmap, cx0, cy0, cw, ch, (1 << depth) - 1, ZPixmap,
3442 // allocate error diffusion accumulators
3444 errDown = (GfxRGB *)gmalloc(bw * sizeof(GfxRGB));
3445 for (j = 0; j < bw; ++j) {
3446 errDown[j].r = errDown[j].g = errDown[j].b = 0;
3452 // optimize the one-bit-deep image case
3453 if ((oneBitMode = nComps == 1 && nBits == 1)) {
3455 colorMap->getRGB(pixBuf2, &oneBitRGB[0]);
3457 colorMap->getRGB(pixBuf2, &oneBitRGB[1]);
3460 // initialize the image stream
3461 imgStr = new ImageStream(str, width, nComps, nBits);
3464 // init y scale Bresenham
3468 for (y = 0; y < scaledHeight; ++y) {
3470 // initialize error diffusion accumulator
3471 errRight.r = errRight.g = errRight.b = 0;
3473 // y scale Bresenham
3476 if (yt >= scaledHeight) {
3481 // read row(s) from image
3482 n = (yp > 0) ? yStep : lastYStep;
3486 for (i = 0; i < n; ++i) {
3487 for (j = 0; j < width; ++j) {
3488 imgStr->getPixel(pixBuf2);
3490 *p++ = oneBitRGB[pixBuf2[0]];
3492 colorMap->getRGB(pixBuf2, p);
3497 for (k = 0; k < nComps; ++k) {
3498 if (pixBuf2[k] < maskColors[2*k] ||
3499 pixBuf2[k] > maskColors[2*k]) {
3511 // init x scale Bresenham
3515 for (x = 0; x < scaledWidth; ++x) {
3517 // x scale Bresenham
3520 if (xt >= scaledWidth) {
3526 x1 = xSign * x + xoutRound(xShear * ySign * y);
3529 y1 = ySign * y + xoutRound(yShear * x1);
3540 // compute the filtered pixel at (x,y) after the
3541 // x and y scaling operations
3542 n = yStep > 0 ? yStep : 1;
3543 m = xStep > 0 ? xStep : 1;
3546 q = alphaBuf ? alphaBuf + xSrc : (Guchar *)NULL;
3548 for (i = 0; i < n; ++i) {
3549 for (j = 0; j < m; ++j) {
3560 mul = 1 / (double)(n * m);
3566 // x scale Bresenham
3571 color2.r = r0 + errRight.r + errDown[tx + x2 - bx0].r;
3574 } else if (color2.r < 0) {
3577 color2.g = g0 + errRight.g + errDown[tx + x2 - bx0].g;
3580 } else if (color2.g < 0) {
3583 color2.b = b0 + errRight.b + errDown[tx + x2 - bx0].b;
3586 } else if (color2.b < 0) {
3589 pix = findColor(&color2, &err);
3590 errRight.r = errDown[tx + x2 - bx0].r = err.r / 2;
3591 errRight.g = errDown[tx + x2 - bx0].g = err.g / 2;
3592 errRight.b = errDown[tx + x2 - bx0].b = err.b / 2;
3597 pix = findColor(&color2, &err);
3601 //~ this should do a blend when 0 < alpha < 1
3603 XPutPixel(image, tx + x2 - bx0, ty + y2 - by0, pix);
3608 // blit the image into the pixmap
3609 XPutImage(display, pixmap, fillGC, image, cx1, cy1, cx0, cy0, cw, ch);
3619 XDestroyImage(image);
3623 GBool XOutputDev::findText(Unicode *s, int len, GBool top, GBool bottom,
3624 int *xMin, int *yMin, int *xMax, int *yMax) {
3625 double xMin1, yMin1, xMax1, yMax1;
3627 xMin1 = (double)*xMin;
3628 yMin1 = (double)*yMin;
3629 xMax1 = (double)*xMax;
3630 yMax1 = (double)*yMax;
3631 if (text->findText(s, len, top, bottom, &xMin1, &yMin1, &xMax1, &yMax1)) {
3632 *xMin = xoutRound(xMin1);
3633 *xMax = xoutRound(xMax1);
3634 *yMin = xoutRound(yMin1);
3635 *yMax = xoutRound(yMax1);
3641 GString *XOutputDev::getText(int xMin, int yMin, int xMax, int yMax) {
3642 return text->getText((double)xMin, (double)yMin,
3643 (double)xMax, (double)yMax);