From 6c85243ff859071be4fd2a3847b0fc2086206d31 Mon Sep 17 00:00:00 2001 From: Martin Kretzschmar Date: Mon, 17 May 2004 19:37:57 +0000 Subject: Imported Xpdf 3.00 and fixed build. * ANNOUNCE: * CHANGES: * Makefile.am: * README: * aconf-win32.h: * configure.in: * dj_make.bat: * doc/pdffonts.1: * doc/pdffonts.cat: * doc/pdffonts.hlp: * doc/pdfimages.1: * doc/pdfimages.cat: * doc/pdfimages.hlp: * doc/pdfinfo.1: * doc/pdfinfo.cat: * doc/pdfinfo.hlp: * doc/pdftopbm.1: * doc/pdftopbm.cat: * doc/pdftopbm.hlp: * doc/pdftops.1: * doc/pdftops.cat: * doc/pdftops.hlp: * doc/pdftotext.1: * doc/pdftotext.cat: * doc/pdftotext.hlp: * doc/xpdf.1: * doc/xpdf.cat: * doc/xpdf.hlp: * doc/xpdfrc.5: * doc/xpdfrc.cat: * doc/xpdfrc.hlp: * fofi/Makefile.in: * goo/GHash.cc: * goo/GHash.h: * ms_make.bat: * splash/Makefile.in: * xpdf/DisplayFontTable.h: * xpdf/ErrorCodes.h: * xpdf/FTFont.cc: * xpdf/FTFont.h: * xpdf/FontFile.cc: * xpdf/FontFile.h: * xpdf/Function.h: * xpdf/GPOutputDev.cc: * xpdf/Gfx.cc: * xpdf/Gfx.h: * xpdf/GfxFont.cc: * xpdf/GfxFont.h: * xpdf/GfxState.cc: * xpdf/GfxState.h: * xpdf/GlobalParams.cc: * xpdf/GlobalParams.h: * xpdf/Makefile.am: * xpdf/Object.cc: * xpdf/Object.h: * xpdf/Outline.cc: * xpdf/OutputDev.cc: * xpdf/OutputDev.h: * xpdf/PBMOutputDev.cc: * xpdf/PBMOutputDev.h: * xpdf/PDFDoc.cc: * xpdf/PDFDoc.h: * xpdf/PSOutputDev.cc: * xpdf/PSOutputDev.h: * xpdf/Page.cc: * xpdf/Page.h: * xpdf/Parser.cc: * xpdf/SFont.cc: * xpdf/SFont.h: * xpdf/Stream.cc: * xpdf/Stream.h: * xpdf/T1Font.cc: * xpdf/T1Font.h: * xpdf/TTFont.cc: * xpdf/TTFont.h: * xpdf/TextOutputDev.cc: * xpdf/TextOutputDev.h: * xpdf/XOutputDev.cc: * xpdf/XOutputDev.h: * xpdf/XPixmapOutputDev.cc: * xpdf/XPixmapOutputDev.h: * xpdf/XRef.cc: * xpdf/XRef.h: * xpdf/config.h: * xpdf/gpdf-control.cc: * xpdf/pdffonts.cc: * xpdf/pdfimages.cc: * xpdf/pdfinfo.cc: * xpdf/pdftopbm.cc: * xpdf/pdftops.cc: * xpdf/pdftotext.cc: * xpdf/tests/Makefile.am: * xpdf/vms_make.com: * xpdf/xpdf.cc: Imported Xpdf 3.00 and fixed build. --- diff --git a/pdf/goo/GHash.cc b/pdf/goo/GHash.cc index 7036316..1dd0e26 100644 --- a/pdf/goo/GHash.cc +++ b/pdf/goo/GHash.cc @@ -20,7 +20,10 @@ struct GHashBucket { GString *key; - void *val; + union { + void *p; + int i; + } val; GHashBucket *next; }; @@ -61,35 +64,37 @@ GHash::~GHash() { } void GHash::add(GString *key, void *val) { - GHashBucket **oldTab; GHashBucket *p; - int oldSize, i, h; + int h; // expand the table if necessary if (len >= size) { - oldSize = size; - oldTab = tab; - size = 2*size + 1; - tab = (GHashBucket **)gmalloc(size * sizeof(GHashBucket *)); - for (h = 0; h < size; ++h) { - tab[h] = NULL; - } - for (i = 0; i < oldSize; ++i) { - while (oldTab[i]) { - p = oldTab[i]; - oldTab[i] = oldTab[i]->next; - h = hash(p->key); - p->next = tab[h]; - tab[h] = p; - } - } - gfree(oldTab); + expand(); + } + + // add the new symbol + p = new GHashBucket; + p->key = key; + p->val.p = val; + h = hash(key); + p->next = tab[h]; + tab[h] = p; + ++len; +} + +void GHash::add(GString *key, int val) { + GHashBucket *p; + int h; + + // expand the table if necessary + if (len >= size) { + expand(); } // add the new symbol p = new GHashBucket; p->key = key; - p->val = val; + p->val.i = val; h = hash(key); p->next = tab[h]; tab[h] = p; @@ -103,7 +108,17 @@ void *GHash::lookup(GString *key) { if (!(p = find(key, &h))) { return NULL; } - return p->val; + return p->val.p; +} + +int GHash::lookupInt(GString *key) { + GHashBucket *p; + int h; + + if (!(p = find(key, &h))) { + return 0; + } + return p->val.i; } void *GHash::lookup(char *key) { @@ -113,7 +128,17 @@ void *GHash::lookup(char *key) { if (!(p = find(key, &h))) { return NULL; } - return p->val; + return p->val.p; +} + +int GHash::lookupInt(char *key) { + GHashBucket *p; + int h; + + if (!(p = find(key, &h))) { + return 0; + } + return p->val.i; } void *GHash::remove(GString *key) { @@ -133,7 +158,30 @@ void *GHash::remove(GString *key) { if (deleteKeys) { delete p->key; } - val = p->val; + val = p->val.p; + delete p; + --len; + return val; +} + +int GHash::removeInt(GString *key) { + GHashBucket *p; + GHashBucket **q; + int val; + int h; + + if (!(p = find(key, &h))) { + return 0; + } + q = &tab[h]; + while (*q != p) { + q = &((*q)->next); + } + *q = p->next; + if (deleteKeys) { + delete p->key; + } + val = p->val.i; delete p; --len; return val; @@ -156,7 +204,30 @@ void *GHash::remove(char *key) { if (deleteKeys) { delete p->key; } - val = p->val; + val = p->val.p; + delete p; + --len; + return val; +} + +int GHash::removeInt(char *key) { + GHashBucket *p; + GHashBucket **q; + int val; + int h; + + if (!(p = find(key, &h))) { + return 0; + } + q = &tab[h]; + while (*q != p) { + q = &((*q)->next); + } + *q = p->next; + if (deleteKeys) { + delete p->key; + } + val = p->val.i; delete p; --len; return val; @@ -184,7 +255,27 @@ GBool GHash::getNext(GHashIter **iter, GString **key, void **val) { (*iter)->p = tab[(*iter)->h]; } *key = (*iter)->p->key; - *val = (*iter)->p->val; + *val = (*iter)->p->val.p; + return gTrue; +} + +GBool GHash::getNext(GHashIter **iter, GString **key, int *val) { + if (!*iter) { + return gFalse; + } + if ((*iter)->p) { + (*iter)->p = (*iter)->p->next; + } + while (!(*iter)->p) { + if (++(*iter)->h == size) { + delete *iter; + *iter = NULL; + return gFalse; + } + (*iter)->p = tab[(*iter)->h]; + } + *key = (*iter)->p->key; + *val = (*iter)->p->val.i; return gTrue; } @@ -193,6 +284,30 @@ void GHash::killIter(GHashIter **iter) { *iter = NULL; } +void GHash::expand() { + GHashBucket **oldTab; + GHashBucket *p; + int oldSize, h, i; + + oldSize = size; + oldTab = tab; + size = 2*size + 1; + tab = (GHashBucket **)gmalloc(size * sizeof(GHashBucket *)); + for (h = 0; h < size; ++h) { + tab[h] = NULL; + } + for (i = 0; i < oldSize; ++i) { + while (oldTab[i]) { + p = oldTab[i]; + oldTab[i] = oldTab[i]->next; + h = hash(p->key); + p->next = tab[h]; + tab[h] = p; + } + } + gfree(oldTab); +} + GHashBucket *GHash::find(GString *key, int *h) { GHashBucket *p; diff --git a/pdf/goo/GHash.h b/pdf/goo/GHash.h index 69c767b..4a6e08d 100644 --- a/pdf/goo/GHash.h +++ b/pdf/goo/GHash.h @@ -29,17 +29,24 @@ public: GHash(GBool deleteKeysA = gFalse); ~GHash(); void add(GString *key, void *val); + void add(GString *key, int val); void *lookup(GString *key); + int lookupInt(GString *key); void *lookup(char *key); + int lookupInt(char *key); void *remove(GString *key); + int removeInt(GString *key); void *remove(char *key); + int removeInt(char *key); int getLength() { return len; } void startIter(GHashIter **iter); GBool getNext(GHashIter **iter, GString **key, void **val); + GBool getNext(GHashIter **iter, GString **key, int *val); void killIter(GHashIter **iter); private: + void expand(); GHashBucket *find(GString *key, int *h); GHashBucket *find(char *key, int *h); int hash(GString *key); diff --git a/pdf/xpdf/DisplayFontTable.h b/pdf/xpdf/DisplayFontTable.h deleted file mode 100644 index 3c2379f..0000000 --- a/pdf/xpdf/DisplayFontTable.h +++ /dev/null @@ -1,29 +0,0 @@ -//======================================================================== -// -// DisplayFontTable.h -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -static struct { - char *name; - char *xlfd; - char *encoding; -} displayFontTab[] = { - {"Courier", "-*-courier-medium-r-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, - {"Courier-Bold", "-*-courier-bold-r-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, - {"Courier-BoldOblique", "-*-courier-bold-o-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, - {"Courier-Oblique", "-*-courier-medium-o-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, - {"Helvetica", "-*-helvetica-medium-r-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, - {"Helvetica-Bold", "-*-helvetica-bold-r-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, - {"Helvetica-BoldOblique", "-*-helvetica-bold-o-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, - {"Helvetica-Oblique", "-*-helvetica-medium-o-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, - {"Symbol", "-*-symbol-medium-r-normal-*-%s-*-*-*-*-*-adobe-fontspecific", "Symbol"}, - {"Times-Bold", "-*-times-bold-r-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, - {"Times-BoldItalic", "-*-times-bold-i-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, - {"Times-Italic", "-*-times-medium-i-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, - {"Times-Roman", "-*-times-medium-r-normal-*-%s-*-*-*-*-*-iso8859-1", "Latin1"}, - {"ZapfDingbats", "-*-zapfdingbats-medium-r-normal-*-%s-*-*-*-*-*-*-*", "ZapfDingbats"}, - {NULL} -}; diff --git a/pdf/xpdf/ErrorCodes.h b/pdf/xpdf/ErrorCodes.h index 6eb1435..b28528d 100644 --- a/pdf/xpdf/ErrorCodes.h +++ b/pdf/xpdf/ErrorCodes.h @@ -31,4 +31,6 @@ #define errBadPageNum 9 // invalid page number +#define errFileIO 10 // file I/O error + #endif diff --git a/pdf/xpdf/FTFont.cc b/pdf/xpdf/FTFont.cc deleted file mode 100644 index 1a5ecfa..0000000 --- a/pdf/xpdf/FTFont.cc +++ /dev/null @@ -1,703 +0,0 @@ -//======================================================================== -// -// FTFont.cc -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include "gmem.h" -#include "freetype/ftoutln.h" -#include "freetype/internal/ftobjs.h" -#if 1 //~ cff cid->gid map -#include "freetype/internal/cfftypes.h" -#include "freetype/internal/tttypes.h" -#endif -#include "GlobalParams.h" -#include "GfxState.h" -#include "FTFont.h" - -//------------------------------------------------------------------------ - -FTFontEngine::FTFontEngine(Display *displayA, Visual *visualA, int depthA, - Colormap colormapA, GBool aaA): - SFontEngine(displayA, visualA, depthA, colormapA) { - - ok = gFalse; - if (FT_Init_FreeType(&lib)) { - return; - } - aa = aaA; - ok = gTrue; -} - -FTFontEngine::~FTFontEngine() { - FT_Done_FreeType(lib); -} - -//------------------------------------------------------------------------ - -FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName, - char **fontEnc, Gushort *codeToGID) { - char *name; - int i; - - ok = gFalse; - engine = engineA; - codeMap = NULL; - cidToGID = NULL; - cidToGIDLen = 0; - - if (FT_New_Face(engine->lib, fontFileName, 0, &face)) { - return; - } - - if (!strcmp(face->driver->root.clazz->module_name, "type1") || - !strcmp(face->driver->root.clazz->module_name, "cff")) { - mode = ftFontModeCodeMapDirect; - codeMap = (Guint *)gmalloc(256 * sizeof(Guint)); - for (i = 0; i < 256; ++i) { - codeMap[i] = 0; - if ((name = fontEnc[i])) { - codeMap[i] = FT_Get_Name_Index(face, name); - } - } - - } else { - mode = ftFontModeCodeMapDirect; - codeMap = (Guint *)gmalloc(256 * sizeof(Guint)); - for (i = 0; i < 256; ++i) { - codeMap[i] = (int)codeToGID[i]; - } - } - - ok = gTrue; -} - -FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName, - Gushort *cidToGIDA, int cidToGIDLenA, GBool embedded) { - int i; - - ok = gFalse; - engine = engineA; - codeMap = NULL; - cidToGID = NULL; - cidToGIDLen = 0; - - if (FT_New_Face(engine->lib, fontFileName, 0, &face)) { - return; - } - cidToGIDLen = cidToGIDLenA; - cidToGID = (Gushort *)gmalloc(cidToGIDLen * sizeof(Gushort)); - memcpy(cidToGID, cidToGIDA, cidToGIDLen * sizeof(Gushort)); - if (!strcmp(face->driver->root.clazz->module_name, "t1cid")) { - mode = ftFontModeCID; - } else if (!strcmp(face->driver->root.clazz->module_name, "cff")) { - mode = ftFontModeCFFCharset; - } else if (embedded) { - mode = ftFontModeCIDToGIDMap; - } else { - mode = ftFontModeUnicode; - for (i = 0; i < face->num_charmaps; ++i) { - if ((face->charmaps[i]->platform_id == 3 && - face->charmaps[i]->encoding_id == 1) || - face->charmaps[i]->platform_id == 0) { - break; - } - } - if (i == face->num_charmaps) { - i = 0; - } - FT_Set_Charmap(face, face->charmaps[i]); - } - ok = gTrue; -} - -FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName, - GBool embedded) { - int i; - - ok = gFalse; - engine = engineA; - codeMap = NULL; - cidToGID = NULL; - cidToGIDLen = 0; - - if (FT_New_Face(engine->lib, fontFileName, 0, &face)) { - return; - } - if (!strcmp(face->driver->root.clazz->module_name, "t1cid")) { - mode = ftFontModeCID; - } else if (embedded) { - mode = ftFontModeCFFCharset; - } else { - mode = ftFontModeUnicode; - for (i = 0; i < face->num_charmaps; ++i) { - if ((face->charmaps[i]->platform_id == 3 && - face->charmaps[i]->encoding_id == 1) || - face->charmaps[i]->platform_id == 0) { - break; - } - } - if (i == face->num_charmaps) { - i = 0; - } - FT_Set_Charmap(face, face->charmaps[i]); - } - ok = gTrue; -} - -FTFontFile::~FTFontFile() { - if (face) { - FT_Done_Face(face); - } - if (codeMap) { - gfree(codeMap); - } - if (cidToGID) { - gfree(cidToGID); - } -} - -//------------------------------------------------------------------------ - -FTFont::FTFont(FTFontFile *fontFileA, double *m) { - FTFontEngine *engine; - FT_Face face; - double size, div; - int x, xMin, xMax; - int y, yMin, yMax; - int i; - - ok = gFalse; - fontFile = fontFileA; - engine = fontFile->engine; - face = fontFile->face; - if (FT_New_Size(face, &sizeObj)) { - return; - } - face->size = sizeObj; - size = sqrt(m[2]*m[2] + m[3]*m[3]); - if (FT_Set_Pixel_Sizes(face, 0, (int)size)) { - return; - } - - div = face->bbox.xMax > 20000 ? 65536 : 1; - - // transform the four corners of the font bounding box -- the min - // and max values form the bounding box of the transformed font - x = (int)((m[0] * face->bbox.xMin + m[2] * face->bbox.yMin) / - (div * face->units_per_EM)); - xMin = xMax = x; - y = (int)((m[1] * face->bbox.xMin + m[3] * face->bbox.yMin) / - (div * face->units_per_EM)); - yMin = yMax = y; - x = (int)((m[0] * face->bbox.xMin + m[2] * face->bbox.yMax) / - (div * face->units_per_EM)); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - y = (int)((m[1] * face->bbox.xMin + m[3] * face->bbox.yMax) / - (div * face->units_per_EM)); - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - x = (int)((m[0] * face->bbox.xMax + m[2] * face->bbox.yMin) / - (div * face->units_per_EM)); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - y = (int)((m[1] * face->bbox.xMax + m[3] * face->bbox.yMin) / - (div * face->units_per_EM)); - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - x = (int)((m[0] * face->bbox.xMax + m[2] * face->bbox.yMax) / - (div * face->units_per_EM)); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - y = (int)((m[1] * face->bbox.xMax + m[3] * face->bbox.yMax) / - (div * face->units_per_EM)); - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - // This is a kludge: some buggy PDF generators embed fonts with - // zero bounding boxes. - if (xMax == xMin) { - xMin = 0; - xMax = (int)size; - } - if (yMax == yMin) { - yMin = 0; - yMax = (int)(1.2 * size); - } - // this should be (max - min + 1), but we add some padding to - // deal with rounding errors, bogus bboxes, etc. - glyphW = xMax - xMin + 3; - glyphW += glyphW >> 1; - glyphH = yMax - yMin + 3; - glyphH += glyphH >> 1; - if (engine->aa) { - glyphSize = glyphW * glyphH; - } else { - glyphSize = ((glyphW + 7) >> 3) * glyphH; - } - - // set up the glyph pixmap cache - cacheAssoc = 8; - if (glyphSize <= 256) { - cacheSets = 8; - } else if (glyphSize <= 512) { - cacheSets = 4; - } else if (glyphSize <= 1024) { - cacheSets = 2; - } else { - cacheSets = 1; - } - cache = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize); - cacheTags = (FTFontCacheTag *)gmalloc(cacheSets * cacheAssoc * - sizeof(FTFontCacheTag)); - for (i = 0; i < cacheSets * cacheAssoc; ++i) { - cacheTags[i].mru = i & (cacheAssoc - 1); - } - - // create the XImage - if (!(image = XCreateImage(engine->display, engine->visual, engine->depth, - ZPixmap, 0, NULL, glyphW, glyphH, 8, 0))) { - return; - } - image->data = (char *)gmalloc(glyphH * image->bytes_per_line); - - // compute the transform matrix - matrix.xx = (FT_Fixed)((m[0] / size) * 65536); - matrix.yx = (FT_Fixed)((m[1] / size) * 65536); - matrix.xy = (FT_Fixed)((m[2] / size) * 65536); - matrix.yy = (FT_Fixed)((m[3] / size) * 65536); - - ok = gTrue; -} - -FTFont::~FTFont() { - gfree(cacheTags); - gfree(cache); - gfree(image->data); - image->data = NULL; - XDestroyImage(image); -} - -GBool FTFont::drawChar(Drawable d, int w, int h, GC gc, - int x, int y, int r, int g, int b, - CharCode c, Unicode u) { - FTFontEngine *engine; - XColor xcolor; - int bgR, bgG, bgB; - Gulong colors[5]; - Guchar *bitmap, *p; - GBool tempBitmap; - XImage *img; - int pix; - int xOffset, yOffset, x0, y0, x1, y1, gw, gh, w0, h0; - int xx, yy, xx1; - - engine = fontFile->engine; - - // no Unicode index for this char - don't draw anything - if (fontFile->mode == ftFontModeUnicode && u == 0) { - return gFalse; - } - - // generate the glyph pixmap - if (!(bitmap = getGlyphPixmap(c, u, &xOffset, &yOffset, &gw, &gh, - &tempBitmap))) { - return gFalse; - } - - // compute: (x0,y0) = position in destination drawable - // (x1,y1) = position in glyph image - // (w0,h0) = size of image transfer - x0 = x - xOffset; - y0 = y - yOffset; - x1 = 0; - y1 = 0; - w0 = gw; - h0 = gh; - if (x0 < 0) { - x1 = -x0; - w0 += x0; - x0 = 0; - } - if (x0 + w0 > w) { - w0 = w - x0; - } - if (w0 < 0) { - goto done; - } - if (y0 < 0) { - y1 = -y0; - h0 += y0; - y0 = 0; - } - if (y0 + h0 > h) { - h0 = h - y0; - } - if (h0 < 0) { - goto done; - } - - // getGlyphPixmap may have returned a larger-than-cache-entry - // bitmap, in which case we need to allocate a temporary XImage here - if (tempBitmap) { - if (!(img = XCreateImage(engine->display, engine->visual, engine->depth, - ZPixmap, 0, NULL, gw, gh, 8, 0))) { - goto done; - } - img->data = (char *)gmalloc(gh * img->bytes_per_line); - } else { - img = image; - } - - // read the X image - XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1, - ZPixmap, img, x1, y1); - - if (engine->aa) { - - // compute the colors - xcolor.pixel = XGetPixel(img, x1 + w0/2, y1 + h0/2); - XQueryColor(engine->display, engine->colormap, &xcolor); - bgR = xcolor.red; - bgG = xcolor.green; - bgB = xcolor.blue; - colors[1] = engine->findColor((r + 3*bgR) / 4, - (g + 3*bgG) / 4, - (b + 3*bgB) / 4); - colors[2] = engine->findColor((r + bgR) / 2, - (g + bgG) / 2, - (b + bgB) / 2); - colors[3] = engine->findColor((3*r + bgR) / 4, - (3*g + bgG) / 4, - (3*b + bgB) / 4); - colors[4] = engine->findColor(r, g, b); - - // stuff the glyph pixmap into the X image - p = bitmap; - for (yy = 0; yy < gh; ++yy) { - for (xx = 0; xx < gw; ++xx) { - pix = *p++ & 0xff; - // this is a heuristic which seems to produce decent - // results -- the linear mapping would be: - // pix = (pix * 5) / 256; - pix = ((pix + 10) * 5) / 256; - if (pix > 4) { - pix = 4; - } - if (pix > 0) { - XPutPixel(img, xx, yy, colors[pix]); - } - } - } - - } else { - - // one color - colors[1] = engine->findColor(r, g, b); - - // stuff the glyph bitmap into the X image - p = bitmap; - for (yy = 0; yy < gh; ++yy) { - for (xx = 0; xx < gw; xx += 8) { - pix = *p++; - for (xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) { - if (pix & 0x80) { - XPutPixel(img, xx1, yy, colors[1]); - } - pix <<= 1; - } - } - } - - } - - // draw the X image - XPutImage(engine->display, d, gc, img, x1, y1, x0, y0, w0, h0); - - if (tempBitmap) { - gfree(img->data); - img->data = NULL; - XDestroyImage(img); - } - done: - if (tempBitmap) { - gfree(bitmap); - } - return gTrue; -} - -Guchar *FTFont::getGlyphPixmap(CharCode c, Unicode u, - int *x, int *y, int *w, int *h, - GBool *tempBitmap) { - FT_GlyphSlot slot; - FT_UInt idx; - int rowSize; - int i, j, k; - Guchar *ret, *p, *q; - - // check the cache - i = (c & (cacheSets - 1)) * cacheAssoc; - for (j = 0; j < cacheAssoc; ++j) { - if ((cacheTags[i+j].mru & 0x8000) && cacheTags[i+j].code == c) { - *x = cacheTags[i+j].x; - *y = cacheTags[i+j].y; - *w = cacheTags[i+j].w; - *h = cacheTags[i+j].h; - for (k = 0; k < cacheAssoc; ++k) { - if (k != j && - (cacheTags[i+k].mru & 0x7fff) < (cacheTags[i+j].mru & 0x7fff)) { - ++cacheTags[i+k].mru; - } - } - cacheTags[i+j].mru = 0x8000; - *tempBitmap = gFalse; - return cache + (i+j) * glyphSize; - } - } - - // generate the glyph pixmap or bitmap - fontFile->face->size = sizeObj; - FT_Set_Transform(fontFile->face, &matrix, NULL); - slot = fontFile->face->glyph; - idx = getGlyphIndex(c, u); - // if we have the FT2 bytecode interpreter, autohinting won't be used -#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER - if (FT_Load_Glyph(fontFile->face, idx, - fontFile->engine->aa ? FT_LOAD_NO_BITMAP - : FT_LOAD_DEFAULT)) { - return gFalse; - } -#else - // FT2's autohinting doesn't always work very well (especially with - // font subsets), so turn it off if anti-aliasing is enabled; if - // anti-aliasing is disabled, this seems to be a tossup - some fonts - // look better with hinting, some without, so leave hinting on - if (FT_Load_Glyph(fontFile->face, idx, - fontFile->engine->aa ? FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP - : FT_LOAD_DEFAULT)) { - return gFalse; - } -#endif - if (FT_Render_Glyph(slot, - fontFile->engine->aa ? ft_render_mode_normal : - ft_render_mode_mono)) { - return gFalse; - } - - // copy the glyph into the cache or a temporary bitmap - *x = -slot->bitmap_left; - *y = slot->bitmap_top; - *w = slot->bitmap.width; - *h = slot->bitmap.rows; - if (fontFile->engine->aa) { - rowSize = *w; - } else { - rowSize = (*w + 7) >> 3; - } - if (*w > glyphW || *h > glyphH) { - // the glyph doesn't fit in the bounding box -- return a - // temporary, uncached bitmap (this shouldn't happen but some - // fonts have incorrect bboxes) - ret = (Guchar *)gmalloc(*h * rowSize); - *tempBitmap = gTrue; - } else { - // store glyph pixmap in cache - ret = NULL; // make gcc happy - for (j = 0; j < cacheAssoc; ++j) { - if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) { - cacheTags[i+j].mru = 0x8000; - cacheTags[i+j].code = c; - cacheTags[i+j].x = *x; - cacheTags[i+j].y = *y; - cacheTags[i+j].w = *w; - cacheTags[i+j].h = *h; - ret = cache + (i+j) * glyphSize; - } else { - ++cacheTags[i+j].mru; - } - } - *tempBitmap = gFalse; - } - for (k = 0, p = ret, q = slot->bitmap.buffer; - k < slot->bitmap.rows; - ++k, p += rowSize, q += slot->bitmap.pitch) { - memcpy(p, q, rowSize); - } - return ret; -} - -GBool FTFont::getCharPath(CharCode c, Unicode u, GfxState *state) { - static FT_Outline_Funcs outlineFuncs = { - &charPathMoveTo, - &charPathLineTo, - &charPathConicTo, - &charPathCubicTo, - 0, 0 - }; - FT_GlyphSlot slot; - FT_UInt idx; - FT_Glyph glyph; - - fontFile->face->size = sizeObj; - FT_Set_Transform(fontFile->face, &matrix, NULL); - slot = fontFile->face->glyph; - idx = getGlyphIndex(c, u); -#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER - if (FT_Load_Glyph(fontFile->face, idx, FT_LOAD_DEFAULT)) { - return gFalse; - } -#else - // FT2's autohinting doesn't always work very well (especially with - // font subsets), so turn it off if anti-aliasing is enabled; if - // anti-aliasing is disabled, this seems to be a tossup - some fonts - // look better with hinting, some without, so leave hinting on - if (FT_Load_Glyph(fontFile->face, idx, - fontFile->engine->aa ? FT_LOAD_NO_HINTING - : FT_LOAD_DEFAULT)) { - return gFalse; - } -#endif - if (FT_Get_Glyph(slot, &glyph)) { - return gFalse; - } - FT_Outline_Decompose(&((FT_OutlineGlyph)glyph)->outline, - &outlineFuncs, state); - return gTrue; -} - -int FTFont::charPathMoveTo(FT_Vector *pt, void *state) { - ((GfxState *)state)->moveTo(pt->x / 64.0, -pt->y / 64.0); - return 0; -} - -int FTFont::charPathLineTo(FT_Vector *pt, void *state) { - ((GfxState *)state)->lineTo(pt->x / 64.0, -pt->y / 64.0); - return 0; -} - -int FTFont::charPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *state) { - double x0, y0, x1, y1, x2, y2, x3, y3, xc, yc; - - x0 = ((GfxState *)state)->getCurX(); - y0 = ((GfxState *)state)->getCurY(); - xc = ctrl->x / 64.0; - yc = -ctrl->y / 64.0; - x3 = pt->x / 64.0; - y3 = -pt->y / 64.0; - - // A second-order Bezier curve is defined by two endpoints, p0 and - // p3, and one control point, pc: - // - // p(t) = (1-t)^2*p0 + t*(1-t)*pc + t^2*p3 - // - // A third-order Bezier curve is defined by the same two endpoints, - // p0 and p3, and two control points, p1 and p2: - // - // p(t) = (1-t)^3*p0 + 3t*(1-t)^2*p1 + 3t^2*(1-t)*p2 + t^3*p3 - // - // Applying some algebra, we can convert a second-order curve to a - // third-order curve: - // - // p1 = (1/3) * (p0 + 2pc) - // p2 = (1/3) * (2pc + p3) - - x1 = (1.0 / 3.0) * (x0 + 2 * xc); - y1 = (1.0 / 3.0) * (y0 + 2 * yc); - x2 = (1.0 / 3.0) * (2 * xc + x3); - y2 = (1.0 / 3.0) * (2 * yc + y3); - - ((GfxState *)state)->curveTo(x1, y1, x2, y2, x3, y3); - return 0; -} - -int FTFont::charPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2, - FT_Vector *pt, void *state) { - ((GfxState *)state)->curveTo(ctrl1->x / 64.0, -ctrl1->y / 64.0, - ctrl2->x / 64.0, -ctrl2->y / 64.0, - pt->x / 64.0, -pt->y / 64.0); - return 0; -} - -FT_UInt FTFont::getGlyphIndex(CharCode c, Unicode u) { - FT_UInt idx; - int j; - - idx = 0; // make gcc happy - switch (fontFile->mode) { - case ftFontModeUnicode: - idx = FT_Get_Char_Index(fontFile->face, (FT_ULong)u); - break; - case ftFontModeCodeMapDirect: - if (c <= 0xff) { - idx = (FT_UInt)fontFile->codeMap[c]; - } else { - idx = 0; - } - break; - case ftFontModeCIDToGIDMap: - if (fontFile->cidToGIDLen) { - if ((int)c < fontFile->cidToGIDLen) { - idx = (FT_UInt)fontFile->cidToGID[c]; - } else { - idx = (FT_UInt)0; - } - } else { - idx = (FT_UInt)c; - } - break; - case ftFontModeCFFCharset: -#if 1 //~ cff cid->gid map - { -#if FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 0 - CFF_Font *cff = (CFF_Font *)((TT_Face)fontFile->face)->extra.data; -#else - CFF_Font cff = (CFF_Font)((TT_Face)fontFile->face)->extra.data; -#endif - idx = 0; - for (j = 0; j < (int)cff->num_glyphs; ++j) { - if (cff->charset.sids[j] == c) { - idx = j; - break; - } - } - } -#endif - break; - case ftFontModeCID: - idx = c; - break; - } - return idx; -} - -#endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) diff --git a/pdf/xpdf/FTFont.h b/pdf/xpdf/FTFont.h deleted file mode 100644 index 8da5558..0000000 --- a/pdf/xpdf/FTFont.h +++ /dev/null @@ -1,134 +0,0 @@ -//======================================================================== -// -// FTFont.h -// -// An X wrapper for the FreeType font rasterizer. -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef FTFONT_H -#define FTFONT_H - -#include - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include "CharTypes.h" -#include "SFont.h" - -//------------------------------------------------------------------------ - -class FTFontEngine: public SFontEngine { -public: - - FTFontEngine(Display *displayA, Visual *visualA, int depthA, - Colormap colormapA, GBool aaA); - GBool isOk() { return ok; } - virtual ~FTFontEngine(); - -private: - - FT_Library lib; - GBool aa; - Gulong palette[5]; - GBool ok; - - friend class FTFontFile; - friend class FTFont; -}; - -//------------------------------------------------------------------------ - -enum FTFontIndexMode { - ftFontModeUnicode, - ftFontModeCodeMapDirect, - ftFontModeCIDToGIDMap, - ftFontModeCFFCharset, - ftFontModeCID -}; - -class FTFontFile: public SFontFile { -public: - - // 8-bit font, TrueType or Type 1/1C - FTFontFile(FTFontEngine *engineA, char *fontFileName, - char **fontEnc, Gushort *codeToGID); - - // CID font, TrueType - FTFontFile(FTFontEngine *engineA, char *fontFileName, - Gushort *cidToGIDA, int cidToGIDLenA, GBool embedded); - - // CID font, Type 0C (CFF) - FTFontFile(FTFontEngine *engineA, char *fontFileName, - GBool embedded); - - GBool isOk() { return ok; } - virtual ~FTFontFile(); - -private: - - FTFontEngine *engine; - FT_Face face; - FTFontIndexMode mode; - Guint *codeMap; - Gushort *cidToGID; - int cidToGIDLen; - GBool ok; - - friend class FTFont; -}; - -//------------------------------------------------------------------------ - -struct FTFontCacheTag { - Gushort code; - Gushort mru; // valid bit (0x8000) and MRU index - int x, y, w, h; // offset and size of glyph -}; - -class FTFont: public SFont { -public: - - FTFont(FTFontFile *fontFileA, double *m); - GBool isOk() { return ok; } - virtual ~FTFont(); - virtual GBool drawChar(Drawable d, int w, int h, GC gc, - int x, int y, int r, int g, int b, - CharCode c, Unicode u); - virtual GBool getCharPath(CharCode c, Unicode u, GfxState *state); - -private: - - Guchar *getGlyphPixmap(CharCode c, Unicode u, - int *x, int *y, int *w, int *h, - GBool *tempBitmap); - static int charPathMoveTo(FT_Vector *pt, void *state); - static int charPathLineTo(FT_Vector *pt, void *state); - static int charPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *state); - static int charPathCubicTo(FT_Vector *ctrl1, FT_Vector *ctrl2, - FT_Vector *pt, void *state); - FT_UInt getGlyphIndex(CharCode c, Unicode u); - - FTFontFile *fontFile; - FT_Size sizeObj; - XImage *image; - FT_Matrix matrix; - int glyphW, glyphH; // size of glyph pixmaps - int glyphSize; // size of glyph pixmaps, in bytes - Guchar *cache; // glyph pixmap cache - FTFontCacheTag *cacheTags; // cache tags, i.e., char codes - int cacheSets; // number of sets in cache - int cacheAssoc; // cache associativity (glyphs per set) - GBool ok; -}; - -#endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -#endif diff --git a/pdf/xpdf/FontFile.cc b/pdf/xpdf/FontFile.cc deleted file mode 100644 index 0c44422..0000000 --- a/pdf/xpdf/FontFile.cc +++ /dev/null @@ -1,4113 +0,0 @@ -//======================================================================== -// -// FontFile.cc -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include -#include -#include -#include -#include "gmem.h" -#include "GHash.h" -#include "Error.h" -#include "GlobalParams.h" -#include "CharCodeToUnicode.h" -#include "FontEncodingTables.h" -#include "FontFile.h" - -#include "CompactFontTables.h" - -//------------------------------------------------------------------------ - -static inline char *nextLine(char *line, char *end) { - while (line < end && *line != '\n' && *line != '\r') - ++line; - while (line < end && (*line == '\n' || *line == '\r')) - ++line; - return line; -} - -static char hexChars[17] = "0123456789ABCDEF"; - -//------------------------------------------------------------------------ -// FontFile -//------------------------------------------------------------------------ - -FontFile::FontFile() { -} - -FontFile::~FontFile() { -} - -//------------------------------------------------------------------------ -// Type1FontFile -//------------------------------------------------------------------------ - -Type1FontFile::Type1FontFile(char *file, int len) { - char *line, *line1, *p, *p2; - GBool haveEncoding; - char buf[256]; - char c; - int n, code, i, j; - - name = NULL; - encoding = (char **)gmalloc(256 * sizeof(char *)); - for (i = 0; i < 256; ++i) { - encoding[i] = NULL; - } - haveEncoding = gFalse; - - for (i = 1, line = file; - i <= 100 && line < file + len && !haveEncoding; - ++i) { - - // get font name - if (!strncmp(line, "/FontName", 9)) { - strncpy(buf, line, 255); - buf[255] = '\0'; - if ((p = strchr(buf+9, '/')) && - (p = strtok(p+1, " \t\n\r"))) { - name = copyString(p); - } - line = nextLine(line, file + len); - - // get encoding - } else if (!strncmp(line, "/Encoding StandardEncoding def", 30)) { - for (j = 0; j < 256; ++j) { - if (standardEncoding[j]) { - encoding[j] = copyString(standardEncoding[j]); - } - } - haveEncoding = gTrue; - } else if (!strncmp(line, "/Encoding 256 array", 19)) { - for (j = 0; j < 300; ++j) { - line1 = nextLine(line, file + len); - if ((n = line1 - line) > 255) { - n = 255; - } - strncpy(buf, line, n); - buf[n] = '\0'; - for (p = buf; *p == ' ' || *p == '\t'; ++p) ; - if (!strncmp(p, "dup", 3)) { - for (p += 3; *p == ' ' || *p == '\t'; ++p) ; - for (p2 = p; *p2 >= '0' && *p2 <= '9'; ++p2) ; - if (*p2) { - c = *p2; - *p2 = '\0'; - if ((code = atoi(p)) < 256) { - *p2 = c; - for (p = p2; *p == ' ' || *p == '\t'; ++p) ; - if (*p == '/') { - ++p; - for (p2 = p; *p2 && *p2 != ' ' && *p2 != '\t'; ++p2) ; - *p2 = '\0'; - encoding[code] = copyString(p); - } - } - } - } else { - if (strtok(buf, " \t") && - (p = strtok(NULL, " \t\n\r")) && !strcmp(p, "def")) { - break; - } - } - line = line1; - } - //~ check for getinterval/putinterval junk - haveEncoding = gTrue; - - } else { - line = nextLine(line, file + len); - } - } -} - -Type1FontFile::~Type1FontFile() { - int i; - - if (name) { - gfree(name); - } - for (i = 0; i < 256; ++i) { - gfree(encoding[i]); - } - gfree(encoding); -} - -//------------------------------------------------------------------------ -// Type1CFontFile -//------------------------------------------------------------------------ - -struct Type1CTopDict { - int version; - int notice; - int copyright; - int fullName; - int familyName; - int weight; - int isFixedPitch; - double italicAngle; - double underlinePosition; - double underlineThickness; - int paintType; - int charstringType; - double fontMatrix[6]; - int uniqueID; - double fontBBox[4]; - double strokeWidth; - int charset; - int encoding; - int charStrings; - int privateSize; - int privateOffset; - - //----- CIDFont entries - int registry; - int ordering; - int supplement; - int fdArrayOffset; - int fdSelectOffset; -}; - -struct Type1CPrivateDict { - GString *dictData; - int subrsOffset; - double defaultWidthX; - GBool defaultWidthXFP; - double nominalWidthX; - GBool nominalWidthXFP; -}; - -Type1CFontFile::Type1CFontFile(char *fileA, int lenA) { - int nameIdxPos, namePos, nameLen; - - file = (Guchar *)fileA; - len = lenA; - name = NULL; - encoding = NULL; - ok = gFalse; - - // some tools embed Type 1C fonts with an extra whitespace char at - // the beginning - if (len > 0 && file[0] != '\x01') { - ++file; - --len; - } - - // make sure the header exists - if (len < 4) { - return; - } - - // read name index (first font only) - nameIdxPos = file[2] & 0xff; - if ((namePos = getIndexValPos(nameIdxPos, 0, &nameLen)) < 0) { - return; - } - name = new GString((char *)&file[namePos], nameLen); - - topDictIdxPos = getIndexEnd(nameIdxPos); - stringIdxPos = getIndexEnd(topDictIdxPos); - gsubrIdxPos = getIndexEnd(stringIdxPos); - - ok = gTrue; -} - -Type1CFontFile::~Type1CFontFile() { - int i; - - delete name; - if (encoding) { - for (i = 0; i < 256; ++i) { - gfree(encoding[i]); - } - gfree(encoding); - } -} - -char *Type1CFontFile::getName() { - return name->getCString(); -} - -char **Type1CFontFile::getEncoding() { - if (!encoding) { - readEncoding(); - } - return encoding; -} - -void Type1CFontFile::readEncoding() { - char buf[256]; - int idxPos, idxLen, pos; - int nGlyphs; - int nCodes, nRanges, nLeft, nSups; - Gushort *glyphNames; - int charset, enc, charstrings; - int encFormat; - int c, sid; - double x; - GBool isFP; - int key; - int i, j; - - encoding = (char **)gmalloc(256 * sizeof(char *)); - for (i = 0; i < 256; ++i) { - encoding[i] = NULL; - } - - // read top dict (first font only) - if ((idxPos = getIndexValPos(topDictIdxPos, 0, &idxLen)) < 0) { - return; - } - charset = enc = charstrings = 0; - i = 0; - pos = idxPos; - while (pos < idxPos + idxLen) { - if (file[pos] <= 27 || file[pos] == 31) { - key = file[pos++]; - if (key == 0x0c) { - if (pos >= idxPos + idxLen) { - return; - } - key = (key << 8) | file[pos++]; - } - if (key == 0x0f) { // charset - charset = (int)op[0]; - } else if (key == 0x10) { // encoding - enc = (int)op[0]; - } else if (key == 0x11) { // charstrings - charstrings = (int)op[0]; - } - i = 0; - } else { - x = getNum(&pos, &isFP); - if (i < 48) { - op[i++] = x; - } - } - } - - // get number of glyphs from charstrings index - nGlyphs = getIndexLen(charstrings); - - // read charset (GID -> name mapping) - glyphNames = readCharset(charset, nGlyphs); - - // read encoding (GID -> code mapping) - if (enc == 0) { - for (i = 0; i < 256; ++i) { - if (standardEncoding[i]) { - encoding[i] = copyString(standardEncoding[i]); - } - } - } else if (enc == 1) { - for (i = 0; i < 256; ++i) { - if (expertEncoding[i]) { - encoding[i] = copyString(expertEncoding[i]); - } - } - } else { - pos = enc; - if (pos < 0 || pos >= len) { - goto err0; - } - encFormat = file[pos++]; - if ((encFormat & 0x7f) == 0) { - if (pos >= len) { - goto err0; - } - nCodes = 1 + file[pos++]; - if (nCodes > nGlyphs) { - nCodes = nGlyphs; - } - if (pos + nCodes - 1 > len) { - goto err0; - } - for (i = 1; i < nCodes; ++i) { - c = file[pos++]; - if (encoding[c]) { - gfree(encoding[c]); - } - encoding[c] = copyString(getString(glyphNames[i], buf)); - } - } else if ((encFormat & 0x7f) == 1) { - if (pos >= len) { - goto err0; - } - nRanges = file[pos++]; - if (pos + 2 * nRanges > len) { - goto err0; - } - nCodes = 1; - for (i = 0; i < nRanges; ++i) { - c = file[pos++]; - nLeft = file[pos++]; - for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) { - if (c < 256) { - if (encoding[c]) { - gfree(encoding[c]); - } - encoding[c] = copyString(getString(glyphNames[nCodes], buf)); - } - ++nCodes; - ++c; - } - } - } - if (encFormat & 0x80) { - if (pos >= len) { - goto err0; - } - nSups = file[pos++]; - if (pos + nSups * 3 > len) { - goto err0; - } - for (i = 0; i < nSups; ++i) { - c = file[pos++]; - sid = getWord(pos, 2); - pos += 2; - if (encoding[c]) { - gfree(encoding[c]); - } - encoding[c] = copyString(getString(sid, buf)); - } - } - } - - err0: - if (charset < 0 || charset > 2) { - gfree(glyphNames); - } -} - -void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA, - void *outputStreamA) { - Type1CTopDict dict; - Type1CPrivateDict privateDict; - char buf[512], eBuf[256]; - int idxPos, idxLen, pos; - int nGlyphs, nCodes, nRanges, nLeft, nSups; - Gushort *glyphNames; - int encFormat, nCharStrings; - int c, sid; - int i, j; - - outputFunc = outputFuncA; - outputStream = outputStreamA; - - // read top dict (first font only) - readTopDict(&dict); - - // write header and font dictionary, up to encoding - (*outputFunc)(outputStream, "%!FontType1-1.0: ", 17); - (*outputFunc)(outputStream, name->getCString(), name->getLength()); - if (dict.version != 0) { - getString(dict.version, buf); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "\n", 1); - // the dictionary needs room for 12 entries: the following 9, plus - // Private and CharStrings (in the eexec section) and FID (which is - // added by definefont) - (*outputFunc)(outputStream, "12 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontInfo 10 dict dup begin\n", 28); - if (dict.version != 0) { - (*outputFunc)(outputStream, "/version (", 10); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (dict.notice != 0) { - getString(dict.notice, buf); - (*outputFunc)(outputStream, "/Notice (", 9); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (dict.copyright != 0) { - getString(dict.copyright, buf); - (*outputFunc)(outputStream, "/Copyright (", 12); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (dict.fullName != 0) { - getString(dict.fullName, buf); - (*outputFunc)(outputStream, "/FullName (", 11); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (dict.familyName != 0) { - getString(dict.familyName, buf); - (*outputFunc)(outputStream, "/FamilyName (", 13); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (dict.weight != 0) { - getString(dict.weight, buf); - (*outputFunc)(outputStream, "/Weight (", 9); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") readonly def\n", 15); - } - if (dict.isFixedPitch) { - (*outputFunc)(outputStream, "/isFixedPitch true def\n", 23); - } else { - (*outputFunc)(outputStream, "/isFixedPitch false def\n", 24); - } - sprintf(buf, "/ItalicAngle %g def\n", dict.italicAngle); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/UnderlinePosition %g def\n", dict.underlinePosition); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/UnderlineThickness %g def\n", dict.underlineThickness); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "end readonly def\n", 17); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, name->getCString(), name->getLength()); - (*outputFunc)(outputStream, " def\n", 5); - sprintf(buf, "/PaintType %d def\n", dict.paintType); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FontType 1 def\n", 16); - sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] readonly def\n", - dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2], - dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/FontBBox [%g %g %g %g] readonly def\n", - dict.fontBBox[0], dict.fontBBox[1], - dict.fontBBox[2], dict.fontBBox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/StrokeWidth %g def\n", dict.strokeWidth); - (*outputFunc)(outputStream, buf, strlen(buf)); - if (dict.uniqueID != 0) { - sprintf(buf, "/UniqueID %d def\n", dict.uniqueID); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - - // get number of glyphs from charstrings index - nGlyphs = getIndexLen(dict.charStrings); - - // read charset - glyphNames = readCharset(dict.charset, nGlyphs); - - // read encoding (glyph -> code mapping), write Type 1 encoding - (*outputFunc)(outputStream, "/Encoding ", 10); - if (dict.encoding == 0) { - (*outputFunc)(outputStream, "StandardEncoding def\n", 21); - } else { - (*outputFunc)(outputStream, "256 array\n", 10); - (*outputFunc)(outputStream, - "0 1 255 {1 index exch /.notdef put} for\n", 40); - if (dict.encoding == 1) { - for (i = 0; i < 256; ++i) { - if (expertEncoding[i]) { - sprintf(buf, "dup %d /%s put\n", i, expertEncoding[i]); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - } - } else { - pos = dict.encoding; - if (pos < 0 || pos >= len) { - goto err0; - } - encFormat = file[pos++]; - if ((encFormat & 0x7f) == 0) { - if (pos >= len) { - goto err0; - } - nCodes = 1 + file[pos++]; - if (nCodes > nGlyphs) { - nCodes = nGlyphs; - } - if (pos + nCodes - 1 > len) { - goto err0; - } - for (i = 1; i < nCodes; ++i) { - c = file[pos++]; - sprintf(buf, "dup %d /", c); - (*outputFunc)(outputStream, buf, strlen(buf)); - getString(glyphNames[i], buf); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, " put\n", 5); - } - } else if ((encFormat & 0x7f) == 1) { - if (pos >= len) { - goto err0; - } - nRanges = file[pos++]; - if (pos + 2 * nRanges > len) { - goto err0; - } - nCodes = 1; - for (i = 0; i < nRanges; ++i) { - c = file[pos++]; - nLeft = file[pos++]; - for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) { - sprintf(buf, "dup %d /", c); - (*outputFunc)(outputStream, buf, strlen(buf)); - getString(glyphNames[nCodes], buf); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, " put\n", 5); - ++nCodes; - ++c; - } - } - } - if (encFormat & 0x80) { - if (pos >= len) { - goto err0; - } - nSups = file[pos++]; - if (pos + nSups * 3 > len) { - goto err0; - } - for (i = 0; i < nSups; ++i) { - c = file[pos++]; - sid = getWord(pos, 2); - pos += 2; - sprintf(buf, "dup %d /", c); - (*outputFunc)(outputStream, buf, strlen(buf)); - getString(sid, buf); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, " put\n", 5); - } - } - err0:; - } - (*outputFunc)(outputStream, "readonly def\n", 13); - } - (*outputFunc)(outputStream, "currentdict end\n", 16); - - // start the binary section - (*outputFunc)(outputStream, "currentfile eexec\n", 18); - r1 = 55665; - line = 0; - - // get private dictionary - eexecWrite("\x83\xca\x73\xd5"); - eexecWrite("dup /Private 32 dict dup begin\n"); - eexecWrite("/RD {string currentfile exch readstring pop} executeonly def\n"); - eexecWrite("/ND {noaccess def} executeonly def\n"); - eexecWrite("/NP {noaccess put} executeonly def\n"); - eexecWrite("/MinFeature {16 16} def\n"); - eexecWrite("/password 5839 def\n"); - readPrivateDict(&privateDict, dict.privateOffset, dict.privateSize); - eexecWrite(privateDict.dictData->getCString()); - defaultWidthX = privateDict.defaultWidthX; - defaultWidthXFP = privateDict.defaultWidthXFP; - nominalWidthX = privateDict.nominalWidthX; - nominalWidthXFP = privateDict.nominalWidthXFP; - - // set up subroutines - subrIdxPos = privateDict.subrsOffset; - i = getIndexLen(gsubrIdxPos); - gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768; - i = getIndexLen(subrIdxPos); - subrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768; - - // get CharStrings - nCharStrings = getIndexLen(dict.charStrings); - sprintf(eBuf, "2 index /CharStrings %d dict dup begin\n", nCharStrings); - eexecWrite(eBuf); - for (i = 0; i < nCharStrings; ++i) { - if ((idxPos = getIndexValPos(dict.charStrings, i, &idxLen)) >= 0) { - eexecCvtGlyph(getString(glyphNames[i], buf), idxPos, idxLen); - } - } - eexecWrite("end\n"); - eexecWrite("end\n"); - eexecWrite("readonly put\n"); - eexecWrite("noaccess put\n"); - eexecWrite("dup /FontName get exch definefont pop\n"); - eexecWrite("mark currentfile closefile\n"); - - // trailer - if (line > 0) { - (*outputFunc)(outputStream, "\n", 1); - } - for (i = 0; i < 8; ++i) { - (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); - } - (*outputFunc)(outputStream, "cleartomark\n", 12); - - // clean up - delete privateDict.dictData; - if (dict.charset > 2) { - gfree(glyphNames); - } -} - -void Type1CFontFile::convertToCIDType0(char *psName, - FontFileOutputFunc outputFuncA, - void *outputStreamA) { - Type1CTopDict dict; - Type1CPrivateDict *privateDicts; - GString *charStrings; - int *charStringOffsets; - Gushort *charset; - int *cidMap; - Guchar *fdSelect; - int idxPos, idxLen, pos; - char buf[512], buf2[16]; - int nGlyphs, nCIDs, gdBytes, nFDs; - int fdSelectFmt, nRanges, gid0, gid1, fd, offset; - int key; - double x; - GBool isFP; - int i, j, k, n; - - outputFunc = outputFuncA; - outputStream = outputStreamA; - - (*outputFunc)(outputStream, "/CIDInit /ProcSet findresource begin\n", 37); - - // read top dict (first font only) - readTopDict(&dict); - - // read the FDArray dictionaries and Private dictionaries - if (dict.fdArrayOffset == 0) { - nFDs = 1; - privateDicts = (Type1CPrivateDict *) - gmalloc(nFDs * sizeof(Type1CPrivateDict)); - privateDicts[0].dictData = new GString(); - privateDicts[0].subrsOffset = 0; - privateDicts[0].defaultWidthX = 0; - privateDicts[0].defaultWidthXFP = gFalse; - privateDicts[0].nominalWidthX = 0; - privateDicts[0].nominalWidthXFP = gFalse; - } else { - if ((nFDs = getIndexLen(dict.fdArrayOffset)) < 0) { - goto err0; - } - privateDicts = (Type1CPrivateDict *) - gmalloc(nFDs * sizeof(Type1CPrivateDict)); - for (i = 0; i < nFDs; ++i) { - privateDicts[i].dictData = NULL; - } - for (i = 0; i < nFDs; ++i) { - privateDicts[i].dictData = NULL; - if ((idxPos = getIndexValPos(dict.fdArrayOffset, i, &idxLen)) < 0) { - goto err1; - } - pos = idxPos; - j = 0; - while (pos < idxPos + idxLen) { - if (file[pos] <= 27 || file[pos] == 31) { - key = file[pos++]; - if (key == 0x0c) { - if (pos >= idxPos + idxLen) { - goto err1; - } - key = (key << 8) | file[pos++]; - } - if (key == 0x0012) { - readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]); - } - j = 0; - } else { - x = getNum(&pos, &isFP); - if (j < 48) { - op[j] = x; - fp[j++] = isFP; - } - } - } - if (!privateDicts[i].dictData) { - privateDicts[i].dictData = new GString(); - privateDicts[i].subrsOffset = 0; - privateDicts[i].defaultWidthX = 0; - privateDicts[i].defaultWidthXFP = gFalse; - privateDicts[i].nominalWidthX = 0; - privateDicts[i].nominalWidthXFP = gFalse; - } - } - } - - // get the glyph count - if ((nGlyphs = getIndexLen(dict.charStrings)) < 0) { - goto err1; - } - - // read the FDSelect table - fdSelect = (Guchar *)gmalloc(nGlyphs); - if (dict.fdSelectOffset == 0) { - for (i = 0; i < nGlyphs; ++i) { - fdSelect[i] = 0; - } - } else { - pos = dict.fdSelectOffset; - if (pos < 0 || pos >= len) { - goto err2; - } - fdSelectFmt = file[pos++]; - if (fdSelectFmt == 0) { - if (pos + nGlyphs > len) { - goto err2; - } - memcpy(fdSelect, file + pos, nGlyphs); - } else if (fdSelectFmt == 3) { - if (pos + 4 > len) { - goto err2; - } - nRanges = getWord(pos, 2); - pos += 2; - gid0 = getWord(pos, 2); - pos += 2; - if (pos + nRanges * 3 > len) { - goto err2; - } - for (i = 1; i <= nRanges; ++i) { - fd = file[pos++]; - gid1 = getWord(pos, 2); - pos += 2; - for (j = gid0; j < gid1; ++j) { - fdSelect[j] = fd; - } - gid0 = gid1; - } - } else { - error(-1, "Unknown FDSelect table format in CID font"); - for (i = 0; i < nGlyphs; ++i) { - fdSelect[i] = 0; - } - } - } - - // read the charset, compute the CID-to-GID mapping - charset = readCharset(dict.charset, nGlyphs); - nCIDs = 0; - for (i = 0; i < nGlyphs; ++i) { - if (charset[i] >= nCIDs) { - nCIDs = charset[i] + 1; - } - } - cidMap = (int *)gmalloc(nCIDs * sizeof(int)); - for (i = 0; i < nCIDs; ++i) { - cidMap[i] = -1; - } - for (i = 0; i < nGlyphs; ++i) { - cidMap[charset[i]] = i; - } - - // set up global subroutines - i = getIndexLen(gsubrIdxPos); - gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768; - - // build the charstrings - charStrings = new GString(); - charStringOffsets = (int *)gmalloc((nCIDs + 1) * sizeof(int)); - for (i = 0; i < nCIDs; ++i) { - charStringOffsets[i] = charStrings->getLength(); - if (cidMap[i] >= 0) { - if ((idxPos = getIndexValPos(dict.charStrings, - cidMap[i], &idxLen)) >= 0) { - j = fdSelect[cidMap[i]]; - defaultWidthX = privateDicts[j].defaultWidthX; - defaultWidthXFP = privateDicts[j].defaultWidthXFP; - nominalWidthX = privateDicts[j].nominalWidthX; - nominalWidthXFP = privateDicts[j].nominalWidthXFP; - subrIdxPos = privateDicts[j].subrsOffset; - k = getIndexLen(subrIdxPos); - subrBias = (k < 1240) ? 107 : (k < 33900) ? 1131 : 32768; - cvtGlyph(idxPos, idxLen, gTrue); - charStrings->append(charBuf); - delete charBuf; - } - } - } - charStringOffsets[nCIDs] = charStrings->getLength(); - - // compute gdBytes = number of bytes needed for charstring offsets - // (offset size needs to account for the charstring offset table, - // with a worst case of five bytes per entry, plus the charstrings - // themselves) - i = (nCIDs + 1) * 5 + charStrings->getLength(); - if (i < 0x100) { - gdBytes = 1; - } else if (i < 0x10000) { - gdBytes = 2; - } else if (i < 0x1000000) { - gdBytes = 3; - } else { - gdBytes = 4; - } - - // begin the font dictionary - (*outputFunc)(outputStream, "20 dict begin\n", 14); - (*outputFunc)(outputStream, "/CIDFontName /", 14); - (*outputFunc)(outputStream, psName, strlen(psName)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/CIDFontType 0 def\n", 19); - (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); - if (dict.registry > 0 && dict.ordering > 0) { - getString(dict.registry, buf); - (*outputFunc)(outputStream, " /Registry (", 13); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") def\n", 6); - getString(dict.ordering, buf); - (*outputFunc)(outputStream, " /Ordering (", 13); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, ") def\n", 6); - } else { - (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); - (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); - } - sprintf(buf, " /Supplement %d def\n", dict.supplement); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "end def\n", 8); - sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", - dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2], - dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/FontBBox [%g %g %g %g] def\n", - dict.fontBBox[0], dict.fontBBox[1], - dict.fontBBox[2], dict.fontBBox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FontInfo 1 dict dup begin\n", 27); - (*outputFunc)(outputStream, " /FSType 8 def\n", 16); - (*outputFunc)(outputStream, "end def\n", 8); - - // CIDFont-specific entries - sprintf(buf, "/CIDCount %d def\n", nCIDs); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FDBytes 1 def\n", 15); - sprintf(buf, "/GDBytes %d def\n", gdBytes); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/CIDMapOffset 0 def\n", 20); - if (dict.paintType != 0) { - sprintf(buf, "/PaintType %d def\n", dict.paintType); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/StrokeWidth %g def\n", dict.strokeWidth); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - - // FDArray entry - sprintf(buf, "/FDArray %d array\n", nFDs); - (*outputFunc)(outputStream, buf, strlen(buf)); - for (i = 0; i < nFDs; ++i) { - sprintf(buf, "dup %d 10 dict begin\n", i); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FontType 1 def\n", 16); - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - sprintf(buf, "/PaintType %d def\n", dict.paintType); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/Private 32 dict begin\n", 23); - (*outputFunc)(outputStream, privateDicts[i].dictData->getCString(), - privateDicts[i].dictData->getLength()); - (*outputFunc)(outputStream, "currentdict end def\n", 20); - (*outputFunc)(outputStream, "currentdict end put\n", 20); - } - (*outputFunc)(outputStream, "def\n", 4); - - // start the binary section - offset = (nCIDs + 1) * (1 + gdBytes); - sprintf(buf, "(Hex) %d StartData\n", - offset + charStrings->getLength()); - (*outputFunc)(outputStream, buf, strlen(buf)); - - // write the charstring offset (CIDMap) table - for (i = 0; i <= nCIDs; i += 6) { - for (j = 0; j < 6 && i+j <= nCIDs; ++j) { - if (i+j < nCIDs && cidMap[i+j] >= 0) { - buf[0] = (char)fdSelect[cidMap[i+j]]; - } else { - buf[0] = (char)0; - } - n = offset + charStringOffsets[i+j]; - for (k = gdBytes; k >= 1; --k) { - buf[k] = (char)(n & 0xff); - n >>= 8; - } - for (k = 0; k <= gdBytes; ++k) { - sprintf(buf2, "%02x", buf[k] & 0xff); - (*outputFunc)(outputStream, buf2, 2); - } - } - (*outputFunc)(outputStream, "\n", 1); - } - - // write the charstring data - n = charStrings->getLength(); - for (i = 0; i < n; i += 32) { - for (j = 0; j < 32 && i+j < n; ++j) { - sprintf(buf, "%02x", charStrings->getChar(i+j) & 0xff); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (i + 32 >= n) { - (*outputFunc)(outputStream, ">", 1); - } - (*outputFunc)(outputStream, "\n", 1); - } - - gfree(charStringOffsets); - delete charStrings; - gfree(cidMap); - gfree(charset); - err2: - gfree(fdSelect); - err1: - for (i = 0; i < nFDs; ++i) { - if (privateDicts[i].dictData) { - delete privateDicts[i].dictData; - } - } - gfree(privateDicts); - err0:; -} - -void Type1CFontFile::convertToType0(char *psName, - FontFileOutputFunc outputFuncA, - void *outputStreamA) { - Type1CTopDict dict; - Type1CPrivateDict *privateDicts; - Gushort *charset; - int *cidMap; - Guchar *fdSelect; - int idxPos, idxLen, pos; - char buf[512]; - char eBuf[256]; - int nGlyphs, nCIDs, nFDs; - int fdSelectFmt, nRanges, gid0, gid1, fd; - int key; - double x; - GBool isFP; - int i, j; - - outputFunc = outputFuncA; - outputStream = outputStreamA; - - // read top dict (first font only) - readTopDict(&dict); - - // read the FDArray dictionaries and Private dictionaries - if (dict.fdArrayOffset == 0) { - nFDs = 1; - privateDicts = (Type1CPrivateDict *) - gmalloc(nFDs * sizeof(Type1CPrivateDict)); - privateDicts[0].dictData = new GString(); - privateDicts[0].subrsOffset = 0; - privateDicts[0].defaultWidthX = 0; - privateDicts[0].defaultWidthXFP = gFalse; - privateDicts[0].nominalWidthX = 0; - privateDicts[0].nominalWidthXFP = gFalse; - } else { - if ((nFDs = getIndexLen(dict.fdArrayOffset)) < 0) { - goto err0; - } - privateDicts = (Type1CPrivateDict *) - gmalloc(nFDs * sizeof(Type1CPrivateDict)); - for (i = 0; i < nFDs; ++i) { - privateDicts[i].dictData = NULL; - } - for (i = 0; i < nFDs; ++i) { - privateDicts[i].dictData = NULL; - if ((idxPos = getIndexValPos(dict.fdArrayOffset, i, &idxLen)) < 0) { - goto err1; - } - pos = idxPos; - j = 0; - while (pos < idxPos + idxLen) { - if (file[pos] <= 27 || file[pos] == 31) { - key = file[pos++]; - if (key == 0x0c) { - if (pos >= idxPos + idxLen) { - goto err1; - } - key = (key << 8) | file[pos++]; - } - if (key == 0x0012) { - readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]); - } - j = 0; - } else { - x = getNum(&pos, &isFP); - if (j < 48) { - op[j] = x; - fp[j++] = isFP; - } - } - } - if (!privateDicts[i].dictData) { - privateDicts[i].dictData = new GString(); - privateDicts[i].subrsOffset = 0; - privateDicts[i].defaultWidthX = 0; - privateDicts[i].defaultWidthXFP = gFalse; - privateDicts[i].nominalWidthX = 0; - privateDicts[i].nominalWidthXFP = gFalse; - } - } - } - - // get the glyph count - if ((nGlyphs = getIndexLen(dict.charStrings)) < 0) { - goto err1; - } - - // read the FDSelect table - fdSelect = (Guchar *)gmalloc(nGlyphs); - if (dict.fdSelectOffset == 0) { - for (i = 0; i < nGlyphs; ++i) { - fdSelect[i] = 0; - } - } else { - pos = dict.fdSelectOffset; - if (pos < 0 || pos >= len) { - goto err2; - } - fdSelectFmt = file[pos++]; - if (fdSelectFmt == 0) { - if (pos + nGlyphs > len) { - goto err2; - } - memcpy(fdSelect, file + pos, nGlyphs); - } else if (fdSelectFmt == 3) { - if (pos + 4 > len) { - goto err2; - } - nRanges = getWord(pos, 2); - pos += 2; - gid0 = getWord(pos, 2); - pos += 2; - if (pos + nRanges * 3 > len) { - goto err2; - } - for (i = 1; i <= nRanges; ++i) { - fd = file[pos++]; - gid1 = getWord(pos, 2); - pos += 2; - for (j = gid0; j < gid1; ++j) { - fdSelect[j] = fd; - } - gid0 = gid1; - } - } else { - error(-1, "Unknown FDSelect table format in CID font"); - for (i = 0; i < nGlyphs; ++i) { - fdSelect[i] = 0; - } - } - } - - // read the charset, compute the CID-to-GID mapping - charset = readCharset(dict.charset, nGlyphs); - nCIDs = 0; - for (i = 0; i < nGlyphs; ++i) { - if (charset[i] >= nCIDs) { - nCIDs = charset[i] + 1; - } - } - cidMap = (int *)gmalloc(nCIDs * sizeof(int)); - for (i = 0; i < nCIDs; ++i) { - cidMap[i] = -1; - } - for (i = 0; i < nGlyphs; ++i) { - cidMap[charset[i]] = i; - } - - // set up global subroutines - i = getIndexLen(gsubrIdxPos); - gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768; - - // write the descendant Type 1 fonts - for (i = 0; i < nCIDs; i += 256) { - - //~ this assumes that all CIDs in this block have the same FD -- - //~ to handle multiple FDs correctly, need to somehow divide the - //~ font up by FD - fd = 0; - for (j = 0; j < 256 && i+j < nCIDs; ++j) { - if (cidMap[i+j] >= 0) { - fd = fdSelect[cidMap[i+j]]; - break; - } - } - - // font dictionary (unencrypted section) - (*outputFunc)(outputStream, "16 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, psName, strlen(psName)); - sprintf(buf, "_%02x def\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FontType 1 def\n", 16); - sprintf(buf, "/FontMatrix [%g %g %g %g %g %g] def\n", - dict.fontMatrix[0], dict.fontMatrix[1], dict.fontMatrix[2], - dict.fontMatrix[3], dict.fontMatrix[4], dict.fontMatrix[5]); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/FontBBox [%g %g %g %g] def\n", - dict.fontBBox[0], dict.fontBBox[1], - dict.fontBBox[2], dict.fontBBox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, "/PaintType %d def\n", dict.paintType); - (*outputFunc)(outputStream, buf, strlen(buf)); - if (dict.paintType != 0) { - sprintf(buf, "/StrokeWidth %g def\n", dict.strokeWidth); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); - for (j = 0; j < 256 && i+j < nCIDs; ++j) { - sprintf(buf, "dup %d /c%02x put\n", j, j); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (j < 256) { - sprintf(buf, "%d 1 255 { 1 index exch /.notdef put } for\n", j); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "readonly def\n", 13); - (*outputFunc)(outputStream, "currentdict end\n", 16); - - // start the binary section - (*outputFunc)(outputStream, "currentfile eexec\n", 18); - r1 = 55665; - line = 0; - - // start the private dictionary - eexecWrite("\x83\xca\x73\xd5"); - eexecWrite("dup /Private 32 dict dup begin\n"); - eexecWrite("/RD {string currentfile exch readstring pop} executeonly def\n"); - eexecWrite("/ND {noaccess def} executeonly def\n"); - eexecWrite("/NP {noaccess put} executeonly def\n"); - eexecWrite("/MinFeature {16 16} def\n"); - eexecWrite("/password 5839 def\n"); - eexecWrite(privateDicts[fd].dictData->getCString()); - defaultWidthX = privateDicts[fd].defaultWidthX; - defaultWidthXFP = privateDicts[fd].defaultWidthXFP; - nominalWidthX = privateDicts[fd].nominalWidthX; - nominalWidthXFP = privateDicts[fd].nominalWidthXFP; - - // set up the subroutines - subrIdxPos = privateDicts[fd].subrsOffset; - j = getIndexLen(subrIdxPos); - subrBias = (j < 1240) ? 107 : (j < 33900) ? 1131 : 32768; - - // start the CharStrings - sprintf(eBuf, "2 index /CharStrings 256 dict dup begin\n"); - eexecWrite(eBuf); - - // write the .notdef CharString - if ((idxPos = getIndexValPos(dict.charStrings, 0, &idxLen)) >= 0) { - eexecCvtGlyph(".notdef", idxPos, idxLen); - } - - // write the CharStrings - for (j = 0; j < 256 && i+j < nCIDs; ++j) { - if (cidMap[i+j] >= 0) { - if ((idxPos = getIndexValPos(dict.charStrings, - cidMap[i+j], &idxLen)) >= 0) { - sprintf(buf, "c%02x", j); - eexecCvtGlyph(buf, idxPos, idxLen); - } - } - } - eexecWrite("end\n"); - eexecWrite("end\n"); - eexecWrite("readonly put\n"); - eexecWrite("noaccess put\n"); - eexecWrite("dup /FontName get exch definefont pop\n"); - eexecWrite("mark currentfile closefile\n"); - - // trailer - if (line > 0) { - (*outputFunc)(outputStream, "\n", 1); - } - for (j = 0; j < 8; ++j) { - (*outputFunc)(outputStream, "0000000000000000000000000000000000000000000000000000000000000000\n", 65); - } - (*outputFunc)(outputStream, "cleartomark\n", 12); - } - - // write the Type 0 parent font - (*outputFunc)(outputStream, "16 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, psName, strlen(psName)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/FontType 0 def\n", 16); - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); - (*outputFunc)(outputStream, "/Encoding [\n", 12); - for (i = 0; i < nCIDs; i += 256) { - sprintf(buf, "%d\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - (*outputFunc)(outputStream, "/FDepVector [\n", 14); - for (i = 0; i < nCIDs; i += 256) { - (*outputFunc)(outputStream, "/", 1); - (*outputFunc)(outputStream, psName, strlen(psName)); - sprintf(buf, "_%02x findfont\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); - - // clean up - gfree(cidMap); - gfree(charset); - err2: - gfree(fdSelect); - err1: - for (i = 0; i < nFDs; ++i) { - if (privateDicts[i].dictData) { - delete privateDicts[i].dictData; - } - } - gfree(privateDicts); - err0:; -} - -void Type1CFontFile::readTopDict(Type1CTopDict *dict) { - int idxPos, idxLen, pos; - double x; - GBool isFP; - int key; - int i; - - dict->version = 0; - dict->notice = 0; - dict->copyright = 0; - dict->fullName = 0; - dict->familyName = 0; - dict->weight = 0; - dict->isFixedPitch = 0; - dict->italicAngle = 0; - dict->underlinePosition = -100; - dict->underlineThickness = 50; - dict->paintType = 0; - dict->charstringType = 2; - dict->fontMatrix[0] = 0.001; - dict->fontMatrix[1] = 0; - dict->fontMatrix[2] = 0; - dict->fontMatrix[3] = 0.001; - dict->fontMatrix[4] = 0; - dict->fontMatrix[5] = 0; - dict->uniqueID = 0; - dict->fontBBox[0] = 0; - dict->fontBBox[1] = 0; - dict->fontBBox[2] = 0; - dict->fontBBox[3] = 0; - dict->strokeWidth = 0; - dict->charset = 0; - dict->encoding = 0; - dict->charStrings = 0; - dict->privateSize = 0; - dict->privateOffset = 0; - dict->registry = 0; - dict->ordering = 0; - dict->supplement = 0; - dict->fdArrayOffset = 0; - dict->fdSelectOffset = 0; - if ((idxPos = getIndexValPos(topDictIdxPos, 0, &idxLen)) < 0) { - return; - } - i = 0; - pos = idxPos; - while (pos < idxPos + idxLen) { - if (file[pos] <= 27 || file[pos] == 31) { - key = file[pos++]; - if (key == 0x0c) { - if (pos >= idxPos + idxLen) { - break; - } - key = (key << 8) | file[pos++]; - } - switch (key) { - case 0x0000: dict->version = (int)op[0]; break; - case 0x0001: dict->notice = (int)op[0]; break; - case 0x0c00: dict->copyright = (int)op[0]; break; - case 0x0002: dict->fullName = (int)op[0]; break; - case 0x0003: dict->familyName = (int)op[0]; break; - case 0x0004: dict->weight = (int)op[0]; break; - case 0x0c01: dict->isFixedPitch = (int)op[0]; break; - case 0x0c02: dict->italicAngle = op[0]; break; - case 0x0c03: dict->underlinePosition = op[0]; break; - case 0x0c04: dict->underlineThickness = op[0]; break; - case 0x0c05: dict->paintType = (int)op[0]; break; - case 0x0c06: dict->charstringType = (int)op[0]; break; - case 0x0c07: dict->fontMatrix[0] = op[0]; - dict->fontMatrix[1] = op[1]; - dict->fontMatrix[2] = op[2]; - dict->fontMatrix[3] = op[3]; - dict->fontMatrix[4] = op[4]; - dict->fontMatrix[5] = op[5]; break; - case 0x000d: dict->uniqueID = (int)op[0]; break; - case 0x0005: dict->fontBBox[0] = op[0]; - dict->fontBBox[1] = op[1]; - dict->fontBBox[2] = op[2]; - dict->fontBBox[3] = op[3]; break; - case 0x0c08: dict->strokeWidth = op[0]; break; - case 0x000f: dict->charset = (int)op[0]; break; - case 0x0010: dict->encoding = (int)op[0]; break; - case 0x0011: dict->charStrings = (int)op[0]; break; - case 0x0012: dict->privateSize = (int)op[0]; - dict->privateOffset = (int)op[1]; break; - case 0x0c1e: dict->registry = (int)op[0]; - dict->ordering = (int)op[1]; - dict->supplement = (int)op[2]; break; - case 0x0c24: dict->fdArrayOffset = (int)op[0]; break; - case 0x0c25: dict->fdSelectOffset = (int)op[0]; break; - } - i = 0; - } else { - x = getNum(&pos, &isFP); - if (i < 48) { - op[i] = x; - fp[i++] = isFP; - } - } - } -} - -void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict, - int offset, int size) { - int pos; - char eBuf[256]; - int key; - double x; - GBool isFP; - int i; - - privateDict->dictData = new GString(); - privateDict->subrsOffset = 0; - privateDict->defaultWidthX = 0; - privateDict->defaultWidthXFP = gFalse; - privateDict->nominalWidthX = 0; - privateDict->nominalWidthXFP = gFalse; - if (offset < 0 || offset + size > len) { - return; - } - pos = offset; - i = 0; - while (pos < offset + size) { - if (file[pos] <= 27 || file[pos] == 31) { - key = file[pos++]; - if (key == 0x0c) { - if (pos >= offset + size) { - break; - } - key = (key << 8) | file[pos++]; - } - switch (key) { - case 0x0006: - getDeltaInt(eBuf, "BlueValues", op, i); - privateDict->dictData->append(eBuf); - break; - case 0x0007: - getDeltaInt(eBuf, "OtherBlues", op, i); - privateDict->dictData->append(eBuf); - break; - case 0x0008: - getDeltaInt(eBuf, "FamilyBlues", op, i); - privateDict->dictData->append(eBuf); - break; - case 0x0009: - getDeltaInt(eBuf, "FamilyOtherBlues", op, i); - privateDict->dictData->append(eBuf); - break; - case 0x0c09: - sprintf(eBuf, "/BlueScale %g def\n", op[0]); - privateDict->dictData->append(eBuf); - break; - case 0x0c0a: - sprintf(eBuf, "/BlueShift %d def\n", (int)op[0]); - privateDict->dictData->append(eBuf); - break; - case 0x0c0b: - sprintf(eBuf, "/BlueFuzz %d def\n", (int)op[0]); - privateDict->dictData->append(eBuf); - break; - case 0x000a: - sprintf(eBuf, "/StdHW [%g] def\n", op[0]); - privateDict->dictData->append(eBuf); - break; - case 0x000b: - sprintf(eBuf, "/StdVW [%g] def\n", op[0]); - privateDict->dictData->append(eBuf); - break; - case 0x0c0c: - getDeltaReal(eBuf, "StemSnapH", op, i); - privateDict->dictData->append(eBuf); - break; - case 0x0c0d: - getDeltaReal(eBuf, "StemSnapV", op, i); - privateDict->dictData->append(eBuf); - break; - case 0x0c0e: - sprintf(eBuf, "/ForceBold %s def\n", op[0] ? "true" : "false"); - privateDict->dictData->append(eBuf); - break; - case 0x0c0f: - sprintf(eBuf, "/ForceBoldThreshold %g def\n", op[0]); - privateDict->dictData->append(eBuf); - break; - case 0x0c11: - sprintf(eBuf, "/LanguageGroup %d def\n", (int)op[0]); - privateDict->dictData->append(eBuf); - break; - case 0x0c12: - sprintf(eBuf, "/ExpansionFactor %g def\n", op[0]); - privateDict->dictData->append(eBuf); - break; - case 0x0c13: - error(-1, "Got Type 1C InitialRandomSeed"); - break; - case 0x0013: - privateDict->subrsOffset = offset + (int)op[0]; - break; - case 0x0014: - privateDict->defaultWidthX = op[0]; - privateDict->defaultWidthXFP = fp[0]; - break; - case 0x0015: - privateDict->nominalWidthX = op[0]; - privateDict->nominalWidthXFP = fp[0]; - break; - default: - error(-1, "Unknown Type 1C private dict entry %04x", key); - break; - } - i = 0; - } else { - x = getNum(&pos, &isFP); - if (i < 48) { - op[i] = x; - fp[i++] = isFP; - } - } - } -} - -Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) { - Gushort *glyphNames; - int pos; - int charsetFormat, c; - int nLeft, i, j; - - if (charset == 0) { - glyphNames = type1CISOAdobeCharset; - } else if (charset == 1) { - glyphNames = type1CExpertCharset; - } else if (charset == 2) { - glyphNames = type1CExpertSubsetCharset; - } else { - glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort)); - for (i = 0; i < nGlyphs; ++i) { - glyphNames[i] = 0; - } - pos = charset; - if (pos < 0 || pos >= len) { - goto err0; - } - charsetFormat = file[pos++]; - if (charsetFormat == 0) { - if (pos + (nGlyphs - 1) * 2 >= len) { - goto err0; - } - for (i = 1; i < nGlyphs; ++i) { - glyphNames[i] = getWord(pos, 2); - pos += 2; - } - } else if (charsetFormat == 1) { - i = 1; - while (i < nGlyphs) { - if (pos + 3 > len) { - goto err0; - } - c = getWord(pos, 2); - pos += 2; - nLeft = file[pos++]; - for (j = 0; j <= nLeft && i < nGlyphs; ++j) { - glyphNames[i++] = c++; - } - } - } else if (charsetFormat == 2) { - i = 1; - while (i < nGlyphs) { - if (pos + 4 > len) { - goto err0; - } - c = getWord(pos, 2); - pos += 2; - nLeft = getWord(pos, 2); - pos += 2; - for (j = 0; j <= nLeft && i < nGlyphs; ++j) { - glyphNames[i++] = c++; - } - } - } - } - err0: - return glyphNames; -} - -void Type1CFontFile::eexecWrite(char *s) { - Guchar *p; - Guchar x; - - for (p = (Guchar *)s; *p; ++p) { - x = *p ^ (r1 >> 8); - r1 = (x + r1) * 52845 + 22719; - (*outputFunc)(outputStream, &hexChars[x >> 4], 1); - (*outputFunc)(outputStream, &hexChars[x & 0x0f], 1); - line += 2; - if (line == 64) { - (*outputFunc)(outputStream, "\n", 1); - line = 0; - } - } -} - -void Type1CFontFile::eexecCvtGlyph(char *glyphName, int pos, int n) { - char eBuf[256]; - - cvtGlyph(pos, n, gTrue); - sprintf(eBuf, "/%s %d RD ", glyphName, charBuf->getLength()); - eexecWrite(eBuf); - eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength()); - eexecWrite(" ND\n"); - delete charBuf; -} - -void Type1CFontFile::cvtGlyph(int pos, int n, GBool top) { - int x; - int subrPos, subrLen; - double d, dx, dy; - GBool dFP; - Gushort r2; - Guchar byte; - int i, k; - - if (pos < 0 || pos + n > len) { - return; - } - - if (top) { - charBuf = new GString(); - charBuf->append((char)73); - charBuf->append((char)58); - charBuf->append((char)147); - charBuf->append((char)134); - nOps = 0; - nHints = 0; - firstOp = gTrue; - } - - i = pos; - while (i < pos + n) { - if (file[i] == 12) { - if (i + 2 > pos + n) { - break; - } - switch (file[i+1]) { - case 0: // dotsection (should be Type 1 only?) - // ignored - break; - case 34: // hflex - if (nOps != 7) { - error(-1, "Wrong number of args (%d) to Type 2 hflex", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(0, gFalse); - eexecDumpOp1(8); - eexecDumpNum(op[4], fp[4]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[5], fp[5]); - eexecDumpNum(-op[2], fp[2]); - eexecDumpNum(op[6], fp[6]); - eexecDumpNum(0, gFalse); - eexecDumpOp1(8); - break; - case 35: // flex - if (nOps != 13) { - error(-1, "Wrong number of args (%d) to Type 2 flex", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(op[4], fp[4]); - eexecDumpNum(op[5], fp[5]); - eexecDumpOp1(8); - eexecDumpNum(op[6], fp[6]); - eexecDumpNum(op[7], fp[7]); - eexecDumpNum(op[8], fp[8]); - eexecDumpNum(op[9], fp[9]); - eexecDumpNum(op[10], fp[10]); - eexecDumpNum(op[11], fp[11]); - eexecDumpOp1(8); - break; - case 36: // hflex1 - if (nOps != 9) { - error(-1, "Wrong number of args (%d) to Type 2 hflex1", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(op[4], fp[4]); - eexecDumpNum(0, gFalse); - eexecDumpOp1(8); - eexecDumpNum(op[5], fp[5]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[6], fp[6]); - eexecDumpNum(op[7], fp[7]); - eexecDumpNum(op[8], fp[8]); - eexecDumpNum(-(op[1] + op[3] + op[7]), fp[1] | fp[3] | fp[7]); - eexecDumpOp1(8); - break; - case 37: // flex1 - if (nOps != 11) { - error(-1, "Wrong number of args (%d) to Type 2 flex1", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(op[4], fp[4]); - eexecDumpNum(op[5], fp[5]); - eexecDumpOp1(8); - eexecDumpNum(op[6], fp[6]); - eexecDumpNum(op[7], fp[7]); - eexecDumpNum(op[8], fp[8]); - eexecDumpNum(op[9], fp[9]); - dx = op[0] + op[2] + op[4] + op[6] + op[8]; - dy = op[1] + op[3] + op[5] + op[7] + op[9]; - if (fabs(dx) > fabs(dy)) { - eexecDumpNum(op[10], fp[10]); - eexecDumpNum(-dy, fp[1] | fp[3] | fp[5] | fp[7] | fp[9]); - } else { - eexecDumpNum(-dx, fp[0] | fp[2] | fp[4] | fp[6] | fp[8]); - eexecDumpNum(op[10], fp[10]); - } - eexecDumpOp1(8); - break; - case 3: // and - case 4: // or - case 5: // not - case 8: // store - case 9: // abs - case 10: // add - case 11: // sub - case 12: // div - case 13: // load - case 14: // neg - case 15: // eq - case 18: // drop - case 20: // put - case 21: // get - case 22: // ifelse - case 23: // random - case 24: // mul - case 26: // sqrt - case 27: // dup - case 28: // exch - case 29: // index - case 30: // roll - error(-1, "Unimplemented Type 2 charstring op: 12.%d", file[i+1]); - break; - default: - error(-1, "Illegal Type 2 charstring op: 12.%d", file[i+1]); - break; - } - i += 2; - nOps = 0; - } else if (file[i] == 19) { // hintmask - // ignored - if (firstOp) { - cvtGlyphWidth(nOps & 1); - firstOp = gFalse; - } - if (nOps > 0) { - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 hintmask/vstemhm", - nOps); - } - nHints += nOps / 2; - } - i += 1 + ((nHints + 7) >> 3); - nOps = 0; - } else if (file[i] == 20) { // cntrmask - // ignored - if (firstOp) { - cvtGlyphWidth(nOps & 1); - firstOp = gFalse; - } - if (nOps > 0) { - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 cntrmask/vstemhm", - nOps); - } - nHints += nOps / 2; - } - i += 1 + ((nHints + 7) >> 3); - nOps = 0; - } else if (file[i] == 28) { - if (i + 3 > len) { - break; - } - x = (file[i+1] << 8) + file[i+2]; - if (x & 0x8000) { - x |= -1 << 15; - } - if (nOps < 48) { - fp[nOps] = gFalse; - op[nOps++] = x; - } - i += 3; - } else if (file[i] == 10) { // callsubr - if (nOps >= 1) { - k = subrBias + (int)op[nOps - 1]; - --nOps; - if ((subrPos = getIndexValPos(subrIdxPos, k, &subrLen)) >= 0) { - cvtGlyph(subrPos, subrLen, gFalse); - } - } else { - error(-1, "Too few args to Type 2 callsubr"); - } - // don't clear the stack - ++i; - } else if (file[i] == 29) { // callgsubr - if (nOps >= 1) { - k = gsubrBias + (int)op[nOps - 1]; - --nOps; - if ((subrPos = getIndexValPos(gsubrIdxPos, k, &subrLen)) >= 0) { - cvtGlyph(subrPos, subrLen, gFalse); - } - } else { - error(-1, "Too few args to Type 2 callgsubr"); - } - // don't clear the stack - ++i; - } else if (file[i] == 11) { // return - // don't clear the stack - ++i; - } else if (file[i] <= 31) { - switch (file[i]) { - case 4: // vmoveto - if (firstOp) { - cvtGlyphWidth(nOps == 2); - firstOp = gFalse; - } - if (nOps != 1) { - error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpOp1(4); - break; - case 5: // rlineto - if (nOps < 2 || nOps % 2 != 0) { - error(-1, "Wrong number of args (%d) to Type 2 rlineto", nOps); - } - for (k = 0; k < nOps; k += 2) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpOp1(5); - } - break; - case 6: // hlineto - if (nOps < 1) { - error(-1, "Wrong number of args (%d) to Type 2 hlineto", nOps); - } - for (k = 0; k < nOps; ++k) { - eexecDumpNum(op[k], fp[k]); - eexecDumpOp1((k & 1) ? 7 : 6); - } - break; - case 7: // vlineto - if (nOps < 1) { - error(-1, "Wrong number of args (%d) to Type 2 vlineto", nOps); - } - for (k = 0; k < nOps; ++k) { - eexecDumpNum(op[k], fp[k]); - eexecDumpOp1((k & 1) ? 6 : 7); - } - break; - case 8: // rrcurveto - if (nOps < 6 || nOps % 6 != 0) { - error(-1, "Wrong number of args (%d) to Type 2 rrcurveto", nOps); - } - for (k = 0; k < nOps; k += 6) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(op[k+4], fp[k+4]); - eexecDumpNum(op[k+5], fp[k+5]); - eexecDumpOp1(8); - } - break; - case 14: // endchar / seac - if (firstOp) { - cvtGlyphWidth(nOps == 1 || nOps == 5); - firstOp = gFalse; - } - if (nOps == 4) { - eexecDumpNum(0, 0); - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpOp2(6); - } else if (nOps == 0) { - eexecDumpOp1(14); - } else { - error(-1, "Wrong number of args (%d) to Type 2 endchar", nOps); - } - break; - case 21: // rmoveto - if (firstOp) { - cvtGlyphWidth(nOps == 3); - firstOp = gFalse; - } - if (nOps != 2) { - error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpOp1(21); - break; - case 22: // hmoveto - if (firstOp) { - cvtGlyphWidth(nOps == 2); - firstOp = gFalse; - } - if (nOps != 1) { - error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps); - } - eexecDumpNum(op[0], fp[0]); - eexecDumpOp1(22); - break; - case 24: // rcurveline - if (nOps < 8 || (nOps - 2) % 6 != 0) { - error(-1, "Wrong number of args (%d) to Type 2 rcurveline", nOps); - } - for (k = 0; k < nOps - 2; k += 6) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(op[k+4], fp[k+4]); - eexecDumpNum(op[k+5], fp[k+5]); - eexecDumpOp1(8); - } - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k]); - eexecDumpOp1(5); - break; - case 25: // rlinecurve - if (nOps < 8 || (nOps - 6) % 2 != 0) { - error(-1, "Wrong number of args (%d) to Type 2 rlinecurve", nOps); - } - for (k = 0; k < nOps - 6; k += 2) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k]); - eexecDumpOp1(5); - } - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(op[k+4], fp[k+4]); - eexecDumpNum(op[k+5], fp[k+5]); - eexecDumpOp1(8); - break; - case 26: // vvcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { - error(-1, "Wrong number of args (%d) to Type 2 vvcurveto", nOps); - } - if (nOps % 2 == 1) { - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[4], fp[4]); - eexecDumpOp1(8); - k = 5; - } else { - k = 0; - } - for (; k < nOps; k += 4) { - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpOp1(8); - } - break; - case 27: // hhcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { - error(-1, "Wrong number of args (%d) to Type 2 hhcurveto", nOps); - } - if (nOps % 2 == 1) { - eexecDumpNum(op[1], fp[1]); - eexecDumpNum(op[0], fp[0]); - eexecDumpNum(op[2], fp[2]); - eexecDumpNum(op[3], fp[3]); - eexecDumpNum(op[4], fp[4]); - eexecDumpNum(0, gFalse); - eexecDumpOp1(8); - k = 5; - } else { - k = 0; - } - for (; k < nOps; k += 4) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(0, gFalse); - eexecDumpOp1(8); - } - break; - case 30: // vhcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { - error(-1, "Wrong number of args (%d) to Type 2 vhcurveto", nOps); - } - for (k = 0; k < nOps && k != nOps-5; k += 4) { - if (k % 8 == 0) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpOp1(30); - } else { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpOp1(31); - } - } - if (k == nOps-5) { - if (k % 8 == 0) { - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(op[k+4], fp[k+4]); - } else { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+4], fp[k+4]); - eexecDumpNum(op[k+3], fp[k+3]); - } - eexecDumpOp1(8); - } - break; - case 31: // hvcurveto - if (nOps < 4 || !(nOps % 4 == 0 || (nOps-1) % 4 == 0)) { - error(-1, "Wrong number of args (%d) to Type 2 hvcurveto", nOps); - } - for (k = 0; k < nOps && k != nOps-5; k += 4) { - if (k % 8 == 0) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpOp1(31); - } else { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpOp1(30); - } - } - if (k == nOps-5) { - if (k % 8 == 0) { - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+4], fp[k+4]); - eexecDumpNum(op[k+3], fp[k+3]); - } else { - eexecDumpNum(0, gFalse); - eexecDumpNum(op[k], fp[k]); - eexecDumpNum(op[k+1], fp[k+1]); - eexecDumpNum(op[k+2], fp[k+2]); - eexecDumpNum(op[k+3], fp[k+3]); - eexecDumpNum(op[k+4], fp[k+4]); - } - eexecDumpOp1(8); - } - break; - case 1: // hstem - if (firstOp) { - cvtGlyphWidth(nOps & 1); - firstOp = gFalse; - } - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps); - } - d = 0; - dFP = gFalse; - for (k = 0; k < nOps; k += 2) { - if (op[k+1] < 0) { - d += op[k] + op[k+1]; - dFP |= fp[k] | fp[k+1]; - eexecDumpNum(d, dFP); - eexecDumpNum(-op[k+1], fp[k+1]); - } else { - d += op[k]; - dFP |= fp[k]; - eexecDumpNum(d, dFP); - eexecDumpNum(op[k+1], fp[k+1]); - d += op[k+1]; - dFP |= fp[k+1]; - } - eexecDumpOp1(1); - } - nHints += nOps / 2; - break; - case 3: // vstem - if (firstOp) { - cvtGlyphWidth(nOps & 1); - firstOp = gFalse; - } - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps); - } - d = 0; - dFP = gFalse; - for (k = 0; k < nOps; k += 2) { - if (op[k+1] < 0) { - d += op[k] + op[k+1]; - dFP |= fp[k] | fp[k+1]; - eexecDumpNum(d, dFP); - eexecDumpNum(-op[k+1], fp[k+1]); - } else { - d += op[k]; - dFP |= fp[k]; - eexecDumpNum(d, dFP); - eexecDumpNum(op[k+1], fp[k+1]); - d += op[k+1]; - dFP |= fp[k+1]; - } - eexecDumpOp1(3); - } - nHints += nOps / 2; - break; - case 15: // (obsolete) - // this op is ignored, but we need the glyph width - if (firstOp) { - cvtGlyphWidth(nOps > 0); - firstOp = gFalse; - } - break; - case 18: // hstemhm - // ignored - if (firstOp) { - cvtGlyphWidth(nOps & 1); - firstOp = gFalse; - } - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps); - } - nHints += nOps / 2; - break; - case 23: // vstemhm - // ignored - if (firstOp) { - cvtGlyphWidth(nOps & 1); - firstOp = gFalse; - } - if (nOps & 1) { - error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps); - } - nHints += nOps / 2; - break; - case 16: // blend - error(-1, "Unimplemented Type 2 charstring op: %d", file[i]); - break; - default: - error(-1, "Illegal Type 2 charstring op: %d", file[i]); - break; - } - ++i; - nOps = 0; - } else if (file[i] <= 246) { - if (nOps < 48) { - fp[nOps] = gFalse; - op[nOps++] = (int)file[i] - 139; - } - ++i; - } else if (file[i] <= 250) { - if (i + 2 > len) { - break; - } - if (nOps < 48) { - fp[nOps] = gFalse; - op[nOps++] = (((int)file[i] - 247) << 8) + (int)file[i+1] + 108; - } - i += 2; - } else if (file[i] <= 254) { - if (i + 2 > len) { - break; - } - if (nOps < 48) { - fp[nOps] = gFalse; - op[nOps++] = -(((int)file[i] - 251) << 8) - (int)file[i+1] - 108; - } - i += 2; - } else { - if (i + 5 > len) { - break; - } - x = (file[i+1] << 24) | (file[i+2] << 16) | (file[i+3] << 8) | file[i+4]; - if (x & 0x80000000) { - x |= -1 << 31; - } - if (nOps < 48) { - fp[nOps] = gTrue; - op[nOps++] = (double)x / 65536.0; - } - i += 5; - } - } - - // charstring encryption - if (top) { - r2 = 4330; - for (i = 0; i < charBuf->getLength(); ++i) { - byte = charBuf->getChar(i) ^ (r2 >> 8); - charBuf->setChar(i, byte); - r2 = (byte + r2) * 52845 + 22719; - } - } -} - -void Type1CFontFile::cvtGlyphWidth(GBool useOp) { - double w; - GBool wFP; - int i; - - if (useOp) { - w = nominalWidthX + op[0]; - wFP = nominalWidthXFP | fp[0]; - for (i = 1; i < nOps; ++i) { - op[i-1] = op[i]; - fp[i-1] = fp[i]; - } - --nOps; - } else { - w = defaultWidthX; - wFP = defaultWidthXFP; - } - eexecDumpNum(0, gFalse); - eexecDumpNum(w, wFP); - eexecDumpOp1(13); -} - -void Type1CFontFile::eexecDumpNum(double x, GBool fpA) { - Guchar buf[12]; - int y, n; - - n = 0; - if (fpA) { - if (x >= -32768 && x < 32768) { - y = (int)(x * 256.0); - buf[0] = 255; - buf[1] = (Guchar)(y >> 24); - buf[2] = (Guchar)(y >> 16); - buf[3] = (Guchar)(y >> 8); - buf[4] = (Guchar)y; - buf[5] = 255; - buf[6] = 0; - buf[7] = 0; - buf[8] = 1; - buf[9] = 0; - buf[10] = 12; - buf[11] = 12; - n = 12; - } else { - error(-1, "Type 2 fixed point constant out of range"); - } - } else { - y = (int)x; - if (y >= -107 && y <= 107) { - buf[0] = (Guchar)(y + 139); - n = 1; - } else if (y > 107 && y <= 1131) { - y -= 108; - buf[0] = (Guchar)((y >> 8) + 247); - buf[1] = (Guchar)(y & 0xff); - n = 2; - } else if (y < -107 && y >= -1131) { - y = -y - 108; - buf[0] = (Guchar)((y >> 8) + 251); - buf[1] = (Guchar)(y & 0xff); - n = 2; - } else { - buf[0] = 255; - buf[1] = (Guchar)(y >> 24); - buf[2] = (Guchar)(y >> 16); - buf[3] = (Guchar)(y >> 8); - buf[4] = (Guchar)y; - n = 5; - } - } - charBuf->append((char *)buf, n); -} - -void Type1CFontFile::eexecDumpOp1(int opA) { - charBuf->append((char)opA); -} - -void Type1CFontFile::eexecDumpOp2(int opA) { - charBuf->append((char)12); - charBuf->append((char)opA); -} - -void Type1CFontFile::eexecWriteCharstring(Guchar *s, int n) { - Guchar x; - int i; - - // eexec encryption - for (i = 0; i < n; ++i) { - x = s[i] ^ (r1 >> 8); - r1 = (x + r1) * 52845 + 22719; - (*outputFunc)(outputStream, &hexChars[x >> 4], 1); - (*outputFunc)(outputStream, &hexChars[x & 0x0f], 1); - line += 2; - if (line == 64) { - (*outputFunc)(outputStream, "\n", 1); - line = 0; - } - } -} - -void Type1CFontFile::getDeltaInt(char *buf, char *key, double *opA, - int n) { - int x, i; - - sprintf(buf, "/%s [", key); - buf += strlen(buf); - x = 0; - for (i = 0; i < n; ++i) { - x += (int)opA[i]; - sprintf(buf, "%s%d", i > 0 ? " " : "", x); - buf += strlen(buf); - } - sprintf(buf, "] def\n"); -} - -void Type1CFontFile::getDeltaReal(char *buf, char *key, double *opA, - int n) { - double x; - int i; - - sprintf(buf, "/%s [", key); - buf += strlen(buf); - x = 0; - for (i = 0; i < n; ++i) { - x += opA[i]; - sprintf(buf, "%s%g", i > 0 ? " " : "", x); - buf += strlen(buf); - } - sprintf(buf, "] def\n"); -} - -int Type1CFontFile::getIndexLen(int indexPos) { - if (indexPos + 2 > len) { - return -1; - } - return (int)getWord(indexPos, 2); -} - -int Type1CFontFile::getIndexValPos(int indexPos, int i, int *valLen) { - int n, offSize, idxStartPos; - int pos0, pos1; - - if (indexPos < 0 || indexPos + 3 > len) { - return -1; - } - n = (int)getWord(indexPos, 2); - if (i >= n) { - return -1; - } - offSize = file[indexPos + 2]; - if (offSize < 1 || offSize > 4) { - return -1; - } - idxStartPos = indexPos + 3 + (n + 1) * offSize - 1; - if (idxStartPos >= len) { - return -1; - } - pos0 = idxStartPos + getWord(indexPos + 3 + i * offSize, offSize); - pos1 = idxStartPos + getWord(indexPos + 3 + (i + 1) * offSize, offSize); - if (pos0 < 0 || pos0 >= len || pos1 < pos0 || pos1 > len) { - return -1; - } - *valLen = pos1 - pos0; - return pos0; -} - -int Type1CFontFile::getIndexEnd(int indexPos) { - int n, offSize, idxStartPos; - - if (indexPos < 0 || indexPos + 3 > len) { - return -1; - } - n = (int)getWord(indexPos, 2); - offSize = file[indexPos + 2]; - idxStartPos = indexPos + 3 + (n + 1) * offSize - 1; - if (idxStartPos >= len) { - return -1; - } - return idxStartPos + getWord(indexPos + 3 + n * offSize, offSize); -} - -Guint Type1CFontFile::getWord(int pos, int size) { - Guint x; - int i; - - if (pos < 0 || pos + size > len) { - return 0; - } - x = 0; - for (i = 0; i < size; ++i) { - x = (x << 8) + file[pos + i]; - } - return x; -} - -double Type1CFontFile::getNum(int *pos, GBool *isFP) { - static char nybChars[16] = "0123456789.ee -"; - int b0, b, nyb0, nyb1; - double x; - char buf[65]; - int i; - - x = 0; - *isFP = gFalse; - if (*pos >= len) { - return 0; - } - b0 = file[*pos]; - if (b0 < 28) { - x = 0; - } else if (b0 == 28) { - if (*pos + 3 <= len) { - x = (file[*pos + 1] << 8) + file[*pos + 2]; - *pos += 3; - } - } else if (b0 == 29) { - if (*pos + 5 <= len) { - x = (file[*pos + 1] << 24) + (file[*pos + 2] << 16) + - (file[*pos + 3] << 8) + file[*pos + 4]; - *pos += 5; - } - } else if (b0 == 30) { - *pos += 1; - i = 0; - do { - if (*pos >= len) { - break; - } - b = file[(*pos)++]; - nyb0 = b >> 4; - nyb1 = b & 0x0f; - if (nyb0 == 0xf) { - break; - } - buf[i++] = nybChars[nyb0]; - if (i == 64) { - break; - } - if (nyb0 == 0xc) { - buf[i++] = '-'; - } - if (i == 64) { - break; - } - if (nyb1 == 0xf) { - break; - } - buf[i++] = nybChars[nyb1]; - if (i == 64) { - break; - } - if (nyb1 == 0xc) { - buf[i++] = '-'; - } - } while (i < 64); - buf[i] = '\0'; - { - char *theLocale = setlocale(LC_NUMERIC, "C"); - x = atof(buf); - setlocale(LC_NUMERIC, theLocale); - } - *isFP = gTrue; - } else if (b0 == 31) { - x = 0; - } else if (b0 < 247) { - x = b0 - 139; - *pos += 1; - } else if (b0 < 251) { - if (*pos + 2 <= len) { - x = ((b0 - 247) << 8) + file[*pos + 1] + 108; - *pos += 2; - } - } else { - if (*pos + 2 <= len) { - x = -((b0 - 251) << 8) - file[*pos + 1] - 108; - *pos += 2; - } - } - return x; -} - -char *Type1CFontFile::getString(int sid, char *buf) { - int idxPos, n; - - if (sid < 391) { - strcpy(buf, type1CStdStrings[sid]); - } else { - sid -= 391; - idxPos = getIndexValPos(stringIdxPos, sid, &n); - if (idxPos < 0 || n < 0 || n > 255 || idxPos + n > len) { - buf[0] = '\0'; - } else { - strncpy(buf, (char *)&file[idxPos], n); - buf[n] = '\0'; - } - } - return buf; -} - -//------------------------------------------------------------------------ -// TrueTypeFontFile -//------------------------------------------------------------------------ - -// -// Terminology -// ----------- -// -// character code = number used as an element of a text string -// -// character name = glyph name = name for a particular glyph within a -// font -// -// glyph index = position (within some internal table in the font) -// where the instructions to draw a particular glyph are -// stored -// -// Type 1 fonts -// ------------ -// -// Type 1 fonts contain: -// -// Encoding: array of glyph names, maps char codes to glyph names -// -// Encoding[charCode] = charName -// -// CharStrings: dictionary of instructions, keyed by character names, -// maps character name to glyph data -// -// CharStrings[charName] = glyphData -// -// TrueType fonts -// -------------- -// -// TrueType fonts contain: -// -// 'cmap' table: mapping from character code to glyph index; there may -// be multiple cmaps in a TrueType font -// -// cmap[charCode] = glyphIdx -// -// 'post' table: mapping from glyph index to glyph name -// -// post[glyphIdx] = glyphName -// -// Type 42 fonts -// ------------- -// -// Type 42 fonts contain: -// -// Encoding: array of glyph names, maps char codes to glyph names -// -// Encoding[charCode] = charName -// -// CharStrings: dictionary of glyph indexes, keyed by character names, -// maps character name to glyph index -// -// CharStrings[charName] = glyphIdx -// - -struct TTFontTableHdr { - char tag[4]; - Guint checksum; - Guint offset; - Guint length; -}; - -struct T42Table { - char *tag; // 4-byte tag - GBool required; // required by the TrueType spec? -}; - -struct TTFontCmap { - int platform; - int encoding; - int offset; - int len; - int fmt; -}; - -// TrueType tables to be embedded in Type 42 fonts. -// NB: the table names must be in alphabetical order here. -#define nT42Tables 11 -static T42Table t42Tables[nT42Tables] = { - { "cvt ", gTrue }, - { "fpgm", gTrue }, - { "glyf", gTrue }, - { "head", gTrue }, - { "hhea", gTrue }, - { "hmtx", gTrue }, - { "loca", gTrue }, - { "maxp", gTrue }, - { "prep", gTrue }, - { "vhea", gFalse }, - { "vmtx", gFalse } -}; -#define t42HeadTable 3 -#define t42LocaTable 6 -#define t42GlyfTable 2 - -// Glyph names in some arbitrary standard that Apple uses for their -// TrueType fonts. -static char *macGlyphNames[258] = { - ".notdef", - "null", - "CR", - "space", - "exclam", - "quotedbl", - "numbersign", - "dollar", - "percent", - "ampersand", - "quotesingle", - "parenleft", - "parenright", - "asterisk", - "plus", - "comma", - "hyphen", - "period", - "slash", - "zero", - "one", - "two", - "three", - "four", - "five", - "six", - "seven", - "eight", - "nine", - "colon", - "semicolon", - "less", - "equal", - "greater", - "question", - "at", - "A", - "B", - "C", - "D", - "E", - "F", - "G", - "H", - "I", - "J", - "K", - "L", - "M", - "N", - "O", - "P", - "Q", - "R", - "S", - "T", - "U", - "V", - "W", - "X", - "Y", - "Z", - "bracketleft", - "backslash", - "bracketright", - "asciicircum", - "underscore", - "grave", - "a", - "b", - "c", - "d", - "e", - "f", - "g", - "h", - "i", - "j", - "k", - "l", - "m", - "n", - "o", - "p", - "q", - "r", - "s", - "t", - "u", - "v", - "w", - "x", - "y", - "z", - "braceleft", - "bar", - "braceright", - "asciitilde", - "Adieresis", - "Aring", - "Ccedilla", - "Eacute", - "Ntilde", - "Odieresis", - "Udieresis", - "aacute", - "agrave", - "acircumflex", - "adieresis", - "atilde", - "aring", - "ccedilla", - "eacute", - "egrave", - "ecircumflex", - "edieresis", - "iacute", - "igrave", - "icircumflex", - "idieresis", - "ntilde", - "oacute", - "ograve", - "ocircumflex", - "odieresis", - "otilde", - "uacute", - "ugrave", - "ucircumflex", - "udieresis", - "dagger", - "degree", - "cent", - "sterling", - "section", - "bullet", - "paragraph", - "germandbls", - "registered", - "copyright", - "trademark", - "acute", - "dieresis", - "notequal", - "AE", - "Oslash", - "infinity", - "plusminus", - "lessequal", - "greaterequal", - "yen", - "mu1", - "partialdiff", - "summation", - "product", - "pi", - "integral", - "ordfeminine", - "ordmasculine", - "Ohm", - "ae", - "oslash", - "questiondown", - "exclamdown", - "logicalnot", - "radical", - "florin", - "approxequal", - "increment", - "guillemotleft", - "guillemotright", - "ellipsis", - "nbspace", - "Agrave", - "Atilde", - "Otilde", - "OE", - "oe", - "endash", - "emdash", - "quotedblleft", - "quotedblright", - "quoteleft", - "quoteright", - "divide", - "lozenge", - "ydieresis", - "Ydieresis", - "fraction", - "currency", - "guilsinglleft", - "guilsinglright", - "fi", - "fl", - "daggerdbl", - "periodcentered", - "quotesinglbase", - "quotedblbase", - "perthousand", - "Acircumflex", - "Ecircumflex", - "Aacute", - "Edieresis", - "Egrave", - "Iacute", - "Icircumflex", - "Idieresis", - "Igrave", - "Oacute", - "Ocircumflex", - "applelogo", - "Ograve", - "Uacute", - "Ucircumflex", - "Ugrave", - "dotlessi", - "circumflex", - "tilde", - "overscore", - "breve", - "dotaccent", - "ring", - "cedilla", - "hungarumlaut", - "ogonek", - "caron", - "Lslash", - "lslash", - "Scaron", - "scaron", - "Zcaron", - "zcaron", - "brokenbar", - "Eth", - "eth", - "Yacute", - "yacute", - "Thorn", - "thorn", - "minus", - "multiply", - "onesuperior", - "twosuperior", - "threesuperior", - "onehalf", - "onequarter", - "threequarters", - "franc", - "Gbreve", - "gbreve", - "Idot", - "Scedilla", - "scedilla", - "Cacute", - "cacute", - "Ccaron", - "ccaron", - "dmacron" -}; - -struct TrueTypeLoca { - int idx; - int pos; - int length; -}; - -TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) { - int pos, pos2, i, idx, n, length; - Guint size, startPos, endPos; - - file = fileA; - len = lenA; - - encoding = NULL; - cmaps = NULL; - nCmaps = 0; - - // read table directory - nTables = getUShort(4); - tableHdrs = (TTFontTableHdr *)gmalloc(nTables * sizeof(TTFontTableHdr)); - pos = 12; - for (i = 0; i < nTables; ++i) { - tableHdrs[i].tag[0] = getByte(pos+0); - tableHdrs[i].tag[1] = getByte(pos+1); - tableHdrs[i].tag[2] = getByte(pos+2); - tableHdrs[i].tag[3] = getByte(pos+3); - tableHdrs[i].checksum = getULong(pos+4); - tableHdrs[i].offset = getULong(pos+8); - tableHdrs[i].length = getULong(pos+12); - if (tableHdrs[i].offset + tableHdrs[i].length < tableHdrs[i].offset || - tableHdrs[i].offset + tableHdrs[i].length > (Guint)len) { - tableHdrs[i].offset = (Guint)-1; - } - pos += 16; - } - - // check for tables that are required by both the TrueType spec - // and the Type 42 spec - if (seekTable("head") < 0 || - seekTable("hhea") < 0 || - seekTable("loca") < 0 || - seekTable("maxp") < 0 || - seekTable("glyf") < 0 || - seekTable("hmtx") < 0) { - error(-1, "TrueType font file is missing a required table"); - return; - } - - // some embedded TrueType fonts have an incorrect (too small) cmap - // table size - idx = seekTableIdx("cmap"); - if (idx >= 0) { - pos = tableHdrs[idx].offset; - n = getUShort(pos + 2); - size = (Guint)(4 + 8 * n); - for (i = 0; i < n; ++i) { - startPos = getULong(pos + 4 + 8*i + 4); - length = getUShort(pos + startPos + 2); - endPos = startPos + length; - if (endPos > size) { - size = endPos; - } - } - if ((mungedCmapSize = size > tableHdrs[idx].length)) { -#if 0 // don't bother printing this error message - it's too common - error(-1, "Bad cmap table size in TrueType font"); -#endif - tableHdrs[idx].length = size; - } - } else { - mungedCmapSize = gFalse; - } - - // read the 'head' table - pos = seekTable("head"); - bbox[0] = getShort(pos + 36); - bbox[1] = getShort(pos + 38); - bbox[2] = getShort(pos + 40); - bbox[3] = getShort(pos + 42); - locaFmt = getShort(pos + 50); - - // read the 'maxp' table - pos = seekTable("maxp"); - nGlyphs = getUShort(pos + 4); - - // read the 'cmap' table - if ((pos = seekTable("cmap")) >= 0) { - pos2 = pos + 2; - if ((nCmaps = getUShort(pos2)) > 0) { - pos2 += 2; - cmaps = (TTFontCmap *)gmalloc(nCmaps * sizeof(TTFontCmap)); - for (i = 0; i < nCmaps; ++i) { - cmaps[i].platform = getUShort(pos2); - cmaps[i].encoding = getUShort(pos2 + 2); - cmaps[i].offset = pos + getULong(pos2 + 4); - pos2 += 8; - cmaps[i].fmt = getUShort(cmaps[i].offset); - cmaps[i].len = getUShort(cmaps[i].offset + 2); - } - } - } -} - -TrueTypeFontFile::~TrueTypeFontFile() { - int i; - - if (encoding) { - for (i = 0; i < 256; ++i) { - gfree(encoding[i]); - } - gfree(encoding); - } - if (cmaps) { - gfree(cmaps); - } - gfree(tableHdrs); -} - -char *TrueTypeFontFile::getName() { - return NULL; -} - -char **TrueTypeFontFile::getEncoding() { - int i; - - if (!encoding) { - encoding = (char **)gmalloc(256 * sizeof(char *)); - for (i = 0; i < 256; ++i) { - encoding[i] = NULL; - } - } - return encoding; -} - -int TrueTypeFontFile::getNumCmaps() { - return nCmaps; -} - -int TrueTypeFontFile::getCmapPlatform(int i) { - return cmaps[i].platform; -} - -int TrueTypeFontFile::getCmapEncoding(int i) { - return cmaps[i].encoding; -} - -int TrueTypeFontFile::findCmap(int platform, int enc) { - int i; - - for (i = 0; i < nCmaps; ++i) { - if (cmaps[i].platform == platform && cmaps[i].encoding == enc) { - return i; - } - } - return -1; -} - -Gushort TrueTypeFontFile::mapCodeToGID(int i, int c) { - if (i < 0 || i >= nCmaps) { - return 0; - } - return (Gushort)getCmapEntry(cmaps[i].fmt, cmaps[i].offset, c); -} - -GHash *TrueTypeFontFile::getNameToGID() { - GHash *nameToGID; - Guint fmt; - GString *s; - int stringIdx, stringPos, pos, i, j, n; - - if ((pos = seekTable("post")) < 0) { - return NULL; - } - - fmt = getULong(pos); - nameToGID = NULL; - - // Apple font - if (fmt == 0x00010000) { - nameToGID = new GHash(gTrue); - for (i = 0; i < 258; ++i) { - nameToGID->add(new GString(macGlyphNames[i]), (void *)i); - } - - // Microsoft font - } else if (fmt == 0x00020000) { - nameToGID = new GHash(gTrue); - n = getUShort(pos + 32); - if (n > nGlyphs) { - n = nGlyphs; - } - stringIdx = 0; - stringPos = pos + 34 + 2*nGlyphs; - for (i = 0; i < nGlyphs; ++i) { - j = getUShort(pos + 34 + 2*i); - if (j < 258) { - nameToGID->remove(macGlyphNames[j]); - nameToGID->add(new GString(macGlyphNames[j]), (void *)i); - } else { - j -= 258; - if (j != stringIdx) { - for (stringIdx = 0, stringPos = pos + 34 + 2*nGlyphs; - stringIdx < j; - ++stringIdx, stringPos += 1 + getByte(stringPos)) ; - } - n = getByte(stringPos); - if (stringPos >= 0 && stringPos + 1 + n <= len) { - s = new GString(file + stringPos + 1, n); - nameToGID->remove(s); - nameToGID->add(s, (void *)i); - } - ++stringIdx; - stringPos += 1 + n; - } - } - - // Apple subset - } else if (fmt == 0x000280000) { - nameToGID = new GHash(gTrue); - for (i = 0; i < nGlyphs; ++i) { - j = getByte(pos + 32 + i); - if (j < 258) { - nameToGID->remove(macGlyphNames[j]); - nameToGID->add(new GString(macGlyphNames[j]), (void *)i); - } - } - } - - return nameToGID; -} - -void TrueTypeFontFile::convertToType42(char *name, char **encodingA, - GBool pdfFontHasEncoding, - Gushort *codeToGID, - FontFileOutputFunc outputFunc, - void *outputStream) { - char buf[512]; - - // write the header - sprintf(buf, "%%!PS-TrueTypeFont-%g\n", getFixed(0)); - (*outputFunc)(outputStream, buf, strlen(buf)); - - // begin the font dictionary - (*outputFunc)(outputStream, "10 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, name, strlen(name)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/FontType 42 def\n", 17); - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - sprintf(buf, "/FontBBox [%d %d %d %d] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); - - // write the guts of the dictionary - cvtEncoding(encodingA, pdfFontHasEncoding, outputFunc, outputStream); - cvtCharStrings(encodingA, pdfFontHasEncoding, codeToGID, - outputFunc, outputStream); - cvtSfnts(outputFunc, outputStream, NULL); - - // end the dictionary and define the font - (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); -} - -void TrueTypeFontFile::convertToCIDType2(char *name, Gushort *cidMap, - int nCIDs, - FontFileOutputFunc outputFunc, - void *outputStream) { - char buf[512]; - Gushort cid; - int i, j, k; - - // write the header - sprintf(buf, "%%!PS-TrueTypeFont-%g\n", getFixed(0)); - (*outputFunc)(outputStream, buf, strlen(buf)); - - // begin the font dictionary - (*outputFunc)(outputStream, "20 dict begin\n", 14); - (*outputFunc)(outputStream, "/CIDFontName /", 14); - (*outputFunc)(outputStream, name, strlen(name)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/CIDFontType 2 def\n", 19); - (*outputFunc)(outputStream, "/FontType 42 def\n", 17); - (*outputFunc)(outputStream, "/CIDSystemInfo 3 dict dup begin\n", 32); - (*outputFunc)(outputStream, " /Registry (Adobe) def\n", 24); - (*outputFunc)(outputStream, " /Ordering (Identity) def\n", 27); - (*outputFunc)(outputStream, " /Supplement 0 def\n", 20); - (*outputFunc)(outputStream, " end def\n", 10); - (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15); - if (cidMap) { - sprintf(buf, "/CIDCount %d def\n", nCIDs); - (*outputFunc)(outputStream, buf, strlen(buf)); - if (nCIDs > 32767) { - (*outputFunc)(outputStream, "/CIDMap [", 9); - for (i = 0; i < nCIDs; i += 32768 - 16) { - (*outputFunc)(outputStream, "<\n", 2); - for (j = 0; j < 32768 - 16 && i+j < nCIDs; j += 16) { - (*outputFunc)(outputStream, " ", 2); - for (k = 0; k < 16 && i+j+k < nCIDs; ++k) { - cid = cidMap[i+j+k]; - sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "\n", 1); - } - (*outputFunc)(outputStream, " >", 3); - } - (*outputFunc)(outputStream, "\n", 1); - (*outputFunc)(outputStream, "] def\n", 6); - } else { - (*outputFunc)(outputStream, "/CIDMap <\n", 10); - for (i = 0; i < nCIDs; i += 16) { - (*outputFunc)(outputStream, " ", 2); - for (j = 0; j < 16 && i+j < nCIDs; ++j) { - cid = cidMap[i+j]; - sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "\n", 1); - } - (*outputFunc)(outputStream, "> def\n", 6); - } - } else { - // direct mapping - just fill the string(s) with s[i]=i - sprintf(buf, "/CIDCount %d def\n", nGlyphs); - (*outputFunc)(outputStream, buf, strlen(buf)); - if (nGlyphs > 32767) { - (*outputFunc)(outputStream, "/CIDMap [\n", 10); - for (i = 0; i < nGlyphs; i += 32767) { - j = nGlyphs - i < 32767 ? nGlyphs - i : 32767; - sprintf(buf, " %d string 0 1 %d {\n", 2 * j, j - 1); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, " 2 copy dup 2 mul exch %d add -8 bitshift put\n", i); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, " 1 index exch dup 2 mul 1 add exch %d add" - " 255 and put\n", i); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, " } for\n", 8); - } - (*outputFunc)(outputStream, "] def\n", 6); - } else { - sprintf(buf, "/CIDMap %d string\n", 2 * nGlyphs); - (*outputFunc)(outputStream, buf, strlen(buf)); - sprintf(buf, " 0 1 %d {\n", nGlyphs - 1); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, - " 2 copy dup 2 mul exch -8 bitshift put\n", 42); - (*outputFunc)(outputStream, - " 1 index exch dup 2 mul 1 add exch 255 and put\n", 50); - (*outputFunc)(outputStream, " } for\n", 8); - (*outputFunc)(outputStream, "def\n", 4); - } - } - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - sprintf(buf, "/FontBBox [%d %d %d %d] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); - (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26); - (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30); - (*outputFunc)(outputStream, " /.notdef 0 def\n", 17); - (*outputFunc)(outputStream, " end readonly def\n", 19); - - // write the guts of the dictionary - cvtSfnts(outputFunc, outputStream, NULL); - - // end the dictionary and define the font - (*outputFunc)(outputStream, - "CIDFontName currentdict end /CIDFont defineresource pop\n", - 56); -} - -void TrueTypeFontFile::convertToType0(char *name, Gushort *cidMap, - int nCIDs, - FontFileOutputFunc outputFunc, - void *outputStream) { - char buf[512]; - GString *sfntsName; - int n, i, j; - - // write the Type 42 sfnts array - sfntsName = (new GString(name))->append("_sfnts"); - cvtSfnts(outputFunc, outputStream, sfntsName); - delete sfntsName; - - // write the descendant Type 42 fonts - n = cidMap ? nCIDs : nGlyphs; - for (i = 0; i < n; i += 256) { - (*outputFunc)(outputStream, "10 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, name, strlen(name)); - sprintf(buf, "_%02x def\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/FontType 42 def\n", 17); - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - sprintf(buf, "/FontBBox [%d %d %d %d] def\n", - bbox[0], bbox[1], bbox[2], bbox[3]); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, "/PaintType 0 def\n", 17); - (*outputFunc)(outputStream, "/sfnts ", 7); - (*outputFunc)(outputStream, name, strlen(name)); - (*outputFunc)(outputStream, "_sfnts def\n", 11); - (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); - for (j = 0; j < 256 && i+j < n; ++j) { - sprintf(buf, "dup %d /c%02x put\n", j, j); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "readonly def\n", 13); - (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32); - (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); - for (j = 0; j < 256 && i+j < n; ++j) { - sprintf(buf, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "end readonly def\n", 17); - (*outputFunc)(outputStream, - "FontName currentdict end definefont pop\n", 40); - } - - // write the Type 0 parent font - (*outputFunc)(outputStream, "16 dict begin\n", 14); - (*outputFunc)(outputStream, "/FontName /", 11); - (*outputFunc)(outputStream, name, strlen(name)); - (*outputFunc)(outputStream, " def\n", 5); - (*outputFunc)(outputStream, "/FontType 0 def\n", 16); - (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30); - (*outputFunc)(outputStream, "/FMapType 2 def\n", 16); - (*outputFunc)(outputStream, "/Encoding [\n", 12); - for (i = 0; i < n; i += 256) { - sprintf(buf, "%d\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - (*outputFunc)(outputStream, "/FDepVector [\n", 14); - for (i = 0; i < n; i += 256) { - (*outputFunc)(outputStream, "/", 1); - (*outputFunc)(outputStream, name, strlen(name)); - sprintf(buf, "_%02x findfont\n", i >> 8); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - (*outputFunc)(outputStream, "] def\n", 6); - (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40); -} - -int TrueTypeFontFile::getByte(int pos) { - if (pos < 0 || pos >= len) { - return 0; - } - return file[pos] & 0xff; -} - -int TrueTypeFontFile::getChar(int pos) { - int x; - - if (pos < 0 || pos >= len) { - return 0; - } - x = file[pos] & 0xff; - if (x & 0x80) - x |= 0xffffff00; - return x; -} - -int TrueTypeFontFile::getUShort(int pos) { - int x; - - if (pos < 0 || pos+1 >= len) { - return 0; - } - x = file[pos] & 0xff; - x = (x << 8) + (file[pos+1] & 0xff); - return x; -} - -int TrueTypeFontFile::getShort(int pos) { - int x; - - if (pos < 0 || pos+1 >= len) { - return 0; - } - x = file[pos] & 0xff; - x = (x << 8) + (file[pos+1] & 0xff); - if (x & 0x8000) - x |= 0xffff0000; - return x; -} - -Guint TrueTypeFontFile::getULong(int pos) { - int x; - - if (pos < 0 || pos+3 >= len) { - return 0; - } - x = file[pos] & 0xff; - x = (x << 8) + (file[pos+1] & 0xff); - x = (x << 8) + (file[pos+2] & 0xff); - x = (x << 8) + (file[pos+3] & 0xff); - return x; -} - -double TrueTypeFontFile::getFixed(int pos) { - int x, y; - - x = getShort(pos); - y = getUShort(pos+2); - return (double)x + (double)y / 65536; -} - -int TrueTypeFontFile::seekTable(char *tag) { - int i; - - for (i = 0; i < nTables; ++i) { - if (!strncmp(tableHdrs[i].tag, tag, 4)) { - return (int)tableHdrs[i].offset; - } - } - return -1; -} - -int TrueTypeFontFile::seekTableIdx(char *tag) { - int i; - - for (i = 0; i < nTables; ++i) { - if (!strncmp(tableHdrs[i].tag, tag, 4)) { - if (tableHdrs[i].offset == (Guint)-1) { - return -1; - } - return i; - } - } - return -1; -} - -void TrueTypeFontFile::cvtEncoding(char **encodingA, GBool pdfFontHasEncoding, - FontFileOutputFunc outputFunc, - void *outputStream) { - char *name; - char buf[64]; - int i; - - (*outputFunc)(outputStream, "/Encoding 256 array\n", 20); - if (pdfFontHasEncoding) { - for (i = 0; i < 256; ++i) { - if (!(name = encodingA[i])) { - name = ".notdef"; - } - sprintf(buf, "dup %d /", i); - (*outputFunc)(outputStream, buf, strlen(buf)); - (*outputFunc)(outputStream, name, strlen(name)); - (*outputFunc)(outputStream, " put\n", 5); - } - } else { - for (i = 0; i < 256; ++i) { - sprintf(buf, "dup %d /c%02x put\n", i, i); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - } - (*outputFunc)(outputStream, "readonly def\n", 13); -} - -void TrueTypeFontFile::cvtCharStrings(char **encodingA, - GBool pdfFontHasEncoding, - Gushort *codeToGID, - FontFileOutputFunc outputFunc, - void *outputStream) { - char *name; - char buf[64], buf2[16]; - int i, k; - - // always define '.notdef' - (*outputFunc)(outputStream, "/CharStrings 256 dict dup begin\n", 32); - (*outputFunc)(outputStream, "/.notdef 0 def\n", 15); - - // if there's no 'cmap' table, punt - if (nCmaps == 0) { - goto err; - } - - // map char name to glyph index: - // 1. use encoding to map name to char code - // 2. use codeToGID to map char code to glyph index - // N.B. We do this in reverse order because font subsets can have - // weird encodings that use the same character name twice, and - // the first definition is probably the one we want. - k = 0; // make gcc happy - for (i = 255; i >= 0; --i) { - if (pdfFontHasEncoding) { - name = encodingA[i]; - } else { - sprintf(buf2, "c%02x", i); - name = buf2; - } - if (name && strcmp(name, ".notdef")) { - k = codeToGID[i]; - // note: Distiller (maybe Adobe's PS interpreter in general) - // doesn't like TrueType fonts that have CharStrings entries - // which point to nonexistent glyphs, hence the (k < nGlyphs) - // test - if (k > 0 && k < nGlyphs) { - (*outputFunc)(outputStream, "/", 1); - (*outputFunc)(outputStream, name, strlen(name)); - sprintf(buf, " %d def\n", k); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - } - } - - err: - (*outputFunc)(outputStream, "end readonly def\n", 17); -} - -int TrueTypeFontFile::getCmapEntry(int cmapFmt, int pos, int code) { - int cmapLen, cmapFirst; - int segCnt, segEnd, segStart, segDelta, segOffset; - int a, b, m, i; - - switch (cmapFmt) { - case 0: // byte encoding table (Apple standard) - cmapLen = getUShort(pos + 2); - if (code >= cmapLen) { - return 0; - } - return getByte(pos + 6 + code); - - case 4: // segment mapping to delta values (Microsoft standard) - segCnt = getUShort(pos + 6) / 2; - a = -1; - b = segCnt - 1; - segEnd = getUShort(pos + 14 + 2*b); - if (code > segEnd) { - // malformed font -- the TrueType spec requires the last segEnd - // to be 0xffff - return 0; - } - // invariant: seg[a].end < code <= seg[b].end - while (b - a > 1) { - m = (a + b) / 2; - segEnd = getUShort(pos + 14 + 2*m); - if (segEnd < code) { - a = m; - } else { - b = m; - } - } - segStart = getUShort(pos + 16 + 2*segCnt + 2*b); - segDelta = getUShort(pos + 16 + 4*segCnt + 2*b); - segOffset = getUShort(pos + 16 + 6*segCnt + 2*b); - if (code < segStart) { - return 0; - } - if (segOffset == 0) { - i = (code + segDelta) & 0xffff; - } else { - i = getUShort(pos + 16 + 6*segCnt + 2*b + - segOffset + 2 * (code - segStart)); - if (i != 0) { - i = (i + segDelta) & 0xffff; - } - } - return i; - - case 6: // trimmed table mapping - cmapFirst = getUShort(pos + 6); - cmapLen = getUShort(pos + 8); - if (code < cmapFirst || code >= cmapFirst + cmapLen) { - return 0; - } - return getUShort(pos + 10 + 2*(code - cmapFirst)); - - default: - // shouldn't happen - this is checked earlier - break; - } - return 0; -} - -static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) { - return ((TrueTypeLoca *)p1)->idx - ((TrueTypeLoca *)p2)->idx; -} - -static int cmpTrueTypeLocaPos(const void *p1, const void *p2) { - if (((TrueTypeLoca *)p1)->pos == ((TrueTypeLoca *)p2)->pos) { - return ((TrueTypeLoca *)p1)->idx - ((TrueTypeLoca *)p2)->idx; - } else { - return ((TrueTypeLoca *)p1)->pos - ((TrueTypeLoca *)p2)->pos; - } -} - -void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc, - void *outputStream, GString *name) { - TTFontTableHdr newTableHdrs[nT42Tables]; - char tableDir[12 + nT42Tables*16]; - char headTable[54]; - TrueTypeLoca *origLocaTable; - char *locaTable; - int nNewTables; - Guint checksum; - int pos, glyfPos, length, glyphLength, pad; - int i, j, k; - - // construct the 'head' table, zero out the font checksum - memcpy(headTable, file + seekTable("head"), 54); - headTable[8] = headTable[9] = headTable[10] = headTable[11] = (char)0; - - // read the original 'loca' table and sort it into proper order -- - // some (non-compliant) fonts have out-of-order loca tables; in - // order to correctly handle the case where (compliant) fonts have - // empty entries in the middle of the table, cmpTrueTypeLocaPos uses - // pos as its primary sort key, and idx as its secondary key - // (ensuring that adjacent entries with the same pos value remain in - // the same order) - origLocaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) * - sizeof(TrueTypeLoca)); - pos = seekTable("loca"); - for (i = 0; i <= nGlyphs; ++i) { - origLocaTable[i].idx = i; - if (locaFmt) { - origLocaTable[i].pos = getULong(pos + 4*i); - } else { - origLocaTable[i].pos = 2 * getUShort(pos + 2*i); - } - } - qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaPos); - for (i = 0; i < nGlyphs; ++i) { - origLocaTable[i].length = origLocaTable[i+1].pos - origLocaTable[i].pos; - } - origLocaTable[nGlyphs].length = 0; - qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaIdx); - - // construct the new 'loca' table, padding each glyph out to a - // multiple of 4 bytes - locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2)); - pos = 0; - for (i = 0; i <= nGlyphs; ++i) { - if (locaFmt) { - locaTable[4*i ] = (char)(pos >> 24); - locaTable[4*i+1] = (char)(pos >> 16); - locaTable[4*i+2] = (char)(pos >> 8); - locaTable[4*i+3] = (char) pos; - } else { - locaTable[2*i ] = (char)(pos >> 9); - locaTable[2*i+1] = (char)(pos >> 1); - } - length = origLocaTable[i].length; - if (length & 3) { - length += 4 - (length & 3); - } - pos += length; - } - - // count the number of tables - nNewTables = 0; - for (i = 0; i < nT42Tables; ++i) { - if (t42Tables[i].required || - seekTable(t42Tables[i].tag) >= 0) { - ++nNewTables; - } - } - - // construct the new table headers, including table checksums - // (pad each table out to a multiple of 4 bytes) - pos = 12 + nNewTables*16; - k = 0; - for (i = 0; i < nT42Tables; ++i) { - length = -1; - checksum = 0; // make gcc happy - if (i == t42HeadTable) { - length = 54; - checksum = computeTableChecksum(headTable, 54); - } else if (i == t42LocaTable) { - length = (nGlyphs + 1) * (locaFmt ? 4 : 2); - checksum = computeTableChecksum(locaTable, length); - } else if (i == t42GlyfTable) { - length = 0; - checksum = 0; - glyfPos = seekTable("glyf"); - for (j = 0; j < nGlyphs; ++j) { - glyphLength = origLocaTable[j].length; - pad = (glyphLength & 3) ? 4 - (glyphLength & 3) : 0; - length += glyphLength + pad; - if (glyphLength >= 0 && - glyfPos + origLocaTable[j].pos + glyphLength <= len) { - checksum += - computeTableChecksum(file + glyfPos + origLocaTable[j].pos, - glyphLength); - } - } - } else { - if ((j = seekTableIdx(t42Tables[i].tag)) >= 0) { - length = tableHdrs[j].length; - checksum = computeTableChecksum(file + tableHdrs[j].offset, length); - } else if (t42Tables[i].required) { - error(-1, "Embedded TrueType font is missing a required table ('%s')", - t42Tables[i].tag); - length = 0; - checksum = 0; - } - } - if (length >= 0) { - strncpy(newTableHdrs[k].tag, t42Tables[i].tag, 4); - newTableHdrs[k].checksum = checksum; - newTableHdrs[k].offset = pos; - newTableHdrs[k].length = length; - pad = (length & 3) ? 4 - (length & 3) : 0; - pos += length + pad; - ++k; - } - } - - // construct the table directory - tableDir[0] = 0x00; // sfnt version - tableDir[1] = 0x01; - tableDir[2] = 0x00; - tableDir[3] = 0x00; - tableDir[4] = 0; // numTables - tableDir[5] = nNewTables; - tableDir[6] = 0; // searchRange - tableDir[7] = (char)128; - tableDir[8] = 0; // entrySelector - tableDir[9] = 3; - tableDir[10] = 0; // rangeShift - tableDir[11] = (char)(16 * nNewTables - 128); - pos = 12; - for (i = 0; i < nNewTables; ++i) { - tableDir[pos ] = newTableHdrs[i].tag[0]; - tableDir[pos+ 1] = newTableHdrs[i].tag[1]; - tableDir[pos+ 2] = newTableHdrs[i].tag[2]; - tableDir[pos+ 3] = newTableHdrs[i].tag[3]; - tableDir[pos+ 4] = (char)(newTableHdrs[i].checksum >> 24); - tableDir[pos+ 5] = (char)(newTableHdrs[i].checksum >> 16); - tableDir[pos+ 6] = (char)(newTableHdrs[i].checksum >> 8); - tableDir[pos+ 7] = (char) newTableHdrs[i].checksum; - tableDir[pos+ 8] = (char)(newTableHdrs[i].offset >> 24); - tableDir[pos+ 9] = (char)(newTableHdrs[i].offset >> 16); - tableDir[pos+10] = (char)(newTableHdrs[i].offset >> 8); - tableDir[pos+11] = (char) newTableHdrs[i].offset; - tableDir[pos+12] = (char)(newTableHdrs[i].length >> 24); - tableDir[pos+13] = (char)(newTableHdrs[i].length >> 16); - tableDir[pos+14] = (char)(newTableHdrs[i].length >> 8); - tableDir[pos+15] = (char) newTableHdrs[i].length; - pos += 16; - } - - // compute the font checksum and store it in the head table - checksum = computeTableChecksum(tableDir, 12 + nNewTables*16); - for (i = 0; i < nNewTables; ++i) { - checksum += newTableHdrs[i].checksum; - } - checksum = 0xb1b0afba - checksum; // because the TrueType spec says so - headTable[ 8] = (char)(checksum >> 24); - headTable[ 9] = (char)(checksum >> 16); - headTable[10] = (char)(checksum >> 8); - headTable[11] = (char) checksum; - - // start the sfnts array - if (name) { - (*outputFunc)(outputStream, "/", 1); - (*outputFunc)(outputStream, name->getCString(), name->getLength()); - (*outputFunc)(outputStream, " [\n", 3); - } else { - (*outputFunc)(outputStream, "/sfnts [\n", 9); - } - - // write the table directory - dumpString(tableDir, 12 + nNewTables*16, outputFunc, outputStream); - - // write the tables - for (i = 0; i < nNewTables; ++i) { - if (i == t42HeadTable) { - dumpString(headTable, 54, outputFunc, outputStream); - } else if (i == t42LocaTable) { - length = (nGlyphs + 1) * (locaFmt ? 4 : 2); - dumpString(locaTable, length, outputFunc, outputStream); - } else if (i == t42GlyfTable) { - glyfPos = seekTable("glyf"); - for (j = 0; j < nGlyphs; ++j) { - length = origLocaTable[j].length; - if (length > 0 && - glyfPos + origLocaTable[j].pos + length <= len) { - dumpString(file + glyfPos + origLocaTable[j].pos, length, - outputFunc, outputStream); - } - } - } else { - // length == 0 means the table is missing and the error was - // already reported during the construction of the table - // headers - if ((length = newTableHdrs[i].length) > 0) { - j = seekTable(t42Tables[i].tag); - if (j >= 0) { - dumpString(file + seekTable(t42Tables[i].tag), length, - outputFunc, outputStream); - } - } - } - } - - // end the sfnts array - (*outputFunc)(outputStream, "] def\n", 6); - - gfree(origLocaTable); - gfree(locaTable); -} - -void TrueTypeFontFile::dumpString(char *s, int length, - FontFileOutputFunc outputFunc, - void *outputStream) { - char buf[64]; - int pad, i, j; - - (*outputFunc)(outputStream, "<", 1); - for (i = 0; i < length; i += 32) { - for (j = 0; j < 32 && i+j < length; ++j) { - sprintf(buf, "%02X", s[i+j] & 0xff); - (*outputFunc)(outputStream, buf, strlen(buf)); - } - if (i % (65536 - 32) == 65536 - 64) { - (*outputFunc)(outputStream, ">\n<", 3); - } else if (i+32 < length) { - (*outputFunc)(outputStream, "\n", 1); - } - } - if (length & 3) { - pad = 4 - (length & 3); - for (i = 0; i < pad; ++i) { - (*outputFunc)(outputStream, "00", 2); - } - } - // add an extra zero byte because the Adobe Type 42 spec says so - (*outputFunc)(outputStream, "00>\n", 4); -} - -Guint TrueTypeFontFile::computeTableChecksum(char *data, int length) { - Guint checksum, word; - int i; - - checksum = 0; - for (i = 0; i+3 < length; i += 4) { - word = ((data[i ] & 0xff) << 24) + - ((data[i+1] & 0xff) << 16) + - ((data[i+2] & 0xff) << 8) + - (data[i+3] & 0xff); - checksum += word; - } - if (length & 3) { - word = 0; - i = length & ~3; - switch (length & 3) { - case 3: - word |= (data[i+2] & 0xff) << 8; - case 2: - word |= (data[i+1] & 0xff) << 16; - case 1: - word |= (data[i ] & 0xff) << 24; - break; - } - checksum += word; - } - return checksum; -} - -void TrueTypeFontFile::writeTTF(FILE *out) { - static char cmapTab[20] = { - 0, 0, // table version number - 0, 1, // number of encoding tables - 0, 1, // platform ID - 0, 0, // encoding ID - 0, 0, 0, 12, // offset of subtable - 0, 0, // subtable format - 0, 1, // subtable length - 0, 1, // subtable version - 0, // map char 0 -> glyph 0 - 0 // pad to multiple of four bytes - }; - static char nameTab[8] = { - 0, 0, // format - 0, 0, // number of name records - 0, 6, // offset to start of string storage - 0, 0 // pad to multiple of four bytes - }; - static char postTab[32] = { - 0, 1, 0, 0, // format - 0, 0, 0, 0, // italic angle - 0, 0, // underline position - 0, 0, // underline thickness - 0, 0, 0, 0, // fixed pitch - 0, 0, 0, 0, // min Type 42 memory - 0, 0, 0, 0, // max Type 42 memory - 0, 0, 0, 0, // min Type 1 memory - 0, 0, 0, 0 // max Type 1 memory - }; - GBool haveCmap, haveName, havePost; - GBool dirCmap, dirName, dirPost; - GBool unsortedLoca; - int nNewTables, nZeroLengthTables, nAllTables; - TTFontTableHdr *newTableHdrs; - char *tableDir; - TrueTypeLoca *origLocaTable; - char *locaTable; - int length, glyfLength; - Guint t, pos, pos2, pos3; - int i, j, k; - - // check for missing/broken tables - haveCmap = seekTable("cmap") >= 0; - haveName = seekTable("name") >= 0; - havePost = seekTable("post") >= 0; - unsortedLoca = gFalse; - pos = seekTable("loca"); - pos2 = 0; - for (i = 0; i <= nGlyphs; ++i) { - if (locaFmt) { - pos3 = getULong(pos + 4*i); - } else { - pos3 = 2 * getUShort(pos + 2*i); - } - if (pos3 < pos2) { - unsortedLoca = gTrue; - break; - } - pos2 = pos3; - } - nNewTables = (haveCmap ? 0 : 1) + (haveName ? 0 : 1) + (havePost ? 0 : 1); - nZeroLengthTables = 0; - for (i = 0; i < nTables; ++i) { - if (tableHdrs[i].length == 0) { - ++nZeroLengthTables; - } - } - if (!nNewTables && !nZeroLengthTables && !mungedCmapSize && !unsortedLoca) { - // nothing is broken - write the TTF file as is - fwrite(file, 1, len, out); - return; - } - - // if the glyph data isn't sorted (as listed in the 'loca' table), - // construct a new 'loca' table - if (unsortedLoca) { - origLocaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) * - sizeof(TrueTypeLoca)); - pos = seekTable("loca"); - for (i = 0; i <= nGlyphs; ++i) { - origLocaTable[i].idx = i; - if (locaFmt) { - origLocaTable[i].pos = getULong(pos + 4*i); - } else { - origLocaTable[i].pos = 2 * getUShort(pos + 2*i); - } - } - qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca), - &cmpTrueTypeLocaPos); - for (i = 0; i < nGlyphs; ++i) { - origLocaTable[i].length = origLocaTable[i+1].pos - origLocaTable[i].pos; - } - origLocaTable[nGlyphs].length = 0; - qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca), - &cmpTrueTypeLocaIdx); - locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2)); - pos = 0; - for (i = 0; i <= nGlyphs; ++i) { - if (locaFmt) { - locaTable[4*i ] = (char)(pos >> 24); - locaTable[4*i+1] = (char)(pos >> 16); - locaTable[4*i+2] = (char)(pos >> 8); - locaTable[4*i+3] = (char) pos; - } else { - locaTable[2*i ] = (char)(pos >> 9); - locaTable[2*i+1] = (char)(pos >> 1); - } - length = origLocaTable[i].length; - if (length & 3) { - length += 4 - (length & 3); - } - pos += length; - } - glyfLength = pos; - } else { - origLocaTable = NULL; // make gcc happy - locaTable = NULL; // make gcc happy - glyfLength = 0; // make gcc happy - } - - // construct the new table directory - nAllTables = nTables - nZeroLengthTables + nNewTables; - newTableHdrs = (TTFontTableHdr *)gmalloc(nAllTables * - sizeof(TTFontTableHdr)); - dirCmap = haveCmap; - dirName = haveName; - dirPost = havePost; - pos = 12 + nAllTables * 16; - j = 0; - for (i = 0; i < nTables; ++i) { - if (!dirCmap && strncmp(tableHdrs[i].tag, "cmap", 4) > 0) { - memcpy(newTableHdrs[j].tag, "cmap", 4); - newTableHdrs[j].checksum = 0; //~ should compute the checksum - newTableHdrs[j].offset = pos; - pos += newTableHdrs[j].length = sizeof(cmapTab); - if (pos & 3) { - pos += 4 - (pos & 3); - } - ++j; - dirCmap = gTrue; - } - if (!dirName && strncmp(tableHdrs[i].tag, "name", 4) > 0) { - memcpy(newTableHdrs[j].tag, "name", 4); - newTableHdrs[j].checksum = 0; //~ should compute the checksum - newTableHdrs[j].offset = pos; - pos += newTableHdrs[j].length = sizeof(nameTab); - if (pos & 3) { - pos += 4 - (pos & 3); - } - ++j; - dirName = gTrue; - } - if (!dirPost && strncmp(tableHdrs[i].tag, "post", 4) > 0) { - memcpy(newTableHdrs[j].tag, "post", 4); - newTableHdrs[j].checksum = 0; //~ should compute the checksum - newTableHdrs[j].offset = pos; - pos += newTableHdrs[j].length = sizeof(postTab); - if (pos & 3) { - pos += 4 - (pos & 3); - } - ++j; - dirPost = gTrue; - } - // throw away zero-length tables - they confuse FreeType - if (tableHdrs[i].length > 0) { - memcpy(newTableHdrs[j].tag, tableHdrs[i].tag, 4); - newTableHdrs[j].checksum = tableHdrs[i].checksum; - newTableHdrs[j].offset = pos; - if (unsortedLoca && !strncmp(tableHdrs[i].tag, "loca", 4)) { - newTableHdrs[j].length = (nGlyphs + 1) * (locaFmt ? 4 : 2); - } else if (unsortedLoca && !strncmp(tableHdrs[i].tag, "glyf", 4)) { - newTableHdrs[j].length = glyfLength; - } else { - newTableHdrs[j].length = tableHdrs[i].length; - } - pos += newTableHdrs[j].length; - if (pos & 3) { - pos += 4 - (pos & 3); - } - ++j; - } - } - if (!dirCmap) { - memcpy(newTableHdrs[j].tag, "cmap", 4); - newTableHdrs[j].checksum = 0; //~ should compute the checksum - newTableHdrs[j].offset = pos; - pos += newTableHdrs[j].length = sizeof(cmapTab); - if (pos & 3) { - pos += 4 - (pos & 3); - } - ++j; - } - if (!dirName) { - memcpy(newTableHdrs[j].tag, "name", 4); - newTableHdrs[j].checksum = 0; //~ should compute the checksum - newTableHdrs[j].offset = pos; - pos += newTableHdrs[j].length = sizeof(nameTab); - if (pos & 3) { - pos += 4 - (pos & 3); - } - ++j; - } - if (!dirPost) { - memcpy(newTableHdrs[j].tag, "post", 4); - newTableHdrs[j].checksum = 0; //~ should compute the checksum - newTableHdrs[j].offset = pos; - pos += newTableHdrs[j].length = sizeof(postTab); - if (pos & 3) { - pos += 4 - (pos & 3); - } - ++j; - } - tableDir = (char *)gmalloc(12 + nAllTables * 16); - tableDir[0] = 0x00; // sfnt version - tableDir[1] = 0x01; - tableDir[2] = 0x00; - tableDir[3] = 0x00; - tableDir[4] = (char)((nAllTables >> 8) & 0xff); // numTables - tableDir[5] = (char)(nAllTables & 0xff); - for (i = -1, t = (Guint)nAllTables; t; ++i, t >>= 1) ; - t = 1 << (4 + i); - tableDir[6] = (char)((t >> 8) & 0xff); // searchRange - tableDir[7] = (char)(t & 0xff); - tableDir[8] = (char)((i >> 8) & 0xff); // entrySelector - tableDir[9] = (char)(i & 0xff); - t = nAllTables * 16 - t; - tableDir[10] = (char)((t >> 8) & 0xff); // rangeShift - tableDir[11] = (char)(t & 0xff); - pos = 12; - for (i = 0; i < nAllTables; ++i) { - tableDir[pos ] = newTableHdrs[i].tag[0]; - tableDir[pos+ 1] = newTableHdrs[i].tag[1]; - tableDir[pos+ 2] = newTableHdrs[i].tag[2]; - tableDir[pos+ 3] = newTableHdrs[i].tag[3]; - tableDir[pos+ 4] = (char)(newTableHdrs[i].checksum >> 24); - tableDir[pos+ 5] = (char)(newTableHdrs[i].checksum >> 16); - tableDir[pos+ 6] = (char)(newTableHdrs[i].checksum >> 8); - tableDir[pos+ 7] = (char) newTableHdrs[i].checksum; - tableDir[pos+ 8] = (char)(newTableHdrs[i].offset >> 24); - tableDir[pos+ 9] = (char)(newTableHdrs[i].offset >> 16); - tableDir[pos+10] = (char)(newTableHdrs[i].offset >> 8); - tableDir[pos+11] = (char) newTableHdrs[i].offset; - tableDir[pos+12] = (char)(newTableHdrs[i].length >> 24); - tableDir[pos+13] = (char)(newTableHdrs[i].length >> 16); - tableDir[pos+14] = (char)(newTableHdrs[i].length >> 8); - tableDir[pos+15] = (char) newTableHdrs[i].length; - pos += 16; - } - - // write the table directory - fwrite(tableDir, 1, 12 + 16 * nAllTables, out); - - // write the tables - for (i = 0; i < nAllTables; ++i) { - if (!haveCmap && !strncmp(newTableHdrs[i].tag, "cmap", 4)) { - fwrite(cmapTab, 1, newTableHdrs[i].length, out); - } else if (!haveName && !strncmp(newTableHdrs[i].tag, "name", 4)) { - fwrite(nameTab, 1, newTableHdrs[i].length, out); - } else if (!havePost && !strncmp(newTableHdrs[i].tag, "post", 4)) { - fwrite(postTab, 1, newTableHdrs[i].length, out); - } else if (unsortedLoca && !strncmp(newTableHdrs[i].tag, "loca", 4)) { - fwrite(locaTable, 1, newTableHdrs[i].length, out); - } else if (unsortedLoca && !strncmp(newTableHdrs[i].tag, "glyf", 4)) { - pos = seekTable("glyf"); - for (j = 0; j < nGlyphs; ++j) { - length = origLocaTable[j].length; - if (length > 0 && - pos + origLocaTable[j].pos + length <= (Guint)len) { - fwrite(file + pos + origLocaTable[j].pos, 1, length, out); - if ((k = length & 3)) { - for (; k < 4; ++k) { - fputc((char)0, out); - } - } - } - } - } else { - fwrite(file + seekTable(newTableHdrs[i].tag), - 1, newTableHdrs[i].length, out); - } - if ((j = (newTableHdrs[i].length & 3))) { - for (; j < 4; ++j) { - fputc((char)0, out); - } - } - } - - gfree(tableDir); - gfree(newTableHdrs); - if (unsortedLoca) { - gfree(origLocaTable); - gfree(locaTable); - } -} diff --git a/pdf/xpdf/FontFile.h b/pdf/xpdf/FontFile.h deleted file mode 100644 index 7aa5ba9..0000000 --- a/pdf/xpdf/FontFile.h +++ /dev/null @@ -1,261 +0,0 @@ -//======================================================================== -// -// FontFile.h -// -// Copyright 1999-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef FONTFILE_H -#define FONTFILE_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include "gtypes.h" -#include "GString.h" -#include "CharTypes.h" - -class GHash; -class CharCodeToUnicode; - -//------------------------------------------------------------------------ - -typedef void (*FontFileOutputFunc)(void *stream, char *data, int len); - -//------------------------------------------------------------------------ -// FontFile -//------------------------------------------------------------------------ - -class FontFile { -public: - - FontFile(); - virtual ~FontFile(); - - // Returns the font name, as specified internally by the font file. - // Returns NULL if no name is available. - virtual char *getName() = 0; - - // Returns the custom font encoding, or NULL if the encoding is not - // available. - virtual char **getEncoding() = 0; -}; - -//------------------------------------------------------------------------ -// Type1FontFile -//------------------------------------------------------------------------ - -class Type1FontFile: public FontFile { -public: - - Type1FontFile(char *file, int len); - virtual ~Type1FontFile(); - virtual char *getName() { return name; } - virtual char **getEncoding() { return encoding; } - -private: - - char *name; - char **encoding; -}; - -//------------------------------------------------------------------------ -// Type1CFontFile -//------------------------------------------------------------------------ - -struct Type1CTopDict; -struct Type1CPrivateDict; - -class Type1CFontFile: public FontFile { -public: - - Type1CFontFile(char *fileA, int lenA); - virtual ~Type1CFontFile(); - GBool isOk() { return ok; } - - virtual char *getName(); - virtual char **getEncoding(); - - // Convert to a Type 1 font, suitable for embedding in a PostScript - // file. The name will be used as the PostScript font name. - void convertToType1(FontFileOutputFunc outputFuncA, void *outputStreamA); - - // Convert to a Type 0 CIDFont, suitable for embedding in a - // PostScript file. The name will be used as the PostScript font - // name. - void convertToCIDType0(char *psName, - FontFileOutputFunc outputFuncA, void *outputStreamA); - - // Convert to a Type 0 (but non-CID) composite font, suitable for - // embedding in a PostScript file. The name will be used as the - // PostScript font name. - void convertToType0(char *psName, - FontFileOutputFunc outputFuncA, void *outputStreamA); - -private: - - void readEncoding(); - void readTopDict(Type1CTopDict *dict); - void readPrivateDict(Type1CPrivateDict *privateDict, - int offset, int size); - Gushort *readCharset(int charset, int nGlyphs); - void eexecWrite(char *s); - void eexecCvtGlyph(char *glyphName, int pos, int n); - void cvtGlyph(int pos, int n, GBool top); - void cvtGlyphWidth(GBool useOp); - void eexecDumpNum(double x, GBool fpA); - void eexecDumpOp1(int opA); - void eexecDumpOp2(int opA); - void eexecWriteCharstring(Guchar *s, int n); - void getDeltaInt(char *buf, char *key, double *opA, int n); - void getDeltaReal(char *buf, char *key, double *opA, int n); - int getIndexLen(int indexPos); - int getIndexValPos(int indexPos, int i, int *valLen); - int getIndexEnd(int indexPos); - Guint getWord(int pos, int size); - double getNum(int *pos, GBool *fp); - char *getString(int sid, char *buf); - - Guchar *file; - int len; - - GString *name; - char **encoding; - - int topDictIdxPos; - int stringIdxPos; - int gsubrIdxPos; - int subrIdxPos; - int gsubrBias; - int subrBias; - - FontFileOutputFunc outputFunc; - void *outputStream; - double op[48]; // operands - GBool fp[48]; // true if operand is fixed point - int nOps; // number of operands - int nHints; // number of hints for the current glyph - GBool firstOp; // true if we haven't hit the first op yet - double defaultWidthX; // default glyph width - double nominalWidthX; // nominal glyph width - GBool defaultWidthXFP; // true if defaultWidthX is fixed point - GBool nominalWidthXFP; // true if nominalWidthX is fixed point - Gushort r1; // eexec encryption key - GString *charBuf; // charstring output buffer - int line; // number of eexec chars on current line - - GBool ok; -}; - -//------------------------------------------------------------------------ -// TrueTypeFontFile -//------------------------------------------------------------------------ - -struct TTFontTableHdr; -struct TTFontCmap; - -class TrueTypeFontFile: public FontFile { -public: - - TrueTypeFontFile(char *fileA, int lenA); - ~TrueTypeFontFile(); - - // This always returns NULL, since it's probably better to trust the - // font name in the PDF file rather than the one in the TrueType - // font file. - virtual char *getName(); - - virtual char **getEncoding(); - - // Return the number of cmaps defined by this font. - int getNumCmaps(); - - // Return the platform ID of the th cmap. - int getCmapPlatform(int i); - - // Return the encoding ID of the th cmap. - int getCmapEncoding(int i); - - // Return the index of the cmap for , . Returns - // -1 if there is no corresponding cmap. - int findCmap(int platform, int enc); - - // Return the GID corresponding to according to the th cmap. - Gushort mapCodeToGID(int i, int c); - - // Return a name-to-GID mapping, constructed from the font's post - // table. Returns NULL if there is no post table. - GHash *getNameToGID(); - - // Convert to a Type 42 font, suitable for embedding in a PostScript - // file. The name will be used as the PostScript font name (so we - // don't need to depend on the 'name' table in the font). The - // encoding is needed because the PDF Font object can modify the - // encoding. - void convertToType42(char *name, char **encodingA, - GBool pdfFontHasEncoding, - Gushort *codeToGID, - FontFileOutputFunc outputFunc, void *outputStream); - - // Convert to a Type 2 CIDFont, suitable for embedding in a - // PostScript file. The name will be used as the PostScript font - // name (so we don't need to depend on the 'name' table in the - // font). - void convertToCIDType2(char *name, Gushort *cidMap, int nCIDs, - FontFileOutputFunc outputFunc, void *outputStream); - - // Convert to a Type 0 (but non-CID) composite font, suitable for - // embedding in a PostScript file. The name will be used as the - // PostScript font name (so we don't need to depend on the 'name' - // table in the font). - void convertToType0(char *name, Gushort *cidMap, int nCIDs, - FontFileOutputFunc outputFunc, void *outputStream); - - // Write a TTF file, filling in any missing tables that are required - // by the TrueType spec. If the font already has all the required - // tables, it will be written unmodified. - void writeTTF(FILE *out); - -private: - - char *file; - int len; - - char **encoding; - - TTFontTableHdr *tableHdrs; - int nTables; - int bbox[4]; - int locaFmt; - int nGlyphs; - GBool mungedCmapSize; - TTFontCmap *cmaps; - int nCmaps; - - int getByte(int pos); - int getChar(int pos); - int getUShort(int pos); - int getShort(int pos); - Guint getULong(int pos); - double getFixed(int pos); - int seekTable(char *tag); - int seekTableIdx(char *tag); - void cvtEncoding(char **encodingA, GBool pdfFontHasEncoding, - FontFileOutputFunc outputFunc, void *outputStream); - void cvtCharStrings(char **encodingA, GBool pdfFontHasEncoding, - Gushort *codeToGID, - FontFileOutputFunc outputFunc, void *outputStream); - int getCmapEntry(int cmapFmt, int pos, int code); - void cvtSfnts(FontFileOutputFunc outputFunc, void *outputStream, - GString *name); - void dumpString(char *s, int length, - FontFileOutputFunc outputFunc, void *outputStream); - Guint computeTableChecksum(char *data, int length); -}; - -#endif diff --git a/pdf/xpdf/Function.h b/pdf/xpdf/Function.h index d795a51..0ceb035 100644 --- a/pdf/xpdf/Function.h +++ b/pdf/xpdf/Function.h @@ -27,8 +27,8 @@ class PSStack; // Function //------------------------------------------------------------------------ -#define funcMaxInputs 8 -#define funcMaxOutputs 8 +#define funcMaxInputs 8 +#define funcMaxOutputs 32 class Function { public: diff --git a/pdf/xpdf/Gfx.cc b/pdf/xpdf/Gfx.cc index d108208..a52aa02 100644 --- a/pdf/xpdf/Gfx.cc +++ b/pdf/xpdf/Gfx.cc @@ -1254,6 +1254,7 @@ void Gfx::doPatternFill(GBool eoFill) { void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill) { GfxPatternColorSpace *patCS; GfxColorSpace *cs; + GfxPath *savedPath; double xMin, yMin, xMax, yMax, x, y, x1, y1; double cxMin, cyMin, cxMax, cyMax; int xi0, yi0, xi1, yi1, xi, yi; @@ -1303,6 +1304,7 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill) { imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det; // save current graphics state + savedPath = state->getPath()->copy(); saveState(); // set underlying color space (for uncolored tiling patterns); set @@ -1378,17 +1380,17 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill) { //~ edge instead of left/bottom (?) xstep = fabs(tPat->getXStep()); ystep = fabs(tPat->getYStep()); - xi0 = (int)floor(xMin / xstep); - xi1 = (int)ceil(xMax / xstep); - yi0 = (int)floor(yMin / ystep); - yi1 = (int)ceil(yMax / ystep); + xi0 = (int)floor((xMin - tPat->getBBox()[0]) / xstep); + xi1 = (int)ceil((xMax - tPat->getBBox()[0]) / xstep); + yi0 = (int)floor((yMin - tPat->getBBox()[1]) / ystep); + yi1 = (int)ceil((yMax - tPat->getBBox()[1]) / ystep); for (i = 0; i < 4; ++i) { m1[i] = m[i]; } for (yi = yi0; yi < yi1; ++yi) { for (xi = xi0; xi < xi1; ++xi) { - x = xi * xstep - tPat->getBBox()[0]; - y = yi * ystep - tPat->getBBox()[1]; + x = xi * xstep; + y = yi * ystep; m1[4] = x * m[0] + y * m[2] + m[4]; m1[5] = x * m[1] + y * m[3] + m[5]; doForm1(tPat->getContentStream(), tPat->getResDict(), @@ -1398,10 +1400,12 @@ void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill) { // restore graphics state restoreState(); + state->setPath(savedPath); } void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, GBool eoFill) { GfxShading *shading; + GfxPath *savedPath; double *ctm, *btm, *ptm; double m[6], ictm[6], m1[6]; double xMin, yMin, xMax, yMax; @@ -1410,6 +1414,7 @@ void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, GBool eoFill) { shading = sPat->getShading(); // save current graphics state + savedPath = state->getPath()->copy(); saveState(); // clip to bbox @@ -1483,10 +1488,12 @@ void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, GBool eoFill) { // restore graphics state restoreState(); + state->setPath(savedPath); } void Gfx::opShFill(Object args[], int numArgs) { GfxShading *shading; + GfxPath *savedPath; double xMin, yMin, xMax, yMax; if (!(shading = res->lookupShading(args[0].getName()))) { @@ -1494,6 +1501,7 @@ void Gfx::opShFill(Object args[], int numArgs) { } // save current graphics state + savedPath = state->getPath()->copy(); saveState(); // clip to bbox @@ -1527,6 +1535,7 @@ void Gfx::opShFill(Object args[], int numArgs) { // restore graphics state restoreState(); + state->setPath(savedPath); delete shading; } @@ -2335,6 +2344,8 @@ void Gfx::doShowText(GString *s) { newCTM[2] = mat[2] * newCTM[0] + mat[3] * newCTM[2]; newCTM[3] = mat[2] * newCTM[1] + mat[3] * newCTM[3]; newCTM[0] *= state->getFontSize(); + newCTM[1] *= state->getFontSize(); + newCTM[2] *= state->getFontSize(); newCTM[3] *= state->getFontSize(); newCTM[0] *= state->getHorizScaling(); newCTM[2] *= state->getHorizScaling(); @@ -2361,7 +2372,8 @@ void Gfx::doShowText(GString *s) { saveState(); state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y); //~ out->updateCTM(???) - if (!out->beginType3Char(state, code, u, uLen)) { + if (!out->beginType3Char(state, curX + riseX, curY + riseY, tdx, tdy, + code, u, uLen)) { ((Gfx8BitFont *)font)->getCharProc(code, &charProc); if ((resDict = ((Gfx8BitFont *)font)->getResources())) { pushResources(resDict); @@ -2970,7 +2982,7 @@ Stream *Gfx::buildImageStream() { obj.free(); // make stream - str = new EmbedStream(parser->getStream(), &dict); + str = new EmbedStream(parser->getStream(), &dict, gFalse, 0); str = str->addFilters(&dict); return str; diff --git a/pdf/xpdf/Gfx.h b/pdf/xpdf/Gfx.h index 20898ec..2069e97 100644 --- a/pdf/xpdf/Gfx.h +++ b/pdf/xpdf/Gfx.h @@ -35,7 +35,7 @@ class GfxFunctionShading; class GfxAxialShading; class GfxRadialShading; class GfxState; -class GfxColor; +struct GfxColor; class Gfx; class PDFRectangle; diff --git a/pdf/xpdf/GfxFont.cc b/pdf/xpdf/GfxFont.cc index 6f83676..ed9f076 100644 --- a/pdf/xpdf/GfxFont.cc +++ b/pdf/xpdf/GfxFont.cc @@ -17,7 +17,6 @@ #include #include #include "gmem.h" -#include "GHash.h" #include "Error.h" #include "Object.h" #include "Dict.h" @@ -26,7 +25,9 @@ #include "CharCodeToUnicode.h" #include "FontEncodingTables.h" #include "BuiltinFontTables.h" -#include "FontFile.h" +#include "FoFiType1.h" +#include "FoFiType1C.h" +#include "FoFiTrueType.h" #include "GfxFont.h" //------------------------------------------------------------------------ @@ -89,7 +90,10 @@ static StdFontMapEntry stdFontMap[] = { { "TimesNewRomanPS-BoldMT", "Times-Bold" }, { "TimesNewRomanPS-Italic", "Times-Italic" }, { "TimesNewRomanPS-ItalicMT", "Times-Italic" }, - { "TimesNewRomanPSMT", "Times-Roman" } + { "TimesNewRomanPSMT", "Times-Roman" }, + { "TimesNewRomanPSMT,Bold", "Times-Bold" }, + { "TimesNewRomanPSMT,BoldItalic", "Times-BoldItalic" }, + { "TimesNewRomanPSMT,Italic", "Times-Italic" } }; //------------------------------------------------------------------------ @@ -400,7 +404,8 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, GBool baseEncFromFontFile; char *buf; int len; - FontFile *fontFile; + FoFiType1 *ffT1; + FoFiType1C *ffT1C; int code, code2; char *charName; GBool missing, hex; @@ -554,43 +559,51 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, // check embedded or external font file for base encoding // (only for Type 1 fonts - trying to get an encoding out of a // TrueType font is a losing proposition) - fontFile = NULL; + ffT1 = NULL; + ffT1C = NULL; buf = NULL; - if ((type == fontType1 || type == fontType1C) && - (extFontFile || embFontID.num >= 0)) { + if (type == fontType1 && (extFontFile || embFontID.num >= 0)) { if (extFontFile) { - buf = readExtFontFile(&len); + ffT1 = FoFiType1::load(extFontFile->getCString()); } else { buf = readEmbFontFile(xref, &len); + ffT1 = FoFiType1::make(buf, len); } - if (buf) { - if (type == fontType1C && !strncmp(buf, "%!", 2)) { - // various tools (including Adobe's) occasionally embed Type 1 - // fonts but label them Type 1C - type = fontType1; - } - if (type == fontType1) { - fontFile = new Type1FontFile(buf, len); - } else { - fontFile = new Type1CFontFile(buf, len); - if (!((Type1CFontFile *)fontFile)->isOk()) { - delete fontFile; - fontFile = NULL; + if (ffT1) { + if (ffT1->getName()) { + if (embFontName) { + delete embFontName; } + embFontName = new GString(ffT1->getName()); + } + if (!baseEnc) { + baseEnc = ffT1->getEncoding(); + baseEncFromFontFile = gTrue; } - if (fontFile && fontFile->getName()) { + } + } else if (type == fontType1C && (extFontFile || embFontID.num >= 0)) { + if (extFontFile) { + ffT1C = FoFiType1C::load(extFontFile->getCString()); + } else { + buf = readEmbFontFile(xref, &len); + ffT1C = FoFiType1C::make(buf, len); + } + if (ffT1C) { + if (ffT1C->getName()) { if (embFontName) { delete embFontName; } - embFontName = new GString(fontFile->getName()); + embFontName = new GString(ffT1C->getName()); } - if (fontFile && !baseEnc) { - baseEnc = fontFile->getEncoding(); + if (!baseEnc) { + baseEnc = ffT1C->getEncoding(); baseEncFromFontFile = gTrue; } - gfree(buf); } } + if (buf) { + gfree(buf); + } // get default base encoding if (!baseEnc) { @@ -612,6 +625,20 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, } } + // some Type 1C font files have empty encodings, which can break the + // T1C->T1 conversion (since the 'seac' operator depends on having + // the accents in the encoding), so we fill in any gaps from + // StandardEncoding + if (type == fontType1C && (extFontFile || embFontID.num >= 0) && + baseEncFromFontFile) { + for (i = 0; i < 256; ++i) { + if (!enc[i] && standardEncoding[i]) { + enc[i] = standardEncoding[i]; + encFree[i] = gFalse; + } + } + } + // merge differences into encoding if (obj1.isDict()) { obj1.dictLookup("Differences", &obj2); @@ -641,8 +668,11 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA, obj2.free(); } obj1.free(); - if (fontFile) { - delete fontFile; + if (ffT1) { + delete ffT1; + } + if (ffT1C) { + delete ffT1C; } //----- build the mapping to Unicode ----- @@ -860,12 +890,11 @@ CharCodeToUnicode *Gfx8BitFont::getToUnicode() { return ctu; } -Gushort *Gfx8BitFont::getCodeToGIDMap(TrueTypeFontFile *ff) { +Gushort *Gfx8BitFont::getCodeToGIDMap(FoFiTrueType *ff) { Gushort *map; int cmapPlatform, cmapEncoding; int unicodeCmap, macRomanCmap, msSymbolCmap, cmap; GBool useMacRoman, useUnicode; - GHash *nameToGID; char *charName; Unicode u; int code, i, n; @@ -966,13 +995,10 @@ Gushort *Gfx8BitFont::getCodeToGIDMap(TrueTypeFontFile *ff) { } // try the TrueType 'post' table to handle any unmapped characters - if ((nameToGID = ff->getNameToGID())) { - for (i = 0; i < 256; ++i) { - if (!map[i] && (charName = enc[i])) { - map[i] = (Gushort)(int)nameToGID->lookup(charName); - } + for (i = 0; i < 256; ++i) { + if (!map[i] && (charName = enc[i])) { + map[i] = (Gushort)(int)ff->mapNameToGID(charName); } - delete nameToGID; } return map; @@ -983,7 +1009,7 @@ Dict *Gfx8BitFont::getCharProcs() { } Object *Gfx8BitFont::getCharProc(int code, Object *proc) { - if (charProcs.isDict()) { + if (enc[code] && charProcs.isDict()) { charProcs.dictLookup(enc[code], proc); } else { proc->initNull(); @@ -1406,7 +1432,9 @@ int GfxCIDFont::getWMode() { } CharCodeToUnicode *GfxCIDFont::getToUnicode() { - ctu->incRefCnt(); + if (ctu) { + ctu->incRefCnt(); + } return ctu; } diff --git a/pdf/xpdf/GfxFont.h b/pdf/xpdf/GfxFont.h index ddd88be..62dfd08 100644 --- a/pdf/xpdf/GfxFont.h +++ b/pdf/xpdf/GfxFont.h @@ -23,7 +23,7 @@ class Dict; class CMap; class CharCodeToUnicode; -class TrueTypeFontFile; +class FoFiTrueType; struct GfxFontCIDWidths; //------------------------------------------------------------------------ @@ -220,7 +220,7 @@ public: // Return a char code-to-GID mapping for the provided font file. // (This is only useful for TrueType fonts.) - Gushort *getCodeToGIDMap(TrueTypeFontFile *ff); + Gushort *getCodeToGIDMap(FoFiTrueType *ff); // Return the Type 3 CharProc dictionary, or NULL if none. Dict *getCharProcs(); diff --git a/pdf/xpdf/GfxState.cc b/pdf/xpdf/GfxState.cc index d202939..be60405 100644 --- a/pdf/xpdf/GfxState.cc +++ b/pdf/xpdf/GfxState.cc @@ -766,12 +766,18 @@ void GfxICCBasedColorSpace::getCMYK(GfxColor *color, GfxCMYK *cmyk) { void GfxICCBasedColorSpace::getDefaultRanges(double *decodeLow, double *decodeRange, int maxImgPixel) { + alt->getDefaultRanges(decodeLow, decodeRange, maxImgPixel); + +#if 0 + // this is nominally correct, but some PDF files don't set the + // correct ranges in the ICCBased dict int i; for (i = 0; i < nComps; ++i) { decodeLow[i] = rangeMin[i]; decodeRange[i] = rangeMax[i] - rangeMin[i]; } +#endif } //------------------------------------------------------------------------ @@ -1053,6 +1059,11 @@ GfxColorSpace *GfxDeviceNColorSpace::parse(Array *arr) { goto err2; } nCompsA = obj1.arrayGetLength(); + if (nCompsA > gfxColorMaxComps) { + error(-1, "DeviceN color space with more than %d > %d components", + nCompsA, gfxColorMaxComps); + nCompsA = gfxColorMaxComps; + } for (i = 0; i < nCompsA; ++i) { if (!obj1.arrayGet(i, &obj2)->isName()) { error(-1, "Bad DeviceN color space (names)"); @@ -2030,13 +2041,18 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode, colorSpace2 = indexedCS->getBase(); indexHigh = indexedCS->getIndexHigh(); nComps2 = colorSpace2->getNComps(); - lookup = (double *)gmalloc((indexHigh + 1) * nComps2 * sizeof(double)); + lookup = (double *)gmalloc((maxPixel + 1) * nComps2 * sizeof(double)); lookup2 = indexedCS->getLookup(); colorSpace2->getDefaultRanges(x, y, indexHigh); - for (i = 0; i <= indexHigh; ++i) { + for (i = 0; i <= maxPixel; ++i) { j = (int)(decodeLow[0] + (i * decodeRange[0]) / maxPixel + 0.5); + if (j < 0) { + j = 0; + } else if (j > indexHigh) { + j = indexHigh; + } for (k = 0; k < nComps2; ++k) { - lookup[j*nComps2 + k] = x[k] + (lookup2[i*nComps2 + k] / 255.0) * y[k]; + lookup[i*nComps2 + k] = x[k] + (lookup2[j*nComps2 + k] / 255.0) * y[k]; } } } else if (colorSpace->getMode() == csSeparation) { @@ -2079,17 +2095,15 @@ GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) { nComps2 = colorMap->nComps2; colorSpace2 = NULL; lookup = NULL; + n = 1 << bits; if (colorSpace->getMode() == csIndexed) { colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase(); - n = ((GfxIndexedColorSpace *)colorSpace)->getIndexHigh(); - n = (n + 1) * nComps2 * sizeof(double); + n = n * nComps2 * sizeof(double); } else if (colorSpace->getMode() == csSeparation) { colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt(); - n = (1 << bits) - 1; - n = (n + 1) * nComps2 * sizeof(double); + n = n * nComps2 * sizeof(double); } else { - n = (1 << bits) - 1; - n = (n + 1) * nComps * sizeof(double); + n = n * nComps * sizeof(double); } lookup = (double *)gmalloc(n); memcpy(lookup, colorMap->lookup, n); @@ -2497,6 +2511,11 @@ GfxState::GfxState(GfxState *state) { saved = NULL; } +void GfxState::setPath(GfxPath *pathA) { + delete path; + path = pathA; +} + void GfxState::getUserClipBBox(double *xMin, double *yMin, double *xMax, double *yMax) { double ictm[6]; diff --git a/pdf/xpdf/GfxState.h b/pdf/xpdf/GfxState.h index d072fd3..f747a83 100644 --- a/pdf/xpdf/GfxState.h +++ b/pdf/xpdf/GfxState.h @@ -429,7 +429,6 @@ private: *names[gfxColorMaxComps]; GfxColorSpace *alt; // alternate color space Function *func; // tint transform (into alternate color space) - }; //------------------------------------------------------------------------ @@ -910,6 +909,7 @@ public: double getRise() { return rise; } int getRender() { return render; } GfxPath *getPath() { return path; } + void setPath(GfxPath *pathA); double getCurX() { return curX; } double getCurY() { return curY; } void getClipBBox(double *xMin, double *yMin, double *xMax, double *yMax) diff --git a/pdf/xpdf/GlobalParams.cc b/pdf/xpdf/GlobalParams.cc index 9aa54e9..c125430 100644 --- a/pdf/xpdf/GlobalParams.cc +++ b/pdf/xpdf/GlobalParams.cc @@ -13,6 +13,7 @@ #endif #include +#include #include #if HAVE_PAPER_H #include @@ -49,7 +50,6 @@ #include "NameToUnicodeTable.h" #include "UnicodeMapTables.h" -#include "DisplayFontTable.h" #include "UTF8.h" //------------------------------------------------------------------------ @@ -59,6 +59,36 @@ //------------------------------------------------------------------------ +static struct { + char *name; + char *fileName; +} displayFontTab[] = { + {"Courier", "n022003l.pfb"}, + {"Courier-Bold", "n022004l.pfb"}, + {"Courier-BoldOblique", "n022024l.pfb"}, + {"Courier-Oblique", "n022023l.pfb"}, + {"Helvetica", "n019003l.pfb"}, + {"Helvetica-Bold", "n019004l.pfb"}, + {"Helvetica-BoldOblique", "n019024l.pfb"}, + {"Helvetica-Oblique", "n019023l.pfb"}, + {"Symbol", "s050000l.pfb"}, + {"Times-Bold", "n021004l.pfb"}, + {"Times-BoldItalic", "n021024l.pfb"}, + {"Times-Italic", "n021023l.pfb"}, + {"Times-Roman", "n021003l.pfb"}, + {"ZapfDingbats", "d050000l.pfb"}, + {NULL} +}; + +static char *displayFontDirs[] = { + "/usr/share/ghostscript/fonts", + "/usr/local/share/ghostscript/fonts", + "/usr/share/fonts/default/Type1", + NULL +}; + +//------------------------------------------------------------------------ + GlobalParams *globalParams = NULL; //------------------------------------------------------------------------ @@ -70,10 +100,6 @@ DisplayFontParam::DisplayFontParam(GString *nameA, name = nameA; kind = kindA; switch (kind) { - case displayFontX: - x.xlfd = NULL; - x.encoding = NULL; - break; case displayFontT1: t1.fileName = NULL; break; @@ -83,24 +109,9 @@ DisplayFontParam::DisplayFontParam(GString *nameA, } } -DisplayFontParam::DisplayFontParam(char *nameA, char *xlfdA, char *encodingA) { - name = new GString(nameA); - kind = displayFontX; - x.xlfd = new GString(xlfdA); - x.encoding = new GString(encodingA); -} - DisplayFontParam::~DisplayFontParam() { delete name; switch (kind) { - case displayFontX: - if (x.xlfd) { - delete x.xlfd; - } - if (x.encoding) { - delete x.encoding; - } - break; case displayFontT1: if (t1.fileName) { delete t1.fileName; @@ -140,7 +151,6 @@ PSFontParam::~PSFontParam() { GlobalParams::GlobalParams(char *cfgFileName) { UnicodeMap *map; - DisplayFontParam *dfp; GString *fileName; FILE *f; int i; @@ -190,6 +200,13 @@ GlobalParams::GlobalParams(char *cfgFileName) { psPaperWidth = defPaperWidth; psPaperHeight = defPaperHeight; #endif + psImageableLLX = psImageableLLY = 0; + psImageableURX = psPaperWidth; + psImageableURY = psPaperHeight; + psCrop = gTrue; + psExpandSmaller = gFalse; + psShrinkLarger = gTrue; + psCenter = gTrue; psDuplex = gFalse; psLevel = psLevel2; psFile = NULL; @@ -214,8 +231,9 @@ GlobalParams::GlobalParams(char *cfgFileName) { textKeepTinyChars = gFalse; fontDirs = new GList(); initialZoom = new GString("125"); - t1libControl = fontRastAALow; - freetypeControl = fontRastAALow; + enableT1lib = gTrue; + enableFreeType = gTrue; + antialias = gTrue; urlCommand = NULL; movieCommand = NULL; mapNumericCharNames = gTrue; @@ -251,14 +269,6 @@ GlobalParams::GlobalParams(char *cfgFileName) { map = new UnicodeMap("UCS-2", gTrue, &mapUCS2); residentUnicodeMaps->add(map->getEncodingName(), map); - // default displayFonts table - for (i = 0; displayFontTab[i].name; ++i) { - dfp = new DisplayFontParam(displayFontTab[i].name, - displayFontTab[i].xlfd, - displayFontTab[i].encoding); - displayFonts->add(dfp->name, dfp); - } - // look for a user config file, then a system-wide config file f = NULL; fileName = NULL; @@ -356,18 +366,10 @@ void GlobalParams::parseFile(GString *fileName, FILE *f) { parseCMapDir(tokens, fileName, line); } else if (!cmd->cmp("toUnicodeDir")) { parseToUnicodeDir(tokens, fileName, line); - } else if (!cmd->cmp("displayFontX")) { - parseDisplayFont(tokens, displayFonts, displayFontX, fileName, line); } else if (!cmd->cmp("displayFontT1")) { parseDisplayFont(tokens, displayFonts, displayFontT1, fileName, line); } else if (!cmd->cmp("displayFontTT")) { parseDisplayFont(tokens, displayFonts, displayFontTT, fileName, line); - } else if (!cmd->cmp("displayNamedCIDFontX")) { - parseDisplayFont(tokens, displayNamedCIDFonts, - displayFontX, fileName, line); - } else if (!cmd->cmp("displayCIDFontX")) { - parseDisplayFont(tokens, displayCIDFonts, - displayFontX, fileName, line); } else if (!cmd->cmp("displayNamedCIDFontT1")) { parseDisplayFont(tokens, displayNamedCIDFonts, displayFontT1, fileName, line); @@ -391,6 +393,17 @@ void GlobalParams::parseFile(GString *fileName, FILE *f) { parsePSFont16("psFont16", psFonts16, tokens, fileName, line); } else if (!cmd->cmp("psPaperSize")) { parsePSPaperSize(tokens, fileName, line); + } else if (!cmd->cmp("psImageableArea")) { + parsePSImageableArea(tokens, fileName, line); + } else if (!cmd->cmp("psCrop")) { + parseYesNo("psCrop", &psCrop, tokens, fileName, line); + } else if (!cmd->cmp("psExpandSmaller")) { + parseYesNo("psExpandSmaller", &psExpandSmaller, + tokens, fileName, line); + } else if (!cmd->cmp("psShrinkLarger")) { + parseYesNo("psShrinkLarger", &psShrinkLarger, tokens, fileName, line); + } else if (!cmd->cmp("psCenter")) { + parseYesNo("psCenter", &psCenter, tokens, fileName, line); } else if (!cmd->cmp("psDuplex")) { parseYesNo("psDuplex", &psDuplex, tokens, fileName, line); } else if (!cmd->cmp("psLevel")) { @@ -424,12 +437,12 @@ void GlobalParams::parseFile(GString *fileName, FILE *f) { parseFontDir(tokens, fileName, line); } else if (!cmd->cmp("initialZoom")) { parseInitialZoom(tokens, fileName, line); - } else if (!cmd->cmp("t1libControl")) { - parseFontRastControl("t1libControl", &t1libControl, - tokens, fileName, line); - } else if (!cmd->cmp("freetypeControl")) { - parseFontRastControl("freetypeControl", &freetypeControl, - tokens, fileName, line); + } else if (!cmd->cmp("enableT1lib")) { + parseYesNo("enableT1lib", &enableT1lib, tokens, fileName, line); + } else if (!cmd->cmp("enableFreeType")) { + parseYesNo("enableFreeType", &enableFreeType, tokens, fileName, line); + } else if (!cmd->cmp("antialias")) { + parseYesNo("antialias", &antialias, tokens, fileName, line); } else if (!cmd->cmp("urlCommand")) { parseCommand("urlCommand", &urlCommand, tokens, fileName, line); } else if (!cmd->cmp("movieCommand")) { @@ -441,12 +454,19 @@ void GlobalParams::parseFile(GString *fileName, FILE *f) { parseYesNo("printCommands", &printCommands, tokens, fileName, line); } else if (!cmd->cmp("errQuiet")) { parseYesNo("errQuiet", &errQuiet, tokens, fileName, line); - } else if (!cmd->cmp("fontpath") || !cmd->cmp("fontmap")) { - error(-1, "Unknown config file command"); - error(-1, "-- the config file format has changed since Xpdf 0.9x"); } else { error(-1, "Unknown config file command '%s' (%s:%d)", cmd->getCString(), fileName->getCString(), line); + if (!cmd->cmp("displayFontX") || + !cmd->cmp("displayNamedCIDFontX") || + !cmd->cmp("displayCIDFontX")) { + error(-1, "-- Xpdf no longer supports X fonts"); + } else if (!cmd->cmp("t1libControl") || !cmd->cmp("freetypeControl")) { + error(-1, "-- The t1libControl and freetypeControl options have been replaced"); + error(-1, " by the enableT1lib, enableFreeType, and antialias options"); + } else if (!cmd->cmp("fontpath") || !cmd->cmp("fontmap")) { + error(-1, "-- the config file format has changed since Xpdf 0.9x"); + } } } @@ -580,13 +600,6 @@ void GlobalParams::parseDisplayFont(GList *tokens, GHash *fontHash, param = new DisplayFontParam(((GString *)tokens->get(1))->copy(), kind); switch (kind) { - case displayFontX: - if (tokens->getLength() != 4) { - goto err2; - } - param->x.xlfd = ((GString *)tokens->get(2))->copy(); - param->x.encoding = ((GString *)tokens->get(3))->copy(); - break; case displayFontT1: if (tokens->getLength() != 3) { goto err2; @@ -629,12 +642,28 @@ void GlobalParams::parsePSPaperSize(GList *tokens, GString *fileName, psPaperWidth = atoi(tok->getCString()); tok = (GString *)tokens->get(2); psPaperHeight = atoi(tok->getCString()); + psImageableLLX = psImageableLLY = 0; + psImageableURX = psPaperWidth; + psImageableURY = psPaperHeight; } else { error(-1, "Bad 'psPaperSize' config file command (%s:%d)", fileName->getCString(), line); } } +void GlobalParams::parsePSImageableArea(GList *tokens, GString *fileName, + int line) { + if (tokens->getLength() != 5) { + error(-1, "Bad 'psImageableArea' config file command (%s:%d)", + fileName->getCString(), line); + return; + } + psImageableLLX = atoi(((GString *)tokens->get(1))->getCString()); + psImageableLLY = atoi(((GString *)tokens->get(2))->getCString()); + psImageableURX = atoi(((GString *)tokens->get(3))->getCString()); + psImageableURY = atoi(((GString *)tokens->get(4))->getCString()); +} + void GlobalParams::parsePSLevel(GList *tokens, GString *fileName, int line) { GString *tok; @@ -767,23 +796,6 @@ void GlobalParams::parseInitialZoom(GList *tokens, initialZoom = ((GString *)tokens->get(1))->copy(); } -void GlobalParams::parseFontRastControl(char *cmdName, FontRastControl *val, - GList *tokens, GString *fileName, - int line) { - GString *tok; - - if (tokens->getLength() != 2) { - error(-1, "Bad '%s' config file command (%s:%d)", - cmdName, fileName->getCString(), line); - return; - } - tok = (GString *)tokens->get(1); - if (!setFontRastControl(val, tok->getCString())) { - error(-1, "Bad '%s' config file command (%s:%d)", - cmdName, fileName->getCString(), line); - } -} - void GlobalParams::parseCommand(char *cmdName, GString **val, GList *tokens, GString *fileName, int line) { if (tokens->getLength() != 2) { @@ -807,14 +819,21 @@ void GlobalParams::parseYesNo(char *cmdName, GBool *flag, return; } tok = (GString *)tokens->get(1); - if (!tok->cmp("yes")) { + if (!parseYesNo2(tok->getCString(), flag)) { + error(-1, "Bad '%s' config file command (%s:%d)", + cmdName, fileName->getCString(), line); + } +} + +GBool GlobalParams::parseYesNo2(char *token, GBool *flag) { + if (!strcmp(token, "yes")) { *flag = gTrue; - } else if (!tok->cmp("no")) { + } else if (!strcmp(token, "no")) { *flag = gFalse; } else { - error(-1, "Bad '%s' config file command (%s:%d)", - cmdName, fileName->getCString(), line); + return gFalse; } + return gTrue; } GlobalParams::~GlobalParams() { @@ -870,6 +889,54 @@ GlobalParams::~GlobalParams() { } //------------------------------------------------------------------------ + +void GlobalParams::setupBaseFonts(char *dir) { + GString *fontName; + GString *fileName; + FILE *f; + DisplayFontParam *dfp; + int i, j; + + for (i = 0; displayFontTab[i].name; ++i) { + fontName = new GString(displayFontTab[i].name); + if (getDisplayFont(fontName)) { + delete fontName; + continue; + } + fileName = NULL; + if (dir) { + fileName = appendToPath(new GString(dir), displayFontTab[i].fileName); + if ((f = fopen(fileName->getCString(), "rb"))) { + fclose(f); + } else { + delete fileName; + fileName = NULL; + } + } +#ifndef WIN32 + for (j = 0; !fileName && displayFontDirs[j]; ++j) { + fileName = appendToPath(new GString(displayFontDirs[j]), + displayFontTab[i].fileName); + if ((f = fopen(fileName->getCString(), "rb"))) { + fclose(f); + } else { + delete fileName; + fileName = NULL; + } + } +#endif + if (!fileName) { + error(-1, "No display font for '%s'", displayFontTab[i].name); + delete fontName; + continue; + } + dfp = new DisplayFontParam(fontName, displayFontT1); + dfp->t1.fileName = fileName; + globalParams->addDisplayFont(dfp); + } +} + +//------------------------------------------------------------------------ // accessors //------------------------------------------------------------------------ @@ -1004,6 +1071,51 @@ int GlobalParams::getPSPaperHeight() { return h; } +void GlobalParams::getPSImageableArea(int *llx, int *lly, int *urx, int *ury) { + lockGlobalParams; + *llx = psImageableLLX; + *lly = psImageableLLY; + *urx = psImageableURX; + *ury = psImageableURY; + unlockGlobalParams; +} + +GBool GlobalParams::getPSCrop() { + GBool f; + + lockGlobalParams; + f = psCrop; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getPSExpandSmaller() { + GBool f; + + lockGlobalParams; + f = psExpandSmaller; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getPSShrinkLarger() { + GBool f; + + lockGlobalParams; + f = psShrinkLarger; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getPSCenter() { + GBool f; + + lockGlobalParams; + f = psCenter; + unlockGlobalParams; + return f; +} + GBool GlobalParams::getPSDuplex() { GBool d; @@ -1185,22 +1297,32 @@ GString *GlobalParams::getInitialZoom() { return s; } -FontRastControl GlobalParams::getT1libControl() { - FontRastControl c; +GBool GlobalParams::getEnableT1lib() { + GBool f; + + lockGlobalParams; + f = enableT1lib; + unlockGlobalParams; + return f; +} + +GBool GlobalParams::getEnableFreeType() { + GBool f; lockGlobalParams; - c = t1libControl; + f = enableFreeType; unlockGlobalParams; - return c; + return f; } -FontRastControl GlobalParams::getFreeTypeControl() { - FontRastControl c; + +GBool GlobalParams::getAntialias() { + GBool f; lockGlobalParams; - c = freetypeControl; + f = antialias; unlockGlobalParams; - return c; + return f; } GBool GlobalParams::getMapNumericCharNames() { @@ -1345,6 +1467,9 @@ GBool GlobalParams::setPSPaperSize(char *size) { unlockGlobalParams; return gFalse; } + psImageableLLX = psImageableLLY = 0; + psImageableURX = psPaperWidth; + psImageableURY = psPaperHeight; unlockGlobalParams; return gTrue; } @@ -1352,12 +1477,49 @@ GBool GlobalParams::setPSPaperSize(char *size) { void GlobalParams::setPSPaperWidth(int width) { lockGlobalParams; psPaperWidth = width; + psImageableLLX = 0; + psImageableURX = psPaperWidth; unlockGlobalParams; } void GlobalParams::setPSPaperHeight(int height) { lockGlobalParams; psPaperHeight = height; + psImageableLLY = 0; + psImageableURY = psPaperHeight; + unlockGlobalParams; +} + +void GlobalParams::setPSImageableArea(int llx, int lly, int urx, int ury) { + lockGlobalParams; + psImageableLLX = llx; + psImageableLLY = lly; + psImageableURX = urx; + psImageableURY = ury; + unlockGlobalParams; +} + +void GlobalParams::setPSCrop(GBool crop) { + lockGlobalParams; + psCrop = crop; + unlockGlobalParams; +} + +void GlobalParams::setPSExpandSmaller(GBool expand) { + lockGlobalParams; + psExpandSmaller = expand; + unlockGlobalParams; +} + +void GlobalParams::setPSShrinkLarger(GBool shrink) { + lockGlobalParams; + psShrinkLarger = shrink; + unlockGlobalParams; +} + +void GlobalParams::setPSCenter(GBool center) { + lockGlobalParams; + psCenter = center; unlockGlobalParams; } @@ -1451,40 +1613,32 @@ void GlobalParams::setInitialZoom(char *s) { unlockGlobalParams; } -GBool GlobalParams::setT1libControl(char *s) { +GBool GlobalParams::setEnableT1lib(char *s) { GBool ok; lockGlobalParams; - ok = setFontRastControl(&t1libControl, s); + ok = parseYesNo2(s, &enableT1lib); unlockGlobalParams; return ok; } -GBool GlobalParams::setFreeTypeControl(char *s) { +GBool GlobalParams::setEnableFreeType(char *s) { GBool ok; lockGlobalParams; - ok = setFontRastControl(&freetypeControl, s); + ok = parseYesNo2(s, &enableFreeType); unlockGlobalParams; return ok; } -GBool GlobalParams::setFontRastControl(FontRastControl *val, char *s) { + +GBool GlobalParams::setAntialias(char *s) { + GBool ok; + lockGlobalParams; - if (!strcmp(s, "none")) { - *val = fontRastNone; - } else if (!strcmp(s, "plain")) { - *val = fontRastPlain; - } else if (!strcmp(s, "low")) { - *val = fontRastAALow; - } else if (!strcmp(s, "high")) { - *val = fontRastAAHigh; - } else { - unlockGlobalParams; - return gFalse; - } + ok = parseYesNo2(s, &antialias); unlockGlobalParams; - return gTrue; + return ok; } void GlobalParams::setMapNumericCharNames(GBool map) { diff --git a/pdf/xpdf/GlobalParams.h b/pdf/xpdf/GlobalParams.h index 472beed..93ec06a 100644 --- a/pdf/xpdf/GlobalParams.h +++ b/pdf/xpdf/GlobalParams.h @@ -43,7 +43,6 @@ extern GlobalParams *globalParams; //------------------------------------------------------------------------ enum DisplayFontParamKind { - displayFontX, displayFontT1, displayFontTT }; @@ -57,10 +56,6 @@ public: DisplayFontParamKind kind; union { struct { - GString *xlfd; - GString *encoding; - } x; - struct { GString *fileName; } t1; struct { @@ -69,18 +64,9 @@ public: }; DisplayFontParam(GString *nameA, DisplayFontParamKind kindA); - DisplayFontParam(char *nameA, char *xlfdA, char *encodingA); ~DisplayFontParam(); }; -// Font rasterizer control. -enum FontRastControl { - fontRastNone, // don't use this rasterizer - fontRastPlain, // use it, without anti-aliasing - fontRastAALow, // use it, with low-level anti-aliasing - fontRastAAHigh // use it, with high-level anti-aliasing -}; - //------------------------------------------------------------------------ class PSFontParam { @@ -129,6 +115,8 @@ public: ~GlobalParams(); + void setupBaseFonts(char *dir); + //----- accessors CharCode getMacRomanCharCode(char *charName); @@ -143,7 +131,12 @@ public: GString *getPSFile(); int getPSPaperWidth(); int getPSPaperHeight(); + void getPSImageableArea(int *llx, int *lly, int *urx, int *ury); GBool getPSDuplex(); + GBool getPSCrop(); + GBool getPSExpandSmaller(); + GBool getPSShrinkLarger(); + GBool getPSCenter(); PSLevel getPSLevel(); PSFontParam *getPSFont(GString *fontName); PSFontParam *getPSFont16(GString *fontName, GString *collection, int wMode); @@ -159,8 +152,9 @@ public: GBool getTextKeepTinyChars(); GString *findFontFile(GString *fontName, char **exts); GString *getInitialZoom(); - FontRastControl getT1libControl(); - FontRastControl getFreeTypeControl(); + GBool getEnableT1lib(); + GBool getEnableFreeType(); + GBool getAntialias(); GString *getURLCommand() { return urlCommand; } GString *getMovieCommand() { return movieCommand; } GBool getMapNumericCharNames(); @@ -180,7 +174,12 @@ public: GBool setPSPaperSize(char *size); void setPSPaperWidth(int width); void setPSPaperHeight(int height); + void setPSImageableArea(int llx, int lly, int urx, int ury); void setPSDuplex(GBool duplex); + void setPSCrop(GBool crop); + void setPSExpandSmaller(GBool expand); + void setPSShrinkLarger(GBool shrink); + void setPSCenter(GBool center); void setPSLevel(PSLevel level); void setPSEmbedType1(GBool embed); void setPSEmbedTrueType(GBool embed); @@ -193,8 +192,9 @@ public: void setTextPageBreaks(GBool pageBreaks); void setTextKeepTinyChars(GBool keep); void setInitialZoom(char *s); - GBool setT1libControl(char *s); - GBool setFreeTypeControl(char *s); + GBool setEnableT1lib(char *s); + GBool setEnableFreeType(char *s); + GBool setAntialias(char *s); void setMapNumericCharNames(GBool map); void setPrintCommands(GBool printCommandsA); void setErrQuiet(GBool errQuietA); @@ -213,6 +213,7 @@ private: GString *fileName, int line); void parsePSFile(GList *tokens, GString *fileName, int line); void parsePSPaperSize(GList *tokens, GString *fileName, int line); + void parsePSImageableArea(GList *tokens, GString *fileName, int line); void parsePSLevel(GList *tokens, GString *fileName, int line); void parsePSFont(GList *tokens, GString *fileName, int line); void parsePSFont16(char *cmdName, GList *fontList, @@ -221,14 +222,12 @@ private: void parseTextEOL(GList *tokens, GString *fileName, int line); void parseFontDir(GList *tokens, GString *fileName, int line); void parseInitialZoom(GList *tokens, GString *fileName, int line); - void parseFontRastControl(char *cmdName, FontRastControl *val, - GList *tokens, GString *fileName, int line); void parseCommand(char *cmdName, GString **val, GList *tokens, GString *fileName, int line); void parseYesNo(char *cmdName, GBool *flag, GList *tokens, GString *fileName, int line); + GBool parseYesNo2(char *token, GBool *flag); UnicodeMap *getUnicodeMap2(GString *encodingName); - GBool setFontRastControl(FontRastControl *val, char *s); //----- static tables @@ -260,6 +259,14 @@ private: GString *psFile; // PostScript file or command (for xpdf) int psPaperWidth; // paper size, in PostScript points, for int psPaperHeight; // PostScript output + int psImageableLLX, // imageable area, in PostScript points, + psImageableLLY, // for PostScript output + psImageableURX, + psImageableURY; + GBool psCrop; // crop PS output to CropBox + GBool psExpandSmaller; // expand smaller pages to fill paper + GBool psShrinkLarger; // shrink larger pages to fit paper + GBool psCenter; // center pages on the paper GBool psDuplex; // enable duplexing in PostScript? PSLevel psLevel; // PostScript level to generate GHash *psFonts; // PostScript font info, indexed by PDF @@ -280,9 +287,9 @@ private: GBool textKeepTinyChars; // keep all characters in text output GList *fontDirs; // list of font dirs [GString] GString *initialZoom; // initial zoom level - FontRastControl t1libControl; // t1lib rasterization mode - FontRastControl // FreeType rasterization mode - freetypeControl; + GBool enableT1lib; // t1lib enable flag + GBool enableFreeType; // FreeType enable flag + GBool antialias; // anti-aliasing enable flag GString *urlCommand; // command executed for URL links GString *movieCommand; // command executed for movie annotations GBool mapNumericCharNames; // map numeric char names (from font subsets)? diff --git a/pdf/xpdf/Makefile.am b/pdf/xpdf/Makefile.am index 96d57ec..db62813 100644 --- a/pdf/xpdf/Makefile.am +++ b/pdf/xpdf/Makefile.am @@ -4,6 +4,8 @@ INCLUDES = \ -I$(top_srcdir) \ -I$(top_srcdir)/goo \ -I$(top_srcdir)/lib/ggv-sidebar \ + -I$(top_srcdir)/fofi \ + -I$(top_srcdir)/splash \ -DDATADIR=\""$(datadir)"\" \ -DGNOMELOCALEDIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \ -DGNOMEICONDIR=\""$(datadir)/pixmaps"\" \ @@ -55,8 +57,6 @@ libxpdf_a_SOURCES = \ Error.h \ FontEncodingTables.cc \ FontEncodingTables.h \ - FontFile.cc \ - FontFile.h \ Function.cc \ Function.h \ Gfx.cc \ @@ -67,8 +67,12 @@ libxpdf_a_SOURCES = \ GfxState.h \ GlobalParams.cc \ GlobalParams.h \ + JArithmeticDecoder.cc \ + JArithmeticDecoder.h \ JBIG2Stream.cc \ JBIG2Stream.h \ + JPXStream.cc \ + JPXStream.h \ Lexer.cc \ Lexer.h \ Link.cc \ @@ -98,23 +102,15 @@ libxpdf_a_SOURCES = \ UnicodeMap.h \ UnicodeMapTables.h \ UnicodeTypeTable.cc \ + UnicodeTypeTable.h \ XRef.cc \ XRef.h common_sources = \ CharTypes.h \ CompactFontTables.h \ - DisplayFontTable.h \ ErrorCodes.h \ - FTFont.cc \ - FTFont.h \ NameToUnicodeTable.h \ - SFont.cc \ - SFont.h \ - T1Font.cc \ - T1Font.h \ - TTFont.cc \ - TTFont.h \ TextOutputDev.cc \ TextOutputDev.h \ UTF8.h @@ -200,12 +196,15 @@ gnome_pdf_viewer_LDADD = \ libxpdf.a \ libgpdf.a \ $(top_builddir)/goo/libGoo.a \ + $(top_builddir)/fofi/libfofi.a \ $(top_builddir)/lib/ggv-sidebar/libggv-sidebar.a \ $(EXTRA_GNOME_LIBS) \ $(libpaper_LIBS) xpdf_SOURCES = \ $(common_sources) \ + SplashOutputDev.cc \ + SplashOutputDev.h \ XPDFApp.cc \ XPDFApp.h \ XPDFCore.cc \ @@ -214,10 +213,8 @@ xpdf_SOURCES = \ XPDFTree.h \ XPDFViewer.cc \ XPDFViewer.h \ - XOutputDev.cc \ - XOutputDev.h \ - XPixmapOutputDev.cc \ - XPixmapOutputDev.h \ + XSplashOutputDev.cc \ + XSplashOutputDev.h \ PSOutputDev.cc \ PSOutputDev.h \ xpdf.cc @@ -254,16 +251,14 @@ xpdf_LDADD = \ # pdfinfo.cc #pdfinfo_LDADD = ../goo/libGoo.a -#pdftopbm_SOURCES = +#pdftopüm_SOURCES = # $(common_sources) -# PBMOutputDev.cc -# PBMOutputDev.h # XOutputDev.cc # XOutputDev.h # XOutputFontInfo.h # pdftopbm.cc -#pdftopbm_LDADD = ../goo/libGoo.a $(EXTRA_GNOME_LIBS) +#pdftoppm_LDADD = ../goo/libGoo.a $(EXTRA_GNOME_LIBS) #bitmaps = # about.xbm diff --git a/pdf/xpdf/Object.cc b/pdf/xpdf/Object.cc index b0976fd..ddd6da6 100644 --- a/pdf/xpdf/Object.cc +++ b/pdf/xpdf/Object.cc @@ -58,6 +58,13 @@ Object *Object::initDict(XRef *xref) { return this; } +Object *Object::initDict(Dict *dictA) { + initObj(objDict); + dict = dictA; + dict->incRef(); + return this; +} + Object *Object::initStream(Stream *streamA) { initObj(objStream); stream = streamA; diff --git a/pdf/xpdf/Object.h b/pdf/xpdf/Object.h index 8f0b370..8b1807c 100644 --- a/pdf/xpdf/Object.h +++ b/pdf/xpdf/Object.h @@ -95,6 +95,7 @@ public: { initObj(objNull); return this; } Object *initArray(XRef *xref); Object *initDict(XRef *xref); + Object *initDict(Dict *dictA); Object *initStream(Stream *streamA); Object *initRef(int numA, int genA) { initObj(objRef); ref.num = numA; ref.gen = genA; return this; } diff --git a/pdf/xpdf/Outline.cc b/pdf/xpdf/Outline.cc index 23efed1..b7e0645 100644 --- a/pdf/xpdf/Outline.cc +++ b/pdf/xpdf/Outline.cc @@ -22,15 +22,17 @@ //------------------------------------------------------------------------ Outline::Outline(Object *outlineObj, XRef *xref) { - Object first; + Object first, last; items = NULL; if (!outlineObj->isDict()) { return; } items = OutlineItem::readItemList(outlineObj->dictLookupNF("First", &first), + outlineObj->dictLookupNF("Last", &last), xref); first.free(); + last.free(); } Outline::~Outline() { @@ -68,6 +70,8 @@ OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) { title[i] = pdfDocEncoding[s->getChar(i) & 0xff]; } } + } else { + titleLen = 0; } obj1.free(); @@ -82,6 +86,7 @@ OutlineItem::OutlineItem(Dict *dict, XRef *xrefA) { obj1.free(); dict->lookupNF("First", &firstRef); + dict->lookupNF("Last", &lastRef); dict->lookupNF("Next", &nextRef); startsOpen = gFalse; @@ -102,17 +107,19 @@ OutlineItem::~OutlineItem() { delete action; } firstRef.free(); + lastRef.free(); nextRef.free(); } -GList *OutlineItem::readItemList(Object *itemRef, XRef *xrefA) { +GList *OutlineItem::readItemList(Object *firstItemRef, Object *lastItemRef, + XRef *xrefA) { GList *items; OutlineItem *item; Object obj; Object *p; items = new GList(); - p = itemRef; + p = firstItemRef; while (p->isRef()) { if (!p->fetch(xrefA, &obj)->isDict()) { obj.free(); @@ -121,6 +128,10 @@ GList *OutlineItem::readItemList(Object *itemRef, XRef *xrefA) { item = new OutlineItem(obj.getDict(), xrefA); obj.free(); items->append(item); + if (p->getRef().num == lastItemRef->getRef().num && + p->getRef().gen == lastItemRef->getRef().gen) { + break; + } p = &item->nextRef; } return items; @@ -128,7 +139,7 @@ GList *OutlineItem::readItemList(Object *itemRef, XRef *xrefA) { void OutlineItem::open() { if (!kids) { - kids = readItemList(&firstRef, xref); + kids = readItemList(&firstRef, &lastRef, xref); } } diff --git a/pdf/xpdf/OutputDev.cc b/pdf/xpdf/OutputDev.cc index cbb5df5..e83882d 100644 --- a/pdf/xpdf/OutputDev.cc +++ b/pdf/xpdf/OutputDev.cc @@ -60,7 +60,8 @@ void OutputDev::updateAll(GfxState *state) { updateFont(state); } -GBool OutputDev::beginType3Char(GfxState *state, +GBool OutputDev::beginType3Char(GfxState *state, double x, double y, + double dx, double dy, CharCode code, Unicode *u, int uLen) { return gFalse; } diff --git a/pdf/xpdf/OutputDev.h b/pdf/xpdf/OutputDev.h index 67737af..bbf8b69 100644 --- a/pdf/xpdf/OutputDev.h +++ b/pdf/xpdf/OutputDev.h @@ -126,7 +126,8 @@ public: double originX, double originY, CharCode code, Unicode *u, int uLen) {} virtual void drawString(GfxState *state, GString *s) {} - virtual GBool beginType3Char(GfxState *state, + virtual GBool beginType3Char(GfxState *state, double x, double y, + double dx, double dy, CharCode code, Unicode *u, int uLen); virtual void endType3Char(GfxState *state) {} virtual void endTextObject(GfxState *state) {} diff --git a/pdf/xpdf/PBMOutputDev.cc b/pdf/xpdf/PBMOutputDev.cc deleted file mode 100644 index dde860a..0000000 --- a/pdf/xpdf/PBMOutputDev.cc +++ /dev/null @@ -1,162 +0,0 @@ -//======================================================================== -// -// PBMOutputDev.cc -// -// Copyright 1998-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include -#include "gmem.h" -#include "GString.h" -#include "Object.h" -#include "Stream.h" -#include "GfxState.h" -#include "GfxFont.h" -#include "Error.h" -#include "PBMOutputDev.h" - -//------------------------------------------------------------------------ - -PBMOutputDev *PBMOutputDev::makePBMOutputDev(char *displayName, - char *fileRootA) { - Display *displayA; - Pixmap pixmapA; - Window dummyWinA; - int screenA; - int invertA; - unsigned long black, white; - PBMOutputDev *out; - - if (!(displayA = XOpenDisplay(displayName))) { - fprintf(stderr, "Couldn't open display '%s'\n", displayName); - exit(1); - } - screenA = DefaultScreen(displayA); - - black = BlackPixel(displayA, screenA); - white = WhitePixel(displayA, screenA); - if ((black & 1) == (white & 1)) { - fprintf(stderr, "Weird black/white pixel colors\n"); - XCloseDisplay(displayA); - return NULL; - } - invertA = (white & 1) == 1 ? 0xff : 0x00; - - dummyWinA = XCreateSimpleWindow(displayA, RootWindow(displayA, screenA), - 0, 0, 1, 1, 0, - black, white); - pixmapA = XCreatePixmap(displayA, dummyWinA, 1, 1, 1); - out = new PBMOutputDev(displayA, screenA, pixmapA, dummyWinA, - invertA, fileRootA); - return out; -} - -void PBMOutputDev::killPBMOutputDev(PBMOutputDev *out) { - Display *displayA; - Pixmap pixmapA; - Window dummyWinA; - - displayA = out->display; - pixmapA = out->pixmap; - dummyWinA = out->dummyWin; - - delete out; - - // these have to be done *after* the XOutputDev (parent of the - // PBMOutputDev) is deleted, since XOutputDev::~XOutputDev() needs - // them - XFreePixmap(displayA, pixmapA); - XDestroyWindow(displayA, dummyWinA); - XCloseDisplay(displayA); -} - -PBMOutputDev::PBMOutputDev(Display *displayA, int screenA, - Pixmap pixmapA, Window dummyWinA, - int invertA, char *fileRootA): - XOutputDev(displayA, screenA, - DefaultVisual(displayA, screenA), - DefaultColormap(displayA, screenA), - gFalse, - WhitePixel(displayA, DefaultScreen(displayA)), - gFalse, 1, 1) -{ - display = displayA; - screen = screenA; - pixmap = pixmapA; - dummyWin = dummyWinA; - invert = invertA; - fileRoot = fileRootA; - fileName = (char *)gmalloc(strlen(fileRoot) + 20); -} - -PBMOutputDev::~PBMOutputDev() { - gfree(fileName); -} - -void PBMOutputDev::startPage(int pageNum, GfxState *state) { - curPage = pageNum; - width = (int)(state->getPageWidth() + 0.5); - height = (int)(state->getPageHeight() + 0.5); - XFreePixmap(display, pixmap); - pixmap = XCreatePixmap(display, dummyWin, width, height, 1); - setPixmap(pixmap, width, height); - XOutputDev::startPage(pageNum, state); -} - -void PBMOutputDev::endPage() { - XImage *image; - FILE *f; - int p; - int x, y, i; - - image = XCreateImage(display, DefaultVisual(display, screen), - 1, ZPixmap, 0, NULL, width, height, 8, 0); - image->data = (char *)gmalloc(height * image->bytes_per_line); - XGetSubImage(display, pixmap, 0, 0, width, height, 1, ZPixmap, - image, 0, 0); - - sprintf(fileName, "%s-%06d.pbm", fileRoot, curPage); - if (!(f = fopen(fileName, "wb"))) { - fprintf(stderr, "Couldn't open output file '%s'\n", fileName); - goto err; - } - fprintf(f, "P4\n"); - fprintf(f, "%d %d\n", width, height); - - for (y = 0; y < height; ++y) { - for (x = 0; x+8 <= width; x += 8) { - p = 0; - for (i = 0; i < 8; ++i) - p = (p << 1) + (XGetPixel(image, x+i, y) & 1); - p ^= invert; - fputc((char)p, f); - } - if (width & 7) { - p = 0; - for (i = 0; i < (width & 7); ++i) - p = (p << 1) + (XGetPixel(image, x+i, y) & 1); - p <<= 8 - (width & 7); - p ^= invert; - fputc((char)p, f); - } - } - - fclose(f); - - err: - gfree(image->data); - image->data = NULL; - XDestroyImage(image); - - XOutputDev::endPage(); -} diff --git a/pdf/xpdf/PBMOutputDev.h b/pdf/xpdf/PBMOutputDev.h deleted file mode 100644 index 9d1539d..0000000 --- a/pdf/xpdf/PBMOutputDev.h +++ /dev/null @@ -1,64 +0,0 @@ -//======================================================================== -// -// PBMOutputDev.h -// -// Copyright 1998-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef PBMOUTPUTDEV_H -#define PBMOUTPUTDEV_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include "config.h" -#include "XOutputDev.h" - -//------------------------------------------------------------------------ - -class PBMOutputDev: public XOutputDev { -public: - - // NB: Users must use makePBMOutputDev and killPBMOutputDev rather - // than the constructor and destructor. (This is due to some - // constraints in the underlying XOutputDev object.) - - static PBMOutputDev *makePBMOutputDev(char *displayName, - char *fileRootA); - - static void killPBMOutputDev(PBMOutputDev *out); - - virtual ~PBMOutputDev(); - - //----- initialization and control - - // Start a page. - virtual void startPage(int pageNum, GfxState *state); - - // End a page. - virtual void endPage(); - -private: - - PBMOutputDev(Display *displayA, int screenA, - Pixmap pixmapA, Window dummyWinA, - int invertA, char *fileRootA); - - char *fileRoot; - char *fileName; - int curPage; - - Display *display; - int screen; - Pixmap pixmap; - Window dummyWin; - int width, height; - int invert; -}; - -#endif diff --git a/pdf/xpdf/PDFDoc.cc b/pdf/xpdf/PDFDoc.cc index c92048b..e156c3f 100644 --- a/pdf/xpdf/PDFDoc.cc +++ b/pdf/xpdf/PDFDoc.cc @@ -206,7 +206,7 @@ void PDFDoc::checkHeader() { } void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI, - int rotate, GBool doLinks, + int rotate, GBool crop, GBool doLinks, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData, GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), @@ -223,18 +223,19 @@ void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI, links = NULL; } getLinks(p); - p->display(out, hDPI, vDPI, rotate, links, catalog, + p->display(out, hDPI, vDPI, rotate, crop, links, catalog, abortCheckCbk, abortCheckCbkData, annotDisplayDecideCbk, annotDisplayDecideCbkData); } else { - p->display(out, hDPI, vDPI, rotate, NULL, catalog, + p->display(out, hDPI, vDPI, rotate, crop, NULL, catalog, abortCheckCbk, abortCheckCbkData, annotDisplayDecideCbk, annotDisplayDecideCbkData); } } void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, - double hDPI, double vDPI, int rotate, GBool doLinks, + double hDPI, double vDPI, int rotate, + GBool crop, GBool doLinks, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData, GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), @@ -242,7 +243,7 @@ void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, int page; for (page = firstPage; page <= lastPage; ++page) { - displayPage(out, page, hDPI, vDPI, rotate, doLinks, + displayPage(out, page, hDPI, vDPI, rotate, crop, doLinks, abortCheckCbk, abortCheckCbkData, annotDisplayDecideCbk, annotDisplayDecideCbkData); } @@ -250,8 +251,8 @@ void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, void PDFDoc::displayPageSlice(OutputDev *out, int page, double hDPI, double vDPI, - int rotate, int sliceX, int sliceY, - int sliceW, int sliceH, + int rotate, GBool crop, + int sliceX, int sliceY, int sliceW, int sliceH, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData, GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), @@ -259,7 +260,8 @@ void PDFDoc::displayPageSlice(OutputDev *out, int page, Page *p; p = catalog->getPage(page); - p->displaySlice(out, hDPI, vDPI, rotate, sliceX, sliceY, sliceW, sliceH, + p->displaySlice(out, hDPI, vDPI, rotate, crop, + sliceX, sliceY, sliceW, sliceH, NULL, catalog, abortCheckCbk, abortCheckCbkData, annotDisplayDecideCbk, annotDisplayDecideCbkData); diff --git a/pdf/xpdf/PDFDoc.h b/pdf/xpdf/PDFDoc.h index 2d060dc..57e37a2 100644 --- a/pdf/xpdf/PDFDoc.h +++ b/pdf/xpdf/PDFDoc.h @@ -81,7 +81,7 @@ public: // Display a page. void displayPage(OutputDev *out, int page, double hDPI, double vDPI, - int rotate, GBool doLinks, + int rotate, GBool crop, GBool doLinks, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL, GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL, @@ -89,7 +89,8 @@ public: // Display a range of pages. void displayPages(OutputDev *out, int firstPage, int lastPage, - double hDPI, double vDPI, int rotate, GBool doLinks, + double hDPI, double vDPI, int rotate, + GBool crop, GBool doLinks, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL, GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL, @@ -98,8 +99,8 @@ public: // Display part of a page. void displayPageSlice(OutputDev *out, int page, double hDPI, double vDPI, - int rotate, int sliceX, int sliceY, - int sliceW, int sliceH, + int rotate, GBool crop, + int sliceX, int sliceY, int sliceW, int sliceH, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL, GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL, diff --git a/pdf/xpdf/PSOutputDev.cc b/pdf/xpdf/PSOutputDev.cc index 34d7fdc..6170dfd 100644 --- a/pdf/xpdf/PSOutputDev.cc +++ b/pdf/xpdf/PSOutputDev.cc @@ -28,7 +28,8 @@ #include "GfxState.h" #include "GfxFont.h" #include "UnicodeMap.h" -#include "FontFile.h" +#include "FoFiType1C.h" +#include "FoFiTrueType.h" #include "Catalog.h" #include "Page.h" #include "Stream.h" @@ -368,8 +369,9 @@ static char *prolog[] = { " pdfTextMat dtransform rmoveto } def", "/TJmV { pdfFontSize 0.001 mul mul neg 0 exch", " pdfTextMat dtransform rmoveto } def", - "/Tclip { pdfTextClipPath cvx exec clip", + "/Tclip { pdfTextClipPath cvx exec clip newpath", " /pdfTextClipPath [] def } def", + "~1", "% Level 1 image operators", "/pdfIm1 {", " /pdfImBuf1 4 index string def", @@ -390,6 +392,11 @@ static char *prolog[] = { " /pdfImBuf1 4 index 7 add 8 idiv string def", " { currentfile pdfImBuf1 readhexstring pop } imagemask", "} def", + "/pdfImM1a {", + " { 2 copy get exch 1 add exch } imagemask", + " pop pop", + "} def", + "~2", "% Level 2 image operators", "/pdfImBuf 100 string def", "/pdfIm {", @@ -422,6 +429,7 @@ static char *prolog[] = { " not { pop exit } if", " (%-EOD-) eq { exit } if } loop", "} def", + "~a", "end", NULL }; @@ -560,6 +568,87 @@ PSOutCustomColor::~PSOutCustomColor() { } //------------------------------------------------------------------------ +// DeviceNRecoder +//------------------------------------------------------------------------ + +class DeviceNRecoder: public FilterStream { +public: + + DeviceNRecoder(Stream *strA, int widthA, int heightA, + GfxImageColorMap *colorMapA); + virtual ~DeviceNRecoder(); + virtual StreamKind getKind() { return strWeird; } + virtual void reset(); + virtual int getChar() + { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx++]; } + virtual int lookChar() + { return (bufIdx >= bufSize && !fillBuf()) ? EOF : buf[bufIdx]; } + virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; } + virtual GBool isBinary(GBool last = gTrue) { return gTrue; } + virtual GBool isEncoder() { return gTrue; } + +private: + + GBool fillBuf(); + + int width, height; + GfxImageColorMap *colorMap; + Function *func; + ImageStream *imgStr; + int buf[gfxColorMaxComps]; + int pixelIdx; + int bufIdx; + int bufSize; +}; + +DeviceNRecoder::DeviceNRecoder(Stream *strA, int widthA, int heightA, + GfxImageColorMap *colorMapA): + FilterStream(strA) { + width = widthA; + height = heightA; + colorMap = colorMapA; + imgStr = NULL; + pixelIdx = 0; + bufIdx = gfxColorMaxComps; + bufSize = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> + getAlt()->getNComps(); + func = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> + getTintTransformFunc(); +} + +DeviceNRecoder::~DeviceNRecoder() { + if (imgStr) { + delete imgStr; + } +} + +void DeviceNRecoder::reset() { + imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), + colorMap->getBits()); + imgStr->reset(); +} + +GBool DeviceNRecoder::fillBuf() { + Guchar pixBuf[gfxColorMaxComps]; + GfxColor color; + double y[gfxColorMaxComps]; + int i; + + if (pixelIdx >= width * height) { + return gFalse; + } + imgStr->getPixel(pixBuf); + colorMap->getColor(pixBuf, &color); + func->transform(color.c, y); + for (i = 0; i < bufSize; ++i) { + buf[i] = (int)(y[i] * 255 + 0.5); + } + bufIdx = 0; + ++pixelIdx; + return gTrue; +} + +//------------------------------------------------------------------------ // PSOutputDev //------------------------------------------------------------------------ @@ -573,7 +662,7 @@ static void outputToFile(void *stream, char *data, int len) { PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog, int firstPage, int lastPage, PSOutMode modeA, - int paperWidthA, int paperHeightA, + int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, GBool manualCtrlA) { FILE *f; PSFileType fileTypeA; @@ -624,14 +713,19 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog, init(outputToFile, f, fileTypeA, xrefA, catalog, firstPage, lastPage, modeA, - paperWidthA, paperHeightA, manualCtrlA); + imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA); } PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, XRef *xrefA, Catalog *catalog, int firstPage, int lastPage, PSOutMode modeA, - int paperWidthA, int paperHeightA, + int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, GBool manualCtrlA) { + underlayCbk = NULL; + underlayCbkData = NULL; + overlayCbk = NULL; + overlayCbkData = NULL; + fontIDs = NULL; fontFileIDs = NULL; fontFileNames = NULL; @@ -644,15 +738,16 @@ PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, init(outputFuncA, outputStreamA, psGeneric, xrefA, catalog, firstPage, lastPage, modeA, - paperWidthA, paperHeightA, manualCtrlA); + imgLLXA, imgLLYA, imgURXA, imgURYA, manualCtrlA); } void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, PSFileType fileTypeA, XRef *xrefA, Catalog *catalog, int firstPage, int lastPage, PSOutMode modeA, - int paperWidthA, int paperHeightA, + int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, GBool manualCtrlA) { Page *page; + PDFRectangle *box; // initialize ok = gTrue; @@ -662,18 +757,28 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, xref = xrefA; level = globalParams->getPSLevel(); mode = modeA; - paperWidth = paperWidthA; - paperHeight = paperHeightA; - if (paperWidth == 0) { - paperWidth = globalParams->getPSPaperWidth(); - } - if (paperHeight == 0) { - paperHeight = globalParams->getPSPaperHeight(); + paperWidth = globalParams->getPSPaperWidth(); + paperHeight = globalParams->getPSPaperHeight(); + imgLLX = imgLLXA; + imgLLY = imgLLYA; + imgURX = imgURXA; + imgURY = imgURYA; + if (imgLLX == 0 && imgURX == 0 && imgLLY == 0 && imgURY == 0) { + globalParams->getPSImageableArea(&imgLLX, &imgLLY, &imgURX, &imgURY); } if (paperWidth < 0 || paperHeight < 0) { - page = catalog->getPage(firstPage); - paperWidth = (int)(page->getWidth() + 0.5); - paperHeight = (int)(page->getHeight() + 0.5); + // this check is needed in case the document has zero pages + if (firstPage > 0 && firstPage <= catalog->getNumPages()) { + page = catalog->getPage(firstPage); + paperWidth = (int)(page->getWidth() + 0.5); + paperHeight = (int)(page->getHeight() + 0.5); + } else { + paperWidth = 1; + paperHeight = 1; + } + imgLLX = imgLLY = 0; + imgURX = paperWidth; + imgURY = paperHeight; } manualCtrl = manualCtrlA; if (mode == psModeForm) { @@ -688,6 +793,12 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, opi20Nest = 0; #endif + tx0 = ty0 = 0; + xScale0 = yScale0 = 1; + rotate0 = 0; + clipLLX0 = clipLLY0 = 0; + clipURX0 = clipURY0 = -1; + // initialize fontIDs, fontFileIDs, and fontFileNames lists fontIDSize = 64; fontIDLen = 0; @@ -709,7 +820,16 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA, embFontList = new GString(); if (!manualCtrl) { - writeHeader(firstPage, lastPage, catalog->getPage(firstPage)->getBox()); + // this check is needed in case the document has zero pages + if (firstPage > 0 && firstPage <= catalog->getNumPages()) { + writeHeader(firstPage, lastPage, + catalog->getPage(firstPage)->getBox(), + catalog->getPage(firstPage)->getCropBox()); + } else { + box = new PDFRectangle(0, 0, 1, 1); + writeHeader(firstPage, lastPage, box, box); + delete box; + } if (mode != psModeForm) { writePS("%%BeginProlog\n"); } @@ -786,7 +906,8 @@ PSOutputDev::~PSOutputDev() { } } -void PSOutputDev::writeHeader(int firstPage, int lastPage, PDFRectangle *box) { +void PSOutputDev::writeHeader(int firstPage, int lastPage, + PDFRectangle *mediaBox, PDFRectangle *cropBox) { switch (mode) { case psModePS: writePS("%!PS-Adobe-3.0\n"); @@ -819,14 +940,14 @@ void PSOutputDev::writeHeader(int firstPage, int lastPage, PDFRectangle *box) { writePS("%%DocumentCustomColors: (atend)\n"); } writePSFmt("%%%%BoundingBox: %d %d %d %d\n", - (int)floor(box->x1), (int)floor(box->y1), - (int)ceil(box->x2), (int)ceil(box->y2)); - if (floor(box->x1) != ceil(box->x1) || - floor(box->y1) != ceil(box->y1) || - floor(box->x2) != ceil(box->x2) || - floor(box->y2) != ceil(box->y2)) { + (int)floor(cropBox->x1), (int)floor(cropBox->y1), + (int)ceil(cropBox->x2), (int)ceil(cropBox->y2)); + if (floor(cropBox->x1) != ceil(cropBox->x1) || + floor(cropBox->y1) != ceil(cropBox->y1) || + floor(cropBox->x2) != ceil(cropBox->x2) || + floor(cropBox->y2) != ceil(cropBox->y2)) { writePSFmt("%%%%HiResBoundingBox: %g %g %g %g\n", - box->x1, box->y1, box->x2, box->y2); + cropBox->x1, cropBox->y1, cropBox->x2, cropBox->y2); } writePS("%%DocumentSuppliedResources: (atend)\n"); writePS("%%EndComments\n"); @@ -845,7 +966,8 @@ void PSOutputDev::writeHeader(int firstPage, int lastPage, PDFRectangle *box) { writePS("%%EndComments\n"); writePS("32 dict dup begin\n"); writePSFmt("/BBox [%d %d %d %d] def\n", - (int)box->x1, (int)box->y1, (int)box->x2, (int)box->y2); + (int)floor(mediaBox->x1), (int)floor(mediaBox->y1), + (int)ceil(mediaBox->x2), (int)ceil(mediaBox->y2)); writePS("/FormType 1 def\n"); writePS("/Matrix [1 0 0 1 0 0] def\n"); break; @@ -1044,8 +1166,9 @@ void PSOutputDev::setupFonts(Dict *resDict) { } if (gfxFontDict) { for (i = 0; i < gfxFontDict->getNumFonts(); ++i) { - font = gfxFontDict->getFont(i); - setupFont(font, resDict); + if ((font = gfxFontDict->getFont(i))) { + setupFont(font, resDict); + } } delete gfxFontDict; } @@ -1455,7 +1578,7 @@ void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id, GString *psName) { char *fontBuf; int fontLen; - Type1CFontFile *t1cFile; + FoFiType1C *ffT1C; int i; // check if font is already embedded @@ -1480,11 +1603,10 @@ void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id, // convert it to a Type 1 font fontBuf = font->readEmbFontFile(xref, &fontLen); - t1cFile = new Type1CFontFile(fontBuf, fontLen); - if (t1cFile->isOk()) { - t1cFile->convertToType1(outputFunc, outputStream); + if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { + ffT1C->convertToType1(NULL, gTrue, outputFunc, outputStream); + delete ffT1C; } - delete t1cFile; gfree(fontBuf); // ending comment @@ -1496,7 +1618,7 @@ void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, char unique[32]; char *fontBuf; int fontLen; - TrueTypeFontFile *ttFile; + FoFiTrueType *ffTT; Gushort *codeToGID; int i; @@ -1527,15 +1649,16 @@ void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, // convert it to a Type 42 font fontBuf = font->readEmbFontFile(xref, &fontLen); - ttFile = new TrueTypeFontFile(fontBuf, fontLen); - codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ttFile); - ttFile->convertToType42(psName->getCString(), - ((Gfx8BitFont *)font)->getEncoding(), - ((Gfx8BitFont *)font)->getHasEncoding(), - codeToGID, - outputFunc, outputStream); - gfree(codeToGID); - delete ttFile; + if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { + codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT); + ffTT->convertToType42(psName->getCString(), + ((Gfx8BitFont *)font)->getHasEncoding() + ? ((Gfx8BitFont *)font)->getEncoding() + : (char **)NULL, + codeToGID, outputFunc, outputStream); + gfree(codeToGID); + delete ffTT; + } gfree(fontBuf); // ending comment @@ -1547,7 +1670,7 @@ void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *psName) { GString *fileName; char *fontBuf; int fontLen; - TrueTypeFontFile *ttFile; + FoFiTrueType *ffTT; Gushort *codeToGID; int i; @@ -1580,14 +1703,15 @@ void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *psName) { // convert it to a Type 42 font fontBuf = font->readExtFontFile(&fontLen); - ttFile = new TrueTypeFontFile(fontBuf, fontLen); - codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ttFile); - ttFile->convertToType42(psName->getCString(), - ((Gfx8BitFont *)font)->getEncoding(), - ((Gfx8BitFont *)font)->getHasEncoding(), - codeToGID, - outputFunc, outputStream); - delete ttFile; + if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { + codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ffTT); + ffTT->convertToType42(psName->getCString(), + ((Gfx8BitFont *)font)->getHasEncoding() + ? ((Gfx8BitFont *)font)->getEncoding() + : (char **)NULL, + codeToGID, outputFunc, outputStream); + delete ffTT; + } gfree(fontBuf); // ending comment @@ -1598,7 +1722,7 @@ void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GString *psName) { char *fontBuf; int fontLen; - Type1CFontFile *t1cFile; + FoFiType1C *ffT1C; int i; // check if font is already embedded @@ -1623,18 +1747,16 @@ void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, // convert it to a Type 0 font fontBuf = font->readEmbFontFile(xref, &fontLen); - t1cFile = new Type1CFontFile(fontBuf, fontLen); - if (t1cFile->isOk()) { + if ((ffT1C = FoFiType1C::make(fontBuf, fontLen))) { if (globalParams->getPSLevel() >= psLevel3) { // Level 3: use a CID font - t1cFile->convertToCIDType0(psName->getCString(), - outputFunc, outputStream); + ffT1C->convertToCIDType0(psName->getCString(), outputFunc, outputStream); } else { // otherwise: use a non-CID composite font - t1cFile->convertToType0(psName->getCString(), outputFunc, outputStream); + ffT1C->convertToType0(psName->getCString(), outputFunc, outputStream); } + delete ffT1C; } - delete t1cFile; gfree(fontBuf); // ending comment @@ -1645,7 +1767,7 @@ void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GString *psName) { char *fontBuf; int fontLen; - TrueTypeFontFile *ttFile; + FoFiTrueType *ffTT; int i; // check if font is already embedded @@ -1670,20 +1792,22 @@ void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, // convert it to a Type 0 font fontBuf = font->readEmbFontFile(xref, &fontLen); - ttFile = new TrueTypeFontFile(fontBuf, fontLen); - if (globalParams->getPSLevel() >= psLevel3) { - ttFile->convertToCIDType2(psName->getCString(), + if ((ffTT = FoFiTrueType::make(fontBuf, fontLen))) { + if (globalParams->getPSLevel() >= psLevel3) { + // Level 3: use a CID font + ffTT->convertToCIDType2(psName->getCString(), ((GfxCIDFont *)font)->getCIDToGID(), ((GfxCIDFont *)font)->getCIDToGIDLen(), outputFunc, outputStream); - } else { - // otherwise: use a non-CID composite font - ttFile->convertToType0(psName->getCString(), + } else { + // otherwise: use a non-CID composite font + ffTT->convertToType0(psName->getCString(), ((GfxCIDFont *)font)->getCIDToGID(), ((GfxCIDFont *)font)->getCIDToGIDLen(), outputFunc, outputStream); + } + delete ffTT; } - delete ttFile; gfree(fontBuf); // ending comment @@ -1717,7 +1841,7 @@ void PSOutputDev::setupType3Font(GfxFont *font, GString *psName, embFontList->append("\n"); // font dictionary - writePS("7 dict begin\n"); + writePS("8 dict begin\n"); writePS("/FontType 3 def\n"); m = font->getFontMatrix(); writePSFmt("/FontMatrix [%g %g %g %g %g %g] def\n", @@ -1811,11 +1935,14 @@ void PSOutputDev::setupImages(Dict *resDict) { } void PSOutputDev::setupImage(Ref id, Stream *str) { + GBool useASCIIHex; int c; int size, line, col, i; // construct an encoder stream - if (globalParams->getPSASCIIHex()) { + useASCIIHex = level == psLevel1 || level == psLevel1Sep || + globalParams->getPSASCIIHex(); + if (useASCIIHex) { str = new ASCIIHexEncoder(str); } else { str = new ASCII85Encoder(str); @@ -1828,18 +1955,18 @@ void PSOutputDev::setupImage(Ref id, Stream *str) { do { c = str->getChar(); } while (c == '\n' || c == '\r'); - if (c == '~' || c == EOF) { + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { break; } if (c == 'z') { ++col; } else { ++col; - for (i = 1; i <= 4; ++i) { + for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { do { c = str->getChar(); } while (c == '\n' || c == '\r'); - if (c == '~' || c == EOF) { + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { break; } ++col; @@ -1849,7 +1976,7 @@ void PSOutputDev::setupImage(Ref id, Stream *str) { ++size; col = 0; } - } while (c != '~' && c != EOF); + } while (c != (useASCIIHex ? '>' : '~') && c != EOF); ++size; writePSFmt("%d array dup /ImData_%d_%d exch def\n", size, id.num, id.gen); str->close(); @@ -1857,12 +1984,12 @@ void PSOutputDev::setupImage(Ref id, Stream *str) { // write the data into the array str->reset(); line = col = 0; - writePS("dup 0 <~"); + writePS((char *)(useASCIIHex ? "dup 0 <" : "dup 0 <~")); do { do { c = str->getChar(); } while (c == '\n' || c == '\r'); - if (c == '~' || c == EOF) { + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { break; } if (c == 'z') { @@ -1871,11 +1998,11 @@ void PSOutputDev::setupImage(Ref id, Stream *str) { } else { writePSChar(c); ++col; - for (i = 1; i <= 4; ++i) { + for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { do { c = str->getChar(); } while (c == '\n' || c == '\r'); - if (c == '~' || c == EOF) { + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { break; } writePSChar(c); @@ -1887,13 +2014,13 @@ void PSOutputDev::setupImage(Ref id, Stream *str) { // chunks are 1 or 4 bytes each, so we have to stop at 232 // but make it 225 just to be safe if (col > 225) { - writePS("~> put\n"); + writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n")); ++line; - writePSFmt("dup %d <~", line); + writePSFmt((char *)(useASCIIHex ? "dup %d <" : "dup %d <~"), line); col = 0; } - } while (c != '~' && c != EOF); - writePS("~> put\n"); + } while (c != (useASCIIHex ? '>' : '~') && c != EOF); + writePS((char *)(useASCIIHex ? "> put\n" : "~> put\n")); writePS("pop\n"); str->close(); @@ -1901,7 +2028,8 @@ void PSOutputDev::setupImage(Ref id, Stream *str) { } void PSOutputDev::startPage(int pageNum, GfxState *state) { - int x1, y1, x2, y2, width, height, paperWidth2, paperHeight2; + int x1, y1, x2, y2, width, height; + int imgWidth, imgHeight, imgWidth2, imgHeight2; switch (mode) { @@ -1911,53 +2039,70 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { writePS("%%BeginPageSetup\n"); // rotate, translate, and scale page + imgWidth = imgURX - imgLLX; + imgHeight = imgURY - imgLLY; x1 = (int)(state->getX1() + 0.5); y1 = (int)(state->getY1() + 0.5); x2 = (int)(state->getX2() + 0.5); y2 = (int)(state->getY2() + 0.5); width = x2 - x1; height = y2 - y1; - if (width > height && width > paperWidth) { - landscape = gTrue; + tx = ty = 0; + // portrait or landscape + if (width > height && width > imgWidth) { + rotate = 90; writePSFmt("%%%%PageOrientation: %s\n", state->getCTM()[0] ? "Landscape" : "Portrait"); writePS("pdfStartPage\n"); writePS("90 rotate\n"); - tx = -x1; - ty = -(y1 + paperWidth); - paperWidth2 = paperHeight; - paperHeight2 = paperWidth; + ty = -imgWidth; + imgWidth2 = imgHeight; + imgHeight2 = imgWidth; } else { - landscape = gFalse; + rotate = 0; writePSFmt("%%%%PageOrientation: %s\n", state->getCTM()[0] ? "Portrait" : "Landscape"); writePS("pdfStartPage\n"); - tx = -x1; - ty = -y1; - paperWidth2 = paperWidth; - paperHeight2 = paperHeight; - } - if (width < paperWidth2) { - tx += (paperWidth2 - width) / 2; - } - if (height < paperHeight2) { - ty += (paperHeight2 - height) / 2; - } - if (tx != 0 || ty != 0) { - writePSFmt("%g %g translate\n", tx, ty); - } - if (width > paperWidth2 || height > paperHeight2) { - xScale = (double)paperWidth2 / (double)width; - yScale = (double)paperHeight2 / (double)height; + imgWidth2 = imgWidth; + imgHeight2 = imgHeight; + } + // shrink or expand + if ((globalParams->getPSShrinkLarger() && + (width > imgWidth2 || height > imgHeight2)) || + (globalParams->getPSExpandSmaller() && + (width < imgWidth2 && height < imgHeight2))) { + xScale = (double)imgWidth2 / (double)width; + yScale = (double)imgHeight2 / (double)height; if (yScale < xScale) { xScale = yScale; } else { yScale = xScale; } - writePSFmt("%0.4f %0.4f scale\n", xScale, xScale); } else { xScale = yScale = 1; } + // deal with odd bounding boxes + tx -= xScale * x1; + ty -= yScale * y1; + // center + if (globalParams->getPSCenter()) { + tx += (imgWidth2 - xScale * width) / 2; + ty += (imgHeight2 - yScale * height) / 2; + } + tx += imgLLX + tx0; + ty += imgLLY + ty0; + xScale *= xScale0; + yScale *= yScale0; + if (tx != 0 || ty != 0) { + writePSFmt("%g %g translate\n", tx, ty); + } + if (xScale != 1 || yScale != 1) { + writePSFmt("%0.4f %0.4f scale\n", xScale, xScale); + } + if (clipLLX0 < clipURX0 && clipLLY0 < clipURY0) { + writePSFmt("%g %g %g %g re W\n", + clipLLX0, clipLLY0, clipURX0 - clipLLX0, clipURY0 - clipLLY0); + } writePS("%%EndPageSetup\n"); ++seqPage; @@ -1967,7 +2112,7 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { writePS("pdfStartPage\n"); tx = ty = 0; xScale = yScale = 1; - landscape = gFalse; + rotate = 0; break; case psModeForm: @@ -1976,7 +2121,7 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) { writePS("pdfStartPage\n"); tx = ty = 0; xScale = yScale = 1; - landscape = gFalse; + rotate = 0; break; } @@ -2229,7 +2374,12 @@ void PSOutputDev::updateWordSpace(GfxState *state) { } void PSOutputDev::updateHorizScaling(GfxState *state) { - writePSFmt("%g Tz\n", state->getHorizScaling()); + double h; + + if ((h = state->getHorizScaling()) < 0.01) { + h = 0.01; + } + writePSFmt("%g Tz\n", h); } void PSOutputDev::updateTextPos(GfxState *state) { @@ -2451,7 +2601,7 @@ void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, len = height * ((width + 7) / 8); if (level == psLevel1 || level == psLevel1Sep) { - doImageL1(NULL, invert, inlineImg, str, width, height, len); + doImageL1(ref, NULL, invert, inlineImg, str, width, height, len); } else { doImageL2(ref, NULL, invert, inlineImg, str, width, height, len); } @@ -2466,7 +2616,7 @@ void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, colorMap->getBits() + 7) / 8); switch (level) { case psLevel1: - doImageL1(colorMap, gFalse, inlineImg, str, width, height, len); + doImageL1(ref, colorMap, gFalse, inlineImg, str, width, height, len); break; case psLevel1Sep: //~ handle indexed, separation, ... color spaces @@ -2482,16 +2632,56 @@ void PSOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, t3Cacheable = gFalse; } -void PSOutputDev::doImageL1(GfxImageColorMap *colorMap, +void PSOutputDev::doImageL1(Object *ref, GfxImageColorMap *colorMap, GBool invert, GBool inlineImg, Stream *str, int width, int height, int len) { ImageStream *imgStr; Guchar pixBuf[gfxColorMaxComps]; double gray; - int x, y, i; + int col, x, y, c, i; - // width, height, matrix, bits per component - if (colorMap) { + if (inType3Char && !colorMap) { + if (inlineImg) { + // create an array + str = new FixedLengthEncoder(str, len); + str = new ASCIIHexEncoder(str); + str->reset(); + col = 0; + writePS("[<"); + do { + do { + c = str->getChar(); + } while (c == '\n' || c == '\r'); + if (c == '>' || c == EOF) { + break; + } + writePSChar(c); + ++col; + // each line is: "<...data...>" + // so max data length = 255 - 4 = 251 + // but make it 240 just to be safe + // chunks are 2 bytes each, so we need to stop on an even col number + if (col == 240) { + writePS(">\n<"); + col = 0; + } + } while (c != '>' && c != EOF); + writePS(">]\n"); + writePS("0\n"); + str->close(); + delete str; + } else { + // set up to use the array already created by setupImages() + writePSFmt("ImData_%d_%d 0\n", ref->getRefNum(), ref->getRefGen()); + } + } + + // image/imagemask command + if (inType3Char && !colorMap) { + writePSFmt("%d %d %s [%d 0 0 %d 0 %d] pdfImM1a\n", + width, height, invert ? "true" : "false", + width, -height, height); + } else if (colorMap) { writePSFmt("%d %d 8 [%d 0 0 %d 0 %d] pdfIm1\n", width, height, width, -height, height); @@ -2501,51 +2691,54 @@ void PSOutputDev::doImageL1(GfxImageColorMap *colorMap, width, -height, height); } - // image - if (colorMap) { + // image data + if (!(inType3Char && !colorMap)) { - // set up to process the data stream - imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), - colorMap->getBits()); - imgStr->reset(); + if (colorMap) { - // process the data stream - i = 0; - for (y = 0; y < height; ++y) { + // set up to process the data stream + imgStr = new ImageStream(str, width, colorMap->getNumPixelComps(), + colorMap->getBits()); + imgStr->reset(); - // write the line - for (x = 0; x < width; ++x) { - imgStr->getPixel(pixBuf); - colorMap->getGray(pixBuf, &gray); - writePSFmt("%02x", (int)(gray * 255 + 0.5)); - if (++i == 32) { - writePSChar('\n'); - i = 0; + // process the data stream + i = 0; + for (y = 0; y < height; ++y) { + + // write the line + for (x = 0; x < width; ++x) { + imgStr->getPixel(pixBuf); + colorMap->getGray(pixBuf, &gray); + writePSFmt("%02x", (int)(gray * 255 + 0.5)); + if (++i == 32) { + writePSChar('\n'); + i = 0; + } } } - } - if (i != 0) { - writePSChar('\n'); - } - delete imgStr; + if (i != 0) { + writePSChar('\n'); + } + delete imgStr; - // imagemask - } else { - str->reset(); - i = 0; - for (y = 0; y < height; ++y) { - for (x = 0; x < width; x += 8) { - writePSFmt("%02x", str->getChar() & 0xff); - if (++i == 32) { - writePSChar('\n'); - i = 0; + // imagemask + } else { + str->reset(); + i = 0; + for (y = 0; y < height; ++y) { + for (x = 0; x < width; x += 8) { + writePSFmt("%02x", str->getChar() & 0xff); + if (++i == 32) { + writePSChar('\n'); + i = 0; + } } } + if (i != 0) { + writePSChar('\n'); + } + str->close(); } - if (i != 0) { - writePSChar('\n'); - } - str->close(); } } @@ -2611,12 +2804,12 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, Stream *str, int width, int height, int len) { GString *s; int n, numComps; - GBool useRLE, useASCII, useCompressed; + GBool useRLE, useASCII, useASCIIHex, useCompressed; GfxSeparationColorSpace *sepCS; GfxColor color; GfxCMYK cmyk; int c; - int line, col, i; + int col, i; // color space if (colorMap) { @@ -2624,24 +2817,26 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, writePS(" setcolorspace\n"); } + useASCIIHex = globalParams->getPSASCIIHex(); + // set up the image data if (mode == psModeForm || inType3Char) { if (inlineImg) { // create an array str = new FixedLengthEncoder(str, len); - if (globalParams->getPSASCIIHex()) { + if (useASCIIHex) { str = new ASCIIHexEncoder(str); } else { str = new ASCII85Encoder(str); } str->reset(); - line = col = 0; - writePS("[<~"); + col = 0; + writePS((char *)(useASCIIHex ? "[<" : "[<~")); do { do { c = str->getChar(); } while (c == '\n' || c == '\r'); - if (c == '~' || c == EOF) { + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { break; } if (c == 'z') { @@ -2650,29 +2845,27 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, } else { writePSChar(c); ++col; - for (i = 1; i <= 4; ++i) { + for (i = 1; i <= (useASCIIHex ? 1 : 4); ++i) { do { c = str->getChar(); } while (c == '\n' || c == '\r'); - if (c == '~' || c == EOF) { + if (c == (useASCIIHex ? '>' : '~') || c == EOF) { break; } writePSChar(c); ++col; } } - // each line is: "dup nnnnn <~...data...~> put" - // so max data length = 255 - 20 = 235 - // chunks are 1 or 4 bytes each, so we have to stop at 232 - // but make it 225 just to be safe - if (col > 225) { - writePS("~>\n"); - ++line; - writePSFmt("<~", line); + // each line is: "<~...data...~>" + // so max data length = 255 - 6 = 249 + // chunks are 1 or 5 bytes each, so we have to stop at 245 + // but make it 240 just to be safe + if (col > 240) { + writePS((char *)(useASCIIHex ? ">\n<" : "~>\n<~")); col = 0; } - } while (c != '~' && c != EOF); - writePS("~>]\n"); + } while (c != (useASCIIHex ? '>' : '~') && c != EOF); + writePS((char *)(useASCIIHex ? ">]\n" : "~>]\n")); writePS("0\n"); str->close(); delete str; @@ -2689,8 +2882,12 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, writePSFmt(" /Width %d\n", width); writePSFmt(" /Height %d\n", height); writePSFmt(" /ImageMatrix [%d 0 0 %d 0 %d]\n", width, -height, height); - writePSFmt(" /BitsPerComponent %d\n", - colorMap ? colorMap->getBits() : 1); + if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) { + writePSFmt(" /BitsPerComponent 8\n"); + } else { + writePSFmt(" /BitsPerComponent %d\n", + colorMap ? colorMap->getBits() : 1); + } // decode if (colorMap) { @@ -2700,6 +2897,16 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, n = (1 << colorMap->getBits()) - 1; writePSFmt("%g %g", colorMap->getDecodeLow(0) * n, colorMap->getDecodeHigh(0) * n); + } else if (colorMap->getColorSpace()->getMode() == csDeviceN) { + numComps = ((GfxDeviceNColorSpace *)colorMap->getColorSpace())-> + getAlt()->getNComps(); + for (i = 0; i < numComps; ++i) { + if (i > 0) { + writePS(" "); + } + writePSFmt("0 1", colorMap->getDecodeLow(i), + colorMap->getDecodeHigh(i)); + } } else { numComps = colorMap->getNumPixelComps(); for (i = 0; i < numComps; ++i) { @@ -2732,7 +2939,8 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, writePS(" /DataSource currentfile\n"); s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3, " "); - if (inlineImg || !s) { + if ((colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) || + inlineImg || !s) { useRLE = gTrue; useASCII = gTrue; useCompressed = gFalse; @@ -2743,7 +2951,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, } if (useASCII) { writePSFmt(" /ASCII%sDecode filter\n", - globalParams->getPSASCIIHex() ? "Hex" : "85"); + useASCIIHex ? "Hex" : "85"); } if (useRLE) { writePS(" /RunLengthDecode filter\n"); @@ -2762,12 +2970,17 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap, str = str->getBaseStream(); } + // recode DeviceN data + if (colorMap && colorMap->getColorSpace()->getMode() == csDeviceN) { + str = new DeviceNRecoder(str, width, height, colorMap); + } + // add RunLengthEncode and ASCIIHex/85 encode filters if (useRLE) { str = new RunLengthEncoder(str); } if (useASCII) { - if (globalParams->getPSASCIIHex()) { + if (useASCIIHex) { str = new ASCIIHexEncoder(str); } else { str = new ASCII85Encoder(str); @@ -2932,6 +3145,8 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) { break; case csICCBased: + // there is no transform function to the alternate color space, so + // we can use it directly dumpColorSpaceL2(((GfxICCBasedColorSpace *)colorSpace)->getAlt()); break; @@ -3380,10 +3595,17 @@ void PSOutputDev::opiTransform(GfxState *state, double x0, double y0, state->transform(x0, y0, x1, y1); *x1 += tx; *y1 += ty; - if (landscape) { + if (rotate == 90) { t = *x1; *x1 = -*y1; *y1 = t; + } else if (rotate == 180) { + *x1 = -*x1; + *y1 = -*y1; + } else if (rotate == 270) { + t = *x1; + *x1 = *y1; + *y1 = -t; } *x1 *= xScale; *y1 *= yScale; diff --git a/pdf/xpdf/PSOutputDev.h b/pdf/xpdf/PSOutputDev.h index 06130fb..6c379a9 100644 --- a/pdf/xpdf/PSOutputDev.h +++ b/pdf/xpdf/PSOutputDev.h @@ -54,14 +54,16 @@ public: // Open a PostScript output file, and write the prolog. PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog, int firstPage, int lastPage, PSOutMode modeA, - int paperWidthA = 0, int paperHeightA = 0, + int imgLLXA = 0, int imgLLYA = 0, + int imgURXA = 0, int imgURYA = 0, GBool manualCtrlA = gFalse); // Open a PSOutputDev that will write to a generic stream. PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA, XRef *xrefA, Catalog *catalog, int firstPage, int lastPage, PSOutMode modeA, - int paperWidthA = 0, int paperHeightA = 0, + int imgLLXA = 0, int imgLLYA = 0, + int imgURXA = 0, int imgURYA = 0, GBool manualCtrlA = gFalse); // Destructor -- writes the trailer and closes the file. @@ -86,7 +88,8 @@ public: //----- header/trailer (used only if manualCtrl is true) // Write the document-level header. - void writeHeader(int firstPage, int lastPage, PDFRectangle *box); + void writeHeader(int firstPage, int lastPage, + PDFRectangle *mediaBox, PDFRectangle *cropBox); // Write the Xpdf procset. void writeXpdfProcset(); @@ -174,6 +177,14 @@ public: virtual void psXObject(Stream *psStream, Stream *level1Stream); //----- miscellaneous + void setOffset(double x, double y) + { tx0 = x; ty0 = y; } + void setScale(double x, double y) + { xScale0 = x; yScale0 = y; } + void setRotate(int rotateA) + { rotate0 = rotateA; } + void setClip(double llx, double lly, double urx, double ury) + { clipLLX0 = llx; clipLLY0 = lly; clipURX0 = urx; clipURY0 = ury; } void setUnderlayCbk(void (*cbk)(PSOutputDev *psOut, void *data), void *data) { underlayCbk = cbk; underlayCbkData = data; } @@ -186,7 +197,7 @@ private: void init(PSOutputFunc outputFuncA, void *outputStreamA, PSFileType fileTypeA, XRef *xrefA, Catalog *catalog, int firstPage, int lastPage, PSOutMode modeA, - int paperWidthA, int paperHeightA, + int imgLLXA, int imgLLYA, int imgURXA, int imgURYA, GBool manualCtrlA); void setupResources(Dict *resDict); void setupFonts(Dict *resDict); @@ -204,7 +215,7 @@ private: void addProcessColor(double c, double m, double y, double k); void addCustomColor(GfxSeparationColorSpace *sepCS); void doPath(GfxPath *path); - void doImageL1(GfxImageColorMap *colorMap, + void doImageL1(Object *ref, GfxImageColorMap *colorMap, GBool invert, GBool inlineImg, Stream *str, int width, int height, int len); void doImageL1Sep(GfxImageColorMap *colorMap, @@ -232,6 +243,8 @@ private: PSOutMode mode; // PostScript mode (PS, EPS, form) int paperWidth; // width of paper, in pts int paperHeight; // height of paper, in pts + int imgLLX, imgLLY, // imageable area, in pts + imgURX, imgURY; PSOutputFunc outputFunc; void *outputStream; @@ -263,9 +276,14 @@ private: // processed int numSaves; // current number of gsaves - double tx, ty; // global translation - double xScale, yScale; // global scaling - GBool landscape; // true for landscape, false for portrait + double tx0, ty0; // global translation + double xScale0, yScale0; // global scaling + int rotate0; // rotation angle (0, 90, 180, 270) + double clipLLX0, clipLLY0, + clipURX0, clipURY0; + double tx, ty; // global translation for current page + double xScale, yScale; // global scaling for current page + int rotate; // rotation angle for current page GString *embFontList; // resource comments for embedded fonts diff --git a/pdf/xpdf/Page.cc b/pdf/xpdf/Page.cc index e12e65c..817e1d5 100644 --- a/pdf/xpdf/Page.cc +++ b/pdf/xpdf/Page.cc @@ -226,18 +226,20 @@ Page::~Page() { contents.free(); } -void Page::display(OutputDev *out, double hDPI, double vDPI, int rotate, +void Page::display(OutputDev *out, double hDPI, double vDPI, + int rotate, GBool crop, Links *links, Catalog *catalog, GBool (*abortCheckCbk)(void *data), void *abortCheckCbkData, GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), void *annotDisplayDecideCbkData) { - displaySlice(out, hDPI, vDPI, rotate, -1, -1, -1, -1, links, catalog, + displaySlice(out, hDPI, vDPI, rotate, crop, -1, -1, -1, -1, links, catalog, abortCheckCbk, abortCheckCbkData, annotDisplayDecideCbk, annotDisplayDecideCbkData); } -void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, int rotate, +void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, + int rotate, GBool crop, int sliceX, int sliceY, int sliceW, int sliceH, Links *links, Catalog *catalog, GBool (*abortCheckCbk)(void *data), @@ -322,7 +324,7 @@ void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, int rotate, } gfx = new Gfx(xref, out, num, attrs->getResourceDict(), - hDPI, vDPI, &box, isCropped(), cropBox, rotate, + hDPI, vDPI, &box, crop && isCropped(), cropBox, rotate, abortCheckCbk, abortCheckCbkData); contents.fetch(xref, &obj); if (!obj.isNull()) { diff --git a/pdf/xpdf/Page.h b/pdf/xpdf/Page.h index 8fa1ef6..ab6442c 100644 --- a/pdf/xpdf/Page.h +++ b/pdf/xpdf/Page.h @@ -146,7 +146,8 @@ public: Object *getThumb(Object *obj) { return thumb.fetch(xref, obj); } // Display a page. - void display(OutputDev *out, double hDPI, double vDPI, int rotate, + void display(OutputDev *out, double hDPI, double vDPI, + int rotate, GBool crop, Links *links, Catalog *catalog, GBool (*abortCheckCbk)(void *data) = NULL, void *abortCheckCbkData = NULL, @@ -154,7 +155,8 @@ public: void *annotDisplayDecideCbkData = NULL); // Display part of a page. - void displaySlice(OutputDev *out, double hDPI, double vDPI, int rotate, + void displaySlice(OutputDev *out, double hDPI, double vDPI, + int rotate, GBool crop, int sliceX, int sliceY, int sliceW, int sliceH, Links *links, Catalog *catalog, GBool (*abortCheckCbk)(void *data) = NULL, diff --git a/pdf/xpdf/Parser.cc b/pdf/xpdf/Parser.cc index 2f881d4..0aa66d3 100644 --- a/pdf/xpdf/Parser.cc +++ b/pdf/xpdf/Parser.cc @@ -176,7 +176,7 @@ Stream *Parser::makeStream(Object *dict) { } // check for length in damaged file - if (xref->getStreamEnd(pos, &endPos)) { + if (xref && xref->getStreamEnd(pos, &endPos)) { length = endPos - pos; } diff --git a/pdf/xpdf/SFont.cc b/pdf/xpdf/SFont.cc deleted file mode 100644 index 1f421dd..0000000 --- a/pdf/xpdf/SFont.cc +++ /dev/null @@ -1,81 +0,0 @@ -//======================================================================== -// -// SFont.cc -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include "SFont.h" - -//------------------------------------------------------------------------ - -SFontEngine::SFontEngine(Display *displayA, Visual *visualA, int depthA, - Colormap colormapA) { - display = displayA; - visual = visualA; - depth = depthA; - colormap = colormapA; -} - -SFontEngine::~SFontEngine() { -} - -void SFontEngine::useTrueColor(int rMaxA, int rShiftA, int gMaxA, int gShiftA, - int bMaxA, int bShiftA) { - trueColor = gTrue; - rMax = rMaxA; - rShift = rShiftA; - gMax = gMaxA; - gShift = gShiftA; - bMax = bMaxA; - bShift = bShiftA; -} - -void SFontEngine::useColorCube(Gulong *colorsA, int nRGBA) { - trueColor = gFalse; - colors = colorsA; - nRGB = nRGBA; - rMax = gMax = bMax = nRGB - 1; -} - -Gulong SFontEngine::findColor(int r, int g, int b) { - int r1, g1, b1; - Gulong pix; - - r1 = ((r & 0xffff) * rMax) / 0xffff; - g1 = ((g & 0xffff) * gMax) / 0xffff; - b1 = ((b & 0xffff) * bMax) / 0xffff; - if (trueColor) { - pix = (r1 << rShift) + (g1 << gShift) + (b1 << bShift); - } else { - pix = colors[(r1 * nRGB + g1) * nRGB + b1]; - } - return pix; -} - -//------------------------------------------------------------------------ - -SFontFile::SFontFile() { -} - -SFontFile::~SFontFile() { -} - -//------------------------------------------------------------------------ - -SFont::SFont() { -} - -SFont::~SFont() { -} - -GBool SFont::getCharPath(CharCode c, Unicode u, GfxState *state) { - return gFalse; -} diff --git a/pdf/xpdf/SFont.h b/pdf/xpdf/SFont.h deleted file mode 100644 index aadf991..0000000 --- a/pdf/xpdf/SFont.h +++ /dev/null @@ -1,142 +0,0 @@ -//======================================================================== -// -// SFont.h -// -// Base class for font rasterizers. -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef SFONT_H -#define SFONT_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include -#include "gtypes.h" -#include "CharTypes.h" - -class GfxState; - -//------------------------------------------------------------------------ - -class SFontEngine { -public: - - SFontEngine(Display *displayA, Visual *visualA, int depthA, - Colormap colormapA); - virtual ~SFontEngine(); - - // Use a TrueColor visual. Pixel values are computed as: - // - // (r << rShift) + (g << gShift) + (b << bShift) - // - // where r, g, and b are scaled to the ranges [0,rMax], [0,gMax], - // and [0,bMax], respectively. - virtual void useTrueColor(int rMaxA, int rShiftA, int gMaxA, int gShiftA, - int bMaxA, int bShiftA); - - // Use an RGB color cube. is an array containing - // ** pixel values in red,green,blue order, e.g., - // for =2, there will be 8 entries: - // - // |--- colors[i] ---| - // i red green blue - // - ----- ----- ----- - // 0 0000 0000 0000 - // 1 0000 0000 ffff - // 2 0000 ffff 0000 - // 3 0000 ffff ffff - // 4 ffff 0000 0000 - // 5 ffff 0000 ffff - // 6 ffff ffff 0000 - // 7 ffff ffff ffff - // - // The array is not copied and must remain valid for the - // lifetime of this SFont object. - virtual void useColorCube(Gulong *colorsA, int nRGBA); - -protected: - - // Find the closest match to (,,). - Gulong findColor(int r, int g, int b); - - //----- X parameters - Display *display; - Visual *visual; - int depth; - Colormap colormap; - - GBool trueColor; // true for TrueColor, false for RGB cube - - //----- TrueColor parameters - int rMax, gMax, bMax; - int rShift, gShift, bShift; - - //----- RGB color cube parameters - Gulong *colors; - int nRGB; -}; - -//------------------------------------------------------------------------ - -class SFontFile { -public: - - // A typical subclass will provide a constructor along the lines of: - // - // SomeFontFile(SomeFontEngine *engine, char *fontFileName); - SFontFile(); - - virtual ~SFontFile(); - -private: -}; - -//------------------------------------------------------------------------ - -class SFont { -public: - - // A typical subclass will provide a constructor along the lines of: - // - // SomeFont(SomeFontFile *fontFile, double *m); - // - // where is a transform matrix consisting of four elements, - // using the PostScript ordering conventions (without any - // translation): - // - // [x' y'] = [x y] * [m0 m1] - // [m2 m3] - // - // This is the level at which fonts are cached, and so the font - // cannot be transformed after it is created. - SFont(); - - virtual ~SFont(); - - // Draw a character / at , in color (,,). The - // RGB values should each be in the range [0,65535]. Draws into - // , clipped to the rectangle (0,0)-(-1,-1). Returns true - // if the character was drawn successfully. - virtual GBool drawChar(Drawable d, int w, int h, GC gc, - int x, int y, int r, int g, int b, - CharCode c, Unicode u) = 0; - - // Add the outline of the specified character to the current path by - // calling state->moveTo, lineTo, and curveTo. Returns true if - // successful. If this SFont subclass doesn't implement character - // paths, returns false immediately without modifying the current - // path. - virtual GBool getCharPath(CharCode c, Unicode u, GfxState *state); - -protected: -}; - -#endif diff --git a/pdf/xpdf/Stream.cc b/pdf/xpdf/Stream.cc index e770b61..49bbb46 100644 --- a/pdf/xpdf/Stream.cc +++ b/pdf/xpdf/Stream.cc @@ -30,6 +30,7 @@ #endif #include "Stream.h" #include "JBIG2Stream.h" +#include "JPXStream.h" #include "Stream-CCITT.h" #ifdef __DJGPP__ @@ -256,6 +257,8 @@ Stream *Stream::makeFilter(char *name, Stream *str, Object *params) { } str = new JBIG2Stream(str, &globals); globals.free(); + } else if (!strcmp(name, "JPXDecode")) { + str = new JPXStream(str); } else { error(getPos(), "Unknown filter '%s'", name); str = new EOFStream(str); @@ -450,7 +453,7 @@ GBool StreamPredictor::getNextLine() { int i, j, k; // get PNG optimum predictor number - if (predictor == 15) { + if (predictor >= 10) { if ((curPred = str->getRawChar()) == EOF) { return gFalse; } @@ -784,20 +787,38 @@ void MemStream::doDecryption(Guchar *fileKey, int keyLength, // EmbedStream //------------------------------------------------------------------------ -EmbedStream::EmbedStream(Stream *strA, Object *dictA): +EmbedStream::EmbedStream(Stream *strA, Object *dictA, + GBool limitedA, Guint lengthA): BaseStream(dictA) { str = strA; + limited = limitedA; + length = lengthA; } EmbedStream::~EmbedStream() { } -Stream *EmbedStream::makeSubStream(Guint start, GBool limited, - Guint length, Object *dictA) { +Stream *EmbedStream::makeSubStream(Guint start, GBool limitedA, + Guint lengthA, Object *dictA) { error(-1, "Internal: called makeSubStream() on EmbedStream"); return NULL; } +int EmbedStream::getChar() { + if (limited && !length) { + return EOF; + } + --length; + return str->getChar(); +} + +int EmbedStream::lookChar() { + if (limited && !length) { + return EOF; + } + return str->lookChar(); +} + void EmbedStream::setPos(Guint pos, int dir) { error(-1, "Internal: called setPos() on EmbedStream"); } @@ -1263,7 +1284,7 @@ CCITTFaxStream::~CCITTFaxStream() { } void CCITTFaxStream::reset() { - int n; + short code1; str->reset(); eof = gFalse; @@ -1275,16 +1296,13 @@ void CCITTFaxStream::reset() { a0 = 1; buf = EOF; - // get initial end-of-line marker and 2D encoding tag - if (endOfBlock) { - if (lookBits(12) == 0x001) { - eatBits(12); - } - } else { - for (n = 0; n < 11 && lookBits(n) == 0; ++n) ; - if (n == 11 && lookBits(12) == 0x001) { - eatBits(12); - } + // skip any initial zero bits and end-of-line marker, and get the 2D + // encoding tag + while ((code1 = lookBits(12)) == 0) { + eatBits(1); + } + if (code1 == 0x001) { + eatBits(12); } if (encoding > 0) { nextLine2D = !lookBits(1); @@ -1295,10 +1313,7 @@ void CCITTFaxStream::reset() { int CCITTFaxStream::lookChar() { short code1, code2, code3; int a0New; -#if 0 - GBool err; -#endif - GBool gotEOL; + GBool err, gotEOL; int ret; int bits, i; @@ -1308,9 +1323,7 @@ int CCITTFaxStream::lookChar() { } // read the next row -#if 0 err = gFalse; -#endif if (codingLine[a0] >= columns) { // 2-D encoding @@ -1412,13 +1425,8 @@ int CCITTFaxStream::lookChar() { return EOF; default: error(getPos(), "Bad 2D code %04x in CCITTFax stream", code1); -#if 0 err = gTrue; break; -#else - eof = gTrue; - return EOF; -#endif } } while (codingLine[a0] < columns); @@ -1447,9 +1455,12 @@ int CCITTFaxStream::lookChar() { if (codingLine[a0] != columns) { error(getPos(), "CCITTFax row is wrong length (%d)", codingLine[a0]); -#if 0 + // force the row to be the correct length + while (codingLine[a0] > columns) { + --a0; + } + codingLine[++a0] = columns; err = gTrue; -#endif } // byte-align the row @@ -1505,14 +1516,11 @@ int CCITTFaxStream::lookChar() { } eof = gTrue; } - } -#if 0 - // This looks for an end-of-line marker after an error, however - // some (most?) CCITT streams in PDF files don't use end-of-line - // markers, and the just-plow-on technique works better in those - // cases. - else if (err) { + // look for an end-of-line marker after an error -- we only do + // this if we know the stream contains end-of-line markers because + // the "just plow on" technique tends to work better otherwise + } else if (err && endOfLine) { do { if (code1 == EOF) { eof = gTrue; @@ -1522,13 +1530,11 @@ int CCITTFaxStream::lookChar() { code1 = lookBits(13); } while ((code1 >> 1) != 0x001); eatBits(12); - codingLine[++a0] = columns; if (encoding > 0) { eatBits(1); nextLine2D = !(code1 & 1); } } -#endif a0 = 0; outputBits = codingLine[1] - codingLine[0]; @@ -3747,6 +3753,10 @@ int FixedLengthEncoder::lookChar() { return str->getChar(); } +GBool FixedLengthEncoder::isBinary(GBool last) { + return str->isBinary(gTrue); +} + //------------------------------------------------------------------------ // ASCIIHexEncoder //------------------------------------------------------------------------ diff --git a/pdf/xpdf/Stream.h b/pdf/xpdf/Stream.h index 0121df1..0b70afa 100644 --- a/pdf/xpdf/Stream.h +++ b/pdf/xpdf/Stream.h @@ -36,6 +36,7 @@ enum StreamKind { strDCT, strFlate, strJBIG2, + strJPX, strWeird // internal-use stream types }; @@ -92,7 +93,7 @@ public: // Does this stream type potentially contain non-printable chars? virtual GBool isBinary(GBool last = gTrue) = 0; - // Get the BaseStream or EmbedStream of this stream. + // Get the BaseStream of this stream. virtual BaseStream *getBaseStream() = 0; // Get the dictionary associated with this stream. @@ -131,6 +132,7 @@ public: virtual Stream *makeSubStream(Guint start, GBool limited, Guint length, Object *dict) = 0; virtual void setPos(Guint pos, int dir = 0) = 0; + virtual GBool isBinary(GBool last = gTrue) { return last; } virtual BaseStream *getBaseStream() { return this; } virtual Dict *getDict() { return dict.getDict(); } @@ -273,7 +275,6 @@ public: { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } virtual int getPos() { return bufPos + (bufPtr - buf); } virtual void setPos(Guint pos, int dir = 0); - virtual GBool isBinary(GBool last = gTrue) { return last; } virtual void ignoreLength() { limited = gFalse; } virtual Guint getStart() { return start; } virtual void moveStart(int delta); @@ -314,7 +315,6 @@ public: { return (bufPtr < bufEnd) ? (*bufPtr & 0xff) : EOF; } virtual int getPos() { return (int)(bufPtr - buf); } virtual void setPos(Guint pos, int dir = 0); - virtual GBool isBinary(GBool last = gTrue) { return last; } virtual Guint getStart() { return start; } virtual void moveStart(int delta); #ifndef NO_DECRYPTION @@ -345,23 +345,24 @@ private: class EmbedStream: public BaseStream { public: - EmbedStream(Stream *strA, Object *dictA); + EmbedStream(Stream *strA, Object *dictA, GBool limitedA, Guint lengthA); virtual ~EmbedStream(); - virtual Stream *makeSubStream(Guint start, GBool limited, - Guint length, Object *dictA); + virtual Stream *makeSubStream(Guint start, GBool limitedA, + Guint lengthA, Object *dictA); virtual StreamKind getKind() { return str->getKind(); } virtual void reset() {} - virtual int getChar() { return str->getChar(); } - virtual int lookChar() { return str->lookChar(); } + virtual int getChar(); + virtual int lookChar(); virtual int getPos() { return str->getPos(); } virtual void setPos(Guint pos, int dir = 0); - virtual GBool isBinary(GBool last = gTrue) { return last; } virtual Guint getStart(); virtual void moveStart(int delta); private: Stream *str; + GBool limited; + Guint length; }; //------------------------------------------------------------------------ @@ -740,7 +741,7 @@ public: virtual int getChar(); virtual int lookChar(); virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; } - virtual GBool isBinary(GBool last = gTrue) { return gFalse; } + virtual GBool isBinary(GBool last = gTrue); virtual GBool isEncoder() { return gTrue; } private: @@ -825,7 +826,7 @@ public: virtual int lookChar() { return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); } virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; } - virtual GBool isBinary(GBool last = gTrue) { return gFalse; } + virtual GBool isBinary(GBool last = gTrue) { return gTrue; } virtual GBool isEncoder() { return gTrue; } private: diff --git a/pdf/xpdf/T1Font.cc b/pdf/xpdf/T1Font.cc deleted file mode 100644 index a03351d..0000000 --- a/pdf/xpdf/T1Font.cc +++ /dev/null @@ -1,566 +0,0 @@ -//======================================================================== -// -// T1Font.cc -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#if HAVE_T1LIB_H - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include "gmem.h" -#include "GfxState.h" -#include "T1Font.h" - -//------------------------------------------------------------------------ - -int T1FontEngine::t1libInitCount = 0; - -//------------------------------------------------------------------------ - -T1FontEngine::T1FontEngine(Display *displayA, Visual *visualA, int depthA, - Colormap colormapA, GBool aaA, GBool aaHighA): - SFontEngine(displayA, visualA, depthA, colormapA) -{ - static unsigned long grayVals[17] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 - }; - - ok = gFalse; - aa = aaA; - aaHigh = aaHighA; - //~ for multithreading: need a mutex here - if (t1libInitCount == 0) { - T1_SetBitmapPad(8); - if (!T1_InitLib(NO_LOGFILE | IGNORE_CONFIGFILE | IGNORE_FONTDATABASE | - T1_NO_AFM)) { - return; - } - if (aa) { - T1_AASetBitsPerPixel(8); - if (aaHigh) { - T1_AASetLevel(T1_AA_HIGH); - T1_AAHSetGrayValues(grayVals); - } else { - T1_AASetLevel(T1_AA_LOW); - T1_AASetGrayValues(0, 1, 2, 3, 4); - } - } else { - T1_AANSetGrayValues(0, 1); - } - } - ++t1libInitCount; - ok = gTrue; -} - -T1FontEngine::~T1FontEngine() { - //~ for multithreading: need a mutex here - if (--t1libInitCount == 0) { - T1_CloseLib(); - } -} - -//------------------------------------------------------------------------ - -T1FontFile::T1FontFile(T1FontEngine *engineA, char *fontFileName, - char **fontEnc, double *bboxA) { - int encStrSize; - char *encPtr; - int i; - - ok = gFalse; - engine = engineA; - enc = NULL; - encStr = NULL; - for (i = 0; i < 4; ++i) { - bbox[i] = bboxA[i]; - } - - // load the font file - if ((id = T1_AddFont(fontFileName)) < 0) { - return; - } - T1_LoadFont(id); - - // reencode it - encStrSize = 0; - for (i = 0; i < 256; ++i) { - if (fontEnc[i]) { - encStrSize += strlen(fontEnc[i]) + 1; - } - } - enc = (char **)gmalloc(257 * sizeof(char *)); - encStr = (char *)gmalloc(encStrSize * sizeof(char)); - encPtr = encStr; - for (i = 0; i < 256; ++i) { - if (fontEnc[i]) { - strcpy(encPtr, fontEnc[i]); - enc[i] = encPtr; - encPtr += strlen(encPtr) + 1; - } else { - enc[i] = ".notdef"; - } - } - enc[256] = "custom"; - T1_ReencodeFont(id, enc); - - ok = gTrue; -} - -T1FontFile::~T1FontFile() { - gfree(enc); - gfree(encStr); - if (id >= 0) { - T1_DeleteFont(id); - } -} - -//------------------------------------------------------------------------ - -T1Font::T1Font(T1FontFile *fontFileA, double *m) { - T1FontEngine *engine; - T1_TMATRIX matrix; - BBox bbox; - double bbx0, bby0, bbx1, bby1; - int x, y, xMin, xMax, yMin, yMax; - int i; - - ok = gFalse; - fontFile = fontFileA; - engine = fontFile->engine; - - id = T1_CopyFont(fontFile->id); - - // compute font size - size = (float)sqrt(m[2]*m[2] + m[3]*m[3]); - - // transform the four corners of the font bounding box -- the min - // and max values form the bounding box of the transformed font - bbx0 = fontFile->bbox[0]; - bby0 = fontFile->bbox[1]; - bbx1 = fontFile->bbox[2]; - bby1 = fontFile->bbox[3]; - // some fonts in PDF files have bboxes which are just plain wrong, - // so we check the font file's bbox too - bbox = T1_GetFontBBox(id); - if (0.001 * bbox.llx < bbx0) { - bbx0 = 0.001 * bbox.llx; - } - if (0.001 * bbox.lly < bby0) { - bby0 = 0.001 * bbox.lly; - } - if (0.001 * bbox.urx > bbx1) { - bbx1 = 0.001 * bbox.urx; - } - if (0.001 * bbox.ury > bby1) { - bby1 = 0.001 * bbox.ury; - } - // some fonts are completely broken, so we fake it (with values - // large enough that most glyphs should fit) - if (bbx0 == 0 && bby0 == 0 && bbx1 == 0 && bby1 == 0) { - bbx0 = bby0 = -0.5; - bbx1 = bby1 = 1.5; - } - x = (int)(m[0] * bbx0 + m[2] * bby0); - xMin = xMax = x; - y = (int)(m[1] * bbx0 + m[3] * bby0); - yMin = yMax = y; - x = (int)(m[0] * bbx0 + m[2] * bby1); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - y = (int)(m[1] * bbx0 + m[3] * bby1); - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - x = (int)(m[0] * bbx1 + m[2] * bby0); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - y = (int)(m[1] * bbx1 + m[3] * bby0); - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - x = (int)(m[0] * bbx1 + m[2] * bby1); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - y = (int)(m[1] * bbx1 + m[3] * bby1); - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - // This is a kludge: some buggy PDF generators embed fonts with - // zero bounding boxes. - if (xMax == xMin) { - xMin = 0; - xMax = (int)size; - } - if (yMax == yMin) { - yMin = 0; - yMax = (int)(1.2 * size); - } - // Another kludge: an unusually large xMin or yMin coordinate is - // probably wrong. - if (xMin > 0) { - xMin = 0; - } - if (yMin > 0) { - yMin = 0; - } - // Another kludge: t1lib doesn't correctly handle fonts with - // real (non-integer) bounding box coordinates. - if (xMax - xMin > 5000) { - xMin = 0; - xMax = (int)size; - } - if (yMax - yMin > 5000) { - yMin = 0; - yMax = (int)(1.2 * size); - } - // this should be (max - min + 1), but we add some padding to - // deal with rounding errors - glyphW = xMax - xMin + 3; - glyphH = yMax - yMin + 3; - if (engine->aa) { - glyphSize = glyphW * glyphH; - } else { - glyphSize = ((glyphW + 7) >> 3) * glyphH; - } - - // set up the glyph pixmap cache - cacheAssoc = 8; - if (glyphSize <= 256) { - cacheSets = 8; - } else if (glyphSize <= 512) { - cacheSets = 4; - } else if (glyphSize <= 1024) { - cacheSets = 2; - } else { - cacheSets = 1; - } - cache = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize); - cacheTags = (T1FontCacheTag *)gmalloc(cacheSets * cacheAssoc * - sizeof(T1FontCacheTag)); - for (i = 0; i < cacheSets * cacheAssoc; ++i) { - cacheTags[i].mru = i & (cacheAssoc - 1); - } - - // create the XImage - if (!(image = XCreateImage(engine->display, engine->visual, engine->depth, - ZPixmap, 0, NULL, glyphW, glyphH, 8, 0))) { - return; - } - image->data = (char *)gmalloc(glyphH * image->bytes_per_line); - - // transform the font - matrix.cxx = m[0] / size; - matrix.cxy = m[1] / size; - matrix.cyx = m[2] / size; - matrix.cyy = m[3] / size; - T1_TransformFont(id, &matrix); - - ok = gTrue; -} - -T1Font::~T1Font() { - gfree(cacheTags); - gfree(cache); - if (image) { - gfree(image->data); - image->data = NULL; - XDestroyImage(image); - } - T1_DeleteFont(id); -} - -GBool T1Font::drawChar(Drawable d, int w, int h, GC gc, - int x, int y, int r, int g, int b, - CharCode c, Unicode u) { - T1FontEngine *engine; - XColor xcolor; - int bgR, bgG, bgB; - Gulong colors[17]; - Guchar *bitmap, *p; - GBool tempBitmap; - XImage *img; - int xOffset, yOffset, x0, y0, x1, y1, gw, gh, w0, h0; - int xx, yy, xx1; - Guchar pix, mPix; - int i; - - engine = fontFile->engine; - - // generate the glyph pixmap - if (!(bitmap = getGlyphPixmap(c, &xOffset, &yOffset, &gw, &gh, - &tempBitmap))) { - return gFalse; - } - - // compute: (x0,y0) = position in destination drawable - // (x1,y1) = position in glyph image - // (w0,h0) = size of image transfer - x0 = x - xOffset; - y0 = y - yOffset; - x1 = 0; - y1 = 0; - w0 = gw; - h0 = gh; - if (x0 < 0) { - x1 = -x0; - w0 += x0; - x0 = 0; - } - if (x0 + w0 > w) { - w0 = w - x0; - } - if (w0 < 0) { - goto done; - } - if (y0 < 0) { - y1 = -y0; - h0 += y0; - y0 = 0; - } - if (y0 + h0 > h) { - h0 = h - y0; - } - if (h0 < 0) { - goto done; - } - - // getGlyphPixmap may have returned a larger-than-cache-entry - // bitmap, in which case we need to allocate a temporary XImage here - if (tempBitmap) { - if (!(img = XCreateImage(engine->display, engine->visual, engine->depth, - ZPixmap, 0, NULL, gw, gh, 8, 0))) { - goto done; - } - img->data = (char *)gmalloc(gh * img->bytes_per_line); - } else { - img = image; - } - - // read the X image - XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1, - ZPixmap, img, x1, y1); - - if (engine->aa) { - - // compute the colors - xcolor.pixel = XGetPixel(img, x1 + w0/2, y1 + h0/2); - XQueryColor(engine->display, engine->colormap, &xcolor); - bgR = xcolor.red; - bgG = xcolor.green; - bgB = xcolor.blue; - if (engine->aaHigh) { - mPix = 16; - for (i = 1; i <= 16; ++i) { - colors[i] = engine->findColor((i * r + (16 - i) * bgR) / 16, - (i * g + (16 - i) * bgG) / 16, - (i * b + (16 - i) * bgB) / 16); - } - } else { - mPix = 4; - colors[1] = engine->findColor((r + 3*bgR) / 4, - (g + 3*bgG) / 4, - (b + 3*bgB) / 4); - colors[2] = engine->findColor((r + bgR) / 2, - (g + bgG) / 2, - (b + bgB) / 2); - colors[3] = engine->findColor((3*r + bgR) / 4, - (3*g + bgG) / 4, - (3*b + bgB) / 4); - colors[4] = engine->findColor(r, g, b); - } - - // stuff the glyph pixmap into the X image - p = bitmap; - for (yy = 0; yy < gh; ++yy) { - for (xx = 0; xx < gw; ++xx) { - pix = *p++; - if (pix > 0) { - if (pix > mPix) { - pix = mPix; - } - XPutPixel(img, xx, yy, colors[pix]); - } - } - } - - } else { - - // one color - colors[1] = engine->findColor(r, g, b); - - // stuff the glyph bitmap into the X image - p = bitmap; - for (yy = 0; yy < gh; ++yy) { - for (xx = 0; xx < gw; xx += 8) { - pix = *p++; - for (xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) { - if (pix & 0x01) { - XPutPixel(img, xx1, yy, colors[1]); - } - pix >>= 1; - } - } - } - - } - - // draw the X image - XPutImage(engine->display, d, gc, img, x1, y1, x0, y0, w0, h0); - - if (tempBitmap) { - gfree(img->data); - img->data = NULL; - XDestroyImage(img); - } - done: - if (tempBitmap) { - gfree(bitmap); - } - return gTrue; -} - -Guchar *T1Font::getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h, - GBool *tempBitmap) { - T1FontEngine *engine; - GLYPH *glyph; - int gSize; - int i, j, k; - Guchar *ret; - - engine = fontFile->engine; - - // check the cache - i = (c & (cacheSets - 1)) * cacheAssoc; - for (j = 0; j < cacheAssoc; ++j) { - if ((cacheTags[i+j].mru & 0x8000) && cacheTags[i+j].code == c) { - *x = cacheTags[i+j].x; - *y = cacheTags[i+j].y; - *w = cacheTags[i+j].w; - *h = cacheTags[i+j].h; - for (k = 0; k < cacheAssoc; ++k) { - if (k != j && - (cacheTags[i+k].mru & 0x7fff) < (cacheTags[i+j].mru & 0x7fff)) { - ++cacheTags[i+k].mru; - } - } - cacheTags[i+j].mru = 0x8000; - *tempBitmap = gFalse; - return cache + (i+j) * glyphSize; - } - } - - // generate the glyph pixmap - if (engine->aa) { - glyph = T1_AASetChar(id, c, size, NULL); - } else { - glyph = T1_SetChar(id, c, size, NULL); - } - if (!glyph) { - return NULL; - } - - // copy the glyph into the cache or a temporary bitmap - *x = -glyph->metrics.leftSideBearing; - *y = glyph->metrics.ascent; - *w = glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing; - *h = glyph->metrics.ascent - glyph->metrics.descent; - if (engine->aa) { - gSize = *w * *h; - } else { - gSize = ((*w + 7) >> 3) * *h; - } - if (*w > glyphW || *h > glyphH) { - // the glyph doesn't fit in the bounding box -- return a - // temporary, uncached bitmap (this shouldn't happen but some - // fonts have incorrect bboxes) - ret = (Guchar *)gmalloc(gSize); - *tempBitmap = gTrue; - } else { - // store glyph pixmap in cache - ret = NULL; // make gcc happy - for (j = 0; j < cacheAssoc; ++j) { - if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) { - cacheTags[i+j].mru = 0x8000; - cacheTags[i+j].code = c; - cacheTags[i+j].x = *x; - cacheTags[i+j].y = *y; - cacheTags[i+j].w = *w; - cacheTags[i+j].h = *h; - ret = cache + (i+j) * glyphSize; - } else { - ++cacheTags[i+j].mru; - } - } - *tempBitmap = gFalse; - } - if (glyph->bits) { - memcpy(ret, glyph->bits, gSize); - } else { - memset(ret, 0, gSize); - } - return ret; -} - -GBool T1Font::getCharPath(CharCode c, Unicode u, GfxState *state) { - T1_OUTLINE *outline; - T1_PATHSEGMENT *seg; - T1_BEZIERSEGMENT *bez; - double x, y, x1, y1; - - outline = T1_GetCharOutline(id, c, size, NULL); - x = 0; - y = 0; - for (seg = outline; seg; seg = seg->link) { - switch (seg->type) { - case T1_PATHTYPE_MOVE: - x += seg->dest.x / 65536.0; - y += seg->dest.y / 65536.0; - state->moveTo(x, y); - break; - case T1_PATHTYPE_LINE: - x += seg->dest.x / 65536.0; - y += seg->dest.y / 65536.0; - state->lineTo(x, y); - break; - case T1_PATHTYPE_BEZIER: - bez = (T1_BEZIERSEGMENT *)seg; - x1 = x + bez->dest.x / 65536.0; - y1 = y + bez->dest.y / 65536.0; - state->curveTo(x + bez->B.x / 65536.0, y + bez->B.y / 65536.0, - x + bez->C.x / 65536.0, y + bez->C.y / 65536.0, - x1, y1); - x = x1; - y = y1; - break; - } - } - T1_FreeOutline(outline); - return gTrue; -} - -#endif // HAVE_T1LIB_H diff --git a/pdf/xpdf/T1Font.h b/pdf/xpdf/T1Font.h deleted file mode 100644 index 416f533..0000000 --- a/pdf/xpdf/T1Font.h +++ /dev/null @@ -1,111 +0,0 @@ -//======================================================================== -// -// T1Font.h -// -// An X wrapper for the t1lib Type 1 font rasterizer. -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef T1FONT_H -#define T1FONT_H - -#include - -#if HAVE_T1LIB_H - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include -#include "SFont.h" - -class GfxState; - -//------------------------------------------------------------------------ - -class T1FontEngine: public SFontEngine { -public: - - T1FontEngine(Display *displayA, Visual *visualA, int depthA, - Colormap colormapA, GBool aaA, GBool aaHighA); - GBool isOk() { return ok; } - virtual ~T1FontEngine(); - -private: - - GBool aa; // use anti-aliasing? - GBool aaHigh; // use high-res anti-aliasing? - GBool ok; - - static int t1libInitCount; - - friend class T1FontFile; - friend class T1Font; -}; - -//------------------------------------------------------------------------ - -class T1FontFile: public SFontFile { -public: - - T1FontFile(T1FontEngine *engineA, char *fontFileName, - char **fontEnc, double *bboxA); - GBool isOk() { return ok; } - virtual ~T1FontFile(); - -private: - - T1FontEngine *engine; - int id; // t1lib font ID - char **enc; - char *encStr; - double bbox[4]; - GBool ok; - - friend class T1Font; -}; - -//------------------------------------------------------------------------ - -struct T1FontCacheTag { - Gushort code; - Gushort mru; // valid bit (0x8000) and MRU index - int x, y, w, h; // offset and size of glyph -}; - -class T1Font: public SFont { -public: - - T1Font(T1FontFile *fontFileA, double *m); - GBool isOk() { return ok; } - virtual ~T1Font(); - virtual GBool drawChar(Drawable d, int w, int h, GC gc, - int x, int y, int r, int g, int b, - CharCode c, Unicode u); - virtual GBool getCharPath(CharCode c, Unicode u, GfxState *state); - -private: - - Guchar *getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h, - GBool *tempBitmap); - - T1FontFile *fontFile; - int id; - float size; - XImage *image; - int glyphW, glyphH; // size of glyph pixmaps - int glyphSize; // size of glyph pixmaps, in bytes - Guchar *cache; // glyph pixmap cache - T1FontCacheTag *cacheTags; // cache tags, i.e., char codes - int cacheSets; // number of sets in cache - int cacheAssoc; // cache associativity (glyphs per set) - GBool ok; -}; - -#endif // HAVE_T1LIB_H - -#endif diff --git a/pdf/xpdf/TTFont.cc b/pdf/xpdf/TTFont.cc deleted file mode 100644 index c499cf1..0000000 --- a/pdf/xpdf/TTFont.cc +++ /dev/null @@ -1,485 +0,0 @@ -//======================================================================== -// -// TTFont.cc -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include "gmem.h" -#include "GlobalParams.h" -#include "TTFont.h" - -//------------------------------------------------------------------------ - -TTFontEngine::TTFontEngine(Display *displayA, Visual *visualA, int depthA, - Colormap colormapA, GBool aaA): - SFontEngine(displayA, visualA, depthA, colormapA) { - static TT_Byte ttPalette[5] = {0, 1, 2, 3, 4}; - - ok = gFalse; - if (TT_Init_FreeType(&engine)) { - return; - } - aa = aaA; - if (aa) { - if (TT_Set_Raster_Gray_Palette(engine, ttPalette)) { - return; - } - } - ok = gTrue; -} - -TTFontEngine::~TTFontEngine() { - TT_Done_FreeType(engine); -} - -//------------------------------------------------------------------------ - -TTFontFile::TTFontFile(TTFontEngine *engineA, char *fontFileName, - char **fontEnc, GBool pdfFontHasEncoding) { - TT_Face_Properties props; - TT_UShort unicodeCmap, macRomanCmap, msSymbolCmap; - TT_UShort platform, encoding, i; - int j; - - ok = gFalse; - engine = engineA; - codeMap = NULL; - if (TT_Open_Face(engine->engine, fontFileName, &face)) { - return; - } - if (TT_Get_Face_Properties(face, &props)) { - return; - } - - // To match up with the Adobe-defined behaviour, we choose a cmap - // like this: - // 1. If the PDF font has an encoding: - // 1a. If the PDF font specified MacRomanEncoding and the - // TrueType font has a Macintosh Roman cmap, use it, and - // reverse map the char names through MacRomanEncoding to - // get char codes. - // 1b. If the TrueType font has a Microsoft Unicode cmap or a - // non-Microsoft Unicode cmap, use it, and use the Unicode - // indexes, not the char codes. - // 1c. If the PDF font is symbolic and the TrueType font has a - // Microsoft Symbol cmap, use it, and use char codes - // directly (possibly with an offset of 0xf000). - // 1d. If the TrueType font has a Macintosh Roman cmap, use it, - // as in case 1a. - // 2. If the PDF font does not have an encoding: - // 2a. If the TrueType font has a Macintosh Roman cmap, use it, - // and use char codes directly (possibly with an offset of - // 0xf000). - // 2b. If the TrueType font has a Microsoft Symbol cmap, use it, - // and use char codes directly (possible with an offset of - // 0xf000). - // 3. If none of these rules apply, use the first cmap and hope for - // the best (this shouldn't happen). - unicodeCmap = macRomanCmap = msSymbolCmap = 0xffff; - for (i = 0; i < props.num_CharMaps; ++i) { - if (!TT_Get_CharMap_ID(face, i, &platform, &encoding)) { - if ((platform == 3 && encoding == 1) || platform == 0) { - unicodeCmap = i; - } else if (platform == 1 && encoding == 0) { - macRomanCmap = i; - } else if (platform == 3 && encoding == 0) { - msSymbolCmap = i; - } - } - } - i = 0; - mode = ttFontModeCharCode; - if (pdfFontHasEncoding) { - if (unicodeCmap != 0xffff) { - i = unicodeCmap; - mode = ttFontModeUnicode; - } else if (macRomanCmap != 0xffff) { - i = macRomanCmap; - mode = ttFontModeCodeMap; - codeMap = (Guchar *)gmalloc(256 * sizeof(Guchar)); - for (j = 0; j < 256; ++j) { - if (fontEnc[j]) { - codeMap[j] = (Guchar)globalParams->getMacRomanCharCode(fontEnc[j]); - } else { - codeMap[j] = 0; - } - } - } - } else { - if (macRomanCmap != 0xffff) { - i = macRomanCmap; - mode = ttFontModeCharCode; - } else if (msSymbolCmap != 0xffff) { - i = msSymbolCmap; - mode = ttFontModeCharCode; - } - } - TT_Get_CharMap(face, i, &charMap); - - ok = gTrue; -} - -TTFontFile::TTFontFile(TTFontEngine *engineA, char *fontFileName, - Gushort *cidToGIDA, int cidToGIDLenA) { - ok = gFalse; - engine = engineA; - codeMap = NULL; - cidToGID = cidToGIDA; - cidToGIDLen = cidToGIDLenA; - if (TT_Open_Face(engine->engine, fontFileName, &face)) { - return; - } - mode = ttFontModeCIDToGIDMap; - ok = gTrue; -} - -TTFontFile::~TTFontFile() { - TT_Close_Face(face); - if (codeMap) { - gfree(codeMap); - } -} - -//------------------------------------------------------------------------ - -TTFont::TTFont(TTFontFile *fontFileA, double *m) { - TTFontEngine *engine; - TT_Face_Properties props; - TT_Instance_Metrics metrics; - int x, xMin, xMax; - int y, yMin, yMax; - int i; - - ok = gFalse; - fontFile = fontFileA; - engine = fontFile->engine; - if (TT_New_Instance(fontFile->face, &instance) || - TT_Set_Instance_Resolutions(instance, 72, 72) || - TT_Set_Instance_CharSize(instance, 1000 * 64) || - TT_New_Glyph(fontFile->face, &glyph) || - TT_Get_Face_Properties(fontFile->face, &props) || - TT_Get_Instance_Metrics(instance, &metrics)) { - return; - } - - // transform the four corners of the font bounding box -- the min - // and max values form the bounding box of the transformed font - x = (int)((m[0] * props.header->xMin + m[2] * props.header->yMin) * - 0.001 * metrics.x_ppem / props.header->Units_Per_EM); - xMin = xMax = x; - y = (int)((m[1] * props.header->xMin + m[3] * props.header->yMin) * - 0.001 * metrics.x_ppem / props.header->Units_Per_EM); - yMin = yMax = y; - x = (int)((m[0] * props.header->xMin + m[2] * props.header->yMax) * - 0.001 * metrics.x_ppem / props.header->Units_Per_EM); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - y = (int)((m[1] * props.header->xMin + m[3] * props.header->yMax) * - 0.001 * metrics.x_ppem / props.header->Units_Per_EM); - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - x = (int)((m[0] * props.header->xMax + m[2] * props.header->yMin) * - 0.001 * metrics.x_ppem / props.header->Units_Per_EM); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - y = (int)((m[1] * props.header->xMax + m[3] * props.header->yMin) * - 0.001 * metrics.x_ppem / props.header->Units_Per_EM); - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - x = (int)((m[0] * props.header->xMax + m[2] * props.header->yMax) * - 0.001 * metrics.x_ppem / props.header->Units_Per_EM); - if (x < xMin) { - xMin = x; - } else if (x > xMax) { - xMax = x; - } - y = (int)((m[1] * props.header->xMax + m[3] * props.header->yMax) * - 0.001 * metrics.x_ppem / props.header->Units_Per_EM); - if (y < yMin) { - yMin = y; - } else if (y > yMax) { - yMax = y; - } - xOffset = -xMin; - yOffset = -yMin; - ras.width = xMax - xMin + 1; - ras.rows = yMax - yMin + 1; - - // set up the Raster_Map structure - if (engine->aa) { - ras.width = (ras.width + 3) & ~3; - ras.cols = ras.width; - } else { - ras.width = (ras.width + 7) & ~7; - ras.cols = ras.width >> 3; - } - ras.flow = TT_Flow_Down; - ras.size = ras.rows * ras.cols; - ras.bitmap = gmalloc(ras.size); - - // set up the glyph pixmap cache - cacheAssoc = 8; - if (ras.size <= 256) { - cacheSets = 8; - } else if (ras.size <= 512) { - cacheSets = 4; - } else if (ras.size <= 1024) { - cacheSets = 2; - } else { - cacheSets = 1; - } - cache = (Guchar *)gmalloc(cacheSets * cacheAssoc * ras.size); - cacheTags = (TTFontCacheTag *)gmalloc(cacheSets * cacheAssoc * - sizeof(TTFontCacheTag)); - for (i = 0; i < cacheSets * cacheAssoc; ++i) { - cacheTags[i].mru = i & (cacheAssoc - 1); - } - - // create the XImage - if (!(image = XCreateImage(engine->display, engine->visual, engine->depth, - ZPixmap, 0, NULL, ras.width, ras.rows, 8, 0))) { - return; - } - image->data = (char *)gmalloc(ras.rows * image->bytes_per_line); - - // compute the transform matrix - matrix.xx = (TT_Fixed)(m[0] * 65.536); - matrix.yx = (TT_Fixed)(m[1] * 65.536); - matrix.xy = (TT_Fixed)(m[2] * 65.536); - matrix.yy = (TT_Fixed)(m[3] * 65.536); - - ok = gTrue; -} - -TTFont::~TTFont() { - gfree(cacheTags); - gfree(cache); - gfree(image->data); - image->data = NULL; - XDestroyImage(image); - gfree(ras.bitmap); - TT_Done_Glyph(glyph); - TT_Done_Instance(instance); -} - -GBool TTFont::drawChar(Drawable d, int w, int h, GC gc, - int x, int y, int r, int g, int b, - CharCode c, Unicode u) { - TTFontEngine *engine; - XColor xcolor; - int bgR, bgG, bgB; - Gulong colors[5]; - TT_Byte *p; - TT_Byte pix; - int xx, yy, xx1; - int x0, y0, x1, y1, w0, h0; - - engine = fontFile->engine; - - // compute: (x0,y0) = position in destination drawable - // (x1,y1) = position in glyph image - // (w0,h0) = size of image transfer - x0 = x - xOffset; - y0 = y - (ras.rows - yOffset); - x1 = 0; - y1 = 0; - w0 = ras.width; - h0 = ras.rows; - if (x0 < 0) { - x1 = -x0; - w0 += x0; - x0 = 0; - } - if (x0 + w0 > w) { - w0 = w - x0; - } - if (w0 < 0) { - return gTrue; - } - if (y0 < 0) { - y1 = -y0; - h0 += y0; - y0 = 0; - } - if (y0 + h0 > h) { - h0 = h - y0; - } - if (h0 < 0) { - return gTrue; - } - - // read the X image - XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1, - ZPixmap, image, x1, y1); - - // generate the glyph pixmap - if (!getGlyphPixmap(c, u)) { - return gFalse; - } - - if (engine->aa) { - - // compute the colors - xcolor.pixel = XGetPixel(image, x1 + w0/2, y1 + h0/2); - XQueryColor(engine->display, engine->colormap, &xcolor); - bgR = xcolor.red; - bgG = xcolor.green; - bgB = xcolor.blue; - colors[1] = engine->findColor((r + 3*bgR) / 4, - (g + 3*bgG) / 4, - (b + 3*bgB) / 4); - colors[2] = engine->findColor((r + bgR) / 2, - (g + bgG) / 2, - (b + bgB) / 2); - colors[3] = engine->findColor((3*r + bgR) / 4, - (3*g + bgG) / 4, - (3*b + bgB) / 4); - colors[4] = engine->findColor(r, g, b); - - // stuff the glyph pixmap into the X image - p = (TT_Byte *)ras.bitmap; - for (yy = 0; yy < ras.rows; ++yy) { - for (xx = 0; xx < ras.width; ++xx) { - pix = *p++; - if (pix > 0) { - if (pix > 4) { - pix = 4; - } - XPutPixel(image, xx, yy, colors[pix]); - } - } - } - - } else { - - // one color - colors[1] = engine->findColor(r, g, b); - - // stuff the glyph bitmap into the X image - p = (TT_Byte *)ras.bitmap; - for (yy = 0; yy < ras.rows; ++yy) { - for (xx = 0; xx < ras.width; xx += 8) { - pix = *p++; - for (xx1 = xx; xx1 < xx + 8 && xx1 < ras.width; ++xx1) { - if (pix & 0x80) { - XPutPixel(image, xx1, yy, colors[1]); - } - pix <<= 1; - } - } - } - - } - - // draw the X image - XPutImage(engine->display, d, gc, image, x1, y1, x0, y0, w0, h0); - - return gTrue; -} - -GBool TTFont::getGlyphPixmap(CharCode c, Unicode u) { - TT_UShort idx; - TT_Outline outline; - int i, j, k; - - // check the cache - i = (c & (cacheSets - 1)) * cacheAssoc; - for (j = 0; j < cacheAssoc; ++j) { - if ((cacheTags[i+j].mru & 0x8000) && cacheTags[i+j].code == c) { - memcpy(ras.bitmap, cache + (i+j) * ras.size, ras.size); - for (k = 0; k < cacheAssoc; ++k) { - if (k != j && - (cacheTags[i+k].mru & 0x7fff) < (cacheTags[i+j].mru & 0x7fff)) { - ++cacheTags[i+k].mru; - } - } - cacheTags[i+j].mru = 0x8000; - return gTrue; - } - } - - // generate the glyph pixmap or bitmap - idx = 0; // make gcc happy - switch (fontFile->mode) { - case ttFontModeUnicode: - idx = TT_Char_Index(fontFile->charMap, (TT_UShort)u); - break; - case ttFontModeCharCode: - if ((idx = TT_Char_Index(fontFile->charMap, (TT_UShort)c)) == 0) { - idx = TT_Char_Index(fontFile->charMap, (TT_UShort)(0xf000 + c)); - } - break; - case ttFontModeCodeMap: - if (c <= 0xff) { - idx = TT_Char_Index(fontFile->charMap, - (TT_UShort)(fontFile->codeMap[c] & 0xff)); - } else { - idx = 0; - } - break; - case ttFontModeCIDToGIDMap: - if (fontFile->cidToGIDLen) { - if ((int)c < fontFile->cidToGIDLen) { - idx = (TT_UShort)fontFile->cidToGID[c]; - } else { - idx = (TT_UShort)0; - } - } else { - idx = (TT_UShort)c; - } - break; - } - if (TT_Load_Glyph(instance, glyph, idx, TTLOAD_DEFAULT) || - TT_Get_Glyph_Outline(glyph, &outline)) { - return gFalse; - } - TT_Transform_Outline(&outline, &matrix); - memset(ras.bitmap, 0, ras.size); - if (fontFile->engine->aa) { - if (TT_Get_Glyph_Pixmap(glyph, &ras, xOffset * 64, yOffset * 64)) { - return gFalse; - } - } else { - if (TT_Get_Glyph_Bitmap(glyph, &ras, xOffset * 64, yOffset * 64)) { - return gFalse; - } - } - - // store glyph pixmap in cache - for (j = 0; j < cacheAssoc; ++j) { - if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) { - cacheTags[i+j].mru = 0x8000; - cacheTags[i+j].code = c; - memcpy(cache + (i+j) * ras.size, ras.bitmap, ras.size); - } else { - ++cacheTags[i+j].mru; - } - } - - return gTrue; -} - -#endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) diff --git a/pdf/xpdf/TTFont.h b/pdf/xpdf/TTFont.h deleted file mode 100644 index e4740ea..0000000 --- a/pdf/xpdf/TTFont.h +++ /dev/null @@ -1,127 +0,0 @@ -//======================================================================== -// -// TTFont.h -// -// An X wrapper for the FreeType TrueType font rasterizer. -// -// Copyright 2001-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef TTFONT_H -#define TTFONT_H - -#include - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#if HAVE_FREETYPE_FREETYPE_H -#include -#include -#else -#include -#include -#endif -#include "gtypes.h" -#include "SFont.h" - -//------------------------------------------------------------------------ - -class TTFontEngine: public SFontEngine { -public: - - TTFontEngine(Display *displayA, Visual *visualA, int depthA, - Colormap colormapA, GBool aaA); - GBool isOk() { return ok; } - virtual ~TTFontEngine(); - -private: - - TT_Engine engine; - GBool aa; - Gulong palette[5]; - GBool ok; - - friend class TTFontFile; - friend class TTFont; -}; - -//------------------------------------------------------------------------ - -enum TTFontIndexMode { - ttFontModeUnicode, - ttFontModeCharCode, - ttFontModeCodeMap, - ttFontModeCIDToGIDMap -}; - -class TTFontFile: public SFontFile { -public: - - // 8-bit font, TrueType or Type 1/1C - TTFontFile(TTFontEngine *engineA, char *fontFileName, - char **fontEnc, GBool pdfFontHasEncoding); - - // CID font, TrueType - TTFontFile(TTFontEngine *engineA, char *fontFileName, - Gushort *cidToGIDA, int cidToGIDLenA); - - GBool isOk() { return ok; } - virtual ~TTFontFile(); - -private: - - TTFontEngine *engine; - TT_Face face; - TT_CharMap charMap; - TTFontIndexMode mode; - Guchar *codeMap; - Gushort *cidToGID; - int cidToGIDLen; - GBool ok; - - friend class TTFont; -}; - -//------------------------------------------------------------------------ - -struct TTFontCacheTag { - Gushort code; - Gushort mru; // valid bit (0x8000) and MRU index -}; - -class TTFont: public SFont { -public: - - TTFont(TTFontFile *fontFileA, double *m); - GBool isOk() { return ok; } - virtual ~TTFont(); - virtual GBool drawChar(Drawable d, int w, int h, GC gc, - int x, int y, int r, int g, int b, - CharCode c, Unicode u); - -private: - - GBool getGlyphPixmap(CharCode c, Unicode u); - - TTFontFile *fontFile; - TT_Instance instance; - TT_Glyph glyph; - TT_Raster_Map ras; - XImage *image; - TT_Matrix matrix; - TT_F26Dot6 xOffset, yOffset; - Guchar *cache; // glyph pixmap cache - TTFontCacheTag *cacheTags; // cache tags, i.e., char codes - int cacheSets; // number of sets in cache - int cacheAssoc; // cache associativity (glyphs per set) - GBool ok; -}; - -#endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -#endif diff --git a/pdf/xpdf/TextOutputDev.cc b/pdf/xpdf/TextOutputDev.cc index aeee59c..c6fdfb9 100644 --- a/pdf/xpdf/TextOutputDev.cc +++ b/pdf/xpdf/TextOutputDev.cc @@ -45,9 +45,13 @@ // this many points. #define textPoolStep 4 -// Inter-character space width which will cause addChar to break up a -// text string. -#define defaultSpaceWidth 0.25 +// Inter-character space width which will cause addChar to start a new +// word. +#define minWordBreakSpace 0.1 + +// Negative inter-character space width, i.e., overlap, which will +// cause addChar to start a new word. +#define minDupBreakOverlap 0.2 // Max distance between baselines of two lines within a block, as a // fraction of the font size. @@ -72,13 +76,17 @@ // Minimum inter-word spacing, as a fraction of the font size. (Only // used for raw ordering.) -#define minWordSpacing 0.2 +#define minWordSpacing 0.15 // Maximum inter-word spacing, as a fraction of the font size. #define maxWordSpacing 1.5 +// Maximum horizontal spacing which will allow a word to be pulled +// into a block. +#define minColSpacing1 0.3 + // Minimum spacing between columns, as a fraction of the font size. -#define minColSpacing 1.0 +#define minColSpacing2 1.0 // Maximum vertical spacing between blocks within a flow, as a // multiple of the font size. @@ -1591,6 +1599,7 @@ TextPage::TextPage(GBool rawOrderA) { curFontSize = 0; nest = 0; nTinyChars = 0; + lastCharOverlap = gFalse; if (!rawOrder) { for (rot = 0; rot < 4; ++rot) { pools[rot] = new TextPool(); @@ -1627,6 +1636,12 @@ void TextPage::startPage(GfxState *state) { } } +void TextPage::endPage() { + if (curWord) { + endWord(); + } +} + void TextPage::clear() { int rot; TextFlow *flow; @@ -1748,7 +1763,7 @@ void TextPage::beginWord(GfxState *state, double x0, double y0) { // This check is needed because Type 3 characters can contain // text-drawing operations (when TextPage is being used via - // XOutputDev rather than TextOutputDev). + // {X,Win}SplashOutputDev rather than TextOutputDev). if (curWord) { ++nest; return; @@ -1784,8 +1799,8 @@ void TextPage::beginWord(GfxState *state, double x0, double y0) { void TextPage::addChar(GfxState *state, double x, double y, double dx, double dy, CharCode c, Unicode *u, int uLen) { - double x1, y1, w1, h1, dx2, dy2, sp; - int n, i; + double x1, y1, w1, h1, dx2, dy2, base, sp; + int i; // if the previous char was a space, addChar will have called // endWord, so we need to start a new word @@ -1826,21 +1841,46 @@ void TextPage::addChar(GfxState *state, double x, double y, return; } - // large char spacing is sometimes used to move text around -- in - // this case, break text into individual chars and let the coalesce - // function deal with it later - n = curWord->len; - if (n > 0) { + // start a new word if: + // (1) this character's baseline doesn't match the current word's + // baseline, or + // (2) there is space between the end of the current word and this + // character, or + // (3) this character overlaps the previous one (duplicated text), or + // (4) the previous character was an overlap (we want each duplicated + // characters to be in a word by itself) + base = sp = 0; // make gcc happy + if (curWord->len > 0) { switch (curWord->rot) { - case 0: sp = x1 - curWord->xMax; break; - case 1: sp = y1 - curWord->yMax; break; - case 2: sp = curWord->xMin - x1; break; - case 3: sp = curWord->yMin - y1; break; + case 0: + base = y1; + sp = x1 - curWord->xMax; + break; + case 1: + base = x1; + sp = y1 - curWord->yMax; + break; + case 2: + base = y1; + sp = curWord->xMin - x1; + break; + case 3: + base = x1; + sp = curWord->yMin - y1; + break; } - if (sp > defaultSpaceWidth * curWord->fontSize) { + if (fabs(base - curWord->base) > 0.5 || + sp > minWordBreakSpace * curWord->fontSize || + sp < -minDupBreakOverlap * curWord->fontSize || + lastCharOverlap) { + lastCharOverlap = gTrue; endWord(); beginWord(state, x, y); + } else { + lastCharOverlap = gFalse; } + } else { + lastCharOverlap = gFalse; } // page rotation and/or transform matrices can cause text to be @@ -1873,7 +1913,7 @@ void TextPage::addChar(GfxState *state, double x, double y, void TextPage::endWord() { // This check is needed because Type 3 characters can contain // text-drawing operations (when TextPage is being used via - // XOutputDev rather than TextOutputDev). + // {X,Win}SplashOutputDev rather than TextOutputDev). if (nest > 0) { --nest; return; @@ -1915,7 +1955,7 @@ void TextPage::coalesce(GBool physLayout) { TextFlow *flow, *lastFlow; int rot, poolMinBaseIdx, baseIdx, startBaseIdx; double minBase, maxBase, newMinBase, newMaxBase; - double fontSize, colSpace, lineSpace, intraLineSpace, blkSpace; + double fontSize, colSpace1, colSpace2, lineSpace, intraLineSpace, blkSpace; GBool found; int count[4]; int lrCount; @@ -2000,7 +2040,8 @@ void TextPage::coalesce(GBool physLayout) { fontSize = word0->fontSize; minBase = maxBase = word0->base; - colSpace = minColSpacing * fontSize; + colSpace1 = minColSpacing1 * fontSize; + colSpace2 = minColSpacing2 * fontSize; lineSpace = maxLineSpacingDelta * fontSize; intraLineSpace = maxIntraLineDelta * fontSize; @@ -2089,8 +2130,10 @@ void TextPage::coalesce(GBool physLayout) { if (word1->base >= minBase - intraLineSpace && word1->base <= maxBase + intraLineSpace && ((rot == 0 || rot == 2) - ? (word1->xMin < blk->xMax && word1->xMax > blk->xMin) - : (word1->yMin < blk->yMax && word1->yMax > blk->yMin)) && + ? (word1->xMin < blk->xMax + colSpace1 && + word1->xMax > blk->xMin - colSpace1) + : (word1->yMin < blk->yMax + colSpace1 && + word1->yMax > blk->yMin - colSpace1)) && fabs(word1->fontSize - fontSize) < maxBlockFontSizeDelta2 * fontSize) { word2 = word1; @@ -2129,9 +2172,9 @@ void TextPage::coalesce(GBool physLayout) { word1->base <= maxBase + intraLineSpace && ((rot == 0 || rot == 2) ? (word1->xMax <= blk->xMin && - word1->xMax > blk->xMin - colSpace) + word1->xMax > blk->xMin - colSpace2) : (word1->yMax <= blk->yMin && - word1->yMax > blk->yMin - colSpace)) && + word1->yMax > blk->yMin - colSpace2)) && fabs(word1->fontSize - fontSize) < maxBlockFontSizeDelta3 * fontSize) { ++n; @@ -2151,9 +2194,9 @@ void TextPage::coalesce(GBool physLayout) { word1->base <= maxBase + intraLineSpace && ((rot == 0 || rot == 2) ? (word1->xMax <= blk->xMin && - word1->xMax > blk->xMin - colSpace) + word1->xMax > blk->xMin - colSpace2) : (word1->yMax <= blk->yMin && - word1->yMax > blk->yMin - colSpace)) && + word1->yMax > blk->yMin - colSpace2)) && fabs(word1->fontSize - fontSize) < maxBlockFontSizeDelta3 * fontSize) { word2 = word1; @@ -2193,9 +2236,9 @@ void TextPage::coalesce(GBool physLayout) { word1->base <= maxBase + intraLineSpace && ((rot == 0 || rot == 2) ? (word1->xMin >= blk->xMax && - word1->xMin < blk->xMax + colSpace) + word1->xMin < blk->xMax + colSpace2) : (word1->yMin >= blk->yMax && - word1->yMin < blk->yMax + colSpace)) && + word1->yMin < blk->yMax + colSpace2)) && fabs(word1->fontSize - fontSize) < maxBlockFontSizeDelta3 * fontSize) { ++n; @@ -2215,9 +2258,9 @@ void TextPage::coalesce(GBool physLayout) { word1->base <= maxBase + intraLineSpace && ((rot == 0 || rot == 2) ? (word1->xMin >= blk->xMax && - word1->xMin < blk->xMax + colSpace) + word1->xMin < blk->xMax + colSpace2) : (word1->yMin >= blk->yMax && - word1->yMin < blk->yMax + colSpace)) && + word1->yMin < blk->yMax + colSpace2)) && fabs(word1->fontSize - fontSize) < maxBlockFontSizeDelta3 * fontSize) { word2 = word1; @@ -3435,6 +3478,7 @@ void TextOutputDev::startPage(int pageNum, GfxState *state) { } void TextOutputDev::endPage() { + text->endPage(); text->coalesce(physLayout); if (outputStream) { text->dump(outputStream, outputFunc, physLayout); @@ -3446,11 +3490,9 @@ void TextOutputDev::updateFont(GfxState *state) { } void TextOutputDev::beginString(GfxState *state, GString *s) { - text->beginWord(state, state->getCurX(), state->getCurY()); } void TextOutputDev::endString(GfxState *state) { - text->endWord(); } void TextOutputDev::drawChar(GfxState *state, double x, double y, diff --git a/pdf/xpdf/TextOutputDev.h b/pdf/xpdf/TextOutputDev.h index b501907..2c62237 100644 --- a/pdf/xpdf/TextOutputDev.h +++ b/pdf/xpdf/TextOutputDev.h @@ -354,6 +354,9 @@ public: // Start a new page. void startPage(GfxState *state); + // End the current page. + void endPage(); + // Update the current font. void updateFont(GfxState *state); @@ -426,6 +429,8 @@ private: double curFontSize; // current font size int nest; // current nesting level (for Type 3 fonts) int nTinyChars; // number of "tiny" chars seen so far + GBool lastCharOverlap; // set if the last added char overlapped the + // previous char TextPool *pools[4]; // a "pool" of TextWords for each rotation TextFlow *flows; // linked list of flows diff --git a/pdf/xpdf/XOutputDev.cc b/pdf/xpdf/XOutputDev.cc deleted file mode 100644 index a156b55..0000000 --- a/pdf/xpdf/XOutputDev.cc +++ /dev/null @@ -1,3986 +0,0 @@ -//======================================================================== -// -// XOutputDev.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include -#include -#include -#include -#include -#include -#include -#include "gmem.h" -#include "gfile.h" -#include "GString.h" -#include "GList.h" -#include "Object.h" -#include "Stream.h" -#include "Link.h" -#include "GfxState.h" -#include "GfxFont.h" -#include "UnicodeMap.h" -#include "CharCodeToUnicode.h" -#include "FontFile.h" -#include "Error.h" -#include "TextOutputDev.h" -#include "XOutputDev.h" -#if HAVE_T1LIB_H -#include "T1Font.h" -#endif -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -#include "FTFont.h" -#endif -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -#include "TTFont.h" -#endif - -#ifdef VMS -#if (__VMS_VER < 70000000) -extern "C" int unlink(char *filename); -#endif -#endif - -#ifdef XlibSpecificationRelease -#if XlibSpecificationRelease < 5 -typedef char *XPointer; -#endif -#else -typedef char *XPointer; -#endif - -//------------------------------------------------------------------------ -// Constants and macros -//------------------------------------------------------------------------ - -#define xoutRound(x) ((int)(x + 0.5)) - -#define maxCurveSplits 6 // max number of splits when recursively - // drawing Bezier curves - -//------------------------------------------------------------------------ -// Font substitutions -//------------------------------------------------------------------------ - -struct XOutFontSubst { - char *name; - double mWidth; -}; - -// index: {symbolic:12, fixed:8, serif:4, sans-serif:0} + bold*2 + italic -static XOutFontSubst xOutSubstFonts[16] = { - {"Helvetica", 0.833}, - {"Helvetica-Oblique", 0.833}, - {"Helvetica-Bold", 0.889}, - {"Helvetica-BoldOblique", 0.889}, - {"Times-Roman", 0.788}, - {"Times-Italic", 0.722}, - {"Times-Bold", 0.833}, - {"Times-BoldItalic", 0.778}, - {"Courier", 0.600}, - {"Courier-Oblique", 0.600}, - {"Courier-Bold", 0.600}, - {"Courier-BoldOblique", 0.600}, - {"Symbol", 0.576}, - {"Symbol", 0.576}, - {"Symbol", 0.576}, - {"Symbol", 0.576} -}; - -//------------------------------------------------------------------------ - -static void outputToFile(void *stream, char *data, int len) { - fwrite(data, 1, len, (FILE *)stream); -} - -//------------------------------------------------------------------------ -// XOutputFont -//------------------------------------------------------------------------ - -XOutputFont::XOutputFont(Ref *idA, double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA, - double m11A, double m12A, double m21A, double m22A, - Display *displayA, XOutputDev *xOutA) { - id = *idA; - display = displayA; - xOut = xOutA; - m11Orig = m11OrigA; - m12Orig = m12OrigA; - m21Orig = m21OrigA; - m22Orig = m22OrigA; - m11 = m11A; - m12 = m12A; - m21 = m21A; - m22 = m22A; -} - -XOutputFont::~XOutputFont() { -} - -void XOutputFont::getCharPath(GfxState *state, - CharCode c, Unicode *u, int ulen) { -} - -#if HAVE_T1LIB_H -//------------------------------------------------------------------------ -// XOutputT1Font -//------------------------------------------------------------------------ - -XOutputT1Font::XOutputT1Font(Ref *idA, T1FontFile *fontFileA, - double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA, - double m11A, double m12A, - double m21A, double m22A, - Display *displayA, XOutputDev *xOutA): - XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA, - m11A, m12A, m21A, m22A, displayA, xOutA) -{ - double matrix[4]; - - fontFile = fontFileA; - - // create the transformed instance - matrix[0] = m11; - matrix[1] = -m12; - matrix[2] = m21; - matrix[3] = -m22; - font = new T1Font(fontFile, matrix); -} - -XOutputT1Font::~XOutputT1Font() { - if (font) { - delete font; - } -} - -GBool XOutputT1Font::isOk() { - return font != NULL; -} - -void XOutputT1Font::updateGC(GC gc) { -} - -void XOutputT1Font::drawChar(GfxState *state, Pixmap pixmap, int w, int h, - GC gc, GfxRGB *rgb, - double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen) { - font->drawChar(pixmap, w, h, gc, xoutRound(x), xoutRound(y), - (int)(rgb->r * 65535), (int)(rgb->g * 65535), - (int)(rgb->b * 65535), c, u[0]); -} - -void XOutputT1Font::getCharPath(GfxState *state, - CharCode c, Unicode *u, int uLen) { - font->getCharPath(c, u[0], state); -} -#endif // HAVE_T1LIB_H - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -//------------------------------------------------------------------------ -// XOutputFTFont -//------------------------------------------------------------------------ - -XOutputFTFont::XOutputFTFont(Ref *idA, FTFontFile *fontFileA, - double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA, - double m11A, double m12A, - double m21A, double m22A, - Display *displayA, XOutputDev *xOutA): - XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA, - m11A, m12A, m21A, m22A, displayA, xOutA) -{ - double matrix[4]; - - fontFile = fontFileA; - - // create the transformed instance - matrix[0] = m11; - matrix[1] = -m12; - matrix[2] = m21; - matrix[3] = -m22; - font = new FTFont(fontFile, matrix); -} - -XOutputFTFont::~XOutputFTFont() { - if (font) { - delete font; - } -} - -GBool XOutputFTFont::isOk() { - return font != NULL; -} - -void XOutputFTFont::updateGC(GC gc) { -} - -void XOutputFTFont::drawChar(GfxState *state, Pixmap pixmap, int w, int h, - GC gc, GfxRGB *rgb, - double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen) { - font->drawChar(pixmap, w, h, gc, xoutRound(x), xoutRound(y), - (int)(rgb->r * 65535), (int)(rgb->g * 65535), - (int)(rgb->b * 65535), c, uLen > 0 ? u[0] : 0); -} - -void XOutputFTFont::getCharPath(GfxState *state, - CharCode c, Unicode *u, int uLen) { - font->getCharPath(c, u[0], state); -} -#endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -//------------------------------------------------------------------------ -// XOutputTTFont -//------------------------------------------------------------------------ - -XOutputTTFont::XOutputTTFont(Ref *idA, TTFontFile *fontFileA, - double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA, - double m11A, double m12A, - double m21A, double m22A, - Display *displayA, XOutputDev *xOutA): - XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA, - m11A, m12A, m21A, m22A, displayA, xOutA) -{ - double matrix[4]; - - fontFile = fontFileA; - - // create the transformed instance - matrix[0] = m11; - matrix[1] = -m12; - matrix[2] = m21; - matrix[3] = -m22; - font = new TTFont(fontFile, matrix); -} - -XOutputTTFont::~XOutputTTFont() { - if (font) { - delete font; - } -} - -GBool XOutputTTFont::isOk() { - return font != NULL; -} - -void XOutputTTFont::updateGC(GC gc) { -} - -void XOutputTTFont::drawChar(GfxState *state, Pixmap pixmap, int w, int h, - GC gc, GfxRGB *rgb, - double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen) { - font->drawChar(pixmap, w, h, gc, xoutRound(x), xoutRound(y), - (int)(rgb->r * 65535), (int)(rgb->g * 65535), - (int)(rgb->b * 65535), c, u[0]); -} -#endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -//------------------------------------------------------------------------ -// XOutputServer8BitFont -//------------------------------------------------------------------------ - -// Copy , substituting for one occurrence of "%s", into -// . -static void stringSubst(char *buf, int bufSize, char *fmt, char *val) { - char *p, *q; - int i; - - i = 0; - p = fmt; - while (*p) { - if (p[0] == '%' && p[1] == 's') { - q = val; - while (*q && i < bufSize - 1) { - buf[i++] = *q++; - } - p += 2; - } else { - if (i < bufSize - 1) { - buf[i++] = *p; - } - ++p; - } - } - buf[i] = '\0'; -} - -XOutputServer8BitFont::XOutputServer8BitFont(Ref *idA, GString *xlfdFmt, - UnicodeMap *xUMapA, - CharCodeToUnicode *fontUMap, - double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA, - double m11A, double m12A, - double m21A, double m22A, - Display *displayA, - XOutputDev *xOutA): - XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA, - m11A, m12A, m21A, m22A, displayA, xOutA) -{ - double size, ntm11, ntm12, ntm21, ntm22; - GBool rotated; - int startSize, sz; - char fontName[500], fontSize[100]; - Unicode u; - char buf; - int i; - - // compute size and normalized transform matrix - size = sqrt(m21*m21 + m22*m22); - ntm11 = m11 / size; - ntm12 = -m12 / size; - ntm21 = m21 / size; - ntm22 = -m22 / size; - - // try to get a rotated font? - rotated = !(ntm11 > 0 && ntm22 > 0 && - fabs(ntm11 / ntm22 - 1) < 0.2 && - fabs(ntm12) < 0.01 && - fabs(ntm21) < 0.01); - - // open X font -- if font is not found (which means the server can't - // scale fonts), try progressively smaller and then larger sizes - startSize = (int)size; - if (rotated) { - sprintf(fontSize, "[%s%0.2f %s%0.2f %s%0.2f %s%0.2f]", - ntm11<0 ? "~" : "", fabs(ntm11 * size), - ntm12<0 ? "~" : "", fabs(ntm12 * size), - ntm21<0 ? "~" : "", fabs(ntm21 * size), - ntm22<0 ? "~" : "", fabs(ntm22 * size)); - } else { - sprintf(fontSize, "%d", startSize); - } - stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize); - xFont = XLoadQueryFont(display, fontName); - if (!xFont) { - for (sz = startSize; sz >= startSize/2 && sz >= 1; --sz) { - sprintf(fontSize, "%d", sz); - stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize); - if ((xFont = XLoadQueryFont(display, fontName))) - break; - } - if (!xFont) { - for (sz = startSize + 1; sz < startSize + 10; ++sz) { - sprintf(fontSize, "%d", sz); - stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), - fontSize); - if ((xFont = XLoadQueryFont(display, fontName))) { - break; - } - } - if (!xFont) { - sprintf(fontSize, "%d", startSize); - stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), - fontSize); - error(-1, "Failed to open font: '%s'", fontName); - return; - } - } - } - - // Construct char code map. - xUMap = xUMapA; - for (i = 0; i < 256; ++i) { - if (fontUMap->mapToUnicode((CID)i, &u, 1) == 1 && - xUMap->mapUnicode(u, &buf, 1) == 1) { - map[i] = buf & 0xff; - } else { - map[i] = 0; - } - } -} - -XOutputServer8BitFont::~XOutputServer8BitFont() { - if (xFont) { - XFreeFont(display, xFont); - } -} - -GBool XOutputServer8BitFont::isOk() { - return xFont != NULL; -} - -void XOutputServer8BitFont::updateGC(GC gc) { - XSetFont(display, gc, xFont->fid); -} - -void XOutputServer8BitFont::drawChar(GfxState *state, Pixmap pixmap, - int w, int h, GC gc, GfxRGB *rgb, - double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen) { - Gushort c1; - char buf[8]; - double dx1, dy1; - int m, n, i, j, k; - - c1 = map[c]; - if (c1 > 0) { - buf[0] = (char)c1; - XDrawString(display, pixmap, gc, xoutRound(x), xoutRound(y), buf, 1); - } else { - // substituted character, using more than one character - n = 0; - for (i = 0; i < uLen; ++i) { - n += xUMap->mapUnicode(u[i], buf, sizeof(buf)); - } - if (n > 0) { - dx1 = dx / n; - dy1 = dy / n; - k = 0; - for (i = 0; i < uLen; ++i) { - m = xUMap->mapUnicode(u[i], buf, sizeof(buf)); - for (j = 0; j < m; ++j) { - XDrawString(display, pixmap, gc, - xoutRound(x + k*dx1), xoutRound(y + k*dy1), - buf + j, 1); - ++k; - } - } - } - } -} - -//------------------------------------------------------------------------ -// XOutputServer16BitFont -//------------------------------------------------------------------------ - -XOutputServer16BitFont::XOutputServer16BitFont(Ref *idA, GString *xlfdFmt, - UnicodeMap *xUMapA, - CharCodeToUnicode *fontUMap, - double m11OrigA, - double m12OrigA, - double m21OrigA, - double m22OrigA, - double m11A, double m12A, - double m21A, double m22A, - Display *displayA, - XOutputDev *xOutA): - XOutputFont(idA, m11OrigA, m12OrigA, m21OrigA, m22OrigA, - m11A, m12A, m21A, m22A, displayA, xOutA) -{ - double size, ntm11, ntm12, ntm21, ntm22; - GBool rotated; - int startSize, sz; - char fontName[500], fontSize[100]; - - xUMap = xUMapA; - xUMap->incRefCnt(); - - // compute size and normalized transform matrix - size = sqrt(m21*m21 + m22*m22); - ntm11 = m11 / size; - ntm12 = -m12 / size; - ntm21 = m21 / size; - ntm22 = -m22 / size; - - // try to get a rotated font? - rotated = !(ntm11 > 0 && ntm22 > 0 && - fabs(ntm11 / ntm22 - 1) < 0.2 && - fabs(ntm12) < 0.01 && - fabs(ntm21) < 0.01); - - // open X font -- if font is not found (which means the server can't - // scale fonts), try progressively smaller and then larger sizes - startSize = (int)size; - if (rotated) { - sprintf(fontSize, "[%s%0.2f %s%0.2f %s%0.2f %s%0.2f]", - ntm11<0 ? "~" : "", fabs(ntm11 * size), - ntm12<0 ? "~" : "", fabs(ntm12 * size), - ntm21<0 ? "~" : "", fabs(ntm21 * size), - ntm22<0 ? "~" : "", fabs(ntm22 * size)); - } else { - sprintf(fontSize, "%d", startSize); - } - stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize); - xFont = XLoadQueryFont(display, fontName); - if (!xFont) { - for (sz = startSize; sz >= startSize/2 && sz >= 1; --sz) { - sprintf(fontSize, "%d", sz); - stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), fontSize); - if ((xFont = XLoadQueryFont(display, fontName))) - break; - } - if (!xFont) { - for (sz = startSize + 1; sz < startSize + 10; ++sz) { - sprintf(fontSize, "%d", sz); - stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), - fontSize); - if ((xFont = XLoadQueryFont(display, fontName))) { - break; - } - } - if (!xFont) { - sprintf(fontSize, "%d", startSize); - stringSubst(fontName, sizeof(fontName), xlfdFmt->getCString(), - fontSize); - error(-1, "Failed to open font: '%s'", fontName); - return; - } - } - } -} - -XOutputServer16BitFont::~XOutputServer16BitFont() { - xUMap->decRefCnt(); - if (xFont) { - XFreeFont(display, xFont); - } -} - -GBool XOutputServer16BitFont::isOk() { - return xFont != NULL; -} - -void XOutputServer16BitFont::updateGC(GC gc) { - XSetFont(display, gc, xFont->fid); -} - -void XOutputServer16BitFont::drawChar(GfxState *state, Pixmap pixmap, - int w, int h, GC gc, GfxRGB *rgb, - double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen) { - char buf[16]; - XChar2b c1; - double dx1, dy1; - int m, n, i, j, k; - - n = 0; - for (i = 0; i < uLen; ++i) { - n += xUMap->mapUnicode(u[i], buf, sizeof(buf)); - } - if (n > 0) { - dx1 = dx / n; - dy1 = dy / n; - k = 0; - for (i = 0; i < uLen; ++i) { - m = xUMap->mapUnicode(u[i], buf, sizeof(buf)); - for (j = 0; j+1 < m; j += 2) { - c1.byte1 = buf[j]; - c1.byte2 = buf[j+1]; - XDrawString16(display, pixmap, gc, - xoutRound(x + k*dx1), xoutRound(y + k*dy1), - &c1, 1); - ++k; - } - } - } else if (c != 0) { - // some PDF files use CID 0, which is .notdef, so just ignore it - error(-1, "Unknown character (CID=%d Unicode=%04x)", - c, uLen > 0 ? u[0] : (Unicode)0); - } -} - -//------------------------------------------------------------------------ -// XOutputFontCache -//------------------------------------------------------------------------ - -#if HAVE_T1LIB_H -XOutputT1FontFile::~XOutputT1FontFile() { - delete fontFile; - if (tmpFileName) { - unlink(tmpFileName->getCString()); - delete tmpFileName; - } -} -#endif - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -XOutputFTFontFile::~XOutputFTFontFile() { - delete fontFile; - if (tmpFileName) { - unlink(tmpFileName->getCString()); - delete tmpFileName; - } -} -#endif - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -XOutputTTFontFile::~XOutputTTFontFile() { - delete fontFile; - if (tmpFileName) { - unlink(tmpFileName->getCString()); - delete tmpFileName; - } -} -#endif - -XOutputFontCache::XOutputFontCache(Display *displayA, Guint depthA, - XOutputDev *xOutA, - FontRastControl t1libControlA, - FontRastControl freetypeControlA) { - display = displayA; - depth = depthA; - xOut = xOutA; - -#if HAVE_T1LIB_H - t1libControl = t1libControlA; - t1Engine = NULL; - t1FontFiles = NULL; -#endif - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - freetypeControl = freetypeControlA; - ftEngine = NULL; - ftFontFiles = NULL; -#endif -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - freetypeControl = freetypeControlA; - ttEngine = NULL; - ttFontFiles = NULL; -#endif - - clear(); -} - -XOutputFontCache::~XOutputFontCache() { - delFonts(); -} - -void XOutputFontCache::startDoc(int screenNum, Visual *visual, - Colormap colormap, GBool trueColor, - int rMul, int gMul, int bMul, - int rShift, int gShift, int bShift, - Gulong *colors, int numColors) { - delFonts(); - clear(); - -#if HAVE_T1LIB_H - if (t1libControl != fontRastNone) { - t1Engine = new T1FontEngine(display, visual, depth, colormap, - t1libControl == fontRastAALow || - t1libControl == fontRastAAHigh, - t1libControl == fontRastAAHigh); - if (t1Engine->isOk()) { - if (trueColor) { - t1Engine->useTrueColor(rMul, rShift, gMul, gShift, bMul, bShift); - } else { - t1Engine->useColorCube(colors, numColors); - } - } else { - delete t1Engine; - t1Engine = NULL; - } - } -#endif // HAVE_T1LIB_H - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (freetypeControl != fontRastNone) { - ftEngine = new FTFontEngine(display, visual, depth, colormap, - freetypeControl == fontRastAALow || - freetypeControl == fontRastAAHigh); - if (ftEngine->isOk()) { - if (trueColor) { - ftEngine->useTrueColor(rMul, rShift, gMul, gShift, bMul, bShift); - } else { - ftEngine->useColorCube(colors, numColors); - } - } else { - delete ftEngine; - ftEngine = NULL; - } - } -#endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (freetypeControl != fontRastNone) { - ttEngine = new TTFontEngine(display, visual, depth, colormap, - freetypeControl == fontRastAALow || - freetypeControl == fontRastAAHigh); - if (ttEngine->isOk()) { - if (trueColor) { - ttEngine->useTrueColor(rMul, rShift, gMul, gShift, bMul, bShift); - } else { - ttEngine->useColorCube(colors, numColors); - } - } else { - delete ttEngine; - ttEngine = NULL; - } - } -#endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -} - -void XOutputFontCache::delFonts() { - int i; - - for (i = 0; i < nFonts; ++i) { - delete fonts[i]; - } - -#if HAVE_T1LIB_H - // delete Type 1 font files - if (t1FontFiles) { - deleteGList(t1FontFiles, XOutputT1FontFile); - t1FontFiles = NULL; - } - if (t1Engine) { - delete t1Engine; - t1Engine = NULL; - } -#endif - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - // delete FreeType font files - if (ftFontFiles) { - deleteGList(ftFontFiles, XOutputFTFontFile); - ftFontFiles = NULL; - } - if (ftEngine) { - delete ftEngine; - ftEngine = NULL; - } -#endif - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - // delete TrueType fonts - if (ttFontFiles) { - deleteGList(ttFontFiles, XOutputTTFontFile); - ttFontFiles = NULL; - } - if (ttEngine) { - delete ttEngine; - ttEngine = NULL; - } -#endif -} - -void XOutputFontCache::clear() { - int i; - - for (i = 0; i < xOutFontCacheSize; ++i) { - fonts[i] = NULL; - } - nFonts = 0; - -#if HAVE_T1LIB_H - // clear Type 1 font files - t1FontFiles = new GList(); -#endif - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - // clear FreeType font cache - ftFontFiles = new GList(); -#endif - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - // clear TrueType font cache - ttFontFiles = new GList(); -#endif -} - -XOutputFont *XOutputFontCache::getFont(XRef *xref, GfxFont *gfxFont, - double m11, double m12, - double m21, double m22) { - XOutputFont *font; - DisplayFontParam *dfp; - GString *substName; - double m11New, m12New, m21New, m22New; - double w1, w2, v; - double *fm; - char *name; - int index; - int code; - int i, j; - - // is it the most recently used font? - if (nFonts > 0 && fonts[0]->matches(gfxFont->getID(), m11, m12, m21, m22)) { - return fonts[0]; - } - - // is it in the cache? - for (i = 1; i < nFonts; ++i) { - if (fonts[i]->matches(gfxFont->getID(), m11, m12, m21, m22)) { - font = fonts[i]; - for (j = i; j > 0; --j) { - fonts[j] = fonts[j-1]; - } - fonts[0] = font; - return font; - } - } - - // try for a cached FontFile, an embedded font, or an external font - // file - font = NULL; - switch (gfxFont->getType()) { - case fontType1: - case fontType1C: -#if HAVE_T1LIB_H - if (t1libControl != fontRastNone) { - font = tryGetT1Font(xref, gfxFont, m11, m12, m21, m22); - } -#endif -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (!font) { - if (freetypeControl != fontRastNone) { - font = tryGetFTFont(xref, gfxFont, m11, m12, m21, m22); - } - } -#endif - break; - case fontTrueType: - case fontCIDType2: -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (freetypeControl != fontRastNone) { - font = tryGetFTFont(xref, gfxFont, m11, m12, m21, m22); - } -#endif -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (freetypeControl != fontRastNone) { - font = tryGetTTFont(xref, gfxFont, m11, m12, m21, m22); - } -#endif - break; - case fontCIDType0: - case fontCIDType0C: -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (freetypeControl != fontRastNone) { - font = tryGetFTFont(xref, gfxFont, m11, m12, m21, m22); - } -#endif - break; - default: - break; - } - - if (!font) { - - // search for a display font mapping - dfp = NULL; - if (gfxFont->isCIDFont()) { - if (((GfxCIDFont *)gfxFont)->getCollection()) { - dfp = globalParams-> - getDisplayCIDFont(gfxFont->getName(), - ((GfxCIDFont *)gfxFont)->getCollection()); - } else { - // this error (no CMap file) was already reported by GfxFont - return NULL; - } - } else { - if (gfxFont->getName()) { - dfp = globalParams->getDisplayFont(gfxFont->getName()); - } - } - if (dfp) { - font = tryGetFont(xref, dfp, gfxFont, m11, m12, m21, m22, - m11, m12, m21, m22, gFalse); - } - - // substitute a font (8-bit fonts only) - if (!font && !gfxFont->isCIDFont()) { - - // choose a substitute font - if (gfxFont->isFixedWidth()) { - index = 8; - } else if (gfxFont->isSerif()) { - index = 4; - } else { - index = 0; - } - if (gfxFont->isBold()) { - index += 2; - } - if (gfxFont->isItalic()) { - index += 1; - } - substName = new GString(xOutSubstFonts[index].name); - - // adjust the font matrix -- compare the width of 'm' in the - // original font and the substituted font - m11New = m11; - m12New = m12; - m21New = m21; - m22New = m22; - for (code = 0; code < 256; ++code) { - if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) && - name[0] == 'm' && name[1] == '\0') { - break; - } - } - if (code < 256) { - w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code); - w2 = xOutSubstFonts[index].mWidth; - if (gfxFont->getType() == fontType3) { - // This is a hack which makes it possible to substitute for some - // Type 3 fonts. The problem is that it's impossible to know what - // the base coordinate system used in the font is without actually - // rendering the font. This code tries to guess by looking at the - // width of the character 'm' (which breaks if the font is a - // subset that doesn't contain 'm'). - if (w1 > 0 && (w1 > 1.1 * w2 || w1 < 0.9 * w2)) { - w1 /= w2; - m11New *= w1; - m12New *= w1; - m21New *= w1; - m22New *= w1; - } - fm = gfxFont->getFontMatrix(); - v = (fm[0] == 0) ? 1 : (fm[3] / fm[0]); - m21New *= v; - m22New *= v; - } else if (!gfxFont->isSymbolic()) { - // if real font is substantially narrower than substituted - // font, reduce the font size accordingly - if (w1 > 0.01 && w1 < 0.9 * w2) { - w1 /= w2; - m11New *= w1; - m21New *= w1; - } - } - } - - // get the font - dfp = globalParams->getDisplayFont(substName); - delete substName; - if (!dfp) { - // this should never happen since GlobalParams sets up default - // mappings for the Base-14 fonts - error(-1, "Couldn't find a font for '%s'", - gfxFont->getName()->getCString()); - return NULL; - } - font = tryGetFont(xref, dfp, gfxFont, m11, m12, m21, m22, - m11New, m12New, m21New, m22New, gTrue); - } - } - - // check for error - if (!font) { - // This will happen if the user specifies a bogus font in the - // config file (a non-existent font file or a font that requires a - // rasterizer that is disabled or wasn't built in), or if a CID - // font has no associated font in the config file. - if (gfxFont->isCIDFont()) { - error(-1, "Couldn't find a font for the '%s' character collection", - ((GfxCIDFont *)gfxFont)->getCollection()->getCString()); - } else { - error(-1, "Couldn't find a font for '%s'", - gfxFont->getName() ? - gfxFont->getName()->getCString() : "[unnamed]"); - } - return NULL; - } - - // insert font in cache - if (nFonts == xOutFontCacheSize) { - --nFonts; - delete fonts[nFonts]; - } - for (j = nFonts; j > 0; --j) { - fonts[j] = fonts[j-1]; - } - fonts[0] = font; - ++nFonts; - - return font; -} - -XOutputFont *XOutputFontCache::tryGetFont(XRef *xref, DisplayFontParam *dfp, - GfxFont *gfxFont, - double m11Orig, double m12Orig, - double m21Orig, double m22Orig, - double m11, double m12, - double m21, double m22, - GBool subst) { - XOutputFont *font; - - font = NULL; - - // create the new font - switch (dfp->kind) { - - case displayFontX: - font = tryGetServerFont(dfp->x.xlfd, dfp->x.encoding, gfxFont, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22); - break; - - case displayFontT1: -#if HAVE_T1LIB_H - if (t1libControl != fontRastNone && !gfxFont->isCIDFont()) { - font = tryGetT1FontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, subst); - } -#endif -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (!font) { - if (freetypeControl != fontRastNone) { - font = tryGetFTFontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, gFalse, subst); - } - } -#endif -#if !((FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)) || defined(HAVE_T1LIB_H)) - error(-1, "Config file specifies a Type 1 font,"); - error(-1, "but xpdf was not built with t1lib or FreeType2 support"); -#endif - break; - - case displayFontTT: -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (freetypeControl != fontRastNone) { - font = tryGetFTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, gFalse, subst); - } -#endif -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - if (freetypeControl != fontRastNone) { - font = tryGetTTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, subst); - } -#endif -#if !(HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - error(-1, "Config file specifies a TrueType font,"); - error(-1, "but xpdf was not built with FreeType support"); - dfp = NULL; -#endif - break; - } - - return font; -} - -#if HAVE_T1LIB_H -XOutputFont *XOutputFontCache::tryGetT1Font(XRef *xref, - GfxFont *gfxFont, - double m11, double m12, - double m21, double m22) { - Ref *id; - XOutputT1FontFile *xFontFile; - XOutputFont *font; - Ref embRef; - GString *fileName; - FILE *f; - char *fontBuf; - int fontLen; - Type1CFontFile *ff; - Object refObj, strObj; - int c; - int i; - - // check the already available font files - id = gfxFont->getID(); - for (i = 0; i < t1FontFiles->getLength(); ++i) { - xFontFile = (XOutputT1FontFile *)t1FontFiles->get(i); - if (xFontFile->num == id->num && xFontFile->gen == id->gen && - !xFontFile->subst) { - font = new XOutputT1Font(id, xFontFile->fontFile, - m11, m12, m21, m22, - m11, m12, m21, m22, display, xOut); - if (!font->isOk()) { - delete font; - return NULL; - } - return font; - } - } - - // check for an embedded font - if (gfxFont->getEmbeddedFontID(&embRef)) { - - // create the font file - fileName = NULL; - if (!openTempFile(&fileName, &f, "wb", NULL)) { - error(-1, "Couldn't create temporary Type 1 font file"); - return NULL; - } - if (gfxFont->getType() == fontType1C) { - if (!(fontBuf = gfxFont->readEmbFontFile(xref, &fontLen))) { - fclose(f); - unlink(fileName->getCString()); - delete fileName; - return NULL; - } - ff = new Type1CFontFile(fontBuf, fontLen); - if (!ff->isOk()) { - delete ff; - gfree(fontBuf); - unlink(fileName->getCString()); - delete fileName; - return NULL; - } - ff->convertToType1(outputToFile, f); - delete ff; - gfree(fontBuf); - } else { // fontType1 - refObj.initRef(embRef.num, embRef.gen); - refObj.fetch(xref, &strObj); - refObj.free(); - strObj.streamReset(); - while ((c = strObj.streamGetChar()) != EOF) { - fputc(c, f); - } - strObj.streamClose(); - strObj.free(); - } - fclose(f); - - // create the Font - font = tryGetT1FontFromFile(xref, fileName, gTrue, gfxFont, - m11, m12, m21, m22, - m11, m12, m21, m22, gFalse); - - // on systems with Unix hard link semantics, this will remove the - // last link to the temp file - unlink(fileName->getCString()); - - delete fileName; - - // check for an external font file - } else if ((fileName = gfxFont->getExtFontFile())) { - font = tryGetT1FontFromFile(xref, fileName, gFalse, gfxFont, - m11, m12, m21, m22, - m11, m12, m21, m22, gFalse); - - } else { - font = NULL; - } - - return font; -} - -XOutputFont *XOutputFontCache::tryGetT1FontFromFile(XRef *xref, - GString *fileName, - GBool deleteFile, - GfxFont *gfxFont, - double m11Orig, - double m12Orig, - double m21Orig, - double m22Orig, - double m11, double m12, - double m21, double m22, - GBool subst) { - Ref *id; - T1FontFile *fontFile; - XOutputFont *font; - - // create the t1lib font file - fontFile = new T1FontFile(t1Engine, fileName->getCString(), - ((Gfx8BitFont *)gfxFont)->getEncoding(), - gfxFont->getFontBBox()); - if (!fontFile->isOk()) { - error(-1, "Couldn't create t1lib font from '%s'", - fileName->getCString()); - delete fontFile; - if (deleteFile) { - unlink(fileName->getCString()); - } - return NULL; - } - - // add to list - id = gfxFont->getID(); - t1FontFiles->append(new XOutputT1FontFile(id->num, id->gen, - subst, fontFile, - deleteFile ? fileName->copy() - : (GString *)NULL)); - - // create the Font - font = new XOutputT1Font(gfxFont->getID(), fontFile, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, display, xOut); - if (!font->isOk()) { - delete font; - return NULL; - } - return font; -} -#endif // HAVE_T1LIB_H - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -XOutputFont *XOutputFontCache::tryGetFTFont(XRef *xref, - GfxFont *gfxFont, - double m11, double m12, - double m21, double m22) { - Ref *id; - XOutputFTFontFile *xFontFile; - XOutputFont *font; - Ref embRef; - GString *fileName; - FILE *f; -#if 1 //~ need this until FT can handle fonts with missing tables - char *fontBuf; - int fontLen; - TrueTypeFontFile *ff; -#endif - Object refObj, strObj; - int c; - int i; - - // check the already available font files - id = gfxFont->getID(); - for (i = 0; i < ftFontFiles->getLength(); ++i) { - xFontFile = (XOutputFTFontFile *)ftFontFiles->get(i); - if (xFontFile->num == id->num && xFontFile->gen == id->gen && - !xFontFile->subst) { - font = new XOutputFTFont(id, xFontFile->fontFile, - m11, m12, m21, m22, - m11, m12, m21, m22, display, xOut); - if (!font->isOk()) { - delete font; - return NULL; - } - return font; - } - } - - // check for an embedded font - if (gfxFont->getEmbeddedFontID(&embRef)) { - - // create the font file - fileName = NULL; - if (!openTempFile(&fileName, &f, "wb", NULL)) { - error(-1, "Couldn't create temporary TrueType font file"); - return NULL; - } -#if 1 //~ need this until FT can handle fonts with missing tables - if (gfxFont->getType() == fontTrueType || - gfxFont->getType() == fontCIDType2) { - if (!(fontBuf = gfxFont->readEmbFontFile(xref, &fontLen))) { - fclose(f); - unlink(fileName->getCString()); - delete fileName; - return NULL; - } - ff = new TrueTypeFontFile(fontBuf, fontLen); - ff->writeTTF(f); - delete ff; - gfree(fontBuf); - } else { - refObj.initRef(embRef.num, embRef.gen); - refObj.fetch(xref, &strObj); - refObj.free(); - strObj.streamReset(); - while ((c = strObj.streamGetChar()) != EOF) { - fputc(c, f); - } - strObj.streamClose(); - strObj.free(); - } -#else - refObj.initRef(embRef.num, embRef.gen); - refObj.fetch(xref, &strObj); - refObj.free(); - strObj.streamReset(); - while ((c = strObj.streamGetChar()) != EOF) { - fputc(c, f); - } - strObj.streamClose(); - strObj.free(); -#endif - fclose(f); - - // create the Font - font = tryGetFTFontFromFile(xref, fileName, gTrue, gfxFont, - m11, m12, m21, m22, - m11, m12, m21, m22, gTrue, gFalse); - - // on systems with Unix hard link semantics, this will remove the - // last link to the temp file - unlink(fileName->getCString()); - - delete fileName; - - // check for an external font file - } else if ((fileName = gfxFont->getExtFontFile())) { - font = tryGetFTFontFromFile(xref, fileName, gFalse, gfxFont, - m11, m12, m21, m22, - m11, m12, m21, m22, gFalse, gFalse); - - } else { - font = NULL; - } - - return font; -} - -XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref, - GString *fileName, - GBool deleteFile, - GfxFont *gfxFont, - double m11Orig, - double m12Orig, - double m21Orig, - double m22Orig, - double m11, double m12, - double m21, double m22, - GBool embedded, - GBool subst) { - Ref *id; - FTFontFile *fontFile; - XOutputFont *font; - char *buf; - int len; - FILE *f; - TrueTypeFontFile *ff; - Gushort *codeToGID; - - // create the FreeType font file - if (gfxFont->isCIDFont()) { - if (gfxFont->getType() == fontCIDType2) { - fontFile = new FTFontFile(ftEngine, fileName->getCString(), - ((GfxCIDFont *)gfxFont)->getCIDToGID(), - ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(), - embedded); - } else { // fontCIDType0, fontCIDType0C - fontFile = new FTFontFile(ftEngine, fileName->getCString(), embedded); - } - } else { - if (!(f = fopen(fileName->getCString(), "rb"))) { - return NULL; - } - fseek(f, 0, SEEK_END); - len = (int)ftell(f); - fseek(f, 0, SEEK_SET); - buf = (char *)gmalloc(len); - if ((int)fread(buf, 1, len, f) != len) { - gfree(buf); - fclose(f); - return NULL; - } - fclose(f); - ff = new TrueTypeFontFile(buf, len); - codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff); - fontFile = new FTFontFile(ftEngine, fileName->getCString(), - ((Gfx8BitFont *)gfxFont)->getEncoding(), - codeToGID); - gfree(codeToGID); - delete ff; - gfree(buf); - } - if (!fontFile->isOk()) { - error(-1, "Couldn't create FreeType font from '%s'", - fileName->getCString()); - delete fontFile; - if (deleteFile) { - unlink(fileName->getCString()); - } - return NULL; - } - - // add to list - id = gfxFont->getID(); - ftFontFiles->append(new XOutputFTFontFile(id->num, id->gen, - subst, fontFile, - deleteFile ? fileName->copy() - : (GString *)NULL)); - - // create the Font - font = new XOutputFTFont(gfxFont->getID(), fontFile, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, display, xOut); - if (!font->isOk()) { - delete font; - return NULL; - } - return font; -} -#endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -XOutputFont *XOutputFontCache::tryGetTTFont(XRef *xref, - GfxFont *gfxFont, - double m11, double m12, - double m21, double m22) { - Ref *id; - XOutputTTFontFile *xFontFile; - XOutputFont *font; - Ref embRef; - GString *fileName; - FILE *f; - Object refObj, strObj; - int c; - int i; - - // check the already available font files - id = gfxFont->getID(); - xFontFile = NULL; - for (i = 0; i < ttFontFiles->getLength(); ++i) { - xFontFile = (XOutputTTFontFile *)ttFontFiles->get(i); - if (xFontFile->num == id->num && xFontFile->gen == id->gen && - !xFontFile->subst) { - font = new XOutputTTFont(id, xFontFile->fontFile, - m11, m12, m21, m22, - m11, m12, m21, m22, display, xOut); - if (!font->isOk()) { - delete font; - return NULL; - } - return font; - } - } - - // check for an embedded font - if (gfxFont->getEmbeddedFontID(&embRef)) { - - // create the font file - fileName = NULL; - if (!openTempFile(&fileName, &f, "wb", NULL)) { - error(-1, "Couldn't create temporary TrueType font file"); - return NULL; - } - refObj.initRef(embRef.num, embRef.gen); - refObj.fetch(xref, &strObj); - refObj.free(); - strObj.streamReset(); - while ((c = strObj.streamGetChar()) != EOF) { - fputc(c, f); - } - strObj.streamClose(); - strObj.free(); - fclose(f); - - // create the Font - font = tryGetTTFontFromFile(xref, fileName, gTrue, gfxFont, - m11, m12, m21, m22, - m11, m12, m21, m22, gFalse); - - // on systems with Unix hard link semantics, this will remove the - // last link to the temp file - unlink(fileName->getCString()); - - delete fileName; - - } else if ((fileName = gfxFont->getExtFontFile())) { - font = tryGetTTFontFromFile(xref, fileName, gFalse, gfxFont, - m11, m12, m21, m22, - m11, m12, m21, m22, gFalse); - - } else { - font = NULL; - } - - return font; -} - -XOutputFont *XOutputFontCache::tryGetTTFontFromFile(XRef *xref, - GString *fileName, - GBool deleteFile, - GfxFont *gfxFont, - double m11Orig, - double m12Orig, - double m21Orig, - double m22Orig, - double m11, double m12, - double m21, double m22, - GBool subst) { - Ref *id; - TTFontFile *fontFile; - XOutputFont *font; - - // create the FreeType font file - if (gfxFont->isCIDFont()) { - // fontCIDType2 - fontFile = new TTFontFile(ttEngine, fileName->getCString(), - ((GfxCIDFont *)gfxFont)->getCIDToGID(), - ((GfxCIDFont *)gfxFont)->getCIDToGIDLen()); - } else { - fontFile = new TTFontFile(ttEngine, fileName->getCString(), - ((Gfx8BitFont *)gfxFont)->getEncoding(), - ((Gfx8BitFont *)gfxFont)->getHasEncoding()); - } - if (!fontFile->isOk()) { - error(-1, "Couldn't create FreeType font from '%s'", - fileName->getCString()); - delete fontFile; - if (deleteFile) { - unlink(fileName->getCString()); - } - return NULL; - } - - // add to list - id = gfxFont->getID(); - ttFontFiles->append(new XOutputTTFontFile(id->num, id->gen, - subst, fontFile, - deleteFile ? fileName->copy() - : (GString *)NULL)); - - // create the Font - font = new XOutputTTFont(gfxFont->getID(), fontFile, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, display, xOut); - if (!font->isOk()) { - delete font; - return NULL; - } - return font; -} -#endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -XOutputFont *XOutputFontCache::tryGetServerFont(GString *xlfd, - GString *encodingName, - GfxFont *gfxFont, - double m11Orig, double m12Orig, - double m21Orig, double m22Orig, - double m11, double m12, - double m21, double m22) { - XOutputFont *font; - UnicodeMap *uMap; - CharCodeToUnicode *ctu; - - uMap = globalParams->getUnicodeMap(encodingName); - if (gfxFont->isCIDFont()) { - ctu = ((GfxCIDFont *)gfxFont)->getToUnicode(); - font = new XOutputServer16BitFont(gfxFont->getID(), xlfd, uMap, ctu, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, - display, xOut); - ctu->decRefCnt(); - } else { - ctu = ((Gfx8BitFont *)gfxFont)->getToUnicode(); - font = new XOutputServer8BitFont(gfxFont->getID(), xlfd, uMap, ctu, - m11Orig, m12Orig, m21Orig, m22Orig, - m11, m12, m21, m22, - display, xOut); - ctu->decRefCnt(); - } - uMap->decRefCnt(); - if (!font->isOk()) { - delete font; - return NULL; - } - return font; -} - -//------------------------------------------------------------------------ -// T3FontCache -//------------------------------------------------------------------------ - -struct T3FontCacheTag { - Gushort code; - Gushort mru; // valid bit (0x8000) and MRU index - double wx, wy; // untransformed glyph metrics -}; - -class T3FontCache { -public: - - T3FontCache(Ref *fontID, double m11A, double m12A, - double m21A, double m22A, - int glyphXA, int glyphYA, int glyphWA, int glyphHA, - Display *displayA, Visual *visual, Guint depth, - Pixmap origPixmap); - ~T3FontCache(); - GBool matches(Ref *idA, double m11A, double m12A, - double m21A, double m22A) - { return fontID.num == idA->num && fontID.gen == idA->gen && - m11 == m11A && m12 == m12A && m21 == m21A && m22 == m22A; } - - Ref fontID; // PDF font ID - double m11, m12, m21, m22; // transform matrix - int glyphX, glyphY; // pixel offset of glyph pixmaps - int glyphW, glyphH; // size of glyph pixmaps, in pixels - int glyphSize; // size of glyph pixmaps, in bytes - int cacheSets; // number of sets in cache - int cacheAssoc; // cache associativity (glyphs per set) - Guchar *cacheData; // glyph pixmap cache - T3FontCacheTag *cacheTags; // cache tags, i.e., char codes - Display *display; - Pixmap pixmap; - XImage *image; -}; - -T3FontCache::T3FontCache(Ref *fontIDA, double m11A, double m12A, - double m21A, double m22A, - int glyphXA, int glyphYA, int glyphWA, int glyphHA, - Display *displayA, Visual *visual, Guint depth, - Pixmap origPixmap) { - int i; - - fontID = *fontIDA; - m11 = m11A; - m12 = m12A; - m21 = m21A; - m22 = m22A; - glyphX = glyphXA; - glyphY = glyphYA; - glyphW = glyphWA; - glyphH = glyphHA; - glyphSize = glyphW * glyphH; - cacheAssoc = 8; - if (glyphSize <= 256) { - cacheSets = 8; - } else if (glyphSize <= 512) { - cacheSets = 4; - } else if (glyphSize <= 1024) { - cacheSets = 2; - } else { - cacheSets = 1; - } - cacheData = (Guchar *)gmalloc(cacheSets * cacheAssoc * glyphSize); - cacheTags = (T3FontCacheTag *)gmalloc(cacheSets * cacheAssoc * - sizeof(T3FontCacheTag)); - for (i = 0; i < cacheSets * cacheAssoc; ++i) { - cacheTags[i].mru = i & (cacheAssoc - 1); - } - display = displayA; - pixmap = XCreatePixmap(display, origPixmap, glyphW, glyphH, depth); - image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, - glyphW, glyphH, 8, 0); - image->data = (char *)gmalloc(glyphH * image->bytes_per_line); -} - -T3FontCache::~T3FontCache() { - gfree(cacheData); - gfree(cacheTags); - XFreePixmap(display, pixmap); - gfree(image->data); - image->data = NULL; - XDestroyImage(image); -} - -struct T3GlyphStack { - GBool cacheable; - Gushort code; - T3FontCache *cache; - int cacheIdx; - T3FontCacheTag *cacheTag; - Guchar *cacheData; - double x, y; - Unicode *u; - int uLen; - GfxRGB color; - int origPixmapW, origPixmapH; - Pixmap origPixmap; - GC origStrokeGC; - GC origFillGC; - Region origClipRegion; - double origCTM4, origCTM5; - double wx, wy; // untransformed glyph metrics - T3GlyphStack *next; -}; - -//------------------------------------------------------------------------ -// XOutputDev -//------------------------------------------------------------------------ - -XOutputDev::XOutputDev(Display *displayA, int screenNumA, - Visual *visualA, Colormap colormapA, - GBool reverseVideoA, unsigned long paperColorA, - GBool installCmap, int rgbCubeSize, - int forceDepth) { - XVisualInfo visualTempl; - XVisualInfo *visualList; - int nVisuals; - Gulong mask; - XColor xcolor; - XColor *xcolors; - int r, g, b, n, m; - GBool ok; - - // no document yet - xref = NULL; - - // display / screen / visual / colormap - display = displayA; - screenNum = screenNumA; - visual = visualA; - colormap = colormapA; - - // no pixmap yet - pixmapW = pixmapH = 0; - - // check for TrueColor visual - if (forceDepth != 0) { - depth = forceDepth; - trueColor = depth >= 16; - } else { - visualTempl.visualid = XVisualIDFromVisual(visual); - visualList = XGetVisualInfo(display, VisualIDMask, - &visualTempl, &nVisuals); - if (nVisuals < 1) { - // this shouldn't happen - XFree((XPointer)visualList); - visualList = XGetVisualInfo(display, VisualNoMask, &visualTempl, - &nVisuals); - } - depth = visualList->depth; - if (visualList->c_class == TrueColor) { - trueColor = gTrue; - for (mask = visualList->red_mask, rShift = 0; - mask && !(mask & 1); - mask >>= 1, ++rShift) ; - rMul = (int)mask; - for (mask = visualList->green_mask, gShift = 0; - mask && !(mask & 1); - mask >>= 1, ++gShift) ; - gMul = (int)mask; - for (mask = visualList->blue_mask, bShift = 0; - mask && !(mask & 1); - mask >>= 1, ++bShift) ; - bMul = (int)mask; - } else { - trueColor = gFalse; - } - XFree((XPointer)visualList); - } - - // allocate a color cube - if (!trueColor) { - redMap[BlackPixel(display, screenNum) & 0xff] = 0; - redMap[WhitePixel(display, screenNum) & 0xff] = 1; - - // set colors in private colormap - if (installCmap) { - for (numColors = 6; numColors >= 2; --numColors) { - m = numColors * numColors * numColors; - if (XAllocColorCells(display, colormap, False, NULL, 0, colors, m)) { - break; - } - } - if (numColors >= 2) { - m = numColors * numColors * numColors; - xcolors = (XColor *)gmalloc(m * sizeof(XColor)); - n = 0; - for (r = 0; r < numColors; ++r) { - for (g = 0; g < numColors; ++g) { - for (b = 0; b < numColors; ++b) { - xcolors[n].pixel = colors[n]; - xcolors[n].red = (r * 65535) / (numColors - 1); - xcolors[n].green = (g * 65535) / (numColors - 1); - xcolors[n].blue = (b * 65535) / (numColors - 1); - xcolors[n].flags = DoRed | DoGreen | DoBlue; - redMap[xcolors[n].pixel & 0xff] = xcolors[n].red / 65535.0; - ++n; - } - } - } - XStoreColors(display, colormap, xcolors, m); - gfree(xcolors); - } else { - numColors = 1; - colors[0] = BlackPixel(display, screenNum); - colors[1] = WhitePixel(display, screenNum); - } - - // allocate colors in shared colormap - } else { - if (rgbCubeSize > maxRGBCube) { - rgbCubeSize = maxRGBCube; - } - ok = gFalse; - for (numColors = rgbCubeSize; numColors >= 2; --numColors) { - ok = gTrue; - n = 0; - for (r = 0; r < numColors && ok; ++r) { - for (g = 0; g < numColors && ok; ++g) { - for (b = 0; b < numColors && ok; ++b) { - if (n == 0) { - colors[n] = BlackPixel(display, screenNum); - redMap[colors[n] & 0xff] = 0; - ++n; - } else { - xcolor.red = (r * 65535) / (numColors - 1); - xcolor.green = (g * 65535) / (numColors - 1); - xcolor.blue = (b * 65535) / (numColors - 1); - if (XAllocColor(display, colormap, &xcolor)) { - colors[n++] = xcolor.pixel; - redMap[xcolor.pixel & 0xff] = xcolor.red / 65535.0; - } else { - ok = gFalse; - } - } - } - } - } - if (ok) { - break; - } - XFreeColors(display, colormap, &colors[1], n-1, 0); - } - if (!ok) { - numColors = 1; - colors[0] = BlackPixel(display, screenNum); - colors[1] = WhitePixel(display, screenNum); - } - } - } - - // misc parameters - reverseVideo = reverseVideoA; - paperColor = paperColorA; - - // set up the font cache and fonts - gfxFont = NULL; - font = NULL; - needFontUpdate = gFalse; - fontCache = new XOutputFontCache(display, depth, this, - globalParams->getT1libControl(), - globalParams->getFreeTypeControl()); - nT3Fonts = 0; - t3GlyphStack = NULL; - - // no text outline clipping path - textClipPath = NULL; - - // empty state stack - save = NULL; - - // create text object - text = new TextPage(gFalse); -} - -XOutputDev::~XOutputDev() { - int i; - - delete fontCache; - for (i = 0; i < nT3Fonts; ++i) { - delete t3FontCache[i]; - } - delete text; -} - -void XOutputDev::startDoc(XRef *xrefA) { - int i; - - xref = xrefA; - fontCache->startDoc(screenNum, visual, colormap, trueColor, rMul, gMul, bMul, - rShift, gShift, bShift, colors, numColors); - for (i = 0; i < nT3Fonts; ++i) { - delete t3FontCache[i]; - } - nT3Fonts = 0; -} - -void XOutputDev::startPage(int pageNum, GfxState *state) { - XGCValues gcValues; - XRectangle rect; - - // default line flatness - flatness = 0; - - // allocate GCs - gcValues.foreground = BlackPixel(display, screenNum); - gcValues.background = WhitePixel(display, screenNum); - gcValues.line_width = 0; - gcValues.line_style = LineSolid; - strokeGC = XCreateGC(display, pixmap, - GCForeground | GCBackground | GCLineWidth | GCLineStyle, - &gcValues); - fillGC = XCreateGC(display, pixmap, - GCForeground | GCBackground | GCLineWidth | GCLineStyle, - &gcValues); - gcValues.foreground = paperColor; - paperGC = XCreateGC(display, pixmap, - GCForeground | GCBackground | GCLineWidth | GCLineStyle, - &gcValues); - - // initialize clip region - clipRegion = XCreateRegion(); - rect.x = rect.y = 0; - rect.width = pixmapW; - rect.height = pixmapH; - XUnionRectWithRegion(&rect, clipRegion, clipRegion); - XSetRegion(display, strokeGC, clipRegion); - XSetRegion(display, fillGC, clipRegion); - - // clear font - gfxFont = NULL; - font = NULL; - - // clear window - XFillRectangle(display, pixmap, paperGC, 0, 0, pixmapW, pixmapH); - - // clear text object - text->startPage(state); -} - -void XOutputDev::endPage() { - XOutputState *s; - - text->coalesce(gTrue); - - // clear state stack, free all GCs, free the clip region - while (save) { - s = save; - save = save->next; - XFreeGC(display, s->strokeGC); - XFreeGC(display, s->fillGC); - XDestroyRegion(s->clipRegion); - delete s; - } - XFreeGC(display, strokeGC); - XFreeGC(display, fillGC); - XFreeGC(display, paperGC); - XDestroyRegion(clipRegion); -} - -void XOutputDev::drawLink(Link *link, Catalog *catalog) { - double x1, y1, x2, y2; - LinkBorderStyle *borderStyle; - GfxRGB rgb; - double *dash; - char dashList[20]; - int dashLength; - XPoint points[5]; - int x, y, i; - - link->getRect(&x1, &y1, &x2, &y2); - borderStyle = link->getBorderStyle(); - if (borderStyle->getWidth() > 0) { - borderStyle->getColor(&rgb.r, &rgb.g, &rgb.b); - XSetForeground(display, strokeGC, findColor(&rgb)); - borderStyle->getDash(&dash, &dashLength); - if (borderStyle->getType() == linkBorderDashed && dashLength > 0) { - if (dashLength > 20) { - dashLength = 20; - } - for (i = 0; i < dashLength; ++i) { - if ((dashList[i] = xoutRound(dash[i])) == 0) { - dashList[i] = 1; - } - } - XSetLineAttributes(display, strokeGC, xoutRound(borderStyle->getWidth()), - LineOnOffDash, CapButt, JoinMiter); - XSetDashes(display, strokeGC, 0, dashList, dashLength); - } else { - XSetLineAttributes(display, strokeGC, xoutRound(borderStyle->getWidth()), - LineSolid, CapButt, JoinMiter); - } - if (borderStyle->getType() == linkBorderUnderlined) { - cvtUserToDev(x1, y1, &x, &y); - points[0].x = x; - points[0].y = y; - cvtUserToDev(x2, y1, &x, &y); - points[1].x = x; - points[1].y = y; - XDrawLine(display, pixmap, strokeGC, points[0].x, points[0].y, - points[1].x, points[1].y); - } else { - cvtUserToDev(x1, y1, &x, &y); - points[0].x = points[4].x = x; - points[0].y = points[4].y = y; - cvtUserToDev(x2, y1, &x, &y); - points[1].x = x; - points[1].y = y; - cvtUserToDev(x2, y2, &x, &y); - points[2].x = x; - points[2].y = y; - cvtUserToDev(x1, y2, &x, &y); - points[3].x = x; - points[3].y = y; - XDrawLines(display, pixmap, strokeGC, points, 5, CoordModeOrigin); - } - } -} - -void XOutputDev::saveState(GfxState *state) { - XOutputState *s; - XGCValues values; - - // save current state - s = new XOutputState; - s->strokeGC = strokeGC; - s->fillGC = fillGC; - s->clipRegion = clipRegion; - - // push onto state stack - s->next = save; - save = s; - - // create a new current state by copying - strokeGC = XCreateGC(display, pixmap, 0, &values); - XCopyGC(display, s->strokeGC, 0xffffffff, strokeGC); - fillGC = XCreateGC(display, pixmap, 0, &values); - XCopyGC(display, s->fillGC, 0xffffffff, fillGC); - clipRegion = XCreateRegion(); - XUnionRegion(s->clipRegion, clipRegion, clipRegion); - XSetRegion(display, strokeGC, clipRegion); - XSetRegion(display, fillGC, clipRegion); -} - -void XOutputDev::restoreState(GfxState *state) { - XOutputState *s; - - if (save) { - // kill current state - XFreeGC(display, strokeGC); - XFreeGC(display, fillGC); - XDestroyRegion(clipRegion); - - // restore state - flatness = state->getFlatness(); - strokeGC = save->strokeGC; - fillGC = save->fillGC; - clipRegion = save->clipRegion; - XSetRegion(display, strokeGC, clipRegion); - XSetRegion(display, fillGC, clipRegion); - - // pop state stack - s = save; - save = save->next; - delete s; - - // we'll need to restore the font - needFontUpdate = gTrue; - } -} - -void XOutputDev::updateAll(GfxState *state) { - updateLineAttrs(state, gTrue); - updateFlatness(state); - updateMiterLimit(state); - updateFillColor(state); - updateStrokeColor(state); - needFontUpdate = gTrue; -} - -void XOutputDev::updateCTM(GfxState *state, double m11, double m12, - double m21, double m22, double m31, double m32) { - updateLineAttrs(state, gTrue); -} - -void XOutputDev::updateLineDash(GfxState *state) { - updateLineAttrs(state, gTrue); -} - -void XOutputDev::updateFlatness(GfxState *state) { - flatness = state->getFlatness(); -} - -void XOutputDev::updateLineJoin(GfxState *state) { - updateLineAttrs(state, gFalse); -} - -void XOutputDev::updateLineCap(GfxState *state) { - updateLineAttrs(state, gFalse); -} - -// unimplemented -void XOutputDev::updateMiterLimit(GfxState *state) { -} - -void XOutputDev::updateLineWidth(GfxState *state) { - updateLineAttrs(state, gFalse); -} - -void XOutputDev::updateLineAttrs(GfxState *state, GBool updateDash) { - double width; - int cap, join; - double *dashPattern; - int dashLength; - double dashStart; - char dashList[20]; - int i; - - width = state->getTransformedLineWidth(); - switch (state->getLineCap()) { - case 0: cap = CapButt; break; - case 1: cap = CapRound; break; - case 2: cap = CapProjecting; break; - default: - error(-1, "Bad line cap style (%d)", state->getLineCap()); - cap = CapButt; - break; - } - switch (state->getLineJoin()) { - case 0: join = JoinMiter; break; - case 1: join = JoinRound; break; - case 2: join = JoinBevel; break; - default: - error(-1, "Bad line join style (%d)", state->getLineJoin()); - join = JoinMiter; - break; - } - state->getLineDash(&dashPattern, &dashLength, &dashStart); -#if 1 //~ work around a bug in XFree86 (???) - if (dashLength > 0 && cap == CapProjecting) { - cap = CapButt; - } -#endif - XSetLineAttributes(display, strokeGC, xoutRound(width), - dashLength > 0 ? LineOnOffDash : LineSolid, - cap, join); - if (updateDash && dashLength > 0) { - if (dashLength > 20) - dashLength = 20; - for (i = 0; i < dashLength; ++i) { - dashList[i] = xoutRound(state->transformWidth(dashPattern[i])); - if (dashList[i] == 0) - dashList[i] = 1; - } - XSetDashes(display, strokeGC, xoutRound(dashStart), dashList, dashLength); - } -} - -void XOutputDev::updateFillColor(GfxState *state) { - GfxRGB rgb; - - state->getFillRGB(&rgb); - if (reverseVideo) { - rgb.r = 1 - rgb.r; - rgb.g = 1 - rgb.g; - rgb.b = 1 - rgb.b; - } - XSetForeground(display, fillGC, findColor(&rgb)); -} - -void XOutputDev::updateStrokeColor(GfxState *state) { - GfxRGB rgb; - - state->getStrokeRGB(&rgb); - if (reverseVideo) { - rgb.r = 1 - rgb.r; - rgb.g = 1 - rgb.g; - rgb.b = 1 - rgb.b; - } - XSetForeground(display, strokeGC, findColor(&rgb)); -} - -void XOutputDev::updateFont(GfxState *state) { - double m11, m12, m21, m22; - - needFontUpdate = gFalse; - - text->updateFont(state); - - if (!(gfxFont = state->getFont())) { - font = NULL; - return; - } - if (gfxFont->getType() == fontType3) { - font = NULL; - return; - } - state->getFontTransMat(&m11, &m12, &m21, &m22); - m11 *= state->getHorizScaling(); - m12 *= state->getHorizScaling(); - font = fontCache->getFont(xref, gfxFont, m11, m12, m21, m22); - if (font) { - font->updateGC(fillGC); - font->updateGC(strokeGC); - } -} - -void XOutputDev::stroke(GfxState *state) { - XPoint *points; - int *lengths; - int n, size, numPoints, i, j; - - // transform points - n = convertPath(state, state->getPath(), - &points, &size, &numPoints, &lengths, gFalse); - - // draw each subpath - j = 0; - for (i = 0; i < n; ++i) { - XDrawLines(display, pixmap, strokeGC, points + j, lengths[i], - CoordModeOrigin); - j += lengths[i]; - } - - // free points and lengths arrays - if (points != tmpPoints) - gfree(points); - if (lengths != tmpLengths) - gfree(lengths); -} - -void XOutputDev::fill(GfxState *state) { - doFill(state, WindingRule); -} - -void XOutputDev::eoFill(GfxState *state) { - doFill(state, EvenOddRule); -} - -// -// X doesn't color the pixels on the right-most and bottom-most -// borders of a polygon. This means that one-pixel-thick polygons -// are not colored at all. I think this is supposed to be a -// feature, but I can't figure out why. So after it fills a -// polygon, it also draws lines around the border. This is done -// only for single-component polygons, since it's not very -// compatible with the compound polygon kludge (see convertPath()). -// -void XOutputDev::doFill(GfxState *state, int rule) { - XPoint *points; - int *lengths; - int n, size, numPoints, i, j; - - // set fill rule - XSetFillRule(display, fillGC, rule); - - // transform points, build separate polygons - n = convertPath(state, state->getPath(), - &points, &size, &numPoints, &lengths, gTrue); - - // fill them - j = 0; - for (i = 0; i < n; ++i) { - XFillPolygon(display, pixmap, fillGC, points + j, lengths[i], - Complex, CoordModeOrigin); - if (state->getPath()->getNumSubpaths() == 1) { - XDrawLines(display, pixmap, fillGC, points + j, lengths[i], - CoordModeOrigin); - } - j += lengths[i] + 1; - } - - // free points and lengths arrays - if (points != tmpPoints) - gfree(points); - if (lengths != tmpLengths) - gfree(lengths); -} - -void XOutputDev::clip(GfxState *state) { - doClip(state, state->getPath(), WindingRule); -} - -void XOutputDev::eoClip(GfxState *state) { - doClip(state, state->getPath(), EvenOddRule); -} - -void XOutputDev::doClip(GfxState *state, GfxPath *path, int rule) { - GfxSubpath *subpath; - Region region, region2; - XPoint rect[5]; - XPoint *points; - int *lengths; - double x0, y0, x1, y1, x2, y2, x3, y3; - GBool gotRect; - int n, size, numPoints, i, j; - - // special case for rectangular clipping paths -- this is a common - // case, and we want to make sure not to clip an extra pixel on the - // right and bottom edges due to the difference between the PDF and - // X rendering models - gotRect = gFalse; - if (path->getNumSubpaths() == 1) { - subpath = path->getSubpath(0); - if ((subpath->isClosed() && subpath->getNumPoints() == 5) || - (!subpath->isClosed() && subpath->getNumPoints() == 4)) { - state->transform(subpath->getX(0), subpath->getY(0), &x0, &y0); - state->transform(subpath->getX(1), subpath->getY(1), &x1, &y1); - state->transform(subpath->getX(2), subpath->getY(2), &x2, &y2); - state->transform(subpath->getX(3), subpath->getY(3), &x3, &y3); - if (fabs(x0-x1) < 1 && fabs(x2-x3) < 1 && - fabs(y0-y3) < 1 && fabs(y1-y2) < 1) { - if (x0 < x2) { - rect[0].x = rect[1].x = rect[4].x = (int)floor(x0); - rect[2].x = rect[3].x = (int)floor(x2) + 1; - } else { - rect[0].x = rect[1].x = rect[4].x = (int)floor(x0) + 1; - rect[2].x = rect[3].x = (int)floor(x2); - } - if (y0 < y1) { - rect[0].y = rect[3].y = rect[4].y = (int)floor(y0); - rect[1].y = rect[2].y = (int)floor(y1) + 1; - } else { - rect[0].y = rect[3].y = rect[4].y = (int)floor(y0) + 1; - rect[1].y = rect[2].y = (int)floor(y1); - } - gotRect = gTrue; - } else if (fabs(x0-x3) < 1 && fabs(x1-x2) < 1 && - fabs(y0-y1) < 1 && fabs(y2-y3) < 1) { - if (x0 < x1) { - rect[0].x = rect[3].x = rect[4].x = (int)floor(x0); - rect[1].x = rect[2].x = (int)floor(x1) + 1; - } else { - rect[0].x = rect[3].x = rect[4].x = (int)floor(x0) + 1; - rect[1].x = rect[2].x = (int)floor(x1); - } - if (y0 < y2) { - rect[0].y = rect[1].y = rect[4].y = (int)floor(y0); - rect[2].y = rect[3].y = (int)floor(y2) + 1; - } else { - rect[0].y = rect[1].y = rect[4].y = (int)floor(y0) + 1; - rect[2].y = rect[3].y = (int)floor(y2); - } - gotRect = gTrue; - } - } - } - - if (gotRect) { - region = XPolygonRegion(rect, 5, EvenOddRule); - - } else { - // transform points, build separate polygons - n = convertPath(state, path, &points, &size, &numPoints, &lengths, gTrue); - - // construct union of subpath regions - // (XPolygonRegion chokes if there aren't at least three points -- - // this happens if the PDF file does moveto/closepath/clip, which - // sets an empty clipping region) - if (lengths[0] > 2) { - region = XPolygonRegion(points, lengths[0], rule); - } else { - region = XCreateRegion(); - } - j = lengths[0] + 1; - for (i = 1; i < n; ++i) { - if (lengths[i] > 2) { - region2 = XPolygonRegion(points + j, lengths[i], rule); - } else { - region2 = XCreateRegion(); - } - XUnionRegion(region2, region, region); - XDestroyRegion(region2); - j += lengths[i] + 1; - } - - // free points and lengths arrays - if (points != tmpPoints) { - gfree(points); - } - if (lengths != tmpLengths) { - gfree(lengths); - } - } - - // intersect region with clipping region - XIntersectRegion(region, clipRegion, clipRegion); - XDestroyRegion(region); - XSetRegion(display, strokeGC, clipRegion); - XSetRegion(display, fillGC, clipRegion); -} - -// -// Transform points in the path and convert curves to line segments. -// Builds a set of subpaths and returns the number of subpaths. -// If is set, close any unclosed subpaths and activate a -// kludge for polygon fills: First, it divides up the subpaths into -// non-overlapping polygons by simply comparing bounding rectangles. -// Then it connects subaths within a single compound polygon to a single -// point so that X can fill the polygon (sort of). -// -int XOutputDev::convertPath(GfxState *state, GfxPath *path, - XPoint **points, int *size, - int *numPoints, int **lengths, GBool fillHack) { - BoundingRect *rects; - BoundingRect rect; - int n, i, ii, j, k, k0; - - // get path and number of subpaths - n = path->getNumSubpaths(); - - // allocate lengths array - if (n < numTmpSubpaths) - *lengths = tmpLengths; - else - *lengths = (int *)gmalloc(n * sizeof(int)); - - // allocate bounding rectangles array - if (fillHack) { - if (n < numTmpSubpaths) - rects = tmpRects; - else - rects = (BoundingRect *)gmalloc(n * sizeof(BoundingRect)); - } else { - rects = NULL; - } - - // do each subpath - *points = tmpPoints; - *size = numTmpPoints; - *numPoints = 0; - for (i = 0; i < n; ++i) { - - // transform the points - j = *numPoints; - convertSubpath(state, path->getSubpath(i), points, size, numPoints); - - // construct bounding rectangle - if (fillHack) { - rects[i].xMin = rects[i].xMax = (*points)[j].x; - rects[i].yMin = rects[i].yMax = (*points)[j].y; - for (k = j + 1; k < *numPoints; ++k) { - if ((*points)[k].x < rects[i].xMin) - rects[i].xMin = (*points)[k].x; - else if ((*points)[k].x > rects[i].xMax) - rects[i].xMax = (*points)[k].x; - if ((*points)[k].y < rects[i].yMin) - rects[i].yMin = (*points)[k].y; - else if ((*points)[k].y > rects[i].yMax) - rects[i].yMax = (*points)[k].y; - } - } - - // close subpath if necessary - if (fillHack && ((*points)[*numPoints-1].x != (*points)[j].x || - (*points)[*numPoints-1].y != (*points)[j].y)) { - addPoint(points, size, numPoints, (*points)[j].x, (*points)[j].y); - } - - // length of this subpath - (*lengths)[i] = *numPoints - j; - - // leave an extra point for compound fill hack - if (fillHack) - addPoint(points, size, numPoints, 0, 0); - } - - // kludge: munge any points that are *way* out of bounds - these can - // crash certain (buggy) X servers - for (i = 0; i < *numPoints; ++i) { - if ((*points)[i].x < -4 * pixmapW) { - (*points)[i].x = -4 * pixmapW; - } else if ((*points)[i].x > 4 * pixmapW) { - (*points)[i].x = 4 * pixmapW; - } - if ((*points)[i].y < -pixmapH) { - (*points)[i].y = -4 * pixmapH; - } else if ((*points)[i].y > 4 * pixmapH) { - (*points)[i].y = 4 * pixmapH; - } - } - - // combine compound polygons - if (fillHack) { - i = j = k = 0; - while (i < n) { - - // start with subpath i - rect = rects[i]; - (*lengths)[j] = (*lengths)[i]; - k0 = k; - (*points)[k + (*lengths)[i]] = (*points)[k0]; - k += (*lengths)[i] + 1; - ++i; - - // combine overlapping polygons - do { - - // look for the first subsequent subpath, if any, which overlaps - for (ii = i; ii < n; ++ii) { - if (rects[ii].xMax > rects[i].xMin && - rects[ii].xMin < rects[i].xMax && - rects[ii].yMax > rects[i].yMin && - rects[ii].yMin < rects[i].yMax) { - break; - } - } - - // if there is an overlap, combine the polygons - if (ii < n) { - for (; i <= ii; ++i) { - if (rects[i].xMin < rect.xMin) - rect.xMin = rects[j].xMin; - if (rects[i].xMax > rect.xMax) - rect.xMax = rects[j].xMax; - if (rects[i].yMin < rect.yMin) - rect.yMin = rects[j].yMin; - if (rects[i].yMax > rect.yMax) - rect.yMax = rects[j].yMax; - (*lengths)[j] += (*lengths)[i] + 1; - (*points)[k + (*lengths)[i]] = (*points)[k0]; - k += (*lengths)[i] + 1; - } - } - } while (ii < n && i < n); - - ++j; - } - - // free bounding rectangles - if (rects != tmpRects) - gfree(rects); - - n = j; - } - - return n; -} - -// -// Transform points in a single subpath and convert curves to line -// segments. -// -void XOutputDev::convertSubpath(GfxState *state, GfxSubpath *subpath, - XPoint **points, int *size, int *n) { - double x0, y0, x1, y1, x2, y2, x3, y3; - int m, i; - - m = subpath->getNumPoints(); - i = 0; - while (i < m) { - if (i >= 1 && subpath->getCurve(i)) { - state->transform(subpath->getX(i-1), subpath->getY(i-1), &x0, &y0); - state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1); - state->transform(subpath->getX(i+1), subpath->getY(i+1), &x2, &y2); - state->transform(subpath->getX(i+2), subpath->getY(i+2), &x3, &y3); - doCurve(points, size, n, x0, y0, x1, y1, x2, y2, x3, y3); - i += 3; - } else { - state->transform(subpath->getX(i), subpath->getY(i), &x1, &y1); - addPoint(points, size, n, xoutRound(x1), xoutRound(y1)); - ++i; - } - } -} - -// -// Subdivide a Bezier curve. This uses floating point to avoid -// propagating rounding errors. (The curves look noticeably more -// jagged with integer arithmetic.) -// -void XOutputDev::doCurve(XPoint **points, int *size, int *n, - double x0, double y0, double x1, double y1, - double x2, double y2, double x3, double y3) { - double x[(1<= *size) { - *size += 32; - if (*points == tmpPoints) { - *points = (XPoint *)gmalloc(*size * sizeof(XPoint)); - memcpy(*points, tmpPoints, *k * sizeof(XPoint)); - } else { - *points = (XPoint *)grealloc(*points, *size * sizeof(XPoint)); - } - } - (*points)[*k].x = x; - (*points)[*k].y = y; - ++(*k); -} - -void XOutputDev::beginString(GfxState *state, GString *s) { - text->beginWord(state, state->getCurX(), state->getCurY()); -} - -void XOutputDev::endString(GfxState *state) { - text->endWord(); -} - -void XOutputDev::drawChar(GfxState *state, double x, double y, - double dx, double dy, - double originX, double originY, - CharCode code, Unicode *u, int uLen) { - int render; - double x1, y1, dx1, dy1; - GfxRGB rgb; - double saveCurX, saveCurY; - double *ctm; - double saveCTM[6]; - - if (needFontUpdate) { - updateFont(state); - } - - text->addChar(state, x, y, dx, dy, code, u, uLen); - - if (!font) { - return; - } - - // check for invisible text -- this is used by Acrobat Capture - render = state->getRender(); - if (render == 3) { - return; - } - - x -= originX; - y -= originY; - state->transform(x, y, &x1, &y1); - state->transformDelta(dx, dy, &dx1, &dy1); - - // fill - if (!(render & 1)) { - state->getFillRGB(&rgb); - if (reverseVideo) { - rgb.r = 1 - rgb.r; - rgb.g = 1 - rgb.g; - rgb.b = 1 - rgb.b; - } - font->drawChar(state, pixmap, pixmapW, pixmapH, fillGC, &rgb, - x1, y1, dx1, dy1, code, u, uLen); - } - - // stroke - if ((render & 3) == 1 || (render & 3) == 2) { - if (font->hasGetCharPath()) { - saveCurX = state->getCurX(); - saveCurY = state->getCurY(); - ctm = state->getCTM(); - memcpy(saveCTM, ctm, 6 * sizeof(double)); - state->setCTM(1, 0, 0, 1, x1, y1); - font->getCharPath(state, code, u, uLen); - stroke(state); - state->clearPath(); - state->setCTM(saveCTM[0], saveCTM[1], saveCTM[2], saveCTM[3], - saveCTM[4], saveCTM[5]); - state->moveTo(saveCurX, saveCurY); - } else { - // can't stroke the outline, so just fill it using the stroke - // color - state->getStrokeRGB(&rgb); - if (reverseVideo) { - rgb.r = 1 - rgb.r; - rgb.g = 1 - rgb.g; - rgb.b = 1 - rgb.b; - } - font->drawChar(state, pixmap, pixmapW, pixmapH, strokeGC, &rgb, - x1, y1, dx1, dy1, code, u, uLen); - } - } - - // clip - if (render & 4) { - if (font->hasGetCharPath()) { - saveCurX = state->getCurX(); - saveCurY = state->getCurY(); - font->getCharPath(state, code, u, uLen); - state->getPath()->offset(x1, y1); - if (textClipPath) { - textClipPath->append(state->getPath()); - } else { - textClipPath = state->getPath()->copy(); - } - state->clearPath(); - state->moveTo(saveCurX, saveCurY); - } - } -} - -GBool XOutputDev::beginType3Char(GfxState *state, - CharCode code, Unicode *u, int uLen) { - Ref *fontID; - double *ctm, *bbox; - GfxRGB color; - T3FontCache *t3Font; - T3GlyphStack *t3gs; - double x1, y1, xMin, yMin, xMax, yMax, xt, yt; - int i, j; - - if (needFontUpdate) { - updateFont(state); - } - if (!gfxFont) { - return gFalse; - } - fontID = gfxFont->getID(); - ctm = state->getCTM(); - state->transform(0, 0, &xt, &yt); - - // is it the first (MRU) font in the cache? - if (!(nT3Fonts > 0 && - t3FontCache[0]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3]))) { - - // is the font elsewhere in the cache? - for (i = 1; i < nT3Fonts; ++i) { - if (t3FontCache[i]->matches(fontID, ctm[0], ctm[1], ctm[2], ctm[3])) { - t3Font = t3FontCache[i]; - for (j = i; j > 0; --j) { - t3FontCache[j] = t3FontCache[j - 1]; - } - t3FontCache[0] = t3Font; - break; - } - } - if (i >= nT3Fonts) { - - // create new entry in the font cache - if (nT3Fonts == xOutT3FontCacheSize) { - delete t3FontCache[nT3Fonts - 1]; - --nT3Fonts; - } - for (j = nT3Fonts; j > 0; --j) { - t3FontCache[j] = t3FontCache[j - 1]; - } - ++nT3Fonts; - bbox = gfxFont->getFontBBox(); - if (bbox[0] == 0 && bbox[1] == 0 && bbox[2] == 0 && bbox[3] == 0) { - // broken bounding box -- just take a guess - xMin = xt - 5; - xMax = xMin + 30; - yMax = yt + 15; - yMin = yMax - 45; - } else { - state->transform(bbox[0], bbox[1], &x1, &y1); - xMin = xMax = x1; - yMin = yMax = y1; - state->transform(bbox[0], bbox[3], &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - state->transform(bbox[2], bbox[1], &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - state->transform(bbox[2], bbox[3], &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - } - t3FontCache[0] = new T3FontCache(fontID, ctm[0], ctm[1], ctm[2], ctm[3], - (int)floor(xMin - xt), - (int)floor(yMin - yt), - (int)ceil(xMax) - (int)floor(xMin) + 3, - (int)ceil(yMax) - (int)floor(yMin) + 3, - display, visual, depth, pixmap); - } - } - t3Font = t3FontCache[0]; - - // is the glyph in the cache? - i = (code & (t3Font->cacheSets - 1)) * t3Font->cacheAssoc; - for (j = 0; j < t3Font->cacheAssoc; ++j) { - if ((t3Font->cacheTags[i+j].mru & 0x8000) && - t3Font->cacheTags[i+j].code == code) { - state->getFillRGB(&color); - if (reverseVideo) { - color.r = 1 - color.r; - color.g = 1 - color.g; - color.b = 1 - color.b; - } - text->addChar(state, 0, 0, - t3Font->cacheTags[i+j].wx, t3Font->cacheTags[i+j].wy, - code, u, uLen); - drawType3Glyph(t3Font, &t3Font->cacheTags[i+j], - t3Font->cacheData + (i+j) * t3Font->glyphSize, - xt, yt, &color); - return gTrue; - } - } - - // push a new Type 3 glyph record - t3gs = new T3GlyphStack(); - t3gs->next = t3GlyphStack; - t3GlyphStack = t3gs; - t3GlyphStack->cacheable = gFalse; - t3GlyphStack->code = code; - t3GlyphStack->cache = t3Font; - t3GlyphStack->cacheIdx = i; - t3GlyphStack->x = xt; - t3GlyphStack->y = yt; - t3GlyphStack->u = u; - t3GlyphStack->uLen = uLen; - - return gFalse; -} - -void XOutputDev::endType3Char(GfxState *state) { - XImage *image; - Guchar *p; - int x, y; - Gulong pixel; - double alpha; - T3GlyphStack *t3gs; - double *ctm; - - if (t3GlyphStack->cacheable) { - image = t3GlyphStack->cache->image; - XGetSubImage(display, pixmap, 0, 0, - t3GlyphStack->cache->glyphW, t3GlyphStack->cache->glyphH, - (1 << depth) - 1, ZPixmap, image, 0, 0); - p = t3GlyphStack->cacheData; - for (y = 0; y < t3GlyphStack->cache->glyphH; ++y) { - for (x = 0; x < t3GlyphStack->cache->glyphW; ++x) { - pixel = XGetPixel(image, x, y); - if (trueColor) { - alpha = (double)((pixel >> rShift) & rMul) / (double)rMul; - } else { - alpha = redMap[pixel & 0xff]; - } - if (alpha <= 0.2) { - *p++ = 4; - } else if (alpha <= 0.4) { - *p++ = 3; - } else if (alpha <= 0.6) { - *p++ = 2; - } else if (alpha <= 0.8) { - *p++ = 1; - } else { - *p++ = 0; - } - } - } - XDestroyRegion(clipRegion); - XFreeGC(display, strokeGC); - XFreeGC(display, fillGC); - pixmapW = t3GlyphStack->origPixmapW; - pixmapH = t3GlyphStack->origPixmapH; - pixmap = t3GlyphStack->origPixmap; - strokeGC = t3GlyphStack->origStrokeGC; - fillGC = t3GlyphStack->origFillGC; - clipRegion = t3GlyphStack->origClipRegion; - drawType3Glyph(t3GlyphStack->cache, - t3GlyphStack->cacheTag, t3GlyphStack->cacheData, - t3GlyphStack->x, t3GlyphStack->y, &t3GlyphStack->color); - // the CTM must be restored here in order for TextPage::addChar to - // work correctly - ctm = state->getCTM(); - state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3], - t3GlyphStack->origCTM4, t3GlyphStack->origCTM5); - } - text->addChar(state, 0, 0, t3GlyphStack->wx, t3GlyphStack->wy, - t3GlyphStack->code, t3GlyphStack->u, t3GlyphStack->uLen); - t3gs = t3GlyphStack; - t3GlyphStack = t3gs->next; - delete t3gs; -} - -void XOutputDev::drawType3Glyph(T3FontCache *t3Font, - T3FontCacheTag *tag, Guchar *data, - double x, double y, GfxRGB *color) { - XImage *image; - XColor xcolor; - GfxRGB bg, rgb; - Gulong map[5]; - Gulong pixel; - Guchar *p; - int x0, y0, w0, h0, x1, y1; - int ix, iy; - - // compute: (x0,y0) = position in destination pixmap - // (x1,y1) = position in the XImage - // (w0,h0) = size of XImage transfer - x0 = xoutRound(x + t3Font->glyphX); - y0 = xoutRound(y + t3Font->glyphY); - x1 = 0; - y1 = 0; - w0 = t3Font->glyphW; - h0 = t3Font->glyphH; - if (x0 < 0) { - x1 = -x0; - w0 += x0; - x0 = 0; - } - if (x0 + w0 > pixmapW) { - w0 = pixmapW - x0; - } - if (w0 <= 0) { - return; - } - if (y0 < 0) { - y1 = -y0; - h0 += y0; - y0 = 0; - } - if (y0 + h0 > pixmapH) { - h0 = pixmapH - y0; - } - if (h0 <= 0) { - return; - } - - image = t3Font->image; - XGetSubImage(display, pixmap, x0, y0, w0, h0, - (1 << depth) - 1, ZPixmap, image, x1, y1); - xcolor.pixel = XGetPixel(image, t3Font->glyphW / 2, t3Font->glyphH / 2); - XQueryColor(display, colormap, &xcolor); - bg.r = xcolor.red / 65535.0; - bg.g = xcolor.green / 65535.0; - bg.b = xcolor.blue / 65535.0; - rgb.r = 0.25 * (color->r + 3 * bg.r); - rgb.g = 0.25 * (color->g + 3 * bg.g); - rgb.b = 0.25 * (color->b + 3 * bg.b); - map[1] = findColor(&rgb); - rgb.r = 0.5 * (color->r + bg.r); - rgb.g = 0.5 * (color->g + bg.g); - rgb.b = 0.5 * (color->b + bg.b); - map[2] = findColor(&rgb); - rgb.r = 0.25 * (3 * color->r + bg.r); - rgb.g = 0.25 * (3 * color->g + bg.g); - rgb.b = 0.25 * (3 * color->b + bg.b); - map[3] = findColor(&rgb); - map[4] = findColor(color); - p = data; - for (iy = 0; iy < t3Font->glyphH; ++iy) { - for (ix = 0; ix < t3Font->glyphW; ++ix) { - pixel = *p++; - if (pixel > 0) { - XPutPixel(image, ix, iy, map[pixel]); - } - } - } - XPutImage(display, pixmap, fillGC, image, x1, y1, x0, y0, w0, h0); -} - -void XOutputDev::type3D0(GfxState *state, double wx, double wy) { - t3GlyphStack->wx = wx; - t3GlyphStack->wy = wy; -} - -void XOutputDev::type3D1(GfxState *state, double wx, double wy, - double llx, double lly, double urx, double ury) { - GfxColor fgColor; - XGCValues gcValues; - XRectangle rect; - double *ctm; - T3FontCache *t3Font; - double xt, yt, xMin, xMax, yMin, yMax, x1, y1; - int i, j; - - t3Font = t3GlyphStack->cache; - t3GlyphStack->wx = wx; - t3GlyphStack->wy = wy; - - // check for a valid bbox - state->transform(0, 0, &xt, &yt); - state->transform(llx, lly, &x1, &y1); - xMin = xMax = x1; - yMin = yMax = y1; - state->transform(llx, ury, &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - state->transform(urx, lly, &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - state->transform(urx, ury, &x1, &y1); - if (x1 < xMin) { - xMin = x1; - } else if (x1 > xMax) { - xMax = x1; - } - if (y1 < yMin) { - yMin = y1; - } else if (y1 > yMax) { - yMax = y1; - } - if (xMin - xt < t3Font->glyphX || - yMin - yt < t3Font->glyphY || - xMax - xt > t3Font->glyphX + t3Font->glyphW || - yMax - yt > t3Font->glyphY + t3Font->glyphH) { - error(-1, "Bad bounding box in Type 3 glyph"); - return; - } - - // allocate a cache entry - t3GlyphStack->cacheable = gTrue; - i = t3GlyphStack->cacheIdx; - for (j = 0; j < t3Font->cacheAssoc; ++j) { - if ((t3Font->cacheTags[i+j].mru & 0x7fff) == t3Font->cacheAssoc - 1) { - t3Font->cacheTags[i+j].mru = 0x8000; - t3Font->cacheTags[i+j].code = t3GlyphStack->code; - t3GlyphStack->cacheTag = &t3Font->cacheTags[i+j]; - t3GlyphStack->cacheData = t3Font->cacheData + (i+j) * t3Font->glyphSize; - } else { - ++t3Font->cacheTags[i+j].mru; - } - } - t3GlyphStack->cacheTag->wx = wx; - t3GlyphStack->cacheTag->wy = wy; - - // prepare to rasterize the glyph - //~ do we need to handle both fill and stroke color? - state->getFillRGB(&t3GlyphStack->color); - if (reverseVideo) { - t3GlyphStack->color.r = 1 - t3GlyphStack->color.r; - t3GlyphStack->color.g = 1 - t3GlyphStack->color.g; - t3GlyphStack->color.b = 1 - t3GlyphStack->color.b; - } - fgColor.c[0] = reverseVideo ? 1 : 0; - state->setFillColorSpace(new GfxDeviceGrayColorSpace()); - state->setFillColor(&fgColor); - state->setStrokeColorSpace(new GfxDeviceGrayColorSpace()); - state->setStrokeColor(&fgColor); - t3GlyphStack->origPixmapW = pixmapW; - t3GlyphStack->origPixmapH = pixmapH; - t3GlyphStack->origPixmap = pixmap; - t3GlyphStack->origStrokeGC = strokeGC; - t3GlyphStack->origFillGC = fillGC; - t3GlyphStack->origClipRegion = clipRegion; - pixmapW = t3GlyphStack->cache->glyphW; - pixmapH = t3GlyphStack->cache->glyphH; - pixmap = t3GlyphStack->cache->pixmap; - gcValues.foreground = BlackPixel(display, screenNum); - gcValues.background = WhitePixel(display, screenNum); - gcValues.line_width = 0; - gcValues.line_style = LineSolid; - strokeGC = XCreateGC(display, pixmap, - GCForeground | GCBackground | GCLineWidth | GCLineStyle, - &gcValues); - updateLineAttrs(state, gTrue); - gcValues.foreground = WhitePixel(display, screenNum); - fillGC = XCreateGC(display, pixmap, - GCForeground | GCBackground | GCLineWidth | GCLineStyle, - &gcValues); - XFillRectangle(display, pixmap, fillGC, 0, 0, pixmapW, pixmapH); - XSetForeground(display, fillGC, BlackPixel(display, screenNum)); - clipRegion = XCreateRegion(); - rect.x = rect.y = 0; - rect.width = pixmapW; - rect.height = pixmapH; - XUnionRectWithRegion(&rect, clipRegion, clipRegion); - XSetRegion(display, strokeGC, clipRegion); - XSetRegion(display, fillGC, clipRegion); - ctm = state->getCTM(); - t3GlyphStack->origCTM4 = ctm[4]; - t3GlyphStack->origCTM5 = ctm[5]; - state->setCTM(ctm[0], ctm[1], ctm[2], ctm[3], - -t3GlyphStack->cache->glyphX, -t3GlyphStack->cache->glyphY); -} - -void XOutputDev::endTextObject(GfxState *state) { - double *ctm; - double saveCTM[6]; - - if (textClipPath) { - ctm = state->getCTM(); - memcpy(saveCTM, ctm, 6 * sizeof(double)); - state->setCTM(1, 0, 0, 1, 0, 0); - doClip(state, textClipPath, WindingRule); - state->setCTM(saveCTM[0], saveCTM[1], saveCTM[2], saveCTM[3], - saveCTM[4], saveCTM[5]); - delete textClipPath; - textClipPath = NULL; - } -} - -inline Gulong XOutputDev::findColor(GfxRGB *x, GfxRGB *actual) { - double gray; - int r, g, b; - Gulong pixel; - - if (trueColor) { - r = xoutRound(x->r * rMul); - g = xoutRound(x->g * gMul); - b = xoutRound(x->b * bMul); - pixel = ((Gulong)r << rShift) + - ((Gulong)g << gShift) + - ((Gulong)b << bShift); - actual->r = (double)r / rMul; - actual->g = (double)g / gMul; - actual->b = (double)b / bMul; - } else if (numColors == 1) { - gray = 0.299 * x->r + 0.587 * x->g + 0.114 * x->b; - if (gray < 0.5) { - pixel = colors[0]; - actual->r = actual->g = actual->b = 0; - } else { - pixel = colors[1]; - actual->r = actual->g = actual->b = 1; - } - } else { - r = xoutRound(x->r * (numColors - 1)); - g = xoutRound(x->g * (numColors - 1)); - b = xoutRound(x->b * (numColors - 1)); - pixel = colors[(r * numColors + g) * numColors + b]; - actual->r = (double)r / (numColors - 1); - actual->g = (double)g / (numColors - 1); - actual->b = (double)b / (numColors - 1); - } - return pixel; -} - -Gulong XOutputDev::findColor(GfxRGB *rgb) { - int r, g, b; - double gray; - Gulong pixel; - - if (trueColor) { - r = xoutRound(rgb->r * rMul); - g = xoutRound(rgb->g * gMul); - b = xoutRound(rgb->b * bMul); - pixel = ((Gulong)r << rShift) + - ((Gulong)g << gShift) + - ((Gulong)b << bShift); - } else if (numColors == 1) { - gray = 0.299 * rgb->r + 0.587 * rgb->g + 0.114 * rgb->b; - if (gray < 0.5) - pixel = colors[0]; - else - pixel = colors[1]; - } else { - r = xoutRound(rgb->r * (numColors - 1)); - g = xoutRound(rgb->g * (numColors - 1)); - b = xoutRound(rgb->b * (numColors - 1)); -#if 0 // this makes things worse as often as better - // even a very light color shouldn't map to white - if (r == numColors - 1 && g == numColors - 1 && b == numColors - 1) { - if (color->getR() < 0.95) - --r; - if (color->getG() < 0.95) - --g; - if (color->getB() < 0.95) - --b; - } -#endif - pixel = colors[(r * numColors + g) * numColors + b]; - } - return pixel; -} - -void XOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool inlineImg) { - ImageStream *imgStr; - XImage *image; - double *ctm; - GBool rot; - double xScale, yScale, xShear, yShear; - int tx, ty, scaledWidth, scaledHeight, xSign, ySign; - int ulx, uly, llx, lly, urx, ury, lrx, lry; - int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1; - int bx0, by0, bx1, by1, bw, bh; - int cx0, cy0, cx1, cy1, cw, ch; - int yp, yq, yt, yStep, lastYStep; - int xp, xq, xt, xStep, xSrc; - GfxRGB rgb; - Guchar *pixBuf; - int imgPix; - double alpha; - XColor xcolor; - Gulong lastPixel; - GfxRGB rgb2; - double r0, g0, b0, r1, g1, b1; - Gulong pix; - Guchar *p; - int x, y, x1, y1, x2, y2; - int n, m, i, j; - - // get CTM, check for singular matrix - ctm = state->getCTM(); - if (fabs(ctm[0] * ctm[3] - ctm[1] * ctm[2]) < 0.000001) { - error(-1, "Singular CTM in drawImage"); - if (inlineImg) { - j = height * ((width + 7) / 8); - str->reset(); - for (i = 0; i < j; ++i) { - str->getChar(); - } - str->close(); - } - return; - } - - // compute scale, shear, rotation, translation parameters - rot = fabs(ctm[1]) > fabs(ctm[0]); - if (rot) { - xScale = -ctm[1]; - yScale = -ctm[2] + (ctm[0] * ctm[3]) / ctm[1]; - xShear = ctm[3] / yScale; - yShear = -ctm[0] / ctm[1]; - } else { - xScale = ctm[0]; - yScale = -ctm[3] + (ctm[1] * ctm[2]) / ctm[0]; - xShear = -ctm[2] / yScale; - yShear = ctm[1] / ctm[0]; - } - tx = xoutRound(ctm[2] + ctm[4]); - ty = xoutRound(ctm[3] + ctm[5]); - // use ceil() to avoid gaps between "striped" images - scaledWidth = (int)ceil(fabs(xScale)); - xSign = (xScale < 0) ? -1 : 1; - scaledHeight = (int)ceil(fabs(yScale)); - ySign = (yScale < 0) ? -1 : 1; - - // compute corners in device space - ulx1 = 0; - uly1 = 0; - urx1 = xSign * (scaledWidth - 1); - ury1 = xoutRound(yShear * urx1); - llx1 = xoutRound(xShear * ySign * (scaledHeight - 1)); - lly1 = ySign * (scaledHeight - 1) + xoutRound(yShear * llx1); - lrx1 = xSign * (scaledWidth - 1) + - xoutRound(xShear * ySign * (scaledHeight - 1)); - lry1 = ySign * (scaledHeight - 1) + xoutRound(yShear * lrx1); - if (rot) { - ulx = tx + uly1; uly = ty - ulx1; - urx = tx + ury1; ury = ty - urx1; - llx = tx + lly1; lly = ty - llx1; - lrx = tx + lry1; lry = ty - lrx1; - } else { - ulx = tx + ulx1; uly = ty + uly1; - urx = tx + urx1; ury = ty + ury1; - llx = tx + llx1; lly = ty + lly1; - lrx = tx + lrx1; lry = ty + lry1; - } - - // bounding box: - // (bx0, by0) = upper-left corner - // (bx1, by1) = lower-right corner - // (bw, bh) = size - bx0 = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx - : (llx < lrx) ? llx : lrx - : (urx < llx) ? (urx < lrx) ? urx : lrx - : (llx < lrx) ? llx : lrx; - bx1 = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx - : (llx > lrx) ? llx : lrx - : (urx > llx) ? (urx > lrx) ? urx : lrx - : (llx > lrx) ? llx : lrx; - by0 = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry - : (lly < lry) ? lly : lry - : (ury < lly) ? (ury < lry) ? ury : lry - : (lly < lry) ? lly : lry; - by1 = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry - : (lly > lry) ? lly : lry - : (ury > lly) ? (ury > lry) ? ury : lry - : (lly > lry) ? lly : lry; - bw = bx1 - bx0 + 1; - bh = by1 - by0 + 1; - - // Bounding box clipped to pixmap, i.e., "valid" rectangle: - // (cx0, cy0) = upper-left corner of valid rectangle in Pixmap - // (cx1, cy1) = upper-left corner of valid rectangle in XImage - // (cw, ch) = size of valid rectangle - // These values will be used to transfer the XImage from/to the - // Pixmap. - cw = (bx1 >= pixmapW) ? pixmapW - bx0 : bw; - if (bx0 < 0) { - cx0 = 0; - cx1 = -bx0; - cw += bx0; - } else { - cx0 = bx0; - cx1 = 0; - } - ch = (by1 >= pixmapH) ? pixmapH - by0 : bh; - if (by0 < 0) { - cy0 = 0; - cy1 = -by0; - ch += by0; - } else { - cy0 = by0; - cy1 = 0; - } - - // check for tiny (zero width or height) images - // and off-page images - if (scaledWidth <= 0 || scaledHeight <= 0 || cw <= 0 || ch <= 0) { - if (inlineImg) { - j = height * ((width + 7) / 8); - str->reset(); - for (i = 0; i < j; ++i) { - str->getChar(); - } - str->close(); - } - return; - } - - // compute Bresenham parameters for x and y scaling - yp = height / scaledHeight; - yq = height % scaledHeight; - xp = width / scaledWidth; - xq = width % scaledWidth; - - // allocate pixel buffer - pixBuf = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar)); - - // allocate XImage and read from page pixmap - image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, bw, bh, 8, 0); - image->data = (char *)gmalloc(bh * image->bytes_per_line); - XGetSubImage(display, pixmap, cx0, cy0, cw, ch, (1 << depth) - 1, ZPixmap, - image, cx1, cy1); - - // get mask color - state->getFillRGB(&rgb); - if (reverseVideo) { - rgb.r = 1 - rgb.r; - rgb.g = 1 - rgb.g; - rgb.b = 1 - rgb.b; - } - r0 = rgb.r; - g0 = rgb.g; - b0 = rgb.b; - - // initialize background color - // (the specific pixel value doesn't matter here, as long as - // r1,g1,b1 correspond correctly to lastPixel) - xcolor.pixel = lastPixel = 0; - XQueryColor(display, colormap, &xcolor); - r1 = (double)xcolor.red / 65535.0; - g1 = (double)xcolor.green / 65535.0; - b1 = (double)xcolor.blue / 65535.0; - - // initialize the image stream - imgStr = new ImageStream(str, width, 1, 1); - imgStr->reset(); - - // init y scale Bresenham - yt = 0; - lastYStep = 1; - - for (y = 0; y < scaledHeight; ++y) { - - // y scale Bresenham - yStep = yp; - yt += yq; - if (yt >= scaledHeight) { - yt -= scaledHeight; - ++yStep; - } - - // read row(s) from image - n = (yp > 0) ? yStep : lastYStep; - if (n > 0) { - p = pixBuf; - for (i = 0; i < n; ++i) { - memcpy(p, imgStr->getLine(), width); - if (invert) { - for (j = 0; j < width; ++j) { - p[j] ^= 1; - } - } - p += width; - } - } - lastYStep = yStep; - - // init x scale Bresenham - xt = 0; - xSrc = 0; - - for (x = 0; x < scaledWidth; ++x) { - - // x scale Bresenham - xStep = xp; - xt += xq; - if (xt >= scaledWidth) { - xt -= scaledWidth; - ++xStep; - } - - // x shear - x1 = xSign * x + xoutRound(xShear * ySign * y); - - // y shear - y1 = ySign * y + xoutRound(yShear * x1); - - // rotation - if (rot) { - x2 = y1; - y2 = -x1; - } else { - x2 = x1; - y2 = y1; - } - - // compute the filtered pixel at (x,y) after the - // x and y scaling operations - n = yStep > 0 ? yStep : 1; - m = xStep > 0 ? xStep : 1; - p = pixBuf + xSrc; - imgPix = 0; - for (i = 0; i < n; ++i) { - for (j = 0; j < m; ++j) { - imgPix += *p++; - } - p += width - m; - } - - // x scale Bresenham - xSrc += xStep; - - // blend image pixel with background - alpha = (double)imgPix / (double)(n * m); - xcolor.pixel = XGetPixel(image, tx + x2 - bx0, ty + y2 - by0); - if (xcolor.pixel != lastPixel) { - XQueryColor(display, colormap, &xcolor); - r1 = (double)xcolor.red / 65535.0; - g1 = (double)xcolor.green / 65535.0; - b1 = (double)xcolor.blue / 65535.0; - lastPixel = xcolor.pixel; - } - rgb2.r = r0 * (1 - alpha) + r1 * alpha; - rgb2.g = g0 * (1 - alpha) + g1 * alpha; - rgb2.b = b0 * (1 - alpha) + b1 * alpha; - pix = findColor(&rgb2); - - // set pixel - XPutPixel(image, tx + x2 - bx0, ty + y2 - by0, pix); - } - } - - // blit the image into the pixmap - XPutImage(display, pixmap, fillGC, image, cx1, cy1, cx0, cy0, cw, ch); - - // free memory - delete imgStr; - gfree(pixBuf); - gfree(image->data); - image->data = NULL; - XDestroyImage(image); -} - -void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str, - int width, int height, GfxImageColorMap *colorMap, - int *maskColors, GBool inlineImg) { - ImageStream *imgStr; - XImage *image; - int nComps, nVals, nBits; - GBool dither; - double *ctm; - GBool rot; - double xScale, yScale, xShear, yShear; - int tx, ty, scaledWidth, scaledHeight, xSign, ySign; - int ulx, uly, llx, lly, urx, ury, lrx, lry; - int ulx1, uly1, llx1, lly1, urx1, ury1, lrx1, lry1; - int bx0, by0, bx1, by1, bw, bh; - int cx0, cy0, cx1, cy1, cw, ch; - int yp, yq, yt, yStep, lastYStep; - int xp, xq, xt, xStep, xSrc; - GfxRGB *pixBuf; - Guchar *pixBuf1, *alphaBuf; - Guchar pixBuf2[gfxColorMaxComps]; - GfxRGB color2, color3, actual, err, errRight; - GfxRGB *errDown0, *errDown1, *errDownTmp; - double r0, g0, b0, alpha, mul; - Gulong pix; - GfxRGB *p; - Guchar *q, *p1, *p2; - GBool oneBitMode; - GfxRGB oneBitRGB[2]; - int x, y, x1, y1, x2, y2; - int n, m, i, j, k; - - // image parameters - nComps = colorMap->getNumPixelComps(); - nVals = width * nComps; - nBits = colorMap->getBits(); - oneBitMode = nComps == 1 && nBits == 1 && !maskColors; - dither = nComps > 1 || nBits > 1; - - // get CTM, check for singular matrix - ctm = state->getCTM(); - if (fabs(ctm[0] * ctm[3] - ctm[1] * ctm[2]) < 0.000001) { - error(-1, "Singular CTM in drawImage"); - if (inlineImg) { - str->reset(); - j = height * ((nVals * nBits + 7) / 8); - for (i = 0; i < j; ++i) { - str->getChar(); - } - str->close(); - } - return; - } - - // compute scale, shear, rotation, translation parameters - rot = fabs(ctm[1]) > fabs(ctm[0]); - if (rot) { - xScale = -ctm[1]; - yScale = -ctm[2] + (ctm[0] * ctm[3]) / ctm[1]; - xShear = ctm[3] / yScale; - yShear = -ctm[0] / ctm[1]; - } else { - xScale = ctm[0]; - yScale = -ctm[3] + (ctm[1] * ctm[2]) / ctm[0]; - xShear = -ctm[2] / yScale; - yShear = ctm[1] / ctm[0]; - } - tx = xoutRound(ctm[2] + ctm[4]); - ty = xoutRound(ctm[3] + ctm[5]); - if (xScale < 0) { - // this is the right edge which needs to be (left + width - 1) - --tx; - } - if (yScale < 0) { - // this is the bottom edge which needs to be (top + height - 1) - --ty; - } - // use ceil() to avoid gaps between "striped" images - scaledWidth = (int)ceil(fabs(xScale)); - xSign = (xScale < 0) ? -1 : 1; - scaledHeight = (int)ceil(fabs(yScale)); - ySign = (yScale < 0) ? -1 : 1; - - // compute corners in device space - ulx1 = 0; - uly1 = 0; - urx1 = xSign * (scaledWidth - 1); - ury1 = xoutRound(yShear * urx1); - llx1 = xoutRound(xShear * ySign * (scaledHeight - 1)); - lly1 = ySign * (scaledHeight - 1) + xoutRound(yShear * llx1); - lrx1 = xSign * (scaledWidth - 1) + - xoutRound(xShear * ySign * (scaledHeight - 1)); - lry1 = ySign * (scaledHeight - 1) + xoutRound(yShear * lrx1); - if (rot) { - ulx = tx + uly1; uly = ty - ulx1; - urx = tx + ury1; ury = ty - urx1; - llx = tx + lly1; lly = ty - llx1; - lrx = tx + lry1; lry = ty - lrx1; - } else { - ulx = tx + ulx1; uly = ty + uly1; - urx = tx + urx1; ury = ty + ury1; - llx = tx + llx1; lly = ty + lly1; - lrx = tx + lrx1; lry = ty + lry1; - } - - // bounding box: - // (bx0, by0) = upper-left corner - // (bx1, by1) = lower-right corner - // (bw, bh) = size - bx0 = (ulx < urx) ? (ulx < llx) ? (ulx < lrx) ? ulx : lrx - : (llx < lrx) ? llx : lrx - : (urx < llx) ? (urx < lrx) ? urx : lrx - : (llx < lrx) ? llx : lrx; - bx1 = (ulx > urx) ? (ulx > llx) ? (ulx > lrx) ? ulx : lrx - : (llx > lrx) ? llx : lrx - : (urx > llx) ? (urx > lrx) ? urx : lrx - : (llx > lrx) ? llx : lrx; - by0 = (uly < ury) ? (uly < lly) ? (uly < lry) ? uly : lry - : (lly < lry) ? lly : lry - : (ury < lly) ? (ury < lry) ? ury : lry - : (lly < lry) ? lly : lry; - by1 = (uly > ury) ? (uly > lly) ? (uly > lry) ? uly : lry - : (lly > lry) ? lly : lry - : (ury > lly) ? (ury > lry) ? ury : lry - : (lly > lry) ? lly : lry; - bw = bx1 - bx0 + 1; - bh = by1 - by0 + 1; - - // Bounding box clipped to pixmap, i.e., "valid" rectangle: - // (cx0, cy0) = upper-left corner of valid rectangle in Pixmap - // (cx1, cy1) = upper-left corner of valid rectangle in XImage - // (cw, ch) = size of valid rectangle - // These values will be used to transfer the XImage from/to the - // Pixmap. - cw = (bx1 >= pixmapW) ? pixmapW - bx0 : bw; - if (bx0 < 0) { - cx0 = 0; - cx1 = -bx0; - cw += bx0; - } else { - cx0 = bx0; - cx1 = 0; - } - ch = (by1 >= pixmapH) ? pixmapH - by0 : bh; - if (by0 < 0) { - cy0 = 0; - cy1 = -by0; - ch += by0; - } else { - cy0 = by0; - cy1 = 0; - } - - // check for tiny (zero width or height) images - // and off-page images - if (scaledWidth <= 0 || scaledHeight <= 0 || cw <= 0 || ch <= 0) { - if (inlineImg) { - str->reset(); - j = height * ((nVals * nBits + 7) / 8); - for (i = 0; i < j; ++i) - str->getChar(); - str->close(); - } - return; - } - - // compute Bresenham parameters for x and y scaling - yp = height / scaledHeight; - yq = height % scaledHeight; - xp = width / scaledWidth; - xq = width % scaledWidth; - - // allocate pixel buffer - if (oneBitMode) { - pixBuf1 = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar)); - pixBuf = NULL; - } else { - pixBuf = (GfxRGB *)gmalloc((yp + 1) * width * sizeof(GfxRGB)); - pixBuf1 = NULL; - } - if (maskColors) { - alphaBuf = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar)); - } else { - alphaBuf = NULL; - } - - // allocate XImage - image = XCreateImage(display, visual, depth, ZPixmap, 0, NULL, bw, bh, 8, 0); - image->data = (char *)gmalloc(bh * image->bytes_per_line); - - // if the transform is anything other than a 0/90/180/270 degree - // rotation/flip, or if there is color key masking, read the - // backgound pixmap to fill in the corners - if (!((ulx == llx && uly == ury) || - (uly == lly && ulx == urx)) || - maskColors) { - XGetSubImage(display, pixmap, cx0, cy0, cw, ch, (1 << depth) - 1, ZPixmap, - image, cx1, cy1); - } - - // allocate error diffusion accumulators - if (dither) { - errDown0 = (GfxRGB *)gmalloc((scaledWidth + 2) * sizeof(GfxRGB)); - errDown1 = (GfxRGB *)gmalloc((scaledWidth + 2) * sizeof(GfxRGB)); - for (j = 0; j < scaledWidth + 2; ++j) { - errDown0[j].r = errDown0[j].g = errDown0[j].b = 0; - errDown1[j].r = errDown1[j].g = errDown1[j].b = 0; - } - } else { - errDown0 = errDown1 = NULL; - } - - // optimize the one-bit-deep image case - if (oneBitMode) { - pixBuf2[0] = 0; - colorMap->getRGB(pixBuf2, &oneBitRGB[0]); - pixBuf2[0] = 1; - colorMap->getRGB(pixBuf2, &oneBitRGB[1]); - } - - // initialize the image stream - imgStr = new ImageStream(str, width, nComps, nBits); - imgStr->reset(); - - // init y scale Bresenham - yt = 0; - lastYStep = 1; - - for (y = 0; y < scaledHeight; ++y) { - - // initialize error diffusion accumulators - if (dither) { - errDownTmp = errDown0; - errDown0 = errDown1; - errDown1 = errDownTmp; - for (j = 0; j < scaledWidth + 2; ++j) { - errDown1[j].r = errDown1[j].g = errDown1[j].b = 0; - } - errRight.r = errRight.g = errRight.b = 0; - } - - // y scale Bresenham - yStep = yp; - yt += yq; - if (yt >= scaledHeight) { - yt -= scaledHeight; - ++yStep; - } - - // read row(s) from image - n = (yp > 0) ? yStep : lastYStep; - if (n > 0) { - if (oneBitMode) { - p1 = pixBuf1; - for (i = 0; i < n; ++i) { - p2 = imgStr->getLine(); - memcpy(p1, p2, width); - p1 += width; - } - } else { - p = pixBuf; - q = alphaBuf; - for (i = 0; i < n; ++i) { - p2 = imgStr->getLine(); - for (j = 0; j < width; ++j) { - colorMap->getRGB(p2, p); - ++p; - if (q) { - *q = 1; - for (k = 0; k < nComps; ++k) { - if (p2[k] < maskColors[2*k] || - p2[k] > maskColors[2*k+1]) { - *q = 0; - break; - } - } - ++q; - } - p2 += nComps; - } - } - } - } - lastYStep = yStep; - - // init x scale Bresenham - xt = 0; - xSrc = 0; - - for (x = 0; x < scaledWidth; ++x) { - - // x scale Bresenham - xStep = xp; - xt += xq; - if (xt >= scaledWidth) { - xt -= scaledWidth; - ++xStep; - } - - // x shear - x1 = xSign * x + xoutRound(xShear * ySign * y); - - // y shear - y1 = ySign * y + xoutRound(yShear * x1); - - // rotation - if (rot) { - x2 = y1; - y2 = -x1; - } else { - x2 = x1; - y2 = y1; - } - - // compute the filtered pixel at (x,y) after the - // x and y scaling operations - n = yStep > 0 ? yStep : 1; - m = xStep > 0 ? xStep : 1; - if (oneBitMode) { - p1 = pixBuf1 + xSrc; - k = 0; - for (i = 0; i < n; ++i) { - for (j = 0; j < m; ++j) { - k += *p1++; - } - p1 += width - m; - } - mul = (double)k / (double)(n * m); - r0 = mul * oneBitRGB[1].r + (1 - mul) * oneBitRGB[0].r; - g0 = mul * oneBitRGB[1].g + (1 - mul) * oneBitRGB[0].g; - b0 = mul * oneBitRGB[1].b + (1 - mul) * oneBitRGB[0].b; - alpha = 0; - } else { - p = pixBuf + xSrc; - q = alphaBuf ? alphaBuf + xSrc : (Guchar *)NULL; - alpha = 0; - r0 = g0 = b0 = 0; - for (i = 0; i < n; ++i) { - for (j = 0; j < m; ++j) { - r0 += p->r; - g0 += p->g; - b0 += p->b; - ++p; - if (q) { - alpha += *q++; - } - } - p += width - m; - } - mul = 1 / (double)(n * m); - r0 *= mul; - g0 *= mul; - b0 *= mul; - alpha *= mul; - } - - // x scale Bresenham - xSrc += xStep; - - // compute pixel - if (dither) { - color2.r = r0 + errRight.r + errDown0[x + 1].r; - if (color2.r > 1) { - color3.r = 1; - } else if (color2.r < 0) { - color3.r = 0; - } else { - color3.r = color2.r; - } - color2.g = g0 + errRight.g + errDown0[x + 1].g; - if (color2.g > 1) { - color3.g = 1; - } else if (color2.g < 0) { - color3.g = 0; - } else { - color3.g = color2.g; - } - color2.b = b0 + errRight.b + errDown0[x + 1].b; - if (color2.b > 1) { - color3.b = 1; - } else if (color2.b < 0) { - color3.b = 0; - } else { - color3.b = color2.b; - } - pix = findColor(&color3, &actual); - err.r = (color2.r - actual.r) / 16; - err.g = (color2.g - actual.g) / 16; - err.b = (color2.b - actual.b) / 16; - errRight.r = 7 * err.r; - errRight.g = 7 * err.g; - errRight.b = 7 * err.b; - errDown1[x].r += 3 * err.r; - errDown1[x].g += 3 * err.g; - errDown1[x].b += 3 * err.b; - errDown1[x + 1].r += 5 * err.r; - errDown1[x + 1].g += 5 * err.g; - errDown1[x + 1].b += 5 * err.b; - errDown1[x + 2].r = err.r; - errDown1[x + 2].g = err.g; - errDown1[x + 2].b = err.b; - } else { - color2.r = r0; - color2.g = g0; - color2.b = b0; - pix = findColor(&color2, &actual); - } - - // set pixel - //~ this should do a blend when 0 < alpha < 1 - if (alpha < 0.75) { - XPutPixel(image, tx + x2 - bx0, ty + y2 - by0, pix); - } - } - } - - // blit the image into the pixmap - XPutImage(display, pixmap, fillGC, image, cx1, cy1, cx0, cy0, cw, ch); - - // free memory - delete imgStr; - if (oneBitMode) { - gfree(pixBuf1); - } else { - gfree(pixBuf); - } - if (maskColors) { - gfree(alphaBuf); - } - gfree(image->data); - image->data = NULL; - XDestroyImage(image); - gfree(errDown0); - gfree(errDown1); -} - -GBool XOutputDev::findText(Unicode *s, int len, - GBool startAtTop, GBool stopAtBottom, - GBool startAtLast, GBool stopAtLast, - int *xMin, int *yMin, - int *xMax, int *yMax) { - double xMin1, yMin1, xMax1, yMax1; - - xMin1 = (double)*xMin; - yMin1 = (double)*yMin; - xMax1 = (double)*xMax; - yMax1 = (double)*yMax; - if (text->findText(s, len, startAtTop, stopAtBottom, - startAtLast, stopAtLast, - &xMin1, &yMin1, &xMax1, &yMax1)) { - *xMin = xoutRound(xMin1); - *xMax = xoutRound(xMax1); - *yMin = xoutRound(yMin1); - *yMax = xoutRound(yMax1); - return gTrue; - } - return gFalse; -} - -GString *XOutputDev::getText(int xMin, int yMin, int xMax, int yMax) { - return text->getText((double)xMin, (double)yMin, - (double)xMax, (double)yMax); -} diff --git a/pdf/xpdf/XOutputDev.h b/pdf/xpdf/XOutputDev.h deleted file mode 100644 index 3efa1dd..0000000 --- a/pdf/xpdf/XOutputDev.h +++ /dev/null @@ -1,680 +0,0 @@ -//======================================================================== -// -// XOutputDev.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef XOUTPUTDEV_H -#define XOUTPUTDEV_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include -#include -#include "config.h" -#include "Object.h" -#include "CharTypes.h" -#include "GlobalParams.h" -#include "OutputDev.h" - -class GString; -class GList; -struct GfxRGB; -class GfxFont; -class GfxPath; -class GfxSubpath; -class TextPage; -class XOutputFontCache; -struct T3FontCacheTag; -class T3FontCache; -struct T3GlyphStack; -class XOutputDev; -class Link; -class Catalog; -class DisplayFontParam; -class UnicodeMap; -class CharCodeToUnicode; - -#if HAVE_T1LIB_H -class T1FontEngine; -class T1FontFile; -class T1Font; -#endif - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -class FTFontEngine; -class FTFontFile; -class FTFont; -#endif - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -class TTFontEngine; -class TTFontFile; -class TTFont; -#endif - -//------------------------------------------------------------------------ -// Constants -//------------------------------------------------------------------------ - -#define maxRGBCube 7 // max size of RGB color cube - -#define numTmpPoints 256 // number of XPoints in temporary array -#define numTmpSubpaths 16 // number of elements in temporary arrays - // for fill/clip - -//------------------------------------------------------------------------ -// Misc types -//------------------------------------------------------------------------ - -struct BoundingRect { - short xMin, xMax; // min/max x values - short yMin, yMax; // min/max y values -}; - -//------------------------------------------------------------------------ -// XOutputFont -//------------------------------------------------------------------------ - -class XOutputFont { -public: - - XOutputFont(Ref *idA, double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA, - double m11A, double m12A, double m21A, double m22A, - Display *displayA, XOutputDev *xOutA); - - virtual ~XOutputFont(); - - // Does this font match the ID and transform? - GBool matches(Ref *idA, double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA) - { return id.num == idA->num && id.gen == idA->gen && - m11Orig == m11OrigA && m12Orig == m12OrigA && - m21Orig == m21OrigA && m22Orig == m22OrigA; } - - // Was font created successfully? - virtual GBool isOk() = 0; - - // Update with this font. - virtual void updateGC(GC gc) = 0; - - // Draw character / at , (in device space). - virtual void drawChar(GfxState *state, Pixmap pixmap, int w, int h, - GC gc, GfxRGB *rgb, - double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen) = 0; - - // Returns true if this XOutputFont subclass provides the - // getCharPath function. - virtual GBool hasGetCharPath() { return gFalse; } - - // Add the character outline for / to the current path. - virtual void getCharPath(GfxState *state, - CharCode c, Unicode *u, int ulen); - -protected: - - Ref id; // font ID - double m11Orig, m12Orig, // original transform matrix - m21Orig, m22Orig; - double m11, m12, m21, m22; // actual transform matrix (possibly - // modified for font substitution) - Display *display; // X display - XOutputDev *xOut; -}; - -#if HAVE_T1LIB_H -//------------------------------------------------------------------------ -// XOutputT1Font -//------------------------------------------------------------------------ - -class XOutputT1Font: public XOutputFont { -public: - - XOutputT1Font(Ref *idA, T1FontFile *fontFileA, - double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA, - double m11A, double m12A, - double m21A, double m22A, - Display *displayA, XOutputDev *xOutA); - - virtual ~XOutputT1Font(); - - // Was font created successfully? - virtual GBool isOk(); - - // Update with this font. - virtual void updateGC(GC gc); - - // Draw character / at ,. - virtual void drawChar(GfxState *state, Pixmap pixmap, int w, int h, - GC gc, GfxRGB *rgb, - double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen); - - // Returns true if this XOutputFont subclass provides the - // getCharPath function. - virtual GBool hasGetCharPath() { return gTrue; } - - // Add the character outline for / to the current path. - virtual void getCharPath(GfxState *state, - CharCode c, Unicode *u, int ulen); - -private: - - T1FontFile *fontFile; - T1Font *font; -}; -#endif // HAVE_T1LIB_H - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -//------------------------------------------------------------------------ -// XOutputFTFont -//------------------------------------------------------------------------ - -class XOutputFTFont: public XOutputFont { -public: - - XOutputFTFont(Ref *idA, FTFontFile *fontFileA, - double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA, - double m11A, double m12A, - double m21A, double m22A, - Display *displayA, XOutputDev *xOutA); - - virtual ~XOutputFTFont(); - - // Was font created successfully? - virtual GBool isOk(); - - // Update with this font. - virtual void updateGC(GC gc); - - // Draw character / at ,. - virtual void drawChar(GfxState *state, Pixmap pixmap, int w, int h, - GC gc, GfxRGB *rgb, - double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen); - - // Returns true if this XOutputFont subclass provides the - // getCharPath function. - virtual GBool hasGetCharPath() { return gTrue; } - - // Add the character outline for / to the current path. - virtual void getCharPath(GfxState *state, - CharCode c, Unicode *u, int ulen); - -private: - - FTFontFile *fontFile; - FTFont *font; -}; -#endif // FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -//------------------------------------------------------------------------ -// XOutputTTFont -//------------------------------------------------------------------------ - -class XOutputTTFont: public XOutputFont { -public: - - XOutputTTFont(Ref *idA, TTFontFile *fontFileA, - double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA, - double m11A, double m12A, - double m21A, double m22A, - Display *displayA, XOutputDev *xOutA); - - virtual ~XOutputTTFont(); - - // Was font created successfully? - virtual GBool isOk(); - - // Update with this font. - virtual void updateGC(GC gc); - - // Draw character / at ,. - virtual void drawChar(GfxState *state, Pixmap pixmap, int w, int h, - GC gc, GfxRGB *rgb, - double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen); - -private: - - TTFontFile *fontFile; - TTFont *font; -}; -#endif // !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - -//------------------------------------------------------------------------ -// XOutputServer8BitFont -//------------------------------------------------------------------------ - -class XOutputServer8BitFont: public XOutputFont { -public: - - XOutputServer8BitFont(Ref *idA, GString *xlfdFmt, - UnicodeMap *xUMapA, CharCodeToUnicode *fontUMap, - double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA, - double m11A, double m12A, double m21A, double m22A, - Display *displayA, XOutputDev *xOutA); - - virtual ~XOutputServer8BitFont(); - - // Was font created successfully? - virtual GBool isOk(); - - // Update with this font. - virtual void updateGC(GC gc); - - // Draw character / at ,. - virtual void drawChar(GfxState *state, Pixmap pixmap, int w, int h, - GC gc, GfxRGB *rgb, - double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen); - -private: - - XFontStruct *xFont; // the X font - Gushort map[256]; // forward map (char code -> X font code) - UnicodeMap *xUMap; -}; - -//------------------------------------------------------------------------ -// XOutputServer16BitFont -//------------------------------------------------------------------------ - -class XOutputServer16BitFont: public XOutputFont { -public: - - XOutputServer16BitFont(Ref *idA, GString *xlfdFmt, - UnicodeMap *xUMapA, CharCodeToUnicode *fontUMap, - double m11OrigA, double m12OrigA, - double m21OrigA, double m22OrigA, - double m11A, double m12A, double m21A, double m22A, - Display *displayA, XOutputDev *xOutA); - - virtual ~XOutputServer16BitFont(); - - // Was font created successfully? - virtual GBool isOk(); - - // Update with this font. - virtual void updateGC(GC gc); - - // Draw character / at ,. - virtual void drawChar(GfxState *state, Pixmap pixmap, int w, int h, - GC gc, GfxRGB *rgb, - double x, double y, double dx, double dy, - CharCode c, Unicode *u, int uLen); - -private: - - XFontStruct *xFont; // the X font - UnicodeMap *xUMap; -}; - -//------------------------------------------------------------------------ -// XOutputFontCache -//------------------------------------------------------------------------ - -#if HAVE_T1LIB_H -class XOutputT1FontFile { -public: - XOutputT1FontFile(int numA, int genA, GBool substA, - T1FontFile *fontFileA, GString *tmpFileNameA) - { num = numA; gen = genA; subst = substA; - fontFile = fontFileA; tmpFileName = tmpFileNameA; } - ~XOutputT1FontFile(); - int num, gen; - GBool subst; - T1FontFile *fontFile; - GString *tmpFileName; -}; -#endif - -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -class XOutputFTFontFile { -public: - XOutputFTFontFile(int numA, int genA, GBool substA, - FTFontFile *fontFileA, GString *tmpFileNameA) - { num = numA; gen = genA; subst = substA; - fontFile = fontFileA; tmpFileName = tmpFileNameA; } - ~XOutputFTFontFile(); - int num, gen; - GBool subst; - FTFontFile *fontFile; - GString *tmpFileName; -}; -#endif - -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) -class XOutputTTFontFile { -public: - XOutputTTFontFile(int numA, int genA, GBool substA, - TTFontFile *fontFileA, GString *tmpFileNameA) - { num = numA; gen = genA; subst = substA; - fontFile = fontFileA; tmpFileName = tmpFileNameA; } - ~XOutputTTFontFile(); - int num, gen; - GBool subst; - TTFontFile *fontFile; - GString *tmpFileName; -}; -#endif - -class XOutputFontCache { -public: - - // Constructor. - XOutputFontCache(Display *displayA, Guint depthA, - XOutputDev *xOutA, - FontRastControl t1libControlA, - FontRastControl freetypeControlA); - - // Destructor. - ~XOutputFontCache(); - - // Initialize (or re-initialize) the font cache for a new document. - void startDoc(int screenNum, Visual *visual, - Colormap colormap, GBool trueColor, - int rMul, int gMul, int bMul, - int rShift, int gShift, int bShift, - Gulong *colors, int numColors); - - // Get a font. This creates a new font if necessary. - XOutputFont *getFont(XRef *xref, GfxFont *gfxFont, double m11, double m12, - double m21, double m22); - -private: - - void delFonts(); - void clear(); - XOutputFont *tryGetFont(XRef *xref, DisplayFontParam *dfp, GfxFont *gfxFont, - double m11Orig, double m12Orig, - double m21Orig, double m22Orig, - double m11, double m12, double m21, double m22, - GBool subst); -#if HAVE_T1LIB_H - XOutputFont *tryGetT1Font(XRef *xref, GfxFont *gfxFont, - double m11, double m12, double m21, double m22); - XOutputFont *tryGetT1FontFromFile(XRef *xref, GString *fileName, - GBool deleteFile, GfxFont *gfxFont, - double m11Orig, double m12Orig, - double m21Orig, double m22Orig, - double m11, double m12, - double m21, double m22, GBool subst); -#endif -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - XOutputFont *tryGetFTFont(XRef *xref, GfxFont *gfxFont, - double m11, double m12, double m21, double m22); - XOutputFont *tryGetFTFontFromFile(XRef *xref, GString *fileName, - GBool deleteFile, GfxFont *gfxFont, - double m11Orig, double m12Orig, - double m21Orig, double m22Orig, - double m11, double m12, - double m21, double m22, - GBool embedded, GBool subst); -#endif -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - XOutputFont *tryGetTTFont(XRef *xref, GfxFont *gfxFont, - double m11, double m12, double m21, double m22); - XOutputFont *tryGetTTFontFromFile(XRef *xref, GString *fileName, - GBool deleteFile, GfxFont *gfxFont, - double m11Orig, double m12Orig, - double m21Orig, double m22Orig, - double m11, double m12, - double m21, double m22, GBool subst); -#endif - XOutputFont *tryGetServerFont(GString *xlfd, GString *encodingName, - GfxFont *gfxFont, - double m11Orig, double m12Orig, - double m21Orig, double m22Orig, - double m11, double m12, - double m21, double m22); - - Display *display; // X display pointer - XOutputDev *xOut; - Guint depth; // pixmap depth - - XOutputFont * - fonts[xOutFontCacheSize]; - int nFonts; - -#if HAVE_T1LIB_H - FontRastControl t1libControl; // t1lib settings - T1FontEngine *t1Engine; // Type 1 font engine - GList *t1FontFiles; // list of Type 1 font files - // [XOutputT1FontFile] -#endif - -#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H - FontRastControl // FreeType settings - freetypeControl; -#endif -#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - FTFontEngine *ftEngine; // FreeType font engine - GList *ftFontFiles; // list of FreeType font files - // [XOutputFTFontFile] -#endif -#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H) - TTFontEngine *ttEngine; // TrueType font engine - GList *ttFontFiles; // list of TrueType font files - // [XOutputTTFontFile] -#endif -}; - -//------------------------------------------------------------------------ -// XOutputState -//------------------------------------------------------------------------ - -struct XOutputState { - GC strokeGC; - GC fillGC; - Region clipRegion; - XOutputState *next; -}; - -//------------------------------------------------------------------------ -// XOutputDev -//------------------------------------------------------------------------ - -class XOutputDev: public OutputDev { -public: - - // Constructor. - XOutputDev(Display *displayA, int screenNumA, - Visual *visualA, Colormap colormapA, - GBool reverseVideoA, unsigned long paperColorA, - GBool installCmap, int rgbCubeSize, - int forceDepth = 0); - - // Destructor. - virtual ~XOutputDev(); - - //---- get info about output device - - // Does this device use upside-down coordinates? - // (Upside-down means (0,0) is the top left corner of the page.) - virtual GBool upsideDown() { return gTrue; } - - // Does this device use drawChar() or drawString()? - virtual GBool useDrawChar() { return gTrue; } - - // Does this device use beginType3Char/endType3Char? Otherwise, - // text in Type 3 fonts will be drawn with drawChar/drawString. - virtual GBool interpretType3Chars() { return gTrue; } - - //----- initialization and control - - // Start a page. - virtual void startPage(int pageNum, GfxState *state); - - // End a page. - virtual void endPage(); - - //----- link borders - virtual void drawLink(Link *link, Catalog *catalog); - - //----- save/restore graphics state - virtual void saveState(GfxState *state); - virtual void restoreState(GfxState *state); - - //----- update graphics state - virtual void updateAll(GfxState *state); - virtual void updateCTM(GfxState *state, double m11, double m12, - double m21, double m22, double m31, double m32); - virtual void updateLineDash(GfxState *state); - virtual void updateFlatness(GfxState *state); - virtual void updateLineJoin(GfxState *state); - virtual void updateLineCap(GfxState *state); - virtual void updateMiterLimit(GfxState *state); - virtual void updateLineWidth(GfxState *state); - virtual void updateFillColor(GfxState *state); - virtual void updateStrokeColor(GfxState *state); - - //----- update text state - virtual void updateFont(GfxState *state); - - //----- path painting - virtual void stroke(GfxState *state); - virtual void fill(GfxState *state); - virtual void eoFill(GfxState *state); - - //----- path clipping - virtual void clip(GfxState *state); - virtual void eoClip(GfxState *state); - - //----- text drawing - virtual void beginString(GfxState *state, GString *s); - virtual void endString(GfxState *state); - virtual void drawChar(GfxState *state, double x, double y, - double dx, double dy, - double originX, double originY, - CharCode code, Unicode *u, int uLen); - virtual GBool beginType3Char(GfxState *state, - CharCode code, Unicode *u, int uLen); - virtual void endType3Char(GfxState *state); - virtual void endTextObject(GfxState *state); - - //----- image drawing - virtual void drawImageMask(GfxState *state, Object *ref, Stream *str, - int width, int height, GBool invert, - GBool inlineImg); - virtual void drawImage(GfxState *state, Object *ref, Stream *str, - int width, int height, GfxImageColorMap *colorMap, - int *maskColors, GBool inlineImg); - - //----- Type 3 font operators - virtual void type3D0(GfxState *state, double wx, double wy); - virtual void type3D1(GfxState *state, double wx, double wy, - double llx, double lly, double urx, double ury); - - //----- special access - - // Called to indicate that a new PDF document has been loaded. - void startDoc(XRef *xrefA); - - // Find a string. If is true, starts looking at the - // top of the page; else if is true, starts looking - // immediately after the last find result; else starts looking at - // ,. If is true, stops looking at the - // bottom of the page; else if is true, stops looking - // just before the last find result; else stops looking at - // ,. - GBool findText(Unicode *s, int len, - GBool startAtTop, GBool stopAtBottom, - GBool startAtLast, GBool stopAtLast, - int *xMin, int *yMin, - int *xMax, int *yMax); - - // Get the text which is inside the specified rectangle. - GString *getText(int xMin, int yMin, int xMax, int yMax); - - GBool isReverseVideo() { return reverseVideo; } - - // Update pixmap ID after a page change. - void setPixmap(Pixmap pixmapA, int pixmapWA, int pixmapHA) - { pixmap = pixmapA; pixmapW = pixmapWA; pixmapH = pixmapHA; } - - // Get the off-screen pixmap, its size, various display info. - Pixmap getPixmap() { return pixmap; } - int getPixmapWidth() { return pixmapW; } - int getPixmapHeight() { return pixmapH; } - Display *getDisplay() { return display; } - Guint getDepth() { return depth; } - - Gulong findColor(GfxRGB *rgb); - -private: - - XRef *xref; // the xref table for this PDF file - Display *display; // X display pointer - int screenNum; // X screen number - Pixmap pixmap; // pixmap to draw into - int pixmapW, pixmapH; // size of pixmap - Guint depth; // pixmap depth - Visual *visual; // X visual - Colormap colormap; // X colormap - int flatness; // line flatness - GC paperGC; // GC for background - GC strokeGC; // GC with stroke color - GC fillGC; // GC with fill color - Region clipRegion; // clipping region - GBool trueColor; // set if using a TrueColor visual - int rMul, gMul, bMul; // RGB multipliers (for TrueColor) - int rShift, gShift, bShift; // RGB shifts (for TrueColor) - Gulong // color cube - colors[maxRGBCube * maxRGBCube * maxRGBCube]; - unsigned long paperColor; // paper color (pixel value) - int numColors; // size of color cube - double redMap[256]; // map pixel (from color cube) to red value - GBool reverseVideo; // reverse video mode - XPoint // temporary points array - tmpPoints[numTmpPoints]; - int // temporary arrays for fill/clip - tmpLengths[numTmpSubpaths]; - BoundingRect - tmpRects[numTmpSubpaths]; - GfxFont *gfxFont; // current PDF font - XOutputFont *font; // current font - GBool needFontUpdate; // set when the font needs to be updated - XOutputFontCache *fontCache; // font cache - T3FontCache * // Type 3 font cache - t3FontCache[xOutT3FontCacheSize]; - int nT3Fonts; // number of valid entries in t3FontCache - T3GlyphStack *t3GlyphStack; // Type 3 glyph context stack - GfxPath *textClipPath; // text outline clipping path - XOutputState *save; // stack of saved states - - TextPage *text; // text from the current page - - void updateLineAttrs(GfxState *state, GBool updateDash); - void doFill(GfxState *state, int rule); - void doClip(GfxState *state, GfxPath *path, int rule); - int convertPath(GfxState *state, GfxPath *path, - XPoint **points, int *size, - int *numPoints, int **lengths, GBool fillHack); - void convertSubpath(GfxState *state, GfxSubpath *subpath, - XPoint **points, int *size, int *n); - void doCurve(XPoint **points, int *size, int *k, - double x0, double y0, double x1, double y1, - double x2, double y2, double x3, double y3); - void addPoint(XPoint **points, int *size, int *k, int x, int y); - void drawType3Glyph(T3FontCache *t3Font, - T3FontCacheTag *tag, Guchar *data, - double x, double y, GfxRGB *color); - Gulong findColor(GfxRGB *x, GfxRGB *actual); -}; - -#endif diff --git a/pdf/xpdf/XPixmapOutputDev.cc b/pdf/xpdf/XPixmapOutputDev.cc deleted file mode 100644 index d55b2d2..0000000 --- a/pdf/xpdf/XPixmapOutputDev.cc +++ /dev/null @@ -1,84 +0,0 @@ -//======================================================================== -// -// XPixmapOutputDev.cc -// -// Copyright 2002-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include "Object.h" -#include "GfxState.h" -#include "XPixmapOutputDev.h" - -//------------------------------------------------------------------------ - -#define xoutRound(x) ((int)(x + 0.5)) - -//------------------------------------------------------------------------ - -XPixmapOutputDev::XPixmapOutputDev(Display *displayA, int screenNumA, - Visual *visualA, Colormap colormapA, - GBool reverseVideoA, Gulong paperColorA, - GBool installCmapA, int rgbCubeSizeA, - GBool incrementalUpdateA, - void (*redrawCbkA)(void *data), - void *redrawCbkDataA): - XOutputDev(displayA, screenNumA, visualA, colormapA, - reverseVideoA, paperColorA, installCmapA, rgbCubeSizeA) -{ - incrementalUpdate = incrementalUpdateA; - redrawCbk = redrawCbkA; - redrawCbkData = redrawCbkDataA; -} - -XPixmapOutputDev::~XPixmapOutputDev() { - if (getPixmapWidth() > 0) { - XFreePixmap(getDisplay(), getPixmap()); - } -} - -void XPixmapOutputDev::clear() { - startDoc(NULL); - startPage(0, NULL); -} - -void XPixmapOutputDev::startPage(int pageNum, GfxState *state) { - int oldPixmapW, oldPixmapH, newPixmapW, newPixmapH; - - // resize the off-screen pixmap (if needed) - oldPixmapW = getPixmapWidth(); - oldPixmapH = getPixmapHeight(); - newPixmapW = xoutRound(state ? state->getPageWidth() : 1); - newPixmapH = xoutRound(state ? state->getPageHeight() : 1); - if (oldPixmapW == 0 || - newPixmapW != oldPixmapW || newPixmapH != oldPixmapH) { - if (oldPixmapW > 0) { - XFreePixmap(getDisplay(), getPixmap()); - } - setPixmap(XCreatePixmap(getDisplay(), win, newPixmapW, newPixmapH, - getDepth()), - newPixmapW, newPixmapH); - } - - XOutputDev::startPage(pageNum, state); -} - -void XPixmapOutputDev::endPage() { - if (!incrementalUpdate) { - (*redrawCbk)(redrawCbkData); - } - XOutputDev::endPage(); -} - -void XPixmapOutputDev::dump() { - if (incrementalUpdate) { - (*redrawCbk)(redrawCbkData); - } - XOutputDev::dump(); -} diff --git a/pdf/xpdf/XPixmapOutputDev.h b/pdf/xpdf/XPixmapOutputDev.h deleted file mode 100644 index 8b83167..0000000 --- a/pdf/xpdf/XPixmapOutputDev.h +++ /dev/null @@ -1,63 +0,0 @@ -//======================================================================== -// -// XPixmapOutputDev.h -// -// Copyright 2002-2003 Glyph & Cog, LLC -// -//======================================================================== - -#ifndef XPIXMAPOUTPUTDEV_H -#define XPIXMAPOUTPUTDEV_H - -#include - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include -#include "XOutputDev.h" - -//------------------------------------------------------------------------ - -class XPixmapOutputDev: public XOutputDev { -public: - - XPixmapOutputDev(Display *displayA, int screenNumA, - Visual *visualA, Colormap colormapA, - GBool reverseVideoA, Gulong paperColorA, - GBool installCmapA, int rgbCubeSizeA, - GBool incrementalUpdateA, - void (*redrawCbkA)(void *data), - void *redrawCbkDataA); - - ~XPixmapOutputDev(); - - //----- initialization and control - - // Start a page. - virtual void startPage(int pageNum, GfxState *state); - - // End a page. - virtual void endPage(); - - // Dump page contents to display. - virtual void dump(); - - //----- special access - - // Set the window - this is used only to create a compatible pixmap. - void setWindow(Window winA) { win = winA; } - - // Clear out the document (used when displaying an empty window). - void clear(); - -private: - - GBool incrementalUpdate; // incrementally update the display? - void (*redrawCbk)(void *data); - void *redrawCbkData; - Window win; -}; - -#endif diff --git a/pdf/xpdf/XRef.cc b/pdf/xpdf/XRef.cc index eca638d..e0d82d2 100644 --- a/pdf/xpdf/XRef.cc +++ b/pdf/xpdf/XRef.cc @@ -47,12 +47,148 @@ #endif //------------------------------------------------------------------------ +// ObjectStream +//------------------------------------------------------------------------ + +class ObjectStream { +public: + + // Create an object stream, using object number , + // generation 0. + ObjectStream(XRef *xref, int objStrNumA); + + ~ObjectStream(); + + // Return the object number of this object stream. + int getObjStrNum() { return objStrNum; } + + // Get the th object from this stream, which should be + // object number , generation 0. + Object *getObject(int objIdx, int objNum, Object *obj); + +private: + + int objStrNum; // object number of the object stream + int nObjects; // number of objects in the stream + Object *objs; // the objects (length = nObjects) + int *objNums; // the object numbers (length = nObjects) +}; + +ObjectStream::ObjectStream(XRef *xref, int objStrNumA) { + Stream *str; + Parser *parser; + int *offsets; + Object objStr, obj1, obj2; + int first, i; + + objStrNum = objStrNumA; + nObjects = 0; + objs = NULL; + objNums = NULL; + + if (!xref->fetch(objStrNum, 0, &objStr)->isStream()) { + goto err1; + } + + if (!objStr.streamGetDict()->lookup("N", &obj1)->isInt()) { + obj1.free(); + goto err1; + } + nObjects = obj1.getInt(); + obj1.free(); + if (nObjects == 0) { + goto err1; + } + + if (!objStr.streamGetDict()->lookup("First", &obj1)->isInt()) { + obj1.free(); + goto err1; + } + first = obj1.getInt(); + obj1.free(); + + objs = new Object[nObjects]; + objNums = (int *)gmalloc(nObjects * sizeof(int)); + offsets = (int *)gmalloc(nObjects * sizeof(int)); + + // parse the header: object numbers and offsets + objStr.streamReset(); + obj1.initNull(); + str = new EmbedStream(objStr.getStream(), &obj1, gTrue, first); + parser = new Parser(xref, new Lexer(xref, str)); + for (i = 0; i < nObjects; ++i) { + parser->getObj(&obj1); + parser->getObj(&obj2); + if (!obj1.isInt() || !obj2.isInt()) { + obj1.free(); + obj2.free(); + delete parser; + gfree(offsets); + goto err1; + } + objNums[i] = obj1.getInt(); + offsets[i] = obj2.getInt(); + obj1.free(); + obj2.free(); + } + while (str->getChar() != EOF) ; + delete parser; + + // skip to the first object - this shouldn't be necessary because + // the First key is supposed to be equal to offsets[0], but just in + // case... + for (i = first; i < offsets[0]; ++i) { + objStr.getStream()->getChar(); + } + + // parse the objects + for (i = 0; i < nObjects; ++i) { + obj1.initNull(); + if (i == nObjects - 1) { + str = new EmbedStream(objStr.getStream(), &obj1, gFalse, 0); + } else { + str = new EmbedStream(objStr.getStream(), &obj1, gTrue, + offsets[i+1] - offsets[i]); + } + parser = new Parser(xref, new Lexer(xref, str)); + parser->getObj(&objs[i]); + while (str->getChar() != EOF) ; + delete parser; + } + + gfree(offsets); + + err1: + objStr.free(); + return; +} + +ObjectStream::~ObjectStream() { + int i; + + if (objs) { + for (i = 0; i < nObjects; ++i) { + objs[i].free(); + } + delete[] objs; + } + gfree(objNums); +} + +Object *ObjectStream::getObject(int objIdx, int objNum, Object *obj) { + if (objIdx < 0 || objIdx >= nObjects || objNum != objNums[objIdx]) { + return obj->initNull(); + } + return objs[objIdx].copy(obj); +} + +//------------------------------------------------------------------------ // XRef //------------------------------------------------------------------------ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { Guint pos; - int i; + Object obj; ok = gTrue; errCode = errNone; @@ -60,35 +196,28 @@ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { entries = NULL; streamEnds = NULL; streamEndsLen = 0; + objStr = NULL; // read the trailer str = strA; start = str->getStart(); - pos = readTrailer(); + pos = getStartXref(); - // if there was a problem with the trailer, - // try to reconstruct the xref table + // if there was a problem with the 'startxref' position, try to + // reconstruct the xref table if (pos == 0) { if (!(ok = constructXRef())) { errCode = errDamaged; return; } - // trailer is ok - read the xref table + // read the xref table } else { - entries = (XRefEntry *)gmalloc(size * sizeof(XRefEntry)); - for (i = 0; i < size; ++i) { - entries[i].offset = 0xffffffff; - entries[i].used = gFalse; - } while (readXRef(&pos)) ; // if there was a problem with the xref table, // try to reconstruct it if (!ok) { - gfree(entries); - size = 0; - entries = NULL; if (!(ok = constructXRef())) { errCode = errDamaged; return; @@ -96,6 +225,20 @@ XRef::XRef(BaseStream *strA, GString *ownerPassword, GString *userPassword) { } } + // get the root dictionary (catalog) object + trailerDict.dictLookupNF("Root", &obj); + if (obj.isRef()) { + rootNum = obj.getRefNum(); + rootGen = obj.getRefGen(); + obj.free(); + } else { + obj.free(); + if (!(ok = constructXRef())) { + errCode = errDamaged; + return; + } + } + // now set the trailer dictionary's xref pointer so we can fetch // indirect objects from it trailerDict.getDict()->setXRef(this); @@ -117,19 +260,16 @@ XRef::~XRef() { if (streamEnds) { gfree(streamEnds); } + if (objStr) { + delete objStr; + } } -// Read startxref position, xref table size, and root. Returns -// first xref position. -Guint XRef::readTrailer() { - Parser *parser; - Object obj; +// Read the 'startxref' position. +Guint XRef::getStartXref() { char buf[xrefSearchSize+1]; - int n; - Guint pos, pos1; char *p; - int c; - int i; + int c, n, i; // read last xrefSearchSize bytes str->setPos(xrefSearchSize, -1); @@ -148,175 +288,126 @@ Guint XRef::readTrailer() { } } if (i < 0) { - goto err1; + return 0; } for (p = &buf[i+9]; isspace(*p); ++p) ; - pos = lastXRefPos = strToUnsigned(p); + lastXRefPos = strToUnsigned(p); - // find trailer dict by looking after first xref table - // (NB: we can't just use the trailer dict at the end of the file -- - // this won't work for linearized files.) - str->setPos(start + pos); - for (i = 0; i < 4; ++i) { - buf[i] = str->getChar(); - } - if (strncmp(buf, "xref", 4)) { - goto err1; - } - pos1 = pos + 4; - while (1) { - str->setPos(start + pos1); - for (i = 0; i < 35; ++i) { - if ((c = str->getChar()) == EOF) { - goto err1; - } - buf[i] = c; - } - if (!strncmp(buf, "trailer", 7)) { - break; - } - p = buf; - while (isspace(*p)) ++p; - while ('0' <= *p && *p <= '9') ++p; - while (isspace(*p)) ++p; - n = atoi(p); - while ('0' <= *p && *p <= '9') ++p; - while (isspace(*p)) ++p; - if (p == buf) { - goto err1; - } - pos1 += (p - buf) + n * 20; - } - pos1 += 7; + return lastXRefPos; +} + +// Read one xref table section. Also reads the associated trailer +// dictionary, and returns the prev pointer (if any). +GBool XRef::readXRef(Guint *pos) { + Parser *parser; + Object obj; + GBool more; - // read trailer dict + // start up a parser, parse one token obj.initNull(); parser = new Parser(NULL, new Lexer(NULL, - str->makeSubStream(start + pos1, gFalse, 0, &obj))); - parser->getObj(&trailerDict); - if (trailerDict.isDict()) { - trailerDict.dictLookupNF("Size", &obj); - if (obj.isInt()) { - size = obj.getInt(); - } else { - goto err3; + str->makeSubStream(start + *pos, gFalse, 0, &obj))); + parser->getObj(&obj); + + // parse an old-style xref table + if (obj.isCmd("xref")) { + obj.free(); + more = readXRefTable(parser, pos); + + // parse an xref stream + } else if (obj.isInt()) { + obj.free(); + if (!parser->getObj(&obj)->isInt()) { + goto err1; } obj.free(); - trailerDict.dictLookupNF("Root", &obj); - if (obj.isRef()) { - rootNum = obj.getRefNum(); - rootGen = obj.getRefGen(); - } else { - goto err3; + if (!parser->getObj(&obj)->isCmd("obj")) { + goto err1; + } + obj.free(); + if (!parser->getObj(&obj)->isStream()) { + goto err1; } + more = readXRefStream(obj.getStream(), pos); obj.free(); + } else { - goto err2; + goto err1; } - delete parser; - // return first xref position - return pos; + delete parser; + return more; - err3: + err1: obj.free(); - err2: - trailerDict.free(); delete parser; - err1: - size = 0; - return 0; + ok = gFalse; + return gFalse; } -// Read an xref table and the prev pointer from the trailer. -GBool XRef::readXRef(Guint *pos) { - Parser *parser; - Object obj, obj2; - char s[20]; +GBool XRef::readXRefTable(Parser *parser, Guint *pos) { + XRefEntry entry; GBool more; - int first, newSize, n, i, j; - int c; - - // seek to xref in stream - str->setPos(start + *pos); - - // make sure it's an xref table - while ((c = str->getChar()) != EOF && isspace(c)) ; - s[0] = (char)c; - s[1] = (char)str->getChar(); - s[2] = (char)str->getChar(); - s[3] = (char)str->getChar(); - if (!(s[0] == 'x' && s[1] == 'r' && s[2] == 'e' && s[3] == 'f')) { - goto err2; - } + Object obj, obj2; + Guint pos2; + int first, n, newSize, i; - // read xref while (1) { - while ((c = str->lookChar()) != EOF && isspace(c)) { - str->getChar(); - } - if (c == 't') { + parser->getObj(&obj); + if (obj.isCmd("trailer")) { + obj.free(); break; } - for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i) { - s[i] = (char)c; - } - if (i == 0) { - goto err2; - } - s[i] = '\0'; - first = atoi(s); - while ((c = str->lookChar()) != EOF && isspace(c)) { - str->getChar(); - } - for (i = 0; (c = str->getChar()) != EOF && isdigit(c) && i < 20; ++i) { - s[i] = (char)c; - } - if (i == 0) { - goto err2; + if (!obj.isInt()) { + goto err1; } - s[i] = '\0'; - n = atoi(s); - while ((c = str->lookChar()) != EOF && isspace(c)) { - str->getChar(); + first = obj.getInt(); + obj.free(); + if (!parser->getObj(&obj)->isInt()) { + goto err1; } - // check for buggy PDF files with an incorrect (too small) xref - // table size + n = obj.getInt(); + obj.free(); if (first + n > size) { - newSize = first + n; + for (newSize = size ? 2 * size : 1024; + first + n > newSize; + newSize <<= 1) ; entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; - entries[i].used = gFalse; + entries[i].type = xrefEntryFree; } size = newSize; } for (i = first; i < first + n; ++i) { - for (j = 0; j < 20; ++j) { - if ((c = str->getChar()) == EOF) { - goto err2; - } - s[j] = (char)c; + if (!parser->getObj(&obj)->isInt()) { + goto err1; + } + entry.offset = (Guint)obj.getInt(); + obj.free(); + if (!parser->getObj(&obj)->isInt()) { + goto err1; + } + entry.gen = obj.getInt(); + obj.free(); + parser->getObj(&obj); + if (obj.isCmd("n")) { + entry.type = xrefEntryUncompressed; + } else if (obj.isCmd("f")) { + entry.type = xrefEntryFree; + } else { + goto err1; } + obj.free(); if (entries[i].offset == 0xffffffff) { - s[10] = '\0'; - entries[i].offset = strToUnsigned(s); - s[16] = '\0'; - entries[i].gen = atoi(&s[11]); - if (s[17] == 'n') { - entries[i].used = gTrue; - } else if (s[17] == 'f') { - entries[i].used = gFalse; - } else { - goto err2; - } + entries[i] = entry; // PDF files of patents from the IBM Intellectual Property // Network have a bug: the xref table claims to start at 1 // instead of 0. if (i == 1 && first == 1 && entries[1].offset == 0 && entries[1].gen == 65535 && - !entries[1].used) { + entries[1].type == xrefEntryFree) { i = first = 0; entries[0] = entries[1]; entries[1].offset = 0xffffffff; @@ -325,20 +416,12 @@ GBool XRef::readXRef(Guint *pos) { } } - // read prev pointer from trailer dictionary - obj.initNull(); - parser = new Parser(NULL, - new Lexer(NULL, - str->makeSubStream(str->getPos(), gFalse, 0, &obj))); - parser->getObj(&obj); - if (!obj.isCmd("trailer")) { - goto err1; - } - obj.free(); - parser->getObj(&obj); - if (!obj.isDict()) { + // read the trailer dictionary + if (!parser->getObj(&obj)->isDict()) { goto err1; } + + // get the 'Prev' pointer obj.getDict()->lookupNF("Prev", &obj2); if (obj2.isInt()) { *pos = (Guint)obj2.getInt(); @@ -351,23 +434,185 @@ GBool XRef::readXRef(Guint *pos) { } else { more = gFalse; } - obj.free(); obj2.free(); - delete parser; + // save the first trailer dictionary + if (trailerDict.isNone()) { + obj.copy(&trailerDict); + } + + // check for an 'XRefStm' key + if (obj.getDict()->lookup("XRefStm", &obj2)->isInt()) { + pos2 = obj2.getInt(); + readXRef(&pos2); + if (!ok) { + goto err1; + } + } + obj2.free(); + + obj.free(); return more; err1: obj.free(); - err2: ok = gFalse; return gFalse; } +GBool XRef::readXRefStream(Stream *xrefStr, Guint *pos) { + Dict *dict; + int w[3]; + GBool more; + Object obj, obj2, idx; + int newSize, first, n, i; + + dict = xrefStr->getDict(); + + if (!dict->lookupNF("Size", &obj)->isInt()) { + goto err1; + } + newSize = obj.getInt(); + obj.free(); + if (newSize > size) { + entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); + for (i = size; i < newSize; ++i) { + entries[i].offset = 0xffffffff; + entries[i].type = xrefEntryFree; + } + size = newSize; + } + + if (!dict->lookupNF("W", &obj)->isArray() || + obj.arrayGetLength() < 3) { + goto err1; + } + for (i = 0; i < 3; ++i) { + if (!obj.arrayGet(i, &obj2)->isInt()) { + obj2.free(); + goto err1; + } + w[i] = obj2.getInt(); + obj2.free(); + } + obj.free(); + + xrefStr->reset(); + dict->lookupNF("Index", &idx); + if (idx.isArray()) { + for (i = 0; i+1 < idx.arrayGetLength(); i += 2) { + if (!idx.arrayGet(i, &obj)->isInt()) { + idx.free(); + goto err1; + } + first = obj.getInt(); + obj.free(); + if (!idx.arrayGet(i+1, &obj)->isInt()) { + idx.free(); + goto err1; + } + n = obj.getInt(); + obj.free(); + if (!readXRefStreamSection(xrefStr, w, first, n)) { + idx.free(); + goto err0; + } + } + } else { + if (!readXRefStreamSection(xrefStr, w, 0, size)) { + idx.free(); + goto err0; + } + } + idx.free(); + + dict->lookupNF("Prev", &obj); + if (obj.isInt()) { + *pos = (Guint)obj.getInt(); + more = gTrue; + } else { + more = gFalse; + } + obj.free(); + if (trailerDict.isNone()) { + trailerDict.initDict(dict); + } + + return more; + + err1: + obj.free(); + err0: + ok = gFalse; + return gFalse; +} + +GBool XRef::readXRefStreamSection(Stream *xrefStr, int *w, int first, int n) { + Guint offset; + int type, gen, c, newSize, i, j; + + if (first + n > size) { + for (newSize = size ? 2 * size : 1024; + first + n > newSize; + newSize <<= 1) ; + entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry)); + for (i = size; i < newSize; ++i) { + entries[i].offset = 0xffffffff; + entries[i].type = xrefEntryFree; + } + size = newSize; + } + for (i = first; i < first + n; ++i) { + if (w[0] == 0) { + type = 1; + } else { + for (type = 0, j = 0; j < w[0]; ++j) { + if ((c = xrefStr->getChar()) == EOF) { + return gFalse; + } + type = (type << 8) + c; + } + } + for (offset = 0, j = 0; j < w[1]; ++j) { + if ((c = xrefStr->getChar()) == EOF) { + return gFalse; + } + offset = (offset << 8) + c; + } + for (gen = 0, j = 0; j < w[2]; ++j) { + if ((c = xrefStr->getChar()) == EOF) { + return gFalse; + } + gen = (gen << 8) + c; + } + switch (type) { + case 0: + entries[i].offset = offset; + entries[i].gen = gen; + entries[i].type = xrefEntryFree; + break; + case 1: + entries[i].offset = offset; + entries[i].gen = gen; + entries[i].type = xrefEntryUncompressed; + break; + case 2: + entries[i].offset = offset; + entries[i].gen = gen; + entries[i].type = xrefEntryCompressed; + break; + default: + return gFalse; + } + } + + return gTrue; +} + // Attempt to construct an xref table for a damaged file. GBool XRef::constructXRef() { Parser *parser; - Object obj; + Object newTrailerDict, obj; char buf[256]; Guint pos; int num, gen; @@ -377,6 +622,10 @@ GBool XRef::constructXRef() { int i; GBool gotRoot; + gfree(entries); + size = 0; + entries = NULL; + error(0, "PDF file is damaged - attempting to reconstruct xref table..."); gotRoot = gFalse; streamEndsLen = streamEndsSize = 0; @@ -391,26 +640,25 @@ GBool XRef::constructXRef() { // got trailer dictionary if (!strncmp(p, "trailer", 7)) { - gotRoot = gFalse; obj.initNull(); parser = new Parser(NULL, new Lexer(NULL, str->makeSubStream(start + pos + 7, gFalse, 0, &obj))); - if (!trailerDict.isNone()) { - trailerDict.free(); - } - parser->getObj(&trailerDict); - if (trailerDict.isDict()) { - trailerDict.dictLookupNF("Root", &obj); + parser->getObj(&newTrailerDict); + if (newTrailerDict.isDict()) { + newTrailerDict.dictLookupNF("Root", &obj); if (obj.isRef()) { rootNum = obj.getRefNum(); rootGen = obj.getRefGen(); + if (!trailerDict.isNone()) { + trailerDict.free(); + } + newTrailerDict.copy(&trailerDict); gotRoot = gTrue; } obj.free(); - } else { - trailerDict.free(); } + newTrailerDict.free(); delete parser; // look for object @@ -439,14 +687,15 @@ GBool XRef::constructXRef() { grealloc(entries, newSize * sizeof(XRefEntry)); for (i = size; i < newSize; ++i) { entries[i].offset = 0xffffffff; - entries[i].used = gFalse; + entries[i].type = xrefEntryFree; } size = newSize; } - if (!entries[num].used || gen >= entries[num].gen) { + if (entries[num].type == xrefEntryFree || + gen >= entries[num].gen) { entries[num].offset = pos - start; entries[num].gen = gen; - entries[num].used = gTrue; + entries[num].type = xrefEntryUncompressed; } } } @@ -610,12 +859,16 @@ Object *XRef::fetch(int num, int gen, Object *obj) { // check for bogus ref - this can happen in corrupted PDF files if (num < 0 || num >= size) { - obj->initNull(); - return obj; + goto err; } e = &entries[num]; - if (e->gen == gen && e->offset != 0xffffffff) { + switch (e->type) { + + case xrefEntryUncompressed: + if (e->gen != gen) { + goto err; + } obj1.initNull(); parser = new Parser(this, new Lexer(this, @@ -623,26 +876,44 @@ Object *XRef::fetch(int num, int gen, Object *obj) { parser->getObj(&obj1); parser->getObj(&obj2); parser->getObj(&obj3); - if (obj1.isInt() && obj1.getInt() == num && - obj2.isInt() && obj2.getInt() == gen && - obj3.isCmd("obj")) { + if (!obj1.isInt() || obj1.getInt() != num || + !obj2.isInt() || obj2.getInt() != gen || + !obj3.isCmd("obj")) { + goto err; + } #ifndef NO_DECRYPTION - parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength, - num, gen); + parser->getObj(obj, encrypted ? fileKey : (Guchar *)NULL, keyLength, + num, gen); #else - parser->getObj(obj); + parser->getObj(obj); #endif - } else { - obj->initNull(); - } obj1.free(); obj2.free(); obj3.free(); delete parser; - } else { - obj->initNull(); + break; + + case xrefEntryCompressed: + if (gen != 0) { + goto err; + } + if (!objStr || objStr->getObjStrNum() != (int)e->offset) { + if (objStr) { + delete objStr; + } + objStr = new ObjectStream(this, e->offset); + } + objStr->getObject(e->gen, num, obj); + break; + + default: + goto err; } + return obj; + + err: + return obj->initNull(); } Object *XRef::getDocInfo(Object *obj) { diff --git a/pdf/xpdf/XRef.h b/pdf/xpdf/XRef.h index 3f5a598..bec487a 100644 --- a/pdf/xpdf/XRef.h +++ b/pdf/xpdf/XRef.h @@ -20,15 +20,23 @@ class Dict; class Stream; +class Parser; +class ObjectStream; //------------------------------------------------------------------------ // XRef //------------------------------------------------------------------------ +enum XRefEntryType { + xrefEntryFree, + xrefEntryUncompressed, + xrefEntryCompressed +}; + struct XRefEntry { Guint offset; int gen; - GBool used; + XRefEntryType type; }; class XRef { @@ -103,6 +111,7 @@ private: Guint *streamEnds; // 'endstream' positions - only used in // damaged files int streamEndsLen; // number of valid entries in streamEnds + ObjectStream *objStr; // cached object stream #ifndef NO_DECRYPTION GBool encrypted; // true if file is encrypted int encVersion; // encryption algorithm @@ -113,8 +122,11 @@ private: GBool ownerPasswordOk; // true if owner password is correct #endif - Guint readTrailer(); + Guint getStartXref(); GBool readXRef(Guint *pos); + GBool readXRefTable(Parser *parser, Guint *pos); + GBool readXRefStreamSection(Stream *xrefStr, int *w, int first, int n); + GBool readXRefStream(Stream *xrefStr, Guint *pos); GBool constructXRef(); GBool checkEncrypted(GString *ownerPassword, GString *userPassword); Guint strToUnsigned(char *s); diff --git a/pdf/xpdf/pdffonts.cc b/pdf/xpdf/pdffonts.cc index 2fcd1a8..2f17995 100644 --- a/pdf/xpdf/pdffonts.cc +++ b/pdf/xpdf/pdffonts.cc @@ -197,8 +197,9 @@ static void scanFonts(Dict *resDict, PDFDoc *doc) { } if (gfxFontDict) { for (i = 0; i < gfxFontDict->getNumFonts(); ++i) { - font = gfxFontDict->getFont(i); - scanFont(font, doc); + if ((font = gfxFontDict->getFont(i))) { + scanFont(font, doc); + } } delete gfxFontDict; } @@ -225,9 +226,9 @@ static void scanFonts(Dict *resDict, PDFDoc *doc) { static void scanFont(GfxFont *font, PDFDoc *doc) { Ref fontRef, embRef; - Object fontObj, nameObj, toUnicodeObj; + Object fontObj, toUnicodeObj; GString *name; - GBool subset, hasToUnicode; + GBool emb, subset, hasToUnicode; int i; fontRef = *font->getID(); @@ -242,6 +243,13 @@ static void scanFont(GfxFont *font, PDFDoc *doc) { // font name name = font->getOrigName(); + // check for an embedded font + if (font->getType() == fontType3) { + emb = gTrue; + } else { + emb = font->getEmbeddedFontID(&embRef); + } + // look for a ToUnicode map hasToUnicode = gFalse; if (doc->getXRef()->fetch(fontRef.num, fontRef.gen, &fontObj)->isDict()) { @@ -266,7 +274,7 @@ static void scanFont(GfxFont *font, PDFDoc *doc) { printf("%-36s %-12s %-3s %-3s %-3s", name ? name->getCString() : "[none]", fontTypeNames[font->getType()], - font->getEmbeddedFontID(&embRef) ? "yes" : "no", + emb ? "yes" : "no", subset ? "yes" : "no", hasToUnicode ? "yes" : "no"); if (fontRef.gen >= 100000) { diff --git a/pdf/xpdf/pdfimages.cc b/pdf/xpdf/pdfimages.cc index a661fb5..20e1add 100644 --- a/pdf/xpdf/pdfimages.cc +++ b/pdf/xpdf/pdfimages.cc @@ -134,7 +134,7 @@ int main(int argc, char *argv[]) { // write image files imgOut = new ImageOutputDev(imgRoot, dumpJPEG); if (imgOut->isOk()) { - doc->displayPages(imgOut, firstPage, lastPage, 72, 72, 0, gFalse); + doc->displayPages(imgOut, firstPage, lastPage, 72, 72, 0, gTrue, gFalse); } delete imgOut; diff --git a/pdf/xpdf/pdfinfo.cc b/pdf/xpdf/pdfinfo.cc index e29e673..4a50fee 100644 --- a/pdf/xpdf/pdfinfo.cc +++ b/pdf/xpdf/pdfinfo.cc @@ -33,9 +33,11 @@ static void printInfoString(Dict *infoDict, char *key, char *text, UnicodeMap *uMap); static void printInfoDate(Dict *infoDict, char *key, char *text); +static void printBox(char *text, PDFRectangle *box); static int firstPage = 1; static int lastPage = 0; +static GBool printBoxes = gFalse; static GBool printMetadata = gFalse; static char textEncName[128] = ""; static char ownerPassword[33] = "\001"; @@ -49,6 +51,8 @@ static ArgDesc argDesc[] = { "first page to convert"}, {"-l", argInt, &lastPage, 0, "last page to convert"}, + {"-box", argFlag, &printBoxes, 0, + "print the page bounding boxes"}, {"-meta", argFlag, &printMetadata, 0, "print the document metadata (XML)"}, {"-enc", argString, textEncName, sizeof(textEncName), @@ -77,7 +81,9 @@ int main(int argc, char *argv[]) { GString *fileName; GString *ownerPW, *userPW; UnicodeMap *uMap; + Page *page; Object info; + char buf[256]; double w, h, wISO, hISO; FILE *f; GString *metadata; @@ -211,6 +217,32 @@ int main(int argc, char *argv[]) { printf("\n"); } + // print the boxes + if (printBoxes) { + if (multiPage) { + for (pg = firstPage; pg <= lastPage; ++pg) { + page = doc->getCatalog()->getPage(pg); + sprintf(buf, "Page %4d MediaBox: ", pg); + printBox(buf, page->getMediaBox()); + sprintf(buf, "Page %4d CropBox: ", pg); + printBox(buf, page->getCropBox()); + sprintf(buf, "Page %4d BleedBox: ", pg); + printBox(buf, page->getBleedBox()); + sprintf(buf, "Page %4d TrimBox: ", pg); + printBox(buf, page->getTrimBox()); + sprintf(buf, "Page %4d ArtBox: ", pg); + printBox(buf, page->getArtBox()); + } + } else { + page = doc->getCatalog()->getPage(firstPage); + printBox("MediaBox: ", page->getMediaBox()); + printBox("CropBox: ", page->getCropBox()); + printBox("BleedBox: ", page->getBleedBox()); + printBox("TrimBox: ", page->getTrimBox()); + printBox("ArtBox: ", page->getArtBox()); + } + } + // print file size #ifdef VMS f = fopen(fileName->getCString(), "rb", "ctx=stm"); @@ -337,3 +369,8 @@ static void printInfoDate(Dict *infoDict, char *key, char *text) { } obj.free(); } + +static void printBox(char *text, PDFRectangle *box) { + printf("%s%8.2f %8.2f %8.2f %8.2f\n", + text, box->x1, box->y1, box->x2, box->y2); +} diff --git a/pdf/xpdf/pdftopbm.cc b/pdf/xpdf/pdftopbm.cc deleted file mode 100644 index a0d0af5..0000000 --- a/pdf/xpdf/pdftopbm.cc +++ /dev/null @@ -1,147 +0,0 @@ -//======================================================================== -// -// pdftopbm.cc -// -// Copyright 1998-2003 Glyph & Cog, LLC -// -//======================================================================== - -#include -#include -#include -#include -#include -#include "parseargs.h" -#include "GString.h" -#include "gmem.h" -#include "GlobalParams.h" -#include "Object.h" -#include "Stream.h" -#include "Array.h" -#include "Dict.h" -#include "XRef.h" -#include "Catalog.h" -#include "Page.h" -#include "PDFDoc.h" -#include "PBMOutputDev.h" -#include "Error.h" -#include "config.h" - -static int firstPage = 1; -static int lastPage = 0; -static int resolution = 150; -static char ownerPassword[33] = "\001"; -static char userPassword[33] = "\001"; -static GBool quiet = gFalse; -static char cfgFileName[256] = ""; -static GBool printVersion = gFalse; -static GBool printHelp = gFalse; - -static ArgDesc argDesc[] = { - {"-f", argInt, &firstPage, 0, - "first page to print"}, - {"-l", argInt, &lastPage, 0, - "last page to print"}, - {"-r", argInt, &resolution, 0, - "resolution, in DPI (default is 150)"}, - {"-opw", argString, ownerPassword, sizeof(ownerPassword), - "owner password (for encrypted files)"}, - {"-upw", argString, userPassword, sizeof(userPassword), - "user password (for encrypted files)"}, - {"-q", argFlag, &quiet, 0, - "don't print any messages or errors"}, - {"-cfg", argString, cfgFileName, sizeof(cfgFileName), - "configuration file to use in place of .xpdfrc"}, - {"-v", argFlag, &printVersion, 0, - "print copyright and version info"}, - {"-h", argFlag, &printHelp, 0, - "print usage information"}, - {"-help", argFlag, &printHelp, 0, - "print usage information"}, - {"--help", argFlag, &printHelp, 0, - "print usage information"}, - {"-?", argFlag, &printHelp, 0, - "print usage information"}, - {NULL} -}; - -int main(int argc, char *argv[]) { - PDFDoc *doc; - GString *fileName; - char *pbmRoot; - GString *ownerPW, *userPW; - PBMOutputDev *pbmOut; - GBool ok; - int exitCode; - - exitCode = 99; - - // parse args - ok = parseArgs(argDesc, &argc, argv); - if (!ok || argc != 3 || printVersion || printHelp) { - fprintf(stderr, "pdftopbm version %s\n", xpdfVersion); - fprintf(stderr, "%s\n", xpdfCopyright); - if (!printVersion) { - printUsage("pdftopbm", " ", argDesc); - } - goto err0; - } - fileName = new GString(argv[1]); - pbmRoot = argv[2]; - - // read config file - globalParams = new GlobalParams(cfgFileName); - if (quiet) { - globalParams->setErrQuiet(quiet); - } - - // open PDF file - if (ownerPassword[0] != '\001') { - ownerPW = new GString(ownerPassword); - } else { - ownerPW = NULL; - } - if (userPassword[0] != '\001') { - userPW = new GString(userPassword); - } else { - userPW = NULL; - } - doc = new PDFDoc(fileName, ownerPW, userPW); - if (userPW) { - delete userPW; - } - if (ownerPW) { - delete ownerPW; - } - if (!doc->isOk()) { - exitCode = 1; - goto err1; - } - - // get page range - if (firstPage < 1) - firstPage = 1; - if (lastPage < 1 || lastPage > doc->getNumPages()) - lastPage = doc->getNumPages(); - - // write PBM files - pbmOut = PBMOutputDev::makePBMOutputDev(NULL, pbmRoot); - pbmOut->startDoc(doc->getXRef()); - doc->displayPages(pbmOut, firstPage, lastPage, - resolution, resolution, 0, gFalse); - PBMOutputDev::killPBMOutputDev(pbmOut); - - exitCode = 0; - - // clean up - err1: - delete doc; - delete globalParams; - err0: - - // check for memory leaks - Object::memCheck(stderr); - gMemReport(stderr); - - return exitCode; -} diff --git a/pdf/xpdf/pdftops.cc b/pdf/xpdf/pdftops.cc index 247e455..3042006 100644 --- a/pdf/xpdf/pdftops.cc +++ b/pdf/xpdf/pdftops.cc @@ -47,6 +47,10 @@ static GBool noEmbedCIDTTFonts = gFalse; static char paperSize[15] = ""; static int paperWidth = 0; static int paperHeight = 0; +static GBool noCrop = gFalse; +static GBool expand = gFalse; +static GBool noShrink = gFalse; +static GBool noCenter = gFalse; static GBool duplex = gFalse; static char ownerPassword[33] = "\001"; static char userPassword[33] = "\001"; @@ -56,63 +60,71 @@ static GBool printVersion = gFalse; static GBool printHelp = gFalse; static ArgDesc argDesc[] = { - {"-f", argInt, &firstPage, 0, + {"-f", argInt, &firstPage, 0, "first page to print"}, - {"-l", argInt, &lastPage, 0, + {"-l", argInt, &lastPage, 0, "last page to print"}, - {"-level1", argFlag, &level1, 0, + {"-level1", argFlag, &level1, 0, "generate Level 1 PostScript"}, - {"-level1sep", argFlag, &level1Sep, 0, + {"-level1sep", argFlag, &level1Sep, 0, "generate Level 1 separable PostScript"}, - {"-level2", argFlag, &level2, 0, + {"-level2", argFlag, &level2, 0, "generate Level 2 PostScript"}, - {"-level2sep", argFlag, &level2Sep, 0, + {"-level2sep", argFlag, &level2Sep, 0, "generate Level 2 separable PostScript"}, - {"-level3", argFlag, &level3, 0, + {"-level3", argFlag, &level3, 0, "generate Level 3 PostScript"}, - {"-level3sep", argFlag, &level3Sep, 0, + {"-level3sep", argFlag, &level3Sep, 0, "generate Level 3 separable PostScript"}, - {"-eps", argFlag, &doEPS, 0, + {"-eps", argFlag, &doEPS, 0, "generate Encapsulated PostScript (EPS)"}, - {"-form", argFlag, &doForm, 0, + {"-form", argFlag, &doForm, 0, "generate a PostScript form"}, #if OPI_SUPPORT - {"-opi", argFlag, &doOPI, 0, + {"-opi", argFlag, &doOPI, 0, "generate OPI comments"}, #endif - {"-noembt1", argFlag, &noEmbedT1Fonts, 0, + {"-noembt1", argFlag, &noEmbedT1Fonts, 0, "don't embed Type 1 fonts"}, - {"-noembtt", argFlag, &noEmbedTTFonts, 0, + {"-noembtt", argFlag, &noEmbedTTFonts, 0, "don't embed TrueType fonts"}, - {"-noembcidps", argFlag, &noEmbedCIDPSFonts, 0, + {"-noembcidps", argFlag, &noEmbedCIDPSFonts, 0, "don't embed CID PostScript fonts"}, - {"-noembcidtt", argFlag, &noEmbedCIDTTFonts, 0, + {"-noembcidtt", argFlag, &noEmbedCIDTTFonts, 0, "don't embed CID TrueType fonts"}, - {"-paper", argString, paperSize, sizeof(paperSize), + {"-paper", argString, paperSize, sizeof(paperSize), "paper size (letter, legal, A4, A3, match)"}, - {"-paperw", argInt, &paperWidth, 0, + {"-paperw", argInt, &paperWidth, 0, "paper width, in points"}, - {"-paperh", argInt, &paperHeight, 0, + {"-paperh", argInt, &paperHeight, 0, "paper height, in points"}, - {"-duplex", argFlag, &duplex, 0, + {"-nocrop", argFlag, &noCrop, 0, + "don't crop pages to CropBox"}, + {"-expand", argFlag, &expand, 0, + "expand pages smaller than the paper size"}, + {"-noshrink", argFlag, &noShrink, 0, + "don't shrink pages larger than the paper size"}, + {"-nocenter", argFlag, &noCenter, 0, + "don't center pages smaller than the paper size"}, + {"-duplex", argFlag, &duplex, 0, "enable duplex printing"}, - {"-opw", argString, ownerPassword, sizeof(ownerPassword), + {"-opw", argString, ownerPassword, sizeof(ownerPassword), "owner password (for encrypted files)"}, - {"-upw", argString, userPassword, sizeof(userPassword), + {"-upw", argString, userPassword, sizeof(userPassword), "user password (for encrypted files)"}, - {"-q", argFlag, &quiet, 0, + {"-q", argFlag, &quiet, 0, "don't print any messages or errors"}, {"-cfg", argString, cfgFileName, sizeof(cfgFileName), "configuration file to use in place of .xpdfrc"}, - {"-v", argFlag, &printVersion, 0, + {"-v", argFlag, &printVersion, 0, "print copyright and version info"}, - {"-h", argFlag, &printHelp, 0, + {"-h", argFlag, &printHelp, 0, "print usage information"}, - {"-help", argFlag, &printHelp, 0, + {"-help", argFlag, &printHelp, 0, "print usage information"}, - {"--help", argFlag, &printHelp, 0, + {"--help", argFlag, &printHelp, 0, "print usage information"}, - {"-?", argFlag, &printHelp, 0, + {"-?", argFlag, &printHelp, 0, "print usage information"}, {NULL} }; @@ -192,6 +204,18 @@ int main(int argc, char *argv[]) { globalParams->setPSPaperHeight(paperHeight); } } + if (noCrop) { + globalParams->setPSCrop(gFalse); + } + if (expand) { + globalParams->setPSExpandSmaller(gTrue); + } + if (noShrink) { + globalParams->setPSShrinkLarger(gFalse); + } + if (noCenter) { + globalParams->setPSCenter(gFalse); + } if (duplex) { globalParams->setPSDuplex(duplex); } @@ -281,7 +305,8 @@ int main(int argc, char *argv[]) { psOut = new PSOutputDev(psFileName->getCString(), doc->getXRef(), doc->getCatalog(), firstPage, lastPage, mode); if (psOut->isOk()) { - doc->displayPages(psOut, firstPage, lastPage, 72, 72, 0, gFalse); + doc->displayPages(psOut, firstPage, lastPage, 72, 72, + 0, globalParams->getPSCrop(), gFalse); } else { delete psOut; exitCode = 2; diff --git a/pdf/xpdf/pdftotext.cc b/pdf/xpdf/pdftotext.cc index c6ad9c0..2de03e3 100644 --- a/pdf/xpdf/pdftotext.cc +++ b/pdf/xpdf/pdftotext.cc @@ -234,7 +234,7 @@ int main(int argc, char *argv[]) { textOut = new TextOutputDev(textFileName->getCString(), physLayout, rawOrder, htmlMeta); if (textOut->isOk()) { - doc->displayPages(textOut, firstPage, lastPage, 72, 72, 0, gFalse); + doc->displayPages(textOut, firstPage, lastPage, 72, 72, 0, gTrue, gFalse); } else { delete textOut; exitCode = 2; diff --git a/pdf/xpdf/vms_make.com b/pdf/xpdf/vms_make.com index 4a59bda..f4fb74a 100644 --- a/pdf/xpdf/vms_make.com +++ b/pdf/xpdf/vms_make.com @@ -18,9 +18,9 @@ $ COMMON_OBJS = "Annot.obj,Array.obj,BuiltinFont.obj," + - "CMap.obj,Decrypt.obj,Dict.obj,Error.obj," + - "FontEncodingTables.obj,FontFile.obj," + - "Function.obj,Gfx.obj,GfxFont.obj,GfxState.obj,"+ - - "GlobalParams.obj,JBIG2Stream.obj,Lexer.obj," + - - "Link.obj,NameToCharCode.obj,Object.obj,Outline.obj,"+ - - "OutputDev.obj,Page.obj,Parser.obj,PDFdoc.obj," + - + "GlobalParams.obj,JArithmeticDecoder.obj,JBIG2Stream.obj,"+ - + "Lexer.obj,Link.obj,NameToCharCode.obj,Object.obj,"+ - + "Outline.obj,OutputDev.obj,Page.obj,Parser.obj,PDFdoc.obj," + - "PDFDocEncoding.obj,PSTokenizer.obj,Stream.obj," + - "UnicodeMap.obj,UnicodeTypeTable.obj,XRef.obj" $ COMMON_LIBS = "[]common.olb/lib,[-.goo]libgoo.olb/lib" diff --git a/pdf/xpdf/xpdf.cc b/pdf/xpdf/xpdf.cc index bda355e..0824e4c 100644 --- a/pdf/xpdf/xpdf.cc +++ b/pdf/xpdf/xpdf.cc @@ -21,8 +21,9 @@ // command line options //------------------------------------------------------------------------ -static char t1libControlStr[16] = ""; -static char freetypeControlStr[16] = ""; +static char enableT1libStr[16] = ""; +static char enableFreeTypeStr[16] = ""; +static char antialiasStr[16] = ""; static char psFileArg[256]; static char paperSize[15] = ""; static int paperWidth = 0; @@ -61,13 +62,15 @@ static ArgDesc argDesc[] = { {"-z", argStringDummy, NULL, 0, "initial zoom level (percent, 'page', 'width')"}, #if HAVE_T1LIB_H - {"-t1lib", argString, t1libControlStr, sizeof(t1libControlStr), - "t1lib font rasterizer control: none, plain, low, high"}, + {"-t1lib", argString, enableT1libStr, sizeof(enableT1libStr), + "enable t1lib font rasterizer: yes, no"}, #endif #if HAVE_FREETYPE_FREETYPE_H | HAVE_FREETYPE_H - {"-freetype", argString, freetypeControlStr, sizeof(freetypeControlStr), - "FreeType font rasterizer control: none, plain, low, high"}, + {"-freetype", argString, enableFreeTypeStr, sizeof(enableFreeTypeStr), + "enable FreeType font rasterizer: yes, no"}, #endif + {"-aa", argString, antialiasStr, sizeof(antialiasStr), + "enable font anti-aliasing: yes, no"}, {"-ps", argString, psFileArg, sizeof(psFileArg), "default PostScript file name or command"}, {"-paper", argString, paperSize, sizeof(paperSize), @@ -131,9 +134,19 @@ int main(int argc, char *argv[]) { // parse args ok = parseArgs(argDesc, &argc, argv); + if (!ok || printVersion || printHelp) { + fprintf(stderr, "xpdf version %s\n", xpdfVersion); + fprintf(stderr, "%s\n", xpdfCopyright); + if (!printVersion) { + printUsage("xpdf", "[ [ | +]]", argDesc); + } + exitCode = 99; + goto done0; + } // read config file globalParams = new GlobalParams(cfgFileName); + globalParams->setupBaseFonts(NULL); if (psFileArg[0]) { globalParams->setPSFile(psFileArg); } @@ -160,16 +173,21 @@ int main(int argc, char *argv[]) { fprintf(stderr, "Bad '-eol' value on command line\n"); } } - if (t1libControlStr[0]) { - if (!globalParams->setT1libControl(t1libControlStr)) { + if (enableT1libStr[0]) { + if (!globalParams->setEnableT1lib(enableT1libStr)) { fprintf(stderr, "Bad '-t1lib' value on command line\n"); } } - if (freetypeControlStr[0]) { - if (!globalParams->setFreeTypeControl(freetypeControlStr)) { + if (enableFreeTypeStr[0]) { + if (!globalParams->setEnableFreeType(enableFreeTypeStr)) { fprintf(stderr, "Bad '-freetype' value on command line\n"); } } + if (antialiasStr[0]) { + if (!globalParams->setAntialias(antialiasStr)) { + fprintf(stderr, "Bad '-aa' value on command line\n"); + } + } if (printCommands) { globalParams->setPrintCommands(printCommands); } @@ -290,6 +308,7 @@ int main(int argc, char *argv[]) { delete globalParams; // check for memory leaks + done0: Object::memCheck(stderr); gMemReport(stderr); diff --git a/pdf/xpdf/xpdfconfig.h b/pdf/xpdf/xpdfconfig.h index ef08a7f..bf6baf4 100644 --- a/pdf/xpdf/xpdfconfig.h +++ b/pdf/xpdf/xpdfconfig.h @@ -2,7 +2,7 @@ // // config.h // -// Copyright 1996-2003 Glyph & Cog, LLC +// Copyright 1996-2004 Glyph & Cog, LLC // //======================================================================== @@ -14,23 +14,23 @@ //------------------------------------------------------------------------ // xpdf version -#define xpdfVersion "2.03" -#define xpdfVersionNum 2.03 -#define xpdfMajorVersion 2 -#define xpdfMinorVersion 3 -#define xpdfMajorVersionStr "2" -#define xpdfMinorVersionStr "3" +#define xpdfVersion "3.00" +#define xpdfVersionNum 3.00 +#define xpdfMajorVersion 3 +#define xpdfMinorVersion 0 +#define xpdfMajorVersionStr "3" +#define xpdfMinorVersionStr "0" // supported PDF version -#define supportedPDFVersionStr "1.4" -#define supportedPDFVersionNum 1.4 +#define supportedPDFVersionStr "1.5" +#define supportedPDFVersionNum 1.5 // copyright notice -#define xpdfCopyright "Copyright 1996-2003 Glyph & Cog, LLC" +#define xpdfCopyright "Copyright 1996-2004 Glyph & Cog, LLC" // Windows resource file stuff -#define winxpdfVersion "WinXpdf 2.03" -#define xpdfCopyrightAmp "Copyright 1996-2003 Glyph && Cog, LLC" +#define winxpdfVersion "WinXpdf 3.00" +#define xpdfCopyrightAmp "Copyright 1996-2004 Glyph && Cog, LLC" //------------------------------------------------------------------------ // paper size -- cgit v0.9.1