//
// XOutputDev.cc
//
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
//
//========================================================================
-#ifdef __GNUC__
+#include <aconf.h>
+
+#ifdef USE_GCC_PRAGMAS
#pragma implementation
#endif
-#include <aconf.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
{"Symbol", 0.576}
};
+//------------------------------------------------------------------------
+
+static void outputToFile(void *stream, char *data, int len) {
+ fwrite(data, 1, len, (FILE *)stream);
+}
+
//------------------------------------------------------------------------
// XOutputFont
//------------------------------------------------------------------------
#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
xOut = xOutA;
#if HAVE_T1LIB_H
- t1Engine = NULL;
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)
- ttEngine = NULL;
-#endif
-#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
freetypeControl = freetypeControlA;
+ ttEngine = NULL;
+ ttFontFiles = NULL;
#endif
clear();
delFonts();
}
-void XOutputFontCache::startDoc(int screenNum, Colormap colormap,
- GBool trueColor,
+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) {
#if HAVE_T1LIB_H
if (t1libControl != fontRastNone) {
- t1Engine = new T1FontEngine(display, DefaultVisual(display, screenNum),
- depth, colormap,
+ t1Engine = new T1FontEngine(display, visual, depth, colormap,
t1libControl == fontRastAALow ||
t1libControl == fontRastAAHigh,
t1libControl == fontRastAAHigh);
#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
if (freetypeControl != fontRastNone) {
- ftEngine = new FTFontEngine(display, DefaultVisual(display, screenNum),
- depth, colormap,
+ ftEngine = new FTFontEngine(display, visual, depth, colormap,
freetypeControl == fontRastAALow ||
freetypeControl == fontRastAAHigh);
if (ftEngine->isOk()) {
#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
if (freetypeControl != fontRastNone) {
- ttEngine = new TTFontEngine(display, DefaultVisual(display, screenNum),
- depth, colormap,
+ ttEngine = new TTFontEngine(display, visual, depth, colormap,
freetypeControl == fontRastAALow ||
freetypeControl == fontRastAAHigh);
if (ttEngine->isOk()) {
#if HAVE_T1LIB_H
// delete Type 1 font files
- deleteGList(t1FontFiles, XOutputT1FontFile);
+ 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
- deleteGList(ftFontFiles, XOutputFTFontFile);
+ 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
- deleteGList(ttFontFiles, XOutputTTFontFile);
+ if (ttFontFiles) {
+ deleteGList(ttFontFiles, XOutputTTFontFile);
+ ttFontFiles = NULL;
+ }
if (ttEngine) {
delete ttEngine;
+ ttEngine = NULL;
}
#endif
}
}
#endif
break;
+ case fontCIDType0:
case fontCIDType0C:
#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
if (freetypeControl != fontRastNone) {
case displayFontT1:
#if HAVE_T1LIB_H
- if (t1libControl != fontRastNone) {
- font = tryGetT1FontFromFile(xref, dfp->t1.fileName, gfxFont,
+ if (t1libControl != fontRastNone && !gfxFont->isCIDFont()) {
+ font = tryGetT1FontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont,
m11Orig, m12Orig, m21Orig, m22Orig,
m11, m12, m21, m22, subst);
}
#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
if (!font) {
if (freetypeControl != fontRastNone) {
- font = tryGetFTFontFromFile(xref, dfp->t1.fileName, gfxFont,
+ font = tryGetFTFontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont,
m11Orig, m12Orig, m21Orig, m22Orig,
- m11, m12, m21, m22, subst);
+ m11, m12, m21, m22, gFalse, subst);
}
}
#endif
case displayFontTT:
#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
if (freetypeControl != fontRastNone) {
- font = tryGetFTFontFromFile(xref, dfp->tt.fileName, gfxFont,
+ font = tryGetFTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont,
m11Orig, m12Orig, m21Orig, m22Orig,
- m11, m12, m21, m22, subst);
+ 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, gfxFont,
+ font = tryGetTTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont,
m11Orig, m12Orig, m21Orig, m22Orig,
m11, m12, m21, m22, subst);
}
if (gfxFont->getType() == fontType1C) {
if (!(fontBuf = gfxFont->readEmbFontFile(xref, &fontLen))) {
fclose(f);
+ unlink(fileName->getCString());
+ delete fileName;
return NULL;
}
ff = new Type1CFontFile(fontBuf, fontLen);
- ff->convertToType1(f);
+ if (!ff->isOk()) {
+ delete ff;
+ gfree(fontBuf);
+ unlink(fileName->getCString());
+ delete fileName;
+ return NULL;
+ }
+ ff->convertToType1(outputToFile, f);
delete ff;
gfree(fontBuf);
} else { // fontType1
fclose(f);
// create the Font
- font = tryGetT1FontFromFile(xref, fileName, gfxFont,
+ font = tryGetT1FontFromFile(xref, fileName, gTrue, gfxFont,
m11, m12, m21, m22,
m11, m12, m21, m22, gFalse);
- // remove the temporary file
+ // 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, gfxFont,
+ font = tryGetT1FontFromFile(xref, fileName, gFalse, gfxFont,
m11, m12, m21, m22,
m11, m12, m21, m22, gFalse);
XOutputFont *XOutputFontCache::tryGetT1FontFromFile(XRef *xref,
GString *fileName,
+ GBool deleteFile,
GfxFont *gfxFont,
double m11Orig,
double m12Orig,
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));
+ subst, fontFile,
+ deleteFile ? fileName->copy()
+ : (GString *)NULL));
// create the Font
font = new XOutputT1Font(gfxFont->getID(), fontFile,
gfxFont->getType() == fontCIDType2) {
if (!(fontBuf = gfxFont->readEmbFontFile(xref, &fontLen))) {
fclose(f);
+ unlink(fileName->getCString());
+ delete fileName;
return NULL;
}
ff = new TrueTypeFontFile(fontBuf, fontLen);
fclose(f);
// create the Font
- font = tryGetFTFontFromFile(xref, fileName, gfxFont,
+ font = tryGetFTFontFromFile(xref, fileName, gTrue, gfxFont,
m11, m12, m21, m22,
- m11, m12, m21, m22, gFalse);
+ m11, m12, m21, m22, gTrue, gFalse);
- // remove the temporary file
+ // 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, gfxFont,
+ font = tryGetFTFontFromFile(xref, fileName, gFalse, gfxFont,
m11, m12, m21, m22,
- m11, m12, m21, m22, gFalse);
+ m11, m12, m21, m22, gFalse, gFalse);
} else {
font = NULL;
XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref,
GString *fileName,
+ GBool deleteFile,
GfxFont *gfxFont,
double m11Orig,
double m12Orig,
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());
- } else { // fontCIDType0C
- fontFile = new FTFontFile(ftEngine, fileName->getCString());
+ ((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(),
- ((Gfx8BitFont *)gfxFont)->getHasEncoding());
+ 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));
+ subst, fontFile,
+ deleteFile ? fileName->copy()
+ : (GString *)NULL));
// create the Font
font = new XOutputFTFont(gfxFont->getID(), fontFile,
fclose(f);
// create the Font
- font = tryGetTTFontFromFile(xref, fileName, gfxFont,
+ font = tryGetTTFontFromFile(xref, fileName, gTrue, gfxFont,
m11, m12, m21, m22,
m11, m12, m21, m22, gFalse);
- // remove the temporary file
+ // 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, gfxFont,
+ font = tryGetTTFontFromFile(xref, fileName, gFalse, gfxFont,
m11, m12, m21, m22,
m11, m12, m21, m22, gFalse);
XOutputFont *XOutputFontCache::tryGetTTFontFromFile(XRef *xref,
GString *fileName,
+ GBool deleteFile,
GfxFont *gfxFont,
double m11Orig,
double m12Orig,
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));
+ subst, fontFile,
+ deleteFile ? fileName->copy()
+ : (GString *)NULL));
// create the Font
font = new XOutputTTFont(gfxFont->getID(), fontFile,
GC origStrokeGC;
GC origFillGC;
Region origClipRegion;
+ double origCTM4, origCTM5;
double wx, wy; // untransformed glyph metrics
T3GlyphStack *next;
};
// XOutputDev
//------------------------------------------------------------------------
-XOutputDev::XOutputDev(Display *displayA, Pixmap pixmapA, Guint depthA,
- Colormap colormapA, GBool reverseVideoA,
- unsigned long paperColor, GBool installCmap,
- int rgbCubeSize) {
+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;
- XGCValues gcValues;
XColor xcolor;
XColor *xcolors;
- int r, g, b, n, m, i;
+ int r, g, b, n, m;
GBool ok;
+ // no document yet
xref = NULL;
- // get display/pixmap info
+ // display / screen / visual / colormap
display = displayA;
- screenNum = DefaultScreen(display);
- pixmap = pixmapA;
- depth = depthA;
+ screenNum = screenNumA;
+ visual = visualA;
colormap = colormapA;
+ // no pixmap yet
+ pixmapW = pixmapH = 0;
+
// check for TrueColor visual
- trueColor = gFalse;
- if (depth == 0) {
- depth = DefaultDepth(display, screenNum);
- visualList = XGetVisualInfo(display, 0, &visualTempl, &nVisuals);
- for (i = 0; i < nVisuals; ++i) {
- if (visualList[i].visual == DefaultVisual(display, screenNum)) {
- if (visualList[i].c_class == TrueColor) {
- trueColor = gTrue;
- for (mask = visualList[i].red_mask, rShift = 0;
- mask && !(mask & 1);
- mask >>= 1, ++rShift) ;
- rMul = (int)mask;
- for (mask = visualList[i].green_mask, gShift = 0;
- mask && !(mask & 1);
- mask >>= 1, ++gShift) ;
- gMul = (int)mask;
- for (mask = visualList[i].blue_mask, bShift = 0;
- mask && !(mask & 1);
- mask >>= 1, ++bShift) ;
- bMul = (int)mask;
- }
- break;
- }
+ 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);
}
}
}
- // reverse video mode
+ // misc parameters
reverseVideo = reverseVideoA;
-
- // 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);
-
- // no clip region yet
- clipRegion = NULL;
+ 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;
for (i = 0; i < nT3Fonts; ++i) {
delete t3FontCache[i];
}
- XFreeGC(display, strokeGC);
- XFreeGC(display, fillGC);
- XFreeGC(display, paperGC);
- if (clipRegion) {
- XDestroyRegion(clipRegion);
- }
delete text;
}
int i;
xref = xrefA;
- fontCache->startDoc(screenNum, colormap, trueColor, rMul, gMul, bMul,
+ fontCache->startDoc(screenNum, visual, colormap, trueColor, rMul, gMul, bMul,
rShift, gShift, bShift, colors, numColors);
for (i = 0; i < nT3Fonts; ++i) {
delete t3FontCache[i];
}
void XOutputDev::startPage(int pageNum, GfxState *state) {
- XOutputState *s;
XGCValues gcValues;
XRectangle rect;
- // clear state stack
- while (save) {
- s = save;
- save = save->next;
- XFreeGC(display, s->strokeGC);
- XFreeGC(display, s->fillGC);
- XDestroyRegion(s->clipRegion);
- delete s;
- }
- save = NULL;
-
// default line flatness
flatness = 0;
- // reset GCs
+ // allocate GCs
gcValues.foreground = BlackPixel(display, screenNum);
gcValues.background = WhitePixel(display, screenNum);
gcValues.line_width = 0;
gcValues.line_style = LineSolid;
- XChangeGC(display, strokeGC,
- GCForeground | GCBackground | GCLineWidth | GCLineStyle,
- &gcValues);
- XChangeGC(display, fillGC,
- GCForeground | GCBackground | GCLineWidth | GCLineStyle,
- &gcValues);
-
- // clear clipping region
- if (clipRegion)
- XDestroyRegion(clipRegion);
+ 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;
XFillRectangle(display, pixmap, paperGC, 0, 0, pixmapW, pixmapH);
// clear text object
- text->clear();
+ text->startPage(state);
}
void XOutputDev::endPage() {
- text->coalesce();
+ 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, w;
+ double x1, y1, x2, y2;
+ LinkBorderStyle *borderStyle;
GfxRGB rgb;
+ double *dash;
+ char dashList[20];
+ int dashLength;
XPoint points[5];
- int x, y;
+ int x, y, i;
- link->getBorder(&x1, &y1, &x2, &y2, &w);
- if (w > 0) {
- rgb.r = 0;
- rgb.g = 0;
- rgb.b = 1;
+ 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));
- XSetLineAttributes(display, strokeGC, xoutRound(w),
- LineSolid, CapRound, JoinRound);
- 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);
+ 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);
+ }
}
}
s = save;
save = save->next;
delete s;
+
+ // we'll need to restore the font
+ needFontUpdate = gTrue;
}
}
updateMiterLimit(state);
updateFillColor(state);
updateStrokeColor(state);
- updateFont(state);
+ needFontUpdate = gTrue;
}
void XOutputDev::updateCTM(GfxState *state, double m11, double m12,
void XOutputDev::updateFont(GfxState *state) {
double m11, m12, m21, m22;
+ needFontUpdate = gFalse;
+
+ text->updateFont(state);
+
if (!(gfxFont = state->getFont())) {
font = NULL;
return;
font->updateGC(fillGC);
font->updateGC(strokeGC);
}
-
- text->updateFont(state);
}
void XOutputDev::stroke(GfxState *state) {
int n, size, numPoints, i, j;
// transform points
- n = convertPath(state, &points, &size, &numPoints, &lengths, gFalse);
+ n = convertPath(state, state->getPath(),
+ &points, &size, &numPoints, &lengths, gFalse);
// draw each subpath
j = 0;
XSetFillRule(display, fillGC, rule);
// transform points, build separate polygons
- n = convertPath(state, &points, &size, &numPoints, &lengths, gTrue);
+ n = convertPath(state, state->getPath(),
+ &points, &size, &numPoints, &lengths, gTrue);
// fill them
j = 0;
}
void XOutputDev::clip(GfxState *state) {
- doClip(state, WindingRule);
+ doClip(state, state->getPath(), WindingRule);
}
void XOutputDev::eoClip(GfxState *state) {
- doClip(state, EvenOddRule);
+ doClip(state, state->getPath(), EvenOddRule);
}
-void XOutputDev::doClip(GfxState *state, int rule) {
+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;
- // transform points, build separate polygons
- n = convertPath(state, &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();
+ // 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;
+ }
+ }
}
- j = lengths[0] + 1;
- for (i = 1; i < n; ++i) {
- if (lengths[i] > 2) {
- region2 = XPolygonRegion(points + j, lengths[i], rule);
+
+ 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 {
- region2 = XCreateRegion();
+ 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);
}
- XUnionRegion(region2, region, region);
- XDestroyRegion(region2);
- j += lengths[i] + 1;
}
// intersect region with clipping region
XDestroyRegion(region);
XSetRegion(display, strokeGC, clipRegion);
XSetRegion(display, fillGC, clipRegion);
-
- // free points and lengths arrays
- if (points != tmpPoints)
- gfree(points);
- if (lengths != tmpLengths)
- gfree(lengths);
}
//
// 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, XPoint **points, int *size,
+int XOutputDev::convertPath(GfxState *state, GfxPath *path,
+ XPoint **points, int *size,
int *numPoints, int **lengths, GBool fillHack) {
- GfxPath *path;
BoundingRect *rects;
BoundingRect rect;
int n, i, ii, j, k, k0;
// get path and number of subpaths
- path = state->getPath();
n = path->getNumSubpaths();
// allocate lengths array
// 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 < -pixmapW) {
- (*points)[i].x = -pixmapW;
- } else if ((*points)[i].x > 2 * pixmapW) {
- (*points)[i].x = 2 * pixmapW;
+ 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 = -pixmapH;
- } else if ((*points)[i].y > 2 * pixmapH) {
- (*points)[i].y = 2 * pixmapH;
+ (*points)[i].y = -4 * pixmapH;
+ } else if ((*points)[i].y > 4 * pixmapH) {
+ (*points)[i].y = 4 * pixmapH;
}
}
}
void XOutputDev::beginString(GfxState *state, GString *s) {
- text->beginString(state);
+ text->beginWord(state, state->getCurX(), state->getCurY());
}
void XOutputDev::endString(GfxState *state) {
- text->endString();
+ text->endWord();
}
void XOutputDev::drawChar(GfxState *state, double x, double y,
double *ctm;
double saveCTM[6];
- text->addChar(state, x, y, dx, dy, u, uLen);
+ 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) == 3) {
+ if (render == 3) {
return;
}
}
}
-#if 0 //~ unimplemented: clipping to char path
// 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);
+ }
}
-#endif
}
GBool XOutputDev::beginType3Char(GfxState *state,
double x1, y1, xMin, yMin, xMax, yMax, xt, yt;
int i, j;
+ if (needFontUpdate) {
+ updateFont(state);
+ }
if (!gfxFont) {
return gFalse;
}
(int)floor(yMin - yt),
(int)ceil(xMax) - (int)floor(xMin) + 3,
(int)ceil(yMax) - (int)floor(yMin) + 3,
- display,
- DefaultVisual(display, screenNum),
- depth, pixmap);
+ display, visual, depth, pixmap);
}
}
t3Font = t3FontCache[0];
}
text->addChar(state, 0, 0,
t3Font->cacheTags[i+j].wx, t3Font->cacheTags[i+j].wy,
- u, uLen);
+ code, u, uLen);
drawType3Glyph(t3Font, &t3Font->cacheTags[i+j],
t3Font->cacheData + (i+j) * t3Font->glyphSize,
xt, yt, &color);
Gulong pixel;
double alpha;
T3GlyphStack *t3gs;
+ double *ctm;
if (t3GlyphStack->cacheable) {
image = t3GlyphStack->cache->image;
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->u, t3GlyphStack->uLen);
+ t3GlyphStack->code, t3GlyphStack->u, t3GlyphStack->uLen);
t3gs = t3GlyphStack;
t3GlyphStack = t3gs->next;
delete t3gs;
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;
- t3Font = t3GlyphStack->cache;
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;
}
}
- t3GlyphStack->wx = wx;
- t3GlyphStack->wy = wy;
t3GlyphStack->cacheTag->wx = wx;
t3GlyphStack->cacheTag->wy = wy;
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);
}
-inline Gulong XOutputDev::findColor(GfxRGB *x, GfxRGB *err) {
+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;
pixel = ((Gulong)r << rShift) +
((Gulong)g << gShift) +
((Gulong)b << bShift);
- err->r = x->r - (double)r / rMul;
- err->g = x->g - (double)g / gMul;
- err->b = x->b - (double)b / bMul;
+ 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];
- err->r = x->r;
- err->g = x->g;
- err->b = x->b;
+ actual->r = actual->g = actual->b = 0;
} else {
pixel = colors[1];
- err->r = x->r - 1;
- err->g = x->g - 1;
- err->b = x->b - 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];
- err->r = x->r - (double)r / (numColors - 1);
- err->g = x->g - (double)g / (numColors - 1);
- err->b = x->b - (double)b / (numColors - 1);
+ actual->r = (double)r / (numColors - 1);
+ actual->g = (double)g / (numColors - 1);
+ actual->b = (double)b / (numColors - 1);
}
return pixel;
}
pixBuf = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar));
// allocate XImage and read from page pixmap
- image = XCreateImage(display, DefaultVisual(display, screenNum),
- depth, ZPixmap, 0, NULL, bw, bh, 8, 0);
+ 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);
if (n > 0) {
p = pixBuf;
for (i = 0; i < n; ++i) {
- for (j = 0; j < width; ++j) {
- imgStr->getPixel(p);
- if (invert) {
- *p ^= 1;
+ memcpy(p, imgStr->getLine(), width);
+ if (invert) {
+ for (j = 0; j < width; ++j) {
+ p[j] ^= 1;
}
- ++p;
}
+ p += width;
}
}
lastYStep = yStep;
int yp, yq, yt, yStep, lastYStep;
int xp, xq, xt, xStep, xSrc;
GfxRGB *pixBuf;
- Guchar *alphaBuf;
+ Guchar *pixBuf1, *alphaBuf;
Guchar pixBuf2[gfxColorMaxComps];
- GfxRGB color2, err, errRight;
- GfxRGB *errDown;
+ GfxRGB color2, color3, actual, err, errRight;
+ GfxRGB *errDown0, *errDown1, *errDownTmp;
double r0, g0, b0, alpha, mul;
Gulong pix;
GfxRGB *p;
- Guchar *q;
+ Guchar *q, *p1, *p2;
GBool oneBitMode;
GfxRGB oneBitRGB[2];
int x, y, x1, y1, x2, y2;
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
}
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;
xq = width % scaledWidth;
// allocate pixel buffer
- pixBuf = (GfxRGB *)gmalloc((yp + 1) * width * sizeof(GfxRGB));
+ 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 {
}
// allocate XImage
- image = XCreateImage(display, DefaultVisual(display, screenNum),
- depth, ZPixmap, 0, NULL, bw, bh, 8, 0);
+ 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
// allocate error diffusion accumulators
if (dither) {
- errDown = (GfxRGB *)gmalloc(bw * sizeof(GfxRGB));
- for (j = 0; j < bw; ++j) {
- errDown[j].r = errDown[j].g = errDown[j].b = 0;
+ 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 {
- errDown = NULL;
+ errDown0 = errDown1 = NULL;
}
// optimize the one-bit-deep image case
- if ((oneBitMode = nComps == 1 && nBits == 1)) {
+ if (oneBitMode) {
pixBuf2[0] = 0;
colorMap->getRGB(pixBuf2, &oneBitRGB[0]);
pixBuf2[0] = 1;
for (y = 0; y < scaledHeight; ++y) {
- // initialize error diffusion accumulator
- errRight.r = errRight.g = errRight.b = 0;
+ // 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;
// read row(s) from image
n = (yp > 0) ? yStep : lastYStep;
if (n > 0) {
- p = pixBuf;
- q = alphaBuf;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < width; ++j) {
- imgStr->getPixel(pixBuf2);
- if (oneBitMode) {
- *p++ = oneBitRGB[pixBuf2[0]];
- } else {
- colorMap->getRGB(pixBuf2, p);
+ 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 (pixBuf2[k] < maskColors[2*k] ||
- pixBuf2[k] > maskColors[2*k]) {
- *q = 0;
- break;
+ 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;
}
- ++q;
+ p2 += nComps;
}
}
}
// x and y scaling operations
n = yStep > 0 ? yStep : 1;
m = xStep > 0 ? xStep : 1;
- p = pixBuf + xSrc;
- r0 = g0 = b0 = 0;
- q = alphaBuf ? alphaBuf + xSrc : (Guchar *)NULL;
- alpha = 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++;
+ if (oneBitMode) {
+ p1 = pixBuf1 + xSrc;
+ k = 0;
+ for (i = 0; i < n; ++i) {
+ for (j = 0; j < m; ++j) {
+ k += *p1++;
}
+ p1 += width - m;
}
- p += 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;
}
- 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 + errDown[tx + x2 - bx0].r;
+ color2.r = r0 + errRight.r + errDown0[x + 1].r;
if (color2.r > 1) {
- color2.r = 1;
+ color3.r = 1;
} else if (color2.r < 0) {
- color2.r = 0;
+ color3.r = 0;
+ } else {
+ color3.r = color2.r;
}
- color2.g = g0 + errRight.g + errDown[tx + x2 - bx0].g;
+ color2.g = g0 + errRight.g + errDown0[x + 1].g;
if (color2.g > 1) {
- color2.g = 1;
+ color3.g = 1;
} else if (color2.g < 0) {
- color2.g = 0;
+ color3.g = 0;
+ } else {
+ color3.g = color2.g;
}
- color2.b = b0 + errRight.b + errDown[tx + x2 - bx0].b;
+ color2.b = b0 + errRight.b + errDown0[x + 1].b;
if (color2.b > 1) {
- color2.b = 1;
+ color3.b = 1;
} else if (color2.b < 0) {
- color2.b = 0;
+ color3.b = 0;
+ } else {
+ color3.b = color2.b;
}
- pix = findColor(&color2, &err);
- errRight.r = errDown[tx + x2 - bx0].r = err.r / 2;
- errRight.g = errDown[tx + x2 - bx0].g = err.g / 2;
- errRight.b = errDown[tx + x2 - bx0].b = err.b / 2;
+ 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, &err);
+ pix = findColor(&color2, &actual);
}
// set pixel
// free memory
delete imgStr;
- gfree(pixBuf);
+ if (oneBitMode) {
+ gfree(pixBuf1);
+ } else {
+ gfree(pixBuf);
+ }
if (maskColors) {
gfree(alphaBuf);
}
gfree(image->data);
image->data = NULL;
XDestroyImage(image);
- gfree(errDown);
+ gfree(errDown0);
+ gfree(errDown1);
}
-GBool XOutputDev::findText(Unicode *s, int len, GBool top, GBool bottom,
- int *xMin, int *yMin, int *xMax, int *yMax) {
+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, top, bottom, &xMin1, &yMin1, &xMax1, &yMax1)) {
+ if (text->findText(s, len, startAtTop, stopAtBottom,
+ startAtLast, stopAtLast,
+ &xMin1, &yMin1, &xMax1, &yMax1)) {
*xMin = xoutRound(xMin1);
*xMax = xoutRound(xMax1);
*yMin = xoutRound(yMin1);