]> www.fi.muni.cz Git - evince.git/commitdiff
Merge with Xpdf 2.02 and make it build
authorMartin Kretzschmar <mkretzschmar@src.gnome.org>
Tue, 1 Apr 2003 19:47:11 +0000 (19:47 +0000)
committerMartin Kretzschmar <mkretzschmar@src.gnome.org>
Tue, 1 Apr 2003 19:47:11 +0000 (19:47 +0000)
100 files changed:
pdf/goo/GHash.cc
pdf/goo/GHash.h
pdf/goo/GList.cc
pdf/goo/GList.h
pdf/goo/GString.cc
pdf/goo/GString.h
pdf/goo/gfile.cc
pdf/goo/gfile.h
pdf/goo/gmem.c
pdf/goo/gmem.h
pdf/goo/gmempp.cc
pdf/goo/gtypes.h
pdf/goo/parseargs.c
pdf/goo/parseargs.h
pdf/goo/vms_make.com
pdf/xpdf/Annot.cc
pdf/xpdf/Annot.h
pdf/xpdf/Array.cc
pdf/xpdf/Array.h
pdf/xpdf/BuiltinFont.cc
pdf/xpdf/BuiltinFont.h
pdf/xpdf/BuiltinFontTables.cc
pdf/xpdf/CMap.cc
pdf/xpdf/CMap.h
pdf/xpdf/Catalog.cc
pdf/xpdf/Catalog.h
pdf/xpdf/CharCodeToUnicode.cc
pdf/xpdf/CharCodeToUnicode.h
pdf/xpdf/Decrypt.cc
pdf/xpdf/Decrypt.h
pdf/xpdf/Dict.cc
pdf/xpdf/Dict.h
pdf/xpdf/Error.cc
pdf/xpdf/Error.h
pdf/xpdf/FTFont.cc
pdf/xpdf/FTFont.h
pdf/xpdf/FontEncodingTables.cc
pdf/xpdf/FontFile.cc
pdf/xpdf/FontFile.h
pdf/xpdf/Function.cc
pdf/xpdf/Function.h
pdf/xpdf/Gfx.cc
pdf/xpdf/Gfx.h
pdf/xpdf/GfxFont.cc
pdf/xpdf/GfxFont.h
pdf/xpdf/GfxState.cc
pdf/xpdf/GfxState.h
pdf/xpdf/GlobalParams.cc
pdf/xpdf/GlobalParams.h
pdf/xpdf/ImageOutputDev.cc
pdf/xpdf/ImageOutputDev.h
pdf/xpdf/Lexer.cc
pdf/xpdf/Lexer.h
pdf/xpdf/Link.cc
pdf/xpdf/Link.h
pdf/xpdf/NameToCharCode.cc
pdf/xpdf/NameToCharCode.h
pdf/xpdf/NameToUnicodeTable.h
pdf/xpdf/Object.cc
pdf/xpdf/Object.h
pdf/xpdf/OutputDev.cc
pdf/xpdf/OutputDev.h
pdf/xpdf/PBMOutputDev.cc
pdf/xpdf/PBMOutputDev.h
pdf/xpdf/PDFDoc.cc
pdf/xpdf/PDFDoc.h
pdf/xpdf/PSOutputDev.cc
pdf/xpdf/PSOutputDev.h
pdf/xpdf/PSTokenizer.cc
pdf/xpdf/PSTokenizer.h
pdf/xpdf/Page.cc
pdf/xpdf/Page.h
pdf/xpdf/Parser.cc
pdf/xpdf/Parser.h
pdf/xpdf/SFont.cc
pdf/xpdf/SFont.h
pdf/xpdf/Stream-CCITT.h
pdf/xpdf/Stream.cc
pdf/xpdf/Stream.h
pdf/xpdf/T1Font.cc
pdf/xpdf/T1Font.h
pdf/xpdf/TTFont.cc
pdf/xpdf/TTFont.h
pdf/xpdf/TextOutputDev.cc
pdf/xpdf/TextOutputDev.h
pdf/xpdf/UnicodeMap.cc
pdf/xpdf/UnicodeMap.h
pdf/xpdf/XOutputDev.cc
pdf/xpdf/XOutputDev.h
pdf/xpdf/XRef.cc
pdf/xpdf/XRef.h
pdf/xpdf/pdffonts.cc
pdf/xpdf/pdfimages.cc
pdf/xpdf/pdfinfo.cc
pdf/xpdf/pdftopbm.cc
pdf/xpdf/pdftops.cc
pdf/xpdf/pdftotext.cc
pdf/xpdf/vms_make.com
pdf/xpdf/xpdf.cc
pdf/xpdf/xpdfconfig.h

index dfab92607a564d0d4303afbf3a4b394e51faf40c..7036316b3c93e36cf034b4d854cfe6384b97a976 100644 (file)
@@ -2,7 +2,7 @@
 //
 // GHash.cc
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 8d73f3bbf38ead84220daa9e8c0a1b2f0795025c..69c767b3aaef0235337b902f6e242f1faa8a2a15 100644 (file)
@@ -2,7 +2,7 @@
 //
 // GHash.h
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index accd73dcfd44dd71822ba6201c35a0111ce1a302..9534232e87aadc84ef7a726223bbbd7cdecb5f36 100644 (file)
@@ -2,7 +2,7 @@
 //
 // GList.cc
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 6a610ed1295dad4046327d4a11b5df431e276147..4c52489f35db22acd3103d4862cdbb6144fba8db 100644 (file)
@@ -2,7 +2,7 @@
 //
 // GList.h
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 25e0e05737934cb1291a00a1d597487d97aa5fd1..7653fd06e3e6b1dd2d1ed30f6321dba2e069a22b 100644 (file)
@@ -4,7 +4,7 @@
 //
 // Simple variable-length string type.
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index d22cc196848a88955c91ab92585b33089f6baf43..2083802b381736d16a56a954eb1da8205b1ebe97 100644 (file)
@@ -4,7 +4,7 @@
 //
 // Simple variable-length string type.
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index e6603c675bbd907d9bc40e6b93b8fc90ad8ba545..b4fb616c0718553b0e69747d4f7256c98ff0afa6 100644 (file)
@@ -4,7 +4,7 @@
 //
 // Miscellaneous file and directory name manipulation.
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 193209cc99c1bd0fd6c82c0ca64603c3f7243528..d364d8d44f82d2c0781a990db77ebd715ff8538d 100644 (file)
@@ -4,7 +4,7 @@
 //
 // Miscellaneous file and directory name manipulation.
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 27ebb2b6ec9e0d6774b4c6854602e6bc611e9851..07bbf8108b0cf1be314e0b3a82c172df4674176b 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Memory routines with out-of-memory checking.
  *
- * Copyright 1996-2002 Glyph & Cog, LLC
+ * Copyright 1996-2003 Glyph & Cog, LLC
  */
 
 #include <aconf.h>
index 93ccb94be13605304df354e37366c0708b4b58eb..587e7fa43c9fd8c14eb1adc459f2369e0be83e3a 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Memory routines with out-of-memory checking.
  *
- * Copyright 1996-2002 Glyph & Cog, LLC
+ * Copyright 1996-2003 Glyph & Cog, LLC
  */
 
 #ifndef GMEM_H
index ed94f7a1d16163b41173d700c2a38b058860a6e6..b1ee970d38ab14c8fa9ab3cb1f10eaa1876c7ea4 100644 (file)
@@ -4,7 +4,7 @@
 //
 // Use gmalloc/gfree for C++ new/delete operators.
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 1879b88b73c5faa86d047b076f336ed6151cf002..9f64f57d4a1c3439a0e4e04d569577a662f42f9b 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Some useful simple types.
  *
- * Copyright 1996-2002 Glyph & Cog, LLC
+ * Copyright 1996-2003 Glyph & Cog, LLC
  */
 
 #ifndef GTYPES_H
index 1f2c986a84300e66ed05003ad2fe76ca7e2aa873..6bcde2c291b94548427000c208b6b50dd03a5f11 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Command line argument parser.
  *
- * Copyright 1996-2002 Glyph & Cog, LLC
+ * Copyright 1996-2003 Glyph & Cog, LLC
  */
 
 #include <locale.h>
index 2cc2df7dca5bff2be198f62cbb750e581a87a51e..0d163b9856e094787bee0d4739a67ade8a2e003b 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Command line argument parser.
  *
- * Copyright 1996-2002 Glyph & Cog, LLC
+ * Copyright 1996-2003 Glyph & Cog, LLC
  */
 
 #ifndef PARSEARGS_H
index e57c9602c1e0b25670eca0fedcf9139ce0581ce5..676643fcc73689715674629ed6a80bbe5dd34d18 100644 (file)
@@ -4,7 +4,7 @@ $! Goo library compile script for VMS.
 $!
 $! Written by Patrick Moreau, Martin P.J. Zinser.
 $!
-$! Copyright 1996-2002 Glyph & Cog, LLC
+$! Copyright 1996-2003 Glyph & Cog, LLC
 $!
 $!========================================================================
 $!
index 8ebf6a0c088fdfe817340a5be19fa814b25fd8b9..68373f9b17e53bef5e070e656f29c813876ae558 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Annot.cc
 //
-// Copyright 2000-2002 Glyph & Cog, LLC
+// Copyright 2000-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 731fa8a5844a9fbec433a67f27aab6da5bc83450..89dde0f90f17a012493b1998d4d69621a36d391d 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Annot.h
 //
-// Copyright 2000-2002 Glyph & Cog, LLC
+// Copyright 2000-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 9c6cb3415a5911531de6470379d941a0c07190c0..27ecbe9e7a1ae4a1559da5c3ac125d9ab71a4a5b 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Array.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -12,6 +12,7 @@
 #pragma implementation
 #endif
 
+#include <stdlib.h>
 #include <stddef.h>
 #include "gmem.h"
 #include "Object.h"
@@ -46,9 +47,23 @@ void Array::add(Object *elem) {
 }
 
 Object *Array::get(int i, Object *obj) {
+  if (i < 0 || i >= length) {
+#ifdef DEBUG_MEM
+    abort();
+#else
+    return obj->initNull();
+#endif
+  }
   return elems[i].fetch(xref, obj);
 }
 
 Object *Array::getNF(int i, Object *obj) {
+  if (i < 0 || i >= length) {
+#ifdef DEBUG_MEM
+    abort();
+#else
+    return obj->initNull();
+#endif
+  }
   return elems[i].copy(obj);
 }
index 09dbe2bcfbd36f1c02a2dcf3627d5bf8ed876ea5..20ae05f29707ba81e9a3f213609e17471947b755 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Array.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index a504b4c31790edbc7a8b8c4db6159c6b28b6466d..a687e73ab5d84474921a1caf5ab9212a58a61d08 100644 (file)
@@ -2,7 +2,7 @@
 //
 // BuiltinFont.cc
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 69d2e75d1a93230ea4f111960be3534324e18b35..903ed19ec507ba5c67bac890b88e33f584ce0fb4 100644 (file)
@@ -2,7 +2,7 @@
 //
 // BuiltinFont.h
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index e2acfef8a46a59bcdd6639df62dd959def16f3c4..296e5645e1b65387d85dc6aa87040b236f288a5b 100644 (file)
@@ -2,7 +2,7 @@
 //
 // BuiltinFontTables.cc
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index b00021835342d1736b41e41d574023e42ec4bbe1..c60ce3c3761338d57e7e779eafc35cb5b2e185a3 100644 (file)
@@ -2,7 +2,7 @@
 //
 // CMap.cc
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index ce926baf3f54c7535b8ba12c4ea392975c5d8228..b44f07a0d8d943becefbfc32dfff475ef212b935 100644 (file)
@@ -2,7 +2,7 @@
 //
 // CMap.h
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index efea82862e43ebbd92f91229cc16986d9fc1d7ef..ad0821bc5c872c67972d253af4f9124e8d111e7d 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Catalog.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 7f89a611a30b4750674032320d323eec6bf3f52f..8ab7c61c5b9aa6dd0f36ea31fd9017fc62b395c0 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Catalog.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index e2fecbc04d87b55a959bf7350f19561411ea3d9b..a374b1bc352259a8b4e0702de5b2f5b85298e1d0 100644 (file)
@@ -2,7 +2,7 @@
 //
 // CharCodeToUnicode.cc
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 9cbd2a96b4da69ca5268e6441fafacba8ca73ea4..b20f323c14fe6c913bd3832dbb6386d84cb81f4f 100644 (file)
@@ -4,7 +4,7 @@
 //
 // Mapping from character codes to Unicode.
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index b58a6c55c4b1581e28aa940de66bc0f9375c1ece..dca3762c1b37c96458fca0c47f05bfc2d67a7f34 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Decrypt.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 903ee12b1b0439e28850b1e1913a623a7eff8131..71f94574871bc422776c8b33a04ec4b4e6ff61c9 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Decrypt.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index ad4ec3ef36df5421fdffaad3608684cccb0dc2dd..9575e4cbf108f523870fca77fba975ddb45e7a1a 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Dict.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index e87ed9034cec7183c58eee6b1888e8c66a9d8f11..08f55ecd48ed657acdde8ad72e102ae58d1706f8 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Dict.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 4b2d120a616dec6544e933a0209ebd230bf41027..c03f75f4835f862b24f32026eb68eb706e6e7fc1 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Error.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index c924065d323b1664fbf6de4c1023f1d9ec19c6cd..0ce55e9ab41505e2dacc2e833ef211e20c1dc660 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Error.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index ab101acdec795a2f3f4f48ef15e2c5c6306cb188..c360eb7540c18b80bb365169712f6c9757f71eb2 100644 (file)
@@ -2,7 +2,7 @@
 //
 // FTFont.cc
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -48,7 +48,8 @@ FTFontEngine::~FTFontEngine() {
 //------------------------------------------------------------------------
 
 FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
-                      char **fontEnc, GBool pdfFontHasEncoding) {
+                      char **fontEnc, GBool pdfFontHasEncoding,
+                      GBool pdfFontIsSymbolic) {
   char *name;
   int unicodeCmap, macRomanCmap, msSymbolCmap;
   int i, j;
@@ -82,7 +83,9 @@ FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
     // 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,
+    //    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:
@@ -94,8 +97,9 @@ FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
     //    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) {
+      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) {
@@ -112,6 +116,10 @@ FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
       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;
@@ -143,7 +151,9 @@ FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
 }
 
 FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
-                      Gushort *cidToGIDA, int cidToGIDLenA) {
+                      Gushort *cidToGIDA, int cidToGIDLenA, GBool embedded) {
+  int i;
+
   ok = gFalse;
   engine = engineA;
   codeMap = NULL;
@@ -156,11 +166,33 @@ FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
   cidToGIDLen = cidToGIDLenA;
   cidToGID = (Gushort *)gmalloc(cidToGIDLen * sizeof(Gushort));
   memcpy(cidToGID, cidToGIDA, cidToGIDLen * sizeof(Gushort));
-  mode = ftFontModeCIDToGIDMap;
+  if (!strcmp(face->driver->root.clazz->module_name, "t1cid")) {
+    mode = ftFontModeCID;
+  } else if (!strcmp(face->driver->root.clazz->module_name, "cff")) {
+    mode = ftFontModeCFFCharset;
+  } else if (embedded) {
+    mode = ftFontModeCIDToGIDMap;
+  } else {
+    mode = ftFontModeUnicode;
+    for (i = 0; i < face->num_charmaps; ++i) {
+      if ((face->charmaps[i]->platform_id == 3 &&
+          face->charmaps[i]->encoding_id == 1) ||
+         face->charmaps[i]->platform_id == 0) {
+       break;
+      }
+    }
+    if (i == face->num_charmaps) {
+      i = 0;
+    }
+    FT_Set_Charmap(face, face->charmaps[i]);
+  }
   ok = gTrue;
 }
 
-FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName) {
+FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName,
+                      GBool embedded) {
+  int i;
+
   ok = gFalse;
   engine = engineA;
   codeMap = NULL;
@@ -172,8 +204,21 @@ FTFontFile::FTFontFile(FTFontEngine *engineA, char *fontFileName) {
   }
   if (!strcmp(face->driver->root.clazz->module_name, "t1cid")) {
     mode = ftFontModeCID;
-  } else {
+  } else if (embedded) {
     mode = ftFontModeCFFCharset;
+  } else {
+    mode = ftFontModeUnicode;
+    for (i = 0; i < face->num_charmaps; ++i) {
+      if ((face->charmaps[i]->platform_id == 3 &&
+          face->charmaps[i]->encoding_id == 1) ||
+         face->charmaps[i]->platform_id == 0) {
+       break;
+      }
+    }
+    if (i == face->num_charmaps) {
+      i = 0;
+    }
+    FT_Set_Charmap(face, face->charmaps[i]);
   }
   ok = gTrue;
 }
@@ -336,7 +381,9 @@ GBool FTFont::drawChar(Drawable d, int w, int h, GC gc,
   XColor xcolor;
   int bgR, bgG, bgB;
   Gulong colors[5];
-  Guchar *p;
+  Guchar *bitmap, *p;
+  GBool tempBitmap;
+  XImage *img;
   int pix;
   int xOffset, yOffset, x0, y0, x1, y1, gw, gh, w0, h0;
   int xx, yy, xx1;
@@ -349,7 +396,8 @@ GBool FTFont::drawChar(Drawable d, int w, int h, GC gc,
   }
 
   // generate the glyph pixmap
-  if (!(p = getGlyphPixmap(c, u, &xOffset, &yOffset, &gw, &gh))) {
+  if (!(bitmap = getGlyphPixmap(c, u, &xOffset, &yOffset, &gw, &gh,
+                               &tempBitmap))) {
     return gFalse;
   }
 
@@ -371,7 +419,7 @@ GBool FTFont::drawChar(Drawable d, int w, int h, GC gc,
     w0 = w - x0;
   }
   if (w0 < 0) {
-    return gTrue;
+    goto done;
   }
   if (y0 < 0) {
     y1 = -y0;
@@ -382,17 +430,29 @@ GBool FTFont::drawChar(Drawable d, int w, int h, GC gc,
     h0 = h - y0;
   }
   if (h0 < 0) {
-    return gTrue;
+    goto done;
+  }
+
+  // getGlyphPixmap may have returned a larger-than-cache-entry
+  // bitmap, in which case we need to allocate a temporary XImage here
+  if (tempBitmap) {
+    if (!(img = XCreateImage(engine->display, engine->visual, engine->depth,
+                            ZPixmap, 0, NULL, gw, gh, 8, 0))) {
+      goto done;
+    }
+    img->data = (char *)gmalloc(gh * img->bytes_per_line);
+  } else {
+    img = image;
   }
 
   // read the X image
   XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1,
-              ZPixmap, image, x1, y1);
+              ZPixmap, img, x1, y1);
 
   if (engine->aa) {
 
     // compute the colors
-    xcolor.pixel = XGetPixel(image, x1 + w0/2, y1 + h0/2);
+    xcolor.pixel = XGetPixel(img, x1 + w0/2, y1 + h0/2);
     XQueryColor(engine->display, engine->colormap, &xcolor);
     bgR = xcolor.red;
     bgG = xcolor.green;
@@ -409,6 +469,7 @@ GBool FTFont::drawChar(Drawable d, int w, int h, GC gc,
     colors[4] = engine->findColor(r, g, b);
 
     // stuff the glyph pixmap into the X image
+    p = bitmap;
     for (yy = 0; yy < gh; ++yy) {
       for (xx = 0; xx < gw; ++xx) {
        pix = *p++ & 0xff;
@@ -420,7 +481,7 @@ GBool FTFont::drawChar(Drawable d, int w, int h, GC gc,
          pix = 4;
        }
        if (pix > 0) {
-         XPutPixel(image, xx, yy, colors[pix]);
+         XPutPixel(img, xx, yy, colors[pix]);
        }
       }
     }
@@ -431,12 +492,13 @@ GBool FTFont::drawChar(Drawable d, int w, int h, GC gc,
     colors[1] = engine->findColor(r, g, b);
 
     // stuff the glyph bitmap into the X image
+    p = bitmap;
     for (yy = 0; yy < gh; ++yy) {
       for (xx = 0; xx < gw; xx += 8) {
        pix = *p++;
        for (xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) {
          if (pix & 0x80) {
-           XPutPixel(image, xx1, yy, colors[1]);
+           XPutPixel(img, xx1, yy, colors[1]);
          }
          pix <<= 1;
        }
@@ -446,13 +508,23 @@ GBool FTFont::drawChar(Drawable d, int w, int h, GC gc,
   }
 
   // draw the X image
-  XPutImage(engine->display, d, gc, image, x1, y1, x0, y0, w0, h0);
+  XPutImage(engine->display, d, gc, img, x1, y1, x0, y0, w0, h0);
 
+  if (tempBitmap) {
+    gfree(img->data);
+    img->data = NULL;
+    XDestroyImage(img);
+  }
+ done:
+  if (tempBitmap) {
+    gfree(bitmap);
+  }
   return gTrue;
 }
 
 Guchar *FTFont::getGlyphPixmap(CharCode c, Unicode u,
-                              int *x, int *y, int *w, int *h) {
+                              int *x, int *y, int *w, int *h,
+                              GBool *tempBitmap) {
   FT_GlyphSlot slot;
   FT_UInt idx;
   int rowSize;
@@ -474,6 +546,7 @@ Guchar *FTFont::getGlyphPixmap(CharCode c, Unicode u,
        }
       }
       cacheTags[i+j].mru = 0x8000;
+      *tempBitmap = gFalse;
       return cache + (i+j) * glyphSize;
     }
   }
@@ -504,42 +577,45 @@ Guchar *FTFont::getGlyphPixmap(CharCode c, Unicode u,
                                             ft_render_mode_mono)) {
     return gFalse;
   }
+
+  // copy the glyph into the cache or a temporary bitmap
   *x = -slot->bitmap_left;
   *y = slot->bitmap_top;
   *w = slot->bitmap.width;
   *h = slot->bitmap.rows;
-  if (*w > glyphW || *h > glyphH) {
-#if 1 //~ debug
-    fprintf(stderr, "Weird FreeType glyph size: %d > %d or %d > %d\n",
-           *w, glyphW, *h, glyphH);
-#endif
-    return NULL;
+  if (fontFile->engine->aa) {
+    rowSize = *w;
+  } else {
+    rowSize = (*w + 7) >> 3;
   }
-
-  // store glyph pixmap in cache
-  ret = NULL;
-  for (j = 0; j < cacheAssoc; ++j) {
-    if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) {
-      cacheTags[i+j].mru = 0x8000;
-      cacheTags[i+j].code = c;
-      cacheTags[i+j].x = *x;
-      cacheTags[i+j].y = *y;
-      cacheTags[i+j].w = *w;
-      cacheTags[i+j].h = *h;
-      if (fontFile->engine->aa) {
-       rowSize = *w;
+  if (*w > glyphW || *h > glyphH) {
+    // the glyph doesn't fit in the bounding box -- return a
+    // temporary, uncached bitmap (this shouldn't happen but some
+    // fonts have incorrect bboxes)
+    ret = (Guchar *)gmalloc(*h * rowSize);
+    *tempBitmap = gTrue;
+  } else {
+    // store glyph pixmap in cache
+    ret = NULL; // make gcc happy
+    for (j = 0; j < cacheAssoc; ++j) {
+      if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) {
+       cacheTags[i+j].mru = 0x8000;
+       cacheTags[i+j].code = c;
+       cacheTags[i+j].x = *x;
+       cacheTags[i+j].y = *y;
+       cacheTags[i+j].w = *w;
+       cacheTags[i+j].h = *h;
+       ret = cache + (i+j) * glyphSize;
       } else {
-       rowSize = (*w + 7) >> 3;
-      }
-      ret = cache + (i+j) * glyphSize;
-      for (k = 0, p = ret, q = slot->bitmap.buffer;
-          k < slot->bitmap.rows;
-          ++k, p += rowSize, q += slot->bitmap.pitch) {
-       memcpy(p, q, rowSize);
+       ++cacheTags[i+j].mru;
       }
-    } else {
-      ++cacheTags[i+j].mru;
     }
+    *tempBitmap = gFalse;
+  }
+  for (k = 0, p = ret, q = slot->bitmap.buffer;
+       k < slot->bitmap.rows;
+       ++k, p += rowSize, q += slot->bitmap.pitch) {
+    memcpy(p, q, rowSize);
   }
   return ret;
 }
@@ -649,8 +725,10 @@ FT_UInt FTFont::getGlyphIndex(CharCode c, Unicode u) {
     idx = FT_Get_Char_Index(fontFile->face, (FT_ULong)c);
     break;
   case ftFontModeCharCodeOffset:
-    idx = FT_Get_Char_Index(fontFile->face,
-                           (FT_ULong)(c + fontFile->charMapOffset));
+    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) {
index 32675c63b266b8503fb479f0445a086cfb27d909..52bc149b180a3d8f74fc7763ae7f6441b3bc1173 100644 (file)
@@ -4,7 +4,7 @@
 //
 // An X wrapper for the FreeType font rasterizer.
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -62,14 +62,16 @@ public:
 
   // 8-bit font, TrueType or Type 1/1C
   FTFontFile(FTFontEngine *engineA, char *fontFileName,
-            char **fontEnc, GBool pdfFontHasEncoding);
+            char **fontEnc, GBool pdfFontHasEncoding,
+            GBool pdfFontIsSymbolic);
 
   // CID font, TrueType
   FTFontFile(FTFontEngine *engineA, char *fontFileName,
-            Gushort *cidToGIDA, int cidToGIDLenA);
+            Gushort *cidToGIDA, int cidToGIDLenA, GBool embedded);
 
   // CID font, Type 0C (CFF)
-  FTFontFile(FTFontEngine *engineA, char *fontFileName);
+  FTFontFile(FTFontEngine *engineA, char *fontFileName,
+            GBool embedded);
 
   GBool isOk() { return ok; }
   virtual ~FTFontFile();
@@ -110,7 +112,8 @@ public:
 private:
 
   Guchar *getGlyphPixmap(CharCode c, Unicode u,
-                        int *x, int *y, int *w, int *h);
+                        int *x, int *y, int *w, int *h,
+                        GBool *tempBitmap);
   static int charPathMoveTo(FT_Vector *pt, void *state);
   static int charPathLineTo(FT_Vector *pt, void *state);
   static int charPathConicTo(FT_Vector *ctrl, FT_Vector *pt, void *state);
index 6deff95ca688fa74663f1be83617426a70578471..f3b9280aa319cb3b23a0d0020243caa68a62022d 100644 (file)
@@ -2,7 +2,7 @@
 //
 // FontEncodingTables.cc
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 6860e4acec3791cfd92e0d01f89f540abfc6865d..fde0ae6e41dd0596111105216c788e9883c3db0f 100644 (file)
@@ -2,7 +2,7 @@
 //
 // FontFile.cc
 //
-// Copyright 1999-2002 Glyph & Cog, LLC
+// Copyright 1999-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -190,31 +190,38 @@ struct Type1CPrivateDict {
 };
 
 Type1CFontFile::Type1CFontFile(char *fileA, int lenA) {
-  Guchar *nameIdxPtr, *idxPtr0, *idxPtr1;
+  int nameIdxPos, namePos, nameLen;
 
-  file = fileA;
+  file = (Guchar *)fileA;
   len = lenA;
   name = NULL;
   encoding = NULL;
+  ok = gFalse;
 
   // some tools embed Type 1C fonts with an extra whitespace char at
   // the beginning
-  if (file[0] != '\x01') {
+  if (len > 0 && file[0] != '\x01') {
     ++file;
+    --len;
   }
 
-  // read header
-  topOffSize = file[3] & 0xff;
+  // make sure the header exists
+  if (len < 4) {
+    return;
+  }
 
   // read name index (first font only)
-  nameIdxPtr = (Guchar *)file + (file[2] & 0xff);
-  idxPtr0 = getIndexValPtr(nameIdxPtr, 0);
-  idxPtr1 = getIndexValPtr(nameIdxPtr, 1);
-  name = new GString((char *)idxPtr0, idxPtr1 - idxPtr0);
-
-  topDictIdxPtr = getIndexEnd(nameIdxPtr);
-  stringIdxPtr = getIndexEnd(topDictIdxPtr);
-  gsubrIdxPtr = getIndexEnd(stringIdxPtr);
+  nameIdxPos = file[2] & 0xff;
+  if ((namePos = getIndexValPos(nameIdxPos, 0, &nameLen)) < 0) {
+    return;
+  }
+  name = new GString((char *)&file[namePos], nameLen);
+
+  topDictIdxPos = getIndexEnd(nameIdxPos);
+  stringIdxPos = getIndexEnd(topDictIdxPos);
+  gsubrIdxPos = getIndexEnd(stringIdxPos);
+
+  ok = gTrue;
 }
 
 Type1CFontFile::~Type1CFontFile() {
@@ -235,14 +242,14 @@ char *Type1CFontFile::getName() {
 
 char **Type1CFontFile::getEncoding() {
   if (!encoding) {
-    readNameAndEncoding();
+    readEncoding();
   }
   return encoding;
 }
 
-void Type1CFontFile::readNameAndEncoding() {
+void Type1CFontFile::readEncoding() {
   char buf[256];
-  Guchar *idxPtr0, *idxPtr1, *ptr;
+  int idxPos, idxLen, pos;
   int nGlyphs;
   int nCodes, nRanges, nLeft, nSups;
   Gushort *glyphNames;
@@ -260,16 +267,20 @@ void Type1CFontFile::readNameAndEncoding() {
   }
 
   // read top dict (first font only)
-  idxPtr0 = getIndexValPtr(topDictIdxPtr, 0);
-  idxPtr1 = getIndexValPtr(topDictIdxPtr, 1);
+  if ((idxPos = getIndexValPos(topDictIdxPos, 0, &idxLen)) < 0) {
+    return;
+  }
   charset = enc = charstrings = 0;
   i = 0;
-  ptr = idxPtr0;
-  while (ptr < idxPtr1) {
-    if (*ptr <= 27 || *ptr == 31) {
-      key = *ptr++;
+  pos = idxPos;
+  while (pos < idxPos + idxLen) {
+    if (file[pos] <= 27 || file[pos] == 31) {
+      key = file[pos++];
       if (key == 0x0c) {
-       key = (key << 8) | *ptr++;
+       if (pos >= idxPos + idxLen) {
+         return;
+       }
+       key = (key << 8) | file[pos++];
       }
       if (key == 0x0f) { // charset
        charset = (int)op[0];
@@ -280,7 +291,7 @@ void Type1CFontFile::readNameAndEncoding() {
       }
       i = 0;
     } else {
-      x = getNum(&ptr, &isFP);
+      x = getNum(&pos, &isFP);
       if (i < 48) {
        op[i++] = x;
       }
@@ -288,7 +299,7 @@ void Type1CFontFile::readNameAndEncoding() {
   }
 
   // get number of glyphs from charstrings index
-  nGlyphs = getIndexLen((Guchar *)file + charstrings);
+  nGlyphs = getIndexLen(charstrings);
 
   // read charset (GID -> name mapping)
   glyphNames = readCharset(charset, nGlyphs);
@@ -307,24 +318,45 @@ void Type1CFontFile::readNameAndEncoding() {
       }
     }
   } else {
-    ptr = (Guchar *)file + enc;
-    encFormat = *ptr++;
+    pos = enc;
+    if (pos < 0 || pos >= len) {
+      goto err0;
+    }
+    encFormat = file[pos++];
     if ((encFormat & 0x7f) == 0) {
-      nCodes = 1 + *ptr++;
+      if (pos >= len) {
+       goto err0;
+      }
+      nCodes = 1 + file[pos++];
       if (nCodes > nGlyphs) {
        nCodes = nGlyphs;
       }
+      if (pos + nCodes - 1 > len) {
+       goto err0;
+      }
       for (i = 1; i < nCodes; ++i) {
-       c = *ptr++;
+       c = file[pos++];
+       if (encoding[c]) {
+         gfree(encoding[c]);
+       }
        encoding[c] = copyString(getString(glyphNames[i], buf));
       }
     } else if ((encFormat & 0x7f) == 1) {
-      nRanges = *ptr++;
+      if (pos >= len) {
+       goto err0;
+      }
+      nRanges = file[pos++];
+      if (pos + 2 * nRanges > len) {
+       goto err0;
+      }
       nCodes = 1;
       for (i = 0; i < nRanges; ++i) {
-       c = *ptr++;
-       nLeft = *ptr++;
+       c = file[pos++];
+       nLeft = file[pos++];
        for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
+         if (encoding[c]) {
+           gfree(encoding[c]);
+         }
          encoding[c] = copyString(getString(glyphNames[nCodes], buf));
          ++nCodes;
          ++c;
@@ -332,17 +364,27 @@ void Type1CFontFile::readNameAndEncoding() {
       }
     }
     if (encFormat & 0x80) {
-      nSups = *ptr++;
+      if (pos >= len) {
+       goto err0;
+      }
+      nSups = file[pos++];
+      if (pos + nSups * 3 > len) {
+       goto err0;
+      }
       for (i = 0; i < nSups; ++i) {
-       c = *ptr++;
-       sid = getWord(ptr, 2);
-       ptr += 2;
+       c = file[pos++];
+       sid = getWord(pos, 2);
+       pos += 2;
+       if (encoding[c]) {
+         gfree(encoding[c]);
+       }
        encoding[c] = copyString(getString(sid, buf));
       }
     }
   }
 
-  if (charset > 2) {
+ err0:
+  if (charset < 0 || charset > 2) {
     gfree(glyphNames);
   }
 }
@@ -352,12 +394,12 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA,
   Type1CTopDict dict;
   Type1CPrivateDict privateDict;
   char buf[512], eBuf[256];
-  Guchar *idxPtr0, *idxPtr1, *subrsIdxPtr, *charStringsIdxPtr, *ptr;
+  int idxPos, idxLen, pos;
   int nGlyphs, nCodes, nRanges, nLeft, nSups;
   Gushort *glyphNames;
-  int encFormat, nSubrs, nCharStrings;
+  int encFormat, nCharStrings;
   int c, sid;
-  int i, j, n;
+  int i, j;
 
   outputFunc = outputFuncA;
   outputStream = outputStreamA;
@@ -365,9 +407,6 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA,
   // read top dict (first font only)
   readTopDict(&dict);
 
-  // get global subrs
-  //~ ... global subrs are unimplemented
-
   // write header and font dictionary, up to encoding
   (*outputFunc)(outputStream, "%!FontType1-1.0: ", 17);
   (*outputFunc)(outputStream, name->getCString(), name->getLength());
@@ -447,7 +486,7 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA,
   }
 
   // get number of glyphs from charstrings index
-  nGlyphs = getIndexLen((Guchar *)file + dict.charStrings);
+  nGlyphs = getIndexLen(dict.charStrings);
 
   // read charset
   glyphNames = readCharset(dict.charset, nGlyphs);
@@ -468,15 +507,24 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA,
        }
       }
     } else {
-      ptr = (Guchar *)file + dict.encoding;
-      encFormat = *ptr++;
+      pos = dict.encoding;
+      if (pos < 0 || pos >= len) {
+       goto err0;
+      }
+      encFormat = file[pos++];
       if ((encFormat & 0x7f) == 0) {
-       nCodes = 1 + *ptr++;
+       if (pos >= len) {
+         goto err0;
+       }
+       nCodes = 1 + file[pos++];
        if (nCodes > nGlyphs) {
          nCodes = nGlyphs;
        }
+       if (pos + nCodes - 1 > len) {
+         goto err0;
+       }
        for (i = 1; i < nCodes; ++i) {
-         c = *ptr++;
+         c = file[pos++];
          sprintf(buf, "dup %d /", c);
          (*outputFunc)(outputStream, buf, strlen(buf));
          getString(glyphNames[i], buf);
@@ -484,11 +532,17 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA,
          (*outputFunc)(outputStream, " put\n", 5);
        }
       } else if ((encFormat & 0x7f) == 1) {
-       nRanges = *ptr++;
+       if (pos >= len) {
+         goto err0;
+       }
+       nRanges = file[pos++];
+       if (pos + 2 * nRanges > len) {
+         goto err0;
+       }
        nCodes = 1;
        for (i = 0; i < nRanges; ++i) {
-         c = *ptr++;
-         nLeft = *ptr++;
+         c = file[pos++];
+         nLeft = file[pos++];
          for (j = 0; j <= nLeft && nCodes < nGlyphs; ++j) {
            sprintf(buf, "dup %d /", c);
            (*outputFunc)(outputStream, buf, strlen(buf));
@@ -501,11 +555,17 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA,
        }
       }
       if (encFormat & 0x80) {
-       nSups = *ptr++;
+       if (pos >= len) {
+         goto err0;
+       }
+       nSups = file[pos++];
+       if (pos + nSups * 3 > len) {
+         goto err0;
+       }
        for (i = 0; i < nSups; ++i) {
-         c = *ptr++;
-         sid = getWord(ptr, 2);
-         ptr += 2;
+         c = file[pos++];
+         sid = getWord(pos, 2);
+         pos += 2;
          sprintf(buf, "dup %d /", c);
          (*outputFunc)(outputStream, buf, strlen(buf));
          getString(sid, buf);
@@ -513,6 +573,7 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA,
          (*outputFunc)(outputStream, " put\n", 5);
        }
       }
+     err0:;
     }
     (*outputFunc)(outputStream, "readonly def\n", 13);
   }
@@ -537,41 +598,21 @@ void Type1CFontFile::convertToType1(FontFileOutputFunc outputFuncA,
   nominalWidthX = privateDict.nominalWidthX;
   nominalWidthXFP = privateDict.nominalWidthXFP;
 
-  // get subrs
-  if (privateDict.subrsOffset != 0) {
-    subrsIdxPtr = (Guchar *)file + dict.privateOffset +
-                  privateDict.subrsOffset;
-    nSubrs = getIndexLen(subrsIdxPtr);
-    sprintf(eBuf, "/Subrs %d array\n", nSubrs);
-    eexecWrite(eBuf);
-    idxPtr1 = getIndexValPtr(subrsIdxPtr, 0);
-    for (i = 0; i < nSubrs; ++i) {
-      idxPtr0 = idxPtr1;
-      idxPtr1 = getIndexValPtr(subrsIdxPtr, i+1);
-      n = idxPtr1 - idxPtr0;
-#if 1 //~ Type 2 subrs are unimplemented
-      error(-1, "Unimplemented Type 2 subrs");
-#else
-      sprintf(eBuf, "dup %d %d RD ", i, n);
-      eexecWrite(eBuf);
-      eexecCvtGlyph(idxPtr0, n);
-      eexecWrite(" NP\n");
-#endif
-    }
-    eexecWrite("ND\n");
-  }
+  // set up subroutines
+  subrIdxPos = dict.privateOffset + privateDict.subrsOffset;
+  i = getIndexLen(gsubrIdxPos);
+  gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768;
+  i = getIndexLen(subrIdxPos);
+  subrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768;
 
   // get CharStrings
-  charStringsIdxPtr = (Guchar *)file + dict.charStrings;
-  nCharStrings = getIndexLen(charStringsIdxPtr);
+  nCharStrings = getIndexLen(dict.charStrings);
   sprintf(eBuf, "2 index /CharStrings %d dict dup begin\n", nCharStrings);
   eexecWrite(eBuf);
-  idxPtr1 = getIndexValPtr(charStringsIdxPtr, 0);
   for (i = 0; i < nCharStrings; ++i) {
-    idxPtr0 = idxPtr1;
-    idxPtr1 = getIndexValPtr(charStringsIdxPtr, i+1);
-    n = idxPtr1 - idxPtr0;
-    eexecCvtGlyph(getString(glyphNames[i], buf), idxPtr0, n);
+    if ((idxPos = getIndexValPos(dict.charStrings, i, &idxLen)) >= 0) {
+      eexecCvtGlyph(getString(glyphNames[i], buf), idxPos, idxLen);
+    }
   }
   eexecWrite("end\n");
   eexecWrite("end\n");
@@ -606,7 +647,7 @@ void Type1CFontFile::convertToCIDType0(char *psName,
   Gushort *charset;
   int *cidMap;
   Guchar *fdSelect;
-  Guchar *charStringsIdxPtr, *fdArrayIdx, *idxPtr0, *idxPtr1, *ptr;
+  int idxPos, idxLen, pos;
   char buf[512], buf2[16];
   int nGlyphs, nCIDs, gdBytes, nFDs;
   int fdSelectFmt, nRanges, gid0, gid1, fd, offset;
@@ -635,29 +676,36 @@ void Type1CFontFile::convertToCIDType0(char *psName,
     privateDicts[0].nominalWidthX = 0;
     privateDicts[0].nominalWidthXFP = gFalse;
   } else {
-    fdArrayIdx = (Guchar *)file + dict.fdArrayOffset;
-    nFDs = getIndexLen(fdArrayIdx);
+    if ((nFDs = getIndexLen(dict.fdArrayOffset)) < 0) {
+      goto err0;
+    }
     privateDicts = (Type1CPrivateDict *)
                      gmalloc(nFDs * sizeof(Type1CPrivateDict));
-    idxPtr1 = getIndexValPtr(fdArrayIdx, 0);
     for (i = 0; i < nFDs; ++i) {
       privateDicts[i].dictData = NULL;
-      idxPtr0 = idxPtr1;
-      idxPtr1 = getIndexValPtr(fdArrayIdx, i + 1);
-      ptr = idxPtr0;
+    }
+    for (i = 0; i < nFDs; ++i) {
+      privateDicts[i].dictData = NULL;
+      if ((idxPos = getIndexValPos(dict.fdArrayOffset, i, &idxLen)) < 0) {
+       goto err1;
+      }
+      pos = idxPos;
       j = 0;
-      while (ptr < idxPtr1) {
-       if (*ptr <= 27 || *ptr == 31) {
-         key = *ptr++;
+      while (pos < idxPos + idxLen) {
+       if (file[pos] <= 27 || file[pos] == 31) {
+         key = file[pos++];
          if (key == 0x0c) {
-           key = (key << 8) | *ptr++;
+           if (pos >= idxPos + idxLen) {
+             goto err1;
+           }
+           key = (key << 8) | file[pos++];
          }
          if (key == 0x0012) {
            readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]);
          }
          j = 0;
        } else {
-         x = getNum(&ptr, &isFP);
+         x = getNum(&pos, &isFP);
          if (j < 48) {
            op[j] = x;
            fp[j++] = isFP;
@@ -676,8 +724,9 @@ void Type1CFontFile::convertToCIDType0(char *psName,
   }
 
   // get the glyph count
-  charStringsIdxPtr = (Guchar *)file + dict.charStrings;
-  nGlyphs = getIndexLen(charStringsIdxPtr);
+  if ((nGlyphs = getIndexLen(dict.charStrings)) < 0) {
+    goto err1;
+  }
 
   // read the FDSelect table
   fdSelect = (Guchar *)gmalloc(nGlyphs);
@@ -686,19 +735,31 @@ void Type1CFontFile::convertToCIDType0(char *psName,
       fdSelect[i] = 0;
     }
   } else {
-    ptr = (Guchar *)file + dict.fdSelectOffset;
-    fdSelectFmt = *ptr++;
+    pos = dict.fdSelectOffset;
+    if (pos < 0 || pos >= len) {
+      goto err2;
+    }
+    fdSelectFmt = file[pos++];
     if (fdSelectFmt == 0) {
-      memcpy(fdSelect, ptr, nGlyphs);
+      if (pos + nGlyphs > len) {
+       goto err2;
+      }
+      memcpy(fdSelect, file + pos, nGlyphs);
     } else if (fdSelectFmt == 3) {
-      nRanges = getWord(ptr, 2);
-      ptr += 2;
-      gid0 = getWord(ptr, 2);
-      ptr += 2;
+      if (pos + 4 > len) {
+       goto err2;
+      }
+      nRanges = getWord(pos, 2);
+      pos += 2;
+      gid0 = getWord(pos, 2);
+      pos += 2;
+      if (pos + nRanges * 3 > len) {
+       goto err2;
+      }
       for (i = 1; i <= nRanges; ++i) {
-       fd = *ptr++;
-       gid1 = getWord(ptr, 2);
-       ptr += 2;
+       fd = file[pos++];
+       gid1 = getWord(pos, 2);
+       pos += 2;
        for (j = gid0; j < gid1; ++j) {
          fdSelect[j] = fd;
        }
@@ -728,23 +789,30 @@ void Type1CFontFile::convertToCIDType0(char *psName,
     cidMap[charset[i]] = i;
   }
 
+  // set up global subroutines
+  i = getIndexLen(gsubrIdxPos);
+  gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768;
+
   // build the charstrings
   charStrings = new GString();
   charStringOffsets = (int *)gmalloc((nCIDs + 1) * sizeof(int));
   for (i = 0; i < nCIDs; ++i) {
     charStringOffsets[i] = charStrings->getLength();
     if (cidMap[i] >= 0) {
-      idxPtr0 = getIndexValPtr(charStringsIdxPtr, cidMap[i]);
-      idxPtr1 = getIndexValPtr(charStringsIdxPtr, cidMap[i]+1);
-      n = idxPtr1 - idxPtr0;
-      j = fdSelect[cidMap[i]];
-      defaultWidthX = privateDicts[j].defaultWidthX;
-      defaultWidthXFP = privateDicts[j].defaultWidthXFP;
-      nominalWidthX = privateDicts[j].nominalWidthX;
-      nominalWidthXFP = privateDicts[j].nominalWidthXFP;
-      cvtGlyph(idxPtr0, n);
-      charStrings->append(charBuf);
-      delete charBuf;
+      if ((idxPos = getIndexValPos(dict.charStrings,
+                                  cidMap[i], &idxLen)) >= 0) {
+       j = fdSelect[cidMap[i]];
+       defaultWidthX = privateDicts[j].defaultWidthX;
+       defaultWidthXFP = privateDicts[j].defaultWidthXFP;
+       nominalWidthX = privateDicts[j].nominalWidthX;
+       nominalWidthXFP = privateDicts[j].nominalWidthXFP;
+       subrIdxPos = dict.privateOffset + privateDicts[j].subrsOffset;
+       k = getIndexLen(subrIdxPos);
+       subrBias = (k < 1240) ? 107 : (k < 33900) ? 1131 : 32768;
+       cvtGlyph(idxPos, idxLen, gTrue);
+       charStrings->append(charBuf);
+       delete charBuf;
+      }
     }
   }
   charStringOffsets[nCIDs] = charStrings->getLength();
@@ -831,8 +899,6 @@ void Type1CFontFile::convertToCIDType0(char *psName,
   }
   (*outputFunc)(outputStream, "def\n", 4);
 
-  //~ need to deal with subrs
-  
   // start the binary section
   offset = (nCIDs + 1) * (1 + gdBytes);
   sprintf(buf, "(Hex) %d StartData\n",
@@ -873,15 +939,20 @@ void Type1CFontFile::convertToCIDType0(char *psName,
     (*outputFunc)(outputStream, "\n", 1);
   }
 
-  for (i = 0; i < nFDs; ++i) {
-    delete privateDicts[i].dictData;
-  }
-  gfree(privateDicts);
-  gfree(cidMap);
-  gfree(charset);
   gfree(charStringOffsets);
   delete charStrings;
+  gfree(cidMap);
+  gfree(charset);
+ err2:
   gfree(fdSelect);
+ err1:
+  for (i = 0; i < nFDs; ++i) {
+    if (privateDicts[i].dictData) {
+      delete privateDicts[i].dictData;
+    }
+  }
+  gfree(privateDicts);
+ err0:;
 }
 
 void Type1CFontFile::convertToType0(char *psName,
@@ -892,7 +963,7 @@ void Type1CFontFile::convertToType0(char *psName,
   Gushort *charset;
   int *cidMap;
   Guchar *fdSelect;
-  Guchar *charStringsIdxPtr, *fdArrayIdx, *idxPtr0, *idxPtr1, *ptr;
+  int idxPos, idxLen, pos;
   char buf[512];
   char eBuf[256];
   int nGlyphs, nCIDs, nFDs;
@@ -900,7 +971,7 @@ void Type1CFontFile::convertToType0(char *psName,
   int key;
   double x;
   GBool isFP;
-  int i, j, n;
+  int i, j;
 
   outputFunc = outputFuncA;
   outputStream = outputStreamA;
@@ -920,29 +991,36 @@ void Type1CFontFile::convertToType0(char *psName,
     privateDicts[0].nominalWidthX = 0;
     privateDicts[0].nominalWidthXFP = gFalse;
   } else {
-    fdArrayIdx = (Guchar *)file + dict.fdArrayOffset;
-    nFDs = getIndexLen(fdArrayIdx);
+    if ((nFDs = getIndexLen(dict.fdArrayOffset)) < 0) {
+      goto err0;
+    }
     privateDicts = (Type1CPrivateDict *)
                      gmalloc(nFDs * sizeof(Type1CPrivateDict));
-    idxPtr1 = getIndexValPtr(fdArrayIdx, 0);
     for (i = 0; i < nFDs; ++i) {
       privateDicts[i].dictData = NULL;
-      idxPtr0 = idxPtr1;
-      idxPtr1 = getIndexValPtr(fdArrayIdx, i + 1);
-      ptr = idxPtr0;
+    }
+    for (i = 0; i < nFDs; ++i) {
+      privateDicts[i].dictData = NULL;
+      if ((idxPos = getIndexValPos(dict.fdArrayOffset, i, &idxLen)) < 0) {
+       goto err1;
+      }
+      pos = idxPos;
       j = 0;
-      while (ptr < idxPtr1) {
-       if (*ptr <= 27 || *ptr == 31) {
-         key = *ptr++;
+      while (pos < idxPos + idxLen) {
+       if (file[pos] <= 27 || file[pos] == 31) {
+         key = file[pos++];
          if (key == 0x0c) {
-           key = (key << 8) | *ptr++;
+           if (pos >= idxPos + idxLen) {
+             goto err1;
+           }
+           key = (key << 8) | file[pos++];
          }
          if (key == 0x0012) {
            readPrivateDict(&privateDicts[i], (int)op[1], (int)op[0]);
          }
          j = 0;
        } else {
-         x = getNum(&ptr, &isFP);
+         x = getNum(&pos, &isFP);
          if (j < 48) {
            op[j] = x;
            fp[j++] = isFP;
@@ -961,8 +1039,9 @@ void Type1CFontFile::convertToType0(char *psName,
   }
 
   // get the glyph count
-  charStringsIdxPtr = (Guchar *)file + dict.charStrings;
-  nGlyphs = getIndexLen(charStringsIdxPtr);
+  if ((nGlyphs = getIndexLen(dict.charStrings)) < 0) {
+    goto err1;
+  }
 
   // read the FDSelect table
   fdSelect = (Guchar *)gmalloc(nGlyphs);
@@ -971,19 +1050,31 @@ void Type1CFontFile::convertToType0(char *psName,
       fdSelect[i] = 0;
     }
   } else {
-    ptr = (Guchar *)file + dict.fdSelectOffset;
-    fdSelectFmt = *ptr++;
+    pos = dict.fdSelectOffset;
+    if (pos < 0 || pos >= len) {
+      goto err2;
+    }
+    fdSelectFmt = file[pos++];
     if (fdSelectFmt == 0) {
-      memcpy(fdSelect, ptr, nGlyphs);
+      if (pos + nGlyphs > len) {
+       goto err2;
+      }
+      memcpy(fdSelect, file + pos, nGlyphs);
     } else if (fdSelectFmt == 3) {
-      nRanges = getWord(ptr, 2);
-      ptr += 2;
-      gid0 = getWord(ptr, 2);
-      ptr += 2;
+      if (pos + 4 > len) {
+       goto err2;
+      }
+      nRanges = getWord(pos, 2);
+      pos += 2;
+      gid0 = getWord(pos, 2);
+      pos += 2;
+      if (pos + nRanges * 3 > len) {
+       goto err2;
+      }
       for (i = 1; i <= nRanges; ++i) {
-       fd = *ptr++;
-       gid1 = getWord(ptr, 2);
-       ptr += 2;
+       fd = file[pos++];
+       gid1 = getWord(pos, 2);
+       pos += 2;
        for (j = gid0; j < gid1; ++j) {
          fdSelect[j] = fd;
        }
@@ -1013,6 +1104,10 @@ void Type1CFontFile::convertToType0(char *psName,
     cidMap[charset[i]] = i;
   }
 
+  // set up global subroutines
+  i = getIndexLen(gsubrIdxPos);
+  gsubrBias = (i < 1240) ? 107 : (i < 33900) ? 1131 : 32768;
+
   // write the descendant Type 1 fonts
   for (i = 0; i < nCIDs; i += 256) {
 
@@ -1074,24 +1169,28 @@ void Type1CFontFile::convertToType0(char *psName,
     nominalWidthX = privateDicts[fd].nominalWidthX;
     nominalWidthXFP = privateDicts[fd].nominalWidthXFP;
 
+    // set up the subroutines
+    subrIdxPos = dict.privateOffset + privateDicts[fd].subrsOffset;
+    j = getIndexLen(subrIdxPos);
+    subrBias = (j < 1240) ? 107 : (j < 33900) ? 1131 : 32768;
+
     // start the CharStrings
     sprintf(eBuf, "2 index /CharStrings 256 dict dup begin\n");
     eexecWrite(eBuf);
 
     // write the .notdef CharString
-    idxPtr0 = getIndexValPtr(charStringsIdxPtr, 0);
-    idxPtr1 = getIndexValPtr(charStringsIdxPtr, 1);
-    n = idxPtr1 - idxPtr0;
-    eexecCvtGlyph(".notdef", idxPtr0, n);
+    if ((idxPos = getIndexValPos(dict.charStrings, 0, &idxLen)) >= 0) {
+      eexecCvtGlyph(".notdef", idxPos, idxLen);
+    }
 
     // write the CharStrings
     for (j = 0; j < 256 && i+j < nCIDs; ++j) {
       if (cidMap[i+j] >= 0) {
-       idxPtr0 = getIndexValPtr(charStringsIdxPtr, cidMap[i+j]);
-       idxPtr1 = getIndexValPtr(charStringsIdxPtr, cidMap[i+j]+1);
-       n = idxPtr1 - idxPtr0;
-       sprintf(buf, "c%02x", j);
-       eexecCvtGlyph(buf, idxPtr0, n);
+       if ((idxPos = getIndexValPos(dict.charStrings,
+                                    cidMap[i+j], &idxLen)) >= 0) {
+         sprintf(buf, "c%02x", j);
+         eexecCvtGlyph(buf, idxPos, idxLen);
+       }
       }
     }
     eexecWrite("end\n");
@@ -1136,24 +1235,27 @@ void Type1CFontFile::convertToType0(char *psName,
   (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
 
   // clean up
-  for (i = 0; i < nFDs; ++i) {
-    delete privateDicts[i].dictData;
-  }
-  gfree(privateDicts);
   gfree(cidMap);
   gfree(charset);
+ err2:
   gfree(fdSelect);
+ err1:
+  for (i = 0; i < nFDs; ++i) {
+    if (privateDicts[i].dictData) {
+      delete privateDicts[i].dictData;
+    }
+  }
+  gfree(privateDicts);
+ err0:;
 }
 
 void Type1CFontFile::readTopDict(Type1CTopDict *dict) {
-  Guchar *idxPtr0, *idxPtr1, *ptr;
+  int idxPos, idxLen, pos;
   double x;
   GBool isFP;
   int key;
   int i;
 
-  idxPtr0 = getIndexValPtr(topDictIdxPtr, 0);
-  idxPtr1 = getIndexValPtr(topDictIdxPtr, 1);
   dict->version = 0;
   dict->notice = 0;
   dict->copyright = 0;
@@ -1188,13 +1290,19 @@ void Type1CFontFile::readTopDict(Type1CTopDict *dict) {
   dict->supplement = 0;
   dict->fdArrayOffset = 0;
   dict->fdSelectOffset = 0;
+  if ((idxPos = getIndexValPos(topDictIdxPos, 0, &idxLen)) < 0) {
+    return;
+  }
   i = 0;
-  ptr = idxPtr0;
-  while (ptr < idxPtr1) {
-    if (*ptr <= 27 || *ptr == 31) {
-      key = *ptr++;
+  pos = idxPos;
+  while (pos < idxPos + idxLen) {
+    if (file[pos] <= 27 || file[pos] == 31) {
+      key = file[pos++];
       if (key == 0x0c) {
-       key = (key << 8) | *ptr++;
+       if (pos >= idxPos + idxLen) {
+         break;
+       }
+       key = (key << 8) | file[pos++];
       }
       switch (key) {
       case 0x0000: dict->version = (int)op[0]; break;
@@ -1234,7 +1342,7 @@ void Type1CFontFile::readTopDict(Type1CTopDict *dict) {
       }
       i = 0;
     } else {
-      x = getNum(&ptr, &isFP);
+      x = getNum(&pos, &isFP);
       if (i < 48) {
        op[i] = x;
        fp[i++] = isFP;
@@ -1245,7 +1353,7 @@ void Type1CFontFile::readTopDict(Type1CTopDict *dict) {
 
 void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict,
                                     int offset, int size) {
-  Guchar *idxPtr0, *idxPtr1, *ptr;
+  int pos;
   char eBuf[256];
   int key;
   double x;
@@ -1258,15 +1366,19 @@ void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict,
   privateDict->defaultWidthXFP = gFalse;
   privateDict->nominalWidthX = 0;
   privateDict->nominalWidthXFP = gFalse;
-  idxPtr0 = (Guchar *)file + offset;
-  idxPtr1 = idxPtr0 + size;
-  ptr = idxPtr0;
+  if (offset < 0 || offset + size > len) {
+    return;
+  }
+  pos = offset;
   i = 0;
-  while (ptr < idxPtr1) {
-    if (*ptr <= 27 || *ptr == 31) {
-      key = *ptr++;
+  while (pos < offset + size) {
+    if (file[pos] <= 27 || file[pos] == 31) {
+      key = file[pos++];
       if (key == 0x0c) {
-       key = (key << 8) | *ptr++;
+       if (pos >= offset + size) {
+         break;
+       }
+       key = (key << 8) | file[pos++];
       }
       switch (key) {
       case 0x0006:
@@ -1349,7 +1461,7 @@ void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict,
       }
       i = 0;
     } else {
-      x = getNum(&ptr, &isFP);
+      x = getNum(&pos, &isFP);
       if (i < 48) {
        op[i] = x;
        fp[i++] = isFP;
@@ -1360,7 +1472,7 @@ void Type1CFontFile::readPrivateDict(Type1CPrivateDict *privateDict,
 
 Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) {
   Gushort *glyphNames;
-  Guchar *ptr;
+  int pos;
   int charsetFormat, c;
   int nLeft, i, j;
 
@@ -1372,20 +1484,31 @@ Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) {
     glyphNames = type1CExpertSubsetCharset;
   } else {
     glyphNames = (Gushort *)gmalloc(nGlyphs * sizeof(Gushort));
-    glyphNames[0] = 0;
-    ptr = (Guchar *)file + charset;
-    charsetFormat = *ptr++;
+    for (i = 0; i < nGlyphs; ++i) {
+      glyphNames[i] = 0;
+    }
+    pos = charset;
+    if (pos < 0 || pos >= len) {
+      goto err0;
+    }
+    charsetFormat = file[pos++];
     if (charsetFormat == 0) {
+      if (pos + (nGlyphs - 1) * 2 >= len) {
+       goto err0;
+      }
       for (i = 1; i < nGlyphs; ++i) {
-       glyphNames[i] = getWord(ptr, 2);
-       ptr += 2;
+       glyphNames[i] = getWord(pos, 2);
+       pos += 2;
       }
     } else if (charsetFormat == 1) {
       i = 1;
       while (i < nGlyphs) {
-       c = getWord(ptr, 2);
-       ptr += 2;
-       nLeft = *ptr++;
+       if (pos + 3 > len) {
+         goto err0;
+       }
+       c = getWord(pos, 2);
+       pos += 2;
+       nLeft = file[pos++];
        for (j = 0; j <= nLeft && i < nGlyphs; ++j) {
          glyphNames[i++] = c++;
        }
@@ -1393,16 +1516,20 @@ Gushort *Type1CFontFile::readCharset(int charset, int nGlyphs) {
     } else if (charsetFormat == 2) {
       i = 1;
       while (i < nGlyphs) {
-       c = getWord(ptr, 2);
-       ptr += 2;
-       nLeft = getWord(ptr, 2);
-       ptr += 2;
+       if (pos + 4 > len) {
+         goto err0;
+       }
+       c = getWord(pos, 2);
+       pos += 2;
+       nLeft = getWord(pos, 2);
+       pos += 2;
        for (j = 0; j <= nLeft && i < nGlyphs; ++j) {
          glyphNames[i++] = c++;
        }
       }
     }
   }
+ err0:
   return glyphNames;
 }
 
@@ -1423,10 +1550,10 @@ void Type1CFontFile::eexecWrite(char *s) {
   }
 }
 
-void Type1CFontFile::eexecCvtGlyph(char *glyphName, Guchar *s, int n) {
+void Type1CFontFile::eexecCvtGlyph(char *glyphName, int pos, int n) {
   char eBuf[256];
 
-  cvtGlyph(s, n);
+  cvtGlyph(pos, n, gTrue);
   sprintf(eBuf, "/%s %d RD ", glyphName, charBuf->getLength());
   eexecWrite(eBuf);
   eexecWriteCharstring((Guchar *)charBuf->getCString(), charBuf->getLength());
@@ -1434,28 +1561,37 @@ void Type1CFontFile::eexecCvtGlyph(char *glyphName, Guchar *s, int n) {
   delete charBuf;
 }
 
-void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
-  int nHints;
+void Type1CFontFile::cvtGlyph(int pos, int n, GBool top) {
   int x;
-  GBool first = gTrue;
+  int subrPos, subrLen;
   double d, dx, dy;
   GBool dFP;
   Gushort r2;
   Guchar byte;
   int i, k;
 
-  charBuf = new GString();
-  charBuf->append((char)73);
-  charBuf->append((char)58);
-  charBuf->append((char)147);
-  charBuf->append((char)134);
+  if (pos < 0 || pos + n > len) {
+    return;
+  }
 
-  i = 0;
-  nOps = 0;
-  nHints = 0;
-  while (i < n) {
-    if (s[i] == 12) {
-      switch (s[i+1]) {
+  if (top) {
+    charBuf = new GString();
+    charBuf->append((char)73);
+    charBuf->append((char)58);
+    charBuf->append((char)147);
+    charBuf->append((char)134);
+    nOps = 0;
+    nHints = 0;
+    firstOp = gTrue;
+  }
+
+  i = pos;
+  while (i < pos + n) {
+    if (file[i] == 12) {
+      if (i + 2 > pos + n) {
+       break;
+      }
+      switch (file[i+1]) {
       case 0:                  // dotsection (should be Type 1 only?)
        // ignored
        break;
@@ -1564,19 +1700,19 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
       case 28:                 // exch
       case 29:                 // index
       case 30:                 // roll
-       error(-1, "Unimplemented Type 2 charstring op: 12.%d", s[i+1]);
+       error(-1, "Unimplemented Type 2 charstring op: 12.%d", file[i+1]);
        break;
       default:
-       error(-1, "Illegal Type 2 charstring op: 12.%d", s[i+1]);
+       error(-1, "Illegal Type 2 charstring op: 12.%d", file[i+1]);
        break;
       }
       i += 2;
       nOps = 0;
-    } else if (s[i] == 19) {   // hintmask
+    } else if (file[i] == 19) {        // hintmask
       // ignored
-      if (first) {
+      if (firstOp) {
        cvtGlyphWidth(nOps == 1);
-       first = gFalse;
+       firstOp = gFalse;
       }
       if (nOps > 0) {
        if (nOps & 1) {
@@ -1587,11 +1723,11 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
       }
       i += 1 + ((nHints + 7) >> 3);
       nOps = 0;
-    } else if (s[i] == 20) {   // cntrmask
+    } else if (file[i] == 20) {        // cntrmask
       // ignored
-      if (first) {
+      if (firstOp) {
        cvtGlyphWidth(nOps == 1);
-       first = gFalse;
+       firstOp = gFalse;
       }
       if (nOps > 0) {
        if (nOps & 1) {
@@ -1602,8 +1738,11 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
       }
       i += 1 + ((nHints + 7) >> 3);
       nOps = 0;
-    } else if (s[i] == 28) {
-      x = (s[i+1] << 8) + s[i+2];
+    } else if (file[i] == 28) {
+      if (i + 3 > len) {
+       break;
+      }
+      x = (file[i+1] << 8) + file[i+2];
       if (x & 0x8000) {
        x |= -1 << 15;
       }
@@ -1612,12 +1751,39 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
        op[nOps++] = x;
       }
       i += 3;
-    } else if (s[i] <= 31) {
-      switch (s[i]) {
+    } else if (file[i] == 10) {        // callsubr
+      if (nOps >= 1) {
+       k = subrBias + (int)op[nOps - 1];
+       --nOps;
+       if ((subrPos = getIndexValPos(subrIdxPos, k, &subrLen)) >= 0) {
+         cvtGlyph(subrPos, subrLen, gFalse);
+       }
+      } else {
+       error(-1, "Too few args to Type 2 callsubr");
+      }
+      // don't clear the stack
+      ++i;
+    } else if (file[i] == 29) {        // callgsubr
+      if (nOps >= 1) {
+       k = gsubrBias + (int)op[nOps - 1];
+       --nOps;
+       if ((subrPos = getIndexValPos(gsubrIdxPos, k, &subrLen)) >= 0) {
+         cvtGlyph(subrPos, subrLen, gFalse);
+       }
+      } else {
+       error(-1, "Too few args to Type 2 callgsubr");
+      }
+      // don't clear the stack
+      ++i;
+    } else if (file[i] == 11) {        // return
+      // don't clear the stack
+      ++i;
+    } else if (file[i] <= 31) {
+      switch (file[i]) {
       case 4:                  // vmoveto
-       if (first) {
+       if (firstOp) {
          cvtGlyphWidth(nOps == 2);
-         first = gFalse;
+         firstOp = gFalse;
        }
        if (nOps != 1) {
          error(-1, "Wrong number of args (%d) to Type 2 vmoveto", nOps);
@@ -1668,9 +1834,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
        }
        break;
       case 14:                 // endchar / seac
-       if (first) {
+       if (firstOp) {
          cvtGlyphWidth(nOps == 1 || nOps == 5);
-         first = gFalse;
+         firstOp = gFalse;
        }
        if (nOps == 4) {
          eexecDumpNum(0, 0);
@@ -1686,9 +1852,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
        }
        break;
       case 21:                 // rmoveto
-       if (first) {
+       if (firstOp) {
          cvtGlyphWidth(nOps == 3);
-         first = gFalse;
+         firstOp = gFalse;
        }
        if (nOps != 2) {
          error(-1, "Wrong number of args (%d) to Type 2 rmoveto", nOps);
@@ -1698,9 +1864,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
        eexecDumpOp1(21);
        break;
       case 22:                 // hmoveto
-       if (first) {
+       if (firstOp) {
          cvtGlyphWidth(nOps == 2);
-         first = gFalse;
+         firstOp = gFalse;
        }
        if (nOps != 1) {
          error(-1, "Wrong number of args (%d) to Type 2 hmoveto", nOps);
@@ -1871,9 +2037,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
        }
        break;
       case 1:                  // hstem
-       if (first) {
+       if (firstOp) {
          cvtGlyphWidth(nOps & 1);
-         first = gFalse;
+         firstOp = gFalse;
        }
        if (nOps & 1) {
          error(-1, "Wrong number of args (%d) to Type 2 hstem", nOps);
@@ -1899,9 +2065,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
        nHints += nOps / 2;
        break;
       case 3:                  // vstem
-       if (first) {
+       if (firstOp) {
          cvtGlyphWidth(nOps & 1);
-         first = gFalse;
+         firstOp = gFalse;
        }
        if (nOps & 1) {
          error(-1, "Wrong number of args (%d) to Type 2 vstem", nOps);
@@ -1928,9 +2094,9 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
        break;
       case 18:                 // hstemhm
        // ignored
-       if (first) {
+       if (firstOp) {
          cvtGlyphWidth(nOps & 1);
-         first = gFalse;
+         firstOp = gFalse;
        }
        if (nOps & 1) {
          error(-1, "Wrong number of args (%d) to Type 2 hstemhm", nOps);
@@ -1939,49 +2105,56 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
        break;
       case 23:                 // vstemhm
        // ignored
-       if (first) {
+       if (firstOp) {
          cvtGlyphWidth(nOps & 1);
-         first = gFalse;
+         firstOp = gFalse;
        }
        if (nOps & 1) {
          error(-1, "Wrong number of args (%d) to Type 2 vstemhm", nOps);
        }
        nHints += nOps / 2;
        break;
-      case 10:                 // callsubr
-      case 11:                 // return
       case 16:                 // blend
-      case 29:                 // callgsubr
-       error(-1, "Unimplemented Type 2 charstring op: %d", s[i]);
+       error(-1, "Unimplemented Type 2 charstring op: %d", file[i]);
        break;
       default:
-       error(-1, "Illegal Type 2 charstring op: %d", s[i]);
+       error(-1, "Illegal Type 2 charstring op: %d", file[i]);
        break;
       }
       ++i;
       nOps = 0;
-    } else if (s[i] <= 246) {
+    } else if (file[i] <= 246) {
       if (nOps < 48) {
        fp[nOps] = gFalse;
-       op[nOps++] = (int)s[i] - 139;
+       op[nOps++] = (int)file[i] - 139;
       }
       ++i;
-    } else if (s[i] <= 250) {
+    } else if (file[i] <= 250) {
+      if (i + 2 > len) {
+       break;
+      }
       if (nOps < 48) {
        fp[nOps] = gFalse;
-       op[nOps++] = (((int)s[i] - 247) << 8) + (int)s[i+1] + 108;
+       op[nOps++] = (((int)file[i] - 247) << 8) + (int)file[i+1] + 108;
       }
       i += 2;
-    } else if (s[i] <= 254) {
+    } else if (file[i] <= 254) {
+      if (i + 2 > len) {
+       break;
+      }
       if (nOps < 48) {
        fp[nOps] = gFalse;
-       op[nOps++] = -(((int)s[i] - 251) << 8) - (int)s[i+1] - 108;
+       op[nOps++] = -(((int)file[i] - 251) << 8) - (int)file[i+1] - 108;
       }
       i += 2;
     } else {
-      x = (s[i+1] << 24) | (s[i+2] << 16) | (s[i+3] << 8) | s[i+4];
-      if (x & 0x80000000)
+      if (i + 5 > len) {
+       break;
+      }
+      x = (file[i+1] << 24) | (file[i+2] << 16) | (file[i+3] << 8) | file[i+4];
+      if (x & 0x80000000) {
        x |= -1 << 31;
+      }
       if (nOps < 48) {
        fp[nOps] = gTrue;
        op[nOps++] = (double)x / 65536.0;
@@ -1991,11 +2164,13 @@ void Type1CFontFile::cvtGlyph(Guchar *s, int n) {
   }
 
   // charstring encryption
-  r2 = 4330;
-  for (i = 0; i < charBuf->getLength(); ++i) {
-    byte = charBuf->getChar(i) ^ (r2 >> 8);
-    charBuf->setChar(i, byte);
-    r2 = (byte + r2) * 52845 + 22719;
+  if (top) {
+    r2 = 4330;
+    for (i = 0; i < charBuf->getLength(); ++i) {
+      byte = charBuf->getChar(i) ^ (r2 >> 8);
+      charBuf->setChar(i, byte);
+      r2 = (byte + r2) * 52845 + 22719;
+    }
   }
 }
 
@@ -2130,42 +2305,71 @@ void Type1CFontFile::getDeltaReal(char *buf, char *key, double *opA,
   sprintf(buf, "] def\n");
 }
 
-int Type1CFontFile::getIndexLen(Guchar *indexPtr) {
-  return (int)getWord(indexPtr, 2);
+int Type1CFontFile::getIndexLen(int indexPos) {
+  if (indexPos + 2 > len) {
+    return -1;
+  }
+  return (int)getWord(indexPos, 2);
 }
 
-Guchar *Type1CFontFile::getIndexValPtr(Guchar *indexPtr, int i) {
-  int n, offSize;
-  Guchar *idxStartPtr;
+int Type1CFontFile::getIndexValPos(int indexPos, int i, int *valLen) {
+  int n, offSize, idxStartPos;
+  int pos0, pos1;
 
-  n = (int)getWord(indexPtr, 2);
-  offSize = indexPtr[2];
-  idxStartPtr = indexPtr + 3 + (n + 1) * offSize - 1;
-  return idxStartPtr + getWord(indexPtr + 3 + i * offSize, offSize);
+  if (indexPos < 0 || indexPos + 3 > len) {
+    return -1;
+  }
+  n = (int)getWord(indexPos, 2);
+  if (i >= n) {
+    return -1;
+  }
+  offSize = file[indexPos + 2];
+  if (offSize < 1 || offSize > 4) {
+    return -1;
+  }
+  idxStartPos = indexPos + 3 + (n + 1) * offSize - 1;
+  if (idxStartPos >= len) {
+    return -1;
+  }
+  pos0 = idxStartPos + getWord(indexPos + 3 + i * offSize, offSize);
+  pos1 = idxStartPos + getWord(indexPos + 3 + (i + 1) * offSize, offSize);
+  if (pos0 < 0 || pos0 >= len || pos1 < pos0 || pos1 > len) {
+    return -1;
+  }
+  *valLen = pos1 - pos0;
+  return pos0;
 }
 
-Guchar *Type1CFontFile::getIndexEnd(Guchar *indexPtr) {
-  int n, offSize;
-  Guchar *idxStartPtr;
+int Type1CFontFile::getIndexEnd(int indexPos) {
+  int n, offSize, idxStartPos;
 
-  n = (int)getWord(indexPtr, 2);
-  offSize = indexPtr[2];
-  idxStartPtr = indexPtr + 3 + (n + 1) * offSize - 1;
-  return idxStartPtr + getWord(indexPtr + 3 + n * offSize, offSize);
+  if (indexPos + 3 > len) {
+    return -1;
+  }
+  n = (int)getWord(indexPos, 2);
+  offSize = file[indexPos + 2];
+  idxStartPos = indexPos + 3 + (n + 1) * offSize - 1;
+  if (idxStartPos >= len) {
+    return -1;
+  }
+  return idxStartPos + getWord(indexPos + 3 + n * offSize, offSize);
 }
 
-Guint Type1CFontFile::getWord(Guchar *ptr, int size) {
+Guint Type1CFontFile::getWord(int pos, int size) {
   Guint x;
   int i;
 
+  if (pos < 0 || pos + size > len) {
+    return 0;
+  }
   x = 0;
   for (i = 0; i < size; ++i) {
-    x = (x << 8) + *ptr++;
+    x = (x << 8) + file[pos + i];
   }
   return x;
 }
 
-double Type1CFontFile::getNum(Guchar **ptr, GBool *isFP) {
+double Type1CFontFile::getNum(int *pos, GBool *isFP) {
   static char nybChars[16] = "0123456789.ee -";
   int b0, b, nyb0, nyb1;
   double x;
@@ -2174,20 +2378,31 @@ double Type1CFontFile::getNum(Guchar **ptr, GBool *isFP) {
 
   x = 0;
   *isFP = gFalse;
-  b0 = (*ptr)[0];
+  if (*pos >= len) {
+    return 0;
+  }
+  b0 = file[*pos];
   if (b0 < 28) {
     x = 0;
   } else if (b0 == 28) {
-    x = ((*ptr)[1] << 8) + (*ptr)[2];
-    *ptr += 3;
+    if (*pos + 3 <= len) {
+      x = (file[*pos + 1] << 8) + file[*pos + 2];
+      *pos += 3;
+    }
   } else if (b0 == 29) {
-    x = ((*ptr)[1] << 24) + ((*ptr)[2] << 16) + ((*ptr)[3] << 8) + (*ptr)[4];
-    *ptr += 5;
+    if (*pos + 5 <= len) {
+      x = (file[*pos + 1] << 24) + (file[*pos + 2] << 16) +
+         (file[*pos + 3] << 8) + file[*pos + 4];
+      *pos += 5;
+    }
   } else if (b0 == 30) {
-    *ptr += 1;
+    *pos += 1;
     i = 0;
     do {
-      b = *(*ptr)++;
+      if (*pos >= len) {
+       break;
+      }
+      b = file[(*pos)++];
       nyb0 = b >> 4;
       nyb1 = b & 0x0f;
       if (nyb0 == 0xf) {
@@ -2225,32 +2440,35 @@ double Type1CFontFile::getNum(Guchar **ptr, GBool *isFP) {
     x = 0;
   } else if (b0 < 247) {
     x = b0 - 139;
-    *ptr += 1;
+    *pos += 1;
   } else if (b0 < 251) {
-    x = ((b0 - 247) << 8) + (*ptr)[1] + 108;
-    *ptr += 2;
+    if (*pos + 2 <= len) {
+      x = ((b0 - 247) << 8) + file[*pos + 1] + 108;
+      *pos += 2;
+    }
   } else {
-    x = -((b0 - 251) << 8) - (*ptr)[1] - 108;
-    *ptr += 2;
+    if (*pos + 2 <= len) {
+      x = -((b0 - 251) << 8) - file[*pos + 1] - 108;
+      *pos += 2;
+    }
   }
   return x;
 }
 
 char *Type1CFontFile::getString(int sid, char *buf) {
-  Guchar *idxPtr0, *idxPtr1;
-  int n;
+  int idxPos, n;
 
   if (sid < 391) {
     strcpy(buf, type1CStdStrings[sid]);
   } else {
     sid -= 391;
-    idxPtr0 = getIndexValPtr(stringIdxPtr, sid);
-    idxPtr1 = getIndexValPtr(stringIdxPtr, sid + 1);
-    if ((n = idxPtr1 - idxPtr0) > 255) {
-      n = 255;
+    idxPos = getIndexValPos(stringIdxPos, sid, &n);
+    if (idxPos < 0 || n < 0 || n > 255 || idxPos + n > len) {
+      buf[0] = '\0';
+    } else {
+      strncpy(buf, (char *)&file[idxPos], n);
+      buf[n] = '\0';
     }
-    strncpy(buf, (char *)idxPtr0, n);
-    buf[n] = '\0';
   }
   return buf;
 }
@@ -2617,6 +2835,12 @@ enum T42FontIndexMode {
   t42FontModeMacRoman
 };
 
+struct TrueTypeLoca {
+  int idx;
+  int pos;
+  int length;
+};
+
 TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) {
   int pos, i, idx, n, length;
   Guint size, startPos, endPos;
@@ -2638,6 +2862,10 @@ TrueTypeFontFile::TrueTypeFontFile(char *fileA, int lenA) {
     tableHdrs[i].checksum = getULong(pos+4);
     tableHdrs[i].offset = getULong(pos+8);
     tableHdrs[i].length = getULong(pos+12);
+    if (tableHdrs[i].offset + tableHdrs[i].length < tableHdrs[i].offset ||
+       tableHdrs[i].offset + tableHdrs[i].length > (Guint)len) {
+      tableHdrs[i].offset = (Guint)-1;
+    }
     pos += 16;
   }
 
@@ -2710,9 +2938,7 @@ char *TrueTypeFontFile::getName() {
 char **TrueTypeFontFile::getEncoding() {
   int cmap[256];
   int nCmaps, cmapPlatform, cmapEncoding, cmapFmt;
-  int cmapLen, cmapOffset, cmapFirst;
-  int segCnt, segStart, segEnd, segDelta, segOffset;
-  int pos, i, j, k;
+  int pos, i, j;
   Guint fmt;
   GString *s;
   int stringIdx, stringPos, n;
@@ -2734,6 +2960,8 @@ char **TrueTypeFontFile::getEncoding() {
 
     // 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);
@@ -2750,56 +2978,17 @@ char **TrueTypeFontFile::getEncoding() {
 
     // read the cmap
     cmapFmt = getUShort(pos);
-    switch (cmapFmt) {
-    case 0: // byte encoding table (Apple standard)
-      cmapLen = getUShort(pos + 2);
-      for (i = 0; i < cmapLen && i < 256; ++i) {
-       cmap[i] = getByte(pos + 6 + i);
-      }
-      break;
-    case 4: // segment mapping to delta values (Microsoft standard)
-      if (cmapPlatform == 3 && cmapEncoding == 0) {
-       // Windows-symbol uses char codes 0xf000 - 0xf0ff
-       cmapOffset = 0xf000;
-      } else {
-       cmapOffset = 0;
-      }
-      segCnt = getUShort(pos + 6) / 2;
-      for (i = 0; i < segCnt; ++i) {
-       segEnd = getUShort(pos + 14 + 2*i);
-       segStart = getUShort(pos + 16 + 2*segCnt + 2*i);
-       segDelta = getUShort(pos + 16 + 4*segCnt + 2*i);
-       segOffset = getUShort(pos + 16 + 6*segCnt + 2*i);
-       if (segStart - cmapOffset <= 0xff &&
-           segEnd - cmapOffset >= 0) {
-         for (j = (segStart - cmapOffset >= 0) ? segStart : cmapOffset;
-              j <= segEnd && j - cmapOffset <= 0xff;
-              ++j) {
-           if (segOffset == 0) {
-             k = (j + segDelta) & 0xffff;
-           } else {
-             k = getUShort(pos + 16 + 6*segCnt + 2*i +
-                           segOffset + 2 * (j - segStart));
-             if (k != 0) {
-               k = (k + segDelta) & 0xffff;
-             }
-           }
-           cmap[j - cmapOffset] = k;
-         }
+    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;
        }
       }
-      break;
-    case 6: // trimmed table mapping
-      cmapFirst = getUShort(pos + 6);
-      cmapLen = getUShort(pos + 8);
-      for (i = cmapFirst; i < 256 && i < cmapFirst + cmapLen; ++i) {
-       cmap[i] = getUShort(pos + 10 + 2*i);
-      }
-      break;
-    default:
-      error(-1, "Unimplemented cmap format (%d) in TrueType font file",
-           cmapFmt);
-      break;
     }
   }
 
@@ -2838,9 +3027,13 @@ char **TrueTypeFontFile::getEncoding() {
                   ++stringIdx, stringPos += 1 + getByte(stringPos)) ;
            }
            n = getByte(stringPos);
-           s = new GString(file + stringPos + 1, n);
-           encoding[i] = copyString(s->getCString());
-           delete s;
+           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;
          }
@@ -2882,6 +3075,7 @@ char **TrueTypeFontFile::getEncoding() {
 void TrueTypeFontFile::convertToType42(char *name, char **encodingA,
                                       CharCodeToUnicode *toUnicode,
                                       GBool pdfFontHasEncoding,
+                                      GBool pdfFontIsSymbolic,
                                       FontFileOutputFunc outputFunc,
                                       void *outputStream) {
   char buf[512];
@@ -2904,7 +3098,7 @@ void TrueTypeFontFile::convertToType42(char *name, char **encodingA,
 
   // write the guts of the dictionary
   cvtEncoding(encodingA, pdfFontHasEncoding, outputFunc, outputStream);
-  cvtCharStrings(encodingA, toUnicode, pdfFontHasEncoding,
+  cvtCharStrings(encodingA, toUnicode, pdfFontHasEncoding, pdfFontIsSymbolic,
                 outputFunc, outputStream);
   cvtSfnts(outputFunc, outputStream, NULL);
 
@@ -3161,7 +3355,7 @@ int TrueTypeFontFile::seekTable(char *tag) {
 
   for (i = 0; i < nTables; ++i) {
     if (!strncmp(tableHdrs[i].tag, tag, 4)) {
-      return tableHdrs[i].offset;
+      return (int)tableHdrs[i].offset;
     }
   }
   return -1;
@@ -3172,6 +3366,9 @@ int TrueTypeFontFile::seekTableIdx(char *tag) {
 
   for (i = 0; i < nTables; ++i) {
     if (!strncmp(tableHdrs[i].tag, tag, 4)) {
+      if (tableHdrs[i].offset == (Guint)-1) {
+       return -1;
+      }
       return i;
     }
   }
@@ -3208,6 +3405,7 @@ void TrueTypeFontFile::cvtEncoding(char **encodingA, GBool pdfFontHasEncoding,
 void TrueTypeFontFile::cvtCharStrings(char **encodingA,
                                      CharCodeToUnicode *toUnicode,
                                      GBool pdfFontHasEncoding,
+                                     GBool pdfFontIsSymbolic,
                                      FontFileOutputFunc outputFunc,
                                      void *outputStream) {
   int unicodeCmap, macRomanCmap, msSymbolCmap;
@@ -3232,7 +3430,9 @@ void TrueTypeFontFile::cvtCharStrings(char **encodingA,
   // 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,
+  //    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:
@@ -3248,7 +3448,7 @@ void TrueTypeFontFile::cvtCharStrings(char **encodingA,
   for (i = 0; i < nCmaps; ++i) {
     cmapPlatform = getUShort(pos + 4 + 8*i);
     cmapEncoding = getUShort(pos + 4 + 8*i + 2);
-    if (cmapPlatform == 3 && cmapEncoding == 1) {
+    if ((cmapPlatform == 3 && cmapEncoding == 1) || cmapPlatform == 0) {
       unicodeCmap = i;
     } else if (cmapPlatform == 1 && cmapEncoding == 0) {
       macRomanCmap = i;
@@ -3262,6 +3462,10 @@ void TrueTypeFontFile::cvtCharStrings(char **encodingA,
     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;
@@ -3289,8 +3493,11 @@ void TrueTypeFontFile::cvtCharStrings(char **encodingA,
   // 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
-  j = 0; // make gcc happy
-  for (i = 0; i < 256; ++i) {
+  // N.B. We do this in reverse order because font subsets can have
+  //      weird encodings that use the same character name twice, and
+  //      the first definition is probably the one we want.
+  k = 0; // make gcc happy
+  for (i = 255; i >= 0; --i) {
     if (pdfFontHasEncoding) {
       name = encodingA[i];
     } else {
@@ -3301,24 +3508,26 @@ void TrueTypeFontFile::cvtCharStrings(char **encodingA,
       switch (mode) {
       case t42FontModeUnicode:
        toUnicode->mapToUnicode((CharCode)i, &u, 1);
-       j = (int)u;
+       k = getCmapEntry(cmapFmt, pos, (int)u);
        break;
       case t42FontModeCharCode:
-       j = i;
+       k = getCmapEntry(cmapFmt, pos, i);
        break;
       case t42FontModeCharCodeOffset:
-       j = cmapOffset + i;
+       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;
       }
       // note: Distiller (maybe Adobe's PS interpreter in general)
       // doesn't like TrueType fonts that have CharStrings entries
       // which point to nonexistent glyphs, hence the (k < nGlyphs)
       // test
-      if ((k = getCmapEntry(cmapFmt, pos, j)) > 0 &&
-         k < nGlyphs) {
+      if (k > 0 && k < nGlyphs) {
        (*outputFunc)(outputStream, "/", 1);
        (*outputFunc)(outputStream, name, strlen(name));
        sprintf(buf, " %d def\n", k);
@@ -3367,6 +3576,9 @@ int TrueTypeFontFile::getCmapEntry(int cmapFmt, int pos, int code) {
     segStart = getUShort(pos + 16 + 2*segCnt + 2*b);
     segDelta = getUShort(pos + 16 + 4*segCnt + 2*b);
     segOffset = getUShort(pos + 16 + 6*segCnt + 2*b);
+    if (code < segStart) {
+      return 0;
+    }
     if (segOffset == 0) {
       i = (code + segDelta) & 0xffff;
     } else {
@@ -3393,12 +3605,24 @@ int TrueTypeFontFile::getCmapEntry(int cmapFmt, int pos, int code) {
   return 0;
 }
 
+static int cmpTrueTypeLocaIdx(const void *p1, const void *p2) {
+  return ((TrueTypeLoca *)p1)->idx - ((TrueTypeLoca *)p2)->idx;
+}
+
+static int cmpTrueTypeLocaPos(const void *p1, const void *p2) {
+  if (((TrueTypeLoca *)p1)->pos == ((TrueTypeLoca *)p2)->pos) {
+    return ((TrueTypeLoca *)p1)->idx - ((TrueTypeLoca *)p2)->idx;
+  } else {
+    return ((TrueTypeLoca *)p1)->pos - ((TrueTypeLoca *)p2)->pos;
+  }
+}
+
 void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc,
                                void *outputStream, GString *name) {
   TTFontTableHdr newTableHdrs[nT42Tables];
   char tableDir[12 + nT42Tables*16];
   char headTable[54];
-  int *origLocaTable;
+  TrueTypeLoca *origLocaTable;
   char *locaTable;
   int nNewTables;
   Guint checksum;
@@ -3409,30 +3633,36 @@ void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc,
   memcpy(headTable, file + seekTable("head"), 54);
   headTable[8] = headTable[9] = headTable[10] = headTable[11] = (char)0;
 
-  // read the original 'loca' table and construct the new one
-  // (pad each glyph out to a multiple of 4 bytes)
-  origLocaTable = (int *)gmalloc((nGlyphs + 1) * sizeof(int));
+  // read the original 'loca' table and sort it into proper order --
+  // some (non-compliant) fonts have out-of-order loca tables; in
+  // order to correctly handle the case where (compliant) fonts have
+  // empty entries in the middle of the table, cmpTrueTypeLocaPos uses
+  // pos as its primary sort key, and idx as its secondary key
+  // (ensuring that adjacent entries with the same pos value remain in
+  // the same order)
+  origLocaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) *
+                                         sizeof(TrueTypeLoca));
   pos = seekTable("loca");
   for (i = 0; i <= nGlyphs; ++i) {
+    origLocaTable[i].idx = i;
     if (locaFmt) {
-      origLocaTable[i] = getULong(pos + 4*i);
+      origLocaTable[i].pos = getULong(pos + 4*i);
     } else {
-      origLocaTable[i] = 2 * getUShort(pos + 2*i);
+      origLocaTable[i].pos = 2 * getUShort(pos + 2*i);
     }
   }
-  locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2));
-  if (locaFmt) {
-    locaTable[0] = locaTable[1] = locaTable[2] = locaTable[3] = 0;
-  } else {
-    locaTable[0] = locaTable[1] = 0;
+  qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaPos);
+  for (i = 0; i < nGlyphs; ++i) {
+    origLocaTable[i].length = origLocaTable[i+1].pos - origLocaTable[i].pos;
   }
+  origLocaTable[nGlyphs].length = 0;
+  qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca), &cmpTrueTypeLocaIdx);
+
+  // construct the new 'loca' table, padding each glyph out to a
+  // multiple of 4 bytes
+  locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2));
   pos = 0;
-  for (i = 1; i <= nGlyphs; ++i) {
-    length = origLocaTable[i] - origLocaTable[i-1];
-    if (length & 3) {
-      length += 4 - (length & 3);
-    }
-    pos += length;
+  for (i = 0; i <= nGlyphs; ++i) {
     if (locaFmt) {
       locaTable[4*i  ] = (char)(pos >> 24);
       locaTable[4*i+1] = (char)(pos >> 16);
@@ -3442,6 +3672,11 @@ void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc,
       locaTable[2*i  ] = (char)(pos >> 9);
       locaTable[2*i+1] = (char)(pos >> 1);
     }
+    length = origLocaTable[i].length;
+    if (length & 3) {
+      length += 4 - (length & 3);
+    }
+    pos += length;
   }
 
   // count the number of tables
@@ -3471,11 +3706,15 @@ void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc,
       checksum = 0;
       glyfPos = seekTable("glyf");
       for (j = 0; j < nGlyphs; ++j) {
-       glyphLength = origLocaTable[j+1] - origLocaTable[j];
+       glyphLength = origLocaTable[j].length;
        pad = (glyphLength & 3) ? 4 - (glyphLength & 3) : 0;
        length += glyphLength + pad;
-       checksum += computeTableChecksum(file + glyfPos + origLocaTable[j],
-                                        glyphLength);
+       if (glyphLength >= 0 &&
+           glyfPos + origLocaTable[j].pos + glyphLength <= len) {
+         checksum +=
+             computeTableChecksum(file + glyfPos + origLocaTable[j].pos,
+                                  glyphLength);
+       }
       }
     } else {
       if ((j = seekTableIdx(t42Tables[i].tag)) >= 0) {
@@ -3566,9 +3805,10 @@ void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc,
     } else if (i == t42GlyfTable) {
       glyfPos = seekTable("glyf");
       for (j = 0; j < nGlyphs; ++j) {
-       length = origLocaTable[j+1] - origLocaTable[j];
-       if (length > 0) {
-         dumpString(file + glyfPos + origLocaTable[j], length,
+       length = origLocaTable[j].length;
+       if (length > 0 &&
+           glyfPos + origLocaTable[j].pos + length <= len) {
+         dumpString(file + glyfPos + origLocaTable[j].pos, length,
                     outputFunc, outputStream);
        }
       }
@@ -3577,8 +3817,11 @@ void TrueTypeFontFile::cvtSfnts(FontFileOutputFunc outputFunc,
       // already reported during the construction of the table
       // headers
       if ((length = newTableHdrs[i].length) > 0) {
-       dumpString(file + seekTable(t42Tables[i].tag), length,
-                  outputFunc, outputStream);
+       j = seekTable(t42Tables[i].tag);
+       if (j >= 0) {
+         dumpString(file + seekTable(t42Tables[i].tag), length,
+                    outputFunc, outputStream);
+       }
       }
     }
   }
@@ -3679,209 +3922,265 @@ void TrueTypeFontFile::writeTTF(FILE *out) {
   };
   GBool haveCmap, haveName, havePost;
   GBool dirCmap, dirName, dirPost;
-  int nNewTables, nAllTables, pad;
+  GBool unsortedLoca;
+  int nNewTables, nZeroLengthTables, nAllTables;
+  TTFontTableHdr *newTableHdrs;
   char *tableDir;
-  Guint t, pos;
-  int i, j;
+  TrueTypeLoca *origLocaTable;
+  char *locaTable;
+  int length, glyfLength;
+  Guint t, pos, pos2;
+  int i, j, k;
 
-  // check for missing tables
+  // check for missing/broken tables
   haveCmap = seekTable("cmap") >= 0;
   haveName = seekTable("name") >= 0;
   havePost = seekTable("post") >= 0;
+  unsortedLoca = gFalse;
+  pos = 0;
+  for (i = 0; i <= nGlyphs; ++i) {
+    if (locaFmt) {
+      pos2 = getULong(pos + 4*i);
+    } else {
+      pos2 = 2 * getUShort(pos + 2*i);
+    }
+    if (pos2 < pos) {
+      unsortedLoca = gTrue;
+      break;
+    }
+    pos = pos2;
+  }
   nNewTables = (haveCmap ? 0 : 1) + (haveName ? 0 : 1) + (havePost ? 0 : 1);
-  if (!nNewTables && !mungedCmapSize) {
-    // none are missing - write the TTF file as is
+  nZeroLengthTables = 0;
+  for (i = 0; i < nTables; ++i) {
+    if (tableHdrs[i].length == 0) {
+      ++nZeroLengthTables;
+    }
+  }
+  if (!nNewTables && !nZeroLengthTables && !mungedCmapSize && !unsortedLoca) {
+    // nothing is broken - write the TTF file as is
     fwrite(file, 1, len, out);
     return;
   }
 
+  // if the glyph data isn't sorted (as listed in the 'loca' table),
+  // construct a new 'loca' table
+  if (unsortedLoca) {
+    origLocaTable = (TrueTypeLoca *)gmalloc((nGlyphs + 1) *
+                                           sizeof(TrueTypeLoca));
+    pos = seekTable("loca");
+    for (i = 0; i <= nGlyphs; ++i) {
+      origLocaTable[i].idx = i;
+      if (locaFmt) {
+       origLocaTable[i].pos = getULong(pos + 4*i);
+      } else {
+       origLocaTable[i].pos = 2 * getUShort(pos + 2*i);
+      }
+    }
+    qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
+         &cmpTrueTypeLocaPos);
+    for (i = 0; i < nGlyphs; ++i) {
+      origLocaTable[i].length = origLocaTable[i+1].pos - origLocaTable[i].pos;
+    }
+    origLocaTable[nGlyphs].length = 0;
+    qsort(origLocaTable, nGlyphs + 1, sizeof(TrueTypeLoca),
+         &cmpTrueTypeLocaIdx);
+    locaTable = (char *)gmalloc((nGlyphs + 1) * (locaFmt ? 4 : 2));
+    pos = 0;
+    for (i = 0; i <= nGlyphs; ++i) {
+      if (locaFmt) {
+       locaTable[4*i  ] = (char)(pos >> 24);
+       locaTable[4*i+1] = (char)(pos >> 16);
+       locaTable[4*i+2] = (char)(pos >>  8);
+       locaTable[4*i+3] = (char) pos;
+      } else {
+       locaTable[2*i  ] = (char)(pos >> 9);
+       locaTable[2*i+1] = (char)(pos >> 1);
+      }
+      length = origLocaTable[i].length;
+      if (length & 3) {
+       length += 4 - (length & 3);
+      }
+      pos += length;
+    }
+    glyfLength = pos;
+  } else {
+    origLocaTable = NULL; // make gcc happy
+    locaTable = NULL; // make gcc happy
+    glyfLength = 0; // make gcc happy
+  }
+
   // construct the new table directory
-  nAllTables = nTables + nNewTables;
-  tableDir = (char *)gmalloc(12 + nAllTables * 16);
-  memcpy(tableDir, file, 12 + nTables * 16);
-  tableDir[4] = (char)((nAllTables >> 8) & 0xff);
-  tableDir[5] = (char)(nAllTables & 0xff);
-  for (i = -1, t = (Guint)nAllTables; t; ++i, t >>= 1) ;
-  t = 1 << (4 + i);
-  tableDir[6] = (char)((t >> 8) & 0xff);
-  tableDir[7] = (char)(t & 0xff);
-  tableDir[8] = (char)((i >> 8) & 0xff);
-  tableDir[9] = (char)(i & 0xff);
-  t = nAllTables * 16 - t;
-  tableDir[10] = (char)((t >> 8) & 0xff);
-  tableDir[11] = (char)(t & 0xff);
+  nAllTables = nTables - nZeroLengthTables + nNewTables;
+  newTableHdrs = (TTFontTableHdr *)gmalloc(nAllTables *
+                                          sizeof(TTFontTableHdr));
   dirCmap = haveCmap;
   dirName = haveName;
   dirPost = havePost;
+  pos = 12 + nAllTables * 16;
   j = 0;
-  pad = (len & 3) ? 4 - (len & 3) : 0;
-  pos = len + pad + 16 * nNewTables;
   for (i = 0; i < nTables; ++i) {
     if (!dirCmap && strncmp(tableHdrs[i].tag, "cmap", 4) > 0) {
-      tableDir[12 + 16*j     ] = 'c';
-      tableDir[12 + 16*j +  1] = 'm';
-      tableDir[12 + 16*j +  2] = 'a';
-      tableDir[12 + 16*j +  3] = 'p';
-      tableDir[12 + 16*j +  4] = (char)0; //~ should compute the checksum
-      tableDir[12 + 16*j +  5] = (char)0;
-      tableDir[12 + 16*j +  6] = (char)0;
-      tableDir[12 + 16*j +  7] = (char)0;
-      tableDir[12 + 16*j +  8] = (char)((pos >> 24) & 0xff);
-      tableDir[12 + 16*j +  9] = (char)((pos >> 16) & 0xff);
-      tableDir[12 + 16*j + 10] = (char)((pos >>  8) & 0xff);
-      tableDir[12 + 16*j + 11] = (char)( pos        & 0xff);
-      tableDir[12 + 16*j + 12] = (char)((sizeof(cmapTab) >> 24) & 0xff);
-      tableDir[12 + 16*j + 13] = (char)((sizeof(cmapTab) >> 16) & 0xff);
-      tableDir[12 + 16*j + 14] = (char)((sizeof(cmapTab) >>  8) & 0xff);
-      tableDir[12 + 16*j + 15] = (char)( sizeof(cmapTab)        & 0xff);
-      pos += sizeof(cmapTab);
+      memcpy(newTableHdrs[j].tag, "cmap", 4);
+      newTableHdrs[j].checksum = 0; //~ should compute the checksum
+      newTableHdrs[j].offset = pos;
+      pos += newTableHdrs[j].length = sizeof(cmapTab);
+      if (pos & 3) {
+       pos += 4 - (pos & 3);
+      }
       ++j;
       dirCmap = gTrue;
     }
     if (!dirName && strncmp(tableHdrs[i].tag, "name", 4) > 0) {
-      tableDir[12 + 16*j     ] = 'n';
-      tableDir[12 + 16*j +  1] = 'a';
-      tableDir[12 + 16*j +  2] = 'm';
-      tableDir[12 + 16*j +  3] = 'e';
-      tableDir[12 + 16*j +  4] = (char)0; //~ should compute the checksum
-      tableDir[12 + 16*j +  5] = (char)0;
-      tableDir[12 + 16*j +  6] = (char)0;
-      tableDir[12 + 16*j +  7] = (char)0;
-      tableDir[12 + 16*j +  8] = (char)((pos >> 24) & 0xff);
-      tableDir[12 + 16*j +  9] = (char)((pos >> 16) & 0xff);
-      tableDir[12 + 16*j + 10] = (char)((pos >>  8) & 0xff);
-      tableDir[12 + 16*j + 11] = (char)( pos        & 0xff);
-      tableDir[12 + 16*j + 12] = (char)((sizeof(nameTab) >> 24) & 0xff);
-      tableDir[12 + 16*j + 13] = (char)((sizeof(nameTab) >> 16) & 0xff);
-      tableDir[12 + 16*j + 14] = (char)((sizeof(nameTab) >>  8) & 0xff);
-      tableDir[12 + 16*j + 15] = (char)( sizeof(nameTab)        & 0xff);
-      pos += sizeof(nameTab);
+      memcpy(newTableHdrs[j].tag, "name", 4);
+      newTableHdrs[j].checksum = 0; //~ should compute the checksum
+      newTableHdrs[j].offset = pos;
+      pos += newTableHdrs[j].length = sizeof(nameTab);
+      if (pos & 3) {
+       pos += 4 - (pos & 3);
+      }
       ++j;
       dirName = gTrue;
     }
-    if (!dirName && strncmp(tableHdrs[i].tag, "post", 4) > 0) {
-      tableDir[12 + 16*j     ] = 'p';
-      tableDir[12 + 16*j +  1] = 'o';
-      tableDir[12 + 16*j +  2] = 's';
-      tableDir[12 + 16*j +  3] = 't';
-      tableDir[12 + 16*j +  4] = (char)0; //~ should compute the checksum
-      tableDir[12 + 16*j +  5] = (char)0;
-      tableDir[12 + 16*j +  6] = (char)0;
-      tableDir[12 + 16*j +  7] = (char)0;
-      tableDir[12 + 16*j +  8] = (char)((pos >> 24) & 0xff);
-      tableDir[12 + 16*j +  9] = (char)((pos >> 16) & 0xff);
-      tableDir[12 + 16*j + 10] = (char)((pos >>  8) & 0xff);
-      tableDir[12 + 16*j + 11] = (char)( pos        & 0xff);
-      tableDir[12 + 16*j + 12] = (char)((sizeof(postTab) >> 24) & 0xff);
-      tableDir[12 + 16*j + 13] = (char)((sizeof(postTab) >> 16) & 0xff);
-      tableDir[12 + 16*j + 14] = (char)((sizeof(postTab) >>  8) & 0xff);
-      tableDir[12 + 16*j + 15] = (char)( sizeof(postTab)        & 0xff);
-      pos += sizeof(postTab);
+    if (!dirPost && strncmp(tableHdrs[i].tag, "post", 4) > 0) {
+      memcpy(newTableHdrs[j].tag, "post", 4);
+      newTableHdrs[j].checksum = 0; //~ should compute the checksum
+      newTableHdrs[j].offset = pos;
+      pos += newTableHdrs[j].length = sizeof(postTab);
+      if (pos & 3) {
+       pos += 4 - (pos & 3);
+      }
       ++j;
       dirPost = gTrue;
     }
-    tableDir[12 + 16*j     ] = tableHdrs[i].tag[0];
-    tableDir[12 + 16*j +  1] = tableHdrs[i].tag[1];
-    tableDir[12 + 16*j +  2] = tableHdrs[i].tag[2];
-    tableDir[12 + 16*j +  3] = tableHdrs[i].tag[3];
-    tableDir[12 + 16*j +  4] = (char)((tableHdrs[i].checksum >> 24) & 0xff);
-    tableDir[12 + 16*j +  5] = (char)((tableHdrs[i].checksum >> 16) & 0xff);
-    tableDir[12 + 16*j +  6] = (char)((tableHdrs[i].checksum >>  8) & 0xff);
-    tableDir[12 + 16*j +  7] = (char)( tableHdrs[i].checksum        & 0xff);
-    t = tableHdrs[i].offset + nNewTables * 16;
-    tableDir[12 + 16*j +  8] = (char)((t >> 24) & 0xff);
-    tableDir[12 + 16*j +  9] = (char)((t >> 16) & 0xff);
-    tableDir[12 + 16*j + 10] = (char)((t >>  8) & 0xff);
-    tableDir[12 + 16*j + 11] = (char)( t        & 0xff);
-    tableDir[12 + 16*j + 12] = (char)((tableHdrs[i].length >> 24) & 0xff);
-    tableDir[12 + 16*j + 13] = (char)((tableHdrs[i].length >> 16) & 0xff);
-    tableDir[12 + 16*j + 14] = (char)((tableHdrs[i].length >>  8) & 0xff);
-    tableDir[12 + 16*j + 15] = (char)( tableHdrs[i].length        & 0xff);
-    ++j;
+    // throw away zero-length tables - they confuse FreeType
+    if (tableHdrs[i].length > 0) {
+      memcpy(newTableHdrs[j].tag, tableHdrs[i].tag, 4);
+      newTableHdrs[j].checksum = tableHdrs[i].checksum;
+      newTableHdrs[j].offset = pos;
+      if (unsortedLoca && !strncmp(tableHdrs[i].tag, "loca", 4)) {
+       newTableHdrs[j].length = (nGlyphs + 1) * (locaFmt ? 4 : 2);
+      } else if (unsortedLoca && !strncmp(tableHdrs[i].tag, "glyf", 4)) {
+       newTableHdrs[j].length = glyfLength;
+      } else {
+       newTableHdrs[j].length = tableHdrs[i].length;
+      }
+      pos += newTableHdrs[j].length;
+      if (pos & 3) {
+       pos += 4 - (pos & 3);
+      }
+      ++j;
+    }
   }
   if (!dirCmap) {
-    tableDir[12 + 16*j     ] = 'c';
-    tableDir[12 + 16*j +  1] = 'm';
-    tableDir[12 + 16*j +  2] = 'a';
-    tableDir[12 + 16*j +  3] = 'p';
-    tableDir[12 + 16*j +  4] = (char)0; //~ should compute the checksum
-    tableDir[12 + 16*j +  5] = (char)0;
-    tableDir[12 + 16*j +  6] = (char)0;
-    tableDir[12 + 16*j +  7] = (char)0;
-    tableDir[12 + 16*j +  8] = (char)((pos >> 24) & 0xff);
-    tableDir[12 + 16*j +  9] = (char)((pos >> 16) & 0xff);
-    tableDir[12 + 16*j + 10] = (char)((pos >>  8) & 0xff);
-    tableDir[12 + 16*j + 11] = (char)( pos        & 0xff);
-    tableDir[12 + 16*j + 12] = (char)((sizeof(cmapTab) >> 24) & 0xff);
-    tableDir[12 + 16*j + 13] = (char)((sizeof(cmapTab) >> 16) & 0xff);
-    tableDir[12 + 16*j + 14] = (char)((sizeof(cmapTab) >>  8) & 0xff);
-    tableDir[12 + 16*j + 15] = (char)( sizeof(cmapTab)        & 0xff);
-    pos += sizeof(cmapTab);
+    memcpy(newTableHdrs[j].tag, "cmap", 4);
+    newTableHdrs[j].checksum = 0; //~ should compute the checksum
+    newTableHdrs[j].offset = pos;
+    pos += newTableHdrs[j].length = sizeof(cmapTab);
+    if (pos & 3) {
+      pos += 4 - (pos & 3);
+    }
     ++j;
-    dirCmap = gTrue;
   }
   if (!dirName) {
-    tableDir[12 + 16*j     ] = 'n';
-    tableDir[12 + 16*j +  1] = 'a';
-    tableDir[12 + 16*j +  2] = 'm';
-    tableDir[12 + 16*j +  3] = 'e';
-    tableDir[12 + 16*j +  4] = (char)0; //~ should compute the checksum
-    tableDir[12 + 16*j +  5] = (char)0;
-    tableDir[12 + 16*j +  6] = (char)0;
-    tableDir[12 + 16*j +  7] = (char)0;
-    tableDir[12 + 16*j +  8] = (char)((pos >> 24) & 0xff);
-    tableDir[12 + 16*j +  9] = (char)((pos >> 16) & 0xff);
-    tableDir[12 + 16*j + 10] = (char)((pos >>  8) & 0xff);
-    tableDir[12 + 16*j + 11] = (char)( pos        & 0xff);
-    tableDir[12 + 16*j + 12] = (char)((sizeof(nameTab) >> 24) & 0xff);
-    tableDir[12 + 16*j + 13] = (char)((sizeof(nameTab) >> 16) & 0xff);
-    tableDir[12 + 16*j + 14] = (char)((sizeof(nameTab) >>  8) & 0xff);
-    tableDir[12 + 16*j + 15] = (char)( sizeof(nameTab)        & 0xff);
-    pos += sizeof(nameTab);
+    memcpy(newTableHdrs[j].tag, "name", 4);
+    newTableHdrs[j].checksum = 0; //~ should compute the checksum
+    newTableHdrs[j].offset = pos;
+    pos += newTableHdrs[j].length = sizeof(nameTab);
+    if (pos & 3) {
+      pos += 4 - (pos & 3);
+    }
     ++j;
-    dirName = gTrue;
   }
   if (!dirPost) {
-    tableDir[12 + 16*j     ] = 'p';
-    tableDir[12 + 16*j +  1] = 'o';
-    tableDir[12 + 16*j +  2] = 's';
-    tableDir[12 + 16*j +  3] = 't';
-    tableDir[12 + 16*j +  4] = (char)0; //~ should compute the checksum
-    tableDir[12 + 16*j +  5] = (char)0;
-    tableDir[12 + 16*j +  6] = (char)0;
-    tableDir[12 + 16*j +  7] = (char)0;
-    tableDir[12 + 16*j +  8] = (char)((pos >> 24) & 0xff);
-    tableDir[12 + 16*j +  9] = (char)((pos >> 16) & 0xff);
-    tableDir[12 + 16*j + 10] = (char)((pos >>  8) & 0xff);
-    tableDir[12 + 16*j + 11] = (char)( pos        & 0xff);
-    tableDir[12 + 16*j + 12] = (char)((sizeof(postTab) >> 24) & 0xff);
-    tableDir[12 + 16*j + 13] = (char)((sizeof(postTab) >> 16) & 0xff);
-    tableDir[12 + 16*j + 14] = (char)((sizeof(postTab) >>  8) & 0xff);
-    tableDir[12 + 16*j + 15] = (char)( sizeof(postTab)        & 0xff);
-    pos += sizeof(postTab);
+    memcpy(newTableHdrs[j].tag, "post", 4);
+    newTableHdrs[j].checksum = 0; //~ should compute the checksum
+    newTableHdrs[j].offset = pos;
+    pos += newTableHdrs[j].length = sizeof(postTab);
+    if (pos & 3) {
+      pos += 4 - (pos & 3);
+    }
     ++j;
-    dirPost = gTrue;
+  }
+  tableDir = (char *)gmalloc(12 + nAllTables * 16);
+  tableDir[0] = 0x00;                                  // sfnt version
+  tableDir[1] = 0x01;
+  tableDir[2] = 0x00;
+  tableDir[3] = 0x00;
+  tableDir[4] = (char)((nAllTables >> 8) & 0xff);      // numTables
+  tableDir[5] = (char)(nAllTables & 0xff);
+  for (i = -1, t = (Guint)nAllTables; t; ++i, t >>= 1) ;
+  t = 1 << (4 + i);
+  tableDir[6] = (char)((t >> 8) & 0xff);               // searchRange
+  tableDir[7] = (char)(t & 0xff);
+  tableDir[8] = (char)((i >> 8) & 0xff);               // entrySelector
+  tableDir[9] = (char)(i & 0xff);
+  t = nAllTables * 16 - t;
+  tableDir[10] = (char)((t >> 8) & 0xff);              // rangeShift
+  tableDir[11] = (char)(t & 0xff);
+  pos = 12;
+  for (i = 0; i < nAllTables; ++i) {
+    tableDir[pos   ] = newTableHdrs[i].tag[0];
+    tableDir[pos+ 1] = newTableHdrs[i].tag[1];
+    tableDir[pos+ 2] = newTableHdrs[i].tag[2];
+    tableDir[pos+ 3] = newTableHdrs[i].tag[3];
+    tableDir[pos+ 4] = (char)(newTableHdrs[i].checksum >> 24);
+    tableDir[pos+ 5] = (char)(newTableHdrs[i].checksum >> 16);
+    tableDir[pos+ 6] = (char)(newTableHdrs[i].checksum >>  8);
+    tableDir[pos+ 7] = (char) newTableHdrs[i].checksum;
+    tableDir[pos+ 8] = (char)(newTableHdrs[i].offset >> 24);
+    tableDir[pos+ 9] = (char)(newTableHdrs[i].offset >> 16);
+    tableDir[pos+10] = (char)(newTableHdrs[i].offset >>  8);
+    tableDir[pos+11] = (char) newTableHdrs[i].offset;
+    tableDir[pos+12] = (char)(newTableHdrs[i].length >> 24);
+    tableDir[pos+13] = (char)(newTableHdrs[i].length >> 16);
+    tableDir[pos+14] = (char)(newTableHdrs[i].length >>  8);
+    tableDir[pos+15] = (char) newTableHdrs[i].length;
+    pos += 16;
   }
 
   // write the table directory
   fwrite(tableDir, 1, 12 + 16 * nAllTables, out);
 
-  // write the original tables
-  fwrite(file + 12 + 16*nTables, 1, len - (12 + 16*nTables), out);
-
-  // write the new tables
-  for (i = 0; i < pad; ++i) {
-    fputc((char)0, out);
-  }
-  if (!haveCmap) {
-    fwrite(cmapTab, 1, sizeof(cmapTab), out);
-  }
-  if (!haveName) {
-    fwrite(nameTab, 1, sizeof(nameTab), out);
-  }
-  if (!havePost) {
-    fwrite(postTab, 1, sizeof(postTab), out);
+  // write the tables
+  for (i = 0; i < nAllTables; ++i) {
+    if (!haveCmap && !strncmp(newTableHdrs[i].tag, "cmap", 4)) {
+      fwrite(cmapTab, 1, newTableHdrs[i].length, out);
+    } else if (!haveName && !strncmp(newTableHdrs[i].tag, "name", 4)) {
+      fwrite(nameTab, 1, newTableHdrs[i].length, out);
+    } else if (!havePost && !strncmp(newTableHdrs[i].tag, "post", 4)) {
+      fwrite(postTab, 1, newTableHdrs[i].length, out);
+    } else if (unsortedLoca && !strncmp(newTableHdrs[i].tag, "loca", 4)) {
+      fwrite(locaTable, 1, newTableHdrs[i].length, out);
+    } else if (unsortedLoca && !strncmp(newTableHdrs[i].tag, "glyf", 4)) {
+      pos = seekTable("glyf");
+      for (j = 0; j < nGlyphs; ++j) {
+       length = origLocaTable[j].length;
+       if (length > 0 &&
+           pos + origLocaTable[j].pos + length <= (Guint)len) {
+         fwrite(file + pos + origLocaTable[j].pos, 1, length, out);
+         if ((k = length & 3)) {
+           for (; k < 4; ++k) {
+             fputc((char)0, out);
+           }
+         }
+       }
+      }
+    } else {
+      fwrite(file + seekTable(newTableHdrs[i].tag),
+            1, newTableHdrs[i].length, out);
+    }
+    if ((j = (newTableHdrs[i].length & 3))) {
+      for (; j < 4; ++j) {
+       fputc((char)0, out);
+      }
+    }
   }
-
+    
   gfree(tableDir);
+  gfree(newTableHdrs);
+  if (unsortedLoca) {
+    gfree(origLocaTable);
+    gfree(locaTable);
+  }
 }
index 729399221cf0e9a619004810e5960b8638a0ec87..a71653c2646a898d1742561a1e2a94e92e901e6d 100644 (file)
@@ -2,7 +2,7 @@
 //
 // FontFile.h
 //
-// Copyright 1999-2002 Glyph & Cog, LLC
+// Copyright 1999-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -75,6 +75,7 @@ public:
 
   Type1CFontFile(char *fileA, int lenA);
   virtual ~Type1CFontFile();
+  GBool isOk() { return ok; }
 
   virtual char *getName();
   virtual char **getEncoding();
@@ -97,14 +98,14 @@ public:
 
 private:
 
-  void readNameAndEncoding();
+  void readEncoding();
   void readTopDict(Type1CTopDict *dict);
   void readPrivateDict(Type1CPrivateDict *privateDict,
                       int offset, int size);
   Gushort *readCharset(int charset, int nGlyphs);
   void eexecWrite(char *s);
-  void eexecCvtGlyph(char *glyphName, Guchar *s, int n);
-  void cvtGlyph(Guchar *s, int n);
+  void eexecCvtGlyph(char *glyphName, int pos, int n);
+  void cvtGlyph(int pos, int n, GBool top);
   void cvtGlyphWidth(GBool useOp);
   void eexecDumpNum(double x, GBool fpA);
   void eexecDumpOp1(int opA);
@@ -112,29 +113,33 @@ private:
   void eexecWriteCharstring(Guchar *s, int n);
   void getDeltaInt(char *buf, char *key, double *opA, int n);
   void getDeltaReal(char *buf, char *key, double *opA, int n);
-  int getIndexLen(Guchar *indexPtr);
-  Guchar *getIndexValPtr(Guchar *indexPtr, int i);
-  Guchar *getIndexEnd(Guchar *indexPtr);
-  Guint getWord(Guchar *ptr, int size);
-  double getNum(Guchar **ptr, GBool *fp);
+  int getIndexLen(int indexPos);
+  int getIndexValPos(int indexPos, int i, int *valLen);
+  int getIndexEnd(int indexPos);
+  Guint getWord(int pos, int size);
+  double getNum(int *pos, GBool *fp);
   char *getString(int sid, char *buf);
 
-  char *file;
+  Guchar *file;
   int len;
 
   GString *name;
   char **encoding;
 
-  int topOffSize;
-  Guchar *topDictIdxPtr;
-  Guchar *stringIdxPtr;
-  Guchar *gsubrIdxPtr;
+  int topDictIdxPos;
+  int stringIdxPos;
+  int gsubrIdxPos;
+  int subrIdxPos;
+  int gsubrBias;
+  int subrBias;
 
   FontFileOutputFunc outputFunc;
   void *outputStream;
   double op[48];               // operands
   GBool fp[48];                        // true if operand is fixed point
   int nOps;                    // number of operands
+  int nHints;                  // number of hints for the current glyph
+  GBool firstOp;               // true if we haven't hit the first op yet
   double defaultWidthX;                // default glyph width
   double nominalWidthX;                // nominal glyph width
   GBool defaultWidthXFP;       // true if defaultWidthX is fixed point
@@ -142,6 +147,8 @@ private:
   Gushort r1;                  // eexec encryption key
   GString *charBuf;            // charstring output buffer
   int line;                    // number of eexec chars on current line
+
+  GBool ok;
 };
 
 //------------------------------------------------------------------------
@@ -171,6 +178,7 @@ public:
   void convertToType42(char *name, char **encodingA,
                       CharCodeToUnicode *toUnicode,
                       GBool pdfFontHasEncoding,
+                      GBool pdfFontIsSymbolic,
                       FontFileOutputFunc outputFunc, void *outputStream);
 
   // Convert to a Type 2 CIDFont, suitable for embedding in a
@@ -217,7 +225,7 @@ private:
   void cvtEncoding(char **encodingA, GBool pdfFontHasEncoding,
                   FontFileOutputFunc outputFunc, void *outputStream);
   void cvtCharStrings(char **encodingA, CharCodeToUnicode *toUnicode,
-                     GBool pdfFontHasEncoding,
+                     GBool pdfFontHasEncoding, GBool pdfFontIsSymbolic,
                      FontFileOutputFunc outputFunc, void *outputStream);
   int getCmapEntry(int cmapFmt, int pos, int code);
   void cvtSfnts(FontFileOutputFunc outputFunc, void *outputStream,
index cafb63f32314dfd87285ee0e8d75450ba821116b..28eed87a5e3862ea21785428adaf07756fceaa59 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Function.cc
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -413,7 +413,6 @@ void SampledFunction::transform(double *in, double *out) {
 
 ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
   Object obj1, obj2;
-  GBool hasN;
   int i;
 
   ok = gFalse;
@@ -426,23 +425,14 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
     error(-1, "Exponential function with more than one input");
     goto err1;
   }
-  hasN = hasRange;
-
-  //----- default values
-  for (i = 0; i < funcMaxOutputs; ++i) {
-    c0[i] = 0;
-    c1[i] = 1;
-  }
 
   //----- C0
   if (dict->lookup("C0", &obj1)->isArray()) {
-    if (!hasN) {
-      n = obj1.arrayGetLength();
-      hasN = gTrue;
-    } else if (obj1.arrayGetLength() != n) {
+    if (hasRange && obj1.arrayGetLength() != n) {
       error(-1, "Function's C0 array is wrong length");
       goto err2;
     }
+    n = obj1.arrayGetLength();
     for (i = 0; i < n; ++i) {
       obj1.arrayGet(i, &obj2);
       if (!obj2.isNum()) {
@@ -452,15 +442,19 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
       c0[i] = obj2.getNum();
       obj2.free();
     }
+  } else {
+    if (hasRange && n != 1) {
+      error(-1, "Function's C0 array is wrong length");
+      goto err2;
+    }
+    n = 1;
+    c0[0] = 0;
   }
   obj1.free();
 
   //----- C1
   if (dict->lookup("C1", &obj1)->isArray()) {
-    if (!hasN) {
-      n = obj1.arrayGetLength();
-      hasN = gTrue;
-    } else if (obj1.arrayGetLength() != n) {
+    if (obj1.arrayGetLength() != n) {
       error(-1, "Function's C1 array is wrong length");
       goto err2;
     }
@@ -473,6 +467,12 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
       c1[i] = obj2.getNum();
       obj2.free();
     }
+  } else {
+    if (n != 1) {
+      error(-1, "Function's C1 array is wrong length");
+      goto err2;
+    }
+    c1[0] = 1;
   }
   obj1.free();
 
@@ -484,13 +484,6 @@ ExponentialFunction::ExponentialFunction(Object *funcObj, Dict *dict) {
   e = obj1.getNum();
   obj1.free();
 
-  // this isn't supposed to happen, but I've run into (broken) PDF
-  // files where it does
-  if (!hasN) {
-    error(-1, "Exponential function does not define number of output values");
-    n = 1;
-  }
-
   ok = gTrue;
   return;
 
index eb88211dd16a0f43722a22cccb369b3dc45db507..d795a513cae94b7d6fa9ae12664dd3b29cc3654e 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Function.h
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 21136b1b5b54fbe9ca0a6bf1008806ec2d8d2134..63896d89120e248d6f961de2db7009016eccbdc6 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Gfx.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index c3c57cf1806d5321574e5d8af3abd0a8413f6442..c7aef1117910671500508df429a044d67ae69a13 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Gfx.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index b3b6a7187785d101d8dd98f4db26d105c69bbf09..d6875881fa698fd003534ffec72776026dc9c919 100644 (file)
@@ -2,7 +2,7 @@
 //
 // GfxFont.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -35,6 +35,11 @@ struct StdFontMapEntry {
   char *properName;
 };
 
+// Acrobat 4.0 and earlier substituted Base14-compatible fonts without
+// providing Widths and a FontDescriptor, so we munge the names into
+// the proper Base14 names.  This table is from implementation note 44
+// in the PDF 1.4 spec, with some additions based on empirical
+// evidence.
 static StdFontMapEntry stdFontMap[] = {
   { "Arial",                        "Helvetica" },
   { "Arial,Bold",                   "Helvetica-Bold" },
@@ -304,11 +309,14 @@ CharCodeToUnicode *GfxFont::readToUnicodeCMap(Dict *fontDict, int nBits) {
 }
 
 void GfxFont::findExtFontFile() {
+  static char *type1Exts[] = { ".pfa", ".pfb", ".ps", "", NULL };
+  static char *ttExts[] = { ".ttf", NULL };
+
   if (name) {
     if (type == fontType1) {
-      extFontFile = globalParams->findFontFile(name, ".pfa", ".pfb");
+      extFontFile = globalParams->findFontFile(name, type1Exts);
     } else if (type == fontTrueType) {
-      extFontFile = globalParams->findFontFile(name, ".ttf", NULL);
+      extFontFile = globalParams->findFontFile(name, ttExts);
     }
   }
 }
@@ -396,10 +404,8 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
   type = typeA;
   ctu = NULL;
 
-  // Acrobat 4.0 and earlier substituted Base14-compatible fonts
-  // without providing Widths and a FontDescriptor, so we munge the
-  // names into the proper Base14 names.  (This table is from
-  // implementation note 44 in the PDF 1.4 spec.)
+  // do font name substitution for various aliases of the Base 14 font
+  // names
   if (name) {
     a = 0;
     b = sizeof(stdFontMap) / sizeof(StdFontMapEntry);
@@ -553,14 +559,18 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
        fontFile = new Type1FontFile(buf, len);
       } else {
        fontFile = new Type1CFontFile(buf, len);
+       if (!((Type1CFontFile *)fontFile)->isOk()) {
+         delete fontFile;
+         fontFile = NULL;
+       }
       }
-      if (fontFile->getName()) {
+      if (fontFile && fontFile->getName()) {
        if (embFontName) {
          delete embFontName;
        }
        embFontName = new GString(fontFile->getName());
       }
-      if (!baseEnc) {
+      if (fontFile && !baseEnc) {
        baseEnc = fontFile->getEncoding();
        baseEncFromFontFile = gTrue;
       }
@@ -713,6 +723,9 @@ Gfx8BitFont::Gfx8BitFont(XRef *xref, char *tagA, Ref idA, GString *nameA,
   fontDict->lookup("Widths", &obj1);
   if (obj1.isArray()) {
     flags |= fontFixedWidth;
+    if (obj1.arrayGetLength() < lastChar - firstChar + 1) {
+      lastChar = firstChar + obj1.arrayGetLength() - 1;
+    }
     for (code = firstChar; code <= lastChar; ++code) {
       obj1.arrayGet(code - firstChar, &obj2);
       if (obj2.isNum()) {
@@ -827,12 +840,12 @@ Dict *Gfx8BitFont::getResources() {
 // GfxCIDFont
 //------------------------------------------------------------------------
 
-static int cmpWidthExcep(const void *w1, const void *w2) {
+static int CDECL cmpWidthExcep(const void *w1, const void *w2) {
   return ((GfxFontCIDWidthExcep *)w1)->first -
          ((GfxFontCIDWidthExcep *)w2)->first;
 }
 
-static int cmpWidthExcepV(const void *w1, const void *w2) {
+static int CDECL cmpWidthExcepV(const void *w1, const void *w2) {
   return ((GfxFontCIDWidthExcepV *)w1)->first -
          ((GfxFontCIDWidthExcepV *)w2)->first;
 }
index bcabe5f36bee1f6a0075cdd4aec23c9c980f6fd1..23371b3fb8838af981d8cee0b200ffddad7494e4 100644 (file)
@@ -2,7 +2,7 @@
 //
 // GfxFont.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index a978b50b0be765b8b77cd8dfdb8977075c33dcc1..7efd0b9ad130ee8ac561e4731ba5b344af74fa7c 100644 (file)
@@ -2,7 +2,7 @@
 //
 // GfxState.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index cfe8f9be538cce3f6f9a8fbf258c700dcd1fbf20..a0b1d14aee56440b9e05a0851e4d7e27739150ef 100644 (file)
@@ -2,7 +2,7 @@
 //
 // GfxState.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index ded583f5194fc1add9ea54575fb077f1db328b71..c5083b2afc41ef1f758a21e8e28c4a78d412fbb5 100644 (file)
@@ -2,7 +2,7 @@
 //
 // GlobalParams.cc
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -353,6 +353,12 @@ void GlobalParams::parseFile(GString *fileName, FILE *f) {
       } else if (!cmd->cmp("displayCIDFontT1")) {
        parseDisplayFont(tokens, displayCIDFonts,
                         displayFontT1, fileName, line);
+      } else if (!cmd->cmp("displayNamedCIDFontTT")) {
+       parseDisplayFont(tokens, displayNamedCIDFonts,
+                        displayFontTT, fileName, line);
+      } else if (!cmd->cmp("displayCIDFontTT")) {
+       parseDisplayFont(tokens, displayCIDFonts,
+                        displayFontTT, fileName, line);
       } else if (!cmd->cmp("psFile")) {
        parsePSFile(tokens, fileName, line);
       } else if (!cmd->cmp("psFont")) {
@@ -1061,26 +1067,17 @@ GBool GlobalParams::getTextKeepTinyChars() {
   return tiny;
 }
 
-GString *GlobalParams::findFontFile(GString *fontName,
-                                   char *ext1, char *ext2) {
+GString *GlobalParams::findFontFile(GString *fontName, char **exts) {
   GString *dir, *fileName;
+  char **ext;
   FILE *f;
   int i;
 
   for (i = 0; i < fontDirs->getLength(); ++i) {
     dir = (GString *)fontDirs->get(i);
-    if (ext1) {
-      fileName = appendToPath(dir->copy(), fontName->getCString());
-      fileName->append(ext1);
-      if ((f = fopen(fileName->getCString(), "r"))) {
-       fclose(f);
-       return fileName;
-      }
-      delete fileName;
-    }
-    if (ext2) {
+    for (ext = exts; *ext; ++ext) {
       fileName = appendToPath(dir->copy(), fontName->getCString());
-      fileName->append(ext2);
+      fileName->append(*ext);
       if ((f = fopen(fileName->getCString(), "r"))) {
        fclose(f);
        return fileName;
@@ -1218,7 +1215,9 @@ void GlobalParams::setPSFile(char *file) {
 
 GBool GlobalParams::setPSPaperSize(char *size) {
   globalParamsLock;
-  if (!strcmp(size, "letter")) {
+  if (!strcmp(size, "match")) {
+    psPaperWidth = psPaperHeight = -1;
+  } else if (!strcmp(size, "letter")) {
     psPaperWidth = 612;
     psPaperHeight = 792;
   } else if (!strcmp(size, "legal")) {
index 5fb3be319269dacf06907629cbbef61c7370b03f..dee9e25c62979ba127fed63e431e9a3e06261b84 100644 (file)
@@ -2,7 +2,7 @@
 //
 // GlobalParams.h
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -156,7 +156,7 @@ public:
   GBool getPSASCIIHex();
   EndOfLineKind getTextEOL();
   GBool getTextKeepTinyChars();
-  GString *findFontFile(GString *fontName, char *ext1, char *ext2);
+  GString *findFontFile(GString *fontName, char **exts);
   GString *getInitialZoom();
   FontRastControl getT1libControl();
   FontRastControl getFreeTypeControl();
index 1a6d87e1f687102640e0dcc5fa3bedbe73abd688..29c7f0f956c137c4c1750de605b9a9dab427d744 100644 (file)
@@ -2,7 +2,7 @@
 //
 // ImageOutputDev.cc
 //
-// Copyright 1998-2002 Glyph & Cog, LLC
+// Copyright 1998-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index c3eb36e0e09d7902ee046ef67abc62cbf928fdb3..73f2f15f79957c61420feff6b3b5bab666b585bb 100644 (file)
@@ -2,7 +2,7 @@
 //
 // ImageOutputDev.h
 //
-// Copyright 1998-2002 Glyph & Cog, LLC
+// Copyright 1998-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 982295ee3261bddfa1918e41010df5a45ea5cc84..1fa166f1951e543ba3b167f41b566e38ba645114 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Lexer.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 2dfe31462ec3180c492111f9e1dc9c1a33790ac0..398d27c355a33df5286cdd64f764754211083664 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Lexer.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 0c3a86926203286ce8d81e22a0381af943243832..39b7cebe22d52122d893901a28295af1a395d093 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Link.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -148,7 +148,7 @@ LinkDest::LinkDest(Array *a) {
 
   // get page
   if (a->getLength() < 2) {
-    error(-1, "Annotation destination array has wrong length");
+    error(-1, "Annotation destination array is too short");
     return;
   }
   a->getNF(0, &obj1);
@@ -219,16 +219,16 @@ LinkDest::LinkDest(Array *a) {
 
   // Fit link
   } else if (obj1.isName("Fit")) {
-    if (a->getLength() != 2) {
-      error(-1, "Annotation destination array has wrong length");
+    if (a->getLength() < 2) {
+      error(-1, "Annotation destination array is too short");
       goto err2;
     }
     kind = destFit;
 
   // FitH link
   } else if (obj1.isName("FitH")) {
-    if (a->getLength() != 3) {
-      error(-1, "Annotation destination array has wrong length");
+    if (a->getLength() < 3) {
+      error(-1, "Annotation destination array is too short");
       goto err2;
     }
     kind = destFitH;
@@ -241,8 +241,8 @@ LinkDest::LinkDest(Array *a) {
 
   // FitV link
   } else if (obj1.isName("FitV")) {
-    if (a->getLength() != 3) {
-      error(-1, "Annotation destination array has wrong length");
+    if (a->getLength() < 3) {
+      error(-1, "Annotation destination array is too short");
       goto err2;
     }
     kind = destFitV;
@@ -255,8 +255,8 @@ LinkDest::LinkDest(Array *a) {
 
   // FitR link
   } else if (obj1.isName("FitR")) {
-    if (a->getLength() != 6) {
-      error(-1, "Annotation destination array has wrong length");
+    if (a->getLength() < 6) {
+      error(-1, "Annotation destination array is too short");
       goto err2;
     }
     kind = destFitR;
@@ -287,16 +287,16 @@ LinkDest::LinkDest(Array *a) {
 
   // FitB link
   } else if (obj1.isName("FitB")) {
-    if (a->getLength() != 2) {
-      error(-1, "Annotation destination array has wrong length");
+    if (a->getLength() < 2) {
+      error(-1, "Annotation destination array is too short");
       goto err2;
     }
     kind = destFitB;
 
   // FitBH link
   } else if (obj1.isName("FitBH")) {
-    if (a->getLength() != 3) {
-      error(-1, "Annotation destination array has wrong length");
+    if (a->getLength() < 3) {
+      error(-1, "Annotation destination array is too short");
       goto err2;
     }
     kind = destFitBH;
@@ -309,8 +309,8 @@ LinkDest::LinkDest(Array *a) {
 
   // FitBV link
   } else if (obj1.isName("FitBV")) {
-    if (a->getLength() != 3) {
-      error(-1, "Annotation destination array has wrong length");
+    if (a->getLength() < 3) {
+      error(-1, "Annotation destination array is too short");
       goto err2;
     }
     kind = destFitBV;
index e19c3c035b1764843318bab06bf7e2e3170b862b..20ed4500fab8be4bd085cd2cdd826943edcd7e58 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Link.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 29a1dbbf14559bca991613eaccd835b40cb7d6d8..8f22a9073a65ba4246a825d5c1e5e64c735f6e14 100644 (file)
@@ -2,7 +2,7 @@
 //
 // NameToCharCode.cc
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 622e7d679eb367311fe334364a670550c27fb4d6..65453c3a3eb4cc2530129c022068293e2d1739ec 100644 (file)
@@ -2,7 +2,7 @@
 //
 // NameToCharCode.h
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 99bcf1de023c5d00e7456aabc24a79436b85ea7e..4f28ffff9f78c9b8960564f2a91c944b84fe247c 100644 (file)
@@ -2,7 +2,7 @@
 //
 // NameToUnicodeTable.h
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index a1c71af0f75eb909625edbcc5c629cd4d265cd31..b0976fdea84134ede965f0ec6c456983185f3b2b 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Object.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index d8a5fb545041d9b5873f4ab6c55fa19113132875..8f0b370bc849b5d88b4de1af92041ccd685ef8ad 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Object.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 15e6a8674b5876215a4e2a2b9af02c49a95d6bbd..cbb5df5f7f6aad28c5c340d8bfeb8155f039c33a 100644 (file)
@@ -2,7 +2,7 @@
 //
 // OutputDev.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -38,7 +38,7 @@ void OutputDev::setDefaultCTM(double *ctm) {
   defICTM[5] = (defCTM[1] * defCTM[4] - defCTM[0] * defCTM[5]) * det;
 }
 
-void OutputDev::cvtDevToUser(int dx, int dy, double *ux, double *uy) {
+void OutputDev::cvtDevToUser(double dx, double dy, double *ux, double *uy) {
   *ux = defICTM[0] * dx + defICTM[2] * dy + defICTM[4];
   *uy = defICTM[1] * dx + defICTM[3] * dy + defICTM[5];
 }
index 995c7e75f68dab629ace4251df4d606f8d249aff..f050c0396dc759a40f83d506560096cb43c06801 100644 (file)
@@ -2,7 +2,7 @@
 //
 // OutputDev.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -73,7 +73,7 @@ public:
   //----- coordinate conversion
 
   // Convert between device and user coordinates.
-  virtual void cvtDevToUser(int dx, int dy, double *ux, double *uy);
+  virtual void cvtDevToUser(double dx, double dy, double *ux, double *uy);
   virtual void cvtUserToDev(double ux, double uy, int *dx, int *dy);
 
   //----- link borders
index 34432991da035d225497e79764558da0cf7622d3..dde860a1e4b80f9540ebd84d53fbdf7af7276d5d 100644 (file)
@@ -2,7 +2,7 @@
 //
 // PBMOutputDev.cc
 //
-// Copyright 1998-2002 Glyph & Cog, LLC
+// Copyright 1998-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 6926ce06939a6bd7d2d4d636ea40fb02a5dc971f..9d1539dfe69c58e11ef1e65bc4eef0895dd54c59 100644 (file)
@@ -2,7 +2,7 @@
 //
 // PBMOutputDev.h
 //
-// Copyright 1998-2002 Glyph & Cog, LLC
+// Copyright 1998-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index ff6cefafcaf45797b4ce56e97edf37d76cdff597..3df947247c9c35ba790d272dae6d47cbba6ffc79 100644 (file)
@@ -2,7 +2,7 @@
 //
 // PDFDoc.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index ff6e359ceb784f7a72d51df9645dd9707fc51c84..99832f81b6f688150c4d7b89e52341c8ea0ad4f3 100644 (file)
@@ -2,7 +2,7 @@
 //
 // PDFDoc.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 9844ab324fda9b63aabe0e1783fedaa711ce990f..7bef193e82db1581ffa804587ab41bc8e0c27941 100644 (file)
@@ -2,7 +2,7 @@
 //
 // PSOutputDev.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -18,6 +18,7 @@
 #include <signal.h>
 #include <math.h>
 #include "GString.h"
+#include "GList.h"
 #include "config.h"
 #include "GlobalParams.h"
 #include "Object.h"
@@ -100,7 +101,7 @@ static char *prolog[] = {
   "  /customcolorimage {",
   "    gsave",
   "    [ exch /Separation exch dup 4 get exch /DeviceCMYK exch",
-  "      0 4 getinterval cvx",
+  "      0 4 getinterval",
   "      [ exch /dup load exch { mul exch dup } /forall load",
   "        /pop load dup ] cvx",
   "    ] setcolorspace",
@@ -328,11 +329,15 @@ static char *prolog[] = {
   "/pdfImSep {",
   "  findcmykcustomcolor exch",
   "  dup /Width get /pdfImBuf1 exch string def",
+  "  dup /Decode get aload pop 1 index sub /pdfImDecodeRange exch def",
+  "  /pdfImDecodeLow exch def",
   "  begin Width Height BitsPerComponent ImageMatrix DataSource end",
   "  /pdfImData exch def",
   "  { pdfImData pdfImBuf1 readstring pop",
   "    0 1 2 index length 1 sub {",
-  "      1 index exch 2 copy get 255 exch sub put",
+  "      1 index exch 2 copy get",
+  "      pdfImDecodeRange mul 255 div pdfImDecodeLow add round cvi",
+  "      255 exch sub put",
   "    } for }",
   "  6 5 roll customcolorimage",
   "  { currentfile pdfImBuf readline",
@@ -503,6 +508,7 @@ PSOutputDev::PSOutputDev(char *fileName, XRef *xrefA, Catalog *catalog,
   fontFileIDs = NULL;
   fontFileNames = NULL;
   font16Enc = NULL;
+  xobjStack = NULL;
   embFontList = NULL;
   customColors = NULL;
   t3String = NULL;
@@ -547,6 +553,7 @@ PSOutputDev::PSOutputDev(PSOutputFunc outputFuncA, void *outputStreamA,
   fontFileIDs = NULL;
   fontFileNames = NULL;
   font16Enc = NULL;
+  xobjStack = NULL;
   embFontList = NULL;
   customColors = NULL;
   t3String = NULL;
@@ -577,6 +584,11 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
   mode = modeA;
   paperWidth = globalParams->getPSPaperWidth();
   paperHeight = globalParams->getPSPaperHeight();
+  if (paperWidth < 0 || paperHeight < 0) {
+    page = catalog->getPage(firstPage);
+    paperWidth = (int)(page->getWidth() + 0.5);
+    paperHeight = (int)(page->getHeight() + 0.5);
+  }
   if (mode == psModeForm) {
     lastPage = firstPage;
   }
@@ -601,6 +613,7 @@ void PSOutputDev::init(PSOutputFunc outputFuncA, void *outputStreamA,
   fontFileNames = (GString **)gmalloc(fontFileNameSize * sizeof(GString *));
   font16EncLen = 0;
   font16EncSize = 0;
+  xobjStack = new GList();
 
   // initialize embedded font resource comment list
   embFontList = new GString();
@@ -813,6 +826,9 @@ PSOutputDev::~PSOutputDev() {
     }
     gfree(font16Enc);
   }
+  if (xobjStack) {
+    delete xobjStack;
+  }
   while (customColors) {
     cc = customColors;
     customColors = cc->next;
@@ -821,8 +837,10 @@ PSOutputDev::~PSOutputDev() {
 }
 
 void PSOutputDev::setupResources(Dict *resDict) {
-  Object xObjDict, xObj, resObj;
-  int i;
+  Object xObjDict, xObjRef, xObj, resObj;
+  Ref ref0, ref1;
+  GBool skip;
+  int i, j;
 
   setupFonts(resDict);
   setupImages(resDict);
@@ -830,15 +848,40 @@ void PSOutputDev::setupResources(Dict *resDict) {
   resDict->lookup("XObject", &xObjDict);
   if (xObjDict.isDict()) {
     for (i = 0; i < xObjDict.dictGetLength(); ++i) {
-      xObjDict.dictGetVal(i, &xObj);
-      if (xObj.isStream()) {
-       xObj.streamGetDict()->lookup("Resources", &resObj);
-       if (resObj.isDict()) {
-         setupResources(resObj.getDict());
+
+      // avoid infinite recursion on XObjects
+      skip = gFalse;
+      if ((xObjDict.dictGetValNF(i, &xObjRef)->isRef())) {
+       ref0 = xObjRef.getRef();
+       for (j = 0; j < xobjStack->getLength(); ++j) {
+         ref1 = *(Ref *)xobjStack->get(j);
+         if (ref1.num == ref0.num && ref1.gen == ref0.gen) {
+           skip = gTrue;
+           break;
+         }
+       }
+       if (!skip) {
+         xobjStack->append(&ref0);
        }
-       resObj.free();
       }
-      xObj.free();
+      if (!skip) {
+
+       // process the XObject's resource dictionary
+       xObjDict.dictGetVal(i, &xObj);
+       if (xObj.isStream()) {
+         xObj.streamGetDict()->lookup("Resources", &resObj);
+         if (resObj.isDict()) {
+           setupResources(resObj.getDict());
+         }
+         resObj.free();
+       }
+       xObj.free();
+      }
+
+      if (xObjRef.isRef() && !skip) {
+       xobjStack->del(xobjStack->getLength() - 1);
+      }
+      xObjRef.free();
     }
   }
   xObjDict.free();
@@ -869,6 +912,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
   GString *psNameStr;
   char *psName;
   char type3Name[64], buf[16];
+  GBool subst;
   UnicodeMap *uMap;
   char *charName;
   double xs, ys;
@@ -894,6 +938,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
 
   xs = ys = 1;
   psNameStr = NULL;
+  subst = gFalse;
 
   // check for resident 8-bit font
   if (font->getName() &&
@@ -964,6 +1009,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
 
   // do 8-bit font substitution
   } else if (!font->isCIDFont()) {
+    subst = gTrue;
     name = font->getName();
     psName = NULL;
     if (name) {
@@ -1025,6 +1071,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
                getPSFont16(font->getName(),
                            ((GfxCIDFont *)font)->getCollection(),
                            font->getWMode()))) {
+    subst = gTrue;
     psName = fontParam->psFontName->getCString();
     if (font16EncLen >= font16EncSize) {
       font16EncSize += 16;
@@ -1069,6 +1116,7 @@ void PSOutputDev::setupFont(GfxFont *font, Dict *parentResDict) {
       writePSFmt((i == 0) ? "[ " : "  ");
       for (j = 0; j < 8; ++j) {
        if (font->getType() == fontTrueType &&
+           !subst &&
            !((Gfx8BitFont *)font)->getHasEncoding()) {
          sprintf(buf, "c%02x", i+j);
          charName = buf;
@@ -1288,7 +1336,9 @@ void PSOutputDev::setupEmbeddedType1CFont(GfxFont *font, Ref *id,
   // convert it to a Type 1 font
   fontBuf = font->readEmbFontFile(xref, &fontLen);
   t1cFile = new Type1CFontFile(fontBuf, fontLen);
-  t1cFile->convertToType1(outputFunc, outputStream);
+  if (t1cFile->isOk()) {
+    t1cFile->convertToType1(outputFunc, outputStream);
+  }
   delete t1cFile;
   gfree(fontBuf);
 
@@ -1330,6 +1380,7 @@ void PSOutputDev::setupEmbeddedTrueTypeFont(GfxFont *font, Ref *id,
   ctu = ((Gfx8BitFont *)font)->getToUnicode();
   ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(),
                          ctu, ((Gfx8BitFont *)font)->getHasEncoding(),
+                         ((Gfx8BitFont *)font)->isSymbolic(),
                          outputFunc, outputStream);
   ctu->decRefCnt();
   delete ttFile;
@@ -1375,6 +1426,7 @@ void PSOutputDev::setupExternalTrueTypeFont(GfxFont *font, char *psName) {
   ctu = ((Gfx8BitFont *)font)->getToUnicode();
   ttFile->convertToType42(psName, ((Gfx8BitFont *)font)->getEncoding(),
                          ctu, ((Gfx8BitFont *)font)->getHasEncoding(),
+                         ((Gfx8BitFont *)font)->isSymbolic(),
                          outputFunc, outputStream);
   ctu->decRefCnt();
   delete ttFile;
@@ -1414,12 +1466,14 @@ void PSOutputDev::setupEmbeddedCIDType0Font(GfxFont *font, Ref *id,
   // convert it to a Type 0 font
   fontBuf = font->readEmbFontFile(xref, &fontLen);
   t1cFile = new Type1CFontFile(fontBuf, fontLen);
-  if (globalParams->getPSLevel() >= psLevel3) {
-    // Level 3: use a CID font
-    t1cFile->convertToCIDType0(psName, outputFunc, outputStream);
-  } else {
-    // otherwise: use a non-CID composite font
-    t1cFile->convertToType0(psName, outputFunc, outputStream);
+  if (t1cFile->isOk()) {
+    if (globalParams->getPSLevel() >= psLevel3) {
+      // Level 3: use a CID font
+      t1cFile->convertToCIDType0(psName, outputFunc, outputStream);
+    } else {
+      // otherwise: use a non-CID composite font
+      t1cFile->convertToType0(psName, outputFunc, outputStream);
+    }
   }
   delete t1cFile;
   gfree(fontBuf);
@@ -3309,6 +3363,15 @@ GString *PSOutputDev::filterPSName(GString *name) {
   char c;
 
   name2 = new GString();
+
+  // ghostscript chokes on names that begin with out-of-limits
+  // numbers, e.g., 1e4foo is handled correctly (as a name), but
+  // 1e999foo generates a limitcheck error
+  c = name->getChar(0);
+  if (c >= '0' && c <= '9') {
+    name2->append('f');
+  }
+
   for (i = 0; i < name->getLength(); ++i) {
     c = name->getChar(i);
     if (c <= (char)0x20 || c >= (char)0x7f ||
index fbfc3a5c3d536ab9c0d0caca07f6117ba0fd58d4..f7896ccc73963df346f7f54310997c1e5e80f4bd 100644 (file)
@@ -2,7 +2,7 @@
 //
 // PSOutputDev.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -217,6 +217,8 @@ private:
   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
 
   double tx, ty;               // global translation
   double xScale, yScale;       // global scaling
index 570a7bac71cf42b345d8c647e090cf7e19a28fa9..a65c3241c0f04edb2ab3150ed92aa9093275f71c 100644 (file)
@@ -2,7 +2,7 @@
 //
 // PSTokenizer.cc
 //
-// Copyright 2002 Glyph & Cog, LLC
+// Copyright 2002-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index c885ae1f4f2e8ef9a3204639e3c78915cac79e82..4d5ee97f4ddd7fc1ba5c6531b5009a7be8e2e10f 100644 (file)
@@ -2,7 +2,7 @@
 //
 // PSTokenizer.h
 //
-// Copyright 2002 Glyph & Cog, LLC
+// Copyright 2002-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 72b4a8e623aa7f8be3f908f211312b5424e22746..3f6bc09a68aceb92f3b89b0afbb9162baef39d19 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Page.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 911c5b0e5eb4bdc45ada3eb11f7c053cd504ab5d..cb8706bb17e290b35cd78241d318d5a8240efc46 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Page.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 4bcb0ceb87d30f846bd842ab5a3e56537f226544..deb894aefb39591d427fb1921abaaee7fda1f871 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Parser.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 7b7a812ea2bc6ca1ee285bd24ce7839f6bae4efa..3bc3ab27408755e9f1e662d4a458ee211dc56803 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Parser.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 53214b08f2fa5769e404a28b43a6824bebd4d6f6..1f421dd4541d09ed5dd5ca146aeea2f276bf31bd 100644 (file)
@@ -2,7 +2,7 @@
 //
 // SFont.cc
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 8481ddaa0ce0490754887514a305dababe60bf62..aadf991caf53db8e1ad454636dbc5d587b2e1651 100644 (file)
@@ -4,7 +4,7 @@
 //
 // Base class for font rasterizers.
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index f5a77b0be4c27be9b1cd0711888523e7a54f0395..c4458fe714ec7c3295077206ccd77806fcfb62e6 100644 (file)
@@ -4,7 +4,7 @@
 //
 // Tables for CCITT Fax decoding.
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index b2abef8c2a10c29ae0838343f3731f3e3501c91a..11b51b60fe8626a0c0020a19ed74897c7e94cae1 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Stream.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -2141,7 +2141,7 @@ GBool DCTStream::readMCURow() {
 // Read one scan from a progressive or non-interleaved JPEG stream.
 void DCTStream::readScan() {
   int data[64];
-  int x1, y1, dy1, x2, y2, y3, cc, i;
+  int x1, y1, dx1, dy1, x2, y2, y3, cc, i;
   int h, v, horiz, vert, hSub, vSub;
   int *p1;
   int c;
@@ -2152,13 +2152,15 @@ void DCTStream::readScan() {
        break;
       }
     }
+    dx1 = mcuWidth / compInfo[cc].hSample;
     dy1 = mcuHeight / compInfo[cc].vSample;
   } else {
+    dx1 = mcuWidth;
     dy1 = mcuHeight;
   }
 
-  for (y1 = 0; y1 < bufHeight; y1 += dy1) {
-    for (x1 = 0; x1 < bufWidth; x1 += mcuWidth) {
+  for (y1 = 0; y1 < height; y1 += dy1) {
+    for (x1 = 0; x1 < width; x1 += dx1) {
 
       // deal with restart marker
       if (restartInterval > 0 && restartCtr == 0) {
@@ -2186,7 +2188,7 @@ void DCTStream::readScan() {
        hSub = horiz / 8;
        vSub = vert / 8;
        for (y2 = 0; y2 < dy1; y2 += vert) {
-         for (x2 = 0; x2 < mcuWidth; x2 += horiz) {
+         for (x2 = 0; x2 < dx1; x2 += horiz) {
 
            // pull out the current values
            p1 = &frameBuf[cc][(y1+y2) * bufWidth + (x1+x2)];
@@ -2282,8 +2284,10 @@ GBool DCTStream::readDataUnit(DCTHuffTable *dcHuffTable,
        return gFalse;
       }
       i += run;
-      j = dctZigZag[i++];
-      data[j] = amp;
+      if (i < 64) {
+       j = dctZigZag[i++];
+       data[j] = amp;
+      }
     }
   }
   return gTrue;
@@ -2369,7 +2373,7 @@ GBool DCTStream::readProgressiveDataUnit(DCTHuffTable *dcHuffTable,
       eobRun = 0;
       for (k = 0; k < j; ++k) {
        if ((bit = readBit()) == EOF) {
-         return 9999;
+         return gFalse;
        }
        eobRun = (eobRun << 1) | bit;
       }
@@ -3446,6 +3450,8 @@ GBool FlateStream::readDynamicCodes() {
   int len, repeat, code;
   int i;
 
+  codeLenCodeTab.codes = NULL;
+
   // read lengths
   if ((numLitCodes = getCodeWord(5)) == EOF) {
     goto err;
@@ -3488,23 +3494,35 @@ GBool FlateStream::readDynamicCodes() {
       if ((repeat = getCodeWord(2)) == EOF) {
        goto err;
       }
-      for (repeat += 3; repeat > 0; --repeat) {
+      repeat += 3;
+      if (i + repeat > numLitCodes + numDistCodes) {
+       goto err;
+      }
+      for (; repeat > 0; --repeat) {
        codeLengths[i++] = len;
       }
     } else if (code == 17) {
       if ((repeat = getCodeWord(3)) == EOF) {
        goto err;
       }
+      repeat += 3;
+      if (i + repeat > numLitCodes + numDistCodes) {
+       goto err;
+      }
       len = 0;
-      for (repeat += 3; repeat > 0; --repeat) {
+      for (; repeat > 0; --repeat) {
        codeLengths[i++] = 0;
       }
     } else if (code == 18) {
       if ((repeat = getCodeWord(7)) == EOF) {
        goto err;
       }
+      repeat += 11;
+      if (i + repeat > numLitCodes + numDistCodes) {
+       goto err;
+      }
       len = 0;
-      for (repeat += 11; repeat > 0; --repeat) {
+      for (; repeat > 0; --repeat) {
        codeLengths[i++] = 0;
       }
     } else {
index b0a0c26c3f44adca6c5dea7972e7434dc365f6fc..31c0a973528cb69cd1de42a07f7420477b072ff9 100644 (file)
@@ -2,7 +2,7 @@
 //
 // Stream.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 9815e490147c5278de8a9d55ee9d9964cec96f31..a03351d2355d20d20597c0f34497a5dcefcb82b0 100644 (file)
@@ -2,7 +2,7 @@
 //
 // T1Font.cc
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -301,7 +301,9 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc,
   XColor xcolor;
   int bgR, bgG, bgB;
   Gulong colors[17];
-  Guchar *p;
+  Guchar *bitmap, *p;
+  GBool tempBitmap;
+  XImage *img;
   int xOffset, yOffset, x0, y0, x1, y1, gw, gh, w0, h0;
   int xx, yy, xx1;
   Guchar pix, mPix;
@@ -310,7 +312,8 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc,
   engine = fontFile->engine;
 
   // generate the glyph pixmap
-  if (!(p = getGlyphPixmap(c, &xOffset, &yOffset, &gw, &gh))) {
+  if (!(bitmap = getGlyphPixmap(c, &xOffset, &yOffset, &gw, &gh,
+                               &tempBitmap))) {
     return gFalse;
   }
 
@@ -332,7 +335,7 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc,
     w0 = w - x0;
   }
   if (w0 < 0) {
-    return gTrue;
+    goto done;
   }
   if (y0 < 0) {
     y1 = -y0;
@@ -343,17 +346,29 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc,
     h0 = h - y0;
   }
   if (h0 < 0) {
-    return gTrue;
+    goto done;
+  }
+
+  // getGlyphPixmap may have returned a larger-than-cache-entry
+  // bitmap, in which case we need to allocate a temporary XImage here
+  if (tempBitmap) {
+    if (!(img = XCreateImage(engine->display, engine->visual, engine->depth,
+                            ZPixmap, 0, NULL, gw, gh, 8, 0))) {
+      goto done;
+    }
+    img->data = (char *)gmalloc(gh * img->bytes_per_line);
+  } else {
+    img = image;
   }
 
   // read the X image
   XGetSubImage(engine->display, d, x0, y0, w0, h0, (1 << engine->depth) - 1,
-              ZPixmap, image, x1, y1);
+              ZPixmap, img, x1, y1);
 
   if (engine->aa) {
 
     // compute the colors
-    xcolor.pixel = XGetPixel(image, x1 + w0/2, y1 + h0/2);
+    xcolor.pixel = XGetPixel(img, x1 + w0/2, y1 + h0/2);
     XQueryColor(engine->display, engine->colormap, &xcolor);
     bgR = xcolor.red;
     bgG = xcolor.green;
@@ -380,6 +395,7 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc,
     }
 
     // stuff the glyph pixmap into the X image
+    p = bitmap;
     for (yy = 0; yy < gh; ++yy) {
       for (xx = 0; xx < gw; ++xx) {
        pix = *p++;
@@ -387,7 +403,7 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc,
          if (pix > mPix) {
            pix = mPix;
          }
-         XPutPixel(image, xx, yy, colors[pix]);
+         XPutPixel(img, xx, yy, colors[pix]);
        }
       }
     }
@@ -398,12 +414,13 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc,
     colors[1] = engine->findColor(r, g, b);
 
     // stuff the glyph bitmap into the X image
+    p = bitmap;
     for (yy = 0; yy < gh; ++yy) {
       for (xx = 0; xx < gw; xx += 8) {
        pix = *p++;
        for (xx1 = xx; xx1 < xx + 8 && xx1 < gw; ++xx1) {
          if (pix & 0x01) {
-           XPutPixel(image, xx1, yy, colors[1]);
+           XPutPixel(img, xx1, yy, colors[1]);
          }
          pix >>= 1;
        }
@@ -413,12 +430,22 @@ GBool T1Font::drawChar(Drawable d, int w, int h, GC gc,
   }
 
   // draw the X image
-  XPutImage(engine->display, d, gc, image, x1, y1, x0, y0, w0, h0);
+  XPutImage(engine->display, d, gc, img, x1, y1, x0, y0, w0, h0);
 
+  if (tempBitmap) {
+    gfree(img->data);
+    img->data = NULL;
+    XDestroyImage(img);
+  }
+ done:
+  if (tempBitmap) {
+    gfree(bitmap);
+  }
   return gTrue;
 }
 
-Guchar *T1Font::getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h) {
+Guchar *T1Font::getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h,
+                              GBool *tempBitmap) {
   T1FontEngine *engine;
   GLYPH *glyph;
   int gSize;
@@ -442,6 +469,7 @@ Guchar *T1Font::getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h) {
        }
       }
       cacheTags[i+j].mru = 0x8000;
+      *tempBitmap = gFalse;
       return cache + (i+j) * glyphSize;
     }
   }
@@ -455,42 +483,45 @@ Guchar *T1Font::getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h) {
   if (!glyph) {
     return NULL;
   }
+
+  // copy the glyph into the cache or a temporary bitmap
   *x = -glyph->metrics.leftSideBearing;
   *y = glyph->metrics.ascent;
   *w = glyph->metrics.rightSideBearing - glyph->metrics.leftSideBearing;
   *h = glyph->metrics.ascent - glyph->metrics.descent;
-  if (*w > glyphW || *h > glyphH) {
-#if 1 //~ debug
-    fprintf(stderr, "Weird t1lib glyph size: %d > %d or %d > %d\n",
-           *w, glyphW, *h, glyphH);
-#endif
-    return NULL;
+  if (engine->aa) {
+    gSize = *w * *h;
+  } else {
+    gSize = ((*w + 7) >> 3) * *h;
   }
-
-  // store glyph pixmap in cache
-  ret = NULL;
-  for (j = 0; j < cacheAssoc; ++j) {
-    if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) {
-      cacheTags[i+j].mru = 0x8000;
-      cacheTags[i+j].code = c;
-      cacheTags[i+j].x = *x;
-      cacheTags[i+j].y = *y;
-      cacheTags[i+j].w = *w;
-      cacheTags[i+j].h = *h;
-      if (engine->aa) {
-       gSize = *w * *h;
-      } else {
-       gSize = ((*w + 7) >> 3) * *h;
-      }
-      ret = cache + (i+j) * glyphSize;
-      if (glyph->bits) {
-       memcpy(ret, glyph->bits, gSize);
+  if (*w > glyphW || *h > glyphH) {
+    // the glyph doesn't fit in the bounding box -- return a
+    // temporary, uncached bitmap (this shouldn't happen but some
+    // fonts have incorrect bboxes)
+    ret = (Guchar *)gmalloc(gSize);
+    *tempBitmap = gTrue;
+  } else {
+    // store glyph pixmap in cache
+    ret = NULL; // make gcc happy
+    for (j = 0; j < cacheAssoc; ++j) {
+      if ((cacheTags[i+j].mru & 0x7fff) == cacheAssoc - 1) {
+       cacheTags[i+j].mru = 0x8000;
+       cacheTags[i+j].code = c;
+       cacheTags[i+j].x = *x;
+       cacheTags[i+j].y = *y;
+       cacheTags[i+j].w = *w;
+       cacheTags[i+j].h = *h;
+       ret = cache + (i+j) * glyphSize;
       } else {
-       memset(ret, 0, gSize);
+       ++cacheTags[i+j].mru;
       }
-    } else {
-      ++cacheTags[i+j].mru;
     }
+    *tempBitmap = gFalse;
+  }
+  if (glyph->bits) {
+    memcpy(ret, glyph->bits, gSize);
+  } else {
+    memset(ret, 0, gSize);
   }
   return ret;
 }
index cfd7f620611fc6ecf0a15cbbf0bc0da5062fe54b..416f5337b0327a4c7ca83ed282624306136897f9 100644 (file)
@@ -4,7 +4,7 @@
 //
 // An X wrapper for the t1lib Type 1 font rasterizer.
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -90,7 +90,8 @@ public:
 
 private:
 
-  Guchar *getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h);
+  Guchar *getGlyphPixmap(CharCode c, int *x, int *y, int *w, int *h,
+                        GBool *tempBitmap);
 
   T1FontFile *fontFile;
   int id;
index 6107fd43aa117bc7af7fe324833eefdaab1d1969..fc6d84905ebcef49b63abd85e5aa7c5c61653d9e 100644 (file)
@@ -2,7 +2,7 @@
 //
 // TTFont.cc
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -80,7 +80,7 @@ TTFontFile::TTFontFile(TTFontEngine *engineA, char *fontFileName,
   unicodeCmap = macRomanCmap = msSymbolCmap = 0xffff;
   for (i = 0; i < props.num_CharMaps; ++i) {
     if (!TT_Get_CharMap_ID(face, i, &platform, &encoding)) {
-      if (platform == 3 && encoding == 1) {
+      if ((platform == 3 && encoding == 1) || platform == 0) {
        unicodeCmap = i;
       } else if (platform == 1 && encoding == 0) {
        macRomanCmap = i;
index 997076c2649ec3a582e76e7b5924829236685d26..96208e21b256a398e1ea1ce5d726a84bfd22e5ae 100644 (file)
@@ -4,7 +4,7 @@
 //
 // An X wrapper for the FreeType TrueType font rasterizer.
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index b782b42604d628a93fc3365559d79794e5a4c703..3fcc9ec294ecdbd1e7800c98764c0928e04ca6c8 100644 (file)
@@ -2,7 +2,7 @@
 //
 // TextOutputDev.cc
 //
-// Copyright 1997-2002 Glyph & Cog, LLC
+// Copyright 1997-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
 #include <stddef.h>
 #include <math.h>
 #include <ctype.h>
+#ifdef WIN32
+#include <fcntl.h> // for O_BINARY
+#include <io.h>    // for setmode
+#endif
 #include "gmem.h"
 #include "GString.h"
 #include "GList.h"
@@ -49,7 +53,7 @@
 // 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.2
+#define dupMaxDeltaX 0.1
 #define dupMaxDeltaY 0.2
 
 // Min overlap (as a fraction of the font size) required for two
@@ -124,14 +128,11 @@ TextFontInfo::TextFontInfo(GfxState *state) {
     horizScaling *= t1 / t2;
   }
 
-  if (!gfxFont) {
-    minSpaceWidth = horizScaling * wordDefMinSpaceWidth;
-    maxSpaceWidth = horizScaling * wordDefMaxSpaceWidth;
-  } else if (gfxFont->isCIDFont()) {
+  minSpaceWidth = horizScaling * wordDefMinSpaceWidth;
+  maxSpaceWidth = horizScaling * wordDefMaxSpaceWidth;
+  if (gfxFont && gfxFont->isCIDFont()) {
     //~ handle 16-bit fonts
-    minSpaceWidth = horizScaling * wordDefMinSpaceWidth;
-    maxSpaceWidth = horizScaling * wordDefMaxSpaceWidth;
-  } else {
+  } else if (gfxFont && gfxFont->getType() != fontType3) {
     avgWidth = 0;
     n = 0;
     for (i = 0; i < 256; ++i) {
@@ -141,9 +142,11 @@ TextFontInfo::TextFontInfo(GfxState *state) {
        ++n;
       }
     }
-    avgWidth /= n;
-    minSpaceWidth = horizScaling * wordMinSpaceWidth * avgWidth;
-    maxSpaceWidth = horizScaling * wordMaxSpaceWidth * avgWidth;
+    if (n > 0) {
+      avgWidth /= n;
+      minSpaceWidth = horizScaling * wordMinSpaceWidth * avgWidth;
+      maxSpaceWidth = horizScaling * wordMaxSpaceWidth * avgWidth;
+    }
   }
 
 }
@@ -169,11 +172,13 @@ GBool TextFontInfo::matches(GfxState *state) {
 // TextWord
 //------------------------------------------------------------------------
 
-TextWord::TextWord(GfxState *state, double x0, double y0,
+TextWord::TextWord(GfxState *state, double x0, double y0, int charPosA,
                   TextFontInfo *fontA, double fontSizeA) {
   GfxFont *gfxFont;
   double x, y;
 
+  charPos = charPosA;
+  charLen = 0;
   font = fontA;
   fontSize = fontSizeA;
   state->transform(x0, y0, &x, &y);
@@ -249,6 +254,7 @@ void TextWord::merge(TextWord *word2) {
     xRight[len + i] = word2->xRight[i];
   }
   len += word2->len;
+  charLen += word2->charLen;
 }
 
 //------------------------------------------------------------------------
@@ -299,7 +305,6 @@ GBool TextLine::yxBefore(TextLine *line2) {
 
 // Merge another line's words onto the end of this line.
 void TextLine::merge(TextLine *line2) {
-  TextWord *word;
   int newLen, i;
 
   xMax = line2->xMax;
@@ -310,9 +315,9 @@ void TextLine::merge(TextLine *line2) {
     yMax = line2->yMax;
   }
   xSpaceR = line2->xSpaceR;
-  for (word = words; word->next; word = word->next) ;
-  word->spaceAfter = gTrue;
-  word->next = line2->words;
+  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));
@@ -424,6 +429,7 @@ TextFlow::~TextFlow() {
 TextPage::TextPage(GBool rawOrderA) {
   rawOrder = rawOrderA;
   curWord = NULL;
+  charPos = 0;
   font = NULL;
   fontSize = 0;
   nest = 0;
@@ -516,7 +522,7 @@ void TextPage::beginWord(GfxState *state, double x0, double y0) {
     return;
   }
 
-  curWord = new TextWord(state, x0, y0, font, fontSize);
+  curWord = new TextWord(state, x0, y0, charPos, font, fontSize);
 }
 
 void TextPage::addChar(GfxState *state, double x, double y,
@@ -558,6 +564,8 @@ void TextPage::addChar(GfxState *state, double x, double y,
 
   // break words at space character
   if (uLen == 1 && u[0] == (Unicode)0x20) {
+    ++curWord->charLen;
+    ++charPos;
     endWord();
     return;
   }
@@ -568,11 +576,22 @@ void TextPage::addChar(GfxState *state, double x, double y,
   n = curWord->len;
   if (n > 0 && x1 - curWord->xRight[n-1] >
                     curWord->font->minSpaceWidth * curWord->fontSize) {
-    // large char spacing is sometimes used to move text around
     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) {
+    endWord();
+    beginWord(state, x + dx, y + dy);
+    x1 += w1;
+    y1 += h1;
+    w1 = -w1;
+    h1 = -h1;
+  }
+
   // add the characters to the current word
   if (uLen != 0) {
     w1 /= uLen;
@@ -581,6 +600,8 @@ void TextPage::addChar(GfxState *state, double x, double y,
   for (i = 0; i < uLen; ++i) {
     curWord->addChar(state, x1 + i*w1, y1 + i*h1, w1, h1, u[i]);
   }
+  ++curWord->charLen;
+  ++charPos;
 }
 
 void TextPage::endWord() {
@@ -635,14 +656,14 @@ void TextPage::addWord(TextWord *word) {
   wordPtr = word;
 }
 
-void TextPage::coalesce() {
-  TextWord *word0, *word1, *word2, *word3, *word4;
+void TextPage::coalesce(GBool physLayout) {
+  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, minSpace, maxSpace, yLimit;
-  double fit1, fit2;
+  double sz, xLimit, yLimit;
+  double fit1, fit2, sp1, sp2;
   GBool found;
   UnicodeMap *uMap;
   GBool isUnicode;
@@ -720,7 +741,8 @@ void TextPage::coalesce() {
              word2->xMin < xLimit &&
              word2->font == word0->font &&
              fabs(word2->fontSize - sz) < 0.05 &&
-             fabs(word2->yBase - word0->yBase) < 0.05;
+             fabs(word2->yBase - word0->yBase) < 0.05 &&
+             word2->charPos == word0->charPos + word0->charLen;
     } else {
       found = gFalse;
       for (word1 = word0, word2 = word0->next;
@@ -728,7 +750,8 @@ void TextPage::coalesce() {
           word1 = word2, word2 = word2->next) {
        if (word2->font == word0->font &&
            fabs(word2->fontSize - sz) < 0.05 &&
-           fabs(word2->yBase - word0->yBase) < 0.05) {
+           fabs(word2->yBase - word0->yBase) < 0.05 &&
+           word2->charPos == word0->charPos + word0->charLen) {
          found = gTrue;
          break;
        }
@@ -760,84 +783,83 @@ void TextPage::coalesce() {
 
   //----- assemble words into lines
 
-  uMap = globalParams->getTextEncoding();
-  isUnicode = uMap ? uMap->isUnicode() : gFalse;
-
-  lineList = NULL;
-  line0 = NULL;
+  lineList = line0 = NULL;
   while (words) {
 
-    // build a new line object
+    // remove the first word from the word list
     word0 = words;
     words = words->next;
     word0->next = NULL;
-    line1 = new TextLine();
-    line1->words = 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;
-    minSpace = line1->fontSize * word0->font->minSpaceWidth;
-    maxSpace = line1->fontSize * word0->font->maxSpaceWidth;
-
-    // find subsequent words in the line
-    while (words) {
-      xLimit = line1->xMax + maxSpace;
-      fit1 = fit2 = 0;
-      word3 = word4 = NULL;
-      if (rawOrder) {
-       if (words &&
-           words->xMin < xLimit &&
-           ((fit1 = lineFit(line1, word0, words)) >= 0)) {
-         word3 = NULL;
-         word4 = words;
-       }
+
+    // find the best line (if any) for the word
+    if (rawOrder) {
+      if (line0 && lineFit(line0, word0, &sp2) >= 0) {
+       line1 = line0;
+       sp1 = sp2;
       } else {
-       for (word1 = NULL, word2 = words;
-            word2 && word2->xMin < xLimit;
-            word1 = word2, word2 = word2->next) {
-         fit2 = lineFit(line1, word0, word2);
-         if (fit2 >= 0 && (!word4 ||
-                           (word4 && fit2 < fit1))) {
-           fit1 = fit2;
-           word3 = word1;
-           word4 = word2;
-         }
-       }
+       line1 = NULL;
+       sp1 = 0;
       }
-      if (word4) {
-       if (word3) {
-         word3->next = word4->next;
-       } else {
-         words = word4->next;
-       }
-       word0->next = word4;
-       word4->next = NULL;
-       if (word4->xMax > line1->xMax) {
-         line1->xMax = word4->xMax;
-       }
-       if (word4->yMin < line1->yMin) {
-         line1->yMin = word4->yMin;
-       }
-       if (word4->yMax > line1->yMax) {
-         line1->yMax = word4->yMax;
-       }
-       line1->len += word4->len;
-       if (fit1 > minSpace) {
-         word0->spaceAfter = gTrue;
-         ++line1->len;
+    } 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;
        }
-       word0 = word4;
+      }
+    }
+
+    // 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 {
-       break;
+       lineList = line1;
       }
+      line0 = line1;
     }
+  }
+
+  // build the line text
+  uMap = globalParams->getTextEncoding();
+  isUnicode = uMap ? uMap->isUnicode() : gFalse;
 
-    // build the line text
+  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));
@@ -871,13 +893,6 @@ void TextPage::coalesce() {
       line1->hyphenated = gTrue;
     }
 
-    // insert line on list
-    if (line0) {
-      line0->next = line1;
-    } else {
-      lineList = line1;
-    }
-    line0 = line1;
   }
 
   if (uMap) {
@@ -932,6 +947,26 @@ void TextPage::coalesce() {
     }
   }
 
+#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) {
@@ -1181,6 +1216,7 @@ void TextPage::coalesce() {
       //   +------+ +------+                 +-----------+
       //   | blk4 | | blk6 | ...             | blk4+blk6 |
       //   +------+ +------+                 +-----------+
+      yLimit = 0; // make gcc happy
       if (blkStack) {
        yLimit = blkStack->yMax + blkMaxSpacing * blkStack->lines->fontSize;
       }
@@ -1249,8 +1285,10 @@ void TextPage::coalesce() {
        blk0 = blk4;
 
        // push the block on the traversal stack
-       blk4->stackNext = blkStack;
-       blkStack = blk4;
+       if (!physLayout) {
+         blk4->stackNext = blkStack;
+         blkStack = blk4;
+       }
       }
     }
   } // (!rawOrder)
@@ -1456,18 +1494,21 @@ void TextPage::coalesce() {
 #endif
 }
 
-// Returns a non-negative number if <word> can be added to <line>
-// (whose last word is <lastWord>).  A smaller return value indicates
-// a better fit.  If <word> cannot be added to <line> at all, returns
-// a negative number.
-double TextPage::lineFit(TextLine *line, TextWord *lastWord, TextWord *word) {
+// 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 * line->font->maxSpaceWidth;
+  dxLimit = fontSize0 * lastWord->font->maxSpaceWidth;
 
   // check inter-word spacing
   if (dx < fontSize0 * lineMinDeltaX ||
@@ -1475,36 +1516,30 @@ double TextPage::lineFit(TextLine *line, TextWord *lastWord, TextWord *word) {
     return -1;
   }
 
-  // ensure a non-negative return value
-  if (dx < 0) {
-    dx = 0;
-  }
+  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 adjacent words with close baselines and close font sizes
-  if (fabs(line->yBase - word->yBase) < lineMaxBaselineDelta * fontSize0 &&
-      fontSize0 < lineMaxFontSizeRatio * fontSize1 &&
-      fontSize1 < lineMaxFontSizeRatio * fontSize0) {
-    return dx;
-  }
+      // 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 superscript
-  if (fontSize1 > lineMinSuperscriptFontSizeRatio * fontSize0 &&
-      fontSize1 < lineMaxSuperscriptFontSizeRatio * fontSize0 &&
-      (word->yMax < lastWord->yMax ||
-       word->yBase < lastWord->yBase) &&
-      word->yMax - lastWord->yMin > lineMinSuperscriptOverlap * fontSize0 &&
-      dx < fontSize0 * lineMaxSuperscriptDeltaX) {
-    return dx;
-  }
+      // 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)) {
 
-  // look for a subscript
-  if (fontSize1 > lineMinSubscriptFontSizeRatio * fontSize0 &&
-      fontSize1 < lineMaxSubscriptFontSizeRatio * fontSize0 &&
-      (word->yMin > lastWord->yMin ||
-       word->yBase > lastWord->yBase) &&
-      line->yMax - word->yMin > lineMinSubscriptOverlap * fontSize0 &&
-      dx < fontSize0 * lineMaxSubscriptDeltaX) {
-    return dx;
+    *space = dx;
+    return fabs(word->yBase - line->yBase);
   }
 
   return -1;
@@ -1737,7 +1772,7 @@ GString *TextPage::getText(double xMin, double yMin,
     }
 
     i = 0;
-    while (1) {
+    while (i < line->len) {
       x0 = (i==0) ? line->xMin : line->xRight[i-1];
       x1 = line->xRight[i];
       if (0.5 * (x0 + x1) > xMin) {
@@ -1745,6 +1780,9 @@ GString *TextPage::getText(double xMin, double yMin,
       }
       ++i;
     }
+    if (i == line->len) {
+      continue;
+    }
     col = line->col[i];
 
     if (firstCol < 0 || col < firstCol) {
@@ -1755,9 +1793,8 @@ GString *TextPage::getText(double xMin, double yMin,
   // extract the text
   col = firstCol;
   multiLine = gFalse;
-  for (prevLine = NULL, line = lines;
-       line;
-       prevLine = line, line = line->pageNext) {
+  prevLine = NULL;
+  for (line = lines; line; line = line->pageNext) {
     if (line->yMin > yMax) {
       break;
     }
@@ -1773,7 +1810,7 @@ GString *TextPage::getText(double xMin, double yMin,
     }
 
     i = 0;
-    while (1) {
+    while (i < line->len) {
       x0 = (i==0) ? line->xMin : line->xRight[i-1];
       x1 = line->xRight[i];
       if (0.5 * (x0 + x1) > xMin) {
@@ -1781,9 +1818,12 @@ GString *TextPage::getText(double xMin, double yMin,
       }
       ++i;
     }
+    if (i == line->len) {
+      continue;
+    }
 
     // insert a return
-    if (col > line->col[i] ||
+    if (line->col[i] < col ||
        (prevLine &&
         line->yMin >
           prevLine->yMax - lineOverlapSlack * prevLine->fontSize)) {
@@ -1791,6 +1831,7 @@ GString *TextPage::getText(double xMin, double yMin,
       col = firstCol;
       multiLine = gTrue;
     }
+    prevLine = line;
 
     // line this block up with the correct column
     for (; col < line->col[i]; ++col) {
@@ -1821,6 +1862,53 @@ GString *TextPage::getText(double xMin, double yMin,
   return s;
 }
 
+GBool TextPage::findCharRange(int pos, int length,
+                             double *xMin, double *yMin,
+                             double *xMax, double *yMax) {
+  TextLine *line;
+  TextWord *word;
+  double x;
+  GBool first;
+  int i;
+
+  //~ 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;
+       }
+       first = gFalse;
+      }
+    }
+  }
+  return !first;
+}
+
 void TextPage::dump(void *outputStream, TextOutputFunc outputFunc,
                    GBool physLayout) {
   UnicodeMap *uMap;
@@ -1870,7 +1958,8 @@ void TextPage::dump(void *outputStream, TextOutputFunc outputFunc,
       col += line->convertedLen;
 
       // print one or more returns if necessary
-      if (!line->pageNext ||
+      if (rawOrder ||
+         !line->pageNext ||
          line->pageNext->col[0] < col ||
          line->pageNext->yMin >
            line->yMax - lineOverlapSlack * line->fontSize) {
@@ -1927,8 +2016,12 @@ void TextPage::dump(void *outputStream, TextOutputFunc outputFunc,
 
 void TextPage::startPage(GfxState *state) {
   clear();
-  pageWidth = state->getPageWidth();
-  pageHeight = state->getPageHeight();
+  if (state) {
+    pageWidth = state->getPageWidth();
+    pageHeight = state->getPageHeight();
+  } else {
+    pageWidth = pageHeight = 0;
+  }
 }
 
 void TextPage::clear() {
@@ -1953,6 +2046,7 @@ void TextPage::clear() {
   deleteGList(fonts, TextFontInfo);
 
   curWord = NULL;
+  charPos = 0;
   font = NULL;
   fontSize = 0;
   nest = 0;
@@ -1985,6 +2079,10 @@ TextOutputDev::TextOutputDev(char *fileName, GBool physLayoutA,
   if (fileName) {
     if (!strcmp(fileName, "-")) {
       outputStream = stdout;
+#ifdef WIN32
+      // keep DOS from munging the end-of-line characters
+      setmode(fileno(stdout), O_BINARY);
+#endif
     } else if ((outputStream = fopen(fileName, append ? "ab" : "wb"))) {
       needClose = gTrue;
     } else {
@@ -2029,7 +2127,7 @@ void TextOutputDev::startPage(int pageNum, GfxState *state) {
 }
 
 void TextOutputDev::endPage() {
-  text->coalesce();
+  text->coalesce(physLayout);
   if (outputStream) {
     text->dump(outputStream, outputFunc, physLayout);
   }
@@ -2066,5 +2164,10 @@ GString *TextOutputDev::getText(double xMin, double yMin,
   return text->getText(xMin, yMin, xMax, yMax);
 }
 
+GBool TextOutputDev::findCharRange(int pos, int length,
+                                  double *xMin, double *yMin,
+                                  double *xMax, double *yMax) {
+  return text->findCharRange(pos, length, xMin, yMin, xMax, yMax);
+}
 
 
index 8e94f0404134f5e29e9257e5b10d14195a2e6c24..e0c22c2270277f2ec7020c9345f29a8e9384c64b 100644 (file)
@@ -2,7 +2,7 @@
 //
 // TextOutputDev.h
 //
-// Copyright 1997-2002 Glyph & Cog, LLC
+// Copyright 1997-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -65,7 +65,7 @@ class TextWord {
 public:
 
   // Constructor.
-  TextWord(GfxState *state, double x0, double y0,
+  TextWord(GfxState *state, double x0, double y0, int charPosA,
           TextFontInfo *fontA, double fontSize);
 
 
@@ -89,6 +89,9 @@ private:
   double *xRight;              // right-hand x coord of each char
   int len;                     // length of text and xRight
   int size;                    // size of text and xRight arrays
+  int charPos;                  // character position (within content stream)
+  int charLen;                  // number of content stream characters in
+                                //   this word
   TextFontInfo *font;          // font information
   double fontSize;             // font size
   GBool spaceAfter;            // set if there is a space between this
@@ -123,6 +126,7 @@ private:
   TextFontInfo *font;          // primary font
   double fontSize;             // primary font size
   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
@@ -222,12 +226,12 @@ public:
 
 
   // Coalesce strings that look like parts of the same line.
-  void coalesce();
+  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 rectange and
+  // <xMax>,<yMax>.  If found, sets the text bounding rectangle and
   // returns true; otherwise returns false.
   GBool findText(Unicode *s, int len,
                 GBool top, GBool bottom,
@@ -238,6 +242,13 @@ public:
   GString *getText(double xMin, double yMin,
                   double xMax, double yMax);
 
+  // Find a string by character position and length.  If found, sets
+  // the text bounding rectangle and returns true; otherwise returns
+  // false.
+  GBool findCharRange(int pos, int length,
+                     double *xMin, double *yMin,
+                     double *xMax, double *yMax);
+
   // Dump contents of page to a file.
   void dump(void *outputStream, TextOutputFunc outputFunc,
            GBool physLayout);
@@ -249,7 +260,7 @@ public:
 private:
 
   void clear();
-  double lineFit(TextLine *line, TextWord *lastWord, TextWord *word);
+  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);
@@ -259,6 +270,8 @@ private:
 
   double pageWidth, pageHeight;        // width and height of current page
   TextWord *curWord;           // currently active string
+  int charPos;                 // next character position (within content
+                               //   stream)
   TextFontInfo *font;          // current font
   double fontSize;             // current font size
   int nest;                    // current nesting level (for Type 3 fonts)
@@ -347,7 +360,7 @@ public:
   // 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 rectange and
+  // <xMax>,<yMax>.  If found, sets the text bounding rectangle and
   // returns true; otherwise returns false.
   GBool findText(Unicode *s, int len,
                 GBool top, GBool bottom,
@@ -358,6 +371,13 @@ public:
   GString *getText(double xMin, double yMin,
                   double xMax, double yMax);
 
+  // Find a string by character position and length.  If found, sets
+  // the text bounding rectangle and returns true; otherwise returns
+  // false.
+  GBool findCharRange(int pos, int length,
+                     double *xMin, double *yMin,
+                     double *xMax, double *yMax);
+
 
 private:
 
index bfa5eccb9c605224dde4fe0b02c390db8bade250..e6284eb33bd25ccca0ec7a448dc89ff6fb17f286 100644 (file)
@@ -2,7 +2,7 @@
 //
 // UnicodeMap.cc
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 60c0c279296871477c39ffab11884a7a00b1519b..24de28ce1637cc79a65227169cbe283afae35d4f 100644 (file)
@@ -4,7 +4,7 @@
 //
 // Mapping from Unicode to an encoding.
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index f9064faf88bd98378a0c45f5315f7c9c7de15cb1..2100355af0338a8194e38861452d41f8dffe1e7a 100644 (file)
@@ -2,7 +2,7 @@
 //
 // XOutputDev.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -1005,7 +1005,7 @@ XOutputFont *XOutputFontCache::tryGetFont(XRef *xref, DisplayFontParam *dfp,
       if (freetypeControl != fontRastNone) {
        font = tryGetFTFontFromFile(xref, dfp->t1.fileName, gFalse, gfxFont,
                                    m11Orig, m12Orig, m21Orig, m22Orig,
-                                   m11, m12, m21, m22, subst);
+                                   m11, m12, m21, m22, gFalse, subst);
       }
     }
 #endif
@@ -1020,7 +1020,7 @@ XOutputFont *XOutputFontCache::tryGetFont(XRef *xref, DisplayFontParam *dfp,
     if (freetypeControl != fontRastNone) {
       font = tryGetFTFontFromFile(xref, dfp->tt.fileName, gFalse, gfxFont,
                                  m11Orig, m12Orig, m21Orig, m22Orig,
-                                 m11, m12, m21, m22, subst);
+                                 m11, m12, m21, m22, gFalse, subst);
     }
 #endif
 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
@@ -1091,6 +1091,11 @@ XOutputFont *XOutputFontCache::tryGetT1Font(XRef *xref,
        return NULL;
       }
       ff = new Type1CFontFile(fontBuf, fontLen);
+      if (!ff->isOk()) {
+       delete ff;
+       gfree(fontBuf);
+       return NULL;
+      }
       ff->convertToType1(outputToFile, f);
       delete ff;
       gfree(fontBuf);
@@ -1263,7 +1268,7 @@ XOutputFont *XOutputFontCache::tryGetFTFont(XRef *xref,
     // create the Font
     font = tryGetFTFontFromFile(xref, fileName, gTrue, gfxFont,
                                m11, m12, m21, m22,
-                               m11, m12, m21, m22, gFalse);
+                               m11, m12, m21, m22, gTrue, gFalse);
 
     // on systems with Unix hard link semantics, this will remove the
     // last link to the temp file
@@ -1275,7 +1280,7 @@ XOutputFont *XOutputFontCache::tryGetFTFont(XRef *xref,
   } else if ((fileName = gfxFont->getExtFontFile())) {
     font = tryGetFTFontFromFile(xref, fileName, gFalse, gfxFont,
                                m11, m12, m21, m22,
-                               m11, m12, m21, m22, gFalse);
+                               m11, m12, m21, m22, gFalse, gFalse);
 
   } else {
     font = NULL;
@@ -1294,6 +1299,7 @@ XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref,
                                                    double m22Orig,
                                                    double m11, double m12,
                                                    double m21, double m22,
+                                                   GBool embedded,
                                                    GBool subst) {
   Ref *id;
   FTFontFile *fontFile;
@@ -1304,14 +1310,16 @@ XOutputFont *XOutputFontCache::tryGetFTFontFromFile(XRef *xref,
     if (gfxFont->getType() == fontCIDType2) {
       fontFile = new FTFontFile(ftEngine, fileName->getCString(),
                                ((GfxCIDFont *)gfxFont)->getCIDToGID(),
-                               ((GfxCIDFont *)gfxFont)->getCIDToGIDLen());
+                               ((GfxCIDFont *)gfxFont)->getCIDToGIDLen(),
+                               embedded);
     } else { // fontCIDType0, fontCIDType0C
-      fontFile = new FTFontFile(ftEngine, fileName->getCString());
+      fontFile = new FTFontFile(ftEngine, fileName->getCString(), embedded);
     }
   } else {
     fontFile = new FTFontFile(ftEngine, fileName->getCString(),
                              ((Gfx8BitFont *)gfxFont)->getEncoding(),
-                             ((Gfx8BitFont *)gfxFont)->getHasEncoding());
+                             ((Gfx8BitFont *)gfxFont)->getHasEncoding(),
+                             ((Gfx8BitFont *)gfxFont)->isSymbolic());
   }
   if (!fontFile->isOk()) {
     error(-1, "Couldn't create FreeType font from '%s'",
@@ -1769,6 +1777,7 @@ XOutputDev::XOutputDev(Display *displayA, int screenNumA,
   // set up the font cache and fonts
   gfxFont = NULL;
   font = NULL;
+  needFontUpdate = gFalse;
   fontCache = new XOutputFontCache(display, depth, this,
                                   globalParams->getT1libControl(),
                                   globalParams->getFreeTypeControl());
@@ -1850,7 +1859,7 @@ void XOutputDev::startPage(int pageNum, GfxState *state) {
 void XOutputDev::endPage() {
   XOutputState *s;
 
-  text->coalesce();
+  text->coalesce(gTrue);
 
   // clear state stack, free all GCs, free the clip region
   while (save) {
@@ -1944,8 +1953,8 @@ void XOutputDev::restoreState(GfxState *state) {
     save = save->next;
     delete s;
 
-    // restore the font
-    updateFont(state);
+    // we'll need to restore the font
+    needFontUpdate = gTrue;
   }
 }
 
@@ -1955,7 +1964,7 @@ void XOutputDev::updateAll(GfxState *state) {
   updateMiterLimit(state);
   updateFillColor(state);
   updateStrokeColor(state);
-  updateFont(state);
+  needFontUpdate = gTrue;
 }
 
 void XOutputDev::updateCTM(GfxState *state, double m11, double m12,
@@ -2063,6 +2072,8 @@ void XOutputDev::updateStrokeColor(GfxState *state) {
 void XOutputDev::updateFont(GfxState *state) {
   double m11, m12, m21, m22;
 
+  needFontUpdate = gFalse;
+
   text->updateFont(state);
 
   if (!(gfxFont = state->getFont())) {
@@ -2505,6 +2516,10 @@ void XOutputDev::drawChar(GfxState *state, double x, double y,
   double *ctm;
   double saveCTM[6];
 
+  if (needFontUpdate) {
+    updateFont(state);
+  }
+
   text->addChar(state, x, y, dx, dy, code, u, uLen);
 
   if (!font) {
@@ -2579,6 +2594,9 @@ GBool XOutputDev::beginType3Char(GfxState *state,
   double x1, y1, xMin, yMin, xMax, yMax, xt, yt;
   int i, j;
 
+  if (needFontUpdate) {
+    updateFont(state);
+  }
   if (!gfxFont) {
     return gFalse;
   }
index 149fd6e485a6a8cc97c66ed76cfc9c501163c12d..7a6544dd6fd97aa447862725407972c3b6dc13d9 100644 (file)
@@ -2,7 +2,7 @@
 //
 // XOutputDev.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -422,7 +422,8 @@ private:
                                    double m11Orig, double m12Orig,
                                    double m21Orig, double m22Orig,
                                    double m11, double m12,
-                                   double m21, double m22, GBool subst);
+                                   double m21, double m22,
+                                   GBool embedded, GBool subst);
 #endif
 #if !FREETYPE2 && (HAVE_FREETYPE_FREETYPE_H || HAVE_FREETYPE_H)
   XOutputFont *tryGetTTFont(XRef *xref, GfxFont *gfxFont,
@@ -640,6 +641,7 @@ private:
     tmpRects[numTmpSubpaths];
   GfxFont *gfxFont;            // current PDF font
   XOutputFont *font;           // current font
+  GBool needFontUpdate;                // set when the font needs to be updated
   XOutputFontCache *fontCache; // font cache
   T3FontCache *                        // Type 3 font cache
     t3FontCache[xOutT3FontCacheSize];
index 901caa596b3acd7cb9f56a28e8e4a1406664046a..56cb131c00251cd0fd5bf16379f7a2d8de4464ba 100644 (file)
@@ -2,7 +2,7 @@
 //
 // XRef.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -325,6 +325,11 @@ GBool XRef::readXRef(Guint *pos) {
   if (obj2.isInt()) {
     *pos = (Guint)obj2.getInt();
     more = gTrue;
+  } else if (obj2.isRef()) {
+    // certain buggy PDF generators generate "/Prev NNN 0 R" instead
+    // of "/Prev NNN"
+    *pos = (Guint)obj2.getRefNum();
+    more = gTrue;
   } else {
     more = gFalse;
   }
index ebe5b5434b731e07227b32cea58ee03b714aeab5..3f5a598e9bc058d57d888adb161747793ff879e7 100644 (file)
@@ -2,7 +2,7 @@
 //
 // XRef.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index fcb739a20a6320251cf6e41f18b0b2dfa89895af..f3a1b488df2be7b3c95a6e02b8a77b93e1498c42 100644 (file)
@@ -2,7 +2,7 @@
 //
 // pdffonts.cc
 //
-// Copyright 2001-2002 Glyph & Cog, LLC
+// Copyright 2001-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 5e35bfb48fad33678e6877525b1d891b53f70388..e8a42aaf342a98c17942b2b6f178cb0be2707be7 100644 (file)
@@ -2,7 +2,7 @@
 //
 // pdfimages.cc
 //
-// Copyright 1998-2002 Glyph & Cog, LLC
+// Copyright 1998-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index f1df0953dd0869eff9a8372661fb78d0bf88ca91..f856a6d41e24b728354cf903a459baf60b113495 100644 (file)
@@ -2,7 +2,7 @@
 //
 // pdfinfo.cc
 //
-// Copyright 1998-2002 Glyph & Cog, LLC
+// Copyright 1998-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -72,11 +72,12 @@ int main(int argc, char *argv[]) {
   GString *ownerPW, *userPW;
   UnicodeMap *uMap;
   Object info;
-  double w, h;
+  double w, h, wISO, hISO;
   FILE *f;
   GString *metadata;
   GBool ok;
   int exitCode;
+  int i;
 
   exitCode = 99;
 
@@ -169,9 +170,18 @@ int main(int argc, char *argv[]) {
     if ((fabs(w - 612) < 0.1 && fabs(h - 792) < 0.1) ||
        (fabs(w - 792) < 0.1 && fabs(h - 612) < 0.1)) {
       printf(" (letter)");
-    } else if ((fabs(w - 595) < 0.1 && fabs(h - 842) < 0.1) ||
-              (fabs(w - 842) < 0.1 && fabs(h - 595) < 0.1)) {
-      printf(" (A4)");
+    } else {
+      hISO = sqrt(sqrt(2)) * 7200 / 2.54;
+      wISO = hISO / sqrt(2);
+      for (i = 0; i <= 6; ++i) {
+       if ((fabs(w - wISO) < 1 && fabs(h - hISO) < 1) ||
+           (fabs(w - hISO) < 1 && fabs(h - wISO) < 1)) {
+         printf(" (A%d)", i);
+         break;
+       }
+       hISO = wISO;
+       wISO /= sqrt(2);
+      }
     }
     printf("\n");
   } 
index 76f60a6af85a747e998f29943c0f6121b6a44160..704a3d06d90f56698fa274e7951a571a982a5425 100644 (file)
@@ -2,7 +2,7 @@
 //
 // pdftopbm.cc
 //
-// Copyright 1998-2002 Glyph & Cog, LLC
+// Copyright 1998-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index d5d2de85d38fcf50255062eab3e9f2079eb42454..2bb2e3b284f0cb30b0975f928cf687a593768966 100644 (file)
@@ -2,7 +2,7 @@
 //
 // pdftops.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -89,7 +89,7 @@ static ArgDesc argDesc[] = {
   {"-noembcidtt", argFlag, &noEmbedCIDTTFonts, 0,
    "don't embed CID TrueType fonts"},
   {"-paper",  argString,   paperSize,       sizeof(paperSize),
-   "paper size (letter, legal, A4, A3)"},
+   "paper size (letter, legal, A4, A3, match)"},
   {"-paperw", argInt,      &paperWidth,     0,
    "paper width, in points"},
   {"-paperh", argInt,      &paperHeight,    0,
@@ -181,6 +181,7 @@ int main(int argc, char *argv[]) {
   if (paperSize[0]) {
     if (!globalParams->setPSPaperSize(paperSize)) {
       fprintf(stderr, "Invalid paper size\n");
+      delete fileName;
       goto err0;
     }
   } else {
@@ -295,8 +296,8 @@ int main(int argc, char *argv[]) {
   delete psFileName;
  err1:
   delete doc;
-  delete globalParams;
  err0:
+  delete globalParams;
 
   // check for memory leaks
   Object::memCheck(stderr);
index 8b13ff2513f56c9ae766898f284e60c5b91f71d0..a67f92439990d1249b35d0dff79a5cde54709bdd 100644 (file)
@@ -2,7 +2,7 @@
 //
 // pdftotext.cc
 //
-// Copyright 1997-2002 Glyph & Cog, LLC
+// Copyright 1997-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
index 35cc7c1cf63a38f7ad586e3c82df7299171dc0de..174debb304bf15124abf15bf10d44ef96979bf8f 100644 (file)
@@ -4,7 +4,7 @@ $! Xpdf compile script for VMS.
 $!
 $! Written by Patrick Moreau, Martin P.J. Zinser.
 $!
-$! Copyright 1996-2002 Glyph & Cog, LLC
+$! Copyright 1996-2003 Glyph & Cog, LLC
 $!
 $!========================================================================
 $!
@@ -27,8 +27,8 @@ $ COMMON_LIBS = "[]common.olb/lib,[-.goo]libgoo.olb/lib"
 $!
 $ XPDF_OBJS = "xpdf.obj,FTFont.obj,PSOutputDev.obj," + -
               "SFont.obj,T1Font.obj,TextOutputDev.obj,TTFont.obj," + -
-              "XOutputDev.obj,XPDFApp.o,XPDFCore.o,XPDFTree.o," + -
-              "XPDFViewer.o,XPixmapOutputDev.o"
+              "XOutputDev.obj,XPDFApp.obj,XPDFCore.obj,XPDFTree.obj," + -
+              "XPDFViewer.obj,XPixmapOutputDev.obj"
 $ XPDF_LIBS = ""
 $!
 $ PDFTOPS_OBJS   = "pdftops.obj,PSOutputDev.obj" 
index 290cfe9901fbeea96a9b32f92f108c39c62b4214..73a0fe2a4660fda1da9f83c2221f4e9f95d6430a 100644 (file)
@@ -2,7 +2,7 @@
 //
 // xpdf.cc
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
@@ -71,7 +71,7 @@ static ArgDesc argDesc[] = {
   {"-ps",         argString,      psFileArg,      sizeof(psFileArg),
    "default PostScript file name or command"},
   {"-paper",      argString,      paperSize,      sizeof(paperSize),
-   "paper size (letter, legal, A4, A3)"},
+   "paper size (letter, legal, A4, A3, match)"},
   {"-paperw",     argInt,         &paperWidth,    0,
    "paper width, in points"},
   {"-paperh",     argInt,         &paperHeight,   0,
index ef1764ab7fb725981501f9d3e3b0e5733e9a8699..eda629c72d2203acb2ef42b5ab9eb3e26a32b759 100644 (file)
@@ -2,7 +2,7 @@
 //
 // config.h
 //
-// Copyright 1996-2002 Glyph & Cog, LLC
+// Copyright 1996-2003 Glyph & Cog, LLC
 //
 //========================================================================
 
 //------------------------------------------------------------------------
 
 // xpdf version
-#define xpdfVersion         "2.01"
-#define xpdfVersionNum      2.01
+#define xpdfVersion         "2.02"
+#define xpdfVersionNum      2.02
 #define xpdfMajorVersion    2
-#define xpdfMinorVersion    1
+#define xpdfMinorVersion    2
 #define xpdfMajorVersionStr "2"
+#define xpdfMinorVersionStr "2"
 
 // supported PDF version
 #define supportedPDFVersionStr "1.4"
 #define supportedPDFVersionNum 1.4
 
 // copyright notice
-#define xpdfCopyright "Copyright 1996-2002 Glyph & Cog, LLC"
+#define xpdfCopyright "Copyright 1996-2003 Glyph & Cog, LLC"
 
 // Windows resource file stuff
-#define winxpdfVersion "WinXpdf 2.01"
-#define xpdfCopyrightAmp "Copyright 1996-2002 Glyph && Cog, LLC"
+#define winxpdfVersion "WinXpdf 2.02"
+#define xpdfCopyrightAmp "Copyright 1996-2003 Glyph && Cog, LLC"
 
 //------------------------------------------------------------------------
 // paper size