Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/pdf/xpdf/XOutputDev.cc
diff options
context:
space:
mode:
Diffstat (limited to 'pdf/xpdf/XOutputDev.cc')
-rw-r--r--pdf/xpdf/XOutputDev.cc3986
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);
-}