Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/pdf
diff options
context:
space:
mode:
authorMartin Kretzschmar <mkretzschmar@src.gnome.org>2004-05-16 22:45:42 (GMT)
committer Martin Kretzschmar <mkretzschmar@src.gnome.org>2004-05-16 22:45:42 (GMT)
commitad63666daeeda50acc7630132d61fe044634fddd (patch)
tree487b52b30f8a563cbb2e16c6fd2527a6eeb5990f /pdf
parentd57c02ebc09bfd1a0cac44140ec7a80dbe43877e (diff)
Imported Xpdf 2.03 and fixed build.
* ANNOUNCE: * CHANGES: * README: * aconf2.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: * goo/gfile.cc: * ms_make.bat: * vms_make.com: * xpdf/Annot.cc: * xpdf/Array.cc: * xpdf/BuiltinFontTables.cc: * xpdf/CMap.cc: * xpdf/CMap.h: * xpdf/Catalog.cc: * xpdf/CharCodeToUnicode.cc: * xpdf/CharCodeToUnicode.h: * xpdf/Decrypt.cc: * xpdf/Dict.cc: * xpdf/ErrorCodes.h: * xpdf/FTFont.cc: * xpdf/FTFont.h: * xpdf/FontFile.cc: * xpdf/FontFile.h: * xpdf/Function.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/JBIG2Stream.cc: * xpdf/Link.cc: * xpdf/Link.h: * xpdf/Makefile.am: * xpdf/OutputDev.h: * xpdf/PDFDoc.cc: * xpdf/PDFDoc.h: * xpdf/PSOutputDev.cc: * xpdf/PSOutputDev.h: * xpdf/Page.cc: * xpdf/Page.h: * xpdf/Parser.cc: * xpdf/Stream.cc: * xpdf/Stream.h: * xpdf/TTFont.cc: * xpdf/TTFont.h: * xpdf/TextOutputDev.cc: * xpdf/TextOutputDev.h: * xpdf/UnicodeMap.cc: * xpdf/UnicodeMap.h: * xpdf/UnicodeTypeTable.cc: * xpdf/UnicodeTypeTable.h: * xpdf/XOutputDev.cc: * xpdf/XOutputDev.h: * xpdf/XPDFApp.cc: * xpdf/XPDFCore.cc: * xpdf/XPDFCore.h: * xpdf/XPDFViewer.cc: * xpdf/XPDFViewer.h: * xpdf/XRef.cc: * xpdf/about-text.h: * xpdf/config.h: * xpdf/gpdf-control.cc: * xpdf/gpdf-link-canvas-item.cc: * xpdf/gpdf-links-canvas-layer.cc: * xpdf/pdffonts.cc: * xpdf/pdfimages.cc: * xpdf/pdfinfo.cc: * xpdf/pdftopbm.cc: * xpdf/pdftops.cc: * xpdf/pdftotext.cc: * xpdf/tests/test-links.cc: * xpdf/vms_make.com: * xpdf/xpdf.cc: Imported Xpdf 2.03 and fixed build.
Diffstat (limited to 'pdf')
-rw-r--r--pdf/goo/gfile.cc21
-rw-r--r--pdf/xpdf/Annot.cc22
-rw-r--r--pdf/xpdf/Array.cc8
-rw-r--r--pdf/xpdf/BuiltinFontTables.cc1297
-rw-r--r--pdf/xpdf/CMap.cc26
-rw-r--r--pdf/xpdf/CMap.h7
-rw-r--r--pdf/xpdf/Catalog.cc7
-rw-r--r--pdf/xpdf/CharCodeToUnicode.cc363
-rw-r--r--pdf/xpdf/CharCodeToUnicode.h65
-rw-r--r--pdf/xpdf/Decrypt.cc60
-rw-r--r--pdf/xpdf/Dict.cc8
-rw-r--r--pdf/xpdf/ErrorCodes.h8
-rw-r--r--pdf/xpdf/FTFont.cc102
-rw-r--r--pdf/xpdf/FTFont.h7
-rw-r--r--pdf/xpdf/FontFile.cc397
-rw-r--r--pdf/xpdf/FontFile.h31
-rw-r--r--pdf/xpdf/Function.cc32
-rw-r--r--pdf/xpdf/Gfx.cc433
-rw-r--r--pdf/xpdf/Gfx.h27
-rw-r--r--pdf/xpdf/GfxFont.cc317
-rw-r--r--pdf/xpdf/GfxFont.h21
-rw-r--r--pdf/xpdf/GfxState.cc697
-rw-r--r--pdf/xpdf/GfxState.h105
-rw-r--r--pdf/xpdf/GlobalParams.cc373
-rw-r--r--pdf/xpdf/GlobalParams.h18
-rw-r--r--pdf/xpdf/Link.cc128
-rw-r--r--pdf/xpdf/Link.h54
-rw-r--r--pdf/xpdf/Makefile.am1
-rw-r--r--pdf/xpdf/OutputDev.h1
-rw-r--r--pdf/xpdf/PDFDoc.cc17
-rw-r--r--pdf/xpdf/PDFDoc.h10
-rw-r--r--pdf/xpdf/PSOutputDev.cc713
-rw-r--r--pdf/xpdf/PSOutputDev.h70
-rw-r--r--pdf/xpdf/Page.cc74
-rw-r--r--pdf/xpdf/Page.h4
-rw-r--r--pdf/xpdf/Parser.cc12
-rw-r--r--pdf/xpdf/Stream.cc206
-rw-r--r--pdf/xpdf/Stream.h48
-rw-r--r--pdf/xpdf/TTFont.cc33
-rw-r--r--pdf/xpdf/TTFont.h2
-rw-r--r--pdf/xpdf/TextOutputDev.cc4136
-rw-r--r--pdf/xpdf/TextOutputDev.h329
-rw-r--r--pdf/xpdf/UnicodeMap.cc70
-rw-r--r--pdf/xpdf/UnicodeMap.h7
-rw-r--r--pdf/xpdf/XOutputDev.cc544
-rw-r--r--pdf/xpdf/XOutputDev.h31
-rw-r--r--pdf/xpdf/XRef.cc90
-rw-r--r--pdf/xpdf/pdffonts.cc51
-rw-r--r--pdf/xpdf/pdfimages.cc10
-rw-r--r--pdf/xpdf/pdfinfo.cc81
-rw-r--r--pdf/xpdf/pdftopbm.cc11
-rw-r--r--pdf/xpdf/pdftops.cc10
-rw-r--r--pdf/xpdf/pdftotext.cc48
-rw-r--r--pdf/xpdf/vms_make.com2
-rw-r--r--pdf/xpdf/xpdf.cc14
-rw-r--r--pdf/xpdf/xpdfconfig.h14
56 files changed, 7819 insertions, 3454 deletions
diff --git a/pdf/goo/gfile.cc b/pdf/goo/gfile.cc
index b4fb616..11f5cf6 100644
--- a/pdf/goo/gfile.cc
+++ b/pdf/goo/gfile.cc
@@ -10,13 +10,7 @@
#include <aconf.h>
-#ifdef WIN32
- extern "C" {
-# ifndef _MSC_VER
-# include <kpathsea/win32lib.h>
-# endif
- }
-#else // !WIN32
+#ifndef WIN32
# if defined(MACOS)
# include <sys/stat.h>
# elif !defined(ACORN)
@@ -647,10 +641,14 @@ GDirEntry *GDir::getNextEntry() {
GDirEntry *e;
#if defined(WIN32)
- e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
- if (hnd && !FindNextFile(hnd, &ffd)) {
- FindClose(hnd);
- hnd = NULL;
+ if (hnd) {
+ e = new GDirEntry(path->getCString(), ffd.cFileName, doStat);
+ if (hnd && !FindNextFile(hnd, &ffd)) {
+ FindClose(hnd);
+ hnd = NULL;
+ }
+ } else {
+ e = NULL;
}
#elif defined(ACORN)
#elif defined(MACOS)
@@ -694,6 +692,7 @@ void GDir::rewind() {
tmp = path->copy();
tmp->append("/*.*");
hnd = FindFirstFile(tmp->getCString(), &ffd);
+ delete tmp;
#elif defined(ACORN)
#elif defined(MACOS)
#else
diff --git a/pdf/xpdf/Annot.cc b/pdf/xpdf/Annot.cc
index 20fe24b..42bf849 100644
--- a/pdf/xpdf/Annot.cc
+++ b/pdf/xpdf/Annot.cc
@@ -100,7 +100,7 @@ void Annot::draw(Gfx *gfx) {
Annots::Annots(XRef *xref, Object *annotsObj) {
Annot *annot;
- Object obj1, obj2;
+ Object obj1;
int size;
int i;
@@ -111,18 +111,16 @@ Annots::Annots(XRef *xref, Object *annotsObj) {
if (annotsObj->isArray()) {
for (i = 0; i < annotsObj->arrayGetLength(); ++i) {
if (annotsObj->arrayGet(i, &obj1)->isDict()) {
- obj1.dictLookup("Subtype", &obj2);
- annot = new Annot(xref, obj1.getDict());
- if (annot->isOk()) {
- if (nAnnots >= size) {
- size += 16;
- annots = (Annot **)grealloc(annots, size * sizeof(Annot *));
- }
- annots[nAnnots++] = annot;
- } else {
- delete annot;
+ annot = new Annot(xref, obj1.getDict());
+ if (annot->isOk()) {
+ if (nAnnots >= size) {
+ size += 16;
+ annots = (Annot **)grealloc(annots, size * sizeof(Annot *));
+ }
+ annots[nAnnots++] = annot;
+ } else {
+ delete annot;
}
- obj2.free();
}
obj1.free();
}
diff --git a/pdf/xpdf/Array.cc b/pdf/xpdf/Array.cc
index 27ecbe9..a6c6db1 100644
--- a/pdf/xpdf/Array.cc
+++ b/pdf/xpdf/Array.cc
@@ -38,8 +38,12 @@ Array::~Array() {
}
void Array::add(Object *elem) {
- if (length + 1 > size) {
- size += 8;
+ if (length == size) {
+ if (length == 0) {
+ size = 8;
+ } else {
+ size *= 2;
+ }
elems = (Object *)grealloc(elems, size * sizeof(Object));
}
elems[length] = *elem;
diff --git a/pdf/xpdf/BuiltinFontTables.cc b/pdf/xpdf/BuiltinFontTables.cc
index 296e564..9c36238 100644
--- a/pdf/xpdf/BuiltinFontTables.cc
+++ b/pdf/xpdf/BuiltinFontTables.cc
@@ -13,30 +13,40 @@
static BuiltinFontWidth courierWidthsTab[] = {
{ "Ntilde", 600, NULL },
+ { "rcaron", 600, NULL },
+ { "kcommaaccent", 600, NULL },
+ { "Ncommaaccent", 600, NULL },
+ { "Zacute", 600, NULL },
{ "comma", 600, NULL },
{ "cedilla", 600, NULL },
{ "plusminus", 600, NULL },
- { "arrowup", 600, NULL },
{ "circumflex", 600, NULL },
{ "dotaccent", 600, NULL },
- { "LL", 600, NULL },
+ { "edotaccent", 600, NULL },
{ "asciitilde", 600, NULL },
{ "colon", 600, NULL },
{ "onehalf", 600, NULL },
{ "dollar", 600, NULL },
+ { "Lcaron", 600, NULL },
{ "ntilde", 600, NULL },
- { "left", 600, NULL },
+ { "Aogonek", 600, NULL },
+ { "ncommaaccent", 600, NULL },
{ "minus", 600, NULL },
+ { "Iogonek", 600, NULL },
+ { "zacute", 600, NULL },
{ "yen", 600, NULL },
{ "space", 600, NULL },
+ { "Omacron", 600, NULL },
{ "questiondown", 600, NULL },
{ "emdash", 600, NULL },
{ "Agrave", 600, NULL },
{ "three", 600, NULL },
{ "numbersign", 600, NULL },
+ { "lcaron", 600, NULL },
{ "A", 600, NULL },
{ "B", 600, NULL },
{ "C", 600, NULL },
+ { "aogonek", 600, NULL },
{ "D", 600, NULL },
{ "E", 600, NULL },
{ "onequarter", 600, NULL },
@@ -46,14 +56,18 @@ static BuiltinFontWidth courierWidthsTab[] = {
{ "I", 600, NULL },
{ "J", 600, NULL },
{ "K", 600, NULL },
+ { "iogonek", 600, NULL },
{ "L", 600, NULL },
{ "backslash", 600, NULL },
{ "periodcentered", 600, NULL },
{ "M", 600, NULL },
{ "N", 600, NULL },
+ { "omacron", 600, NULL },
+ { "Tcommaaccent", 600, NULL },
{ "O", 600, NULL },
{ "P", 600, NULL },
{ "Q", 600, NULL },
+ { "Uhungarumlaut", 600, NULL },
{ "R", 600, NULL },
{ "Aacute", 600, NULL },
{ "caron", 600, NULL },
@@ -62,9 +76,7 @@ static BuiltinFontWidth courierWidthsTab[] = {
{ "U", 600, NULL },
{ "agrave", 600, NULL },
{ "V", 600, NULL },
- { "tab", 600, NULL },
{ "W", 600, NULL },
- { "ll", 600, NULL },
{ "equal", 600, NULL },
{ "question", 600, NULL },
{ "X", 600, NULL },
@@ -72,6 +84,7 @@ static BuiltinFontWidth courierWidthsTab[] = {
{ "Z", 600, NULL },
{ "four", 600, NULL },
{ "a", 600, NULL },
+ { "Gcommaaccent", 600, NULL },
{ "b", 600, NULL },
{ "c", 600, NULL },
{ "d", 600, NULL },
@@ -88,44 +101,57 @@ static BuiltinFontWidth courierWidthsTab[] = {
{ "l", 600, NULL },
{ "m", 600, NULL },
{ "n", 600, NULL },
+ { "tcommaaccent", 600, NULL },
{ "o", 600, NULL },
{ "ordfeminine", 600, NULL },
{ "ring", 600, NULL },
{ "p", 600, NULL },
{ "q", 600, NULL },
+ { "uhungarumlaut", 600, NULL },
{ "r", 600, NULL },
{ "twosuperior", 600, NULL },
- { "largebullet", 600, NULL },
{ "aacute", 600, NULL },
{ "s", 600, NULL },
{ "OE", 600, NULL },
{ "t", 600, NULL },
{ "divide", 600, NULL },
{ "u", 600, NULL },
+ { "Ccaron", 600, NULL },
{ "v", 600, NULL },
{ "w", 600, NULL },
{ "x", 600, NULL },
{ "y", 600, NULL },
{ "z", 600, NULL },
+ { "Gbreve", 600, NULL },
+ { "commaaccent", 600, NULL },
{ "hungarumlaut", 600, NULL },
+ { "Idotaccent", 600, NULL },
+ { "Nacute", 600, NULL },
{ "quotedbl", 600, NULL },
+ { "gcommaaccent", 600, NULL },
{ "mu", 600, NULL },
+ { "greaterequal", 600, NULL },
{ "Scaron", 600, NULL },
{ "Lslash", 600, NULL },
{ "semicolon", 600, NULL },
{ "oslash", 600, NULL },
+ { "lessequal", 600, NULL },
+ { "lozenge", 600, NULL },
{ "parenright", 600, NULL },
+ { "ccaron", 600, NULL },
{ "Ecircumflex", 600, NULL },
+ { "gbreve", 600, NULL },
{ "trademark", 600, NULL },
{ "daggerdbl", 600, NULL },
+ { "nacute", 600, NULL },
{ "macron", 600, NULL },
{ "Otilde", 600, NULL },
+ { "Emacron", 600, NULL },
{ "ellipsis", 600, NULL },
{ "scaron", 600, NULL },
{ "AE", 600, NULL },
{ "Ucircumflex", 600, NULL },
{ "lslash", 600, NULL },
- { "lira", 600, NULL },
{ "quotedblleft", 600, NULL },
{ "hyphen", 600, NULL },
{ "guilsinglright", 600, NULL },
@@ -134,9 +160,11 @@ static BuiltinFontWidth courierWidthsTab[] = {
{ "exclamdown", 600, NULL },
{ "endash", 600, NULL },
{ "oe", 600, NULL },
+ { "Abreve", 600, NULL },
+ { "Umacron", 600, NULL },
{ "ecircumflex", 600, NULL },
- { "copyright", 600, NULL },
{ "Adieresis", 600, NULL },
+ { "copyright", 600, NULL },
{ "Egrave", 600, NULL },
{ "slash", 600, NULL },
{ "Edieresis", 600, NULL },
@@ -144,14 +172,17 @@ static BuiltinFontWidth courierWidthsTab[] = {
{ "Idieresis", 600, NULL },
{ "parenleft", 600, NULL },
{ "one", 600, NULL },
- { "ucircumflex", 600, NULL },
+ { "emacron", 600, NULL },
{ "Odieresis", 600, NULL },
+ { "ucircumflex", 600, NULL },
{ "bracketleft", 600, NULL },
{ "Ugrave", 600, NULL },
{ "quoteright", 600, NULL },
{ "Udieresis", 600, NULL },
{ "perthousand", 600, NULL },
{ "Ydieresis", 600, NULL },
+ { "umacron", 600, NULL },
+ { "abreve", 600, NULL },
{ "Eacute", 600, NULL },
{ "adieresis", 600, NULL },
{ "egrave", 600, NULL },
@@ -167,139 +198,173 @@ static BuiltinFontWidth courierWidthsTab[] = {
{ "nine", 600, NULL },
{ "udieresis", 600, NULL },
{ "Zcaron", 600, NULL },
+ { "Scommaaccent", 600, NULL },
{ "threequarters", 600, NULL },
{ "guillemotright", 600, NULL },
- { "ydieresis", 600, NULL },
{ "Ccedilla", 600, NULL },
+ { "ydieresis", 600, NULL },
{ "tilde", 600, NULL },
{ "at", 600, NULL },
{ "eacute", 600, NULL },
- { "Gcaron", 600, NULL },
{ "underscore", 600, NULL },
+ { "Euro", 600, NULL },
+ { "Dcroat", 600, NULL },
{ "zero", 600, NULL },
{ "multiply", 600, NULL },
- { "Scedilla", 600, NULL },
{ "eth", 600, NULL },
+ { "Scedilla", 600, NULL },
+ { "Racute", 600, NULL },
{ "Ograve", 600, NULL },
+ { "partialdiff", 600, NULL },
{ "uacute", 600, NULL },
{ "braceleft", 600, NULL },
{ "Thorn", 600, NULL },
{ "zcaron", 600, NULL },
+ { "scommaaccent", 600, NULL },
{ "ccedilla", 600, NULL },
- { "gcaron", 600, NULL },
+ { "Dcaron", 600, NULL },
+ { "dcroat", 600, NULL },
+ { "scedilla", 600, NULL },
{ "Oacute", 600, NULL },
{ "Ocircumflex", 600, NULL },
- { "scedilla", 600, NULL },
{ "ogonek", 600, NULL },
- { "arrowdown", 600, NULL },
{ "ograve", 600, NULL },
+ { "racute", 600, NULL },
+ { "Tcaron", 600, NULL },
+ { "Eogonek", 600, NULL },
{ "thorn", 600, NULL },
{ "degree", 600, NULL },
{ "registered", 600, NULL },
- { "percent", 600, NULL },
+ { "radical", 600, NULL },
{ "Aring", 600, NULL },
+ { "percent", 600, NULL },
{ "six", 600, NULL },
{ "paragraph", 600, NULL },
+ { "dcaron", 600, NULL },
+ { "Uogonek", 600, NULL },
{ "two", 600, NULL },
+ { "summation", 600, NULL },
{ "Igrave", 600, NULL },
- { "oacute", 600, NULL },
+ { "Lacute", 600, NULL },
{ "ocircumflex", 600, NULL },
+ { "oacute", 600, NULL },
+ { "Uring", 600, NULL },
+ { "Lcommaaccent", 600, NULL },
+ { "tcaron", 600, NULL },
+ { "eogonek", 600, NULL },
+ { "Delta", 600, NULL },
+ { "Ohungarumlaut", 600, NULL },
{ "asciicircum", 600, NULL },
{ "aring", 600, NULL },
- { "square", 600, NULL },
{ "grave", 600, NULL },
+ { "uogonek", 600, NULL },
{ "bracketright", 600, NULL },
{ "ampersand", 600, NULL },
{ "Iacute", 600, NULL },
+ { "lacute", 600, NULL },
{ "igrave", 600, NULL },
- { "return", 600, NULL },
+ { "Ncaron", 600, NULL },
{ "plus", 600, NULL },
+ { "uring", 600, NULL },
{ "quotesinglbase", 600, NULL },
+ { "lcommaaccent", 600, NULL },
{ "Yacute", 600, NULL },
+ { "ohungarumlaut", 600, NULL },
{ "threesuperior", 600, NULL },
{ "acute", 600, NULL },
- { "notegraphic", 600, NULL },
{ "section", 600, NULL },
- { "arrowleft", 600, NULL },
{ "dieresis", 600, NULL },
{ "quotedblbase", 600, NULL },
{ "iacute", 600, NULL },
- { "up", 600, NULL },
+ { "ncaron", 600, NULL },
{ "florin", 600, NULL },
{ "yacute", 600, NULL },
+ { "Rcommaaccent", 600, NULL },
{ "fi", 600, NULL },
{ "fl", 600, NULL },
{ "Acircumflex", 600, NULL },
+ { "Cacute", 600, NULL },
{ "Icircumflex", 600, NULL },
{ "guillemotleft", 600, NULL },
{ "germandbls", 600, NULL },
{ "seven", 600, NULL },
- { "indent", 600, NULL },
- { "prescription", 600, NULL },
- { "dectab", 600, NULL },
+ { "Amacron", 600, NULL },
+ { "Sacute", 600, NULL },
{ "ordmasculine", 600, NULL },
{ "dotlessi", 600, NULL },
{ "sterling", 600, NULL },
- { "IJ", 600, NULL },
+ { "notequal", 600, NULL },
+ { "Imacron", 600, NULL },
+ { "rcommaaccent", 600, NULL },
+ { "Zdotaccent", 600, NULL },
{ "acircumflex", 600, NULL },
- { "overscore", 600, NULL },
+ { "cacute", 600, NULL },
+ { "Ecaron", 600, NULL },
{ "braceright", 600, NULL },
{ "icircumflex", 600, NULL },
- { "graybox", 600, NULL },
{ "quotedblright", 600, NULL },
- { "center", 600, NULL },
- { "stop", 600, NULL },
+ { "amacron", 600, NULL },
+ { "sacute", 600, NULL },
+ { "imacron", 600, NULL },
{ "cent", 600, NULL },
{ "currency", 600, NULL },
{ "logicalnot", 600, NULL },
- { "Idot", 600, NULL },
- { "merge", 600, NULL },
+ { "zdotaccent", 600, NULL },
{ "Atilde", 600, NULL },
{ "breve", 600, NULL },
{ "bar", 600, NULL },
{ "fraction", 600, NULL },
{ "less", 600, NULL },
- { "down", 600, NULL },
+ { "ecaron", 600, NULL },
{ "guilsinglleft", 600, NULL },
{ "exclam", 600, NULL },
{ "period", 600, NULL },
- { "arrowright", 600, NULL },
- { "format", 600, NULL },
+ { "Rcaron", 600, NULL },
+ { "Kcommaaccent", 600, NULL },
{ "greater", 600, NULL },
{ "atilde", 600, NULL },
- { "ij", 600, NULL },
{ "brokenbar", 600, NULL },
- { "arrowboth", 600, NULL },
{ "quoteleft", 600, NULL },
+ { "Edotaccent", 600, NULL },
{ "onesuperior", 600, NULL }
};
static BuiltinFontWidth courierBoldWidthsTab[] = {
{ "Ntilde", 600, NULL },
+ { "rcaron", 600, NULL },
+ { "kcommaaccent", 600, NULL },
+ { "Ncommaaccent", 600, NULL },
+ { "Zacute", 600, NULL },
{ "comma", 600, NULL },
{ "cedilla", 600, NULL },
{ "plusminus", 600, NULL },
- { "arrowup", 600, NULL },
{ "circumflex", 600, NULL },
{ "dotaccent", 600, NULL },
- { "LL", 600, NULL },
+ { "edotaccent", 600, NULL },
{ "asciitilde", 600, NULL },
{ "colon", 600, NULL },
{ "onehalf", 600, NULL },
{ "dollar", 600, NULL },
+ { "Lcaron", 600, NULL },
{ "ntilde", 600, NULL },
- { "left", 600, NULL },
+ { "Aogonek", 600, NULL },
+ { "ncommaaccent", 600, NULL },
{ "minus", 600, NULL },
+ { "Iogonek", 600, NULL },
+ { "zacute", 600, NULL },
{ "yen", 600, NULL },
{ "space", 600, NULL },
+ { "Omacron", 600, NULL },
{ "questiondown", 600, NULL },
{ "emdash", 600, NULL },
{ "Agrave", 600, NULL },
{ "three", 600, NULL },
{ "numbersign", 600, NULL },
+ { "lcaron", 600, NULL },
{ "A", 600, NULL },
{ "B", 600, NULL },
{ "C", 600, NULL },
+ { "aogonek", 600, NULL },
{ "D", 600, NULL },
{ "E", 600, NULL },
{ "onequarter", 600, NULL },
@@ -309,14 +374,18 @@ static BuiltinFontWidth courierBoldWidthsTab[] = {
{ "I", 600, NULL },
{ "J", 600, NULL },
{ "K", 600, NULL },
+ { "iogonek", 600, NULL },
{ "backslash", 600, NULL },
{ "L", 600, NULL },
{ "periodcentered", 600, NULL },
{ "M", 600, NULL },
{ "N", 600, NULL },
+ { "omacron", 600, NULL },
+ { "Tcommaaccent", 600, NULL },
{ "O", 600, NULL },
{ "P", 600, NULL },
{ "Q", 600, NULL },
+ { "Uhungarumlaut", 600, NULL },
{ "R", 600, NULL },
{ "Aacute", 600, NULL },
{ "caron", 600, NULL },
@@ -325,9 +394,7 @@ static BuiltinFontWidth courierBoldWidthsTab[] = {
{ "U", 600, NULL },
{ "agrave", 600, NULL },
{ "V", 600, NULL },
- { "tab", 600, NULL },
{ "W", 600, NULL },
- { "ll", 600, NULL },
{ "X", 600, NULL },
{ "question", 600, NULL },
{ "equal", 600, NULL },
@@ -335,6 +402,7 @@ static BuiltinFontWidth courierBoldWidthsTab[] = {
{ "Z", 600, NULL },
{ "four", 600, NULL },
{ "a", 600, NULL },
+ { "Gcommaaccent", 600, NULL },
{ "b", 600, NULL },
{ "c", 600, NULL },
{ "d", 600, NULL },
@@ -351,44 +419,57 @@ static BuiltinFontWidth courierBoldWidthsTab[] = {
{ "l", 600, NULL },
{ "m", 600, NULL },
{ "n", 600, NULL },
+ { "tcommaaccent", 600, NULL },
{ "o", 600, NULL },
{ "ordfeminine", 600, NULL },
{ "ring", 600, NULL },
{ "p", 600, NULL },
{ "q", 600, NULL },
+ { "uhungarumlaut", 600, NULL },
{ "r", 600, NULL },
{ "twosuperior", 600, NULL },
- { "largebullet", 600, NULL },
{ "aacute", 600, NULL },
{ "s", 600, NULL },
{ "OE", 600, NULL },
{ "t", 600, NULL },
{ "divide", 600, NULL },
{ "u", 600, NULL },
+ { "Ccaron", 600, NULL },
{ "v", 600, NULL },
{ "w", 600, NULL },
{ "x", 600, NULL },
{ "y", 600, NULL },
{ "z", 600, NULL },
+ { "Gbreve", 600, NULL },
+ { "commaaccent", 600, NULL },
{ "hungarumlaut", 600, NULL },
+ { "Idotaccent", 600, NULL },
+ { "Nacute", 600, NULL },
{ "quotedbl", 600, NULL },
+ { "gcommaaccent", 600, NULL },
{ "mu", 600, NULL },
+ { "greaterequal", 600, NULL },
{ "Scaron", 600, NULL },
{ "Lslash", 600, NULL },
{ "semicolon", 600, NULL },
{ "oslash", 600, NULL },
+ { "lessequal", 600, NULL },
+ { "lozenge", 600, NULL },
{ "parenright", 600, NULL },
+ { "ccaron", 600, NULL },
{ "Ecircumflex", 600, NULL },
+ { "gbreve", 600, NULL },
{ "trademark", 600, NULL },
{ "daggerdbl", 600, NULL },
+ { "nacute", 600, NULL },
{ "macron", 600, NULL },
{ "Otilde", 600, NULL },
+ { "Emacron", 600, NULL },
{ "ellipsis", 600, NULL },
{ "scaron", 600, NULL },
{ "AE", 600, NULL },
{ "Ucircumflex", 600, NULL },
{ "lslash", 600, NULL },
- { "lira", 600, NULL },
{ "quotedblleft", 600, NULL },
{ "guilsinglright", 600, NULL },
{ "hyphen", 600, NULL },
@@ -397,9 +478,11 @@ static BuiltinFontWidth courierBoldWidthsTab[] = {
{ "exclamdown", 600, NULL },
{ "endash", 600, NULL },
{ "oe", 600, NULL },
+ { "Abreve", 600, NULL },
+ { "Umacron", 600, NULL },
{ "ecircumflex", 600, NULL },
- { "copyright", 600, NULL },
{ "Adieresis", 600, NULL },
+ { "copyright", 600, NULL },
{ "Egrave", 600, NULL },
{ "slash", 600, NULL },
{ "Edieresis", 600, NULL },
@@ -407,14 +490,17 @@ static BuiltinFontWidth courierBoldWidthsTab[] = {
{ "Idieresis", 600, NULL },
{ "parenleft", 600, NULL },
{ "one", 600, NULL },
- { "ucircumflex", 600, NULL },
+ { "emacron", 600, NULL },
{ "Odieresis", 600, NULL },
+ { "ucircumflex", 600, NULL },
{ "bracketleft", 600, NULL },
{ "Ugrave", 600, NULL },
{ "quoteright", 600, NULL },
{ "Udieresis", 600, NULL },
{ "perthousand", 600, NULL },
{ "Ydieresis", 600, NULL },
+ { "umacron", 600, NULL },
+ { "abreve", 600, NULL },
{ "Eacute", 600, NULL },
{ "adieresis", 600, NULL },
{ "egrave", 600, NULL },
@@ -430,139 +516,173 @@ static BuiltinFontWidth courierBoldWidthsTab[] = {
{ "five", 600, NULL },
{ "udieresis", 600, NULL },
{ "Zcaron", 600, NULL },
+ { "Scommaaccent", 600, NULL },
{ "threequarters", 600, NULL },
{ "guillemotright", 600, NULL },
- { "ydieresis", 600, NULL },
{ "Ccedilla", 600, NULL },
+ { "ydieresis", 600, NULL },
{ "tilde", 600, NULL },
{ "at", 600, NULL },
{ "eacute", 600, NULL },
- { "Gcaron", 600, NULL },
{ "underscore", 600, NULL },
+ { "Euro", 600, NULL },
+ { "Dcroat", 600, NULL },
{ "multiply", 600, NULL },
{ "zero", 600, NULL },
{ "eth", 600, NULL },
{ "Scedilla", 600, NULL },
{ "Ograve", 600, NULL },
+ { "Racute", 600, NULL },
+ { "partialdiff", 600, NULL },
{ "uacute", 600, NULL },
{ "braceleft", 600, NULL },
{ "Thorn", 600, NULL },
{ "zcaron", 600, NULL },
+ { "scommaaccent", 600, NULL },
{ "ccedilla", 600, NULL },
- { "gcaron", 600, NULL },
- { "scedilla", 600, NULL },
+ { "Dcaron", 600, NULL },
+ { "dcroat", 600, NULL },
{ "Ocircumflex", 600, NULL },
{ "Oacute", 600, NULL },
- { "arrowdown", 600, NULL },
+ { "scedilla", 600, NULL },
{ "ogonek", 600, NULL },
{ "ograve", 600, NULL },
+ { "racute", 600, NULL },
+ { "Tcaron", 600, NULL },
+ { "Eogonek", 600, NULL },
{ "thorn", 600, NULL },
{ "degree", 600, NULL },
{ "registered", 600, NULL },
+ { "radical", 600, NULL },
{ "Aring", 600, NULL },
{ "percent", 600, NULL },
{ "six", 600, NULL },
{ "paragraph", 600, NULL },
+ { "dcaron", 600, NULL },
+ { "Uogonek", 600, NULL },
{ "two", 600, NULL },
+ { "summation", 600, NULL },
{ "Igrave", 600, NULL },
+ { "Lacute", 600, NULL },
{ "ocircumflex", 600, NULL },
{ "oacute", 600, NULL },
+ { "Uring", 600, NULL },
+ { "Lcommaaccent", 600, NULL },
+ { "tcaron", 600, NULL },
+ { "eogonek", 600, NULL },
+ { "Delta", 600, NULL },
+ { "Ohungarumlaut", 600, NULL },
{ "asciicircum", 600, NULL },
- { "square", 600, NULL },
{ "aring", 600, NULL },
{ "grave", 600, NULL },
+ { "uogonek", 600, NULL },
{ "bracketright", 600, NULL },
{ "Iacute", 600, NULL },
{ "ampersand", 600, NULL },
{ "igrave", 600, NULL },
- { "return", 600, NULL },
+ { "lacute", 600, NULL },
+ { "Ncaron", 600, NULL },
{ "plus", 600, NULL },
+ { "uring", 600, NULL },
{ "quotesinglbase", 600, NULL },
+ { "lcommaaccent", 600, NULL },
{ "Yacute", 600, NULL },
+ { "ohungarumlaut", 600, NULL },
{ "threesuperior", 600, NULL },
{ "acute", 600, NULL },
- { "notegraphic", 600, NULL },
{ "section", 600, NULL },
- { "arrowleft", 600, NULL },
{ "dieresis", 600, NULL },
{ "iacute", 600, NULL },
{ "quotedblbase", 600, NULL },
- { "up", 600, NULL },
+ { "ncaron", 600, NULL },
{ "florin", 600, NULL },
{ "yacute", 600, NULL },
+ { "Rcommaaccent", 600, NULL },
{ "fi", 600, NULL },
{ "fl", 600, NULL },
{ "Acircumflex", 600, NULL },
+ { "Cacute", 600, NULL },
{ "Icircumflex", 600, NULL },
{ "guillemotleft", 600, NULL },
{ "germandbls", 600, NULL },
+ { "Amacron", 600, NULL },
{ "seven", 600, NULL },
- { "prescription", 600, NULL },
- { "indent", 600, NULL },
- { "dectab", 600, NULL },
+ { "Sacute", 600, NULL },
{ "ordmasculine", 600, NULL },
{ "dotlessi", 600, NULL },
{ "sterling", 600, NULL },
+ { "notequal", 600, NULL },
+ { "Imacron", 600, NULL },
+ { "rcommaaccent", 600, NULL },
+ { "Zdotaccent", 600, NULL },
{ "acircumflex", 600, NULL },
- { "IJ", 600, NULL },
- { "overscore", 600, NULL },
+ { "cacute", 600, NULL },
+ { "Ecaron", 600, NULL },
{ "icircumflex", 600, NULL },
{ "braceright", 600, NULL },
- { "graybox", 600, NULL },
{ "quotedblright", 600, NULL },
- { "center", 600, NULL },
- { "stop", 600, NULL },
+ { "amacron", 600, NULL },
+ { "sacute", 600, NULL },
+ { "imacron", 600, NULL },
{ "cent", 600, NULL },
{ "currency", 600, NULL },
{ "logicalnot", 600, NULL },
- { "merge", 600, NULL },
- { "Idot", 600, NULL },
+ { "zdotaccent", 600, NULL },
{ "Atilde", 600, NULL },
{ "breve", 600, NULL },
{ "bar", 600, NULL },
{ "fraction", 600, NULL },
{ "less", 600, NULL },
- { "down", 600, NULL },
+ { "ecaron", 600, NULL },
{ "guilsinglleft", 600, NULL },
{ "exclam", 600, NULL },
{ "period", 600, NULL },
- { "format", 600, NULL },
- { "arrowright", 600, NULL },
+ { "Rcaron", 600, NULL },
+ { "Kcommaaccent", 600, NULL },
{ "greater", 600, NULL },
- { "ij", 600, NULL },
{ "atilde", 600, NULL },
{ "brokenbar", 600, NULL },
- { "arrowboth", 600, NULL },
{ "quoteleft", 600, NULL },
+ { "Edotaccent", 600, NULL },
{ "onesuperior", 600, NULL }
};
static BuiltinFontWidth courierBoldObliqueWidthsTab[] = {
{ "Ntilde", 600, NULL },
+ { "rcaron", 600, NULL },
+ { "kcommaaccent", 600, NULL },
+ { "Ncommaaccent", 600, NULL },
+ { "Zacute", 600, NULL },
{ "comma", 600, NULL },
{ "cedilla", 600, NULL },
{ "plusminus", 600, NULL },
- { "arrowup", 600, NULL },
{ "circumflex", 600, NULL },
{ "dotaccent", 600, NULL },
- { "LL", 600, NULL },
+ { "edotaccent", 600, NULL },
{ "asciitilde", 600, NULL },
{ "colon", 600, NULL },
{ "onehalf", 600, NULL },
{ "dollar", 600, NULL },
+ { "Lcaron", 600, NULL },
{ "ntilde", 600, NULL },
- { "left", 600, NULL },
+ { "Aogonek", 600, NULL },
+ { "ncommaaccent", 600, NULL },
{ "minus", 600, NULL },
+ { "Iogonek", 600, NULL },
+ { "zacute", 600, NULL },
{ "yen", 600, NULL },
{ "space", 600, NULL },
+ { "Omacron", 600, NULL },
{ "questiondown", 600, NULL },
{ "emdash", 600, NULL },
{ "Agrave", 600, NULL },
{ "three", 600, NULL },
{ "numbersign", 600, NULL },
+ { "lcaron", 600, NULL },
{ "A", 600, NULL },
{ "B", 600, NULL },
{ "C", 600, NULL },
+ { "aogonek", 600, NULL },
{ "D", 600, NULL },
{ "E", 600, NULL },
{ "onequarter", 600, NULL },
@@ -572,14 +692,18 @@ static BuiltinFontWidth courierBoldObliqueWidthsTab[] = {
{ "I", 600, NULL },
{ "J", 600, NULL },
{ "K", 600, NULL },
+ { "iogonek", 600, NULL },
{ "backslash", 600, NULL },
{ "L", 600, NULL },
{ "periodcentered", 600, NULL },
{ "M", 600, NULL },
{ "N", 600, NULL },
+ { "omacron", 600, NULL },
+ { "Tcommaaccent", 600, NULL },
{ "O", 600, NULL },
{ "P", 600, NULL },
{ "Q", 600, NULL },
+ { "Uhungarumlaut", 600, NULL },
{ "R", 600, NULL },
{ "Aacute", 600, NULL },
{ "caron", 600, NULL },
@@ -588,9 +712,7 @@ static BuiltinFontWidth courierBoldObliqueWidthsTab[] = {
{ "U", 600, NULL },
{ "agrave", 600, NULL },
{ "V", 600, NULL },
- { "tab", 600, NULL },
{ "W", 600, NULL },
- { "ll", 600, NULL },
{ "X", 600, NULL },
{ "question", 600, NULL },
{ "equal", 600, NULL },
@@ -598,6 +720,7 @@ static BuiltinFontWidth courierBoldObliqueWidthsTab[] = {
{ "Z", 600, NULL },
{ "four", 600, NULL },
{ "a", 600, NULL },
+ { "Gcommaaccent", 600, NULL },
{ "b", 600, NULL },
{ "c", 600, NULL },
{ "d", 600, NULL },
@@ -614,44 +737,57 @@ static BuiltinFontWidth courierBoldObliqueWidthsTab[] = {
{ "l", 600, NULL },
{ "m", 600, NULL },
{ "n", 600, NULL },
+ { "tcommaaccent", 600, NULL },
{ "o", 600, NULL },
{ "ordfeminine", 600, NULL },
{ "ring", 600, NULL },
{ "p", 600, NULL },
{ "q", 600, NULL },
+ { "uhungarumlaut", 600, NULL },
{ "r", 600, NULL },
{ "twosuperior", 600, NULL },
- { "largebullet", 600, NULL },
{ "aacute", 600, NULL },
{ "s", 600, NULL },
{ "OE", 600, NULL },
{ "t", 600, NULL },
{ "divide", 600, NULL },
{ "u", 600, NULL },
+ { "Ccaron", 600, NULL },
{ "v", 600, NULL },
{ "w", 600, NULL },
{ "x", 600, NULL },
{ "y", 600, NULL },
{ "z", 600, NULL },
+ { "Gbreve", 600, NULL },
+ { "commaaccent", 600, NULL },
{ "hungarumlaut", 600, NULL },
+ { "Idotaccent", 600, NULL },
+ { "Nacute", 600, NULL },
{ "quotedbl", 600, NULL },
+ { "gcommaaccent", 600, NULL },
{ "mu", 600, NULL },
+ { "greaterequal", 600, NULL },
{ "Scaron", 600, NULL },
{ "Lslash", 600, NULL },
{ "semicolon", 600, NULL },
{ "oslash", 600, NULL },
+ { "lessequal", 600, NULL },
+ { "lozenge", 600, NULL },
{ "parenright", 600, NULL },
+ { "ccaron", 600, NULL },
{ "Ecircumflex", 600, NULL },
+ { "gbreve", 600, NULL },
{ "trademark", 600, NULL },
{ "daggerdbl", 600, NULL },
+ { "nacute", 600, NULL },
{ "macron", 600, NULL },
{ "Otilde", 600, NULL },
+ { "Emacron", 600, NULL },
{ "ellipsis", 600, NULL },
{ "scaron", 600, NULL },
{ "AE", 600, NULL },
{ "Ucircumflex", 600, NULL },
{ "lslash", 600, NULL },
- { "lira", 600, NULL },
{ "quotedblleft", 600, NULL },
{ "guilsinglright", 600, NULL },
{ "hyphen", 600, NULL },
@@ -660,9 +796,11 @@ static BuiltinFontWidth courierBoldObliqueWidthsTab[] = {
{ "exclamdown", 600, NULL },
{ "endash", 600, NULL },
{ "oe", 600, NULL },
+ { "Abreve", 600, NULL },
+ { "Umacron", 600, NULL },
{ "ecircumflex", 600, NULL },
- { "copyright", 600, NULL },
{ "Adieresis", 600, NULL },
+ { "copyright", 600, NULL },
{ "Egrave", 600, NULL },
{ "slash", 600, NULL },
{ "Edieresis", 600, NULL },
@@ -670,14 +808,17 @@ static BuiltinFontWidth courierBoldObliqueWidthsTab[] = {
{ "Idieresis", 600, NULL },
{ "parenleft", 600, NULL },
{ "one", 600, NULL },
- { "ucircumflex", 600, NULL },
+ { "emacron", 600, NULL },
{ "Odieresis", 600, NULL },
+ { "ucircumflex", 600, NULL },
{ "bracketleft", 600, NULL },
{ "Ugrave", 600, NULL },
{ "quoteright", 600, NULL },
{ "Udieresis", 600, NULL },
{ "perthousand", 600, NULL },
{ "Ydieresis", 600, NULL },
+ { "umacron", 600, NULL },
+ { "abreve", 600, NULL },
{ "Eacute", 600, NULL },
{ "adieresis", 600, NULL },
{ "egrave", 600, NULL },
@@ -693,139 +834,173 @@ static BuiltinFontWidth courierBoldObliqueWidthsTab[] = {
{ "five", 600, NULL },
{ "udieresis", 600, NULL },
{ "Zcaron", 600, NULL },
+ { "Scommaaccent", 600, NULL },
{ "threequarters", 600, NULL },
{ "guillemotright", 600, NULL },
- { "ydieresis", 600, NULL },
{ "Ccedilla", 600, NULL },
+ { "ydieresis", 600, NULL },
{ "tilde", 600, NULL },
{ "at", 600, NULL },
{ "eacute", 600, NULL },
- { "Gcaron", 600, NULL },
{ "underscore", 600, NULL },
+ { "Euro", 600, NULL },
+ { "Dcroat", 600, NULL },
{ "multiply", 600, NULL },
{ "zero", 600, NULL },
{ "eth", 600, NULL },
{ "Scedilla", 600, NULL },
{ "Ograve", 600, NULL },
+ { "Racute", 600, NULL },
+ { "partialdiff", 600, NULL },
{ "uacute", 600, NULL },
{ "braceleft", 600, NULL },
{ "Thorn", 600, NULL },
{ "zcaron", 600, NULL },
+ { "scommaaccent", 600, NULL },
{ "ccedilla", 600, NULL },
- { "gcaron", 600, NULL },
- { "scedilla", 600, NULL },
+ { "Dcaron", 600, NULL },
+ { "dcroat", 600, NULL },
{ "Ocircumflex", 600, NULL },
{ "Oacute", 600, NULL },
- { "arrowdown", 600, NULL },
+ { "scedilla", 600, NULL },
{ "ogonek", 600, NULL },
{ "ograve", 600, NULL },
+ { "racute", 600, NULL },
+ { "Tcaron", 600, NULL },
+ { "Eogonek", 600, NULL },
{ "thorn", 600, NULL },
{ "degree", 600, NULL },
{ "registered", 600, NULL },
+ { "radical", 600, NULL },
{ "Aring", 600, NULL },
{ "percent", 600, NULL },
{ "six", 600, NULL },
{ "paragraph", 600, NULL },
+ { "dcaron", 600, NULL },
+ { "Uogonek", 600, NULL },
{ "two", 600, NULL },
+ { "summation", 600, NULL },
{ "Igrave", 600, NULL },
+ { "Lacute", 600, NULL },
{ "ocircumflex", 600, NULL },
{ "oacute", 600, NULL },
+ { "Uring", 600, NULL },
+ { "Lcommaaccent", 600, NULL },
+ { "tcaron", 600, NULL },
+ { "eogonek", 600, NULL },
+ { "Delta", 600, NULL },
+ { "Ohungarumlaut", 600, NULL },
{ "asciicircum", 600, NULL },
- { "square", 600, NULL },
{ "aring", 600, NULL },
{ "grave", 600, NULL },
+ { "uogonek", 600, NULL },
{ "bracketright", 600, NULL },
{ "Iacute", 600, NULL },
{ "ampersand", 600, NULL },
{ "igrave", 600, NULL },
- { "return", 600, NULL },
+ { "lacute", 600, NULL },
+ { "Ncaron", 600, NULL },
{ "plus", 600, NULL },
+ { "uring", 600, NULL },
{ "quotesinglbase", 600, NULL },
+ { "lcommaaccent", 600, NULL },
{ "Yacute", 600, NULL },
+ { "ohungarumlaut", 600, NULL },
{ "threesuperior", 600, NULL },
{ "acute", 600, NULL },
- { "notegraphic", 600, NULL },
{ "section", 600, NULL },
- { "arrowleft", 600, NULL },
{ "dieresis", 600, NULL },
{ "iacute", 600, NULL },
{ "quotedblbase", 600, NULL },
- { "up", 600, NULL },
+ { "ncaron", 600, NULL },
{ "florin", 600, NULL },
{ "yacute", 600, NULL },
+ { "Rcommaaccent", 600, NULL },
{ "fi", 600, NULL },
{ "fl", 600, NULL },
{ "Acircumflex", 600, NULL },
+ { "Cacute", 600, NULL },
{ "Icircumflex", 600, NULL },
{ "guillemotleft", 600, NULL },
{ "germandbls", 600, NULL },
+ { "Amacron", 600, NULL },
{ "seven", 600, NULL },
- { "prescription", 600, NULL },
- { "indent", 600, NULL },
- { "dectab", 600, NULL },
+ { "Sacute", 600, NULL },
{ "ordmasculine", 600, NULL },
{ "dotlessi", 600, NULL },
{ "sterling", 600, NULL },
+ { "notequal", 600, NULL },
+ { "Imacron", 600, NULL },
+ { "rcommaaccent", 600, NULL },
+ { "Zdotaccent", 600, NULL },
{ "acircumflex", 600, NULL },
- { "IJ", 600, NULL },
- { "overscore", 600, NULL },
+ { "cacute", 600, NULL },
+ { "Ecaron", 600, NULL },
{ "icircumflex", 600, NULL },
{ "braceright", 600, NULL },
- { "graybox", 600, NULL },
{ "quotedblright", 600, NULL },
- { "center", 600, NULL },
- { "stop", 600, NULL },
+ { "amacron", 600, NULL },
+ { "sacute", 600, NULL },
+ { "imacron", 600, NULL },
{ "cent", 600, NULL },
{ "currency", 600, NULL },
{ "logicalnot", 600, NULL },
- { "merge", 600, NULL },
- { "Idot", 600, NULL },
+ { "zdotaccent", 600, NULL },
{ "Atilde", 600, NULL },
{ "breve", 600, NULL },
{ "bar", 600, NULL },
{ "fraction", 600, NULL },
{ "less", 600, NULL },
- { "down", 600, NULL },
+ { "ecaron", 600, NULL },
{ "guilsinglleft", 600, NULL },
{ "exclam", 600, NULL },
{ "period", 600, NULL },
- { "format", 600, NULL },
- { "arrowright", 600, NULL },
+ { "Rcaron", 600, NULL },
+ { "Kcommaaccent", 600, NULL },
{ "greater", 600, NULL },
- { "ij", 600, NULL },
{ "atilde", 600, NULL },
{ "brokenbar", 600, NULL },
- { "arrowboth", 600, NULL },
{ "quoteleft", 600, NULL },
+ { "Edotaccent", 600, NULL },
{ "onesuperior", 600, NULL }
};
static BuiltinFontWidth courierObliqueWidthsTab[] = {
{ "Ntilde", 600, NULL },
+ { "rcaron", 600, NULL },
+ { "kcommaaccent", 600, NULL },
+ { "Ncommaaccent", 600, NULL },
+ { "Zacute", 600, NULL },
{ "comma", 600, NULL },
{ "cedilla", 600, NULL },
{ "plusminus", 600, NULL },
- { "arrowup", 600, NULL },
{ "circumflex", 600, NULL },
{ "dotaccent", 600, NULL },
- { "LL", 600, NULL },
+ { "edotaccent", 600, NULL },
{ "asciitilde", 600, NULL },
{ "colon", 600, NULL },
{ "onehalf", 600, NULL },
{ "dollar", 600, NULL },
+ { "Lcaron", 600, NULL },
{ "ntilde", 600, NULL },
- { "left", 600, NULL },
+ { "Aogonek", 600, NULL },
+ { "ncommaaccent", 600, NULL },
{ "minus", 600, NULL },
+ { "Iogonek", 600, NULL },
+ { "zacute", 600, NULL },
{ "yen", 600, NULL },
{ "space", 600, NULL },
+ { "Omacron", 600, NULL },
{ "questiondown", 600, NULL },
{ "emdash", 600, NULL },
{ "Agrave", 600, NULL },
{ "three", 600, NULL },
{ "numbersign", 600, NULL },
+ { "lcaron", 600, NULL },
{ "A", 600, NULL },
{ "B", 600, NULL },
{ "C", 600, NULL },
+ { "aogonek", 600, NULL },
{ "D", 600, NULL },
{ "E", 600, NULL },
{ "onequarter", 600, NULL },
@@ -835,14 +1010,18 @@ static BuiltinFontWidth courierObliqueWidthsTab[] = {
{ "I", 600, NULL },
{ "J", 600, NULL },
{ "K", 600, NULL },
+ { "iogonek", 600, NULL },
{ "backslash", 600, NULL },
{ "L", 600, NULL },
{ "periodcentered", 600, NULL },
{ "M", 600, NULL },
{ "N", 600, NULL },
+ { "omacron", 600, NULL },
+ { "Tcommaaccent", 600, NULL },
{ "O", 600, NULL },
{ "P", 600, NULL },
{ "Q", 600, NULL },
+ { "Uhungarumlaut", 600, NULL },
{ "R", 600, NULL },
{ "Aacute", 600, NULL },
{ "caron", 600, NULL },
@@ -851,9 +1030,7 @@ static BuiltinFontWidth courierObliqueWidthsTab[] = {
{ "U", 600, NULL },
{ "agrave", 600, NULL },
{ "V", 600, NULL },
- { "tab", 600, NULL },
{ "W", 600, NULL },
- { "ll", 600, NULL },
{ "X", 600, NULL },
{ "question", 600, NULL },
{ "equal", 600, NULL },
@@ -861,6 +1038,7 @@ static BuiltinFontWidth courierObliqueWidthsTab[] = {
{ "Z", 600, NULL },
{ "four", 600, NULL },
{ "a", 600, NULL },
+ { "Gcommaaccent", 600, NULL },
{ "b", 600, NULL },
{ "c", 600, NULL },
{ "d", 600, NULL },
@@ -877,44 +1055,57 @@ static BuiltinFontWidth courierObliqueWidthsTab[] = {
{ "l", 600, NULL },
{ "m", 600, NULL },
{ "n", 600, NULL },
+ { "tcommaaccent", 600, NULL },
{ "o", 600, NULL },
{ "ordfeminine", 600, NULL },
{ "ring", 600, NULL },
{ "p", 600, NULL },
{ "q", 600, NULL },
+ { "uhungarumlaut", 600, NULL },
{ "r", 600, NULL },
{ "twosuperior", 600, NULL },
- { "largebullet", 600, NULL },
{ "aacute", 600, NULL },
{ "s", 600, NULL },
{ "OE", 600, NULL },
{ "t", 600, NULL },
{ "divide", 600, NULL },
{ "u", 600, NULL },
+ { "Ccaron", 600, NULL },
{ "v", 600, NULL },
{ "w", 600, NULL },
{ "x", 600, NULL },
{ "y", 600, NULL },
{ "z", 600, NULL },
+ { "Gbreve", 600, NULL },
+ { "commaaccent", 600, NULL },
{ "hungarumlaut", 600, NULL },
+ { "Idotaccent", 600, NULL },
+ { "Nacute", 600, NULL },
{ "quotedbl", 600, NULL },
+ { "gcommaaccent", 600, NULL },
{ "mu", 600, NULL },
+ { "greaterequal", 600, NULL },
{ "Scaron", 600, NULL },
{ "Lslash", 600, NULL },
{ "semicolon", 600, NULL },
{ "oslash", 600, NULL },
+ { "lessequal", 600, NULL },
+ { "lozenge", 600, NULL },
{ "parenright", 600, NULL },
+ { "ccaron", 600, NULL },
{ "Ecircumflex", 600, NULL },
+ { "gbreve", 600, NULL },
{ "trademark", 600, NULL },
{ "daggerdbl", 600, NULL },
+ { "nacute", 600, NULL },
{ "macron", 600, NULL },
{ "Otilde", 600, NULL },
+ { "Emacron", 600, NULL },
{ "ellipsis", 600, NULL },
{ "scaron", 600, NULL },
{ "AE", 600, NULL },
{ "Ucircumflex", 600, NULL },
{ "lslash", 600, NULL },
- { "lira", 600, NULL },
{ "quotedblleft", 600, NULL },
{ "guilsinglright", 600, NULL },
{ "hyphen", 600, NULL },
@@ -923,9 +1114,11 @@ static BuiltinFontWidth courierObliqueWidthsTab[] = {
{ "exclamdown", 600, NULL },
{ "endash", 600, NULL },
{ "oe", 600, NULL },
+ { "Abreve", 600, NULL },
+ { "Umacron", 600, NULL },
{ "ecircumflex", 600, NULL },
- { "copyright", 600, NULL },
{ "Adieresis", 600, NULL },
+ { "copyright", 600, NULL },
{ "Egrave", 600, NULL },
{ "slash", 600, NULL },
{ "Edieresis", 600, NULL },
@@ -933,14 +1126,17 @@ static BuiltinFontWidth courierObliqueWidthsTab[] = {
{ "Idieresis", 600, NULL },
{ "parenleft", 600, NULL },
{ "one", 600, NULL },
- { "ucircumflex", 600, NULL },
+ { "emacron", 600, NULL },
{ "Odieresis", 600, NULL },
+ { "ucircumflex", 600, NULL },
{ "bracketleft", 600, NULL },
{ "Ugrave", 600, NULL },
{ "quoteright", 600, NULL },
{ "Udieresis", 600, NULL },
{ "perthousand", 600, NULL },
{ "Ydieresis", 600, NULL },
+ { "umacron", 600, NULL },
+ { "abreve", 600, NULL },
{ "Eacute", 600, NULL },
{ "adieresis", 600, NULL },
{ "egrave", 600, NULL },
@@ -956,136 +1152,173 @@ static BuiltinFontWidth courierObliqueWidthsTab[] = {
{ "five", 600, NULL },
{ "udieresis", 600, NULL },
{ "Zcaron", 600, NULL },
+ { "Scommaaccent", 600, NULL },
{ "threequarters", 600, NULL },
{ "guillemotright", 600, NULL },
- { "ydieresis", 600, NULL },
{ "Ccedilla", 600, NULL },
+ { "ydieresis", 600, NULL },
{ "tilde", 600, NULL },
{ "at", 600, NULL },
{ "eacute", 600, NULL },
- { "Gcaron", 600, NULL },
{ "underscore", 600, NULL },
+ { "Euro", 600, NULL },
+ { "Dcroat", 600, NULL },
{ "multiply", 600, NULL },
{ "zero", 600, NULL },
{ "eth", 600, NULL },
{ "Scedilla", 600, NULL },
{ "Ograve", 600, NULL },
+ { "Racute", 600, NULL },
+ { "partialdiff", 600, NULL },
{ "uacute", 600, NULL },
{ "braceleft", 600, NULL },
{ "Thorn", 600, NULL },
{ "zcaron", 600, NULL },
+ { "scommaaccent", 600, NULL },
{ "ccedilla", 600, NULL },
- { "gcaron", 600, NULL },
- { "scedilla", 600, NULL },
+ { "Dcaron", 600, NULL },
+ { "dcroat", 600, NULL },
{ "Ocircumflex", 600, NULL },
{ "Oacute", 600, NULL },
- { "arrowdown", 600, NULL },
+ { "scedilla", 600, NULL },
{ "ogonek", 600, NULL },
{ "ograve", 600, NULL },
+ { "racute", 600, NULL },
+ { "Tcaron", 600, NULL },
+ { "Eogonek", 600, NULL },
{ "thorn", 600, NULL },
{ "degree", 600, NULL },
{ "registered", 600, NULL },
+ { "radical", 600, NULL },
{ "Aring", 600, NULL },
{ "percent", 600, NULL },
{ "six", 600, NULL },
{ "paragraph", 600, NULL },
+ { "dcaron", 600, NULL },
+ { "Uogonek", 600, NULL },
{ "two", 600, NULL },
+ { "summation", 600, NULL },
{ "Igrave", 600, NULL },
+ { "Lacute", 600, NULL },
{ "ocircumflex", 600, NULL },
{ "oacute", 600, NULL },
+ { "Uring", 600, NULL },
+ { "Lcommaaccent", 600, NULL },
+ { "tcaron", 600, NULL },
+ { "eogonek", 600, NULL },
+ { "Delta", 600, NULL },
+ { "Ohungarumlaut", 600, NULL },
{ "asciicircum", 600, NULL },
- { "square", 600, NULL },
{ "aring", 600, NULL },
{ "grave", 600, NULL },
+ { "uogonek", 600, NULL },
{ "bracketright", 600, NULL },
{ "Iacute", 600, NULL },
{ "ampersand", 600, NULL },
{ "igrave", 600, NULL },
- { "return", 600, NULL },
+ { "lacute", 600, NULL },
+ { "Ncaron", 600, NULL },
{ "plus", 600, NULL },
+ { "uring", 600, NULL },
{ "quotesinglbase", 600, NULL },
+ { "lcommaaccent", 600, NULL },
{ "Yacute", 600, NULL },
+ { "ohungarumlaut", 600, NULL },
{ "threesuperior", 600, NULL },
{ "acute", 600, NULL },
- { "notegraphic", 600, NULL },
{ "section", 600, NULL },
- { "arrowleft", 600, NULL },
{ "dieresis", 600, NULL },
{ "iacute", 600, NULL },
{ "quotedblbase", 600, NULL },
- { "up", 600, NULL },
+ { "ncaron", 600, NULL },
{ "florin", 600, NULL },
{ "yacute", 600, NULL },
+ { "Rcommaaccent", 600, NULL },
{ "fi", 600, NULL },
{ "fl", 600, NULL },
{ "Acircumflex", 600, NULL },
+ { "Cacute", 600, NULL },
{ "Icircumflex", 600, NULL },
{ "guillemotleft", 600, NULL },
{ "germandbls", 600, NULL },
+ { "Amacron", 600, NULL },
{ "seven", 600, NULL },
- { "prescription", 600, NULL },
- { "indent", 600, NULL },
- { "dectab", 600, NULL },
+ { "Sacute", 600, NULL },
{ "ordmasculine", 600, NULL },
{ "dotlessi", 600, NULL },
{ "sterling", 600, NULL },
+ { "notequal", 600, NULL },
+ { "Imacron", 600, NULL },
+ { "rcommaaccent", 600, NULL },
+ { "Zdotaccent", 600, NULL },
{ "acircumflex", 600, NULL },
- { "IJ", 600, NULL },
- { "overscore", 600, NULL },
+ { "cacute", 600, NULL },
+ { "Ecaron", 600, NULL },
{ "icircumflex", 600, NULL },
{ "braceright", 600, NULL },
- { "graybox", 600, NULL },
{ "quotedblright", 600, NULL },
- { "center", 600, NULL },
- { "stop", 600, NULL },
+ { "amacron", 600, NULL },
+ { "sacute", 600, NULL },
+ { "imacron", 600, NULL },
{ "cent", 600, NULL },
{ "currency", 600, NULL },
{ "logicalnot", 600, NULL },
- { "merge", 600, NULL },
- { "Idot", 600, NULL },
+ { "zdotaccent", 600, NULL },
{ "Atilde", 600, NULL },
{ "breve", 600, NULL },
{ "bar", 600, NULL },
{ "fraction", 600, NULL },
{ "less", 600, NULL },
- { "down", 600, NULL },
+ { "ecaron", 600, NULL },
{ "guilsinglleft", 600, NULL },
{ "exclam", 600, NULL },
{ "period", 600, NULL },
- { "format", 600, NULL },
- { "arrowright", 600, NULL },
+ { "Rcaron", 600, NULL },
+ { "Kcommaaccent", 600, NULL },
{ "greater", 600, NULL },
- { "ij", 600, NULL },
{ "atilde", 600, NULL },
{ "brokenbar", 600, NULL },
- { "arrowboth", 600, NULL },
{ "quoteleft", 600, NULL },
+ { "Edotaccent", 600, NULL },
{ "onesuperior", 600, NULL }
};
static BuiltinFontWidth helveticaWidthsTab[] = {
{ "Ntilde", 722, NULL },
+ { "rcaron", 333, NULL },
+ { "kcommaaccent", 500, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
{ "comma", 278, NULL },
{ "cedilla", 333, NULL },
{ "plusminus", 584, NULL },
{ "circumflex", 333, NULL },
{ "dotaccent", 333, NULL },
+ { "edotaccent", 556, NULL },
{ "asciitilde", 584, NULL },
{ "colon", 278, NULL },
{ "onehalf", 834, NULL },
{ "dollar", 556, NULL },
+ { "Lcaron", 556, NULL },
{ "ntilde", 556, NULL },
+ { "Aogonek", 667, NULL },
+ { "ncommaaccent", 556, NULL },
{ "minus", 584, NULL },
+ { "Iogonek", 278, NULL },
+ { "zacute", 500, NULL },
{ "yen", 556, NULL },
{ "space", 278, NULL },
+ { "Omacron", 778, NULL },
{ "questiondown", 611, NULL },
{ "emdash", 1000, NULL },
{ "Agrave", 667, NULL },
{ "three", 556, NULL },
{ "numbersign", 556, NULL },
+ { "lcaron", 299, NULL },
{ "A", 667, NULL },
{ "B", 667, NULL },
{ "C", 722, NULL },
+ { "aogonek", 556, NULL },
{ "D", 722, NULL },
{ "E", 667, NULL },
{ "onequarter", 834, NULL },
@@ -1095,14 +1328,18 @@ static BuiltinFontWidth helveticaWidthsTab[] = {
{ "I", 278, NULL },
{ "J", 500, NULL },
{ "K", 667, NULL },
+ { "iogonek", 222, NULL },
{ "backslash", 278, NULL },
{ "L", 556, NULL },
{ "periodcentered", 278, NULL },
{ "M", 833, NULL },
{ "N", 722, NULL },
+ { "omacron", 556, NULL },
+ { "Tcommaaccent", 611, NULL },
{ "O", 778, NULL },
{ "P", 667, NULL },
{ "Q", 778, NULL },
+ { "Uhungarumlaut", 722, NULL },
{ "R", 722, NULL },
{ "Aacute", 667, NULL },
{ "caron", 333, NULL },
@@ -1119,6 +1356,7 @@ static BuiltinFontWidth helveticaWidthsTab[] = {
{ "Z", 611, NULL },
{ "four", 556, NULL },
{ "a", 556, NULL },
+ { "Gcommaaccent", 778, NULL },
{ "b", 556, NULL },
{ "c", 500, NULL },
{ "d", 556, NULL },
@@ -1135,11 +1373,13 @@ static BuiltinFontWidth helveticaWidthsTab[] = {
{ "l", 222, NULL },
{ "m", 833, NULL },
{ "n", 556, NULL },
+ { "tcommaaccent", 278, NULL },
{ "o", 556, NULL },
{ "ordfeminine", 370, NULL },
{ "ring", 333, NULL },
{ "p", 556, NULL },
{ "q", 556, NULL },
+ { "uhungarumlaut", 556, NULL },
{ "r", 333, NULL },
{ "twosuperior", 333, NULL },
{ "aacute", 556, NULL },
@@ -1148,24 +1388,37 @@ static BuiltinFontWidth helveticaWidthsTab[] = {
{ "t", 278, NULL },
{ "divide", 584, NULL },
{ "u", 556, NULL },
+ { "Ccaron", 722, NULL },
{ "v", 500, NULL },
{ "w", 722, NULL },
{ "x", 500, NULL },
{ "y", 500, NULL },
{ "z", 500, NULL },
+ { "Gbreve", 778, NULL },
+ { "commaaccent", 250, NULL },
{ "hungarumlaut", 333, NULL },
+ { "Idotaccent", 278, NULL },
+ { "Nacute", 722, NULL },
{ "quotedbl", 355, NULL },
+ { "gcommaaccent", 556, NULL },
{ "mu", 556, NULL },
+ { "greaterequal", 549, NULL },
{ "Scaron", 667, NULL },
{ "Lslash", 556, NULL },
{ "semicolon", 278, NULL },
{ "oslash", 611, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 471, NULL },
{ "parenright", 333, NULL },
+ { "ccaron", 500, NULL },
{ "Ecircumflex", 667, NULL },
+ { "gbreve", 556, NULL },
{ "trademark", 1000, NULL },
{ "daggerdbl", 556, NULL },
+ { "nacute", 556, NULL },
{ "macron", 333, NULL },
{ "Otilde", 778, NULL },
+ { "Emacron", 667, NULL },
{ "ellipsis", 1000, NULL },
{ "scaron", 500, NULL },
{ "AE", 1000, NULL },
@@ -1179,9 +1432,11 @@ static BuiltinFontWidth helveticaWidthsTab[] = {
{ "exclamdown", 333, NULL },
{ "endash", 556, NULL },
{ "oe", 944, NULL },
+ { "Abreve", 667, NULL },
+ { "Umacron", 722, NULL },
{ "ecircumflex", 556, NULL },
- { "copyright", 737, NULL },
{ "Adieresis", 667, NULL },
+ { "copyright", 737, NULL },
{ "Egrave", 667, NULL },
{ "slash", 278, NULL },
{ "Edieresis", 667, NULL },
@@ -1189,14 +1444,17 @@ static BuiltinFontWidth helveticaWidthsTab[] = {
{ "Idieresis", 278, NULL },
{ "parenleft", 333, NULL },
{ "one", 556, NULL },
- { "ucircumflex", 556, NULL },
+ { "emacron", 556, NULL },
{ "Odieresis", 778, NULL },
+ { "ucircumflex", 556, NULL },
{ "bracketleft", 278, NULL },
{ "Ugrave", 722, NULL },
{ "quoteright", 222, NULL },
{ "Udieresis", 722, NULL },
{ "perthousand", 1000, NULL },
{ "Ydieresis", 667, NULL },
+ { "umacron", 556, NULL },
+ { "abreve", 556, NULL },
{ "Eacute", 667, NULL },
{ "adieresis", 556, NULL },
{ "egrave", 556, NULL },
@@ -1212,111 +1470,173 @@ static BuiltinFontWidth helveticaWidthsTab[] = {
{ "five", 556, NULL },
{ "udieresis", 556, NULL },
{ "Zcaron", 611, NULL },
+ { "Scommaaccent", 667, NULL },
{ "threequarters", 834, NULL },
{ "guillemotright", 556, NULL },
- { "ydieresis", 500, NULL },
{ "Ccedilla", 722, NULL },
+ { "ydieresis", 500, NULL },
{ "tilde", 333, NULL },
{ "at", 1015, NULL },
{ "eacute", 556, NULL },
{ "underscore", 556, NULL },
+ { "Euro", 556, NULL },
+ { "Dcroat", 722, NULL },
{ "multiply", 584, NULL },
{ "zero", 556, NULL },
{ "eth", 556, NULL },
+ { "Scedilla", 667, NULL },
{ "Ograve", 778, NULL },
+ { "Racute", 722, NULL },
+ { "partialdiff", 476, NULL },
{ "uacute", 556, NULL },
{ "braceleft", 334, NULL },
{ "Thorn", 667, NULL },
{ "zcaron", 500, NULL },
+ { "scommaaccent", 500, NULL },
{ "ccedilla", 500, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 556, NULL },
{ "Ocircumflex", 778, NULL },
{ "Oacute", 778, NULL },
+ { "scedilla", 500, NULL },
{ "ogonek", 333, NULL },
{ "ograve", 556, NULL },
+ { "racute", 333, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 667, NULL },
{ "thorn", 556, NULL },
{ "degree", 400, NULL },
{ "registered", 737, NULL },
+ { "radical", 453, NULL },
{ "Aring", 667, NULL },
{ "percent", 889, NULL },
{ "six", 556, NULL },
{ "paragraph", 537, NULL },
+ { "dcaron", 643, NULL },
+ { "Uogonek", 722, NULL },
{ "two", 556, NULL },
+ { "summation", 600, NULL },
{ "Igrave", 278, NULL },
+ { "Lacute", 556, NULL },
{ "ocircumflex", 556, NULL },
{ "oacute", 556, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 556, NULL },
+ { "tcaron", 317, NULL },
+ { "eogonek", 556, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 778, NULL },
{ "asciicircum", 469, NULL },
{ "aring", 556, NULL },
{ "grave", 333, NULL },
+ { "uogonek", 556, NULL },
{ "bracketright", 278, NULL },
{ "Iacute", 278, NULL },
{ "ampersand", 667, NULL },
{ "igrave", 278, NULL },
+ { "lacute", 222, NULL },
+ { "Ncaron", 722, NULL },
{ "plus", 584, NULL },
+ { "uring", 556, NULL },
{ "quotesinglbase", 222, NULL },
+ { "lcommaaccent", 222, NULL },
{ "Yacute", 667, NULL },
+ { "ohungarumlaut", 556, NULL },
{ "threesuperior", 333, NULL },
{ "acute", 333, NULL },
{ "section", 556, NULL },
{ "dieresis", 333, NULL },
{ "iacute", 278, NULL },
{ "quotedblbase", 333, NULL },
+ { "ncaron", 556, NULL },
{ "florin", 556, NULL },
{ "yacute", 500, NULL },
+ { "Rcommaaccent", 722, NULL },
{ "fi", 500, NULL },
{ "fl", 500, NULL },
{ "Acircumflex", 667, NULL },
+ { "Cacute", 722, NULL },
{ "Icircumflex", 278, NULL },
{ "guillemotleft", 556, NULL },
{ "germandbls", 611, NULL },
+ { "Amacron", 667, NULL },
{ "seven", 556, NULL },
+ { "Sacute", 667, NULL },
{ "ordmasculine", 365, NULL },
{ "dotlessi", 278, NULL },
{ "sterling", 556, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 278, NULL },
+ { "rcommaaccent", 333, NULL },
+ { "Zdotaccent", 611, NULL },
{ "acircumflex", 556, NULL },
+ { "cacute", 500, NULL },
+ { "Ecaron", 667, NULL },
{ "icircumflex", 278, NULL },
{ "braceright", 334, NULL },
{ "quotedblright", 333, NULL },
+ { "amacron", 556, NULL },
+ { "sacute", 500, NULL },
+ { "imacron", 278, NULL },
{ "cent", 556, NULL },
{ "currency", 556, NULL },
{ "logicalnot", 584, NULL },
+ { "zdotaccent", 500, NULL },
{ "Atilde", 667, NULL },
{ "breve", 333, NULL },
{ "bar", 260, NULL },
{ "fraction", 167, NULL },
{ "less", 584, NULL },
+ { "ecaron", 556, NULL },
{ "guilsinglleft", 333, NULL },
{ "exclam", 278, NULL },
{ "period", 278, NULL },
+ { "Rcaron", 722, NULL },
+ { "Kcommaaccent", 667, NULL },
{ "greater", 584, NULL },
{ "atilde", 556, NULL },
{ "brokenbar", 260, NULL },
{ "quoteleft", 222, NULL },
+ { "Edotaccent", 667, NULL },
{ "onesuperior", 333, NULL }
};
static BuiltinFontWidth helveticaBoldWidthsTab[] = {
{ "Ntilde", 722, NULL },
+ { "rcaron", 389, NULL },
+ { "kcommaaccent", 556, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
{ "comma", 278, NULL },
{ "cedilla", 333, NULL },
{ "plusminus", 584, NULL },
{ "circumflex", 333, NULL },
{ "dotaccent", 333, NULL },
+ { "edotaccent", 556, NULL },
{ "asciitilde", 584, NULL },
{ "colon", 333, NULL },
{ "onehalf", 834, NULL },
{ "dollar", 556, NULL },
+ { "Lcaron", 611, NULL },
{ "ntilde", 611, NULL },
+ { "Aogonek", 722, NULL },
+ { "ncommaaccent", 611, NULL },
{ "minus", 584, NULL },
+ { "Iogonek", 278, NULL },
+ { "zacute", 500, NULL },
{ "yen", 556, NULL },
{ "space", 278, NULL },
+ { "Omacron", 778, NULL },
{ "questiondown", 611, NULL },
{ "emdash", 1000, NULL },
{ "Agrave", 722, NULL },
{ "three", 556, NULL },
{ "numbersign", 556, NULL },
+ { "lcaron", 400, NULL },
{ "A", 722, NULL },
{ "B", 722, NULL },
{ "C", 722, NULL },
+ { "aogonek", 556, NULL },
{ "D", 722, NULL },
{ "E", 667, NULL },
{ "onequarter", 834, NULL },
@@ -1326,14 +1646,18 @@ static BuiltinFontWidth helveticaBoldWidthsTab[] = {
{ "I", 278, NULL },
{ "J", 556, NULL },
{ "K", 722, NULL },
+ { "iogonek", 278, NULL },
{ "backslash", 278, NULL },
{ "L", 611, NULL },
{ "periodcentered", 278, NULL },
{ "M", 833, NULL },
{ "N", 722, NULL },
+ { "omacron", 611, NULL },
+ { "Tcommaaccent", 611, NULL },
{ "O", 778, NULL },
{ "P", 667, NULL },
{ "Q", 778, NULL },
+ { "Uhungarumlaut", 722, NULL },
{ "R", 722, NULL },
{ "Aacute", 722, NULL },
{ "caron", 333, NULL },
@@ -1350,6 +1674,7 @@ static BuiltinFontWidth helveticaBoldWidthsTab[] = {
{ "Z", 611, NULL },
{ "four", 556, NULL },
{ "a", 556, NULL },
+ { "Gcommaaccent", 778, NULL },
{ "b", 611, NULL },
{ "c", 556, NULL },
{ "d", 611, NULL },
@@ -1366,11 +1691,13 @@ static BuiltinFontWidth helveticaBoldWidthsTab[] = {
{ "l", 278, NULL },
{ "m", 889, NULL },
{ "n", 611, NULL },
+ { "tcommaaccent", 333, NULL },
{ "o", 611, NULL },
{ "ordfeminine", 370, NULL },
{ "ring", 333, NULL },
{ "p", 611, NULL },
{ "q", 611, NULL },
+ { "uhungarumlaut", 611, NULL },
{ "r", 389, NULL },
{ "twosuperior", 333, NULL },
{ "aacute", 556, NULL },
@@ -1379,24 +1706,37 @@ static BuiltinFontWidth helveticaBoldWidthsTab[] = {
{ "t", 333, NULL },
{ "divide", 584, NULL },
{ "u", 611, NULL },
+ { "Ccaron", 722, NULL },
{ "v", 556, NULL },
{ "w", 778, NULL },
{ "x", 556, NULL },
{ "y", 556, NULL },
{ "z", 500, NULL },
+ { "Gbreve", 778, NULL },
+ { "commaaccent", 250, NULL },
{ "hungarumlaut", 333, NULL },
+ { "Idotaccent", 278, NULL },
+ { "Nacute", 722, NULL },
{ "quotedbl", 474, NULL },
+ { "gcommaaccent", 611, NULL },
{ "mu", 611, NULL },
+ { "greaterequal", 549, NULL },
{ "Scaron", 667, NULL },
{ "Lslash", 611, NULL },
{ "semicolon", 333, NULL },
{ "oslash", 611, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 494, NULL },
{ "parenright", 333, NULL },
+ { "ccaron", 556, NULL },
{ "Ecircumflex", 667, NULL },
+ { "gbreve", 611, NULL },
{ "trademark", 1000, NULL },
{ "daggerdbl", 556, NULL },
+ { "nacute", 611, NULL },
{ "macron", 333, NULL },
{ "Otilde", 778, NULL },
+ { "Emacron", 667, NULL },
{ "ellipsis", 1000, NULL },
{ "scaron", 556, NULL },
{ "AE", 1000, NULL },
@@ -1410,9 +1750,11 @@ static BuiltinFontWidth helveticaBoldWidthsTab[] = {
{ "exclamdown", 333, NULL },
{ "endash", 556, NULL },
{ "oe", 944, NULL },
+ { "Abreve", 722, NULL },
+ { "Umacron", 722, NULL },
{ "ecircumflex", 556, NULL },
- { "copyright", 737, NULL },
{ "Adieresis", 722, NULL },
+ { "copyright", 737, NULL },
{ "Egrave", 667, NULL },
{ "slash", 278, NULL },
{ "Edieresis", 667, NULL },
@@ -1420,14 +1762,17 @@ static BuiltinFontWidth helveticaBoldWidthsTab[] = {
{ "Idieresis", 278, NULL },
{ "parenleft", 333, NULL },
{ "one", 556, NULL },
- { "ucircumflex", 611, NULL },
+ { "emacron", 556, NULL },
{ "Odieresis", 778, NULL },
+ { "ucircumflex", 611, NULL },
{ "bracketleft", 333, NULL },
{ "Ugrave", 722, NULL },
{ "quoteright", 278, NULL },
{ "Udieresis", 722, NULL },
{ "perthousand", 1000, NULL },
{ "Ydieresis", 667, NULL },
+ { "umacron", 611, NULL },
+ { "abreve", 556, NULL },
{ "Eacute", 667, NULL },
{ "adieresis", 556, NULL },
{ "egrave", 556, NULL },
@@ -1443,112 +1788,174 @@ static BuiltinFontWidth helveticaBoldWidthsTab[] = {
{ "five", 556, NULL },
{ "udieresis", 611, NULL },
{ "Zcaron", 611, NULL },
+ { "Scommaaccent", 667, NULL },
{ "threequarters", 834, NULL },
{ "guillemotright", 556, NULL },
- { "ydieresis", 556, NULL },
{ "Ccedilla", 722, NULL },
+ { "ydieresis", 556, NULL },
{ "tilde", 333, NULL },
{ "dbldaggerumlaut", 556, NULL },
{ "at", 975, NULL },
{ "eacute", 556, NULL },
{ "underscore", 556, NULL },
+ { "Euro", 556, NULL },
+ { "Dcroat", 722, NULL },
{ "multiply", 584, NULL },
{ "zero", 556, NULL },
{ "eth", 611, NULL },
+ { "Scedilla", 667, NULL },
{ "Ograve", 778, NULL },
+ { "Racute", 722, NULL },
+ { "partialdiff", 494, NULL },
{ "uacute", 611, NULL },
{ "braceleft", 389, NULL },
{ "Thorn", 667, NULL },
{ "zcaron", 500, NULL },
+ { "scommaaccent", 556, NULL },
{ "ccedilla", 556, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 611, NULL },
{ "Ocircumflex", 778, NULL },
{ "Oacute", 778, NULL },
+ { "scedilla", 556, NULL },
{ "ogonek", 333, NULL },
{ "ograve", 611, NULL },
+ { "racute", 389, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 667, NULL },
{ "thorn", 611, NULL },
{ "degree", 400, NULL },
{ "registered", 737, NULL },
+ { "radical", 549, NULL },
{ "Aring", 722, NULL },
{ "percent", 889, NULL },
{ "six", 556, NULL },
{ "paragraph", 556, NULL },
+ { "dcaron", 743, NULL },
+ { "Uogonek", 722, NULL },
{ "two", 556, NULL },
+ { "summation", 600, NULL },
{ "Igrave", 278, NULL },
+ { "Lacute", 611, NULL },
{ "ocircumflex", 611, NULL },
{ "oacute", 611, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 611, NULL },
+ { "tcaron", 389, NULL },
+ { "eogonek", 556, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 778, NULL },
{ "asciicircum", 584, NULL },
{ "aring", 556, NULL },
{ "grave", 333, NULL },
+ { "uogonek", 611, NULL },
{ "bracketright", 333, NULL },
{ "Iacute", 278, NULL },
{ "ampersand", 722, NULL },
{ "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 722, NULL },
{ "plus", 584, NULL },
+ { "uring", 611, NULL },
{ "quotesinglbase", 278, NULL },
+ { "lcommaaccent", 278, NULL },
{ "Yacute", 667, NULL },
+ { "ohungarumlaut", 611, NULL },
{ "threesuperior", 333, NULL },
{ "acute", 333, NULL },
{ "section", 556, NULL },
{ "dieresis", 333, NULL },
{ "iacute", 278, NULL },
{ "quotedblbase", 500, NULL },
+ { "ncaron", 611, NULL },
{ "florin", 556, NULL },
{ "yacute", 556, NULL },
+ { "Rcommaaccent", 722, NULL },
{ "fi", 611, NULL },
{ "fl", 611, NULL },
{ "Acircumflex", 722, NULL },
+ { "Cacute", 722, NULL },
{ "Icircumflex", 278, NULL },
{ "guillemotleft", 556, NULL },
{ "germandbls", 611, NULL },
+ { "Amacron", 722, NULL },
{ "seven", 556, NULL },
+ { "Sacute", 667, NULL },
{ "ordmasculine", 365, NULL },
{ "dotlessi", 278, NULL },
{ "sterling", 556, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 278, NULL },
+ { "rcommaaccent", 389, NULL },
+ { "Zdotaccent", 611, NULL },
{ "acircumflex", 556, NULL },
+ { "cacute", 556, NULL },
+ { "Ecaron", 667, NULL },
{ "icircumflex", 278, NULL },
{ "braceright", 389, NULL },
{ "quotedblright", 500, NULL },
+ { "amacron", 556, NULL },
+ { "sacute", 556, NULL },
+ { "imacron", 278, NULL },
{ "cent", 556, NULL },
{ "currency", 556, NULL },
{ "logicalnot", 584, NULL },
+ { "zdotaccent", 500, NULL },
{ "Atilde", 722, NULL },
{ "breve", 333, NULL },
{ "bar", 280, NULL },
{ "fraction", 167, NULL },
{ "less", 584, NULL },
+ { "ecaron", 556, NULL },
{ "guilsinglleft", 333, NULL },
{ "exclam", 333, NULL },
{ "period", 278, NULL },
+ { "Rcaron", 722, NULL },
+ { "Kcommaaccent", 722, NULL },
{ "greater", 584, NULL },
{ "atilde", 556, NULL },
{ "brokenbar", 280, NULL },
{ "quoteleft", 278, NULL },
+ { "Edotaccent", 667, NULL },
{ "onesuperior", 333, NULL }
};
static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = {
{ "Ntilde", 722, NULL },
+ { "rcaron", 389, NULL },
+ { "kcommaaccent", 556, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
{ "comma", 278, NULL },
{ "cedilla", 333, NULL },
{ "plusminus", 584, NULL },
{ "circumflex", 333, NULL },
{ "dotaccent", 333, NULL },
+ { "edotaccent", 556, NULL },
{ "asciitilde", 584, NULL },
{ "colon", 333, NULL },
{ "onehalf", 834, NULL },
{ "dollar", 556, NULL },
+ { "Lcaron", 611, NULL },
{ "ntilde", 611, NULL },
+ { "Aogonek", 722, NULL },
+ { "ncommaaccent", 611, NULL },
{ "minus", 584, NULL },
+ { "Iogonek", 278, NULL },
+ { "zacute", 500, NULL },
{ "yen", 556, NULL },
{ "space", 278, NULL },
+ { "Omacron", 778, NULL },
{ "questiondown", 611, NULL },
{ "emdash", 1000, NULL },
{ "Agrave", 722, NULL },
{ "three", 556, NULL },
{ "numbersign", 556, NULL },
+ { "lcaron", 400, NULL },
{ "A", 722, NULL },
{ "B", 722, NULL },
{ "C", 722, NULL },
+ { "aogonek", 556, NULL },
{ "D", 722, NULL },
{ "E", 667, NULL },
{ "onequarter", 834, NULL },
@@ -1558,14 +1965,18 @@ static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = {
{ "I", 278, NULL },
{ "J", 556, NULL },
{ "K", 722, NULL },
+ { "iogonek", 278, NULL },
{ "backslash", 278, NULL },
{ "L", 611, NULL },
{ "periodcentered", 278, NULL },
{ "M", 833, NULL },
{ "N", 722, NULL },
+ { "omacron", 611, NULL },
+ { "Tcommaaccent", 611, NULL },
{ "O", 778, NULL },
{ "P", 667, NULL },
{ "Q", 778, NULL },
+ { "Uhungarumlaut", 722, NULL },
{ "R", 722, NULL },
{ "Aacute", 722, NULL },
{ "caron", 333, NULL },
@@ -1582,6 +1993,7 @@ static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = {
{ "Z", 611, NULL },
{ "four", 556, NULL },
{ "a", 556, NULL },
+ { "Gcommaaccent", 778, NULL },
{ "b", 611, NULL },
{ "c", 556, NULL },
{ "d", 611, NULL },
@@ -1598,11 +2010,13 @@ static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = {
{ "l", 278, NULL },
{ "m", 889, NULL },
{ "n", 611, NULL },
+ { "tcommaaccent", 333, NULL },
{ "o", 611, NULL },
{ "ordfeminine", 370, NULL },
{ "ring", 333, NULL },
{ "p", 611, NULL },
{ "q", 611, NULL },
+ { "uhungarumlaut", 611, NULL },
{ "r", 389, NULL },
{ "twosuperior", 333, NULL },
{ "aacute", 556, NULL },
@@ -1611,24 +2025,37 @@ static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = {
{ "t", 333, NULL },
{ "divide", 584, NULL },
{ "u", 611, NULL },
+ { "Ccaron", 722, NULL },
{ "v", 556, NULL },
{ "w", 778, NULL },
{ "x", 556, NULL },
{ "y", 556, NULL },
{ "z", 500, NULL },
+ { "Gbreve", 778, NULL },
+ { "commaaccent", 250, NULL },
{ "hungarumlaut", 333, NULL },
+ { "Idotaccent", 278, NULL },
+ { "Nacute", 722, NULL },
{ "quotedbl", 474, NULL },
+ { "gcommaaccent", 611, NULL },
{ "mu", 611, NULL },
+ { "greaterequal", 549, NULL },
{ "Scaron", 667, NULL },
{ "Lslash", 611, NULL },
{ "semicolon", 333, NULL },
{ "oslash", 611, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 494, NULL },
{ "parenright", 333, NULL },
+ { "ccaron", 556, NULL },
{ "Ecircumflex", 667, NULL },
+ { "gbreve", 611, NULL },
{ "trademark", 1000, NULL },
{ "daggerdbl", 556, NULL },
+ { "nacute", 611, NULL },
{ "macron", 333, NULL },
{ "Otilde", 778, NULL },
+ { "Emacron", 667, NULL },
{ "ellipsis", 1000, NULL },
{ "scaron", 556, NULL },
{ "AE", 1000, NULL },
@@ -1642,9 +2069,11 @@ static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = {
{ "exclamdown", 333, NULL },
{ "endash", 556, NULL },
{ "oe", 944, NULL },
+ { "Abreve", 722, NULL },
+ { "Umacron", 722, NULL },
{ "ecircumflex", 556, NULL },
- { "copyright", 737, NULL },
{ "Adieresis", 722, NULL },
+ { "copyright", 737, NULL },
{ "Egrave", 667, NULL },
{ "slash", 278, NULL },
{ "Edieresis", 667, NULL },
@@ -1652,14 +2081,17 @@ static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = {
{ "Idieresis", 278, NULL },
{ "parenleft", 333, NULL },
{ "one", 556, NULL },
- { "ucircumflex", 611, NULL },
+ { "emacron", 556, NULL },
{ "Odieresis", 778, NULL },
+ { "ucircumflex", 611, NULL },
{ "bracketleft", 333, NULL },
{ "Ugrave", 722, NULL },
{ "quoteright", 278, NULL },
{ "Udieresis", 722, NULL },
{ "perthousand", 1000, NULL },
{ "Ydieresis", 667, NULL },
+ { "umacron", 611, NULL },
+ { "abreve", 556, NULL },
{ "Eacute", 667, NULL },
{ "adieresis", 556, NULL },
{ "egrave", 556, NULL },
@@ -1675,111 +2107,173 @@ static BuiltinFontWidth helveticaBoldObliqueWidthsTab[] = {
{ "five", 556, NULL },
{ "udieresis", 611, NULL },
{ "Zcaron", 611, NULL },
+ { "Scommaaccent", 667, NULL },
{ "threequarters", 834, NULL },
{ "guillemotright", 556, NULL },
- { "ydieresis", 556, NULL },
{ "Ccedilla", 722, NULL },
+ { "ydieresis", 556, NULL },
{ "tilde", 333, NULL },
{ "at", 975, NULL },
{ "eacute", 556, NULL },
{ "underscore", 556, NULL },
+ { "Euro", 556, NULL },
+ { "Dcroat", 722, NULL },
{ "multiply", 584, NULL },
{ "zero", 556, NULL },
{ "eth", 611, NULL },
+ { "Scedilla", 667, NULL },
{ "Ograve", 778, NULL },
+ { "Racute", 722, NULL },
+ { "partialdiff", 494, NULL },
{ "uacute", 611, NULL },
{ "braceleft", 389, NULL },
{ "Thorn", 667, NULL },
{ "zcaron", 500, NULL },
+ { "scommaaccent", 556, NULL },
{ "ccedilla", 556, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 611, NULL },
{ "Ocircumflex", 778, NULL },
{ "Oacute", 778, NULL },
+ { "scedilla", 556, NULL },
{ "ogonek", 333, NULL },
{ "ograve", 611, NULL },
+ { "racute", 389, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 667, NULL },
{ "thorn", 611, NULL },
{ "degree", 400, NULL },
{ "registered", 737, NULL },
+ { "radical", 549, NULL },
{ "Aring", 722, NULL },
{ "percent", 889, NULL },
{ "six", 556, NULL },
{ "paragraph", 556, NULL },
+ { "dcaron", 743, NULL },
+ { "Uogonek", 722, NULL },
{ "two", 556, NULL },
+ { "summation", 600, NULL },
{ "Igrave", 278, NULL },
+ { "Lacute", 611, NULL },
{ "ocircumflex", 611, NULL },
{ "oacute", 611, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 611, NULL },
+ { "tcaron", 389, NULL },
+ { "eogonek", 556, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 778, NULL },
{ "asciicircum", 584, NULL },
{ "aring", 556, NULL },
{ "grave", 333, NULL },
+ { "uogonek", 611, NULL },
{ "bracketright", 333, NULL },
{ "Iacute", 278, NULL },
{ "ampersand", 722, NULL },
{ "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 722, NULL },
{ "plus", 584, NULL },
+ { "uring", 611, NULL },
{ "quotesinglbase", 278, NULL },
+ { "lcommaaccent", 278, NULL },
{ "Yacute", 667, NULL },
+ { "ohungarumlaut", 611, NULL },
{ "threesuperior", 333, NULL },
{ "acute", 333, NULL },
{ "section", 556, NULL },
{ "dieresis", 333, NULL },
{ "iacute", 278, NULL },
{ "quotedblbase", 500, NULL },
+ { "ncaron", 611, NULL },
{ "florin", 556, NULL },
{ "yacute", 556, NULL },
+ { "Rcommaaccent", 722, NULL },
{ "fi", 611, NULL },
{ "fl", 611, NULL },
{ "Acircumflex", 722, NULL },
+ { "Cacute", 722, NULL },
{ "Icircumflex", 278, NULL },
{ "guillemotleft", 556, NULL },
{ "germandbls", 611, NULL },
+ { "Amacron", 722, NULL },
{ "seven", 556, NULL },
+ { "Sacute", 667, NULL },
{ "ordmasculine", 365, NULL },
{ "dotlessi", 278, NULL },
{ "sterling", 556, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 278, NULL },
+ { "rcommaaccent", 389, NULL },
+ { "Zdotaccent", 611, NULL },
{ "acircumflex", 556, NULL },
+ { "cacute", 556, NULL },
+ { "Ecaron", 667, NULL },
{ "icircumflex", 278, NULL },
{ "braceright", 389, NULL },
{ "quotedblright", 500, NULL },
+ { "amacron", 556, NULL },
+ { "sacute", 556, NULL },
+ { "imacron", 278, NULL },
{ "cent", 556, NULL },
{ "currency", 556, NULL },
{ "logicalnot", 584, NULL },
+ { "zdotaccent", 500, NULL },
{ "Atilde", 722, NULL },
{ "breve", 333, NULL },
{ "bar", 280, NULL },
{ "fraction", 167, NULL },
{ "less", 584, NULL },
+ { "ecaron", 556, NULL },
{ "guilsinglleft", 333, NULL },
{ "exclam", 333, NULL },
{ "period", 278, NULL },
+ { "Rcaron", 722, NULL },
+ { "Kcommaaccent", 722, NULL },
{ "greater", 584, NULL },
{ "atilde", 556, NULL },
{ "brokenbar", 280, NULL },
{ "quoteleft", 278, NULL },
+ { "Edotaccent", 667, NULL },
{ "onesuperior", 333, NULL }
};
static BuiltinFontWidth helveticaObliqueWidthsTab[] = {
{ "Ntilde", 722, NULL },
+ { "rcaron", 333, NULL },
+ { "kcommaaccent", 500, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
{ "comma", 278, NULL },
{ "cedilla", 333, NULL },
{ "plusminus", 584, NULL },
{ "circumflex", 333, NULL },
{ "dotaccent", 333, NULL },
+ { "edotaccent", 556, NULL },
{ "asciitilde", 584, NULL },
{ "colon", 278, NULL },
{ "onehalf", 834, NULL },
{ "dollar", 556, NULL },
+ { "Lcaron", 556, NULL },
{ "ntilde", 556, NULL },
+ { "Aogonek", 667, NULL },
+ { "ncommaaccent", 556, NULL },
{ "minus", 584, NULL },
+ { "Iogonek", 278, NULL },
+ { "zacute", 500, NULL },
{ "yen", 556, NULL },
{ "space", 278, NULL },
+ { "Omacron", 778, NULL },
{ "questiondown", 611, NULL },
{ "emdash", 1000, NULL },
{ "Agrave", 667, NULL },
{ "three", 556, NULL },
{ "numbersign", 556, NULL },
+ { "lcaron", 299, NULL },
{ "A", 667, NULL },
{ "B", 667, NULL },
{ "C", 722, NULL },
+ { "aogonek", 556, NULL },
{ "D", 722, NULL },
{ "E", 667, NULL },
{ "onequarter", 834, NULL },
@@ -1789,14 +2283,18 @@ static BuiltinFontWidth helveticaObliqueWidthsTab[] = {
{ "I", 278, NULL },
{ "J", 500, NULL },
{ "K", 667, NULL },
+ { "iogonek", 222, NULL },
{ "backslash", 278, NULL },
{ "L", 556, NULL },
{ "periodcentered", 278, NULL },
{ "M", 833, NULL },
{ "N", 722, NULL },
+ { "omacron", 556, NULL },
+ { "Tcommaaccent", 611, NULL },
{ "O", 778, NULL },
{ "P", 667, NULL },
{ "Q", 778, NULL },
+ { "Uhungarumlaut", 722, NULL },
{ "R", 722, NULL },
{ "Aacute", 667, NULL },
{ "caron", 333, NULL },
@@ -1813,6 +2311,7 @@ static BuiltinFontWidth helveticaObliqueWidthsTab[] = {
{ "Z", 611, NULL },
{ "four", 556, NULL },
{ "a", 556, NULL },
+ { "Gcommaaccent", 778, NULL },
{ "b", 556, NULL },
{ "c", 500, NULL },
{ "d", 556, NULL },
@@ -1829,11 +2328,13 @@ static BuiltinFontWidth helveticaObliqueWidthsTab[] = {
{ "l", 222, NULL },
{ "m", 833, NULL },
{ "n", 556, NULL },
+ { "tcommaaccent", 278, NULL },
{ "o", 556, NULL },
{ "ordfeminine", 370, NULL },
{ "ring", 333, NULL },
{ "p", 556, NULL },
{ "q", 556, NULL },
+ { "uhungarumlaut", 556, NULL },
{ "r", 333, NULL },
{ "twosuperior", 333, NULL },
{ "aacute", 556, NULL },
@@ -1842,24 +2343,37 @@ static BuiltinFontWidth helveticaObliqueWidthsTab[] = {
{ "t", 278, NULL },
{ "divide", 584, NULL },
{ "u", 556, NULL },
+ { "Ccaron", 722, NULL },
{ "v", 500, NULL },
{ "w", 722, NULL },
{ "x", 500, NULL },
{ "y", 500, NULL },
{ "z", 500, NULL },
+ { "Gbreve", 778, NULL },
+ { "commaaccent", 250, NULL },
{ "hungarumlaut", 333, NULL },
+ { "Idotaccent", 278, NULL },
+ { "Nacute", 722, NULL },
{ "quotedbl", 355, NULL },
+ { "gcommaaccent", 556, NULL },
{ "mu", 556, NULL },
+ { "greaterequal", 549, NULL },
{ "Scaron", 667, NULL },
{ "Lslash", 556, NULL },
{ "semicolon", 278, NULL },
{ "oslash", 611, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 471, NULL },
{ "parenright", 333, NULL },
+ { "ccaron", 500, NULL },
{ "Ecircumflex", 667, NULL },
+ { "gbreve", 556, NULL },
{ "trademark", 1000, NULL },
{ "daggerdbl", 556, NULL },
+ { "nacute", 556, NULL },
{ "macron", 333, NULL },
{ "Otilde", 778, NULL },
+ { "Emacron", 667, NULL },
{ "ellipsis", 1000, NULL },
{ "scaron", 500, NULL },
{ "AE", 1000, NULL },
@@ -1873,9 +2387,11 @@ static BuiltinFontWidth helveticaObliqueWidthsTab[] = {
{ "exclamdown", 333, NULL },
{ "endash", 556, NULL },
{ "oe", 944, NULL },
+ { "Abreve", 667, NULL },
+ { "Umacron", 722, NULL },
{ "ecircumflex", 556, NULL },
- { "copyright", 737, NULL },
{ "Adieresis", 667, NULL },
+ { "copyright", 737, NULL },
{ "Egrave", 667, NULL },
{ "slash", 278, NULL },
{ "Edieresis", 667, NULL },
@@ -1883,14 +2399,17 @@ static BuiltinFontWidth helveticaObliqueWidthsTab[] = {
{ "Idieresis", 278, NULL },
{ "parenleft", 333, NULL },
{ "one", 556, NULL },
- { "ucircumflex", 556, NULL },
+ { "emacron", 556, NULL },
{ "Odieresis", 778, NULL },
+ { "ucircumflex", 556, NULL },
{ "bracketleft", 278, NULL },
{ "Ugrave", 722, NULL },
{ "quoteright", 222, NULL },
{ "Udieresis", 722, NULL },
{ "perthousand", 1000, NULL },
{ "Ydieresis", 667, NULL },
+ { "umacron", 556, NULL },
+ { "abreve", 556, NULL },
{ "Eacute", 667, NULL },
{ "adieresis", 556, NULL },
{ "egrave", 556, NULL },
@@ -1906,85 +2425,134 @@ static BuiltinFontWidth helveticaObliqueWidthsTab[] = {
{ "five", 556, NULL },
{ "udieresis", 556, NULL },
{ "Zcaron", 611, NULL },
+ { "Scommaaccent", 667, NULL },
{ "threequarters", 834, NULL },
{ "guillemotright", 556, NULL },
- { "ydieresis", 500, NULL },
{ "Ccedilla", 722, NULL },
+ { "ydieresis", 500, NULL },
{ "tilde", 333, NULL },
{ "at", 1015, NULL },
{ "eacute", 556, NULL },
{ "underscore", 556, NULL },
+ { "Euro", 556, NULL },
+ { "Dcroat", 722, NULL },
{ "multiply", 584, NULL },
{ "zero", 556, NULL },
{ "eth", 556, NULL },
+ { "Scedilla", 667, NULL },
{ "Ograve", 778, NULL },
+ { "Racute", 722, NULL },
+ { "partialdiff", 476, NULL },
{ "uacute", 556, NULL },
{ "braceleft", 334, NULL },
{ "Thorn", 667, NULL },
{ "zcaron", 500, NULL },
+ { "scommaaccent", 500, NULL },
{ "ccedilla", 500, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 556, NULL },
{ "Ocircumflex", 778, NULL },
{ "Oacute", 778, NULL },
+ { "scedilla", 500, NULL },
{ "ogonek", 333, NULL },
{ "ograve", 556, NULL },
+ { "racute", 333, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 667, NULL },
{ "thorn", 556, NULL },
{ "degree", 400, NULL },
{ "registered", 737, NULL },
+ { "radical", 453, NULL },
{ "Aring", 667, NULL },
{ "percent", 889, NULL },
{ "six", 556, NULL },
{ "paragraph", 537, NULL },
+ { "dcaron", 643, NULL },
+ { "Uogonek", 722, NULL },
{ "two", 556, NULL },
+ { "summation", 600, NULL },
{ "Igrave", 278, NULL },
+ { "Lacute", 556, NULL },
{ "ocircumflex", 556, NULL },
{ "oacute", 556, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 556, NULL },
+ { "tcaron", 317, NULL },
+ { "eogonek", 556, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 778, NULL },
{ "asciicircum", 469, NULL },
{ "aring", 556, NULL },
{ "grave", 333, NULL },
+ { "uogonek", 556, NULL },
{ "bracketright", 278, NULL },
{ "Iacute", 278, NULL },
{ "ampersand", 667, NULL },
{ "igrave", 278, NULL },
+ { "lacute", 222, NULL },
+ { "Ncaron", 722, NULL },
{ "plus", 584, NULL },
+ { "uring", 556, NULL },
{ "quotesinglbase", 222, NULL },
+ { "lcommaaccent", 222, NULL },
{ "Yacute", 667, NULL },
+ { "ohungarumlaut", 556, NULL },
{ "threesuperior", 333, NULL },
{ "acute", 333, NULL },
{ "section", 556, NULL },
{ "dieresis", 333, NULL },
{ "iacute", 278, NULL },
{ "quotedblbase", 333, NULL },
+ { "ncaron", 556, NULL },
{ "florin", 556, NULL },
{ "yacute", 500, NULL },
+ { "Rcommaaccent", 722, NULL },
{ "fi", 500, NULL },
{ "fl", 500, NULL },
{ "Acircumflex", 667, NULL },
+ { "Cacute", 722, NULL },
{ "Icircumflex", 278, NULL },
{ "guillemotleft", 556, NULL },
{ "germandbls", 611, NULL },
+ { "Amacron", 667, NULL },
{ "seven", 556, NULL },
+ { "Sacute", 667, NULL },
{ "ordmasculine", 365, NULL },
{ "dotlessi", 278, NULL },
{ "sterling", 556, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 278, NULL },
+ { "rcommaaccent", 333, NULL },
+ { "Zdotaccent", 611, NULL },
{ "acircumflex", 556, NULL },
+ { "cacute", 500, NULL },
+ { "Ecaron", 667, NULL },
{ "icircumflex", 278, NULL },
{ "braceright", 334, NULL },
{ "quotedblright", 333, NULL },
+ { "amacron", 556, NULL },
+ { "sacute", 500, NULL },
+ { "imacron", 278, NULL },
{ "cent", 556, NULL },
{ "currency", 556, NULL },
{ "logicalnot", 584, NULL },
+ { "zdotaccent", 500, NULL },
{ "Atilde", 667, NULL },
{ "breve", 333, NULL },
{ "bar", 260, NULL },
{ "fraction", 167, NULL },
{ "less", 584, NULL },
+ { "ecaron", 556, NULL },
{ "guilsinglleft", 333, NULL },
{ "exclam", 278, NULL },
{ "period", 278, NULL },
+ { "Rcaron", 722, NULL },
+ { "Kcommaaccent", 667, NULL },
{ "greater", 584, NULL },
{ "atilde", 556, NULL },
{ "brokenbar", 260, NULL },
{ "quoteleft", 222, NULL },
+ { "Edotaccent", 667, NULL },
{ "onesuperior", 333, NULL }
};
@@ -2099,6 +2667,7 @@ static BuiltinFontWidth symbolWidthsTab[] = {
{ "parenrighttp", 384, NULL },
{ "eta", 603, NULL },
{ "underscore", 500, NULL },
+ { "Euro", 750, NULL },
{ "multiply", 549, NULL },
{ "zero", 500, NULL },
{ "partialdiff", 494, NULL },
@@ -2182,27 +2751,40 @@ static BuiltinFontWidth symbolWidthsTab[] = {
static BuiltinFontWidth timesBoldWidthsTab[] = {
{ "Ntilde", 722, NULL },
+ { "rcaron", 444, NULL },
+ { "kcommaaccent", 556, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 667, NULL },
{ "comma", 250, NULL },
{ "cedilla", 333, NULL },
{ "plusminus", 570, NULL },
{ "circumflex", 333, NULL },
{ "dotaccent", 333, NULL },
+ { "edotaccent", 444, NULL },
{ "asciitilde", 520, NULL },
{ "colon", 333, NULL },
{ "onehalf", 750, NULL },
{ "dollar", 500, NULL },
+ { "Lcaron", 667, NULL },
{ "ntilde", 556, NULL },
+ { "Aogonek", 722, NULL },
+ { "ncommaaccent", 556, NULL },
{ "minus", 570, NULL },
+ { "Iogonek", 389, NULL },
+ { "zacute", 444, NULL },
{ "yen", 500, NULL },
{ "space", 250, NULL },
+ { "Omacron", 778, NULL },
{ "questiondown", 500, NULL },
{ "emdash", 1000, NULL },
{ "Agrave", 722, NULL },
{ "three", 500, NULL },
{ "numbersign", 500, NULL },
+ { "lcaron", 394, NULL },
{ "A", 722, NULL },
{ "B", 667, NULL },
{ "C", 722, NULL },
+ { "aogonek", 500, NULL },
{ "D", 722, NULL },
{ "E", 667, NULL },
{ "onequarter", 750, NULL },
@@ -2212,14 +2794,18 @@ static BuiltinFontWidth timesBoldWidthsTab[] = {
{ "I", 389, NULL },
{ "J", 500, NULL },
{ "K", 778, NULL },
+ { "iogonek", 278, NULL },
{ "backslash", 278, NULL },
{ "L", 667, NULL },
{ "periodcentered", 250, NULL },
{ "M", 944, NULL },
{ "N", 722, NULL },
+ { "omacron", 500, NULL },
+ { "Tcommaaccent", 667, NULL },
{ "O", 778, NULL },
{ "P", 611, NULL },
{ "Q", 778, NULL },
+ { "Uhungarumlaut", 722, NULL },
{ "R", 722, NULL },
{ "Aacute", 722, NULL },
{ "caron", 333, NULL },
@@ -2236,6 +2822,7 @@ static BuiltinFontWidth timesBoldWidthsTab[] = {
{ "Z", 667, NULL },
{ "four", 500, NULL },
{ "a", 500, NULL },
+ { "Gcommaaccent", 778, NULL },
{ "b", 556, NULL },
{ "c", 444, NULL },
{ "d", 556, NULL },
@@ -2252,11 +2839,13 @@ static BuiltinFontWidth timesBoldWidthsTab[] = {
{ "l", 278, NULL },
{ "m", 833, NULL },
{ "n", 556, NULL },
+ { "tcommaaccent", 333, NULL },
{ "o", 500, NULL },
{ "ordfeminine", 300, NULL },
{ "ring", 333, NULL },
{ "p", 556, NULL },
{ "q", 556, NULL },
+ { "uhungarumlaut", 556, NULL },
{ "r", 444, NULL },
{ "twosuperior", 300, NULL },
{ "aacute", 500, NULL },
@@ -2265,24 +2854,37 @@ static BuiltinFontWidth timesBoldWidthsTab[] = {
{ "t", 333, NULL },
{ "divide", 570, NULL },
{ "u", 556, NULL },
+ { "Ccaron", 722, NULL },
{ "v", 500, NULL },
{ "w", 722, NULL },
{ "x", 500, NULL },
{ "y", 500, NULL },
{ "z", 444, NULL },
+ { "Gbreve", 778, NULL },
+ { "commaaccent", 250, NULL },
{ "hungarumlaut", 333, NULL },
+ { "Idotaccent", 389, NULL },
+ { "Nacute", 722, NULL },
{ "quotedbl", 555, NULL },
+ { "gcommaaccent", 500, NULL },
{ "mu", 556, NULL },
+ { "greaterequal", 549, NULL },
{ "Scaron", 556, NULL },
{ "Lslash", 667, NULL },
{ "semicolon", 333, NULL },
{ "oslash", 500, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 494, NULL },
{ "parenright", 333, NULL },
+ { "ccaron", 444, NULL },
{ "Ecircumflex", 667, NULL },
+ { "gbreve", 500, NULL },
{ "trademark", 1000, NULL },
{ "daggerdbl", 500, NULL },
+ { "nacute", 556, NULL },
{ "macron", 333, NULL },
{ "Otilde", 778, NULL },
+ { "Emacron", 667, NULL },
{ "ellipsis", 1000, NULL },
{ "scaron", 389, NULL },
{ "AE", 1000, NULL },
@@ -2296,9 +2898,11 @@ static BuiltinFontWidth timesBoldWidthsTab[] = {
{ "exclamdown", 333, NULL },
{ "endash", 500, NULL },
{ "oe", 722, NULL },
+ { "Abreve", 722, NULL },
+ { "Umacron", 722, NULL },
{ "ecircumflex", 444, NULL },
- { "copyright", 747, NULL },
{ "Adieresis", 722, NULL },
+ { "copyright", 747, NULL },
{ "Egrave", 667, NULL },
{ "slash", 278, NULL },
{ "Edieresis", 667, NULL },
@@ -2306,14 +2910,17 @@ static BuiltinFontWidth timesBoldWidthsTab[] = {
{ "Idieresis", 389, NULL },
{ "parenleft", 333, NULL },
{ "one", 500, NULL },
- { "ucircumflex", 556, NULL },
+ { "emacron", 444, NULL },
{ "Odieresis", 778, NULL },
+ { "ucircumflex", 556, NULL },
{ "bracketleft", 333, NULL },
{ "Ugrave", 722, NULL },
{ "quoteright", 333, NULL },
{ "Udieresis", 722, NULL },
{ "perthousand", 1000, NULL },
{ "Ydieresis", 722, NULL },
+ { "umacron", 556, NULL },
+ { "abreve", 500, NULL },
{ "Eacute", 667, NULL },
{ "adieresis", 500, NULL },
{ "egrave", 444, NULL },
@@ -2329,111 +2936,173 @@ static BuiltinFontWidth timesBoldWidthsTab[] = {
{ "five", 500, NULL },
{ "udieresis", 556, NULL },
{ "Zcaron", 667, NULL },
+ { "Scommaaccent", 556, NULL },
{ "threequarters", 750, NULL },
{ "guillemotright", 500, NULL },
- { "ydieresis", 500, NULL },
{ "Ccedilla", 722, NULL },
+ { "ydieresis", 500, NULL },
{ "tilde", 333, NULL },
{ "at", 930, NULL },
{ "eacute", 444, NULL },
{ "underscore", 500, NULL },
+ { "Euro", 500, NULL },
+ { "Dcroat", 722, NULL },
{ "multiply", 570, NULL },
{ "zero", 500, NULL },
{ "eth", 500, NULL },
+ { "Scedilla", 556, NULL },
{ "Ograve", 778, NULL },
+ { "Racute", 722, NULL },
+ { "partialdiff", 494, NULL },
{ "uacute", 556, NULL },
{ "braceleft", 394, NULL },
{ "Thorn", 611, NULL },
{ "zcaron", 444, NULL },
+ { "scommaaccent", 389, NULL },
{ "ccedilla", 444, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 556, NULL },
{ "Ocircumflex", 778, NULL },
{ "Oacute", 778, NULL },
+ { "scedilla", 389, NULL },
{ "ogonek", 333, NULL },
{ "ograve", 500, NULL },
+ { "racute", 444, NULL },
+ { "Tcaron", 667, NULL },
+ { "Eogonek", 667, NULL },
{ "thorn", 556, NULL },
{ "degree", 400, NULL },
{ "registered", 747, NULL },
+ { "radical", 549, NULL },
{ "Aring", 722, NULL },
{ "percent", 1000, NULL },
{ "six", 500, NULL },
{ "paragraph", 540, NULL },
+ { "dcaron", 672, NULL },
+ { "Uogonek", 722, NULL },
{ "two", 500, NULL },
+ { "summation", 600, NULL },
{ "Igrave", 389, NULL },
+ { "Lacute", 667, NULL },
{ "ocircumflex", 500, NULL },
{ "oacute", 500, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 667, NULL },
+ { "tcaron", 416, NULL },
+ { "eogonek", 444, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 778, NULL },
{ "asciicircum", 581, NULL },
{ "aring", 500, NULL },
{ "grave", 333, NULL },
+ { "uogonek", 556, NULL },
{ "bracketright", 333, NULL },
{ "Iacute", 389, NULL },
{ "ampersand", 833, NULL },
{ "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 722, NULL },
{ "plus", 570, NULL },
+ { "uring", 556, NULL },
{ "quotesinglbase", 333, NULL },
+ { "lcommaaccent", 278, NULL },
{ "Yacute", 722, NULL },
+ { "ohungarumlaut", 500, NULL },
{ "threesuperior", 300, NULL },
{ "acute", 333, NULL },
{ "section", 500, NULL },
{ "dieresis", 333, NULL },
{ "iacute", 278, NULL },
{ "quotedblbase", 500, NULL },
+ { "ncaron", 556, NULL },
{ "florin", 500, NULL },
{ "yacute", 500, NULL },
+ { "Rcommaaccent", 722, NULL },
{ "fi", 556, NULL },
{ "fl", 556, NULL },
{ "Acircumflex", 722, NULL },
+ { "Cacute", 722, NULL },
{ "Icircumflex", 389, NULL },
{ "guillemotleft", 500, NULL },
{ "germandbls", 556, NULL },
+ { "Amacron", 722, NULL },
{ "seven", 500, NULL },
+ { "Sacute", 556, NULL },
{ "ordmasculine", 330, NULL },
{ "dotlessi", 278, NULL },
{ "sterling", 500, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 389, NULL },
+ { "rcommaaccent", 444, NULL },
+ { "Zdotaccent", 667, NULL },
{ "acircumflex", 500, NULL },
+ { "cacute", 444, NULL },
+ { "Ecaron", 667, NULL },
{ "icircumflex", 278, NULL },
{ "braceright", 394, NULL },
{ "quotedblright", 500, NULL },
+ { "amacron", 500, NULL },
+ { "sacute", 389, NULL },
+ { "imacron", 278, NULL },
{ "cent", 500, NULL },
{ "currency", 500, NULL },
{ "logicalnot", 570, NULL },
+ { "zdotaccent", 444, NULL },
{ "Atilde", 722, NULL },
{ "breve", 333, NULL },
{ "bar", 220, NULL },
{ "fraction", 167, NULL },
{ "less", 570, NULL },
+ { "ecaron", 444, NULL },
{ "guilsinglleft", 333, NULL },
{ "exclam", 333, NULL },
{ "period", 250, NULL },
+ { "Rcaron", 722, NULL },
+ { "Kcommaaccent", 778, NULL },
{ "greater", 570, NULL },
{ "atilde", 500, NULL },
{ "brokenbar", 220, NULL },
{ "quoteleft", 333, NULL },
+ { "Edotaccent", 667, NULL },
{ "onesuperior", 300, NULL }
};
static BuiltinFontWidth timesBoldItalicWidthsTab[] = {
{ "Ntilde", 722, NULL },
+ { "rcaron", 389, NULL },
+ { "kcommaaccent", 500, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
{ "comma", 250, NULL },
{ "cedilla", 333, NULL },
{ "plusminus", 570, NULL },
{ "circumflex", 333, NULL },
{ "dotaccent", 333, NULL },
+ { "edotaccent", 444, NULL },
{ "asciitilde", 570, NULL },
{ "colon", 333, NULL },
{ "onehalf", 750, NULL },
{ "dollar", 500, NULL },
+ { "Lcaron", 611, NULL },
{ "ntilde", 556, NULL },
+ { "Aogonek", 667, NULL },
+ { "ncommaaccent", 556, NULL },
{ "minus", 606, NULL },
+ { "Iogonek", 389, NULL },
+ { "zacute", 389, NULL },
{ "yen", 500, NULL },
{ "space", 250, NULL },
+ { "Omacron", 722, NULL },
{ "questiondown", 500, NULL },
{ "emdash", 1000, NULL },
{ "Agrave", 667, NULL },
{ "three", 500, NULL },
{ "numbersign", 500, NULL },
+ { "lcaron", 382, NULL },
{ "A", 667, NULL },
{ "B", 667, NULL },
{ "C", 667, NULL },
+ { "aogonek", 500, NULL },
{ "D", 722, NULL },
{ "E", 667, NULL },
{ "onequarter", 750, NULL },
@@ -2443,14 +3112,18 @@ static BuiltinFontWidth timesBoldItalicWidthsTab[] = {
{ "I", 389, NULL },
{ "J", 500, NULL },
{ "K", 667, NULL },
+ { "iogonek", 278, NULL },
{ "backslash", 278, NULL },
{ "L", 611, NULL },
{ "periodcentered", 250, NULL },
{ "M", 889, NULL },
{ "N", 722, NULL },
+ { "omacron", 500, NULL },
+ { "Tcommaaccent", 611, NULL },
{ "O", 722, NULL },
{ "P", 611, NULL },
{ "Q", 722, NULL },
+ { "Uhungarumlaut", 722, NULL },
{ "R", 667, NULL },
{ "Aacute", 667, NULL },
{ "caron", 333, NULL },
@@ -2467,6 +3140,7 @@ static BuiltinFontWidth timesBoldItalicWidthsTab[] = {
{ "Z", 611, NULL },
{ "four", 500, NULL },
{ "a", 500, NULL },
+ { "Gcommaaccent", 722, NULL },
{ "b", 500, NULL },
{ "c", 444, NULL },
{ "d", 500, NULL },
@@ -2483,11 +3157,13 @@ static BuiltinFontWidth timesBoldItalicWidthsTab[] = {
{ "l", 278, NULL },
{ "m", 778, NULL },
{ "n", 556, NULL },
+ { "tcommaaccent", 278, NULL },
{ "o", 500, NULL },
{ "ordfeminine", 266, NULL },
{ "ring", 333, NULL },
{ "p", 500, NULL },
{ "q", 500, NULL },
+ { "uhungarumlaut", 556, NULL },
{ "r", 389, NULL },
{ "twosuperior", 300, NULL },
{ "aacute", 500, NULL },
@@ -2496,24 +3172,37 @@ static BuiltinFontWidth timesBoldItalicWidthsTab[] = {
{ "t", 278, NULL },
{ "divide", 570, NULL },
{ "u", 556, NULL },
+ { "Ccaron", 667, NULL },
{ "v", 444, NULL },
{ "w", 667, NULL },
{ "x", 500, NULL },
{ "y", 444, NULL },
{ "z", 389, NULL },
+ { "Gbreve", 722, NULL },
+ { "commaaccent", 250, NULL },
{ "hungarumlaut", 333, NULL },
+ { "Idotaccent", 389, NULL },
+ { "Nacute", 722, NULL },
{ "quotedbl", 555, NULL },
+ { "gcommaaccent", 500, NULL },
{ "mu", 576, NULL },
+ { "greaterequal", 549, NULL },
{ "Scaron", 556, NULL },
{ "Lslash", 611, NULL },
{ "semicolon", 333, NULL },
{ "oslash", 500, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 494, NULL },
{ "parenright", 333, NULL },
+ { "ccaron", 444, NULL },
{ "Ecircumflex", 667, NULL },
+ { "gbreve", 500, NULL },
{ "trademark", 1000, NULL },
{ "daggerdbl", 500, NULL },
+ { "nacute", 556, NULL },
{ "macron", 333, NULL },
{ "Otilde", 722, NULL },
+ { "Emacron", 667, NULL },
{ "ellipsis", 1000, NULL },
{ "scaron", 389, NULL },
{ "AE", 944, NULL },
@@ -2527,9 +3216,11 @@ static BuiltinFontWidth timesBoldItalicWidthsTab[] = {
{ "exclamdown", 389, NULL },
{ "endash", 500, NULL },
{ "oe", 722, NULL },
+ { "Abreve", 667, NULL },
+ { "Umacron", 722, NULL },
{ "ecircumflex", 444, NULL },
- { "copyright", 747, NULL },
{ "Adieresis", 667, NULL },
+ { "copyright", 747, NULL },
{ "Egrave", 667, NULL },
{ "slash", 278, NULL },
{ "Edieresis", 667, NULL },
@@ -2537,14 +3228,17 @@ static BuiltinFontWidth timesBoldItalicWidthsTab[] = {
{ "Idieresis", 389, NULL },
{ "parenleft", 333, NULL },
{ "one", 500, NULL },
- { "ucircumflex", 556, NULL },
+ { "emacron", 444, NULL },
{ "Odieresis", 722, NULL },
+ { "ucircumflex", 556, NULL },
{ "bracketleft", 333, NULL },
{ "Ugrave", 722, NULL },
{ "quoteright", 333, NULL },
{ "Udieresis", 722, NULL },
{ "perthousand", 1000, NULL },
{ "Ydieresis", 611, NULL },
+ { "umacron", 556, NULL },
+ { "abreve", 500, NULL },
{ "Eacute", 667, NULL },
{ "adieresis", 500, NULL },
{ "egrave", 444, NULL },
@@ -2560,111 +3254,173 @@ static BuiltinFontWidth timesBoldItalicWidthsTab[] = {
{ "five", 500, NULL },
{ "udieresis", 556, NULL },
{ "Zcaron", 611, NULL },
+ { "Scommaaccent", 556, NULL },
{ "threequarters", 750, NULL },
{ "guillemotright", 500, NULL },
- { "ydieresis", 444, NULL },
{ "Ccedilla", 667, NULL },
+ { "ydieresis", 444, NULL },
{ "tilde", 333, NULL },
{ "at", 832, NULL },
{ "eacute", 444, NULL },
{ "underscore", 500, NULL },
+ { "Euro", 500, NULL },
+ { "Dcroat", 722, NULL },
{ "multiply", 570, NULL },
{ "zero", 500, NULL },
{ "eth", 500, NULL },
+ { "Scedilla", 556, NULL },
{ "Ograve", 722, NULL },
+ { "Racute", 667, NULL },
+ { "partialdiff", 494, NULL },
{ "uacute", 556, NULL },
{ "braceleft", 348, NULL },
{ "Thorn", 611, NULL },
{ "zcaron", 389, NULL },
+ { "scommaaccent", 389, NULL },
{ "ccedilla", 444, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 500, NULL },
{ "Ocircumflex", 722, NULL },
{ "Oacute", 722, NULL },
+ { "scedilla", 389, NULL },
{ "ogonek", 333, NULL },
{ "ograve", 500, NULL },
+ { "racute", 389, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 667, NULL },
{ "thorn", 500, NULL },
{ "degree", 400, NULL },
{ "registered", 747, NULL },
+ { "radical", 549, NULL },
{ "Aring", 667, NULL },
{ "percent", 833, NULL },
{ "six", 500, NULL },
{ "paragraph", 500, NULL },
+ { "dcaron", 608, NULL },
+ { "Uogonek", 722, NULL },
{ "two", 500, NULL },
+ { "summation", 600, NULL },
{ "Igrave", 389, NULL },
+ { "Lacute", 611, NULL },
{ "ocircumflex", 500, NULL },
{ "oacute", 500, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 611, NULL },
+ { "tcaron", 366, NULL },
+ { "eogonek", 444, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 722, NULL },
{ "asciicircum", 570, NULL },
{ "aring", 500, NULL },
{ "grave", 333, NULL },
+ { "uogonek", 556, NULL },
{ "bracketright", 333, NULL },
{ "Iacute", 389, NULL },
{ "ampersand", 778, NULL },
{ "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 722, NULL },
{ "plus", 570, NULL },
+ { "uring", 556, NULL },
{ "quotesinglbase", 333, NULL },
+ { "lcommaaccent", 278, NULL },
{ "Yacute", 611, NULL },
+ { "ohungarumlaut", 500, NULL },
{ "threesuperior", 300, NULL },
{ "acute", 333, NULL },
{ "section", 500, NULL },
{ "dieresis", 333, NULL },
{ "iacute", 278, NULL },
{ "quotedblbase", 500, NULL },
+ { "ncaron", 556, NULL },
{ "florin", 500, NULL },
{ "yacute", 444, NULL },
+ { "Rcommaaccent", 667, NULL },
{ "fi", 556, NULL },
{ "fl", 556, NULL },
{ "Acircumflex", 667, NULL },
+ { "Cacute", 667, NULL },
{ "Icircumflex", 389, NULL },
{ "guillemotleft", 500, NULL },
{ "germandbls", 500, NULL },
+ { "Amacron", 667, NULL },
{ "seven", 500, NULL },
+ { "Sacute", 556, NULL },
{ "ordmasculine", 300, NULL },
{ "dotlessi", 278, NULL },
{ "sterling", 500, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 389, NULL },
+ { "rcommaaccent", 389, NULL },
+ { "Zdotaccent", 611, NULL },
{ "acircumflex", 500, NULL },
+ { "cacute", 444, NULL },
+ { "Ecaron", 667, NULL },
{ "icircumflex", 278, NULL },
{ "braceright", 348, NULL },
{ "quotedblright", 500, NULL },
+ { "amacron", 500, NULL },
+ { "sacute", 389, NULL },
+ { "imacron", 278, NULL },
{ "cent", 500, NULL },
{ "currency", 500, NULL },
{ "logicalnot", 606, NULL },
+ { "zdotaccent", 389, NULL },
{ "Atilde", 667, NULL },
{ "breve", 333, NULL },
{ "bar", 220, NULL },
{ "fraction", 167, NULL },
{ "less", 570, NULL },
+ { "ecaron", 444, NULL },
{ "guilsinglleft", 333, NULL },
{ "exclam", 389, NULL },
{ "period", 250, NULL },
+ { "Rcaron", 667, NULL },
+ { "Kcommaaccent", 667, NULL },
{ "greater", 570, NULL },
{ "atilde", 500, NULL },
{ "brokenbar", 220, NULL },
{ "quoteleft", 333, NULL },
+ { "Edotaccent", 667, NULL },
{ "onesuperior", 300, NULL }
};
static BuiltinFontWidth timesItalicWidthsTab[] = {
{ "Ntilde", 667, NULL },
+ { "rcaron", 389, NULL },
+ { "kcommaaccent", 444, NULL },
+ { "Ncommaaccent", 667, NULL },
+ { "Zacute", 556, NULL },
{ "comma", 250, NULL },
{ "cedilla", 333, NULL },
{ "plusminus", 675, NULL },
{ "circumflex", 333, NULL },
{ "dotaccent", 333, NULL },
+ { "edotaccent", 444, NULL },
{ "asciitilde", 541, NULL },
{ "colon", 333, NULL },
{ "onehalf", 750, NULL },
{ "dollar", 500, NULL },
+ { "Lcaron", 611, NULL },
{ "ntilde", 500, NULL },
+ { "Aogonek", 611, NULL },
+ { "ncommaaccent", 500, NULL },
{ "minus", 675, NULL },
+ { "Iogonek", 333, NULL },
+ { "zacute", 389, NULL },
{ "yen", 500, NULL },
{ "space", 250, NULL },
+ { "Omacron", 722, NULL },
{ "questiondown", 500, NULL },
{ "emdash", 889, NULL },
{ "Agrave", 611, NULL },
{ "three", 500, NULL },
{ "numbersign", 500, NULL },
+ { "lcaron", 300, NULL },
{ "A", 611, NULL },
{ "B", 611, NULL },
{ "C", 667, NULL },
+ { "aogonek", 500, NULL },
{ "D", 722, NULL },
{ "E", 611, NULL },
{ "onequarter", 750, NULL },
@@ -2674,14 +3430,18 @@ static BuiltinFontWidth timesItalicWidthsTab[] = {
{ "I", 333, NULL },
{ "J", 444, NULL },
{ "K", 667, NULL },
+ { "iogonek", 278, NULL },
{ "backslash", 278, NULL },
{ "L", 556, NULL },
{ "periodcentered", 250, NULL },
{ "M", 833, NULL },
{ "N", 667, NULL },
+ { "omacron", 500, NULL },
+ { "Tcommaaccent", 556, NULL },
{ "O", 722, NULL },
{ "P", 611, NULL },
{ "Q", 722, NULL },
+ { "Uhungarumlaut", 722, NULL },
{ "R", 611, NULL },
{ "Aacute", 611, NULL },
{ "caron", 333, NULL },
@@ -2698,6 +3458,7 @@ static BuiltinFontWidth timesItalicWidthsTab[] = {
{ "Z", 556, NULL },
{ "four", 500, NULL },
{ "a", 500, NULL },
+ { "Gcommaaccent", 722, NULL },
{ "b", 500, NULL },
{ "c", 444, NULL },
{ "d", 500, NULL },
@@ -2714,11 +3475,13 @@ static BuiltinFontWidth timesItalicWidthsTab[] = {
{ "l", 278, NULL },
{ "m", 722, NULL },
{ "n", 500, NULL },
+ { "tcommaaccent", 278, NULL },
{ "o", 500, NULL },
{ "ordfeminine", 276, NULL },
{ "ring", 333, NULL },
{ "p", 500, NULL },
{ "q", 500, NULL },
+ { "uhungarumlaut", 500, NULL },
{ "r", 389, NULL },
{ "twosuperior", 300, NULL },
{ "aacute", 500, NULL },
@@ -2727,24 +3490,37 @@ static BuiltinFontWidth timesItalicWidthsTab[] = {
{ "t", 278, NULL },
{ "divide", 675, NULL },
{ "u", 500, NULL },
+ { "Ccaron", 667, NULL },
{ "v", 444, NULL },
{ "w", 667, NULL },
{ "x", 444, NULL },
{ "y", 444, NULL },
{ "z", 389, NULL },
+ { "Gbreve", 722, NULL },
+ { "commaaccent", 250, NULL },
{ "hungarumlaut", 333, NULL },
+ { "Idotaccent", 333, NULL },
+ { "Nacute", 667, NULL },
{ "quotedbl", 420, NULL },
+ { "gcommaaccent", 500, NULL },
{ "mu", 500, NULL },
+ { "greaterequal", 549, NULL },
{ "Scaron", 500, NULL },
{ "Lslash", 556, NULL },
{ "semicolon", 333, NULL },
{ "oslash", 500, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 471, NULL },
{ "parenright", 333, NULL },
+ { "ccaron", 444, NULL },
{ "Ecircumflex", 611, NULL },
+ { "gbreve", 500, NULL },
{ "trademark", 980, NULL },
{ "daggerdbl", 500, NULL },
+ { "nacute", 500, NULL },
{ "macron", 333, NULL },
{ "Otilde", 722, NULL },
+ { "Emacron", 611, NULL },
{ "ellipsis", 889, NULL },
{ "scaron", 389, NULL },
{ "AE", 889, NULL },
@@ -2758,9 +3534,11 @@ static BuiltinFontWidth timesItalicWidthsTab[] = {
{ "exclamdown", 389, NULL },
{ "endash", 500, NULL },
{ "oe", 667, NULL },
+ { "Abreve", 611, NULL },
+ { "Umacron", 722, NULL },
{ "ecircumflex", 444, NULL },
- { "copyright", 760, NULL },
{ "Adieresis", 611, NULL },
+ { "copyright", 760, NULL },
{ "Egrave", 611, NULL },
{ "slash", 278, NULL },
{ "Edieresis", 611, NULL },
@@ -2768,14 +3546,17 @@ static BuiltinFontWidth timesItalicWidthsTab[] = {
{ "Idieresis", 333, NULL },
{ "parenleft", 333, NULL },
{ "one", 500, NULL },
- { "ucircumflex", 500, NULL },
+ { "emacron", 444, NULL },
{ "Odieresis", 722, NULL },
+ { "ucircumflex", 500, NULL },
{ "bracketleft", 389, NULL },
{ "Ugrave", 722, NULL },
{ "quoteright", 333, NULL },
{ "Udieresis", 722, NULL },
{ "perthousand", 1000, NULL },
{ "Ydieresis", 556, NULL },
+ { "umacron", 500, NULL },
+ { "abreve", 500, NULL },
{ "Eacute", 611, NULL },
{ "adieresis", 500, NULL },
{ "egrave", 444, NULL },
@@ -2791,111 +3572,173 @@ static BuiltinFontWidth timesItalicWidthsTab[] = {
{ "five", 500, NULL },
{ "udieresis", 500, NULL },
{ "Zcaron", 556, NULL },
+ { "Scommaaccent", 500, NULL },
{ "threequarters", 750, NULL },
{ "guillemotright", 500, NULL },
- { "ydieresis", 444, NULL },
{ "Ccedilla", 667, NULL },
+ { "ydieresis", 444, NULL },
{ "tilde", 333, NULL },
{ "at", 920, NULL },
{ "eacute", 444, NULL },
{ "underscore", 500, NULL },
+ { "Euro", 500, NULL },
+ { "Dcroat", 722, NULL },
{ "multiply", 675, NULL },
{ "zero", 500, NULL },
{ "eth", 500, NULL },
+ { "Scedilla", 500, NULL },
{ "Ograve", 722, NULL },
+ { "Racute", 611, NULL },
+ { "partialdiff", 476, NULL },
{ "uacute", 500, NULL },
{ "braceleft", 400, NULL },
{ "Thorn", 611, NULL },
{ "zcaron", 389, NULL },
+ { "scommaaccent", 389, NULL },
{ "ccedilla", 444, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 500, NULL },
{ "Ocircumflex", 722, NULL },
{ "Oacute", 722, NULL },
+ { "scedilla", 389, NULL },
{ "ogonek", 333, NULL },
{ "ograve", 500, NULL },
+ { "racute", 389, NULL },
+ { "Tcaron", 556, NULL },
+ { "Eogonek", 611, NULL },
{ "thorn", 500, NULL },
{ "degree", 400, NULL },
{ "registered", 760, NULL },
+ { "radical", 453, NULL },
{ "Aring", 611, NULL },
{ "percent", 833, NULL },
{ "six", 500, NULL },
{ "paragraph", 523, NULL },
+ { "dcaron", 544, NULL },
+ { "Uogonek", 722, NULL },
{ "two", 500, NULL },
+ { "summation", 600, NULL },
{ "Igrave", 333, NULL },
+ { "Lacute", 556, NULL },
{ "ocircumflex", 500, NULL },
{ "oacute", 500, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 556, NULL },
+ { "tcaron", 300, NULL },
+ { "eogonek", 444, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 722, NULL },
{ "asciicircum", 422, NULL },
{ "aring", 500, NULL },
{ "grave", 333, NULL },
+ { "uogonek", 500, NULL },
{ "bracketright", 389, NULL },
{ "Iacute", 333, NULL },
{ "ampersand", 778, NULL },
{ "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 667, NULL },
{ "plus", 675, NULL },
+ { "uring", 500, NULL },
{ "quotesinglbase", 333, NULL },
+ { "lcommaaccent", 278, NULL },
{ "Yacute", 556, NULL },
+ { "ohungarumlaut", 500, NULL },
{ "threesuperior", 300, NULL },
{ "acute", 333, NULL },
{ "section", 500, NULL },
{ "dieresis", 333, NULL },
{ "iacute", 278, NULL },
{ "quotedblbase", 556, NULL },
+ { "ncaron", 500, NULL },
{ "florin", 500, NULL },
{ "yacute", 444, NULL },
+ { "Rcommaaccent", 611, NULL },
{ "fi", 500, NULL },
{ "fl", 500, NULL },
{ "Acircumflex", 611, NULL },
+ { "Cacute", 667, NULL },
{ "Icircumflex", 333, NULL },
{ "guillemotleft", 500, NULL },
{ "germandbls", 500, NULL },
+ { "Amacron", 611, NULL },
{ "seven", 500, NULL },
+ { "Sacute", 500, NULL },
{ "ordmasculine", 310, NULL },
{ "dotlessi", 278, NULL },
{ "sterling", 500, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 333, NULL },
+ { "rcommaaccent", 389, NULL },
+ { "Zdotaccent", 556, NULL },
{ "acircumflex", 500, NULL },
+ { "cacute", 444, NULL },
+ { "Ecaron", 611, NULL },
{ "icircumflex", 278, NULL },
{ "braceright", 400, NULL },
{ "quotedblright", 556, NULL },
+ { "amacron", 500, NULL },
+ { "sacute", 389, NULL },
+ { "imacron", 278, NULL },
{ "cent", 500, NULL },
{ "currency", 500, NULL },
{ "logicalnot", 675, NULL },
+ { "zdotaccent", 389, NULL },
{ "Atilde", 611, NULL },
{ "breve", 333, NULL },
{ "bar", 275, NULL },
{ "fraction", 167, NULL },
{ "less", 675, NULL },
+ { "ecaron", 444, NULL },
{ "guilsinglleft", 333, NULL },
{ "exclam", 333, NULL },
{ "period", 250, NULL },
+ { "Rcaron", 611, NULL },
+ { "Kcommaaccent", 667, NULL },
{ "greater", 675, NULL },
{ "atilde", 500, NULL },
{ "brokenbar", 275, NULL },
{ "quoteleft", 333, NULL },
+ { "Edotaccent", 611, NULL },
{ "onesuperior", 300, NULL }
};
static BuiltinFontWidth timesRomanWidthsTab[] = {
{ "Ntilde", 722, NULL },
+ { "rcaron", 333, NULL },
+ { "kcommaaccent", 500, NULL },
+ { "Ncommaaccent", 722, NULL },
+ { "Zacute", 611, NULL },
{ "comma", 250, NULL },
{ "cedilla", 333, NULL },
{ "plusminus", 564, NULL },
{ "circumflex", 333, NULL },
{ "dotaccent", 333, NULL },
+ { "edotaccent", 444, NULL },
{ "asciitilde", 541, NULL },
{ "colon", 278, NULL },
{ "onehalf", 750, NULL },
{ "dollar", 500, NULL },
+ { "Lcaron", 611, NULL },
{ "ntilde", 500, NULL },
+ { "Aogonek", 722, NULL },
+ { "ncommaaccent", 500, NULL },
{ "minus", 564, NULL },
+ { "Iogonek", 333, NULL },
+ { "zacute", 444, NULL },
{ "yen", 500, NULL },
{ "space", 250, NULL },
+ { "Omacron", 722, NULL },
{ "questiondown", 444, NULL },
{ "emdash", 1000, NULL },
{ "Agrave", 722, NULL },
{ "three", 500, NULL },
{ "numbersign", 500, NULL },
+ { "lcaron", 344, NULL },
{ "A", 722, NULL },
{ "B", 667, NULL },
{ "C", 667, NULL },
+ { "aogonek", 444, NULL },
{ "D", 722, NULL },
{ "E", 611, NULL },
{ "onequarter", 750, NULL },
@@ -2905,14 +3748,18 @@ static BuiltinFontWidth timesRomanWidthsTab[] = {
{ "I", 333, NULL },
{ "J", 389, NULL },
{ "K", 722, NULL },
+ { "iogonek", 278, NULL },
{ "backslash", 278, NULL },
{ "L", 611, NULL },
{ "periodcentered", 250, NULL },
{ "M", 889, NULL },
{ "N", 722, NULL },
+ { "omacron", 500, NULL },
+ { "Tcommaaccent", 611, NULL },
{ "O", 722, NULL },
{ "P", 556, NULL },
{ "Q", 722, NULL },
+ { "Uhungarumlaut", 722, NULL },
{ "R", 667, NULL },
{ "Aacute", 722, NULL },
{ "caron", 333, NULL },
@@ -2929,6 +3776,7 @@ static BuiltinFontWidth timesRomanWidthsTab[] = {
{ "Z", 611, NULL },
{ "four", 500, NULL },
{ "a", 444, NULL },
+ { "Gcommaaccent", 722, NULL },
{ "b", 500, NULL },
{ "c", 444, NULL },
{ "d", 500, NULL },
@@ -2945,11 +3793,13 @@ static BuiltinFontWidth timesRomanWidthsTab[] = {
{ "l", 278, NULL },
{ "m", 778, NULL },
{ "n", 500, NULL },
+ { "tcommaaccent", 278, NULL },
{ "o", 500, NULL },
{ "ordfeminine", 276, NULL },
{ "ring", 333, NULL },
{ "p", 500, NULL },
{ "q", 500, NULL },
+ { "uhungarumlaut", 500, NULL },
{ "r", 333, NULL },
{ "twosuperior", 300, NULL },
{ "aacute", 444, NULL },
@@ -2958,24 +3808,37 @@ static BuiltinFontWidth timesRomanWidthsTab[] = {
{ "t", 278, NULL },
{ "divide", 564, NULL },
{ "u", 500, NULL },
+ { "Ccaron", 667, NULL },
{ "v", 500, NULL },
{ "w", 722, NULL },
{ "x", 500, NULL },
{ "y", 500, NULL },
{ "z", 444, NULL },
+ { "Gbreve", 722, NULL },
+ { "commaaccent", 250, NULL },
{ "hungarumlaut", 333, NULL },
+ { "Idotaccent", 333, NULL },
+ { "Nacute", 722, NULL },
{ "quotedbl", 408, NULL },
+ { "gcommaaccent", 500, NULL },
{ "mu", 500, NULL },
+ { "greaterequal", 549, NULL },
{ "Scaron", 556, NULL },
{ "Lslash", 611, NULL },
{ "semicolon", 278, NULL },
{ "oslash", 500, NULL },
+ { "lessequal", 549, NULL },
+ { "lozenge", 471, NULL },
{ "parenright", 333, NULL },
+ { "ccaron", 444, NULL },
{ "Ecircumflex", 611, NULL },
+ { "gbreve", 500, NULL },
{ "trademark", 980, NULL },
{ "daggerdbl", 500, NULL },
+ { "nacute", 500, NULL },
{ "macron", 333, NULL },
{ "Otilde", 722, NULL },
+ { "Emacron", 611, NULL },
{ "ellipsis", 1000, NULL },
{ "scaron", 389, NULL },
{ "AE", 889, NULL },
@@ -2989,9 +3852,11 @@ static BuiltinFontWidth timesRomanWidthsTab[] = {
{ "exclamdown", 333, NULL },
{ "endash", 500, NULL },
{ "oe", 722, NULL },
+ { "Abreve", 722, NULL },
+ { "Umacron", 722, NULL },
{ "ecircumflex", 444, NULL },
- { "copyright", 760, NULL },
{ "Adieresis", 722, NULL },
+ { "copyright", 760, NULL },
{ "Egrave", 611, NULL },
{ "slash", 278, NULL },
{ "Edieresis", 611, NULL },
@@ -2999,14 +3864,17 @@ static BuiltinFontWidth timesRomanWidthsTab[] = {
{ "Idieresis", 333, NULL },
{ "parenleft", 333, NULL },
{ "one", 500, NULL },
- { "ucircumflex", 500, NULL },
+ { "emacron", 444, NULL },
{ "Odieresis", 722, NULL },
+ { "ucircumflex", 500, NULL },
{ "bracketleft", 333, NULL },
{ "Ugrave", 722, NULL },
{ "quoteright", 333, NULL },
{ "Udieresis", 722, NULL },
{ "perthousand", 1000, NULL },
{ "Ydieresis", 722, NULL },
+ { "umacron", 500, NULL },
+ { "abreve", 444, NULL },
{ "Eacute", 611, NULL },
{ "adieresis", 444, NULL },
{ "egrave", 444, NULL },
@@ -3022,85 +3890,134 @@ static BuiltinFontWidth timesRomanWidthsTab[] = {
{ "five", 500, NULL },
{ "udieresis", 500, NULL },
{ "Zcaron", 611, NULL },
+ { "Scommaaccent", 556, NULL },
{ "threequarters", 750, NULL },
{ "guillemotright", 500, NULL },
- { "ydieresis", 500, NULL },
{ "Ccedilla", 667, NULL },
+ { "ydieresis", 500, NULL },
{ "tilde", 333, NULL },
{ "at", 921, NULL },
{ "eacute", 444, NULL },
{ "underscore", 500, NULL },
+ { "Euro", 500, NULL },
+ { "Dcroat", 722, NULL },
{ "multiply", 564, NULL },
{ "zero", 500, NULL },
{ "eth", 500, NULL },
+ { "Scedilla", 556, NULL },
{ "Ograve", 722, NULL },
+ { "Racute", 667, NULL },
+ { "partialdiff", 476, NULL },
{ "uacute", 500, NULL },
{ "braceleft", 480, NULL },
{ "Thorn", 556, NULL },
{ "zcaron", 444, NULL },
+ { "scommaaccent", 389, NULL },
{ "ccedilla", 444, NULL },
+ { "Dcaron", 722, NULL },
+ { "dcroat", 500, NULL },
{ "Ocircumflex", 722, NULL },
{ "Oacute", 722, NULL },
+ { "scedilla", 389, NULL },
{ "ogonek", 333, NULL },
{ "ograve", 500, NULL },
+ { "racute", 333, NULL },
+ { "Tcaron", 611, NULL },
+ { "Eogonek", 611, NULL },
{ "thorn", 500, NULL },
{ "degree", 400, NULL },
{ "registered", 760, NULL },
+ { "radical", 453, NULL },
{ "Aring", 722, NULL },
{ "percent", 833, NULL },
{ "six", 500, NULL },
{ "paragraph", 453, NULL },
+ { "dcaron", 588, NULL },
+ { "Uogonek", 722, NULL },
{ "two", 500, NULL },
+ { "summation", 600, NULL },
{ "Igrave", 333, NULL },
+ { "Lacute", 611, NULL },
{ "ocircumflex", 500, NULL },
{ "oacute", 500, NULL },
+ { "Uring", 722, NULL },
+ { "Lcommaaccent", 611, NULL },
+ { "tcaron", 326, NULL },
+ { "eogonek", 444, NULL },
+ { "Delta", 612, NULL },
+ { "Ohungarumlaut", 722, NULL },
{ "asciicircum", 469, NULL },
{ "aring", 444, NULL },
{ "grave", 333, NULL },
+ { "uogonek", 500, NULL },
{ "bracketright", 333, NULL },
{ "Iacute", 333, NULL },
{ "ampersand", 778, NULL },
{ "igrave", 278, NULL },
+ { "lacute", 278, NULL },
+ { "Ncaron", 722, NULL },
{ "plus", 564, NULL },
+ { "uring", 500, NULL },
{ "quotesinglbase", 333, NULL },
+ { "lcommaaccent", 278, NULL },
{ "Yacute", 722, NULL },
+ { "ohungarumlaut", 500, NULL },
{ "threesuperior", 300, NULL },
{ "acute", 333, NULL },
{ "section", 500, NULL },
{ "dieresis", 333, NULL },
{ "iacute", 278, NULL },
{ "quotedblbase", 444, NULL },
+ { "ncaron", 500, NULL },
{ "florin", 500, NULL },
{ "yacute", 500, NULL },
+ { "Rcommaaccent", 667, NULL },
{ "fi", 556, NULL },
{ "fl", 556, NULL },
{ "Acircumflex", 722, NULL },
+ { "Cacute", 667, NULL },
{ "Icircumflex", 333, NULL },
{ "guillemotleft", 500, NULL },
{ "germandbls", 500, NULL },
+ { "Amacron", 722, NULL },
{ "seven", 500, NULL },
+ { "Sacute", 556, NULL },
{ "ordmasculine", 310, NULL },
{ "dotlessi", 278, NULL },
{ "sterling", 500, NULL },
+ { "notequal", 549, NULL },
+ { "Imacron", 333, NULL },
+ { "rcommaaccent", 333, NULL },
+ { "Zdotaccent", 611, NULL },
{ "acircumflex", 444, NULL },
+ { "cacute", 444, NULL },
+ { "Ecaron", 611, NULL },
{ "icircumflex", 278, NULL },
{ "braceright", 480, NULL },
{ "quotedblright", 444, NULL },
+ { "amacron", 444, NULL },
+ { "sacute", 389, NULL },
+ { "imacron", 278, NULL },
{ "cent", 500, NULL },
{ "currency", 500, NULL },
{ "logicalnot", 564, NULL },
+ { "zdotaccent", 444, NULL },
{ "Atilde", 722, NULL },
{ "breve", 333, NULL },
{ "bar", 200, NULL },
{ "fraction", 167, NULL },
{ "less", 564, NULL },
+ { "ecaron", 444, NULL },
{ "guilsinglleft", 333, NULL },
{ "exclam", 333, NULL },
{ "period", 250, NULL },
+ { "Rcaron", 667, NULL },
+ { "Kcommaaccent", 722, NULL },
{ "greater", 564, NULL },
{ "atilde", 444, NULL },
{ "brokenbar", 200, NULL },
{ "quoteleft", 333, NULL },
+ { "Edotaccent", 611, NULL },
{ "onesuperior", 300, NULL }
};
@@ -3279,10 +4196,10 @@ static BuiltinFontWidth zapfDingbatsWidthsTab[] = {
{ "a203", 762, NULL },
{ "a123", 788, NULL },
{ "a204", 759, NULL },
- { "a205", 509, NULL },
{ "a124", 788, NULL },
- { "a206", 410, NULL },
+ { "a205", 509, NULL },
{ "a125", 788, NULL },
+ { "a206", 410, NULL },
{ "a126", 788, NULL },
{ "a127", 788, NULL },
{ "a128", 788, NULL },
@@ -3310,19 +4227,19 @@ static BuiltinFontWidth zapfDingbatsWidthsTab[] = {
};
BuiltinFont builtinFonts[] = {
- { "Courier", standardEncoding, 624, -207, { -40, -290, 640, 795}, NULL },
- { "Courier-Bold", standardEncoding, 674, -257, {-100, -350, 700, 855}, NULL },
- { "Courier-BoldOblique", standardEncoding, 674, -257, {-145, -350, 817, 855}, NULL },
- { "Courier-Oblique", standardEncoding, 624, -207, { -85, -290, 759, 795}, NULL },
- { "Helvetica", standardEncoding, 729, -219, {-174, -220, 1001, 944}, NULL },
- { "Helvetica-Bold", standardEncoding, 729, -219, {-173, -221, 1003, 936}, NULL },
- { "Helvetica-BoldOblique", standardEncoding, 729, -219, {-177, -221, 1107, 936}, NULL },
- { "Helvetica-Oblique", standardEncoding, 729, -219, {-178, -220, 1108, 944}, NULL },
+ { "Courier", standardEncoding, 629, -157, { -23, -250, 715, 805}, NULL },
+ { "Courier-Bold", standardEncoding, 629, -157, {-113, -250, 749, 801}, NULL },
+ { "Courier-BoldOblique", standardEncoding, 629, -157, { -57, -250, 869, 801}, NULL },
+ { "Courier-Oblique", standardEncoding, 629, -157, { -27, -250, 849, 805}, NULL },
+ { "Helvetica", standardEncoding, 718, -207, {-166, -225, 1000, 931}, NULL },
+ { "Helvetica-Bold", standardEncoding, 718, -207, {-170, -228, 1003, 962}, NULL },
+ { "Helvetica-BoldOblique", standardEncoding, 718, -207, {-174, -228, 1114, 962}, NULL },
+ { "Helvetica-Oblique", standardEncoding, 718, -207, {-170, -225, 1116, 931}, NULL },
{ "Symbol", symbolEncoding, 1010, -293, {-180, -293, 1090, 1010}, NULL },
- { "Times-Bold", standardEncoding, 670, -210, {-172, -256, 1008, 965}, NULL },
- { "Times-BoldItalic", standardEncoding, 682, -203, {-168, -232, 1014, 894}, NULL },
- { "Times-Italic", standardEncoding, 684, -206, {-176, -252, 990, 930}, NULL },
- { "Times-Roman", standardEncoding, 682, -217, {-170, -223, 1024, 896}, NULL },
+ { "Times-Bold", standardEncoding, 683, -217, {-168, -218, 1000, 935}, NULL },
+ { "Times-BoldItalic", standardEncoding, 683, -217, {-200, -218, 996, 921}, NULL },
+ { "Times-Italic", standardEncoding, 683, -217, {-169, -217, 1010, 883}, NULL },
+ { "Times-Roman", standardEncoding, 683, -217, {-168, -218, 1000, 898}, NULL },
{ "ZapfDingbats", zapfDingbatsEncoding, 820, -143, { -1, -143, 981, 820}, NULL }
};
@@ -3342,19 +4259,19 @@ BuiltinFont *builtinFontSubst[] = {
};
void initBuiltinFontTables() {
- builtinFonts[0].widths = new BuiltinFontWidths(courierWidthsTab, 260);
- builtinFonts[1].widths = new BuiltinFontWidths(courierBoldWidthsTab, 260);
- builtinFonts[2].widths = new BuiltinFontWidths(courierBoldObliqueWidthsTab, 260);
- builtinFonts[3].widths = new BuiltinFontWidths(courierObliqueWidthsTab, 260);
- builtinFonts[4].widths = new BuiltinFontWidths(helveticaWidthsTab, 228);
- builtinFonts[5].widths = new BuiltinFontWidths(helveticaBoldWidthsTab, 229);
- builtinFonts[6].widths = new BuiltinFontWidths(helveticaBoldObliqueWidthsTab, 228);
- builtinFonts[7].widths = new BuiltinFontWidths(helveticaObliqueWidthsTab, 228);
- builtinFonts[8].widths = new BuiltinFontWidths(symbolWidthsTab, 189);
- builtinFonts[9].widths = new BuiltinFontWidths(timesBoldWidthsTab, 228);
- builtinFonts[10].widths = new BuiltinFontWidths(timesBoldItalicWidthsTab, 228);
- builtinFonts[11].widths = new BuiltinFontWidths(timesItalicWidthsTab, 228);
- builtinFonts[12].widths = new BuiltinFontWidths(timesRomanWidthsTab, 228);
+ builtinFonts[0].widths = new BuiltinFontWidths(courierWidthsTab, 315);
+ builtinFonts[1].widths = new BuiltinFontWidths(courierBoldWidthsTab, 315);
+ builtinFonts[2].widths = new BuiltinFontWidths(courierBoldObliqueWidthsTab, 315);
+ builtinFonts[3].widths = new BuiltinFontWidths(courierObliqueWidthsTab, 315);
+ builtinFonts[4].widths = new BuiltinFontWidths(helveticaWidthsTab, 315);
+ builtinFonts[5].widths = new BuiltinFontWidths(helveticaBoldWidthsTab, 316);
+ builtinFonts[6].widths = new BuiltinFontWidths(helveticaBoldObliqueWidthsTab, 315);
+ builtinFonts[7].widths = new BuiltinFontWidths(helveticaObliqueWidthsTab, 315);
+ builtinFonts[8].widths = new BuiltinFontWidths(symbolWidthsTab, 190);
+ builtinFonts[9].widths = new BuiltinFontWidths(timesBoldWidthsTab, 315);
+ builtinFonts[10].widths = new BuiltinFontWidths(timesBoldItalicWidthsTab, 315);
+ builtinFonts[11].widths = new BuiltinFontWidths(timesItalicWidthsTab, 315);
+ builtinFonts[12].widths = new BuiltinFontWidths(timesRomanWidthsTab, 315);
builtinFonts[13].widths = new BuiltinFontWidths(zapfDingbatsWidthsTab, 202);
}
diff --git a/pdf/xpdf/CMap.cc b/pdf/xpdf/CMap.cc
index c60ce3c..25f3af7 100644
--- a/pdf/xpdf/CMap.cc
+++ b/pdf/xpdf/CMap.cc
@@ -144,6 +144,9 @@ CMap::CMap(GString *collectionA, GString *cMapNameA) {
vector[i].cid = 0;
}
refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
}
CMap::CMap(GString *collectionA, GString *cMapNameA, int wModeA) {
@@ -152,6 +155,9 @@ CMap::CMap(GString *collectionA, GString *cMapNameA, int wModeA) {
wMode = wModeA;
vector = NULL;
refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
}
void CMap::useCMap(CMapCache *cache, char *useName) {
@@ -252,6 +258,9 @@ CMap::~CMap() {
if (vector) {
freeCMapVector(vector);
}
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
}
void CMap::freeCMapVector(CMapVectorEntry *vec) {
@@ -266,11 +275,26 @@ void CMap::freeCMapVector(CMapVectorEntry *vec) {
}
void CMap::incRefCnt() {
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
++refCnt;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
}
void CMap::decRefCnt() {
- if (--refCnt == 0) {
+ GBool done;
+
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+ done = --refCnt == 0;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+ if (done) {
delete this;
}
}
diff --git a/pdf/xpdf/CMap.h b/pdf/xpdf/CMap.h
index b44f07a..eff2a81 100644
--- a/pdf/xpdf/CMap.h
+++ b/pdf/xpdf/CMap.h
@@ -18,6 +18,10 @@
#include "gtypes.h"
#include "CharTypes.h"
+#if MULTITHREADED
+#include "GMutex.h"
+#endif
+
class GString;
struct CMapVectorEntry;
class CMapCache;
@@ -69,6 +73,9 @@ private:
CMapVectorEntry *vector; // vector for first byte (NULL for
// identity CMap)
int refCnt;
+#ifdef MULTITHREADED
+ GMutex mutex;
+#endif
};
//------------------------------------------------------------------------
diff --git a/pdf/xpdf/Catalog.cc b/pdf/xpdf/Catalog.cc
index ad0821b..c645fd0 100644
--- a/pdf/xpdf/Catalog.cc
+++ b/pdf/xpdf/Catalog.cc
@@ -56,12 +56,13 @@ Catalog::Catalog(XRef *xrefA) {
goto err2;
}
pagesDict.dictLookup("Count", &obj);
- if (!obj.isInt()) {
+ // some PDF files actually use real numbers here ("/Count 9.0")
+ if (!obj.isNum()) {
error(-1, "Page count in top-level pages object is wrong type (%s)",
obj.getTypeName());
goto err3;
}
- pagesSize = numPages0 = obj.getInt();
+ pagesSize = numPages0 = (int)obj.getNum();
obj.free();
pages = (Page **)gmalloc(pagesSize * sizeof(Page *));
pageRefs = (Ref *)gmalloc(pagesSize * sizeof(Ref));
@@ -307,8 +308,8 @@ Object *Catalog::findDestInTree(Object *tree, GString *name, Object *obj) {
} else if (cmp < 0) {
done = gTrue;
}
- name1.free();
}
+ name1.free();
}
names.free();
if (!found)
diff --git a/pdf/xpdf/CharCodeToUnicode.cc b/pdf/xpdf/CharCodeToUnicode.cc
index a374b1b..2e2ad47 100644
--- a/pdf/xpdf/CharCodeToUnicode.cc
+++ b/pdf/xpdf/CharCodeToUnicode.cc
@@ -54,7 +54,8 @@ static int getCharFromFile(void *data) {
//------------------------------------------------------------------------
-CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *collectionA) {
+CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *fileName,
+ GString *collection) {
FILE *f;
Unicode *mapA;
CharCode size, mapLenA;
@@ -62,9 +63,9 @@ CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *collectionA) {
Unicode u;
CharCodeToUnicode *ctu;
- if (!(f = globalParams->getCIDToUnicodeFile(collectionA))) {
- error(-1, "Couldn't find cidToUnicode file for the '%s' collection",
- collectionA->getCString());
+ if (!(f = fopen(fileName->getCString(), "r"))) {
+ error(-1, "Couldn't open cidToUnicode file '%s'",
+ fileName->getCString());
return NULL;
}
@@ -80,22 +81,110 @@ CharCodeToUnicode *CharCodeToUnicode::parseCIDToUnicode(GString *collectionA) {
if (sscanf(buf, "%x", &u) == 1) {
mapA[mapLenA] = u;
} else {
- error(-1, "Bad line (%d) in cidToUnicode file for the '%s' collection",
- (int)(mapLenA + 1), collectionA->getCString());
+ error(-1, "Bad line (%d) in cidToUnicode file '%s'",
+ (int)(mapLenA + 1), fileName->getCString());
mapA[mapLenA] = 0;
}
++mapLenA;
}
fclose(f);
- ctu = new CharCodeToUnicode(collectionA->copy(), mapA, mapLenA, gTrue,
- NULL, 0);
+ ctu = new CharCodeToUnicode(collection->copy(), mapA, mapLenA, gTrue,
+ NULL, 0, 0);
+ gfree(mapA);
+ return ctu;
+}
+
+CharCodeToUnicode *CharCodeToUnicode::parseUnicodeToUnicode(
+ GString *fileName) {
+ FILE *f;
+ Unicode *mapA;
+ CharCodeToUnicodeString *sMapA;
+ CharCode size, oldSize, len, sMapSizeA, sMapLenA;
+ char buf[256];
+ char *tok;
+ Unicode u0;
+ Unicode uBuf[maxUnicodeString];
+ CharCodeToUnicode *ctu;
+ int line, n, i;
+
+ if (!(f = fopen(fileName->getCString(), "r"))) {
+ error(-1, "Couldn't open unicodeToUnicode file '%s'",
+ fileName->getCString());
+ return NULL;
+ }
+
+ size = 4096;
+ mapA = (Unicode *)gmalloc(size * sizeof(Unicode));
+ memset(mapA, 0, size * sizeof(Unicode));
+ len = 0;
+ sMapA = NULL;
+ sMapSizeA = sMapLenA = 0;
+
+ line = 0;
+ while (getLine(buf, sizeof(buf), f)) {
+ ++line;
+ if (!(tok = strtok(buf, " \t\r\n")) ||
+ sscanf(tok, "%x", &u0) != 1) {
+ error(-1, "Bad line (%d) in unicodeToUnicode file '%s'",
+ line, fileName->getCString());
+ continue;
+ }
+ n = 0;
+ while (n < maxUnicodeString) {
+ if (!(tok = strtok(NULL, " \t\r\n"))) {
+ break;
+ }
+ if (sscanf(tok, "%x", &uBuf[n]) != 1) {
+ error(-1, "Bad line (%d) in unicodeToUnicode file '%s'",
+ line, fileName->getCString());
+ break;
+ }
+ ++n;
+ }
+ if (n < 1) {
+ error(-1, "Bad line (%d) in unicodeToUnicode file '%s'",
+ line, fileName->getCString());
+ continue;
+ }
+ if (u0 >= size) {
+ oldSize = size;
+ while (u0 >= size) {
+ size *= 2;
+ }
+ mapA = (Unicode *)grealloc(mapA, size * sizeof(Unicode));
+ memset(mapA + oldSize, 0, (size - oldSize) * sizeof(Unicode));
+ }
+ if (n == 1) {
+ mapA[u0] = uBuf[0];
+ } else {
+ mapA[u0] = 0;
+ if (sMapLenA == sMapSizeA) {
+ sMapSizeA += 16;
+ sMapA = (CharCodeToUnicodeString *)
+ grealloc(sMapA, sMapSizeA * sizeof(CharCodeToUnicodeString));
+ }
+ sMapA[sMapLenA].c = u0;
+ for (i = 0; i < n; ++i) {
+ sMapA[sMapLenA].u[i] = uBuf[i];
+ }
+ sMapA[sMapLenA].len = n;
+ ++sMapLenA;
+ }
+ if (u0 >= len) {
+ len = u0 + 1;
+ }
+ }
+ fclose(f);
+
+ ctu = new CharCodeToUnicode(fileName->copy(), mapA, len, gTrue,
+ sMapA, sMapLenA, sMapSizeA);
gfree(mapA);
return ctu;
}
CharCodeToUnicode *CharCodeToUnicode::make8BitToUnicode(Unicode *toUnicode) {
- return new CharCodeToUnicode(NULL, toUnicode, 256, gTrue, NULL, 0);
+ return new CharCodeToUnicode(NULL, toUnicode, 256, gTrue, NULL, 0, 0);
}
CharCodeToUnicode *CharCodeToUnicode::parseCMap(GString *buf, int nBits) {
@@ -108,16 +197,20 @@ CharCodeToUnicode *CharCodeToUnicode::parseCMap(GString *buf, int nBits) {
return ctu;
}
+void CharCodeToUnicode::mergeCMap(GString *buf, int nBits) {
+ char *p;
+
+ p = buf->getCString();
+ parseCMap1(&getCharFromString, &p, nBits);
+}
+
void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data,
int nBits) {
PSTokenizer *pst;
char tok1[256], tok2[256], tok3[256];
int nDigits, n1, n2, n3;
- CharCode oldLen, i;
+ CharCode i;
CharCode code1, code2;
- Unicode u;
- char uHex[5];
- int j;
GString *name;
FILE *f;
@@ -158,38 +251,7 @@ void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data,
error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
continue;
}
- if (code1 >= mapLen) {
- oldLen = mapLen;
- mapLen = (code1 + 256) & ~255;
- map = (Unicode *)grealloc(map, mapLen * sizeof(Unicode));
- for (i = oldLen; i < mapLen; ++i) {
- map[i] = 0;
- }
- }
- if (n2 == 6) {
- if (sscanf(tok2 + 1, "%x", &u) != 1) {
- error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
- continue;
- }
- map[code1] = u;
- } else {
- map[code1] = 0;
- if (sMapLen == sMapSize) {
- sMapSize += 8;
- sMap = (CharCodeToUnicodeString *)
- grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString));
- }
- sMap[sMapLen].c = code1;
- sMap[sMapLen].len = (n2 - 2) / 4;
- for (j = 0; j < sMap[sMapLen].len && j < maxUnicodeString; ++j) {
- strncpy(uHex, tok2 + 1 + j*4, 4);
- uHex[4] = '\0';
- if (sscanf(uHex, "%x", &sMap[sMapLen].u[j]) != 1) {
- error(-1, "Illegal entry in bfchar block in ToUnicode CMap");
- }
- }
- ++sMapLen;
- }
+ addMapping(code1, tok2 + 1, n2 - 1, 0);
}
pst->getToken(tok1, sizeof(tok1), &n1);
} else if (!strcmp(tok2, "beginbfrange")) {
@@ -205,53 +267,39 @@ void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data,
break;
}
if (!(n1 == 2 + nDigits && tok1[0] == '<' && tok1[n1 - 1] == '>' &&
- n2 == 2 + nDigits && tok2[0] == '<' && tok2[n2 - 1] == '>' &&
- tok3[0] == '<' && tok3[n3 - 1] == '>')) {
+ n2 == 2 + nDigits && tok2[0] == '<' && tok2[n2 - 1] == '>')) {
error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
continue;
}
- tok1[n1 - 1] = tok2[n2 - 1] = tok3[n3 - 1] = '\0';
+ tok1[n1 - 1] = tok2[n2 - 1] = '\0';
if (sscanf(tok1 + 1, "%x", &code1) != 1 ||
sscanf(tok2 + 1, "%x", &code2) != 1) {
error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
continue;
}
- if (code2 >= mapLen) {
- oldLen = mapLen;
- mapLen = (code2 + 256) & ~255;
- map = (Unicode *)grealloc(map, mapLen * sizeof(Unicode));
- for (i = oldLen; i < mapLen; ++i) {
- map[i] = 0;
- }
- }
- if (n3 <= 6) {
- if (sscanf(tok3 + 1, "%x", &u) != 1) {
- error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
- continue;
- }
- for (; code1 <= code2; ++code1) {
- map[code1] = u++;
- }
- } else {
- if (sMapLen + (int)(code2 - code1 + 1) > sMapSize) {
- sMapSize = (sMapSize + (code2 - code1 + 1) + 7) & ~7;
- sMap = (CharCodeToUnicodeString *)
- grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString));
+ if (!strcmp(tok3, "[")) {
+ i = 0;
+ while (pst->getToken(tok1, sizeof(tok1), &n1) &&
+ code1 + i <= code2) {
+ if (!strcmp(tok1, "]")) {
+ break;
+ }
+ if (tok1[0] == '<' && tok1[n1 - 1] == '>') {
+ tok1[n1 - 1] = '\0';
+ addMapping(code1 + i, tok1 + 1, n1 - 2, 0);
+ } else {
+ error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
+ }
+ ++i;
}
+ } else if (tok3[0] == '<' && tok3[n3 - 1] == '>') {
+ tok3[n3 - 1] = '\0';
for (i = 0; code1 <= code2; ++code1, ++i) {
- map[code1] = 0;
- sMap[sMapLen].c = code1;
- sMap[sMapLen].len = (n3 - 2) / 4;
- for (j = 0; j < sMap[sMapLen].len && j < maxUnicodeString; ++j) {
- strncpy(uHex, tok3 + 1 + j*4, 4);
- uHex[4] = '\0';
- if (sscanf(uHex, "%x", &sMap[sMapLen].u[j]) != 1) {
- error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
- }
- }
- sMap[sMapLen].u[sMap[sMapLen].len - 1] += i;
- ++sMapLen;
+ addMapping(code1, tok3 + 1, n3 - 2, i);
}
+
+ } else {
+ error(-1, "Illegal entry in bfrange block in ToUnicode CMap");
}
}
pst->getToken(tok1, sizeof(tok1), &n1);
@@ -262,10 +310,52 @@ void CharCodeToUnicode::parseCMap1(int (*getCharFunc)(void *), void *data,
delete pst;
}
-CharCodeToUnicode::CharCodeToUnicode(GString *collectionA) {
+void CharCodeToUnicode::addMapping(CharCode code, char *uStr, int n,
+ int offset) {
+ CharCode oldLen, i;
+ Unicode u;
+ char uHex[5];
+ int j;
+
+ if (code >= mapLen) {
+ oldLen = mapLen;
+ mapLen = (code + 256) & ~255;
+ map = (Unicode *)grealloc(map, mapLen * sizeof(Unicode));
+ for (i = oldLen; i < mapLen; ++i) {
+ map[i] = 0;
+ }
+ }
+ if (n <= 4) {
+ if (sscanf(uStr, "%x", &u) != 1) {
+ error(-1, "Illegal entry in ToUnicode CMap");
+ return;
+ }
+ map[code] = u + offset;
+ } else {
+ if (sMapLen >= sMapSize) {
+ sMapSize = sMapSize + 16;
+ sMap = (CharCodeToUnicodeString *)
+ grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString));
+ }
+ map[code] = 0;
+ sMap[sMapLen].c = code;
+ sMap[sMapLen].len = n / 4;
+ for (j = 0; j < sMap[sMapLen].len && j < maxUnicodeString; ++j) {
+ strncpy(uHex, uStr + j*4, 4);
+ uHex[4] = '\0';
+ if (sscanf(uHex, "%x", &sMap[sMapLen].u[j]) != 1) {
+ error(-1, "Illegal entry in ToUnicode CMap");
+ }
+ }
+ sMap[sMapLen].u[sMap[sMapLen].len - 1] += offset;
+ ++sMapLen;
+ }
+}
+
+CharCodeToUnicode::CharCodeToUnicode(GString *tagA) {
CharCode i;
- collection = collectionA;
+ tag = tagA;
mapLen = 256;
map = (Unicode *)gmalloc(mapLen * sizeof(Unicode));
for (i = 0; i < mapLen; ++i) {
@@ -274,13 +364,16 @@ CharCodeToUnicode::CharCodeToUnicode(GString *collectionA) {
sMap = NULL;
sMapLen = sMapSize = 0;
refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
}
-CharCodeToUnicode::CharCodeToUnicode(GString *collectionA, Unicode *mapA,
+CharCodeToUnicode::CharCodeToUnicode(GString *tagA, Unicode *mapA,
CharCode mapLenA, GBool copyMap,
CharCodeToUnicodeString *sMapA,
- int sMapLenA) {
- collection = collectionA;
+ int sMapLenA, int sMapSizeA) {
+ tag = tagA;
mapLen = mapLenA;
if (copyMap) {
map = (Unicode *)gmalloc(mapLen * sizeof(Unicode));
@@ -289,32 +382,75 @@ CharCodeToUnicode::CharCodeToUnicode(GString *collectionA, Unicode *mapA,
map = mapA;
}
sMap = sMapA;
- sMapLen = sMapSize = sMapLenA;
+ sMapLen = sMapLenA;
+ sMapSize = sMapSizeA;
refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
}
CharCodeToUnicode::~CharCodeToUnicode() {
- if (collection) {
- delete collection;
+ if (tag) {
+ delete tag;
}
gfree(map);
if (sMap) {
gfree(sMap);
}
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
}
void CharCodeToUnicode::incRefCnt() {
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
++refCnt;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
}
void CharCodeToUnicode::decRefCnt() {
- if (--refCnt == 0) {
+ GBool done;
+
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+ done = --refCnt == 0;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+ if (done) {
delete this;
}
}
-GBool CharCodeToUnicode::match(GString *collectionA) {
- return collection && !collection->cmp(collectionA);
+GBool CharCodeToUnicode::match(GString *tagA) {
+ return tag && !tag->cmp(tagA);
+}
+
+void CharCodeToUnicode::setMapping(CharCode c, Unicode *u, int len) {
+ int i;
+
+ if (len == 1) {
+ map[c] = u[0];
+ } else {
+ map[c] = 0;
+ if (sMapLen == sMapSize) {
+ sMapSize += 8;
+ sMap = (CharCodeToUnicodeString *)
+ grealloc(sMap, sMapSize * sizeof(CharCodeToUnicodeString));
+ }
+ sMap[sMapLen].c = c;
+ sMap[sMapLen].len = len;
+ for (i = 0; i < len && i < maxUnicodeString; ++i) {
+ sMap[sMapLen].u[i] = u[i];
+ }
+ ++sMapLen;
+ }
}
int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode *u, int size) {
@@ -340,34 +476,37 @@ int CharCodeToUnicode::mapToUnicode(CharCode c, Unicode *u, int size) {
//------------------------------------------------------------------------
-CIDToUnicodeCache::CIDToUnicodeCache() {
+CharCodeToUnicodeCache::CharCodeToUnicodeCache(int sizeA) {
int i;
- for (i = 0; i < cidToUnicodeCacheSize; ++i) {
+ size = sizeA;
+ cache = (CharCodeToUnicode **)gmalloc(size * sizeof(CharCodeToUnicode *));
+ for (i = 0; i < size; ++i) {
cache[i] = NULL;
}
}
-CIDToUnicodeCache::~CIDToUnicodeCache() {
+CharCodeToUnicodeCache::~CharCodeToUnicodeCache() {
int i;
- for (i = 0; i < cidToUnicodeCacheSize; ++i) {
+ for (i = 0; i < size; ++i) {
if (cache[i]) {
cache[i]->decRefCnt();
}
}
+ gfree(cache);
}
-CharCodeToUnicode *CIDToUnicodeCache::getCIDToUnicode(GString *collection) {
+CharCodeToUnicode *CharCodeToUnicodeCache::getCharCodeToUnicode(GString *tag) {
CharCodeToUnicode *ctu;
int i, j;
- if (cache[0] && cache[0]->match(collection)) {
+ if (cache[0] && cache[0]->match(tag)) {
cache[0]->incRefCnt();
return cache[0];
}
- for (i = 1; i < cidToUnicodeCacheSize; ++i) {
- if (cache[i] && cache[i]->match(collection)) {
+ for (i = 1; i < size; ++i) {
+ if (cache[i] && cache[i]->match(tag)) {
ctu = cache[i];
for (j = i; j >= 1; --j) {
cache[j] = cache[j - 1];
@@ -377,16 +516,18 @@ CharCodeToUnicode *CIDToUnicodeCache::getCIDToUnicode(GString *collection) {
return ctu;
}
}
- if ((ctu = CharCodeToUnicode::parseCIDToUnicode(collection))) {
- if (cache[cidToUnicodeCacheSize - 1]) {
- cache[cidToUnicodeCacheSize - 1]->decRefCnt();
- }
- for (j = cidToUnicodeCacheSize - 1; j >= 1; --j) {
- cache[j] = cache[j - 1];
- }
- cache[0] = ctu;
- ctu->incRefCnt();
- return ctu;
- }
return NULL;
}
+
+void CharCodeToUnicodeCache::add(CharCodeToUnicode *ctu) {
+ int i;
+
+ if (cache[size - 1]) {
+ cache[size - 1]->decRefCnt();
+ }
+ for (i = size - 1; i >= 1; --i) {
+ cache[i] = cache[i - 1];
+ }
+ cache[0] = ctu;
+ ctu->incRefCnt();
+}
diff --git a/pdf/xpdf/CharCodeToUnicode.h b/pdf/xpdf/CharCodeToUnicode.h
index b20f323..605e2bd 100644
--- a/pdf/xpdf/CharCodeToUnicode.h
+++ b/pdf/xpdf/CharCodeToUnicode.h
@@ -19,6 +19,10 @@
#include "CharTypes.h"
+#if MULTITHREADED
+#include "GMutex.h"
+#endif
+
struct CharCodeToUnicodeString;
//------------------------------------------------------------------------
@@ -26,10 +30,16 @@ struct CharCodeToUnicodeString;
class CharCodeToUnicode {
public:
- // Create the CID-to-Unicode mapping specified by <collection>.
- // This reads a .cidToUnicode file from disk. Sets the initial
- // reference count to 1. Returns NULL on failure.
- static CharCodeToUnicode *parseCIDToUnicode(GString *collectionA);
+ // Read the CID-to-Unicode mapping for <collection> from the file
+ // specified by <fileName>. Sets the initial reference count to 1.
+ // Returns NULL on failure.
+ static CharCodeToUnicode *parseCIDToUnicode(GString *fileName,
+ GString *collection);
+
+ // Create a Unicode-to-Unicode mapping from the file specified by
+ // <fileName>. Sets the initial reference count to 1. Returns NULL
+ // on failure.
+ static CharCodeToUnicode *parseUnicodeToUnicode(GString *fileName);
// Create the CharCode-to-Unicode mapping for an 8-bit font.
// <toUnicode> is an array of 256 Unicode indexes. Sets the initial
@@ -39,13 +49,20 @@ public:
// Parse a ToUnicode CMap for an 8- or 16-bit font.
static CharCodeToUnicode *parseCMap(GString *buf, int nBits);
+ // Parse a ToUnicode CMap for an 8- or 16-bit font, merging it into
+ // <this>.
+ void mergeCMap(GString *buf, int nBits);
+
~CharCodeToUnicode();
void incRefCnt();
void decRefCnt();
- // Return true if this mapping matches the specified <collectionA>.
- GBool match(GString *collectionA);
+ // Return true if this mapping matches the specified <tagA>.
+ GBool match(GString *tagA);
+
+ // Set the mapping for <c>.
+ void setMapping(CharCode c, Unicode *u, int len);
// Map a CharCode to Unicode.
int mapToUnicode(CharCode c, Unicode *u, int size);
@@ -53,38 +70,44 @@ public:
private:
void parseCMap1(int (*getCharFunc)(void *), void *data, int nBits);
- CharCodeToUnicode(GString *collectionA);
- CharCodeToUnicode(GString *collectionA, Unicode *mapA,
+ void addMapping(CharCode code, char *uStr, int n, int offset);
+ CharCodeToUnicode(GString *tagA);
+ CharCodeToUnicode(GString *tagA, Unicode *mapA,
CharCode mapLenA, GBool copyMap,
- CharCodeToUnicodeString *sMapA, int sMapLenA);
+ CharCodeToUnicodeString *sMapA,
+ int sMapLenA, int sMapSizeA);
- GString *collection;
+ GString *tag;
Unicode *map;
CharCode mapLen;
CharCodeToUnicodeString *sMap;
int sMapLen, sMapSize;
int refCnt;
+#ifdef MULTITHREADED
+ GMutex mutex;
+#endif
};
//------------------------------------------------------------------------
-#define cidToUnicodeCacheSize 4
-
-class CIDToUnicodeCache {
+class CharCodeToUnicodeCache {
public:
- CIDToUnicodeCache();
- ~CIDToUnicodeCache();
+ CharCodeToUnicodeCache(int sizeA);
+ ~CharCodeToUnicodeCache();
+
+ // Get the CharCodeToUnicode object for <tag>. Increments its
+ // reference count; there will be one reference for the cache plus
+ // one for the caller of this function. Returns NULL on failure.
+ CharCodeToUnicode *getCharCodeToUnicode(GString *tag);
- // Get the CharCodeToUnicode object for <collection>. Increments
- // its reference count; there will be one reference for the cache
- // plus one for the caller of this function. Returns NULL on
- // failure.
- CharCodeToUnicode *getCIDToUnicode(GString *collection);
+ // Insert <ctu> into the cache, in the most-recently-used position.
+ void add(CharCodeToUnicode *ctu);
private:
- CharCodeToUnicode *cache[cidToUnicodeCacheSize];
+ CharCodeToUnicode **cache;
+ int size;
};
#endif
diff --git a/pdf/xpdf/Decrypt.cc b/pdf/xpdf/Decrypt.cc
index dca3762..dab0750 100644
--- a/pdf/xpdf/Decrypt.cc
+++ b/pdf/xpdf/Decrypt.cc
@@ -74,6 +74,7 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength,
int len, i, j;
// try using the supplied owner password to generate the user password
+ *ownerPasswordOk = gFalse;
if (ownerPassword) {
len = ownerPassword->getLength();
if (len < 32) {
@@ -82,43 +83,40 @@ GBool Decrypt::makeFileKey(int encVersion, int encRevision, int keyLength,
} else {
memcpy(test, ownerPassword->getCString(), 32);
}
- } else {
- memcpy(test, passwordPad, 32);
- }
- md5(test, 32, test);
- if (encRevision == 3) {
- for (i = 0; i < 50; ++i) {
- md5(test, 16, test);
- }
- }
- if (encRevision == 2) {
- rc4InitKey(test, keyLength, fState);
- fx = fy = 0;
- for (i = 0; i < 32; ++i) {
- test2[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i));
- }
- } else {
- memcpy(test2, ownerKey->getCString(), 32);
- for (i = 19; i >= 0; --i) {
- for (j = 0; j < keyLength; ++j) {
- tmpKey[j] = test[j] ^ i;
+ md5(test, 32, test);
+ if (encRevision == 3) {
+ for (i = 0; i < 50; ++i) {
+ md5(test, 16, test);
}
- rc4InitKey(tmpKey, keyLength, fState);
+ }
+ if (encRevision == 2) {
+ rc4InitKey(test, keyLength, fState);
fx = fy = 0;
- for (j = 0; j < 32; ++j) {
- test2[j] = rc4DecryptByte(fState, &fx, &fy, test2[j]);
+ for (i = 0; i < 32; ++i) {
+ test2[i] = rc4DecryptByte(fState, &fx, &fy, ownerKey->getChar(i));
+ }
+ } else {
+ memcpy(test2, ownerKey->getCString(), 32);
+ for (i = 19; i >= 0; --i) {
+ for (j = 0; j < keyLength; ++j) {
+ tmpKey[j] = test[j] ^ i;
+ }
+ rc4InitKey(tmpKey, keyLength, fState);
+ fx = fy = 0;
+ for (j = 0; j < 32; ++j) {
+ test2[j] = rc4DecryptByte(fState, &fx, &fy, test2[j]);
+ }
}
}
- }
- userPassword2 = new GString((char *)test2, 32);
- if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
- permissions, fileID, userPassword2, fileKey)) {
- *ownerPasswordOk = gTrue;
+ userPassword2 = new GString((char *)test2, 32);
+ if (makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
+ permissions, fileID, userPassword2, fileKey)) {
+ *ownerPasswordOk = gTrue;
+ delete userPassword2;
+ return gTrue;
+ }
delete userPassword2;
- return gTrue;
}
- *ownerPasswordOk = gFalse;
- delete userPassword2;
// try using the supplied user password
return makeFileKey2(encVersion, encRevision, keyLength, ownerKey, userKey,
diff --git a/pdf/xpdf/Dict.cc b/pdf/xpdf/Dict.cc
index 9575e4c..6274590 100644
--- a/pdf/xpdf/Dict.cc
+++ b/pdf/xpdf/Dict.cc
@@ -41,8 +41,12 @@ Dict::~Dict() {
}
void Dict::add(char *key, Object *val) {
- if (length + 1 > size) {
- size += 8;
+ if (length == size) {
+ if (length == 0) {
+ size = 8;
+ } else {
+ size *= 2;
+ }
entries = (DictEntry *)grealloc(entries, size * sizeof(DictEntry));
}
entries[length].key = key;
diff --git a/pdf/xpdf/ErrorCodes.h b/pdf/xpdf/ErrorCodes.h
index 8de2b01..6eb1435 100644
--- a/pdf/xpdf/ErrorCodes.h
+++ b/pdf/xpdf/ErrorCodes.h
@@ -23,4 +23,12 @@
#define errHighlightFile 5 // nonexistent or invalid highlight file
+#define errBadPrinter 6 // invalid printer
+
+#define errPrinting 7 // error during printing
+
+#define errPermission 8 // PDF file doesn't allow that operation
+
+#define errBadPageNum 9 // invalid page number
+
#endif
diff --git a/pdf/xpdf/FTFont.cc b/pdf/xpdf/FTFont.cc
index c360eb7..1a5ecfa 100644
--- a/pdf/xpdf/FTFont.cc
+++ b/pdf/xpdf/FTFont.cc
@@ -48,11 +48,9 @@ FTFontEngine::~FTFontEngine() {
//------------------------------------------------------------------------
FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
- char **fontEnc, GBool pdfFontHasEncoding,
- GBool pdfFontIsSymbolic) {
+ char **fontEnc, Gushort *codeToGID) {
char *name;
- int unicodeCmap, macRomanCmap, msSymbolCmap;
- int i, j;
+ int i;
ok = gFalse;
engine = engineA;
@@ -66,7 +64,6 @@ FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
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) {
@@ -77,73 +74,10 @@ FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
}
} else {
-
- // 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 TrueType font has a Microsoft Unicode cmap, use it,
- // and use the Unicode indexes, not the char codes.
- // 1b. If the PDF font is symbolic and the TrueType font has a
- // Microsoft Symbol cmap, use it, and use (0xf000 + char code).
- // 1c. If the TrueType font has a Macintosh Roman cmap, use it,
- // and reverse map the char names through MacRomanEncoding to
- // get char codes.
- // 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.
- // 2b. If the TrueType font has a Microsoft Symbol cmap, use it,
- // and use (0xf000 + char code).
- // 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 < face->num_charmaps; ++i) {
- if ((face->charmaps[i]->platform_id == 3 &&
- face->charmaps[i]->encoding_id == 1) ||
- face->charmaps[i]->platform_id == 0) {
- unicodeCmap = i;
- } else if (face->charmaps[i]->platform_id == 1 &&
- face->charmaps[i]->encoding_id == 0) {
- macRomanCmap = i;
- } else if (face->charmaps[i]->platform_id == 3 &&
- face->charmaps[i]->encoding_id == 0) {
- msSymbolCmap = i;
- }
- }
- i = 0;
- mode = ftFontModeCharCode;
- charMapOffset = 0;
- if (pdfFontHasEncoding) {
- if (unicodeCmap != 0xffff) {
- i = unicodeCmap;
- mode = ftFontModeUnicode;
- } else if (pdfFontIsSymbolic && msSymbolCmap != 0xffff) {
- i = msSymbolCmap;
- mode = ftFontModeCharCodeOffset;
- charMapOffset = 0xf000;
- } else if (macRomanCmap != 0xffff) {
- i = macRomanCmap;
- mode = ftFontModeCodeMap;
- codeMap = (Guint *)gmalloc(256 * sizeof(Guint));
- for (j = 0; j < 256; ++j) {
- if (fontEnc[j]) {
- codeMap[j] = globalParams->getMacRomanCharCode(fontEnc[j]);
- } else {
- codeMap[j] = 0;
- }
- }
- }
- } else {
- if (macRomanCmap != 0xffff) {
- i = macRomanCmap;
- mode = ftFontModeCharCode;
- } else if (msSymbolCmap != 0xffff) {
- i = msSymbolCmap;
- mode = ftFontModeCharCodeOffset;
- charMapOffset = 0xf000;
- }
- }
- if (FT_Set_Charmap(face, face->charmaps[i])) {
- return;
+ mode = ftFontModeCodeMapDirect;
+ codeMap = (Guint *)gmalloc(256 * sizeof(Guint));
+ for (i = 0; i < 256; ++i) {
+ codeMap[i] = (int)codeToGID[i];
}
}
@@ -558,7 +492,9 @@ Guchar *FTFont::getGlyphPixmap(CharCode c, Unicode u,
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, FT_LOAD_DEFAULT)) {
+ if (FT_Load_Glyph(fontFile->face, idx,
+ fontFile->engine->aa ? FT_LOAD_NO_BITMAP
+ : FT_LOAD_DEFAULT)) {
return gFalse;
}
#else
@@ -567,8 +503,8 @@ Guchar *FTFont::getGlyphPixmap(CharCode c, Unicode u,
// 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)) {
+ fontFile->engine->aa ? FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP
+ : FT_LOAD_DEFAULT)) {
return gFalse;
}
#endif
@@ -721,22 +657,6 @@ FT_UInt FTFont::getGlyphIndex(CharCode c, Unicode u) {
case ftFontModeUnicode:
idx = FT_Get_Char_Index(fontFile->face, (FT_ULong)u);
break;
- case ftFontModeCharCode:
- idx = FT_Get_Char_Index(fontFile->face, (FT_ULong)c);
- break;
- case ftFontModeCharCodeOffset:
- if ((idx = FT_Get_Char_Index(fontFile->face, (FT_ULong)c)) == 0) {
- idx = FT_Get_Char_Index(fontFile->face,
- (FT_ULong)(c + fontFile->charMapOffset));
- }
- break;
- case ftFontModeCodeMap:
- if (c <= 0xff) {
- idx = FT_Get_Char_Index(fontFile->face, (FT_ULong)fontFile->codeMap[c]);
- } else {
- idx = 0;
- }
- break;
case ftFontModeCodeMapDirect:
if (c <= 0xff) {
idx = (FT_UInt)fontFile->codeMap[c];
diff --git a/pdf/xpdf/FTFont.h b/pdf/xpdf/FTFont.h
index 52bc149..8da5558 100644
--- a/pdf/xpdf/FTFont.h
+++ b/pdf/xpdf/FTFont.h
@@ -48,9 +48,6 @@ private:
enum FTFontIndexMode {
ftFontModeUnicode,
- ftFontModeCharCode,
- ftFontModeCharCodeOffset,
- ftFontModeCodeMap,
ftFontModeCodeMapDirect,
ftFontModeCIDToGIDMap,
ftFontModeCFFCharset,
@@ -62,8 +59,7 @@ public:
// 8-bit font, TrueType or Type 1/1C
FTFontFile(FTFontEngine *engineA, char *fontFileName,
- char **fontEnc, GBool pdfFontHasEncoding,
- GBool pdfFontIsSymbolic);
+ char **fontEnc, Gushort *codeToGID);
// CID font, TrueType
FTFontFile(FTFontEngine *engineA, char *fontFileName,
@@ -81,7 +77,6 @@ private:
FTFontEngine *engine;
FT_Face face;
FTFontIndexMode mode;
- int charMapOffset;
Guint *codeMap;
Gushort *cidToGID;
int cidToGIDLen;
diff --git a/pdf/xpdf/FontFile.cc b/pdf/xpdf/FontFile.cc
index fde0ae6..0c44422 100644
--- a/pdf/xpdf/FontFile.cc
+++ b/pdf/xpdf/FontFile.cc
@@ -20,6 +20,7 @@
#include <string.h>
#include <ctype.h>
#include "gmem.h"
+#include "GHash.h"
#include "Error.h"
#include "GlobalParams.h"
#include "CharCodeToUnicode.h"
@@ -33,7 +34,7 @@
static inline char *nextLine(char *line, char *end) {
while (line < end && *line != '\n' && *line != '\r')
++line;
- while (line < end && *line == '\n' || *line == '\r')
+ while (line < end && (*line == '\n' || *line == '\r'))
++line;
return line;
}
@@ -354,10 +355,12 @@ void Type1CFontFile::readEncoding() {
c = file[pos++];
nLeft = file[pos++];
for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
- if (encoding[c]) {
- gfree(encoding[c]);
+ if (c < 256) {
+ if (encoding[c]) {
+ gfree(encoding[c]);
+ }
+ encoding[c] = copyString(getString(glyphNames[nCodes], buf));
}
- encoding[c] = copyString(getString(glyphNames[nCodes], buf));
++nCodes;
++c;
}
@@ -415,7 +418,10 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA,
(*outputFunc)(outputStream, buf, strlen(buf));
}
(*outputFunc)(outputStream, "\n", 1);
- (*outputFunc)(outputStream, "11 dict begin\n", 14);
+ // 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);
@@ -590,7 +596,8 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA,
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} ND\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;
@@ -599,7 +606,7 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA,
nominalWidthXFP = privateDict.nominalWidthXFP;
// set up subroutines
- subrIdxPos = dict.privateOffset + privateDict.subrsOffset;
+ subrIdxPos = privateDict.subrsOffset;
i = getIndexLen(gsubrIdxPos);
gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768;
i = getIndexLen(subrIdxPos);
@@ -806,7 +813,7 @@ void Type1CFontFile::convertToCIDType0(char *psName,
defaultWidthXFP = privateDicts[j].defaultWidthXFP;
nominalWidthX = privateDicts[j].nominalWidthX;
nominalWidthXFP = privateDicts[j].nominalWidthXFP;
- subrIdxPos = dict.privateOffset + privateDicts[j].subrsOffset;
+ subrIdxPos = privateDicts[j].subrsOffset;
k = getIndexLen(subrIdxPos);
subrBias = (k < 1240) ? 107 : (k < 33900) ? 1131 : 32768;
cvtGlyph(idxPos, idxLen, gTrue);
@@ -1148,6 +1155,10 @@ void Type1CFontFile::convertToType0(char *psName,
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);
@@ -1162,7 +1173,8 @@ void Type1CFontFile::convertToType0(char *psName,
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} ND\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;
@@ -1170,7 +1182,7 @@ void Type1CFontFile::convertToType0(char *psName,
nominalWidthXFP = privateDicts[fd].nominalWidthXFP;
// set up the subroutines
- subrIdxPos = dict.privateOffset + privateDicts[fd].subrsOffset;
+ subrIdxPos = privateDicts[fd].subrsOffset;
j = getIndexLen(subrIdxPos);
subrBias = (j < 1240) ? 107 : (j < 33900) ? 1131 : 32768;
@@ -1445,7 +1457,7 @@ void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict,
error(-1, "Got Type 1C InitialRandomSeed");
break;
case 0x0013:
- privateDict->subrsOffset = (int)op[0];
+ privateDict->subrsOffset = offset + (int)op[0];
break;
case 0x0014:
privateDict->defaultWidthX = op[0];
@@ -1711,7 +1723,7 @@ void Type1CFontFile::cvtGlyph(int pos, int n, GBool top) {
} else if (file[i] == 19) { // hintmask
// ignored
if (firstOp) {
- cvtGlyphWidth(nOps == 1);
+ cvtGlyphWidth(nOps & 1);
firstOp = gFalse;
}
if (nOps > 0) {
@@ -1726,7 +1738,7 @@ void Type1CFontFile::cvtGlyph(int pos, int n, GBool top) {
} else if (file[i] == 20) { // cntrmask
// ignored
if (firstOp) {
- cvtGlyphWidth(nOps == 1);
+ cvtGlyphWidth(nOps & 1);
firstOp = gFalse;
}
if (nOps > 0) {
@@ -2092,6 +2104,13 @@ void Type1CFontFile::cvtGlyph(int pos, int n, GBool top) {
}
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) {
@@ -2343,7 +2362,7 @@ int Type1CFontFile::getIndexValPos(int indexPos, int i, int *valLen) {
int Type1CFontFile::getIndexEnd(int indexPos) {
int n, offSize, idxStartPos;
- if (indexPos + 3 > len) {
+ if (indexPos < 0 || indexPos + 3 > len) {
return -1;
}
n = (int)getWord(indexPos, 2);
@@ -2545,6 +2564,14 @@ struct T42Table {
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
@@ -2828,13 +2855,6 @@ static char *macGlyphNames[258] = {
"dmacron"
};
-enum T42FontIndexMode {
- t42FontModeUnicode,
- t42FontModeCharCode,
- t42FontModeCharCodeOffset,
- t42FontModeMacRoman
-};
-
struct TrueTypeLoca {
int idx;
int pos;
@@ -2842,13 +2862,15 @@ struct TrueTypeLoca {
};
TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) {
- int pos, i, idx, n, length;
+ 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);
@@ -2917,6 +2939,23 @@ TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) {
// 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() {
@@ -2928,6 +2967,9 @@ TrueTypeFontFile::~TrueTypeFontFile() {
}
gfree(encoding);
}
+ if (cmaps) {
+ gfree(cmaps);
+ }
gfree(tableHdrs);
}
@@ -2936,146 +2978,117 @@ char *TrueTypeFontFile::getName() {
}
char **TrueTypeFontFile::getEncoding() {
- int cmap[256];
- int nCmaps, cmapPlatform, cmapEncoding, cmapFmt;
- int pos, i, j;
- Guint fmt;
- GString *s;
- int stringIdx, stringPos, n;
+ int i;
- if (encoding) {
- return encoding;
+ if (!encoding) {
+ encoding = (char **)gmalloc(256 * sizeof(char *));
+ for (i = 0; i < 256; ++i) {
+ encoding[i] = NULL;
+ }
}
+ return encoding;
+}
- //----- construct the (char code) -> (glyph idx) mapping
+int TrueTypeFontFile::getNumCmaps() {
+ return nCmaps;
+}
- // map everything to the missing glyph
- for (i = 0; i < 256; ++i) {
- cmap[i] = 0;
- }
+int TrueTypeFontFile::getCmapPlatform(int i) {
+ return cmaps[i].platform;
+}
- // look for the 'cmap' table
- if ((pos = seekTable("cmap")) >= 0) {
- nCmaps = getUShort(pos+2);
-
- // if the font has a Windows-symbol cmap, use it;
- // otherwise, use the first cmap in the table
- cmapPlatform = 0; // make gcc happy
- cmapEncoding = 0; // make gcc happy
- for (i = 0; i < nCmaps; ++i) {
- cmapPlatform = getUShort(pos + 4 + 8*i);
- cmapEncoding = getUShort(pos + 4 + 8*i + 2);
- if (cmapPlatform == 3 && cmapEncoding == 0) {
- break;
- }
- }
- if (i >= nCmaps) {
- i = 0;
- cmapPlatform = getUShort(pos + 4);
- cmapEncoding = getUShort(pos + 4 + 2);
- }
- pos += getULong(pos + 4 + 8*i + 4);
+int TrueTypeFontFile::getCmapEncoding(int i) {
+ return cmaps[i].encoding;
+}
- // read the cmap
- cmapFmt = getUShort(pos);
- for (i = 0; i < 256; ++i) {
- cmap[i] = getCmapEntry(cmapFmt, pos, i);
- }
- // Windows-symbol sometimes uses char codes 0xf000 - 0xf0ff, so
- // we use these to override 0x0000 - 0x00ff
- if (cmapPlatform == 3 && cmapEncoding == 0) {
- for (i = 0; i < 256; ++i) {
- if ((j = getCmapEntry(cmapFmt, pos, 0xf000 + i)) != 0) {
- cmap[i] = j;
- }
- }
+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);
+}
- //----- construct the (glyph idx) -> (glyph name) mapping
- //----- and compute the (char code) -> (glyph name) mapping
+GHash *TrueTypeFontFile::getNameToGID() {
+ GHash *nameToGID;
+ Guint fmt;
+ GString *s;
+ int stringIdx, stringPos, pos, i, j, n;
- encoding = (char **)gmalloc(256 * sizeof(char *));
- for (i = 0; i < 256; ++i) {
- encoding[i] = NULL;
+ if ((pos = seekTable("post")) < 0) {
+ return NULL;
}
- if ((pos = seekTable("post")) >= 0) {
- fmt = getULong(pos);
+ fmt = getULong(pos);
+ nameToGID = NULL;
- // Apple font
- if (fmt == 0x00010000) {
- for (i = 0; i < 256; ++i) {
- j = (cmap[i] < 258) ? cmap[i] : 0;
- encoding[i] = copyString(macGlyphNames[j]);
- }
+ // 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) {
- stringIdx = 0;
- stringPos = pos + 34 + 2*nGlyphs;
- for (i = 0; i < 256; ++i) {
- if (cmap[i] < nGlyphs) {
- j = getUShort(pos + 34 + 2 * cmap[i]);
- if (j < 258) {
- encoding[i] = copyString(macGlyphNames[j]);
- } 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);
- encoding[i] = copyString(s->getCString());
- delete s;
- } else {
- encoding[i] = copyString(macGlyphNames[0]);
- }
- ++stringIdx;
- stringPos += 1 + n;
- }
- } else {
- encoding[i] = copyString(macGlyphNames[0]);
+ // 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)) ;
}
- }
-
- // Apple subset
- } else if (fmt == 0x000280000) {
- for (i = 0; i < 256; ++i) {
- if (cmap[i] < nGlyphs) {
- j = i + getChar(pos + 32 + cmap[i]);
- } else {
- j = 0;
+ 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);
}
- encoding[i] = copyString(macGlyphNames[j]);
- }
-
- // Ugh, just assume the Apple glyph set
- } else {
- for (i = 0; i < 256; ++i) {
- j = (cmap[i] < 258) ? cmap[i] : 0;
- encoding[i] = copyString(macGlyphNames[j]);
+ ++stringIdx;
+ stringPos += 1 + n;
}
}
- // no "post" table: assume the Apple glyph set
- } else {
- for (i = 0; i < 256; ++i) {
- j = (cmap[i] < 258) ? cmap[i] : 0;
- encoding[i] = copyString(macGlyphNames[j]);
+ // 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 encoding;
+ return nameToGID;
}
void TrueTypeFontFile::convertToType42(char *name, char **encodingA,
- CharCodeToUnicode *toUnicode,
GBool pdfFontHasEncoding,
- GBool pdfFontIsSymbolic,
+ Gushort *codeToGID,
FontFileOutputFunc outputFunc,
void *outputStream) {
char buf[512];
@@ -3098,7 +3111,7 @@ void TrueTypeFontFile::convertToType42(char *name, char **encodingA,
// write the guts of the dictionary
cvtEncoding(encodingA, pdfFontHasEncoding, outputFunc, outputStream);
- cvtCharStrings(encodingA, toUnicode, pdfFontHasEncoding, pdfFontIsSymbolic,
+ cvtCharStrings(encodingA, pdfFontHasEncoding, codeToGID,
outputFunc, outputStream);
cvtSfnts(outputFunc, outputStream, NULL);
@@ -3403,96 +3416,26 @@ void TrueTypeFontFile::cvtEncoding(char **encodingA, GBool pdfFontHasEncoding,
}
void TrueTypeFontFile::cvtCharStrings(char **encodingA,
- CharCodeToUnicode *toUnicode,
GBool pdfFontHasEncoding,
- GBool pdfFontIsSymbolic,
+ Gushort *codeToGID,
FontFileOutputFunc outputFunc,
void *outputStream) {
- int unicodeCmap, macRomanCmap, msSymbolCmap;
- int nCmaps, cmapPlatform, cmapEncoding, cmapFmt, cmapOffset;
- T42FontIndexMode mode;
char *name;
char buf[64], buf2[16];
- Unicode u;
- int pos, i, j, k;
+ 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 ((pos = seekTable("cmap")) < 0) {
- goto err;
- }
-
- // 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 TrueType font has a Microsoft Unicode cmap, use it,
- // and use the Unicode indexes, not the char codes.
- // 1b. If the PDF font is symbolic and the TrueType font has a
- // Microsoft Symbol cmap, use it, and use (0xf000 + char code).
- // 1c. If the TrueType font has a Macintosh Roman cmap, use it,
- // and reverse map the char names through MacRomanEncoding to
- // get char codes.
- // 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.
- // 2b. If the TrueType font has a Microsoft Symbol cmap, use it,
- // and use (0xf000 + char code).
- // 3. If none of these rules apply, use the first cmap and hope for
- // the best (this shouldn't happen).
- nCmaps = getUShort(pos+2);
- unicodeCmap = macRomanCmap = msSymbolCmap = -1;
- cmapOffset = 0;
- for (i = 0; i < nCmaps; ++i) {
- cmapPlatform = getUShort(pos + 4 + 8*i);
- cmapEncoding = getUShort(pos + 4 + 8*i + 2);
- if ((cmapPlatform == 3 && cmapEncoding == 1) || cmapPlatform == 0) {
- unicodeCmap = i;
- } else if (cmapPlatform == 1 && cmapEncoding == 0) {
- macRomanCmap = i;
- } else if (cmapPlatform == 3 && cmapEncoding == 0) {
- msSymbolCmap = i;
- }
- }
- i = 0;
- mode = t42FontModeCharCode;
- if (pdfFontHasEncoding) {
- if (unicodeCmap >= 0) {
- i = unicodeCmap;
- mode = t42FontModeUnicode;
- } else if (pdfFontIsSymbolic && msSymbolCmap >= 0) {
- i = msSymbolCmap;
- mode = t42FontModeCharCodeOffset;
- cmapOffset = 0xf000;
- } else if (macRomanCmap >= 0) {
- i = macRomanCmap;
- mode = t42FontModeMacRoman;
- }
- } else {
- if (macRomanCmap >= 0) {
- i = macRomanCmap;
- mode = t42FontModeCharCode;
- } else if (msSymbolCmap >= 0) {
- i = msSymbolCmap;
- mode = t42FontModeCharCodeOffset;
- cmapOffset = 0xf000;
- }
- }
- cmapPlatform = getUShort(pos + 4 + 8*i);
- cmapEncoding = getUShort(pos + 4 + 8*i + 2);
- pos += getULong(pos + 4 + 8*i + 4);
- cmapFmt = getUShort(pos);
- if (cmapFmt != 0 && cmapFmt != 4 && cmapFmt != 6) {
- error(-1, "Unimplemented cmap format (%d) in TrueType font file",
- cmapFmt);
+ if (nCmaps == 0) {
goto err;
}
// map char name to glyph index:
// 1. use encoding to map name to char code
- // 2. use cmap to map char code to glyph index
+ // 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.
@@ -3505,24 +3448,7 @@ void TrueTypeFontFile::cvtCharStrings(char **encodingA,
name = buf2;
}
if (name && strcmp(name, ".notdef")) {
- switch (mode) {
- case t42FontModeUnicode:
- toUnicode->mapToUnicode((CharCode)i, &u, 1);
- k = getCmapEntry(cmapFmt, pos, (int)u);
- break;
- case t42FontModeCharCode:
- k = getCmapEntry(cmapFmt, pos, i);
- break;
- case t42FontModeCharCodeOffset:
- if ((k = getCmapEntry(cmapFmt, pos, cmapOffset + i)) == 0) {
- k = getCmapEntry(cmapFmt, pos, i);
- }
- break;
- case t42FontModeMacRoman:
- j = globalParams->getMacRomanCharCode(name);
- k = getCmapEntry(cmapFmt, pos, j);
- break;
- }
+ 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)
@@ -3929,7 +3855,7 @@ void TrueTypeFontFile::writeTTF(FILE *out) {
TrueTypeLoca *origLocaTable;
char *locaTable;
int length, glyfLength;
- Guint t, pos, pos2;
+ Guint t, pos, pos2, pos3;
int i, j, k;
// check for missing/broken tables
@@ -3937,18 +3863,19 @@ void TrueTypeFontFile::writeTTF(FILE *out) {
haveName = seekTable("name") >= 0;
havePost = seekTable("post") >= 0;
unsortedLoca = gFalse;
- pos = 0;
+ pos = seekTable("loca");
+ pos2 = 0;
for (i = 0; i <= nGlyphs; ++i) {
if (locaFmt) {
- pos2 = getULong(pos + 4*i);
+ pos3 = getULong(pos + 4*i);
} else {
- pos2 = 2 * getUShort(pos + 2*i);
+ pos3 = 2 * getUShort(pos + 2*i);
}
- if (pos2 < pos) {
+ if (pos3 < pos2) {
unsortedLoca = gTrue;
break;
}
- pos = pos2;
+ pos2 = pos3;
}
nNewTables = (haveCmap ? 0 : 1) + (haveName ? 0 : 1) + (havePost ? 0 : 1);
nZeroLengthTables = 0;
diff --git a/pdf/xpdf/FontFile.h b/pdf/xpdf/FontFile.h
index a71653c..7aa5ba9 100644
--- a/pdf/xpdf/FontFile.h
+++ b/pdf/xpdf/FontFile.h
@@ -20,6 +20,7 @@
#include "GString.h"
#include "CharTypes.h"
+class GHash;
class CharCodeToUnicode;
//------------------------------------------------------------------------
@@ -156,6 +157,7 @@ private:
//------------------------------------------------------------------------
struct TTFontTableHdr;
+struct TTFontCmap;
class TrueTypeFontFile: public FontFile {
public:
@@ -170,15 +172,34 @@ public:
virtual char **getEncoding();
+ // Return the number of cmaps defined by this font.
+ int getNumCmaps();
+
+ // Return the platform ID of the <i>th cmap.
+ int getCmapPlatform(int i);
+
+ // Return the encoding ID of the <i>th cmap.
+ int getCmapEncoding(int i);
+
+ // Return the index of the cmap for <platform>, <encoding>. Returns
+ // -1 if there is no corresponding cmap.
+ int findCmap(int platform, int enc);
+
+ // Return the GID corresponding to <c> according to the <i>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,
- CharCodeToUnicode *toUnicode,
GBool pdfFontHasEncoding,
- GBool pdfFontIsSymbolic,
+ Gushort *codeToGID,
FontFileOutputFunc outputFunc, void *outputStream);
// Convert to a Type 2 CIDFont, suitable for embedding in a
@@ -213,6 +234,8 @@ private:
int locaFmt;
int nGlyphs;
GBool mungedCmapSize;
+ TTFontCmap *cmaps;
+ int nCmaps;
int getByte(int pos);
int getChar(int pos);
@@ -224,8 +247,8 @@ private:
int seekTableIdx(char *tag);
void cvtEncoding(char **encodingA, GBool pdfFontHasEncoding,
FontFileOutputFunc outputFunc, void *outputStream);
- void cvtCharStrings(char **encodingA, CharCodeToUnicode *toUnicode,
- GBool pdfFontHasEncoding, GBool pdfFontIsSymbolic,
+ 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,
diff --git a/pdf/xpdf/Function.cc b/pdf/xpdf/Function.cc
index 28eed87..d9d4a93 100644
--- a/pdf/xpdf/Function.cc
+++ b/pdf/xpdf/Function.cc
@@ -381,8 +381,8 @@ void SampledFunction::transform(double *in, double *out) {
// pull 2^m values out of the sample array
for (j = 0; j < (1<<m); ++j) {
- idx = e[j & 1][m - 1];
- for (k = m - 2; k >= 0; --k) {
+ idx = 0;
+ for (k = m - 1; k >= 0; --k) {
idx = idx * sampleSize[k] + e[(j >> k) & 1][k];
}
idx = idx * n + i;
@@ -617,9 +617,13 @@ StitchingFunction::StitchingFunction(Object *funcObj, Dict *dict) {
}
StitchingFunction::StitchingFunction(StitchingFunction *func) {
+ int i;
+
k = func->k;
funcs = (Function **)gmalloc(k * sizeof(Function *));
- memcpy(funcs, func->funcs, k * sizeof(Function *));
+ for (i = 0; i < k; ++i) {
+ funcs[i] = func->funcs[i]->copy();
+ }
bounds = (double *)gmalloc((k + 1) * sizeof(double));
memcpy(bounds, func->bounds, (k + 1) * sizeof(double));
encode = (double *)gmalloc(2 * k * sizeof(double));
@@ -630,9 +634,11 @@ StitchingFunction::StitchingFunction(StitchingFunction *func) {
StitchingFunction::~StitchingFunction() {
int i;
- for (i = 0; i < k; ++i) {
- if (funcs[i]) {
- delete funcs[i];
+ if (funcs) {
+ for (i = 0; i < k; ++i) {
+ if (funcs[i]) {
+ delete funcs[i];
+ }
}
}
gfree(funcs);
@@ -1246,7 +1252,7 @@ void PostScriptFunction::exec(PSStack *stack, int codePtr) {
} else {
b2 = stack->popBool();
b1 = stack->popBool();
- stack->pushReal(b1 && b2);
+ stack->pushBool(b1 && b2);
}
break;
case psOpAtan:
@@ -1313,8 +1319,8 @@ void PostScriptFunction::exec(PSStack *stack, int codePtr) {
stack->roll(2, 1);
break;
case psOpExp:
- r2 = stack->popInt();
- r1 = stack->popInt();
+ r2 = stack->popNum();
+ r1 = stack->popNum();
stack->pushReal(pow(r1, r2));
break;
case psOpFalse:
@@ -1426,7 +1432,7 @@ void PostScriptFunction::exec(PSStack *stack, int codePtr) {
if (stack->topIsInt()) {
stack->pushInt(~stack->popInt());
} else {
- stack->pushReal(!stack->popBool());
+ stack->pushBool(!stack->popBool());
}
break;
case psOpOr:
@@ -1437,7 +1443,7 @@ void PostScriptFunction::exec(PSStack *stack, int codePtr) {
} else {
b2 = stack->popBool();
b1 = stack->popBool();
- stack->pushReal(b1 || b2);
+ stack->pushBool(b1 || b2);
}
break;
case psOpPop:
@@ -1455,7 +1461,7 @@ void PostScriptFunction::exec(PSStack *stack, int codePtr) {
}
break;
case psOpSin:
- stack->pushReal(cos(stack->popNum()));
+ stack->pushReal(sin(stack->popNum()));
break;
case psOpSqrt:
stack->pushReal(sqrt(stack->popNum()));
@@ -1488,7 +1494,7 @@ void PostScriptFunction::exec(PSStack *stack, int codePtr) {
} else {
b2 = stack->popBool();
b1 = stack->popBool();
- stack->pushReal(b1 ^ b2);
+ stack->pushBool(b1 ^ b2);
}
break;
case psOpIf:
diff --git a/pdf/xpdf/Gfx.cc b/pdf/xpdf/Gfx.cc
index 63896d8..d108208 100644
--- a/pdf/xpdf/Gfx.cc
+++ b/pdf/xpdf/Gfx.cc
@@ -41,6 +41,12 @@
// constants
//------------------------------------------------------------------------
+// Max recursive depth for a function shading fill.
+#define functionMaxDepth 6
+
+// Max delta allowed in any color component for a function shading fill.
+#define functionColorDelta (1 / 256.0)
+
// Max number of splits along the t axis for an axial shading fill.
#define axialMaxSplits 256
@@ -57,6 +63,10 @@
// Operator table
//------------------------------------------------------------------------
+#ifdef WIN32 // this works around a bug in the VC7 compiler
+# pragma optimize("",off)
+#endif
+
Operator Gfx::opTab[] = {
{"\"", 3, {tchkNum, tchkNum, tchkString},
&Gfx::opMoveSetShowText},
@@ -212,6 +222,10 @@ Operator Gfx::opTab[] = {
&Gfx::opCurveTo2},
};
+#ifdef WIN32 // this works around a bug in the VC7 compiler
+# pragma optimize("",on)
+#endif
+
#define numOps (sizeof(opTab) / sizeof(Operator))
//------------------------------------------------------------------------
@@ -219,15 +233,23 @@ Operator Gfx::opTab[] = {
//------------------------------------------------------------------------
GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) {
- Object obj1;
+ Object obj1, obj2;
+ Ref r;
if (resDict) {
// build font dictionary
fonts = NULL;
- resDict->lookup("Font", &obj1);
- if (obj1.isDict()) {
- fonts = new GfxFontDict(xref, obj1.getDict());
+ resDict->lookupNF("Font", &obj1);
+ if (obj1.isRef()) {
+ obj1.fetch(xref, &obj2);
+ if (obj2.isDict()) {
+ r = obj1.getRef();
+ fonts = new GfxFontDict(xref, &r, obj2.getDict());
+ }
+ obj2.free();
+ } else if (obj1.isDict()) {
+ fonts = new GfxFontDict(xref, NULL, obj1.getDict());
}
obj1.free();
@@ -251,6 +273,7 @@ GfxResources::GfxResources(XRef *xref, Dict *resDict, GfxResources *nextA) {
xObjDict.initNull();
colorSpaceDict.initNull();
patternDict.initNull();
+ shadingDict.initNull();
gStateDict.initNull();
}
@@ -381,8 +404,9 @@ GBool GfxResources::lookupGState(char *name, Object *obj) {
// Gfx
//------------------------------------------------------------------------
-Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi,
- PDFRectangle *box, GBool crop, PDFRectangle *cropBox, int rotate,
+Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict,
+ double hDPI, double vDPI, PDFRectangle *box, GBool crop,
+ PDFRectangle *cropBox, int rotate,
GBool (*abortCheckCbkA)(void *data),
void *abortCheckCbkDataA) {
int i;
@@ -396,7 +420,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi,
// initialize
out = outA;
- state = new GfxState(dpi, box, rotate, out->upsideDown());
+ state = new GfxState(hDPI, vDPI, box, rotate, out->upsideDown());
fontChanged = gFalse;
clip = clipNone;
ignoreUndef = 0;
@@ -406,6 +430,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi,
for (i = 0; i < 6; ++i) {
baseMatrix[i] = state->getCTM()[i];
}
+ formDepth = 0;
abortCheckCbk = abortCheckCbkA;
abortCheckCbkData = abortCheckCbkDataA;
@@ -437,13 +462,14 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict,
// initialize
out = outA;
- state = new GfxState(72, box, 0, gFalse);
+ state = new GfxState(72, 72, box, 0, gFalse);
fontChanged = gFalse;
clip = clipNone;
ignoreUndef = 0;
for (i = 0; i < 6; ++i) {
baseMatrix[i] = state->getCTM()[i];
}
+ formDepth = 0;
abortCheckCbk = abortCheckCbkA;
abortCheckCbkData = abortCheckCbkDataA;
@@ -462,8 +488,7 @@ Gfx::Gfx(XRef *xrefA, OutputDev *outA, Dict *resDict,
Gfx::~Gfx() {
while (state->hasSaves()) {
- state = state->restore();
- out->restoreState(state);
+ restoreState();
}
if (!subPage) {
out->endPage();
@@ -591,6 +616,7 @@ void Gfx::go(GBool topLevel) {
void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
Operator *op;
char *name;
+ Object *argPtr;
int i;
// find operator
@@ -602,12 +628,19 @@ void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
}
// type check args
+ argPtr = args;
if (op->numArgs >= 0) {
- if (numArgs != op->numArgs) {
- error(getPos(), "Wrong number (%d) of args to '%s' operator",
- numArgs, name);
+ if (numArgs < op->numArgs) {
+ error(getPos(), "Too few (%d) args to '%s' operator", numArgs, name);
return;
}
+ if (numArgs > op->numArgs) {
+#if 0
+ error(getPos(), "Too many (%d) args to '%s' operator", numArgs, name);
+#endif
+ argPtr += numArgs - op->numArgs;
+ numArgs = op->numArgs;
+ }
} else {
if (numArgs > -op->numArgs) {
error(getPos(), "Too many (%d) args to '%s' operator",
@@ -616,15 +649,15 @@ void Gfx::execOp(Object *cmd, Object args[], int numArgs) {
}
}
for (i = 0; i < numArgs; ++i) {
- if (!checkArg(&args[i], op->tchk[i])) {
+ if (!checkArg(&argPtr[i], op->tchk[i])) {
error(getPos(), "Arg #%d to '%s' operator is wrong type (%s)",
- i, name, args[i].getTypeName());
+ i, name, argPtr[i].getTypeName());
return;
}
}
// do it
- (this->*op->func)(args, numArgs);
+ (this->*op->func)(argPtr, numArgs);
}
Operator *Gfx::findOp(char *name) {
@@ -672,13 +705,11 @@ int Gfx::getPos() {
//------------------------------------------------------------------------
void Gfx::opSave(Object args[], int numArgs) {
- out->saveState(state);
- state = state->save();
+ saveState();
}
void Gfx::opRestore(Object args[], int numArgs) {
- state = state->restore();
- out->restoreState(state);
+ restoreState();
}
void Gfx::opConcat(Object args[], int numArgs) {
@@ -1194,18 +1225,7 @@ void Gfx::opCloseEOFillStroke(Object args[], int numArgs) {
}
void Gfx::doPatternFill(GBool eoFill) {
- GfxPatternColorSpace *patCS;
GfxPattern *pattern;
- GfxTilingPattern *tPat;
- GfxColorSpace *cs;
- double xMin, yMin, xMax, yMax, x, y, x1, y1;
- double cxMin, cyMin, cxMax, cyMax;
- int xi0, yi0, xi1, yi1, xi, yi;
- double *ctm, *btm, *ptm;
- double m[6], ictm[6], m1[6], imb[6];
- double det;
- double xstep, ystep;
- int i;
// this is a bit of a kludge -- patterns can be really slow, so we
// skip them if we're only doing text extraction, since they almost
@@ -1214,17 +1234,37 @@ void Gfx::doPatternFill(GBool eoFill) {
return;
}
- // get color space
- patCS = (GfxPatternColorSpace *)state->getFillColorSpace();
-
- // get pattern
if (!(pattern = state->getFillPattern())) {
return;
}
- if (pattern->getType() != 1) {
- return;
+ switch (pattern->getType()) {
+ case 1:
+ doTilingPatternFill((GfxTilingPattern *)pattern, eoFill);
+ break;
+ case 2:
+ doShadingPatternFill((GfxShadingPattern *)pattern, eoFill);
+ break;
+ default:
+ error(getPos(), "Unimplemented pattern type (%d) in fill",
+ pattern->getType());
+ break;
}
- tPat = (GfxTilingPattern *)pattern;
+}
+
+void Gfx::doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill) {
+ GfxPatternColorSpace *patCS;
+ GfxColorSpace *cs;
+ double xMin, yMin, xMax, yMax, x, y, x1, y1;
+ double cxMin, cyMin, cxMax, cyMax;
+ int xi0, yi0, xi1, yi1, xi, yi;
+ double *ctm, *btm, *ptm;
+ double m[6], ictm[6], m1[6], imb[6];
+ double det;
+ double xstep, ystep;
+ int i;
+
+ // get color space
+ patCS = (GfxPatternColorSpace *)state->getFillColorSpace();
// construct a (pattern space) -> (current space) transform matrix
ctm = state->getCTM();
@@ -1263,17 +1303,25 @@ void Gfx::doPatternFill(GBool eoFill) {
imb[5] = (m1[1] * m1[4] - m1[0] * m1[5]) * det;
// save current graphics state
- out->saveState(state);
- state = state->save();
+ saveState();
- // set underlying color space (for uncolored tiling patterns)
+ // set underlying color space (for uncolored tiling patterns); set
+ // various other parameters (stroke color, line width) to match
+ // Adobe's behavior
if (tPat->getPaintType() == 2 && (cs = patCS->getUnder())) {
state->setFillColorSpace(cs->copy());
+ state->setStrokeColorSpace(cs->copy());
+ state->setStrokeColor(state->getFillColor());
} else {
state->setFillColorSpace(new GfxDeviceGrayColorSpace());
+ state->setStrokeColorSpace(new GfxDeviceGrayColorSpace());
}
state->setFillPattern(NULL);
out->updateFillColor(state);
+ state->setStrokePattern(NULL);
+ out->updateStrokeColor(state);
+ state->setLineWidth(0);
+ out->updateLineWidth(state);
// clip to current path
state->clip();
@@ -1339,8 +1387,8 @@ void Gfx::doPatternFill(GBool eoFill) {
}
for (yi = yi0; yi < yi1; ++yi) {
for (xi = xi0; xi < xi1; ++xi) {
- x = xi * xstep;
- y = yi * ystep;
+ x = xi * xstep - tPat->getBBox()[0];
+ y = yi * ystep - tPat->getBBox()[1];
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(),
@@ -1349,8 +1397,92 @@ void Gfx::doPatternFill(GBool eoFill) {
}
// restore graphics state
- state = state->restore();
- out->restoreState(state);
+ restoreState();
+}
+
+void Gfx::doShadingPatternFill(GfxShadingPattern *sPat, GBool eoFill) {
+ GfxShading *shading;
+ double *ctm, *btm, *ptm;
+ double m[6], ictm[6], m1[6];
+ double xMin, yMin, xMax, yMax;
+ double det;
+
+ shading = sPat->getShading();
+
+ // save current graphics state
+ saveState();
+
+ // clip to bbox
+ if (shading->getHasBBox()) {
+ shading->getBBox(&xMin, &yMin, &xMax, &yMax);
+ state->moveTo(xMin, yMin);
+ state->lineTo(xMax, yMin);
+ state->lineTo(xMax, yMax);
+ state->lineTo(xMin, yMax);
+ state->closePath();
+ state->clip();
+ out->clip(state);
+ state->clearPath();
+ }
+
+ // clip to current path
+ state->clip();
+ if (eoFill) {
+ out->eoClip(state);
+ } else {
+ out->clip(state);
+ }
+ state->clearPath();
+
+ // construct a (pattern space) -> (current space) transform matrix
+ ctm = state->getCTM();
+ btm = baseMatrix;
+ ptm = sPat->getMatrix();
+ // iCTM = invert CTM
+ det = 1 / (ctm[0] * ctm[3] - ctm[1] * ctm[2]);
+ ictm[0] = ctm[3] * det;
+ ictm[1] = -ctm[1] * det;
+ ictm[2] = -ctm[2] * det;
+ ictm[3] = ctm[0] * det;
+ ictm[4] = (ctm[2] * ctm[5] - ctm[3] * ctm[4]) * det;
+ ictm[5] = (ctm[1] * ctm[4] - ctm[0] * ctm[5]) * det;
+ // m1 = PTM * BTM = PTM * base transform matrix
+ m1[0] = ptm[0] * btm[0] + ptm[1] * btm[2];
+ m1[1] = ptm[0] * btm[1] + ptm[1] * btm[3];
+ m1[2] = ptm[2] * btm[0] + ptm[3] * btm[2];
+ m1[3] = ptm[2] * btm[1] + ptm[3] * btm[3];
+ m1[4] = ptm[4] * btm[0] + ptm[5] * btm[2] + btm[4];
+ m1[5] = ptm[4] * btm[1] + ptm[5] * btm[3] + btm[5];
+ // m = m1 * iCTM = (PTM * BTM) * (iCTM)
+ m[0] = m1[0] * ictm[0] + m1[1] * ictm[2];
+ m[1] = m1[0] * ictm[1] + m1[1] * ictm[3];
+ m[2] = m1[2] * ictm[0] + m1[3] * ictm[2];
+ m[3] = m1[2] * ictm[1] + m1[3] * ictm[3];
+ m[4] = m1[4] * ictm[0] + m1[5] * ictm[2] + ictm[4];
+ m[5] = m1[4] * ictm[1] + m1[5] * ictm[3] + ictm[5];
+
+ // set the new matrix
+ state->concatCTM(m[0], m[1], m[2], m[3], m[4], m[5]);
+ out->updateCTM(state, m[0], m[1], m[2], m[3], m[4], m[5]);
+
+ // set the color space
+ state->setFillColorSpace(shading->getColorSpace()->copy());
+
+ // do shading type-specific operations
+ switch (shading->getType()) {
+ case 1:
+ doFunctionShFill((GfxFunctionShading *)shading);
+ break;
+ case 2:
+ doAxialShFill((GfxAxialShading *)shading);
+ break;
+ case 3:
+ doRadialShFill((GfxRadialShading *)shading);
+ break;
+ }
+
+ // restore graphics state
+ restoreState();
}
void Gfx::opShFill(Object args[], int numArgs) {
@@ -1362,8 +1494,7 @@ void Gfx::opShFill(Object args[], int numArgs) {
}
// save current graphics state
- out->saveState(state);
- state = state->save();
+ saveState();
// clip to bbox
if (shading->getHasBBox()) {
@@ -1383,6 +1514,9 @@ void Gfx::opShFill(Object args[], int numArgs) {
// do shading type-specific operations
switch (shading->getType()) {
+ case 1:
+ doFunctionShFill((GfxFunctionShading *)shading);
+ break;
case 2:
doAxialShFill((GfxAxialShading *)shading);
break;
@@ -1392,12 +1526,131 @@ void Gfx::opShFill(Object args[], int numArgs) {
}
// restore graphics state
- state = state->restore();
- out->restoreState(state);
+ restoreState();
delete shading;
}
+void Gfx::doFunctionShFill(GfxFunctionShading *shading) {
+ double x0, y0, x1, y1;
+ GfxColor colors[4];
+
+ shading->getDomain(&x0, &y0, &x1, &y1);
+ shading->getColor(x0, y0, &colors[0]);
+ shading->getColor(x0, y1, &colors[1]);
+ shading->getColor(x1, y0, &colors[2]);
+ shading->getColor(x1, y1, &colors[3]);
+ doFunctionShFill1(shading, x0, y0, x1, y1, colors, 0);
+}
+
+void Gfx::doFunctionShFill1(GfxFunctionShading *shading,
+ double x0, double y0,
+ double x1, double y1,
+ GfxColor *colors, int depth) {
+ GfxColor fillColor;
+ GfxColor color0M, color1M, colorM0, colorM1, colorMM;
+ GfxColor colors2[4];
+ double *matrix;
+ double xM, yM;
+ int nComps, i, j;
+
+ nComps = shading->getColorSpace()->getNComps();
+ matrix = shading->getMatrix();
+
+ // compare the four corner colors
+ for (i = 0; i < 4; ++i) {
+ for (j = 0; j < nComps; ++j) {
+ if (fabs(colors[i].c[j] - colors[(i+1)&3].c[j]) > functionColorDelta) {
+ break;
+ }
+ }
+ if (j < nComps) {
+ break;
+ }
+ }
+
+ // center of the rectangle
+ xM = 0.5 * (x0 + x1);
+ yM = 0.5 * (y0 + y1);
+
+ // the four corner colors are close (or we hit the recursive limit)
+ // -- fill the rectangle; but require at least one subdivision
+ // (depth==0) to avoid problems when the four outer corners of the
+ // shaded region are the same color
+ if ((i == 4 && depth > 0) || depth == functionMaxDepth) {
+
+ // use the center color
+ shading->getColor(xM, yM, &fillColor);
+ state->setFillColor(&fillColor);
+ out->updateFillColor(state);
+
+ // fill the rectangle
+ state->moveTo(x0 * matrix[0] + y0 * matrix[2] + matrix[4],
+ x0 * matrix[1] + y0 * matrix[3] + matrix[5]);
+ state->lineTo(x1 * matrix[0] + y0 * matrix[2] + matrix[4],
+ x1 * matrix[1] + y0 * matrix[3] + matrix[5]);
+ state->lineTo(x1 * matrix[0] + y1 * matrix[2] + matrix[4],
+ x1 * matrix[1] + y1 * matrix[3] + matrix[5]);
+ state->lineTo(x0 * matrix[0] + y1 * matrix[2] + matrix[4],
+ x0 * matrix[1] + y1 * matrix[3] + matrix[5]);
+ state->closePath();
+ out->fill(state);
+ state->clearPath();
+
+ // the four corner colors are not close enough -- subdivide the
+ // rectangle
+ } else {
+
+ // colors[0] colorM0 colors[2]
+ // (x0,y0) (xM,y0) (x1,y0)
+ // +----------+----------+
+ // | | |
+ // | UL | UR |
+ // color0M | colorMM | color1M
+ // (x0,yM) +----------+----------+ (x1,yM)
+ // | (xM,yM) |
+ // | LL | LR |
+ // | | |
+ // +----------+----------+
+ // colors[1] colorM1 colors[3]
+ // (x0,y1) (xM,y1) (x1,y1)
+
+ shading->getColor(x0, yM, &color0M);
+ shading->getColor(x1, yM, &color1M);
+ shading->getColor(xM, y0, &colorM0);
+ shading->getColor(xM, y1, &colorM1);
+ shading->getColor(xM, yM, &colorMM);
+
+ // upper-left sub-rectangle
+ colors2[0] = colors[0];
+ colors2[1] = color0M;
+ colors2[2] = colorM0;
+ colors2[3] = colorMM;
+ doFunctionShFill1(shading, x0, y0, xM, yM, colors2, depth + 1);
+
+ // lower-left sub-rectangle
+ colors2[0] = color0M;
+ colors2[1] = colors[1];
+ colors2[2] = colorMM;
+ colors2[3] = colorM1;
+ doFunctionShFill1(shading, x0, yM, xM, y1, colors2, depth + 1);
+
+ // upper-right sub-rectangle
+ colors2[0] = colorM0;
+ colors2[1] = colorMM;
+ colors2[2] = colors[2];
+ colors2[3] = color1M;
+ doFunctionShFill1(shading, xM, y0, x1, yM, colors2, depth + 1);
+
+ // lower-right sub-rectangle
+ colors2[0] = colorMM;
+ colors2[1] = colorM1;
+ colors2[2] = color1M;
+ colors2[3] = colors[3];
+ doFunctionShFill1(shading, xM, yM, x1, y1, colors2, depth + 1);
+ }
+}
+
void Gfx::doAxialShFill(GfxAxialShading *shading) {
double xMin, yMin, xMax, yMax;
double x0, y0, x1, y1;
@@ -1480,11 +1733,14 @@ void Gfx::doAxialShFill(GfxAxialShading *shading) {
// difference across a region is small enough, and then the region
// is painted with a single color.
- // set up
+ // set up: require at least one split to avoid problems when the two
+ // ends of the t axis have the same color
nComps = shading->getColorSpace()->getNComps();
ta[0] = tMin;
+ next[0] = axialMaxSplits / 2;
+ ta[axialMaxSplits / 2] = 0.5 * (tMin + tMax);
+ next[axialMaxSplits / 2] = axialMaxSplits;
ta[axialMaxSplits] = tMax;
- next[0] = axialMaxSplits;
// compute the color at t = tMin
if (tMin < 0) {
@@ -1749,7 +2005,9 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
// go as far along the t axis (toward t1) as we can, such that the
// color difference is within the tolerance (radialColorDelta) --
// this uses bisection (between the current value, t, and t1),
- // limited to radialMaxSplits points along the t axis
+ // limited to radialMaxSplits points along the t axis; require at
+ // least one split to avoid problems when the innermost and
+ // outermost colors are the same
ib = radialMaxSplits;
sb = sMin + ((double)ib / (double)radialMaxSplits) * (sMax - sMin);
tb = t0 + sb * (t1 - t0);
@@ -1766,7 +2024,7 @@ void Gfx::doRadialShFill(GfxRadialShading *shading) {
break;
}
}
- if (k == nComps) {
+ if (k == nComps && ib < radialMaxSplits) {
break;
}
ib = (ia + ib) / 2;
@@ -1862,6 +2120,7 @@ void Gfx::opBeginText(Object args[], int numArgs) {
}
void Gfx::opEndText(Object args[], int numArgs) {
+ out->endTextObject(state);
}
//------------------------------------------------------------------------
@@ -2099,8 +2358,7 @@ void Gfx::doShowText(GString *s) {
dy *= state->getFontSize();
state->textTransformDelta(dx, dy, &tdx, &tdy);
state->transform(curX + riseX, curY + riseY, &x, &y);
- out->saveState(state);
- state = state->save();
+ saveState();
state->setCTM(newCTM[0], newCTM[1], newCTM[2], newCTM[3], x, y);
//~ out->updateCTM(???)
if (!out->beginType3Char(state, code, u, uLen)) {
@@ -2119,8 +2377,7 @@ void Gfx::doShowText(GString *s) {
}
charProc.free();
}
- state = state->restore();
- out->restoreState(state);
+ restoreState();
// GfxState::restore() does *not* restore the current position,
// so we deal with it here using (curX, curY) and (lineX, lineY)
curX += tdx;
@@ -2313,9 +2570,13 @@ void Gfx::doImage(Object *ref, Stream *str, GBool inlineImg) {
obj1.free();
dict->lookup("BPC", &obj1);
}
- if (!obj1.isInt())
+ if (obj1.isInt()) {
+ bits = obj1.getInt();
+ } else if (mask) {
+ bits = 1;
+ } else {
goto err2;
- bits = obj1.getInt();
+ }
obj1.free();
// display a mask
@@ -2419,6 +2680,11 @@ void Gfx::doForm(Object *str) {
Object obj1;
int i;
+ // check for excessive recursion
+ if (formDepth > 20) {
+ return;
+ }
+
// get stream dict
dict = str->streamGetDict();
@@ -2464,7 +2730,9 @@ void Gfx::doForm(Object *str) {
resDict = resObj.isDict() ? resObj.getDict() : (Dict *)NULL;
// draw it
+ ++formDepth;
doForm1(str, resDict, m, bbox);
+ --formDepth;
resObj.free();
}
@@ -2592,8 +2860,10 @@ void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox) {
pushResources(resDict);
// save current graphics state
- out->saveState(state);
- state = state->save();
+ saveState();
+
+ // kill any pre-existing path
+ state->clearPath();
// save current parser
oldParser = parser;
@@ -2632,8 +2902,7 @@ void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox) {
parser = oldParser;
// restore graphics state
- state = state->restore();
- out->restoreState(state);
+ restoreState();
// pop resource stack
popResources();
@@ -2641,18 +2910,6 @@ void Gfx::doForm1(Object *str, Dict *resDict, double *matrix, double *bbox) {
return;
}
-void Gfx::pushResources(Dict *resDict) {
- res = new GfxResources(xref, resDict, res);
-}
-
-void Gfx::popResources() {
- GfxResources *resPtr;
-
- resPtr = res->getNext();
- delete res;
- res = resPtr;
-}
-
//------------------------------------------------------------------------
// in-line image operators
//------------------------------------------------------------------------
@@ -2780,3 +3037,29 @@ void Gfx::opMarkPoint(Object args[], int numArgs) {
fflush(stdout);
}
}
+
+//------------------------------------------------------------------------
+// misc
+//------------------------------------------------------------------------
+
+void Gfx::saveState() {
+ out->saveState(state);
+ state = state->save();
+}
+
+void Gfx::restoreState() {
+ state = state->restore();
+ out->restoreState(state);
+}
+
+void Gfx::pushResources(Dict *resDict) {
+ res = new GfxResources(xref, resDict, res);
+}
+
+void Gfx::popResources() {
+ GfxResources *resPtr;
+
+ resPtr = res->getNext();
+ delete res;
+ res = resPtr;
+}
diff --git a/pdf/xpdf/Gfx.h b/pdf/xpdf/Gfx.h
index c7aef11..20898ec 100644
--- a/pdf/xpdf/Gfx.h
+++ b/pdf/xpdf/Gfx.h
@@ -28,10 +28,14 @@ class OutputDev;
class GfxFontDict;
class GfxFont;
class GfxPattern;
+class GfxTilingPattern;
+class GfxShadingPattern;
class GfxShading;
+class GfxFunctionShading;
class GfxAxialShading;
class GfxRadialShading;
class GfxState;
+class GfxColor;
class Gfx;
class PDFRectangle;
@@ -97,8 +101,9 @@ class Gfx {
public:
// Constructor for regular output.
- Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict, double dpi,
- PDFRectangle *box, GBool crop, PDFRectangle *cropBox, int rotate,
+ Gfx(XRef *xrefA, OutputDev *outA, int pageNum, Dict *resDict,
+ double hDPI, double vDPI, PDFRectangle *box, GBool crop,
+ PDFRectangle *cropBox, int rotate,
GBool (*abortCheckCbkA)(void *data) = NULL,
void *abortCheckCbkDataA = NULL);
@@ -118,8 +123,11 @@ public:
void doAnnot(Object *str, double xMin, double yMin,
double xMax, double yMax);
- void pushResources(Dict *resDict);
- void popResources();
+ // Save graphics state.
+ void saveState();
+
+ // Restore graphics state.
+ void restoreState();
private:
@@ -136,6 +144,7 @@ private:
int ignoreUndef; // current BX/EX nesting level
double baseMatrix[6]; // default matrix for most recent
// page/form/pattern
+ int formDepth;
Parser *parser; // parser for page content stream(s)
@@ -198,7 +207,14 @@ private:
void opEOFillStroke(Object args[], int numArgs);
void opCloseEOFillStroke(Object args[], int numArgs);
void doPatternFill(GBool eoFill);
+ void doTilingPatternFill(GfxTilingPattern *tPat, GBool eoFill);
+ void doShadingPatternFill(GfxShadingPattern *sPat, GBool eoFill);
void opShFill(Object args[], int numArgs);
+ void doFunctionShFill(GfxFunctionShading *shading);
+ void doFunctionShFill1(GfxFunctionShading *shading,
+ double x0, double y0,
+ double x1, double y1,
+ GfxColor *colors, int depth);
void doAxialShFill(GfxAxialShading *shading);
void doRadialShFill(GfxRadialShading *shading);
void doEndPath();
@@ -257,6 +273,9 @@ private:
void opBeginMarkedContent(Object args[], int numArgs);
void opEndMarkedContent(Object args[], int numArgs);
void opMarkPoint(Object args[], int numArgs);
+
+ void pushResources(Dict *resDict);
+ void popResources();
};
#endif
diff --git a/pdf/xpdf/GfxFont.cc b/pdf/xpdf/GfxFont.cc
index d687588..6f83676 100644
--- a/pdf/xpdf/GfxFont.cc
+++ b/pdf/xpdf/GfxFont.cc
@@ -17,6 +17,7 @@
#include <string.h>
#include <ctype.h>
#include "gmem.h"
+#include "GHash.h"
#include "Error.h"
#include "Object.h"
#include "Dict.h"
@@ -136,12 +137,16 @@ GfxFont::GfxFont(char *tagA, Ref idA, GString *nameA) {
tag = new GString(tagA);
id = idA;
name = nameA;
+ origName = nameA;
embFontName = NULL;
extFontFile = NULL;
}
GfxFont::~GfxFont() {
delete tag;
+ if (origName && origName != name) {
+ delete origName;
+ }
if (name) {
delete name;
}
@@ -286,8 +291,8 @@ void GfxFont::readFontDescriptor(XRef *xref, Dict *fontDict) {
obj1.free();
}
-CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits) {
- CharCodeToUnicode *ctu;
+CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits,
+ CharCodeToUnicode *ctu) {
GString *buf;
Object obj1;
int c;
@@ -303,7 +308,11 @@ CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits) {
}
obj1.streamClose();
obj1.free();
- ctu = CharCodeToUnicode::parseCMap(buf, nBits);
+ if (ctu) {
+ ctu->mergeCMap(buf, nBits);
+ } else {
+ ctu = CharCodeToUnicode::parseCMap(buf, nBits);
+ }
delete buf;
return ctu;
}
@@ -334,7 +343,8 @@ char *GfxFont::readExtFontFile(int *len) {
fseek(f, 0, SEEK_SET);
buf = (char *)gmalloc(*len);
if ((int)fread(buf, 1, *len, f) != *len) {
- error(-1, "Error reading external font file '%s'", extFontFile);
+ error(-1, "Error reading external font file '%s'",
+ extFontFile->getCString());
}
fclose(f);
return buf;
@@ -395,6 +405,8 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
char *charName;
GBool missing, hex;
Unicode toUnicode[256];
+ CharCodeToUnicode *utu, *ctu2;
+ Unicode uBuf[8];
double mul;
int firstChar, lastChar;
Gushort w;
@@ -419,7 +431,6 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
}
}
if (!name->cmp(stdFontMap[a].altName)) {
- delete name;
name = new GString(stdFontMap[a].properName);
}
}
@@ -504,6 +515,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
// check FontDict for base encoding
hasEncoding = gFalse;
+ usesMacRomanEnc = gFalse;
baseEnc = NULL;
baseEncFromFontFile = gFalse;
fontDict->lookup("Encoding", &obj1);
@@ -511,6 +523,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
obj1.dictLookup("BaseEncoding", &obj2);
if (obj2.isName("MacRomanEncoding")) {
hasEncoding = gTrue;
+ usesMacRomanEnc = gTrue;
baseEnc = macRomanEncoding;
} else if (obj2.isName("MacExpertEncoding")) {
hasEncoding = gTrue;
@@ -525,6 +538,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
obj2.free();
} else if (obj1.isName("MacRomanEncoding")) {
hasEncoding = gTrue;
+ usesMacRomanEnc = gTrue;
baseEnc = macRomanEncoding;
} else if (obj1.isName("MacExpertEncoding")) {
hasEncoding = gTrue;
@@ -609,7 +623,7 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
if (obj3.isInt()) {
code = obj3.getInt();
} else if (obj3.isName()) {
- if (code < 256) {
+ if (code >= 0 && code < 256) {
if (encFree[code]) {
gfree(enc[code]);
}
@@ -633,76 +647,97 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
//----- build the mapping to Unicode -----
- // look for a ToUnicode CMap
- if (!(ctu = readToUnicodeCMap(fontDict, 8))) {
-
- // no ToUnicode CMap, so use the char names
+ // pass 1: use the name-to-Unicode mapping table
+ missing = hex = gFalse;
+ for (code = 0; code < 256; ++code) {
+ if ((charName = enc[code])) {
+ if (!(toUnicode[code] = globalParams->mapNameToUnicode(charName)) &&
+ strcmp(charName, ".notdef")) {
+ // if it wasn't in the name-to-Unicode table, check for a
+ // name that looks like 'Axx' or 'xx', where 'A' is any letter
+ // and 'xx' is two hex digits
+ if ((strlen(charName) == 3 &&
+ isalpha(charName[0]) &&
+ isxdigit(charName[1]) && isxdigit(charName[2]) &&
+ ((charName[1] >= 'a' && charName[1] <= 'f') ||
+ (charName[1] >= 'A' && charName[1] <= 'F') ||
+ (charName[2] >= 'a' && charName[2] <= 'f') ||
+ (charName[2] >= 'A' && charName[2] <= 'F'))) ||
+ (strlen(charName) == 2 &&
+ isxdigit(charName[0]) && isxdigit(charName[1]) &&
+ ((charName[0] >= 'a' && charName[0] <= 'f') ||
+ (charName[0] >= 'A' && charName[0] <= 'F') ||
+ (charName[1] >= 'a' && charName[1] <= 'f') ||
+ (charName[1] >= 'A' && charName[1] <= 'F')))) {
+ hex = gTrue;
+ }
+ missing = gTrue;
+ }
+ } else {
+ toUnicode[code] = 0;
+ }
+ }
- // pass 1: use the name-to-Unicode mapping table
- missing = hex = gFalse;
+ // pass 2: try to fill in the missing chars, looking for names of
+ // the form 'Axx', 'xx', 'Ann', 'ABnn', or 'nn', where 'A' and 'B'
+ // are any letters, 'xx' is two hex digits, and 'nn' is 2-4
+ // decimal digits
+ if (missing && globalParams->getMapNumericCharNames()) {
for (code = 0; code < 256; ++code) {
- if ((charName = enc[code])) {
- if (!(toUnicode[code] = globalParams->mapNameToUnicode(charName)) &&
- strcmp(charName, ".notdef")) {
- // if it wasn't in the name-to-Unicode table, check for a
- // name that looks like 'Axx' or 'xx', where 'A' is any letter
- // and 'xx' is two hex digits
- if ((strlen(charName) == 3 &&
- isalpha(charName[0]) &&
- isxdigit(charName[1]) && isxdigit(charName[2]) &&
- ((charName[1] >= 'a' && charName[1] <= 'f') ||
- (charName[1] >= 'A' && charName[1] <= 'F') ||
- (charName[2] >= 'a' && charName[2] <= 'f') ||
- (charName[2] >= 'A' && charName[2] <= 'F'))) ||
- (strlen(charName) == 2 &&
- isxdigit(charName[0]) && isxdigit(charName[1]) &&
- ((charName[0] >= 'a' && charName[0] <= 'f') ||
- (charName[0] >= 'A' && charName[0] <= 'F') ||
- (charName[1] >= 'a' && charName[1] <= 'f') ||
- (charName[1] >= 'A' && charName[1] <= 'F')))) {
- hex = gTrue;
- }
- missing = gTrue;
+ if ((charName = enc[code]) && !toUnicode[code] &&
+ strcmp(charName, ".notdef")) {
+ n = strlen(charName);
+ code2 = -1;
+ if (hex && n == 3 && isalpha(charName[0]) &&
+ isxdigit(charName[1]) && isxdigit(charName[2])) {
+ sscanf(charName+1, "%x", &code2);
+ } else if (hex && n == 2 &&
+ isxdigit(charName[0]) && isxdigit(charName[1])) {
+ sscanf(charName, "%x", &code2);
+ } else if (!hex && n >= 2 && n <= 4 &&
+ isdigit(charName[0]) && isdigit(charName[1])) {
+ code2 = atoi(charName);
+ } else if (n >= 3 && n <= 5 &&
+ isdigit(charName[1]) && isdigit(charName[2])) {
+ code2 = atoi(charName+1);
+ } else if (n >= 4 && n <= 6 &&
+ isdigit(charName[2]) && isdigit(charName[3])) {
+ code2 = atoi(charName+2);
+ }
+ if (code2 >= 0 && code2 <= 0xff) {
+ toUnicode[code] = (Unicode)code2;
}
- } else {
- toUnicode[code] = 0;
}
}
+ }
- // pass 2: try to fill in the missing chars, looking for names of
- // the form 'Axx', 'xx', 'Ann', 'ABnn', or 'nn', where 'A' and 'B'
- // are any letters, 'xx' is two hex digits, and 'nn' is 2-4
- // decimal digits
- if (missing && globalParams->getMapNumericCharNames()) {
- for (code = 0; code < 256; ++code) {
- if ((charName = enc[code]) && !toUnicode[code] &&
- strcmp(charName, ".notdef")) {
- n = strlen(charName);
- code2 = -1;
- if (hex && n == 3 && isalpha(charName[0]) &&
- isxdigit(charName[1]) && isxdigit(charName[2])) {
- sscanf(charName+1, "%x", &code2);
- } else if (hex && n == 2 &&
- isxdigit(charName[0]) && isxdigit(charName[1])) {
- sscanf(charName, "%x", &code2);
- } else if (!hex && n >= 2 && n <= 4 &&
- isdigit(charName[0]) && isdigit(charName[1])) {
- code2 = atoi(charName);
- } else if (n >= 3 && n <= 5 &&
- isdigit(charName[1]) && isdigit(charName[2])) {
- code2 = atoi(charName+1);
- } else if (n >= 4 && n <= 6 &&
- isdigit(charName[2]) && isdigit(charName[3])) {
- code2 = atoi(charName+2);
- }
- if (code2 >= 0 && code2 <= 0xff) {
- toUnicode[code] = (Unicode)code2;
- }
+ // construct the char code -> Unicode mapping object
+ ctu = CharCodeToUnicode::make8BitToUnicode(toUnicode);
+
+ // merge in a ToUnicode CMap, if there is one -- this overwrites
+ // existing entries in ctu, i.e., the ToUnicode CMap takes
+ // precedence, but the other encoding info is allowed to fill in any
+ // holes
+ readToUnicodeCMap(fontDict, 8, ctu);
+
+ // look for a Unicode-to-Unicode mapping
+ if (name && (utu = globalParams->getUnicodeToUnicode(name))) {
+ for (i = 0; i < 256; ++i) {
+ toUnicode[i] = 0;
+ }
+ ctu2 = CharCodeToUnicode::make8BitToUnicode(toUnicode);
+ for (i = 0; i < 256; ++i) {
+ n = ctu->mapToUnicode((CharCode)i, uBuf, 8);
+ if (n >= 1) {
+ n = utu->mapToUnicode((CharCode)uBuf[0], uBuf, 8);
+ if (n >= 1) {
+ ctu2->setMapping((CharCode)i, uBuf, n);
}
}
}
-
- ctu = CharCodeToUnicode::make8BitToUnicode(toUnicode);
+ utu->decRefCnt();
+ delete ctu;
+ ctu = ctu2;
}
//----- get the character widths -----
@@ -716,9 +751,15 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
fontDict->lookup("FirstChar", &obj1);
firstChar = obj1.isInt() ? obj1.getInt() : 0;
obj1.free();
+ if (firstChar < 0 || firstChar > 255) {
+ firstChar = 0;
+ }
fontDict->lookup("LastChar", &obj1);
lastChar = obj1.isInt() ? obj1.getInt() : 255;
obj1.free();
+ if (lastChar < 0 || lastChar > 255) {
+ lastChar = 255;
+ }
mul = (type == fontType3) ? fontMat[0] : 0.001;
fontDict->lookup("Widths", &obj1);
if (obj1.isArray()) {
@@ -819,6 +860,124 @@ CharCodeToUnicode *Gfx8BitFont::getToUnicode() {
return ctu;
}
+Gushort *Gfx8BitFont::getCodeToGIDMap(TrueTypeFontFile *ff) {
+ Gushort *map;
+ int cmapPlatform, cmapEncoding;
+ int unicodeCmap, macRomanCmap, msSymbolCmap, cmap;
+ GBool useMacRoman, useUnicode;
+ GHash *nameToGID;
+ char *charName;
+ Unicode u;
+ int code, i, n;
+
+ map = (Gushort *)gmalloc(256 * sizeof(Gushort));
+ for (i = 0; i < 256; ++i) {
+ map[i] = 0;
+ }
+
+ // 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 = -1;
+ for (i = 0; i < ff->getNumCmaps(); ++i) {
+ cmapPlatform = ff->getCmapPlatform(i);
+ cmapEncoding = ff->getCmapEncoding(i);
+ if ((cmapPlatform == 3 && cmapEncoding == 1) ||
+ cmapPlatform == 0) {
+ unicodeCmap = i;
+ } else if (cmapPlatform == 1 && cmapEncoding == 0) {
+ macRomanCmap = i;
+ } else if (cmapPlatform == 3 && cmapEncoding == 0) {
+ msSymbolCmap = i;
+ }
+ }
+ cmap = 0;
+ useMacRoman = gFalse;
+ useUnicode = gFalse;
+ if (hasEncoding) {
+ if (usesMacRomanEnc && macRomanCmap >= 0) {
+ cmap = macRomanCmap;
+ useMacRoman = gTrue;
+ } else if (unicodeCmap >= 0) {
+ cmap = unicodeCmap;
+ useUnicode = gTrue;
+ } else if ((flags & fontSymbolic) && msSymbolCmap >= 0) {
+ cmap = msSymbolCmap;
+ } else if (macRomanCmap >= 0) {
+ cmap = macRomanCmap;
+ useMacRoman = gTrue;
+ }
+ } else {
+ if (macRomanCmap >= 0) {
+ cmap = macRomanCmap;
+ } else if (msSymbolCmap >= 0) {
+ cmap = msSymbolCmap;
+ }
+ }
+
+ // reverse map the char names through MacRomanEncoding, then map the
+ // char codes through the cmap
+ if (useMacRoman) {
+ for (i = 0; i < 256; ++i) {
+ if ((charName = enc[i])) {
+ if ((code = globalParams->getMacRomanCharCode(charName))) {
+ map[i] = ff->mapCodeToGID(cmap, code);
+ }
+ }
+ }
+
+ // map Unicode through the cmap
+ } else if (useUnicode) {
+ for (i = 0; i < 256; ++i) {
+ if ((n = ctu->mapToUnicode((CharCode)i, &u, 1))) {
+ map[i] = ff->mapCodeToGID(cmap, u);
+ }
+ }
+
+ // map the char codes through the cmap, possibly with an offset of
+ // 0xf000
+ } else {
+ for (i = 0; i < 256; ++i) {
+ if (!(map[i] = ff->mapCodeToGID(cmap, i))) {
+ map[i] = ff->mapCodeToGID(cmap, 0xf000 + i);
+ }
+ }
+ }
+
+ // 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);
+ }
+ }
+ delete nameToGID;
+ }
+
+ return map;
+}
+
Dict *Gfx8BitFont::getCharProcs() {
return charProcs.isDict() ? charProcs.getDict() : (Dict *)NULL;
}
@@ -930,7 +1089,7 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
obj1.free();
// look for a ToUnicode CMap
- if (!(ctu = readToUnicodeCMap(fontDict, 16))) {
+ if (!(ctu = readToUnicodeCMap(fontDict, 16, NULL))) {
// the "Adobe-Identity" and "Adobe-UCS" collections don't have
// cidToUnicode files
@@ -1058,11 +1217,11 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
if (desFontDict->lookup("DW2", &obj1)->isArray() &&
obj1.arrayGetLength() == 2) {
if (obj1.arrayGet(0, &obj2)->isNum()) {
- widths.defVY = obj1.getNum() * 0.001;
+ widths.defVY = obj2.getNum() * 0.001;
}
obj2.free();
if (obj1.arrayGet(1, &obj2)->isNum()) {
- widths.defHeight = obj1.getNum() * 0.001;
+ widths.defHeight = obj2.getNum() * 0.001;
}
obj2.free();
}
@@ -1073,8 +1232,8 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
excepsSize = 0;
i = 0;
while (i + 1 < obj1.arrayGetLength()) {
- obj1.arrayGet(0, &obj2);
- obj2.arrayGet(0, &obj3);
+ obj1.arrayGet(i, &obj2);
+ obj1.arrayGet(i+ 1, &obj3);
if (obj2.isInt() && obj3.isInt() && i + 4 < obj1.arrayGetLength()) {
if (obj1.arrayGet(i + 2, &obj4)->isNum() &&
obj1.arrayGet(i + 3, &obj5)->isNum() &&
@@ -1107,10 +1266,10 @@ GfxCIDFont::GfxCIDFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
excepsSize * sizeof(GfxFontCIDWidthExcepV));
}
j = obj2.getInt();
- for (k = 0; k < obj3.arrayGetLength(); ++k) {
+ for (k = 0; k < obj3.arrayGetLength(); k += 3) {
if (obj3.arrayGet(k, &obj4)->isNum() &&
- obj3.arrayGet(k, &obj5)->isNum() &&
- obj3.arrayGet(k, &obj6)->isNum()) {
+ obj3.arrayGet(k+1, &obj5)->isNum() &&
+ obj3.arrayGet(k+2, &obj6)->isNum()) {
widths.excepsV[widths.nExceps].first = j;
widths.excepsV[widths.nExceps].last = j;
widths.excepsV[widths.nExceps].height = obj4.getNum() * 0.001;
@@ -1259,7 +1418,7 @@ GString *GfxCIDFont::getCollection() {
// GfxFontDict
//------------------------------------------------------------------------
-GfxFontDict::GfxFontDict(XRef *xref, Dict *fontDict) {
+GfxFontDict::GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict) {
int i;
Object obj1, obj2;
Ref r;
@@ -1277,7 +1436,11 @@ GfxFontDict::GfxFontDict(XRef *xref, Dict *fontDict) {
// (legal generation numbers are five digits, so any 6-digit
// number would be safe)
r.num = i;
- r.gen = 999999;
+ if (fontDictRef) {
+ r.gen = 100000 + fontDictRef->num;
+ } else {
+ r.gen = 999999;
+ }
}
fonts[i] = GfxFont::makeFont(xref, fontDict->getKey(i),
r, obj2.getDict());
diff --git a/pdf/xpdf/GfxFont.h b/pdf/xpdf/GfxFont.h
index 23371b3..ddd88be 100644
--- a/pdf/xpdf/GfxFont.h
+++ b/pdf/xpdf/GfxFont.h
@@ -23,6 +23,7 @@
class Dict;
class CMap;
class CharCodeToUnicode;
+class TrueTypeFontFile;
struct GfxFontCIDWidths;
//------------------------------------------------------------------------
@@ -104,6 +105,10 @@ public:
// Get base font name.
GString *getName() { return name; }
+ // Get the original font name (ignornig any munging that might have
+ // been done to map to a canonical Base-14 font name).
+ GString *getOrigName() { return origName; }
+
// Get font type.
GfxFontType getType() { return type; }
virtual GBool isCIDFont() { return gFalse; }
@@ -158,12 +163,14 @@ public:
protected:
void readFontDescriptor(XRef *xref, Dict *fontDict);
- CharCodeToUnicode *readToUnicodeCMap(Dict *fontDict, int nBits);
+ CharCodeToUnicode *readToUnicodeCMap(Dict *fontDict, int nBits,
+ CharCodeToUnicode *ctu);
void findExtFontFile();
GString *tag; // PDF font tag
Ref id; // reference (used as unique ID)
GString *name; // font name
+ GString *origName; // original font name
GfxFontType type; // type of font
int flags; // font descriptor flags
GString *embFontName; // name of embedded font
@@ -205,9 +212,16 @@ public:
// Returns true if the PDF font specified an encoding.
GBool getHasEncoding() { return hasEncoding; }
- // Get width of a character or string.
+ // Returns true if the PDF font specified MacRomanEncoding.
+ GBool getUsesMacRomanEnc() { return usesMacRomanEnc; }
+
+ // Get width of a character.
double getWidth(Guchar c) { return widths[c]; }
+ // Return a char code-to-GID mapping for the provided font file.
+ // (This is only useful for TrueType fonts.)
+ Gushort *getCodeToGIDMap(TrueTypeFontFile *ff);
+
// Return the Type 3 CharProc dictionary, or NULL if none.
Dict *getCharProcs();
@@ -224,6 +238,7 @@ private:
// the string is malloc'ed
CharCodeToUnicode *ctu; // char code --> Unicode
GBool hasEncoding;
+ GBool usesMacRomanEnc;
double widths[256]; // character widths
Object charProcs; // Type 3 CharProcs dictionary
Object resources; // Type 3 Resources dictionary
@@ -279,7 +294,7 @@ class GfxFontDict {
public:
// Build the font dictionary, given the PDF font dictionary.
- GfxFontDict(XRef *xref, Dict *fontDict);
+ GfxFontDict(XRef *xref, Ref *fontDictRef, Dict *fontDict);
// Destructor.
~GfxFontDict();
diff --git a/pdf/xpdf/GfxState.cc b/pdf/xpdf/GfxState.cc
index 7efd0b9..d202939 100644
--- a/pdf/xpdf/GfxState.cc
+++ b/pdf/xpdf/GfxState.cc
@@ -98,7 +98,7 @@ GfxColorSpace *GfxColorSpace::parse(Object *csObj) {
} else if (obj1.isName("Pattern")) {
cs = GfxPatternColorSpace::parse(csObj->getArray());
} else {
- error(-1, "Bad color space '%s'", csObj->getName());
+ error(-1, "Bad color space");
}
obj1.free();
} else {
@@ -1181,18 +1181,22 @@ GfxPattern::~GfxPattern() {
GfxPattern *GfxPattern::parse(Object *obj) {
GfxPattern *pattern;
- Dict *dict;
Object obj1;
+ if (obj->isDict()) {
+ obj->dictLookup("PatternType", &obj1);
+ } else if (obj->isStream()) {
+ obj->streamGetDict()->lookup("PatternType", &obj1);
+ } else {
+ return NULL;
+ }
pattern = NULL;
- if (obj->isStream()) {
- dict = obj->streamGetDict();
- dict->lookup("PatternType", &obj1);
- if (obj1.isInt() && obj1.getInt() == 1) {
- pattern = new GfxTilingPattern(dict, obj);
- }
- obj1.free();
+ if (obj1.isInt() && obj1.getInt() == 1) {
+ pattern = GfxTilingPattern::parse(obj);
+ } else if (obj1.isInt() && obj1.getInt() == 2) {
+ pattern = GfxShadingPattern::parse(obj);
}
+ obj1.free();
return pattern;
}
@@ -1200,33 +1204,42 @@ GfxPattern *GfxPattern::parse(Object *obj) {
// GfxTilingPattern
//------------------------------------------------------------------------
-GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
- GfxPattern(1)
-{
+GfxTilingPattern *GfxTilingPattern::parse(Object *patObj) {
+ GfxTilingPattern *pat;
+ Dict *dict;
+ int paintTypeA, tilingTypeA;
+ double bboxA[4], matrixA[6];
+ double xStepA, yStepA;
+ Object resDictA;
Object obj1, obj2;
int i;
- if (streamDict->lookup("PaintType", &obj1)->isInt()) {
- paintType = obj1.getInt();
+ if (!patObj->isStream()) {
+ return NULL;
+ }
+ dict = patObj->streamGetDict();
+
+ if (dict->lookup("PaintType", &obj1)->isInt()) {
+ paintTypeA = obj1.getInt();
} else {
- paintType = 1;
+ paintTypeA = 1;
error(-1, "Invalid or missing PaintType in pattern");
}
obj1.free();
- if (streamDict->lookup("TilingType", &obj1)->isInt()) {
- tilingType = obj1.getInt();
+ if (dict->lookup("TilingType", &obj1)->isInt()) {
+ tilingTypeA = obj1.getInt();
} else {
- tilingType = 1;
+ tilingTypeA = 1;
error(-1, "Invalid or missing TilingType in pattern");
}
obj1.free();
- bbox[0] = bbox[1] = 0;
- bbox[2] = bbox[3] = 1;
- if (streamDict->lookup("BBox", &obj1)->isArray() &&
+ bboxA[0] = bboxA[1] = 0;
+ bboxA[2] = bboxA[3] = 1;
+ if (dict->lookup("BBox", &obj1)->isArray() &&
obj1.arrayGetLength() == 4) {
for (i = 0; i < 4; ++i) {
if (obj1.arrayGet(i, &obj2)->isNum()) {
- bbox[i] = obj2.getNum();
+ bboxA[i] = obj2.getNum();
}
obj2.free();
}
@@ -1234,39 +1247,65 @@ GfxTilingPattern::GfxTilingPattern(Dict *streamDict, Object *stream):
error(-1, "Invalid or missing BBox in pattern");
}
obj1.free();
- if (streamDict->lookup("XStep", &obj1)->isNum()) {
- xStep = obj1.getNum();
+ if (dict->lookup("XStep", &obj1)->isNum()) {
+ xStepA = obj1.getNum();
} else {
- xStep = 1;
+ xStepA = 1;
error(-1, "Invalid or missing XStep in pattern");
}
obj1.free();
- if (streamDict->lookup("YStep", &obj1)->isNum()) {
- yStep = obj1.getNum();
+ if (dict->lookup("YStep", &obj1)->isNum()) {
+ yStepA = obj1.getNum();
} else {
- yStep = 1;
+ yStepA = 1;
error(-1, "Invalid or missing YStep in pattern");
}
obj1.free();
- if (!streamDict->lookup("Resources", &resDict)->isDict()) {
- resDict.free();
- resDict.initNull();
+ if (!dict->lookup("Resources", &resDictA)->isDict()) {
+ resDictA.free();
+ resDictA.initNull();
error(-1, "Invalid or missing Resources in pattern");
}
- matrix[0] = 1; matrix[1] = 0;
- matrix[2] = 0; matrix[3] = 1;
- matrix[4] = 0; matrix[5] = 0;
- if (streamDict->lookup("Matrix", &obj1)->isArray() &&
+ matrixA[0] = 1; matrixA[1] = 0;
+ matrixA[2] = 0; matrixA[3] = 1;
+ matrixA[4] = 0; matrixA[5] = 0;
+ if (dict->lookup("Matrix", &obj1)->isArray() &&
obj1.arrayGetLength() == 6) {
for (i = 0; i < 6; ++i) {
if (obj1.arrayGet(i, &obj2)->isNum()) {
- matrix[i] = obj2.getNum();
+ matrixA[i] = obj2.getNum();
}
obj2.free();
}
}
obj1.free();
- stream->copy(&contentStream);
+
+ pat = new GfxTilingPattern(paintTypeA, tilingTypeA, bboxA, xStepA, yStepA,
+ &resDictA, matrixA, patObj);
+ resDictA.free();
+ return pat;
+}
+
+GfxTilingPattern::GfxTilingPattern(int paintTypeA, int tilingTypeA,
+ double *bboxA, double xStepA, double yStepA,
+ Object *resDictA, double *matrixA,
+ Object *contentStreamA):
+ GfxPattern(1)
+{
+ int i;
+
+ paintType = paintTypeA;
+ tilingType = tilingTypeA;
+ for (i = 0; i < 4; ++i) {
+ bbox[i] = bboxA[i];
+ }
+ xStep = xStepA;
+ yStep = yStepA;
+ resDictA->copy(&resDict);
+ for (i = 0; i < 6; ++i) {
+ matrix[i] = matrixA[i];
+ }
+ contentStreamA->copy(&contentStream);
}
GfxTilingPattern::~GfxTilingPattern() {
@@ -1275,127 +1314,341 @@ GfxTilingPattern::~GfxTilingPattern() {
}
GfxPattern *GfxTilingPattern::copy() {
- return new GfxTilingPattern(this);
+ return new GfxTilingPattern(paintType, tilingType, bbox, xStep, yStep,
+ &resDict, matrix, &contentStream);
}
-GfxTilingPattern::GfxTilingPattern(GfxTilingPattern *pat):
- GfxPattern(1)
+//------------------------------------------------------------------------
+// GfxShadingPattern
+//------------------------------------------------------------------------
+
+GfxShadingPattern *GfxShadingPattern::parse(Object *patObj) {
+ Dict *dict;
+ GfxShading *shadingA;
+ double matrixA[6];
+ Object obj1, obj2;
+ int i;
+
+ if (!patObj->isDict()) {
+ return NULL;
+ }
+ dict = patObj->getDict();
+
+ dict->lookup("Shading", &obj1);
+ shadingA = GfxShading::parse(&obj1);
+ obj1.free();
+ if (!shadingA) {
+ return NULL;
+ }
+
+ matrixA[0] = 1; matrixA[1] = 0;
+ matrixA[2] = 0; matrixA[3] = 1;
+ matrixA[4] = 0; matrixA[5] = 0;
+ if (dict->lookup("Matrix", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 6) {
+ for (i = 0; i < 6; ++i) {
+ if (obj1.arrayGet(i, &obj2)->isNum()) {
+ matrixA[i] = obj2.getNum();
+ }
+ obj2.free();
+ }
+ }
+ obj1.free();
+
+ return new GfxShadingPattern(shadingA, matrixA);
+}
+
+GfxShadingPattern::GfxShadingPattern(GfxShading *shadingA, double *matrixA):
+ GfxPattern(2)
{
- memcpy(this, pat, sizeof(GfxTilingPattern));
- pat->resDict.copy(&resDict);
- pat->contentStream.copy(&contentStream);
+ int i;
+
+ shading = shadingA;
+ for (i = 0; i < 6; ++i) {
+ matrix[i] = matrixA[i];
+ }
+}
+
+GfxShadingPattern::~GfxShadingPattern() {
+ delete shading;
+}
+
+GfxPattern *GfxShadingPattern::copy() {
+ return new GfxShadingPattern(shading->copy(), matrix);
}
//------------------------------------------------------------------------
// GfxShading
//------------------------------------------------------------------------
-GfxShading::GfxShading() {
+GfxShading::GfxShading(int typeA) {
+ type = typeA;
+ colorSpace = NULL;
+}
+
+GfxShading::GfxShading(GfxShading *shading) {
+ int i;
+
+ type = shading->type;
+ colorSpace = shading->colorSpace->copy();
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ background.c[i] = shading->background.c[i];
+ }
+ hasBackground = shading->hasBackground;
+ xMin = shading->xMin;
+ yMin = shading->yMin;
+ xMax = shading->xMax;
+ yMax = shading->yMax;
+ hasBBox = shading->hasBBox;
}
GfxShading::~GfxShading() {
- delete colorSpace;
+ if (colorSpace) {
+ delete colorSpace;
+ }
}
GfxShading *GfxShading::parse(Object *obj) {
GfxShading *shading;
+ Dict *dict;
int typeA;
- GfxColorSpace *colorSpaceA;
- GfxColor backgroundA;
- GBool hasBackgroundA;
- double xMinA, yMinA, xMaxA, yMaxA;
- GBool hasBBoxA;
- Object obj1, obj2;
- int i;
+ Object obj1;
- shading = NULL;
if (obj->isDict()) {
+ dict = obj->getDict();
+ } else if (obj->isStream()) {
+ dict = obj->streamGetDict();
+ } else {
+ return NULL;
+ }
- if (!obj->dictLookup("ShadingType", &obj1)->isInt()) {
- error(-1, "Invalid ShadingType in shading dictionary");
- obj1.free();
- goto err1;
- }
- typeA = obj1.getInt();
+ if (!dict->lookup("ShadingType", &obj1)->isInt()) {
+ error(-1, "Invalid ShadingType in shading dictionary");
obj1.free();
+ return NULL;
+ }
+ typeA = obj1.getInt();
+ obj1.free();
- obj->dictLookup("ColorSpace", &obj1);
- if (!(colorSpaceA = GfxColorSpace::parse(&obj1))) {
- error(-1, "Bad color space in shading dictionary");
- obj1.free();
- goto err1;
- }
- obj1.free();
+ switch (typeA) {
+ case 1:
+ shading = GfxFunctionShading::parse(dict);
+ break;
+ case 2:
+ shading = GfxAxialShading::parse(dict);
+ break;
+ case 3:
+ shading = GfxRadialShading::parse(dict);
+ break;
+ default:
+ error(-1, "Unimplemented shading type %d", typeA);
+ goto err1;
+ }
- for (i = 0; i < gfxColorMaxComps; ++i) {
- backgroundA.c[i] = 0;
- }
- hasBackgroundA = gFalse;
- if (obj->dictLookup("Background", &obj1)->isArray()) {
- if (obj1.arrayGetLength() == colorSpaceA->getNComps()) {
- hasBackgroundA = gTrue;
- for (i = 0; i < colorSpaceA->getNComps(); ++i) {
- backgroundA.c[i] = obj1.arrayGet(i, &obj2)->getNum();
- obj2.free();
- }
- } else {
- error(-1, "Bad Background in shading dictionary");
- }
- }
+ return shading;
+
+ err1:
+ return NULL;
+}
+
+GBool GfxShading::init(Dict *dict) {
+ Object obj1, obj2;
+ int i;
+
+ dict->lookup("ColorSpace", &obj1);
+ if (!(colorSpace = GfxColorSpace::parse(&obj1))) {
+ error(-1, "Bad color space in shading dictionary");
obj1.free();
+ return gFalse;
+ }
+ obj1.free();
- xMinA = yMinA = xMaxA = yMaxA = 0;
- hasBBoxA = gFalse;
- if (obj->dictLookup("BBox", &obj1)->isArray()) {
- if (obj1.arrayGetLength() == 4) {
- hasBBoxA = gTrue;
- xMinA = obj1.arrayGet(0, &obj2)->getNum();
- obj2.free();
- yMinA = obj1.arrayGet(1, &obj2)->getNum();
- obj2.free();
- xMaxA = obj1.arrayGet(2, &obj2)->getNum();
- obj2.free();
- yMaxA = obj1.arrayGet(3, &obj2)->getNum();
+ for (i = 0; i < gfxColorMaxComps; ++i) {
+ background.c[i] = 0;
+ }
+ hasBackground = gFalse;
+ if (dict->lookup("Background", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() == colorSpace->getNComps()) {
+ hasBackground = gTrue;
+ for (i = 0; i < colorSpace->getNComps(); ++i) {
+ background.c[i] = obj1.arrayGet(i, &obj2)->getNum();
obj2.free();
- } else {
- error(-1, "Bad BBox in shading dictionary");
}
+ } else {
+ error(-1, "Bad Background in shading dictionary");
}
- obj1.free();
+ }
+ obj1.free();
- switch (typeA) {
- case 2:
- shading = GfxAxialShading::parse(obj->getDict());
- break;
- case 3:
- shading = GfxRadialShading::parse(obj->getDict());
- break;
- default:
- error(-1, "Unimplemented shading type %d", typeA);
- goto err1;
+ xMin = yMin = xMax = yMax = 0;
+ hasBBox = gFalse;
+ if (dict->lookup("BBox", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() == 4) {
+ hasBBox = gTrue;
+ xMin = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ yMin = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ xMax = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ yMax = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ } else {
+ error(-1, "Bad BBox in shading dictionary");
}
+ }
+ obj1.free();
- if (shading) {
- shading->type = typeA;
- shading->colorSpace = colorSpaceA;
- shading->background = backgroundA;
- shading->hasBackground = hasBackgroundA;
- shading->xMin = xMinA;
- shading->yMin = yMinA;
- shading->xMax = xMaxA;
- shading->yMax = yMaxA;
- shading->hasBBox = hasBBoxA;
- } else {
- delete colorSpaceA;
+ return gTrue;
+}
+
+//------------------------------------------------------------------------
+// GfxFunctionShading
+//------------------------------------------------------------------------
+
+GfxFunctionShading::GfxFunctionShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double *matrixA,
+ Function **funcsA, int nFuncsA):
+ GfxShading(1)
+{
+ int i;
+
+ x0 = x0A;
+ y0 = y0A;
+ x1 = x1A;
+ y1 = y1A;
+ for (i = 0; i < 6; ++i) {
+ matrix[i] = matrixA[i];
+ }
+ nFuncs = nFuncsA;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = funcsA[i];
+ }
+}
+
+GfxFunctionShading::GfxFunctionShading(GfxFunctionShading *shading):
+ GfxShading(shading)
+{
+ int i;
+
+ x0 = shading->x0;
+ y0 = shading->y0;
+ x1 = shading->x1;
+ y1 = shading->y1;
+ for (i = 0; i < 6; ++i) {
+ matrix[i] = shading->matrix[i];
+ }
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
+ }
+}
+
+GfxFunctionShading::~GfxFunctionShading() {
+ int i;
+
+ for (i = 0; i < nFuncs; ++i) {
+ delete funcs[i];
+ }
+}
+
+GfxFunctionShading *GfxFunctionShading::parse(Dict *dict) {
+ GfxFunctionShading *shading;
+ double x0A, y0A, x1A, y1A;
+ double matrixA[6];
+ Function *funcsA[gfxColorMaxComps];
+ int nFuncsA;
+ Object obj1, obj2;
+ int i;
+
+ x0A = y0A = 0;
+ x1A = y1A = 1;
+ if (dict->lookup("Domain", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 4) {
+ x0A = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ y0A = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ x1A = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ y1A = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ matrixA[0] = 1; matrixA[1] = 0;
+ matrixA[2] = 0; matrixA[3] = 1;
+ matrixA[4] = 0; matrixA[5] = 0;
+ if (dict->lookup("Matrix", &obj1)->isArray() &&
+ obj1.arrayGetLength() == 6) {
+ matrixA[0] = obj1.arrayGet(0, &obj2)->getNum();
+ obj2.free();
+ matrixA[1] = obj1.arrayGet(1, &obj2)->getNum();
+ obj2.free();
+ matrixA[2] = obj1.arrayGet(2, &obj2)->getNum();
+ obj2.free();
+ matrixA[3] = obj1.arrayGet(3, &obj2)->getNum();
+ obj2.free();
+ matrixA[4] = obj1.arrayGet(4, &obj2)->getNum();
+ obj2.free();
+ matrixA[5] = obj1.arrayGet(5, &obj2)->getNum();
+ obj2.free();
+ }
+ obj1.free();
+
+ dict->lookup("Function", &obj1);
+ if (obj1.isArray()) {
+ nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps) {
+ error(-1, "Invalid Function array in shading dictionary");
+ goto err1;
+ }
+ for (i = 0; i < nFuncsA; ++i) {
+ obj1.arrayGet(i, &obj2);
+ if (!(funcsA[i] = Function::parse(&obj2))) {
+ goto err2;
+ }
+ obj2.free();
+ }
+ } else {
+ nFuncsA = 1;
+ if (!(funcsA[0] = Function::parse(&obj1))) {
+ goto err1;
}
}
+ obj1.free();
+ shading = new GfxFunctionShading(x0A, y0A, x1A, y1A, matrixA,
+ funcsA, nFuncsA);
+ if (!shading->init(dict)) {
+ delete shading;
+ return NULL;
+ }
return shading;
+ err2:
+ obj2.free();
err1:
+ obj1.free();
return NULL;
}
+GfxShading *GfxFunctionShading::copy() {
+ return new GfxFunctionShading(this);
+}
+
+void GfxFunctionShading::getColor(double x, double y, GfxColor *color) {
+ double in[2];
+ int i;
+
+ in[0] = x;
+ in[1] = y;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i]->transform(in, &color->c[i]);
+ }
+}
+
//------------------------------------------------------------------------
// GfxAxialShading
//------------------------------------------------------------------------
@@ -1404,7 +1657,9 @@ GfxAxialShading::GfxAxialShading(double x0A, double y0A,
double x1A, double y1A,
double t0A, double t1A,
Function **funcsA, int nFuncsA,
- GBool extend0A, GBool extend1A) {
+ GBool extend0A, GBool extend1A):
+ GfxShading(2)
+{
int i;
x0 = x0A;
@@ -1421,6 +1676,25 @@ GfxAxialShading::GfxAxialShading(double x0A, double y0A,
extend1 = extend1A;
}
+GfxAxialShading::GfxAxialShading(GfxAxialShading *shading):
+ GfxShading(shading)
+{
+ int i;
+
+ x0 = shading->x0;
+ y0 = shading->y0;
+ x1 = shading->x1;
+ y1 = shading->y1;
+ t0 = shading->t0;
+ y1 = shading->t1;
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
+ }
+ extend0 = shading->extend0;
+ extend1 = shading->extend1;
+}
+
GfxAxialShading::~GfxAxialShading() {
int i;
@@ -1430,6 +1704,7 @@ GfxAxialShading::~GfxAxialShading() {
}
GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
+ GfxAxialShading *shading;
double x0A, y0A, x1A, y1A;
double t0A, t1A;
Function *funcsA[gfxColorMaxComps];
@@ -1469,6 +1744,10 @@ GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
dict->lookup("Function", &obj1);
if (obj1.isArray()) {
nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps) {
+ error(-1, "Invalid Function array in shading dictionary");
+ goto err1;
+ }
for (i = 0; i < nFuncsA; ++i) {
obj1.arrayGet(i, &obj2);
if (!(funcsA[i] = Function::parse(&obj2))) {
@@ -1497,16 +1776,27 @@ GfxAxialShading *GfxAxialShading::parse(Dict *dict) {
}
obj1.free();
- return new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
- funcsA, nFuncsA, extend0A, extend1A);
+ shading = new GfxAxialShading(x0A, y0A, x1A, y1A, t0A, t1A,
+ funcsA, nFuncsA, extend0A, extend1A);
+ if (!shading->init(dict)) {
+ delete shading;
+ return NULL;
+ }
+ return shading;
err1:
return NULL;
}
+GfxShading *GfxAxialShading::copy() {
+ return new GfxAxialShading(this);
+}
+
void GfxAxialShading::getColor(double t, GfxColor *color) {
int i;
+ // NB: there can be one function with n outputs or n functions with
+ // one output each (where n = number of color components)
for (i = 0; i < nFuncs; ++i) {
funcs[i]->transform(&t, &color->c[i]);
}
@@ -1520,7 +1810,9 @@ GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
double x1A, double y1A, double r1A,
double t0A, double t1A,
Function **funcsA, int nFuncsA,
- GBool extend0A, GBool extend1A) {
+ GBool extend0A, GBool extend1A):
+ GfxShading(3)
+{
int i;
x0 = x0A;
@@ -1539,6 +1831,27 @@ GfxRadialShading::GfxRadialShading(double x0A, double y0A, double r0A,
extend1 = extend1A;
}
+GfxRadialShading::GfxRadialShading(GfxRadialShading *shading):
+ GfxShading(shading)
+{
+ int i;
+
+ x0 = shading->x0;
+ y0 = shading->y0;
+ r0 = shading->r0;
+ x1 = shading->x1;
+ y1 = shading->y1;
+ r1 = shading->r1;
+ t0 = shading->t0;
+ y1 = shading->t1;
+ nFuncs = shading->nFuncs;
+ for (i = 0; i < nFuncs; ++i) {
+ funcs[i] = shading->funcs[i]->copy();
+ }
+ extend0 = shading->extend0;
+ extend1 = shading->extend1;
+}
+
GfxRadialShading::~GfxRadialShading() {
int i;
@@ -1548,6 +1861,7 @@ GfxRadialShading::~GfxRadialShading() {
}
GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
+ GfxRadialShading *shading;
double x0A, y0A, r0A, x1A, y1A, r1A;
double t0A, t1A;
Function *funcsA[gfxColorMaxComps];
@@ -1591,6 +1905,10 @@ GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
dict->lookup("Function", &obj1);
if (obj1.isArray()) {
nFuncsA = obj1.arrayGetLength();
+ if (nFuncsA > gfxColorMaxComps) {
+ error(-1, "Invalid Function array in shading dictionary");
+ goto err1;
+ }
for (i = 0; i < nFuncsA; ++i) {
obj1.arrayGet(i, &obj2);
if (!(funcsA[i] = Function::parse(&obj2))) {
@@ -1619,16 +1937,27 @@ GfxRadialShading *GfxRadialShading::parse(Dict *dict) {
}
obj1.free();
- return new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
- funcsA, nFuncsA, extend0A, extend1A);
+ shading = new GfxRadialShading(x0A, y0A, r0A, x1A, y1A, r1A, t0A, t1A,
+ funcsA, nFuncsA, extend0A, extend1A);
+ if (!shading->init(dict)) {
+ delete shading;
+ return NULL;
+ }
+ return shading;
err1:
return NULL;
}
+GfxShading *GfxRadialShading::copy() {
+ return new GfxRadialShading(this);
+}
+
void GfxRadialShading::getColor(double t, GfxColor *color) {
int i;
+ // NB: there can be one function with n outputs or n functions with
+ // one output each (where n = number of color components)
for (i = 0; i < nFuncs; ++i) {
funcs[i]->transform(&t, &color->c[i]);
}
@@ -1741,6 +2070,36 @@ GfxImageColorMap::GfxImageColorMap(int bitsA, Object *decode,
ok = gFalse;
}
+GfxImageColorMap::GfxImageColorMap(GfxImageColorMap *colorMap) {
+ int n, i;
+
+ colorSpace = colorMap->colorSpace->copy();
+ bits = colorMap->bits;
+ nComps = colorMap->nComps;
+ nComps2 = colorMap->nComps2;
+ colorSpace2 = NULL;
+ lookup = NULL;
+ if (colorSpace->getMode() == csIndexed) {
+ colorSpace2 = ((GfxIndexedColorSpace *)colorSpace)->getBase();
+ n = ((GfxIndexedColorSpace *)colorSpace)->getIndexHigh();
+ n = (n + 1) * nComps2 * sizeof(double);
+ } else if (colorSpace->getMode() == csSeparation) {
+ colorSpace2 = ((GfxSeparationColorSpace *)colorSpace)->getAlt();
+ n = (1 << bits) - 1;
+ n = (n + 1) * nComps2 * sizeof(double);
+ } else {
+ n = (1 << bits) - 1;
+ n = (n + 1) * nComps * sizeof(double);
+ }
+ lookup = (double *)gmalloc(n);
+ memcpy(lookup, colorMap->lookup, n);
+ for (i = 0; i < nComps; ++i) {
+ decodeLow[i] = colorMap->decodeLow[i];
+ decodeRange[i] = colorMap->decodeRange[i];
+ }
+ ok = gTrue;
+}
+
GfxImageColorMap::~GfxImageColorMap() {
delete colorSpace;
gfree(lookup);
@@ -1886,6 +2245,15 @@ void GfxSubpath::close() {
closed = gTrue;
}
+void GfxSubpath::offset(double dx, double dy) {
+ int i;
+
+ for (i = 0; i < n; ++i) {
+ x[i] += dx;
+ y[i] += dy;
+ }
+}
+
GfxPath::GfxPath() {
justMoved = gFalse;
size = 16;
@@ -1968,55 +2336,78 @@ void GfxPath::close() {
subpaths[n-1]->close();
}
+void GfxPath::append(GfxPath *path) {
+ int i;
+
+ if (n + path->n > size) {
+ size = n + path->n;
+ subpaths = (GfxSubpath **)
+ grealloc(subpaths, size * sizeof(GfxSubpath *));
+ }
+ for (i = 0; i < path->n; ++i) {
+ subpaths[n++] = path->subpaths[i]->copy();
+ }
+ justMoved = gFalse;
+}
+
+void GfxPath::offset(double dx, double dy) {
+ int i;
+
+ for (i = 0; i < n; ++i) {
+ subpaths[i]->offset(dx, dy);
+ }
+}
+
//------------------------------------------------------------------------
// GfxState
//------------------------------------------------------------------------
-GfxState::GfxState(double dpi, PDFRectangle *pageBox, int rotate,
- GBool upsideDown) {
- double k;
+GfxState::GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
+ int rotate, GBool upsideDown) {
+ double kx, ky;
px1 = pageBox->x1;
py1 = pageBox->y1;
px2 = pageBox->x2;
py2 = pageBox->y2;
- k = dpi / 72.0;
+ kx = hDPI / 72.0;
+ ky = vDPI / 72.0;
if (rotate == 90) {
ctm[0] = 0;
- ctm[1] = upsideDown ? k : -k;
- ctm[2] = k;
+ ctm[1] = upsideDown ? ky : -ky;
+ ctm[2] = kx;
ctm[3] = 0;
- ctm[4] = -k * py1;
- ctm[5] = k * (upsideDown ? -px1 : px2);
- pageWidth = k * (py2 - py1);
- pageHeight = k * (px2 - px1);
+ ctm[4] = -kx * py1;
+ ctm[5] = ky * (upsideDown ? -px1 : px2);
+ pageWidth = kx * (py2 - py1);
+ pageHeight = ky * (px2 - px1);
} else if (rotate == 180) {
- ctm[0] = -k;
+ ctm[0] = -kx;
ctm[1] = 0;
ctm[2] = 0;
- ctm[3] = upsideDown ? k : -k;
- ctm[4] = k * px2;
- ctm[5] = k * (upsideDown ? -py1 : py2);
- pageWidth = k * (px2 - px1);
- pageHeight = k * (py2 - py1);
+ ctm[3] = upsideDown ? ky : -ky;
+ ctm[4] = kx * px2;
+ ctm[5] = ky * (upsideDown ? -py1 : py2);
+ pageWidth = kx * (px2 - px1);
+ pageHeight = ky * (py2 - py1);
} else if (rotate == 270) {
ctm[0] = 0;
- ctm[1] = upsideDown ? -k : k;
- ctm[2] = -k;
+ ctm[1] = upsideDown ? -ky : ky;
+ ctm[2] = -kx;
ctm[3] = 0;
- ctm[4] = k * py2;
- ctm[5] = k * (upsideDown ? px2 : -px1);
- pageWidth = k * (py2 - py1);
- pageHeight = k * (px2 - px1);
+ ctm[4] = kx * py2;
+ ctm[5] = ky * (upsideDown ? px2 : -px1);
+ pageWidth = kx * (py2 - py1);
+ pageHeight = ky * (px2 - px1);
} else {
- ctm[0] = k;
+ ctm[0] = kx;
ctm[1] = 0;
ctm[2] = 0;
- ctm[3] = upsideDown ? -k : k;
- ctm[4] = -k * px1;
- ctm[5] = k * (upsideDown ? py2 : -py1);
- pageWidth = k * (px2 - px1);
- pageHeight = k * (py2 - py1);
+ ctm[3] = upsideDown ? -ky : ky;
+ ctm[4] = -kx * px1;
+ ctm[5] = ky * (upsideDown ? py2 : -py1);
+ pageWidth = kx * (px2 - px1);
+ pageHeight = ky * (py2 - py1);
}
fillColorSpace = new GfxDeviceGrayColorSpace();
@@ -2032,7 +2423,7 @@ GfxState::GfxState(double dpi, PDFRectangle *pageBox, int rotate,
lineDash = NULL;
lineDashLength = 0;
lineDashStart = 0;
- flatness = 0;
+ flatness = 1;
lineJoin = 0;
lineCap = 0;
miterLimit = 10;
diff --git a/pdf/xpdf/GfxState.h b/pdf/xpdf/GfxState.h
index a0b1d14..d072fd3 100644
--- a/pdf/xpdf/GfxState.h
+++ b/pdf/xpdf/GfxState.h
@@ -22,6 +22,7 @@
class Array;
class GfxFont;
class PDFRectangle;
+class GfxShading;
//------------------------------------------------------------------------
// GfxColor
@@ -402,7 +403,7 @@ private:
class GfxDeviceNColorSpace: public GfxColorSpace {
public:
- GfxDeviceNColorSpace(int nComps, GfxColorSpace *alt, Function *func);
+ GfxDeviceNColorSpace(int nCompsA, GfxColorSpace *alt, Function *func);
virtual ~GfxDeviceNColorSpace();
virtual GfxColorSpace *copy();
virtual GfxColorSpaceMode getMode() { return csDeviceN; }
@@ -489,7 +490,7 @@ private:
class GfxTilingPattern: public GfxPattern {
public:
- GfxTilingPattern(Dict *streamDict, Object *stream);
+ static GfxTilingPattern *parse(Object *patObj);
virtual ~GfxTilingPattern();
virtual GfxPattern *copy();
@@ -506,7 +507,10 @@ public:
private:
- GfxTilingPattern(GfxTilingPattern *pat);
+ GfxTilingPattern(int paintTypeA, int tilingTypeA,
+ double *bboxA, double xStepA, double yStepA,
+ Object *resDictA, double *matrixA,
+ Object *contentStreamA);
int paintType;
int tilingType;
@@ -518,17 +522,43 @@ private:
};
//------------------------------------------------------------------------
+// GfxShadingPattern
+//------------------------------------------------------------------------
+
+class GfxShadingPattern: public GfxPattern {
+public:
+
+ static GfxShadingPattern *parse(Object *patObj);
+ virtual ~GfxShadingPattern();
+
+ virtual GfxPattern *copy();
+
+ GfxShading *getShading() { return shading; }
+ double *getMatrix() { return matrix; }
+
+private:
+
+ GfxShadingPattern(GfxShading *shadingA, double *matrixA);
+
+ GfxShading *shading;
+ double matrix[6];
+};
+
+//------------------------------------------------------------------------
// GfxShading
//------------------------------------------------------------------------
class GfxShading {
public:
- GfxShading();
+ GfxShading(int typeA);
+ GfxShading(GfxShading *shading);
virtual ~GfxShading();
static GfxShading *parse(Object *obj);
+ virtual GfxShading *copy() = 0;
+
int getType() { return type; }
GfxColorSpace *getColorSpace() { return colorSpace; }
GfxColor *getBackground() { return &background; }
@@ -537,7 +567,9 @@ public:
{ *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
GBool getHasBBox() { return hasBBox; }
-private:
+protected:
+
+ GBool init(Dict *dict);
int type;
GfxColorSpace *colorSpace;
@@ -548,6 +580,37 @@ private:
};
//------------------------------------------------------------------------
+// GfxFunctionShading
+//------------------------------------------------------------------------
+
+class GfxFunctionShading: public GfxShading {
+public:
+
+ GfxFunctionShading(double x0A, double y0A,
+ double x1A, double y1A,
+ double *matrixA,
+ Function **funcsA, int nFuncsA);
+ GfxFunctionShading(GfxFunctionShading *shading);
+ virtual ~GfxFunctionShading();
+
+ static GfxFunctionShading *parse(Dict *dict);
+
+ virtual GfxShading *copy();
+
+ void getDomain(double *x0A, double *y0A, double *x1A, double *y1A)
+ { *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; }
+ double *getMatrix() { return matrix; }
+ void getColor(double x, double y, GfxColor *color);
+
+private:
+
+ double x0, y0, x1, y1;
+ double matrix[6];
+ Function *funcs[gfxColorMaxComps];
+ int nFuncs;
+};
+
+//------------------------------------------------------------------------
// GfxAxialShading
//------------------------------------------------------------------------
@@ -559,10 +622,13 @@ public:
double t0A, double t1A,
Function **funcsA, int nFuncsA,
GBool extend0A, GBool extend1A);
+ GfxAxialShading(GfxAxialShading *shading);
virtual ~GfxAxialShading();
static GfxAxialShading *parse(Dict *dict);
+ virtual GfxShading *copy();
+
void getCoords(double *x0A, double *y0A, double *x1A, double *y1A)
{ *x0A = x0; *y0A = y0; *x1A = x1; *y1A = y1; }
double getDomain0() { return t0; }
@@ -592,10 +658,13 @@ public:
double t0A, double t1A,
Function **funcsA, int nFuncsA,
GBool extend0A, GBool extend1A);
+ GfxRadialShading(GfxRadialShading *shading);
virtual ~GfxRadialShading();
static GfxRadialShading *parse(Dict *dict);
+ virtual GfxShading *copy();
+
void getCoords(double *x0A, double *y0A, double *r0A,
double *x1A, double *y1A, double *r1A)
{ *x0A = x0; *y0A = y0; *r0A = r0; *x1A = x1; *y1A = y1; *r1A = r1; }
@@ -627,6 +696,9 @@ public:
// Destructor.
~GfxImageColorMap();
+ // Return a copy of this color map.
+ GfxImageColorMap *copy() { return new GfxImageColorMap(this); }
+
// Is color map valid?
GBool isOk() { return ok; }
@@ -649,6 +721,8 @@ public:
private:
+ GfxImageColorMap(GfxImageColorMap *colorMap);
+
GfxColorSpace *colorSpace; // the image color space
int bits; // bits per component
int nComps; // number of components in a pixel
@@ -699,6 +773,9 @@ public:
void close();
GBool isClosed() { return closed; }
+ // Add (<dx>, <dy>) to each point in the subpath.
+ void offset(double dx, double dy);
+
private:
double *x, *y; // points
@@ -751,6 +828,12 @@ public:
// Close the last subpath.
void close();
+ // Append <path> to <this>.
+ void append(GfxPath *path);
+
+ // Add (<dx>, <dy>) to each point in the path.
+ void offset(double dx, double dy);
+
private:
GBool justMoved; // set if a new subpath was just started
@@ -770,11 +853,11 @@ private:
class GfxState {
public:
- // Construct a default GfxState, for a device with resolution <dpi>,
- // page box <pageBox>, page rotation <rotate>, and coordinate system
- // specified by <upsideDown>.
- GfxState(double dpi, PDFRectangle *pageBox, int rotate,
- GBool upsideDown);
+ // Construct a default GfxState, for a device with resolution <hDPI>
+ // x <vDPI>, page box <pageBox>, page rotation <rotate>, and
+ // coordinate system specified by <upsideDown>.
+ GfxState(double hDPI, double vDPI, PDFRectangle *pageBox,
+ int rotate, GBool upsideDown);
// Destructor.
~GfxState();
@@ -795,7 +878,7 @@ public:
void getFillGray(double *gray)
{ fillColorSpace->getGray(&fillColor, gray); }
void getStrokeGray(double *gray)
- { strokeColorSpace->getGray(&fillColor, gray); }
+ { strokeColorSpace->getGray(&strokeColor, gray); }
void getFillRGB(GfxRGB *rgb)
{ fillColorSpace->getRGB(&fillColor, rgb); }
void getStrokeRGB(GfxRGB *rgb)
diff --git a/pdf/xpdf/GlobalParams.cc b/pdf/xpdf/GlobalParams.cc
index c5083b2..9aa54e9 100644
--- a/pdf/xpdf/GlobalParams.cc
+++ b/pdf/xpdf/GlobalParams.cc
@@ -32,11 +32,19 @@
#include "GlobalParams.h"
#if MULTITHREADED
-# define globalParamsLock gLockMutex(&mutex)
-# define globalParamsUnlock gUnlockMutex(&mutex)
+# define lockGlobalParams gLockMutex(&mutex)
+# define lockUnicodeMapCache gLockMutex(&unicodeMapCacheMutex)
+# define lockCMapCache gLockMutex(&cMapCacheMutex)
+# define unlockGlobalParams gUnlockMutex(&mutex)
+# define unlockUnicodeMapCache gUnlockMutex(&unicodeMapCacheMutex)
+# define unlockCMapCache gUnlockMutex(&cMapCacheMutex)
#else
-# define globalParamsLock
-# define globalParamsUnlock
+# define lockGlobalParams
+# define lockUnicodeMapCache
+# define lockCMapCache
+# define unlockGlobalParams
+# define unlockUnicodeMapCache
+# define unlockCMapCache
#endif
#include "NameToUnicodeTable.h"
@@ -46,6 +54,11 @@
//------------------------------------------------------------------------
+#define cidToUnicodeCacheSize 4
+#define unicodeToUnicodeCacheSize 4
+
+//------------------------------------------------------------------------
+
GlobalParams *globalParams = NULL;
//------------------------------------------------------------------------
@@ -134,6 +147,8 @@ GlobalParams::GlobalParams(char *cfgFileName) {
#if MULTITHREADED
gInitMutex(&mutex);
+ gInitMutex(&unicodeMapCacheMutex);
+ gInitMutex(&cMapCacheMutex);
#endif
initBuiltinFontTables();
@@ -149,6 +164,7 @@ GlobalParams::GlobalParams(char *cfgFileName) {
nameToUnicode = new NameToCharCode();
cidToUnicodes = new GHash(gTrue);
+ unicodeToUnicodes = new GHash(gTrue);
residentUnicodeMaps = new GHash();
unicodeMaps = new GHash(gTrue);
cMapDirs = new GHash(gTrue);
@@ -194,9 +210,10 @@ GlobalParams::GlobalParams(char *cfgFileName) {
#else
textEOL = eolUnix;
#endif
+ textPageBreaks = gTrue;
textKeepTinyChars = gFalse;
fontDirs = new GList();
- initialZoom = new GString("1");
+ initialZoom = new GString("125");
t1libControl = fontRastAALow;
freetypeControl = fontRastAALow;
urlCommand = NULL;
@@ -205,7 +222,9 @@ GlobalParams::GlobalParams(char *cfgFileName) {
printCommands = gFalse;
errQuiet = gFalse;
- cidToUnicodeCache = new CIDToUnicodeCache();
+ cidToUnicodeCache = new CharCodeToUnicodeCache(cidToUnicodeCacheSize);
+ unicodeToUnicodeCache =
+ new CharCodeToUnicodeCache(unicodeToUnicodeCacheSize);
unicodeMapCache = new UnicodeMapCache();
cMapCache = new CMapCache();
@@ -329,6 +348,8 @@ void GlobalParams::parseFile(GString *fileName, FILE *f) {
parseNameToUnicode(tokens, fileName, line);
} else if (!cmd->cmp("cidToUnicode")) {
parseCIDToUnicode(tokens, fileName, line);
+ } else if (!cmd->cmp("unicodeToUnicode")) {
+ parseUnicodeToUnicode(tokens, fileName, line);
} else if (!cmd->cmp("unicodeMap")) {
parseUnicodeMap(tokens, fileName, line);
} else if (!cmd->cmp("cMapDir")) {
@@ -393,6 +414,9 @@ void GlobalParams::parseFile(GString *fileName, FILE *f) {
parseTextEncoding(tokens, fileName, line);
} else if (!cmd->cmp("textEOL")) {
parseTextEOL(tokens, fileName, line);
+ } else if (!cmd->cmp("textPageBreaks")) {
+ parseYesNo("textPageBreaks", &textPageBreaks,
+ tokens, fileName, line);
} else if (!cmd->cmp("textKeepTinyChars")) {
parseYesNo("textKeepTinyChars", &textKeepTinyChars,
tokens, fileName, line);
@@ -483,6 +507,23 @@ void GlobalParams::parseCIDToUnicode(GList *tokens, GString *fileName,
cidToUnicodes->add(collection->copy(), name->copy());
}
+void GlobalParams::parseUnicodeToUnicode(GList *tokens, GString *fileName,
+ int line) {
+ GString *font, *file, *old;
+
+ if (tokens->getLength() != 3) {
+ error(-1, "Bad 'unicodeToUnicode' config file command (%s:%d)",
+ fileName->getCString(), line);
+ return;
+ }
+ font = (GString *)tokens->get(1);
+ file = (GString *)tokens->get(2);
+ if ((old = (GString *)unicodeToUnicodes->remove(font))) {
+ delete old;
+ }
+ unicodeToUnicodes->add(font->copy(), file->copy());
+}
+
void GlobalParams::parseUnicodeMap(GList *tokens, GString *fileName,
int line) {
GString *encodingName, *name, *old;
@@ -787,6 +828,7 @@ GlobalParams::~GlobalParams() {
delete nameToUnicode;
deleteGHash(cidToUnicodes, GString);
+ deleteGHash(unicodeToUnicodes, GString);
deleteGHash(residentUnicodeMaps, UnicodeMap);
deleteGHash(unicodeMaps, GString);
deleteGList(toUnicodeDirs, GString);
@@ -816,11 +858,14 @@ GlobalParams::~GlobalParams() {
delete cMapDirs;
delete cidToUnicodeCache;
+ delete unicodeToUnicodeCache;
delete unicodeMapCache;
delete cMapCache;
#if MULTITHREADED
gDestroyMutex(&mutex);
+ gDestroyMutex(&unicodeMapCacheMutex);
+ gDestroyMutex(&cMapCacheMutex);
#endif
}
@@ -829,33 +874,39 @@ GlobalParams::~GlobalParams() {
//------------------------------------------------------------------------
CharCode GlobalParams::getMacRomanCharCode(char *charName) {
+ // no need to lock - macRomanReverseMap is constant
return macRomanReverseMap->lookup(charName);
}
Unicode GlobalParams::mapNameToUnicode(char *charName) {
+ // no need to lock - nameToUnicode is constant
return nameToUnicode->lookup(charName);
}
-FILE *GlobalParams::getCIDToUnicodeFile(GString *collection) {
- GString *fileName;
+UnicodeMap *GlobalParams::getResidentUnicodeMap(GString *encodingName) {
+ UnicodeMap *map;
- if (!(fileName = (GString *)cidToUnicodes->lookup(collection))) {
- return NULL;
+ lockGlobalParams;
+ map = (UnicodeMap *)residentUnicodeMaps->lookup(encodingName);
+ unlockGlobalParams;
+ if (map) {
+ map->incRefCnt();
}
- return fopen(fileName->getCString(), "r");
-}
-
-UnicodeMap *GlobalParams::getResidentUnicodeMap(GString *encodingName) {
- return (UnicodeMap *)residentUnicodeMaps->lookup(encodingName);
+ return map;
}
FILE *GlobalParams::getUnicodeMapFile(GString *encodingName) {
GString *fileName;
+ FILE *f;
- if (!(fileName = (GString *)unicodeMaps->lookup(encodingName))) {
- return NULL;
+ lockGlobalParams;
+ if ((fileName = (GString *)unicodeMaps->lookup(encodingName))) {
+ f = fopen(fileName->getCString(), "r");
+ } else {
+ f = NULL;
}
- return fopen(fileName->getCString(), "r");
+ unlockGlobalParams;
+ return f;
}
FILE *GlobalParams::findCMapFile(GString *collection, GString *cMapName) {
@@ -865,7 +916,9 @@ FILE *GlobalParams::findCMapFile(GString *collection, GString *cMapName) {
FILE *f;
int i;
+ lockGlobalParams;
if (!(list = (GList *)cMapDirs->lookup(collection))) {
+ unlockGlobalParams;
return NULL;
}
for (i = 0; i < list->getLength(); ++i) {
@@ -874,9 +927,11 @@ FILE *GlobalParams::findCMapFile(GString *collection, GString *cMapName) {
f = fopen(fileName->getCString(), "r");
delete fileName;
if (f) {
+ unlockGlobalParams;
return f;
}
}
+ unlockGlobalParams;
return NULL;
}
@@ -885,24 +940,27 @@ FILE *GlobalParams::findToUnicodeFile(GString *name) {
FILE *f;
int i;
+ lockGlobalParams;
for (i = 0; i < toUnicodeDirs->getLength(); ++i) {
dir = (GString *)toUnicodeDirs->get(i);
fileName = appendToPath(dir->copy(), name->getCString());
f = fopen(fileName->getCString(), "r");
delete fileName;
if (f) {
+ unlockGlobalParams;
return f;
}
}
+ unlockGlobalParams;
return NULL;
}
DisplayFontParam *GlobalParams::getDisplayFont(GString *fontName) {
DisplayFontParam *dfp;
- globalParamsLock;
+ lockGlobalParams;
dfp = (DisplayFontParam *)displayFonts->lookup(fontName);
- globalParamsUnlock;
+ unlockGlobalParams;
return dfp;
}
@@ -910,60 +968,67 @@ DisplayFontParam *GlobalParams::getDisplayCIDFont(GString *fontName,
GString *collection) {
DisplayFontParam *dfp;
+ lockGlobalParams;
if (!fontName ||
!(dfp = (DisplayFontParam *)displayNamedCIDFonts->lookup(fontName))) {
dfp = (DisplayFontParam *)displayCIDFonts->lookup(collection);
}
+ unlockGlobalParams;
return dfp;
}
GString *GlobalParams::getPSFile() {
GString *s;
- globalParamsLock;
+ lockGlobalParams;
s = psFile ? psFile->copy() : (GString *)NULL;
- globalParamsUnlock;
+ unlockGlobalParams;
return s;
}
int GlobalParams::getPSPaperWidth() {
int w;
- globalParamsLock;
+ lockGlobalParams;
w = psPaperWidth;
- globalParamsUnlock;
+ unlockGlobalParams;
return w;
}
int GlobalParams::getPSPaperHeight() {
int h;
- globalParamsLock;
+ lockGlobalParams;
h = psPaperHeight;
- globalParamsUnlock;
+ unlockGlobalParams;
return h;
}
GBool GlobalParams::getPSDuplex() {
GBool d;
- globalParamsLock;
+ lockGlobalParams;
d = psDuplex;
- globalParamsUnlock;
+ unlockGlobalParams;
return d;
}
PSLevel GlobalParams::getPSLevel() {
PSLevel level;
- globalParamsLock;
+ lockGlobalParams;
level = psLevel;
- globalParamsUnlock;
+ unlockGlobalParams;
return level;
}
PSFontParam *GlobalParams::getPSFont(GString *fontName) {
- return (PSFontParam *)psFonts->lookup(fontName);
+ PSFontParam *p;
+
+ lockGlobalParams;
+ p = (PSFontParam *)psFonts->lookup(fontName);
+ unlockGlobalParams;
+ return p;
}
PSFontParam *GlobalParams::getPSFont16(GString *fontName,
@@ -971,6 +1036,7 @@ PSFontParam *GlobalParams::getPSFont16(GString *fontName,
PSFontParam *p;
int i;
+ lockGlobalParams;
p = NULL;
if (fontName) {
for (i = 0; i < psNamedFonts16->getLength(); ++i) {
@@ -992,78 +1058,97 @@ PSFontParam *GlobalParams::getPSFont16(GString *fontName,
p = NULL;
}
}
+ unlockGlobalParams;
return p;
}
GBool GlobalParams::getPSEmbedType1() {
GBool e;
- globalParamsLock;
+ lockGlobalParams;
e = psEmbedType1;
- globalParamsUnlock;
+ unlockGlobalParams;
return e;
}
GBool GlobalParams::getPSEmbedTrueType() {
GBool e;
- globalParamsLock;
+ lockGlobalParams;
e = psEmbedTrueType;
- globalParamsUnlock;
+ unlockGlobalParams;
return e;
}
GBool GlobalParams::getPSEmbedCIDPostScript() {
GBool e;
- globalParamsLock;
+ lockGlobalParams;
e = psEmbedCIDPostScript;
- globalParamsUnlock;
+ unlockGlobalParams;
return e;
}
GBool GlobalParams::getPSEmbedCIDTrueType() {
GBool e;
- globalParamsLock;
+ lockGlobalParams;
e = psEmbedCIDTrueType;
- globalParamsUnlock;
+ unlockGlobalParams;
return e;
}
GBool GlobalParams::getPSOPI() {
GBool opi;
- globalParamsLock;
+ lockGlobalParams;
opi = psOPI;
- globalParamsUnlock;
+ unlockGlobalParams;
return opi;
}
GBool GlobalParams::getPSASCIIHex() {
GBool ah;
- globalParamsLock;
+ lockGlobalParams;
ah = psASCIIHex;
- globalParamsUnlock;
+ unlockGlobalParams;
return ah;
}
+GString *GlobalParams::getTextEncodingName() {
+ GString *s;
+
+ lockGlobalParams;
+ s = textEncoding->copy();
+ unlockGlobalParams;
+ return s;
+}
+
EndOfLineKind GlobalParams::getTextEOL() {
EndOfLineKind eol;
- globalParamsLock;
+ lockGlobalParams;
eol = textEOL;
- globalParamsUnlock;
+ unlockGlobalParams;
return eol;
}
+GBool GlobalParams::getTextPageBreaks() {
+ GBool pageBreaks;
+
+ lockGlobalParams;
+ pageBreaks = textPageBreaks;
+ unlockGlobalParams;
+ return pageBreaks;
+}
+
GBool GlobalParams::getTextKeepTinyChars() {
GBool tiny;
- globalParamsLock;
+ lockGlobalParams;
tiny = textKeepTinyChars;
- globalParamsUnlock;
+ unlockGlobalParams;
return tiny;
}
@@ -1073,100 +1158,132 @@ GString *GlobalParams::findFontFile(GString *fontName, char **exts) {
FILE *f;
int i;
+ lockGlobalParams;
for (i = 0; i < fontDirs->getLength(); ++i) {
dir = (GString *)fontDirs->get(i);
for (ext = exts; *ext; ++ext) {
fileName = appendToPath(dir->copy(), fontName->getCString());
fileName->append(*ext);
- if ((f = fopen(fileName->getCString(), "r"))) {
+ if ((f = fopen(fileName->getCString(), "rb"))) {
fclose(f);
+ unlockGlobalParams;
return fileName;
}
delete fileName;
}
}
+ unlockGlobalParams;
return NULL;
}
GString *GlobalParams::getInitialZoom() {
GString *s;
- globalParamsLock;
+ lockGlobalParams;
s = initialZoom->copy();
- globalParamsUnlock;
+ unlockGlobalParams;
return s;
}
FontRastControl GlobalParams::getT1libControl() {
FontRastControl c;
- globalParamsLock;
+ lockGlobalParams;
c = t1libControl;
- globalParamsUnlock;
+ unlockGlobalParams;
return c;
}
FontRastControl GlobalParams::getFreeTypeControl() {
FontRastControl c;
- globalParamsLock;
+ lockGlobalParams;
c = freetypeControl;
- globalParamsUnlock;
+ unlockGlobalParams;
return c;
}
GBool GlobalParams::getMapNumericCharNames() {
GBool map;
- globalParamsLock;
+ lockGlobalParams;
map = mapNumericCharNames;
- globalParamsUnlock;
+ unlockGlobalParams;
return map;
}
GBool GlobalParams::getPrintCommands() {
GBool p;
- globalParamsLock;
+ lockGlobalParams;
p = printCommands;
- globalParamsUnlock;
+ unlockGlobalParams;
return p;
}
GBool GlobalParams::getErrQuiet() {
GBool q;
- globalParamsLock;
+ lockGlobalParams;
q = errQuiet;
- globalParamsUnlock;
+ unlockGlobalParams;
return q;
}
CharCodeToUnicode *GlobalParams::getCIDToUnicode(GString *collection) {
+ GString *fileName;
CharCodeToUnicode *ctu;
- globalParamsLock;
- ctu = cidToUnicodeCache->getCIDToUnicode(collection);
- globalParamsUnlock;
+ lockGlobalParams;
+ if (!(ctu = cidToUnicodeCache->getCharCodeToUnicode(collection))) {
+ if ((fileName = (GString *)cidToUnicodes->lookup(collection)) &&
+ (ctu = CharCodeToUnicode::parseCIDToUnicode(fileName, collection))) {
+ cidToUnicodeCache->add(ctu);
+ }
+ }
+ unlockGlobalParams;
return ctu;
}
-UnicodeMap *GlobalParams::getUnicodeMap(GString *encodingName) {
- UnicodeMap *map;
+CharCodeToUnicode *GlobalParams::getUnicodeToUnicode(GString *fontName) {
+ CharCodeToUnicode *ctu;
+ GHashIter *iter;
+ GString *fontPattern, *fileName;
- globalParamsLock;
- map = getUnicodeMap2(encodingName);
- globalParamsUnlock;
- return map;
+ lockGlobalParams;
+ fileName = NULL;
+ unicodeToUnicodes->startIter(&iter);
+ while (unicodeToUnicodes->getNext(&iter, &fontPattern, (void **)&fileName)) {
+ if (strstr(fontName->getCString(), fontPattern->getCString())) {
+ unicodeToUnicodes->killIter(&iter);
+ break;
+ }
+ fileName = NULL;
+ }
+ if (fileName) {
+ if (!(ctu = unicodeToUnicodeCache->getCharCodeToUnicode(fileName))) {
+ if ((ctu = CharCodeToUnicode::parseUnicodeToUnicode(fileName))) {
+ unicodeToUnicodeCache->add(ctu);
+ }
+ }
+ } else {
+ ctu = NULL;
+ }
+ unlockGlobalParams;
+ return ctu;
+}
+
+UnicodeMap *GlobalParams::getUnicodeMap(GString *encodingName) {
+ return getUnicodeMap2(encodingName);
}
UnicodeMap *GlobalParams::getUnicodeMap2(GString *encodingName) {
UnicodeMap *map;
- if ((map = getResidentUnicodeMap(encodingName))) {
- map->incRefCnt();
- } else {
+ if (!(map = getResidentUnicodeMap(encodingName))) {
+ lockUnicodeMapCache;
map = unicodeMapCache->getUnicodeMap(encodingName);
+ unlockUnicodeMapCache;
}
return map;
}
@@ -1174,19 +1291,14 @@ UnicodeMap *GlobalParams::getUnicodeMap2(GString *encodingName) {
CMap *GlobalParams::getCMap(GString *collection, GString *cMapName) {
CMap *cMap;
- globalParamsLock;
+ lockCMapCache;
cMap = cMapCache->getCMap(collection, cMapName);
- globalParamsUnlock;
+ unlockCMapCache;
return cMap;
}
UnicodeMap *GlobalParams::getTextEncoding() {
- UnicodeMap *map;
-
- globalParamsLock;
- map = getUnicodeMap2(textEncoding);
- globalParamsUnlock;
- return map;
+ return getUnicodeMap2(textEncoding);
}
//------------------------------------------------------------------------
@@ -1196,25 +1308,25 @@ UnicodeMap *GlobalParams::getTextEncoding() {
void GlobalParams::addDisplayFont(DisplayFontParam *param) {
DisplayFontParam *old;
- globalParamsLock;
+ lockGlobalParams;
if ((old = (DisplayFontParam *)displayFonts->remove(param->name))) {
delete old;
}
displayFonts->add(param->name, param);
- globalParamsUnlock;
+ unlockGlobalParams;
}
void GlobalParams::setPSFile(char *file) {
- globalParamsLock;
+ lockGlobalParams;
if (psFile) {
delete psFile;
}
psFile = new GString(file);
- globalParamsUnlock;
+ unlockGlobalParams;
}
GBool GlobalParams::setPSPaperSize(char *size) {
- globalParamsLock;
+ lockGlobalParams;
if (!strcmp(size, "match")) {
psPaperWidth = psPaperHeight = -1;
} else if (!strcmp(size, "letter")) {
@@ -1230,82 +1342,82 @@ GBool GlobalParams::setPSPaperSize(char *size) {
psPaperWidth = 842;
psPaperHeight = 1190;
} else {
- globalParamsUnlock;
+ unlockGlobalParams;
return gFalse;
}
- globalParamsUnlock;
+ unlockGlobalParams;
return gTrue;
}
void GlobalParams::setPSPaperWidth(int width) {
- globalParamsLock;
+ lockGlobalParams;
psPaperWidth = width;
- globalParamsUnlock;
+ unlockGlobalParams;
}
void GlobalParams::setPSPaperHeight(int height) {
- globalParamsLock;
+ lockGlobalParams;
psPaperHeight = height;
- globalParamsUnlock;
+ unlockGlobalParams;
}
void GlobalParams::setPSDuplex(GBool duplex) {
- globalParamsLock;
+ lockGlobalParams;
psDuplex = duplex;
- globalParamsUnlock;
+ unlockGlobalParams;
}
void GlobalParams::setPSLevel(PSLevel level) {
- globalParamsLock;
+ lockGlobalParams;
psLevel = level;
- globalParamsUnlock;
+ unlockGlobalParams;
}
void GlobalParams::setPSEmbedType1(GBool embed) {
- globalParamsLock;
+ lockGlobalParams;
psEmbedType1 = embed;
- globalParamsUnlock;
+ unlockGlobalParams;
}
void GlobalParams::setPSEmbedTrueType(GBool embed) {
- globalParamsLock;
+ lockGlobalParams;
psEmbedTrueType = embed;
- globalParamsUnlock;
+ unlockGlobalParams;
}
void GlobalParams::setPSEmbedCIDPostScript(GBool embed) {
- globalParamsLock;
+ lockGlobalParams;
psEmbedCIDPostScript = embed;
- globalParamsUnlock;
+ unlockGlobalParams;
}
void GlobalParams::setPSEmbedCIDTrueType(GBool embed) {
- globalParamsLock;
+ lockGlobalParams;
psEmbedCIDTrueType = embed;
- globalParamsUnlock;
+ unlockGlobalParams;
}
void GlobalParams::setPSOPI(GBool opi) {
- globalParamsLock;
+ lockGlobalParams;
psOPI = opi;
- globalParamsUnlock;
+ unlockGlobalParams;
}
void GlobalParams::setPSASCIIHex(GBool hex) {
- globalParamsLock;
+ lockGlobalParams;
psASCIIHex = hex;
- globalParamsUnlock;
+ unlockGlobalParams;
}
void GlobalParams::setTextEncoding(char *encodingName) {
- globalParamsLock;
+ lockGlobalParams;
delete textEncoding;
textEncoding = new GString(encodingName);
- globalParamsUnlock;
+ unlockGlobalParams;
}
GBool GlobalParams::setTextEOL(char *s) {
- globalParamsLock;
+ lockGlobalParams;
if (!strcmp(s, "unix")) {
textEOL = eolUnix;
} else if (!strcmp(s, "dos")) {
@@ -1313,45 +1425,52 @@ GBool GlobalParams::setTextEOL(char *s) {
} else if (!strcmp(s, "mac")) {
textEOL = eolMac;
} else {
- globalParamsUnlock;
+ unlockGlobalParams;
return gFalse;
}
- globalParamsUnlock;
+ unlockGlobalParams;
return gTrue;
}
+void GlobalParams::setTextPageBreaks(GBool pageBreaks) {
+ lockGlobalParams;
+ textPageBreaks = pageBreaks;
+ unlockGlobalParams;
+}
+
void GlobalParams::setTextKeepTinyChars(GBool keep) {
- globalParamsLock;
+ lockGlobalParams;
textKeepTinyChars = keep;
- globalParamsUnlock;
+ unlockGlobalParams;
}
void GlobalParams::setInitialZoom(char *s) {
- globalParamsLock;
+ lockGlobalParams;
delete initialZoom;
initialZoom = new GString(s);
- globalParamsUnlock;
+ unlockGlobalParams;
}
GBool GlobalParams::setT1libControl(char *s) {
GBool ok;
- globalParamsLock;
+ lockGlobalParams;
ok = setFontRastControl(&t1libControl, s);
- globalParamsUnlock;
+ unlockGlobalParams;
return ok;
}
GBool GlobalParams::setFreeTypeControl(char *s) {
GBool ok;
- globalParamsLock;
+ lockGlobalParams;
ok = setFontRastControl(&freetypeControl, s);
- globalParamsUnlock;
+ unlockGlobalParams;
return ok;
}
GBool GlobalParams::setFontRastControl(FontRastControl *val, char *s) {
+ lockGlobalParams;
if (!strcmp(s, "none")) {
*val = fontRastNone;
} else if (!strcmp(s, "plain")) {
@@ -1361,25 +1480,27 @@ GBool GlobalParams::setFontRastControl(FontRastControl *val, char *s) {
} else if (!strcmp(s, "high")) {
*val = fontRastAAHigh;
} else {
+ unlockGlobalParams;
return gFalse;
}
+ unlockGlobalParams;
return gTrue;
}
void GlobalParams::setMapNumericCharNames(GBool map) {
- globalParamsLock;
+ lockGlobalParams;
mapNumericCharNames = map;
- globalParamsUnlock;
+ unlockGlobalParams;
}
void GlobalParams::setPrintCommands(GBool printCommandsA) {
- globalParamsLock;
+ lockGlobalParams;
printCommands = printCommandsA;
- globalParamsUnlock;
+ unlockGlobalParams;
}
void GlobalParams::setErrQuiet(GBool errQuietA) {
- globalParamsLock;
+ lockGlobalParams;
errQuiet = errQuietA;
- globalParamsUnlock;
+ unlockGlobalParams;
}
diff --git a/pdf/xpdf/GlobalParams.h b/pdf/xpdf/GlobalParams.h
index dee9e25..472beed 100644
--- a/pdf/xpdf/GlobalParams.h
+++ b/pdf/xpdf/GlobalParams.h
@@ -28,7 +28,7 @@ class GList;
class GHash;
class NameToCharCode;
class CharCodeToUnicode;
-class CIDToUnicodeCache;
+class CharCodeToUnicodeCache;
class UnicodeMap;
class UnicodeMapCache;
class CMap;
@@ -134,7 +134,6 @@ public:
CharCode getMacRomanCharCode(char *charName);
Unicode mapNameToUnicode(char *charName);
- FILE *getCIDToUnicodeFile(GString *collection);
UnicodeMap *getResidentUnicodeMap(GString *encodingName);
FILE *getUnicodeMapFile(GString *encodingName);
FILE *findCMapFile(GString *collection, GString *cMapName);
@@ -154,7 +153,9 @@ public:
GBool getPSEmbedCIDTrueType();
GBool getPSOPI();
GBool getPSASCIIHex();
+ GString *getTextEncodingName();
EndOfLineKind getTextEOL();
+ GBool getTextPageBreaks();
GBool getTextKeepTinyChars();
GString *findFontFile(GString *fontName, char **exts);
GString *getInitialZoom();
@@ -167,6 +168,7 @@ public:
GBool getErrQuiet();
CharCodeToUnicode *getCIDToUnicode(GString *collection);
+ CharCodeToUnicode *getUnicodeToUnicode(GString *fontName);
UnicodeMap *getUnicodeMap(GString *encodingName);
CMap *getCMap(GString *collection, GString *cMapName);
UnicodeMap *getTextEncoding();
@@ -188,6 +190,7 @@ public:
void setPSASCIIHex(GBool hex);
void setTextEncoding(char *encodingName);
GBool setTextEOL(char *s);
+ void setTextPageBreaks(GBool pageBreaks);
void setTextKeepTinyChars(GBool keep);
void setInitialZoom(char *s);
GBool setT1libControl(char *s);
@@ -201,6 +204,7 @@ private:
void parseFile(GString *fileName, FILE *f);
void parseNameToUnicode(GList *tokens, GString *fileName, int line);
void parseCIDToUnicode(GList *tokens, GString *fileName, int line);
+ void parseUnicodeToUnicode(GList *tokens, GString *fileName, int line);
void parseUnicodeMap(GList *tokens, GString *fileName, int line);
void parseCMapDir(GList *tokens, GString *fileName, int line);
void parseToUnicodeDir(GList *tokens, GString *fileName, int line);
@@ -238,6 +242,8 @@ private:
GHash *cidToUnicodes; // files for mappings from char collections
// to Unicode, indexed by collection name
// [GString]
+ GHash *unicodeToUnicodes; // files for Unicode-to-Unicode mappings,
+ // indexed by font name pattern [GString]
GHash *residentUnicodeMaps; // mappings from Unicode to char codes,
// indexed by encoding name [UnicodeMap]
GHash *unicodeMaps; // files for mappings from Unicode to char
@@ -270,6 +276,7 @@ private:
// output
EndOfLineKind textEOL; // type of EOL marker to use for text
// output
+ GBool textPageBreaks; // insert end-of-page markers?
GBool textKeepTinyChars; // keep all characters in text output
GList *fontDirs; // list of font dirs [GString]
GString *initialZoom; // initial zoom level
@@ -282,12 +289,15 @@ private:
GBool printCommands; // print the drawing commands
GBool errQuiet; // suppress error messages?
- CIDToUnicodeCache *cidToUnicodeCache;
+ CharCodeToUnicodeCache *cidToUnicodeCache;
+ CharCodeToUnicodeCache *unicodeToUnicodeCache;
UnicodeMapCache *unicodeMapCache;
CMapCache *cMapCache;
-#ifdef MULTITHREADED
+#if MULTITHREADED
GMutex mutex;
+ GMutex unicodeMapCacheMutex;
+ GMutex cMapCacheMutex;
#endif
};
diff --git a/pdf/xpdf/Link.cc b/pdf/xpdf/Link.cc
index c87f6ce..bfb41b7 100644
--- a/pdf/xpdf/Link.cc
+++ b/pdf/xpdf/Link.cc
@@ -583,13 +583,42 @@ LinkUnknown::~LinkUnknown() {
}
//------------------------------------------------------------------------
+// LinkBorderStyle
+//------------------------------------------------------------------------
+
+LinkBorderStyle::LinkBorderStyle(LinkBorderType typeA, double widthA,
+ double *dashA, int dashLengthA,
+ double rA, double gA, double bA) {
+ type = typeA;
+ width = widthA;
+ dash = dashA;
+ dashLength = dashLengthA;
+ r = rA;
+ g = gA;
+ b = bA;
+}
+
+LinkBorderStyle::~LinkBorderStyle() {
+ if (dash) {
+ gfree(dash);
+ }
+}
+
+//------------------------------------------------------------------------
// Link
//------------------------------------------------------------------------
Link::Link(Dict *dict, GString *baseURI) {
- Object obj1, obj2;
+ Object obj1, obj2, obj3;
+ LinkBorderType borderType;
+ double borderWidth;
+ double *borderDash;
+ int borderDashLength;
+ double borderR, borderG, borderB;
double t;
+ int i;
+ borderStyle = NULL;
action = NULL;
ok = gFalse;
@@ -634,19 +663,92 @@ Link::Link(Dict *dict, GString *baseURI) {
y2 = t;
}
- // get border
- borderW = 1;
- if (!dict->lookup("Border", &obj1)->isNull()) {
- if (obj1.isArray() && obj1.arrayGetLength() >= 3) {
- if (obj1.arrayGet(2, &obj2)->isNum()) {
- borderW = obj2.getNum();
- } else {
- error(-1, "Bad annotation border");
+ // get the border style info
+ borderType = linkBorderSolid;
+ borderWidth = 1;
+ borderDash = NULL;
+ borderDashLength = 0;
+ borderR = 0;
+ borderG = 0;
+ borderB = 1;
+ if (dict->lookup("BS", &obj1)->isDict()) {
+ if (obj1.dictLookup("S", &obj2)->isName()) {
+ if (obj2.isName("S")) {
+ borderType = linkBorderSolid;
+ } else if (obj2.isName("D")) {
+ borderType = linkBorderDashed;
+ } else if (obj2.isName("B")) {
+ borderType = linkBorderEmbossed;
+ } else if (obj2.isName("I")) {
+ borderType = linkBorderEngraved;
+ } else if (obj2.isName("U")) {
+ borderType = linkBorderUnderlined;
}
- obj2.free();
}
+ obj2.free();
+ if (obj1.dictLookup("W", &obj2)->isNum()) {
+ borderWidth = obj2.getNum();
+ }
+ obj2.free();
+ if (obj1.dictLookup("D", &obj2)->isArray()) {
+ borderDashLength = obj2.arrayGetLength();
+ borderDash = (double *)gmalloc(borderDashLength * sizeof(double));
+ for (i = 0; i < borderDashLength; ++i) {
+ if (obj2.arrayGet(i, &obj3)->isNum()) {
+ borderDash[i] = obj3.getNum();
+ } else {
+ borderDash[i] = 1;
+ }
+ obj3.free();
+ }
+ }
+ obj2.free();
+ } else {
+ obj1.free();
+ if (dict->lookup("Border", &obj1)->isArray()) {
+ if (obj1.arrayGetLength() >= 3) {
+ if (obj1.arrayGet(2, &obj2)->isNum()) {
+ borderWidth = obj2.getNum();
+ }
+ obj2.free();
+ if (obj1.arrayGetLength() >= 4) {
+ if (obj1.arrayGet(3, &obj2)->isArray()) {
+ borderType = linkBorderDashed;
+ borderDashLength = obj2.arrayGetLength();
+ borderDash = (double *)gmalloc(borderDashLength * sizeof(double));
+ for (i = 0; i < borderDashLength; ++i) {
+ if (obj2.arrayGet(i, &obj3)->isNum()) {
+ borderDash[i] = obj3.getNum();
+ } else {
+ borderDash[i] = 1;
+ }
+ obj3.free();
+ }
+ }
+ obj2.free();
+ }
+ }
+ }
+ }
+ obj1.free();
+ if (dict->lookup("C", &obj1)->isArray() && obj1.arrayGetLength() == 3) {
+ if (obj1.arrayGet(0, &obj2)->isNum()) {
+ borderR = obj2.getNum();
+ }
+ obj1.free();
+ if (obj1.arrayGet(1, &obj2)->isNum()) {
+ borderG = obj2.getNum();
+ }
+ obj1.free();
+ if (obj1.arrayGet(2, &obj2)->isNum()) {
+ borderB = obj2.getNum();
+ }
+ obj1.free();
}
obj1.free();
+ borderStyle = new LinkBorderStyle(borderType, borderWidth,
+ borderDash, borderDashLength,
+ borderR, borderG, borderB);
// look for destination
if (!dict->lookup("Dest", &obj1)->isNull()) {
@@ -675,8 +777,12 @@ Link::Link(Dict *dict, GString *baseURI) {
}
Link::~Link() {
- if (action)
+ if (borderStyle) {
+ delete borderStyle;
+ }
+ if (action) {
delete action;
+ }
}
//------------------------------------------------------------------------
diff --git a/pdf/xpdf/Link.h b/pdf/xpdf/Link.h
index 20ed450..aa8727f 100644
--- a/pdf/xpdf/Link.h
+++ b/pdf/xpdf/Link.h
@@ -302,6 +302,42 @@ private:
};
//------------------------------------------------------------------------
+// LinkBorderStyle
+//------------------------------------------------------------------------
+
+enum LinkBorderType {
+ linkBorderSolid,
+ linkBorderDashed,
+ linkBorderEmbossed,
+ linkBorderEngraved,
+ linkBorderUnderlined
+};
+
+class LinkBorderStyle {
+public:
+
+ LinkBorderStyle(LinkBorderType typeA, double widthA,
+ double *dashA, int dashLengthA,
+ double rA, double gA, double bA);
+ ~LinkBorderStyle();
+
+ LinkBorderType getType() { return type; }
+ double getWidth() { return width; }
+ void getDash(double **dashA, int *dashLengthA)
+ { *dashA = dash; *dashLengthA = dashLength; }
+ void getColor(double *rA, double *gA, double *bA)
+ { *rA = r; *gA = g; *bA = b; }
+
+private:
+
+ LinkBorderType type;
+ double width;
+ double *dash;
+ int dashLength;
+ double r, g, b;
+};
+
+//------------------------------------------------------------------------
// Link
//------------------------------------------------------------------------
@@ -315,25 +351,27 @@ public:
~Link();
// Was the link created successfully?
- GBool isOk() const { return ok; }
+ GBool isOk() { return ok; }
// Check if point is inside the link rectangle.
- GBool inRect(double x, double y) const
+ GBool inRect(double x, double y)
{ return x1 <= x && x <= x2 && y1 <= y && y <= y2; }
// Get action.
- LinkAction *getAction() const { return action; }
+ LinkAction *getAction() { return action; }
+
+ // Get the link rectangle.
+ void getRect(double *xa1, double *ya1, double *xa2, double *ya2)
+ { *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; }
- // Get border corners and width.
- void getBorder(double *xa1, double *ya1, double *xa2, double *ya2,
- double *wa) const
- { *xa1 = x1; *ya1 = y1; *xa2 = x2; *ya2 = y2; *wa = borderW; }
+ // Get the border style info.
+ LinkBorderStyle *getBorderStyle() { return borderStyle; }
private:
double x1, y1; // lower left corner
double x2, y2; // upper right corner
- double borderW; // border width
+ LinkBorderStyle *borderStyle; // border style
LinkAction *action; // action
GBool ok; // is link valid?
};
diff --git a/pdf/xpdf/Makefile.am b/pdf/xpdf/Makefile.am
index 5ff9a34..96d57ec 100644
--- a/pdf/xpdf/Makefile.am
+++ b/pdf/xpdf/Makefile.am
@@ -97,6 +97,7 @@ libxpdf_a_SOURCES = \
UnicodeMap.cc \
UnicodeMap.h \
UnicodeMapTables.h \
+ UnicodeTypeTable.cc \
XRef.cc \
XRef.h
diff --git a/pdf/xpdf/OutputDev.h b/pdf/xpdf/OutputDev.h
index f050c03..67737af 100644
--- a/pdf/xpdf/OutputDev.h
+++ b/pdf/xpdf/OutputDev.h
@@ -129,6 +129,7 @@ public:
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,
diff --git a/pdf/xpdf/PDFDoc.cc b/pdf/xpdf/PDFDoc.cc
index 9108220..c92048b 100644
--- a/pdf/xpdf/PDFDoc.cc
+++ b/pdf/xpdf/PDFDoc.cc
@@ -114,6 +114,8 @@ PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword,
}
GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) {
+ str->reset();
+
// check header
checkHeader();
@@ -203,7 +205,7 @@ void PDFDoc::checkHeader() {
}
}
-void PDFDoc::displayPage(OutputDev *out, int page, double zoom,
+void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI,
int rotate, GBool doLinks,
GBool (*abortCheckCbk)(void *data),
void *abortCheckCbkData,
@@ -221,18 +223,18 @@ void PDFDoc::displayPage(OutputDev *out, int page, double zoom,
links = NULL;
}
getLinks(p);
- p->display(out, zoom, rotate, links, catalog,
+ p->display(out, hDPI, vDPI, rotate, links, catalog,
abortCheckCbk, abortCheckCbkData,
annotDisplayDecideCbk, annotDisplayDecideCbkData);
} else {
- p->display(out, zoom, rotate, NULL, catalog,
+ p->display(out, hDPI, vDPI, rotate, NULL, catalog,
abortCheckCbk, abortCheckCbkData,
annotDisplayDecideCbk, annotDisplayDecideCbkData);
}
}
void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage,
- int zoom, int rotate, GBool doLinks,
+ double hDPI, double vDPI, int rotate, GBool doLinks,
GBool (*abortCheckCbk)(void *data),
void *abortCheckCbkData,
GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
@@ -240,13 +242,14 @@ void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage,
int page;
for (page = firstPage; page <= lastPage; ++page) {
- displayPage(out, page, zoom, rotate, doLinks,
+ displayPage(out, page, hDPI, vDPI, rotate, doLinks,
abortCheckCbk, abortCheckCbkData,
annotDisplayDecideCbk, annotDisplayDecideCbkData);
}
}
-void PDFDoc::displayPageSlice(OutputDev *out, int page, double zoom,
+void PDFDoc::displayPageSlice(OutputDev *out, int page,
+ double hDPI, double vDPI,
int rotate, int sliceX, int sliceY,
int sliceW, int sliceH,
GBool (*abortCheckCbk)(void *data),
@@ -256,7 +259,7 @@ void PDFDoc::displayPageSlice(OutputDev *out, int page, double zoom,
Page *p;
p = catalog->getPage(page);
- p->displaySlice(out, zoom, rotate, sliceX, sliceY, sliceW, sliceH,
+ p->displaySlice(out, hDPI, vDPI, rotate, sliceX, sliceY, sliceW, sliceH,
NULL, catalog,
abortCheckCbk, abortCheckCbkData,
annotDisplayDecideCbk, annotDisplayDecideCbkData);
diff --git a/pdf/xpdf/PDFDoc.h b/pdf/xpdf/PDFDoc.h
index ea73282..2d060dc 100644
--- a/pdf/xpdf/PDFDoc.h
+++ b/pdf/xpdf/PDFDoc.h
@@ -80,7 +80,7 @@ public:
Object *getStructTreeRoot() { return catalog->getStructTreeRoot(); }
// Display a page.
- void displayPage(OutputDev *out, int page, double zoom,
+ void displayPage(OutputDev *out, int page, double hDPI, double vDPI,
int rotate, GBool doLinks,
GBool (*abortCheckCbk)(void *data) = NULL,
void *abortCheckCbkData = NULL,
@@ -89,14 +89,15 @@ public:
// Display a range of pages.
void displayPages(OutputDev *out, int firstPage, int lastPage,
- int zoom, int rotate, GBool doLinks,
+ double hDPI, double vDPI, int rotate, GBool doLinks,
GBool (*abortCheckCbk)(void *data) = NULL,
void *abortCheckCbkData = NULL,
GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data) = NULL,
void *annotDisplayDecideCbkData = NULL);
// Display part of a page.
- void displayPageSlice(OutputDev *out, int page, double zoom,
+ void displayPageSlice(OutputDev *out, int page,
+ double hDPI, double vDPI,
int rotate, int sliceX, int sliceY,
int sliceW, int sliceH,
GBool (*abortCheckCbk)(void *data) = NULL,
@@ -110,7 +111,8 @@ public:
// If point <x>,<y> is in a link, return the associated action;
// else return NULL.
- LinkAction *findLink(double x, double y) { return links->find(x, y); }
+ LinkAction *findLink(double x, double y)
+ { return links ? links->find(x, y) : (LinkAction *)NULL; }
// Return true if <x>,<y> is in a link.
GBool onLink(double x, double y) { return links->onLink(x, y); }
diff --git a/pdf/xpdf/PSOutputDev.cc b/pdf/xpdf/PSOutputDev.cc
index 7bef193..34d7fdc 100644
--- a/pdf/xpdf/PSOutputDev.cc
+++ b/pdf/xpdf/PSOutputDev.cc
@@ -27,7 +27,6 @@
#include "Gfx.h"
#include "GfxState.h"
#include "GfxFont.h"
-#include "CharCodeToUnicode.h"
#include "UnicodeMap.h"
#include "FontFile.h"
#include "Catalog.h"
@@ -48,7 +47,15 @@
static char *prolog[] = {
"/xpdf 75 dict def xpdf begin",
"% PDF special state",
- "/pdfDictSize 14 def",
+ "/pdfDictSize 15 def",
+ "~1",
+ "/pdfStates 64 array def",
+ " 0 1 63 {",
+ " pdfStates exch pdfDictSize dict",
+ " dup /pdfStateIdx 3 index put",
+ " put",
+ " } for",
+ "~a",
"/pdfSetup {",
" 3 1 roll 2 array astore",
" /setpagedevice where {",
@@ -62,8 +69,19 @@ static char *prolog[] = {
" pop pop",
" } ifelse",
"} def",
+ "~1",
+ "/pdfOpNames [",
+ " /pdfFill /pdfStroke /pdfLastFill /pdfLastStroke",
+ " /pdfTextMat /pdfFontSize /pdfCharSpacing /pdfTextRender",
+ " /pdfTextRise /pdfWordSpacing /pdfHorizScaling /pdfTextClipPath",
+ "] def",
+ "~a",
"/pdfStartPage {",
+ "~1",
+ " pdfStates 0 get begin",
+ "~2",
" pdfDictSize dict begin",
+ "~a",
" /pdfFill [0] def",
" /pdfStroke [0] def",
" /pdfLastFill false def",
@@ -75,6 +93,7 @@ static char *prolog[] = {
" /pdfTextRise 0 def",
" /pdfWordSpacing 0 def",
" /pdfHorizScaling 1 def",
+ " /pdfTextClipPath [] def",
"} def",
"/pdfEndPage { end } def",
"% separation convention operators",
@@ -191,7 +210,16 @@ static char *prolog[] = {
" } ifelse",
"} def",
"% graphics state operators",
+ "~1",
+ "/q {",
+ " gsave",
+ " pdfOpNames length 1 sub -1 0 { pdfOpNames exch get load } for",
+ " pdfStates pdfStateIdx 1 add get begin",
+ " pdfOpNames { exch def } forall",
+ "} def",
+ "~2",
"/q { gsave pdfDictSize dict begin } def",
+ "~a",
"/Q { end grestore } def",
"/cm { concat } def",
"/d { setdash } def",
@@ -248,56 +276,100 @@ static char *prolog[] = {
"/Td { pdfTextMat transform moveto } def",
"/Tm { /pdfTextMat exch def } def",
"% text string operators",
- "/awcp { % awidthcharpath",
+ "/cshow where {",
+ " pop",
+ " /cshow2 {",
+ " dup {",
+ " pop pop",
+ " 1 string dup 0 3 index put 3 index exec",
+ " } exch cshow",
+ " pop pop",
+ " } def",
+ "}{",
+ " /cshow2 {",
+ " currentfont /FontType get 0 eq {",
+ " 0 2 2 index length 1 sub {",
+ " 2 copy get exch 1 add 2 index exch get",
+ " 2 copy exch 256 mul add",
+ " 2 string dup 0 6 5 roll put dup 1 5 4 roll put",
+ " 3 index exec",
+ " } for",
+ " } {",
+ " dup {",
+ " 1 string dup 0 3 index put 3 index exec",
+ " } forall",
+ " } ifelse",
+ " pop pop",
+ " } def",
+ "} ifelse",
+ "/awcp {", // awidthcharpath
" exch {",
- " 1 string dup 0 3 index put 2 index charpath",
- " 3 index 3 index rmoveto",
- " 4 index eq { 5 index 5 index rmoveto } if",
- " } forall",
+ " false charpath",
+ " 5 index 5 index rmoveto",
+ " 6 index eq { 7 index 7 index rmoveto } if",
+ " } exch cshow2",
" 6 {pop} repeat",
"} def",
- "/Tj { fCol", // because stringwidth has to draw Type 3 chars
- " 0 pdfTextRise pdfTextMat dtransform rmoveto",
- " 1 index stringwidth pdfTextMat idtransform pop",
- " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
- " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
- " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
- " pdfTextMat dtransform",
- " 6 5 roll",
- " currentpoint 8 2 roll",
- " pdfTextRender 1 and 0 eq {",
- " 6 copy awidthshow",
- " } if",
- " pdfTextRender 3 and dup 1 eq exch 2 eq or {",
- " 8 6 roll moveto",
- " currentfont /FontType get 3 eq { fCol } { sCol } ifelse",
- " false awcp currentpoint stroke moveto",
- " } {",
- " 8 {pop} repeat",
- " } ifelse",
- " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
- "/Tj16 { pdfTextRender 1 and 0 eq { fCol } { sCol } ifelse",
- " 0 pdfTextRise pdfTextMat dtransform rmoveto",
- " 2 index stringwidth pdfTextMat idtransform pop",
- " sub exch div",
- " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
- " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
- " pdfTextMat dtransform",
- " 6 5 roll awidthshow",
- " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
- "/Tj16V { pdfTextRender 1 and 0 eq { fCol } { sCol } ifelse",
- " 0 pdfTextRise pdfTextMat dtransform rmoveto",
- " 2 index stringwidth pdfTextMat idtransform exch pop",
- " sub exch div",
- " 0 pdfWordSpacing pdfTextMat dtransform 32",
- " 4 3 roll pdfCharSpacing add 0 exch",
- " pdfTextMat dtransform",
- " 6 5 roll awidthshow",
- " 0 pdfTextRise neg pdfTextMat dtransform rmoveto } def",
+ "/Tj {",
+ " fCol", // because stringwidth has to draw Type 3 chars
+ " 1 index stringwidth pdfTextMat idtransform pop",
+ " sub 1 index length dup 0 ne { div } { pop pop 0 } ifelse",
+ " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
+ " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
+ " pdfTextMat dtransform",
+ " 6 5 roll Tj1",
+ "} def",
+ "/Tj16 {",
+ " fCol", // because stringwidth has to draw Type 3 chars
+ " 2 index stringwidth pdfTextMat idtransform pop",
+ " sub exch div",
+ " pdfWordSpacing pdfHorizScaling mul 0 pdfTextMat dtransform 32",
+ " 4 3 roll pdfCharSpacing pdfHorizScaling mul add 0",
+ " pdfTextMat dtransform",
+ " 6 5 roll Tj1",
+ "} def",
+ "/Tj16V {",
+ " fCol", // because stringwidth has to draw Type 3 chars
+ " 2 index stringwidth pdfTextMat idtransform exch pop",
+ " sub exch div",
+ " 0 pdfWordSpacing pdfTextMat dtransform 32",
+ " 4 3 roll pdfCharSpacing add 0 exch",
+ " pdfTextMat dtransform",
+ " 6 5 roll Tj1",
+ "} def",
+ "/Tj1 {",
+ " 0 pdfTextRise pdfTextMat dtransform rmoveto",
+ " currentpoint 8 2 roll",
+ " pdfTextRender 1 and 0 eq {",
+ " 6 copy awidthshow",
+ " } if",
+ " pdfTextRender 3 and dup 1 eq exch 2 eq or {",
+ " 7 index 7 index moveto",
+ " 6 copy",
+ " currentfont /FontType get 3 eq { fCol } { sCol } ifelse",
+ " false awcp currentpoint stroke moveto",
+ " } if",
+ " pdfTextRender 4 and 0 ne {",
+ " 8 6 roll moveto",
+ " false awcp",
+ " /pdfTextClipPath [ pdfTextClipPath aload pop",
+ " {/moveto cvx}",
+ " {/lineto cvx}",
+ " {/curveto cvx}",
+ " {/closepath cvx}",
+ " pathforall ] def",
+ " currentpoint newpath moveto",
+ " } {",
+ " 8 {pop} repeat",
+ " } ifelse",
+ " 0 pdfTextRise neg pdfTextMat dtransform rmoveto",
+ "} def",
"/TJm { pdfFontSize 0.001 mul mul neg 0",
" pdfTextMat dtransform rmoveto } def",
"/TJmV { pdfFontSize 0.001 mul mul neg 0 exch",
" pdfTextMat dtransform rmoveto } def",
+ "/Tclip { pdfTextClipPath cvx exec clip",
+ " /pdfTextClipPath [] def } def",
"% Level 1 image operators",
"/pdfIm1 {",
" /pdfImBuf1 4 index string def",
@@ -500,10 +572,17 @@ static void outputToFile(void *stream, char *data, int len) {
}
PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
- int firstPage, int lastPage, PSOutMode modeA) {
+ int firstPage, int lastPage, PSOutMode modeA,
+ int paperWidthA, int paperHeightA,
+ GBool manualCtrlA) {
FILE *f;
PSFileType fileTypeA;
+ underlayCbk = NULL;
+ underlayCbkData = NULL;
+ overlayCbk = NULL;
+ overlayCbkData = NULL;
+
fontIDs = NULL;
fontFileIDs = NULL;
fontFileNames = NULL;
@@ -511,6 +590,7 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
xobjStack = NULL;
embFontList = NULL;
customColors = NULL;
+ haveTextClip = gFalse;
t3String = NULL;
// open file or pipe
@@ -543,12 +623,15 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
}
init(outputToFile, f, fileTypeA,
- xrefA, catalog, firstPage, lastPage, modeA);
+ xrefA, catalog, firstPage, lastPage, modeA,
+ paperWidthA, paperHeightA, manualCtrlA);
}
PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
XRef *xrefA, Catalog *catalog,
- int firstPage, int lastPage, PSOutMode modeA) {
+ int firstPage, int lastPage, PSOutMode modeA,
+ int paperWidthA, int paperHeightA,
+ GBool manualCtrlA) {
fontIDs = NULL;
fontFileIDs = NULL;
fontFileNames = NULL;
@@ -556,23 +639,20 @@ PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
xobjStack = NULL;
embFontList = NULL;
customColors = NULL;
+ haveTextClip = gFalse;
t3String = NULL;
init(outputFuncA, outputStreamA, psGeneric,
- xrefA, catalog, firstPage, lastPage, modeA);
+ xrefA, catalog, firstPage, lastPage, modeA,
+ paperWidthA, paperHeightA, manualCtrlA);
}
void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
PSFileType fileTypeA, XRef *xrefA, Catalog *catalog,
- int firstPage, int lastPage, PSOutMode modeA) {
+ int firstPage, int lastPage, PSOutMode modeA,
+ int paperWidthA, int paperHeightA,
+ GBool manualCtrlA) {
Page *page;
- PDFRectangle *box;
- Dict *resDict;
- Annots *annots;
- char **p;
- int pg;
- Object obj1, obj2;
- int i;
// initialize
ok = gTrue;
@@ -582,13 +662,20 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
xref = xrefA;
level = globalParams->getPSLevel();
mode = modeA;
- paperWidth = globalParams->getPSPaperWidth();
- paperHeight = globalParams->getPSPaperHeight();
+ paperWidth = paperWidthA;
+ paperHeight = paperHeightA;
+ if (paperWidth == 0) {
+ paperWidth = globalParams->getPSPaperWidth();
+ }
+ if (paperHeight == 0) {
+ paperHeight = globalParams->getPSPaperHeight();
+ }
if (paperWidth < 0 || paperHeight < 0) {
page = catalog->getPage(firstPage);
paperWidth = (int)(page->getWidth() + 0.5);
paperHeight = (int)(page->getHeight() + 0.5);
}
+ manualCtrl = manualCtrlA;
if (mode == psModeForm) {
lastPage = firstPage;
}
@@ -611,14 +698,95 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
fontFileNameSize = 64;
fontFileNameLen = 0;
fontFileNames = (GString **)gmalloc(fontFileNameSize * sizeof(GString *));
+ nextTrueTypeNum = 0;
font16EncLen = 0;
font16EncSize = 0;
+
xobjStack = new GList();
+ numSaves = 0;
// initialize embedded font resource comment list
embFontList = new GString();
- // write header
+ if (!manualCtrl) {
+ writeHeader(firstPage, lastPage, catalog->getPage(firstPage)->getBox());
+ if (mode != psModeForm) {
+ writePS("%%BeginProlog\n");
+ }
+ writeXpdfProcset();
+ if (mode != psModeForm) {
+ writePS("%%EndProlog\n");
+ writePS("%%BeginSetup\n");
+ }
+ writeDocSetup(catalog, firstPage, lastPage);
+ if (mode != psModeForm) {
+ writePS("%%EndSetup\n");
+ }
+ }
+
+ // initialize sequential page number
+ seqPage = 1;
+}
+
+PSOutputDev::~PSOutputDev() {
+ PSOutCustomColor *cc;
+ int i;
+
+ if (ok) {
+ if (!manualCtrl) {
+ writePS("%%Trailer\n");
+ writeTrailer();
+ if (mode != psModeForm) {
+ writePS("%%EOF\n");
+ }
+ }
+ if (fileType == psFile) {
+#ifdef MACOS
+ ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle);
+#endif
+ fclose((FILE *)outputStream);
+ }
+#ifdef HAVE_POPEN
+ else if (fileType == psPipe) {
+ pclose((FILE *)outputStream);
+#ifndef WIN32
+ signal(SIGPIPE, (SignalFunc)SIG_DFL);
+#endif
+ }
+#endif
+ }
+ if (embFontList) {
+ delete embFontList;
+ }
+ if (fontIDs) {
+ gfree(fontIDs);
+ }
+ if (fontFileIDs) {
+ gfree(fontFileIDs);
+ }
+ if (fontFileNames) {
+ for (i = 0; i < fontFileNameLen; ++i) {
+ delete fontFileNames[i];
+ }
+ gfree(fontFileNames);
+ }
+ if (font16Enc) {
+ for (i = 0; i < font16EncLen; ++i) {
+ delete font16Enc[i].enc;
+ }
+ gfree(font16Enc);
+ }
+ if (xobjStack) {
+ delete xobjStack;
+ }
+ while (customColors) {
+ cc = customColors;
+ customColors = cc->next;
+ delete cc;
+ }
+}
+
+void PSOutputDev::writeHeader(int firstPage, int lastPage, PDFRectangle *box) {
switch (mode) {
case psModePS:
writePS("%!PS-Adobe-3.0\n");
@@ -633,6 +801,7 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
writePS("%%DocumentSuppliedResources: (atend)\n");
writePSFmt("%%%%DocumentMedia: plain %d %d 0 () ()\n",
paperWidth, paperHeight);
+ writePSFmt("%%%%BoundingBox: 0 0 %d %d\n", paperWidth, paperHeight);
writePSFmt("%%%%Pages: %d\n", lastPage - firstPage + 1);
writePS("%%EndComments\n");
writePS("%%BeginDefaults\n");
@@ -649,8 +818,6 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
writePS("%%DocumentProcessColors: (atend)\n");
writePS("%%DocumentCustomColors: (atend)\n");
}
- page = catalog->getPage(firstPage);
- box = page->getBox();
writePSFmt("%%%%BoundingBox: %d %d %d %d\n",
(int)floor(box->x1), (int)floor(box->y1),
(int)ceil(box->x2), (int)ceil(box->y2));
@@ -676,8 +843,6 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
}
writePS("%%DocumentSuppliedResources: (atend)\n");
writePS("%%EndComments\n");
- page = catalog->getPage(firstPage);
- box = page->getBox();
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);
@@ -685,31 +850,48 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
writePS("/Matrix [1 0 0 1 0 0] def\n");
break;
}
+}
+
+void PSOutputDev::writeXpdfProcset() {
+ char prologLevel;
+ char **p;
- // write prolog
- if (mode != psModeForm) {
- writePS("%%BeginProlog\n");
- }
writePSFmt("%%%%BeginResource: procset xpdf %s 0\n", xpdfVersion);
+ prologLevel = 'a';
for (p = prolog; *p; ++p) {
- writePSFmt("%s\n", *p);
+ if ((*p)[0] == '~' && (*p)[1] == '1') {
+ prologLevel = '1';
+ } else if ((*p)[0] == '~' && (*p)[1] == '2') {
+ prologLevel = '2';
+ } else if ((*p)[0] == '~' && (*p)[1] == 'a') {
+ prologLevel = 'a';
+ } else if (prologLevel == 'a' ||
+ (prologLevel == '1' && level < psLevel2) ||
+ (prologLevel == '2' && level >= psLevel2)) {
+ writePSFmt("%s\n", *p);
+ }
}
writePS("%%EndResource\n");
+
if (level >= psLevel3) {
for (p = cmapProlog; *p; ++p) {
writePSFmt("%s\n", *p);
}
}
- if (mode != psModeForm) {
- writePS("%%EndProlog\n");
- }
+}
+
+void PSOutputDev::writeDocSetup(Catalog *catalog,
+ int firstPage, int lastPage) {
+ Page *page;
+ Dict *resDict;
+ Annots *annots;
+ Object obj1, obj2;
+ int pg, i;
- // set up fonts and images
if (mode == psModeForm) {
// swap the form and xpdf dicts
writePS("xpdf end begin dup begin\n");
} else {
- writePS("%%BeginSetup\n");
writePS("xpdf begin\n");
}
for (pg = firstPage; pg <= lastPage; ++pg) {
@@ -732,7 +914,7 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
delete annots;
}
if (mode != psModeForm) {
- if (mode != psModeEPS) {
+ if (mode != psModeEPS && !manualCtrl) {
writePSFmt("%d %d %s pdfSetup\n",
paperWidth, paperHeight,
globalParams->getPSDuplex() ? "true" : "false");
@@ -742,97 +924,51 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
writePS("/opiMatrix matrix currentmatrix def\n");
}
#endif
- writePS("%%EndSetup\n");
}
+}
- // initialize sequential page number
- seqPage = 1;
+void PSOutputDev::writePageTrailer() {
+ if (mode != psModeForm) {
+ writePS("pdfEndPage\n");
+ }
}
-PSOutputDev::~PSOutputDev() {
+void PSOutputDev::writeTrailer() {
PSOutCustomColor *cc;
- int i;
- if (ok) {
- if (mode == psModeForm) {
- writePS("/Foo exch /Form defineresource pop\n");
- } else {
- writePS("%%Trailer\n");
- writePS("end\n");
- writePS("%%DocumentSuppliedResources:\n");
- writePS(embFontList->getCString());
- if (level == psLevel1Sep || level == psLevel2Sep ||
- level == psLevel3Sep) {
- writePS("%%DocumentProcessColors:");
- if (processColors & psProcessCyan) {
- writePS(" Cyan");
- }
- if (processColors & psProcessMagenta) {
- writePS(" Magenta");
- }
- if (processColors & psProcessYellow) {
- writePS(" Yellow");
- }
- if (processColors & psProcessBlack) {
- writePS(" Black");
- }
- writePS("\n");
- writePS("%%DocumentCustomColors:");
- for (cc = customColors; cc; cc = cc->next) {
- writePSFmt(" (%s)", cc->name->getCString());
+ if (mode == psModeForm) {
+ writePS("/Foo exch /Form defineresource pop\n");
+ } else {
+ writePS("end\n");
+ writePS("%%DocumentSuppliedResources:\n");
+ writePS(embFontList->getCString());
+ if (level == psLevel1Sep || level == psLevel2Sep ||
+ level == psLevel3Sep) {
+ writePS("%%DocumentProcessColors:");
+ if (processColors & psProcessCyan) {
+ writePS(" Cyan");
}
- writePS("\n");
- writePS("%%CMYKCustomColor:\n");
- for (cc = customColors; cc; cc = cc->next) {
- writePSFmt("%%%%+ %g %g %g %g (%s)\n",
+ if (processColors & psProcessMagenta) {
+ writePS(" Magenta");
+ }
+ if (processColors & psProcessYellow) {
+ writePS(" Yellow");
+ }
+ if (processColors & psProcessBlack) {
+ writePS(" Black");
+ }
+ writePS("\n");
+ writePS("%%DocumentCustomColors:");
+ for (cc = customColors; cc; cc = cc->next) {
+ writePSFmt(" (%s)", cc->name->getCString());
+ }
+ writePS("\n");
+ writePS("%%CMYKCustomColor:\n");
+ for (cc = customColors; cc; cc = cc->next) {
+ writePSFmt("%%%%+ %g %g %g %g (%s)\n",
cc->c, cc->m, cc->y, cc->k, cc->name->getCString());
- }
}
- writePS("%%EOF\n");
- }
- if (fileType == psFile) {
-#ifdef MACOS
- ICS_MapRefNumAndAssign((short)((FILE *)outputStream)->handle);
-#endif
- fclose((FILE *)outputStream);
- }
-#ifdef HAVE_POPEN
- else if (fileType == psPipe) {
- pclose((FILE *)outputStream);
-#ifndef WIN32
- signal(SIGPIPE, (SignalFunc)SIG_DFL);
-#endif
}
-#endif
- }
- if (embFontList) {
- delete embFontList;
- }
- if (fontIDs) {
- gfree(fontIDs);
- }
- if (fontFileIDs) {
- gfree(fontFileIDs);
- }
- if (fontFileNames) {
- for (i = 0; i < fontFileNameLen; ++i) {
- delete fontFileNames[i];
- }
- gfree(fontFileNames);
- }
- if (font16Enc) {
- for (i = 0; i < font16EncLen; ++i) {
- delete font16Enc[i].enc;
- }
- gfree(font16Enc);
- }
- if (xobjStack) {
- delete xobjStack;
- }
- while (customColors) {
- cc = customColors;
- customColors = cc->next;
- delete cc;
}
}
@@ -888,29 +1024,39 @@ void PSOutputDev::setupResources(Dict *resDict) {
}
void PSOutputDev::setupFonts(Dict *resDict) {
- Object fontDict;
+ Object obj1, obj2;
+ Ref r;
GfxFontDict *gfxFontDict;
GfxFont *font;
int i;
- resDict->lookup("Font", &fontDict);
- if (fontDict.isDict()) {
- gfxFontDict = new GfxFontDict(xref, fontDict.getDict());
+ gfxFontDict = NULL;
+ resDict->lookupNF("Font", &obj1);
+ if (obj1.isRef()) {
+ obj1.fetch(xref, &obj2);
+ if (obj2.isDict()) {
+ r = obj1.getRef();
+ gfxFontDict = new GfxFontDict(xref, &r, obj2.getDict());
+ }
+ obj2.free();
+ } else if (obj1.isDict()) {
+ gfxFontDict = new GfxFontDict(xref, NULL, obj1.getDict());
+ }
+ if (gfxFontDict) {
for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
font = gfxFontDict->getFont(i);
setupFont(font, resDict);
}
delete gfxFontDict;
}
- fontDict.free();
+ obj1.free();
}
void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
Ref fontFileID;
GString *name;
PSFontParam *fontParam;
- GString *psNameStr;
- char *psName;
+ GString *psName;
char type3Name[64], buf[16];
GBool subst;
UnicodeMap *uMap;
@@ -937,28 +1083,25 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
fontIDs[fontIDLen++] = *font->getID();
xs = ys = 1;
- psNameStr = NULL;
subst = gFalse;
// check for resident 8-bit font
if (font->getName() &&
(fontParam = globalParams->getPSFont(font->getName()))) {
- psName = fontParam->psFontName->getCString();
+ psName = new GString(fontParam->psFontName->getCString());
// check for embedded Type 1 font
} else if (globalParams->getPSEmbedType1() &&
font->getType() == fontType1 &&
font->getEmbeddedFontID(&fontFileID)) {
- psNameStr = filterPSName(font->getEmbeddedFontName());
- psName = psNameStr->getCString();
+ psName = filterPSName(font->getEmbeddedFontName());
setupEmbeddedType1Font(&fontFileID, psName);
// check for embedded Type 1C font
} else if (globalParams->getPSEmbedType1() &&
font->getType() == fontType1C &&
font->getEmbeddedFontID(&fontFileID)) {
- psNameStr = filterPSName(font->getEmbeddedFontName());
- psName = psNameStr->getCString();
+ psName = filterPSName(font->getEmbeddedFontName());
setupEmbeddedType1CFont(font, &fontFileID, psName);
// check for external Type 1 font file
@@ -966,45 +1109,41 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
font->getType() == fontType1 &&
font->getExtFontFile()) {
// this assumes that the PS font name matches the PDF font name
- psName = font->getName()->getCString();
+ psName = font->getName()->copy();
setupExternalType1Font(font->getExtFontFile(), psName);
// check for embedded TrueType font
} else if (globalParams->getPSEmbedTrueType() &&
font->getType() == fontTrueType &&
font->getEmbeddedFontID(&fontFileID)) {
- psNameStr = filterPSName(font->getEmbeddedFontName());
- psName = psNameStr->getCString();
+ psName = filterPSName(font->getEmbeddedFontName());
setupEmbeddedTrueTypeFont(font, &fontFileID, psName);
// check for external TrueType font file
} else if (globalParams->getPSEmbedTrueType() &&
font->getType() == fontTrueType &&
font->getExtFontFile()) {
- psNameStr = filterPSName(font->getName());
- psName = psNameStr->getCString();
+ psName = filterPSName(font->getName());
setupExternalTrueTypeFont(font, psName);
// check for embedded CID PostScript font
} else if (globalParams->getPSEmbedCIDPostScript() &&
font->getType() == fontCIDType0C &&
font->getEmbeddedFontID(&fontFileID)) {
- psNameStr = filterPSName(font->getEmbeddedFontName());
- psName = psNameStr->getCString();
+ psName = filterPSName(font->getEmbeddedFontName());
setupEmbeddedCIDType0Font(font, &fontFileID, psName);
// check for embedded CID TrueType font
} else if (globalParams->getPSEmbedCIDTrueType() &&
font->getType() == fontCIDType2 &&
font->getEmbeddedFontID(&fontFileID)) {
- psNameStr = filterPSName(font->getEmbeddedFontName());
- psName = psNameStr->getCString();
+ psName = filterPSName(font->getEmbeddedFontName());
setupEmbeddedCIDTrueTypeFont(font, &fontFileID, psName);
} else if (font->getType() == fontType3) {
sprintf(type3Name, "T3_%d_%d",
font->getID()->num, font->getID()->gen);
- psName = type3Name;
+ psName = new GString(type3Name);
setupType3Font(font, psName, parentResDict);
// do 8-bit font substitution
@@ -1015,7 +1154,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
if (name) {
for (i = 0; psFonts[i]; ++i) {
if (name->cmp(psFonts[i]) == 0) {
- psName = psFonts[i];
+ psName = new GString(psFonts[i]);
break;
}
}
@@ -1034,7 +1173,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
if (font->isItalic()) {
i += 1;
}
- psName = psSubstFonts[i].psName;
+ psName = new GString(psSubstFonts[i].psName);
for (code = 0; code < 256; ++code) {
if ((charName = ((Gfx8BitFont *)font)->getCharName(code)) &&
charName[0] == 'm' && charName[1] == '\0') {
@@ -1072,7 +1211,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
((GfxCIDFont *)font)->getCollection(),
font->getWMode()))) {
subst = gTrue;
- psName = fontParam->psFontName->getCString();
+ psName = fontParam->psFontName->copy();
if (font16EncLen >= font16EncSize) {
font16EncSize += 16;
font16Enc = (PSFont16Enc *)grealloc(font16Enc,
@@ -1102,16 +1241,17 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
if (font->isCIDFont()) {
if (level == psLevel3 || level == psLevel3Sep) {
writePSFmt("/F%d_%d /%s %d pdfMakeFont16L3\n",
- font->getID()->num, font->getID()->gen, psName,
+ font->getID()->num, font->getID()->gen, psName->getCString(),
font->getWMode());
} else {
writePSFmt("/F%d_%d /%s %d pdfMakeFont16\n",
- font->getID()->num, font->getID()->gen, psName,
+ font->getID()->num, font->getID()->gen, psName->getCString(),
font->getWMode());
}
} else {
writePSFmt("/F%d_%d /%s %g %g\n",
- font->getID()->num, font->getID()->gen, psName, xs, ys);
+ font->getID()->num, font->getID()->gen, psName->getCString(),
+ xs, ys);
for (i = 0; i < 256; i += 8) {
writePSFmt((i == 0) ? "[ " : " ");
for (j = 0; j < 8; ++j) {
@@ -1136,16 +1276,14 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
writePS("pdfMakeFont\n");
}
- if (psNameStr) {
- delete psNameStr;
- }
+ delete psName;
}
-void PSOutputDev::setupEmbeddedType1Font(Ref *id, char *psName) {
+void PSOutputDev::setupEmbeddedType1Font(Ref *id, GString *psName) {
static char hexChar[17] = "0123456789abcdef";
- Object refObj, strObj, obj1, obj2;
+ Object refObj, strObj, obj1, obj2, obj3;
Dict *dict;
- int length1, length2;
+ int length1, length2, length3;
int c;
int start[4];
GBool binMode;
@@ -1179,21 +1317,25 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, char *psName) {
}
dict->lookup("Length1", &obj1);
dict->lookup("Length2", &obj2);
- if (!obj1.isInt() || !obj2.isInt()) {
+ dict->lookup("Length3", &obj3);
+ if (!obj1.isInt() || !obj2.isInt() || !obj3.isInt()) {
error(-1, "Missing length fields in embedded font stream dictionary");
obj1.free();
obj2.free();
+ obj3.free();
goto err1;
}
length1 = obj1.getInt();
length2 = obj2.getInt();
+ length3 = obj3.getInt();
obj1.free();
obj2.free();
+ obj3.free();
// beginning comment
- writePSFmt("%%%%BeginResource: font %s\n", psName);
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
embFontList->append("%%+ font ");
- embFontList->append(psName);
+ embFontList->append(psName->getCString());
embFontList->append("\n");
// copy ASCII portion of font
@@ -1222,6 +1364,9 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, char *psName) {
writePSChar(hexChar[(start[i] >> 4) & 0x0f]);
writePSChar(hexChar[start[i] & 0x0f]);
}
+ // if Length2 is incorrect (too small), font data gets chopped, so
+ // we take a few extra characters from the trailer just in case
+ length2 += length3 >= 8 ? 8 : length3;
while (i < length2) {
if ((c = strObj.streamGetChar()) == EOF) {
break;
@@ -1266,7 +1411,7 @@ void PSOutputDev::setupEmbeddedType1Font(Ref *id, char *psName) {
//~ This doesn't handle .pfb files or binary eexec data (which only
//~ happens in pfb files?).
-void PSOutputDev::setupExternalType1Font(GString *fileName, char *psName) {
+void PSOutputDev::setupExternalType1Font(GString *fileName, GString *psName) {
FILE *fontFile;
int c;
int i;
@@ -1287,9 +1432,9 @@ void PSOutputDev::setupExternalType1Font(GString *fileName, char *psName) {
fontFileNames[fontFileNameLen++] = fileName->copy();
// beginning comment
- writePSFmt("%%%%BeginResource: font %s\n", psName);
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
embFontList->append("%%+ font ");
- embFontList->append(psName);
+ embFontList->append(psName->getCString());
embFontList->append("\n");
// copy the font file
@@ -1307,7 +1452,7 @@ void PSOutputDev::setupExternalType1Font(GString *fileName, char *psName) {
}
void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
- char *psName) {
+ GString *psName) {
char *fontBuf;
int fontLen;
Type1CFontFile *t1cFile;
@@ -1328,9 +1473,9 @@ void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
fontFileIDs[fontFileIDLen++] = *id;
// beginning comment
- writePSFmt("%%%%BeginResource: font %s\n", psName);
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
embFontList->append("%%+ font ");
- embFontList->append(psName);
+ embFontList->append(psName->getCString());
embFontList->append("\n");
// convert it to a Type 1 font
@@ -1347,42 +1492,49 @@ void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
}
void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
- char *psName) {
+ GString *psName) {
+ char unique[32];
char *fontBuf;
int fontLen;
TrueTypeFontFile *ttFile;
- CharCodeToUnicode *ctu;
+ Gushort *codeToGID;
int i;
// check if font is already embedded
for (i = 0; i < fontFileIDLen; ++i) {
if (fontFileIDs[i].num == id->num &&
- fontFileIDs[i].gen == id->gen)
- return;
+ fontFileIDs[i].gen == id->gen) {
+ sprintf(unique, "_%d", nextTrueTypeNum++);
+ psName->append(unique);
+ break;
+ }
}
// add entry to fontFileIDs list
- if (fontFileIDLen >= fontFileIDSize) {
- fontFileIDSize += 64;
- fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
+ if (i == fontFileIDLen) {
+ if (fontFileIDLen >= fontFileIDSize) {
+ fontFileIDSize += 64;
+ fontFileIDs = (Ref *)grealloc(fontFileIDs, fontFileIDSize * sizeof(Ref));
+ }
+ fontFileIDs[fontFileIDLen++] = *id;
}
- fontFileIDs[fontFileIDLen++] = *id;
// beginning comment
- writePSFmt("%%%%BeginResource: font %s\n", psName);
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
embFontList->append("%%+ font ");
- embFontList->append(psName);
+ embFontList->append(psName->getCString());
embFontList->append("\n");
// convert it to a Type 42 font
fontBuf = font->readEmbFontFile(xref, &fontLen);
ttFile = new TrueTypeFontFile(fontBuf, fontLen);
- ctu = ((Gfx8BitFont *)font)->getToUnicode();
- ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(),
- ctu, ((Gfx8BitFont *)font)->getHasEncoding(),
- ((Gfx8BitFont *)font)->isSymbolic(),
+ codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ttFile);
+ ttFile->convertToType42(psName->getCString(),
+ ((Gfx8BitFont *)font)->getEncoding(),
+ ((Gfx8BitFont *)font)->getHasEncoding(),
+ codeToGID,
outputFunc, outputStream);
- ctu->decRefCnt();
+ gfree(codeToGID);
delete ttFile;
gfree(fontBuf);
@@ -1390,45 +1542,51 @@ void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
writePS("%%EndResource\n");
}
-void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, char *psName) {
+void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, GString *psName) {
+ char unique[32];
GString *fileName;
char *fontBuf;
int fontLen;
TrueTypeFontFile *ttFile;
- CharCodeToUnicode *ctu;
+ Gushort *codeToGID;
int i;
// check if font is already embedded
fileName = font->getExtFontFile();
for (i = 0; i < fontFileNameLen; ++i) {
if (!fontFileNames[i]->cmp(fileName)) {
- return;
+ sprintf(unique, "_%d", nextTrueTypeNum++);
+ psName->append(unique);
+ break;
}
}
// add entry to fontFileNames list
- if (fontFileNameLen >= fontFileNameSize) {
- fontFileNameSize += 64;
- fontFileNames = (GString **)grealloc(fontFileNames,
- fontFileNameSize * sizeof(GString *));
+ if (i == fontFileNameLen) {
+ if (fontFileNameLen >= fontFileNameSize) {
+ fontFileNameSize += 64;
+ fontFileNames =
+ (GString **)grealloc(fontFileNames,
+ fontFileNameSize * sizeof(GString *));
+ }
}
fontFileNames[fontFileNameLen++] = fileName->copy();
// beginning comment
- writePSFmt("%%%%BeginResource: font %s\n", psName);
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
embFontList->append("%%+ font ");
- embFontList->append(psName);
+ embFontList->append(psName->getCString());
embFontList->append("\n");
// convert it to a Type 42 font
fontBuf = font->readExtFontFile(&fontLen);
ttFile = new TrueTypeFontFile(fontBuf, fontLen);
- ctu = ((Gfx8BitFont *)font)->getToUnicode();
- ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(),
- ctu, ((Gfx8BitFont *)font)->getHasEncoding(),
- ((Gfx8BitFont *)font)->isSymbolic(),
+ codeToGID = ((Gfx8BitFont *)font)->getCodeToGIDMap(ttFile);
+ ttFile->convertToType42(psName->getCString(),
+ ((Gfx8BitFont *)font)->getEncoding(),
+ ((Gfx8BitFont *)font)->getHasEncoding(),
+ codeToGID,
outputFunc, outputStream);
- ctu->decRefCnt();
delete ttFile;
gfree(fontBuf);
@@ -1437,7 +1595,7 @@ void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, char *psName) {
}
void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
- char *psName) {
+ GString *psName) {
char *fontBuf;
int fontLen;
Type1CFontFile *t1cFile;
@@ -1458,9 +1616,9 @@ void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
fontFileIDs[fontFileIDLen++] = *id;
// beginning comment
- writePSFmt("%%%%BeginResource: font %s\n", psName);
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
embFontList->append("%%+ font ");
- embFontList->append(psName);
+ embFontList->append(psName->getCString());
embFontList->append("\n");
// convert it to a Type 0 font
@@ -1469,10 +1627,11 @@ void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
if (t1cFile->isOk()) {
if (globalParams->getPSLevel() >= psLevel3) {
// Level 3: use a CID font
- t1cFile->convertToCIDType0(psName, outputFunc, outputStream);
+ t1cFile->convertToCIDType0(psName->getCString(),
+ outputFunc, outputStream);
} else {
// otherwise: use a non-CID composite font
- t1cFile->convertToType0(psName, outputFunc, outputStream);
+ t1cFile->convertToType0(psName->getCString(), outputFunc, outputStream);
}
}
delete t1cFile;
@@ -1483,7 +1642,7 @@ void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
}
void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
- char *psName) {
+ GString *psName) {
char *fontBuf;
int fontLen;
TrueTypeFontFile *ttFile;
@@ -1504,22 +1663,23 @@ void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
fontFileIDs[fontFileIDLen++] = *id;
// beginning comment
- writePSFmt("%%%%BeginResource: font %s\n", psName);
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
embFontList->append("%%+ font ");
- embFontList->append(psName);
+ embFontList->append(psName->getCString());
embFontList->append("\n");
// convert it to a Type 0 font
fontBuf = font->readEmbFontFile(xref, &fontLen);
ttFile = new TrueTypeFontFile(fontBuf, fontLen);
if (globalParams->getPSLevel() >= psLevel3) {
- ttFile->convertToCIDType2(psName,
+ ttFile->convertToCIDType2(psName->getCString(),
((GfxCIDFont *)font)->getCIDToGID(),
((GfxCIDFont *)font)->getCIDToGIDLen(),
outputFunc, outputStream);
} else {
// otherwise: use a non-CID composite font
- ttFile->convertToType0(psName, ((GfxCIDFont *)font)->getCIDToGID(),
+ ttFile->convertToType0(psName->getCString(),
+ ((GfxCIDFont *)font)->getCIDToGID(),
((GfxCIDFont *)font)->getCIDToGIDLen(),
outputFunc, outputStream);
}
@@ -1530,7 +1690,7 @@ void PSOutputDev::setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id,
writePS("%%EndResource\n");
}
-void PSOutputDev::setupType3Font(GfxFont *font, char *psName,
+void PSOutputDev::setupType3Font(GfxFont *font, GString *psName,
Dict *parentResDict) {
Dict *resDict;
Dict *charProcs;
@@ -1543,15 +1703,17 @@ void PSOutputDev::setupType3Font(GfxFont *font, char *psName,
// set up resources used by font
if ((resDict = ((Gfx8BitFont *)font)->getResources())) {
+ inType3Char = gTrue;
setupResources(resDict);
+ inType3Char = gFalse;
} else {
resDict = parentResDict;
}
// beginning comment
- writePSFmt("%%%%BeginResource: font %s\n", psName);
+ writePSFmt("%%%%BeginResource: font %s\n", psName->getCString());
embFontList->append("%%+ font ");
- embFontList->append(psName);
+ embFontList->append(psName->getCString());
embFontList->append("\n");
// font dictionary
@@ -1611,7 +1773,7 @@ void PSOutputDev::setupType3Font(GfxFont *font, char *psName,
writePS("end\n");
}
writePS("currentdict end\n");
- writePSFmt("/%s exch definefont pop\n", psName);
+ writePSFmt("/%s exch definefont pop\n", psName->getCString());
// ending comment
writePS("%%EndResource\n");
@@ -1621,7 +1783,7 @@ void PSOutputDev::setupImages(Dict *resDict) {
Object xObjDict, xObj, xObjRef, subtypeObj;
int i;
- if (mode != psModeForm) {
+ if (!(mode == psModeForm || inType3Char)) {
return;
}
@@ -1690,6 +1852,7 @@ void PSOutputDev::setupImage(Ref id, Stream *str) {
} while (c != '~' && c != EOF);
++size;
writePSFmt("%d array dup /ImData_%d_%d exch def\n", size, id.num, id.gen);
+ str->close();
// write the data into the array
str->reset();
@@ -1732,12 +1895,13 @@ void PSOutputDev::setupImage(Ref id, Stream *str) {
} while (c != '~' && c != EOF);
writePS("~> put\n");
writePS("pop\n");
+ str->close();
delete str;
}
void PSOutputDev::startPage(int pageNum, GfxState *state) {
- int x1, y1, x2, y2, width, height, t;
+ int x1, y1, x2, y2, width, height, paperWidth2, paperHeight2;
switch (mode) {
@@ -1761,9 +1925,8 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
writePS("90 rotate\n");
tx = -x1;
ty = -(y1 + paperWidth);
- t = width;
- width = height;
- height = t;
+ paperWidth2 = paperHeight;
+ paperHeight2 = paperWidth;
} else {
landscape = gFalse;
writePSFmt("%%%%PageOrientation: %s\n",
@@ -1771,19 +1934,21 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
writePS("pdfStartPage\n");
tx = -x1;
ty = -y1;
+ paperWidth2 = paperWidth;
+ paperHeight2 = paperHeight;
}
- if (width < paperWidth) {
- tx += (paperWidth - width) / 2;
+ if (width < paperWidth2) {
+ tx += (paperWidth2 - width) / 2;
}
- if (height < paperHeight) {
- ty += (paperHeight - height) / 2;
+ if (height < paperHeight2) {
+ ty += (paperHeight2 - height) / 2;
}
if (tx != 0 || ty != 0) {
writePSFmt("%g %g translate\n", tx, ty);
}
- if (width > paperWidth || height > paperHeight) {
- xScale = (double)paperWidth / (double)width;
- yScale = (double)paperHeight / (double)height;
+ if (width > paperWidth2 || height > paperHeight2) {
+ xScale = (double)paperWidth2 / (double)width;
+ yScale = (double)paperHeight2 / (double)height;
if (yScale < xScale) {
xScale = yScale;
} else {
@@ -1814,9 +1979,17 @@ void PSOutputDev::startPage(int pageNum, GfxState *state) {
landscape = gFalse;
break;
}
+
+ if (underlayCbk) {
+ (*underlayCbk)(this, underlayCbkData);
+ }
}
void PSOutputDev::endPage() {
+ if (overlayCbk) {
+ (*overlayCbk)(this, overlayCbkData);
+ }
+
if (mode == psModeForm) {
writePS("pdfEndPage\n");
@@ -1824,18 +1997,22 @@ void PSOutputDev::endPage() {
writePS("} def\n");
writePS("end end\n");
} else {
- writePS("showpage\n");
- writePS("%%PageTrailer\n");
- writePS("pdfEndPage\n");
+ if (!manualCtrl) {
+ writePS("showpage\n");
+ writePS("%%PageTrailer\n");
+ writePageTrailer();
+ }
}
}
void PSOutputDev::saveState(GfxState *state) {
writePS("q\n");
+ ++numSaves;
}
void PSOutputDev::restoreState(GfxState *state) {
writePS("Q\n");
+ --numSaves;
}
void PSOutputDev::updateCTM(GfxState *state, double m11, double m12,
@@ -2167,7 +2344,7 @@ void PSOutputDev::drawString(GfxState *state, GString *s) {
int len, nChars, uLen, n, m, i, j;
// check for invisible text -- this is used by Acrobat Capture
- if ((state->getRender() & 3) == 3) {
+ if (state->getRender() == 3) {
return;
}
@@ -2254,6 +2431,17 @@ void PSOutputDev::drawString(GfxState *state, GString *s) {
if (font->isCIDFont()) {
delete s2;
}
+
+ if (state->getRender() & 4) {
+ haveTextClip = gTrue;
+ }
+}
+
+void PSOutputDev::endTextObject(GfxState *state) {
+ if (haveTextClip) {
+ writePS("Tclip\n");
+ haveTextClip = gFalse;
+ }
}
void PSOutputDev::drawImageMask(GfxState *state, Object *ref, Stream *str,
@@ -2486,6 +2674,7 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
} while (c != '~' && c != EOF);
writePS("~>]\n");
writePS("0\n");
+ str->close();
delete str;
} else {
// set up to use the array already created by setupImages()
@@ -2541,7 +2730,8 @@ void PSOutputDev::doImageL2(Object *ref, GfxImageColorMap *colorMap,
// data source
writePS(" /DataSource currentfile\n");
- s = str->getPSFilter(" ");
+ s = str->getPSFilter(level < psLevel2 ? 1 : level < psLevel3 ? 2 : 3,
+ " ");
if (inlineImg || !s) {
useRLE = gTrue;
useASCII = gTrue;
@@ -2818,7 +3008,10 @@ void PSOutputDev::dumpColorSpaceL2(GfxColorSpace *colorSpace) {
writePS("\n");
}
writePS(">]");
+#if 0 //~ this shouldn't be here since the PS file doesn't actually refer
+ //~ to this colorant (it's converted to CMYK instead)
addCustomColor(separationCS);
+#endif
break;
case csDeviceN:
diff --git a/pdf/xpdf/PSOutputDev.h b/pdf/xpdf/PSOutputDev.h
index f7896cc..06130fb 100644
--- a/pdf/xpdf/PSOutputDev.h
+++ b/pdf/xpdf/PSOutputDev.h
@@ -25,6 +25,7 @@ class GfxPath;
class GfxFont;
class GfxColorSpace;
class GfxSeparationColorSpace;
+class PDFRectangle;
struct PSFont16Enc;
class PSOutCustomColor;
@@ -52,12 +53,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 firstPage, int lastPage, PSOutMode modeA,
+ int paperWidthA = 0, int paperHeightA = 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 firstPage, int lastPage, PSOutMode modeA,
+ int paperWidthA = 0, int paperHeightA = 0,
+ GBool manualCtrlA = gFalse);
// Destructor -- writes the trailer and closes the file.
virtual ~PSOutputDev();
@@ -78,6 +83,26 @@ public:
// text in Type 3 fonts will be drawn with drawChar/drawString.
virtual GBool interpretType3Chars() { return gFalse; }
+ //----- header/trailer (used only if manualCtrl is true)
+
+ // Write the document-level header.
+ void writeHeader(int firstPage, int lastPage, PDFRectangle *box);
+
+ // Write the Xpdf procset.
+ void writeXpdfProcset();
+
+ // Write the document-level setup.
+ void writeDocSetup(Catalog *catalog, int firstPage, int lastPage);
+
+ // Write the setup for the current page.
+ void writePageSetup();
+
+ // Write the trailer for the current page.
+ void writePageTrailer();
+
+ // Write the document trailer.
+ void writeTrailer();
+
//----- initialization and control
// Start a page.
@@ -124,6 +149,7 @@ public:
//----- text drawing
virtual void drawString(GfxState *state, GString *s);
+ virtual void endTextObject(GfxState *state);
//----- image drawing
virtual void drawImageMask(GfxState *state, Object *ref, Stream *str,
@@ -147,23 +173,32 @@ public:
//----- PostScript XObjects
virtual void psXObject(Stream *psStream, Stream *level1Stream);
+ //----- miscellaneous
+ void setUnderlayCbk(void (*cbk)(PSOutputDev *psOut, void *data),
+ void *data)
+ { underlayCbk = cbk; underlayCbkData = data; }
+ void setOverlayCbk(void (*cbk)(PSOutputDev *psOut, void *data),
+ void *data)
+ { overlayCbk = cbk; overlayCbkData = data; }
private:
void init(PSOutputFunc outputFuncA, void *outputStreamA,
PSFileType fileTypeA, XRef *xrefA, Catalog *catalog,
- int firstPage, int lastPage, PSOutMode modeA);
+ int firstPage, int lastPage, PSOutMode modeA,
+ int paperWidthA, int paperHeightA,
+ GBool manualCtrlA);
void setupResources(Dict *resDict);
void setupFonts(Dict *resDict);
void setupFont(GfxFont *font, Dict *parentResDict);
- void setupEmbeddedType1Font(Ref *id, char *psName);
- void setupExternalType1Font(GString *fileName, char *psName);
- void setupEmbeddedType1CFont(GfxFont *font, Ref *id, char *psName);
- void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, char *psName);
- void setupExternalTrueTypeFont(GfxFont *font, char *psName);
- void setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, char *psName);
- void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, char *psName);
- void setupType3Font(GfxFont *font, char *psName, Dict *parentResDict);
+ void setupEmbeddedType1Font(Ref *id, GString *psName);
+ void setupExternalType1Font(GString *fileName, GString *psName);
+ void setupEmbeddedType1CFont(GfxFont *font, Ref *id, GString *psName);
+ void setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id, GString *psName);
+ void setupExternalTrueTypeFont(GfxFont *font, GString *psName);
+ void setupEmbeddedCIDType0Font(GfxFont *font, Ref *id, GString *psName);
+ void setupEmbeddedCIDTrueTypeFont(GfxFont *font, Ref *id, GString *psName);
+ void setupType3Font(GfxFont *font, GString *psName, Dict *parentResDict);
void setupImages(Dict *resDict);
void setupImage(Ref id, Stream *str);
void addProcessColor(double c, double m, double y, double k);
@@ -201,7 +236,12 @@ private:
PSOutputFunc outputFunc;
void *outputStream;
PSFileType fileType; // file / pipe / stdout
+ GBool manualCtrl;
int seqPage; // current sequential page number
+ void (*underlayCbk)(PSOutputDev *psOut, void *data);
+ void *underlayCbkData;
+ void (*overlayCbk)(PSOutputDev *psOut, void *data);
+ void *overlayCbkData;
XRef *xref; // the xref table for this PDF file
@@ -214,11 +254,14 @@ private:
GString **fontFileNames; // list of names of all embedded external fonts
int fontFileNameLen; // number of entries in fontFileNames array
int fontFileNameSize; // size of fontFileNames array
+ int nextTrueTypeNum; // next unique number to append to a TrueType
+ // font name
PSFont16Enc *font16Enc; // encodings for substitute 16-bit fonts
int font16EncLen; // number of entries in font16Enc array
int font16EncSize; // size of font16Enc array
GList *xobjStack; // stack of XObject dicts currently being
// processed
+ int numSaves; // current number of gsaves
double tx, ty; // global translation
double xScale, yScale; // global scaling
@@ -230,6 +273,9 @@ private:
PSOutCustomColor // used custom colors
*customColors;
+ GBool haveTextClip; // set if text has been drawn with a
+ // clipping render mode
+
GBool inType3Char; // inside a Type 3 CharProc
GString *t3String; // Type 3 content string
double t3WX, t3WY, // Type 3 character parameters
@@ -243,6 +289,8 @@ private:
GBool ok; // set up ok?
+
+ friend class WinPDFPrinter;
};
#endif
diff --git a/pdf/xpdf/Page.cc b/pdf/xpdf/Page.cc
index c7a1e13..e12e65c 100644
--- a/pdf/xpdf/Page.cc
+++ b/pdf/xpdf/Page.cc
@@ -59,8 +59,12 @@ PageAttrs::PageAttrs(PageAttrs *attrs, Dict *dict) {
readBox(dict, "MediaBox", &mediaBox);
// crop box
- cropBox = mediaBox;
- haveCropBox = readBox(dict, "CropBox", &cropBox);
+ if (readBox(dict, "CropBox", &cropBox)) {
+ haveCropBox = gTrue;
+ }
+ if (!haveCropBox) {
+ cropBox = mediaBox;
+ }
// if the MediaBox is excessively larger than the CropBox,
// just use the CropBox
@@ -222,18 +226,18 @@ Page::~Page() {
contents.free();
}
-void Page::display(OutputDev *out, double dpi, int rotate,
+void Page::display(OutputDev *out, double hDPI, double vDPI, int rotate,
Links *links, Catalog *catalog,
GBool (*abortCheckCbk)(void *data),
void *abortCheckCbkData,
GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data),
void *annotDisplayDecideCbkData) {
- displaySlice(out, dpi, rotate, -1, -1, -1, -1, links, catalog,
+ displaySlice(out, hDPI, vDPI, rotate, -1, -1, -1, -1, links, catalog,
abortCheckCbk, abortCheckCbkData,
annotDisplayDecideCbk, annotDisplayDecideCbkData);
}
-void Page::displaySlice(OutputDev *out, double dpi, int rotate,
+void Page::displaySlice(OutputDev *out, double hDPI, double vDPI, int rotate,
int sliceX, int sliceY, int sliceW, int sliceH,
Links *links, Catalog *catalog,
GBool (*abortCheckCbk)(void *data),
@@ -247,7 +251,7 @@ void Page::displaySlice(OutputDev *out, double dpi, int rotate,
Object obj;
Link *link;
Annots *annotList;
- double k;
+ double kx, ky;
int i;
rotate += getRotate();
@@ -259,46 +263,47 @@ void Page::displaySlice(OutputDev *out, double dpi, int rotate,
mediaBox = getBox();
if (sliceW >= 0 && sliceH >= 0) {
- k = 72.0 / dpi;
+ kx = 72.0 / hDPI;
+ ky = 72.0 / vDPI;
if (rotate == 90) {
if (out->upsideDown()) {
- box.x1 = mediaBox->x1 + k * sliceY;
- box.x2 = mediaBox->x1 + k * (sliceY + sliceH);
+ box.x1 = mediaBox->x1 + ky * sliceY;
+ box.x2 = mediaBox->x1 + ky * (sliceY + sliceH);
} else {
- box.x1 = mediaBox->x2 - k * (sliceY + sliceH);
- box.x2 = mediaBox->x2 - k * sliceY;
+ box.x1 = mediaBox->x2 - ky * (sliceY + sliceH);
+ box.x2 = mediaBox->x2 - ky * sliceY;
}
- box.y1 = mediaBox->y1 + k * sliceX;
- box.y2 = mediaBox->y1 + k * (sliceX + sliceW);
+ box.y1 = mediaBox->y1 + kx * sliceX;
+ box.y2 = mediaBox->y1 + kx * (sliceX + sliceW);
} else if (rotate == 180) {
- box.x1 = mediaBox->x2 - k * (sliceX + sliceW);
- box.x2 = mediaBox->x2 - k * sliceX;
+ box.x1 = mediaBox->x2 - kx * (sliceX + sliceW);
+ box.x2 = mediaBox->x2 - kx * sliceX;
if (out->upsideDown()) {
- box.y1 = mediaBox->y1 + k * sliceY;
- box.y2 = mediaBox->y1 + k * (sliceY + sliceH);
+ box.y1 = mediaBox->y1 + ky * sliceY;
+ box.y2 = mediaBox->y1 + ky * (sliceY + sliceH);
} else {
- box.y1 = mediaBox->y2 - k * (sliceY + sliceH);
- box.y2 = mediaBox->y2 - k * sliceY;
+ box.y1 = mediaBox->y2 - ky * (sliceY + sliceH);
+ box.y2 = mediaBox->y2 - ky * sliceY;
}
} else if (rotate == 270) {
if (out->upsideDown()) {
- box.x1 = mediaBox->x2 - k * (sliceY + sliceH);
- box.x2 = mediaBox->x2 - k * sliceY;
+ box.x1 = mediaBox->x2 - ky * (sliceY + sliceH);
+ box.x2 = mediaBox->x2 - ky * sliceY;
} else {
- box.x1 = mediaBox->x1 + k * sliceY;
- box.x2 = mediaBox->x1 + k * (sliceY + sliceH);
+ box.x1 = mediaBox->x1 + ky * sliceY;
+ box.x2 = mediaBox->x1 + ky * (sliceY + sliceH);
}
- box.y1 = mediaBox->y2 - k * (sliceX + sliceW);
- box.y2 = mediaBox->y2 - k * sliceX;
+ box.y1 = mediaBox->y2 - kx * (sliceX + sliceW);
+ box.y2 = mediaBox->y2 - kx * sliceX;
} else {
- box.x1 = mediaBox->x1 + k * sliceX;
- box.x2 = mediaBox->x1 + k * (sliceX + sliceW);
+ box.x1 = mediaBox->x1 + kx * sliceX;
+ box.x2 = mediaBox->x1 + kx * (sliceX + sliceW);
if (out->upsideDown()) {
- box.y1 = mediaBox->y2 - k * (sliceY + sliceH);
- box.y2 = mediaBox->y2 - k * sliceY;
+ box.y1 = mediaBox->y2 - ky * (sliceY + sliceH);
+ box.y2 = mediaBox->y2 - ky * sliceY;
} else {
- box.y1 = mediaBox->y1 + k * sliceY;
- box.y2 = mediaBox->y1 + k * (sliceY + sliceH);
+ box.y1 = mediaBox->y1 + ky * sliceY;
+ box.y2 = mediaBox->y1 + ky * (sliceY + sliceH);
}
}
} else {
@@ -317,25 +322,28 @@ void Page::displaySlice(OutputDev *out, double dpi, int rotate,
}
gfx = new Gfx(xref, out, num, attrs->getResourceDict(),
- dpi, &box, isCropped(), cropBox, rotate,
+ hDPI, vDPI, &box, isCropped(), cropBox, rotate,
abortCheckCbk, abortCheckCbkData);
contents.fetch(xref, &obj);
if (!obj.isNull()) {
+ gfx->saveState();
gfx->display(&obj);
+ gfx->restoreState();
}
obj.free();
// draw links
if (links) {
+ gfx->saveState();
for (i = 0; i < links->getNumLinks(); ++i) {
link = links->getLink(i);
out->drawLink(link, catalog);
}
+ gfx->restoreState();
out->dump();
}
// draw non-link annotations
- //~ need to reset CTM ???
annotList = new Annots(xref, annots.fetch(xref, &obj));
obj.free();
#ifdef USE_ANNOTS_VIEW
diff --git a/pdf/xpdf/Page.h b/pdf/xpdf/Page.h
index 8b339eb..8fa1ef6 100644
--- a/pdf/xpdf/Page.h
+++ b/pdf/xpdf/Page.h
@@ -146,7 +146,7 @@ public:
Object *getThumb(Object *obj) { return thumb.fetch(xref, obj); }
// Display a page.
- void display(OutputDev *out, double dpi, int rotate,
+ void display(OutputDev *out, double hDPI, double vDPI, int rotate,
Links *links, Catalog *catalog,
GBool (*abortCheckCbk)(void *data) = NULL,
void *abortCheckCbkData = NULL,
@@ -154,7 +154,7 @@ public:
void *annotDisplayDecideCbkData = NULL);
// Display part of a page.
- void displaySlice(OutputDev *out, double dpi, int rotate,
+ void displaySlice(OutputDev *out, double hDPI, double vDPI, int rotate,
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 deb894a..2f881d4 100644
--- a/pdf/xpdf/Parser.cc
+++ b/pdf/xpdf/Parser.cc
@@ -180,6 +180,12 @@ Stream *Parser::makeStream(Object *dict) {
length = endPos - pos;
}
+ // in badly damaged PDF files, we can run off the end of the input
+ // stream immediately after the "stream" token
+ if (!lexer->getStream()) {
+ return NULL;
+ }
+
// make base stream
str = lexer->getStream()->getBaseStream()->makeSubStream(pos, gTrue,
length, dict);
@@ -193,10 +199,12 @@ Stream *Parser::makeStream(Object *dict) {
// refill token buffers and check for 'endstream'
shift(); // kill '>>'
shift(); // kill 'stream'
- if (buf1.isCmd("endstream"))
+ if (buf1.isCmd("endstream")) {
shift();
- else
+ } else {
error(getPos(), "Missing 'endstream'");
+ str->ignoreLength();
+ }
return str;
}
diff --git a/pdf/xpdf/Stream.cc b/pdf/xpdf/Stream.cc
index 11b51b6..e770b61 100644
--- a/pdf/xpdf/Stream.cc
+++ b/pdf/xpdf/Stream.cc
@@ -84,7 +84,7 @@ char *Stream::getLine(char *buf, int size) {
return buf;
}
-GString *Stream::getPSFilter(char *indent) {
+GString *Stream::getPSFilter(int psLevel, char *indent) {
return new GString();
}
@@ -696,13 +696,14 @@ void FileStream::moveStart(int delta) {
// MemStream
//------------------------------------------------------------------------
-MemStream::MemStream(char *bufA, Guint lengthA, Object *dictA):
+MemStream::MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA):
BaseStream(dictA) {
buf = bufA;
- needFree = gFalse;
+ start = startA;
length = lengthA;
- bufEnd = buf + length;
- bufPtr = buf;
+ bufEnd = buf + start + length;
+ bufPtr = buf + start;
+ needFree = gFalse;
}
MemStream::~MemStream() {
@@ -711,20 +712,22 @@ MemStream::~MemStream() {
}
}
-Stream *MemStream::makeSubStream(Guint start, GBool limited,
+Stream *MemStream::makeSubStream(Guint startA, GBool limited,
Guint lengthA, Object *dictA) {
+ MemStream *subStr;
Guint newLength;
- if (!limited || start + lengthA > length) {
- newLength = length - start;
+ if (!limited || startA + lengthA > start + length) {
+ newLength = start + length - startA;
} else {
newLength = lengthA;
}
- return new MemStream(buf + start, newLength, dictA);
+ subStr = new MemStream(buf, startA, newLength, dictA);
+ return subStr;
}
void MemStream::reset() {
- bufPtr = buf;
+ bufPtr = buf + start;
#ifndef NO_DECRYPTION
if (decrypt) {
decrypt->reset();
@@ -736,24 +739,24 @@ void MemStream::close() {
}
void MemStream::setPos(Guint pos, int dir) {
+ Guint i;
+
if (dir >= 0) {
- if (pos > length) {
- bufPtr = bufEnd;
- } else {
- bufPtr = buf + pos;
- }
+ i = pos;
} else {
- if (pos > length) {
- bufPtr = buf;
- } else {
- bufPtr = bufEnd - pos;
- }
+ i = start + length - pos;
}
+ if (i < start) {
+ i = start;
+ } else if (i > start + length) {
+ i = start + length;
+ }
+ bufPtr = buf + i;
}
void MemStream::moveStart(int delta) {
- buf += delta;
- bufPtr = buf;
+ start += delta;
+ bufPtr = buf + start;
}
#ifndef NO_DECRYPTION
@@ -764,12 +767,13 @@ void MemStream::doDecryption(Guchar *fileKey, int keyLength,
this->BaseStream::doDecryption(fileKey, keyLength, objNum, objGen);
if (decrypt) {
- newBuf = (char *)gmalloc(bufEnd - buf);
- for (p = buf, q = newBuf; p < bufEnd; ++p, ++q) {
+ newBuf = (char *)gmalloc(length);
+ for (p = buf + start, q = newBuf; p < bufEnd; ++p, ++q) {
*q = (char)decrypt->decryptByte((Guchar)*p);
}
- bufEnd = newBuf + (bufEnd - buf);
- bufPtr = newBuf + (bufPtr - buf);
+ bufEnd = newBuf + length;
+ bufPtr = newBuf + (bufPtr - (buf + start));
+ start = 0;
buf = newBuf;
needFree = gTrue;
}
@@ -880,10 +884,13 @@ int ASCIIHexStream::lookChar() {
return buf;
}
-GString *ASCIIHexStream::getPSFilter(char *indent) {
+GString *ASCIIHexStream::getPSFilter(int psLevel, char *indent) {
GString *s;
- if (!(s = str->getPSFilter(indent))) {
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
return NULL;
}
s->append(indent)->append("/ASCIIHexDecode filter\n");
@@ -958,10 +965,13 @@ int ASCII85Stream::lookChar() {
return b[index];
}
-GString *ASCII85Stream::getPSFilter(char *indent) {
+GString *ASCII85Stream::getPSFilter(int psLevel, char *indent) {
GString *s;
- if (!(s = str->getPSFilter(indent))) {
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
return NULL;
}
s->append(indent)->append("/ASCII85Decode filter\n");
@@ -1137,13 +1147,13 @@ int LZWStream::getCode() {
return code;
}
-GString *LZWStream::getPSFilter(char *indent) {
+GString *LZWStream::getPSFilter(int psLevel, char *indent) {
GString *s;
- if (pred) {
+ if (psLevel < 2 || pred) {
return NULL;
}
- if (!(s = str->getPSFilter(indent))) {
+ if (!(s = str->getPSFilter(psLevel, indent))) {
return NULL;
}
s->append(indent)->append("/LZWDecode filter\n");
@@ -1174,10 +1184,13 @@ void RunLengthStream::reset() {
eof = gFalse;
}
-GString *RunLengthStream::getPSFilter(char *indent) {
+GString *RunLengthStream::getPSFilter(int psLevel, char *indent) {
GString *s;
- if (!(s = str->getPSFilter(indent))) {
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
return NULL;
}
s->append(indent)->append("/RunLengthDecode filter\n");
@@ -1334,12 +1347,14 @@ int CCITTFaxStream::lookChar() {
code2 += code3 = getWhiteCode();
} while (code3 >= 64);
}
- codingLine[a0 + 1] = a0New + code1;
- ++a0;
- a0New = codingLine[a0 + 1] = codingLine[a0] + code2;
- ++a0;
- while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
- b1 += 2;
+ if (code1 > 0 || code2 > 0) {
+ codingLine[a0 + 1] = a0New + code1;
+ ++a0;
+ a0New = codingLine[a0 + 1] = codingLine[a0] + code2;
+ ++a0;
+ while (refLine[b1] <= codingLine[a0] && refLine[b1] < columns)
+ b1 += 2;
+ }
break;
case twoDimVert0:
a0New = codingLine[++a0] = refLine[b1];
@@ -1504,7 +1519,7 @@ int CCITTFaxStream::lookChar() {
return EOF;
}
eatBits(1);
- code1 = look13Bits();
+ code1 = lookBits(13);
} while ((code1 >> 1) != 0x001);
eatBits(12);
codingLine[++a0] = columns;
@@ -1724,11 +1739,14 @@ short CCITTFaxStream::lookBits(int n) {
return (inputBuf >> (inputBits - n)) & (0xffff >> (16 - n));
}
-GString *CCITTFaxStream::getPSFilter(char *indent) {
+GString *CCITTFaxStream::getPSFilter(int psLevel, char *indent) {
GString *s;
char s1[50];
- if (!(s = str->getPSFilter(indent))) {
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
return NULL;
}
s->append(indent)->append("<< ");
@@ -1864,6 +1882,7 @@ void DCTStream::reset() {
numDCHuffTables = 0;
numACHuffTables = 0;
colorXform = 0;
+ gotJFIFMarker = gFalse;
gotAdobeMarker = gFalse;
restartInterval = 0;
@@ -1894,7 +1913,12 @@ void DCTStream::reset() {
// figure out color transform
if (!gotAdobeMarker && numComps == 3) {
- if (compInfo[0].id == 1 && compInfo[1].id == 2 && compInfo[2].id == 3) {
+ if (gotJFIFMarker) {
+ colorXform = 1;
+ } else if (compInfo[0].id == 82 && compInfo[1].id == 71 &&
+ compInfo[2].id == 66) { // ASCII "RGB"
+ colorXform = 0;
+ } else {
colorXform = 1;
}
}
@@ -2142,7 +2166,7 @@ GBool DCTStream::readMCURow() {
void DCTStream::readScan() {
int data[64];
int x1, y1, dx1, dy1, x2, y2, y3, cc, i;
- int h, v, horiz, vert, hSub, vSub;
+ int h, v, horiz, vert, vSub;
int *p1;
int c;
@@ -2185,7 +2209,6 @@ void DCTStream::readScan() {
v = compInfo[cc].vSample;
horiz = mcuWidth / h;
vert = mcuHeight / v;
- hSub = horiz / 8;
vSub = vert / 8;
for (y2 = 0; y2 < dy1; y2 += vert) {
for (x2 = 0; x2 < dx1; x2 += horiz) {
@@ -2810,7 +2833,6 @@ GBool DCTStream::readHeader() {
break;
case 0xd9: // EOI
return gFalse;
- break;
case 0xda: // SOS
if (!readScanInfo()) {
return gFalse;
@@ -2827,6 +2849,11 @@ GBool DCTStream::readHeader() {
return gFalse;
}
break;
+ case 0xe0: // APP0
+ if (!readJFIFMarker()) {
+ return gFalse;
+ }
+ break;
case 0xee: // APP14
if (!readAdobeMarker()) {
return gFalse;
@@ -2923,14 +2950,21 @@ GBool DCTStream::readScanInfo() {
}
for (i = 0; i < scanInfo.numComps; ++i) {
id = str->getChar();
- for (j = 0; j < numComps; ++j) {
- if (id == compInfo[j].id) {
- break;
+ // some (broken) DCT streams reuse ID numbers, but at least they
+ // keep the components in order, so we check compInfo[i] first to
+ // work around the problem
+ if (id == compInfo[i].id) {
+ j = i;
+ } else {
+ for (j = 0; j < numComps; ++j) {
+ if (id == compInfo[j].id) {
+ break;
+ }
+ }
+ if (j == numComps) {
+ error(getPos(), "Bad DCT component ID in scan info block");
+ return gFalse;
}
- }
- if (j == numComps) {
- error(getPos(), "Bad DCT component ID in scan info block");
- return gFalse;
}
scanInfo.comp[j] = gTrue;
c = str->getChar();
@@ -3023,6 +3057,36 @@ GBool DCTStream::readRestartInterval() {
return gTrue;
}
+GBool DCTStream::readJFIFMarker() {
+ int length, i;
+ char buf[5];
+ int c;
+
+ length = read16();
+ length -= 2;
+ if (length >= 5) {
+ for (i = 0; i < 5; ++i) {
+ if ((c = str->getChar()) == EOF) {
+ error(getPos(), "Bad DCT APP0 marker");
+ return gFalse;
+ }
+ buf[i] = c;
+ }
+ length -= 5;
+ if (!memcmp(buf, "JFIF\0", 5)) {
+ gotJFIFMarker = gTrue;
+ }
+ }
+ while (length > 0) {
+ if (str->getChar() == EOF) {
+ error(getPos(), "Bad DCT APP0 marker");
+ return gFalse;
+ }
+ --length;
+ }
+ return gTrue;
+}
+
GBool DCTStream::readAdobeMarker() {
int length, i;
char buf[12];
@@ -3090,10 +3154,13 @@ int DCTStream::read16() {
return (c1 << 8) + c2;
}
-GString *DCTStream::getPSFilter(char *indent) {
+GString *DCTStream::getPSFilter(int psLevel, char *indent) {
GString *s;
- if (!(s = str->getPSFilter(indent))) {
+ if (psLevel < 2) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
return NULL;
}
s->append(indent)->append("<< >> /DCTDecode filter\n");
@@ -3280,8 +3347,17 @@ int FlateStream::getRawChar() {
return c;
}
-GString *FlateStream::getPSFilter(char *indent) {
- return NULL;
+GString *FlateStream::getPSFilter(int psLevel, char *indent) {
+ GString *s;
+
+ if (psLevel < 3 || pred) {
+ return NULL;
+ }
+ if (!(s = str->getPSFilter(psLevel, indent))) {
+ return NULL;
+ }
+ s->append(indent)->append("<< >> /FlateDecode filter\n");
+ return s;
}
GBool FlateStream::isBinary(GBool last) {
@@ -3658,9 +3734,6 @@ void FixedLengthEncoder::reset() {
count = 0;
}
-void FixedLengthEncoder::close() {
-}
-
int FixedLengthEncoder::getChar() {
if (length >= 0 && count >= length)
return EOF;
@@ -3698,9 +3771,6 @@ void ASCIIHexEncoder::reset() {
eof = gFalse;
}
-void ASCIIHexEncoder::close() {
-}
-
GBool ASCIIHexEncoder::fillBuf() {
static char *hex = "0123456789abcdef";
int c;
@@ -3747,9 +3817,6 @@ void ASCII85Encoder::reset() {
eof = gFalse;
}
-void ASCII85Encoder::close() {
-}
-
GBool ASCII85Encoder::fillBuf() {
Gulong t;
char buf1[5];
@@ -3817,9 +3884,6 @@ void RunLengthEncoder::reset() {
eof = gFalse;
}
-void RunLengthEncoder::close() {
-}
-
//
// When fillBuf finishes, buf[] looks like this:
// +-----+--------------+-----------------+--
diff --git a/pdf/xpdf/Stream.h b/pdf/xpdf/Stream.h
index 31c0a97..0121df1 100644
--- a/pdf/xpdf/Stream.h
+++ b/pdf/xpdf/Stream.h
@@ -87,7 +87,7 @@ public:
virtual void setPos(Guint pos, int dir = 0) = 0;
// Get PostScript command for the filter(s).
- virtual GString *getPSFilter(char *indent);
+ virtual GString *getPSFilter(int psLevel, char *indent);
// Does this stream type potentially contain non-printable chars?
virtual GBool isBinary(GBool last = gTrue) = 0;
@@ -105,6 +105,11 @@ public:
// Returns the new stream.
Stream *addFilters(Object *dict);
+ // Tell this stream to ignore any length limitation -- this only
+ // applies to BaseStream subclasses, and is used as a hack to work
+ // around broken PDF files with incorrect stream lengths.
+ virtual void ignoreLength() {}
+
private:
Stream *makeFilter(char *name, Stream *str, Object *params);
@@ -166,6 +171,7 @@ public:
virtual void setPos(Guint pos, int dir = 0);
virtual BaseStream *getBaseStream() { return str->getBaseStream(); }
virtual Dict *getDict() { return str->getDict(); }
+ virtual void ignoreLength() { str->ignoreLength(); }
protected:
@@ -268,6 +274,7 @@ public:
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);
@@ -294,7 +301,7 @@ private:
class MemStream: public BaseStream {
public:
- MemStream(char *bufA, Guint lengthA, Object *dictA);
+ MemStream(char *bufA, Guint startA, Guint lengthA, Object *dictA);
virtual ~MemStream();
virtual Stream *makeSubStream(Guint start, GBool limited,
Guint lengthA, Object *dictA);
@@ -305,10 +312,10 @@ public:
{ return (bufPtr < bufEnd) ? (*bufPtr++ & 0xff) : EOF; }
virtual int lookChar()
{ return (bufPtr < bufEnd) ? (*bufPtr & 0xff) : EOF; }
- virtual int getPos() { return bufPtr - buf; }
+ 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 0; }
+ virtual Guint getStart() { return start; }
virtual void moveStart(int delta);
#ifndef NO_DECRYPTION
virtual void doDecryption(Guchar *fileKey, int keyLength,
@@ -318,10 +325,11 @@ public:
private:
char *buf;
+ Guint start;
Guint length;
- GBool needFree;
char *bufEnd;
char *bufPtr;
+ GBool needFree;
};
//------------------------------------------------------------------------
@@ -370,7 +378,7 @@ public:
virtual int getChar()
{ int c = lookChar(); buf = EOF; return c; }
virtual int lookChar();
- virtual GString *getPSFilter(char *indent);
+ virtual GString *getPSFilter(int psLevel, char *indent);
virtual GBool isBinary(GBool last = gTrue);
private:
@@ -393,7 +401,7 @@ public:
virtual int getChar()
{ int ch = lookChar(); ++index; return ch; }
virtual int lookChar();
- virtual GString *getPSFilter(char *indent);
+ virtual GString *getPSFilter(int psLevel, char *indent);
virtual GBool isBinary(GBool last = gTrue);
private:
@@ -419,7 +427,7 @@ public:
virtual int getChar();
virtual int lookChar();
virtual int getRawChar();
- virtual GString *getPSFilter(char *indent);
+ virtual GString *getPSFilter(int psLevel, char *indent);
virtual GBool isBinary(GBool last = gTrue);
private:
@@ -463,7 +471,7 @@ public:
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
virtual int lookChar()
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
- virtual GString *getPSFilter(char *indent);
+ virtual GString *getPSFilter(int psLevel, char *indent);
virtual GBool isBinary(GBool last = gTrue);
private:
@@ -494,7 +502,7 @@ public:
virtual int getChar()
{ int c = lookChar(); buf = EOF; return c; }
virtual int lookChar();
- virtual GString *getPSFilter(char *indent);
+ virtual GString *getPSFilter(int psLevel, char *indent);
virtual GBool isBinary(GBool last = gTrue);
private:
@@ -564,7 +572,7 @@ public:
virtual void reset();
virtual int getChar();
virtual int lookChar();
- virtual GString *getPSFilter(char *indent);
+ virtual GString *getPSFilter(int psLevel, char *indent);
virtual GBool isBinary(GBool last = gTrue);
Stream *getRawStream() { return str; }
@@ -579,6 +587,7 @@ private:
DCTScanInfo scanInfo; // info for the current scan
int numComps; // number of components in image
int colorXform; // need YCbCr-to-RGB transform?
+ GBool gotJFIFMarker; // set if APP0 JFIF marker was present
GBool gotAdobeMarker; // set if APP14 Adobe marker was present
int restartInterval; // restart interval, in MCUs
Guchar quantTables[4][64]; // quantization tables
@@ -618,6 +627,7 @@ private:
GBool readQuantTables();
GBool readHuffmanTables();
GBool readRestartInterval();
+ GBool readJFIFMarker();
GBool readAdobeMarker();
GBool readTrailer();
int readMarker();
@@ -663,7 +673,7 @@ public:
virtual int getChar();
virtual int lookChar();
virtual int getRawChar();
- virtual GString *getPSFilter(char *indent);
+ virtual GString *getPSFilter(int psLevel, char *indent);
virtual GBool isBinary(GBool last = gTrue);
private:
@@ -712,7 +722,7 @@ public:
virtual void reset() {}
virtual int getChar() { return EOF; }
virtual int lookChar() { return EOF; }
- virtual GString *getPSFilter(char *indent) { return NULL; }
+ virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; }
virtual GBool isBinary(GBool last = gTrue) { return gFalse; }
};
@@ -727,10 +737,9 @@ public:
~FixedLengthEncoder();
virtual StreamKind getKind() { return strWeird; }
virtual void reset();
- virtual void close();
virtual int getChar();
virtual int lookChar();
- virtual GString *getPSFilter(char *indent) { return NULL; }
+ virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; }
virtual GBool isBinary(GBool last = gTrue) { return gFalse; }
virtual GBool isEncoder() { return gTrue; }
@@ -751,12 +760,11 @@ public:
virtual ~ASCIIHexEncoder();
virtual StreamKind getKind() { return strWeird; }
virtual void reset();
- virtual void close();
virtual int getChar()
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
virtual int lookChar()
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
- virtual GString *getPSFilter(char *indent) { return NULL; }
+ virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; }
virtual GBool isBinary(GBool last = gTrue) { return gFalse; }
virtual GBool isEncoder() { return gTrue; }
@@ -782,12 +790,11 @@ public:
virtual ~ASCII85Encoder();
virtual StreamKind getKind() { return strWeird; }
virtual void reset();
- virtual void close();
virtual int getChar()
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
virtual int lookChar()
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
- virtual GString *getPSFilter(char *indent) { return NULL; }
+ virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; }
virtual GBool isBinary(GBool last = gTrue) { return gFalse; }
virtual GBool isEncoder() { return gTrue; }
@@ -813,12 +820,11 @@ public:
virtual ~RunLengthEncoder();
virtual StreamKind getKind() { return strWeird; }
virtual void reset();
- virtual void close();
virtual int getChar()
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr++ & 0xff); }
virtual int lookChar()
{ return (bufPtr >= bufEnd && !fillBuf()) ? EOF : (*bufPtr & 0xff); }
- virtual GString *getPSFilter(char *indent) { return NULL; }
+ virtual GString *getPSFilter(int psLevel, char *indent) { return NULL; }
virtual GBool isBinary(GBool last = gTrue) { return gFalse; }
virtual GBool isEncoder() { return gTrue; }
diff --git a/pdf/xpdf/TTFont.cc b/pdf/xpdf/TTFont.cc
index fc6d849..c499cf1 100644
--- a/pdf/xpdf/TTFont.cc
+++ b/pdf/xpdf/TTFont.cc
@@ -65,16 +65,25 @@ TTFontFile::TTFontFile(TTFontEngine *engineA, char *fontFileName,
// 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 TrueType font has a Microsoft Unicode cmap, use it,
- // and use the Unicode indexes, not the char codes.
- // 1b. If the TrueType font has a Macintosh Roman cmap, use it,
- // and reverse map the char names through MacRomanEncoding to
+ // 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.
+ // 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 (0xf000 + char code).
+ // 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;
@@ -91,7 +100,6 @@ TTFontFile::TTFontFile(TTFontEngine *engineA, char *fontFileName,
}
i = 0;
mode = ttFontModeCharCode;
- charMapOffset = 0;
if (pdfFontHasEncoding) {
if (unicodeCmap != 0xffff) {
i = unicodeCmap;
@@ -114,8 +122,7 @@ TTFontFile::TTFontFile(TTFontEngine *engineA, char *fontFileName,
mode = ttFontModeCharCode;
} else if (msSymbolCmap != 0xffff) {
i = msSymbolCmap;
- mode = ttFontModeCharCodeOffset;
- charMapOffset = 0xf000;
+ mode = ttFontModeCharCode;
}
}
TT_Get_CharMap(face, i, &charMap);
@@ -421,11 +428,9 @@ GBool TTFont::getGlyphPixmap(CharCode c, Unicode u) {
idx = TT_Char_Index(fontFile->charMap, (TT_UShort)u);
break;
case ttFontModeCharCode:
- idx = TT_Char_Index(fontFile->charMap, (TT_UShort)c);
- break;
- case ttFontModeCharCodeOffset:
- idx = TT_Char_Index(fontFile->charMap,
- (TT_UShort)(c + fontFile->charMapOffset));
+ 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) {
diff --git a/pdf/xpdf/TTFont.h b/pdf/xpdf/TTFont.h
index 96208e2..e4740ea 100644
--- a/pdf/xpdf/TTFont.h
+++ b/pdf/xpdf/TTFont.h
@@ -55,7 +55,6 @@ private:
enum TTFontIndexMode {
ttFontModeUnicode,
ttFontModeCharCode,
- ttFontModeCharCodeOffset,
ttFontModeCodeMap,
ttFontModeCIDToGIDMap
};
@@ -80,7 +79,6 @@ private:
TT_Face face;
TT_CharMap charMap;
TTFontIndexMode mode;
- int charMapOffset;
Guchar *codeMap;
Gushort *cidToGID;
int cidToGIDLen;
diff --git a/pdf/xpdf/TextOutputDev.cc b/pdf/xpdf/TextOutputDev.cc
index 4e9a63a..aeee59c 100644
--- a/pdf/xpdf/TextOutputDev.cc
+++ b/pdf/xpdf/TextOutputDev.cc
@@ -28,6 +28,7 @@
#include "Error.h"
#include "GlobalParams.h"
#include "UnicodeMap.h"
+#include "UnicodeTypeTable.h"
#include "GfxState.h"
#include "TextOutputDev.h"
@@ -40,176 +41,187 @@
// parameters
//------------------------------------------------------------------------
-// Minium and maximum inter-word spacing (as a fraction of the average
-// character width).
-#define wordMinSpaceWidth 0.3
-#define wordMaxSpaceWidth 2.0
-
-// Default min and max inter-word spacing (when the average character
-// width is unknown).
-#define wordDefMinSpaceWidth 0.2
-#define wordDefMaxSpaceWidth 1.5
-
-// Max difference in x,y coordinates (as a fraction of the font size)
-// allowed for duplicated text (fake boldface, drop shadows) which is
-// to be discarded.
-#define dupMaxDeltaX 0.1
-#define dupMaxDeltaY 0.2
-
-// Min overlap (as a fraction of the font size) required for two
-// lines to be considered vertically overlapping.
-#define lineOverlapSlack 0.5
-
-// Max difference in baseline y coordinates (as a fraction of the font
-// size) allowed for words which are to be grouped into a line, not
-// including sub/superscripts.
-#define lineMaxBaselineDelta 0.1
-
-// Max ratio of font sizes allowed for words which are to be grouped
-// into a line, not including sub/superscripts.
-#define lineMaxFontSizeRatio 1.4
-
-// Min spacing (as a fraction of the font size) allowed between words
-// which are to be grouped into a line.
-#define lineMinDeltaX -0.5
-
-// Minimum vertical overlap (as a fraction of the font size) required
-// for superscript and subscript words.
-#define lineMinSuperscriptOverlap 0.3
-#define lineMinSubscriptOverlap 0.3
-
-// Min/max ratio of font sizes allowed for sub/superscripts compared to
-// the base text.
-#define lineMinSubscriptFontSizeRatio 0.4
-#define lineMaxSubscriptFontSizeRatio 1.01
-#define lineMinSuperscriptFontSizeRatio 0.4
-#define lineMaxSuperscriptFontSizeRatio 1.01
-
-// Max horizontal spacing (as a fraction of the font size) allowed
-// before sub/superscripts.
-#define lineMaxSubscriptDeltaX 0.2
-#define lineMaxSuperscriptDeltaX 0.2
-
-// Maximum vertical spacing (as a fraction of the font size) allowed
-// for lines which are to be grouped into a block.
-#define blkMaxSpacing 2.0
-
-// Max ratio of primary font sizes allowed for lines which are to be
-// grouped into a block.
-#define blkMaxFontSizeRatio 1.3
-
-// Min overlap (as a fraction of the font size) required for two
-// blocks to be considered vertically overlapping.
-#define blkOverlapSlack 0.5
-
-// Max vertical spacing (as a fraction of the font size) allowed
-// between blocks which are 'adjacent' when sorted by reading order.
-#define blkMaxSortSpacing 2.0
-
-// Max vertical offset (as a fraction of the font size) of the top and
-// bottom edges allowed for blocks which are to be grouped into a
-// flow.
-#define flowMaxDeltaY 1.0
+// Each bucket in a text pool includes baselines within a range of
+// this many points.
+#define textPoolStep 4
+
+// Inter-character space width which will cause addChar to break up a
+// text string.
+#define defaultSpaceWidth 0.25
+
+// Max distance between baselines of two lines within a block, as a
+// fraction of the font size.
+#define maxLineSpacingDelta 1.5
+
+// Max difference in primary font sizes on two lines in the same
+// block. Delta1 is used when examining new lines above and below the
+// current block; delta2 is used when examining text that overlaps the
+// current block; delta3 is used when examining text to the left and
+// right of the current block.
+#define maxBlockFontSizeDelta1 0.05
+#define maxBlockFontSizeDelta2 0.6
+#define maxBlockFontSizeDelta3 0.2
+
+// Max difference in font sizes inside a word.
+#define maxWordFontSizeDelta 0.05
+
+// Maximum distance between baselines of two words on the same line,
+// e.g., distance between subscript or superscript and the primary
+// baseline, as a fraction of the font size.
+#define maxIntraLineDelta 0.5
+
+// Minimum inter-word spacing, as a fraction of the font size. (Only
+// used for raw ordering.)
+#define minWordSpacing 0.2
+
+// Maximum inter-word spacing, as a fraction of the font size.
+#define maxWordSpacing 1.5
+
+// Minimum spacing between columns, as a fraction of the font size.
+#define minColSpacing 1.0
+
+// Maximum vertical spacing between blocks within a flow, as a
+// multiple of the font size.
+#define maxBlockSpacing 2.5
+
+// Minimum spacing between characters within a word, as a fraction of
+// the font size.
+#define minCharSpacing -0.2
+
+// Maximum spacing between characters within a word, as a fraction of
+// the font size, when there is no obvious extra-wide character
+// spacing.
+#define maxCharSpacing 0.03
+
+// When extra-wide character spacing is detected, the inter-character
+// space threshold is set to the minimum inter-character space
+// multiplied by this constant.
+#define maxWideCharSpacingMul 1.3
+
+// Max difference in primary,secondary coordinates (as a fraction of
+// the font size) allowed for duplicated text (fake boldface, drop
+// shadows) which is to be discarded.
+#define dupMaxPriDelta 0.1
+#define dupMaxSecDelta 0.2
//------------------------------------------------------------------------
// TextFontInfo
//------------------------------------------------------------------------
TextFontInfo::TextFontInfo(GfxState *state) {
- double *textMat;
- double t1, t2, avgWidth, w;
- int n, i;
-
gfxFont = state->getFont();
- textMat = state->getTextMat();
- horizScaling = state->getHorizScaling();
- if ((t1 = fabs(textMat[0])) > 0.01 &&
- (t2 = fabs(textMat[3])) > 0.01) {
- horizScaling *= t1 / t2;
- }
-
- minSpaceWidth = horizScaling * wordDefMinSpaceWidth;
- maxSpaceWidth = horizScaling * wordDefMaxSpaceWidth;
- if (gfxFont && gfxFont->isCIDFont()) {
- //~ handle 16-bit fonts
- } else if (gfxFont && gfxFont->getType() != fontType3) {
- avgWidth = 0;
- n = 0;
- for (i = 0; i < 256; ++i) {
- w = ((Gfx8BitFont *)gfxFont)->getWidth(i);
- if (w > 0) {
- avgWidth += w;
- ++n;
- }
- }
- if (n > 0) {
- avgWidth /= n;
- minSpaceWidth = horizScaling * wordMinSpaceWidth * avgWidth;
- maxSpaceWidth = horizScaling * wordMaxSpaceWidth * avgWidth;
- }
- }
-
+#if TEXTOUT_WORD_LIST
+ fontName = (gfxFont && gfxFont->getOrigName())
+ ? gfxFont->getOrigName()->copy()
+ : (GString *)NULL;
+#endif
}
TextFontInfo::~TextFontInfo() {
+#if TEXTOUT_WORD_LIST
+ if (fontName) {
+ delete fontName;
+ }
+#endif
}
GBool TextFontInfo::matches(GfxState *state) {
- double *textMat;
- double t1, t2, h;
-
- textMat = state->getTextMat();
- h = state->getHorizScaling();
- if ((t1 = fabs(textMat[0])) > 0.01 &&
- (t2 = fabs(textMat[3])) > 0.01) {
- h *= t1 / t2;
- }
- return state->getFont() == gfxFont &&
- fabs(h - horizScaling) < 0.01;
+ return state->getFont() == gfxFont;
}
//------------------------------------------------------------------------
// TextWord
//------------------------------------------------------------------------
-TextWord::TextWord(GfxState *state, double x0, double y0, int charPosA,
- TextFontInfo *fontA, double fontSizeA) {
+TextWord::TextWord(GfxState *state, int rotA, double x0, double y0,
+ int charPosA, TextFontInfo *fontA, double fontSizeA) {
GfxFont *gfxFont;
- double x, y;
+ double x, y, ascent, descent;
+ rot = rotA;
charPos = charPosA;
charLen = 0;
font = fontA;
fontSize = fontSizeA;
state->transform(x0, y0, &x, &y);
if ((gfxFont = font->gfxFont)) {
- yMin = y - gfxFont->getAscent() * fontSize;
- yMax = y - gfxFont->getDescent() * fontSize;
+ ascent = gfxFont->getAscent() * fontSize;
+ descent = gfxFont->getDescent() * fontSize;
} else {
// this means that the PDF file draws text without a current font,
// which should never happen
- yMin = y - 0.95 * fontSize;
- yMax = y + 0.35 * fontSize;
- }
- if (yMin == yMax) {
- // this is a sanity check for a case that shouldn't happen -- but
- // if it does happen, we want to avoid dividing by zero later
- yMin = y;
- yMax = y + 1;
+ ascent = 0.95 * fontSize;
+ descent = -0.35 * fontSize;
+ }
+ switch (rot) {
+ case 0:
+ yMin = y - ascent;
+ yMax = y - descent;
+ if (yMin == yMax) {
+ // this is a sanity check for a case that shouldn't happen -- but
+ // if it does happen, we want to avoid dividing by zero later
+ yMin = y;
+ yMax = y + 1;
+ }
+ base = y;
+ break;
+ case 1:
+ xMin = x + descent;
+ xMax = x + ascent;
+ if (xMin == xMax) {
+ // this is a sanity check for a case that shouldn't happen -- but
+ // if it does happen, we want to avoid dividing by zero later
+ xMin = x;
+ xMax = x + 1;
+ }
+ base = x;
+ break;
+ case 2:
+ yMin = y + descent;
+ yMax = y + ascent;
+ if (yMin == yMax) {
+ // this is a sanity check for a case that shouldn't happen -- but
+ // if it does happen, we want to avoid dividing by zero later
+ yMin = y;
+ yMax = y + 1;
+ }
+ base = y;
+ break;
+ case 3:
+ xMin = x - ascent;
+ xMax = x - descent;
+ if (xMin == xMax) {
+ // this is a sanity check for a case that shouldn't happen -- but
+ // if it does happen, we want to avoid dividing by zero later
+ xMin = x;
+ xMax = x + 1;
+ }
+ base = x;
+ break;
}
- yBase = y;
text = NULL;
- xRight = NULL;
+ edge = NULL;
len = size = 0;
spaceAfter = gFalse;
next = NULL;
-}
+#if TEXTOUT_WORD_LIST
+ GfxRGB rgb;
+ if ((state->getRender() & 3) == 1) {
+ state->getStrokeRGB(&rgb);
+ } else {
+ state->getFillRGB(&rgb);
+ }
+ colorR = rgb.r;
+ colorG = rgb.g;
+ colorB = rgb.b;
+#endif
+}
TextWord::~TextWord() {
gfree(text);
- gfree(xRight);
+ gfree(edge);
}
void TextWord::addChar(GfxState *state, double x, double y,
@@ -217,234 +229,1450 @@ void TextWord::addChar(GfxState *state, double x, double y,
if (len == size) {
size += 16;
text = (Unicode *)grealloc(text, size * sizeof(Unicode));
- xRight = (double *)grealloc(xRight, size * sizeof(double));
+ edge = (double *)grealloc(edge, (size + 1) * sizeof(double));
}
text[len] = u;
- if (len == 0) {
- xMin = x;
+ switch (rot) {
+ case 0:
+ if (len == 0) {
+ xMin = x;
+ }
+ edge[len] = x;
+ xMax = edge[len+1] = x + dx;
+ break;
+ case 1:
+ if (len == 0) {
+ yMin = y;
+ }
+ edge[len] = y;
+ yMax = edge[len+1] = y + dy;
+ break;
+ case 2:
+ if (len == 0) {
+ xMax = x;
+ }
+ edge[len] = x;
+ xMin = edge[len+1] = x + dx;
+ break;
+ case 3:
+ if (len == 0) {
+ yMax = y;
+ }
+ edge[len] = y;
+ yMin = edge[len+1] = y + dy;
+ break;
}
- xMax = xRight[len] = x + dx;
++len;
}
-// Returns true if <this> comes before <word2> in xy order.
-GBool TextWord::xyBefore(TextWord *word2) {
- return xMin < word2->xMin ||
- (xMin == word2->xMin && yMin < word2->yMin);
-}
-
-// Merge another word onto the end of this one.
-void TextWord::merge(TextWord *word2) {
+void TextWord::merge(TextWord *word) {
int i;
- xMax = word2->xMax;
- if (word2->yMin < yMin) {
- yMin = word2->yMin;
+ if (word->xMin < xMin) {
+ xMin = word->xMin;
+ }
+ if (word->yMin < yMin) {
+ yMin = word->yMin;
}
- if (word2->yMax > yMax) {
- yMax = word2->yMax;
+ if (word->xMax > xMax) {
+ xMax = word->xMax;
}
- if (len + word2->len > size) {
- size = len + word2->len;
+ if (word->yMax > yMax) {
+ yMax = word->yMax;
+ }
+ if (len + word->len > size) {
+ size = len + word->len;
text = (Unicode *)grealloc(text, size * sizeof(Unicode));
- xRight = (double *)grealloc(xRight, size * sizeof(double));
+ edge = (double *)grealloc(edge, (size + 1) * sizeof(double));
+ }
+ for (i = 0; i < word->len; ++i) {
+ text[len + i] = word->text[i];
+ edge[len + i] = word->edge[i];
+ }
+ edge[len + word->len] = word->edge[word->len];
+ len += word->len;
+ charLen += word->charLen;
+}
+
+inline int TextWord::primaryCmp(TextWord *word) {
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ cmp = xMin - word->xMin;
+ break;
+ case 1:
+ cmp = yMin - word->yMin;
+ break;
+ case 2:
+ cmp = word->xMax - xMax;
+ break;
+ case 3:
+ cmp = word->yMax - yMax;
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+double TextWord::primaryDelta(TextWord *word) {
+ double delta;
+
+ delta = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ delta = word->xMin - xMax;
+ break;
+ case 1:
+ delta = word->yMin - yMax;
+ break;
+ case 2:
+ delta = xMin - word->xMax;
+ break;
+ case 3:
+ delta = yMin - word->yMax;
+ break;
+ }
+ return delta;
+}
+
+int TextWord::cmpYX(const void *p1, const void *p2) {
+ TextWord *word1 = *(TextWord **)p1;
+ TextWord *word2 = *(TextWord **)p2;
+ double cmp;
+
+ cmp = word1->yMin - word2->yMin;
+ if (cmp == 0) {
+ cmp = word1->xMin - word2->xMin;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+#if TEXTOUT_WORD_LIST
+
+GString *TextWord::getText() {
+ GString *s;
+ UnicodeMap *uMap;
+ char buf[8];
+ int n, i;
+
+ s = new GString();
+ if (!(uMap = globalParams->getTextEncoding())) {
+ return s;
}
- for (i = 0; i < word2->len; ++i) {
- text[len + i] = word2->text[i];
- xRight[len + i] = word2->xRight[i];
+ for (i = 0; i < len; ++i) {
+ n = uMap->mapUnicode(text[i], buf, sizeof(buf));
+ s->append(buf, n);
}
- len += word2->len;
- charLen += word2->charLen;
+ uMap->decRefCnt();
+ return s;
+}
+
+#endif // TEXTOUT_WORD_LIST
+
+//------------------------------------------------------------------------
+// TextPool
+//------------------------------------------------------------------------
+
+TextPool::TextPool() {
+ minBaseIdx = 0;
+ maxBaseIdx = -1;
+ pool = NULL;
+ cursor = NULL;
+ cursorBaseIdx = -1;
+}
+
+TextPool::~TextPool() {
+ int baseIdx;
+ TextWord *word, *word2;
+
+ for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) {
+ for (word = pool[baseIdx - minBaseIdx]; word; word = word2) {
+ word2 = word->next;
+ delete word;
+ }
+ }
+ gfree(pool);
+}
+
+int TextPool::getBaseIdx(double base) {
+ int baseIdx;
+
+ baseIdx = (int)(base / textPoolStep);
+ if (baseIdx < minBaseIdx) {
+ return minBaseIdx;
+ }
+ if (baseIdx > maxBaseIdx) {
+ return maxBaseIdx;
+ }
+ return baseIdx;
+}
+
+void TextPool::addWord(TextWord *word) {
+ TextWord **newPool;
+ int wordBaseIdx, newMinBaseIdx, newMaxBaseIdx, baseIdx;
+ TextWord *w0, *w1;
+
+ // expand the array if needed
+ wordBaseIdx = (int)(word->base / textPoolStep);
+ if (minBaseIdx > maxBaseIdx) {
+ minBaseIdx = wordBaseIdx - 128;
+ maxBaseIdx = wordBaseIdx + 128;
+ pool = (TextWord **)gmalloc((maxBaseIdx - minBaseIdx + 1) *
+ sizeof(TextWord *));
+ for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) {
+ pool[baseIdx - minBaseIdx] = NULL;
+ }
+ } else if (wordBaseIdx < minBaseIdx) {
+ newMinBaseIdx = wordBaseIdx - 128;
+ newPool = (TextWord **)gmalloc((maxBaseIdx - newMinBaseIdx + 1) *
+ sizeof(TextWord *));
+ for (baseIdx = newMinBaseIdx; baseIdx < minBaseIdx; ++baseIdx) {
+ newPool[baseIdx - newMinBaseIdx] = NULL;
+ }
+ memcpy(&newPool[minBaseIdx - newMinBaseIdx], pool,
+ (maxBaseIdx - minBaseIdx + 1) * sizeof(TextWord *));
+ gfree(pool);
+ pool = newPool;
+ minBaseIdx = newMinBaseIdx;
+ } else if (wordBaseIdx > maxBaseIdx) {
+ newMaxBaseIdx = wordBaseIdx + 128;
+ pool = (TextWord **)grealloc(pool, (newMaxBaseIdx - minBaseIdx + 1) *
+ sizeof(TextWord *));
+ for (baseIdx = maxBaseIdx + 1; baseIdx <= newMaxBaseIdx; ++baseIdx) {
+ pool[baseIdx - minBaseIdx] = NULL;
+ }
+ maxBaseIdx = newMaxBaseIdx;
+ }
+
+ // insert the new word
+ if (cursor && wordBaseIdx == cursorBaseIdx &&
+ word->primaryCmp(cursor) > 0) {
+ w0 = cursor;
+ w1 = cursor->next;
+ } else {
+ w0 = NULL;
+ w1 = pool[wordBaseIdx - minBaseIdx];
+ }
+ for (; w1 && word->primaryCmp(w1) > 0; w0 = w1, w1 = w1->next) ;
+ word->next = w1;
+ if (w0) {
+ w0->next = word;
+ } else {
+ pool[wordBaseIdx - minBaseIdx] = word;
+ }
+ cursor = word;
+ cursorBaseIdx = wordBaseIdx;
}
//------------------------------------------------------------------------
// TextLine
//------------------------------------------------------------------------
-TextLine::TextLine() {
- words = NULL;
+TextLine::TextLine(TextBlock *blkA, int rotA, double baseA) {
+ blk = blkA;
+ rot = rotA;
+ xMin = yMin = 0;
+ xMax = yMax = -1;
+ base = baseA;
+ words = lastWord = NULL;
text = NULL;
- xRight = NULL;
+ edge = NULL;
col = NULL;
len = 0;
+ convertedLen = 0;
hyphenated = gFalse;
- pageNext = NULL;
next = NULL;
- flowNext = NULL;
}
TextLine::~TextLine() {
- TextWord *w1, *w2;
+ TextWord *word;
- for (w1 = words; w1; w1 = w2) {
- w2 = w1->next;
- delete w1;
+ while (words) {
+ word = words;
+ words = words->next;
+ delete word;
}
gfree(text);
- gfree(xRight);
+ gfree(edge);
gfree(col);
}
-// Returns true if <this> comes before <line2> in yx order, allowing
-// slack for vertically overlapping lines.
-GBool TextLine::yxBefore(TextLine *line2) {
- double dy;
+void TextLine::addWord(TextWord *word) {
+ if (lastWord) {
+ lastWord->next = word;
+ } else {
+ words = word;
+ }
+ lastWord = word;
+
+ if (xMin > xMax) {
+ xMin = word->xMin;
+ xMax = word->xMax;
+ yMin = word->yMin;
+ yMax = word->yMax;
+ } else {
+ if (word->xMin < xMin) {
+ xMin = word->xMin;
+ }
+ if (word->xMax > xMax) {
+ xMax = word->xMax;
+ }
+ if (word->yMin < yMin) {
+ yMin = word->yMin;
+ }
+ if (word->yMax > yMax) {
+ yMax = word->yMax;
+ }
+ }
+}
+
+double TextLine::primaryDelta(TextLine *line) {
+ double delta;
+
+ delta = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ delta = line->xMin - xMax;
+ break;
+ case 1:
+ delta = line->yMin - yMax;
+ break;
+ case 2:
+ delta = xMin - line->xMax;
+ break;
+ case 3:
+ delta = yMin - line->yMax;
+ break;
+ }
+ return delta;
+}
+
+int TextLine::primaryCmp(TextLine *line) {
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ cmp = xMin - line->xMin;
+ break;
+ case 1:
+ cmp = yMin - line->yMin;
+ break;
+ case 2:
+ cmp = line->xMax - xMax;
+ break;
+ case 3:
+ cmp = line->yMax - yMax;
+ break;
+ }
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextLine::secondaryCmp(TextLine *line) {
+ double cmp;
+
+ cmp = (rot == 0 || rot == 3) ? base - line->base : line->base - base;
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
- dy = lineOverlapSlack * fontSize;
+int TextLine::cmpYX(TextLine *line) {
+ int cmp;
- // non-overlapping case
- if (line2->yMin > yMax - dy ||
- line2->yMax < yMin + dy) {
- return yMin < line2->yMin ||
- (yMin == line2->yMin && xMin < line2->xMin);
+ if ((cmp = secondaryCmp(line))) {
+ return cmp;
}
+ return primaryCmp(line);
+}
+
+int TextLine::cmpXY(const void *p1, const void *p2) {
+ TextLine *line1 = *(TextLine **)p1;
+ TextLine *line2 = *(TextLine **)p2;
+ int cmp;
+
+ if ((cmp = line1->primaryCmp(line2))) {
+ return cmp;
+ }
+ return line1->secondaryCmp(line2);
+}
+
+void TextLine::coalesce(UnicodeMap *uMap) {
+ TextWord *word0, *word1;
+ double space, delta, minSpace;
+ GBool isUnicode;
+ char buf[8];
+ int i, j;
+
+ if (words->next) {
+
+ // compute the inter-word space threshold
+ if (words->len > 1 || words->next->len > 1) {
+ minSpace = 0;
+ } else {
+ minSpace = words->primaryDelta(words->next);
+ for (word0 = words->next, word1 = word0->next;
+ word1 && minSpace > 0;
+ word0 = word1, word1 = word0->next) {
+ if (word1->len > 1) {
+ minSpace = 0;
+ }
+ delta = word0->primaryDelta(word1);
+ if (delta < minSpace) {
+ minSpace = delta;
+ }
+ }
+ }
+ if (minSpace <= 0) {
+ space = maxCharSpacing * words->fontSize;
+ } else {
+ space = maxWideCharSpacingMul * minSpace;
+ }
+
+ // merge words
+ word0 = words;
+ word1 = words->next;
+ while (word1) {
+ if (word0->primaryDelta(word1) >= space) {
+ word0->spaceAfter = gTrue;
+ word0 = word1;
+ word1 = word1->next;
+ } else if (word0->font == word1->font &&
+ fabs(word0->fontSize - word1->fontSize) <
+ maxWordFontSizeDelta * words->fontSize &&
+ word1->charPos == word0->charPos + word0->charLen) {
+ word0->merge(word1);
+ word0->next = word1->next;
+ delete word1;
+ word1 = word0->next;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
+ }
+ }
+
+ // build the line text
+ isUnicode = uMap ? uMap->isUnicode() : gFalse;
+ len = 0;
+ for (word1 = words; word1; word1 = word1->next) {
+ len += word1->len;
+ if (word1->spaceAfter) {
+ ++len;
+ }
+ }
+ text = (Unicode *)gmalloc(len * sizeof(Unicode));
+ edge = (double *)gmalloc((len + 1) * sizeof(double));
+ i = 0;
+ for (word1 = words; word1; word1 = word1->next) {
+ for (j = 0; j < word1->len; ++j) {
+ text[i] = word1->text[j];
+ edge[i] = word1->edge[j];
+ ++i;
+ }
+ edge[i] = word1->edge[word1->len];
+ if (word1->spaceAfter) {
+ text[i] = (Unicode)0x0020;
+ ++i;
+ }
+ }
+
+ // compute convertedLen and set up the col array
+ col = (int *)gmalloc((len + 1) * sizeof(int));
+ convertedLen = 0;
+ for (i = 0; i < len; ++i) {
+ col[i] = convertedLen;
+ if (isUnicode) {
+ ++convertedLen;
+ } else if (uMap) {
+ convertedLen += uMap->mapUnicode(text[i], buf, sizeof(buf));
+ }
+ }
+ col[len] = convertedLen;
+
+ // check for hyphen at end of line
+ //~ need to check for other chars used as hyphens
+ hyphenated = text[len - 1] == (Unicode)'-';
+}
+
+//------------------------------------------------------------------------
+// TextLineFrag
+//------------------------------------------------------------------------
+
+class TextLineFrag {
+public:
+
+ TextLine *line; // the line object
+ int start, len; // offset and length of this fragment
+ // (in Unicode chars)
+ double xMin, xMax; // bounding box coordinates
+ double yMin, yMax;
+ double base; // baseline virtual coordinate
+ int col; // first column
+
+ void init(TextLine *lineA, int startA, int lenA);
+ void computeCoords(GBool oneRot);
+
+ static int cmpYXPrimaryRot(const void *p1, const void *p2);
+ static int cmpYXLineRot(const void *p1, const void *p2);
+ static int cmpXYLineRot(const void *p1, const void *p2);
+};
+
+void TextLineFrag::init(TextLine *lineA, int startA, int lenA) {
+ line = lineA;
+ start = startA;
+ len = lenA;
+ col = line->col[start];
+}
+
+void TextLineFrag::computeCoords(GBool oneRot) {
+ TextBlock *blk;
+ double d0, d1, d2, d3, d4;
+
+ if (oneRot) {
+
+ switch (line->rot) {
+ case 0:
+ xMin = line->edge[start];
+ xMax = line->edge[start + len];
+ yMin = line->yMin;
+ yMax = line->yMax;
+ break;
+ case 1:
+ xMin = line->xMin;
+ xMax = line->xMax;
+ yMin = line->edge[start];
+ yMax = line->edge[start + len];
+ break;
+ case 2:
+ xMin = line->edge[start + len];
+ xMax = line->edge[start];
+ yMin = line->yMin;
+ yMax = line->yMax;
+ break;
+ case 3:
+ xMin = line->xMin;
+ xMax = line->xMax;
+ yMin = line->edge[start + len];
+ yMax = line->edge[start];
+ break;
+ }
+ base = line->base;
+
+ } else {
+
+ if (line->rot == 0 && line->blk->page->primaryRot == 0) {
+
+ xMin = line->edge[start];
+ xMax = line->edge[start + len];
+ yMin = line->yMin;
+ yMax = line->yMax;
+ base = line->base;
+
+ } else {
+
+ blk = line->blk;
+ d0 = line->edge[start];
+ d1 = line->edge[start + len];
+ d2 = d3 = d4 = 0; // make gcc happy
+
+ switch (line->rot) {
+ case 0:
+ d2 = line->yMin;
+ d3 = line->yMax;
+ d4 = line->base;
+ d0 = (d0 - blk->xMin) / (blk->xMax - blk->xMin);
+ d1 = (d1 - blk->xMin) / (blk->xMax - blk->xMin);
+ d2 = (d2 - blk->yMin) / (blk->yMax - blk->yMin);
+ d3 = (d3 - blk->yMin) / (blk->yMax - blk->yMin);
+ d4 = (d4 - blk->yMin) / (blk->yMax - blk->yMin);
+ break;
+ case 1:
+ d2 = line->xMax;
+ d3 = line->xMin;
+ d4 = line->base;
+ d0 = (d0 - blk->yMin) / (blk->yMax - blk->yMin);
+ d1 = (d1 - blk->yMin) / (blk->yMax - blk->yMin);
+ d2 = (blk->xMax - d2) / (blk->xMax - blk->xMin);
+ d3 = (blk->xMax - d3) / (blk->xMax - blk->xMin);
+ d4 = (blk->xMax - d4) / (blk->xMax - blk->xMin);
+ break;
+ case 2:
+ d2 = line->yMax;
+ d3 = line->yMin;
+ d4 = line->base;
+ d0 = (blk->xMax - d0) / (blk->xMax - blk->xMin);
+ d1 = (blk->xMax - d1) / (blk->xMax - blk->xMin);
+ d2 = (blk->yMax - d2) / (blk->yMax - blk->yMin);
+ d3 = (blk->yMax - d3) / (blk->yMax - blk->yMin);
+ d4 = (blk->yMax - d4) / (blk->yMax - blk->yMin);
+ break;
+ case 3:
+ d2 = line->xMin;
+ d3 = line->xMax;
+ d4 = line->base;
+ d0 = (blk->yMax - d0) / (blk->yMax - blk->yMin);
+ d1 = (blk->yMax - d1) / (blk->yMax - blk->yMin);
+ d2 = (d2 - blk->xMin) / (blk->xMax - blk->xMin);
+ d3 = (d3 - blk->xMin) / (blk->xMax - blk->xMin);
+ d4 = (d4 - blk->xMin) / (blk->xMax - blk->xMin);
+ break;
+ }
+
+ switch (line->blk->page->primaryRot) {
+ case 0:
+ xMin = blk->xMin + d0 * (blk->xMax - blk->xMin);
+ xMax = blk->xMin + d1 * (blk->xMax - blk->xMin);
+ yMin = blk->yMin + d2 * (blk->yMax - blk->yMin);
+ yMax = blk->yMin + d3 * (blk->yMax - blk->yMin);
+ base = blk->yMin + base * (blk->yMax - blk->yMin);
+ break;
+ case 1:
+ xMin = blk->xMax - d3 * (blk->xMax - blk->xMin);
+ xMax = blk->xMax - d2 * (blk->xMax - blk->xMin);
+ yMin = blk->yMin + d0 * (blk->yMax - blk->yMin);
+ yMax = blk->yMin + d1 * (blk->yMax - blk->yMin);
+ base = blk->xMax - d4 * (blk->xMax - blk->xMin);
+ break;
+ case 2:
+ xMin = blk->xMax - d1 * (blk->xMax - blk->xMin);
+ xMax = blk->xMax - d0 * (blk->xMax - blk->xMin);
+ yMin = blk->yMax - d3 * (blk->yMax - blk->yMin);
+ yMax = blk->yMax - d2 * (blk->yMax - blk->yMin);
+ base = blk->yMax - d4 * (blk->yMax - blk->yMin);
+ break;
+ case 3:
+ xMin = blk->xMin + d2 * (blk->xMax - blk->xMin);
+ xMax = blk->xMin + d3 * (blk->xMax - blk->xMin);
+ yMin = blk->yMax - d1 * (blk->yMax - blk->yMin);
+ yMax = blk->yMax - d0 * (blk->yMax - blk->yMin);
+ base = blk->xMin + d4 * (blk->xMax - blk->xMin);
+ break;
+ }
- // overlapping case
- return xMin < line2->xMin;
+ }
+ }
}
-// Merge another line's words onto the end of this line.
-void TextLine::merge(TextLine *line2) {
- int newLen, i;
+int TextLineFrag::cmpYXPrimaryRot(const void *p1, const void *p2) {
+ TextLineFrag *frag1 = (TextLineFrag *)p1;
+ TextLineFrag *frag2 = (TextLineFrag *)p2;
+ double cmp;
- xMax = line2->xMax;
- if (line2->yMin < yMin) {
- yMin = line2->yMin;
+ cmp = 0; // make gcc happy
+ switch (frag1->line->blk->page->primaryRot) {
+ case 0:
+ if ((cmp = frag1->yMin - frag2->yMin) == 0) {
+ cmp = frag1->xMin - frag2->xMin;
+ }
+ break;
+ case 1:
+ if ((cmp = frag2->xMax - frag1->xMax) == 0) {
+ cmp = frag1->yMin - frag2->yMin;
+ }
+ break;
+ case 2:
+ if ((cmp = frag2->yMin - frag1->yMin) == 0) {
+ cmp = frag2->xMax - frag1->xMax;
+ }
+ break;
+ case 3:
+ if ((cmp = frag1->xMax - frag2->xMax) == 0) {
+ cmp = frag2->yMax - frag1->yMax;
+ }
+ break;
}
- if (line2->yMax > yMax) {
- yMax = line2->yMax;
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextLineFrag::cmpYXLineRot(const void *p1, const void *p2) {
+ TextLineFrag *frag1 = (TextLineFrag *)p1;
+ TextLineFrag *frag2 = (TextLineFrag *)p2;
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (frag1->line->rot) {
+ case 0:
+ if ((cmp = frag1->yMin - frag2->yMin) == 0) {
+ cmp = frag1->xMin - frag2->xMin;
+ }
+ break;
+ case 1:
+ if ((cmp = frag2->xMax - frag1->xMax) == 0) {
+ cmp = frag1->yMin - frag2->yMin;
+ }
+ break;
+ case 2:
+ if ((cmp = frag2->yMin - frag1->yMin) == 0) {
+ cmp = frag2->xMax - frag1->xMax;
+ }
+ break;
+ case 3:
+ if ((cmp = frag1->xMax - frag2->xMax) == 0) {
+ cmp = frag2->yMax - frag1->yMax;
+ }
+ break;
}
- xSpaceR = line2->xSpaceR;
- lastWord->spaceAfter = gTrue;
- lastWord->next = line2->words;
- lastWord = line2->lastWord;
- line2->words = NULL;
- newLen = len + 1 + line2->len;
- text = (Unicode *)grealloc(text, newLen * sizeof(Unicode));
- xRight = (double *)grealloc(xRight, newLen * sizeof(double));
- text[len] = (Unicode)0x0020;
- xRight[len] = line2->xMin;
- for (i = 0; i < line2->len; ++i) {
- text[len + 1 + i] = line2->text[i];
- xRight[len + 1 + i] = line2->xRight[i];
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextLineFrag::cmpXYLineRot(const void *p1, const void *p2) {
+ TextLineFrag *frag1 = (TextLineFrag *)p1;
+ TextLineFrag *frag2 = (TextLineFrag *)p2;
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (frag1->line->rot) {
+ case 0:
+ if ((cmp = frag1->xMin - frag2->xMin) == 0) {
+ cmp = frag1->yMin - frag2->yMin;
+ }
+ break;
+ case 1:
+ if ((cmp = frag1->yMin - frag2->yMin) == 0) {
+ cmp = frag2->xMax - frag1->xMax;
+ }
+ break;
+ case 2:
+ if ((cmp = frag2->xMax - frag1->xMax) == 0) {
+ cmp = frag2->yMin - frag1->yMin;
+ }
+ break;
+ case 3:
+ if ((cmp = frag2->yMax - frag1->yMax) == 0) {
+ cmp = frag1->xMax - frag2->xMax;
+ }
+ break;
}
- len = newLen;
- convertedLen += line2->convertedLen;
- hyphenated = line2->hyphenated;
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
}
//------------------------------------------------------------------------
// TextBlock
//------------------------------------------------------------------------
-TextBlock::TextBlock() {
+TextBlock::TextBlock(TextPage *pageA, int rotA) {
+ page = pageA;
+ rot = rotA;
+ xMin = yMin = 0;
+ xMax = yMax = -1;
+ priMin = 0;
+ priMax = page->pageWidth;
+ pool = new TextPool();
lines = NULL;
+ curLine = NULL;
next = NULL;
+ stackNext = NULL;
}
TextBlock::~TextBlock() {
- TextLine *l1, *l2;
+ TextLine *line;
- for (l1 = lines; l1; l1 = l2) {
- l2 = l1->next;
- delete l1;
+ delete pool;
+ while (lines) {
+ line = lines;
+ lines = lines->next;
+ delete line;
}
}
-// Returns true if <this> comes before <blk2> in xy order, allowing
-// slack for vertically overlapping blocks.
-GBool TextBlock::yxBefore(TextBlock *blk2) {
- double dy;
+void TextBlock::addWord(TextWord *word) {
+ pool->addWord(word);
+ if (xMin > xMax) {
+ xMin = word->xMin;
+ xMax = word->xMax;
+ yMin = word->yMin;
+ yMax = word->yMax;
+ } else {
+ if (word->xMin < xMin) {
+ xMin = word->xMin;
+ }
+ if (word->xMax > xMax) {
+ xMax = word->xMax;
+ }
+ if (word->yMin < yMin) {
+ yMin = word->yMin;
+ }
+ if (word->yMax > yMax) {
+ yMax = word->yMax;
+ }
+ }
+}
- dy = blkOverlapSlack * lines->fontSize;
+void TextBlock::coalesce(UnicodeMap *uMap) {
+ TextWord *word0, *word1, *word2, *bestWord0, *bestWord1, *lastWord;
+ TextLine *line, *line0, *line1;
+ int poolMinBaseIdx, startBaseIdx, minBaseIdx, maxBaseIdx;
+ int baseIdx, bestWordBaseIdx, idx0, idx1;
+ double minBase, maxBase;
+ double fontSize, delta, priDelta, secDelta;
+ TextLine **lineArray;
+ GBool found;
+ int col1, col2;
+ int i, j, k;
+
+ // discard duplicated text (fake boldface, drop shadows)
+ for (idx0 = pool->minBaseIdx; idx0 <= pool->maxBaseIdx; ++idx0) {
+ word0 = pool->getPool(idx0);
+ while (word0) {
+ priDelta = dupMaxPriDelta * word0->fontSize;
+ secDelta = dupMaxSecDelta * word0->fontSize;
+ if (rot == 0 || rot == 3) {
+ maxBaseIdx = pool->getBaseIdx(word0->base + secDelta);
+ } else {
+ maxBaseIdx = pool->getBaseIdx(word0->base - secDelta);
+ }
+ found = gFalse;
+ word1 = word2 = NULL; // make gcc happy
+ for (idx1 = idx0; idx1 <= maxBaseIdx; ++idx1) {
+ if (idx1 == idx0) {
+ word1 = word0;
+ word2 = word0->next;
+ } else {
+ word1 = NULL;
+ word2 = pool->getPool(idx1);
+ }
+ for (; word2; word1 = word2, word2 = word2->next) {
+ if (word2->len == word0->len &&
+ !memcmp(word2->text, word0->text,
+ word0->len * sizeof(Unicode))) {
+ switch (rot) {
+ case 0:
+ case 2:
+ found = fabs(word0->xMin - word2->xMin) < priDelta &&
+ fabs(word0->xMax - word2->xMax) < priDelta &&
+ fabs(word0->yMin - word2->yMin) < secDelta &&
+ fabs(word0->yMax - word2->yMax) < secDelta;
+ break;
+ case 1:
+ case 3:
+ found = fabs(word0->xMin - word2->xMin) < secDelta &&
+ fabs(word0->xMax - word2->xMax) < secDelta &&
+ fabs(word0->yMin - word2->yMin) < priDelta &&
+ fabs(word0->yMax - word2->yMax) < priDelta;
+ break;
+ }
+ }
+ if (found) {
+ break;
+ }
+ }
+ if (found) {
+ break;
+ }
+ }
+ if (found) {
+ if (word1) {
+ word1->next = word2->next;
+ } else {
+ pool->setPool(idx1, word2->next);
+ }
+ delete word2;
+ } else {
+ word0 = word0->next;
+ }
+ }
+ }
+
+ // build the lines
+ curLine = NULL;
+ poolMinBaseIdx = pool->minBaseIdx;
+ charCount = 0;
+ nLines = 0;
+ while (1) {
- // non-overlapping case
- if (blk2->yMin > yMax - dy ||
- blk2->yMax < yMin + dy) {
- return yMin < blk2->yMin ||
- (yMin == blk2->yMin && xMin < blk2->xMin);
+ // find the first non-empty line in the pool
+ for (;
+ poolMinBaseIdx <= pool->maxBaseIdx && !pool->getPool(poolMinBaseIdx);
+ ++poolMinBaseIdx) ;
+ if (poolMinBaseIdx > pool->maxBaseIdx) {
+ break;
+ }
+
+ // look for the left-most word in the first four lines of the
+ // pool -- this avoids starting with a superscript word
+ startBaseIdx = poolMinBaseIdx;
+ for (baseIdx = poolMinBaseIdx + 1;
+ baseIdx < poolMinBaseIdx + 4 && baseIdx <= pool->maxBaseIdx;
+ ++baseIdx) {
+ if (!pool->getPool(baseIdx)) {
+ continue;
+ }
+ if (pool->getPool(baseIdx)->primaryCmp(pool->getPool(startBaseIdx))
+ < 0) {
+ startBaseIdx = baseIdx;
+ }
+ }
+
+ // create a new line
+ word0 = pool->getPool(startBaseIdx);
+ pool->setPool(startBaseIdx, word0->next);
+ word0->next = NULL;
+ line = new TextLine(this, word0->rot, word0->base);
+ line->addWord(word0);
+ lastWord = word0;
+
+ // compute the search range
+ fontSize = word0->fontSize;
+ minBase = word0->base - maxIntraLineDelta * fontSize;
+ maxBase = word0->base + maxIntraLineDelta * fontSize;
+ minBaseIdx = pool->getBaseIdx(minBase);
+ maxBaseIdx = pool->getBaseIdx(maxBase);
+
+ // find the rest of the words in this line
+ while (1) {
+
+ // find the left-most word whose baseline is in the range for
+ // this line
+ bestWordBaseIdx = 0;
+ bestWord0 = bestWord1 = NULL;
+ for (baseIdx = minBaseIdx; baseIdx <= maxBaseIdx; ++baseIdx) {
+ for (word0 = NULL, word1 = pool->getPool(baseIdx);
+ word1;
+ word0 = word1, word1 = word1->next) {
+ if (word1->base >= minBase &&
+ word1->base <= maxBase &&
+ (delta = lastWord->primaryDelta(word1)) >=
+ minCharSpacing * fontSize) {
+ if (delta < maxWordSpacing * fontSize &&
+ (!bestWord1 || word1->primaryCmp(bestWord1) < 0)) {
+ bestWordBaseIdx = baseIdx;
+ bestWord0 = word0;
+ bestWord1 = word1;
+ }
+ break;
+ }
+ }
+ }
+ if (!bestWord1) {
+ break;
+ }
+
+ // remove it from the pool, and add it to the line
+ if (bestWord0) {
+ bestWord0->next = bestWord1->next;
+ } else {
+ pool->setPool(bestWordBaseIdx, bestWord1->next);
+ }
+ bestWord1->next = NULL;
+ line->addWord(bestWord1);
+ lastWord = bestWord1;
+ }
+
+ // add the line
+ if (curLine && line->cmpYX(curLine) > 0) {
+ line0 = curLine;
+ line1 = curLine->next;
+ } else {
+ line0 = NULL;
+ line1 = lines;
+ }
+ for (;
+ line1 && line->cmpYX(line1) > 0;
+ line0 = line1, line1 = line1->next) ;
+ if (line0) {
+ line0->next = line;
+ } else {
+ lines = line;
+ }
+ line->next = line1;
+ curLine = line;
+ line->coalesce(uMap);
+ charCount += line->len;
+ ++nLines;
}
- // overlapping case
- return xMin < blk2->xMin;
+ // sort lines into xy order for column assignment
+ lineArray = (TextLine **)gmalloc(nLines * sizeof(TextLine *));
+ for (line = lines, i = 0; line; line = line->next, ++i) {
+ lineArray[i] = line;
+ }
+ qsort(lineArray, nLines, sizeof(TextLine *), &TextLine::cmpXY);
+
+ // column assignment
+ nColumns = 0;
+ for (i = 0; i < nLines; ++i) {
+ line0 = lineArray[i];
+ col1 = 0;
+ for (j = 0; j < i; ++j) {
+ line1 = lineArray[j];
+ if (line1->primaryDelta(line0) >= 0) {
+ col2 = line1->col[line1->len] + 1;
+ } else {
+ k = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ for (k = 0;
+ k < line1->len &&
+ line0->xMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
+ ++k) ;
+ break;
+ case 1:
+ for (k = 0;
+ k < line1->len &&
+ line0->yMin >= 0.5 * (line1->edge[k] + line1->edge[k+1]);
+ ++k) ;
+ break;
+ case 2:
+ for (k = 0;
+ k < line1->len &&
+ line0->xMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
+ ++k) ;
+ break;
+ case 3:
+ for (k = 0;
+ k < line1->len &&
+ line0->yMax <= 0.5 * (line1->edge[k] + line1->edge[k+1]);
+ ++k) ;
+ break;
+ }
+ col2 = line1->col[k];
+ }
+ if (col2 > col1) {
+ col1 = col2;
+ }
+ }
+ for (k = 0; k <= line0->len; ++k) {
+ line0->col[k] += col1;
+ }
+ if (line0->col[line0->len] > nColumns) {
+ nColumns = line0->col[line0->len];
+ }
+ }
+ gfree(lineArray);
}
-// Merge another block's line onto the right of this one.
-void TextBlock::mergeRight(TextBlock *blk2) {
- lines->merge(blk2->lines);
- xMax = lines->xMax;
- yMin = lines->yMin;
- yMax = lines->yMax;
- xSpaceR = lines->xSpaceR;
+void TextBlock::updatePriMinMax(TextBlock *blk) {
+ double newPriMin, newPriMax;
+ GBool gotPriMin, gotPriMax;
+
+ gotPriMin = gotPriMax = gFalse;
+ newPriMin = newPriMax = 0; // make gcc happy
+ switch (page->primaryRot) {
+ case 0:
+ case 2:
+ if (blk->yMin < yMax && blk->yMax > yMin) {
+ if (blk->xMin < xMin) {
+ newPriMin = blk->xMax;
+ gotPriMin = gTrue;
+ }
+ if (blk->xMax > xMax) {
+ newPriMax = blk->xMin;
+ gotPriMax = gTrue;
+ }
+ }
+ break;
+ case 1:
+ case 3:
+ if (blk->xMin < xMax && blk->xMax > xMin) {
+ if (blk->yMin < yMin) {
+ newPriMin = blk->yMax;
+ gotPriMin = gTrue;
+ }
+ if (blk->yMax > yMax) {
+ newPriMax = blk->yMin;
+ gotPriMax = gTrue;
+ }
+ }
+ break;
+ }
+ if (gotPriMin) {
+ if (newPriMin > xMin) {
+ newPriMin = xMin;
+ }
+ if (newPriMin > priMin) {
+ priMin = newPriMin;
+ }
+ }
+ if (gotPriMax) {
+ if (newPriMax < xMax) {
+ newPriMax = xMax;
+ }
+ if (newPriMax < priMax) {
+ priMax = newPriMax;
+ }
+ }
}
-// Merge another block's lines onto the bottom of this block.
-void TextBlock::mergeBelow(TextBlock *blk2) {
- TextLine *line;
+int TextBlock::cmpXYPrimaryRot(const void *p1, const void *p2) {
+ TextBlock *blk1 = *(TextBlock **)p1;
+ TextBlock *blk2 = *(TextBlock **)p2;
+ double cmp;
- if (blk2->xMin < xMin) {
- xMin = blk2->xMin;
+ cmp = 0; // make gcc happy
+ switch (blk1->page->primaryRot) {
+ case 0:
+ if ((cmp = blk1->xMin - blk2->xMin) == 0) {
+ cmp = blk1->yMin - blk2->yMin;
+ }
+ break;
+ case 1:
+ if ((cmp = blk1->yMin - blk2->yMin) == 0) {
+ cmp = blk2->xMax - blk1->xMax;
+ }
+ break;
+ case 2:
+ if ((cmp = blk2->xMax - blk1->xMax) == 0) {
+ cmp = blk2->yMin - blk1->yMin;
+ }
+ break;
+ case 3:
+ if ((cmp = blk2->yMax - blk1->yMax) == 0) {
+ cmp = blk1->xMax - blk2->xMax;
+ }
+ break;
}
- if (blk2->xMax > xMax) {
- xMax = blk2->xMax;
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextBlock::cmpYXPrimaryRot(const void *p1, const void *p2) {
+ TextBlock *blk1 = *(TextBlock **)p1;
+ TextBlock *blk2 = *(TextBlock **)p2;
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (blk1->page->primaryRot) {
+ case 0:
+ if ((cmp = blk1->yMin - blk2->yMin) == 0) {
+ cmp = blk1->xMin - blk2->xMin;
+ }
+ break;
+ case 1:
+ if ((cmp = blk2->xMax - blk1->xMax) == 0) {
+ cmp = blk1->yMin - blk2->yMin;
+ }
+ break;
+ case 2:
+ if ((cmp = blk2->yMin - blk1->yMin) == 0) {
+ cmp = blk2->xMax - blk1->xMax;
+ }
+ break;
+ case 3:
+ if ((cmp = blk1->xMax - blk2->xMax) == 0) {
+ cmp = blk2->yMax - blk1->yMax;
+ }
+ break;
}
- yMax = blk2->yMax;
- if (blk2->xSpaceL > xSpaceL) {
- xSpaceL = blk2->xSpaceL;
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+int TextBlock::primaryCmp(TextBlock *blk) {
+ double cmp;
+
+ cmp = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ cmp = xMin - blk->xMin;
+ break;
+ case 1:
+ cmp = yMin - blk->yMin;
+ break;
+ case 2:
+ cmp = blk->xMax - xMax;
+ break;
+ case 3:
+ cmp = blk->yMax - yMax;
+ break;
}
- if (blk2->xSpaceR < xSpaceR) {
- xSpaceR = blk2->xSpaceR;
+ return cmp < 0 ? -1 : cmp > 0 ? 1 : 0;
+}
+
+double TextBlock::secondaryDelta(TextBlock *blk) {
+ double delta;
+
+ delta = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ delta = blk->yMin - yMax;
+ break;
+ case 1:
+ delta = xMin - blk->xMax;
+ break;
+ case 2:
+ delta = yMin - blk->yMax;
+ break;
+ case 3:
+ delta = blk->xMin - xMax;
+ break;
}
- if (blk2->maxFontSize > maxFontSize) {
- maxFontSize = blk2->maxFontSize;
+ return delta;
+}
+
+GBool TextBlock::isBelow(TextBlock *blk) {
+ GBool below;
+
+ below = gFalse; // make gcc happy
+ switch (page->primaryRot) {
+ case 0:
+ below = xMin >= blk->priMin && xMax <= blk->priMax &&
+ yMin > blk->yMin;
+ break;
+ case 1:
+ below = yMin >= blk->priMin && yMax <= blk->priMax &&
+ xMax < blk->xMax;
+ break;
+ case 2:
+ below = xMin >= blk->priMin && xMax <= blk->priMax &&
+ yMax < blk->yMax;
+ break;
+ case 3:
+ below = yMin >= blk->priMin && yMax <= blk->priMax &&
+ xMin > blk->xMin;
+ break;
}
- for (line = lines; line->next; line = line->next) ;
- line->next = line->flowNext = blk2->lines;
- blk2->lines = NULL;
+
+ return below;
}
//------------------------------------------------------------------------
// TextFlow
//------------------------------------------------------------------------
-TextFlow::TextFlow() {
- blocks = NULL;
+TextFlow::TextFlow(TextPage *pageA, TextBlock *blk) {
+ page = pageA;
+ xMin = blk->xMin;
+ xMax = blk->xMax;
+ yMin = blk->yMin;
+ yMax = blk->yMax;
+ priMin = blk->priMin;
+ priMax = blk->priMax;
+ blocks = lastBlk = blk;
next = NULL;
}
TextFlow::~TextFlow() {
- TextBlock *b1, *b2;
+ TextBlock *blk;
- for (b1 = blocks; b1; b1 = b2) {
- b2 = b1->next;
- delete b1;
+ while (blocks) {
+ blk = blocks;
+ blocks = blocks->next;
+ delete blk;
}
}
+void TextFlow::addBlock(TextBlock *blk) {
+ if (lastBlk) {
+ lastBlk->next = blk;
+ } else {
+ blocks = blk;
+ }
+ lastBlk = blk;
+ if (blk->xMin < xMin) {
+ xMin = blk->xMin;
+ }
+ if (blk->xMax > xMax) {
+ xMax = blk->xMax;
+ }
+ if (blk->yMin < yMin) {
+ yMin = blk->yMin;
+ }
+ if (blk->yMax > yMax) {
+ yMax = blk->yMax;
+ }
+}
+
+GBool TextFlow::blockFits(TextBlock *blk, TextBlock *prevBlk) {
+ GBool fits;
+
+ // lower blocks must use smaller fonts
+ if (blk->lines->words->fontSize > lastBlk->lines->words->fontSize) {
+ return gFalse;
+ }
+
+ fits = gFalse; // make gcc happy
+ switch (page->primaryRot) {
+ case 0:
+ fits = blk->xMin >= priMin && blk->xMax <= priMax;
+ break;
+ case 1:
+ fits = blk->yMin >= priMin && blk->yMax <= priMax;
+ break;
+ case 2:
+ fits = blk->xMin >= priMin && blk->xMax <= priMax;
+ break;
+ case 3:
+ fits = blk->yMin >= priMin && blk->yMax <= priMax;
+ break;
+ }
+ return fits;
+}
+
+#if TEXTOUT_WORD_LIST
+
+//------------------------------------------------------------------------
+// TextWordList
+//------------------------------------------------------------------------
+
+TextWordList::TextWordList(TextPage *text, GBool physLayout) {
+ TextFlow *flow;
+ TextBlock *blk;
+ TextLine *line;
+ TextWord *word;
+ TextWord **wordArray;
+ int nWords, i;
+
+ words = new GList();
+
+ if (text->rawOrder) {
+ for (word = text->rawWords; word; word = word->next) {
+ words->append(word);
+ }
+
+ } else if (physLayout) {
+ // this is inefficient, but it's also the least useful of these
+ // three cases
+ nWords = 0;
+ for (flow = text->flows; flow; flow = flow->next) {
+ for (blk = flow->blocks; blk; blk = blk->next) {
+ for (line = blk->lines; line; line = line->next) {
+ for (word = line->words; word; word = word->next) {
+ ++nWords;
+ }
+ }
+ }
+ }
+ wordArray = (TextWord **)gmalloc(nWords * sizeof(TextWord *));
+ i = 0;
+ for (flow = text->flows; flow; flow = flow->next) {
+ for (blk = flow->blocks; blk; blk = blk->next) {
+ for (line = blk->lines; line; line = line->next) {
+ for (word = line->words; word; word = word->next) {
+ wordArray[i++] = word;
+ }
+ }
+ }
+ }
+ qsort(wordArray, nWords, sizeof(TextWord *), &TextWord::cmpYX);
+ for (i = 0; i < nWords; ++i) {
+ words->append(wordArray[i]);
+ }
+ gfree(wordArray);
+
+ } else {
+ for (flow = text->flows; flow; flow = flow->next) {
+ for (blk = flow->blocks; blk; blk = blk->next) {
+ for (line = blk->lines; line; line = line->next) {
+ for (word = line->words; word; word = word->next) {
+ words->append(word);
+ }
+ }
+ }
+ }
+ }
+}
+
+TextWordList::~TextWordList() {
+ delete words;
+}
+
+int TextWordList::getLength() {
+ return words->getLength();
+}
+
+TextWord *TextWordList::get(int idx) {
+ if (idx < 0 || idx >= words->getLength()) {
+ return NULL;
+ }
+ return (TextWord *)words->get(idx);
+}
+
+#endif // TEXTOUT_WORD_LIST
//------------------------------------------------------------------------
// TextPage
//------------------------------------------------------------------------
TextPage::TextPage(GBool rawOrderA) {
+ int rot;
+
rawOrder = rawOrderA;
curWord = NULL;
charPos = 0;
- font = NULL;
- fontSize = 0;
+ curFont = NULL;
+ curFontSize = 0;
nest = 0;
nTinyChars = 0;
- words = wordPtr = NULL;
- lines = NULL;
+ if (!rawOrder) {
+ for (rot = 0; rot < 4; ++rot) {
+ pools[rot] = new TextPool();
+ }
+ }
flows = NULL;
+ blocks = NULL;
+ rawWords = NULL;
+ rawLastWord = NULL;
fonts = new GList();
+ lastFindXMin = lastFindYMin = 0;
+ haveLastFind = gFalse;
}
TextPage::~TextPage() {
+ int rot;
+
clear();
+ if (!rawOrder) {
+ for (rot = 0; rot < 4; ++rot) {
+ delete pools[rot];
+ }
+ }
delete fonts;
}
+void TextPage::startPage(GfxState *state) {
+ clear();
+ if (state) {
+ pageWidth = state->getPageWidth();
+ pageHeight = state->getPageHeight();
+ } else {
+ pageWidth = pageHeight = 0;
+ }
+}
+
+void TextPage::clear() {
+ int rot;
+ TextFlow *flow;
+ TextWord *word;
+
+ if (curWord) {
+ delete curWord;
+ curWord = NULL;
+ }
+ if (rawOrder) {
+ while (rawWords) {
+ word = rawWords;
+ rawWords = rawWords->next;
+ delete word;
+ }
+ } else {
+ for (rot = 0; rot < 4; ++rot) {
+ delete pools[rot];
+ }
+ while (flows) {
+ flow = flows;
+ flows = flows->next;
+ delete flow;
+ }
+ gfree(blocks);
+ }
+ deleteGList(fonts, TextFontInfo);
+
+ curWord = NULL;
+ charPos = 0;
+ curFont = NULL;
+ curFontSize = 0;
+ nest = 0;
+ nTinyChars = 0;
+ if (!rawOrder) {
+ for (rot = 0; rot < 4; ++rot) {
+ pools[rot] = new TextPool();
+ }
+ }
+ flows = NULL;
+ blocks = NULL;
+ rawWords = NULL;
+ rawLastWord = NULL;
+ fonts = new GList();
+}
+
void TextPage::updateFont(GfxState *state) {
GfxFont *gfxFont;
double *fm;
@@ -454,22 +1682,22 @@ void TextPage::updateFont(GfxState *state) {
int i;
// get the font info object
- font = NULL;
+ curFont = NULL;
for (i = 0; i < fonts->getLength(); ++i) {
- font = (TextFontInfo *)fonts->get(i);
- if (font->matches(state)) {
+ curFont = (TextFontInfo *)fonts->get(i);
+ if (curFont->matches(state)) {
break;
}
- font = NULL;
+ curFont = NULL;
}
- if (!font) {
- font = new TextFontInfo(state);
- fonts->append(font);
+ if (!curFont) {
+ curFont = new TextFontInfo(state);
+ fonts->append(curFont);
}
// adjust the font size
gfxFont = state->getFont();
- fontSize = state->getTransformedFontSize();
+ curFontSize = state->getTransformedFontSize();
if (gfxFont && gfxFont->getType() == fontType3) {
// This is a hack which makes it possible to deal with some Type 3
// fonts. The problem is that it's impossible to know what the
@@ -496,24 +1724,28 @@ void TextPage::updateFont(GfxState *state) {
if (mCode >= 0 &&
(w = ((Gfx8BitFont *)gfxFont)->getWidth(mCode)) > 0) {
// 0.6 is a generic average 'm' width -- yes, this is a hack
- fontSize *= w / 0.6;
+ curFontSize *= w / 0.6;
} else if (letterCode >= 0 &&
(w = ((Gfx8BitFont *)gfxFont)->getWidth(letterCode)) > 0) {
// even more of a hack: 0.5 is a generic letter width
- fontSize *= w / 0.5;
+ curFontSize *= w / 0.5;
} else if (anyCode >= 0 &&
(w = ((Gfx8BitFont *)gfxFont)->getWidth(anyCode)) > 0) {
// better than nothing: 0.5 is a generic character width
- fontSize *= w / 0.5;
+ curFontSize *= w / 0.5;
}
fm = gfxFont->getFontMatrix();
if (fm[0] != 0) {
- fontSize *= fabs(fm[3] / fm[0]);
+ curFontSize *= fabs(fm[3] / fm[0]);
}
}
}
void TextPage::beginWord(GfxState *state, double x0, double y0) {
+ double *txtm, *ctm, *fontm;
+ double m[4], m2[4];
+ int rot;
+
// This check is needed because Type 3 characters can contain
// text-drawing operations (when TextPage is being used via
// XOutputDev rather than TextOutputDev).
@@ -522,7 +1754,31 @@ void TextPage::beginWord(GfxState *state, double x0, double y0) {
return;
}
- curWord = new TextWord(state, x0, y0, charPos, font, fontSize);
+ // compute the rotation
+ txtm = state->getTextMat();
+ ctm = state->getCTM();
+ m[0] = txtm[0] * ctm[0] + txtm[1] * ctm[2];
+ m[1] = txtm[0] * ctm[1] + txtm[1] * ctm[3];
+ m[2] = txtm[2] * ctm[0] + txtm[3] * ctm[2];
+ m[3] = txtm[2] * ctm[1] + txtm[3] * ctm[3];
+ if (state->getFont()->getType() == fontType3) {
+ fontm = state->getFont()->getFontMatrix();
+ m2[0] = fontm[0] * m[0] + fontm[1] * m[2];
+ m2[1] = fontm[0] * m[1] + fontm[1] * m[3];
+ m2[2] = fontm[2] * m[0] + fontm[3] * m[2];
+ m2[3] = fontm[2] * m[1] + fontm[3] * m[3];
+ m[0] = m2[0];
+ m[1] = m2[1];
+ m[2] = m2[2];
+ m[3] = m2[3];
+ }
+ if (fabs(m[0] * m[3]) > fabs(m[1] * m[2])) {
+ rot = (m[3] < 0) ? 0 : 2;
+ } else {
+ rot = (m[2] > 0) ? 1 : 3;
+ }
+
+ curWord = new TextWord(state, rot, x0, y0, charPos, curFont, curFontSize);
}
void TextPage::addChar(GfxState *state, double x, double y,
@@ -557,7 +1813,7 @@ void TextPage::addChar(GfxState *state, double x, double y,
// check the tiny chars limit
if (!globalParams->getTextKeepTinyChars() &&
fabs(w1) < 3 && fabs(h1) < 3) {
- if (++nTinyChars > 20000) {
+ if (++nTinyChars > 50000) {
return;
}
}
@@ -574,16 +1830,26 @@ void TextPage::addChar(GfxState *state, double x, double y,
// this case, break text into individual chars and let the coalesce
// function deal with it later
n = curWord->len;
- if (n > 0 && x1 - curWord->xRight[n-1] >
- curWord->font->minSpaceWidth * curWord->fontSize) {
- endWord();
- beginWord(state, x, y);
+ if (n > 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;
+ }
+ if (sp > defaultSpaceWidth * curWord->fontSize) {
+ endWord();
+ beginWord(state, x, y);
+ }
}
// page rotation and/or transform matrices can cause text to be
// drawn in reverse order -- in this case, swap the begin/end
// coordinates and break text into individual chars
- if (w1 < 0) {
+ if ((curWord->rot == 0 && w1 < 0) ||
+ (curWord->rot == 1 && h1 < 0) ||
+ (curWord->rot == 2 && w1 > 0) ||
+ (curWord->rot == 3 && h1 > 0)) {
endWord();
beginWord(state, x + dx, y + dy);
x1 += w1;
@@ -620,8 +1886,6 @@ void TextPage::endWord() {
}
void TextPage::addWord(TextWord *word) {
- TextWord *p1, *p2;
-
// throw away zero-length words -- they don't have valid xMin/xMax
// values, and they're useless anyway
if (word->len == 0) {
@@ -629,533 +1893,399 @@ void TextPage::addWord(TextWord *word) {
return;
}
- // insert word in xy list
if (rawOrder) {
- p1 = wordPtr;
- p2 = NULL;
- } else {
- if (wordPtr && wordPtr->xyBefore(word)) {
- p1 = wordPtr;
- p2 = wordPtr->next;
+ if (rawLastWord) {
+ rawLastWord->next = word;
} else {
- p1 = NULL;
- p2 = words;
- }
- for (; p2; p1 = p2, p2 = p2->next) {
- if (word->xyBefore(p2)) {
- break;
- }
+ rawWords = word;
}
- }
- if (p1) {
- p1->next = word;
+ rawLastWord = word;
} else {
- words = word;
+ pools[word->rot]->addWord(word);
}
- word->next = p2;
- wordPtr = word;
}
void TextPage::coalesce(GBool physLayout) {
+ UnicodeMap *uMap;
+ TextPool *pool;
TextWord *word0, *word1, *word2;
- TextLine *line0, *line1, *line2, *line3, *line4, *lineList;
- TextBlock *blk0, *blk1, *blk2, *blk3, *blk4, *blk5, *blk6;
- TextBlock *yxBlocks, *blocks, *blkStack;
- TextFlow *flow0, *flow1;
- double sz, xLimit, yLimit;
- double fit1, fit2, sp1, sp2 = 0.0e+0;
+ TextLine *line;
+ TextBlock *blkList, *blkStack, *blk, *lastBlk, *blk0, *blk1;
+ TextBlock **blkArray;
+ TextFlow *flow, *lastFlow;
+ int rot, poolMinBaseIdx, baseIdx, startBaseIdx;
+ double minBase, maxBase, newMinBase, newMaxBase;
+ double fontSize, colSpace, lineSpace, intraLineSpace, blkSpace;
GBool found;
- UnicodeMap *uMap;
- GBool isUnicode;
- char buf[8];
- int col1, col2, d, i, j;
+ int count[4];
+ int lrCount;
+ int firstBlkIdx, nBlocksLeft;
+ int col1, col2;
+ int i, j, n;
-#if 0 // for debugging
- printf("*** initial word list ***\n");
- for (word0 = words; word0; word0 = word0->next) {
- printf("word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f: '",
- word0->xMin, word0->xMax, word0->yMin, word0->yMax, word0->yBase);
- for (i = 0; i < word0->len; ++i) {
- fputc(word0->text[i] & 0xff, stdout);
- }
- printf("'\n");
+ if (rawOrder) {
+ primaryRot = 0;
+ primaryLR = gTrue;
+ return;
}
- printf("\n");
- fflush(stdout);
-#endif
- //----- discard duplicated text (fake boldface, drop shadows)
-
- word0 = words;
- while (word0) {
- sz = word0->fontSize;
- xLimit = word0->xMin + sz * dupMaxDeltaX;
- found = gFalse;
- for (word1 = word0, word2 = word0->next;
- word2 && word2->xMin < xLimit;
- word1 = word2, word2 = word2->next) {
- if (word2->len == word0->len &&
- !memcmp(word2->text, word0->text, word0->len * sizeof(Unicode)) &&
- fabs(word2->yMin - word0->yMin) < sz * dupMaxDeltaY &&
- fabs(word2->yMax - word0->yMax) < sz * dupMaxDeltaY &&
- fabs(word2->xMax - word0->xMax) < sz * dupMaxDeltaX) {
- found = gTrue;
- break;
- }
- }
- if (found) {
- word1->next = word2->next;
- delete word2;
- } else {
- word0 = word0->next;
- }
- }
+ uMap = globalParams->getTextEncoding();
+ blkList = NULL;
+ lastBlk = NULL;
+ nBlocks = 0;
+ primaryRot = -1;
#if 0 // for debugging
- printf("*** words after removing duplicate text ***\n");
- for (word0 = words; word0; word0 = word0->next) {
- printf("word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f: '",
- word0->xMin, word0->xMax, word0->yMin, word0->yMax, word0->yBase);
- for (i = 0; i < word0->len; ++i) {
- fputc(word0->text[i] & 0xff, stdout);
- }
- printf("'\n");
- }
- printf("\n");
- fflush(stdout);
-#endif
-
- //----- merge words
-
- word0 = words;
- while (word0) {
- sz = word0->fontSize;
-
- // look for adjacent text which is part of the same word, and
- // merge it into this word
- xLimit = word0->xMax + sz * word0->font->minSpaceWidth;
- if (rawOrder) {
- word1 = word0;
- word2 = word0->next;
- found = word2 &&
- word2->xMin < xLimit &&
- word2->font == word0->font &&
- fabs(word2->fontSize - sz) < 0.05 &&
- fabs(word2->yBase - word0->yBase) < 0.05 &&
- word2->charPos == word0->charPos + word0->charLen;
- } else {
- found = gFalse;
- for (word1 = word0, word2 = word0->next;
- word2 && word2->xMin < xLimit;
- word1 = word2, word2 = word2->next) {
- if (word2->font == word0->font &&
- fabs(word2->fontSize - sz) < 0.05 &&
- fabs(word2->yBase - word0->yBase) < 0.05 &&
- word2->charPos == word0->charPos + word0->charLen) {
- found = gTrue;
- break;
+ printf("*** initial words ***\n");
+ for (rot = 0; rot < 4; ++rot) {
+ pool = pools[rot];
+ for (baseIdx = pool->minBaseIdx; baseIdx <= pool->maxBaseIdx; ++baseIdx) {
+ for (word0 = pool->getPool(baseIdx); word0; word0 = word0->next) {
+ printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f '",
+ word0->xMin, word0->xMax, word0->yMin, word0->yMax,
+ word0->base, word0->fontSize);
+ for (i = 0; i < word0->len; ++i) {
+ fputc(word0->text[i] & 0xff, stdout);
}
+ printf("'\n");
}
}
- if (found) {
- word0->merge(word2);
- word1->next = word2->next;
- delete word2;
- continue;
- }
-
- word0 = word0->next;
- }
-
-#if 0 // for debugging
- printf("*** after merging words ***\n");
- for (word0 = words; word0; word0 = word0->next) {
- printf("word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f: '",
- word0->xMin, word0->xMax, word0->yMin, word0->yMax, word0->yBase);
- for (i = 0; i < word0->len; ++i) {
- fputc(word0->text[i] & 0xff, stdout);
- }
- printf("'\n");
}
printf("\n");
- fflush(stdout);
#endif
- //----- assemble words into lines
-
- lineList = line0 = NULL;
- while (words) {
-
- // remove the first word from the word list
- word0 = words;
- words = words->next;
- word0->next = NULL;
-
- // find the best line (if any) for the word
- if (rawOrder) {
- if (line0 && lineFit(line0, word0, &sp2) >= 0) {
- line1 = line0;
- sp1 = sp2;
- } else {
- line1 = NULL;
- sp1 = 0;
- }
- } else {
- line1 = NULL;
- fit1 = 0;
- sp1 = 0;
- for (line2 = lineList; line2; line2 = line2->next) {
- fit2 = lineFit(line2, word0, &sp2);
- if (fit2 >= 0 && (!line1 || fit2 < fit1)) {
- line1 = line2;
- fit1 = fit2;
- sp1 = sp2;
- }
- }
- }
-
- // found a line: append the word
- if (line1) {
- word1 = line1->lastWord;
- word1->next = word0;
- line1->lastWord = word0;
- if (word0->xMax > line1->xMax) {
- line1->xMax = word0->xMax;
- }
- if (word0->yMin < line1->yMin) {
- line1->yMin = word0->yMin;
- }
- if (word0->yMax > line1->yMax) {
- line1->yMax = word0->yMax;
- }
- line1->len += word0->len;
- if (sp1 > line1->fontSize * line1->font->minSpaceWidth) {
- word1->spaceAfter = gTrue;
- ++line1->len;
- }
-
- // didn't find a line: create a new line
- } else {
- line1 = new TextLine();
- line1->words = line1->lastWord = word0;
- line1->xMin = word0->xMin;
- line1->xMax = word0->xMax;
- line1->yMin = word0->yMin;
- line1->yMax = word0->yMax;
- line1->yBase = word0->yBase;
- line1->font = word0->font;
- line1->fontSize = word0->fontSize;
- line1->len = word0->len;
- if (line0) {
- line0->next = line1;
- } else {
- lineList = line1;
- }
- line0 = line1;
- }
- }
-
- // build the line text
- uMap = globalParams->getTextEncoding();
- isUnicode = uMap ? uMap->isUnicode() : gFalse;
-
- for (line1 = lineList; line1; line1 = line1->next) {
- line1->text = (Unicode *)gmalloc(line1->len * sizeof(Unicode));
- line1->xRight = (double *)gmalloc(line1->len * sizeof(double));
- line1->col = (int *)gmalloc(line1->len * sizeof(int));
- i = 0;
- for (word1 = line1->words; word1; word1 = word1->next) {
- for (j = 0; j < word1->len; ++j) {
- line1->text[i] = word1->text[j];
- line1->xRight[i] = word1->xRight[j];
- ++i;
- }
- if (word1->spaceAfter && word1->next) {
- line1->text[i] = (Unicode)0x0020;
- line1->xRight[i] = word1->next->xMin;
- ++i;
- }
- }
- line1->convertedLen = 0;
- for (j = 0; j < line1->len; ++j) {
- line1->col[j] = line1->convertedLen;
- if (isUnicode) {
- ++line1->convertedLen;
- } else if (uMap) {
- line1->convertedLen +=
- uMap->mapUnicode(line1->text[j], buf, sizeof(buf));
- }
- }
+ //----- assemble the blocks
- // check for hyphen at end of line
- //~ need to check for other chars used as hyphens
- if (line1->text[line1->len - 1] == (Unicode)'-') {
- line1->hyphenated = gTrue;
- }
+ //~ add an outer loop for writing mode (vertical text)
- }
+ // build blocks for each rotation value
+ for (rot = 0; rot < 4; ++rot) {
+ pool = pools[rot];
+ poolMinBaseIdx = pool->minBaseIdx;
+ count[rot] = 0;
- if (uMap) {
- uMap->decRefCnt();
- }
+ // add blocks until no more words are left
+ while (1) {
-#if 0 // for debugging
- printf("*** lines in xy order ***\n");
- for (line0 = lineList; line0; line0 = line0->next) {
- printf("[line: x=%.2f..%.2f y=%.2f..%.2f base=%.2f len=%d]\n",
- line0->xMin, line0->xMax, line0->yMin, line0->yMax,
- line0->yBase, line0->len);
- for (word0 = line0->words; word0; word0 = word0->next) {
- printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSz=%.2f space=%d: '",
- word0->xMin, word0->xMax, word0->yMin, word0->yMax,
- word0->yBase, word0->fontSize, word0->spaceAfter);
- for (i = 0; i < word0->len; ++i) {
- fputc(word0->text[i] & 0xff, stdout);
+ // find the first non-empty line in the pool
+ for (;
+ poolMinBaseIdx <= pool->maxBaseIdx &&
+ !pool->getPool(poolMinBaseIdx);
+ ++poolMinBaseIdx) ;
+ if (poolMinBaseIdx > pool->maxBaseIdx) {
+ break;
}
- printf("'\n");
- }
- }
- printf("\n");
- fflush(stdout);
-#endif
-
- //----- column assignment
- for (line1 = lineList; line1; line1 = line1->next) {
- col1 = 0;
- for (line2 = lineList; line2 != line1; line2 = line2->next) {
- if (line1->xMin >= line2->xMax) {
- d = (int)((line1->xMin - line2->xMax) /
- (line1->font->maxSpaceWidth * line1->fontSize));
- if (d > 4) {
- d = 4;
+ // look for the left-most word in the first four lines of the
+ // pool -- this avoids starting with a superscript word
+ startBaseIdx = poolMinBaseIdx;
+ for (baseIdx = poolMinBaseIdx + 1;
+ baseIdx < poolMinBaseIdx + 4 && baseIdx <= pool->maxBaseIdx;
+ ++baseIdx) {
+ if (!pool->getPool(baseIdx)) {
+ continue;
}
- col2 = line2->col[0] + line2->convertedLen + d;
- if (col2 > col1) {
- col1 = col2;
- }
- } else if (line1->xMin > line2->xMin) {
- for (i = 0; i < line2->len && line1->xMin >= line2->xRight[i]; ++i) ;
- col2 = line2->col[i];
- if (col2 > col1) {
- col1 = col2;
+ if (pool->getPool(baseIdx)->primaryCmp(pool->getPool(startBaseIdx))
+ < 0) {
+ startBaseIdx = baseIdx;
}
}
- }
- for (j = 0; j < line1->len; ++j) {
- line1->col[j] += col1;
- }
- }
-#if 0 // for debugging
- printf("*** lines in xy order, after column assignment ***\n");
- for (line0 = lineList; line0; line0 = line0->next) {
- printf("[line: x=%.2f..%.2f y=%.2f..%.2f base=%.2f col=%d len=%d]\n",
- line0->xMin, line0->xMax, line0->yMin, line0->yMax,
- line0->yBase, line0->col[0], line0->len);
- for (word0 = line0->words; word0; word0 = word0->next) {
- printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSz=%.2f space=%d: '",
- word0->xMin, word0->xMax, word0->yMin, word0->yMax,
- word0->yBase, word0->fontSize, word0->spaceAfter);
- for (i = 0; i < word0->len; ++i) {
- fputc(word0->text[i] & 0xff, stdout);
- }
- printf("'\n");
- }
- }
- printf("\n");
- fflush(stdout);
-#endif
-
- //----- assemble lines into blocks
-
- if (rawOrder) {
-
- lines = lineList;
- for (line1 = lines; line1; line1 = line1->next) {
- line1->xSpaceL = 0;
- line1->xSpaceR = pageWidth;
- }
-
- } else {
-
- // sort lines into yx order
- lines = NULL;
- while (lineList) {
- line0 = lineList;
- lineList = lineList->next;
- for (line1 = NULL, line2 = lines;
- line2 && !line0->yxBefore(line2);
- line1 = line2, line2 = line2->next) ;
- if (line1) {
- line1->next = line0;
- } else {
- lines = line0;
- }
- line0->next = line2;
- }
-
- // compute whitespace to left and right of each line
- line0 = lines;
- for (line1 = lines; line1; line1 = line1->next) {
-
- // find the first vertically overlapping line
- for (; line0 && line0->yMax < line1->yMin; line0 = line0->next) ;
-
- // check each vertically overlapping line -- look for the nearest
- // on each side
- line1->xSpaceL = 0;
- line1->xSpaceR = pageWidth;
- for (line2 = line0;
- line2 && line2->yMin < line1->yMax;
- line2 = line2->next) {
- if (line2->yMax > line1->yMin) {
- if (line2->xMax < line1->xMin) {
- if (line2->xMax > line1->xSpaceL) {
- line1->xSpaceL = line2->xMax;
- }
- } else if (line2->xMin > line1->xMax) {
- if (line2->xMin < line1->xSpaceR) {
- line1->xSpaceR = line2->xMin;
+ // create a new block
+ word0 = pool->getPool(startBaseIdx);
+ pool->setPool(startBaseIdx, word0->next);
+ word0->next = NULL;
+ blk = new TextBlock(this, rot);
+ blk->addWord(word0);
+
+ fontSize = word0->fontSize;
+ minBase = maxBase = word0->base;
+ colSpace = minColSpacing * fontSize;
+ lineSpace = maxLineSpacingDelta * fontSize;
+ intraLineSpace = maxIntraLineDelta * fontSize;
+
+ // add words to the block
+ do {
+ found = gFalse;
+
+ // look for words on the line above the current top edge of
+ // the block
+ newMinBase = minBase;
+ for (baseIdx = pool->getBaseIdx(minBase);
+ baseIdx >= pool->getBaseIdx(minBase - lineSpace);
+ --baseIdx) {
+ word0 = NULL;
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base < minBase &&
+ word1->base >= minBase - lineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMin < blk->xMax && word1->xMax > blk->xMin)
+ : (word1->yMin < blk->yMax && word1->yMax > blk->yMin)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta1 * fontSize) {
+ word2 = word1;
+ if (word0) {
+ word0->next = word1->next;
+ } else {
+ pool->setPool(baseIdx, word1->next);
+ }
+ word1 = word1->next;
+ word2->next = NULL;
+ blk->addWord(word2);
+ found = gTrue;
+ newMinBase = word2->base;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
}
}
}
- }
- }
- } // (!rawOrder)
-
-#if 0 // for debugging
- printf("*** lines in yx order ***\n");
- for (line0 = lines; line0; line0 = line0->next) {
- printf("[line: x=%.2f..%.2f y=%.2f..%.2f base=%.2f xSpaceL=%.2f xSpaceR=%.2f len=%d]\n",
- line0->xMin, line0->xMax, line0->yMin, line0->yMax,
- line0->yBase, line0->xSpaceL, line0->xSpaceR, line0->len);
- for (word0 = line0->words; word0; word0 = word0->next) {
- printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSz=%.2f space=%d: '",
- word0->xMin, word0->xMax, word0->yMin, word0->yMax,
- word0->yBase, word0->fontSize, word0->spaceAfter);
- for (i = 0; i < word0->len; ++i) {
- fputc(word0->text[i] & 0xff, stdout);
- }
- printf("'\n");
- }
- }
- printf("\n");
- fflush(stdout);
-#endif
-
- lineList = lines;
- yxBlocks = NULL;
- blk0 = NULL;
- while (lineList) {
-
- // build a new block object
- line0 = lineList;
- lineList = lineList->next;
- line0->next = NULL;
- blk1 = new TextBlock();
- blk1->lines = line0;
- blk1->xMin = line0->xMin;
- blk1->xMax = line0->xMax;
- blk1->yMin = line0->yMin;
- blk1->yMax = line0->yMax;
- blk1->xSpaceL = line0->xSpaceL;
- blk1->xSpaceR = line0->xSpaceR;
- blk1->maxFontSize = line0->fontSize;
-
- // find subsequent lines in the block
- while (lineList) {
-
- // look for the first horizontally overlapping line below this
- // one
- yLimit = line0->yMax + blkMaxSpacing * line0->fontSize;
- line3 = line4 = NULL;
- if (rawOrder) {
- if (lineList->yMin < yLimit &&
- lineList->xMax > blk1->xMin &&
- lineList->xMin < blk1->xMax) {
- line3 = NULL;
- line4 = lineList;
+ minBase = newMinBase;
+
+ // look for words on the line below the current bottom edge of
+ // the block
+ newMaxBase = maxBase;
+ for (baseIdx = pool->getBaseIdx(maxBase);
+ baseIdx <= pool->getBaseIdx(maxBase + lineSpace);
+ ++baseIdx) {
+ word0 = NULL;
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base > maxBase &&
+ word1->base <= maxBase + lineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMin < blk->xMax && word1->xMax > blk->xMin)
+ : (word1->yMin < blk->yMax && word1->yMax > blk->yMin)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta1 * fontSize) {
+ word2 = word1;
+ if (word0) {
+ word0->next = word1->next;
+ } else {
+ pool->setPool(baseIdx, word1->next);
+ }
+ word1 = word1->next;
+ word2->next = NULL;
+ blk->addWord(word2);
+ found = gTrue;
+ newMaxBase = word2->base;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
+ }
}
- } else {
- for (line1 = NULL, line2 = lineList;
- line2 && line2->yMin < yLimit;
- line1 = line2, line2 = line2->next) {
- if (line2->xMax > blk1->xMin &&
- line2->xMin < blk1->xMax) {
- line3 = line1;
- line4 = line2;
- break;
+ maxBase = newMaxBase;
+
+ // look for words that are on lines already in the block, and
+ // that overlap the block horizontally
+ for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace);
+ baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace);
+ ++baseIdx) {
+ word0 = NULL;
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ 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)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta2 * fontSize) {
+ word2 = word1;
+ if (word0) {
+ word0->next = word1->next;
+ } else {
+ pool->setPool(baseIdx, word1->next);
+ }
+ word1 = word1->next;
+ word2->next = NULL;
+ blk->addWord(word2);
+ found = gTrue;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
}
}
- }
- // if there is an overlapping line and it fits in the block, add
- // it to the block
- if (line4 && blockFit(blk1, line4)) {
- if (line3) {
- line3->next = line4->next;
- } else {
- lineList = line4->next;
- }
- line0->next = line0->flowNext = line4;
- line4->next = NULL;
- if (line4->xMin < blk1->xMin) {
- blk1->xMin = line4->xMin;
- } else if (line4->xMax > blk1->xMax) {
- blk1->xMax = line4->xMax;
+ // only check for outlying words (the next two chunks of code)
+ // if we didn't find anything else
+ if (found) {
+ continue;
}
- if (line4->yMax > blk1->yMax) {
- blk1->yMax = line4->yMax;
+
+ // scan down the left side of the block, looking for words
+ // that are near (but not overlapping) the block; if there are
+ // three or fewer, add them to the block
+ n = 0;
+ for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace);
+ baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace);
+ ++baseIdx) {
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base >= minBase - intraLineSpace &&
+ word1->base <= maxBase + intraLineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMax <= blk->xMin &&
+ word1->xMax > blk->xMin - colSpace)
+ : (word1->yMax <= blk->yMin &&
+ word1->yMax > blk->yMin - colSpace)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta3 * fontSize) {
+ ++n;
+ break;
+ }
+ word1 = word1->next;
+ }
}
- if (line4->xSpaceL > blk1->xSpaceL) {
- blk1->xSpaceL = line4->xSpaceL;
+ if (n > 0 && n <= 3) {
+ for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace);
+ baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace);
+ ++baseIdx) {
+ word0 = NULL;
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base >= minBase - intraLineSpace &&
+ word1->base <= maxBase + intraLineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMax <= blk->xMin &&
+ word1->xMax > blk->xMin - colSpace)
+ : (word1->yMax <= blk->yMin &&
+ word1->yMax > blk->yMin - colSpace)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta3 * fontSize) {
+ word2 = word1;
+ if (word0) {
+ word0->next = word1->next;
+ } else {
+ pool->setPool(baseIdx, word1->next);
+ }
+ word1 = word1->next;
+ word2->next = NULL;
+ blk->addWord(word2);
+ if (word2->base < minBase) {
+ minBase = word2->base;
+ } else if (word2->base > maxBase) {
+ maxBase = word2->base;
+ }
+ found = gTrue;
+ break;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
+ }
+ }
}
- if (line4->xSpaceR < blk1->xSpaceR) {
- blk1->xSpaceR = line4->xSpaceR;
+
+ // scan down the right side of the block, looking for words
+ // that are near (but not overlapping) the block; if there are
+ // three or fewer, add them to the block
+ n = 0;
+ for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace);
+ baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace);
+ ++baseIdx) {
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base >= minBase - intraLineSpace &&
+ word1->base <= maxBase + intraLineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMin >= blk->xMax &&
+ word1->xMin < blk->xMax + colSpace)
+ : (word1->yMin >= blk->yMax &&
+ word1->yMin < blk->yMax + colSpace)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta3 * fontSize) {
+ ++n;
+ break;
+ }
+ word1 = word1->next;
+ }
}
- if (line4->fontSize > blk1->maxFontSize) {
- blk1->maxFontSize = line4->fontSize;
+ if (n > 0 && n <= 3) {
+ for (baseIdx = pool->getBaseIdx(minBase - intraLineSpace);
+ baseIdx <= pool->getBaseIdx(maxBase + intraLineSpace);
+ ++baseIdx) {
+ word0 = NULL;
+ word1 = pool->getPool(baseIdx);
+ while (word1) {
+ if (word1->base >= minBase - intraLineSpace &&
+ word1->base <= maxBase + intraLineSpace &&
+ ((rot == 0 || rot == 2)
+ ? (word1->xMin >= blk->xMax &&
+ word1->xMin < blk->xMax + colSpace)
+ : (word1->yMin >= blk->yMax &&
+ word1->yMin < blk->yMax + colSpace)) &&
+ fabs(word1->fontSize - fontSize) <
+ maxBlockFontSizeDelta3 * fontSize) {
+ word2 = word1;
+ if (word0) {
+ word0->next = word1->next;
+ } else {
+ pool->setPool(baseIdx, word1->next);
+ }
+ word1 = word1->next;
+ word2->next = NULL;
+ blk->addWord(word2);
+ if (word2->base < minBase) {
+ minBase = word2->base;
+ } else if (word2->base > maxBase) {
+ maxBase = word2->base;
+ }
+ found = gTrue;
+ break;
+ } else {
+ word0 = word1;
+ word1 = word1->next;
+ }
+ }
+ }
}
- line0 = line4;
- // otherwise, we're done with this block
+ } while (found);
+
+ //~ need to compute the primary writing mode (horiz/vert) in
+ //~ addition to primary rotation
+
+ // coalesce the block, and add it to the list
+ blk->coalesce(uMap);
+ if (lastBlk) {
+ lastBlk->next = blk;
} else {
- break;
+ blkList = blk;
+ }
+ lastBlk = blk;
+ count[rot] += blk->charCount;
+ if (primaryRot < 0 || count[rot] > count[primaryRot]) {
+ primaryRot = rot;
}
+ ++nBlocks;
}
+ }
- // insert block on list, in yx order
- if (rawOrder) {
- blk2 = blk0;
- blk3 = NULL;
- blk0 = blk1;
- } else {
- for (blk2 = NULL, blk3 = yxBlocks;
- blk3 && !blk1->yxBefore(blk3);
- blk2 = blk3, blk3 = blk3->next) ;
- }
- blk1->next = blk3;
- if (blk2) {
- blk2->next = blk1;
- } else {
- yxBlocks = blk1;
- }
+#if 0 // for debugging
+ printf("*** rotation ***\n");
+ for (rot = 0; rot < 4; ++rot) {
+ printf(" %d: %6d\n", rot, count[rot]);
}
+ printf(" primary rot = %d\n", primaryRot);
+ printf("\n");
+#endif
#if 0 // for debugging
- printf("*** blocks in yx order ***\n");
- for (blk0 = yxBlocks; blk0; blk0 = blk0->next) {
- printf("[block: x=%.2f..%.2f y=%.2f..%.2f]\n",
- blk0->xMin, blk0->xMax, blk0->yMin, blk0->yMax);
- for (line0 = blk0->lines; line0; line0 = line0->next) {
- printf(" [line: x=%.2f..%.2f y=%.2f..%.2f base=%.2f len=%d]\n",
- line0->xMin, line0->xMax, line0->yMin, line0->yMax,
- line0->yBase, line0->len);
- for (word0 = line0->words; word0; word0 = word0->next) {
- printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f space=%d: '",
+ printf("*** blocks ***\n");
+ for (blk = blkList; blk; blk = blk->next) {
+ printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f\n",
+ blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax);
+ for (line = blk->lines; line; line = line->next) {
+ printf(" line: x=%.2f..%.2f y=%.2f..%.2f base=%.2f\n",
+ line->xMin, line->xMax, line->yMin, line->yMax, line->base);
+ for (word0 = line->words; word0; word0 = word0->next) {
+ printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '",
word0->xMin, word0->xMax, word0->yMin, word0->yMax,
- word0->yBase, word0->spaceAfter);
+ word0->base, word0->fontSize, word0->spaceAfter);
for (i = 0; i < word0->len; ++i) {
fputc(word0->text[i] & 0xff, stdout);
}
@@ -1164,148 +2294,109 @@ void TextPage::coalesce(GBool physLayout) {
}
}
printf("\n");
- fflush(stdout);
#endif
- //----- merge lines and blocks, sort blocks into reading order
-
- if (rawOrder) {
- blocks = yxBlocks;
-
- } else {
- blocks = NULL;
- blk0 = NULL;
- blkStack = NULL;
- while (yxBlocks) {
-
- // find the next two blocks:
- // - if the depth-first traversal stack is empty, take the first
- // (upper-left-most) two blocks on the yx-sorted block list
- // - otherwise, find the two upper-left-most blocks under the top
- // block on the stack
- if (blkStack) {
- blk3 = blk4 = blk5 = blk6 = NULL;
- for (blk1 = NULL, blk2 = yxBlocks;
- blk2;
- blk1 = blk2, blk2 = blk2->next) {
- if (blk2->yMin > blkStack->yMin &&
- blk2->xMax > blkStack->xMin &&
- blk2->xMin < blkStack->xMax) {
- if (!blk4 || blk2->yxBefore(blk4)) {
- blk5 = blk3;
- blk6 = blk4;
- blk3 = blk1;
- blk4 = blk2;
- } else if (!blk6 || blk2->yxBefore(blk6)) {
- blk5 = blk1;
- blk6 = blk2;
- }
+ // determine the primary direction
+ lrCount = 0;
+ for (blk = blkList; blk; blk = blk->next) {
+ for (line = blk->lines; line; line = line->next) {
+ for (word0 = line->words; word0; word0 = word0->next) {
+ for (i = 0; i < word0->len; ++i) {
+ if (unicodeTypeL(word0->text[i])) {
+ ++lrCount;
+ } else if (unicodeTypeR(word0->text[i])) {
+ --lrCount;
}
}
- } else {
- blk3 = NULL;
- blk4 = yxBlocks;
- blk5 = yxBlocks;
- blk6 = yxBlocks->next;
}
+ }
+ }
+ primaryLR = lrCount >= 0;
- // merge case 1:
- // | | |
- // | blkStack | | blkStack
- // +---------------------+ --> +--------------
- // +------+ +------+ +-----------+
- // | blk4 | | blk6 | ... | blk4+blk6 |
- // +------+ +------+ +-----------+
- yLimit = 0; // make gcc happy
- if (blkStack) {
- yLimit = blkStack->yMax + blkMaxSpacing * blkStack->lines->fontSize;
- }
- if (blkStack && blk4 && blk6 &&
- !blk4->lines->next && !blk6->lines->next &&
- lineFit2(blk4->lines, blk6->lines) &&
- blk4->yMin < yLimit &&
- blk4->xMin > blkStack->xSpaceL &&
- blkStack->xMin > blk4->xSpaceL &&
- blk6->xMax < blkStack->xSpaceR) {
- blk4->mergeRight(blk6);
- if (blk5) {
- blk5->next = blk6->next;
+#if 0 // for debugging
+ printf("*** direction ***\n");
+ printf("lrCount = %d\n", lrCount);
+ printf("primaryLR = %d\n", primaryLR);
+#endif
+
+ //----- column assignment
+
+ // sort blocks into xy order for column assignment
+ blocks = (TextBlock **)gmalloc(nBlocks * sizeof(TextBlock *));
+ for (blk = blkList, i = 0; blk; blk = blk->next, ++i) {
+ blocks[i] = blk;
+ }
+ qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpXYPrimaryRot);
+
+ // column assignment
+ for (i = 0; i < nBlocks; ++i) {
+ blk0 = blocks[i];
+ col1 = 0;
+ for (j = 0; j < i; ++j) {
+ blk1 = blocks[j];
+ col2 = 0; // make gcc happy
+ switch (primaryRot) {
+ case 0:
+ if (blk0->xMin > blk1->xMax) {
+ col2 = blk1->col + blk1->nColumns + 3;
} else {
- yxBlocks = blk6->next;
+ col2 = blk1->col + (int)(((blk0->xMin - blk1->xMin) /
+ (blk1->xMax - blk1->xMin)) *
+ blk1->nColumns);
}
- delete blk6;
-
- // merge case 2:
- // | | | |
- // | blkStack | | |
- // +---------------------+ --> | blkStack+blk2 |
- // +---------------------+ | |
- // | blk4 | | |
- // | | | |
- } else if (blkStack && blk4 &&
- blk4->yMin < yLimit &&
- blockFit2(blkStack, blk4)) {
- blkStack->mergeBelow(blk4);
- if (blk3) {
- blk3->next = blk4->next;
+ break;
+ case 1:
+ if (blk0->yMin > blk1->yMax) {
+ col2 = blk1->col + blk1->nColumns + 3;
} else {
- yxBlocks = blk4->next;
+ col2 = blk1->col + (int)(((blk0->yMin - blk1->yMin) /
+ (blk1->yMax - blk1->yMin)) *
+ blk1->nColumns);
}
- delete blk4;
-
- // if any of:
- // 1. no block found
- // 2. non-fully overlapping block found
- // 3. large vertical gap above the overlapping block
- // then pop the stack and try again
- } else if (!blk4 ||
- (blkStack && (blk4->xMin < blkStack->xSpaceL ||
- blk4->xMax > blkStack->xSpaceR ||
- blk4->yMin - blkStack->yMax >
- blkMaxSortSpacing * blkStack->maxFontSize))) {
- blkStack = blkStack->stackNext;
-
- // add a block to the sorted list
- } else {
-
- // remove the block from the yx-sorted list
- if (blk3) {
- blk3->next = blk4->next;
+ break;
+ case 2:
+ if (blk0->xMax < blk1->xMin) {
+ col2 = blk1->col + blk1->nColumns + 3;
} else {
- yxBlocks = blk4->next;
+ col2 = blk1->col + (int)(((blk0->xMax - blk1->xMax) /
+ (blk1->xMin - blk1->xMax)) *
+ blk1->nColumns);
}
- blk4->next = NULL;
-
- // append the block to the reading-order list
- if (blk0) {
- blk0->next = blk4;
+ break;
+ case 3:
+ if (blk0->yMax < blk1->yMin) {
+ col2 = blk1->col + blk1->nColumns + 3;
} else {
- blocks = blk4;
- }
- blk0 = blk4;
-
- // push the block on the traversal stack
- if (!physLayout) {
- blk4->stackNext = blkStack;
- blkStack = blk4;
+ col2 = blk1->col + (int)(((blk0->yMax - blk1->yMax) /
+ (blk1->yMin - blk1->yMax)) *
+ blk1->nColumns);
}
+ break;
+ }
+ if (col2 > col1) {
+ col1 = col2;
+ }
+ }
+ blk0->col = col1;
+ for (line = blk0->lines; line; line = line->next) {
+ for (j = 0; j <= line->len; ++j) {
+ line->col[j] += col1;
}
}
- } // (!rawOrder)
+ }
#if 0 // for debugging
- printf("*** blocks in reading order (after merging) ***\n");
- for (blk0 = blocks; blk0; blk0 = blk0->next) {
- printf("[block: x=%.2f..%.2f y=%.2f..%.2f]\n",
- blk0->xMin, blk0->xMax, blk0->yMin, blk0->yMax);
- for (line0 = blk0->lines; line0; line0 = line0->next) {
- printf(" [line: x=%.2f..%.2f y=%.2f..%.2f base=%.2f len=%d]\n",
- line0->xMin, line0->xMax, line0->yMin, line0->yMax,
- line0->yBase, line0->len);
- for (word0 = line0->words; word0; word0 = word0->next) {
- printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f space=%d: '",
+ printf("*** blocks, after column assignment ***\n");
+ for (blk = blkList; blk; blk = blk->next) {
+ printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f col=%d nCols=%d\n",
+ blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax, blk->col,
+ blk->nColumns);
+ for (line = blk->lines; line; line = line->next) {
+ printf(" line:\n");
+ for (word0 = line->words; word0; word0 = word0->next) {
+ printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '",
word0->xMin, word0->xMax, word0->yMin, word0->yMax,
- word0->yBase, word0->spaceAfter);
+ word0->base, word0->fontSize, word0->spaceAfter);
for (i = 0; i < word0->len; ++i) {
fputc(word0->text[i] & 0xff, stdout);
}
@@ -1314,118 +2405,152 @@ void TextPage::coalesce(GBool physLayout) {
}
}
printf("\n");
- fflush(stdout);
#endif
- //----- assemble blocks into flows
+ //----- reading order sort
- if (rawOrder) {
+ // sort blocks into yx order (in preparation for reading order sort)
+ qsort(blocks, nBlocks, sizeof(TextBlock *), &TextBlock::cmpYXPrimaryRot);
- // one flow per block
- flow0 = NULL;
- while (blocks) {
- flow1 = new TextFlow();
- flow1->blocks = blocks;
- flow1->lines = blocks->lines;
- flow1->yMin = blocks->yMin;
- flow1->yMax = blocks->yMax;
- blocks = blocks->next;
- flow1->blocks->next = NULL;
- if (flow0) {
- flow0->next = flow1;
- } else {
- flows = flow1;
+ // compute space on left and right sides of each block
+ for (i = 0; i < nBlocks; ++i) {
+ blk0 = blocks[i];
+ for (j = 0; j < nBlocks; ++j) {
+ blk1 = blocks[j];
+ if (blk1 != blk0) {
+ blk0->updatePriMinMax(blk1);
}
- flow0 = flow1;
}
+ }
- } else {
-
- // compute whitespace above and below each block
- for (blk0 = blocks; blk0; blk0 = blk0->next) {
- blk0->ySpaceT = 0;
- blk0->ySpaceB = pageHeight;
-
- // check each horizontally overlapping block
- for (blk1 = blocks; blk1; blk1 = blk1->next) {
- if (blk1 != blk0 &&
- blk1->xMin < blk0->xMax &&
- blk1->xMax > blk0->xMin) {
- if (blk1->yMax < blk0->yMin) {
- if (blk1->yMax > blk0->ySpaceT) {
- blk0->ySpaceT = blk1->yMax;
- }
- } else if (blk1->yMin > blk0->yMax) {
- if (blk1->yMin < blk0->ySpaceB) {
- blk0->ySpaceB = blk1->yMin;
- }
- }
+#if 0 // for debugging
+ printf("*** blocks, after yx sort ***\n");
+ for (i = 0; i < nBlocks; ++i) {
+ blk = blocks[i];
+ printf("block: rot=%d x=%.2f..%.2f y=%.2f..%.2f space=%.2f..%.2f\n",
+ blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax,
+ blk->priMin, blk->priMax);
+ for (line = blk->lines; line; line = line->next) {
+ printf(" line:\n");
+ for (word0 = line->words; word0; word0 = word0->next) {
+ printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '",
+ word0->xMin, word0->xMax, word0->yMin, word0->yMax,
+ word0->base, word0->fontSize, word0->spaceAfter);
+ for (j = 0; j < word0->len; ++j) {
+ fputc(word0->text[j] & 0xff, stdout);
}
+ printf("'\n");
}
}
+ }
+ printf("\n");
+#endif
- flow0 = NULL;
- while (blocks) {
-
- // build a new flow object
- flow1 = new TextFlow();
- flow1->blocks = blocks;
- flow1->lines = blocks->lines;
- flow1->yMin = blocks->yMin;
- flow1->yMax = blocks->yMax;
- flow1->ySpaceT = blocks->ySpaceT;
- flow1->ySpaceB = blocks->ySpaceB;
-
- // find subsequent blocks in the flow
- for (blk1 = blocks, blk2 = blocks->next;
- blk2 && flowFit(flow1, blk2);
- blk1 = blk2, blk2 = blk2->next) {
- if (blk2->yMin < flow1->yMin) {
- flow1->yMin = blk2->yMin;
- }
- if (blk2->yMax > flow1->yMax) {
- flow1->yMax = blk2->yMax;
- }
- if (blk2->ySpaceT > flow1->ySpaceT) {
- flow1->ySpaceT = blk2->ySpaceT;
+ // build the flows
+ //~ this needs to be adjusted for writing mode (vertical text)
+ //~ this also needs to account for right-to-left column ordering
+ blkArray = (TextBlock **)gmalloc(nBlocks * sizeof(TextBlock *));
+ memcpy(blkArray, blocks, nBlocks * sizeof(TextBlock *));
+ flows = lastFlow = NULL;
+ firstBlkIdx = 0;
+ nBlocksLeft = nBlocks;
+ while (nBlocksLeft > 0) {
+
+ // find the upper-left-most block
+ for (; !blkArray[firstBlkIdx]; ++firstBlkIdx) ;
+ i = firstBlkIdx;
+ blk = blkArray[i];
+ for (j = firstBlkIdx + 1; j < nBlocks; ++j) {
+ blk1 = blkArray[j];
+ if (blk1) {
+ if (blk && blk->secondaryDelta(blk1) > 0) {
+ break;
}
- if (blk2->ySpaceB < flow1->ySpaceB) {
- flow1->ySpaceB = blk2->ySpaceB;
+ if (blk1->primaryCmp(blk) < 0) {
+ i = j;
+ blk = blk1;
}
- for (line1 = blk1->lines; line1->next; line1 = line1->next) ;
- line1->flowNext = blk2->lines;
}
+ }
+ blkArray[i] = NULL;
+ --nBlocksLeft;
+ blk->next = NULL;
- // chop the block list
- blocks = blk1->next;
- blk1->next = NULL;
+ // create a new flow, starting with the upper-left-most block
+ flow = new TextFlow(this, blk);
+ if (lastFlow) {
+ lastFlow->next = flow;
+ } else {
+ flows = flow;
+ }
+ lastFlow = flow;
+ fontSize = blk->lines->words->fontSize;
+
+ // push the upper-left-most block on the stack
+ blk->stackNext = NULL;
+ blkStack = blk;
+
+ // find the other blocks in this flow
+ while (blkStack) {
+
+ // find the upper-left-most block under (but within
+ // maxBlockSpacing of) the top block on the stack
+ blkSpace = maxBlockSpacing * blkStack->lines->words->fontSize;
+ blk = NULL;
+ i = -1;
+ for (j = firstBlkIdx; j < nBlocks; ++j) {
+ blk1 = blkArray[j];
+ if (blk1) {
+ if (blkStack->secondaryDelta(blk1) > blkSpace) {
+ break;
+ }
+ if (blk && blk->secondaryDelta(blk1) > 0) {
+ break;
+ }
+ if (blk1->isBelow(blkStack) &&
+ (!blk || blk1->primaryCmp(blk) < 0)) {
+ i = j;
+ blk = blk1;
+ }
+ }
+ }
- // append the flow to the list
- if (flow0) {
- flow0->next = flow1;
+ // if a suitable block was found, add it to the flow and push it
+ // onto the stack
+ if (blk && flow->blockFits(blk, blkStack)) {
+ blkArray[i] = NULL;
+ --nBlocksLeft;
+ blk->next = NULL;
+ flow->addBlock(blk);
+ fontSize = blk->lines->words->fontSize;
+ blk->stackNext = blkStack;
+ blkStack = blk;
+
+ // otherwise (if there is no block under the top block or the
+ // block is not suitable), pop the stack
} else {
- flows = flow1;
+ blkStack = blkStack->stackNext;
}
- flow0 = flow1;
}
}
+ gfree(blkArray);
#if 0 // for debugging
printf("*** flows ***\n");
- for (flow0 = flows; flow0; flow0 = flow0->next) {
- printf("[flow]\n");
- for (blk0 = flow0->blocks; blk0; blk0 = blk0->next) {
- printf(" [block: x=%.2f..%.2f y=%.2f..%.2f ySpaceT=%.2f ySpaceB=%.2f]\n",
- blk0->xMin, blk0->xMax, blk0->yMin, blk0->yMax,
- blk0->ySpaceT, blk0->ySpaceB);
- for (line0 = blk0->lines; line0; line0 = line0->next) {
- printf(" [line: x=%.2f..%.2f y=%.2f..%.2f base=%.2f len=%d]\n",
- line0->xMin, line0->xMax, line0->yMin, line0->yMax,
- line0->yBase, line0->len);
- for (word0 = line0->words; word0; word0 = word0->next) {
- printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f space=%d: '",
+ for (flow = flows; flow; flow = flow->next) {
+ printf("flow: x=%.2f..%.2f y=%.2f..%.2f pri:%.2f..%.2f\n",
+ flow->xMin, flow->xMax, flow->yMin, flow->yMax,
+ flow->priMin, flow->priMax);
+ for (blk = flow->blocks; blk; blk = blk->next) {
+ printf(" block: rot=%d x=%.2f..%.2f y=%.2f..%.2f pri=%.2f..%.2f\n",
+ blk->rot, blk->xMin, blk->xMax, blk->yMin, blk->yMax,
+ blk->priMin, blk->priMax);
+ for (line = blk->lines; line; line = line->next) {
+ printf(" line:\n");
+ for (word0 = line->words; word0; word0 = word0->next) {
+ printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f fontSize=%.2f space=%d: '",
word0->xMin, word0->xMax, word0->yMin, word0->yMax,
- word0->yBase, word0->spaceAfter);
+ word0->base, word0->fontSize, word0->spaceAfter);
for (i = 0; i < word0->len; ++i) {
fputc(word0->text[i] & 0xff, stdout);
}
@@ -1435,288 +2560,159 @@ void TextPage::coalesce(GBool physLayout) {
}
}
printf("\n");
- fflush(stdout);
#endif
- //----- sort lines into yx order
-
- // (the block/line merging process doesn't maintain the full-page
- // linked list of lines)
-
- lines = NULL;
- if (rawOrder) {
- line0 = NULL;
- for (flow0 = flows; flow0; flow0 = flow0->next) {
- for (line1 = flow0->lines; line1; line1 = line1->flowNext) {
- if (line0) {
- line0->pageNext = line1;
- } else {
- lines = line1;
- }
- line0 = line1;
- }
- }
- } else {
- for (flow0 = flows; flow0; flow0 = flow0->next) {
- for (line0 = flow0->lines; line0; line0 = line0->flowNext) {
- for (line1 = NULL, line2 = lines;
- line2 && !line0->yxBefore(line2);
- line1 = line2, line2 = line2->pageNext) ;
- if (line1) {
- line1->pageNext = line0;
- } else {
- lines = line0;
- }
- line0->pageNext = line2;
- }
- }
- }
-
-#if 0 // for debugging
- printf("*** lines in yx order ***\n");
- for (line0 = lines; line0; line0 = line0->pageNext) {
- printf("[line: x=%.2f..%.2f y=%.2f..%.2f base=%.2f xSpaceL=%.2f xSpaceR=%.2f col=%d len=%d]\n",
- line0->xMin, line0->xMax, line0->yMin, line0->yMax,
- line0->yBase, line0->xSpaceL, line0->xSpaceR, line0->col[0],
- line0->len);
- for (word0 = line0->words; word0; word0 = word0->next) {
- printf(" word: x=%.2f..%.2f y=%.2f..%.2f base=%.2f space=%d: '",
- word0->xMin, word0->xMax, word0->yMin, word0->yMax,
- word0->yBase, word0->spaceAfter);
- for (i = 0; i < word0->len; ++i) {
- fputc(word0->text[i] & 0xff, stdout);
- }
- printf("'\n");
- }
- }
- printf("\n");
- fflush(stdout);
-#endif
-}
-
-// If <word> can be added the end of <line>, return the absolute value
-// of the difference between <line>'s baseline and <word>'s baseline,
-// and set *<space> to the horizontal space between the current last
-// word in <line> and <word>. A smaller return value indicates a
-// better fit. Otherwise, return a negative number.
-double TextPage::lineFit(TextLine *line, TextWord *word, double *space) {
- TextWord *lastWord;
- double fontSize0, fontSize1;
- double dx, dxLimit;
-
- lastWord = line->lastWord;
- fontSize0 = line->fontSize;
- fontSize1 = word->fontSize;
- dx = word->xMin - lastWord->xMax;
- dxLimit = fontSize0 * lastWord->font->maxSpaceWidth;
-
- // check inter-word spacing
- if (dx < fontSize0 * lineMinDeltaX ||
- dx > dxLimit) {
- return -1;
- }
-
- if (
- // look for adjacent words with close baselines and close font sizes
- (fabs(line->yBase - word->yBase) < lineMaxBaselineDelta * fontSize0 &&
- fontSize0 < lineMaxFontSizeRatio * fontSize1 &&
- fontSize1 < lineMaxFontSizeRatio * fontSize0) ||
-
- // look for a superscript
- (fontSize1 > lineMinSuperscriptFontSizeRatio * fontSize0 &&
- fontSize1 < lineMaxSuperscriptFontSizeRatio * fontSize0 &&
- (word->yMax < lastWord->yMax ||
- word->yBase < lastWord->yBase) &&
- word->yMax - lastWord->yMin > lineMinSuperscriptOverlap * fontSize0 &&
- dx < fontSize0 * lineMaxSuperscriptDeltaX) ||
-
- // look for a subscript
- (fontSize1 > lineMinSubscriptFontSizeRatio * fontSize0 &&
- fontSize1 < lineMaxSubscriptFontSizeRatio * fontSize0 &&
- (word->yMin > lastWord->yMin ||
- word->yBase > lastWord->yBase) &&
- line->yMax - word->yMin > lineMinSubscriptOverlap * fontSize0 &&
- dx < fontSize0 * lineMaxSubscriptDeltaX)) {
-
- *space = dx;
- return fabs(word->yBase - line->yBase);
- }
-
- return -1;
-}
-
-// Returns true if <line0> and <line1> can be merged into a single
-// line, ignoring max word spacing.
-GBool TextPage::lineFit2(TextLine *line0, TextLine *line1) {
- double fontSize0, fontSize1;
- double dx;
-
- fontSize0 = line0->fontSize;
- fontSize1 = line1->fontSize;
- dx = line1->xMin - line0->xMax;
-
- // check inter-word spacing
- if (dx < fontSize0 * lineMinDeltaX) {
- return gFalse;
- }
-
- // look for close baselines and close font sizes
- if (fabs(line0->yBase - line1->yBase) < lineMaxBaselineDelta * fontSize0 &&
- fontSize0 < lineMaxFontSizeRatio * fontSize1 &&
- fontSize1 < lineMaxFontSizeRatio * fontSize0) {
- return gTrue;
+ if (uMap) {
+ uMap->decRefCnt();
}
-
- return gFalse;
}
-// Returns true if <line> can be added to <blk>. Assumes the y
-// coordinates are within range.
-GBool TextPage::blockFit(TextBlock *blk, TextLine *line) {
- double fontSize0, fontSize1;
-
- // check edges
- if (line->xMin < blk->xSpaceL ||
- line->xMax > blk->xSpaceR ||
- blk->xMin < line->xSpaceL ||
- blk->xMax > line->xSpaceR) {
- return gFalse;
- }
-
- // check font sizes
- fontSize0 = blk->lines->fontSize;
- fontSize1 = line->fontSize;
- if (fontSize0 > blkMaxFontSizeRatio * fontSize1 ||
- fontSize1 > blkMaxFontSizeRatio * fontSize0) {
- return gFalse;
- }
-
- return gTrue;
-}
+GBool TextPage::findText(Unicode *s, int len,
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
+ double *xMin, double *yMin,
+ double *xMax, double *yMax) {
+ TextBlock *blk;
+ TextLine *line;
+ Unicode *p;
+ Unicode u1, u2;
+ int m, i, j, k;
+ double xStart, yStart, xStop, yStop;
+ double xMin0, yMin0, xMax0, yMax0;
+ double xMin1, yMin1, xMax1, yMax1;
+ GBool found;
-// Returns true if <blk0> and <blk1> can be merged into a single
-// block. Assumes the y coordinates are within range.
-GBool TextPage::blockFit2(TextBlock *blk0, TextBlock *blk1) {
- double fontSize0, fontSize1;
+ //~ needs to handle right-to-left text
- // check edges
- if (blk1->xMin < blk0->xSpaceL ||
- blk1->xMax > blk0->xSpaceR ||
- blk0->xMin < blk1->xSpaceL ||
- blk0->xMax > blk1->xSpaceR) {
+ if (rawOrder) {
return gFalse;
}
- // check font sizes
- fontSize0 = blk0->lines->fontSize;
- fontSize1 = blk1->lines->fontSize;
- if (fontSize0 > blkMaxFontSizeRatio * fontSize1 ||
- fontSize1 > blkMaxFontSizeRatio * fontSize0) {
- return gFalse;
+ xStart = yStart = xStop = yStop = 0;
+ if (startAtLast && haveLastFind) {
+ xStart = lastFindXMin;
+ yStart = lastFindYMin;
+ } else if (!startAtTop) {
+ xStart = *xMin;
+ yStart = *yMin;
}
-
- return gTrue;
-}
-
-// Returns true if <blk> can be added to <flow>.
-GBool TextPage::flowFit(TextFlow *flow, TextBlock *blk) {
- double dy;
-
- // check whitespace above and below
- if (blk->yMin < flow->ySpaceT ||
- blk->yMax > flow->ySpaceB ||
- flow->yMin < blk->ySpaceT ||
- flow->yMax > blk->ySpaceB) {
- return gFalse;
+ if (stopAtLast && haveLastFind) {
+ xStop = lastFindXMin;
+ yStop = lastFindYMin;
+ } else if (!stopAtBottom) {
+ xStop = *xMax;
+ yStop = *yMax;
}
- // check that block top edge is within +/- dy of flow top edge,
- // and that block bottom edge is above flow bottom edge + dy
- dy = flowMaxDeltaY * flow->blocks->maxFontSize;
- return blk->yMin > flow->yMin - dy &&
- blk->yMin < flow->yMin + dy &&
- blk->yMax < flow->yMax + dy;
-}
+ found = gFalse;
+ xMin0 = xMax0 = yMin0 = yMax0 = 0; // make gcc happy
+ xMin1 = xMax1 = yMin1 = yMax1 = 0; // make gcc happy
+ for (i = 0; i < nBlocks; ++i) {
+ blk = blocks[i];
-GBool TextPage::findText(Unicode *s, int len,
- GBool top, GBool bottom,
- double *xMin, double *yMin,
- double *xMax, double *yMax) {
- TextLine *line;
- Unicode *p;
- Unicode u1, u2;
- int m, i, j;
- double x0, x1, x;
-
- // scan all text on the page
- for (line = lines; line; line = line->pageNext) {
-
- // check: above top limit?
- if (!top && (line->yMax < *yMin ||
- (line->yMin < *yMin && line->xMax <= *xMin))) {
+ // check: is the block above the top limit?
+ if (!startAtTop && blk->yMax < yStart) {
continue;
}
- // check: below bottom limit?
- if (!bottom && (line->yMin > *yMax ||
- (line->yMax > *yMax && line->xMin >= *xMax))) {
- return gFalse;
+ // check: is the block below the bottom limit?
+ if (!stopAtBottom && blk->yMin > yStop) {
+ break;
}
- // search each position in this line
- m = line->len;
- for (i = 0, p = line->text; i <= m - len; ++i, ++p) {
-
- x0 = (i == 0) ? line->xMin : line->xRight[i-1];
- x1 = line->xRight[i];
- x = 0.5 * (x0 + x1);
+ for (line = blk->lines; line; line = line->next) {
- // check: above top limit?
- if (!top && line->yMin < *yMin) {
- if (x < *xMin) {
- continue;
- }
+ // check: is the line above the top limit?
+ if (!startAtTop && line->yMin < yStart) {
+ continue;
}
- // check: below bottom limit?
- if (!bottom && line->yMax > *yMax) {
- if (x > *xMax) {
- return gFalse;
- }
+ // check: is the line below the bottom limit?
+ if (!stopAtBottom && line->yMin > yStop) {
+ continue;
}
- // compare the strings
- for (j = 0; j < len; ++j) {
+ // search each position in this line
+ m = line->len;
+ for (j = 0, p = line->text; j <= m - len; ++j, ++p) {
+
+ // compare the strings
+ for (k = 0; k < len; ++k) {
#if 1 //~ this lowercases Latin A-Z only -- this will eventually be
//~ extended to handle other character sets
- if (p[j] >= 0x41 && p[j] <= 0x5a) {
- u1 = p[j] + 0x20;
- } else {
- u1 = p[j];
- }
- if (s[j] >= 0x41 && s[j] <= 0x5a) {
- u2 = s[j] + 0x20;
- } else {
- u2 = s[j];
- }
+ if (p[k] >= 0x41 && p[k] <= 0x5a) {
+ u1 = p[k] + 0x20;
+ } else {
+ u1 = p[k];
+ }
+ if (s[k] >= 0x41 && s[k] <= 0x5a) {
+ u2 = s[k] + 0x20;
+ } else {
+ u2 = s[k];
+ }
#endif
- if (u1 != u2) {
- break;
+ if (u1 != u2) {
+ break;
+ }
}
- }
- // found it
- if (j == len) {
- *xMin = x0;
- *xMax = line->xRight[i + len - 1];
- *yMin = line->yMin;
- *yMax = line->yMax;
- return gTrue;
+ // found it
+ if (k == len) {
+ switch (line->rot) {
+ case 0:
+ xMin1 = line->edge[j];
+ xMax1 = line->edge[j + len];
+ yMin1 = line->yMin;
+ yMax1 = line->yMax;
+ break;
+ case 1:
+ xMin1 = line->xMin;
+ xMax1 = line->xMax;
+ yMin1 = line->edge[j];
+ yMax1 = line->edge[j + len];
+ break;
+ case 2:
+ xMin1 = line->edge[j + len];
+ xMax1 = line->edge[j];
+ yMin1 = line->yMin;
+ yMax1 = line->yMax;
+ break;
+ case 3:
+ xMin1 = line->xMin;
+ xMax1 = line->xMax;
+ yMin1 = line->edge[j + len];
+ yMax1 = line->edge[j];
+ break;
+ }
+ if ((startAtTop ||
+ yMin1 > yStart || (yMin1 == yStart && xMin1 > xStart)) &&
+ (stopAtBottom ||
+ yMin1 < yStop || (yMin1 == yStop && xMin1 < yStop))) {
+ if (!found || yMin1 < yMin0 || (yMin1 == yMin0 && xMin1 < xMin0)) {
+ xMin0 = xMin1;
+ xMax0 = xMax1;
+ yMin0 = yMin1;
+ yMax0 = yMax1;
+ found = gTrue;
+ }
+ }
+ }
}
}
}
+ if (found) {
+ *xMin = xMin0;
+ *xMax = xMax0;
+ *yMin = yMin0;
+ *yMax = yMax0;
+ lastFindXMin = xMin0;
+ lastFindYMin = yMin0;
+ haveLastFind = gTrue;
+ return gTrue;
+ }
+
return gFalse;
}
@@ -1725,15 +2721,24 @@ GString *TextPage::getText(double xMin, double yMin,
GString *s;
UnicodeMap *uMap;
GBool isUnicode;
- char space[8], eol[16], buf[8];
- int spaceLen, eolLen, len;
- TextLine *line, *prevLine;
- double x0, x1, y;
- int firstCol, col, i;
- GBool multiLine;
+ TextBlock *blk;
+ TextLine *line;
+ TextLineFrag *frags;
+ int nFrags, fragsSize;
+ TextLineFrag *frag;
+ char space[8], eol[16];
+ int spaceLen, eolLen;
+ int lastRot;
+ double x, y;
+ int col, idx0, idx1, i, j;
+ GBool multiLine, oneRot;
s = new GString();
+ if (rawOrder) {
+ return s;
+ }
+
// get the output encoding
if (!(uMap = globalParams->getTextEncoding())) {
return s;
@@ -1754,109 +2759,173 @@ GString *TextPage::getText(double xMin, double yMin,
break;
}
- // find the leftmost column
- firstCol = -1;
- for (line = lines; line; line = line->pageNext) {
- if (line->yMin > yMax) {
- break;
- }
- if (line->yMax < yMin ||
- line->xMax < xMin ||
- line->xMin > xMax) {
- continue;
- }
-
- y = 0.5 * (line->yMin + line->yMax);
- if (y < yMin || y > yMax) {
- continue;
- }
-
- i = 0;
- while (i < line->len) {
- x0 = (i==0) ? line->xMin : line->xRight[i-1];
- x1 = line->xRight[i];
- if (0.5 * (x0 + x1) > xMin) {
- break;
+ //~ writing mode (horiz/vert)
+
+ // collect the line fragments that are in the rectangle
+ fragsSize = 256;
+ frags = (TextLineFrag *)gmalloc(fragsSize * sizeof(TextLineFrag));
+ nFrags = 0;
+ lastRot = -1;
+ oneRot = gTrue;
+ for (i = 0; i < nBlocks; ++i) {
+ blk = blocks[i];
+ if (xMin < blk->xMax && blk->xMin < xMax &&
+ yMin < blk->yMax && blk->yMin < yMax) {
+ for (line = blk->lines; line; line = line->next) {
+ if (xMin < line->xMax && line->xMin < xMax &&
+ yMin < line->yMax && line->yMin < yMax) {
+ idx0 = idx1 = -1;
+ switch (line->rot) {
+ case 0:
+ y = 0.5 * (line->yMin + line->yMax);
+ if (yMin < y && y < yMax) {
+ j = 0;
+ while (j < line->len) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) > xMin) {
+ idx0 = j;
+ break;
+ }
+ ++j;
+ }
+ j = line->len - 1;
+ while (j >= 0) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) < xMax) {
+ idx1 = j;
+ break;
+ }
+ --j;
+ }
+ }
+ break;
+ case 1:
+ x = 0.5 * (line->xMin + line->xMax);
+ if (xMin < x && x < xMax) {
+ j = 0;
+ while (j < line->len) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) > yMin) {
+ idx0 = j;
+ break;
+ }
+ ++j;
+ }
+ j = line->len - 1;
+ while (j >= 0) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) < yMax) {
+ idx1 = j;
+ break;
+ }
+ --j;
+ }
+ }
+ break;
+ case 2:
+ y = 0.5 * (line->yMin + line->yMax);
+ if (yMin < y && y < yMax) {
+ j = 0;
+ while (j < line->len) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) < xMax) {
+ idx0 = j;
+ break;
+ }
+ ++j;
+ }
+ j = line->len - 1;
+ while (j >= 0) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) > xMin) {
+ idx1 = j;
+ break;
+ }
+ --j;
+ }
+ }
+ break;
+ case 3:
+ x = 0.5 * (line->xMin + line->xMax);
+ if (xMin < x && x < xMax) {
+ j = 0;
+ while (j < line->len) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) < yMax) {
+ idx0 = j;
+ break;
+ }
+ ++j;
+ }
+ j = line->len - 1;
+ while (j >= 0) {
+ if (0.5 * (line->edge[j] + line->edge[j+1]) > yMin) {
+ idx1 = j;
+ break;
+ }
+ --j;
+ }
+ }
+ break;
+ }
+ if (idx0 >= 0 && idx1 >= 0) {
+ if (nFrags == fragsSize) {
+ fragsSize *= 2;
+ frags = (TextLineFrag *)
+ grealloc(frags, fragsSize * sizeof(TextLineFrag));
+ }
+ frags[nFrags].init(line, idx0, idx1 - idx0 + 1);
+ ++nFrags;
+ if (lastRot >= 0 && line->rot != lastRot) {
+ oneRot = gFalse;
+ }
+ lastRot = line->rot;
+ }
+ }
}
- ++i;
- }
- if (i == line->len) {
- continue;
- }
- col = line->col[i];
-
- if (firstCol < 0 || col < firstCol) {
- firstCol = col;
}
}
- // extract the text
- col = firstCol;
- multiLine = gFalse;
- prevLine = NULL;
- for (line = lines; line; line = line->pageNext) {
- if (line->yMin > yMax) {
- break;
- }
- if (line->yMax < yMin ||
- line->xMax < xMin ||
- line->xMin > xMax) {
- continue;
- }
+ // sort the fragments and generate the string
+ if (nFrags > 0) {
- y = 0.5 * (line->yMin + line->yMax);
- if (y < yMin || y > yMax) {
- continue;
+ for (i = 0; i < nFrags; ++i) {
+ frags[i].computeCoords(oneRot);
}
+ assignColumns(frags, nFrags, oneRot);
- i = 0;
- while (i < line->len) {
- x0 = (i==0) ? line->xMin : line->xRight[i-1];
- x1 = line->xRight[i];
- if (0.5 * (x0 + x1) > xMin) {
- break;
- }
- ++i;
- }
- if (i == line->len) {
- continue;
- }
-
- // insert a return
- if (line->col[i] < col ||
- (prevLine &&
- line->yMin >
- prevLine->yMax - lineOverlapSlack * prevLine->fontSize)) {
- s->append(eol, eolLen);
- col = firstCol;
- multiLine = gTrue;
- }
- prevLine = line;
-
- // line this block up with the correct column
- for (; col < line->col[i]; ++col) {
- s->append(space, spaceLen);
+ // if all lines in the region have the same rotation, use it;
+ // otherwise, use the page's primary rotation
+ if (oneRot) {
+ qsort(frags, nFrags, sizeof(TextLineFrag),
+ &TextLineFrag::cmpYXLineRot);
+ } else {
+ qsort(frags, nFrags, sizeof(TextLineFrag),
+ &TextLineFrag::cmpYXPrimaryRot);
}
- // print the portion of the line
- for (; i < line->len; ++i) {
+ col = 0;
+ multiLine = gFalse;
+ for (i = 0; i < nFrags; ++i) {
+ frag = &frags[i];
+
+ // insert a return
+ if (frag->col < col ||
+ (i > 0 && fabs(frag->base - frags[i-1].base) >
+ maxIntraLineDelta * frags[i-1].line->words->fontSize)) {
+ s->append(eol, eolLen);
+ col = 0;
+ multiLine = gTrue;
+ }
- x0 = (i==0) ? line->xMin : line->xRight[i-1];
- x1 = line->xRight[i];
- if (0.5 * (x0 + x1) > xMax) {
- break;
+ // column alignment
+ for (; col < frag->col; ++col) {
+ s->append(space, spaceLen);
}
- len = uMap->mapUnicode(line->text[i], buf, sizeof(buf));
- s->append(buf, len);
- col += isUnicode ? 1 : len;
+ // get the fragment text
+ col += dumpFragment(frag->line->text + frag->start, frag->len, uMap, s);
}
- }
- if (multiLine) {
- s->append(eol, eolLen);
+ if (multiLine) {
+ s->append(eol, eolLen);
+ }
}
+ gfree(frags);
uMap->decRefCnt();
return s;
@@ -1865,58 +2934,107 @@ GString *TextPage::getText(double xMin, double yMin,
GBool TextPage::findCharRange(int pos, int length,
double *xMin, double *yMin,
double *xMax, double *yMax) {
+ TextBlock *blk;
TextLine *line;
TextWord *word;
- double x;
+ double xMin0, xMax0, yMin0, yMax0;
+ double xMin1, xMax1, yMin1, yMax1;
GBool first;
- int i;
+ int i, j0, j1;
+
+ if (rawOrder) {
+ return gFalse;
+ }
//~ this doesn't correctly handle:
//~ - ranges split across multiple lines (the highlighted region
//~ is the bounding box of all the parts of the range)
//~ - cases where characters don't convert one-to-one into Unicode
first = gTrue;
- for (line = lines; line; line = line->pageNext) {
- for (word = line->words; word; word = word->next) {
- if (pos < word->charPos + word->charLen &&
- word->charPos < pos + length) {
- i = pos - word->charPos;
- if (i < 0) {
- i = 0;
- }
- x = (i == 0) ? word->xMin : word->xRight[i - 1];
- if (first || x < *xMin) {
- *xMin = x;
- }
- i = pos + length - word->charPos;
- if (i >= word->len) {
- i = word->len - 1;
- }
- x = word->xRight[i];
- if (first || x > *xMax) {
- *xMax = x;
- }
- if (first || word->yMin < *yMin) {
- *yMin = word->yMin;
- }
- if (first || word->yMax > *yMax) {
- *yMax = word->yMax;
+ xMin0 = xMax0 = yMin0 = yMax0 = 0; // make gcc happy
+ xMin1 = xMax1 = yMin1 = yMax1 = 0; // make gcc happy
+ for (i = 0; i < nBlocks; ++i) {
+ blk = blocks[i];
+ for (line = blk->lines; line; line = line->next) {
+ for (word = line->words; word; word = word->next) {
+ if (pos < word->charPos + word->charLen &&
+ word->charPos < pos + length) {
+ j0 = pos - word->charPos;
+ if (j0 < 0) {
+ j0 = 0;
+ }
+ j1 = pos + length - 1 - word->charPos;
+ if (j1 >= word->len) {
+ j1 = word->len - 1;
+ }
+ switch (line->rot) {
+ case 0:
+ xMin1 = word->edge[j0];
+ xMax1 = word->edge[j1 + 1];
+ yMin1 = word->yMin;
+ yMax1 = word->yMax;
+ break;
+ case 1:
+ xMin1 = word->xMin;
+ xMax1 = word->xMax;
+ yMin1 = word->edge[j0];
+ yMax1 = word->edge[j1 + 1];
+ break;
+ case 2:
+ xMin1 = word->edge[j1 + 1];
+ xMax1 = word->edge[j0];
+ yMin1 = word->yMin;
+ yMax1 = word->yMax;
+ break;
+ case 3:
+ xMin1 = word->xMin;
+ xMax1 = word->xMax;
+ yMin1 = word->edge[j1 + 1];
+ yMax1 = word->edge[j0];
+ break;
+ }
+ if (first || xMin1 < xMin0) {
+ xMin0 = xMin1;
+ }
+ if (first || xMax1 > xMax0) {
+ xMax0 = xMax1;
+ }
+ if (first || yMin1 < yMin0) {
+ yMin0 = yMin1;
+ }
+ if (first || yMax1 > yMax0) {
+ yMax0 = yMax1;
+ }
+ first = gFalse;
}
- first = gFalse;
}
}
}
- return !first;
+ if (!first) {
+ *xMin = xMin0;
+ *xMax = xMax0;
+ *yMin = yMin0;
+ *yMax = yMax0;
+ return gTrue;
+ }
+ return gFalse;
}
void TextPage::dump(void *outputStream, TextOutputFunc outputFunc,
GBool physLayout) {
UnicodeMap *uMap;
- char space[8], eol[16], eop[8], buf[8];
- int spaceLen, eolLen, eopLen, len;
TextFlow *flow;
+ TextBlock *blk;
TextLine *line;
- int col, d, n, i;
+ TextLineFrag *frags;
+ TextWord *word;
+ int nFrags, fragsSize;
+ TextLineFrag *frag;
+ char space[8], eol[16], eop[8];
+ int spaceLen, eolLen, eopLen;
+ GBool pageBreaks;
+ GString *s;
+ int col, i, d, n;
// get the output encoding
if (!(uMap = globalParams->getTextEncoding())) {
@@ -1937,69 +3055,119 @@ void TextPage::dump(void *outputStream, TextOutputFunc outputFunc,
break;
}
eopLen = uMap->mapUnicode(0x0c, eop, sizeof(eop));
+ pageBreaks = globalParams->getTextPageBreaks();
- // output the page, maintaining the original physical layout
- if (physLayout || rawOrder) {
- col = 0;
- for (line = lines; line; line = line->pageNext) {
+ //~ writing mode (horiz/vert)
- // line this block up with the correct column
- if (!rawOrder) {
- for (; col < line->col[0]; ++col) {
+ // output the page in raw (content stream) order
+ if (rawOrder) {
+
+ for (word = rawWords; word; word = word->next) {
+ s = new GString();
+ dumpFragment(word->text, word->len, uMap, s);
+ (*outputFunc)(outputStream, s->getCString(), s->getLength());
+ delete s;
+ if (word->next &&
+ fabs(word->next->base - word->base) <
+ maxIntraLineDelta * word->fontSize) {
+ if (word->next->xMin > word->xMax + minWordSpacing * word->fontSize) {
(*outputFunc)(outputStream, space, spaceLen);
}
+ } else {
+ (*outputFunc)(outputStream, eol, eolLen);
}
+ }
- // print the line
- for (i = 0; i < line->len; ++i) {
- len = uMap->mapUnicode(line->text[i], buf, sizeof(buf));
- (*outputFunc)(outputStream, buf, len);
+ // output the page, maintaining the original physical layout
+ } else if (physLayout) {
+
+ // collect the line fragments for the page and sort them
+ fragsSize = 256;
+ frags = (TextLineFrag *)gmalloc(fragsSize * sizeof(TextLineFrag));
+ nFrags = 0;
+ for (i = 0; i < nBlocks; ++i) {
+ blk = blocks[i];
+ for (line = blk->lines; line; line = line->next) {
+ if (nFrags == fragsSize) {
+ fragsSize *= 2;
+ frags = (TextLineFrag *)grealloc(frags,
+ fragsSize * sizeof(TextLineFrag));
+ }
+ frags[nFrags].init(line, 0, line->len);
+ frags[nFrags].computeCoords(gTrue);
+ ++nFrags;
}
- col += line->convertedLen;
+ }
+ qsort(frags, nFrags, sizeof(TextLineFrag), &TextLineFrag::cmpYXPrimaryRot);
- // print one or more returns if necessary
- if (rawOrder ||
- !line->pageNext ||
- line->pageNext->col[0] < col ||
- line->pageNext->yMin >
- line->yMax - lineOverlapSlack * line->fontSize) {
-
- // compute number of returns
- d = 1;
- if (line->pageNext) {
- d += (int)((line->pageNext->yMin - line->yMax) /
- line->fontSize + 0.5);
- }
+ // generate output
+ col = 0;
+ for (i = 0; i < nFrags; ++i) {
+ frag = &frags[i];
+
+ // column alignment
+ for (; col < frag->col; ++col) {
+ (*outputFunc)(outputStream, space, spaceLen);
+ }
- // various things (weird font matrices) can result in bogus
- // values here, so do a sanity check
- if (d < 1) {
+ // print the line
+ s = new GString();
+ col += dumpFragment(frag->line->text + frag->start, frag->len, uMap, s);
+ (*outputFunc)(outputStream, s->getCString(), s->getLength());
+ delete s;
+
+ // print one or more returns if necessary
+ if (i == nFrags - 1 ||
+ frags[i+1].col < col ||
+ fabs(frags[i+1].base - frag->base) >
+ maxIntraLineDelta * frag->line->words->fontSize) {
+ if (i < nFrags - 1) {
+ d = (int)((frags[i+1].base - frag->base) /
+ frag->line->words->fontSize);
+ if (d < 1) {
+ d = 1;
+ } else if (d > 5) {
+ d = 5;
+ }
+ } else {
d = 1;
- } else if (d > 5) {
- d = 5;
}
for (; d > 0; --d) {
(*outputFunc)(outputStream, eol, eolLen);
}
-
col = 0;
}
}
+ gfree(frags);
+
// output the page, "undoing" the layout
} else {
for (flow = flows; flow; flow = flow->next) {
- for (line = flow->lines; line; line = line->flowNext) {
- n = line->len;
- if (line->flowNext && line->hyphenated) {
- --n;
- }
- for (i = 0; i < n; ++i) {
- len = uMap->mapUnicode(line->text[i], buf, sizeof(buf));
- (*outputFunc)(outputStream, buf, len);
- }
- if (line->flowNext && !line->hyphenated) {
- (*outputFunc)(outputStream, space, spaceLen);
+ for (blk = flow->blocks; blk; blk = blk->next) {
+ for (line = blk->lines; line; line = line->next) {
+ n = line->len;
+ if (line->hyphenated && (line->next || blk->next)) {
+ --n;
+ }
+ s = new GString();
+ dumpFragment(line->text, n, uMap, s);
+ (*outputFunc)(outputStream, s->getCString(), s->getLength());
+ delete s;
+ if (!line->hyphenated) {
+ if (line->next) {
+ (*outputFunc)(outputStream, space, spaceLen);
+ } else if (blk->next) {
+ //~ this is a bit of a kludge - we should really do a more
+ //~ intelligent determination of paragraphs
+ if (blk->next->lines->words->fontSize ==
+ blk->lines->words->fontSize) {
+ (*outputFunc)(outputStream, space, spaceLen);
+ } else {
+ (*outputFunc)(outputStream, eol, eolLen);
+ }
+ }
+ }
}
}
(*outputFunc)(outputStream, eol, eolLen);
@@ -2008,56 +3176,196 @@ void TextPage::dump(void *outputStream, TextOutputFunc outputFunc,
}
// end of page
- (*outputFunc)(outputStream, eop, eopLen);
- (*outputFunc)(outputStream, eol, eolLen);
+ if (pageBreaks) {
+ (*outputFunc)(outputStream, eop, eopLen);
+ (*outputFunc)(outputStream, eol, eolLen);
+ }
uMap->decRefCnt();
}
-void TextPage::startPage(GfxState *state) {
- clear();
- if (state) {
- pageWidth = state->getPageWidth();
- pageHeight = state->getPageHeight();
+void TextPage::assignColumns(TextLineFrag *frags, int nFrags, GBool oneRot) {
+ TextLineFrag *frag0, *frag1;
+ int rot, col1, col2, i, j, k;
+
+ // all text in the region has the same rotation -- recompute the
+ // column numbers based only on the text in the region
+ if (oneRot) {
+ qsort(frags, nFrags, sizeof(TextLineFrag), &TextLineFrag::cmpXYLineRot);
+ rot = frags[0].line->rot;
+ for (i = 0; i < nFrags; ++i) {
+ frag0 = &frags[i];
+ col1 = 0;
+ for (j = 0; j < i; ++j) {
+ frag1 = &frags[j];
+ col2 = 0; // make gcc happy
+ switch (rot) {
+ case 0:
+ if (frag0->xMin >= frag1->xMax) {
+ col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+ frag1->line->col[frag1->start]) + 1;
+ } else {
+ for (k = frag1->start;
+ k < frag1->start + frag1->len &&
+ frag0->xMin >= 0.5 * (frag1->line->edge[k] +
+ frag1->line->edge[k+1]);
+ ++k) ;
+ col2 = frag1->col +
+ frag1->line->col[k] - frag1->line->col[frag1->start];
+ }
+ break;
+ case 1:
+ if (frag0->yMin >= frag1->yMax) {
+ col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+ frag1->line->col[frag1->start]) + 1;
+ } else {
+ for (k = frag1->start;
+ k < frag1->start + frag1->len &&
+ frag0->yMin >= 0.5 * (frag1->line->edge[k] +
+ frag1->line->edge[k+1]);
+ ++k) ;
+ col2 = frag1->col +
+ frag1->line->col[k] - frag1->line->col[frag1->start];
+ }
+ break;
+ case 2:
+ if (frag0->xMax <= frag1->xMin) {
+ col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+ frag1->line->col[frag1->start]) + 1;
+ } else {
+ for (k = frag1->start;
+ k < frag1->start + frag1->len &&
+ frag0->xMax <= 0.5 * (frag1->line->edge[k] +
+ frag1->line->edge[k+1]);
+ ++k) ;
+ col2 = frag1->col +
+ frag1->line->col[k] - frag1->line->col[frag1->start];
+ }
+ break;
+ case 3:
+ if (frag0->yMax <= frag1->yMin) {
+ col2 = frag1->col + (frag1->line->col[frag1->start + frag1->len] -
+ frag1->line->col[frag1->start]) + 1;
+ } else {
+ for (k = frag1->start;
+ k < frag1->start + frag1->len &&
+ frag0->yMax <= 0.5 * (frag1->line->edge[k] +
+ frag1->line->edge[k+1]);
+ ++k) ;
+ col2 = frag1->col +
+ frag1->line->col[k] - frag1->line->col[frag1->start];
+ }
+ break;
+ }
+ if (col2 > col1) {
+ col1 = col2;
+ }
+ }
+ frag0->col = col1;
+ }
+
+ // the region includes text at different rotations -- use the
+ // globally assigned column numbers, offset by the minimum column
+ // number (i.e., shift everything over to column 0)
} else {
- pageWidth = pageHeight = 0;
+ col1 = frags[0].col;
+ for (i = 1; i < nFrags; ++i) {
+ if (frags[i].col < col1) {
+ col1 = frags[i].col;
+ }
+ }
+ for (i = 0; i < nFrags; ++i) {
+ frags[i].col -= col1;
+ }
}
}
-void TextPage::clear() {
- TextWord *w1, *w2;
- TextFlow *f1, *f2;
+int TextPage::dumpFragment(Unicode *text, int len, UnicodeMap *uMap,
+ GString *s) {
+ char lre[8], rle[8], popdf[8], buf[8];
+ int lreLen, rleLen, popdfLen, n;
+ int nCols, i, j, k;
+
+ nCols = 0;
+
+ if (uMap->isUnicode()) {
+
+ lreLen = uMap->mapUnicode(0x202a, lre, sizeof(lre));
+ rleLen = uMap->mapUnicode(0x202b, rle, sizeof(rle));
+ popdfLen = uMap->mapUnicode(0x202c, popdf, sizeof(popdf));
+
+ if (primaryLR) {
+
+ i = 0;
+ while (i < len) {
+ // output a left-to-right section
+ for (j = i; j < len && !unicodeTypeR(text[j]); ++j) ;
+ for (k = i; k < j; ++k) {
+ n = uMap->mapUnicode(text[k], buf, sizeof(buf));
+ s->append(buf, n);
+ ++nCols;
+ }
+ i = j;
+ // output a right-to-left section
+ for (j = i; j < len && !unicodeTypeL(text[j]); ++j) ;
+ if (j > i) {
+ s->append(rle, rleLen);
+ for (k = j - 1; k >= i; --k) {
+ n = uMap->mapUnicode(text[k], buf, sizeof(buf));
+ s->append(buf, n);
+ ++nCols;
+ }
+ s->append(popdf, popdfLen);
+ i = j;
+ }
+ }
+
+ } else {
+
+ s->append(rle, rleLen);
+ i = len - 1;
+ while (i >= 0) {
+ // output a right-to-left section
+ for (j = i; j >= 0 && !unicodeTypeL(text[j]); --j) ;
+ for (k = i; k > j; --k) {
+ n = uMap->mapUnicode(text[k], buf, sizeof(buf));
+ s->append(buf, n);
+ ++nCols;
+ }
+ i = j;
+ // output a left-to-right section
+ for (j = i; j >= 0 && !unicodeTypeR(text[j]); --j) ;
+ if (j < i) {
+ s->append(lre, lreLen);
+ for (k = j + 1; k <= i; ++k) {
+ n = uMap->mapUnicode(text[k], buf, sizeof(buf));
+ s->append(buf, n);
+ ++nCols;
+ }
+ s->append(popdf, popdfLen);
+ i = j;
+ }
+ }
+ s->append(popdf, popdfLen);
- if (curWord) {
- delete curWord;
- curWord = NULL;
- }
- if (words) {
- for (w1 = words; w1; w1 = w2) {
- w2 = w1->next;
- delete w1;
}
- } else if (flows) {
- for (f1 = flows; f1; f1 = f2) {
- f2 = f1->next;
- delete f1;
+
+ } else {
+ for (i = 0; i < len; ++i) {
+ n = uMap->mapUnicode(text[i], buf, sizeof(buf));
+ s->append(buf, n);
+ nCols += n;
}
}
- deleteGList(fonts, TextFontInfo);
-
- curWord = NULL;
- charPos = 0;
- font = NULL;
- fontSize = 0;
- nest = 0;
- nTinyChars = 0;
- words = wordPtr = NULL;
- lines = NULL;
- flows = NULL;
- fonts = new GList();
+ return nCols;
}
+#if TEXTOUT_WORD_LIST
+TextWordList *TextPage::makeWordList(GBool physLayout) {
+ return new TextWordList(this, physLayout);
+}
+#endif
//------------------------------------------------------------------------
// TextOutputDev
@@ -2153,10 +3461,12 @@ void TextOutputDev::drawChar(GfxState *state, double x, double y,
}
GBool TextOutputDev::findText(Unicode *s, int len,
- GBool top, GBool bottom,
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
double *xMin, double *yMin,
double *xMax, double *yMax) {
- return text->findText(s, len, top, bottom, xMin, yMin, xMax, yMax);
+ return text->findText(s, len, startAtTop, stopAtBottom,
+ startAtLast, stopAtLast, xMin, yMin, xMax, yMax);
}
GString *TextOutputDev::getText(double xMin, double yMin,
@@ -2170,4 +3480,8 @@ GBool TextOutputDev::findCharRange(int pos, int length,
return text->findCharRange(pos, length, xMin, yMin, xMax, yMax);
}
-
+#if TEXTOUT_WORD_LIST
+TextWordList *TextOutputDev::makeWordList() {
+ return text->makeWordList(physLayout);
+}
+#endif
diff --git a/pdf/xpdf/TextOutputDev.h b/pdf/xpdf/TextOutputDev.h
index e0c22c2..b501907 100644
--- a/pdf/xpdf/TextOutputDev.h
+++ b/pdf/xpdf/TextOutputDev.h
@@ -24,12 +24,12 @@ class GString;
class GList;
class GfxFont;
class GfxState;
+class UnicodeMap;
//------------------------------------------------------------------------
typedef void (*TextOutputFunc)(void *stream, char *text, int len);
-
//------------------------------------------------------------------------
// TextFontInfo
//------------------------------------------------------------------------
@@ -45,13 +45,9 @@ public:
private:
GfxFont *gfxFont;
- double horizScaling;
-
- double minSpaceWidth; // min width for inter-word space, as a
- // fraction of the font size
- double maxSpaceWidth; // max width for inter-word space, as a
- // fraction of the font size
-
+#if TEXTOUT_WORD_LIST
+ GString *fontName;
+#endif
friend class TextWord;
friend class TextPage;
@@ -65,9 +61,8 @@ class TextWord {
public:
// Constructor.
- TextWord(GfxState *state, double x0, double y0, int charPosA,
- TextFontInfo *fontA, double fontSize);
-
+ TextWord(GfxState *state, int rotA, double x0, double y0,
+ int charPosA, TextFontInfo *fontA, double fontSize);
// Destructor.
~TextWord();
@@ -76,19 +71,44 @@ public:
void addChar(GfxState *state, double x, double y,
double dx, double dy, Unicode u);
+ // Merge <word> onto the end of <this>.
+ void merge(TextWord *word);
+
+ // Compares <this> to <word>, returning -1 (<), 0 (=), or +1 (>),
+ // based on a primary-axis comparison, e.g., x ordering if rot=0.
+ int primaryCmp(TextWord *word);
+
+ // Return the distance along the primary axis between <this> and
+ // <word>.
+ double primaryDelta(TextWord *word);
+
+ static int cmpYX(const void *p1, const void *p2);
+
+#if TEXTOUT_WORD_LIST
+ int getLength() { return len; }
+ Unicode getChar(int idx) { return text[idx]; }
+ GString *getText();
+ GString *getFontName() { return font->fontName; }
+ void getColor(double *r, double *g, double *b)
+ { *r = colorR; *g = colorG; *b = colorB; }
+ void getBBox(double *xMinA, double *yMinA, double *xMaxA, double *yMaxA)
+ { *xMinA = xMin; *yMinA = yMin; *xMaxA = xMax; *yMaxA = yMax; }
+ int getCharPos() { return charPos; }
+ int getCharLen() { return charLen; }
+#endif
private:
- GBool xyBefore(TextWord *word2);
- void merge(TextWord *word2);
-
+ int rot; // rotation, multiple of 90 degrees
+ // (0, 1, 2, or 3)
double xMin, xMax; // bounding box x coordinates
double yMin, yMax; // bounding box y coordinates
- double yBase; // baseline y coordinate
+ double base; // baseline x or y coordinate
Unicode *text; // the text
- double *xRight; // right-hand x coord of each char
- int len; // length of text and xRight
- int size; // size of text and xRight arrays
+ double *edge; // "near" edge x or y coord of each char
+ // (plus one extra entry for the last char)
+ int len; // length of text and edge arrays
+ int size; // size of text and edge arrays
int charPos; // character position (within content stream)
int charLen; // number of content stream characters in
// this word
@@ -96,11 +116,49 @@ private:
double fontSize; // font size
GBool spaceAfter; // set if there is a space between this
// word and the next word on the line
- TextWord *next; // next word in line (before lines are
- // assembled: next word in xy order)
+ TextWord *next; // next word in line
+#if TEXTOUT_WORD_LIST
+ double colorR, // word color
+ colorG,
+ colorB;
+#endif
+ friend class TextPool;
friend class TextLine;
+ friend class TextBlock;
+ friend class TextFlow;
+ friend class TextWordList;
+ friend class TextPage;
+};
+
+//------------------------------------------------------------------------
+// TextPool
+//------------------------------------------------------------------------
+
+class TextPool {
+public:
+
+ TextPool();
+ ~TextPool();
+
+ TextWord *getPool(int baseIdx) { return pool[baseIdx - minBaseIdx]; }
+ void setPool(int baseIdx, TextWord *p) { pool[baseIdx - minBaseIdx] = p; }
+
+ int getBaseIdx(double base);
+
+ void addWord(TextWord *word);
+
+private:
+
+ int minBaseIdx; // min baseline bucket index
+ int maxBaseIdx; // max baseline bucket index
+ TextWord **pool; // array of linked lists, one for each
+ // baseline value (multiple of 4 pts)
+ TextWord *cursor; // pointer to last-accessed word
+ int cursorBaseIdx; // baseline bucket index of last-accessed word
+
+ friend class TextBlock;
friend class TextPage;
};
@@ -111,34 +169,53 @@ private:
class TextLine {
public:
- TextLine();
+ TextLine(TextBlock *blkA, int rotA, double baseA);
~TextLine();
-private:
+ void addWord(TextWord *word);
+
+ // Return the distance along the primary axis between <this> and
+ // <line>.
+ double primaryDelta(TextLine *line);
+
+ // Compares <this> to <line>, returning -1 (<), 0 (=), or +1 (>),
+ // based on a primary-axis comparison, e.g., x ordering if rot=0.
+ int primaryCmp(TextLine *line);
+
+ // Compares <this> to <line>, returning -1 (<), 0 (=), or +1 (>),
+ // based on a secondary-axis comparison of the baselines, e.g., y
+ // ordering if rot=0.
+ int secondaryCmp(TextLine *line);
- GBool yxBefore(TextLine *line2);
- void merge(TextLine *line2);
+ int cmpYX(TextLine *line);
+ static int cmpXY(const void *p1, const void *p2);
+
+ void coalesce(UnicodeMap *uMap);
+
+private:
+
+ TextBlock *blk; // parent block
+ int rot; // text rotation
double xMin, xMax; // bounding box x coordinates
double yMin, yMax; // bounding box y coordinates
- double yBase; // primary baseline y coordinate
- double xSpaceL, xSpaceR; // whitespace to left and right of this line
- TextFontInfo *font; // primary font
- double fontSize; // primary font size
+ double base; // baseline x or y coordinate
TextWord *words; // words in this line
TextWord *lastWord; // last word in this line
Unicode *text; // Unicode text of the line, including
// spaces between words
- double *xRight; // right-hand x coord of each Unicode char
+ double *edge; // "near" edge x or y coord of each char
+ // (plus one extra entry for the last char)
int *col; // starting column number of each Unicode char
int len; // number of Unicode chars
int convertedLen; // total number of converted characters
GBool hyphenated; // set if last char is a hyphen
- TextLine *pageNext; // next line on page
TextLine *next; // next line in block
- TextLine *flowNext; // next line in flow
+ friend class TextLineFrag;
friend class TextBlock;
+ friend class TextFlow;
+ friend class TextWordList;
friend class TextPage;
};
@@ -149,25 +226,52 @@ private:
class TextBlock {
public:
- TextBlock();
+ TextBlock(TextPage *pageA, int rotA);
~TextBlock();
-private:
+ void addWord(TextWord *word);
+
+ void coalesce(UnicodeMap *uMap);
+
+ // Update this block's priMin and priMax values, looking at <blk>.
+ void updatePriMinMax(TextBlock *blk);
+
+ static int cmpXYPrimaryRot(const void *p1, const void *p2);
- GBool yxBefore(TextBlock *blk2);
- void mergeRight(TextBlock *blk2);
- void mergeBelow(TextBlock *blk2);
+ static int cmpYXPrimaryRot(const void *p1, const void *p2);
+ int primaryCmp(TextBlock *blk);
+
+ double secondaryDelta(TextBlock *blk);
+
+ // Returns true if <this> is below <blk>, relative to the page's
+ // primary rotation.
+ GBool isBelow(TextBlock *blk);
+
+private:
+
+ TextPage *page; // the parent page
+ int rot; // text rotation
double xMin, xMax; // bounding box x coordinates
double yMin, yMax; // bounding box y coordinates
- double xSpaceL, xSpaceR; // whitespace to left and right of this block
- double ySpaceT, ySpaceB; // whitespace above and below this block
- double maxFontSize; // max primary font size
- TextLine *lines; // lines in block
- TextBlock *next; // next block in flow
- TextBlock *stackNext; // next block on traversal stack
+ double priMin, priMax; // whitespace bounding box along primary axis
+
+ TextPool *pool; // pool of words (used only until lines
+ // are built)
+ TextLine *lines; // linked list of lines
+ TextLine *curLine; // most recently added line
+ int nLines; // number of lines
+ int charCount; // number of characters in the block
+ int col; // starting column
+ int nColumns; // number of columns in the block
+ TextBlock *next;
+ TextBlock *stackNext;
+
+ friend class TextLine;
+ friend class TextLineFrag;
friend class TextFlow;
+ friend class TextWordList;
friend class TextPage;
};
@@ -178,20 +282,61 @@ private:
class TextFlow {
public:
- TextFlow();
+ TextFlow(TextPage *pageA, TextBlock *blk);
~TextFlow();
+ // Add a block to the end of this flow.
+ void addBlock(TextBlock *blk);
+
+ // Returns true if <blk> fits below <prevBlk> in the flow, i.e., (1)
+ // it uses a font no larger than the last block added to the flow,
+ // and (2) it fits within the flow's [priMin, priMax] along the
+ // primary axis.
+ GBool blockFits(TextBlock *blk, TextBlock *prevBlk);
+
private:
+ TextPage *page; // the parent page
+ double xMin, xMax; // bounding box x coordinates
double yMin, yMax; // bounding box y coordinates
- double ySpaceT, ySpaceB; // whitespace above and below this flow
+ double priMin, priMax; // whitespace bounding box along primary axis
TextBlock *blocks; // blocks in flow
- TextLine *lines; // lines in flow
- TextFlow *next; // next flow on page
+ TextBlock *lastBlk; // last block in this flow
+ TextFlow *next;
+ friend class TextWordList;
friend class TextPage;
};
+#if TEXTOUT_WORD_LIST
+
+//------------------------------------------------------------------------
+// TextWordList
+//------------------------------------------------------------------------
+
+class TextWordList {
+public:
+
+ // Build a flat word list, in content stream order (if
+ // text->rawOrder is true), physical layout order (if <physLayout>
+ // is true and text->rawOrder is false), or reading order (if both
+ // flags are false).
+ TextWordList(TextPage *text, GBool physLayout);
+
+ ~TextWordList();
+
+ // Return the number of words on the list.
+ int getLength();
+
+ // Return the <idx>th word from the list.
+ TextWord *get(int idx);
+
+private:
+
+ GList *words;
+};
+
+#endif // TEXTOUT_WORD_LIST
//------------------------------------------------------------------------
// TextPage
@@ -201,15 +346,17 @@ class TextPage {
public:
// Constructor.
- TextPage(GBool rawOrder);
+ TextPage(GBool rawOrderA);
// Destructor.
~TextPage();
+ // Start a new page.
+ void startPage(GfxState *state);
+
// Update the current font.
void updateFont(GfxState *state);
-
// Begin a new word.
void beginWord(GfxState *state, double x0, double y0);
@@ -224,17 +371,19 @@ public:
// Add a word, sorting it into the list of words.
void addWord(TextWord *word);
-
// Coalesce strings that look like parts of the same line.
void coalesce(GBool physLayout);
- // Find a string. If <top> is true, starts looking at top of page;
- // otherwise starts looking at <xMin>,<yMin>. If <bottom> is true,
- // stops looking at bottom of page; otherwise stops looking at
- // <xMax>,<yMax>. If found, sets the text bounding rectangle and
- // returns true; otherwise returns false.
+ // Find a string. If <startAtTop> is true, starts looking at the
+ // top of the page; else if <startAtLast> is true, starts looking
+ // immediately after the last find result; else starts looking at
+ // <xMin>,<yMin>. If <stopAtBottom> is true, stops looking at the
+ // bottom of the page; else if <stopAtLast> is true, stops looking
+ // just before the last find result; else stops looking at
+ // <xMax>,<yMax>.
GBool findText(Unicode *s, int len,
- GBool top, GBool bottom,
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
double *xMin, double *yMin,
double *xMax, double *yMax);
@@ -253,18 +402,19 @@ public:
void dump(void *outputStream, TextOutputFunc outputFunc,
GBool physLayout);
- // Start a new page.
- void startPage(GfxState *state);
-
+#if TEXTOUT_WORD_LIST
+ // Build a flat word list, in content stream order (if
+ // this->rawOrder is true), physical layout order (if <physLayout>
+ // is true and this->rawOrder is false), or reading order (if both
+ // flags are false).
+ TextWordList *makeWordList(GBool physLayout);
+#endif
private:
void clear();
- double lineFit(TextLine *line, TextWord *word, double *space);
- GBool lineFit2(TextLine *line0, TextLine *line1);
- GBool blockFit(TextBlock *blk, TextLine *line);
- GBool blockFit2(TextBlock *blk0, TextBlock *blk1);
- GBool flowFit(TextFlow *flow, TextBlock *blk);
+ void assignColumns(TextLineFrag *frags, int nFrags, int rot);
+ int dumpFragment(Unicode *text, int len, UnicodeMap *uMap, GString *s);
GBool rawOrder; // keep text in content stream order
@@ -272,22 +422,34 @@ private:
TextWord *curWord; // currently active string
int charPos; // next character position (within content
// stream)
- TextFontInfo *font; // current font
- double fontSize; // current font size
+ TextFontInfo *curFont; // current font
+ double curFontSize; // current font size
int nest; // current nesting level (for Type 3 fonts)
int nTinyChars; // number of "tiny" chars seen so far
- TextWord *words; // words, in xy order (before they're
- // sorted into lines)
- TextWord *wordPtr; // cursor for the word list
-
- TextLine *lines; // lines, in xy order
- TextFlow *flows; // flows, in reading order
+ TextPool *pools[4]; // a "pool" of TextWords for each rotation
+ TextFlow *flows; // linked list of flows
+ TextBlock **blocks; // array of blocks, in yx order
+ int nBlocks; // number of blocks
+ int primaryRot; // primary rotation
+ GBool primaryLR; // primary direction (true means L-to-R,
+ // false means R-to-L)
+ TextWord *rawWords; // list of words, in raw order (only if
+ // rawOrder is set)
+ TextWord *rawLastWord; // last word on rawWords list
GList *fonts; // all font info objects used on this
// page [TextFontInfo]
+ double lastFindXMin, // coordinates of the last "find" result
+ lastFindYMin;
+ GBool haveLastFind;
+ friend class TextLine;
+ friend class TextLineFrag;
+ friend class TextBlock;
+ friend class TextFlow;
+ friend class TextWordList;
};
//------------------------------------------------------------------------
@@ -353,17 +515,18 @@ public:
double originX, double originY,
CharCode c, Unicode *u, int uLen);
- //----- path painting
-
//----- special access
- // Find a string. If <top> is true, starts looking at top of page;
- // otherwise starts looking at <xMin>,<yMin>. If <bottom> is true,
- // stops looking at bottom of page; otherwise stops looking at
- // <xMax>,<yMax>. If found, sets the text bounding rectangle and
- // returns true; otherwise returns false.
+ // Find a string. If <startAtTop> is true, starts looking at the
+ // top of the page; else if <startAtLast> is true, starts looking
+ // immediately after the last find result; else starts looking at
+ // <xMin>,<yMin>. If <stopAtBottom> is true, stops looking at the
+ // bottom of the page; else if <stopAtLast> is true, stops looking
+ // just before the last find result; else stops looking at
+ // <xMax>,<yMax>.
GBool findText(Unicode *s, int len,
- GBool top, GBool bottom,
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
double *xMin, double *yMin,
double *xMax, double *yMax);
@@ -378,6 +541,13 @@ public:
double *xMin, double *yMin,
double *xMax, double *yMax);
+#if TEXTOUT_WORD_LIST
+ // Build a flat word list, in content stream order (if
+ // this->rawOrder is true), physical layout order (if
+ // this->physLayout is true and this->rawOrder is false), or reading
+ // order (if both flags are false).
+ TextWordList *makeWordList();
+#endif
private:
@@ -390,7 +560,6 @@ private:
// dumping text
GBool rawOrder; // keep text in content stream order
GBool ok; // set up ok?
-
};
#endif
diff --git a/pdf/xpdf/UnicodeMap.cc b/pdf/xpdf/UnicodeMap.cc
index e6284eb..300d802 100644
--- a/pdf/xpdf/UnicodeMap.cc
+++ b/pdf/xpdf/UnicodeMap.cc
@@ -116,6 +116,9 @@ UnicodeMap::UnicodeMap(GString *encodingNameA) {
eMaps = NULL;
eMapsLen = 0;
refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
}
UnicodeMap::UnicodeMap(char *encodingNameA, GBool unicodeOutA,
@@ -128,6 +131,9 @@ UnicodeMap::UnicodeMap(char *encodingNameA, GBool unicodeOutA,
eMaps = NULL;
eMapsLen = 0;
refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
}
UnicodeMap::UnicodeMap(char *encodingNameA, GBool unicodeOutA,
@@ -139,6 +145,9 @@ UnicodeMap::UnicodeMap(char *encodingNameA, GBool unicodeOutA,
eMaps = NULL;
eMapsLen = 0;
refCnt = 1;
+#if MULTITHREADED
+ gInitMutex(&mutex);
+#endif
}
UnicodeMap::~UnicodeMap() {
@@ -149,14 +158,32 @@ UnicodeMap::~UnicodeMap() {
if (eMaps) {
gfree(eMaps);
}
+#if MULTITHREADED
+ gDestroyMutex(&mutex);
+#endif
}
void UnicodeMap::incRefCnt() {
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
++refCnt;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
}
void UnicodeMap::decRefCnt() {
- if (--refCnt == 0) {
+ GBool done;
+
+#if MULTITHREADED
+ gLockMutex(&mutex);
+#endif
+ done = --refCnt == 0;
+#if MULTITHREADED
+ gUnlockMutex(&mutex);
+#endif
+ if (done) {
delete this;
}
}
@@ -175,29 +202,28 @@ int UnicodeMap::mapUnicode(Unicode u, char *buf, int bufSize) {
a = 0;
b = len;
- if (u < ranges[a].start) {
- return 0;
- }
- // invariant: ranges[a].start <= u < ranges[b].start
- while (b - a > 1) {
- m = (a + b) / 2;
- if (u >= ranges[m].start) {
- a = m;
- } else if (u < ranges[m].start) {
- b = m;
- }
- }
- if (u <= ranges[a].end) {
- n = ranges[a].nBytes;
- if (n > bufSize) {
- return 0;
+ if (u >= ranges[a].start) {
+ // invariant: ranges[a].start <= u < ranges[b].start
+ while (b - a > 1) {
+ m = (a + b) / 2;
+ if (u >= ranges[m].start) {
+ a = m;
+ } else if (u < ranges[m].start) {
+ b = m;
+ }
}
- code = ranges[a].code + (u - ranges[a].start);
- for (i = n - 1; i >= 0; --i) {
- buf[i] = (char)(code & 0xff);
- code >>= 8;
+ if (u <= ranges[a].end) {
+ n = ranges[a].nBytes;
+ if (n > bufSize) {
+ return 0;
+ }
+ code = ranges[a].code + (u - ranges[a].start);
+ for (i = n - 1; i >= 0; --i) {
+ buf[i] = (char)(code & 0xff);
+ code >>= 8;
+ }
+ return n;
}
- return n;
}
for (i = 0; i < eMapsLen; ++i) {
diff --git a/pdf/xpdf/UnicodeMap.h b/pdf/xpdf/UnicodeMap.h
index 24de28c..6fd4ed2 100644
--- a/pdf/xpdf/UnicodeMap.h
+++ b/pdf/xpdf/UnicodeMap.h
@@ -20,6 +20,10 @@
#include "gtypes.h"
#include "CharTypes.h"
+#if MULTITHREADED
+#include "GMutex.h"
+#endif
+
class GString;
//------------------------------------------------------------------------
@@ -91,6 +95,9 @@ private:
UnicodeMapExt *eMaps; // (user)
int eMapsLen; // (user)
int refCnt;
+#ifdef MULTITHREADED
+ GMutex mutex;
+#endif
};
//------------------------------------------------------------------------
diff --git a/pdf/xpdf/XOutputDev.cc b/pdf/xpdf/XOutputDev.cc
index 2100355..a156b55 100644
--- a/pdf/xpdf/XOutputDev.cc
+++ b/pdf/xpdf/XOutputDev.cc
@@ -624,18 +624,20 @@ XOutputFontCache::XOutputFontCache(Display *displayA, Guint depthA,
xOut = xOutA;
#if HAVE_T1LIB_H
- t1Engine = NULL;
t1libControl = t1libControlA;
+ t1Engine = NULL;
+ t1FontFiles = NULL;
#endif
#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
+ freetypeControl = freetypeControlA;
ftEngine = NULL;
+ ftFontFiles = NULL;
#endif
#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
- ttEngine = NULL;
-#endif
-#if HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H
freetypeControl = freetypeControlA;
+ ttEngine = NULL;
+ ttFontFiles = NULL;
#endif
clear();
@@ -718,25 +720,37 @@ void XOutputFontCache::delFonts() {
#if HAVE_T1LIB_H
// delete Type 1 font files
- deleteGList(t1FontFiles, XOutputT1FontFile);
+ if (t1FontFiles) {
+ deleteGList(t1FontFiles, XOutputT1FontFile);
+ t1FontFiles = NULL;
+ }
if (t1Engine) {
delete t1Engine;
+ t1Engine = NULL;
}
#endif
#if FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
// delete FreeType font files
- deleteGList(ftFontFiles, XOutputFTFontFile);
+ if (ftFontFiles) {
+ deleteGList(ftFontFiles, XOutputFTFontFile);
+ ftFontFiles = NULL;
+ }
if (ftEngine) {
delete ftEngine;
+ ftEngine = NULL;
}
#endif
#if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
// delete TrueType fonts
- deleteGList(ttFontFiles, XOutputTTFontFile);
+ if (ttFontFiles) {
+ deleteGList(ttFontFiles, XOutputTTFontFile);
+ ttFontFiles = NULL;
+ }
if (ttEngine) {
delete ttEngine;
+ ttEngine = NULL;
}
#endif
}
@@ -1088,12 +1102,16 @@ XOutputFont *XOutputFontCache::tryGetT1Font(XRef *xref,
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);
@@ -1235,6 +1253,8 @@ XOutputFont *XOutputFontCache::tryGetFTFont(XRef *xref,
gfxFont->getType() == fontCIDType2) {
if (!(fontBuf = gfxFont->readEmbFontFile(xref, &fontLen))) {
fclose(f);
+ unlink(fileName->getCString());
+ delete fileName;
return NULL;
}
ff = new TrueTypeFontFile(fontBuf, fontLen);
@@ -1304,6 +1324,11 @@ XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref,
Ref *id;
FTFontFile *fontFile;
XOutputFont *font;
+ char *buf;
+ int len;
+ FILE *f;
+ TrueTypeFontFile *ff;
+ Gushort *codeToGID;
// create the FreeType font file
if (gfxFont->isCIDFont()) {
@@ -1316,10 +1341,27 @@ XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref,
fontFile = new FTFontFile(ftEngine, fileName->getCString(), embedded);
}
} else {
+ if (!(f = fopen(fileName->getCString(), "rb"))) {
+ return NULL;
+ }
+ fseek(f, 0, SEEK_END);
+ len = (int)ftell(f);
+ fseek(f, 0, SEEK_SET);
+ buf = (char *)gmalloc(len);
+ if ((int)fread(buf, 1, len, f) != len) {
+ gfree(buf);
+ fclose(f);
+ return NULL;
+ }
+ fclose(f);
+ ff = new TrueTypeFontFile(buf, len);
+ codeToGID = ((Gfx8BitFont *)gfxFont)->getCodeToGIDMap(ff);
fontFile = new FTFontFile(ftEngine, fileName->getCString(),
((Gfx8BitFont *)gfxFont)->getEncoding(),
- ((Gfx8BitFont *)gfxFont)->getHasEncoding(),
- ((Gfx8BitFont *)gfxFont)->isSymbolic());
+ codeToGID);
+ gfree(codeToGID);
+ delete ff;
+ gfree(buf);
}
if (!fontFile->isOk()) {
error(-1, "Couldn't create FreeType font from '%s'",
@@ -1784,6 +1826,9 @@ XOutputDev::XOutputDev(Display *displayA, int screenNumA,
nT3Fonts = 0;
t3GlyphStack = NULL;
+ // no text outline clipping path
+ textClipPath = NULL;
+
// empty state stack
save = NULL;
@@ -1877,32 +1922,61 @@ void XOutputDev::endPage() {
}
void XOutputDev::drawLink(Link *link, Catalog *catalog) {
- double x1, y1, x2, y2, w;
+ double x1, y1, x2, y2;
+ LinkBorderStyle *borderStyle;
GfxRGB rgb;
+ double *dash;
+ char dashList[20];
+ int dashLength;
XPoint points[5];
- int x, y;
+ int x, y, i;
- link->getBorder(&x1, &y1, &x2, &y2, &w);
- if (w > 0) {
- rgb.r = 0;
- rgb.g = 0;
- rgb.b = 1;
+ link->getRect(&x1, &y1, &x2, &y2);
+ borderStyle = link->getBorderStyle();
+ if (borderStyle->getWidth() > 0) {
+ borderStyle->getColor(&rgb.r, &rgb.g, &rgb.b);
XSetForeground(display, strokeGC, findColor(&rgb));
- XSetLineAttributes(display, strokeGC, xoutRound(w),
- LineSolid, CapRound, JoinRound);
- cvtUserToDev(x1, y1, &x, &y);
- points[0].x = points[4].x = x;
- points[0].y = points[4].y = y;
- cvtUserToDev(x2, y1, &x, &y);
- points[1].x = x;
- points[1].y = y;
- cvtUserToDev(x2, y2, &x, &y);
- points[2].x = x;
- points[2].y = y;
- cvtUserToDev(x1, y2, &x, &y);
- points[3].x = x;
- points[3].y = y;
- XDrawLines(display, pixmap, strokeGC, points, 5, CoordModeOrigin);
+ borderStyle->getDash(&dash, &dashLength);
+ if (borderStyle->getType() == linkBorderDashed && dashLength > 0) {
+ if (dashLength > 20) {
+ dashLength = 20;
+ }
+ for (i = 0; i < dashLength; ++i) {
+ if ((dashList[i] = xoutRound(dash[i])) == 0) {
+ dashList[i] = 1;
+ }
+ }
+ XSetLineAttributes(display, strokeGC, xoutRound(borderStyle->getWidth()),
+ LineOnOffDash, CapButt, JoinMiter);
+ XSetDashes(display, strokeGC, 0, dashList, dashLength);
+ } else {
+ XSetLineAttributes(display, strokeGC, xoutRound(borderStyle->getWidth()),
+ LineSolid, CapButt, JoinMiter);
+ }
+ if (borderStyle->getType() == linkBorderUnderlined) {
+ cvtUserToDev(x1, y1, &x, &y);
+ points[0].x = x;
+ points[0].y = y;
+ cvtUserToDev(x2, y1, &x, &y);
+ points[1].x = x;
+ points[1].y = y;
+ XDrawLine(display, pixmap, strokeGC, points[0].x, points[0].y,
+ points[1].x, points[1].y);
+ } else {
+ cvtUserToDev(x1, y1, &x, &y);
+ points[0].x = points[4].x = x;
+ points[0].y = points[4].y = y;
+ cvtUserToDev(x2, y1, &x, &y);
+ points[1].x = x;
+ points[1].y = y;
+ cvtUserToDev(x2, y2, &x, &y);
+ points[2].x = x;
+ points[2].y = y;
+ cvtUserToDev(x1, y2, &x, &y);
+ points[3].x = x;
+ points[3].y = y;
+ XDrawLines(display, pixmap, strokeGC, points, 5, CoordModeOrigin);
+ }
}
}
@@ -2100,7 +2174,8 @@ void XOutputDev::stroke(GfxState *state) {
int n, size, numPoints, i, j;
// transform points
- n = convertPath(state, &points, &size, &numPoints, &lengths, gFalse);
+ n = convertPath(state, state->getPath(),
+ &points, &size, &numPoints, &lengths, gFalse);
// draw each subpath
j = 0;
@@ -2143,7 +2218,8 @@ void XOutputDev::doFill(GfxState *state, int rule) {
XSetFillRule(display, fillGC, rule);
// transform points, build separate polygons
- n = convertPath(state, &points, &size, &numPoints, &lengths, gTrue);
+ n = convertPath(state, state->getPath(),
+ &points, &size, &numPoints, &lengths, gTrue);
// fill them
j = 0;
@@ -2165,41 +2241,109 @@ void XOutputDev::doFill(GfxState *state, int rule) {
}
void XOutputDev::clip(GfxState *state) {
- doClip(state, WindingRule);
+ doClip(state, state->getPath(), WindingRule);
}
void XOutputDev::eoClip(GfxState *state) {
- doClip(state, EvenOddRule);
+ doClip(state, state->getPath(), EvenOddRule);
}
-void XOutputDev::doClip(GfxState *state, int rule) {
+void XOutputDev::doClip(GfxState *state, GfxPath *path, int rule) {
+ GfxSubpath *subpath;
Region region, region2;
+ XPoint rect[5];
XPoint *points;
int *lengths;
+ double x0, y0, x1, y1, x2, y2, x3, y3;
+ GBool gotRect;
int n, size, numPoints, i, j;
- // transform points, build separate polygons
- n = convertPath(state, &points, &size, &numPoints, &lengths, gTrue);
-
- // construct union of subpath regions
- // (XPolygonRegion chokes if there aren't at least three points --
- // this happens if the PDF file does moveto/closepath/clip, which
- // sets an empty clipping region)
- if (lengths[0] > 2) {
- region = XPolygonRegion(points, lengths[0], rule);
- } else {
- region = XCreateRegion();
+ // special case for rectangular clipping paths -- this is a common
+ // case, and we want to make sure not to clip an extra pixel on the
+ // right and bottom edges due to the difference between the PDF and
+ // X rendering models
+ gotRect = gFalse;
+ if (path->getNumSubpaths() == 1) {
+ subpath = path->getSubpath(0);
+ if ((subpath->isClosed() && subpath->getNumPoints() == 5) ||
+ (!subpath->isClosed() && subpath->getNumPoints() == 4)) {
+ state->transform(subpath->getX(0), subpath->getY(0), &x0, &y0);
+ state->transform(subpath->getX(1), subpath->getY(1), &x1, &y1);
+ state->transform(subpath->getX(2), subpath->getY(2), &x2, &y2);
+ state->transform(subpath->getX(3), subpath->getY(3), &x3, &y3);
+ if (fabs(x0-x1) < 1 && fabs(x2-x3) < 1 &&
+ fabs(y0-y3) < 1 && fabs(y1-y2) < 1) {
+ if (x0 < x2) {
+ rect[0].x = rect[1].x = rect[4].x = (int)floor(x0);
+ rect[2].x = rect[3].x = (int)floor(x2) + 1;
+ } else {
+ rect[0].x = rect[1].x = rect[4].x = (int)floor(x0) + 1;
+ rect[2].x = rect[3].x = (int)floor(x2);
+ }
+ if (y0 < y1) {
+ rect[0].y = rect[3].y = rect[4].y = (int)floor(y0);
+ rect[1].y = rect[2].y = (int)floor(y1) + 1;
+ } else {
+ rect[0].y = rect[3].y = rect[4].y = (int)floor(y0) + 1;
+ rect[1].y = rect[2].y = (int)floor(y1);
+ }
+ gotRect = gTrue;
+ } else if (fabs(x0-x3) < 1 && fabs(x1-x2) < 1 &&
+ fabs(y0-y1) < 1 && fabs(y2-y3) < 1) {
+ if (x0 < x1) {
+ rect[0].x = rect[3].x = rect[4].x = (int)floor(x0);
+ rect[1].x = rect[2].x = (int)floor(x1) + 1;
+ } else {
+ rect[0].x = rect[3].x = rect[4].x = (int)floor(x0) + 1;
+ rect[1].x = rect[2].x = (int)floor(x1);
+ }
+ if (y0 < y2) {
+ rect[0].y = rect[1].y = rect[4].y = (int)floor(y0);
+ rect[2].y = rect[3].y = (int)floor(y2) + 1;
+ } else {
+ rect[0].y = rect[1].y = rect[4].y = (int)floor(y0) + 1;
+ rect[2].y = rect[3].y = (int)floor(y2);
+ }
+ gotRect = gTrue;
+ }
+ }
}
- j = lengths[0] + 1;
- for (i = 1; i < n; ++i) {
- if (lengths[i] > 2) {
- region2 = XPolygonRegion(points + j, lengths[i], rule);
+
+ if (gotRect) {
+ region = XPolygonRegion(rect, 5, EvenOddRule);
+
+ } else {
+ // transform points, build separate polygons
+ n = convertPath(state, path, &points, &size, &numPoints, &lengths, gTrue);
+
+ // construct union of subpath regions
+ // (XPolygonRegion chokes if there aren't at least three points --
+ // this happens if the PDF file does moveto/closepath/clip, which
+ // sets an empty clipping region)
+ if (lengths[0] > 2) {
+ region = XPolygonRegion(points, lengths[0], rule);
} else {
- region2 = XCreateRegion();
+ region = XCreateRegion();
+ }
+ j = lengths[0] + 1;
+ for (i = 1; i < n; ++i) {
+ if (lengths[i] > 2) {
+ region2 = XPolygonRegion(points + j, lengths[i], rule);
+ } else {
+ region2 = XCreateRegion();
+ }
+ XUnionRegion(region2, region, region);
+ XDestroyRegion(region2);
+ j += lengths[i] + 1;
+ }
+
+ // free points and lengths arrays
+ if (points != tmpPoints) {
+ gfree(points);
+ }
+ if (lengths != tmpLengths) {
+ gfree(lengths);
}
- XUnionRegion(region2, region, region);
- XDestroyRegion(region2);
- j += lengths[i] + 1;
}
// intersect region with clipping region
@@ -2207,12 +2351,6 @@ void XOutputDev::doClip(GfxState *state, int rule) {
XDestroyRegion(region);
XSetRegion(display, strokeGC, clipRegion);
XSetRegion(display, fillGC, clipRegion);
-
- // free points and lengths arrays
- if (points != tmpPoints)
- gfree(points);
- if (lengths != tmpLengths)
- gfree(lengths);
}
//
@@ -2224,15 +2362,14 @@ void XOutputDev::doClip(GfxState *state, int rule) {
// Then it connects subaths within a single compound polygon to a single
// point so that X can fill the polygon (sort of).
//
-int XOutputDev::convertPath(GfxState *state, XPoint **points, int *size,
+int XOutputDev::convertPath(GfxState *state, GfxPath *path,
+ XPoint **points, int *size,
int *numPoints, int **lengths, GBool fillHack) {
- GfxPath *path;
BoundingRect *rects;
BoundingRect rect;
int n, i, ii, j, k, k0;
// get path and number of subpaths
- path = state->getPath();
n = path->getNumSubpaths();
// allocate lengths array
@@ -2294,15 +2431,15 @@ int XOutputDev::convertPath(GfxState *state, XPoint **points, int *size,
// kludge: munge any points that are *way* out of bounds - these can
// crash certain (buggy) X servers
for (i = 0; i < *numPoints; ++i) {
- if ((*points)[i].x < -pixmapW) {
- (*points)[i].x = -pixmapW;
- } else if ((*points)[i].x > 2 * pixmapW) {
- (*points)[i].x = 2 * pixmapW;
+ if ((*points)[i].x < -4 * pixmapW) {
+ (*points)[i].x = -4 * pixmapW;
+ } else if ((*points)[i].x > 4 * pixmapW) {
+ (*points)[i].x = 4 * pixmapW;
}
if ((*points)[i].y < -pixmapH) {
- (*points)[i].y = -pixmapH;
- } else if ((*points)[i].y > 2 * pixmapH) {
- (*points)[i].y = 2 * pixmapH;
+ (*points)[i].y = -4 * pixmapH;
+ } else if ((*points)[i].y > 4 * pixmapH) {
+ (*points)[i].y = 4 * pixmapH;
}
}
@@ -2528,7 +2665,7 @@ void XOutputDev::drawChar(GfxState *state, double x, double y,
// check for invisible text -- this is used by Acrobat Capture
render = state->getRender();
- if ((render & 3) == 3) {
+ if (render == 3) {
return;
}
@@ -2577,11 +2714,22 @@ void XOutputDev::drawChar(GfxState *state, double x, double y,
}
}
-#if 0 //~ unimplemented: clipping to char path
// clip
if (render & 4) {
+ if (font->hasGetCharPath()) {
+ saveCurX = state->getCurX();
+ saveCurY = state->getCurY();
+ font->getCharPath(state, code, u, uLen);
+ state->getPath()->offset(x1, y1);
+ if (textClipPath) {
+ textClipPath->append(state->getPath());
+ } else {
+ textClipPath = state->getPath()->copy();
+ }
+ state->clearPath();
+ state->moveTo(saveCurX, saveCurY);
+ }
}
-#endif
}
GBool XOutputDev::beginType3Char(GfxState *state,
@@ -2991,7 +3139,23 @@ void XOutputDev::type3D1(GfxState *state, double wx, double wy,
-t3GlyphStack->cache->glyphX, -t3GlyphStack->cache->glyphY);
}
-inline Gulong XOutputDev::findColor(GfxRGB *x, GfxRGB *err) {
+void XOutputDev::endTextObject(GfxState *state) {
+ double *ctm;
+ double saveCTM[6];
+
+ if (textClipPath) {
+ ctm = state->getCTM();
+ memcpy(saveCTM, ctm, 6 * sizeof(double));
+ state->setCTM(1, 0, 0, 1, 0, 0);
+ doClip(state, textClipPath, WindingRule);
+ state->setCTM(saveCTM[0], saveCTM[1], saveCTM[2], saveCTM[3],
+ saveCTM[4], saveCTM[5]);
+ delete textClipPath;
+ textClipPath = NULL;
+ }
+}
+
+inline Gulong XOutputDev::findColor(GfxRGB *x, GfxRGB *actual) {
double gray;
int r, g, b;
Gulong pixel;
@@ -3003,30 +3167,26 @@ inline Gulong XOutputDev::findColor(GfxRGB *x, GfxRGB *err) {
pixel = ((Gulong)r << rShift) +
((Gulong)g << gShift) +
((Gulong)b << bShift);
- err->r = x->r - (double)r / rMul;
- err->g = x->g - (double)g / gMul;
- err->b = x->b - (double)b / bMul;
+ actual->r = (double)r / rMul;
+ actual->g = (double)g / gMul;
+ actual->b = (double)b / bMul;
} else if (numColors == 1) {
gray = 0.299 * x->r + 0.587 * x->g + 0.114 * x->b;
if (gray < 0.5) {
pixel = colors[0];
- err->r = x->r;
- err->g = x->g;
- err->b = x->b;
+ actual->r = actual->g = actual->b = 0;
} else {
pixel = colors[1];
- err->r = x->r - 1;
- err->g = x->g - 1;
- err->b = x->b - 1;
+ actual->r = actual->g = actual->b = 1;
}
} else {
r = xoutRound(x->r * (numColors - 1));
g = xoutRound(x->g * (numColors - 1));
b = xoutRound(x->b * (numColors - 1));
pixel = colors[(r * numColors + g) * numColors + b];
- err->r = x->r - (double)r / (numColors - 1);
- err->g = x->g - (double)g / (numColors - 1);
- err->b = x->b - (double)b / (numColors - 1);
+ actual->r = (double)r / (numColors - 1);
+ actual->g = (double)g / (numColors - 1);
+ actual->b = (double)b / (numColors - 1);
}
return pixel;
}
@@ -3380,14 +3540,14 @@ void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
int yp, yq, yt, yStep, lastYStep;
int xp, xq, xt, xStep, xSrc;
GfxRGB *pixBuf;
- Guchar *alphaBuf;
+ Guchar *pixBuf1, *alphaBuf;
Guchar pixBuf2[gfxColorMaxComps];
- GfxRGB color2, err, errRight;
- GfxRGB *errDown;
+ GfxRGB color2, color3, actual, err, errRight;
+ GfxRGB *errDown0, *errDown1, *errDownTmp;
double r0, g0, b0, alpha, mul;
Gulong pix;
GfxRGB *p;
- Guchar *q, *p2;
+ Guchar *q, *p1, *p2;
GBool oneBitMode;
GfxRGB oneBitRGB[2];
int x, y, x1, y1, x2, y2;
@@ -3397,6 +3557,7 @@ void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
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
@@ -3533,7 +3694,13 @@ void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
xq = width % scaledWidth;
// allocate pixel buffer
- pixBuf = (GfxRGB *)gmalloc((yp + 1) * width * sizeof(GfxRGB));
+ if (oneBitMode) {
+ pixBuf1 = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar));
+ pixBuf = NULL;
+ } else {
+ pixBuf = (GfxRGB *)gmalloc((yp + 1) * width * sizeof(GfxRGB));
+ pixBuf1 = NULL;
+ }
if (maskColors) {
alphaBuf = (Guchar *)gmalloc((yp + 1) * width * sizeof(Guchar));
} else {
@@ -3556,16 +3723,18 @@ void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
// allocate error diffusion accumulators
if (dither) {
- errDown = (GfxRGB *)gmalloc(bw * sizeof(GfxRGB));
- for (j = 0; j < bw; ++j) {
- errDown[j].r = errDown[j].g = errDown[j].b = 0;
+ errDown0 = (GfxRGB *)gmalloc((scaledWidth + 2) * sizeof(GfxRGB));
+ errDown1 = (GfxRGB *)gmalloc((scaledWidth + 2) * sizeof(GfxRGB));
+ for (j = 0; j < scaledWidth + 2; ++j) {
+ errDown0[j].r = errDown0[j].g = errDown0[j].b = 0;
+ errDown1[j].r = errDown1[j].g = errDown1[j].b = 0;
}
} else {
- errDown = NULL;
+ errDown0 = errDown1 = NULL;
}
// optimize the one-bit-deep image case
- if ((oneBitMode = nComps == 1 && nBits == 1)) {
+ if (oneBitMode) {
pixBuf2[0] = 0;
colorMap->getRGB(pixBuf2, &oneBitRGB[0]);
pixBuf2[0] = 1;
@@ -3582,8 +3751,16 @@ void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
for (y = 0; y < scaledHeight; ++y) {
- // initialize error diffusion accumulator
- errRight.r = errRight.g = errRight.b = 0;
+ // initialize error diffusion accumulators
+ if (dither) {
+ errDownTmp = errDown0;
+ errDown0 = errDown1;
+ errDown1 = errDownTmp;
+ for (j = 0; j < scaledWidth + 2; ++j) {
+ errDown1[j].r = errDown1[j].g = errDown1[j].b = 0;
+ }
+ errRight.r = errRight.g = errRight.b = 0;
+ }
// y scale Bresenham
yStep = yp;
@@ -3596,30 +3773,35 @@ void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
// read row(s) from image
n = (yp > 0) ? yStep : lastYStep;
if (n > 0) {
- p = pixBuf;
- q = alphaBuf;
- for (i = 0; i < n; ++i) {
- p2 = imgStr->getLine();
- for (j = 0; j < width; ++j) {
- if (oneBitMode) {
- *p = oneBitRGB[*p2];
- } else {
+ 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]) {
- *q = 0;
- break;
- }
- }
- ++q;
- }
- p2 += nComps;
- }
+ ++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;
@@ -3657,60 +3839,94 @@ void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
// x and y scaling operations
n = yStep > 0 ? yStep : 1;
m = xStep > 0 ? xStep : 1;
- p = pixBuf + xSrc;
- r0 = g0 = b0 = 0;
- q = alphaBuf ? alphaBuf + xSrc : (Guchar *)NULL;
- alpha = 0;
- for (i = 0; i < n; ++i) {
- for (j = 0; j < m; ++j) {
- r0 += p->r;
- g0 += p->g;
- b0 += p->b;
- ++p;
- if (q) {
- alpha += *q++;
+ if (oneBitMode) {
+ p1 = pixBuf1 + xSrc;
+ k = 0;
+ for (i = 0; i < n; ++i) {
+ for (j = 0; j < m; ++j) {
+ k += *p1++;
}
+ p1 += width - m;
}
- p += width - m;
+ mul = (double)k / (double)(n * m);
+ r0 = mul * oneBitRGB[1].r + (1 - mul) * oneBitRGB[0].r;
+ g0 = mul * oneBitRGB[1].g + (1 - mul) * oneBitRGB[0].g;
+ b0 = mul * oneBitRGB[1].b + (1 - mul) * oneBitRGB[0].b;
+ alpha = 0;
+ } else {
+ p = pixBuf + xSrc;
+ q = alphaBuf ? alphaBuf + xSrc : (Guchar *)NULL;
+ alpha = 0;
+ r0 = g0 = b0 = 0;
+ for (i = 0; i < n; ++i) {
+ for (j = 0; j < m; ++j) {
+ r0 += p->r;
+ g0 += p->g;
+ b0 += p->b;
+ ++p;
+ if (q) {
+ alpha += *q++;
+ }
+ }
+ p += width - m;
+ }
+ mul = 1 / (double)(n * m);
+ r0 *= mul;
+ g0 *= mul;
+ b0 *= mul;
+ alpha *= mul;
}
- mul = 1 / (double)(n * m);
- r0 *= mul;
- g0 *= mul;
- b0 *= mul;
- alpha *= mul;
// x scale Bresenham
xSrc += xStep;
// compute pixel
if (dither) {
- color2.r = r0 + errRight.r + errDown[tx + x2 - bx0].r;
+ color2.r = r0 + errRight.r + errDown0[x + 1].r;
if (color2.r > 1) {
- color2.r = 1;
+ color3.r = 1;
} else if (color2.r < 0) {
- color2.r = 0;
+ color3.r = 0;
+ } else {
+ color3.r = color2.r;
}
- color2.g = g0 + errRight.g + errDown[tx + x2 - bx0].g;
+ color2.g = g0 + errRight.g + errDown0[x + 1].g;
if (color2.g > 1) {
- color2.g = 1;
+ color3.g = 1;
} else if (color2.g < 0) {
- color2.g = 0;
+ color3.g = 0;
+ } else {
+ color3.g = color2.g;
}
- color2.b = b0 + errRight.b + errDown[tx + x2 - bx0].b;
+ color2.b = b0 + errRight.b + errDown0[x + 1].b;
if (color2.b > 1) {
- color2.b = 1;
+ color3.b = 1;
} else if (color2.b < 0) {
- color2.b = 0;
+ color3.b = 0;
+ } else {
+ color3.b = color2.b;
}
- pix = findColor(&color2, &err);
- errRight.r = errDown[tx + x2 - bx0].r = err.r / 2;
- errRight.g = errDown[tx + x2 - bx0].g = err.g / 2;
- errRight.b = errDown[tx + x2 - bx0].b = err.b / 2;
+ pix = findColor(&color3, &actual);
+ err.r = (color2.r - actual.r) / 16;
+ err.g = (color2.g - actual.g) / 16;
+ err.b = (color2.b - actual.b) / 16;
+ errRight.r = 7 * err.r;
+ errRight.g = 7 * err.g;
+ errRight.b = 7 * err.b;
+ errDown1[x].r += 3 * err.r;
+ errDown1[x].g += 3 * err.g;
+ errDown1[x].b += 3 * err.b;
+ errDown1[x + 1].r += 5 * err.r;
+ errDown1[x + 1].g += 5 * err.g;
+ errDown1[x + 1].b += 5 * err.b;
+ errDown1[x + 2].r = err.r;
+ errDown1[x + 2].g = err.g;
+ errDown1[x + 2].b = err.b;
} else {
color2.r = r0;
color2.g = g0;
color2.b = b0;
- pix = findColor(&color2, &err);
+ pix = findColor(&color2, &actual);
}
// set pixel
@@ -3726,25 +3942,35 @@ void XOutputDev::drawImage(GfxState *state, Object *ref, Stream *str,
// free memory
delete imgStr;
- gfree(pixBuf);
+ if (oneBitMode) {
+ gfree(pixBuf1);
+ } else {
+ gfree(pixBuf);
+ }
if (maskColors) {
gfree(alphaBuf);
}
gfree(image->data);
image->data = NULL;
XDestroyImage(image);
- gfree(errDown);
+ gfree(errDown0);
+ gfree(errDown1);
}
-GBool XOutputDev::findText(Unicode *s, int len, GBool top, GBool bottom,
- int *xMin, int *yMin, int *xMax, int *yMax) {
+GBool XOutputDev::findText(Unicode *s, int len,
+ GBool startAtTop, GBool stopAtBottom,
+ GBool startAtLast, GBool stopAtLast,
+ int *xMin, int *yMin,
+ int *xMax, int *yMax) {
double xMin1, yMin1, xMax1, yMax1;
xMin1 = (double)*xMin;
yMin1 = (double)*yMin;
xMax1 = (double)*xMax;
yMax1 = (double)*yMax;
- if (text->findText(s, len, top, bottom, &xMin1, &yMin1, &xMax1, &yMax1)) {
+ if (text->findText(s, len, startAtTop, stopAtBottom,
+ startAtLast, stopAtLast,
+ &xMin1, &yMin1, &xMax1, &yMax1)) {
*xMin = xoutRound(xMin1);
*xMax = xoutRound(xMax1);
*yMin = xoutRound(yMin1);
diff --git a/pdf/xpdf/XOutputDev.h b/pdf/xpdf/XOutputDev.h
index 7a6544d..3efa1dd 100644
--- a/pdf/xpdf/XOutputDev.h
+++ b/pdf/xpdf/XOutputDev.h
@@ -28,6 +28,7 @@ class GString;
class GList;
struct GfxRGB;
class GfxFont;
+class GfxPath;
class GfxSubpath;
class TextPage;
class XOutputFontCache;
@@ -564,6 +565,7 @@ public:
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,
@@ -582,14 +584,19 @@ public:
// Called to indicate that a new PDF document has been loaded.
void startDoc(XRef *xrefA);
-
- // Find a string. If <top> is true, starts looking at <xMin>,<yMin>;
- // otherwise starts looking at top of page. If <bottom> is true,
- // stops looking at <xMax>,<yMax>; otherwise stops looking at bottom
- // of page. If found, sets the text bounding rectange and returns
- // true; otherwise returns false.
- GBool findText(Unicode *s, int len, GBool top, GBool bottom,
- int *xMin, int *yMin, int *xMax, int *yMax);
+
+ // Find a string. If <startAtTop> is true, starts looking at the
+ // top of the page; else if <startAtLast> is true, starts looking
+ // immediately after the last find result; else starts looking at
+ // <xMin>,<yMin>. If <stopAtBottom> is true, stops looking at the
+ // bottom of the page; else if <stopAtLast> is true, stops looking
+ // just before the last find result; else stops looking at
+ // <xMax>,<yMax>.
+ 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);
@@ -647,14 +654,16 @@ private:
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, int rule);
- int convertPath(GfxState *state, XPoint **points, int *size,
+ 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);
@@ -665,7 +674,7 @@ private:
void drawType3Glyph(T3FontCache *t3Font,
T3FontCacheTag *tag, Guchar *data,
double x, double y, GfxRGB *color);
- Gulong findColor(GfxRGB *x, GfxRGB *err);
+ Gulong findColor(GfxRGB *x, GfxRGB *actual);
};
#endif
diff --git a/pdf/xpdf/XRef.cc b/pdf/xpdf/XRef.cc
index 56cb131..eca638d 100644
--- a/pdf/xpdf/XRef.cc
+++ b/pdf/xpdf/XRef.cc
@@ -134,19 +134,22 @@ Guint XRef::readTrailer() {
// read last xrefSearchSize bytes
str->setPos(xrefSearchSize, -1);
for (n = 0; n < xrefSearchSize; ++n) {
- if ((c = str->getChar()) == EOF)
+ if ((c = str->getChar()) == EOF) {
break;
+ }
buf[n] = c;
}
buf[n] = '\0';
// find startxref
for (i = n - 9; i >= 0; --i) {
- if (!strncmp(&buf[i], "startxref", 9))
+ if (!strncmp(&buf[i], "startxref", 9)) {
break;
+ }
+ }
+ if (i < 0) {
+ goto err1;
}
- if (i < 0)
- return 0;
for (p = &buf[i+9]; isspace(*p); ++p) ;
pos = lastXRefPos = strToUnsigned(p);
@@ -154,20 +157,24 @@ Guint XRef::readTrailer() {
// (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)
+ for (i = 0; i < 4; ++i) {
buf[i] = str->getChar();
- if (strncmp(buf, "xref", 4))
- return 0;
+ }
+ 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)
- return 0;
+ if ((c = str->getChar()) == EOF) {
+ goto err1;
+ }
buf[i] = c;
}
- if (!strncmp(buf, "trailer", 7))
+ if (!strncmp(buf, "trailer", 7)) {
break;
+ }
p = buf;
while (isspace(*p)) ++p;
while ('0' <= *p && *p <= '9') ++p;
@@ -175,8 +182,9 @@ Guint XRef::readTrailer() {
n = atoi(p);
while ('0' <= *p && *p <= '9') ++p;
while (isspace(*p)) ++p;
- if (p == buf)
- return 0;
+ if (p == buf) {
+ goto err1;
+ }
pos1 += (p - buf) + n * 20;
}
pos1 += 7;
@@ -189,26 +197,36 @@ Guint XRef::readTrailer() {
parser->getObj(&trailerDict);
if (trailerDict.isDict()) {
trailerDict.dictLookupNF("Size", &obj);
- if (obj.isInt())
+ if (obj.isInt()) {
size = obj.getInt();
- else
- pos = 0;
+ } else {
+ goto err3;
+ }
obj.free();
trailerDict.dictLookupNF("Root", &obj);
if (obj.isRef()) {
rootNum = obj.getRefNum();
rootGen = obj.getRefGen();
} else {
- pos = 0;
+ goto err3;
}
obj.free();
} else {
- pos = 0;
+ goto err2;
}
delete parser;
// return first xref position
return pos;
+
+ err3:
+ obj.free();
+ err2:
+ trailerDict.free();
+ delete parser;
+ err1:
+ size = 0;
+ return 0;
}
// Read an xref table and the prev pointer from the trailer.
@@ -266,7 +284,7 @@ GBool XRef::readXRef(Guint *pos) {
// check for buggy PDF files with an incorrect (too small) xref
// table size
if (first + n > size) {
- newSize = size + 256;
+ newSize = first + n;
entries = (XRefEntry *)grealloc(entries, newSize * sizeof(XRefEntry));
for (i = size; i < newSize; ++i) {
entries[i].offset = 0xffffffff;
@@ -373,12 +391,14 @@ 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())
+ if (!trailerDict.isNone()) {
trailerDict.free();
+ }
parser->getObj(&trailerDict);
if (trailerDict.isDict()) {
trailerDict.dictLookupNF("Root", &obj);
@@ -389,7 +409,7 @@ GBool XRef::constructXRef() {
}
obj.free();
} else {
- pos = 0;
+ trailerDict.free();
}
delete parser;
@@ -457,6 +477,8 @@ GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) {
GBool encrypted1;
GBool ret;
+ keyLength = 0;
+ encVersion = encRevision = 0;
ret = gFalse;
permFlags = defPermFlags;
@@ -551,38 +573,34 @@ GBool XRef::checkEncrypted(GString *ownerPassword, GString *userPassword) {
GBool XRef::okToPrint(GBool ignoreOwnerPW) {
#ifndef NO_DECRYPTION
- if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permPrint)) {
- return gFalse;
- }
-#endif
+ return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permPrint);
+#else
return gTrue;
+#endif
}
GBool XRef::okToChange(GBool ignoreOwnerPW) {
#ifndef NO_DECRYPTION
- if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permChange)) {
- return gFalse;
- }
-#endif
+ return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permChange);
+#else
return gTrue;
+#endif
}
GBool XRef::okToCopy(GBool ignoreOwnerPW) {
#ifndef NO_DECRYPTION
- if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permCopy)) {
- return gFalse;
- }
-#endif
+ return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permCopy);
+#else
return gTrue;
+#endif
}
GBool XRef::okToAddNotes(GBool ignoreOwnerPW) {
#ifndef NO_DECRYPTION
- if ((ignoreOwnerPW || !ownerPasswordOk) && !(permFlags & permNotes)) {
- return gFalse;
- }
-#endif
+ return (!ignoreOwnerPW && ownerPasswordOk) || (permFlags & permNotes);
+#else
return gTrue;
+#endif
}
Object *XRef::fetch(int num, int gen, Object *obj) {
diff --git a/pdf/xpdf/pdffonts.cc b/pdf/xpdf/pdffonts.cc
index f3a1b48..2fcd1a8 100644
--- a/pdf/xpdf/pdffonts.cc
+++ b/pdf/xpdf/pdffonts.cc
@@ -40,8 +40,8 @@ static void scanFont(GfxFont *font, PDFDoc *doc);
static int firstPage = 1;
static int lastPage = 0;
-static char ownerPassword[33] = "";
-static char userPassword[33] = "";
+static char ownerPassword[33] = "\001";
+static char userPassword[33] = "\001";
static char cfgFileName[256] = "";
static GBool printVersion = gFalse;
static GBool printHelp = gFalse;
@@ -91,10 +91,10 @@ int main(int argc, char *argv[]) {
// parse args
ok = parseArgs(argDesc, &argc, argv);
if (!ok || argc != 2 || printVersion || printHelp) {
- fprintf(stderr, "pdfinfo version %s\n", xpdfVersion);
+ fprintf(stderr, "pdffonts version %s\n", xpdfVersion);
fprintf(stderr, "%s\n", xpdfCopyright);
if (!printVersion) {
- printUsage("pdfinfo", "<PDF-file>", argDesc);
+ printUsage("pdffonts", "<PDF-file>", argDesc);
}
goto err0;
}
@@ -104,12 +104,12 @@ int main(int argc, char *argv[]) {
globalParams = new GlobalParams(cfgFileName);
// open PDF file
- if (ownerPassword[0]) {
+ if (ownerPassword[0] != '\001') {
ownerPW = new GString(ownerPassword);
} else {
ownerPW = NULL;
}
- if (userPassword[0]) {
+ if (userPassword[0] != '\001') {
userPW = new GString(userPassword);
} else {
userPW = NULL;
@@ -176,22 +176,33 @@ int main(int argc, char *argv[]) {
}
static void scanFonts(Dict *resDict, PDFDoc *doc) {
+ Object obj1, obj2, xObjDict, xObj, resObj;
+ Ref r;
GfxFontDict *gfxFontDict;
GfxFont *font;
- Object fontDict, xObjDict, xObj, resObj;
int i;
// scan the fonts in this resource dictionary
- resDict->lookup("Font", &fontDict);
- if (fontDict.isDict()) {
- gfxFontDict = new GfxFontDict(doc->getXRef(), fontDict.getDict());
+ gfxFontDict = NULL;
+ resDict->lookupNF("Font", &obj1);
+ if (obj1.isRef()) {
+ obj1.fetch(doc->getXRef(), &obj2);
+ if (obj2.isDict()) {
+ r = obj1.getRef();
+ gfxFontDict = new GfxFontDict(doc->getXRef(), &r, obj2.getDict());
+ }
+ obj2.free();
+ } else if (obj1.isDict()) {
+ gfxFontDict = new GfxFontDict(doc->getXRef(), NULL, obj1.getDict());
+ }
+ if (gfxFontDict) {
for (i = 0; i < gfxFontDict->getNumFonts(); ++i) {
font = gfxFontDict->getFont(i);
scanFont(font, doc);
}
delete gfxFontDict;
}
- fontDict.free();
+ obj1.free();
// recursively scan any resource dictionaries in objects in this
// resource dictionary
@@ -228,17 +239,12 @@ static void scanFont(GfxFont *font, PDFDoc *doc) {
}
}
- // get the original font name -- the GfxFont class munges substitute
- // Base-14 font names into proper form, so this code grabs the
- // original name from the font dictionary; also look for a ToUnicode
- // map
- name = NULL;
+ // font name
+ name = font->getOrigName();
+
+ // look for a ToUnicode map
hasToUnicode = gFalse;
if (doc->getXRef()->fetch(fontRef.num, fontRef.gen, &fontObj)->isDict()) {
- if (fontObj.dictLookup("BaseFont", &nameObj)->isName()) {
- name = new GString(nameObj.getName());
- }
- nameObj.free();
hasToUnicode = fontObj.dictLookup("ToUnicode", &toUnicodeObj)->isStream();
toUnicodeObj.free();
}
@@ -263,14 +269,11 @@ static void scanFont(GfxFont *font, PDFDoc *doc) {
font->getEmbeddedFontID(&embRef) ? "yes" : "no",
subset ? "yes" : "no",
hasToUnicode ? "yes" : "no");
- if (fontRef.gen == 999999) {
+ if (fontRef.gen >= 100000) {
printf(" [none]\n");
} else {
printf(" %6d %2d\n", fontRef.num, fontRef.gen);
}
- if (name) {
- delete name;
- }
// add this font to the list
if (fontsLen == fontsSize) {
diff --git a/pdf/xpdf/pdfimages.cc b/pdf/xpdf/pdfimages.cc
index e8a42aa..a661fb5 100644
--- a/pdf/xpdf/pdfimages.cc
+++ b/pdf/xpdf/pdfimages.cc
@@ -30,8 +30,8 @@
static int firstPage = 1;
static int lastPage = 0;
static GBool dumpJPEG = gFalse;
-static char ownerPassword[33] = "";
-static char userPassword[33] = "";
+static char ownerPassword[33] = "\001";
+static char userPassword[33] = "\001";
static GBool quiet = gFalse;
static char cfgFileName[256] = "";
static GBool printVersion = gFalse;
@@ -96,12 +96,12 @@ int main(int argc, char *argv[]) {
}
// open PDF file
- if (ownerPassword[0]) {
+ if (ownerPassword[0] != '\001') {
ownerPW = new GString(ownerPassword);
} else {
ownerPW = NULL;
}
- if (userPassword[0]) {
+ if (userPassword[0] != '\001') {
userPW = new GString(userPassword);
} else {
userPW = NULL;
@@ -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, 0, gFalse);
+ doc->displayPages(imgOut, firstPage, lastPage, 72, 72, 0, gFalse);
}
delete imgOut;
diff --git a/pdf/xpdf/pdfinfo.cc b/pdf/xpdf/pdfinfo.cc
index f856a6d..e29e673 100644
--- a/pdf/xpdf/pdfinfo.cc
+++ b/pdf/xpdf/pdfinfo.cc
@@ -34,15 +34,21 @@ static void printInfoString(Dict *infoDict, char *key, char *text,
UnicodeMap *uMap);
static void printInfoDate(Dict *infoDict, char *key, char *text);
+static int firstPage = 1;
+static int lastPage = 0;
static GBool printMetadata = gFalse;
static char textEncName[128] = "";
-static char ownerPassword[33] = "";
-static char userPassword[33] = "";
+static char ownerPassword[33] = "\001";
+static char userPassword[33] = "\001";
static char cfgFileName[256] = "";
static GBool printVersion = gFalse;
static GBool printHelp = gFalse;
static ArgDesc argDesc[] = {
+ {"-f", argInt, &firstPage, 0,
+ "first page to convert"},
+ {"-l", argInt, &lastPage, 0,
+ "last page to convert"},
{"-meta", argFlag, &printMetadata, 0,
"print the document metadata (XML)"},
{"-enc", argString, textEncName, sizeof(textEncName),
@@ -77,7 +83,8 @@ int main(int argc, char *argv[]) {
GString *metadata;
GBool ok;
int exitCode;
- int i;
+ int pg, i;
+ GBool multiPage;
exitCode = 99;
@@ -107,12 +114,12 @@ int main(int argc, char *argv[]) {
}
// open PDF file
- if (ownerPassword[0]) {
+ if (ownerPassword[0] != '\001') {
ownerPW = new GString(ownerPassword);
} else {
ownerPW = NULL;
}
- if (userPassword[0]) {
+ if (userPassword[0] != '\001') {
userPW = new GString(userPassword);
} else {
userPW = NULL;
@@ -129,29 +136,43 @@ int main(int argc, char *argv[]) {
goto err2;
}
+ // get page range
+ if (firstPage < 1) {
+ firstPage = 1;
+ }
+ if (lastPage == 0) {
+ multiPage = gFalse;
+ lastPage = 1;
+ } else {
+ multiPage = gTrue;
+ }
+ if (lastPage < 1 || lastPage > doc->getNumPages()) {
+ lastPage = doc->getNumPages();
+ }
+
// print doc info
doc->getDocInfo(&info);
if (info.isDict()) {
- printInfoString(info.getDict(), "Title", "Title: ", uMap);
- printInfoString(info.getDict(), "Subject", "Subject: ", uMap);
- printInfoString(info.getDict(), "Keywords", "Keywords: ", uMap);
- printInfoString(info.getDict(), "Author", "Author: ", uMap);
- printInfoString(info.getDict(), "Creator", "Creator: ", uMap);
- printInfoString(info.getDict(), "Producer", "Producer: ", uMap);
- printInfoDate(info.getDict(), "CreationDate", "CreationDate: ");
- printInfoDate(info.getDict(), "ModDate", "ModDate: ");
+ printInfoString(info.getDict(), "Title", "Title: ", uMap);
+ printInfoString(info.getDict(), "Subject", "Subject: ", uMap);
+ printInfoString(info.getDict(), "Keywords", "Keywords: ", uMap);
+ printInfoString(info.getDict(), "Author", "Author: ", uMap);
+ printInfoString(info.getDict(), "Creator", "Creator: ", uMap);
+ printInfoString(info.getDict(), "Producer", "Producer: ", uMap);
+ printInfoDate(info.getDict(), "CreationDate", "CreationDate: ");
+ printInfoDate(info.getDict(), "ModDate", "ModDate: ");
}
info.free();
// print tagging info
- printf("Tagged: %s\n",
+ printf("Tagged: %s\n",
doc->getStructTreeRoot()->isDict() ? "yes" : "no");
// print page count
- printf("Pages: %d\n", doc->getNumPages());
+ printf("Pages: %d\n", doc->getNumPages());
// print encryption info
- printf("Encrypted: ");
+ printf("Encrypted: ");
if (doc->isEncrypted()) {
printf("yes (print:%s copy:%s change:%s addNotes:%s)\n",
doc->okToPrint(gTrue) ? "yes" : "no",
@@ -163,16 +184,20 @@ int main(int argc, char *argv[]) {
}
// print page size
- if (doc->getNumPages() >= 1) {
- w = doc->getPageWidth(1);
- h = doc->getPageHeight(1);
- printf("Page size: %g x %g pts", w, h);
+ for (pg = firstPage; pg <= lastPage; ++pg) {
+ w = doc->getPageWidth(pg);
+ h = doc->getPageHeight(pg);
+ if (multiPage) {
+ printf("Page %4d size: %g x %g pts", pg, w, h);
+ } else {
+ printf("Page size: %g x %g pts", w, h);
+ }
if ((fabs(w - 612) < 0.1 && fabs(h - 792) < 0.1) ||
(fabs(w - 792) < 0.1 && fabs(h - 612) < 0.1)) {
printf(" (letter)");
} else {
- hISO = sqrt(sqrt(2)) * 7200 / 2.54;
- wISO = hISO / sqrt(2);
+ hISO = sqrt(sqrt(2.0)) * 7200 / 2.54;
+ wISO = hISO / sqrt(2.0);
for (i = 0; i <= 6; ++i) {
if ((fabs(w - wISO) < 1 && fabs(h - hISO) < 1) ||
(fabs(w - hISO) < 1 && fabs(h - wISO) < 1)) {
@@ -180,7 +205,7 @@ int main(int argc, char *argv[]) {
break;
}
hISO = wISO;
- wISO /= sqrt(2);
+ wISO /= sqrt(2.0);
}
}
printf("\n");
@@ -195,22 +220,22 @@ int main(int argc, char *argv[]) {
if (f) {
#if HAVE_FSEEKO
fseeko(f, 0, SEEK_END);
- printf("File size: %u bytes\n", (Guint)ftello(f));
+ printf("File size: %u bytes\n", (Guint)ftello(f));
#elif HAVE_FSEEK64
fseek64(f, 0, SEEK_END);
- printf("File size: %u bytes\n", (Guint)ftell64(f));
+ printf("File size: %u bytes\n", (Guint)ftell64(f));
#else
fseek(f, 0, SEEK_END);
- printf("File size: %d bytes\n", (int)ftell(f));
+ printf("File size: %d bytes\n", (int)ftell(f));
#endif
fclose(f);
}
// print linearization info
- printf("Optimized: %s\n", doc->isLinearized() ? "yes" : "no");
+ printf("Optimized: %s\n", doc->isLinearized() ? "yes" : "no");
// print PDF version
- printf("PDF version: %.1f\n", doc->getPDFVersion());
+ printf("PDF version: %.1f\n", doc->getPDFVersion());
// print the metadata
if (printMetadata && (metadata = doc->readMetadata())) {
diff --git a/pdf/xpdf/pdftopbm.cc b/pdf/xpdf/pdftopbm.cc
index 704a3d0..a0d0af5 100644
--- a/pdf/xpdf/pdftopbm.cc
+++ b/pdf/xpdf/pdftopbm.cc
@@ -30,8 +30,8 @@
static int firstPage = 1;
static int lastPage = 0;
static int resolution = 150;
-static char ownerPassword[33] = "";
-static char userPassword[33] = "";
+static char ownerPassword[33] = "\001";
+static char userPassword[33] = "\001";
static GBool quiet = gFalse;
static char cfgFileName[256] = "";
static GBool printVersion = gFalse;
@@ -96,12 +96,12 @@ int main(int argc, char *argv[]) {
}
// open PDF file
- if (ownerPassword[0]) {
+ if (ownerPassword[0] != '\001') {
ownerPW = new GString(ownerPassword);
} else {
ownerPW = NULL;
}
- if (userPassword[0]) {
+ if (userPassword[0] != '\001') {
userPW = new GString(userPassword);
} else {
userPW = NULL;
@@ -127,7 +127,8 @@ int main(int argc, char *argv[]) {
// write PBM files
pbmOut = PBMOutputDev::makePBMOutputDev(NULL, pbmRoot);
pbmOut->startDoc(doc->getXRef());
- doc->displayPages(pbmOut, firstPage, lastPage, resolution, 0, gFalse);
+ doc->displayPages(pbmOut, firstPage, lastPage,
+ resolution, resolution, 0, gFalse);
PBMOutputDev::killPBMOutputDev(pbmOut);
exitCode = 0;
diff --git a/pdf/xpdf/pdftops.cc b/pdf/xpdf/pdftops.cc
index 2bb2e3b..247e455 100644
--- a/pdf/xpdf/pdftops.cc
+++ b/pdf/xpdf/pdftops.cc
@@ -48,8 +48,8 @@ static char paperSize[15] = "";
static int paperWidth = 0;
static int paperHeight = 0;
static GBool duplex = gFalse;
-static char ownerPassword[33] = "";
-static char userPassword[33] = "";
+static char ownerPassword[33] = "\001";
+static char userPassword[33] = "\001";
static GBool quiet = gFalse;
static char cfgFileName[256] = "";
static GBool printVersion = gFalse;
@@ -220,12 +220,12 @@ int main(int argc, char *argv[]) {
}
// open PDF file
- if (ownerPassword[0]) {
+ if (ownerPassword[0] != '\001') {
ownerPW = new GString(ownerPassword);
} else {
ownerPW = NULL;
}
- if (userPassword[0]) {
+ if (userPassword[0] != '\001') {
userPW = new GString(userPassword);
} else {
userPW = NULL;
@@ -281,7 +281,7 @@ 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, 0, gFalse);
+ doc->displayPages(psOut, firstPage, lastPage, 72, 72, 0, gFalse);
} else {
delete psOut;
exitCode = 2;
diff --git a/pdf/xpdf/pdftotext.cc b/pdf/xpdf/pdftotext.cc
index a67f924..c6ad9c0 100644
--- a/pdf/xpdf/pdftotext.cc
+++ b/pdf/xpdf/pdftotext.cc
@@ -40,45 +40,48 @@ static GBool rawOrder = gFalse;
static GBool htmlMeta = gFalse;
static char textEncName[128] = "";
static char textEOL[16] = "";
-static char ownerPassword[33] = "";
-static char userPassword[33] = "";
+static GBool noPageBreaks = gFalse;
+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,
+ {"-f", argInt, &firstPage, 0,
"first page to convert"},
- {"-l", argInt, &lastPage, 0,
+ {"-l", argInt, &lastPage, 0,
"last page to convert"},
- {"-layout", argFlag, &physLayout, 0,
+ {"-layout", argFlag, &physLayout, 0,
"maintain original physical layout"},
- {"-raw", argFlag, &rawOrder, 0,
+ {"-raw", argFlag, &rawOrder, 0,
"keep strings in content stream order"},
- {"-htmlmeta", argFlag, &htmlMeta, 0,
+ {"-htmlmeta", argFlag, &htmlMeta, 0,
"generate a simple HTML file, including the meta information"},
- {"-enc", argString, textEncName, sizeof(textEncName),
+ {"-enc", argString, textEncName, sizeof(textEncName),
"output text encoding name"},
- {"-eol", argString, textEOL, sizeof(textEOL),
+ {"-eol", argString, textEOL, sizeof(textEOL),
"output end-of-line convention (unix, dos, or mac)"},
- {"-opw", argString, ownerPassword, sizeof(ownerPassword),
+ {"-nopgbrk", argFlag, &noPageBreaks, 0,
+ "don't insert page breaks between pages"},
+ {"-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),
+ {"-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}
};
@@ -120,6 +123,9 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "Bad '-eol' value on command line\n");
}
}
+ if (noPageBreaks) {
+ globalParams->setTextPageBreaks(gFalse);
+ }
if (quiet) {
globalParams->setErrQuiet(quiet);
}
@@ -132,12 +138,12 @@ int main(int argc, char *argv[]) {
}
// open PDF file
- if (ownerPassword[0]) {
+ if (ownerPassword[0] != '\001') {
ownerPW = new GString(ownerPassword);
} else {
ownerPW = NULL;
}
- if (userPassword[0]) {
+ if (userPassword[0] != '\001') {
userPW = new GString(userPassword);
} else {
userPW = NULL;
@@ -228,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, 0, gFalse);
+ doc->displayPages(textOut, firstPage, lastPage, 72, 72, 0, gFalse);
} else {
delete textOut;
exitCode = 2;
diff --git a/pdf/xpdf/vms_make.com b/pdf/xpdf/vms_make.com
index 174debb..4a59bda 100644
--- a/pdf/xpdf/vms_make.com
+++ b/pdf/xpdf/vms_make.com
@@ -22,7 +22,7 @@ $ COMMON_OBJS = "Annot.obj,Array.obj,BuiltinFont.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,XRef.obj"
+ "UnicodeMap.obj,UnicodeTypeTable.obj,XRef.obj"
$ COMMON_LIBS = "[]common.olb/lib,[-.goo]libgoo.olb/lib"
$!
$ XPDF_OBJS = "xpdf.obj,FTFont.obj,PSOutputDev.obj," + -
diff --git a/pdf/xpdf/xpdf.cc b/pdf/xpdf/xpdf.cc
index 73a0fe2..bda355e 100644
--- a/pdf/xpdf/xpdf.cc
+++ b/pdf/xpdf/xpdf.cc
@@ -30,8 +30,8 @@ static int paperHeight = 0;
static GBool level1 = gFalse;
static char textEncName[128] = "";
static char textEOL[16] = "";
-static char ownerPassword[33] = "";
-static char userPassword[33] = "";
+static char ownerPassword[33] = "\001";
+static char userPassword[33] = "\001";
static GBool fullScreen = gFalse;
static char remoteName[100] = "xpdf_";
static GBool doRemoteReload = gFalse;
@@ -59,7 +59,7 @@ static ArgDesc argDesc[] = {
{"-papercolor", argStringDummy, NULL, 0,
"color of paper background"},
{"-z", argStringDummy, NULL, 0,
- "initial zoom level (-5..5, page, width)"},
+ "initial zoom level (percent, 'page', 'width')"},
#if HAVE_T1LIB_H
{"-t1lib", argString, t1libControlStr, sizeof(t1libControlStr),
"t1lib font rasterizer control: none, plain, low, high"},
@@ -249,10 +249,10 @@ int main(int argc, char *argv[]) {
app->setFullScreen(fullScreen);
// check for password string(s)
- ownerPasswordStr = ownerPassword[0] ? new GString(ownerPassword)
- : (GString *)NULL;
- userPasswordStr = userPassword[0] ? new GString(userPassword)
- : (GString *)NULL;
+ ownerPasswordStr = ownerPassword[0] != '\001' ? new GString(ownerPassword)
+ : (GString *)NULL;
+ userPasswordStr = userPassword[0] != '\001' ? new GString(userPassword)
+ : (GString *)NULL;
// open the file and run the main loop
if (destName) {
diff --git a/pdf/xpdf/xpdfconfig.h b/pdf/xpdf/xpdfconfig.h
index eda629c..ef08a7f 100644
--- a/pdf/xpdf/xpdfconfig.h
+++ b/pdf/xpdf/xpdfconfig.h
@@ -14,12 +14,12 @@
//------------------------------------------------------------------------
// xpdf version
-#define xpdfVersion "2.02"
-#define xpdfVersionNum 2.02
+#define xpdfVersion "2.03"
+#define xpdfVersionNum 2.03
#define xpdfMajorVersion 2
-#define xpdfMinorVersion 2
+#define xpdfMinorVersion 3
#define xpdfMajorVersionStr "2"
-#define xpdfMinorVersionStr "2"
+#define xpdfMinorVersionStr "3"
// supported PDF version
#define supportedPDFVersionStr "1.4"
@@ -29,7 +29,7 @@
#define xpdfCopyright "Copyright 1996-2003 Glyph & Cog, LLC"
// Windows resource file stuff
-#define winxpdfVersion "WinXpdf 2.02"
+#define winxpdfVersion "WinXpdf 2.03"
#define xpdfCopyrightAmp "Copyright 1996-2003 Glyph && Cog, LLC"
//------------------------------------------------------------------------
@@ -82,7 +82,7 @@
// popen
//------------------------------------------------------------------------
-#ifdef _MSC_VER
+#if defined(_MSC_VER) || defined(__BORLANDC__)
#define popen _popen
#define pclose _pclose
#endif
@@ -101,7 +101,7 @@
#undef CDECL
#endif
-#ifdef _MSC_VER
+#if defined(_MSC_VER) || defined(__BORLANDC__)
#define CDECL __cdecl
#else
#define CDECL