[poppler] poppler/fofi: FoFiTrueType.cc, 1.5, 1.5.4.1 FoFiTrueType.h, 1.3, 1.3.4.1 FoFiType1.cc, 1.5, 1.5.4.1 FoFiType1C.cc, 1.3, 1.3.4.1 FoFiType1C.h, 1.3, 1.3.4.1

Albert Astals Cid aacid at kemper.freedesktop.org
Fri Apr 6 07:22:25 PDT 2007


Update of /cvs/poppler/poppler/fofi
In directory kemper:/tmp/cvs-serv11025/fofi

Modified Files:
      Tag: xpdf302merge
	FoFiTrueType.cc FoFiTrueType.h FoFiType1.cc FoFiType1C.cc 
	FoFiType1C.h 
Log Message:
The big xpdf 3.02 merge, it's mostly working except
Annot has still to be merged, i'll leave that to jrebetez
DCTStream and FlateStream classes have not been tested
ArthurOutputDev had some code commented, but as it was nto working it's not crucial
UGooString got removed as i got clear it was not needed, yay!
HtmlOutputDev won't detect links as the base outputdev changed signature
Did not test CairoOutputDev but i have 0 knowledge of Cairo so i need someone here anyway
glib frontend has some nasty warnings probably due to changed signatures, have a look
And in all i'm quite happy of the merge as it renders "something" and my kpdf port all it had was crashes :D


Index: FoFiTrueType.cc
===================================================================
RCS file: /cvs/poppler/poppler/fofi/FoFiTrueType.cc,v
retrieving revision 1.5
retrieving revision 1.5.4.1
diff -u -d -r1.5 -r1.5.4.1
--- FoFiTrueType.cc	2 Feb 2006 22:50:01 -0000	1.5
+++ FoFiTrueType.cc	6 Apr 2007 14:22:22 -0000	1.5.4.1
@@ -18,6 +18,7 @@
 #include "goo/gmem.h"
 #include "goo/GooString.h"
 #include "goo/GooHash.h"
+#include "FoFiType1C.h"
 #include "FoFiTrueType.h"
 
 //
@@ -108,8 +109,11 @@
 #define cmapTag 0x636d6170
 #define glyfTag 0x676c7966
 #define headTag 0x68656164
+#define hheaTag 0x68686561
+#define hmtxTag 0x686d7478
 #define locaTag 0x6c6f6361
 #define nameTag 0x6e616d65
+#define os2Tag  0x4f532f32
 #define postTag 0x706f7374
 
 static int cmpTrueTypeLocaOffset(const void *p1, const void *p2) {
@@ -392,6 +396,28 @@
   return nameToGID->lookupInt(name);
 }
 
+Gushort *FoFiTrueType::getCIDToGIDMap(int *nCIDs) {
+  FoFiType1C *ff;
+  Gushort *map;
+  int i;
+
+  *nCIDs = 0;
+  if (!openTypeCFF) {
+    return NULL;
+  }
+  i = seekTable("CFF ");
+  if (!checkRegion(tables[i].offset, tables[i].len)) {
+    return NULL;
+  }
+  if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
+			      tables[i].len))) {
+    return NULL;
+  }
+  map = ff->getCIDToGIDMap(nCIDs);
+  delete ff;
+  return map;
+}
+
 int FoFiTrueType::getEmbeddingRights() {
   int i, fsType;
   GBool ok;
@@ -420,13 +446,19 @@
 				   Gushort *codeToGID,
 				   FoFiOutputFunc outputFunc,
 				   void *outputStream) {
-  char buf[512];
+  GooString *buf;
   GBool ok;
 
+  if (openTypeCFF) {
+    return;
+  }
+
   // write the header
   ok = gTrue;
-  sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0);
-  (*outputFunc)(outputStream, buf, strlen(buf));
+  buf = GooString::format("%!PS-TrueTypeFont-{0:2g}\n",
+			(double)getS32BE(0, &ok) / 65536.0);
+  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+  delete buf;
 
   // begin the font dictionary
   (*outputFunc)(outputStream, "10 dict begin\n", 14);
@@ -435,9 +467,10 @@
   (*outputFunc)(outputStream, " def\n", 5);
   (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
   (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
-  sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
-	  bbox[0], bbox[1], bbox[2], bbox[3]);
-  (*outputFunc)(outputStream, buf, strlen(buf));
+  buf = GooString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
+			bbox[0], bbox[1], bbox[2], bbox[3]);
+  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+  delete buf;
   (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
 
   // write the guts of the dictionary
@@ -449,20 +482,47 @@
   (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
 }
 
+void FoFiTrueType::convertToType1(char *psName, char **newEncoding,
+				  GBool ascii, FoFiOutputFunc outputFunc,
+				  void *outputStream) {
+  FoFiType1C *ff;
+  int i;
+
+  if (!openTypeCFF) {
+    return;
+  }
+  i = seekTable("CFF ");
+  if (!checkRegion(tables[i].offset, tables[i].len)) {
+    return;
+  }
+  if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
+			      tables[i].len))) {
+    return;
+  }
+  ff->convertToType1(psName, newEncoding, ascii, outputFunc, outputStream);
+  delete ff;
+}
+
 void FoFiTrueType::convertToCIDType2(char *psName,
 				     Gushort *cidMap, int nCIDs,
 				     GBool needVerticalMetrics,
 				     FoFiOutputFunc outputFunc,
 				     void *outputStream) {
-  char buf[512];
+  GooString *buf;
   Gushort cid;
   GBool ok;
   int i, j, k;
 
+  if (openTypeCFF) {
+    return;
+  }
+
   // write the header
   ok = gTrue;
-  sprintf(buf, "%%!PS-TrueTypeFont-%g\n", (double)getS32BE(0, &ok) / 65536.0);
-  (*outputFunc)(outputStream, buf, strlen(buf));
+  buf = GooString::format("%!PS-TrueTypeFont-{0:2g}\n",
+			(double)getS32BE(0, &ok) / 65536.0);
+  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+  delete buf;
 
   // begin the font dictionary
   (*outputFunc)(outputStream, "20 dict begin\n", 14);
@@ -478,8 +538,9 @@
   (*outputFunc)(outputStream, "  end def\n", 10);
   (*outputFunc)(outputStream, "/GDBytes 2 def\n", 15);
   if (cidMap) {
-    sprintf(buf, "/CIDCount %d def\n", nCIDs);
-    (*outputFunc)(outputStream, buf, strlen(buf));
+    buf = GooString::format("/CIDCount {0:d} def\n", nCIDs);
+    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+    delete buf;
     if (nCIDs > 32767) {
       (*outputFunc)(outputStream, "/CIDMap [", 9);
       for (i = 0; i < nCIDs; i += 32768 - 16) {
@@ -488,8 +549,10 @@
 	  (*outputFunc)(outputStream, "  ", 2);
 	  for (k = 0; k < 16 && i+j+k < nCIDs; ++k) {
 	    cid = cidMap[i+j+k];
-	    sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
-	    (*outputFunc)(outputStream, buf, strlen(buf));
+	    buf = GooString::format("{0:02x}{1:02x}",
+				  (cid >> 8) & 0xff, cid & 0xff);
+	    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+	    delete buf;
 	  }
 	  (*outputFunc)(outputStream, "\n", 1);
 	}
@@ -503,8 +566,10 @@
 	(*outputFunc)(outputStream, "  ", 2);
 	for (j = 0; j < 16 && i+j < nCIDs; ++j) {
 	  cid = cidMap[i+j];
-	  sprintf(buf, "%02x%02x", (cid >> 8) & 0xff, cid & 0xff);
-	  (*outputFunc)(outputStream, buf, strlen(buf));
+	  buf = GooString::format("{0:02x}{1:02x}",
+				(cid >> 8) & 0xff, cid & 0xff);
+	  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+	  delete buf;
 	}
 	(*outputFunc)(outputStream, "\n", 1);
       }
@@ -512,27 +577,34 @@
     }
   } else {
     // direct mapping - just fill the string(s) with s[i]=i
-    sprintf(buf, "/CIDCount %d def\n", nGlyphs);
-    (*outputFunc)(outputStream, buf, strlen(buf));
+    buf = GooString::format("/CIDCount {0:d} def\n", nGlyphs);
+    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+    delete buf;
     if (nGlyphs > 32767) {
       (*outputFunc)(outputStream, "/CIDMap [\n", 10);
       for (i = 0; i < nGlyphs; i += 32767) {
 	j = nGlyphs - i < 32767 ? nGlyphs - i : 32767;
-	sprintf(buf, "  %d string 0 1 %d {\n", 2 * j, j - 1);
-	(*outputFunc)(outputStream, buf, strlen(buf));
-	sprintf(buf, "    2 copy dup 2 mul exch %d add -8 bitshift put\n", i);
-	(*outputFunc)(outputStream, buf, strlen(buf));
-	sprintf(buf, "    1 index exch dup 2 mul 1 add exch %d add"
-		" 255 and put\n", i);
-	(*outputFunc)(outputStream, buf, strlen(buf));
+	buf = GooString::format("  {0:d} string 0 1 {1:d} {{\n", 2 * j, j - 1);
+	(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+	delete buf;
+	buf = GooString::format("    2 copy dup 2 mul exch {0:d} add -8 bitshift put\n",
+			      i);
+	(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+	delete buf;
+	buf = GooString::format("    1 index exch dup 2 mul 1 add exch {0:d} add"
+			      " 255 and put\n", i);
+	(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+	delete buf;
 	(*outputFunc)(outputStream, "  } for\n", 8);
       }
       (*outputFunc)(outputStream, "] def\n", 6);
     } else {
-      sprintf(buf, "/CIDMap %d string\n", 2 * nGlyphs);
-      (*outputFunc)(outputStream, buf, strlen(buf));
-      sprintf(buf, "  0 1 %d {\n", nGlyphs - 1);
-      (*outputFunc)(outputStream, buf, strlen(buf));
+      buf = GooString::format("/CIDMap {0:d} string\n", 2 * nGlyphs);
+      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+      delete buf;
+      buf = GooString::format("  0 1 {0:d} {{\n", nGlyphs - 1);
+      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+      delete buf;
       (*outputFunc)(outputStream,
 		    "    2 copy dup 2 mul exch -8 bitshift put\n", 42);
       (*outputFunc)(outputStream,
@@ -542,9 +614,10 @@
     }
   }
   (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
-  sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
-	  bbox[0], bbox[1], bbox[2], bbox[3]);
-  (*outputFunc)(outputStream, buf, strlen(buf));
+  buf = GooString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
+			bbox[0], bbox[1], bbox[2], bbox[3]);
+  (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+  delete buf;
   (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
   (*outputFunc)(outputStream, "/Encoding [] readonly def\n", 26);
   (*outputFunc)(outputStream, "/CharStrings 1 dict dup begin\n", 30);
@@ -560,14 +633,39 @@
 		56);
 }
 
+void FoFiTrueType::convertToCIDType0(char *psName,
+				     FoFiOutputFunc outputFunc,
+				     void *outputStream) {
+  FoFiType1C *ff;
+  int i;
+
+  if (!openTypeCFF) {
+    return;
+  }
+  i = seekTable("CFF ");
+  if (!checkRegion(tables[i].offset, tables[i].len)) {
+    return;
+  }
+  if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
+			      tables[i].len))) {
+    return;
+  }
+  ff->convertToCIDType0(psName, outputFunc, outputStream);
+  delete ff;
+}
+
 void FoFiTrueType::convertToType0(char *psName, Gushort *cidMap, int nCIDs,
 				  GBool needVerticalMetrics,
 				  FoFiOutputFunc outputFunc,
 				  void *outputStream) {
-  char buf[512];
+  GooString *buf;
   GooString *sfntsName;
   int n, i, j;
 
+  if (openTypeCFF) {
+    return;
+  }
+
   // write the Type 42 sfnts array
   sfntsName = (new GooString(psName))->append("_sfnts");
   cvtSfnts(outputFunc, outputStream, sfntsName, needVerticalMetrics);
@@ -579,28 +677,33 @@
     (*outputFunc)(outputStream, "10 dict begin\n", 14);
     (*outputFunc)(outputStream, "/FontName /", 11);
     (*outputFunc)(outputStream, psName, strlen(psName));
-    sprintf(buf, "_%02x def\n", i >> 8);
-    (*outputFunc)(outputStream, buf, strlen(buf));
+    buf = GooString::format("_{0:02x} def\n", i >> 8);
+    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+    delete buf;
     (*outputFunc)(outputStream, "/FontType 42 def\n", 17);
     (*outputFunc)(outputStream, "/FontMatrix [1 0 0 1 0 0] def\n", 30);
-    sprintf(buf, "/FontBBox [%d %d %d %d] def\n",
-	    bbox[0], bbox[1], bbox[2], bbox[3]);
-    (*outputFunc)(outputStream, buf, strlen(buf));
+    buf = GooString::format("/FontBBox [{0:d} {1:d} {2:d} {3:d}] def\n",
+			  bbox[0], bbox[1], bbox[2], bbox[3]);
+    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+    delete buf;
     (*outputFunc)(outputStream, "/PaintType 0 def\n", 17);
     (*outputFunc)(outputStream, "/sfnts ", 7);
     (*outputFunc)(outputStream, psName, strlen(psName));
     (*outputFunc)(outputStream, "_sfnts def\n", 11);
     (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
     for (j = 0; j < 256 && i+j < n; ++j) {
-      sprintf(buf, "dup %d /c%02x put\n", j, j);
-      (*outputFunc)(outputStream, buf, strlen(buf));
+      buf = GooString::format("dup {0:d} /c{1:02x} put\n", j, j);
+      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+      delete buf;
     }
     (*outputFunc)(outputStream, "readonly def\n", 13);
     (*outputFunc)(outputStream, "/CharStrings 257 dict dup begin\n", 32);
     (*outputFunc)(outputStream, "/.notdef 0 def\n", 15);
     for (j = 0; j < 256 && i+j < n; ++j) {
-      sprintf(buf, "/c%02x %d def\n", j, cidMap ? cidMap[i+j] : i+j);
-      (*outputFunc)(outputStream, buf, strlen(buf));
+      buf = GooString::format("/c{0:02x} {1:d} def\n",
+			    j, cidMap ? cidMap[i+j] : i+j);
+      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+      delete buf;
     }
     (*outputFunc)(outputStream, "end readonly def\n", 17);
     (*outputFunc)(outputStream,
@@ -617,21 +720,44 @@
   (*outputFunc)(outputStream, "/FMapType 2 def\n", 16);
   (*outputFunc)(outputStream, "/Encoding [\n", 12);
   for (i = 0; i < n; i += 256) {
-    sprintf(buf, "%d\n", i >> 8);
-    (*outputFunc)(outputStream, buf, strlen(buf));
+    buf = GooString::format("{0:d}\n", i >> 8);
+    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+    delete buf;
   }
   (*outputFunc)(outputStream, "] def\n", 6);
   (*outputFunc)(outputStream, "/FDepVector [\n", 14);
   for (i = 0; i < n; i += 256) {
     (*outputFunc)(outputStream, "/", 1);
     (*outputFunc)(outputStream, psName, strlen(psName));
-    sprintf(buf, "_%02x findfont\n", i >> 8);
-    (*outputFunc)(outputStream, buf, strlen(buf));
+    buf = GooString::format("_{0:02x} findfont\n", i >> 8);
+    (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+    delete buf;
   }
   (*outputFunc)(outputStream, "] def\n", 6);
   (*outputFunc)(outputStream, "FontName currentdict end definefont pop\n", 40);
 }
 
+void FoFiTrueType::convertToType0(char *psName,
+				  FoFiOutputFunc outputFunc,
+				  void *outputStream) {
+  FoFiType1C *ff;
+  int i;
+
+  if (!openTypeCFF) {
+    return;
+  }
+  i = seekTable("CFF ");
+  if (!checkRegion(tables[i].offset, tables[i].len)) {
+    return;
+  }
+  if (!(ff = FoFiType1C::make((char *)file + tables[i].offset,
+			      tables[i].len))) {
+    return;
+  }
+  ff->convertToType0(psName, outputFunc, outputStream);
+  delete ff;
+}
+
 void FoFiTrueType::writeTTF(FoFiOutputFunc outputFunc,
 			    void *outputStream, char *name,
 			    Gushort *codeToGID) {
@@ -673,12 +799,50 @@
     0, 0, 0, 0,			// min Type 1 memory
     0, 0, 0, 0			// max Type 1 memory
   };
-  GBool missingCmap, missingName, missingPost, unsortedLoca, badCmapLen;
+  static char os2Tab[86] = {
+    0, 1,			// version
+    0, 1,			// xAvgCharWidth
+    0, 0,			// usWeightClass
+    0, 0,			// usWidthClass
+    0, 0,			// fsType
+    0, 0,			// ySubscriptXSize
+    0, 0,			// ySubscriptYSize
+    0, 0,			// ySubscriptXOffset
+    0, 0,			// ySubscriptYOffset
+    0, 0,			// ySuperscriptXSize
+    0, 0,			// ySuperscriptYSize
+    0, 0,			// ySuperscriptXOffset
+    0, 0,			// ySuperscriptYOffset
+    0, 0,			// yStrikeoutSize
+    0, 0,			// yStrikeoutPosition
+    0, 0,			// sFamilyClass
+    0, 0, 0, 0, 0,		// panose
+    0, 0, 0, 0, 0,
+    0, 0, 0, 0,			// ulUnicodeRange1
+    0, 0, 0, 0,			// ulUnicodeRange2
+    0, 0, 0, 0,			// ulUnicodeRange3
+    0, 0, 0, 0,			// ulUnicodeRange4
+    0, 0, 0, 0,			// achVendID
+    0, 0,			// fsSelection
+    0, 0,			// usFirstCharIndex
+    0, 0,			// usLastCharIndex
+    0, 0,			// sTypoAscender
+    0, 0,			// sTypoDescender
+    0, 0,			// sTypoLineGap
+    0, 0,			// usWinAscent
+    0, 0,			// usWinDescent
+    0, 0, 0, 0,			// ulCodePageRange1
+    0, 0, 0, 0			// ulCodePageRange2
+  };
+  GBool missingCmap, missingName, missingPost, missingOS2;
+  GBool unsortedLoca, badCmapLen, abbrevHMTX;
   int nZeroLengthTables;
+  int nHMetrics, advWidth, lsb;
   TrueTypeLoca *locaTable;
   TrueTypeTable *newTables;
-  char *newNameTab, *newCmapTab;
+  char *newNameTab, *newCmapTab, *newHHEATab, *newHMTXTab;
   int nNewTables, cmapIdx, cmapLen, glyfLen, newNameLen, newCmapLen, next;
+  int newHHEALen, newHMTXLen;
   Guint locaChecksum, glyfChecksum, fileChecksum;
   char *tableDir;
   char locaBuf[4], checksumBuf[4];
@@ -686,10 +850,20 @@
   Guint t;
   int pos, i, j, k, n;
 
+  if (openTypeCFF) {
+    return;
+  }
+
   // check for missing tables
+  // (Note: if the OS/2 table is missing, the Microsoft PCL5 driver
+  // will embed a PCL TrueType font with the pitch field set to zero,
+  // which apparently causes divide-by-zero errors.  As far as I can
+  // tell, the only important field in the OS/2 table is
+  // xAvgCharWidth.)
   missingCmap = (cmapIdx = seekTable("cmap")) < 0;
   missingName = seekTable("name") < 0;
   missingPost = seekTable("post") < 0;
+  missingOS2 = seekTable("OS/2") < 0;
 
   // read the loca table, check to see if it's sorted
   locaTable = (TrueTypeLoca *)gmallocn(nGlyphs + 1, sizeof(TrueTypeLoca));
@@ -706,6 +880,19 @@
     if (i > 0 && locaTable[i].origOffset < locaTable[i-1].origOffset) {
       unsortedLoca = gTrue;
     }
+    // glyph descriptions must be at least 12 bytes long (nContours,
+    // xMin, yMin, xMax, yMax, instructionLength - two bytes each);
+    // invalid glyph descriptions (even if they're never used) make
+    // Windows choke, so we work around that problem here (ideally,
+    // this would parse the glyph descriptions in the glyf table and
+    // remove any that were invalid, but this quick test is a decent
+    // start)
+    if (i > 0 &&
+	locaTable[i].origOffset - locaTable[i-1].origOffset > 0 &&
+	locaTable[i].origOffset - locaTable[i-1].origOffset < 12) {
+      locaTable[i-1].origOffset = locaTable[i].origOffset;
+      unsortedLoca = gTrue;
+    }
     locaTable[i].idx = i;
   }
 
@@ -733,9 +920,17 @@
     }
   }
 
+  // check for an abbreviated hmtx table (this is completely legal,
+  // but confuses the Microsoft PCL5 printer driver, which generates
+  // embedded fonts with the pitch field set to zero)
+  i = seekTable("hhea");
+  nHMetrics = getU16BE(tables[i].offset + 34, &ok);
+  abbrevHMTX = nHMetrics < nGlyphs;
+
   // if nothing is broken, just write the TTF file as is
-  if (!missingCmap && !missingName && !missingPost && !unsortedLoca &&
-      !badCmapLen && nZeroLengthTables == 0 && !name && !codeToGID) {
+  if (!missingCmap && !missingName && !missingPost && !missingOS2 &&
+      !unsortedLoca && !badCmapLen && !abbrevHMTX && nZeroLengthTables == 0 &&
+      !name && !codeToGID) {
     (*outputFunc)(outputStream, (char *)file, len);
     goto done1;
   }
@@ -893,6 +1088,44 @@
     newCmapTab = NULL;
   }
 
+  // generate the new hmtx table and the updated hhea table
+  if (abbrevHMTX) {
+    i = seekTable("hhea");
+    pos = tables[i].offset;
+    newHHEALen = 36;
+    newHHEATab = (char *)gmalloc(newHHEALen);
+    for (i = 0; i < newHHEALen; ++i) {
+      newHHEATab[i] = getU8(pos++, &ok);
+    }
+    newHHEATab[34] = nGlyphs >> 8;
+    newHHEATab[35] = nGlyphs & 0xff;
+    i = seekTable("hmtx");
+    pos = tables[i].offset;
+    newHMTXLen = 4 * nGlyphs;
+    newHMTXTab = (char *)gmalloc(newHMTXLen);
+    advWidth = 0;
+    for (i = 0; i < nHMetrics; ++i) {
+      advWidth = getU16BE(pos, &ok);
+      lsb = getU16BE(pos + 2, &ok);
+      pos += 4;
+      newHMTXTab[4*i    ] = advWidth >> 8;
+      newHMTXTab[4*i + 1] = advWidth & 0xff;
+      newHMTXTab[4*i + 2] = lsb >> 8;
+      newHMTXTab[4*i + 3] = lsb & 0xff;
+    }
+    for (; i < nGlyphs; ++i) {
+      lsb = getU16BE(pos, &ok);
+      pos += 2;
+      newHMTXTab[4*i    ] = advWidth >> 8;
+      newHMTXTab[4*i + 1] = advWidth & 0xff;
+      newHMTXTab[4*i + 2] = lsb >> 8;
+      newHMTXTab[4*i + 3] = lsb & 0xff;
+    }
+  } else {
+    newHHEATab = newHMTXTab = NULL;
+    newHHEALen = newHMTXLen = 0; // make gcc happy
+  }
+
   // construct the new table directory:
   // - keep all original tables with non-zero length
   // - fix the cmap table's length, if necessary
@@ -902,7 +1135,7 @@
   // - (re)compute table checksums
   nNewTables = nTables - nZeroLengthTables +
                (missingCmap ? 1 : 0) + (missingName ? 1 : 0) +
-               (missingPost ? 1 : 0);
+               (missingPost ? 1 : 0) + (missingOS2 ? 1 : 0);
   newTables = (TrueTypeTable *)gmallocn(nNewTables, sizeof(TrueTypeTable));
   j = 0;
   for (i = 0; i < nTables; ++i) {
@@ -933,6 +1166,14 @@
 	newTables[j].len = newNameLen;
 	newTables[j].checksum = computeTableChecksum((Guchar *)newNameTab,
 						     newNameLen);
+      } else if (newTables[j].tag == hheaTag && abbrevHMTX) {
+	newTables[j].len = newHHEALen;
+	newTables[j].checksum = computeTableChecksum((Guchar *)newHHEATab,
+						     newHHEALen);
+      } else if (newTables[j].tag == hmtxTag && abbrevHMTX) {
+	newTables[j].len = newHMTXLen;
+	newTables[j].checksum = computeTableChecksum((Guchar *)newHMTXTab,
+						     newHMTXLen);
       }
       ++j;
     }
@@ -970,6 +1211,13 @@
     newTables[j].len = sizeof(postTab);
     ++j;
   }
+  if (missingOS2) {
+    newTables[j].tag = os2Tag;
+    newTables[j].checksum = computeTableChecksum((Guchar *)os2Tab,
+						 sizeof(os2Tab));
+    newTables[j].len = sizeof(os2Tab);
+    ++j;
+  }
   qsort(newTables, nNewTables, sizeof(TrueTypeTable),
 	&cmpTrueTypeTableTag);
   pos = 12 + nNewTables * 16;
@@ -1056,6 +1304,12 @@
       (*outputFunc)(outputStream, nameTab, newTables[i].len);
     } else if (newTables[i].tag == postTag && missingPost) {
       (*outputFunc)(outputStream, postTab, newTables[i].len);
+    } else if (newTables[i].tag == os2Tag && missingOS2) {
+      (*outputFunc)(outputStream, os2Tab, newTables[i].len);
+    } else if (newTables[i].tag == hheaTag && abbrevHMTX) {
+      (*outputFunc)(outputStream, newHHEATab, newTables[i].len);
+    } else if (newTables[i].tag == hmtxTag && abbrevHMTX) {
+      (*outputFunc)(outputStream, newHMTXTab, newTables[i].len);
     } else if (newTables[i].tag == locaTag && unsortedLoca) {
       for (j = 0; j <= nGlyphs; ++j) {
 	if (locaFmt) {
@@ -1103,6 +1357,8 @@
     }
   }
 
+  gfree(newHMTXTab);
+  gfree(newHHEATab);
   gfree(newCmapTab);
   gfree(newNameTab);
   gfree(tableDir);
@@ -1115,7 +1371,7 @@
 			       FoFiOutputFunc outputFunc,
 			       void *outputStream) {
   char *name;
-  char buf[64];
+  GooString *buf;
   int i;
 
   (*outputFunc)(outputStream, "/Encoding 256 array\n", 20);
@@ -1124,15 +1380,17 @@
       if (!(name = encoding[i])) {
 	name = ".notdef";
       }
-      sprintf(buf, "dup %d /", i);
-      (*outputFunc)(outputStream, buf, strlen(buf));
+      buf = GooString::format("dup {0:d} /", i);
+      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+      delete buf;
       (*outputFunc)(outputStream, name, strlen(name));
       (*outputFunc)(outputStream, " put\n", 5);
     }
   } else {
     for (i = 0; i < 256; ++i) {
-      sprintf(buf, "dup %d /c%02x put\n", i, i);
-      (*outputFunc)(outputStream, buf, strlen(buf));
+      buf = GooString::format("dup {0:d} /c{1:02x} put\n", i, i);
+      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+      delete buf;
     }
   }
   (*outputFunc)(outputStream, "readonly def\n", 13);
@@ -1143,7 +1401,8 @@
 				  FoFiOutputFunc outputFunc,
 				  void *outputStream) {
   char *name;
-  char buf[64], buf2[16];
+  GooString *buf;
+  char buf2[16];
   int i, k;
 
   // always define '.notdef'
@@ -1178,8 +1437,9 @@
       if (k > 0 && k < nGlyphs) {
 	(*outputFunc)(outputStream, "/", 1);
 	(*outputFunc)(outputStream, name, strlen(name));
-	sprintf(buf, " %d def\n", k);
-	(*outputFunc)(outputStream, buf, strlen(buf));
+	buf = GooString::format(" {0:d} def\n", k);
+	(*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+	delete buf;
       }
     }
   }
@@ -1482,14 +1742,15 @@
 void FoFiTrueType::dumpString(Guchar *s, int length,
 			      FoFiOutputFunc outputFunc,
 			      void *outputStream) {
-  char buf[64];
+  GooString *buf;
   int pad, i, j;
 
   (*outputFunc)(outputStream, "<", 1);
   for (i = 0; i < length; i += 32) {
     for (j = 0; j < 32 && i+j < length; ++j) {
-      sprintf(buf, "%02X", s[i+j] & 0xff);
-      (*outputFunc)(outputStream, buf, strlen(buf));
+      buf = GooString::format("{0:02x}", s[i+j] & 0xff);
+      (*outputFunc)(outputStream, buf->getCString(), buf->getLength());
+      delete buf;
     }
     if (i % (65536 - 32) == 65536 - 64) {
       (*outputFunc)(outputStream, ">\n<", 3);
@@ -1536,12 +1797,9 @@
   return checksum;
 }
 
-#define toTag(a,b,c,d) (((unsigned int)(a)<<24) | ((unsigned int)(b)<<16) | ((unsigned int)(c)<<8) | (d))
-
 void FoFiTrueType::parse() {
   Guint topTag;
-  int pos, i, j;
-  unsigned int head;
+  int pos, ver, i, j;
 
   parsedOk = gTrue;
 
@@ -1551,21 +1809,7 @@
     return;
   }
   if (topTag == ttcfTag) {
-    pos = getU32BE(12, &parsedOk);
-    if (!parsedOk) {
-      return;
-    }
-  } else {
-    pos = 0;
-  }
-
-  // read the table directory
-  head = getU32BE(pos, &parsedOk);
-  if (! parsedOk)
-    return;
-  if (head == toTag('t','t','c','f')) {
     /* TTC font */
-    unsigned int tableDir;
     int dircount;
 
     dircount = getU32BE(8, &parsedOk);
@@ -1581,16 +1825,24 @@
     pos = getU32BE(12 + faceIndex * 4, &parsedOk);
     if (! parsedOk)
       return;
+  } else {
+    pos = 0;
   }
 
-  pos += 4;
-  nTables = getU16BE(pos, &parsedOk);
+  // check the sfnt version
+  ver = getU32BE(pos, &parsedOk);
   if (!parsedOk) {
     return;
   }
+  openTypeCFF = ver == 0x4f54544f; // 'OTTO'
 
-  pos += 8;
+  // read the table directory
+  nTables = getU16BE(pos + 4, &parsedOk);
+  if (!parsedOk) {
+    return;
+  }
   tables = (TrueTypeTable *)gmallocn(nTables, sizeof(TrueTypeTable));
+  pos += 12;
   for (i = 0; i < nTables; ++i) {
     tables[i].tag = getU32BE(pos, &parsedOk);
     tables[i].checksum = getU32BE(pos + 4, &parsedOk);
@@ -1610,10 +1862,11 @@
   // the Type 42 spec
   if (seekTable("head") < 0 ||
       seekTable("hhea") < 0 ||
-      seekTable("loca") < 0 ||
       seekTable("maxp") < 0 ||
-      seekTable("glyf") < 0 ||
-      seekTable("hmtx") < 0) {
+      seekTable("hmtx") < 0 ||
+      (!openTypeCFF && seekTable("loca") < 0) ||
+      (!openTypeCFF && seekTable("glyf") < 0) ||
+      (openTypeCFF && seekTable("CFF ") < 0)) {
     parsedOk = gFalse;
     return;
   }
@@ -1662,23 +1915,28 @@
 
   // make sure the loca table is sane (correct length and entries are
   // in bounds)
-  i = seekTable("loca");
-  if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) {
-    parsedOk = gFalse;
-    return;
-  }
-  for (j = 0; j <= nGlyphs; ++j) {
-    if (locaFmt) {
-      pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk);
-    } else {
-      pos = getU16BE(tables[i].offset + j*2, &parsedOk);
-    }
-    if (pos < 0 || pos > len) {
+  if (!openTypeCFF) {
+    i = seekTable("loca");
+    if (tables[i].len < 0) {
       parsedOk = gFalse;
+      return;
+    }
+    if (tables[i].len < (nGlyphs + 1) * (locaFmt ? 4 : 2)) {
+      nGlyphs = tables[i].len / (locaFmt ? 4 : 2) - 1;
+    }
+    for (j = 0; j <= nGlyphs; ++j) {
+      if (locaFmt) {
+	pos = (int)getU32BE(tables[i].offset + j*4, &parsedOk);
+      } else {
+	pos = getU16BE(tables[i].offset + j*2, &parsedOk);
+      }
+      if (pos < 0 || pos > len) {
+	parsedOk = gFalse;
+      }
+    }
+    if (!parsedOk) {
+      return;
     }
-  }
-  if (!parsedOk) {
-    return;
   }
 
   // read the post table

Index: FoFiTrueType.h
===================================================================
RCS file: /cvs/poppler/poppler/fofi/FoFiTrueType.h,v
retrieving revision 1.3
retrieving revision 1.3.4.1
diff -u -d -r1.3 -r1.3.4.1
--- FoFiTrueType.h	2 Feb 2006 22:50:01 -0000	1.3
+++ FoFiTrueType.h	6 Apr 2007 14:22:23 -0000	1.3.4.1
@@ -34,9 +34,12 @@
   // Create a FoFiTrueType object from a file on disk.
   static FoFiTrueType *load(char *fileName, int faceIndexA=0);
 
-  FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA=0);
   virtual ~FoFiTrueType();
 
+  // Returns true if this an OpenType font containing CFF data, false
+  // if it's a TrueType font (or OpenType font with TrueType data).
+  GBool isOpenTypeCFF() { return openTypeCFF; }
+
   // Return the number of cmaps defined by this font.
   int getNumCmaps();
 
@@ -58,6 +61,11 @@
   // font does not have a post table.
   int mapNameToGID(char *name);
 
+  // Return the mapping from CIDs to GIDs, and return the number of
+  // CIDs in *<nCIDs>.  This is only useful for CID fonts.  (Only
+  // useful for OpenType CFF fonts.)
+  Gushort *getCIDToGIDMap(int *nCIDs);
+
   // Returns the least restrictive embedding licensing right (as
   // defined by the TrueType spec):
   // * 4: OS/2 table is missing or invalid
@@ -73,38 +81,63 @@
   // <encoding> array specifies the mapping from char codes to names.
   // If <encoding> is NULL, the encoding is unknown or undefined.  The
   // <codeToGID> array specifies the mapping from char codes to GIDs.
+  // (Not useful for OpenType CFF fonts.)
   void convertToType42(char *psName, char **encoding,
 		       Gushort *codeToGID,
 		       FoFiOutputFunc outputFunc, void *outputStream);
 
+  // Convert to a Type 1 font, suitable for embedding in a PostScript
+  // file.  This is only useful with 8-bit fonts.  If <newEncoding> is
+  // not NULL, it will be used in place of the encoding in the Type 1C
+  // font.  If <ascii> is true the eexec section will be hex-encoded,
+  // otherwise it will be left as binary data.  If <psName> is
+  // non-NULL, it will be used as the PostScript font name.  (Only
+  // useful for OpenType CFF fonts.)
+  void convertToType1(char *psName, char **newEncoding, GBool ascii,
+		      FoFiOutputFunc outputFunc, void *outputStream);
+
   // Convert to a Type 2 CIDFont, suitable for embedding in a
   // PostScript file.  <psName> will be used as the PostScript font
   // name (so we don't need to depend on the 'name' table in the
   // font).  The <cidMap> array maps CIDs to GIDs; it has <nCIDs>
-  // entries.
+  // entries.  (Not useful for OpenType CFF fonts.)
   void convertToCIDType2(char *psName, Gushort *cidMap, int nCIDs,
 			 GBool needVerticalMetrics,
 			 FoFiOutputFunc outputFunc, void *outputStream);
 
+  // Convert to a Type 0 CIDFont, suitable for embedding in a
+  // PostScript file.  <psName> will be used as the PostScript font
+  // name.  (Only useful for OpenType CFF fonts.)
+  void convertToCIDType0(char *psName,
+			 FoFiOutputFunc outputFunc, void *outputStream);
+
   // Convert to a Type 0 (but non-CID) composite font, suitable for
   // embedding in a PostScript file.  <psName> will be used as the
   // PostScript font name (so we don't need to depend on the 'name'
   // table in the font).  The <cidMap> array maps CIDs to GIDs; it has
-  // <nCIDs> entries.
+  // <nCIDs> entries.  (Not useful for OpenType CFF fonts.)
   void convertToType0(char *psName, Gushort *cidMap, int nCIDs,
 		      GBool needVerticalMetrics,
 		      FoFiOutputFunc outputFunc, void *outputStream);
 
+  // Convert to a Type 0 (but non-CID) composite font, suitable for
+  // embedding in a PostScript file.  <psName> will be used as the
+  // PostScript font name.  (Only useful for OpenType CFF fonts.)
+  void convertToType0(char *psName,
+		      FoFiOutputFunc outputFunc, void *outputStream);
+
   // Write a clean TTF file, filling in missing tables and correcting
   // various other errors.  If <name> is non-NULL, the font is renamed
   // to <name>.  If <codeToGID> is non-NULL, the font is re-encoded,
   // using a Windows Unicode cmap.  If <name> is NULL and the font is
-  // complete and correct, it will be written unmodified.
+  // complete and correct, it will be written unmodified.  (Not useful
+  // for OpenType CFF fonts.)
   void writeTTF(FoFiOutputFunc outputFunc, void *outputStream,
 		char *name = NULL, Gushort *codeToGID = NULL);
 
 private:
 
+  FoFiTrueType(char *fileA, int lenA, GBool freeFileDataA, int faceIndexA);
   void cvtEncoding(char **encoding,
 		   FoFiOutputFunc outputFunc,
 		   void *outputStream);
@@ -131,6 +164,7 @@
   int locaFmt;
   int bbox[4];
   GooHash *nameToGID;
+  GBool openTypeCFF;
 
   GBool parsedOk;
   int faceIndex;

Index: FoFiType1.cc
===================================================================
RCS file: /cvs/poppler/poppler/fofi/FoFiType1.cc,v
retrieving revision 1.5
retrieving revision 1.5.4.1
diff -u -d -r1.5 -r1.5.4.1
--- FoFiType1.cc	14 Sep 2005 21:20:36 -0000	1.5
+++ FoFiType1.cc	6 Apr 2007 14:22:23 -0000	1.5.4.1
@@ -75,7 +75,7 @@
 void FoFiType1::writeEncoded(char **newEncoding,
 			     FoFiOutputFunc outputFunc, void *outputStream) {
   char buf[512];
-  char *line;
+  char *line, *line2, *p;
   int i;
 
   // copy everything up to the encoding
@@ -101,19 +101,57 @@
   }
   (*outputFunc)(outputStream, "readonly def\n", 13);
   
-  // copy everything after the encoding
+  // find the end of the encoding data
+  //~ this ought to parse PostScript tokens
   if (!strncmp(line, "/Encoding StandardEncoding def", 30)) {
     line = getNextLine(line);
   } else {
-    for (line = getNextLine(line);
-	 line && strncmp(line, "readonly def", 12);
-	 line = getNextLine(line)) ;
-    if (line) {
-      line = getNextLine(line);
+    // skip "/Encoding" + one whitespace char,
+    // then look for 'def' preceded by PostScript whitespace
+    p = line + 10;
+    line = NULL;
+    for (; p < (char *)file + len; ++p) {
+      if ((*p == ' ' || *p == '\t' || *p == '\x0a' ||
+	   *p == '\x0d' || *p == '\x0c' || *p == '\0') &&
+	  p + 4 <= (char *)file + len &&
+	  !strncmp(p + 1, "def", 3)) {
+	line = p + 4;
+	break;
+      }
     }
   }
+
+  // some fonts have two /Encoding entries in their dictionary, so we
+  // check for a second one here
   if (line) {
-    (*outputFunc)(outputStream, line, ((char *)file + len) - line);
+    for (line2 = line, i = 0;
+	 i < 20 && line2 && strncmp(line2, "/Encoding", 9);
+	 line2 = getNextLine(line2), ++i) ;
+    if (i < 20 && line2) {
+      (*outputFunc)(outputStream, line, line2 - line);
+      if (!strncmp(line2, "/Encoding StandardEncoding def", 30)) {
+	line = getNextLine(line2);
+      } else {
+	// skip "/Encoding" + one whitespace char,
+	// then look for 'def' preceded by PostScript whitespace
+	p = line2 + 10;
+	line = NULL;
+	for (; p < (char *)file + len; ++p) {
+	  if ((*p == ' ' || *p == '\t' || *p == '\x0a' ||
+	       *p == '\x0d' || *p == '\x0c' || *p == '\0') &&
+	      p + 4 <= (char *)file + len &&
+	      !strncmp(p + 1, "def", 3)) {
+	    line = p + 4;
+	    break;
+	  }
+	}
+      }
+    }
+
+    // copy everything after the encoding
+    if (line) {
+      (*outputFunc)(outputStream, line, ((char *)file + len) - line);
+    }
   }
 }
 
@@ -178,8 +216,15 @@
 	  if (*p2) {
 	    c = *p2;
 	    *p2 = '\0';
-	    if ((code = atoi(p)) < 256) {
-	      *p2 = c;
+	    code = atoi(p);
+	    *p2 = c;
+	    if (code == 8 && *p2 == '#') {
+	      code = 0;
+	      for (++p2; *p2 >= '0' && *p2 <= '7'; ++p2) {
+		code = code * 8 + (*p2 - '0');
+	      }
+	    }
+	    if (code < 256) {
 	      for (p = p2; *p == ' ' || *p == '\t'; ++p) ;
 	      if (*p == '/') {
 		++p;

Index: FoFiType1C.cc
===================================================================
RCS file: /cvs/poppler/poppler/fofi/FoFiType1C.cc,v
retrieving revision 1.3
retrieving revision 1.3.4.1
diff -u -d -r1.3 -r1.3.4.1
--- FoFiType1C.cc	14 Sep 2005 21:20:36 -0000	1.3
+++ FoFiType1C.cc	6 Apr 2007 14:22:23 -0000	1.3.4.1
@@ -129,24 +129,33 @@
   return map;
 }
 
-void FoFiType1C::convertToType1(char **newEncoding, GBool ascii,
+void FoFiType1C::convertToType1(char *psName, char **newEncoding, GBool ascii,
 				FoFiOutputFunc outputFunc,
 				void *outputStream) {
+  int psNameLen;
   Type1CEexecBuf eb;
   Type1CIndex subrIdx;
   Type1CIndexVal val;
[...965 lines suppressed...]
@@ -949,15 +1070,16 @@
 			       int offset, int nBytes,
 			       Type1CIndex *subrIdx,
 			       Type1CPrivateDict *pDict) {
-  char buf[512];
+  GooString *buf;
   GooString *charBuf;
 
   // generate the charstring
   charBuf = new GooString();
   cvtGlyph(offset, nBytes, charBuf, subrIdx, pDict, gTrue);
 
-  sprintf(buf, "/%s %d RD ", glyphName, charBuf->getLength());
-  eexecWrite(eb, buf);
+  buf = GooString::format("/{0:s} {1:d} RD ", glyphName, charBuf->getLength());
+  eexecWrite(eb, buf->getCString());
+  delete buf;
   eexecWriteCharstring(eb, (Guchar *)charBuf->getCString(),
 		       charBuf->getLength());
   eexecWrite(eb, " ND\n");

Index: FoFiType1C.h
===================================================================
RCS file: /cvs/poppler/poppler/fofi/FoFiType1C.h,v
retrieving revision 1.3
retrieving revision 1.3.4.1
diff -u -d -r1.3 -r1.3.4.1
--- FoFiType1C.h	2 Feb 2006 22:50:01 -0000	1.3
+++ FoFiType1C.h	6 Apr 2007 14:22:23 -0000	1.3.4.1
@@ -138,7 +138,6 @@
   // Create a FoFiType1C object from a file on disk.
   static FoFiType1C *load(char *fileName);
 
-  FoFiType1C(char *fileA, int lenA, GBool freeFileDataA);
   virtual ~FoFiType1C();
 
   // Return the font name.
@@ -156,8 +155,9 @@
   // file.  This is only useful with 8-bit fonts.  If <newEncoding> is
   // not NULL, it will be used in place of the encoding in the Type 1C
   // font.  If <ascii> is true the eexec section will be hex-encoded,
-  // otherwise it will be left as binary data.
-  void convertToType1(char **newEncoding, GBool ascii,
+  // otherwise it will be left as binary data.  If <psName> is non-NULL,
+  // it will be used as the PostScript font name.
+  void convertToType1(char *psName, char **newEncoding, GBool ascii,
 		      FoFiOutputFunc outputFunc, void *outputStream);
 
   // Convert to a Type 0 CIDFont, suitable for embedding in a
@@ -174,6 +174,7 @@
 
 private:
 
+  FoFiType1C(char *fileA, int lenA, GBool freeFileDataA);
   void eexecCvtGlyph(Type1CEexecBuf *eb, char *glyphName,
 		     int offset, int nBytes,
 		     Type1CIndex *subrIdx,



More information about the poppler mailing list