00001
00002
00003
00004
00005
00006
00007
00008
00009 #include <aconf.h>
00010
00011 #if HAVE_T1LIB_H
00012
00013 #ifdef USE_GCC_PRAGMAS
00014 #pragma implementation
00015 #endif
00016
00017 #include <math.h>
00018 #include <string.h>
00019 #include <X11/Xlib.h>
00020 #include "gmem.h"
00021 #include "GfxState.h"
00022 #include "T1Font.h"
00023
00024
00025
00026 int T1FontEngine::t1libInitCount = 0;
00027
00028
00029
00030 T1FontEngine::T1FontEngine(Display *displayA, Visual *visualA, int depthA,
00031 Colormap colormapA, GBool aaA, GBool aaHighA):
00032 SFontEngine(displayA, visualA, depthA, colormapA)
00033 {
00034 static unsigned long grayVals[17] = {
00035 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16
00036 };
00037
00038 ok = gFalse;
00039 aa = aaA;
00040 aaHigh = aaHighA;
00041
00042 if (t1libInitCount == 0) {
00043 T1_SetBitmapPad(8);
00044 if (!T1_InitLib(NO_LOGFILE | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE |
00045 T1_NO_AFM)) {
00046 return;
00047 }
00048 if (aa) {
00049 T1_AASetBitsPerPixel(8);
00050 if (aaHigh) {
00051 T1_AASetLevel(T1_AA_HIGH);
00052 T1_AAHSetGrayValues(grayVals);
00053 } else {
00054 T1_AASetLevel(T1_AA_LOW);
00055 T1_AASetGrayValues(0, 1, 2, 3, 4);
00056 }
00057 } else {
00058 T1_AANSetGrayValues(0, 1);
00059 }
00060 }
00061 ++t1libInitCount;
00062 ok = gTrue;
00063 }
00064
00065 T1FontEngine::~T1FontEngine() {
00066
00067 if (--t1libInitCount == 0) {
00068 T1_CloseLib();
00069 }
00070 }
00071
00072
00073
00074 T1FontFile::T1FontFile(T1FontEngine *engineA, char *fontFileName,
00075 char **fontEnc, double *bboxA) {
00076 int encStrSize;
00077 char *encPtr;
00078 int i;
00079
00080 ok = gFalse;
00081 engine = engineA;
00082 enc = NULL;
00083 encStr = NULL;
00084 for (i = 0; i < 4; ++i) {
00085 bbox[i] = bboxA[i];
00086 }
00087
00088
00089 if ((id = T1_AddFont(fontFileName)) < 0) {
00090 return;
00091 }
00092 T1_LoadFont(id);
00093
00094
00095 encStrSize = 0;
00096 for (i = 0; i < 256; ++i) {
00097 if (fontEnc[i]) {
00098 encStrSize += strlen(fontEnc[i]) + 1;
00099 }
00100 }
00101 enc = (char **)gmalloc(257 * sizeof(char *));
00102 encStr = (char *)gmalloc(encStrSize * sizeof(char));
00103 encPtr = encStr;
00104 for (i = 0; i < 256; ++i) {
00105 if (fontEnc[i]) {
00106 strcpy(encPtr, fontEnc[i]);
00107 enc[i] = encPtr;
00108 encPtr += strlen(encPtr) + 1;
00109 } else {
00110 enc[i] = ".notdef";
00111 }
00112 }
00113 enc[256] = "custom";
00114 T1_ReencodeFont(id, enc);
00115
00116 ok = gTrue;
00117 }
00118
00119 T1FontFile::~T1FontFile() {
00120 gfree(enc);
00121 gfree(encStr);
00122 if (id >= 0) {
00123 T1_DeleteFont(id);
00124 }
00125 }
00126
00127
00128
00129 T1Font::T1Font(T1FontFile *fontFileA, double *m) {
00130 T1FontEngine *engine;
00131 T1_TMATRIX matrix;
00132 BBox bbox;
00133 double bbx0, bby0, bbx1, bby1;
00134 int x, y, xMin, xMax, yMin, yMax;
00135 int i;
00136
00137 ok = gFalse;
00138 fontFile = fontFileA;
00139 engine = fontFile->engine;
00140
00141 id = T1_CopyFont(fontFile->id);
00142
00143
00144 size = (float)sqrt(m[2]*m[2] + m[3]*m[3]);
00145
00146
00147
00148 bbx0 = fontFile->bbox[0];
00149 bby0 = fontFile->bbox[1];
00150 bbx1 = fontFile->bbox[2];
00151 bby1 = fontFile->bbox[3];
00152
00153
00154 bbox = T1_GetFontBBox(id);
00155 if (0.001 * bbox.llx < bbx0) {
00156 bbx0 = 0.001 * bbox.llx;
00157 }
00158 if (0.001 * bbox.lly < bby0) {
00159 bby0 = 0.001 * bbox.lly;
00160 }
00161 if (0.001 * bbox.urx > bbx1) {
00162 bbx1 = 0.001 * bbox.urx;
00163 }
00164 if (0.001 * bbox.ury > bby1) {
00165 bby1 = 0.001 * bbox.ury;
00166 }
00167
00168
00169 if (bbx0 == 0 && bby0 == 0 && bbx1 == 0 && bby1 == 0) {
00170 bbx0 = bby0 = -0.5;
00171 bbx1 = bby1 = 1.5;
00172 }
00173 x = (int)(m[0] * bbx0 + m[2] * bby0);
00174 xMin = xMax = x;
00175 y = (int)(m[1] * bbx0 + m[3] * bby0);
00176 yMin = yMax = y;
00177 x = (int)(m[0] * bbx0 + m[2] * bby1);
00178 if (x < xMin) {
00179 xMin = x;
00180 } else if (x > xMax) {
00181 xMax = x;
00182 }
00183 y = (int)(m[1] * bbx0 + m[3] * bby1);
00184 if (y < yMin) {
00185 yMin = y;
00186 } else if (y > yMax) {
00187 yMax = y;
00188 }
00189 x = (int)(m[0] * bbx1 + m[2] * bby0);
00190 if (x < xMin) {
00191 xMin = x;
00192 } else if (x > xMax) {
00193 xMax = x;
00194 }
00195 y = (int)(m[1] * bbx1 + m[3] * bby0);
00196 if (y < yMin) {
00197 yMin = y;
00198 } else if (y > yMax) {
00199 yMax = y;
00200 }
00201 x = (int)(m[0] * bbx1 + m[2] * bby1);
00202 if (x < xMin) {
00203 xMin = x;
00204 } else if (x > xMax) {
00205 xMax = x;
00206 }
00207 y = (int)(m[1] * bbx1 + m[3] * bby1);
00208 if (y < yMin) {
00209 yMin = y;
00210 } else if (y > yMax) {
00211 yMax = y;
00212 }
00213
00214
00215 if (xMax == xMin) {
00216 xMin = 0;
00217 xMax = (int)size;
00218 }
00219 if (yMax == yMin) {
00220 yMin = 0;
00221 yMax = (int)(1.2 * size);
00222 }
00223
00224
00225 if (xMin > 0) {
00226 xMin = 0;
00227 }
00228 if (yMin > 0) {
00229 yMin = 0;
00230 }
00231
00232
00233 if (xMax - xMin > 5000) {
00234 xMin = 0;
00235 xMax = (int)size;
00236 }
00237 if (yMax - yMin > 5000) {
00238 yMin = 0;
00239 yMax = (int)(1.2 * size);
00240 }
00241
00242
00243 glyphW = xMax - xMin + 3;
00244 glyphH = yMax - yMin + 3;
00245 if (engine->aa) {
00246 glyphSize = glyphW * glyphH;
00247 } else {
00248 glyphSize = ((glyphW + 7) >> 3) * glyphH;
00249 }
00250
00251
00252 cacheAssoc = 8;
00253 if (glyphSize <= 256) {
00254 cacheSets = 8;
00255 } else if (glyphSize <= 512) {
00256 cacheSets = 4;
00257 } else if (glyphSize <= 1024) {
00258 cacheSets = 2;
00259 } else {
00260 cacheSets = 1;
00261 }
00262 cache = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize);
00263 cacheTags = (T1FontCacheTag *)gmalloc(cacheSets * cacheAssoc *
00264 sizeof(T1FontCacheTag));
00265 for (i = 0; i < cacheSets * cacheAssoc; ++i) {
00266 cacheTags[i].mru = i & (cacheAssoc - 1);
00267 }
00268
00269
00270 if (!(image = XCreateImage(engine->display, engine->visual, engine->depth,
00271 ZPixmap, 0, NULL, glyphW, glyphH, 8, 0))) {
00272 return;
00273 }
00274 image->data = (char *)gmalloc(glyphH * image->bytes_per_line);
00275
00276
00277 matrix.cxx = m[0] / size;
00278 matrix.cxy = m[1] / size;
00279 matrix.cyx = m[2] / size;
00280 matrix.cyy = m[3] / size;
00281 T1_TransformFont(id, &matrix);
00282
00283 ok = gTrue;
00284 }
00285
00286 T1Font::~T1Font() {
00287 gfree(cacheTags);
00288 gfree(cache);
00289 if (image) {
00290 gfree(image->data);
00291 image->data = NULL;
00292 XDestroyImage(image);
00293 }
00294 T1_DeleteFont(id);
00295 }
00296
00297 GBool T1Font::drawChar(Drawable d, int w, int h, GC gc,
00298 int x, int y, int r, int g, int b,
00299 CharCode c, Unicode u) {
00300 T1FontEngine *engine;
00301 XColor xcolor;
00302 int bgR, bgG, bgB;
00303 Gulong colors[17];
00304 Guchar *p;
00305 int xOffset, yOffset, x0, y0, x1, y1, gw, gh, w0, h0;
00306 int xx, yy, xx1;
00307 Guchar pix, mPix;
00308 int i;
00309
00310 engine = fontFile->engine;
00311
00312
00313 if (!(p = getGlyphPixmap(c, &xOffset, &yOffset, &gw, &gh))) {
00314 return gFalse;
00315 }
00316
00317
00318
00319
00320 x0 = x - xOffset;
00321 y0 = y - yOffset;
00322 x1 = 0;
00323 y1 = 0;
00324 w0 = gw;
00325 h0 = gh;
00326 if (x0 < 0) {
00327 x1 = -x0;
00328 w0 += x0;
00329 x0 = 0;
00330 }
00331 if (x0 + w0 > w) {
00332 w0 = w - x0;
00333 }
00334 if (w0 < 0) {
00335 return gTrue;
00336 }
00337 if (y0 < 0) {
00338 y1 = -y0;
00339 h0 += y0;
00340 y0 = 0;
00341 }
00342 if (y0 + h0 > h) {
00343 h0 = h - y0;
00344 }
00345 if (h0 < 0) {
00346 return gTrue;
00347 }
00348
00349
00350 XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1,
00351 ZPixmap, image, x1, y1);
00352
00353 if (engine->aa) {
00354
00355
00356 xcolor.pixel = XGetPixel(image, x1 + w0/2, y1 + h0/2);
00357 XQueryColor(engine->display, engine->colormap, &xcolor);
00358 bgR = xcolor.red;
00359 bgG = xcolor.green;
00360 bgB = xcolor.blue;
00361 if (engine->aaHigh) {
00362 mPix = 16;
00363 for (i = 1; i <= 16; ++i) {
00364 colors[i] = engine->findColor((i * r + (16 - i) * bgR) / 16,
00365 (i * g + (16 - i) * bgG) / 16,
00366 (i * b + (16 - i) * bgB) / 16);
00367 }
00368 } else {
00369 mPix = 4;
00370 colors[1] = engine->findColor((r + 3*bgR) / 4,
00371 (g + 3*bgG) / 4,
00372 (b + 3*bgB) / 4);
00373 colors[2] = engine->findColor((r + bgR) / 2,
00374 (g + bgG) / 2,
00375 (b + bgB) / 2);
00376 colors[3] = engine->findColor((3*r + bgR) / 4,
00377 (3*g + bgG) / 4,
00378 (3*b + bgB) / 4);
00379 colors[4] = engine->findColor(r, g, b);
00380 }
00381
00382
00383 for (yy = 0; yy < gh; ++yy) {
00384 for (xx = 0; xx < gw; ++xx) {
00385 pix = *p++;
00386 if (pix > 0) {
00387 if (pix > mPix) {
00388 pix = mPix;
00389 }
00390 XPutPixel(image, xx, yy, colors[pix]);
00391 }
00392 }
00393 }
00394
00395 } else {
00396
00397
00398 colors[1] = engine->findColor(r, g, b);
00399
00400
00401 for (yy = 0; yy < gh; ++yy) {
00402 for (xx = 0; xx < gw; xx += 8) {
00403 pix = *p++;
00404 for (xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) {
00405 if (pix & 0x01) {
00406 XPutPixel(image, xx1, yy, colors[1]);
00407 }
00408 pix >>= 1;
00409 }
00410 }
00411 }
00412
00413 }
00414
00415
00416 XPutImage(engine->display, d, gc, image, x1, y1, x0, y0, w0, h0);
00417
00418 return gTrue;
00419 }
00420
00421 Guchar *T1Font::getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h) {
00422 T1FontEngine *engine;
00423 GLYPH *glyph;
00424 int gSize;
00425 int i, j, k;
00426 Guchar *ret;
00427
00428 engine = fontFile->engine;
00429
00430
00431 i = (c & (cacheSets - 1)) * cacheAssoc;
00432 for (j = 0; j < cacheAssoc; ++j) {
00433 if ((cacheTags[i+j].mru & 0x8000) && cacheTags[i+j].code == c) {
00434 *x = cacheTags[i+j].x;
00435 *y = cacheTags[i+j].y;
00436 *w = cacheTags[i+j].w;
00437 *h = cacheTags[i+j].h;
00438 for (k = 0; k < cacheAssoc; ++k) {
00439 if (k != j &&
00440 (cacheTags[i+k].mru & 0x7fff) < (cacheTags[i+j].mru & 0x7fff)) {
00441 ++cacheTags[i+k].mru;
00442 }
00443 }
00444 cacheTags[i+j].mru = 0x8000;
00445 return cache + (i+j) * glyphSize;
00446 }
00447 }
00448
00449
00450 if (engine->aa) {
00451 glyph = T1_AASetChar(id, c, size, NULL);
00452 } else {
00453 glyph = T1_SetChar(id, c, size, NULL);
00454 }
00455 if (!glyph) {
00456 return NULL;
00457 }
00458 *x = -glyph->metrics.leftSideBearing;
00459 *y = glyph->metrics.ascent;
00460 *w = glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing;
00461 *h = glyph->metrics.ascent - glyph->metrics.descent;
00462 if (*w > glyphW || *h > glyphH) {
00463 #if 1 //~ debug
00464 fprintf(stderr, "Weird t1lib glyph size: %d > %d or %d > %d\n",
00465 *w, glyphW, *h, glyphH);
00466 #endif
00467 return NULL;
00468 }
00469
00470
00471 ret = NULL;
00472 for (j = 0; j < cacheAssoc; ++j) {
00473 if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) {
00474 cacheTags[i+j].mru = 0x8000;
00475 cacheTags[i+j].code = c;
00476 cacheTags[i+j].x = *x;
00477 cacheTags[i+j].y = *y;
00478 cacheTags[i+j].w = *w;
00479 cacheTags[i+j].h = *h;
00480 if (engine->aa) {
00481 gSize = *w * *h;
00482 } else {
00483 gSize = ((*w + 7) >> 3) * *h;
00484 }
00485 ret = cache + (i+j) * glyphSize;
00486 if (glyph->bits) {
00487 memcpy(ret, glyph->bits, gSize);
00488 } else {
00489 memset(ret, 0, gSize);
00490 }
00491 } else {
00492 ++cacheTags[i+j].mru;
00493 }
00494 }
00495 return ret;
00496 }
00497
00498 GBool T1Font::getCharPath(CharCode c, Unicode u, GfxState *state) {
00499 T1_OUTLINE *outline;
00500 T1_PATHSEGMENT *seg;
00501 T1_BEZIERSEGMENT *bez;
00502 double x, y, x1, y1;
00503
00504 outline = T1_GetCharOutline(id, c, size, NULL);
00505 x = 0;
00506 y = 0;
00507 for (seg = outline; seg; seg = seg->link) {
00508 switch (seg->type) {
00509 case T1_PATHTYPE_MOVE:
00510 x += seg->dest.x / 65536.0;
00511 y += seg->dest.y / 65536.0;
00512 state->moveTo(x, y);
00513 break;
00514 case T1_PATHTYPE_LINE:
00515 x += seg->dest.x / 65536.0;
00516 y += seg->dest.y / 65536.0;
00517 state->lineTo(x, y);
00518 break;
00519 case T1_PATHTYPE_BEZIER:
00520 bez = (T1_BEZIERSEGMENT *)seg;
00521 x1 = x + bez->dest.x / 65536.0;
00522 y1 = y + bez->dest.y / 65536.0;
00523 state->curveTo(x + bez->B.x / 65536.0, y + bez->B.y / 65536.0,
00524 x + bez->C.x / 65536.0, y + bez->C.y / 65536.0,
00525 x1, y1);
00526 x = x1;
00527 y = y1;
00528 break;
00529 }
00530 }
00531 T1_FreeOutline(outline);
00532 return gTrue;
00533 }
00534
00535 #endif // HAVE_T1LIB_H