]> git.parisson.com Git - pdf.js.git/commitdiff
Fully support truetype composite fonts, clean up
authorAdil Allawi <adil@diwan.com>
Wed, 13 Jul 2011 08:31:34 +0000 (09:31 +0100)
committerAdil Allawi <adil@diwan.com>
Wed, 13 Jul 2011 08:31:34 +0000 (09:31 +0100)
fonts.js
pdf.js

index 3e6756624fc01bb2b0c492d4ebddcf6ba24be1cd..dfcda7af210aadb00c67155ac6692d6622ba15b1 100755 (executable)
--- a/fonts.js
+++ b/fonts.js
@@ -411,7 +411,7 @@ var Font = (function() {
         break;
     }
     this.data = data;
-    this.type = properties.type; //use the type to test if the string is single or multi-byte
+    this.type = properties.type; // Use the type to test if the string is single or multi-byte
     this.id = Fonts.registerFont(name, data, properties);
     this.loadedName = 'pdfFont' + this.id;
     this.compositeFont = properties.compositeFont;
@@ -682,6 +682,65 @@ var Font = (function() {
            '\x00\x00\x00\x00';  // maxMemType1
   };
 
+  function createNameTable(name) {
+    var strings = [
+      'Original licence',  // 0.Copyright
+      name,                // 1.Font family
+      'Unknown',           // 2.Font subfamily (font weight)
+      'uniqueID',          // 3.Unique ID
+      name,                // 4.Full font name
+      'Version 0.11',      // 5.Version
+      '',                  // 6.Postscript name
+      'Unknown',           // 7.Trademark
+      'Unknown',           // 8.Manufacturer
+      'Unknown'            // 9.Designer
+    ];
+  
+    // Mac want 1-byte per character strings while Windows want
+    // 2-bytes per character, so duplicate the names table
+    var stringsUnicode = [];
+    for (var i = 0; i < strings.length; i++) {
+      var str = strings[i];
+  
+      var strUnicode = '';
+      for (var j = 0; j < str.length; j++)
+        strUnicode += string16(str.charCodeAt(j));
+      stringsUnicode.push(strUnicode);
+    }
+  
+    var names = [strings, stringsUnicode];
+    var platforms = ['\x00\x01', '\x00\x03'];
+    var encodings = ['\x00\x00', '\x00\x01'];
+    var languages = ['\x00\x00', '\x04\x09'];
+  
+    var namesRecordCount = strings.length * platforms.length;
+    var nameTable =
+      '\x00\x00' +                           // format
+      string16(namesRecordCount) +           // Number of names Record
+      string16(namesRecordCount * 12 + 6);   // Storage
+  
+    // Build the name records field
+    var strOffset = 0;
+    for (var i = 0; i < platforms.length; i++) {
+      var strs = names[i];
+      for (var j = 0; j < strs.length; j++) {
+        var str = strs[j];
+        var nameRecord =
+          platforms[i] + // platform ID
+          encodings[i] + // encoding ID
+          languages[i] + // language ID
+          string16(j) + // name ID
+          string16(str.length) +
+          string16(strOffset);
+        nameTable += nameRecord;
+        strOffset += str.length;
+      }
+    }
+  
+    nameTable += strings.join('') + stringsUnicode.join('');
+    return nameTable;
+  }
+
   constructor.prototype = {
     name: null,
     font: null,
@@ -814,7 +873,7 @@ var Font = (function() {
 
       // This keep a reference to the CMap and the post tables since they can
       // be rewritted
-      var cmap, post;
+      var cmap, post, nameTable, maxp;
 
       var tables = [];
       for (var i = 0; i < numTables; i++) {
@@ -825,6 +884,10 @@ var Font = (function() {
             cmap = table;
           else if (table.tag == 'post')
             post = table;
+          else if (table.tag == 'name')
+            nameTable = table;
+          else if (table.tag == 'maxp')
+            maxp = table;
 
           requiredTables.splice(index, 1);
         }
@@ -859,24 +922,50 @@ var Font = (function() {
           data: stringToArray(createOS2Table(properties))
         });
 
-        if (!cmap) {
+        // Replace the old CMAP table with a shiny new one
+        if (properties.type == 'CIDFontType2') {
+          // Type2 composite fonts map charcters directly to glyphs so the cmap
+          // table must be replaced.
+          
           var glyphs = [];
           var charset = properties.charset;
-          for (var i=1; i < charset.length; i++) {
-            if (charset.indexOf(i) != -1) {
+          if (charset.length == 0)
+          {
+            // PDF did not contain a GIDMap for the font so create an identity cmap
+            
+            // First get the number of glyphs from the maxp table
+            font.pos = (font.start ? font.start : 0) + maxp.length;
+            var version = int16(font.getBytes(4));
+            var numGlyphs = int16(font.getBytes(2));
+            
+            // Now create an identity mapping
+            for (var i=1; i < numGlyphs; i++) {
               glyphs.push({
-                unicode: charset.indexOf(i)
+                unicode: i
               });
-            } else {
-              break;
+            }
+          } else {
+            for (var i=1; i < charset.length; i++) {
+              if (charset.indexOf(i) != -1) {
+                glyphs.push({
+                  unicode: charset.indexOf(i)
+                });
+              } else {
+                break;
+              }
             }
           }
-          tables.push({
-            tag: 'cmap',
-            data: createCMapTable(glyphs)
-          })
+          
+          if (!cmap) {
+            // Font did not contain a cmap
+            tables.push({
+              tag: 'cmap',
+              data: createCMapTable(glyphs)
+            })
+          } else {
+            cmap.data = createCMapTable(glyphs);
+          }
         } else {
-          // Replace the old CMAP table with a shiny new one
           replaceCMapTable(cmap, font, properties);          
         }
 
@@ -888,6 +977,14 @@ var Font = (function() {
           });
         }
 
+        // Rewrite the 'name' table if needed
+        if (!nameTable) {
+          tables.push({
+            tag: 'name',
+            data: stringToArray(createNameTable(this.name))
+          });
+        }
+
         // Tables needs to be written by ascendant alphabetic order
         tables.sort(function tables_sort(a, b) {
           return (a.tag > b.tag) - (a.tag < b.tag);
@@ -930,65 +1027,6 @@ var Font = (function() {
     },
 
     convert: function font_convert(fontName, font, properties) {
-      function createNameTable(name) {
-        var strings = [
-          'Original licence',  // 0.Copyright
-          name,                // 1.Font family
-          'Unknown',           // 2.Font subfamily (font weight)
-          'uniqueID',          // 3.Unique ID
-          name,                // 4.Full font name
-          'Version 0.11',      // 5.Version
-          '',                  // 6.Postscript name
-          'Unknown',           // 7.Trademark
-          'Unknown',           // 8.Manufacturer
-          'Unknown'            // 9.Designer
-        ];
-
-        // Mac want 1-byte per character strings while Windows want
-        // 2-bytes per character, so duplicate the names table
-        var stringsUnicode = [];
-        for (var i = 0; i < strings.length; i++) {
-          var str = strings[i];
-
-          var strUnicode = '';
-          for (var j = 0; j < str.length; j++)
-            strUnicode += string16(str.charCodeAt(j));
-          stringsUnicode.push(strUnicode);
-        }
-
-        var names = [strings, stringsUnicode];
-        var platforms = ['\x00\x01', '\x00\x03'];
-        var encodings = ['\x00\x00', '\x00\x01'];
-        var languages = ['\x00\x00', '\x04\x09'];
-
-        var namesRecordCount = strings.length * platforms.length;
-        var nameTable =
-          '\x00\x00' +                           // format
-          string16(namesRecordCount) +           // Number of names Record
-          string16(namesRecordCount * 12 + 6);   // Storage
-
-        // Build the name records field
-        var strOffset = 0;
-        for (var i = 0; i < platforms.length; i++) {
-          var strs = names[i];
-          for (var j = 0; j < strs.length; j++) {
-            var str = strs[j];
-            var nameRecord =
-              platforms[i] + // platform ID
-              encodings[i] + // encoding ID
-              languages[i] + // language ID
-              string16(j) + // name ID
-              string16(str.length) +
-              string16(strOffset);
-            nameTable += nameRecord;
-            strOffset += str.length;
-          }
-        }
-
-        nameTable += strings.join('') + stringsUnicode.join('');
-        return nameTable;
-      }
-
       function isFixedPitch(glyphs) {
         for (var i = 0; i < glyphs.length - 1; i++) {
           if (glyphs[i] != glyphs[i + 1])
diff --git a/pdf.js b/pdf.js
index c73558abbd89bff920844472792591b92a199a42..1680c1c59648eddd48e5fc6b19a96d6c683ed180 100644 (file)
--- a/pdf.js
+++ b/pdf.js
@@ -3630,7 +3630,7 @@ var PartialEvaluator = (function() {
       var compositeFont = false;
       assertWellFormed(IsName(subType), 'invalid font Subtype');
       
-      //If font is a composite 
+      // If font is a composite 
       //  - get the descendant font
       //  - set the type according to the descendant font
       //  - get the FontDescriptor from the descendant font
@@ -3664,31 +3664,35 @@ var PartialEvaluator = (function() {
       var encodingMap = {};
       var charset = [];
       if (compositeFont) {
-        //Special CIDFont support
-        //XXX only identity CID Encodings supported for now
-        var encoding = xref.fetchIfRef(fontDict.get('Encoding'));
-        if (IsName(encoding)) {
-          //Encoding is a predefined CMap
-          if (encoding.name == 'Identity-H') {
-            if (subType.name == 'CIDFontType2') {
-              var cidToGidMap = descendant.get('CIDToGIDMap');
-              if (cidToGidMap) {
-                //Extract the charset from the CIDToGIDMap
-                var glyphsStream = xref.fetchIfRef(cidToGidMap);
-                var glyphsData = glyphsStream.getBytes(0);
-                var i = 0;
-                //glyph ids are big-endian 2-byte values
-                for (var j=0; j<glyphsData.length; j++) {
-                  var glyphID = (glyphsData[j++] << 8) | glyphsData[j];
-                  charset.push(glyphID);
-                }
-              }
+        // Special CIDFont support
+        // XXX only CIDFontType2 supported for now
+        if (subType.name == 'CIDFontType2') {
+          var cidToGidMap = descendant.get('CIDToGIDMap');
+          if (cidToGidMap && IsRef(cidToGidMap)) {
+            // Extract the charset from the CIDToGIDMap
+            var glyphsStream = xref.fetchIfRef(cidToGidMap);
+            var glyphsData = glyphsStream.getBytes(0);
+            var i = 0;
+            // Glyph ids are big-endian 2-byte values
+            for (var j=0; j<glyphsData.length; j++) {
+              var glyphID = (glyphsData[j++] << 8) | glyphsData[j];
+              charset.push(glyphID);
+            }
+          }
+        }
+        else {
+          // XXX This is a placeholder for handling of the encoding of CIDFontType0 fonts
+          var encoding = xref.fetchIfRef(fontDict.get('Encoding'));
+          if (IsName(encoding)) {
+            // Encoding is a predefined CMap
+            if (encoding.name == 'Identity-H') {
+              TODO ('Need to create an identity cmap')
+            } else {
+              TODO ('Need to support predefined CMaps see PDF 32000-1:2008 9.7.5.2 Predefined CMaps')
             }
           } else {
-            TODO ('Need to support predefined CMaps see PDF 32000-1:2008 9.7.5.2 Predefined CMaps')
+            TODO ('Need to support encoding streams see PDF 32000-1:2008  9.7.5.3'); 
           }
-        } else {
-          TODO ('Need to support encoding streams see PDF 32000-1:2008  9.7.5.3'); 
         }
       } else if (fontDict.has('Encoding')) {
         var encoding = xref.fetchIfRef(fontDict.get('Encoding'));