]> git.parisson.com Git - pdf.js.git/commitdiff
Make the fonts decoding code works with asynchronous data url
authorVivien Nicolas <21@vingtetun.org>
Tue, 14 Jun 2011 02:35:46 +0000 (04:35 +0200)
committerVivien Nicolas <21@vingtetun.org>
Tue, 14 Jun 2011 02:35:46 +0000 (04:35 +0200)
PDFFont.js
pdf.js
test.js

index 34fb28fc4020f91ae397d4c0116f010db78c0a04..4e81187b9b573e6cdf6a1525de1855c8d168b9f2 100644 (file)
@@ -11,6 +11,16 @@ var kMaxFontFileSize = 40000;
 */
 var kMaxGlyphsCount = 1024;
 
+/**
+ * Maximum time to wait for a font to be loaded by @font-face
+ */
+var kMaxWaitForFontFace = 2000;
+
+ /*
+  * Useful for debugging when you want to certains operations depending on how
+  * many fonts are loaded.
+  */
+var fontCount = 0;
 
 /**
  * Hold a map of decoded fonts and of the standard fourteen Type1 fonts and
@@ -36,9 +46,10 @@ var Font = function(aFontName, aFontFile, aFontType) {
 
   // If the font has already been decoded simply return
   if (Fonts[aFontName]) {
-    this.font = Fonts[aFontName];
+    this.font = Fonts[aFontName].data;
     return;
   }
+  fontCount++;
 
   var start = Date.now();
   switch (aFontType) {
@@ -62,10 +73,13 @@ var Font = function(aFontName, aFontFile, aFontType) {
   }
   var end = Date.now();
 
+  Fonts[aFontName] = {
+    data: this.font,
+    loading: true
+  }
+
   // Attach the font to the document
   this.bind();
-
-  Fonts[aFontName] = this.font;
 };
 
 Font.prototype = {
@@ -84,10 +98,90 @@ Font.prototype = {
                             : String.fromCharCode(data[i]));
 
     var dataBase64 = window.btoa(str.join(""));
+    var fontName = this.name;
+
+    /** Hack begin */
+
+    // Actually there is not event when a font has finished downloading so
+    // the following tons of code are a dirty hack to 'guess' when a font is
+    // ready
+    var debug = false;
+
+    var canvas = document.createElement("canvas");
+    var style = "position:absolute; left: " + 
+                (debug ? (100 * fontCount) : "-200") + "px; top: -200px;";
+    canvas.setAttribute("style", style);
+    canvas.setAttribute("width", 100);
+    canvas.setAttribute("heigth", 100);
+    document.body.appendChild(canvas);
+
+    // Get the first character of the font
+    var page = pdfDocument.getPage(pageNum);
+    var xref = page.xref;
+    var resources = xref.fetchIfRef(page.resources);
+    var fontResource = resources.get("Font");
+    var charset = "";
+    for (var id in fontResource.map) {
+      var res = xref.fetch(fontResource.get(id));
+      var descriptor = xref.fetch(res.get("FontDescriptor"));
+      var name = descriptor.get("FontName").toString();
+      var font = Fonts[name.replace("+", "_")]; 
+      if (font && font.loading && name == fontName.replace("_", "+")) {
+        charset = descriptor.get("CharSet").split("/");
+        break;
+      }
+    }
+
+    // Warn if the charset is not found, this is likely a bug!
+    var testCharset = charset;
+    if (!charset) {
+      warn("No charset found for: " + fontName);
+    } else {
+      // if the charset is too small make it repeat a few times
+      var count = 30;
+      while (count-- && testCharset.length <= 30)
+        testCharset = testCharset.concat(charset.slice());
+    }
+
+    // Get the font size canvas think it will be
+    var ctx = canvas.getContext("2d");
+    var testString = "";
+    for (var i = 0; i < testCharset.length; i++) {
+      var unicode = new Number("0x" + GlyphsUnicode[testCharset[i]]);
+      if (!unicode)
+        error("Unicode for " + testCharset[i] + " is has not been found in the glyphs list");
+      testString += String.fromCharCode(unicode);
+    }
+    ctx.font = "20px " + fontName + ", Symbol";
+    var textWidth = ctx.mozMeasureText(testString);
+
+    if (debug)
+      ctx.fillText(testString, 20, 20);
+
+    var start = Date.now();
+    var interval = window.setInterval(function(self) {
+      ctx.font = "20px " + fontName + ", Symbol";
+
+      // For some reasons the font has not loaded, so mark it loaded for the
+      // page to proceed but cry
+      if ((Date.now() - start) >= kMaxWaitForFontFace) {
+        window.clearInterval(interval);
+        Fonts[fontName].loading = false;
+        warn("Is " + fontName + " for charset: " + charset + " loaded?");
+      } else if (textWidth != ctx.mozMeasureText(testString)) {
+        window.clearInterval(interval);
+        Fonts[fontName].loading = false;
+      }
+
+      if (debug)
+        ctx.fillText(testString, 20, 60);
+    }, 150, this);
+
+    /** Hack end */
 
     // Add the @font-face rule to the document
     var url = "url(data:" + this.mimetype + ";base64," + dataBase64 + ");";
-    var rule = "@font-face { font-family:'" + this.name + "';src:" + url + "}";
+    var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}";
     var styleSheet = document.styleSheets[0];
     styleSheet.insertRule(rule, styleSheet.length);
   },
@@ -473,7 +567,6 @@ var TrueType = function(aFontName, aFontFile) {
  */
 var PSFonts = new Dict();
 
-
 var Stack = function(aStackSize) {
   var innerStack = new Array(aStackSize || 0);
 
@@ -1136,7 +1229,6 @@ var Type1Parser = function(aAsciiStream, aBinaryStream) {
   }
 };
 
-
 var CFF = function(aFontName, aFontFile) {
   var start = Date.now();
 
diff --git a/pdf.js b/pdf.js
index 8b06f5582db8e53c182a551e42173c571162e743..697e6c3adbcc2b3f5494c76baa0fe37c1102b957 100644 (file)
--- a/pdf.js
+++ b/pdf.js
@@ -1399,6 +1399,19 @@ var Page = (function() {
                                              ? obj
                                              : null));
         },
+        get fonts() {
+            var xref = this.xref;
+            var fonts = [];
+
+            var resources = xref.fetchIfRef(this.resources);
+            var fontResource = resources.get("Font");
+            for (var id in fontResource.map) {
+              var res = xref.fetch(fontResource.get(id));
+              var descriptor = xref.fetch(res.get("FontDescriptor"));
+              fonts.push(descriptor.get("FontName").toString());
+            }
+            return shadow(this, "fonts", fonts);
+        },
         display: function(gfx) {
             var xref = this.xref;
             var contents = xref.fetchIfRef(this.contents);
@@ -1843,7 +1856,7 @@ var CanvasGraphics = (function() {
                 var fontFile = this.xref.fetchIfRef(fontDescriptor.get("FontFile"));
                 if (!fontFile)
                   fontFile = this.xref.fetchIfRef(fontDescriptor.get("FontFile2"));
-                fontName = fontDescriptor.get("FontName").name.replace("+", " ");
+                fontName = fontDescriptor.get("FontName").name.replace("+", "_");
                 new Font(fontName, fontFile, subtype);
             }
 
diff --git a/test.js b/test.js
index ec784ea62261451c0a894fbdeda88785e28e41a3..bd6c812e89047f7d0328bbbb04d2544c51c99e40 100644 (file)
--- a/test.js
+++ b/test.js
@@ -21,7 +21,6 @@ function queryParams() {
     return params;
 }
 
-
 function open(url) {
     document.title = url;
     req = new XMLHttpRequest();
@@ -54,21 +53,59 @@ function displayPage(num) {
 
     var page = pdfDocument.getPage(pageNum = num);
 
-    var t1 = Date.now();
+    function display() {
+      var t1 = Date.now();
+      var ctx = canvas.getContext("2d");
+      ctx.save();
+      ctx.fillStyle = "rgb(255, 255, 255)";
+      ctx.fillRect(0, 0, canvas.width, canvas.height);
+      ctx.restore();
 
-    var ctx = canvas.getContext("2d");
-    ctx.save();
-    ctx.fillStyle = "rgb(255, 255, 255)";
-    ctx.fillRect(0, 0, canvas.width, canvas.height);
-    ctx.restore();
+      var gfx = new CanvasGraphics(ctx);
+      page.display(gfx);
 
-    var gfx = new CanvasGraphics(ctx);
-    page.display(gfx);
+      var t2 = Date.now();
+      var infoDisplay = document.getElementById("info");
+      infoDisplay.innerHTML = "Time to render: "+ (t1 - t0) + "/" + (t2 - t1) + " ms";
+    }
 
-    var t2 = Date.now();
+    // Loading a font via data uri is asynchronous, so wait for all font
+    // of the page to be fully loaded before loading the page
+    var fontsReady = true;
+    var fonts = page.fonts;
+    for (var i = 0; i < fonts.length; i++) {
+      var fontName = fonts[i].replace("+", "_");
+      var font = Fonts[fontName];
+      if (!font) {
+        // load the new font
+        var xref = page.xref;
+        var resources = xref.fetchIfRef(page.resources);
+        var fontResource = resources.get("Font");
+        for (var id in fontResource.map) {
+          var res = xref.fetch(fontResource.get(id));
+          var descriptor = xref.fetch(res.get("FontDescriptor"));
+          var name = descriptor.get("FontName").toString();
+          if (name == fontName.replace("_", "+")) {
+            var subtype = res.get("Subtype").name;
+            var fontFile = page.xref.fetchIfRef(descriptor.get("FontFile"));
+            if (!fontFile)
+              fontFile = page.xref.fetchIfRef(descriptor.get("FontFile2"));
+            new Font(fontName, fontFile, subtype);
+            fontsReady = false;
+            break;
+          }
+        }
+      } else if (font.loading) {
+        fontsReady = false;
+        break;
+      }
+    }
 
-    var infoDisplay = document.getElementById("info");
-    infoDisplay.innerHTML = "Time to render: "+ (t1 - t0) + "/" + (t2 - t1) + " ms";
+    // If everything is ready do not delayed the page loading any more
+    if (fontsReady)
+      display();
+    else
+      setTimeout(displayPage, 150, num);
 }
 
 function nextPage() {