diff options
Diffstat (limited to 'pdf/xpdf/XOutputDev.cc')
-rw-r--r-- | pdf/xpdf/XOutputDev.cc | 3986 |
1 files changed, 0 insertions, 3986 deletions
diff --git a/pdf/xpdf/XOutputDev.cc b/pdf/xpdf/XOutputDev.cc deleted file mode 100644 index a156b55..0000000 --- a/pdf/xpdf/XOutputDev.cc +++ /dev/null @@ -1,3986 +0,0 @@ -//======================================================================== -// -// XOutputDev.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include <aconf.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <unistd.h> -#include <string.h> -#include <ctype.h> -#include <math.h> -#include "gmem.h" -#include "gfile.h" -#include "GString.h" -#include "GList.h" -#include "Object.h" -#include "Stream.h" -#include "Link.h" -#include "GfxState.h" -#include "GfxFont.h" -#include "UnicodeMap.h" -#include "CharCodeToUnicode.h" -#include "FontFile.h" -#include "Error.h" -#include "TextOutputDev.h" -#include "XOutputDev.h" -#if HAVE_T1LIB_H -#include "T1Font.h" -#endif -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -#include "FTFont.h" -#endif -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -#include "TTFont.h" -#endif - -#ifdef VMS -#if (__VMS_VER < 70000000) -extern "C" int unlink(char *filename); -#endif -#endif - -#ifdef XlibSpecificationRelease -#if XlibSpecificationRelease < 5 -typedef char *XPointer; -#endif -#else -typedef char *XPointer; -#endif - -//------------------------------------------------------------------------ -// Constants and macros -//------------------------------------------------------------------------ - -#define xoutRound(x) ((int)(x + 0.5)) - -#define maxCurveSplits 6 // max number of splits when recursively - // drawing Bezier curves - -//------------------------------------------------------------------------ -// Font substitutions -//------------------------------------------------------------------------ - -struct XOutFontSubst { - char *name; - double mWidth; -}; - -// index: {symbolic:12, fixed:8, serif:4, sans-serif:0} + bold*2 + italic -static XOutFontSubst xOutSubstFonts[16] = { - {"Helvetica", 0.833}, - {"Helvetica-Oblique", 0.833}, - {"Helvetica-Bold", 0.889}, - {"Helvetica-BoldOblique", 0.889}, - {"Times-Roman", 0.788}, - {"Times-Italic", 0.722}, - {"Times-Bold", 0.833}, - {"Times-BoldItalic", 0.778}, - {"Courier", 0.600}, - {"Courier-Oblique", 0.600}, - {"Courier-Bold", 0.600}, - {"Courier-BoldOblique", 0.600}, - {"Symbol", 0.576}, - {"Symbol", 0.576}, - {"Symbol", 0.576}, - {"Symbol", 0.576} -}; - -//------------------------------------------------------------------------ - -static void outputToFile(void *stream, char *data, int len) { - fwrite(data, 1, len, (FILE *)stream); -} - -//------------------------------------------------------------------------ -// XOutputFont -//------------------------------------------------------------------------ - -XOutputFont::XOutputFont(Ref *idA, double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA, - double m11A, double m12A, double m21A, double m22A, - Display *displayA, XOutputDev *xOutA) { - id = *idA; - display = displayA; - xOut = xOutA; - m11Orig = m11OrigA; - m12Orig = m12OrigA; - m21Orig = m21OrigA; - m22Orig = m22OrigA; - m11 = m11A; - m12 = m12A; - m21 = m21A; - m22 = m22A; -} - -XOutputFont::~XOutputFont() { -} - -void XOutputFont::getCharPath(GfxState *state, - CharCode c, Unicode *u, int ulen) { -} - -#if HAVE_T1LIB_H -//------------------------------------------------------------------------ -// XOutputT1Font -//------------------------------------------------------------------------ - -XOutputT1Font::XOutputT1Font(Ref *idA, T1FontFile *fontFileA, - double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA, - double m11A, double m12A, - double m21A, double m22A, - Display *displayA, XOutputDev *xOutA): - XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA, - m11A, m12A, m21A, m22A, displayA, xOutA) -{ - double matrix[4]; - - fontFile = fontFileA; - - // create the transformed instance - matrix[0] = m11; - matrix[1] = -m12; - matrix[2] = m21; - matrix[3] = -m22; - font = new T1Font(fontFile, matrix); -} - -XOutputT1Font::~XOutputT1Font() { - if (font) { - delete font; - } -} - -GBool XOutputT1Font::isOk() { - return font != NULL; -} - -void XOutputT1Font::updateGC(GC gc) { -} - -void XOutputT1Font::drawChar(GfxState *state, Pixmap pixmap, int w, int h, - GC gc, GfxRGB *rgb, - double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen) { - font->drawChar(pixmap, w, h, gc, xoutRound(x), xoutRound(y), - (int)(rgb->r * 65535), (int)(rgb->g * 65535), - (int)(rgb->b * 65535), c, u[0]); -} - -void XOutputT1Font::getCharPath(GfxState *state, - CharCode c, Unicode *u, int uLen) { - font->getCharPath(c, u[0], state); -} -#endif // HAVE_T1LIB_H - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -//------------------------------------------------------------------------ -// XOutputFTFont -//------------------------------------------------------------------------ - -XOutputFTFont::XOutputFTFont(Ref *idA, FTFontFile *fontFileA, - double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA, - double m11A, double m12A, - double m21A, double m22A, - Display *displayA, XOutputDev *xOutA): - XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA, - m11A, m12A, m21A, m22A, displayA, xOutA) -{ - double matrix[4]; - - fontFile = fontFileA; - - // create the transformed instance - matrix[0] = m11; - matrix[1] = -m12; - matrix[2] = m21; - matrix[3] = -m22; - font = new FTFont(fontFile, matrix); -} - -XOutputFTFont::~XOutputFTFont() { - if (font) { - delete font; - } -} - -GBool XOutputFTFont::isOk() { - return font != NULL; -} - -void XOutputFTFont::updateGC(GC gc) { -} - -void XOutputFTFont::drawChar(GfxState *state, Pixmap pixmap, int w, int h, - GC gc, GfxRGB *rgb, - double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen) { - font->drawChar(pixmap, w, h, gc, xoutRound(x), xoutRound(y), - (int)(rgb->r * 65535), (int)(rgb->g * 65535), - (int)(rgb->b * 65535), c, uLen > 0 ? u[0] : 0); -} - -void XOutputFTFont::getCharPath(GfxState *state, - CharCode c, Unicode *u, int uLen) { - font->getCharPath(c, u[0], state); -} -#endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -//------------------------------------------------------------------------ -// XOutputTTFont -//------------------------------------------------------------------------ - -XOutputTTFont::XOutputTTFont(Ref *idA, TTFontFile *fontFileA, - double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA, - double m11A, double m12A, - double m21A, double m22A, - Display *displayA, XOutputDev *xOutA): - XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA, - m11A, m12A, m21A, m22A, displayA, xOutA) -{ - double matrix[4]; - - fontFile = fontFileA; - - // create the transformed instance - matrix[0] = m11; - matrix[1] = -m12; - matrix[2] = m21; - matrix[3] = -m22; - font = new TTFont(fontFile, matrix); -} - -XOutputTTFont::~XOutputTTFont() { - if (font) { - delete font; - } -} - -GBool XOutputTTFont::isOk() { - return font != NULL; -} - -void XOutputTTFont::updateGC(GC gc) { -} - -void XOutputTTFont::drawChar(GfxState *state, Pixmap pixmap, int w, int h, - GC gc, GfxRGB *rgb, - double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen) { - font->drawChar(pixmap, w, h, gc, xoutRound(x), xoutRound(y), - (int)(rgb->r * 65535), (int)(rgb->g * 65535), - (int)(rgb->b * 65535), c, u[0]); -} -#endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -//------------------------------------------------------------------------ -// XOutputServer8BitFont -//------------------------------------------------------------------------ - -// Copy <fmt>, substituting <val> for one occurrence of "%s", into -// <buf>. -static void stringSubst(char *buf, int bufSize, char *fmt, char *val) { - char *p, *q; - int i; - - i = 0; - p = fmt; - while (*p) { - if (p[0] == '%' && p[1] == 's') { - q = val; - while (*q && i < bufSize - 1) { - buf[i++] = *q++; - } - p += 2; - } else { - if (i < bufSize - 1) { - buf[i++] = *p; - } - ++p; - } - } - buf[i] = '\0'; -} - -XOutputServer8BitFont::XOutputServer8BitFont(Ref *idA, GString *xlfdFmt, - UnicodeMap *xUMapA, - CharCodeToUnicode *fontUMap, - double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA, - double m11A, double m12A, - double m21A, double m22A, - Display *displayA, - XOutputDev *xOutA): - XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA, - m11A, m12A, m21A, m22A, displayA, xOutA) -{ - double size, ntm11, ntm12, ntm21, ntm22; - GBool rotated; - int startSize, sz; - char fontName[500], fontSize[100]; - Unicode u; - char buf; - int i; - - // compute size and normalized transform matrix - size = sqrt(m21*m21 + m22*m22); - ntm11 = m11 / size; - ntm12 = -m12 / size; - ntm21 = m21 / size; - ntm22 = -m22 / size; - - // try to get a rotated font? - rotated = !(ntm11 > 0 && ntm22 > 0 && - fabs(ntm11 / ntm22 - 1) < 0.2 && - fabs(ntm12) < 0.01 && - fabs(ntm21) < 0.01); - - // open X font -- if font is not found (which means the server can't - // scale fonts), try progressively smaller and then larger sizes - startSize = (int)size; - if (rotated) { - sprintf(fontSize, "[%s%0.2f %s%0.2f %s%0.2f %s%0.2f]", - ntm11<0 ? "~" : "", fabs(ntm11 * size), - ntm12<0 ? "~" : "", fabs(ntm12 * size), - ntm21<0 ? "~" : "", fabs(ntm21 * size), - ntm22<0 ? "~" : "", fabs(ntm22 * size)); - } else { - sprintf(fontSize, "%d", startSize); - } - stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize); - xFont = XLoadQueryFont(display, fontName); - if (!xFont) { - for (sz = startSize; sz >= startSize/2 && sz >= 1; --sz) { - sprintf(fontSize, "%d", sz); - stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize); - if ((xFont = XLoadQueryFont(display, fontName))) - break; - } - if (!xFont) { - for (sz = startSize + 1; sz < startSize + 10; ++sz) { - sprintf(fontSize, "%d", sz); - stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), - fontSize); - if ((xFont = XLoadQueryFont(display, fontName))) { - break; - } - } - if (!xFont) { - sprintf(fontSize, "%d", startSize); - stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), - fontSize); - error(-1, "Failed to open font: '%s'", fontName); - return; - } - } - } - - // Construct char code map. - xUMap = xUMapA; - for (i = 0; i < 256; ++i) { - if (fontUMap->mapToUnicode((CID)i, &u, 1) == 1 && - xUMap->mapUnicode(u, &buf, 1) == 1) { - map[i] = buf & 0xff; - } else { - map[i] = 0; - } - } -} - -XOutputServer8BitFont::~XOutputServer8BitFont() { - if (xFont) { - XFreeFont(display, xFont); - } -} - -GBool XOutputServer8BitFont::isOk() { - return xFont != NULL; -} - -void XOutputServer8BitFont::updateGC(GC gc) { - XSetFont(display, gc, xFont->fid); -} - -void XOutputServer8BitFont::drawChar(GfxState *state, Pixmap pixmap, - int w, int h, GC gc, GfxRGB *rgb, - double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen) { - Gushort c1; - char buf[8]; - double dx1, dy1; - int m, n, i, j, k; - - c1 = map[c]; - if (c1 > 0) { - buf[0] = (char)c1; - XDrawString(display, pixmap, gc, xoutRound(x), xoutRound(y), buf, 1); - } else { - // substituted character, using more than one character - n = 0; - for (i = 0; i < uLen; ++i) { - n += xUMap->mapUnicode(u[i], buf, sizeof(buf)); - } - if (n > 0) { - dx1 = dx / n; - dy1 = dy / n; - k = 0; - for (i = 0; i < uLen; ++i) { - m = xUMap->mapUnicode(u[i], buf, sizeof(buf)); - for (j = 0; j < m; ++j) { - XDrawString(display, pixmap, gc, - xoutRound(x + k*dx1), xoutRound(y + k*dy1), - buf + j, 1); - ++k; - } - } - } - } -} - -//------------------------------------------------------------------------ -// XOutputServer16BitFont -//------------------------------------------------------------------------ - -XOutputServer16BitFont::XOutputServer16BitFont(Ref *idA, GString *xlfdFmt, - UnicodeMap *xUMapA, - CharCodeToUnicode *fontUMap, - double m11OrigA, - double m12OrigA, - double m21OrigA, - double m22OrigA, - double m11A, double m12A, - double m21A, double m22A, - Display *displayA, - XOutputDev *xOutA): - XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA, - m11A, m12A, m21A, m22A, displayA, xOutA) -{ - double size, ntm11, ntm12, ntm21, ntm22; - GBool rotated; - int startSize, sz; - char fontName[500], fontSize[100]; - - xUMap = xUMapA; - xUMap->incRefCnt(); - - // compute size and normalized transform matrix - size = sqrt(m21*m21 + m22*m22); - ntm11 = m11 / size; - ntm12 = -m12 / size; - ntm21 = m21 / size; - ntm22 = -m22 / size; - - // try to get a rotated font? - rotated = !(ntm11 > 0 && ntm22 > 0 && - fabs(ntm11 / ntm22 - 1) < 0.2 && - fabs(ntm12) < 0.01 && - fabs(ntm21) < 0.01); - - // open X font -- if font is not found (which means the server can't - // scale fonts), try progressively smaller and then larger sizes - startSize = (int)size; - if (rotated) { - sprintf(fontSize, "[%s%0.2f %s%0.2f %s%0.2f %s%0.2f]", - ntm11<0 ? "~" : "", fabs(ntm11 * size), - ntm12<0 ? "~" : "", fabs(ntm12 * size), - ntm21<0 ? "~" : "", fabs(ntm21 * size), - ntm22<0 ? "~" : "", fabs(ntm22 * size)); - } else { - sprintf(fontSize, "%d", startSize); - } - stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize); - xFont = XLoadQueryFont(display, fontName); - if (!xFont) { - for (sz = startSize; sz >= startSize/2 && sz >= 1; --sz) { - sprintf(fontSize, "%d", sz); - stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize); - if ((xFont = XLoadQueryFont(display, fontName))) - break; - } - if (!xFont) { - for (sz = startSize + 1; sz < startSize + 10; ++sz) { - sprintf(fontSize, "%d", sz); - stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), - fontSize); - if ((xFont = XLoadQueryFont(display, fontName))) { - break; - } - } - if (!xFont) { - sprintf(fontSize, "%d", startSize); - stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), - fontSize); - error(-1, "Failed to open font: '%s'", fontName); - return; - } - } - } -} - -XOutputServer16BitFont::~XOutputServer16BitFont() { - xUMap->decRefCnt(); - if (xFont) { - XFreeFont(display, xFont); - } -} - -GBool XOutputServer16BitFont::isOk() { - return xFont != NULL; -} - -void XOutputServer16BitFont::updateGC(GC gc) { - XSetFont(display, gc, xFont->fid); -} - -void XOutputServer16BitFont::drawChar(GfxState *state, Pixmap pixmap, - int w, int h, GC gc, GfxRGB *rgb, - double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen) { - char buf[16]; - XChar2b c1; - double dx1, dy1; - int m, n, i, j, k; - - n = 0; - for (i = 0; i < uLen; ++i) { - n += xUMap->mapUnicode(u[i], buf, sizeof(buf)); - } - if (n > 0) { - dx1 = dx / n; - dy1 = dy / n; - k = 0; - for (i = 0; i < uLen; ++i) { - m = xUMap->mapUnicode(u[i], buf, sizeof(buf)); - for (j = 0; j+1 < m; j += 2) { - c1.byte1 = buf[j]; - c1.byte2 = buf[j+1]; - XDrawString16(display, pixmap, gc, - xoutRound(x + k*dx1), xoutRound(y + k*dy1), - &c1, 1); - ++k; - } - } - } else if (c != 0) { - // some PDF files use CID 0, which is .notdef, so just ignore it - error(-1, "Unknown character (CID=%d Unicode=%04x)", - c, uLen > 0 ? u[0] : (Unicode)0); - } -} - -//------------------------------------------------------------------------ -// XOutputFontCache -//------------------------------------------------------------------------ - -#if HAVE_T1LIB_H -XOutputT1FontFile::~XOutputT1FontFile() { - delete fontFile; - if (tmpFileName) { - unlink(tmpFileName->getCString()); - delete tmpFileName; - } -} -#endif - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -XOutputFTFontFile::~XOutputFTFontFile() { - delete fontFile; - if (tmpFileName) { - unlink(tmpFileName->getCString()); - delete tmpFileName; - } -} -#endif - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -XOutputTTFontFile::~XOutputTTFontFile() { - delete fontFile; - if (tmpFileName) { - unlink(tmpFileName->getCString()); - delete tmpFileName; - } -} -#endif - -XOutputFontCache::XOutputFontCache(Display *displayA, Guint depthA, - XOutputDev *xOutA, - FontRastControl t1libControlA, - FontRastControl freetypeControlA) { - display = displayA; - depth = depthA; - xOut = xOutA; - -#if HAVE_T1LIB_H - t1libControl = t1libControlA; - t1Engine = NULL; - t1FontFiles = NULL; -#endif - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - freetypeControl = freetypeControlA; - ftEngine = NULL; - ftFontFiles = NULL; -#endif -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - freetypeControl = freetypeControlA; - ttEngine = NULL; - ttFontFiles = NULL; -#endif - - clear(); -} - -XOutputFontCache::~XOutputFontCache() { - delFonts(); -} - -void XOutputFontCache::startDoc(int screenNum, Visual *visual, - Colormap colormap, GBool trueColor, - int rMul, int gMul, int bMul, - int rShift, int gShift, int bShift, - Gulong *colors, int numColors) { - delFonts(); - clear(); - -#if HAVE_T1LIB_H - if (t1libControl != fontRastNone) { - t1Engine = new T1FontEngine(display, visual, depth, colormap, - t1libControl == fontRastAALow || - t1libControl == fontRastAAHigh, - t1libControl == fontRastAAHigh); - if (t1Engine->isOk()) { - if (trueColor) { - t1Engine->useTrueColor(rMul, rShift, gMul, gShift, bMul, bShift); - } else { - t1Engine->useColorCube(colors, numColors); - } - } else { - delete t1Engine; - t1Engine = NULL; - } - } -#endif // HAVE_T1LIB_H - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (freetypeControl != fontRastNone) { - ftEngine = new FTFontEngine(display, visual, depth, colormap, - freetypeControl == fontRastAALow || - freetypeControl == fontRastAAHigh); - if (ftEngine->isOk()) { - if (trueColor) { - ftEngine->useTrueColor(rMul, rShift, gMul, gShift, bMul, bShift); - } else { - ftEngine->useColorCube(colors, numColors); - } - } else { - delete ftEngine; - ftEngine = NULL; - } - } -#endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (freetypeControl != fontRastNone) { - ttEngine = new TTFontEngine(display, visual, depth, colormap, - freetypeControl == fontRastAALow || - freetypeControl == fontRastAAHigh); - if (ttEngine->isOk()) { - if (trueColor) { - ttEngine->useTrueColor(rMul, rShift, gMul, gShift, bMul, bShift); - } else { - ttEngine->useColorCube(colors, numColors); - } - } else { - delete ttEngine; - ttEngine = NULL; - } - } -#endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -} - -void XOutputFontCache::delFonts() { - int i; - - for (i = 0; i < nFonts; ++i) { - delete fonts[i]; - } - -#if HAVE_T1LIB_H - // delete Type 1 font files - if (t1FontFiles) { - deleteGList(t1FontFiles, XOutputT1FontFile); - t1FontFiles = NULL; - } - if (t1Engine) { - delete t1Engine; - t1Engine = NULL; - } -#endif - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - // delete FreeType font files - if (ftFontFiles) { - deleteGList(ftFontFiles, XOutputFTFontFile); - ftFontFiles = NULL; - } - if (ftEngine) { - delete ftEngine; - ftEngine = NULL; - } -#endif - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - // delete TrueType fonts - if (ttFontFiles) { - deleteGList(ttFontFiles, XOutputTTFontFile); - ttFontFiles = NULL; - } - if (ttEngine) { - delete ttEngine; - ttEngine = NULL; - } -#endif -} - -void XOutputFontCache::clear() { - int i; - - for (i = 0; i < xOutFontCacheSize; ++i) { - fonts[i] = NULL; - } - nFonts = 0; - -#if HAVE_T1LIB_H - // clear Type 1 font files - t1FontFiles = new GList(); -#endif - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - // clear FreeType font cache - ftFontFiles = new GList(); -#endif - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - // clear TrueType font cache - ttFontFiles = new GList(); -#endif -} - -XOutputFont *XOutputFontCache::getFont(XRef *xref, GfxFont *gfxFont, - double m11, double m12, - double m21, double m22) { - XOutputFont *font; - DisplayFontParam *dfp; - GString *substName; - double m11New, m12New, m21New, m22New; - double w1, w2, v; - double *fm; - char *name; - int index; - int code; - int i, j; - - // is it the most recently used font? - if (nFonts > 0 && fonts[0]->matches(gfxFont->getID(), m11, m12, m21, m22)) { - return fonts[0]; - } - - // is it in the cache? - for (i = 1; i < nFonts; ++i) { - if (fonts[i]->matches(gfxFont->getID(), m11, m12, m21, m22)) { - font = fonts[i]; - for (j = i; j > 0; --j) { - fonts[j] = fonts[j-1]; - } - fonts[0] = font; - return font; - } - } - - // try for a cached FontFile, an embedded font, or an external font - // file - font = NULL; - switch (gfxFont->getType()) { - case fontType1: - case fontType1C: -#if HAVE_T1LIB_H - if (t1libControl != fontRastNone) { - font = tryGetT1Font(xref, gfxFont, m11, m12, m21, m22); - } -#endif -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (!font) { - if (freetypeControl != fontRastNone) { - font = tryGetFTFont(xref, gfxFont, m11, m12, m21, m22); - } - } -#endif - break; - case fontTrueType: - case fontCIDType2: -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (freetypeControl != fontRastNone) { - font = tryGetFTFont(xref, gfxFont, m11, m12, m21, m22); - } -#endif -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (freetypeControl != fontRastNone) { - font = tryGetTTFont(xref, gfxFont, m11, m12, m21, m22); - } -#endif - break; - case fontCIDType0: - case fontCIDType0C: -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (freetypeControl != fontRastNone) { - font = tryGetFTFont(xref, gfxFont, m11, m12, m21, m22); - } -#endif - break; - default: - break; - } - - if (!font) { - - // search for a display font mapping - dfp = NULL; - if (gfxFont->isCIDFont()) { - if (((GfxCIDFont *)gfxFont)->getCollection()) { - dfp = globalParams-> - getDisplayCIDFont(gfxFont->getName(), - ((GfxCIDFont *)gfxFont)->getCollection()); - } else { - // this error (no CMap file) was already reported by GfxFont - return NULL; - } - } else { - if (gfxFont->getName()) { - dfp = globalParams->getDisplayFont(gfxFont->getName()); - } - } - if (dfp) { - font = tryGetFont(xref, dfp, gfxFont, m11, m12, m21, m22, - m11, m12, m21, m22, gFalse); - } - - // substitute a font (8-bit fonts only) - if (!font && !gfxFont->isCIDFont()) { - - // choose a substitute font - if (gfxFont->isFixedWidth()) { - index = 8; - } else if (gfxFont->isSerif()) { - index = 4; - } else { - index = 0; - } - if (gfxFont->isBold()) { - index += 2; - } - if (gfxFont->isItalic()) { - index += 1; - } - substName = new GString(xOutSubstFonts[index].name); - - // adjust the font matrix -- compare the width of 'm' in the - // original font and the substituted font - m11New = m11; - m12New = m12; - m21New = m21; - m22New = m22; - for (code = 0; code < 256; ++code) { - if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) && - name[0] == 'm' && name[1] == '\0') { - break; - } - } - if (code < 256) { - w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code); - w2 = xOutSubstFonts[index].mWidth; - if (gfxFont->getType() == fontType3) { - // This is a hack which makes it possible to substitute for some - // Type 3 fonts. The problem is that it's impossible to know what - // the base coordinate system used in the font is without actually - // rendering the font. This code tries to guess by looking at the - // width of the character 'm' (which breaks if the font is a - // subset that doesn't contain 'm'). - if (w1 > 0 && (w1 > 1.1 * w2 || w1 < 0.9 * w2)) { - w1 /= w2; - m11New *= w1; - m12New *= w1; - m21New *= w1; - m22New *= w1; - } - fm = gfxFont->getFontMatrix(); - v = (fm[0] == 0) ? 1 : (fm[3] / fm[0]); - m21New *= v; - m22New *= v; - } else if (!gfxFont->isSymbolic()) { - // if real font is substantially narrower than substituted - // font, reduce the font size accordingly - if (w1 > 0.01 && w1 < 0.9 * w2) { - w1 /= w2; - m11New *= w1; - m21New *= w1; - } - } - } - - // get the font - dfp = globalParams->getDisplayFont(substName); - delete substName; - if (!dfp) { - // this should never happen since GlobalParams sets up default - // mappings for the Base-14 fonts - error(-1, "Couldn't find a font for '%s'", - gfxFont->getName()->getCString()); - return NULL; - } - font = tryGetFont(xref, dfp, gfxFont, m11, m12, m21, m22, - m11New, m12New, m21New, m22New, gTrue); - } - } - - // check for error - if (!font) { - // This will happen if the user specifies a bogus font in the - // config file (a non-existent font file or a font that requires a - // rasterizer that is disabled or wasn't built in), or if a CID - // font has no associated font in the config file. - if (gfxFont->isCIDFont()) { - error(-1, "Couldn't find a font for the '%s' character collection", - ((GfxCIDFont *)gfxFont)->getCollection()->getCString()); - } else { - error(-1, "Couldn't find a font for '%s'", - gfxFont->getName() ? - gfxFont->getName()->getCString() : "[unnamed]"); - } - return NULL; - } - - // insert font in cache - if (nFonts == xOutFontCacheSize) { - --nFonts; - delete fonts[nFonts]; - } - for (j = nFonts; j > 0; --j) { - fonts[j] = fonts[j-1]; - } - fonts[0] = font; - ++nFonts; - - return font; -} - -XOutputFont *XOutputFontCache::tryGetFont(XRef *xref, DisplayFontParam *dfp, - GfxFont *gfxFont, - double m11Orig, double m12Orig, - double m21Orig, double m22Orig, - double m11, double m12, - double m21, double m22, - GBool subst) { - XOutputFont *font; - - font = NULL; - - // create the new font - switch (dfp->kind) { - - case displayFontX: - font = tryGetServerFont(dfp->x.xlfd, dfp->x.encoding, gfxFont, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22); - break; - - case displayFontT1: -#if HAVE_T1LIB_H - if (t1libControl != fontRastNone && !gfxFont->isCIDFont()) { - font = tryGetT1FontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, subst); - } -#endif -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (!font) { - if (freetypeControl != fontRastNone) { - font = tryGetFTFontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, gFalse, subst); - } - } -#endif -#if !((FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)) || defined(HAVE_T1LIB_H)) - error(-1, "Config file specifies a Type 1 font,"); - error(-1, "but xpdf was not built with t1lib or FreeType2 support"); -#endif - break; - - case displayFontTT: -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (freetypeControl != fontRastNone) { - font = tryGetFTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, gFalse, subst); - } -#endif -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (freetypeControl != fontRastNone) { - font = tryGetTTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, subst); - } -#endif -#if !(HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - error(-1, "Config file specifies a TrueType font,"); - error(-1, "but xpdf was not built with FreeType support"); - dfp = NULL; -#endif - break; - } - - return font; -} - -#if HAVE_T1LIB_H -XOutputFont *XOutputFontCache::tryGetT1Font(XRef *xref, - GfxFont *gfxFont, - double m11, double m12, - double m21, double m22) { - Ref *id; - XOutputT1FontFile *xFontFile; - XOutputFont *font; - Ref embRef; - GString *fileName; - FILE *f; - char *fontBuf; - int fontLen; - Type1CFontFile *ff; - Object refObj, strObj; - int c; - int i; - - // check the already available font files - id = gfxFont->getID(); - for (i = 0; i < t1FontFiles->getLength(); ++i) { - xFontFile = (XOutputT1FontFile *)t1FontFiles->get(i); - if (xFontFile->num == id->num && xFontFile->gen == id->gen && - !xFontFile->subst) { - font = new XOutputT1Font(id, xFontFile->fontFile, - m11, m12, m21, m22, - m11, m12, m21, m22, display, xOut); - if (!font->isOk()) { - delete font; - return NULL; - } - return font; - } - } - - // check for an embedded font - if (gfxFont->getEmbeddedFontID(&embRef)) { - - // create the font file - fileName = NULL; - if (!openTempFile(&fileName, &f, "wb", NULL)) { - error(-1, "Couldn't create temporary Type 1 font file"); - return NULL; - } - if (gfxFont->getType() == fontType1C) { - if (!(fontBuf = gfxFont->readEmbFontFile(xref, &fontLen))) { - fclose(f); - unlink(fileName->getCString()); - delete fileName; - return NULL; - } - ff = new Type1CFontFile(fontBuf, fontLen); - if (!ff->isOk()) { - delete ff; - gfree(fontBuf); - unlink(fileName->getCString()); - delete fileName; - return NULL; - } - ff->convertToType1(outputToFile, f); - delete ff; - gfree(fontBuf); - } else { // fontType1 - refObj.initRef(embRef.num, embRef.gen); - refObj.fetch(xref, &strObj); - refObj.free(); - strObj.streamReset(); - while ((c = strObj.streamGetChar()) != EOF) { - fputc(c, f); - } - strObj.streamClose(); - strObj.free(); - } - fclose(f); - - // create the Font - font = tryGetT1FontFromFile(xref, fileName, gTrue, gfxFont, - m11, m12, m21, m22, - m11, m12, m21, m22, gFalse); - - // on systems with Unix hard link semantics, this will remove the - // last link to the temp file - unlink(fileName->getCString()); - - delete fileName; - - // check for an external font file - } else if ((fileName = gfxFont->getExtFontFile())) { - font = tryGetT1FontFromFile(xref, fileName, gFalse, gfxFont, - m11, m12, m21, m22, - m11, m12, m21, m22, gFalse); - - } else { - font = NULL; - } - - return font; -} - -XOutputFont *XOutputFontCache::tryGetT1FontFromFile(XRef *xref, - GString *fileName, - GBool deleteFile, - GfxFont *gfxFont, - double m11Orig, - double m12Orig, - double m21Orig, - double m22Orig, - double m11, double m12, - double m21, double m22, - GBool subst) { - Ref *id; - T1FontFile *fontFile; - XOutputFont *font; - - // create the t1lib font file - fontFile = new T1FontFile(t1Engine, fileName->getCString(), - ((Gfx8BitFont *)gfxFont)->getEncoding(), - gfxFont->getFontBBox()); - if (!fontFile->isOk()) { - error(-1, "Couldn't create t1lib font from '%s'", - fileName->getCString()); - delete fontFile; - if (deleteFile) { - unlink(fileName->getCString()); - } - return NULL; - } - - // add to list - id = gfxFont->getID(); - t1FontFiles->append(new XOutputT1FontFile(id->num, id->gen, - subst, fontFile, - deleteFile ? fileName->copy() - : (GString *)NULL)); - - // create the Font - font = new XOutputT1Font(gfxFont->getID(), fontFile, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, display, xOut); - if (!font->isOk()) { - delete font; - return NULL; - } - return font; -} -#endif // HAVE_T1LIB_H - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -XOutputFont *XOutputFontCache::tryGetFTFont(XRef *xref, - GfxFont *gfxFont, - double m11, double m12, - double m21, double m22) { - Ref *id; - XOutputFTFontFile *xFontFile; - XOutputFont *font; - Ref embRef; - GString *fileName; - FILE *f; -#if 1 //~ need this until FT can handle fonts with missing tables - char *fontBuf; - int fontLen; - TrueTypeFontFile *ff; -#endif - Object refObj, strObj; - int c; - int i; - - // check the already available font files - id = gfxFont->getID(); - for (i = 0; i < ftFontFiles->getLength(); ++i) { - xFontFile = (XOutputFTFontFile *)ftFontFiles->get(i); - if (xFontFile->num == id->num && xFontFile->gen == id->gen && - !xFontFile->subst) { - font = new XOutputFTFont(id, xFontFile->fontFile, - m11, m12, m21, m22, - m11, m12, m21, m22, display, xOut); - if (!font->isOk()) { - delete font; - return NULL; - } - return font; - } - } - - // check for an embedded font - if (gfxFont->getEmbeddedFontID(&embRef)) { - - // create the font file - fileName = NULL; - if (!openTempFile(&fileName, &f, "wb", NULL)) { - error(-1, "Couldn't create temporary TrueType font file"); - return NULL; - } -#if 1 //~ need this until FT can handle fonts with missing tables - if (gfxFont->getType() == fontTrueType || - gfxFont->getType() == fontCIDType2) { - if (!(fontBuf = gfxFont->readEmbFontFile(xref, &fontLen))) { - fclose(f); - unlink(fileName->getCString()); - delete fileName; - return NULL; - } - ff = new TrueTypeFontFile(fontBuf, fontLen); - ff->writeTTF(f); - delete ff; - gfree(fontBuf); - } else { - refObj.initRef(embRef.num, embRef.gen); - refObj.fetch(xref, &strObj); - refObj.free(); - strObj.streamReset(); - while ((c = strObj.streamGetChar()) != EOF) { - fputc(c, f); - } - strObj.streamClose(); - strObj.free(); - } -#else - refObj.initRef(embRef.num, embRef.gen); - refObj.fetch(xref, &strObj); - refObj.free(); - strObj.streamReset(); - while ((c = strObj.streamGetChar()) != EOF) { - fputc(c, f); - } - strObj.streamClose(); - strObj.free(); -#endif - fclose(f); - - // create the Font - font = tryGetFTFontFromFile(xref, fileName, gTrue, gfxFont, - m11, m12, m21, m22, - m11, m12, m21, m22, gTrue, gFalse); - - // on systems with Unix hard link semantics, this will remove the - // last link to the temp file - unlink(fileName->getCString()); - - delete fileName; - - // check for an external font file - } else if ((fileName = gfxFont->getExtFontFile())) { - font = tryGetFTFontFromFile(xref, fileName, gFalse, gfxFont, - m11, m12, m21, m22, - m11, m12, m21, m22, gFalse, gFalse); - - } else { - font = NULL; - } - - return font; -} - -XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref, - GString *fileName, - GBool deleteFile, - GfxFont *gfxFont, - double m11Orig, - double m12Orig, - double m21Orig, - double m22Orig, - double m11, double m12, - double m21, double m22, - GBool embedded, - GBool subst) { - Ref *id; - FTFontFile *fontFile; - XOutputFont *font; - char *buf; - int len; - FILE *f; - TrueTypeFontFile *ff; - Gushort *codeToGID; - - // create the FreeType font file - if (gfxFont->isCIDFont()) { - if (gfxFont->getType() == fontCIDType2) { - fontFile = new FTFontFile(ftEngine, fileName->getCString(), - ((GfxCIDFont *)gfxFont)->getCIDToGID(), - ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(), - embedded); - } else { // fontCIDType0, fontCIDType0C - fontFile = new FTFontFile(ftEngine, fileName->getCString(), embedded); - } - } else { - if (!(f = fopen(fileName->getCString(), "rb"))) { - return NULL; - } - fseek(f, 0, SEEK_END); - len = (int)ftell(f); - fseek(f, 0, SEEK_SET); - buf = (char *)gmalloc(len); - if ((int)fread(buf, 1, len, f) != len) { - gfree(buf); - fclose(f); - return NULL; - } - fclose(f); - ff = new TrueTypeFontFile(buf, len); - codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff); - fontFile = new FTFontFile(ftEngine, fileName->getCString(), - ((Gfx8BitFont *)gfxFont)->getEncoding(), - codeToGID); - gfree(codeToGID); - delete ff; - gfree(buf); - } - if (!fontFile->isOk()) { - error(-1, "Couldn't create FreeType font from '%s'", - fileName->getCString()); - delete fontFile; - if (deleteFile) { - unlink(fileName->getCString()); - } - return NULL; - } - - // add to list - id = gfxFont->getID(); - ftFontFiles->append(new XOutputFTFontFile(id->num, id->gen, - subst, fontFile, - deleteFile ? fileName->copy() - : (GString *)NULL)); - - // create the Font - font = new XOutputFTFont(gfxFont->getID(), fontFile, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, display, xOut); - if (!font->isOk()) { - delete font; - return NULL; - } - return font; -} -#endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -XOutputFont *XOutputFontCache::tryGetTTFont(XRef *xref, - GfxFont *gfxFont, - double m11, double m12, - double m21, double m22) { - Ref *id; - XOutputTTFontFile *xFontFile; - XOutputFont *font; - Ref embRef; - GString *fileName; - FILE *f; - Object refObj, strObj; - int c; - int i; - - // check the already available font files - id = gfxFont->getID(); - xFontFile = NULL; - for (i = 0; i < ttFontFiles->getLength(); ++i) { - xFontFile = (XOutputTTFontFile *)ttFontFiles->get(i); - if (xFontFile->num == id->num && xFontFile->gen == id->gen && - !xFontFile->subst) { - font = new XOutputTTFont(id, xFontFile->fontFile, - m11, m12, m21, m22, - m11, m12, m21, m22, display, xOut); - if (!font->isOk()) { - delete font; - return NULL; - } - return font; - } - } - - // check for an embedded font - if (gfxFont->getEmbeddedFontID(&embRef)) { - - // create the font file - fileName = NULL; - if (!openTempFile(&fileName, &f, "wb", NULL)) { - error(-1, "Couldn't create temporary TrueType font file"); - return NULL; - } - refObj.initRef(embRef.num, embRef.gen); - refObj.fetch(xref, &strObj); - refObj.free(); - strObj.streamReset(); - while ((c = strObj.streamGetChar()) != EOF) { - fputc(c, f); - } - strObj.streamClose(); - strObj.free(); - fclose(f); - - // create the Font - font = tryGetTTFontFromFile(xref, fileName, gTrue, gfxFont, - m11, m12, m21, m22, - m11, m12, m21, m22, gFalse); - - // on systems with Unix hard link semantics, this will remove the - // last link to the temp file - unlink(fileName->getCString()); - - delete fileName; - - } else if ((fileName = gfxFont->getExtFontFile())) { - font = tryGetTTFontFromFile(xref, fileName, gFalse, gfxFont, - m11, m12, m21, m22, - m11, m12, m21, m22, gFalse); - - } else { - font = NULL; - } - - return font; -} - -XOutputFont *XOutputFontCache::tryGetTTFontFromFile(XRef *xref, - GString *fileName, - GBool deleteFile, - GfxFont *gfxFont, - double m11Orig, - double m12Orig, - double m21Orig, - double m22Orig, - double m11, double m12, - double m21, double m22, - GBool subst) { - Ref *id; - TTFontFile *fontFile; - XOutputFont *font; - - // create the FreeType font file - if (gfxFont->isCIDFont()) { - // fontCIDType2 - fontFile = new TTFontFile(ttEngine, fileName->getCString(), - ((GfxCIDFont *)gfxFont)->getCIDToGID(), - ((GfxCIDFont *)gfxFont)->getCIDToGIDLen()); - } else { - fontFile = new TTFontFile(ttEngine, fileName->getCString(), - ((Gfx8BitFont *)gfxFont)->getEncoding(), - ((Gfx8BitFont *)gfxFont)->getHasEncoding()); - } - if (!fontFile->isOk()) { - error(-1, "Couldn't create FreeType font from '%s'", - fileName->getCString()); - delete fontFile; - if (deleteFile) { - unlink(fileName->getCString()); - } - return NULL; - } - - // add to list - id = gfxFont->getID(); - ttFontFiles->append(new XOutputTTFontFile(id->num, id->gen, - subst, fontFile, - deleteFile ? fileName->copy() - : (GString *)NULL)); - - // create the Font - font = new XOutputTTFont(gfxFont->getID(), fontFile, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, display, xOut); - if (!font->isOk()) { - delete font; - return NULL; - } - return font; -} -#endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -XOutputFont *XOutputFontCache::tryGetServerFont(GString *xlfd, - GString *encodingName, - GfxFont *gfxFont, - double m11Orig, double m12Orig, - double m21Orig, double m22Orig, - double m11, double m12, - double m21, double m22) { - XOutputFont *font; - UnicodeMap *uMap; - CharCodeToUnicode *ctu; - - uMap = globalParams->getUnicodeMap(encodingName); - if (gfxFont->isCIDFont()) { - ctu = ((GfxCIDFont *)gfxFont)->getToUnicode(); - font = new XOutputServer16BitFont(gfxFont->getID(), xlfd, uMap, ctu, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, - display, xOut); - ctu->decRefCnt(); - } else { - ctu = ((Gfx8BitFont *)gfxFont)->getToUnicode(); - font = new XOutputServer8BitFont(gfxFont->getID(), xlfd, uMap, ctu, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, - display, xOut); - ctu->decRefCnt(); - } - uMap->decRefCnt(); - if (!font->isOk()) { - delete font; - return NULL; - } - return font; -} - -//------------------------------------------------------------------------ -// T3FontCache -//------------------------------------------------------------------------ - -struct T3FontCacheTag { - Gushort code; - Gushort mru; // valid bit (0x8000) and MRU index - double wx, wy; // untransformed glyph metrics -}; - -class T3FontCache { -public: - - T3FontCache(Ref *fontID, double m11A, double m12A, - double m21A, double m22A, - int glyphXA, int glyphYA, int glyphWA, int glyphHA, - Display *displayA, Visual *visual, Guint depth, - Pixmap origPixmap); - ~T3FontCache(); - GBool matches(Ref *idA, double m11A, double m12A, - double m21A, double m22A) - { return fontID.num == idA->num && fontID.gen == idA->gen && - m11 == m11A && m12 == m12A && m21 == m21A && m22 == m22A; } - - Ref fontID; // PDF font ID - double m11, m12, m21, m22; // transform matrix - int glyphX, glyphY; // pixel offset of glyph pixmaps - int glyphW, glyphH; // size of glyph pixmaps, in pixels - int glyphSize; // size of glyph pixmaps, in bytes - int cacheSets; // number of sets in cache - int cacheAssoc; // cache associativity (glyphs per set) - Guchar *cacheData; // glyph pixmap cache - T3FontCacheTag *cacheTags; // cache tags, i.e., char codes - Display *display; - Pixmap pixmap; - XImage *image; -}; - -T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A, - double m21A, double m22A, - int glyphXA, int glyphYA, int glyphWA, int glyphHA, - Display *displayA, Visual *visual, Guint depth, - Pixmap origPixmap) { - int i; - - fontID = *fontIDA; - m11 = m11A; - m12 = m12A; - m21 = m21A; - m22 = m22A; - glyphX = glyphXA; - glyphY = glyphYA; - glyphW = glyphWA; - glyphH = glyphHA; - glyphSize = glyphW * glyphH; - cacheAssoc = 8; - if (glyphSize <= 256) { - cacheSets = 8; - } else if (glyphSize <= 512) { - cacheSets = 4; - } else if (glyphSize <= 1024) { - cacheSets = 2; - } else { - cacheSets = 1; - } - cacheData = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize); - cacheTags = (T3FontCacheTag *)gmalloc(cacheSets * cacheAssoc * - sizeof(T3FontCacheTag)); - for (i = 0; i < cacheSets * cacheAssoc; ++i) { - cacheTags[i].mru = i & (cacheAssoc - 1); - } - display = displayA; - pixmap = XCreatePixmap(display, origPixmap, glyphW, glyphH, depth); - image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, - glyphW, glyphH, 8, 0); - image->data = (char *)gmalloc(glyphH * image->bytes_per_line); -} - -T3FontCache::~T3FontCache() { - gfree(cacheData); - gfree(cacheTags); - XFreePixmap(display, pixmap); - gfree(image->data); - image->data = NULL; - XDestroyImage(image); -} - -struct T3GlyphStack { - GBool cacheable; - Gushort code; - T3FontCache *cache; - int cacheIdx; - T3FontCacheTag *cacheTag; - Guchar *cacheData; - double x, y; - Unicode *u; - int uLen; - GfxRGB color; - int origPixmapW, origPixmapH; - Pixmap origPixmap; - GC origStrokeGC; - GC origFillGC; - Region origClipRegion; - double origCTM4, origCTM5; - double wx, wy; // untransformed glyph metrics - T3GlyphStack *next; -}; - -//------------------------------------------------------------------------ -// XOutputDev -//------------------------------------------------------------------------ - -XOutputDev::XOutputDev(Display *displayA, int screenNumA, - Visual *visualA, Colormap colormapA, - GBool reverseVideoA, unsigned long paperColorA, - GBool installCmap, int rgbCubeSize, - int forceDepth) { - XVisualInfo visualTempl; - XVisualInfo *visualList; - int nVisuals; - Gulong mask; - XColor xcolor; - XColor *xcolors; - int r, g, b, n, m; - GBool ok; - - // no document yet - xref = NULL; - - // display / screen / visual / colormap - display = displayA; - screenNum = screenNumA; - visual = visualA; - colormap = colormapA; - - // no pixmap yet - pixmapW = pixmapH = 0; - - // check for TrueColor visual - if (forceDepth != 0) { - depth = forceDepth; - trueColor = depth >= 16; - } else { - visualTempl.visualid = XVisualIDFromVisual(visual); - visualList = XGetVisualInfo(display, VisualIDMask, - &visualTempl, &nVisuals); - if (nVisuals < 1) { - // this shouldn't happen - XFree((XPointer)visualList); - visualList = XGetVisualInfo(display, VisualNoMask, &visualTempl, - &nVisuals); - } - depth = visualList->depth; - if (visualList->c_class == TrueColor) { - trueColor = gTrue; - for (mask = visualList->red_mask, rShift = 0; - mask && !(mask & 1); - mask >>= 1, ++rShift) ; - rMul = (int)mask; - for (mask = visualList->green_mask, gShift = 0; - mask && !(mask & 1); - mask >>= 1, ++gShift) ; - gMul = (int)mask; - for (mask = visualList->blue_mask, bShift = 0; - mask && !(mask & 1); - mask >>= 1, ++bShift) ; - bMul = (int)mask; - } else { - trueColor = gFalse; - } - XFree((XPointer)visualList); - } - - // allocate a color cube - if (!trueColor) { - redMap[BlackPixel(display, screenNum) & 0xff] = 0; - redMap[WhitePixel(display, screenNum) & 0xff] = 1; - - // set colors in private colormap - if (installCmap) { - for (numColors = 6; numColors >= 2; --numColors) { - m = numColors * numColors * numColors; - if (XAllocColorCells(display, colormap, False, NULL, 0, colors, m)) { - break; - } - } - if (numColors >= 2) { - m = numColors * numColors * numColors; - xcolors = (XColor *)gmalloc(m * sizeof(XColor)); - n = 0; - for (r = 0; r < numColors; ++r) { - for (g = 0; g < numColors; ++g) { - for (b = 0; b < numColors; ++b) { - xcolors[n].pixel = colors[n]; - xcolors[n].red = (r * 65535) / (numColors - 1); - xcolors[n].green = (g * 65535) / (numColors - 1); - xcolors[n].blue = (b * 65535) / (numColors - 1); - xcolors[n].flags = DoRed | DoGreen | DoBlue; - redMap[xcolors[n].pixel & 0xff] = xcolors[n].red / 65535.0; - ++n; - } - } - } - XStoreColors(display, colormap, xcolors, m); - gfree(xcolors); - } else { - numColors = 1; - colors[0] = BlackPixel(display, screenNum); - colors[1] = WhitePixel(display, screenNum); - } - - // allocate colors in shared colormap - } else { - if (rgbCubeSize > maxRGBCube) { - rgbCubeSize = maxRGBCube; - } - ok = gFalse; - for (numColors = rgbCubeSize; numColors >= 2; --numColors) { - ok = gTrue; - n = 0; - for (r = 0; r < numColors && ok; ++r) { - for (g = 0; g < numColors && ok; ++g) { - for (b = 0; b < numColors && ok; ++b) { - if (n == 0) { - colors[n] = BlackPixel(display, screenNum); - redMap[colors[n] & 0xff] = 0; - ++n; - } else { - xcolor.red = (r * 65535) / (numColors - 1); - xcolor.green = (g * 65535) / (numColors - 1); - xcolor.blue = (b * 65535) / (numColors - 1); - if (XAllocColor(display, colormap, &xcolor)) { - colors[n++] = xcolor.pixel; - redMap[xcolor.pixel & 0xff] = xcolor.red / 65535.0; - } else { - ok = gFalse; - } - } - } - } - } - if (ok) { - break; - } - XFreeColors(display, colormap, &colors[1], n-1, 0); - } - if (!ok) { - numColors = 1; - colors[0] = BlackPixel(display, screenNum); - colors[1] = WhitePixel(display, screenNum); - } - } - } - - // misc parameters - reverseVideo = reverseVideoA; - paperColor = paperColorA; - - // set up the font cache and fonts - gfxFont = NULL; - font = NULL; - needFontUpdate = gFalse; - fontCache = new XOutputFontCache(display, depth, this, - globalParams->getT1libControl(), - globalParams->getFreeTypeControl()); - nT3Fonts = 0; - t3GlyphStack = NULL; - - // no text outline clipping path - textClipPath = NULL; - - // empty state stack - save = NULL; - - // create text object - text = new TextPage(gFalse); -} - -XOutputDev::~XOutputDev() { - int i; - - delete fontCache; - for (i = 0; i < nT3Fonts; ++i) { - delete t3FontCache[i]; - } - delete text; -} - -void XOutputDev::startDoc(XRef *xrefA) { - int i; - - xref = xrefA; - fontCache->startDoc(screenNum, visual, colormap, trueColor, rMul, gMul, bMul, - rShift, gShift, bShift, colors, numColors); - for (i = 0; i < nT3Fonts; ++i) { - delete t3FontCache[i]; - } - nT3Fonts = 0; -} - -void XOutputDev::startPage(int pageNum, GfxState *state) { - XGCValues gcValues; - XRectangle rect; - - // default line flatness - flatness = 0; - - // allocate GCs - gcValues.foreground = BlackPixel(display, screenNum); - gcValues.background = WhitePixel(display, screenNum); - gcValues.line_width = 0; - gcValues.line_style = LineSolid; - strokeGC = XCreateGC(display, pixmap, - GCForeground | GCBackground | GCLineWidth | GCLineStyle, - &gcValues); - fillGC = XCreateGC(display, pixmap, - GCForeground | GCBackground | GCLineWidth | GCLineStyle, - &gcValues); - gcValues.foreground = paperColor; - paperGC = XCreateGC(display, pixmap, - GCForeground | GCBackground | GCLineWidth | GCLineStyle, - &gcValues); - - // initialize clip region - clipRegion = XCreateRegion(); - rect.x = rect.y = 0; - rect.width = pixmapW; - rect.height = pixmapH; - XUnionRectWithRegion(&rect, clipRegion, clipRegion); - XSetRegion(display, strokeGC, clipRegion); - XSetRegion(display, fillGC, clipRegion); - - // clear font - gfxFont = NULL; - font = NULL; - - // clear window - XFillRectangle(display, pixmap, paperGC, 0, 0, pixmapW, pixmapH); - - // clear text object - text->startPage(state); -} - -void XOutputDev::endPage() { - XOutputState *s; - - text->coalesce(gTrue); - - // clear state stack, free all GCs, free the clip region - while (save) { - s = save; - save = save->next; - XFreeGC(display, s->strokeGC); - XFreeGC(display, s->fillGC); - XDestroyRegion(s->clipRegion); - delete s; - } - XFreeGC(display, strokeGC); - XFreeGC(display, fillGC); - XFreeGC(display, paperGC); - XDestroyRegion(clipRegion); -} - -void XOutputDev::drawLink(Link *link, Catalog *catalog) { - double x1, y1, x2, y2; - LinkBorderStyle *borderStyle; - GfxRGB rgb; - double *dash; - char dashList[20]; - int dashLength; - XPoint points[5]; - int x, y, i; - - link->getRect(&x1, &y1, &x2, &y2); - borderStyle = link->getBorderStyle(); - if (borderStyle->getWidth() > 0) { - borderStyle->getColor(&rgb.r, &rgb.g, &rgb.b); - XSetForeground(display, strokeGC, findColor(&rgb)); - borderStyle->getDash(&dash, &dashLength); - if (borderStyle->getType() == linkBorderDashed && dashLength > 0) { - if (dashLength > 20) { - dashLength = 20; - } - for (i = 0; i < dashLength; ++i) { - if ((dashList[i] = xoutRound(dash[i])) == 0) { - dashList[i] = 1; - } - } - XSetLineAttributes(display, strokeGC, xoutRound(borderStyle->getWidth()), - LineOnOffDash, CapButt, JoinMiter); - XSetDashes(display, strokeGC, 0, dashList, dashLength); - } else { - XSetLineAttributes(display, strokeGC, xoutRound(borderStyle->getWidth()), - LineSolid, CapButt, JoinMiter); - } - if (borderStyle->getType() == linkBorderUnderlined) { - cvtUserToDev(x1, y1, &x, &y); - points[0].x = x; - points[0].y = y; - cvtUserToDev(x2, y1, &x, &y); - points[1].x = x; - points[1].y = y; - XDrawLine(display, pixmap, strokeGC, points[0].x, points[0].y, - points[1].x, points[1].y); - } else { - cvtUserToDev(x1, y1, &x, &y); - points[0].x = points[4].x = x; - points[0].y = points[4].y = y; - cvtUserToDev(x2, y1, &x, &y); - points[1].x = x; - points[1].y = y; - cvtUserToDev(x2, y2, &x, &y); - points[2].x = x; - points[2].y = y; - cvtUserToDev(x1, y2, &x, &y); - points[3].x = x; - points[3].y = y; - XDrawLines(display, pixmap, strokeGC, points, 5, CoordModeOrigin); - } - } -} - -void XOutputDev::saveState(GfxState *state) { - XOutputState *s; - XGCValues values; - - // save current state - s = new XOutputState; - s->strokeGC = strokeGC; - s->fillGC = fillGC; - s->clipRegion = clipRegion; - - // push onto state stack - s->next = save; - save = s; - - // create a new current state by copying - strokeGC = XCreateGC(display, pixmap, 0, &values); - XCopyGC(display, s->strokeGC, 0xffffffff, strokeGC); - fillGC = XCreateGC(display, pixmap, 0, &values); - XCopyGC(display, s->fillGC, 0xffffffff, fillGC); - clipRegion = XCreateRegion(); - XUnionRegion(s->clipRegion, clipRegion, clipRegion); - XSetRegion(display, strokeGC, clipRegion); - XSetRegion(display, fillGC, clipRegion); -} - -void XOutputDev::restoreState(GfxState *state) { - XOutputState *s; - - if (save) { - // kill current state - XFreeGC(display, strokeGC); - XFreeGC(display, fillGC); - XDestroyRegion(clipRegion); - - // restore state - flatness = state->getFlatness(); - strokeGC = save->strokeGC; - fillGC = save->fillGC; - clipRegion = save->clipRegion; - XSetRegion(display, strokeGC, clipRegion); - XSetRegion(display, fillGC, clipRegion); - - // pop state stack - s = save; - save = save->next; - delete s; - - // we'll need to restore the font - needFontUpdate = gTrue; - } -} - -void XOutputDev::updateAll(GfxState *state) { - updateLineAttrs(state, gTrue); - updateFlatness(state); - updateMiterLimit(state); - updateFillColor(state); - updateStrokeColor(state); - needFontUpdate = gTrue; -} - -void XOutputDev::updateCTM(GfxState *state, double m11, double m12, - double m21, double m22, double m31, double m32) { - updateLineAttrs(state, gTrue); -} - -void XOutputDev::updateLineDash(GfxState *state) { - updateLineAttrs(state, gTrue); -} - -void XOutputDev::updateFlatness(GfxState *state) { - flatness = state->getFlatness(); -} - -void XOutputDev::updateLineJoin(GfxState *state) { - updateLineAttrs(state, gFalse); -} - -void XOutputDev::updateLineCap(GfxState *state) { - updateLineAttrs(state, gFalse); -} - -// unimplemented -void XOutputDev::updateMiterLimit(GfxState *state) { -} - -void XOutputDev::updateLineWidth(GfxState *state) { - updateLineAttrs(state, gFalse); -} - -void XOutputDev::updateLineAttrs(GfxState *state, GBool updateDash) { - double width; - int cap, join; - double *dashPattern; - int dashLength; - double dashStart; - char dashList[20]; - int i; - - width = state->getTransformedLineWidth(); - switch (state->getLineCap()) { - case 0: cap = CapButt; break; - case 1: cap = CapRound; break; - case 2: cap = CapProjecting; break; - default: - error(-1, "Bad line cap style (%d)", state->getLineCap()); - cap = CapButt; - break; - } - switch (state->getLineJoin()) { - case 0: join = JoinMiter; break; - case 1: join = JoinRound; break; - case 2: join = JoinBevel; break; - default: - error(-1, "Bad line join style (%d)", state->getLineJoin()); - join = JoinMiter; - break; - } - state->getLineDash(&dashPattern, &dashLength, &dashStart); -#if 1 //~ work around a bug in XFree86 (???) - if (dashLength > 0 && cap == CapProjecting) { - cap = CapButt; - } -#endif - XSetLineAttributes(display, strokeGC, xoutRound(width), - dashLength > 0 ? LineOnOffDash : LineSolid, - cap, join); - if (updateDash && dashLength > 0) { - if (dashLength > 20) - dashLength = 20; - for (i = 0; i < dashLength; ++i) { - dashList[i] = xoutRound(state->transformWidth(dashPattern[i])); - if (dashList[i] == 0) - dashList[i] = 1; - } - XSetDashes(display, strokeGC, xoutRound(dashStart), dashList, dashLength); - } -} - -void XOutputDev::updateFillColor(GfxState *state) { - GfxRGB rgb; - - state->getFillRGB(&rgb); - if (reverseVideo) { - rgb.r = 1 - rgb.r; - rgb.g = 1 - rgb.g; - rgb.b = 1 - rgb.b; - } - XSetForeground(display, fillGC, findColor(&rgb)); -} - -void XOutputDev::updateStrokeColor(GfxState *state) { - GfxRGB rgb; - - state->getStrokeRGB(&rgb); - if (reverseVideo) { - rgb.r = 1 - rgb.r; - rgb.g = 1 - rgb.g; - rgb.b = 1 - rgb.b; - } - XSetForeground(display, strokeGC, findColor(&rgb)); -} - -void XOutputDev::updateFont(GfxState *state) { - double m11, m12, m21, m22; - - needFontUpdate = gFalse; - - text->updateFont(state); - - if (!(gfxFont = state->getFont())) { - font = NULL; - return; - } - if (gfxFont->getType() == fontType3) { - font = NULL; - return; - } - state->getFontTransMat(&m11, &m12, &m21, &m22); - m11 *= state->getHorizScaling(); - m12 *= state->getHorizScaling(); - font = fontCache->getFont(xref, gfxFont, m11, m12, m21, m22); - if (font) { - font->updateGC(fillGC); - font->updateGC(strokeGC); - } -} - -void XOutputDev::stroke(GfxState *state) { - XPoint *points; - int *lengths; - int n, size, numPoints, i, j; - - // transform points - n = convertPath(state, state->getPath(), - &points, &size, &numPoints, &lengths, gFalse); - - // draw each subpath - j = 0; - for (i = 0; i < n; ++i) { - XDrawLines(display, pixmap, strokeGC, points + j, lengths[i], - CoordModeOrigin); - j += lengths[i]; - } - - // free points and lengths arrays - if (points != tmpPoints) - gfree(points); - if (lengths != tmpLengths) - gfree(lengths); -} - -void XOutputDev::fill(GfxState *state) { - doFill(state, WindingRule); -} - -void XOutputDev::eoFill(GfxState *state) { - doFill(state, EvenOddRule); -} - -// -// X doesn't color the pixels on the right-most and bottom-most -// borders of a polygon. This means that one-pixel-thick polygons -// are not colored at all. I think this is supposed to be a -// feature, but I can't figure out why. So after it fills a -// polygon, it also draws lines around the border. This is done -// only for single-component polygons, since it's not very -// compatible with the compound polygon kludge (see convertPath()). -// -void XOutputDev::doFill(GfxState *state, int rule) { - XPoint *points; - int *lengths; - int n, size, numPoints, i, j; - - // set fill rule - XSetFillRule(display, fillGC, rule); - - // transform points, build separate polygons - n = convertPath(state, state->getPath(), - &points, &size, &numPoints, &lengths, gTrue); - - // fill them - j = 0; - for (i = 0; i < n; ++i) { - XFillPolygon(display, pixmap, fillGC, points + j, lengths[i], - Complex, CoordModeOrigin); - if (state->getPath()->getNumSubpaths() == 1) { - XDrawLines(display, pixmap, fillGC, points + j, lengths[i], - CoordModeOrigin); - } - j += lengths[i] + 1; - } - - // free points and lengths arrays - if (points != tmpPoints) - gfree(points); - if (lengths != tmpLengths) - gfree(lengths); -} - -void XOutputDev::clip(GfxState *state) { - doClip(state, state->getPath(), WindingRule); -} - -void XOutputDev::eoClip(GfxState *state) { - doClip(state, state->getPath(), EvenOddRule); -} - -void XOutputDev::doClip(GfxState *state, GfxPath *path, int rule) { - GfxSubpath *subpath; - Region region, region2; - XPoint rect[5]; - XPoint *points; - int *lengths; - double x0, y0, x1, y1, x2, y2, x3, y3; - GBool gotRect; - int n, size, numPoints, i, j; - - // special case for rectangular clipping paths -- this is a common - // case, and we want to make sure not to clip an extra pixel on the - // right and bottom edges due to the difference between the PDF and - // X rendering models - gotRect = gFalse; - if (path->getNumSubpaths() == 1) { - subpath = path->getSubpath(0); - if ((subpath->isClosed() && subpath->getNumPoints() == 5) || - (!subpath->isClosed() && subpath->getNumPoints() == 4)) { - state->transform(subpath->getX(0), subpath->getY(0), &x0, &y0); - state->transform(subpath->getX(1), subpath->getY(1), &x1, &y1); - state->transform(subpath->getX(2), subpath->getY(2), &x2, &y2); - state->transform(subpath->getX(3), subpath->getY(3), &x3, &y3); - if (fabs(x0-x1) < 1 && fabs(x2-x3) < 1 && - fabs(y0-y3) < 1 && fabs(y1-y2) < 1) { - if (x0 < x2) { - rect[0].x = rect[1].x = rect[4].x = (int)floor(x0); - rect[2].x = rect[3].x = (int)floor(x2) + 1; - } else { - rect[0].x = rect[1].x = rect[4].x = (int)floor(x0) + 1; - rect[2].x = rect[3].x = (int)floor(x2); - } - if (y0 < y1) { - rect[0].y = rect[3].y = rect[4].y = (int)floor(y0); - rect[1].y = rect[2].y = (int)floor(y1) + 1; - } else { - rect[0].y = rect[3].y = rect[4].y = (int)floor(y0) + 1; - rect[1].y = rect[2].y = (int)floor(y1); - } - gotRect = gTrue; - } else if (fabs(x0-x3) < 1 && fabs(x1-x2) < 1 && - fabs(y0-y1) < 1 && fabs(y2-y3) < 1) { - if (x0 < x1) { - rect[0].x = rect[3].x = rect[4].x = (int)floor(x0); - rect[1].x = rect[2].x = (int)floor(x1) + 1; - } else { - rect[0].x = rect[3].x = rect[4].x = (int)floor(x0) + 1; - rect[1].x = rect[2].x = (int)floor(x1); - } - if (y0 < y2) { - rect[0].y = rect[1].y = rect[4].y = (int)floor(y0); - rect[2].y = rect[3].y = (int)floor(y2) + 1; - } else { - rect[0].y = rect[1].y = rect[4].y = (int)floor(y0) + 1; - rect[2].y = rect[3].y = (int)floor(y2); - } - gotRect = gTrue; - } - } - } - - if (gotRect) { - region = XPolygonRegion(rect, 5, EvenOddRule); - - } else { - // transform points, build separate polygons - n = convertPath(state, path, &points, &size, &numPoints, &lengths, gTrue); - - // construct union of subpath regions - // (XPolygonRegion chokes if there aren't at least three points -- - // this happens if the PDF file does moveto/closepath/clip, which - // sets an empty clipping region) - if (lengths[0] > 2) { - region = XPolygonRegion(points, lengths[0], rule); - } else { - region = XCreateRegion(); - } - j = lengths[0] + 1; - for (i = 1; i < n; ++i) { - if (lengths[i] > 2) { - region2 = XPolygonRegion(points + j, lengths[i], rule); - } else { - region2 = XCreateRegion(); - } - XUnionRegion(region2, region, region); - XDestroyRegion(region2); - j += lengths[i] + 1; - } - - // free points and lengths arrays - if (points != tmpPoints) { - gfree(points); - } - if (lengths != tmpLengths) { - gfree(lengths); - } - } - - // intersect region with clipping region - XIntersectRegion(region, clipRegion, clipRegion); - XDestroyRegion(region); - XSetRegion(display, strokeGC, clipRegion); - XSetRegion(display, fillGC, clipRegion); -} - -// -// Transform points in the path and convert curves to line segments. -// Builds a set of subpaths and returns the number of subpaths. -// If <fillHack> is set, close any unclosed subpaths and activate a -// kludge for polygon fills: First, it divides up the subpaths into -// non-overlapping polygons by simply comparing bounding rectangles. -// Then it connects subaths within a single compound polygon to a single -// point so that X can fill the polygon (sort of). -// -int XOutputDev::convertPath(GfxState *state, GfxPath *path, - XPoint **points, int *size, - int *numPoints, int **lengths, GBool fillHack) { - BoundingRect *rects; - BoundingRect rect; - int n, i, ii, j, k, k0; - - // get path and number of subpaths - n = path->getNumSubpaths(); - - // allocate lengths array - if (n < numTmpSubpaths) - *lengths = tmpLengths; - else - *lengths = (int *)gmalloc(n * sizeof(int)); - - // allocate bounding rectangles array - if (fillHack) { - if (n < numTmpSubpaths) - rects = tmpRects; - else - rects = (BoundingRect *)gmalloc(n * sizeof(BoundingRect)); - } else { - rects = NULL; - } - - // do each subpath - *points = tmpPoints; - *size = numTmpPoints; - *numPoints = 0; - for (i = 0; i < n; ++i) { - - // transform the points - j = *numPoints; - convertSubpath(state, path->getSubpath(i), points, size, numPoints); - - // construct bounding rectangle - if (fillHack) { - rects[i].xMin = rects[i].xMax = (*points)[j].x; - rects[i].yMin = rects[i].yMax = (*points)[j].y; - for (k = j + 1; k < *numPoints; ++k) { - if ((*points)[k].x < rects[i].xMin) - rects[i].xMin = (*points)[k].x; - else if ((*points)[k].x > rects[i].xMax) - rects[i].xMax = (*points)[k].x; - if ((*points)[k].y < rects[i].yMin) - rects[i].yMin = (*points)[k].y; - else if ((*points)[k].y > rects[i].yMax) - rects[i].yMax = (*points)[k].y; - } - } - - // close subpath if necessary - if (fillHack && ((*points)[*numPoints-1].x != (*points)[j].x || - (*points)[*numPoints-1].y != (*points)[j].y)) { - addPoint(points, size, numPoints, (*points)[j].x, (*points)[j].y); - } - - // length of this subpath - (*lengths)[i] = *numPoints - j; - - // leave an extra point for compound fill hack - if (fillHack) - addPoint(points, size, numPoints, 0, 0); - } - - // kludge: munge any points that are *way* out of bounds - these can - // crash certain (buggy) X servers - for (i = 0; i < *numPoints; ++i) { - if ((*points)[i].x < -4 * pixmapW) { - (*points)[i].x = -4 * pixmapW; - } else if ((*points)[i].x > 4 * pixmapW) { - (*points)[i].x = 4 * pixmapW; - } - if ((*points)[i].y < -pixmapH) { - (*points)[i].y = -4 * pixmapH; - } else if ((*points)[i].y > 4 * pixmapH) { - (*points)[i].y = 4 * pixmapH; - } - } - - // combine compound polygons - if (fillHack) { - i = j = k = 0; - while (i < n) { - - // start with subpath i - rect = rects[i]; - (*lengths)[j] = (*lengths)[i]; - k0 = k; - (*points)[k + (*lengths)[i]] = (*points)[k0]; - k += (*lengths)[i] + 1; - ++i; - - // combine overlapping polygons - do { - - // look for the first subsequent subpath, if any, which overlaps - for (ii = i; ii < n; ++ii) { - if (rects[ii].xMax > rects[i].xMin && - rects[ii].xMin < rects[i].xMax && - rects[ii].yMax > rects[i].yMin && - rects[ii].yMin < rects[i].yMax) { - break; - } - } - - // if there is an overlap, combine the polygons - if (ii < n) { - for (; i <= ii; ++i) { - if (rects[i].xMin < rect.xMin) - rect.xMin = rects[j].xMin; - if (rects[i].xMax > rect.xMax) - rect.xMax = rects[j].xMax; - if (rects[i].yMin < rect.yMin) - rect.yMin = rects[j].yMin; - if (rects[i].yMax > rect.yMax) - rect.yMax = rects[j].yMax; - (*lengths)[j] += (*lengths)[i] + 1; - (*points)[k + (*lengths)[i]] = (*points)[k0]; - k += (*lengths)[i] + 1; - } - } - } while (ii < n && i < n); - - ++j; - } - - // free bounding rectangles - if (rects != tmpRects) - gfree(rects); - - n = j; - } - - return n; -} - -// -// Transform points in a single subpath and convert curves to line -// segments. -// -void XOutputDev::convertSubpath(GfxState *state, GfxSubpath *subpath, - XPoint **points, int *size, int *n) { - double x0, y0, x1, y1, x2, y2, x3, y3; - int m, i; - - m = subpath->getNumPoints(); - i = 0; - while (i < m) { - if (i >= 1 && subpath->getCurve(i)) { - state->transform(subpath->getX(i-1), subpath->getY(i-1), &x0, &y0); - state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1); - state->transform(subpath->getX(i+1), subpath->getY(i+1), &x2, &y2); - state->transform(subpath->getX(i+2), subpath->getY(i+2), &x3, &y3); - doCurve(points, size, n, x0, y0, x1, y1, x2, y2, x3, y3); - i += 3; - } else { - state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1); - addPoint(points, size, n, xoutRound(x1), xoutRound(y1)); - ++i; - } - } -} - -// -// Subdivide a Bezier curve. This uses floating point to avoid -// propagating rounding errors. (The curves look noticeably more -// jagged with integer arithmetic.) -// -void XOutputDev::doCurve(XPoint **points, int *size, int *n, - double x0, double y0, double x1, double y1, - double x2, double y2, double x3, double y3) { - double x[(1<<maxCurveSplits)+1][3]; - double y[(1<<maxCurveSplits)+1][3]; - int next[1<<maxCurveSplits]; - int p1, p2, p3; - double xx1, yy1, xx2, yy2; - double dx, dy, mx, my, d1, d2; - double xl0, yl0, xl1, yl1, xl2, yl2; - double xr0, yr0, xr1, yr1, xr2, yr2, xr3, yr3; - double xh, yh; - double flat; - - flat = (double)(flatness * flatness); - if (flat < 1) - flat = 1; - - // initial segment - p1 = 0; - p2 = 1<<maxCurveSplits; - x[p1][0] = x0; y[p1][0] = y0; - x[p1][1] = x1; y[p1][1] = y1; - x[p1][2] = x2; y[p1][2] = y2; - x[p2][0] = x3; y[p2][0] = y3; - next[p1] = p2; - - while (p1 < (1<<maxCurveSplits)) { - - // get next segment - xl0 = x[p1][0]; yl0 = y[p1][0]; - xx1 = x[p1][1]; yy1 = y[p1][1]; - xx2 = x[p1][2]; yy2 = y[p1][2]; - p2 = next[p1]; - xr3 = x[p2][0]; yr3 = y[p2][0]; - - // compute distances from control points to midpoint of the - // straight line (this is a bit of a hack, but it's much faster - // than computing the actual distances to the line) - mx = (xl0 + xr3) * 0.5; - my = (yl0 + yr3) * 0.5; - dx = xx1 - mx; - dy = yy1 - my; - d1 = dx*dx + dy*dy; - dx = xx2 - mx; - dy = yy2 - my; - d2 = dx*dx + dy*dy; - - // if curve is flat enough, or no more divisions allowed then - // add the straight line segment - if (p2 - p1 <= 1 || (d1 <= flat && d2 <= flat)) { - addPoint(points, size, n, xoutRound(xr3), xoutRound(yr3)); - p1 = p2; - - // otherwise, subdivide the curve - } else { - xl1 = (xl0 + xx1) * 0.5; - yl1 = (yl0 + yy1) * 0.5; - xh = (xx1 + xx2) * 0.5; - yh = (yy1 + yy2) * 0.5; - xl2 = (xl1 + xh) * 0.5; - yl2 = (yl1 + yh) * 0.5; - xr2 = (xx2 + xr3) * 0.5; - yr2 = (yy2 + yr3) * 0.5; - xr1 = (xh + xr2) * 0.5; - yr1 = (yh + yr2) * 0.5; - xr0 = (xl2 + xr1) * 0.5; - yr0 = (yl2 + yr1) * 0.5; - - // add the new subdivision points - p3 = (p1 + p2) / 2; - x[p1][1] = xl1; y[p1][1] = yl1; - x[p1][2] = xl2; y[p1][2] = yl2; - next[p1] = p3; - x[p3][0] = xr0; y[p3][0] = yr0; - x[p3][1] = xr1; y[p3][1] = yr1; - x[p3][2] = xr2; y[p3][2] = yr2; - next[p3] = p2; - } - } -} - -// -// Add a point to the points array. (This would use a generic resizable -// array type if C++ supported parameterized types in some reasonable -// way -- templates are a disgusting kludge.) -// -void XOutputDev::addPoint(XPoint **points, int *size, int *k, int x, int y) { - if (*k >= *size) { - *size += 32; - if (*points == tmpPoints) { - *points = (XPoint *)gmalloc(*size * sizeof(XPoint)); - memcpy(*points, tmpPoints, *k * sizeof(XPoint)); - } else { - *points = (XPoint *)grealloc(*points, *size * sizeof(XPoint)); - } - } - (*points)[*k].x = x; - (*points)[*k].y = y; - ++(*k); -} - -void XOutputDev::beginString(GfxState *state, GString *s) { - text->beginWord(state, state->getCurX(), state->getCurY()); -} - -void XOutputDev::endString(GfxState *state) { - text->endWord(); -} - -void XOutputDev::drawChar(GfxState *state, double x, double y, - double dx, double dy, - double originX, double originY, - CharCode code, Unicode *u, int uLen) { - int render; - double x1, y1, dx1, dy1; - GfxRGB rgb; - double saveCurX, saveCurY; - double *ctm; - double saveCTM[6]; - - if (needFontUpdate) { - updateFont(state); - } - - text->addChar(state, x, y, dx, dy, code, u, uLen); - - if (!font) { - return; - } - - // check for invisible text -- this is used by Acrobat Capture - render = state->getRender(); - if (render == 3) { - return; - } - - x -= originX; - y -= originY; - state->transform(x, y, &x1, &y1); - state->transformDelta(dx, dy, &dx1, &dy1); - - // fill - if (!(render & 1)) { - state->getFillRGB(&rgb); - if (reverseVideo) { - rgb.r = 1 - rgb.r; - rgb.g = 1 - rgb.g; - rgb.b = 1 - rgb.b; - } - font->drawChar(state, pixmap, pixmapW, pixmapH, fillGC, &rgb, - x1, y1, dx1, dy1, code, u, uLen); - } - - // stroke - if ((render & 3) == 1 || (render & 3) == 2) { - if (font->hasGetCharPath()) { - saveCurX = state->getCurX(); - saveCurY = state->getCurY(); - ctm = state->getCTM(); - memcpy(saveCTM, ctm, 6 * sizeof(double)); - state->setCTM(1, 0, 0, 1, x1, y1); - font->getCharPath(state, code, u, uLen); - stroke(state); - state->clearPath(); - state->setCTM(saveCTM[0], saveCTM[1], saveCTM[2], saveCTM[3], - saveCTM[4], saveCTM[5]); - state->moveTo(saveCurX, saveCurY); - } else { - // can't stroke the outline, so just fill it using the stroke - // color - state->getStrokeRGB(&rgb); - if (reverseVideo) { - rgb.r = 1 - rgb.r; - rgb.g = 1 - rgb.g; - rgb.b = 1 - rgb.b; - } - font->drawChar(state, pixmap, pixmapW, pixmapH, strokeGC, &rgb, - x1, y1, dx1, dy1, code, u, uLen); - } - } - - // clip - if (render & 4) { - if (font->hasGetCharPath()) { - saveCurX = state->getCurX(); - saveCurY = state->getCurY(); - font->getCharPath(state, code, u, uLen); - state->getPath()->offset(x1, y1); - if (textClipPath) { - textClipPath->append(state->getPath()); - } else { - textClipPath = state->getPath()->copy(); - } - state->clearPath(); - state->moveTo(saveCurX, saveCurY); - } - } -} - -GBool XOutputDev::beginType3Char(GfxState *state, - CharCode code, Unicode *u, int uLen) { - Ref *fontID; - double *ctm, *bbox; - GfxRGB color; - T3FontCache *t3Font; - T3GlyphStack *t3gs; - double x1, y1, xMin, yMin, xMax, yMax, xt, yt; - int i, j; - - if (needFontUpdate) { - updateFont(state); - } - if (!gfxFont) { - return gFalse; - } - fontID = gfxFont->getID(); - ctm = state->getCTM(); - state->transform(0, 0, &xt, &yt); - - // is it the first (MRU) font in the cache? - if (!(nT3Fonts > 0 && - t3FontCache[0]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3]))) { - - // is the font elsewhere in the cache? - for (i = 1; i < nT3Fonts; ++i) { - if (t3FontCache[i]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3])) { - t3Font = t3FontCache[i]; - for (j = i; j > 0; --j) { - t3FontCache[j] = t3FontCache[j - 1]; - } - t3FontCache[0] = t3Font; - break; - } - } - if (i >= nT3Fonts) { - - // create new entry in the font cache - if (nT3Fonts == xOutT3FontCacheSize) { - delete t3FontCache[nT3Fonts - 1]; - --nT3Fonts; - } - for (j = nT3Fonts; j > 0; --j) { - t3FontCache[j] = t3FontCache[j - 1]; - } - ++nT3Fonts; - bbox = gfxFont->getFontBBox(); - if (bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0) { - // broken bounding box -- just take a guess - xMin = xt - 5; - xMax = xMin + 30; - yMax = yt + 15; - yMin = yMax - 45; - } else { - state->transform(bbox[0], bbox[1], &x1, &y1); - xMin = xMax = x1; - yMin = yMax = y1; - state->transform(bbox[0], bbox[3], &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - state->transform(bbox[2], bbox[1], &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - state->transform(bbox[2], bbox[3], &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - } - t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3], - (int)floor(xMin - xt), - (int)floor(yMin - yt), - (int)ceil(xMax) - (int)floor(xMin) + 3, - (int)ceil(yMax) - (int)floor(yMin) + 3, - display, visual, depth, pixmap); - } - } - t3Font = t3FontCache[0]; - - // is the glyph in the cache? - i = (code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc; - for (j = 0; j < t3Font->cacheAssoc; ++j) { - if ((t3Font->cacheTags[i+j].mru & 0x8000) && - t3Font->cacheTags[i+j].code == code) { - state->getFillRGB(&color); - if (reverseVideo) { - color.r = 1 - color.r; - color.g = 1 - color.g; - color.b = 1 - color.b; - } - text->addChar(state, 0, 0, - t3Font->cacheTags[i+j].wx, t3Font->cacheTags[i+j].wy, - code, u, uLen); - drawType3Glyph(t3Font, &t3Font->cacheTags[i+j], - t3Font->cacheData + (i+j) * t3Font->glyphSize, - xt, yt, &color); - return gTrue; - } - } - - // push a new Type 3 glyph record - t3gs = new T3GlyphStack(); - t3gs->next = t3GlyphStack; - t3GlyphStack = t3gs; - t3GlyphStack->cacheable = gFalse; - t3GlyphStack->code = code; - t3GlyphStack->cache = t3Font; - t3GlyphStack->cacheIdx = i; - t3GlyphStack->x = xt; - t3GlyphStack->y = yt; - t3GlyphStack->u = u; - t3GlyphStack->uLen = uLen; - - return gFalse; -} - -void XOutputDev::endType3Char(GfxState *state) { - XImage *image; - Guchar *p; - int x, y; - Gulong pixel; - double alpha; - T3GlyphStack *t3gs; - double *ctm; - - if (t3GlyphStack->cacheable) { - image = t3GlyphStack->cache->image; - XGetSubImage(display, pixmap, 0, 0, - t3GlyphStack->cache->glyphW, t3GlyphStack->cache->glyphH, - (1 << depth) - 1, ZPixmap, image, 0, 0); - p = t3GlyphStack->cacheData; - for (y = 0; y < t3GlyphStack->cache->glyphH; ++y) { - for (x = 0; x < t3GlyphStack->cache->glyphW; ++x) { - pixel = XGetPixel(image, x, y); - if (trueColor) { - alpha = (double)((pixel >> rShift) & rMul) / (double)rMul; - } else { - alpha = redMap[pixel & 0xff]; - } - if (alpha <= 0.2) { - *p++ = 4; - } else if (alpha <= 0.4) { - *p++ = 3; - } else if (alpha <= 0.6) { - *p++ = 2; - } else if (alpha <= 0.8) { - *p++ = 1; - } else { - *p++ = 0; - } - } - } - XDestroyRegion(clipRegion); - XFreeGC(display, strokeGC); - XFreeGC(display, fillGC); - pixmapW = t3GlyphStack->origPixmapW; - pixmapH = t3GlyphStack->origPixmapH; - pixmap = t3GlyphStack->origPixmap; - strokeGC = t3GlyphStack->origStrokeGC; - fillGC = t3GlyphStack->origFillGC; - clipRegion = t3GlyphStack->origClipRegion; - drawType3Glyph(t3GlyphStack->cache, - t3GlyphStack->cacheTag, t3GlyphStack->cacheData, - t3GlyphStack->x, t3GlyphStack->y, &t3GlyphStack->color); - // the CTM must be restored here in order for TextPage::addChar to - // work correctly - ctm = state->getCTM(); - state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3], - t3GlyphStack->origCTM4, t3GlyphStack->origCTM5); - } - text->addChar(state, 0, 0, t3GlyphStack->wx, t3GlyphStack->wy, - t3GlyphStack->code, t3GlyphStack->u, t3GlyphStack->uLen); - t3gs = t3GlyphStack; - t3GlyphStack = t3gs->next; - delete t3gs; -} - -void XOutputDev::drawType3Glyph(T3FontCache *t3Font, - T3FontCacheTag *tag, Guchar *data, - double x, double y, GfxRGB *color) { - XImage *image; - XColor xcolor; - GfxRGB bg, rgb; - Gulong map[5]; - Gulong pixel; - Guchar *p; - int x0, y0, w0, h0, x1, y1; - int ix, iy; - - // compute: (x0,y0) = position in destination pixmap - // (x1,y1) = position in the XImage - // (w0,h0) = size of XImage transfer - x0 = xoutRound(x + t3Font->glyphX); - y0 = xoutRound(y + t3Font->glyphY); - x1 = 0; - y1 = 0; - w0 = t3Font->glyphW; - h0 = t3Font->glyphH; - if (x0 < 0) { - x1 = -x0; - w0 += x0; - x0 = 0; - } - if (x0 + w0 > pixmapW) { - w0 = pixmapW - x0; - } - if (w0 <= 0) { - return; - } - if (y0 < 0) { - y1 = -y0; - h0 += y0; - y0 = 0; - } - if (y0 + h0 > pixmapH) { - h0 = pixmapH - y0; - } - if (h0 <= 0) { - return; - } - - image = t3Font->image; - XGetSubImage(display, pixmap, x0, y0, w0, h0, - (1 << depth) - 1, ZPixmap, image, x1, y1); - xcolor.pixel = XGetPixel(image, t3Font->glyphW / 2, t3Font->glyphH / 2); - XQueryColor(display, colormap, &xcolor); - bg.r = xcolor.red / 65535.0; - bg.g = xcolor.green / 65535.0; - bg.b = xcolor.blue / 65535.0; - rgb.r = 0.25 * (color->r + 3 * bg.r); - rgb.g = 0.25 * (color->g + 3 * bg.g); - rgb.b = 0.25 * (color->b + 3 * bg.b); - map[1] = findColor(&rgb); - rgb.r = 0.5 * (color->r + bg.r); - rgb.g = 0.5 * (color->g + bg.g); - rgb.b = 0.5 * (color->b + bg.b); - map[2] = findColor(&rgb); - rgb.r = 0.25 * (3 * color->r + bg.r); - rgb.g = 0.25 * (3 * color->g + bg.g); - rgb.b = 0.25 * (3 * color->b + bg.b); - map[3] = findColor(&rgb); - map[4] = findColor(color); - p = data; - for (iy = 0; iy < t3Font->glyphH; ++iy) { - for (ix = 0; ix < t3Font->glyphW; ++ix) { - pixel = *p++; - if (pixel > 0) { - XPutPixel(image, ix, iy, map[pixel]); - } - } - } - XPutImage(display, pixmap, fillGC, image, x1, y1, x0, y0, w0, h0); -} - -void XOutputDev::type3D0(GfxState *state, double wx, double wy) { - t3GlyphStack->wx = wx; - t3GlyphStack->wy = wy; -} - -void XOutputDev::type3D1(GfxState *state, double wx, double wy, - double llx, double lly, double urx, double ury) { - GfxColor fgColor; - XGCValues gcValues; - XRectangle rect; - double *ctm; - T3FontCache *t3Font; - double xt, yt, xMin, xMax, yMin, yMax, x1, y1; - int i, j; - - t3Font = t3GlyphStack->cache; - t3GlyphStack->wx = wx; - t3GlyphStack->wy = wy; - - // check for a valid bbox - state->transform(0, 0, &xt, &yt); - state->transform(llx, lly, &x1, &y1); - xMin = xMax = x1; - yMin = yMax = y1; - state->transform(llx, ury, &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - state->transform(urx, lly, &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - state->transform(urx, ury, &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - if (xMin - xt < t3Font->glyphX || - yMin - yt < t3Font->glyphY || - xMax - xt > t3Font->glyphX + t3Font->glyphW || - yMax - yt > t3Font->glyphY + t3Font->glyphH) { - error(-1, "Bad bounding box in Type 3 glyph"); - return; - } - - // allocate a cache entry - t3GlyphStack->cacheable = gTrue; - i = t3GlyphStack->cacheIdx; - for (j = 0; j < t3Font->cacheAssoc; ++j) { - if ((t3Font->cacheTags[i+j].mru & 0x7fff) == t3Font->cacheAssoc - 1) { - t3Font->cacheTags[i+j].mru = 0x8000; - t3Font->cacheTags[i+j].code = t3GlyphStack->code; - t3GlyphStack->cacheTag = &t3Font->cacheTags[i+j]; - t3GlyphStack->cacheData = t3Font->cacheData + (i+j) * t3Font->glyphSize; - } else { - ++t3Font->cacheTags[i+j].mru; - } - } - t3GlyphStack->cacheTag->wx = wx; - t3GlyphStack->cacheTag->wy = wy; - - // prepare to rasterize the glyph - //~ do we need to handle both fill and stroke color? - state->getFillRGB(&t3GlyphStack->color); - if (reverseVideo) { - t3GlyphStack->color.r = 1 - t3GlyphStack->color.r; - t3GlyphStack->color.g = 1 - t3GlyphStack->color.g; - t3GlyphStack->color.b = 1 - t3GlyphStack->color.b; - } - fgColor.c[0] = reverseVideo ? 1 : 0; - state->setFillColorSpace(new GfxDeviceGrayColorSpace()); - state->setFillColor(&fgColor); - state->setStrokeColorSpace(new GfxDeviceGrayColorSpace()); - state->setStrokeColor(&fgColor); - t3GlyphStack->origPixmapW = pixmapW; - t3GlyphStack->origPixmapH = pixmapH; - t3GlyphStack->origPixmap = pixmap; - t3GlyphStack->origStrokeGC = strokeGC; - t3GlyphStack->origFillGC = fillGC; - t3GlyphStack->origClipRegion = clipRegion; - pixmapW = t3GlyphStack->cache->glyphW; - pixmapH = t3GlyphStack->cache->glyphH; - pixmap = t3GlyphStack->cache->pixmap; - gcValues.foreground = BlackPixel(display, screenNum); - gcValues.background = WhitePixel(display, screenNum); - gcValues.line_width = 0; - gcValues.line_style = LineSolid; - strokeGC = XCreateGC(display, pixmap, - GCForeground | GCBackground | GCLineWidth | GCLineStyle, - &gcValues); - updateLineAttrs(state, gTrue); - gcValues.foreground = WhitePixel(display, screenNum); - fillGC = XCreateGC(display, pixmap, - GCForeground | GCBackground | GCLineWidth | GCLineStyle, - &gcValues); - XFillRectangle(display, pixmap, fillGC, 0, 0, pixmapW, pixmapH); - XSetForeground(display, fillGC, BlackPixel(display, screenNum)); - clipRegion = XCreateRegion(); - rect.x = rect.y = 0; - rect.width = pixmapW; - rect.height = pixmapH; - XUnionRectWithRegion(&rect, clipRegion, clipRegion); - XSetRegion(display, strokeGC, clipRegion); - XSetRegion(display, fillGC, clipRegion); - ctm = state->getCTM(); - t3GlyphStack->origCTM4 = ctm[4]; - t3GlyphStack->origCTM5 = ctm[5]; - state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3], - -t3GlyphStack->cache->glyphX, -t3GlyphStack->cache->glyphY); -} - -void XOutputDev::endTextObject(GfxState *state) { - double *ctm; - double saveCTM[6]; - - if (textClipPath) { - ctm = state->getCTM(); - memcpy(saveCTM, ctm, 6 * sizeof(double)); - state->setCTM(1, 0, 0, 1, 0, 0); - doClip(state, textClipPath, WindingRule); - state->setCTM(saveCTM[0], saveCTM[1], saveCTM[2], saveCTM[3], - saveCTM[4], saveCTM[5]); - delete textClipPath; - textClipPath = NULL; - } -} - -inline Gulong XOutputDev::findColor(GfxRGB *x, GfxRGB *actual) { - double gray; - int r, g, b; - Gulong pixel; - - if (trueColor) { - r = xoutRound(x->r * rMul); - g = xoutRound(x->g * gMul); - b = xoutRound(x->b * bMul); - pixel = ((Gulong)r << rShift) + - ((Gulong)g << gShift) + - ((Gulong)b << bShift); - actual->r = (double)r / rMul; - actual->g = (double)g / gMul; - actual->b = (double)b / bMul; - } else if (numColors == 1) { - gray = 0.299 * x->r + 0.587 * x->g + 0.114 * x->b; - if (gray < 0.5) { - pixel = colors[0]; - actual->r = actual->g = actual->b = 0; - } else { - pixel = colors[1]; - actual->r = actual->g = actual->b = 1; - } - } else { - r = xoutRound(x->r * (numColors - 1)); - g = xoutRound(x->g * (numColors - 1)); - b = xoutRound(x->b * (numColors - 1)); - pixel = colors[(r * numColors + g) * numColors + b]; - actual->r = (double)r / (numColors - 1); - actual->g = (double)g / (numColors - 1); - actual->b = (double)b / (numColors - 1); - } - return pixel; -} - -Gulong XOutputDev::findColor(GfxRGB *rgb) { - int r, g, b; - double gray; - Gulong pixel; - - if (trueColor) { - r = xoutRound(rgb->r * rMul); - g = xoutRound(rgb->g * gMul); - b = xoutRound(rgb->b * bMul); - pixel = ((Gulong)r << rShift) + - ((Gulong)g << gShift) + - ((Gulong)b << bShift); - } else if (numColors == 1) { - gray = 0.299 * rgb->r + 0.587 * rgb->g + 0.114 * rgb->b; - if (gray < 0.5) - pixel = colors[0]; - else - pixel = colors[1]; - } else { - r = xoutRound(rgb->r * (numColors - 1)); - g = xoutRound(rgb->g * (numColors - 1)); - b = xoutRound(rgb->b * (numColors - 1)); -#if 0 // this makes things worse as often as better - // even a very light color shouldn't map to white - if (r == numColors - 1 && g == numColors - 1 && b == numColors - 1) { - if (color->getR() < 0.95) - --r; - if (color->getG() < 0.95) - --g; - if (color->getB() < 0.95) - --b; - } -#endif - pixel = colors[(r * numColors + g) * numColors + b]; - } - return pixel; -} - -void XOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool inlineImg) { - ImageStream *imgStr; - XImage *image; - double *ctm; - GBool rot; - double xScale, yScale, xShear, yShear; - int tx, ty, scaledWidth, scaledHeight, xSign, ySign; - int ulx, uly, llx, lly, urx, ury, lrx, lry; - int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1; - int bx0, by0, bx1, by1, bw, bh; - int cx0, cy0, cx1, cy1, cw, ch; - int yp, yq, yt, yStep, lastYStep; - int xp, xq, xt, xStep, xSrc; - GfxRGB rgb; - Guchar *pixBuf; - int imgPix; - double alpha; - XColor xcolor; - Gulong lastPixel; - GfxRGB rgb2; - double r0, g0, b0, r1, g1, b1; - Gulong pix; - Guchar *p; - int x, y, x1, y1, x2, y2; - int n, m, i, j; - - // get CTM, check for singular matrix - ctm = state->getCTM(); - if (fabs(ctm[0] * ctm[3] - ctm[1] * ctm[2]) < 0.000001) { - error(-1, "Singular CTM in drawImage"); - if (inlineImg) { - j = height * ((width + 7) / 8); - str->reset(); - for (i = 0; i < j; ++i) { - str->getChar(); - } - str->close(); - } - return; - } - - // compute scale, shear, rotation, translation parameters - rot = fabs(ctm[1]) > fabs(ctm[0]); - if (rot) { - xScale = -ctm[1]; - yScale = -ctm[2] + (ctm[0] * ctm[3]) / ctm[1]; - xShear = ctm[3] / yScale; - yShear = -ctm[0] / ctm[1]; - } else { - xScale = ctm[0]; - yScale = -ctm[3] + (ctm[1] * ctm[2]) / ctm[0]; - xShear = -ctm[2] / yScale; - yShear = ctm[1] / ctm[0]; - } - tx = xoutRound(ctm[2] + ctm[4]); - ty = xoutRound(ctm[3] + ctm[5]); - // use ceil() to avoid gaps between "striped" images - scaledWidth = (int)ceil(fabs(xScale)); - xSign = (xScale < 0) ? -1 : 1; - scaledHeight = (int)ceil(fabs(yScale)); - ySign = (yScale < 0) ? -1 : 1; - - // compute corners in device space - ulx1 = 0; - uly1 = 0; - urx1 = xSign * (scaledWidth - 1); - ury1 = xoutRound(yShear * urx1); - llx1 = xoutRound(xShear * ySign * (scaledHeight - 1)); - lly1 = ySign * (scaledHeight - 1) + xoutRound(yShear * llx1); - lrx1 = xSign * (scaledWidth - 1) + - xoutRound(xShear * ySign * (scaledHeight - 1)); - lry1 = ySign * (scaledHeight - 1) + xoutRound(yShear * lrx1); - if (rot) { - ulx = tx + uly1; uly = ty - ulx1; - urx = tx + ury1; ury = ty - urx1; - llx = tx + lly1; lly = ty - llx1; - lrx = tx + lry1; lry = ty - lrx1; - } else { - ulx = tx + ulx1; uly = ty + uly1; - urx = tx + urx1; ury = ty + ury1; - llx = tx + llx1; lly = ty + lly1; - lrx = tx + lrx1; lry = ty + lry1; - } - - // bounding box: - // (bx0, by0) = upper-left corner - // (bx1, by1) = lower-right corner - // (bw, bh) = size - bx0 = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx - : (llx < lrx) ? llx : lrx - : (urx < llx) ? (urx < lrx) ? urx : lrx - : (llx < lrx) ? llx : lrx; - bx1 = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx - : (llx > lrx) ? llx : lrx - : (urx > llx) ? (urx > lrx) ? urx : lrx - : (llx > lrx) ? llx : lrx; - by0 = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry - : (lly < lry) ? lly : lry - : (ury < lly) ? (ury < lry) ? ury : lry - : (lly < lry) ? lly : lry; - by1 = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry - : (lly > lry) ? lly : lry - : (ury > lly) ? (ury > lry) ? ury : lry - : (lly > lry) ? lly : lry; - bw = bx1 - bx0 + 1; - bh = by1 - by0 + 1; - - // Bounding box clipped to pixmap, i.e., "valid" rectangle: - // (cx0, cy0) = upper-left corner of valid rectangle in Pixmap - // (cx1, cy1) = upper-left corner of valid rectangle in XImage - // (cw, ch) = size of valid rectangle - // These values will be used to transfer the XImage from/to the - // Pixmap. - cw = (bx1 >= pixmapW) ? pixmapW - bx0 : bw; - if (bx0 < 0) { - cx0 = 0; - cx1 = -bx0; - cw += bx0; - } else { - cx0 = bx0; - cx1 = 0; - } - ch = (by1 >= pixmapH) ? pixmapH - by0 : bh; - if (by0 < 0) { - cy0 = 0; - cy1 = -by0; - ch += by0; - } else { - cy0 = by0; - cy1 = 0; - } - - // check for tiny (zero width or height) images - // and off-page images - if (scaledWidth <= 0 || scaledHeight <= 0 || cw <= 0 || ch <= 0) { - if (inlineImg) { - j = height * ((width + 7) / 8); - str->reset(); - for (i = 0; i < j; ++i) { - str->getChar(); - } - str->close(); - } - return; - } - - // compute Bresenham parameters for x and y scaling - yp = height / scaledHeight; - yq = height % scaledHeight; - xp = width / scaledWidth; - xq = width % scaledWidth; - - // allocate pixel buffer - pixBuf = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar)); - - // allocate XImage and read from page pixmap - image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, bw, bh, 8, 0); - image->data = (char *)gmalloc(bh * image->bytes_per_line); - XGetSubImage(display, pixmap, cx0, cy0, cw, ch, (1 << depth) - 1, ZPixmap, - image, cx1, cy1); - - // get mask color - state->getFillRGB(&rgb); - if (reverseVideo) { - rgb.r = 1 - rgb.r; - rgb.g = 1 - rgb.g; - rgb.b = 1 - rgb.b; - } - r0 = rgb.r; - g0 = rgb.g; - b0 = rgb.b; - - // initialize background color - // (the specific pixel value doesn't matter here, as long as - // r1,g1,b1 correspond correctly to lastPixel) - xcolor.pixel = lastPixel = 0; - XQueryColor(display, colormap, &xcolor); - r1 = (double)xcolor.red / 65535.0; - g1 = (double)xcolor.green / 65535.0; - b1 = (double)xcolor.blue / 65535.0; - - // initialize the image stream - imgStr = new ImageStream(str, width, 1, 1); - imgStr->reset(); - - // init y scale Bresenham - yt = 0; - lastYStep = 1; - - for (y = 0; y < scaledHeight; ++y) { - - // y scale Bresenham - yStep = yp; - yt += yq; - if (yt >= scaledHeight) { - yt -= scaledHeight; - ++yStep; - } - - // read row(s) from image - n = (yp > 0) ? yStep : lastYStep; - if (n > 0) { - p = pixBuf; - for (i = 0; i < n; ++i) { - memcpy(p, imgStr->getLine(), width); - if (invert) { - for (j = 0; j < width; ++j) { - p[j] ^= 1; - } - } - p += width; - } - } - lastYStep = yStep; - - // init x scale Bresenham - xt = 0; - xSrc = 0; - - for (x = 0; x < scaledWidth; ++x) { - - // x scale Bresenham - xStep = xp; - xt += xq; - if (xt >= scaledWidth) { - xt -= scaledWidth; - ++xStep; - } - - // x shear - x1 = xSign * x + xoutRound(xShear * ySign * y); - - // y shear - y1 = ySign * y + xoutRound(yShear * x1); - - // rotation - if (rot) { - x2 = y1; - y2 = -x1; - } else { - x2 = x1; - y2 = y1; - } - - // compute the filtered pixel at (x,y) after the - // x and y scaling operations - n = yStep > 0 ? yStep : 1; - m = xStep > 0 ? xStep : 1; - p = pixBuf + xSrc; - imgPix = 0; - for (i = 0; i < n; ++i) { - for (j = 0; j < m; ++j) { - imgPix += *p++; - } - p += width - m; - } - - // x scale Bresenham - xSrc += xStep; - - // blend image pixel with background - alpha = (double)imgPix / (double)(n * m); - xcolor.pixel = XGetPixel(image, tx + x2 - bx0, ty + y2 - by0); - if (xcolor.pixel != lastPixel) { - XQueryColor(display, colormap, &xcolor); - r1 = (double)xcolor.red / 65535.0; - g1 = (double)xcolor.green / 65535.0; - b1 = (double)xcolor.blue / 65535.0; - lastPixel = xcolor.pixel; - } - rgb2.r = r0 * (1 - alpha) + r1 * alpha; - rgb2.g = g0 * (1 - alpha) + g1 * alpha; - rgb2.b = b0 * (1 - alpha) + b1 * alpha; - pix = findColor(&rgb2); - - // set pixel - XPutPixel(image, tx + x2 - bx0, ty + y2 - by0, pix); - } - } - - // blit the image into the pixmap - XPutImage(display, pixmap, fillGC, image, cx1, cy1, cx0, cy0, cw, ch); - - // free memory - delete imgStr; - gfree(pixBuf); - gfree(image->data); - image->data = NULL; - XDestroyImage(image); -} - -void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, - int width, int height, GfxImageColorMap *colorMap, - int *maskColors, GBool inlineImg) { - ImageStream *imgStr; - XImage *image; - int nComps, nVals, nBits; - GBool dither; - double *ctm; - GBool rot; - double xScale, yScale, xShear, yShear; - int tx, ty, scaledWidth, scaledHeight, xSign, ySign; - int ulx, uly, llx, lly, urx, ury, lrx, lry; - int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1; - int bx0, by0, bx1, by1, bw, bh; - int cx0, cy0, cx1, cy1, cw, ch; - int yp, yq, yt, yStep, lastYStep; - int xp, xq, xt, xStep, xSrc; - GfxRGB *pixBuf; - Guchar *pixBuf1, *alphaBuf; - Guchar pixBuf2[gfxColorMaxComps]; - GfxRGB color2, color3, actual, err, errRight; - GfxRGB *errDown0, *errDown1, *errDownTmp; - double r0, g0, b0, alpha, mul; - Gulong pix; - GfxRGB *p; - Guchar *q, *p1, *p2; - GBool oneBitMode; - GfxRGB oneBitRGB[2]; - int x, y, x1, y1, x2, y2; - int n, m, i, j, k; - - // image parameters - nComps = colorMap->getNumPixelComps(); - nVals = width * nComps; - nBits = colorMap->getBits(); - oneBitMode = nComps == 1 && nBits == 1 && !maskColors; - dither = nComps > 1 || nBits > 1; - - // get CTM, check for singular matrix - ctm = state->getCTM(); - if (fabs(ctm[0] * ctm[3] - ctm[1] * ctm[2]) < 0.000001) { - error(-1, "Singular CTM in drawImage"); - if (inlineImg) { - str->reset(); - j = height * ((nVals * nBits + 7) / 8); - for (i = 0; i < j; ++i) { - str->getChar(); - } - str->close(); - } - return; - } - - // compute scale, shear, rotation, translation parameters - rot = fabs(ctm[1]) > fabs(ctm[0]); - if (rot) { - xScale = -ctm[1]; - yScale = -ctm[2] + (ctm[0] * ctm[3]) / ctm[1]; - xShear = ctm[3] / yScale; - yShear = -ctm[0] / ctm[1]; - } else { - xScale = ctm[0]; - yScale = -ctm[3] + (ctm[1] * ctm[2]) / ctm[0]; - xShear = -ctm[2] / yScale; - yShear = ctm[1] / ctm[0]; - } - tx = xoutRound(ctm[2] + ctm[4]); - ty = xoutRound(ctm[3] + ctm[5]); - if (xScale < 0) { - // this is the right edge which needs to be (left + width - 1) - --tx; - } - if (yScale < 0) { - // this is the bottom edge which needs to be (top + height - 1) - --ty; - } - // use ceil() to avoid gaps between "striped" images - scaledWidth = (int)ceil(fabs(xScale)); - xSign = (xScale < 0) ? -1 : 1; - scaledHeight = (int)ceil(fabs(yScale)); - ySign = (yScale < 0) ? -1 : 1; - - // compute corners in device space - ulx1 = 0; - uly1 = 0; - urx1 = xSign * (scaledWidth - 1); - ury1 = xoutRound(yShear * urx1); - llx1 = xoutRound(xShear * ySign * (scaledHeight - 1)); - lly1 = ySign * (scaledHeight - 1) + xoutRound(yShear * llx1); - lrx1 = xSign * (scaledWidth - 1) + - xoutRound(xShear * ySign * (scaledHeight - 1)); - lry1 = ySign * (scaledHeight - 1) + xoutRound(yShear * lrx1); - if (rot) { - ulx = tx + uly1; uly = ty - ulx1; - urx = tx + ury1; ury = ty - urx1; - llx = tx + lly1; lly = ty - llx1; - lrx = tx + lry1; lry = ty - lrx1; - } else { - ulx = tx + ulx1; uly = ty + uly1; - urx = tx + urx1; ury = ty + ury1; - llx = tx + llx1; lly = ty + lly1; - lrx = tx + lrx1; lry = ty + lry1; - } - - // bounding box: - // (bx0, by0) = upper-left corner - // (bx1, by1) = lower-right corner - // (bw, bh) = size - bx0 = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx - : (llx < lrx) ? llx : lrx - : (urx < llx) ? (urx < lrx) ? urx : lrx - : (llx < lrx) ? llx : lrx; - bx1 = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx - : (llx > lrx) ? llx : lrx - : (urx > llx) ? (urx > lrx) ? urx : lrx - : (llx > lrx) ? llx : lrx; - by0 = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry - : (lly < lry) ? lly : lry - : (ury < lly) ? (ury < lry) ? ury : lry - : (lly < lry) ? lly : lry; - by1 = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry - : (lly > lry) ? lly : lry - : (ury > lly) ? (ury > lry) ? ury : lry - : (lly > lry) ? lly : lry; - bw = bx1 - bx0 + 1; - bh = by1 - by0 + 1; - - // Bounding box clipped to pixmap, i.e., "valid" rectangle: - // (cx0, cy0) = upper-left corner of valid rectangle in Pixmap - // (cx1, cy1) = upper-left corner of valid rectangle in XImage - // (cw, ch) = size of valid rectangle - // These values will be used to transfer the XImage from/to the - // Pixmap. - cw = (bx1 >= pixmapW) ? pixmapW - bx0 : bw; - if (bx0 < 0) { - cx0 = 0; - cx1 = -bx0; - cw += bx0; - } else { - cx0 = bx0; - cx1 = 0; - } - ch = (by1 >= pixmapH) ? pixmapH - by0 : bh; - if (by0 < 0) { - cy0 = 0; - cy1 = -by0; - ch += by0; - } else { - cy0 = by0; - cy1 = 0; - } - - // check for tiny (zero width or height) images - // and off-page images - if (scaledWidth <= 0 || scaledHeight <= 0 || cw <= 0 || ch <= 0) { - if (inlineImg) { - str->reset(); - j = height * ((nVals * nBits + 7) / 8); - for (i = 0; i < j; ++i) - str->getChar(); - str->close(); - } - return; - } - - // compute Bresenham parameters for x and y scaling - yp = height / scaledHeight; - yq = height % scaledHeight; - xp = width / scaledWidth; - xq = width % scaledWidth; - - // allocate pixel buffer - if (oneBitMode) { - pixBuf1 = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar)); - pixBuf = NULL; - } else { - pixBuf = (GfxRGB *)gmalloc((yp + 1) * width * sizeof(GfxRGB)); - pixBuf1 = NULL; - } - if (maskColors) { - alphaBuf = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar)); - } else { - alphaBuf = NULL; - } - - // allocate XImage - image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, bw, bh, 8, 0); - image->data = (char *)gmalloc(bh * image->bytes_per_line); - - // if the transform is anything other than a 0/90/180/270 degree - // rotation/flip, or if there is color key masking, read the - // backgound pixmap to fill in the corners - if (!((ulx == llx && uly == ury) || - (uly == lly && ulx == urx)) || - maskColors) { - XGetSubImage(display, pixmap, cx0, cy0, cw, ch, (1 << depth) - 1, ZPixmap, - image, cx1, cy1); - } - - // allocate error diffusion accumulators - if (dither) { - errDown0 = (GfxRGB *)gmalloc((scaledWidth + 2) * sizeof(GfxRGB)); - errDown1 = (GfxRGB *)gmalloc((scaledWidth + 2) * sizeof(GfxRGB)); - for (j = 0; j < scaledWidth + 2; ++j) { - errDown0[j].r = errDown0[j].g = errDown0[j].b = 0; - errDown1[j].r = errDown1[j].g = errDown1[j].b = 0; - } - } else { - errDown0 = errDown1 = NULL; - } - - // optimize the one-bit-deep image case - if (oneBitMode) { - pixBuf2[0] = 0; - colorMap->getRGB(pixBuf2, &oneBitRGB[0]); - pixBuf2[0] = 1; - colorMap->getRGB(pixBuf2, &oneBitRGB[1]); - } - - // initialize the image stream - imgStr = new ImageStream(str, width, nComps, nBits); - imgStr->reset(); - - // init y scale Bresenham - yt = 0; - lastYStep = 1; - - for (y = 0; y < scaledHeight; ++y) { - - // initialize error diffusion accumulators - if (dither) { - errDownTmp = errDown0; - errDown0 = errDown1; - errDown1 = errDownTmp; - for (j = 0; j < scaledWidth + 2; ++j) { - errDown1[j].r = errDown1[j].g = errDown1[j].b = 0; - } - errRight.r = errRight.g = errRight.b = 0; - } - - // y scale Bresenham - yStep = yp; - yt += yq; - if (yt >= scaledHeight) { - yt -= scaledHeight; - ++yStep; - } - - // read row(s) from image - n = (yp > 0) ? yStep : lastYStep; - if (n > 0) { - if (oneBitMode) { - p1 = pixBuf1; - for (i = 0; i < n; ++i) { - p2 = imgStr->getLine(); - memcpy(p1, p2, width); - p1 += width; - } - } else { - p = pixBuf; - q = alphaBuf; - for (i = 0; i < n; ++i) { - p2 = imgStr->getLine(); - for (j = 0; j < width; ++j) { - colorMap->getRGB(p2, p); - ++p; - if (q) { - *q = 1; - for (k = 0; k < nComps; ++k) { - if (p2[k] < maskColors[2*k] || - p2[k] > maskColors[2*k+1]) { - *q = 0; - break; - } - } - ++q; - } - p2 += nComps; - } - } - } - } - lastYStep = yStep; - - // init x scale Bresenham - xt = 0; - xSrc = 0; - - for (x = 0; x < scaledWidth; ++x) { - - // x scale Bresenham - xStep = xp; - xt += xq; - if (xt >= scaledWidth) { - xt -= scaledWidth; - ++xStep; - } - - // x shear - x1 = xSign * x + xoutRound(xShear * ySign * y); - - // y shear - y1 = ySign * y + xoutRound(yShear * x1); - - // rotation - if (rot) { - x2 = y1; - y2 = -x1; - } else { - x2 = x1; - y2 = y1; - } - - // compute the filtered pixel at (x,y) after the - // x and y scaling operations - n = yStep > 0 ? yStep : 1; - m = xStep > 0 ? xStep : 1; - if (oneBitMode) { - p1 = pixBuf1 + xSrc; - k = 0; - for (i = 0; i < n; ++i) { - for (j = 0; j < m; ++j) { - k += *p1++; - } - p1 += width - m; - } - mul = (double)k / (double)(n * m); - r0 = mul * oneBitRGB[1].r + (1 - mul) * oneBitRGB[0].r; - g0 = mul * oneBitRGB[1].g + (1 - mul) * oneBitRGB[0].g; - b0 = mul * oneBitRGB[1].b + (1 - mul) * oneBitRGB[0].b; - alpha = 0; - } else { - p = pixBuf + xSrc; - q = alphaBuf ? alphaBuf + xSrc : (Guchar *)NULL; - alpha = 0; - r0 = g0 = b0 = 0; - for (i = 0; i < n; ++i) { - for (j = 0; j < m; ++j) { - r0 += p->r; - g0 += p->g; - b0 += p->b; - ++p; - if (q) { - alpha += *q++; - } - } - p += width - m; - } - mul = 1 / (double)(n * m); - r0 *= mul; - g0 *= mul; - b0 *= mul; - alpha *= mul; - } - - // x scale Bresenham - xSrc += xStep; - - // compute pixel - if (dither) { - color2.r = r0 + errRight.r + errDown0[x + 1].r; - if (color2.r > 1) { - color3.r = 1; - } else if (color2.r < 0) { - color3.r = 0; - } else { - color3.r = color2.r; - } - color2.g = g0 + errRight.g + errDown0[x + 1].g; - if (color2.g > 1) { - color3.g = 1; - } else if (color2.g < 0) { - color3.g = 0; - } else { - color3.g = color2.g; - } - color2.b = b0 + errRight.b + errDown0[x + 1].b; - if (color2.b > 1) { - color3.b = 1; - } else if (color2.b < 0) { - color3.b = 0; - } else { - color3.b = color2.b; - } - pix = findColor(&color3, &actual); - err.r = (color2.r - actual.r) / 16; - err.g = (color2.g - actual.g) / 16; - err.b = (color2.b - actual.b) / 16; - errRight.r = 7 * err.r; - errRight.g = 7 * err.g; - errRight.b = 7 * err.b; - errDown1[x].r += 3 * err.r; - errDown1[x].g += 3 * err.g; - errDown1[x].b += 3 * err.b; - errDown1[x + 1].r += 5 * err.r; - errDown1[x + 1].g += 5 * err.g; - errDown1[x + 1].b += 5 * err.b; - errDown1[x + 2].r = err.r; - errDown1[x + 2].g = err.g; - errDown1[x + 2].b = err.b; - } else { - color2.r = r0; - color2.g = g0; - color2.b = b0; - pix = findColor(&color2, &actual); - } - - // set pixel - //~ this should do a blend when 0 < alpha < 1 - if (alpha < 0.75) { - XPutPixel(image, tx + x2 - bx0, ty + y2 - by0, pix); - } - } - } - - // blit the image into the pixmap - XPutImage(display, pixmap, fillGC, image, cx1, cy1, cx0, cy0, cw, ch); - - // free memory - delete imgStr; - if (oneBitMode) { - gfree(pixBuf1); - } else { - gfree(pixBuf); - } - if (maskColors) { - gfree(alphaBuf); - } - gfree(image->data); - image->data = NULL; - XDestroyImage(image); - gfree(errDown0); - gfree(errDown1); -} - -GBool XOutputDev::findText(Unicode *s, int len, - GBool startAtTop, GBool stopAtBottom, - GBool startAtLast, GBool stopAtLast, - int *xMin, int *yMin, - int *xMax, int *yMax) { - double xMin1, yMin1, xMax1, yMax1; - - xMin1 = (double)*xMin; - yMin1 = (double)*yMin; - xMax1 = (double)*xMax; - yMax1 = (double)*yMax; - if (text->findText(s, len, startAtTop, stopAtBottom, - startAtLast, stopAtLast, - &xMin1, &yMin1, &xMax1, &yMax1)) { - *xMin = xoutRound(xMin1); - *xMax = xoutRound(xMax1); - *yMin = xoutRound(yMin1); - *yMax = xoutRound(yMax1); - return gTrue; - } - return gFalse; -} - -GString *XOutputDev::getText(int xMin, int yMin, int xMax, int yMax) { - return text->getText((double)xMin, (double)yMin, - (double)xMax, (double)yMax); -} |