]> git.parisson.com Git - pdf.js.git/commitdiff
Remove empty gryphs; improve glyph unicode movements
authornotmasteryet <async.processingjs@yahoo.com>
Tue, 13 Mar 2012 23:59:16 +0000 (18:59 -0500)
committernotmasteryet <async.processingjs@yahoo.com>
Tue, 13 Mar 2012 23:59:16 +0000 (18:59 -0500)
src/fonts.js

index df0acbbc5aa65d454e3f2a319e65e1de4743dbf9..e3178ae9d79a75668571c81d1f7ab9e07e38c787 100644 (file)
@@ -1656,6 +1656,30 @@ var Font = (function FontClosure() {
         glyf.data = newGlyfData.subarray(0, writeOffset);
       }
 
+      function findEmptyGlyphs(locaTable, isGlyphLocationsLong, emptyGlyphIds) {
+        var itemSize, itemDecode;
+        if (isGlyphLocationsLong) {
+          itemSize = 4;
+          itemDecode = function fontItemDecodeLong(data, offset) {
+            return (data[offset] << 24) | (data[offset + 1] << 16) |
+                   (data[offset + 2] << 8) | data[offset + 3];
+          };
+        } else {
+          itemSize = 2;
+          itemDecode = function fontItemDecode(data, offset) {
+            return (data[offset] << 9) | (data[offset + 1] << 1);
+          };
+        }
+        var data = locaTable.data, length = data.length;
+        var lastOffset = itemDecode(data, 0);
+        for (var i = itemSize, j = 0; i < length; i += itemSize, j++) {
+          var offset = itemDecode(data, i);
+          if (offset == lastOffset)
+            emptyGlyphIds[j] = true;
+          lastOffset = offset;
+        }
+      }
+
       function readGlyphNameMap(post, properties) {
         var start = (font.start ? font.start : 0) + post.offset;
         font.pos = start;
@@ -1782,11 +1806,15 @@ var Font = (function FontClosure() {
       sanitizeMetrics(font, hhea, hmtx, numGlyphs);
       sanitizeMetrics(font, vhea, vmtx, numGlyphs);
 
+      var isGlyphLocationsLong = int16([head.data[50], head.data[51]]);
       if (head && loca && glyf) {
-        var isGlyphLocationsLong = int16([head.data[50], head.data[51]]);
         sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong);
       }
 
+      var emptyGlyphIds = [];
+      if (glyf)
+        findEmptyGlyphs(loca, isGlyphLocationsLong, emptyGlyphIds);
+
       // Sanitizer reduces the glyph advanceWidth to the maxAdvanceWidth
       // Sometimes it's 0. That needs to be fixed
       if (hhea.data[10] == 0 && hhea.data[11] == 0) {
@@ -1918,6 +1946,15 @@ var Font = (function FontClosure() {
           }
         }
 
+        // remove glyph references outside range of avaialable glyphs or empty
+        for (var i = ids.length - 1; i >= 0; i--) {
+          if (ids[i] < numGlyphs &&
+              (!emptyGlyphIds[ids[i]] || this.isSymbolicFont))
+            continue;
+          ids.splice(i, 1);
+          glyphs.splice(i, 1);
+        }
+
         if (hasShortCmap && this.hasEncoding && !this.isSymbolicFont) {
           // Re-encode short map encoding to unicode -- that simplifies the
           // resolution of MacRoman encoded glyphs logic for TrueType fonts:
@@ -1951,9 +1988,11 @@ var Font = (function FontClosure() {
           // Re-encode cmap encoding to unicode, based on the 'post' table data
           // diffrence array or base encoding
           var reverseMap = [];
-          for (var i = 0, ii = glyphs.length; i < ii; i++)
+          for (var i = 0, ii = glyphs.length; i < ii; i++) {
             reverseMap[glyphs[i].unicode] = i;
+          }
 
+          var backtrackReplacements = [];
           for (var i = 0, ii = glyphs.length; i < ii; i++) {
             var code = glyphs[i].unicode;
             var changeCode = false;
@@ -1966,13 +2005,36 @@ var Font = (function FontClosure() {
             }
             if (glyphName in GlyphsUnicode) {
               var unicode = GlyphsUnicode[glyphName];
-              if (!unicode || (unicode in reverseMap))
-                continue; // unknown glyph name or its place is taken
+              if (!unicode || reverseMap[unicode] === i)
+                continue; // unknown glyph name or in its own place
+
+              if (unicode in reverseMap) {
+                backtrackReplacements[unicode] = {
+                  index: i,
+                  code: code,
+                  changeCode: changeCode
+                };
+                continue; // its place is taken
+              }
 
-              glyphs[i].unicode = unicode;
-              reverseMap[unicode] = i;
-              if (changeCode)
-                toFontChar[code] = unicode;
+              var index = i;
+              while (true) {
+                glyphs[index].unicode = unicode;
+                reverseMap[unicode] = index;
+                if (changeCode)
+                  toFontChar[code] = unicode;
+
+                // checking if available place can be used by other glyph
+                var backtrack = backtrackReplacements[code];
+                if (!backtrack)
+                  break;
+
+                delete backtrackReplacements[code];
+                index = backtrack.index;
+                code = backtrack.code;
+                changeCode = backtrack.changeCode;
+                unicode = code;
+              }
             }
             this.useToFontChar = true;
           }
@@ -1988,12 +2050,6 @@ var Font = (function FontClosure() {
           this.useToFontChar = true;
         }
 
-        // remove glyph references outside range of avaialable glyphs
-        for (var i = 0, ii = ids.length; i < ii; i++) {
-          if (ids[i] >= numGlyphs)
-            ids[i] = 0;
-        }
-
         createGlyphNameMap(glyphs, ids, properties);
         this.glyphNameMap = properties.glyphNameMap;