From dd9423624c633db28032ed6fbbb905b2286afc55 Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Fri, 24 Jun 2011 23:33:16 +0200
Subject: [PATCH 1/6] Fix some warnings

---
 utils/fonts_utils.js | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/utils/fonts_utils.js b/utils/fonts_utils.js
index de4ceea72..532853460 100644
--- a/utils/fonts_utils.js
+++ b/utils/fonts_utils.js
@@ -194,6 +194,8 @@ function readFontIndexData(aStream, aIsByte) {
       return aStream.getByte() << 24 | aStream.getByte() << 16 |
              aStream.getByte() << 8 | aStream.getByte();
     }
+    error(offsize + " is not a valid offset size");
+    return null;
   };
 
   var offsets = [];
@@ -320,12 +322,12 @@ var Type2Parser = function(aFilePath) {
     dump(subrs);
 
     // Reading Private Dict
-    var private = font.get("Private");
-    log("Reading Private Dict (offset: " + private.offset + " size: " + private.size + ")");
-    aStream.pos = private.offset;
+    var priv = font.get("Private");
+    log("Reading Private Dict (offset: " + priv.offset + " size: " + priv.size + ")");
+    aStream.pos = priv.offset;
 
     var privateDict = [];
-    for (var i = 0; i < private.size; i++)
+    for (var i = 0; i < priv.size; i++)
       privateDict.push(aStream.getByte());
     dump("private:" + privateDict);
     parseAsToken(privateDict, CFFDictPrivateDataMap);
@@ -386,7 +388,7 @@ function writeToFile(aBytes, aFilePath) {
 
   var stream = Cc["@mozilla.org/network/file-output-stream;1"]
                  .createInstance(Ci.nsIFileOutputStream);
-  stream.init(file, 0x04 | 0x08 | 0x20, 0600, 0);
+  stream.init(file, 0x04 | 0x08 | 0x20, 600, 0);
 
   var bos = Cc["@mozilla.org/binaryoutputstream;1"]
               .createInstance(Ci.nsIBinaryOutputStream);

From 69c1a5497184c875a328e408aeebb2090dcc7868 Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Sat, 25 Jun 2011 03:48:49 +0200
Subject: [PATCH 2/6] Add a 'scale' url parameter

---
 viewer.html | 4 ++--
 viewer.js   | 7 +++++--
 2 files changed, 7 insertions(+), 4 deletions(-)

diff --git a/viewer.html b/viewer.html
index 6e733319e..7bb06ee35 100644
--- a/viewer.html
+++ b/viewer.html
@@ -5,6 +5,7 @@
 
         <script type="text/javascript" src="viewer.js"></script>
         <script type="text/javascript" src="pdf.js"></script>
+        <script type="text/javascript" src="utils/fonts_utils.js"></script>
         <script type="text/javascript" src="fonts.js"></script>
         <script type="text/javascript" src="glyphlist.js"></script>
   </head>
@@ -25,8 +26,7 @@
     <div id="viewer">
       <!-- Canvas dimensions must be specified in CSS pixels.  CSS pixels
            are always 96 dpi.  816x1056 is 8.5x11in at 96dpi. -->
-      <!-- We're rendering here at 1.5x scale. -->
-      <canvas id="canvas" width="1224" height="1584"></canvas>
+      <canvas id="canvas" width="816" height="1056" defaultwidth="816" defaultheight="1056"></canvas>
     </div>
   </body>
 </html>
diff --git a/viewer.js b/viewer.js
index 2bcff50a6..c7adee892 100644
--- a/viewer.js
+++ b/viewer.js
@@ -3,11 +3,12 @@
 
 "use strict";
 
-var pdfDocument, canvas, pageDisplay, pageNum, numPages, pageTimeout;
+var pdfDocument, canvas, pageScale, pageDisplay, pageNum, numPages, pageTimeout;
 function load(userInput) {
     canvas = document.getElementById("canvas");
     canvas.mozOpaque = true;
-    pageNum = parseInt(queryParams().page) || 1;
+    pageNum = ("page" in queryParams()) ? parseInt(queryParams().page) : 1;
+    pageScale = ("scale" in queryParams()) ? parseInt(queryParams().scale) : 1.5;
     var fileName = userInput;
     if (!userInput) {
       fileName = queryParams().file || "compressed.tracemonkey-pldi-09.pdf";
@@ -59,6 +60,8 @@ function displayPage(num) {
     var t0 = Date.now();
 
     var page = pdfDocument.getPage(pageNum = num);
+    canvas.width = parseInt(canvas.getAttribute("defaultwidth")) * pageScale;
+    canvas.height = parseInt(canvas.getAttribute("defaultheight")) * pageScale;
 
     var t1 = Date.now();
     var ctx = canvas.getContext("2d");

From 159c986e6e6858b87a609af068d65ca5d9f8aefd Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Sat, 25 Jun 2011 05:12:35 +0200
Subject: [PATCH 3/6] Add the Type1 subrs into the CFF local subrs index

---
 fonts.js | 93 ++++++++++++++++++++++++++++----------------------------
 1 file changed, 47 insertions(+), 46 deletions(-)

diff --git a/fonts.js b/fonts.js
index c817b12e5..ceacf6388 100644
--- a/fonts.js
+++ b/fonts.js
@@ -1288,6 +1288,8 @@ CFF.prototype = {
     "hlineto": 6,
     "vlineto": 7,
     "rrcurveto": 8,
+    "callsubr": 10,
+    "return": 11,
     "endchar": 14,
     "rmoveto": 21,
     "hmoveto": 22,
@@ -1295,7 +1297,7 @@ CFF.prototype = {
     "hvcurveto": 31,
   },
 
-  flattenCharstring: function flattenCharstring(charstring, subrs) {
+  flattenCharstring: function flattenCharstring(charstring) {
     var i = 0;
     while (true) {
       var obj = charstring[i];
@@ -1304,35 +1306,30 @@ CFF.prototype = {
 
       if (obj.charAt) {
         switch (obj) {
-          case "callsubr":
-            var subr = subrs[charstring[i - 1]];
-            if (subr.length > 1) {
-              subr = this.flattenCharstring(subr, subrs);
-              subr.pop();
-              charstring.splice(i - 1, 2, subr);
-            } else {
-              charstring.splice(i - 1, 2);
-            }
-            i -= 1;
-            break;
-
           case "callothersubr":
             var index = charstring[i - 1];
             var count = charstring[i - 2];
             var data = charstring[i - 3];
 
-            // XXX The callothersubr needs to support at least the 3 defaults
-            // otherSubrs of the spec
-            if (index != 3)
-              error("callothersubr for index: " + index + " (" + charstring + ")");
+            // If the flex mechanishm is not used in a font program, Adobe
+            // state that that entries 0, 1 and 2 can simply be replace by
+            // {}, which means that we can simply ignore them.
+            if (index < 3) {
+              i -= 3;
+              continue;
+            }
 
-            if (!data) {
-              charstring.splice(i - 2, 4, "pop", 3);
-              i -= 3;
-            } else {
-              // 5 to remove the arguments, the callothersubr call and the pop command
-              charstring.splice(i - 3, 5, 3);
-              i -= 3;
+            // This is the same things about hint replacment, if it is not used
+            // entry 3 can be replaced by {}
+            if (index == 3) {
+              if (!data) {
+                charstring.splice(i - 2, 4, "pop", 3);
+                i -= 3;
+              } else {
+                // 5 to remove the arguments, the callothersubr call and the pop command
+                charstring.splice(i - 3, 5, 3);
+                i -= 3;
+              }
             }
             break;
 
@@ -1343,15 +1340,6 @@ CFF.prototype = {
             i -= 2;
             break;
 
-          case "pop":
-            if (i)
-              charstring.splice(i - 2, 2);
-            else
-              charstring.splice(i - 1, 1);
-            i -= 1;
-            break;
-
-
           case "hsbw":
             var charWidthVector = charstring[i - 1];
             var leftSidebearing = charstring[i - 2];
@@ -1406,7 +1394,7 @@ CFF.prototype = {
 	  var glyphsCount = charstrings.length;
     for (var i = 0; i < glyphsCount; i++) {
       var charstring = charstrings[i].charstring;
-      glyphs.push(this.flattenCharstring(charstring.slice(), subrs));
+      glyphs.push(this.flattenCharstring(charstring.slice()));
     }
 
     // Create a CFF font data
@@ -1511,22 +1499,35 @@ CFF.prototype = {
       247, 32, 11,
       247, 10, 161, 147, 154, 150, 143, 12, 13,
       139, 12, 14,
-      28, 0, 55, 19
+      28, 0, 55, 19 // Subrs offset
     ]);
     cff.set(privateData, currentOffset);
     currentOffset += privateData.length;
 
-    // Dump shit at the end of the file
-    var shit = [
-      0x00, 0x01, 0x01, 0x01,
-      0x13, 0x5D, 0x65, 0x64,
-      0x5E, 0x5B, 0xAF, 0x66,
-      0xBA, 0xBB, 0xB1, 0xB0,
-      0xB9, 0xBA, 0x65, 0xB2,
-      0x5C, 0x1F, 0x0B
-    ];
-    cff.set(shit, currentOffset);
-    currentOffset += shit.length;
+    // Local Subrs
+    var flattenedSubrs = [];
+
+    var bias = 0;
+    var subrsCount = subrs.length;
+    if (subrsCount < 1240)
+      bias = 107;
+    else if (subrsCount < 33900)
+      bias = 1131;
+    else
+      bias = 32768;
+
+    // Add a bunch of empty subrs to deal with the Type2 bias
+    for (var i = 0; i < bias; i++)
+      flattenedSubrs.push([0x0B]);
+
+    for (var i = 0; i < subrsCount; i++) {
+      var subr = subrs[i];
+      flattenedSubrs.push(this.flattenCharstring(subr));
+    }
+
+    var subrsData = this.createCFFIndexHeader(flattenedSubrs, true);
+    cff.set(subrsData, currentOffset);
+    currentOffset += subrsData.length;
 
     var fontData = [];
     for (var i = 0; i < currentOffset; i++)

From cbd89e26fd05ed2f22b028c700ce1bc9a775d4ac Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Sat, 25 Jun 2011 05:45:15 +0200
Subject: [PATCH 4/6] Do less manual conversion

---
 fonts.js | 25 ++++---------------------
 1 file changed, 4 insertions(+), 21 deletions(-)

diff --git a/fonts.js b/fonts.js
index ceacf6388..ebaffc7c5 100644
--- a/fonts.js
+++ b/fonts.js
@@ -1333,21 +1333,12 @@ CFF.prototype = {
             }
             break;
 
-          case "div":
-            var num2 = charstring[i - 1];
-            var num1 = charstring[i - 2];
-            charstring.splice(i - 2, 3, num1 / num2);
-            i -= 2;
-            break;
-
           case "hsbw":
-            var charWidthVector = charstring[i - 1];
-            var leftSidebearing = charstring[i - 2];
+            var charWidthVector = charstring[1];
+            var leftSidebearing = charstring[0];
 
-            if (leftSidebearing)
-              charstring.splice(i - 2, 3, charWidthVector, leftSidebearing, "hmoveto");
-            else
-              charstring.splice(i - 2, 3, charWidthVector);
+            charstring.splice(i, 1, leftSidebearing, "hmoveto");
+            charstring.splice(0, 1);
             break;
 
           case "endchar":
@@ -1366,14 +1357,6 @@ CFF.prototype = {
                 } else {
                   charstring[j] = command;
                 }
-              } else {
-                charstring.splice(j, 1);
-
-                // command has already been translated, just add them to the
-                // charstring directly
-                for (var k = 0; k < command.length; k++)
-                  charstring.splice(j + k, 0, command[k]);
-                j+= command.length - 1;
               }
             }
             return charstring;

From f1f5617d72d155a7e8e06ce5e6c9d99f9aa7e4f9 Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Sat, 25 Jun 2011 11:22:28 +0200
Subject: [PATCH 5/6] Type1 fonts pass the sanitizer (again)

---
 fonts.js | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)

diff --git a/fonts.js b/fonts.js
index ebaffc7c5..7af850514 100644
--- a/fonts.js
+++ b/fonts.js
@@ -976,6 +976,7 @@ var Type1Parser = function() {
       "6": -1, // seac
       "7": -1, //sbw
 
+      "11": "sub",
       "12": "div",
 
       // callothersubr is a mechanism to make calls on the postscript
@@ -1290,6 +1291,9 @@ CFF.prototype = {
     "rrcurveto": 8,
     "callsubr": 10,
     "return": 11,
+    "sub": [12, 11],
+    "div": [12, 12],
+    "pop": [1, 12, 18],
     "endchar": 14,
     "rmoveto": 21,
     "hmoveto": 22,
@@ -1323,7 +1327,7 @@ CFF.prototype = {
             // entry 3 can be replaced by {}
             if (index == 3) {
               if (!data) {
-                charstring.splice(i - 2, 4, "pop", 3);
+                charstring.splice(i - 2, 4, 3);
                 i -= 3;
               } else {
                 // 5 to remove the arguments, the callothersubr call and the pop command
@@ -1350,12 +1354,15 @@ CFF.prototype = {
                 charstring.splice(j, 1, 28, command >> 8, command);
                 j+= 2;
               } else if (command.charAt) {
-                var command = this.commandsMap[command];
-                if (IsArray(command)) {
-                  charstring.splice(j - 1, 1, command[0], command[1]);
+                var cmd = this.commandsMap[command];
+                if (!cmd)
+                  error(command);
+
+                if (IsArray(cmd)) {
+                  charstring.splice(j, 1, cmd[0], cmd[1]);
                   j += 1;
                 } else {
-                  charstring[j] = command;
+                  charstring[j] = cmd;
                 }
               }
             }

From db5c454ca161ec081a1d57ceaa6a73e6a3f33a70 Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Sat, 25 Jun 2011 11:52:42 +0200
Subject: [PATCH 6/6] Fix windows/mac font loading detection

---
 fonts.js | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/fonts.js b/fonts.js
index 7af850514..6ac582b18 100644
--- a/fonts.js
+++ b/fonts.js
@@ -787,8 +787,8 @@ var Font = (function () {
       // This code could go away when bug 471915 has landed
       var canvas = document.createElement("canvas");
       var ctx = canvas.getContext("2d");
-      ctx.font = "bold italic 20px " + fontName + ", Symbol";
-      var testString = " ";
+      ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial";
+      var testString = "    ";
 
       // Periodicaly check for the width of the testString, it will be
       // different once the real font has loaded
@@ -796,7 +796,7 @@ var Font = (function () {
 
       var interval = window.setInterval(function canvasInterval(self) {
         this.start = this.start || Date.now();
-        ctx.font = "bold italic 20px " + fontName + ", Symbol";
+        ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial";
 
         // For some reasons the font has not loaded, so mark it loaded for the
         // page to proceed but cry