00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <aconf.h>
00010
00011 #ifdef USE_GCC_PRAGMAS
00012 #pragma implementation
00013 #endif
00014
00015 #include <stdio.h>
00016 #include <stdlib.h>
00017 #include <stddef.h>
00018 #include <unistd.h>
00019 #include <string.h>
00020 #include <ctype.h>
00021 #include <math.h>
00022 #include "gmem.h"
00023 #include "gfile.h"
00024 #include "GString.h"
00025 #include "GList.h"
00026 #include "Object.h"
00027 #include "Stream.h"
00028 #include "Link.h"
00029 #include "GfxState.h"
00030 #include "GfxFont.h"
00031 #include "UnicodeMap.h"
00032 #include "CharCodeToUnicode.h"
00033 #include "FontFile.h"
00034 #include "Error.h"
00035 #include "TextOutputDev.h"
00036 #include "XOutputDev.h"
00037 #if HAVE_T1LIB_H
00038 #include "T1Font.h"
00039 #endif
00040 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00041 #include "FTFont.h"
00042 #endif
00043 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00044 #include "TTFont.h"
00045 #endif
00046
00047 #ifdef VMS
00048 #if (__VMS_VER < 70000000)
00049 extern "C" int unlink(char *filename);
00050 #endif
00051 #endif
00052
00053 #ifdef XlibSpecificationRelease
00054 #if XlibSpecificationRelease < 5
00055 typedef char *XPointer;
00056 #endif
00057 #else
00058 typedef char *XPointer;
00059 #endif
00060
00061
00062
00063
00064
00065 #define xoutRound(x) ((int)(x + 0.5))
00066
00067 #define maxCurveSplits 6 // max number of splits when recursively
00068
00069
00070
00071
00072
00073
00074 struct XOutFontSubst {
00075 char *name;
00076 double mWidth;
00077 };
00078
00079
00080 static XOutFontSubst xOutSubstFonts[16] = {
00081 {"Helvetica", 0.833},
00082 {"Helvetica-Oblique", 0.833},
00083 {"Helvetica-Bold", 0.889},
00084 {"Helvetica-BoldOblique", 0.889},
00085 {"Times-Roman", 0.788},
00086 {"Times-Italic", 0.722},
00087 {"Times-Bold", 0.833},
00088 {"Times-BoldItalic", 0.778},
00089 {"Courier", 0.600},
00090 {"Courier-Oblique", 0.600},
00091 {"Courier-Bold", 0.600},
00092 {"Courier-BoldOblique", 0.600},
00093 {"Symbol", 0.576},
00094 {"Symbol", 0.576},
00095 {"Symbol", 0.576},
00096 {"Symbol", 0.576}
00097 };
00098
00099
00100
00101 static void outputToFile(void *stream, char *data, int len) {
00102 fwrite(data, 1, len, (FILE *)stream);
00103 }
00104
00105
00106
00107
00108
00109 XOutputFont::XOutputFont(Ref *idA, double m11OrigA, double m12OrigA,
00110 double m21OrigA, double m22OrigA,
00111 double m11A, double m12A, double m21A, double m22A,
00112 Display *displayA, XOutputDev *xOutA) {
00113 id = *idA;
00114 display = displayA;
00115 xOut = xOutA;
00116 m11Orig = m11OrigA;
00117 m12Orig = m12OrigA;
00118 m21Orig = m21OrigA;
00119 m22Orig = m22OrigA;
00120 m11 = m11A;
00121 m12 = m12A;
00122 m21 = m21A;
00123 m22 = m22A;
00124 }
00125
00126 XOutputFont::~XOutputFont() {
00127 }
00128
00129 void XOutputFont::getCharPath(GfxState *state,
00130 CharCode c, Unicode *u, int ulen) {
00131 }
00132
00133 #if HAVE_T1LIB_H
00134
00135
00136
00137
00138 XOutputT1Font::XOutputT1Font(Ref *idA, T1FontFile *fontFileA,
00139 double m11OrigA, double m12OrigA,
00140 double m21OrigA, double m22OrigA,
00141 double m11A, double m12A,
00142 double m21A, double m22A,
00143 Display *displayA, XOutputDev *xOutA):
00144 XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA,
00145 m11A, m12A, m21A, m22A, displayA, xOutA)
00146 {
00147 double matrix[4];
00148
00149 fontFile = fontFileA;
00150
00151
00152 matrix[0] = m11;
00153 matrix[1] = -m12;
00154 matrix[2] = m21;
00155 matrix[3] = -m22;
00156 font = new T1Font(fontFile, matrix);
00157 }
00158
00159 XOutputT1Font::~XOutputT1Font() {
00160 if (font) {
00161 delete font;
00162 }
00163 }
00164
00165 GBool XOutputT1Font::isOk() {
00166 return font != NULL;
00167 }
00168
00169 void XOutputT1Font::updateGC(GC gc) {
00170 }
00171
00172 void XOutputT1Font::drawChar(GfxState *state, Pixmap pixmap, int w, int h,
00173 GC gc, GfxRGB *rgb,
00174 double x, double y, double dx, double dy,
00175 CharCode c, Unicode *u, int uLen) {
00176 font->drawChar(pixmap, w, h, gc, xoutRound(x), xoutRound(y),
00177 (int)(rgb->r * 65535), (int)(rgb->g * 65535),
00178 (int)(rgb->b * 65535), c, u[0]);
00179 }
00180
00181 void XOutputT1Font::getCharPath(GfxState *state,
00182 CharCode c, Unicode *u, int uLen) {
00183 font->getCharPath(c, u[0], state);
00184 }
00185 #endif // HAVE_T1LIB_H
00186
00187 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00188
00189
00190
00191
00192 XOutputFTFont::XOutputFTFont(Ref *idA, FTFontFile *fontFileA,
00193 double m11OrigA, double m12OrigA,
00194 double m21OrigA, double m22OrigA,
00195 double m11A, double m12A,
00196 double m21A, double m22A,
00197 Display *displayA, XOutputDev *xOutA):
00198 XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA,
00199 m11A, m12A, m21A, m22A, displayA, xOutA)
00200 {
00201 double matrix[4];
00202
00203 fontFile = fontFileA;
00204
00205
00206 matrix[0] = m11;
00207 matrix[1] = -m12;
00208 matrix[2] = m21;
00209 matrix[3] = -m22;
00210 font = new FTFont(fontFile, matrix);
00211 }
00212
00213 XOutputFTFont::~XOutputFTFont() {
00214 if (font) {
00215 delete font;
00216 }
00217 }
00218
00219 GBool XOutputFTFont::isOk() {
00220 return font != NULL;
00221 }
00222
00223 void XOutputFTFont::updateGC(GC gc) {
00224 }
00225
00226 void XOutputFTFont::drawChar(GfxState *state, Pixmap pixmap, int w, int h,
00227 GC gc, GfxRGB *rgb,
00228 double x, double y, double dx, double dy,
00229 CharCode c, Unicode *u, int uLen) {
00230 font->drawChar(pixmap, w, h, gc, xoutRound(x), xoutRound(y),
00231 (int)(rgb->r * 65535), (int)(rgb->g * 65535),
00232 (int)(rgb->b * 65535), c, uLen > 0 ? u[0] : 0);
00233 }
00234
00235 void XOutputFTFont::getCharPath(GfxState *state,
00236 CharCode c, Unicode *u, int uLen) {
00237 font->getCharPath(c, u[0], state);
00238 }
00239 #endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00240
00241 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00242
00243
00244
00245
00246 XOutputTTFont::XOutputTTFont(Ref *idA, TTFontFile *fontFileA,
00247 double m11OrigA, double m12OrigA,
00248 double m21OrigA, double m22OrigA,
00249 double m11A, double m12A,
00250 double m21A, double m22A,
00251 Display *displayA, XOutputDev *xOutA):
00252 XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA,
00253 m11A, m12A, m21A, m22A, displayA, xOutA)
00254 {
00255 double matrix[4];
00256
00257 fontFile = fontFileA;
00258
00259
00260 matrix[0] = m11;
00261 matrix[1] = -m12;
00262 matrix[2] = m21;
00263 matrix[3] = -m22;
00264 font = new TTFont(fontFile, matrix);
00265 }
00266
00267 XOutputTTFont::~XOutputTTFont() {
00268 if (font) {
00269 delete font;
00270 }
00271 }
00272
00273 GBool XOutputTTFont::isOk() {
00274 return font != NULL;
00275 }
00276
00277 void XOutputTTFont::updateGC(GC gc) {
00278 }
00279
00280 void XOutputTTFont::drawChar(GfxState *state, Pixmap pixmap, int w, int h,
00281 GC gc, GfxRGB *rgb,
00282 double x, double y, double dx, double dy,
00283 CharCode c, Unicode *u, int uLen) {
00284 font->drawChar(pixmap, w, h, gc, xoutRound(x), xoutRound(y),
00285 (int)(rgb->r * 65535), (int)(rgb->g * 65535),
00286 (int)(rgb->b * 65535), c, u[0]);
00287 }
00288 #endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00289
00290
00291
00292
00293
00294
00295
00296 static void stringSubst(char *buf, int bufSize, char *fmt, char *val) {
00297 char *p, *q;
00298 int i;
00299
00300 i = 0;
00301 p = fmt;
00302 while (*p) {
00303 if (p[0] == '%' && p[1] == 's') {
00304 q = val;
00305 while (*q && i < bufSize - 1) {
00306 buf[i++] = *q++;
00307 }
00308 p += 2;
00309 } else {
00310 if (i < bufSize - 1) {
00311 buf[i++] = *p;
00312 }
00313 ++p;
00314 }
00315 }
00316 buf[i] = '\0';
00317 }
00318
00319 XOutputServer8BitFont::XOutputServer8BitFont(Ref *idA, GString *xlfdFmt,
00320 UnicodeMap *xUMapA,
00321 CharCodeToUnicode *fontUMap,
00322 double m11OrigA, double m12OrigA,
00323 double m21OrigA, double m22OrigA,
00324 double m11A, double m12A,
00325 double m21A, double m22A,
00326 Display *displayA,
00327 XOutputDev *xOutA):
00328 XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA,
00329 m11A, m12A, m21A, m22A, displayA, xOutA)
00330 {
00331 double size, ntm11, ntm12, ntm21, ntm22;
00332 GBool rotated;
00333 int startSize, sz;
00334 char fontName[500], fontSize[100];
00335 Unicode u;
00336 char buf;
00337 int i;
00338
00339
00340 size = sqrt(m21*m21 + m22*m22);
00341 ntm11 = m11 / size;
00342 ntm12 = -m12 / size;
00343 ntm21 = m21 / size;
00344 ntm22 = -m22 / size;
00345
00346
00347 rotated = !(ntm11 > 0 && ntm22 > 0 &&
00348 fabs(ntm11 / ntm22 - 1) < 0.2 &&
00349 fabs(ntm12) < 0.01 &&
00350 fabs(ntm21) < 0.01);
00351
00352
00353
00354 startSize = (int)size;
00355 if (rotated) {
00356 sprintf(fontSize, "[%s%0.2f %s%0.2f %s%0.2f %s%0.2f]",
00357 ntm11<0 ? "~" : "", fabs(ntm11 * size),
00358 ntm12<0 ? "~" : "", fabs(ntm12 * size),
00359 ntm21<0 ? "~" : "", fabs(ntm21 * size),
00360 ntm22<0 ? "~" : "", fabs(ntm22 * size));
00361 } else {
00362 sprintf(fontSize, "%d", startSize);
00363 }
00364 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize);
00365 xFont = XLoadQueryFont(display, fontName);
00366 if (!xFont) {
00367 for (sz = startSize; sz >= startSize/2 && sz >= 1; --sz) {
00368 sprintf(fontSize, "%d", sz);
00369 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize);
00370 if ((xFont = XLoadQueryFont(display, fontName)))
00371 break;
00372 }
00373 if (!xFont) {
00374 for (sz = startSize + 1; sz < startSize + 10; ++sz) {
00375 sprintf(fontSize, "%d", sz);
00376 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(),
00377 fontSize);
00378 if ((xFont = XLoadQueryFont(display, fontName))) {
00379 break;
00380 }
00381 }
00382 if (!xFont) {
00383 sprintf(fontSize, "%d", startSize);
00384 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(),
00385 fontSize);
00386 error(-1, "Failed to open font: '%s'", fontName);
00387 return;
00388 }
00389 }
00390 }
00391
00392
00393 xUMap = xUMapA;
00394 for (i = 0; i < 256; ++i) {
00395 if (fontUMap->mapToUnicode((CID)i, &u, 1) == 1 &&
00396 xUMap->mapUnicode(u, &buf, 1) == 1) {
00397 map[i] = buf & 0xff;
00398 } else {
00399 map[i] = 0;
00400 }
00401 }
00402 }
00403
00404 XOutputServer8BitFont::~XOutputServer8BitFont() {
00405 if (xFont) {
00406 XFreeFont(display, xFont);
00407 }
00408 }
00409
00410 GBool XOutputServer8BitFont::isOk() {
00411 return xFont != NULL;
00412 }
00413
00414 void XOutputServer8BitFont::updateGC(GC gc) {
00415 XSetFont(display, gc, xFont->fid);
00416 }
00417
00418 void XOutputServer8BitFont::drawChar(GfxState *state, Pixmap pixmap,
00419 int w, int h, GC gc, GfxRGB *rgb,
00420 double x, double y, double dx, double dy,
00421 CharCode c, Unicode *u, int uLen) {
00422 Gushort c1;
00423 char buf[8];
00424 double dx1, dy1;
00425 int m, n, i, j, k;
00426
00427 c1 = map[c];
00428 if (c1 > 0) {
00429 buf[0] = (char)c1;
00430 XDrawString(display, pixmap, gc, xoutRound(x), xoutRound(y), buf, 1);
00431 } else {
00432
00433 n = 0;
00434 for (i = 0; i < uLen; ++i) {
00435 n += xUMap->mapUnicode(u[i], buf, sizeof(buf));
00436 }
00437 if (n > 0) {
00438 dx1 = dx / n;
00439 dy1 = dy / n;
00440 k = 0;
00441 for (i = 0; i < uLen; ++i) {
00442 m = xUMap->mapUnicode(u[i], buf, sizeof(buf));
00443 for (j = 0; j < m; ++j) {
00444 XDrawString(display, pixmap, gc,
00445 xoutRound(x + k*dx1), xoutRound(y + k*dy1),
00446 buf + j, 1);
00447 ++k;
00448 }
00449 }
00450 }
00451 }
00452 }
00453
00454
00455
00456
00457
00458 XOutputServer16BitFont::XOutputServer16BitFont(Ref *idA, GString *xlfdFmt,
00459 UnicodeMap *xUMapA,
00460 CharCodeToUnicode *fontUMap,
00461 double m11OrigA,
00462 double m12OrigA,
00463 double m21OrigA,
00464 double m22OrigA,
00465 double m11A, double m12A,
00466 double m21A, double m22A,
00467 Display *displayA,
00468 XOutputDev *xOutA):
00469 XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA,
00470 m11A, m12A, m21A, m22A, displayA, xOutA)
00471 {
00472 double size, ntm11, ntm12, ntm21, ntm22;
00473 GBool rotated;
00474 int startSize, sz;
00475 char fontName[500], fontSize[100];
00476
00477 xUMap = xUMapA;
00478 xUMap->incRefCnt();
00479
00480
00481 size = sqrt(m21*m21 + m22*m22);
00482 ntm11 = m11 / size;
00483 ntm12 = -m12 / size;
00484 ntm21 = m21 / size;
00485 ntm22 = -m22 / size;
00486
00487
00488 rotated = !(ntm11 > 0 && ntm22 > 0 &&
00489 fabs(ntm11 / ntm22 - 1) < 0.2 &&
00490 fabs(ntm12) < 0.01 &&
00491 fabs(ntm21) < 0.01);
00492
00493
00494
00495 startSize = (int)size;
00496 if (rotated) {
00497 sprintf(fontSize, "[%s%0.2f %s%0.2f %s%0.2f %s%0.2f]",
00498 ntm11<0 ? "~" : "", fabs(ntm11 * size),
00499 ntm12<0 ? "~" : "", fabs(ntm12 * size),
00500 ntm21<0 ? "~" : "", fabs(ntm21 * size),
00501 ntm22<0 ? "~" : "", fabs(ntm22 * size));
00502 } else {
00503 sprintf(fontSize, "%d", startSize);
00504 }
00505 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize);
00506 xFont = XLoadQueryFont(display, fontName);
00507 if (!xFont) {
00508 for (sz = startSize; sz >= startSize/2 && sz >= 1; --sz) {
00509 sprintf(fontSize, "%d", sz);
00510 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize);
00511 if ((xFont = XLoadQueryFont(display, fontName)))
00512 break;
00513 }
00514 if (!xFont) {
00515 for (sz = startSize + 1; sz < startSize + 10; ++sz) {
00516 sprintf(fontSize, "%d", sz);
00517 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(),
00518 fontSize);
00519 if ((xFont = XLoadQueryFont(display, fontName))) {
00520 break;
00521 }
00522 }
00523 if (!xFont) {
00524 sprintf(fontSize, "%d", startSize);
00525 stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(),
00526 fontSize);
00527 error(-1, "Failed to open font: '%s'", fontName);
00528 return;
00529 }
00530 }
00531 }
00532 }
00533
00534 XOutputServer16BitFont::~XOutputServer16BitFont() {
00535 xUMap->decRefCnt();
00536 if (xFont) {
00537 XFreeFont(display, xFont);
00538 }
00539 }
00540
00541 GBool XOutputServer16BitFont::isOk() {
00542 return xFont != NULL;
00543 }
00544
00545 void XOutputServer16BitFont::updateGC(GC gc) {
00546 XSetFont(display, gc, xFont->fid);
00547 }
00548
00549 void XOutputServer16BitFont::drawChar(GfxState *state, Pixmap pixmap,
00550 int w, int h, GC gc, GfxRGB *rgb,
00551 double x, double y, double dx, double dy,
00552 CharCode c, Unicode *u, int uLen) {
00553 char buf[16];
00554 XChar2b c1;
00555 double dx1, dy1;
00556 int m, n, i, j, k;
00557
00558 n = 0;
00559 for (i = 0; i < uLen; ++i) {
00560 n += xUMap->mapUnicode(u[i], buf, sizeof(buf));
00561 }
00562 if (n > 0) {
00563 dx1 = dx / n;
00564 dy1 = dy / n;
00565 k = 0;
00566 for (i = 0; i < uLen; ++i) {
00567 m = xUMap->mapUnicode(u[i], buf, sizeof(buf));
00568 for (j = 0; j+1 < m; j += 2) {
00569 c1.byte1 = buf[j];
00570 c1.byte2 = buf[j+1];
00571 XDrawString16(display, pixmap, gc,
00572 xoutRound(x + k*dx1), xoutRound(y + k*dy1),
00573 &c1, 1);
00574 ++k;
00575 }
00576 }
00577 } else if (c != 0) {
00578
00579 error(-1, "Unknown character (CID=%d Unicode=%04x)",
00580 c, uLen > 0 ? u[0] : (Unicode)0);
00581 }
00582 }
00583
00584
00585
00586
00587
00588 #if HAVE_T1LIB_H
00589 XOutputT1FontFile::~XOutputT1FontFile() {
00590 delete fontFile;
00591 if (tmpFileName) {
00592 unlink(tmpFileName->getCString());
00593 delete tmpFileName;
00594 }
00595 }
00596 #endif
00597
00598 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00599 XOutputFTFontFile::~XOutputFTFontFile() {
00600 delete fontFile;
00601 if (tmpFileName) {
00602 unlink(tmpFileName->getCString());
00603 delete tmpFileName;
00604 }
00605 }
00606 #endif
00607
00608 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00609 XOutputTTFontFile::~XOutputTTFontFile() {
00610 delete fontFile;
00611 if (tmpFileName) {
00612 unlink(tmpFileName->getCString());
00613 delete tmpFileName;
00614 }
00615 }
00616 #endif
00617
00618 XOutputFontCache::XOutputFontCache(Display *displayA, Guint depthA,
00619 XOutputDev *xOutA,
00620 FontRastControl t1libControlA,
00621 FontRastControl freetypeControlA) {
00622 display = displayA;
00623 depth = depthA;
00624 xOut = xOutA;
00625
00626 #if HAVE_T1LIB_H
00627 t1Engine = NULL;
00628 t1libControl = t1libControlA;
00629 #endif
00630
00631 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00632 ftEngine = NULL;
00633 #endif
00634 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00635 ttEngine = NULL;
00636 #endif
00637 #if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
00638 freetypeControl = freetypeControlA;
00639 #endif
00640
00641 clear();
00642 }
00643
00644 XOutputFontCache::~XOutputFontCache() {
00645 delFonts();
00646 }
00647
00648 void XOutputFontCache::startDoc(int screenNum, Visual *visual,
00649 Colormap colormap, GBool trueColor,
00650 int rMul, int gMul, int bMul,
00651 int rShift, int gShift, int bShift,
00652 Gulong *colors, int numColors) {
00653 delFonts();
00654 clear();
00655
00656 #if HAVE_T1LIB_H
00657 if (t1libControl != fontRastNone) {
00658 t1Engine = new T1FontEngine(display, visual, depth, colormap,
00659 t1libControl == fontRastAALow ||
00660 t1libControl == fontRastAAHigh,
00661 t1libControl == fontRastAAHigh);
00662 if (t1Engine->isOk()) {
00663 if (trueColor) {
00664 t1Engine->useTrueColor(rMul, rShift, gMul, gShift, bMul, bShift);
00665 } else {
00666 t1Engine->useColorCube(colors, numColors);
00667 }
00668 } else {
00669 delete t1Engine;
00670 t1Engine = NULL;
00671 }
00672 }
00673 #endif // HAVE_T1LIB_H
00674
00675 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00676 if (freetypeControl != fontRastNone) {
00677 ftEngine = new FTFontEngine(display, visual, depth, colormap,
00678 freetypeControl == fontRastAALow ||
00679 freetypeControl == fontRastAAHigh);
00680 if (ftEngine->isOk()) {
00681 if (trueColor) {
00682 ftEngine->useTrueColor(rMul, rShift, gMul, gShift, bMul, bShift);
00683 } else {
00684 ftEngine->useColorCube(colors, numColors);
00685 }
00686 } else {
00687 delete ftEngine;
00688 ftEngine = NULL;
00689 }
00690 }
00691 #endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00692
00693 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00694 if (freetypeControl != fontRastNone) {
00695 ttEngine = new TTFontEngine(display, visual, depth, colormap,
00696 freetypeControl == fontRastAALow ||
00697 freetypeControl == fontRastAAHigh);
00698 if (ttEngine->isOk()) {
00699 if (trueColor) {
00700 ttEngine->useTrueColor(rMul, rShift, gMul, gShift, bMul, bShift);
00701 } else {
00702 ttEngine->useColorCube(colors, numColors);
00703 }
00704 } else {
00705 delete ttEngine;
00706 ttEngine = NULL;
00707 }
00708 }
00709 #endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00710 }
00711
00712 void XOutputFontCache::delFonts() {
00713 int i;
00714
00715 for (i = 0; i < nFonts; ++i) {
00716 delete fonts[i];
00717 }
00718
00719 #if HAVE_T1LIB_H
00720
00721 deleteGList(t1FontFiles, XOutputT1FontFile);
00722 if (t1Engine) {
00723 delete t1Engine;
00724 }
00725 #endif
00726
00727 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00728
00729 deleteGList(ftFontFiles, XOutputFTFontFile);
00730 if (ftEngine) {
00731 delete ftEngine;
00732 }
00733 #endif
00734
00735 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00736
00737 deleteGList(ttFontFiles, XOutputTTFontFile);
00738 if (ttEngine) {
00739 delete ttEngine;
00740 }
00741 #endif
00742 }
00743
00744 void XOutputFontCache::clear() {
00745 int i;
00746
00747 for (i = 0; i < xOutFontCacheSize; ++i) {
00748 fonts[i] = NULL;
00749 }
00750 nFonts = 0;
00751
00752 #if HAVE_T1LIB_H
00753
00754 t1FontFiles = new GList();
00755 #endif
00756
00757 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00758
00759 ftFontFiles = new GList();
00760 #endif
00761
00762 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00763
00764 ttFontFiles = new GList();
00765 #endif
00766 }
00767
00768 XOutputFont *XOutputFontCache::getFont(XRef *xref, GfxFont *gfxFont,
00769 double m11, double m12,
00770 double m21, double m22) {
00771 XOutputFont *font;
00772 DisplayFontParam *dfp;
00773 GString *substName;
00774 double m11New, m12New, m21New, m22New;
00775 double w1, w2, v;
00776 double *fm;
00777 char *name;
00778 int index;
00779 int code;
00780 int i, j;
00781
00782
00783 if (nFonts > 0 && fonts[0]->matches(gfxFont->getID(), m11, m12, m21, m22)) {
00784 return fonts[0];
00785 }
00786
00787
00788 for (i = 1; i < nFonts; ++i) {
00789 if (fonts[i]->matches(gfxFont->getID(), m11, m12, m21, m22)) {
00790 font = fonts[i];
00791 for (j = i; j > 0; --j) {
00792 fonts[j] = fonts[j-1];
00793 }
00794 fonts[0] = font;
00795 return font;
00796 }
00797 }
00798
00799
00800
00801 font = NULL;
00802 switch (gfxFont->getType()) {
00803 case fontType1:
00804 case fontType1C:
00805 #if HAVE_T1LIB_H
00806 if (t1libControl != fontRastNone) {
00807 font = tryGetT1Font(xref, gfxFont, m11, m12, m21, m22);
00808 }
00809 #endif
00810 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00811 if (!font) {
00812 if (freetypeControl != fontRastNone) {
00813 font = tryGetFTFont(xref, gfxFont, m11, m12, m21, m22);
00814 }
00815 }
00816 #endif
00817 break;
00818 case fontTrueType:
00819 case fontCIDType2:
00820 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00821 if (freetypeControl != fontRastNone) {
00822 font = tryGetFTFont(xref, gfxFont, m11, m12, m21, m22);
00823 }
00824 #endif
00825 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00826 if (freetypeControl != fontRastNone) {
00827 font = tryGetTTFont(xref, gfxFont, m11, m12, m21, m22);
00828 }
00829 #endif
00830 break;
00831 case fontCIDType0C:
00832 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
00833 if (freetypeControl != fontRastNone) {
00834 font = tryGetFTFont(xref, gfxFont, m11, m12, m21, m22);
00835 }
00836 #endif
00837 break;
00838 default:
00839 break;
00840 }
00841
00842 if (!font) {
00843
00844
00845 dfp = NULL;
00846 if (gfxFont->isCIDFont()) {
00847 if (((GfxCIDFont *)gfxFont)->getCollection()) {
00848 dfp = globalParams->
00849 getDisplayCIDFont(gfxFont->getName(),
00850 ((GfxCIDFont *)gfxFont)->getCollection());
00851 } else {
00852
00853 return NULL;
00854 }
00855 } else {
00856 if (gfxFont->getName()) {
00857 dfp = globalParams->getDisplayFont(gfxFont->getName());
00858 }
00859 }
00860 if (dfp) {
00861 font = tryGetFont(xref, dfp, gfxFont, m11, m12, m21, m22,
00862 m11, m12, m21, m22, gFalse);
00863 }
00864
00865
00866 if (!font && !gfxFont->isCIDFont()) {
00867
00868
00869 if (gfxFont->isFixedWidth()) {
00870 index = 8;
00871 } else if (gfxFont->isSerif()) {
00872 index = 4;
00873 } else {
00874 index = 0;
00875 }
00876 if (gfxFont->isBold()) {
00877 index += 2;
00878 }
00879 if (gfxFont->isItalic()) {
00880 index += 1;
00881 }
00882 substName = new GString(xOutSubstFonts[index].name);
00883
00884
00885
00886 m11New = m11;
00887 m12New = m12;
00888 m21New = m21;
00889 m22New = m22;
00890 for (code = 0; code < 256; ++code) {
00891 if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) &&
00892 name[0] == 'm' && name[1] == '\0') {
00893 break;
00894 }
00895 }
00896 if (code < 256) {
00897 w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code);
00898 w2 = xOutSubstFonts[index].mWidth;
00899 if (gfxFont->getType() == fontType3) {
00900
00901
00902
00903
00904
00905
00906 if (w1 > 0 && (w1 > 1.1 * w2 || w1 < 0.9 * w2)) {
00907 w1 /= w2;
00908 m11New *= w1;
00909 m12New *= w1;
00910 m21New *= w1;
00911 m22New *= w1;
00912 }
00913 fm = gfxFont->getFontMatrix();
00914 v = (fm[0] == 0) ? 1 : (fm[3] / fm[0]);
00915 m21New *= v;
00916 m22New *= v;
00917 } else if (!gfxFont->isSymbolic()) {
00918
00919
00920 if (w1 > 0.01 && w1 < 0.9 * w2) {
00921 w1 /= w2;
00922 m11New *= w1;
00923 m21New *= w1;
00924 }
00925 }
00926 }
00927
00928
00929 dfp = globalParams->getDisplayFont(substName);
00930 delete substName;
00931 if (!dfp) {
00932
00933
00934 error(-1, "Couldn't find a font for '%s'",
00935 gfxFont->getName()->getCString());
00936 return NULL;
00937 }
00938 font = tryGetFont(xref, dfp, gfxFont, m11, m12, m21, m22,
00939 m11New, m12New, m21New, m22New, gTrue);
00940 }
00941 }
00942
00943
00944 if (!font) {
00945
00946
00947
00948
00949 if (gfxFont->isCIDFont()) {
00950 error(-1, "Couldn't find a font for the '%s' character collection",
00951 ((GfxCIDFont *)gfxFont)->getCollection()->getCString());
00952 } else {
00953 error(-1, "Couldn't find a font for '%s'",
00954 gfxFont->getName() ?
00955 gfxFont->getName()->getCString() : "[unnamed]");
00956 }
00957 return NULL;
00958 }
00959
00960
00961 if (nFonts == xOutFontCacheSize) {
00962 --nFonts;
00963 delete fonts[nFonts];
00964 }
00965 for (j = nFonts; j > 0; --j) {
00966 fonts[j] = fonts[j-1];
00967 }
00968 fonts[0] = font;
00969 ++nFonts;
00970
00971 return font;
00972 }
00973
00974 XOutputFont *XOutputFontCache::tryGetFont(XRef *xref, DisplayFontParam *dfp,
00975 GfxFont *gfxFont,
00976 double m11Orig, double m12Orig,
00977 double m21Orig, double m22Orig,
00978 double m11, double m12,
00979 double m21, double m22,
00980 GBool subst) {
00981 XOutputFont *font;
00982
00983 font = NULL;
00984
00985
00986 switch (dfp->kind) {
00987
00988 case displayFontX:
00989 font = tryGetServerFont(dfp->x.xlfd, dfp->x.encoding, gfxFont,
00990 m11Orig, m12Orig, m21Orig, m22Orig,
00991 m11, m12, m21, m22);
00992 break;
00993
00994 case displayFontT1:
00995 #if HAVE_T1LIB_H
00996 if (t1libControl != fontRastNone) {
00997 font = tryGetT1FontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont,
00998 m11Orig, m12Orig, m21Orig, m22Orig,
00999 m11, m12, m21, m22, subst);
01000 }
01001 #endif
01002 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
01003 if (!font) {
01004 if (freetypeControl != fontRastNone) {
01005 font = tryGetFTFontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont,
01006 m11Orig, m12Orig, m21Orig, m22Orig,
01007 m11, m12, m21, m22, subst);
01008 }
01009 }
01010 #endif
01011 #if !((FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)) || defined(HAVE_T1LIB_H))
01012 error(-1, "Config file specifies a Type 1 font,");
01013 error(-1, "but xpdf was not built with t1lib or FreeType2 support");
01014 #endif
01015 break;
01016
01017 case displayFontTT:
01018 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
01019 if (freetypeControl != fontRastNone) {
01020 font = tryGetFTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont,
01021 m11Orig, m12Orig, m21Orig, m22Orig,
01022 m11, m12, m21, m22, subst);
01023 }
01024 #endif
01025 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
01026 if (freetypeControl != fontRastNone) {
01027 font = tryGetTTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont,
01028 m11Orig, m12Orig, m21Orig, m22Orig,
01029 m11, m12, m21, m22, subst);
01030 }
01031 #endif
01032 #if !(HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
01033 error(-1, "Config file specifies a TrueType font,");
01034 error(-1, "but xpdf was not built with FreeType support");
01035 dfp = NULL;
01036 #endif
01037 break;
01038 }
01039
01040 return font;
01041 }
01042
01043 #if HAVE_T1LIB_H
01044 XOutputFont *XOutputFontCache::tryGetT1Font(XRef *xref,
01045 GfxFont *gfxFont,
01046 double m11, double m12,
01047 double m21, double m22) {
01048 Ref *id;
01049 XOutputT1FontFile *xFontFile;
01050 XOutputFont *font;
01051 Ref embRef;
01052 GString *fileName;
01053 FILE *f;
01054 char *fontBuf;
01055 int fontLen;
01056 Type1CFontFile *ff;
01057 Object refObj, strObj;
01058 int c;
01059 int i;
01060
01061
01062 id = gfxFont->getID();
01063 for (i = 0; i < t1FontFiles->getLength(); ++i) {
01064 xFontFile = (XOutputT1FontFile *)t1FontFiles->get(i);
01065 if (xFontFile->num == id->num && xFontFile->gen == id->gen &&
01066 !xFontFile->subst) {
01067 font = new XOutputT1Font(id, xFontFile->fontFile,
01068 m11, m12, m21, m22,
01069 m11, m12, m21, m22, display, xOut);
01070 if (!font->isOk()) {
01071 delete font;
01072 return NULL;
01073 }
01074 return font;
01075 }
01076 }
01077
01078
01079 if (gfxFont->getEmbeddedFontID(&embRef)) {
01080
01081
01082 fileName = NULL;
01083 if (!openTempFile(&fileName, &f, "wb", NULL)) {
01084 error(-1, "Couldn't create temporary Type 1 font file");
01085 return NULL;
01086 }
01087 if (gfxFont->getType() == fontType1C) {
01088 if (!(fontBuf = gfxFont->readEmbFontFile(xref, &fontLen))) {
01089 fclose(f);
01090 return NULL;
01091 }
01092 ff = new Type1CFontFile(fontBuf, fontLen);
01093 ff->convertToType1(outputToFile, f);
01094 delete ff;
01095 gfree(fontBuf);
01096 } else {
01097 refObj.initRef(embRef.num, embRef.gen);
01098 refObj.fetch(xref, &strObj);
01099 refObj.free();
01100 strObj.streamReset();
01101 while ((c = strObj.streamGetChar()) != EOF) {
01102 fputc(c, f);
01103 }
01104 strObj.streamClose();
01105 strObj.free();
01106 }
01107 fclose(f);
01108
01109
01110 font = tryGetT1FontFromFile(xref, fileName, gTrue, gfxFont,
01111 m11, m12, m21, m22,
01112 m11, m12, m21, m22, gFalse);
01113
01114
01115
01116 unlink(fileName->getCString());
01117
01118 delete fileName;
01119
01120
01121 } else if ((fileName = gfxFont->getExtFontFile())) {
01122 font = tryGetT1FontFromFile(xref, fileName, gFalse, gfxFont,
01123 m11, m12, m21, m22,
01124 m11, m12, m21, m22, gFalse);
01125
01126 } else {
01127 font = NULL;
01128 }
01129
01130 return font;
01131 }
01132
01133 XOutputFont *XOutputFontCache::tryGetT1FontFromFile(XRef *xref,
01134 GString *fileName,
01135 GBool deleteFile,
01136 GfxFont *gfxFont,
01137 double m11Orig,
01138 double m12Orig,
01139 double m21Orig,
01140 double m22Orig,
01141 double m11, double m12,
01142 double m21, double m22,
01143 GBool subst) {
01144 Ref *id;
01145 T1FontFile *fontFile;
01146 XOutputFont *font;
01147
01148
01149 fontFile = new T1FontFile(t1Engine, fileName->getCString(),
01150 ((Gfx8BitFont *)gfxFont)->getEncoding(),
01151 gfxFont->getFontBBox());
01152 if (!fontFile->isOk()) {
01153 error(-1, "Couldn't create t1lib font from '%s'",
01154 fileName->getCString());
01155 delete fontFile;
01156 if (deleteFile) {
01157 unlink(fileName->getCString());
01158 }
01159 return NULL;
01160 }
01161
01162
01163 id = gfxFont->getID();
01164 t1FontFiles->append(new XOutputT1FontFile(id->num, id->gen,
01165 subst, fontFile,
01166 deleteFile ? fileName->copy()
01167 : (GString *)NULL));
01168
01169
01170 font = new XOutputT1Font(gfxFont->getID(), fontFile,
01171 m11Orig, m12Orig, m21Orig, m22Orig,
01172 m11, m12, m21, m22, display, xOut);
01173 if (!font->isOk()) {
01174 delete font;
01175 return NULL;
01176 }
01177 return font;
01178 }
01179 #endif // HAVE_T1LIB_H
01180
01181 #if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
01182 XOutputFont *XOutputFontCache::tryGetFTFont(XRef *xref,
01183 GfxFont *gfxFont,
01184 double m11, double m12,
01185 double m21, double m22) {
01186 Ref *id;
01187 XOutputFTFontFile *xFontFile;
01188 XOutputFont *font;
01189 Ref embRef;
01190 GString *fileName;
01191 FILE *f;
01192 #if 1 //~ need this until FT can handle fonts with missing tables
01193 char *fontBuf;
01194 int fontLen;
01195 TrueTypeFontFile *ff;
01196 #endif
01197 Object refObj, strObj;
01198 int c;
01199 int i;
01200
01201
01202 id = gfxFont->getID();
01203 for (i = 0; i < ftFontFiles->getLength(); ++i) {
01204 xFontFile = (XOutputFTFontFile *)ftFontFiles->get(i);
01205 if (xFontFile->num == id->num && xFontFile->gen == id->gen &&
01206 !xFontFile->subst) {
01207 font = new XOutputFTFont(id, xFontFile->fontFile,
01208 m11, m12, m21, m22,
01209 m11, m12, m21, m22, display, xOut);
01210 if (!font->isOk()) {
01211 delete font;
01212 return NULL;
01213 }
01214 return font;
01215 }
01216 }
01217
01218
01219 if (gfxFont->getEmbeddedFontID(&embRef)) {
01220
01221
01222 fileName = NULL;
01223 if (!openTempFile(&fileName, &f, "wb", NULL)) {
01224 error(-1, "Couldn't create temporary TrueType font file");
01225 return NULL;
01226 }
01227 #if 1 //~ need this until FT can handle fonts with missing tables
01228 if (gfxFont->getType() == fontTrueType ||
01229 gfxFont->getType() == fontCIDType2) {
01230 if (!(fontBuf = gfxFont->readEmbFontFile(xref, &fontLen))) {
01231 fclose(f);
01232 return NULL;
01233 }
01234 ff = new TrueTypeFontFile(fontBuf, fontLen);
01235 ff->writeTTF(f);
01236 delete ff;
01237 gfree(fontBuf);
01238 } else {
01239 refObj.initRef(embRef.num, embRef.gen);
01240 refObj.fetch(xref, &strObj);
01241 refObj.free();
01242 strObj.streamReset();
01243 while ((c = strObj.streamGetChar()) != EOF) {
01244 fputc(c, f);
01245 }
01246 strObj.streamClose();
01247 strObj.free();
01248 }
01249 #else
01250 refObj.initRef(embRef.num, embRef.gen);
01251 refObj.fetch(xref, &strObj);
01252 refObj.free();
01253 strObj.streamReset();
01254 while ((c = strObj.streamGetChar()) != EOF) {
01255 fputc(c, f);
01256 }
01257 strObj.streamClose();
01258 strObj.free();
01259 #endif
01260 fclose(f);
01261
01262
01263 font = tryGetFTFontFromFile(xref, fileName, gTrue, gfxFont,
01264 m11, m12, m21, m22,
01265 m11, m12, m21, m22, gFalse);
01266
01267
01268
01269 unlink(fileName->getCString());
01270
01271 delete fileName;
01272
01273
01274 } else if ((fileName = gfxFont->getExtFontFile())) {
01275 font = tryGetFTFontFromFile(xref, fileName, gFalse, gfxFont,
01276 m11, m12, m21, m22,
01277 m11, m12, m21, m22, gFalse);
01278
01279 } else {
01280 font = NULL;
01281 }
01282
01283 return font;
01284 }
01285
01286 XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref,
01287 GString *fileName,
01288 GBool deleteFile,
01289 GfxFont *gfxFont,
01290 double m11Orig,
01291 double m12Orig,
01292 double m21Orig,
01293 double m22Orig,
01294 double m11, double m12,
01295 double m21, double m22,
01296 GBool subst) {
01297 Ref *id;
01298 FTFontFile *fontFile;
01299 XOutputFont *font;
01300
01301
01302 if (gfxFont->isCIDFont()) {
01303 if (gfxFont->getType() == fontCIDType2) {
01304 fontFile = new FTFontFile(ftEngine, fileName->getCString(),
01305 ((GfxCIDFont *)gfxFont)->getCIDToGID(),
01306 ((GfxCIDFont *)gfxFont)->getCIDToGIDLen());
01307 } else {
01308 fontFile = new FTFontFile(ftEngine, fileName->getCString());
01309 }
01310 } else {
01311 fontFile = new FTFontFile(ftEngine, fileName->getCString(),
01312 ((Gfx8BitFont *)gfxFont)->getEncoding(),
01313 ((Gfx8BitFont *)gfxFont)->getHasEncoding());
01314 }
01315 if (!fontFile->isOk()) {
01316 error(-1, "Couldn't create FreeType font from '%s'",
01317 fileName->getCString());
01318 delete fontFile;
01319 if (deleteFile) {
01320 unlink(fileName->getCString());
01321 }
01322 return NULL;
01323 }
01324
01325
01326 id = gfxFont->getID();
01327 ftFontFiles->append(new XOutputFTFontFile(id->num, id->gen,
01328 subst, fontFile,
01329 deleteFile ? fileName->copy()
01330 : (GString *)NULL));
01331
01332
01333 font = new XOutputFTFont(gfxFont->getID(), fontFile,
01334 m11Orig, m12Orig, m21Orig, m22Orig,
01335 m11, m12, m21, m22, display, xOut);
01336 if (!font->isOk()) {
01337 delete font;
01338 return NULL;
01339 }
01340 return font;
01341 }
01342 #endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
01343
01344 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
01345 XOutputFont *XOutputFontCache::tryGetTTFont(XRef *xref,
01346 GfxFont *gfxFont,
01347 double m11, double m12,
01348 double m21, double m22) {
01349 Ref *id;
01350 XOutputTTFontFile *xFontFile;
01351 XOutputFont *font;
01352 Ref embRef;
01353 GString *fileName;
01354 FILE *f;
01355 Object refObj, strObj;
01356 int c;
01357 int i;
01358
01359
01360 id = gfxFont->getID();
01361 xFontFile = NULL;
01362 for (i = 0; i < ttFontFiles->getLength(); ++i) {
01363 xFontFile = (XOutputTTFontFile *)ttFontFiles->get(i);
01364 if (xFontFile->num == id->num && xFontFile->gen == id->gen &&
01365 !xFontFile->subst) {
01366 font = new XOutputTTFont(id, xFontFile->fontFile,
01367 m11, m12, m21, m22,
01368 m11, m12, m21, m22, display, xOut);
01369 if (!font->isOk()) {
01370 delete font;
01371 return NULL;
01372 }
01373 return font;
01374 }
01375 }
01376
01377
01378 if (gfxFont->getEmbeddedFontID(&embRef)) {
01379
01380
01381 fileName = NULL;
01382 if (!openTempFile(&fileName, &f, "wb", NULL)) {
01383 error(-1, "Couldn't create temporary TrueType font file");
01384 return NULL;
01385 }
01386 refObj.initRef(embRef.num, embRef.gen);
01387 refObj.fetch(xref, &strObj);
01388 refObj.free();
01389 strObj.streamReset();
01390 while ((c = strObj.streamGetChar()) != EOF) {
01391 fputc(c, f);
01392 }
01393 strObj.streamClose();
01394 strObj.free();
01395 fclose(f);
01396
01397
01398 font = tryGetTTFontFromFile(xref, fileName, gTrue, gfxFont,
01399 m11, m12, m21, m22,
01400 m11, m12, m21, m22, gFalse);
01401
01402
01403
01404 unlink(fileName->getCString());
01405
01406 delete fileName;
01407
01408 } else if ((fileName = gfxFont->getExtFontFile())) {
01409 font = tryGetTTFontFromFile(xref, fileName, gFalse, gfxFont,
01410 m11, m12, m21, m22,
01411 m11, m12, m21, m22, gFalse);
01412
01413 } else {
01414 font = NULL;
01415 }
01416
01417 return font;
01418 }
01419
01420 XOutputFont *XOutputFontCache::tryGetTTFontFromFile(XRef *xref,
01421 GString *fileName,
01422 GBool deleteFile,
01423 GfxFont *gfxFont,
01424 double m11Orig,
01425 double m12Orig,
01426 double m21Orig,
01427 double m22Orig,
01428 double m11, double m12,
01429 double m21, double m22,
01430 GBool subst) {
01431 Ref *id;
01432 TTFontFile *fontFile;
01433 XOutputFont *font;
01434
01435
01436 if (gfxFont->isCIDFont()) {
01437
01438 fontFile = new TTFontFile(ttEngine, fileName->getCString(),
01439 ((GfxCIDFont *)gfxFont)->getCIDToGID(),
01440 ((GfxCIDFont *)gfxFont)->getCIDToGIDLen());
01441 } else {
01442 fontFile = new TTFontFile(ttEngine, fileName->getCString(),
01443 ((Gfx8BitFont *)gfxFont)->getEncoding(),
01444 ((Gfx8BitFont *)gfxFont)->getHasEncoding());
01445 }
01446 if (!fontFile->isOk()) {
01447 error(-1, "Couldn't create FreeType font from '%s'",
01448 fileName->getCString());
01449 delete fontFile;
01450 if (deleteFile) {
01451 unlink(fileName->getCString());
01452 }
01453 return NULL;
01454 }
01455
01456
01457 id = gfxFont->getID();
01458 ttFontFiles->append(new XOutputTTFontFile(id->num, id->gen,
01459 subst, fontFile,
01460 deleteFile ? fileName->copy()
01461 : (GString *)NULL));
01462
01463
01464 font = new XOutputTTFont(gfxFont->getID(), fontFile,
01465 m11Orig, m12Orig, m21Orig, m22Orig,
01466 m11, m12, m21, m22, display, xOut);
01467 if (!font->isOk()) {
01468 delete font;
01469 return NULL;
01470 }
01471 return font;
01472 }
01473 #endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
01474
01475 XOutputFont *XOutputFontCache::tryGetServerFont(GString *xlfd,
01476 GString *encodingName,
01477 GfxFont *gfxFont,
01478 double m11Orig, double m12Orig,
01479 double m21Orig, double m22Orig,
01480 double m11, double m12,
01481 double m21, double m22) {
01482 XOutputFont *font;
01483 UnicodeMap *uMap;
01484 CharCodeToUnicode *ctu;
01485
01486 uMap = globalParams->getUnicodeMap(encodingName);
01487 if (gfxFont->isCIDFont()) {
01488 ctu = ((GfxCIDFont *)gfxFont)->getToUnicode();
01489 font = new XOutputServer16BitFont(gfxFont->getID(), xlfd, uMap, ctu,
01490 m11Orig, m12Orig, m21Orig, m22Orig,
01491 m11, m12, m21, m22,
01492 display, xOut);
01493 ctu->decRefCnt();
01494 } else {
01495 ctu = ((Gfx8BitFont *)gfxFont)->getToUnicode();
01496 font = new XOutputServer8BitFont(gfxFont->getID(), xlfd, uMap, ctu,
01497 m11Orig, m12Orig, m21Orig, m22Orig,
01498 m11, m12, m21, m22,
01499 display, xOut);
01500 ctu->decRefCnt();
01501 }
01502 uMap->decRefCnt();
01503 if (!font->isOk()) {
01504 delete font;
01505 return NULL;
01506 }
01507 return font;
01508 }
01509
01510
01511
01512
01513
01514 struct T3FontCacheTag {
01515 Gushort code;
01516 Gushort mru;
01517 double wx, wy;
01518 };
01519
01520 class T3FontCache {
01521 public:
01522
01523 T3FontCache(Ref *fontID, double m11A, double m12A,
01524 double m21A, double m22A,
01525 int glyphXA, int glyphYA, int glyphWA, int glyphHA,
01526 Display *displayA, Visual *visual, Guint depth,
01527 Pixmap origPixmap);
01528 ~T3FontCache();
01529 GBool matches(Ref *idA, double m11A, double m12A,
01530 double m21A, double m22A)
01531 { return fontID.num == idA->num && fontID.gen == idA->gen &&
01532 m11 == m11A && m12 == m12A && m21 == m21A && m22 == m22A; }
01533
01534 Ref fontID;
01535 double m11, m12, m21, m22;
01536 int glyphX, glyphY;
01537 int glyphW, glyphH;
01538 int glyphSize;
01539 int cacheSets;
01540 int cacheAssoc;
01541 Guchar *cacheData;
01542 T3FontCacheTag *cacheTags;
01543 Display *display;
01544 Pixmap pixmap;
01545 XImage *image;
01546 };
01547
01548 T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A,
01549 double m21A, double m22A,
01550 int glyphXA, int glyphYA, int glyphWA, int glyphHA,
01551 Display *displayA, Visual *visual, Guint depth,
01552 Pixmap origPixmap) {
01553 int i;
01554
01555 fontID = *fontIDA;
01556 m11 = m11A;
01557 m12 = m12A;
01558 m21 = m21A;
01559 m22 = m22A;
01560 glyphX = glyphXA;
01561 glyphY = glyphYA;
01562 glyphW = glyphWA;
01563 glyphH = glyphHA;
01564 glyphSize = glyphW * glyphH;
01565 cacheAssoc = 8;
01566 if (glyphSize <= 256) {
01567 cacheSets = 8;
01568 } else if (glyphSize <= 512) {
01569 cacheSets = 4;
01570 } else if (glyphSize <= 1024) {
01571 cacheSets = 2;
01572 } else {
01573 cacheSets = 1;
01574 }
01575 cacheData = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize);
01576 cacheTags = (T3FontCacheTag *)gmalloc(cacheSets * cacheAssoc *
01577 sizeof(T3FontCacheTag));
01578 for (i = 0; i < cacheSets * cacheAssoc; ++i) {
01579 cacheTags[i].mru = i & (cacheAssoc - 1);
01580 }
01581 display = displayA;
01582 pixmap = XCreatePixmap(display, origPixmap, glyphW, glyphH, depth);
01583 image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL,
01584 glyphW, glyphH, 8, 0);
01585 image->data = (char *)gmalloc(glyphH * image->bytes_per_line);
01586 }
01587
01588 T3FontCache::~T3FontCache() {
01589 gfree(cacheData);
01590 gfree(cacheTags);
01591 XFreePixmap(display, pixmap);
01592 gfree(image->data);
01593 image->data = NULL;
01594 XDestroyImage(image);
01595 }
01596
01597 struct T3GlyphStack {
01598 GBool cacheable;
01599 Gushort code;
01600 T3FontCache *cache;
01601 int cacheIdx;
01602 T3FontCacheTag *cacheTag;
01603 Guchar *cacheData;
01604 double x, y;
01605 Unicode *u;
01606 int uLen;
01607 GfxRGB color;
01608 int origPixmapW, origPixmapH;
01609 Pixmap origPixmap;
01610 GC origStrokeGC;
01611 GC origFillGC;
01612 Region origClipRegion;
01613 double origCTM4, origCTM5;
01614 double wx, wy;
01615 T3GlyphStack *next;
01616 };
01617
01618
01619
01620
01621
01622 XOutputDev::XOutputDev(Display *displayA, int screenNumA,
01623 Visual *visualA, Colormap colormapA,
01624 GBool reverseVideoA, unsigned long paperColorA,
01625 GBool installCmap, int rgbCubeSize,
01626 int forceDepth) {
01627 XVisualInfo visualTempl;
01628 XVisualInfo *visualList;
01629 int nVisuals;
01630 Gulong mask;
01631 XColor xcolor;
01632 XColor *xcolors;
01633 int r, g, b, n, m;
01634 GBool ok;
01635
01636
01637 xref = NULL;
01638
01639
01640 display = displayA;
01641 screenNum = screenNumA;
01642 visual = visualA;
01643 colormap = colormapA;
01644
01645
01646 pixmapW = pixmapH = 0;
01647
01648
01649 if (forceDepth != 0) {
01650 depth = forceDepth;
01651 trueColor = depth >= 16;
01652 } else {
01653 visualTempl.visualid = XVisualIDFromVisual(visual);
01654 visualList = XGetVisualInfo(display, VisualIDMask,
01655 &visualTempl, &nVisuals);
01656 if (nVisuals < 1) {
01657
01658 XFree((XPointer)visualList);
01659 visualList = XGetVisualInfo(display, VisualNoMask, &visualTempl,
01660 &nVisuals);
01661 }
01662 depth = visualList->depth;
01663 if (visualList->c_class == TrueColor) {
01664 trueColor = gTrue;
01665 for (mask = visualList->red_mask, rShift = 0;
01666 mask && !(mask & 1);
01667 mask >>= 1, ++rShift) ;
01668 rMul = (int)mask;
01669 for (mask = visualList->green_mask, gShift = 0;
01670 mask && !(mask & 1);
01671 mask >>= 1, ++gShift) ;
01672 gMul = (int)mask;
01673 for (mask = visualList->blue_mask, bShift = 0;
01674 mask && !(mask & 1);
01675 mask >>= 1, ++bShift) ;
01676 bMul = (int)mask;
01677 } else {
01678 trueColor = gFalse;
01679 }
01680 XFree((XPointer)visualList);
01681 }
01682
01683
01684 if (!trueColor) {
01685 redMap[BlackPixel(display, screenNum) & 0xff] = 0;
01686 redMap[WhitePixel(display, screenNum) & 0xff] = 1;
01687
01688
01689 if (installCmap) {
01690 for (numColors = 6; numColors >= 2; --numColors) {
01691 m = numColors * numColors * numColors;
01692 if (XAllocColorCells(display, colormap, False, NULL, 0, colors, m)) {
01693 break;
01694 }
01695 }
01696 if (numColors >= 2) {
01697 m = numColors * numColors * numColors;
01698 xcolors = (XColor *)gmalloc(m * sizeof(XColor));
01699 n = 0;
01700 for (r = 0; r < numColors; ++r) {
01701 for (g = 0; g < numColors; ++g) {
01702 for (b = 0; b < numColors; ++b) {
01703 xcolors[n].pixel = colors[n];
01704 xcolors[n].red = (r * 65535) / (numColors - 1);
01705 xcolors[n].green = (g * 65535) / (numColors - 1);
01706 xcolors[n].blue = (b * 65535) / (numColors - 1);
01707 xcolors[n].flags = DoRed | DoGreen | DoBlue;
01708 redMap[xcolors[n].pixel & 0xff] = xcolors[n].red / 65535.0;
01709 ++n;
01710 }
01711 }
01712 }
01713 XStoreColors(display, colormap, xcolors, m);
01714 gfree(xcolors);
01715 } else {
01716 numColors = 1;
01717 colors[0] = BlackPixel(display, screenNum);
01718 colors[1] = WhitePixel(display, screenNum);
01719 }
01720
01721
01722 } else {
01723 if (rgbCubeSize > maxRGBCube) {
01724 rgbCubeSize = maxRGBCube;
01725 }
01726 ok = gFalse;
01727 for (numColors = rgbCubeSize; numColors >= 2; --numColors) {
01728 ok = gTrue;
01729 n = 0;
01730 for (r = 0; r < numColors && ok; ++r) {
01731 for (g = 0; g < numColors && ok; ++g) {
01732 for (b = 0; b < numColors && ok; ++b) {
01733 if (n == 0) {
01734 colors[n] = BlackPixel(display, screenNum);
01735 redMap[colors[n] & 0xff] = 0;
01736 ++n;
01737 } else {
01738 xcolor.red = (r * 65535) / (numColors - 1);
01739 xcolor.green = (g * 65535) / (numColors - 1);
01740 xcolor.blue = (b * 65535) / (numColors - 1);
01741 if (XAllocColor(display, colormap, &xcolor)) {
01742 colors[n++] = xcolor.pixel;
01743 redMap[xcolor.pixel & 0xff] = xcolor.red / 65535.0;
01744 } else {
01745 ok = gFalse;
01746 }
01747 }
01748 }
01749 }
01750 }
01751 if (ok) {
01752 break;
01753 }
01754 XFreeColors(display, colormap, &colors[1], n-1, 0);
01755 }
01756 if (!ok) {
01757 numColors = 1;
01758 colors[0] = BlackPixel(display, screenNum);
01759 colors[1] = WhitePixel(display, screenNum);
01760 }
01761 }
01762 }
01763
01764
01765 reverseVideo = reverseVideoA;
01766 paperColor = paperColorA;
01767
01768
01769 gfxFont = NULL;
01770 font = NULL;
01771 fontCache = new XOutputFontCache(display, depth, this,
01772 globalParams->getT1libControl(),
01773 globalParams->getFreeTypeControl());
01774 nT3Fonts = 0;
01775 t3GlyphStack = NULL;
01776
01777
01778 save = NULL;
01779
01780
01781 text = new TextPage(gFalse);
01782 }
01783
01784 XOutputDev::~XOutputDev() {
01785 int i;
01786
01787 delete fontCache;
01788 for (i = 0; i < nT3Fonts; ++i) {
01789 delete t3FontCache[i];
01790 }
01791 delete text;
01792 }
01793
01794 void XOutputDev::startDoc(XRef *xrefA) {
01795 int i;
01796
01797 xref = xrefA;
01798 fontCache->startDoc(screenNum, visual, colormap, trueColor, rMul, gMul, bMul,
01799 rShift, gShift, bShift, colors, numColors);
01800 for (i = 0; i < nT3Fonts; ++i) {
01801 delete t3FontCache[i];
01802 }
01803 nT3Fonts = 0;
01804 }
01805
01806 void XOutputDev::startPage(int pageNum, GfxState *state) {
01807 XGCValues gcValues;
01808 XRectangle rect;
01809
01810
01811 flatness = 0;
01812
01813
01814 gcValues.foreground = BlackPixel(display, screenNum);
01815 gcValues.background = WhitePixel(display, screenNum);
01816 gcValues.line_width = 0;
01817 gcValues.line_style = LineSolid;
01818 strokeGC = XCreateGC(display, pixmap,
01819 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
01820 &gcValues);
01821 fillGC = XCreateGC(display, pixmap,
01822 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
01823 &gcValues);
01824 gcValues.foreground = paperColor;
01825 paperGC = XCreateGC(display, pixmap,
01826 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
01827 &gcValues);
01828
01829
01830 clipRegion = XCreateRegion();
01831 rect.x = rect.y = 0;
01832 rect.width = pixmapW;
01833 rect.height = pixmapH;
01834 XUnionRectWithRegion(&rect, clipRegion, clipRegion);
01835 XSetRegion(display, strokeGC, clipRegion);
01836 XSetRegion(display, fillGC, clipRegion);
01837
01838
01839 gfxFont = NULL;
01840 font = NULL;
01841
01842
01843 XFillRectangle(display, pixmap, paperGC, 0, 0, pixmapW, pixmapH);
01844
01845
01846 text->clear();
01847 }
01848
01849 void XOutputDev::endPage() {
01850 XOutputState *s;
01851
01852 text->coalesce();
01853
01854
01855 while (save) {
01856 s = save;
01857 save = save->next;
01858 XFreeGC(display, s->strokeGC);
01859 XFreeGC(display, s->fillGC);
01860 XDestroyRegion(s->clipRegion);
01861 delete s;
01862 }
01863 XFreeGC(display, strokeGC);
01864 XFreeGC(display, fillGC);
01865 XFreeGC(display, paperGC);
01866 XDestroyRegion(clipRegion);
01867 }
01868
01869 void XOutputDev::drawLink(Link *link, Catalog *catalog) {
01870 double x1, y1, x2, y2, w;
01871 GfxRGB rgb;
01872 XPoint points[5];
01873 int x, y;
01874
01875 link->getBorder(&x1, &y1, &x2, &y2, &w);
01876 if (w > 0) {
01877 rgb.r = 0;
01878 rgb.g = 0;
01879 rgb.b = 1;
01880 XSetForeground(display, strokeGC, findColor(&rgb));
01881 XSetLineAttributes(display, strokeGC, xoutRound(w),
01882 LineSolid, CapRound, JoinRound);
01883 cvtUserToDev(x1, y1, &x, &y);
01884 points[0].x = points[4].x = x;
01885 points[0].y = points[4].y = y;
01886 cvtUserToDev(x2, y1, &x, &y);
01887 points[1].x = x;
01888 points[1].y = y;
01889 cvtUserToDev(x2, y2, &x, &y);
01890 points[2].x = x;
01891 points[2].y = y;
01892 cvtUserToDev(x1, y2, &x, &y);
01893 points[3].x = x;
01894 points[3].y = y;
01895 XDrawLines(display, pixmap, strokeGC, points, 5, CoordModeOrigin);
01896 }
01897 }
01898
01899 void XOutputDev::saveState(GfxState *state) {
01900 XOutputState *s;
01901 XGCValues values;
01902
01903
01904 s = new XOutputState;
01905 s->strokeGC = strokeGC;
01906 s->fillGC = fillGC;
01907 s->clipRegion = clipRegion;
01908
01909
01910 s->next = save;
01911 save = s;
01912
01913
01914 strokeGC = XCreateGC(display, pixmap, 0, &values);
01915 XCopyGC(display, s->strokeGC, 0xffffffff, strokeGC);
01916 fillGC = XCreateGC(display, pixmap, 0, &values);
01917 XCopyGC(display, s->fillGC, 0xffffffff, fillGC);
01918 clipRegion = XCreateRegion();
01919 XUnionRegion(s->clipRegion, clipRegion, clipRegion);
01920 XSetRegion(display, strokeGC, clipRegion);
01921 XSetRegion(display, fillGC, clipRegion);
01922 }
01923
01924 void XOutputDev::restoreState(GfxState *state) {
01925 XOutputState *s;
01926
01927 if (save) {
01928
01929 XFreeGC(display, strokeGC);
01930 XFreeGC(display, fillGC);
01931 XDestroyRegion(clipRegion);
01932
01933
01934 flatness = state->getFlatness();
01935 strokeGC = save->strokeGC;
01936 fillGC = save->fillGC;
01937 clipRegion = save->clipRegion;
01938 XSetRegion(display, strokeGC, clipRegion);
01939 XSetRegion(display, fillGC, clipRegion);
01940
01941
01942 s = save;
01943 save = save->next;
01944 delete s;
01945 }
01946 }
01947
01948 void XOutputDev::updateAll(GfxState *state) {
01949 updateLineAttrs(state, gTrue);
01950 updateFlatness(state);
01951 updateMiterLimit(state);
01952 updateFillColor(state);
01953 updateStrokeColor(state);
01954 updateFont(state);
01955 }
01956
01957 void XOutputDev::updateCTM(GfxState *state, double m11, double m12,
01958 double m21, double m22, double m31, double m32) {
01959 updateLineAttrs(state, gTrue);
01960 }
01961
01962 void XOutputDev::updateLineDash(GfxState *state) {
01963 updateLineAttrs(state, gTrue);
01964 }
01965
01966 void XOutputDev::updateFlatness(GfxState *state) {
01967 flatness = state->getFlatness();
01968 }
01969
01970 void XOutputDev::updateLineJoin(GfxState *state) {
01971 updateLineAttrs(state, gFalse);
01972 }
01973
01974 void XOutputDev::updateLineCap(GfxState *state) {
01975 updateLineAttrs(state, gFalse);
01976 }
01977
01978
01979 void XOutputDev::updateMiterLimit(GfxState *state) {
01980 }
01981
01982 void XOutputDev::updateLineWidth(GfxState *state) {
01983 updateLineAttrs(state, gFalse);
01984 }
01985
01986 void XOutputDev::updateLineAttrs(GfxState *state, GBool updateDash) {
01987 double width;
01988 int cap, join;
01989 double *dashPattern;
01990 int dashLength;
01991 double dashStart;
01992 char dashList[20];
01993 int i;
01994
01995 width = state->getTransformedLineWidth();
01996 switch (state->getLineCap()) {
01997 case 0: cap = CapButt; break;
01998 case 1: cap = CapRound; break;
01999 case 2: cap = CapProjecting; break;
02000 default:
02001 error(-1, "Bad line cap style (%d)", state->getLineCap());
02002 cap = CapButt;
02003 break;
02004 }
02005 switch (state->getLineJoin()) {
02006 case 0: join = JoinMiter; break;
02007 case 1: join = JoinRound; break;
02008 case 2: join = JoinBevel; break;
02009 default:
02010 error(-1, "Bad line join style (%d)", state->getLineJoin());
02011 join = JoinMiter;
02012 break;
02013 }
02014 state->getLineDash(&dashPattern, &dashLength, &dashStart);
02015 #if 1 //~ work around a bug in XFree86 (???)
02016 if (dashLength > 0 && cap == CapProjecting) {
02017 cap = CapButt;
02018 }
02019 #endif
02020 XSetLineAttributes(display, strokeGC, xoutRound(width),
02021 dashLength > 0 ? LineOnOffDash : LineSolid,
02022 cap, join);
02023 if (updateDash && dashLength > 0) {
02024 if (dashLength > 20)
02025 dashLength = 20;
02026 for (i = 0; i < dashLength; ++i) {
02027 dashList[i] = xoutRound(state->transformWidth(dashPattern[i]));
02028 if (dashList[i] == 0)
02029 dashList[i] = 1;
02030 }
02031 XSetDashes(display, strokeGC, xoutRound(dashStart), dashList, dashLength);
02032 }
02033 }
02034
02035 void XOutputDev::updateFillColor(GfxState *state) {
02036 GfxRGB rgb;
02037
02038 state->getFillRGB(&rgb);
02039 if (reverseVideo) {
02040 rgb.r = 1 - rgb.r;
02041 rgb.g = 1 - rgb.g;
02042 rgb.b = 1 - rgb.b;
02043 }
02044 XSetForeground(display, fillGC, findColor(&rgb));
02045 }
02046
02047 void XOutputDev::updateStrokeColor(GfxState *state) {
02048 GfxRGB rgb;
02049
02050 state->getStrokeRGB(&rgb);
02051 if (reverseVideo) {
02052 rgb.r = 1 - rgb.r;
02053 rgb.g = 1 - rgb.g;
02054 rgb.b = 1 - rgb.b;
02055 }
02056 XSetForeground(display, strokeGC, findColor(&rgb));
02057 }
02058
02059 void XOutputDev::updateFont(GfxState *state) {
02060 double m11, m12, m21, m22;
02061
02062 text->updateFont(state);
02063
02064 if (!(gfxFont = state->getFont())) {
02065 font = NULL;
02066 return;
02067 }
02068 if (gfxFont->getType() == fontType3) {
02069 font = NULL;
02070 return;
02071 }
02072 state->getFontTransMat(&m11, &m12, &m21, &m22);
02073 m11 *= state->getHorizScaling();
02074 m12 *= state->getHorizScaling();
02075 font = fontCache->getFont(xref, gfxFont, m11, m12, m21, m22);
02076 if (font) {
02077 font->updateGC(fillGC);
02078 font->updateGC(strokeGC);
02079 }
02080 }
02081
02082 void XOutputDev::stroke(GfxState *state) {
02083 XPoint *points;
02084 int *lengths;
02085 int n, size, numPoints, i, j;
02086
02087
02088 n = convertPath(state, &points, &size, &numPoints, &lengths, gFalse);
02089
02090
02091 j = 0;
02092 for (i = 0; i < n; ++i) {
02093 XDrawLines(display, pixmap, strokeGC, points + j, lengths[i],
02094 CoordModeOrigin);
02095 j += lengths[i];
02096 }
02097
02098
02099 if (points != tmpPoints)
02100 gfree(points);
02101 if (lengths != tmpLengths)
02102 gfree(lengths);
02103 }
02104
02105 void XOutputDev::fill(GfxState *state) {
02106 doFill(state, WindingRule);
02107 }
02108
02109 void XOutputDev::eoFill(GfxState *state) {
02110 doFill(state, EvenOddRule);
02111 }
02112
02113
02114
02115
02116
02117
02118
02119
02120
02121
02122 void XOutputDev::doFill(GfxState *state, int rule) {
02123 XPoint *points;
02124 int *lengths;
02125 int n, size, numPoints, i, j;
02126
02127
02128 XSetFillRule(display, fillGC, rule);
02129
02130
02131 n = convertPath(state, &points, &size, &numPoints, &lengths, gTrue);
02132
02133
02134 j = 0;
02135 for (i = 0; i < n; ++i) {
02136 XFillPolygon(display, pixmap, fillGC, points + j, lengths[i],
02137 Complex, CoordModeOrigin);
02138 if (state->getPath()->getNumSubpaths() == 1) {
02139 XDrawLines(display, pixmap, fillGC, points + j, lengths[i],
02140 CoordModeOrigin);
02141 }
02142 j += lengths[i] + 1;
02143 }
02144
02145
02146 if (points != tmpPoints)
02147 gfree(points);
02148 if (lengths != tmpLengths)
02149 gfree(lengths);
02150 }
02151
02152 void XOutputDev::clip(GfxState *state) {
02153 doClip(state, WindingRule);
02154 }
02155
02156 void XOutputDev::eoClip(GfxState *state) {
02157 doClip(state, EvenOddRule);
02158 }
02159
02160 void XOutputDev::doClip(GfxState *state, int rule) {
02161 Region region, region2;
02162 XPoint *points;
02163 int *lengths;
02164 int n, size, numPoints, i, j;
02165
02166
02167 n = convertPath(state, &points, &size, &numPoints, &lengths, gTrue);
02168
02169
02170
02171
02172
02173 if (lengths[0] > 2) {
02174 region = XPolygonRegion(points, lengths[0], rule);
02175 } else {
02176 region = XCreateRegion();
02177 }
02178 j = lengths[0] + 1;
02179 for (i = 1; i < n; ++i) {
02180 if (lengths[i] > 2) {
02181 region2 = XPolygonRegion(points + j, lengths[i], rule);
02182 } else {
02183 region2 = XCreateRegion();
02184 }
02185 XUnionRegion(region2, region, region);
02186 XDestroyRegion(region2);
02187 j += lengths[i] + 1;
02188 }
02189
02190
02191 XIntersectRegion(region, clipRegion, clipRegion);
02192 XDestroyRegion(region);
02193 XSetRegion(display, strokeGC, clipRegion);
02194 XSetRegion(display, fillGC, clipRegion);
02195
02196
02197 if (points != tmpPoints)
02198 gfree(points);
02199 if (lengths != tmpLengths)
02200 gfree(lengths);
02201 }
02202
02203
02204
02205
02206
02207
02208
02209
02210
02211
02212 int XOutputDev::convertPath(GfxState *state, XPoint **points, int *size,
02213 int *numPoints, int **lengths, GBool fillHack) {
02214 GfxPath *path;
02215 BoundingRect *rects;
02216 BoundingRect rect;
02217 int n, i, ii, j, k, k0;
02218
02219
02220 path = state->getPath();
02221 n = path->getNumSubpaths();
02222
02223
02224 if (n < numTmpSubpaths)
02225 *lengths = tmpLengths;
02226 else
02227 *lengths = (int *)gmalloc(n * sizeof(int));
02228
02229
02230 if (fillHack) {
02231 if (n < numTmpSubpaths)
02232 rects = tmpRects;
02233 else
02234 rects = (BoundingRect *)gmalloc(n * sizeof(BoundingRect));
02235 } else {
02236 rects = NULL;
02237 }
02238
02239
02240 *points = tmpPoints;
02241 *size = numTmpPoints;
02242 *numPoints = 0;
02243 for (i = 0; i < n; ++i) {
02244
02245
02246 j = *numPoints;
02247 convertSubpath(state, path->getSubpath(i), points, size, numPoints);
02248
02249
02250 if (fillHack) {
02251 rects[i].xMin = rects[i].xMax = (*points)[j].x;
02252 rects[i].yMin = rects[i].yMax = (*points)[j].y;
02253 for (k = j + 1; k < *numPoints; ++k) {
02254 if ((*points)[k].x < rects[i].xMin)
02255 rects[i].xMin = (*points)[k].x;
02256 else if ((*points)[k].x > rects[i].xMax)
02257 rects[i].xMax = (*points)[k].x;
02258 if ((*points)[k].y < rects[i].yMin)
02259 rects[i].yMin = (*points)[k].y;
02260 else if ((*points)[k].y > rects[i].yMax)
02261 rects[i].yMax = (*points)[k].y;
02262 }
02263 }
02264
02265
02266 if (fillHack && ((*points)[*numPoints-1].x != (*points)[j].x ||
02267 (*points)[*numPoints-1].y != (*points)[j].y)) {
02268 addPoint(points, size, numPoints, (*points)[j].x, (*points)[j].y);
02269 }
02270
02271
02272 (*lengths)[i] = *numPoints - j;
02273
02274
02275 if (fillHack)
02276 addPoint(points, size, numPoints, 0, 0);
02277 }
02278
02279
02280
02281 for (i = 0; i < *numPoints; ++i) {
02282 if ((*points)[i].x < -pixmapW) {
02283 (*points)[i].x = -pixmapW;
02284 } else if ((*points)[i].x > 2 * pixmapW) {
02285 (*points)[i].x = 2 * pixmapW;
02286 }
02287 if ((*points)[i].y < -pixmapH) {
02288 (*points)[i].y = -pixmapH;
02289 } else if ((*points)[i].y > 2 * pixmapH) {
02290 (*points)[i].y = 2 * pixmapH;
02291 }
02292 }
02293
02294
02295 if (fillHack) {
02296 i = j = k = 0;
02297 while (i < n) {
02298
02299
02300 rect = rects[i];
02301 (*lengths)[j] = (*lengths)[i];
02302 k0 = k;
02303 (*points)[k + (*lengths)[i]] = (*points)[k0];
02304 k += (*lengths)[i] + 1;
02305 ++i;
02306
02307
02308 do {
02309
02310
02311 for (ii = i; ii < n; ++ii) {
02312 if (rects[ii].xMax > rects[i].xMin &&
02313 rects[ii].xMin < rects[i].xMax &&
02314 rects[ii].yMax > rects[i].yMin &&
02315 rects[ii].yMin < rects[i].yMax) {
02316 break;
02317 }
02318 }
02319
02320
02321 if (ii < n) {
02322 for (; i <= ii; ++i) {
02323 if (rects[i].xMin < rect.xMin)
02324 rect.xMin = rects[j].xMin;
02325 if (rects[i].xMax > rect.xMax)
02326 rect.xMax = rects[j].xMax;
02327 if (rects[i].yMin < rect.yMin)
02328 rect.yMin = rects[j].yMin;
02329 if (rects[i].yMax > rect.yMax)
02330 rect.yMax = rects[j].yMax;
02331 (*lengths)[j] += (*lengths)[i] + 1;
02332 (*points)[k + (*lengths)[i]] = (*points)[k0];
02333 k += (*lengths)[i] + 1;
02334 }
02335 }
02336 } while (ii < n && i < n);
02337
02338 ++j;
02339 }
02340
02341
02342 if (rects != tmpRects)
02343 gfree(rects);
02344
02345 n = j;
02346 }
02347
02348 return n;
02349 }
02350
02351
02352
02353
02354
02355 void XOutputDev::convertSubpath(GfxState *state, GfxSubpath *subpath,
02356 XPoint **points, int *size, int *n) {
02357 double x0, y0, x1, y1, x2, y2, x3, y3;
02358 int m, i;
02359
02360 m = subpath->getNumPoints();
02361 i = 0;
02362 while (i < m) {
02363 if (i >= 1 && subpath->getCurve(i)) {
02364 state->transform(subpath->getX(i-1), subpath->getY(i-1), &x0, &y0);
02365 state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1);
02366 state->transform(subpath->getX(i+1), subpath->getY(i+1), &x2, &y2);
02367 state->transform(subpath->getX(i+2), subpath->getY(i+2), &x3, &y3);
02368 doCurve(points, size, n, x0, y0, x1, y1, x2, y2, x3, y3);
02369 i += 3;
02370 } else {
02371 state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1);
02372 addPoint(points, size, n, xoutRound(x1), xoutRound(y1));
02373 ++i;
02374 }
02375 }
02376 }
02377
02378
02379
02380
02381
02382
02383 void XOutputDev::doCurve(XPoint **points, int *size, int *n,
02384 double x0, double y0, double x1, double y1,
02385 double x2, double y2, double x3, double y3) {
02386 double x[(1<<maxCurveSplits)+1][3];
02387 double y[(1<<maxCurveSplits)+1][3];
02388 int next[1<<maxCurveSplits];
02389 int p1, p2, p3;
02390 double xx1, yy1, xx2, yy2;
02391 double dx, dy, mx, my, d1, d2;
02392 double xl0, yl0, xl1, yl1, xl2, yl2;
02393 double xr0, yr0, xr1, yr1, xr2, yr2, xr3, yr3;
02394 double xh, yh;
02395 double flat;
02396
02397 flat = (double)(flatness * flatness);
02398 if (flat < 1)
02399 flat = 1;
02400
02401
02402 p1 = 0;
02403 p2 = 1<<maxCurveSplits;
02404 x[p1][0] = x0; y[p1][0] = y0;
02405 x[p1][1] = x1; y[p1][1] = y1;
02406 x[p1][2] = x2; y[p1][2] = y2;
02407 x[p2][0] = x3; y[p2][0] = y3;
02408 next[p1] = p2;
02409
02410 while (p1 < (1<<maxCurveSplits)) {
02411
02412
02413 xl0 = x[p1][0]; yl0 = y[p1][0];
02414 xx1 = x[p1][1]; yy1 = y[p1][1];
02415 xx2 = x[p1][2]; yy2 = y[p1][2];
02416 p2 = next[p1];
02417 xr3 = x[p2][0]; yr3 = y[p2][0];
02418
02419
02420
02421
02422 mx = (xl0 + xr3) * 0.5;
02423 my = (yl0 + yr3) * 0.5;
02424 dx = xx1 - mx;
02425 dy = yy1 - my;
02426 d1 = dx*dx + dy*dy;
02427 dx = xx2 - mx;
02428 dy = yy2 - my;
02429 d2 = dx*dx + dy*dy;
02430
02431
02432
02433 if (p2 - p1 <= 1 || (d1 <= flat && d2 <= flat)) {
02434 addPoint(points, size, n, xoutRound(xr3), xoutRound(yr3));
02435 p1 = p2;
02436
02437
02438 } else {
02439 xl1 = (xl0 + xx1) * 0.5;
02440 yl1 = (yl0 + yy1) * 0.5;
02441 xh = (xx1 + xx2) * 0.5;
02442 yh = (yy1 + yy2) * 0.5;
02443 xl2 = (xl1 + xh) * 0.5;
02444 yl2 = (yl1 + yh) * 0.5;
02445 xr2 = (xx2 + xr3) * 0.5;
02446 yr2 = (yy2 + yr3) * 0.5;
02447 xr1 = (xh + xr2) * 0.5;
02448 yr1 = (yh + yr2) * 0.5;
02449 xr0 = (xl2 + xr1) * 0.5;
02450 yr0 = (yl2 + yr1) * 0.5;
02451
02452
02453 p3 = (p1 + p2) / 2;
02454 x[p1][1] = xl1; y[p1][1] = yl1;
02455 x[p1][2] = xl2; y[p1][2] = yl2;
02456 next[p1] = p3;
02457 x[p3][0] = xr0; y[p3][0] = yr0;
02458 x[p3][1] = xr1; y[p3][1] = yr1;
02459 x[p3][2] = xr2; y[p3][2] = yr2;
02460 next[p3] = p2;
02461 }
02462 }
02463 }
02464
02465
02466
02467
02468
02469
02470 void XOutputDev::addPoint(XPoint **points, int *size, int *k, int x, int y) {
02471 if (*k >= *size) {
02472 *size += 32;
02473 if (*points == tmpPoints) {
02474 *points = (XPoint *)gmalloc(*size * sizeof(XPoint));
02475 memcpy(*points, tmpPoints, *k * sizeof(XPoint));
02476 } else {
02477 *points = (XPoint *)grealloc(*points, *size * sizeof(XPoint));
02478 }
02479 }
02480 (*points)[*k].x = x;
02481 (*points)[*k].y = y;
02482 ++(*k);
02483 }
02484
02485 void XOutputDev::beginString(GfxState *state, GString *s) {
02486 text->beginString(state, state->getCurX(), state->getCurY());
02487 }
02488
02489 void XOutputDev::endString(GfxState *state) {
02490 text->endString();
02491 }
02492
02493 void XOutputDev::drawChar(GfxState *state, double x, double y,
02494 double dx, double dy,
02495 double originX, double originY,
02496 CharCode code, Unicode *u, int uLen) {
02497 int render;
02498 double x1, y1, dx1, dy1;
02499 GfxRGB rgb;
02500 double saveCurX, saveCurY;
02501 double *ctm;
02502 double saveCTM[6];
02503
02504 text->addChar(state, x, y, dx, dy, u, uLen);
02505
02506 if (!font) {
02507 return;
02508 }
02509
02510
02511 render = state->getRender();
02512 if ((render & 3) == 3) {
02513 return;
02514 }
02515
02516 x -= originX;
02517 y -= originY;
02518 state->transform(x, y, &x1, &y1);
02519 state->transformDelta(dx, dy, &dx1, &dy1);
02520
02521
02522 if (!(render & 1)) {
02523 state->getFillRGB(&rgb);
02524 if (reverseVideo) {
02525 rgb.r = 1 - rgb.r;
02526 rgb.g = 1 - rgb.g;
02527 rgb.b = 1 - rgb.b;
02528 }
02529 font->drawChar(state, pixmap, pixmapW, pixmapH, fillGC, &rgb,
02530 x1, y1, dx1, dy1, code, u, uLen);
02531 }
02532
02533
02534 if ((render & 3) == 1 || (render & 3) == 2) {
02535 if (font->hasGetCharPath()) {
02536 saveCurX = state->getCurX();
02537 saveCurY = state->getCurY();
02538 ctm = state->getCTM();
02539 memcpy(saveCTM, ctm, 6 * sizeof(double));
02540 state->setCTM(1, 0, 0, 1, x1, y1);
02541 font->getCharPath(state, code, u, uLen);
02542 stroke(state);
02543 state->clearPath();
02544 state->setCTM(saveCTM[0], saveCTM[1], saveCTM[2], saveCTM[3],
02545 saveCTM[4], saveCTM[5]);
02546 state->moveTo(saveCurX, saveCurY);
02547 } else {
02548
02549
02550 state->getStrokeRGB(&rgb);
02551 if (reverseVideo) {
02552 rgb.r = 1 - rgb.r;
02553 rgb.g = 1 - rgb.g;
02554 rgb.b = 1 - rgb.b;
02555 }
02556 font->drawChar(state, pixmap, pixmapW, pixmapH, strokeGC, &rgb,
02557 x1, y1, dx1, dy1, code, u, uLen);
02558 }
02559 }
02560
02561 #if 0 //~ unimplemented: clipping to char path
02562
02563 if (render & 4) {
02564 }
02565 #endif
02566 }
02567
02568 GBool XOutputDev::beginType3Char(GfxState *state,
02569 CharCode code, Unicode *u, int uLen) {
02570 Ref *fontID;
02571 double *ctm, *bbox;
02572 GfxRGB color;
02573 T3FontCache *t3Font;
02574 T3GlyphStack *t3gs;
02575 double x1, y1, xMin, yMin, xMax, yMax, xt, yt;
02576 int i, j;
02577
02578 if (!gfxFont) {
02579 return gFalse;
02580 }
02581 fontID = gfxFont->getID();
02582 ctm = state->getCTM();
02583 state->transform(0, 0, &xt, &yt);
02584
02585
02586 if (!(nT3Fonts > 0 &&
02587 t3FontCache[0]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3]))) {
02588
02589
02590 for (i = 1; i < nT3Fonts; ++i) {
02591 if (t3FontCache[i]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3])) {
02592 t3Font = t3FontCache[i];
02593 for (j = i; j > 0; --j) {
02594 t3FontCache[j] = t3FontCache[j - 1];
02595 }
02596 t3FontCache[0] = t3Font;
02597 break;
02598 }
02599 }
02600 if (i >= nT3Fonts) {
02601
02602
02603 if (nT3Fonts == xOutT3FontCacheSize) {
02604 delete t3FontCache[nT3Fonts - 1];
02605 --nT3Fonts;
02606 }
02607 for (j = nT3Fonts; j > 0; --j) {
02608 t3FontCache[j] = t3FontCache[j - 1];
02609 }
02610 ++nT3Fonts;
02611 bbox = gfxFont->getFontBBox();
02612 if (bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0) {
02613
02614 xMin = xt - 5;
02615 xMax = xMin + 30;
02616 yMax = yt + 15;
02617 yMin = yMax - 45;
02618 } else {
02619 state->transform(bbox[0], bbox[1], &x1, &y1);
02620 xMin = xMax = x1;
02621 yMin = yMax = y1;
02622 state->transform(bbox[0], bbox[3], &x1, &y1);
02623 if (x1 < xMin) {
02624 xMin = x1;
02625 } else if (x1 > xMax) {
02626 xMax = x1;
02627 }
02628 if (y1 < yMin) {
02629 yMin = y1;
02630 } else if (y1 > yMax) {
02631 yMax = y1;
02632 }
02633 state->transform(bbox[2], bbox[1], &x1, &y1);
02634 if (x1 < xMin) {
02635 xMin = x1;
02636 } else if (x1 > xMax) {
02637 xMax = x1;
02638 }
02639 if (y1 < yMin) {
02640 yMin = y1;
02641 } else if (y1 > yMax) {
02642 yMax = y1;
02643 }
02644 state->transform(bbox[2], bbox[3], &x1, &y1);
02645 if (x1 < xMin) {
02646 xMin = x1;
02647 } else if (x1 > xMax) {
02648 xMax = x1;
02649 }
02650 if (y1 < yMin) {
02651 yMin = y1;
02652 } else if (y1 > yMax) {
02653 yMax = y1;
02654 }
02655 }
02656 t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3],
02657 (int)floor(xMin - xt),
02658 (int)floor(yMin - yt),
02659 (int)ceil(xMax) - (int)floor(xMin) + 3,
02660 (int)ceil(yMax) - (int)floor(yMin) + 3,
02661 display, visual, depth, pixmap);
02662 }
02663 }
02664 t3Font = t3FontCache[0];
02665
02666
02667 i = (code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc;
02668 for (j = 0; j < t3Font->cacheAssoc; ++j) {
02669 if ((t3Font->cacheTags[i+j].mru & 0x8000) &&
02670 t3Font->cacheTags[i+j].code == code) {
02671 state->getFillRGB(&color);
02672 if (reverseVideo) {
02673 color.r = 1 - color.r;
02674 color.g = 1 - color.g;
02675 color.b = 1 - color.b;
02676 }
02677 text->addChar(state, 0, 0,
02678 t3Font->cacheTags[i+j].wx, t3Font->cacheTags[i+j].wy,
02679 u, uLen);
02680 drawType3Glyph(t3Font, &t3Font->cacheTags[i+j],
02681 t3Font->cacheData + (i+j) * t3Font->glyphSize,
02682 xt, yt, &color);
02683 return gTrue;
02684 }
02685 }
02686
02687
02688 t3gs = new T3GlyphStack();
02689 t3gs->next = t3GlyphStack;
02690 t3GlyphStack = t3gs;
02691 t3GlyphStack->cacheable = gFalse;
02692 t3GlyphStack->code = code;
02693 t3GlyphStack->cache = t3Font;
02694 t3GlyphStack->cacheIdx = i;
02695 t3GlyphStack->x = xt;
02696 t3GlyphStack->y = yt;
02697 t3GlyphStack->u = u;
02698 t3GlyphStack->uLen = uLen;
02699
02700 return gFalse;
02701 }
02702
02703 void XOutputDev::endType3Char(GfxState *state) {
02704 XImage *image;
02705 Guchar *p;
02706 int x, y;
02707 Gulong pixel;
02708 double alpha;
02709 T3GlyphStack *t3gs;
02710 double *ctm;
02711
02712 if (t3GlyphStack->cacheable) {
02713 image = t3GlyphStack->cache->image;
02714 XGetSubImage(display, pixmap, 0, 0,
02715 t3GlyphStack->cache->glyphW, t3GlyphStack->cache->glyphH,
02716 (1 << depth) - 1, ZPixmap, image, 0, 0);
02717 p = t3GlyphStack->cacheData;
02718 for (y = 0; y < t3GlyphStack->cache->glyphH; ++y) {
02719 for (x = 0; x < t3GlyphStack->cache->glyphW; ++x) {
02720 pixel = XGetPixel(image, x, y);
02721 if (trueColor) {
02722 alpha = (double)((pixel >> rShift) & rMul) / (double)rMul;
02723 } else {
02724 alpha = redMap[pixel & 0xff];
02725 }
02726 if (alpha <= 0.2) {
02727 *p++ = 4;
02728 } else if (alpha <= 0.4) {
02729 *p++ = 3;
02730 } else if (alpha <= 0.6) {
02731 *p++ = 2;
02732 } else if (alpha <= 0.8) {
02733 *p++ = 1;
02734 } else {
02735 *p++ = 0;
02736 }
02737 }
02738 }
02739 XDestroyRegion(clipRegion);
02740 XFreeGC(display, strokeGC);
02741 XFreeGC(display, fillGC);
02742 pixmapW = t3GlyphStack->origPixmapW;
02743 pixmapH = t3GlyphStack->origPixmapH;
02744 pixmap = t3GlyphStack->origPixmap;
02745 strokeGC = t3GlyphStack->origStrokeGC;
02746 fillGC = t3GlyphStack->origFillGC;
02747 clipRegion = t3GlyphStack->origClipRegion;
02748 drawType3Glyph(t3GlyphStack->cache,
02749 t3GlyphStack->cacheTag, t3GlyphStack->cacheData,
02750 t3GlyphStack->x, t3GlyphStack->y, &t3GlyphStack->color);
02751
02752
02753 ctm = state->getCTM();
02754 state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
02755 t3GlyphStack->origCTM4, t3GlyphStack->origCTM5);
02756 }
02757 text->addChar(state, 0, 0, t3GlyphStack->wx, t3GlyphStack->wy,
02758 t3GlyphStack->u, t3GlyphStack->uLen);
02759 t3gs = t3GlyphStack;
02760 t3GlyphStack = t3gs->next;
02761 delete t3gs;
02762 }
02763
02764 void XOutputDev::drawType3Glyph(T3FontCache *t3Font,
02765 T3FontCacheTag *tag, Guchar *data,
02766 double x, double y, GfxRGB *color) {
02767 XImage *image;
02768 XColor xcolor;
02769 GfxRGB bg, rgb;
02770 Gulong map[5];
02771 Gulong pixel;
02772 Guchar *p;
02773 int x0, y0, w0, h0, x1, y1;
02774 int ix, iy;
02775
02776
02777
02778
02779 x0 = xoutRound(x + t3Font->glyphX);
02780 y0 = xoutRound(y + t3Font->glyphY);
02781 x1 = 0;
02782 y1 = 0;
02783 w0 = t3Font->glyphW;
02784 h0 = t3Font->glyphH;
02785 if (x0 < 0) {
02786 x1 = -x0;
02787 w0 += x0;
02788 x0 = 0;
02789 }
02790 if (x0 + w0 > pixmapW) {
02791 w0 = pixmapW - x0;
02792 }
02793 if (w0 <= 0) {
02794 return;
02795 }
02796 if (y0 < 0) {
02797 y1 = -y0;
02798 h0 += y0;
02799 y0 = 0;
02800 }
02801 if (y0 + h0 > pixmapH) {
02802 h0 = pixmapH - y0;
02803 }
02804 if (h0 <= 0) {
02805 return;
02806 }
02807
02808 image = t3Font->image;
02809 XGetSubImage(display, pixmap, x0, y0, w0, h0,
02810 (1 << depth) - 1, ZPixmap, image, x1, y1);
02811 xcolor.pixel = XGetPixel(image, t3Font->glyphW / 2, t3Font->glyphH / 2);
02812 XQueryColor(display, colormap, &xcolor);
02813 bg.r = xcolor.red / 65535.0;
02814 bg.g = xcolor.green / 65535.0;
02815 bg.b = xcolor.blue / 65535.0;
02816 rgb.r = 0.25 * (color->r + 3 * bg.r);
02817 rgb.g = 0.25 * (color->g + 3 * bg.g);
02818 rgb.b = 0.25 * (color->b + 3 * bg.b);
02819 map[1] = findColor(&rgb);
02820 rgb.r = 0.5 * (color->r + bg.r);
02821 rgb.g = 0.5 * (color->g + bg.g);
02822 rgb.b = 0.5 * (color->b + bg.b);
02823 map[2] = findColor(&rgb);
02824 rgb.r = 0.25 * (3 * color->r + bg.r);
02825 rgb.g = 0.25 * (3 * color->g + bg.g);
02826 rgb.b = 0.25 * (3 * color->b + bg.b);
02827 map[3] = findColor(&rgb);
02828 map[4] = findColor(color);
02829 p = data;
02830 for (iy = 0; iy < t3Font->glyphH; ++iy) {
02831 for (ix = 0; ix < t3Font->glyphW; ++ix) {
02832 pixel = *p++;
02833 if (pixel > 0) {
02834 XPutPixel(image, ix, iy, map[pixel]);
02835 }
02836 }
02837 }
02838 XPutImage(display, pixmap, fillGC, image, x1, y1, x0, y0, w0, h0);
02839 }
02840
02841 void XOutputDev::type3D0(GfxState *state, double wx, double wy) {
02842 t3GlyphStack->wx = wx;
02843 t3GlyphStack->wy = wy;
02844 }
02845
02846 void XOutputDev::type3D1(GfxState *state, double wx, double wy,
02847 double llx, double lly, double urx, double ury) {
02848 GfxColor fgColor;
02849 XGCValues gcValues;
02850 XRectangle rect;
02851 double *ctm;
02852 T3FontCache *t3Font;
02853 int i, j;
02854
02855
02856 t3GlyphStack->cacheable = gTrue;
02857 t3Font = t3GlyphStack->cache;
02858 i = t3GlyphStack->cacheIdx;
02859 for (j = 0; j < t3Font->cacheAssoc; ++j) {
02860 if ((t3Font->cacheTags[i+j].mru & 0x7fff) == t3Font->cacheAssoc - 1) {
02861 t3Font->cacheTags[i+j].mru = 0x8000;
02862 t3Font->cacheTags[i+j].code = t3GlyphStack->code;
02863 t3GlyphStack->cacheTag = &t3Font->cacheTags[i+j];
02864 t3GlyphStack->cacheData = t3Font->cacheData + (i+j) * t3Font->glyphSize;
02865 } else {
02866 ++t3Font->cacheTags[i+j].mru;
02867 }
02868 }
02869 t3GlyphStack->wx = wx;
02870 t3GlyphStack->wy = wy;
02871 t3GlyphStack->cacheTag->wx = wx;
02872 t3GlyphStack->cacheTag->wy = wy;
02873
02874
02875
02876 state->getFillRGB(&t3GlyphStack->color);
02877 if (reverseVideo) {
02878 t3GlyphStack->color.r = 1 - t3GlyphStack->color.r;
02879 t3GlyphStack->color.g = 1 - t3GlyphStack->color.g;
02880 t3GlyphStack->color.b = 1 - t3GlyphStack->color.b;
02881 }
02882 fgColor.c[0] = reverseVideo ? 1 : 0;
02883 state->setFillColorSpace(new GfxDeviceGrayColorSpace());
02884 state->setFillColor(&fgColor);
02885 state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
02886 state->setStrokeColor(&fgColor);
02887 t3GlyphStack->origPixmapW = pixmapW;
02888 t3GlyphStack->origPixmapH = pixmapH;
02889 t3GlyphStack->origPixmap = pixmap;
02890 t3GlyphStack->origStrokeGC = strokeGC;
02891 t3GlyphStack->origFillGC = fillGC;
02892 t3GlyphStack->origClipRegion = clipRegion;
02893 pixmapW = t3GlyphStack->cache->glyphW;
02894 pixmapH = t3GlyphStack->cache->glyphH;
02895 pixmap = t3GlyphStack->cache->pixmap;
02896 gcValues.foreground = BlackPixel(display, screenNum);
02897 gcValues.background = WhitePixel(display, screenNum);
02898 gcValues.line_width = 0;
02899 gcValues.line_style = LineSolid;
02900 strokeGC = XCreateGC(display, pixmap,
02901 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
02902 &gcValues);
02903 updateLineAttrs(state, gTrue);
02904 gcValues.foreground = WhitePixel(display, screenNum);
02905 fillGC = XCreateGC(display, pixmap,
02906 GCForeground | GCBackground | GCLineWidth | GCLineStyle,
02907 &gcValues);
02908 XFillRectangle(display, pixmap, fillGC, 0, 0, pixmapW, pixmapH);
02909 XSetForeground(display, fillGC, BlackPixel(display, screenNum));
02910 clipRegion = XCreateRegion();
02911 rect.x = rect.y = 0;
02912 rect.width = pixmapW;
02913 rect.height = pixmapH;
02914 XUnionRectWithRegion(&rect, clipRegion, clipRegion);
02915 XSetRegion(display, strokeGC, clipRegion);
02916 XSetRegion(display, fillGC, clipRegion);
02917 ctm = state->getCTM();
02918 t3GlyphStack->origCTM4 = ctm[4];
02919 t3GlyphStack->origCTM5 = ctm[5];
02920 state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3],
02921 -t3GlyphStack->cache->glyphX, -t3GlyphStack->cache->glyphY);
02922 }
02923
02924 inline Gulong XOutputDev::findColor(GfxRGB *x, GfxRGB *err) {
02925 double gray;
02926 int r, g, b;
02927 Gulong pixel;
02928
02929 if (trueColor) {
02930 r = xoutRound(x->r * rMul);
02931 g = xoutRound(x->g * gMul);
02932 b = xoutRound(x->b * bMul);
02933 pixel = ((Gulong)r << rShift) +
02934 ((Gulong)g << gShift) +
02935 ((Gulong)b << bShift);
02936 err->r = x->r - (double)r / rMul;
02937 err->g = x->g - (double)g / gMul;
02938 err->b = x->b - (double)b / bMul;
02939 } else if (numColors == 1) {
02940 gray = 0.299 * x->r + 0.587 * x->g + 0.114 * x->b;
02941 if (gray < 0.5) {
02942 pixel = colors[0];
02943 err->r = x->r;
02944 err->g = x->g;
02945 err->b = x->b;
02946 } else {
02947 pixel = colors[1];
02948 err->r = x->r - 1;
02949 err->g = x->g - 1;
02950 err->b = x->b - 1;
02951 }
02952 } else {
02953 r = xoutRound(x->r * (numColors - 1));
02954 g = xoutRound(x->g * (numColors - 1));
02955 b = xoutRound(x->b * (numColors - 1));
02956 pixel = colors[(r * numColors + g) * numColors + b];
02957 err->r = x->r - (double)r / (numColors - 1);
02958 err->g = x->g - (double)g / (numColors - 1);
02959 err->b = x->b - (double)b / (numColors - 1);
02960 }
02961 return pixel;
02962 }
02963
02964 Gulong XOutputDev::findColor(GfxRGB *rgb) {
02965 int r, g, b;
02966 double gray;
02967 Gulong pixel;
02968
02969 if (trueColor) {
02970 r = xoutRound(rgb->r * rMul);
02971 g = xoutRound(rgb->g * gMul);
02972 b = xoutRound(rgb->b * bMul);
02973 pixel = ((Gulong)r << rShift) +
02974 ((Gulong)g << gShift) +
02975 ((Gulong)b << bShift);
02976 } else if (numColors == 1) {
02977 gray = 0.299 * rgb->r + 0.587 * rgb->g + 0.114 * rgb->b;
02978 if (gray < 0.5)
02979 pixel = colors[0];
02980 else
02981 pixel = colors[1];
02982 } else {
02983 r = xoutRound(rgb->r * (numColors - 1));
02984 g = xoutRound(rgb->g * (numColors - 1));
02985 b = xoutRound(rgb->b * (numColors - 1));
02986 #if 0 // this makes things worse as often as better
02987
02988 if (r == numColors - 1 && g == numColors - 1 && b == numColors - 1) {
02989 if (color->getR() < 0.95)
02990 --r;
02991 if (color->getG() < 0.95)
02992 --g;
02993 if (color->getB() < 0.95)
02994 --b;
02995 }
02996 #endif
02997 pixel = colors[(r * numColors + g) * numColors + b];
02998 }
02999 return pixel;
03000 }
03001
03002 void XOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
03003 int width, int height, GBool invert,
03004 GBool inlineImg) {
03005 ImageStream *imgStr;
03006 XImage *image;
03007 double *ctm;
03008 GBool rot;
03009 double xScale, yScale, xShear, yShear;
03010 int tx, ty, scaledWidth, scaledHeight, xSign, ySign;
03011 int ulx, uly, llx, lly, urx, ury, lrx, lry;
03012 int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
03013 int bx0, by0, bx1, by1, bw, bh;
03014 int cx0, cy0, cx1, cy1, cw, ch;
03015 int yp, yq, yt, yStep, lastYStep;
03016 int xp, xq, xt, xStep, xSrc;
03017 GfxRGB rgb;
03018 Guchar *pixBuf;
03019 int imgPix;
03020 double alpha;
03021 XColor xcolor;
03022 Gulong lastPixel;
03023 GfxRGB rgb2;
03024 double r0, g0, b0, r1, g1, b1;
03025 Gulong pix;
03026 Guchar *p;
03027 int x, y, x1, y1, x2, y2;
03028 int n, m, i, j;
03029
03030
03031 ctm = state->getCTM();
03032 if (fabs(ctm[0] * ctm[3] - ctm[1] * ctm[2]) < 0.000001) {
03033 error(-1, "Singular CTM in drawImage");
03034 if (inlineImg) {
03035 j = height * ((width + 7) / 8);
03036 str->reset();
03037 for (i = 0; i < j; ++i) {
03038 str->getChar();
03039 }
03040 str->close();
03041 }
03042 return;
03043 }
03044
03045
03046 rot = fabs(ctm[1]) > fabs(ctm[0]);
03047 if (rot) {
03048 xScale = -ctm[1];
03049 yScale = -ctm[2] + (ctm[0] * ctm[3]) / ctm[1];
03050 xShear = ctm[3] / yScale;
03051 yShear = -ctm[0] / ctm[1];
03052 } else {
03053 xScale = ctm[0];
03054 yScale = -ctm[3] + (ctm[1] * ctm[2]) / ctm[0];
03055 xShear = -ctm[2] / yScale;
03056 yShear = ctm[1] / ctm[0];
03057 }
03058 tx = xoutRound(ctm[2] + ctm[4]);
03059 ty = xoutRound(ctm[3] + ctm[5]);
03060
03061 scaledWidth = (int)ceil(fabs(xScale));
03062 xSign = (xScale < 0) ? -1 : 1;
03063 scaledHeight = (int)ceil(fabs(yScale));
03064 ySign = (yScale < 0) ? -1 : 1;
03065
03066
03067 ulx1 = 0;
03068 uly1 = 0;
03069 urx1 = xSign * (scaledWidth - 1);
03070 ury1 = xoutRound(yShear * urx1);
03071 llx1 = xoutRound(xShear * ySign * (scaledHeight - 1));
03072 lly1 = ySign * (scaledHeight - 1) + xoutRound(yShear * llx1);
03073 lrx1 = xSign * (scaledWidth - 1) +
03074 xoutRound(xShear * ySign * (scaledHeight - 1));
03075 lry1 = ySign * (scaledHeight - 1) + xoutRound(yShear * lrx1);
03076 if (rot) {
03077 ulx = tx + uly1; uly = ty - ulx1;
03078 urx = tx + ury1; ury = ty - urx1;
03079 llx = tx + lly1; lly = ty - llx1;
03080 lrx = tx + lry1; lry = ty - lrx1;
03081 } else {
03082 ulx = tx + ulx1; uly = ty + uly1;
03083 urx = tx + urx1; ury = ty + ury1;
03084 llx = tx + llx1; lly = ty + lly1;
03085 lrx = tx + lrx1; lry = ty + lry1;
03086 }
03087
03088
03089
03090
03091
03092 bx0 = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
03093 : (llx < lrx) ? llx : lrx
03094 : (urx < llx) ? (urx < lrx) ? urx : lrx
03095 : (llx < lrx) ? llx : lrx;
03096 bx1 = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
03097 : (llx > lrx) ? llx : lrx
03098 : (urx > llx) ? (urx > lrx) ? urx : lrx
03099 : (llx > lrx) ? llx : lrx;
03100 by0 = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
03101 : (lly < lry) ? lly : lry
03102 : (ury < lly) ? (ury < lry) ? ury : lry
03103 : (lly < lry) ? lly : lry;
03104 by1 = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
03105 : (lly > lry) ? lly : lry
03106 : (ury > lly) ? (ury > lry) ? ury : lry
03107 : (lly > lry) ? lly : lry;
03108 bw = bx1 - bx0 + 1;
03109 bh = by1 - by0 + 1;
03110
03111
03112
03113
03114
03115
03116
03117 cw = (bx1 >= pixmapW) ? pixmapW - bx0 : bw;
03118 if (bx0 < 0) {
03119 cx0 = 0;
03120 cx1 = -bx0;
03121 cw += bx0;
03122 } else {
03123 cx0 = bx0;
03124 cx1 = 0;
03125 }
03126 ch = (by1 >= pixmapH) ? pixmapH - by0 : bh;
03127 if (by0 < 0) {
03128 cy0 = 0;
03129 cy1 = -by0;
03130 ch += by0;
03131 } else {
03132 cy0 = by0;
03133 cy1 = 0;
03134 }
03135
03136
03137
03138 if (scaledWidth <= 0 || scaledHeight <= 0 || cw <= 0 || ch <= 0) {
03139 if (inlineImg) {
03140 j = height * ((width + 7) / 8);
03141 str->reset();
03142 for (i = 0; i < j; ++i) {
03143 str->getChar();
03144 }
03145 str->close();
03146 }
03147 return;
03148 }
03149
03150
03151 yp = height / scaledHeight;
03152 yq = height % scaledHeight;
03153 xp = width / scaledWidth;
03154 xq = width % scaledWidth;
03155
03156
03157 pixBuf = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar));
03158
03159
03160 image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, bw, bh, 8, 0);
03161 image->data = (char *)gmalloc(bh * image->bytes_per_line);
03162 XGetSubImage(display, pixmap, cx0, cy0, cw, ch, (1 << depth) - 1, ZPixmap,
03163 image, cx1, cy1);
03164
03165
03166 state->getFillRGB(&rgb);
03167 if (reverseVideo) {
03168 rgb.r = 1 - rgb.r;
03169 rgb.g = 1 - rgb.g;
03170 rgb.b = 1 - rgb.b;
03171 }
03172 r0 = rgb.r;
03173 g0 = rgb.g;
03174 b0 = rgb.b;
03175
03176
03177
03178
03179 xcolor.pixel = lastPixel = 0;
03180 XQueryColor(display, colormap, &xcolor);
03181 r1 = (double)xcolor.red / 65535.0;
03182 g1 = (double)xcolor.green / 65535.0;
03183 b1 = (double)xcolor.blue / 65535.0;
03184
03185
03186 imgStr = new ImageStream(str, width, 1, 1);
03187 imgStr->reset();
03188
03189
03190 yt = 0;
03191 lastYStep = 1;
03192
03193 for (y = 0; y < scaledHeight; ++y) {
03194
03195
03196 yStep = yp;
03197 yt += yq;
03198 if (yt >= scaledHeight) {
03199 yt -= scaledHeight;
03200 ++yStep;
03201 }
03202
03203
03204 n = (yp > 0) ? yStep : lastYStep;
03205 if (n > 0) {
03206 p = pixBuf;
03207 for (i = 0; i < n; ++i) {
03208 memcpy(p, imgStr->getLine(), width);
03209 if (invert) {
03210 for (j = 0; j < width; ++j) {
03211 p[j] ^= 1;
03212 }
03213 }
03214 p += width;
03215 }
03216 }
03217 lastYStep = yStep;
03218
03219
03220 xt = 0;
03221 xSrc = 0;
03222
03223 for (x = 0; x < scaledWidth; ++x) {
03224
03225
03226 xStep = xp;
03227 xt += xq;
03228 if (xt >= scaledWidth) {
03229 xt -= scaledWidth;
03230 ++xStep;
03231 }
03232
03233
03234 x1 = xSign * x + xoutRound(xShear * ySign * y);
03235
03236
03237 y1 = ySign * y + xoutRound(yShear * x1);
03238
03239
03240 if (rot) {
03241 x2 = y1;
03242 y2 = -x1;
03243 } else {
03244 x2 = x1;
03245 y2 = y1;
03246 }
03247
03248
03249
03250 n = yStep > 0 ? yStep : 1;
03251 m = xStep > 0 ? xStep : 1;
03252 p = pixBuf + xSrc;
03253 imgPix = 0;
03254 for (i = 0; i < n; ++i) {
03255 for (j = 0; j < m; ++j) {
03256 imgPix += *p++;
03257 }
03258 p += width - m;
03259 }
03260
03261
03262 xSrc += xStep;
03263
03264
03265 alpha = (double)imgPix / (double)(n * m);
03266 xcolor.pixel = XGetPixel(image, tx + x2 - bx0, ty + y2 - by0);
03267 if (xcolor.pixel != lastPixel) {
03268 XQueryColor(display, colormap, &xcolor);
03269 r1 = (double)xcolor.red / 65535.0;
03270 g1 = (double)xcolor.green / 65535.0;
03271 b1 = (double)xcolor.blue / 65535.0;
03272 lastPixel = xcolor.pixel;
03273 }
03274 rgb2.r = r0 * (1 - alpha) + r1 * alpha;
03275 rgb2.g = g0 * (1 - alpha) + g1 * alpha;
03276 rgb2.b = b0 * (1 - alpha) + b1 * alpha;
03277 pix = findColor(&rgb2);
03278
03279
03280 XPutPixel(image, tx + x2 - bx0, ty + y2 - by0, pix);
03281 }
03282 }
03283
03284
03285 XPutImage(display, pixmap, fillGC, image, cx1, cy1, cx0, cy0, cw, ch);
03286
03287
03288 delete imgStr;
03289 gfree(pixBuf);
03290 gfree(image->data);
03291 image->data = NULL;
03292 XDestroyImage(image);
03293 }
03294
03295 void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
03296 int width, int height, GfxImageColorMap *colorMap,
03297 int *maskColors, GBool inlineImg) {
03298 ImageStream *imgStr;
03299 XImage *image;
03300 int nComps, nVals, nBits;
03301 GBool dither;
03302 double *ctm;
03303 GBool rot;
03304 double xScale, yScale, xShear, yShear;
03305 int tx, ty, scaledWidth, scaledHeight, xSign, ySign;
03306 int ulx, uly, llx, lly, urx, ury, lrx, lry;
03307 int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1;
03308 int bx0, by0, bx1, by1, bw, bh;
03309 int cx0, cy0, cx1, cy1, cw, ch;
03310 int yp, yq, yt, yStep, lastYStep;
03311 int xp, xq, xt, xStep, xSrc;
03312 GfxRGB *pixBuf;
03313 Guchar *alphaBuf;
03314 Guchar pixBuf2[gfxColorMaxComps];
03315 GfxRGB color2, err, errRight;
03316 GfxRGB *errDown;
03317 double r0, g0, b0, alpha, mul;
03318 Gulong pix;
03319 GfxRGB *p;
03320 Guchar *q, *p2;
03321 GBool oneBitMode;
03322 GfxRGB oneBitRGB[2];
03323 int x, y, x1, y1, x2, y2;
03324 int n, m, i, j, k;
03325
03326
03327 nComps = colorMap->getNumPixelComps();
03328 nVals = width * nComps;
03329 nBits = colorMap->getBits();
03330 dither = nComps > 1 || nBits > 1;
03331
03332
03333 ctm = state->getCTM();
03334 if (fabs(ctm[0] * ctm[3] - ctm[1] * ctm[2]) < 0.000001) {
03335 error(-1, "Singular CTM in drawImage");
03336 if (inlineImg) {
03337 str->reset();
03338 j = height * ((nVals * nBits + 7) / 8);
03339 for (i = 0; i < j; ++i) {
03340 str->getChar();
03341 }
03342 str->close();
03343 }
03344 return;
03345 }
03346
03347
03348 rot = fabs(ctm[1]) > fabs(ctm[0]);
03349 if (rot) {
03350 xScale = -ctm[1];
03351 yScale = -ctm[2] + (ctm[0] * ctm[3]) / ctm[1];
03352 xShear = ctm[3] / yScale;
03353 yShear = -ctm[0] / ctm[1];
03354 } else {
03355 xScale = ctm[0];
03356 yScale = -ctm[3] + (ctm[1] * ctm[2]) / ctm[0];
03357 xShear = -ctm[2] / yScale;
03358 yShear = ctm[1] / ctm[0];
03359 }
03360 tx = xoutRound(ctm[2] + ctm[4]);
03361 ty = xoutRound(ctm[3] + ctm[5]);
03362 if (xScale < 0) {
03363
03364 --tx;
03365 }
03366 if (yScale < 0) {
03367
03368 --ty;
03369 }
03370
03371 scaledWidth = (int)ceil(fabs(xScale));
03372 xSign = (xScale < 0) ? -1 : 1;
03373 scaledHeight = (int)ceil(fabs(yScale));
03374 ySign = (yScale < 0) ? -1 : 1;
03375
03376
03377 ulx1 = 0;
03378 uly1 = 0;
03379 urx1 = xSign * (scaledWidth - 1);
03380 ury1 = xoutRound(yShear * urx1);
03381 llx1 = xoutRound(xShear * ySign * (scaledHeight - 1));
03382 lly1 = ySign * (scaledHeight - 1) + xoutRound(yShear * llx1);
03383 lrx1 = xSign * (scaledWidth - 1) +
03384 xoutRound(xShear * ySign * (scaledHeight - 1));
03385 lry1 = ySign * (scaledHeight - 1) + xoutRound(yShear * lrx1);
03386 if (rot) {
03387 ulx = tx + uly1; uly = ty - ulx1;
03388 urx = tx + ury1; ury = ty - urx1;
03389 llx = tx + lly1; lly = ty - llx1;
03390 lrx = tx + lry1; lry = ty - lrx1;
03391 } else {
03392 ulx = tx + ulx1; uly = ty + uly1;
03393 urx = tx + urx1; ury = ty + ury1;
03394 llx = tx + llx1; lly = ty + lly1;
03395 lrx = tx + lrx1; lry = ty + lry1;
03396 }
03397
03398
03399
03400
03401
03402 bx0 = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx
03403 : (llx < lrx) ? llx : lrx
03404 : (urx < llx) ? (urx < lrx) ? urx : lrx
03405 : (llx < lrx) ? llx : lrx;
03406 bx1 = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx
03407 : (llx > lrx) ? llx : lrx
03408 : (urx > llx) ? (urx > lrx) ? urx : lrx
03409 : (llx > lrx) ? llx : lrx;
03410 by0 = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry
03411 : (lly < lry) ? lly : lry
03412 : (ury < lly) ? (ury < lry) ? ury : lry
03413 : (lly < lry) ? lly : lry;
03414 by1 = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry
03415 : (lly > lry) ? lly : lry
03416 : (ury > lly) ? (ury > lry) ? ury : lry
03417 : (lly > lry) ? lly : lry;
03418 bw = bx1 - bx0 + 1;
03419 bh = by1 - by0 + 1;
03420
03421
03422
03423
03424
03425
03426
03427 cw = (bx1 >= pixmapW) ? pixmapW - bx0 : bw;
03428 if (bx0 < 0) {
03429 cx0 = 0;
03430 cx1 = -bx0;
03431 cw += bx0;
03432 } else {
03433 cx0 = bx0;
03434 cx1 = 0;
03435 }
03436 ch = (by1 >= pixmapH) ? pixmapH - by0 : bh;
03437 if (by0 < 0) {
03438 cy0 = 0;
03439 cy1 = -by0;
03440 ch += by0;
03441 } else {
03442 cy0 = by0;
03443 cy1 = 0;
03444 }
03445
03446
03447
03448 if (scaledWidth <= 0 || scaledHeight <= 0 || cw <= 0 || ch <= 0) {
03449 if (inlineImg) {
03450 str->reset();
03451 j = height * ((nVals * nBits + 7) / 8);
03452 for (i = 0; i < j; ++i)
03453 str->getChar();
03454 str->close();
03455 }
03456 return;
03457 }
03458
03459
03460 yp = height / scaledHeight;
03461 yq = height % scaledHeight;
03462 xp = width / scaledWidth;
03463 xq = width % scaledWidth;
03464
03465
03466 pixBuf = (GfxRGB *)gmalloc((yp + 1) * width * sizeof(GfxRGB));
03467 if (maskColors) {
03468 alphaBuf = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar));
03469 } else {
03470 alphaBuf = NULL;
03471 }
03472
03473
03474 image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, bw, bh, 8, 0);
03475 image->data = (char *)gmalloc(bh * image->bytes_per_line);
03476
03477
03478
03479
03480 if (!((ulx == llx && uly == ury) ||
03481 (uly == lly && ulx == urx)) ||
03482 maskColors) {
03483 XGetSubImage(display, pixmap, cx0, cy0, cw, ch, (1 << depth) - 1, ZPixmap,
03484 image, cx1, cy1);
03485 }
03486
03487
03488 if (dither) {
03489 errDown = (GfxRGB *)gmalloc(bw * sizeof(GfxRGB));
03490 for (j = 0; j < bw; ++j) {
03491 errDown[j].r = errDown[j].g = errDown[j].b = 0;
03492 }
03493 } else {
03494 errDown = NULL;
03495 }
03496
03497
03498 if ((oneBitMode = nComps == 1 && nBits == 1)) {
03499 pixBuf2[0] = 0;
03500 colorMap->getRGB(pixBuf2, &oneBitRGB[0]);
03501 pixBuf2[0] = 1;
03502 colorMap->getRGB(pixBuf2, &oneBitRGB[1]);
03503 }
03504
03505
03506 imgStr = new ImageStream(str, width, nComps, nBits);
03507 imgStr->reset();
03508
03509
03510 yt = 0;
03511 lastYStep = 1;
03512
03513 for (y = 0; y < scaledHeight; ++y) {
03514
03515
03516 errRight.r = errRight.g = errRight.b = 0;
03517
03518
03519 yStep = yp;
03520 yt += yq;
03521 if (yt >= scaledHeight) {
03522 yt -= scaledHeight;
03523 ++yStep;
03524 }
03525
03526
03527 n = (yp > 0) ? yStep : lastYStep;
03528 if (n > 0) {
03529 p = pixBuf;
03530 q = alphaBuf;
03531 for (i = 0; i < n; ++i) {
03532 p2 = imgStr->getLine();
03533 for (j = 0; j < width; ++j) {
03534 if (oneBitMode) {
03535 *p = oneBitRGB[*p2];
03536 } else {
03537 colorMap->getRGB(p2, p);
03538 }
03539 ++p;
03540 if (q) {
03541 *q = 1;
03542 for (k = 0; k < nComps; ++k) {
03543 if (p2[k] < maskColors[2*k] ||
03544 p2[k] > maskColors[2*k]) {
03545 *q = 0;
03546 break;
03547 }
03548 }
03549 ++q;
03550 }
03551 p2 += nComps;
03552 }
03553 }
03554 }
03555 lastYStep = yStep;
03556
03557
03558 xt = 0;
03559 xSrc = 0;
03560
03561 for (x = 0; x < scaledWidth; ++x) {
03562
03563
03564 xStep = xp;
03565 xt += xq;
03566 if (xt >= scaledWidth) {
03567 xt -= scaledWidth;
03568 ++xStep;
03569 }
03570
03571
03572 x1 = xSign * x + xoutRound(xShear * ySign * y);
03573
03574
03575 y1 = ySign * y + xoutRound(yShear * x1);
03576
03577
03578 if (rot) {
03579 x2 = y1;
03580 y2 = -x1;
03581 } else {
03582 x2 = x1;
03583 y2 = y1;
03584 }
03585
03586
03587
03588 n = yStep > 0 ? yStep : 1;
03589 m = xStep > 0 ? xStep : 1;
03590 p = pixBuf + xSrc;
03591 r0 = g0 = b0 = 0;
03592 q = alphaBuf ? alphaBuf + xSrc : (Guchar *)NULL;
03593 alpha = 0;
03594 for (i = 0; i < n; ++i) {
03595 for (j = 0; j < m; ++j) {
03596 r0 += p->r;
03597 g0 += p->g;
03598 b0 += p->b;
03599 ++p;
03600 if (q) {
03601 alpha += *q++;
03602 }
03603 }
03604 p += width - m;
03605 }
03606 mul = 1 / (double)(n * m);
03607 r0 *= mul;
03608 g0 *= mul;
03609 b0 *= mul;
03610 alpha *= mul;
03611
03612
03613 xSrc += xStep;
03614
03615
03616 if (dither) {
03617 color2.r = r0 + errRight.r + errDown[tx + x2 - bx0].r;
03618 if (color2.r > 1) {
03619 color2.r = 1;
03620 } else if (color2.r < 0) {
03621 color2.r = 0;
03622 }
03623 color2.g = g0 + errRight.g + errDown[tx + x2 - bx0].g;
03624 if (color2.g > 1) {
03625 color2.g = 1;
03626 } else if (color2.g < 0) {
03627 color2.g = 0;
03628 }
03629 color2.b = b0 + errRight.b + errDown[tx + x2 - bx0].b;
03630 if (color2.b > 1) {
03631 color2.b = 1;
03632 } else if (color2.b < 0) {
03633 color2.b = 0;
03634 }
03635 pix = findColor(&color2, &err);
03636 errRight.r = errDown[tx + x2 - bx0].r = err.r / 2;
03637 errRight.g = errDown[tx + x2 - bx0].g = err.g / 2;
03638 errRight.b = errDown[tx + x2 - bx0].b = err.b / 2;
03639 } else {
03640 color2.r = r0;
03641 color2.g = g0;
03642 color2.b = b0;
03643 pix = findColor(&color2, &err);
03644 }
03645
03646
03647
03648 if (alpha < 0.75) {
03649 XPutPixel(image, tx + x2 - bx0, ty + y2 - by0, pix);
03650 }
03651 }
03652 }
03653
03654
03655 XPutImage(display, pixmap, fillGC, image, cx1, cy1, cx0, cy0, cw, ch);
03656
03657
03658 delete imgStr;
03659 gfree(pixBuf);
03660 if (maskColors) {
03661 gfree(alphaBuf);
03662 }
03663 gfree(image->data);
03664 image->data = NULL;
03665 XDestroyImage(image);
03666 gfree(errDown);
03667 }
03668
03669 GBool XOutputDev::findText(Unicode *s, int len, GBool top, GBool bottom,
03670 int *xMin, int *yMin, int *xMax, int *yMax) {
03671 double xMin1, yMin1, xMax1, yMax1;
03672
03673 xMin1 = (double)*xMin;
03674 yMin1 = (double)*yMin;
03675 xMax1 = (double)*xMax;
03676 yMax1 = (double)*yMax;
03677 if (text->findText(s, len, top, bottom, &xMin1, &yMin1, &xMax1, &yMax1)) {
03678 *xMin = xoutRound(xMin1);
03679 *xMax = xoutRound(xMax1);
03680 *yMin = xoutRound(yMin1);
03681 *yMax = xoutRound(yMax1);
03682 return gTrue;
03683 }
03684 return gFalse;
03685 }
03686
03687 GString *XOutputDev::getText(int xMin, int yMin, int xMax, int yMax) {
03688 return text->getText((double)xMin, (double)yMin,
03689 (double)xMax, (double)yMax);
03690 }