]> git.parisson.com Git - pdf.js.git/commitdiff
Sanitizing the glyphs to avoid OTS rejections
authornotmasteryet <async.processingjs@yahoo.com>
Mon, 13 Feb 2012 03:11:44 +0000 (21:11 -0600)
committernotmasteryet <async.processingjs@yahoo.com>
Mon, 13 Feb 2012 03:11:44 +0000 (21:11 -0600)
src/fonts.js
test/pdfs/html5checker.pdf.link [new file with mode: 0644]
test/test_manifest.json

index f8ae7de4c8d842bd39ed0f88fa202c0d2eb707f8..919441b58b31308e6257ce203de81f376274ec54 100644 (file)
@@ -1553,6 +1553,61 @@ var Font = (function FontClosure() {
         }
       };
 
+      function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart) {
+        if (sourceEnd - sourceStart <= 12) {
+          // glyph with data less than 12 is invalid one
+          return 0;
+        }
+        var glyf = source.subarray(sourceStart, sourceEnd);
+        var contoursCount = (glyf[0] << 8) | glyf[1];
+        if (contoursCount & 0x8000) {
+          // complex glyph, writing as is
+          dest.set(glyf, destStart);
+          return glyf.length;
+        }
+
+        var j = 10, flagsCount = 0;
+        for (var i = 0; i < contoursCount; i++) {
+          var endPoint = (glyf[j] << 8) | glyf[j + 1];
+          flagsCount = endPoint + 1;
+          j += 2;
+        }
+        // skipping instructions
+        var instructionsLength = (glyf[j] << 8) | glyf[j + 1];
+        j += 2 + instructionsLength;
+        // validating flags
+        var coordinatesLength = 0;
+        for (var i = 0; i < flagsCount; i++) {
+          var flag = glyf[j++];
+          if (flag & 0xC0) {
+            // reserved flags must be zero, rejecting
+            return 0;
+          }
+          var xyLength = ((flag & 2) ? 1 : (flag & 16) ? 0 : 2) +
+                         ((flag & 4) ? 1 : (flag & 32) ? 0 : 2);
+          coordinatesLength += xyLength;
+          if (flag & 8) {
+            var repeat = glyf[j++];
+            i += repeat;
+            coordinatesLength += repeat * xyLength;
+          }
+        }
+        var glyphDataLength = j + coordinatesLength;
+        if (glyphDataLength > glyf.length) {
+          // not enough data for coordinates
+          return 0;
+        }
+        if (glyf.length - glyphDataLength > 3) {
+          // truncating and aligning to 4 bytes the long glyph data
+          glyphDataLength = (glyphDataLength + 3) & ~3;
+          dest.set(glyf.subarray(0, glyphDataLength), destStart);
+          return glyphDataLength;
+        }
+        // glyph data is fine
+        dest.set(glyf, destStart);
+        return glyf.length;
+      }
+
       function sanitizeGlyphLocations(loca, glyf, numGlyphs,
                                       isGlyphLocationsLong) {
         var itemSize, itemDecode, itemEncode;
@@ -1579,21 +1634,21 @@ var Font = (function FontClosure() {
           };
         }
         var locaData = loca.data;
+        // removing the invalid glyphs
+        var oldGlyfData = glyf.data;
+        var newGlyfData = new Uint8Array(oldGlyfData.length);
         var startOffset = itemDecode(locaData, 0);
-        var firstOffset = itemDecode(locaData, itemSize);
-        if (firstOffset - startOffset < 12 || startOffset > 0) {
-          // removing first glyph
-          glyf.data = glyf.data.subarray(firstOffset);
-          glyf.length -= firstOffset;
-
-          itemEncode(locaData, 0, 0);
-          var i, pos = itemSize;
-          for (i = 1; i <= numGlyphs; ++i) {
-            itemEncode(locaData, pos,
-              itemDecode(locaData, pos) - firstOffset);
-            pos += itemSize;
-          }
+        var writeOffset = 0;
+        itemEncode(locaData, 0, writeOffset);
+        for (var i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
+          var endOffset = itemDecode(locaData, j);
+          var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset,
+                                        newGlyfData, writeOffset);
+          writeOffset += newLength;
+          itemEncode(locaData, j, writeOffset);
+          startOffset = endOffset;
         }
+        glyf.data = newGlyfData.subarray(0, writeOffset);
       }
 
       function readGlyphNameMap(post, properties) {
diff --git a/test/pdfs/html5checker.pdf.link b/test/pdfs/html5checker.pdf.link
new file mode 100644 (file)
index 0000000..8c4552e
--- /dev/null
@@ -0,0 +1 @@
+http://hsivonen.iki.fi/thesis/html5-conformance-checker.pdf
index 3a1b5bd707f951b7869a8f6b99fa2066851b5fef..5295d07f65a54fd9f6645a335568c4967e78dee8 100644 (file)
       "link": false,
       "type": "eq"
     },
+    {  "id": "html5checker",
+      "file": "pdfs/html5checker.pdf",
+      "md5": "74bbd80d1e7eb5f2951582233ef9ebab",
+      "rounds": 1,
+      "pageLimit": 7,
+      "link": true,
+      "type": "eq"
+    },
     {  "id": "issue1133",
       "file": "pdfs/issue1133.pdf",
       "md5": "d1b61580cb100e3df93d33703af1773a",