From 5cbc6875b367aee7a058db0b683a916f171b9013 Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Fri, 1 Jul 2011 00:44:11 +0200
Subject: [PATCH 01/11] Open the CFF class road for Type1C font

---
 fonts.js | 134 ++++++++++++++++++++++++-------------------------------
 1 file changed, 59 insertions(+), 75 deletions(-)

diff --git a/fonts.js b/fonts.js
index fdc5949a5..054185009 100644
--- a/fonts.js
+++ b/fonts.js
@@ -6,7 +6,7 @@
 /**
  * Maximum file size of the font.
  */
-var kMaxFontFileSize = 40000;
+var kMaxFontFileSize = 200000;
 
 /**
  * Maximum time to wait for a font to be loaded by @font-face
@@ -34,7 +34,7 @@ var kDisableFonts = false;
  *      http://cgit.freedesktop.org/poppler/poppler/tree/poppler/GfxFont.cc#n65
  */
 
-var Fonts = (function () {
+var Fonts = (function Fonts() {
   var kScalePrecision = 40;
   var fonts = Object.create(null);
   var ctx = document.createElement("canvas").getContext("2d");
@@ -1462,13 +1462,17 @@ var CFF = function(name, file, properties) {
   var length1 = file.dict.get("Length1");
   var length2 = file.dict.get("Length2");
   file.skip(length1);
-  var eexecBlock = file.getBytes(length2);
 
   // Decrypt the data blocks and retrieve it's content
+  var eexecBlock = file.getBytes(length2);
   var data = type1Parser.extractFontProgram(eexecBlock);
 
-  this.charstrings = this.getOrderedCharStrings(data.charstrings);
-  this.data = this.wrap(name, this.charstrings, data.subrs, properties);
+  var charstrings = this.getOrderedCharStrings(data.charstrings);
+  var type2Charstrings = this.getType2Charstrings(charstrings);
+  var subrs = this.getType2Subrs(data.subrs);
+
+  this.charstrings = charstrings;
+  this.data = this.wrap(name, type2Charstrings, this.charstrings, subrs, properties);
 };
 
 CFF.prototype = {
@@ -1546,12 +1550,40 @@ CFF.prototype = {
     return charstrings;
   },
 
+  getType2Charstrings: function cff_getType2Charstrings(type1Charstrings) {
+    var type2Charstrings = [];
+	  var count = type1Charstrings.length;
+    for (var i = 0; i < count; i++) {
+      var charstring = type1Charstrings[i].charstring;
+      type2Charstrings.push(this.flattenCharstring(charstring.slice(), this.commandsMap));
+    }
+    return type2Charstrings;
+  },
+
+  getType2Subrs: function cff_getType2Charstrings(type1Subrs) {
+    var bias = 0;
+    var count = type1Subrs.length;
+    if (count < 1240)
+      bias = 107;
+    else if (count < 33900)
+      bias = 1131;
+    else
+      bias = 32768;
+
+    // Add a bunch of empty subrs to deal with the Type2 bias
+    var type2Subrs = [];
+    for (var i = 0; i < bias; i++)
+      type2Subrs.push([0x0B]);
+
+    for (var i = 0; i < count; i++)
+      type2Subrs.push(this.flattenCharstring(type1Subrs[i], this.commandsMap));
+
+    return type2Subrs;
+  },
+
   /*
    * Flatten the commands by interpreting the postscript code and replacing
    * every 'callsubr', 'callothersubr' by the real commands.
-   *
-   * TODO This function also do a string to command number transformation
-   * that can probably be avoided if the Type1 decodeCharstring code is smarter
    */
   commandsMap: {
     "hstem": 1,
@@ -1573,58 +1605,27 @@ CFF.prototype = {
     "hvcurveto": 31,
   },
 
-  flattenCharstring: function flattenCharstring(charstring) {
-    var i = 0;
-    while (true) {
-      var obj = charstring[i];
-      if (obj == undefined) {
-        error("unknow charstring command for " + i + " in " + charstring);
-      }
-      if (obj.charAt) {
-        switch (obj) {
-          case "endchar":
-          case "return":
-            // CharString is ready to be re-encode to commands number at this point
-            for (var j = 0; j < charstring.length; j++) {
-              var command = charstring[j];
-              if (parseFloat(command) == command) {
-                charstring.splice(j, 1, 28, command >> 8, command);
-                j+= 2;
-              } else if (command.charAt) {
-                var cmd = this.commandsMap[command];
-                if (!cmd)
-                  error("Unknow command: " + command);
+  flattenCharstring: function flattenCharstring(charstring, map) {
+    for (var i = 0; i < charstring.length; i++) {
+      var command = charstring[i];
+      if (command.charAt) {
+        var cmd = map[command];
+        assert(cmd, "Unknow command: " + command);
 
-                if (IsArray(cmd)) {
-                  charstring.splice(j, 1, cmd[0], cmd[1]);
-                  j += 1;
-                } else {
-                  charstring[j] = cmd;
-                }
-              }
-            }
-            return charstring;
-
-          default:
-            break;
+        if (IsArray(cmd)) {
+          charstring.splice(i++, 1, cmd[0], cmd[1]);
+        } else {
+          charstring[i] = cmd;
         }
+      } else {
+        charstring.splice(i, 1, 28, command >> 8, command & 0xff);
+        i+= 2;
       }
-      i++;
     }
-    error("failing with i = " + i + " in charstring:" + charstring + "(" + charstring.length + ")");
-    return [];
+    return charstring;
   },
 
-  wrap: function wrap(name, charstrings, subrs, properties) {
-    // Starts the conversion of the Type1 charstrings to Type2
-    var glyphs = [];
-	  var glyphsCount = charstrings.length;
-    for (var i = 0; i < glyphsCount; i++) {
-      var charstring = charstrings[i].charstring;
-      glyphs.push(this.flattenCharstring(charstring.slice()));
-    }
-
-    // Create a CFF font data
+  wrap: function wrap(name, glyphs, charstrings, subrs, properties) {
     var cff = new Uint8Array(kMaxFontFileSize);
     var currentOffset = 0;
 
@@ -1656,10 +1657,12 @@ CFF.prototype = {
 
     // Fill the charset header (first byte is the encoding)
     var charset = [0x00];
+	  var glyphsCount = glyphs.length;
     for (var i = 0; i < glyphsCount; i++) {
       var index = CFFStrings.indexOf(charstrings[i].glyph);
       if (index == -1)
         index = CFFStrings.length + strings.indexOf(charstrings[i].glyph);
+
       var bytes = FontsUtils.integerToBytes(index, 2);
       charset.push(bytes[0]);
       charset.push(bytes[1]);
@@ -1731,28 +1734,9 @@ CFF.prototype = {
     cff.set(privateData, currentOffset);
     currentOffset += privateData.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);
+    // Local subrs
+    var subrsData = this.createCFFIndexHeader(subrs, true);
     cff.set(subrsData, currentOffset);
     currentOffset += subrsData.length;
 

From db30cc6de1a30f24d57f99e4f64d07e2cb082325 Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Fri, 1 Jul 2011 00:57:17 +0200
Subject: [PATCH 02/11] Start converting CFF class to use strings instead of
 arrays

---
 fonts.js | 55 ++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 34 insertions(+), 21 deletions(-)

diff --git a/fonts.js b/fonts.js
index 054185009..ad008c375 100644
--- a/fonts.js
+++ b/fonts.js
@@ -1483,24 +1483,24 @@ CFF.prototype = {
     // If there is no object, just create an array saying that with another
     // offset byte.
     if (count == 0)
-      return [0x00, 0x00, 0x00];
+      return "\x00\x00\x00";
 
-    var data = [];
+    var data = "";
     var bytes = FontsUtils.integerToBytes(count, 2);
     for (var i = 0; i < bytes.length; i++)
-      data.push(bytes[i]);
+      data += String.fromCharCode(bytes[i]);
 
     // Next byte contains the offset size use to reference object in the file
     // Actually we're using 0x04 to be sure to be able to store everything
     // without thinking of it while coding.
-    data.push(0x04);
+    data += "\x04";
 
     // Add another offset after this one because we need a new offset
     var relativeOffset = 1;
     for (var i = 0; i < count + 1; i++) {
       var bytes = FontsUtils.integerToBytes(relativeOffset, 4);
       for (var j = 0; j < bytes.length; j++)
-        data.push(bytes[j]);
+        data += String.fromCharCode(bytes[j]);
 
       if (objects[i])
         relativeOffset += objects[i].length;
@@ -1508,17 +1508,22 @@ CFF.prototype = {
 
     for (var i =0; i < count; i++) {
       for (var j = 0; j < objects[i].length; j++)
-        data.push(isByte ? objects[i][j] : objects[i].charCodeAt(j));
+        data += isByte ? String.fromCharCode(objects[i][j]) : objects[i][j];
     }
     return data;
   },
 
   encodeNumber: function cff_encodeNumber(value) {
-    var x = 0;
     if (value >= -32768 && value <= 32767) {
-      return [ 28, value >> 8, value & 0xFF ];
+      return "\x1c" +
+             String.fromCharCode(value >> 8) +
+             String.fromCharCode(value & 0xFF);
     } else if (value >= (-2147483647-1) && value <= 2147483647) {
-      return [ 0xFF, value >> 24, Value >> 16, value >> 8, value & 0xFF ];
+      return "\xff" +
+             String.fromCharCode(value >> 24) +
+             String.fromCharCode(value >> 16) +
+             String.fromCharCode(value >> 8) +
+             String.fromCharCode(value & 0xFF);
     }
     error("Value: " + value + " is not allowed");
     return null;
@@ -1626,16 +1631,24 @@ CFF.prototype = {
   },
 
   wrap: function wrap(name, glyphs, charstrings, subrs, properties) {
+    function stringToArray(str) {
+      var array = [];
+      for (var i = 0; i < str.length; ++i)
+        array[i] = str.charCodeAt(i);
+
+      return array;
+    };
+
     var cff = new Uint8Array(kMaxFontFileSize);
     var currentOffset = 0;
 
     // Font header (major version, minor version, header size, offset size)
-    var header = [0x01, 0x00, 0x04, 0x04];
+    var header = "\x01\x00\x04\x04";
     currentOffset += header.length;
-    cff.set(header);
+    cff.set(stringToArray(header));
 
     // Names Index
-    var nameIndex = this.createCFFIndexHeader([name]);
+    var nameIndex = stringToArray(this.createCFFIndexHeader([name]));
     cff.set(nameIndex, currentOffset);
     currentOffset += nameIndex.length;
 
@@ -1649,11 +1662,11 @@ CFF.prototype = {
     var weight = "";
     var strings = [version, notice, fullName,
                    familyName, weight];
-    var stringsIndex = this.createCFFIndexHeader(strings);
+    var stringsIndex = stringToArray(this.createCFFIndexHeader(strings));
     var stringsDataLength = stringsIndex.length;
 
     // Create the global subroutines index
-    var globalSubrsIndex = this.createCFFIndexHeader([]);
+    var globalSubrsIndex = stringToArray(this.createCFFIndexHeader([]));
 
     // Fill the charset header (first byte is the encoding)
     var charset = [0x00];
@@ -1668,7 +1681,7 @@ CFF.prototype = {
       charset.push(bytes[1]);
     }
 
-    var charstringsIndex = this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs), true);
+    var charstringsIndex = stringToArray(this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs), true));
 
     //Top Dict Index
     var topDictIndex = [
@@ -1682,25 +1695,25 @@ CFF.prototype = {
 
     var fontBBox = properties.bbox;
     for (var i = 0; i < fontBBox.length; i++)
-      topDictIndex = topDictIndex.concat(this.encodeNumber(fontBBox[i]));
+      topDictIndex = topDictIndex.concat(stringToArray(this.encodeNumber(fontBBox[i])));
     topDictIndex.push(5) // FontBBox;
 
     var charsetOffset = currentOffset +
                         (topDictIndex.length + (4 + 4 + 4 + 7)) +
                         stringsIndex.length +
                         globalSubrsIndex.length;
-    topDictIndex = topDictIndex.concat(this.encodeNumber(charsetOffset));
+    topDictIndex = topDictIndex.concat(stringToArray(this.encodeNumber(charsetOffset)));
     topDictIndex.push(15); // charset
 
     topDictIndex = topDictIndex.concat([28, 0, 0, 16]) // Encoding
 
     var charstringsOffset = charsetOffset + (glyphsCount * 2) + 1;
-    topDictIndex = topDictIndex.concat(this.encodeNumber(charstringsOffset));
+    topDictIndex = topDictIndex.concat(stringToArray(this.encodeNumber(charstringsOffset)));
     topDictIndex.push(17); // charstrings
 
     topDictIndex = topDictIndex.concat([28, 0, 55])
     var privateOffset = charstringsOffset + charstringsIndex.length;
-    topDictIndex = topDictIndex.concat(this.encodeNumber(privateOffset));
+    topDictIndex = topDictIndex.concat(stringToArray(this.encodeNumber(privateOffset)));
     topDictIndex.push(18); // Private
 
     var indexes = [
@@ -1716,7 +1729,7 @@ CFF.prototype = {
     }
 
     // Private Data
-    var defaultWidth = this.encodeNumber(0);
+    var defaultWidth = stringToArray(this.encodeNumber(0));
     var privateData = [].concat(
       defaultWidth, [20],
       [139, 21], // nominalWidth
@@ -1736,7 +1749,7 @@ CFF.prototype = {
 
 
     // Local subrs
-    var subrsData = this.createCFFIndexHeader(subrs, true);
+    var subrsData = stringToArray(this.createCFFIndexHeader(subrs, true));
     cff.set(subrsData, currentOffset);
     currentOffset += subrsData.length;
 

From dae18a271007310ce07a2c2434fface62dcb8f16 Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Fri, 1 Jul 2011 03:24:23 +0200
Subject: [PATCH 03/11] Use strings instead of arrays in CFF.wrap

---
 fonts.js | 213 ++++++++++++++++++++++++-------------------------------
 1 file changed, 92 insertions(+), 121 deletions(-)

diff --git a/fonts.js b/fonts.js
index ad008c375..0c6545f0c 100644
--- a/fonts.js
+++ b/fonts.js
@@ -1631,133 +1631,104 @@ CFF.prototype = {
   },
 
   wrap: function wrap(name, glyphs, charstrings, subrs, properties) {
-    function stringToArray(str) {
-      var array = [];
-      for (var i = 0; i < str.length; ++i)
-        array[i] = str.charCodeAt(i);
+    var fields = {
+      "header": "\x01\x00\x04\x04", // major version, minor version, header size, offset size
 
-      return array;
+      "names": this.createCFFIndexHeader([name]),
+
+      "topDict": (function topDict(self) {
+        return function() {
+          var dict =
+              "\x00\x01\x01\x01\x30" +
+              "\xf8\x1b\x00" + // version
+              "\xf8\x1b\x01" + // Notice
+              "\xf8\x1b\x02" + // FullName
+              "\xf8\x1b\x03" + // FamilyName
+              "\xf8\x1b\x04" +  // Weight
+              "\x1c\x00\x00\x10"; // Encoding
+
+          var boundingBox = properties.bbox;
+          for (var i = 0; i < boundingBox.length; i++)
+            dict += self.encodeNumber(boundingBox[i]);
+          dict += "\x05"; // FontBBox;
+
+          var offset = fields.header.length +
+                       fields.names.length +
+                       (dict.length + (4 + 4 + 7)) +
+                       fields.strings.length +
+                       fields.globalSubrs.length;
+          dict += self.encodeNumber(offset) + "\x0f"; // Charset
+
+          offset = offset + (glyphs.length * 2) + 1;
+          dict += self.encodeNumber(offset) + "\x11"; // Charstrings
+
+          dict += self.encodeNumber(fields.private.length);
+          var offset = offset + fields.charstrings.length;
+          dict += self.encodeNumber(offset) + "\x12"; // Private
+
+          return dict;
+        };
+      })(this),
+
+      "strings": (function strings(self) {
+        var strings = [
+          "Version 0.11",         // Version
+          "See original notice",  // Notice
+          name,                   // FullName
+          name,                   // FamilyName
+          "Medium"                // Weight
+        ];
+        return self.createCFFIndexHeader(strings);
+      })(this),
+
+      "globalSubrs": this.createCFFIndexHeader([]),
+
+      "charset": (function charset(self) {
+        var charset = "\x00"; // Encoding
+
+	      var count = glyphs.length;
+        for (var i = 0; i < count; i++) {
+          var index = CFFStrings.indexOf(charstrings[i].glyph.glyph);
+          // Some characters like asterikmath && circlecopyrt are missing from the
+          // original strings, for the moment let's map them to .notdef and see
+          // later if it cause any problems
+          if (index == -1)
+            index = 0;
+
+          var bytes = FontsUtils.integerToBytes(index, 2);
+          charset += String.fromCharCode(bytes[0]) + String.fromCharCode(bytes[1]);
+        }
+        return charset;
+      })(this),
+
+      "charstrings": this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs), true),
+
+      "private": (function(self) {
+        var data =
+            "\x8b\x14" + // defaultWidth
+            "\x8b\x15" + // nominalWidth
+            "\x8b\x0a" + // StdHW
+            "\x8b\x0a" + // StdVW
+            "\x8b\x8b\x0c\x0c" + // StemSnapH
+            "\x8b\x8b\x0c\x0d";  // StemSnapV
+        data += self.encodeNumber(data.length + 4) + "\x13"; // Subrs offset
+
+        return data;
+      })(this),
+
+      "localSubrs": this.createCFFIndexHeader(subrs, true)
     };
+    fields.topDict = fields.topDict();
 
-    var cff = new Uint8Array(kMaxFontFileSize);
-    var currentOffset = 0;
 
-    // Font header (major version, minor version, header size, offset size)
-    var header = "\x01\x00\x04\x04";
-    currentOffset += header.length;
-    cff.set(stringToArray(header));
-
-    // Names Index
-    var nameIndex = stringToArray(this.createCFFIndexHeader([name]));
-    cff.set(nameIndex, currentOffset);
-    currentOffset += nameIndex.length;
-
-    // Calculate strings before writing the TopDICT index in order
-    // to calculate correct relative offsets for storing 'charset'
-    // and 'charstrings' data
-    var version = "";
-    var notice = "";
-    var fullName = "";
-    var familyName = "";
-    var weight = "";
-    var strings = [version, notice, fullName,
-                   familyName, weight];
-    var stringsIndex = stringToArray(this.createCFFIndexHeader(strings));
-    var stringsDataLength = stringsIndex.length;
-
-    // Create the global subroutines index
-    var globalSubrsIndex = stringToArray(this.createCFFIndexHeader([]));
-
-    // Fill the charset header (first byte is the encoding)
-    var charset = [0x00];
-	  var glyphsCount = glyphs.length;
-    for (var i = 0; i < glyphsCount; i++) {
-      var index = CFFStrings.indexOf(charstrings[i].glyph);
-      if (index == -1)
-        index = CFFStrings.length + strings.indexOf(charstrings[i].glyph);
-
-      var bytes = FontsUtils.integerToBytes(index, 2);
-      charset.push(bytes[0]);
-      charset.push(bytes[1]);
+    var cff = [];
+    for (var index in fields) {
+      var field = fields[index];
+      for (var i = 0; i < field.length; i++)
+        cff.push(field.charCodeAt(i));
     }
 
-    var charstringsIndex = stringToArray(this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs), true));
-
-    //Top Dict Index
-    var topDictIndex = [
-      0x00, 0x01, 0x01, 0x01, 0x30,
-      248, 27, 0, // version
-      248, 28, 1, // Notice
-      248, 29, 2, // FullName
-      248, 30, 3, // FamilyName
-      248, 31, 4  // Weight
-    ];
-
-    var fontBBox = properties.bbox;
-    for (var i = 0; i < fontBBox.length; i++)
-      topDictIndex = topDictIndex.concat(stringToArray(this.encodeNumber(fontBBox[i])));
-    topDictIndex.push(5) // FontBBox;
-
-    var charsetOffset = currentOffset +
-                        (topDictIndex.length + (4 + 4 + 4 + 7)) +
-                        stringsIndex.length +
-                        globalSubrsIndex.length;
-    topDictIndex = topDictIndex.concat(stringToArray(this.encodeNumber(charsetOffset)));
-    topDictIndex.push(15); // charset
-
-    topDictIndex = topDictIndex.concat([28, 0, 0, 16]) // Encoding
-
-    var charstringsOffset = charsetOffset + (glyphsCount * 2) + 1;
-    topDictIndex = topDictIndex.concat(stringToArray(this.encodeNumber(charstringsOffset)));
-    topDictIndex.push(17); // charstrings
-
-    topDictIndex = topDictIndex.concat([28, 0, 55])
-    var privateOffset = charstringsOffset + charstringsIndex.length;
-    topDictIndex = topDictIndex.concat(stringToArray(this.encodeNumber(privateOffset)));
-    topDictIndex.push(18); // Private
-
-    var indexes = [
-      topDictIndex, stringsIndex,
-      globalSubrsIndex, charset,
-      charstringsIndex
-    ];
-
-    for (var i = 0; i < indexes.length; i++) {
-      var index = indexes[i];
-      cff.set(index, currentOffset);
-      currentOffset += index.length;
-    }
-
-    // Private Data
-    var defaultWidth = stringToArray(this.encodeNumber(0));
-    var privateData = [].concat(
-      defaultWidth, [20],
-      [139, 21], // nominalWidth
-      [
-      119, 159, 248, 97, 159, 247, 87, 159, 6,
-      30, 10, 3, 150, 37, 255, 12, 9,
-      139, 12,
-      10, 172, 10,
-      172, 150, 143, 146, 150, 146, 12, 12,
-      247, 32, 11,
-      247, 10, 161, 147, 154, 150, 143, 12, 13,
-      139, 12, 14,
-      28, 0, 55, 19 // Subrs offset
-    ]);
-    cff.set(privateData, currentOffset);
-    currentOffset += privateData.length;
-
-
-    // Local subrs
-    var subrsData = stringToArray(this.createCFFIndexHeader(subrs, true));
-    cff.set(subrsData, currentOffset);
-    currentOffset += subrsData.length;
-
-    var fontData = [];
-    for (var i = 0; i < currentOffset; i++)
-      fontData.push(cff[i]);
-
-    return fontData;
+    return cff;
   }
 };
 

From ae2d130f40fda83f24c3222e953e448864e190f2 Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Fri, 1 Jul 2011 05:16:27 +0200
Subject: [PATCH 04/11] Improve the extractInfo code to be more robust

---
 fonts.js | 78 +++++++++++++++++++++++++-------------------------------
 1 file changed, 35 insertions(+), 43 deletions(-)

diff --git a/fonts.js b/fonts.js
index a3cb05a9f..bc20e22e1 100644
--- a/fonts.js
+++ b/fonts.js
@@ -1333,14 +1333,19 @@ var Type1Parser = function() {
    * extracted from and eexec encrypted block of data
    */
   this.extractFontProgram = function t1_extractFontProgram(stream) {
-    var eexecString = decrypt(stream, kEexecEncryptionKey, 4);
-    var subrs = [],  glyphs = [];
-    var inGlyphs = false;
-    var inSubrs = false;
-    var glyph = "";
+    var eexec = decrypt(stream, kEexecEncryptionKey, 4);
+    var eexecString = "";
+    for (var i = 0; i < eexec.length; i++)
+      eexecString += String.fromCharCode(eexec[i]);
 
+    var glyphsSection = false, subrsSection = false;
+    var extracted = {
+      subrs: [],
+      charstrings: []
+    };
+
+    var glyph = "";
     var token = "";
-    var index = 0;
     var length = 0;
 
     var c = "";
@@ -1348,52 +1353,39 @@ var Type1Parser = function() {
     for (var i = 0; i < count; i++) {
       var c = eexecString[i];
 
-      if (inSubrs && c == 0x52) {
-        length = parseInt(length);
-        var data = eexecString.slice(i + 3, i + 3 + length);
-        var encodedSubr = decrypt(data, kCharStringsEncryptionKey, 4);
-        var str = decodeCharString(encodedSubr);
+      if ((glyphsSection || subrsSection) && c == "R") {
+        var data = eexec.slice(i + 3, i + 3 + length);
+        var encoded = decrypt(data, kCharStringsEncryptionKey, 4);
+        var str = decodeCharString(encoded);
 
-        subrs.push(str.charstring);
-        i += 3 + length;
-      } else if (inGlyphs && c == 0x52) {
-        length = parseInt(length);
-        var data = eexecString.slice(i + 3, i + 3 + length);
-        var encodedCharstring = decrypt(data, kCharStringsEncryptionKey, 4);
-        var str = decodeCharString(encodedCharstring);
-
-        glyphs.push({
+        if (glyphsSection) {
+          extracted.charstrings.push({
             glyph: glyph,
             data: str.charstring,
             lsb: str.lsb,
             width: str.width
-        });
-        i += 3 + length;
-      } else if (inGlyphs && c == 0x2F) {
+          });
+        } else {
+          extracted.subrs.push(str.charstring);
+        }
+        i += length + 3;
+      } else if (c == " ") {
+        length = parseInt(token);
         token = "";
-        glyph = "";
-
-        while ((c = eexecString[++i]) != 0x20)
-          glyph += String.fromCharCode(c);
-      } else if (!inSubrs && !inGlyphs && c == 0x2F && eexecString[i+1] == 0x53) {
-        while ((c = eexecString[++i]) != 0x20) {};
-        inSubrs = true;
-      } else if (c == 0x20) {
-        index = length;
-        length = token;
-        token = "";
-      } else if (c == 0x2F && eexecString[i+1] == 0x43 && eexecString[i+2] == 0x68) {
-        while ((c = eexecString[++i]) != 0x20) {};
-        inSubrs = false;
-        inGlyphs = true;
       } else {
-        token += String.fromCharCode(c);
+        token += c;
+        if (!glyphsSection) {
+          glyphsSection = token.indexOf("/CharString") != -1;
+          subrsSection = subrsSection || token.indexOf("Subrs") != -1;
+        } else if (c == "/") {
+          token = glyph = "";
+          while ((c = eexecString[++i]) != " ")
+            glyph += c;
+        }
       }
     }
-    return {
-      subrs: subrs,
-      charstrings: glyphs
-    }
+
+    return extracted;
   }
 };
 

From e13164eca6a37c71c01ffa5a3ea672a508de564b Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Fri, 1 Jul 2011 07:16:56 +0200
Subject: [PATCH 05/11] Read the text matrix from the Type1 font ascii header

---
 fonts.js | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 pdf.js   |  6 ++++--
 2 files changed, 66 insertions(+), 5 deletions(-)

diff --git a/fonts.js b/fonts.js
index bc20e22e1..1e32dfbc3 100644
--- a/fonts.js
+++ b/fonts.js
@@ -8,7 +8,7 @@ var isWorker = (typeof window == "undefined");
 /**
  * Maximum file size of the font.
  */
-var kMaxFontFileSize = 200000;
+var kMaxFontFileSize = 40000;
 
 /**
  * Maximum time to wait for a font to be loaded by @font-face
@@ -77,6 +77,9 @@ var Fonts = (function Fonts() {
         measureCache = sizes[size] = Object.create(null);
       ctx.font = (size * kScalePrecision) + 'px "' + fontName + '"';
     },
+    getActive: function fonts_getActive() {
+      return current;
+    },
     charsToUnicode: function fonts_chars2Unicode(chars) {
       if (!charsCache)
         return chars;
@@ -1386,7 +1389,57 @@ var Type1Parser = function() {
     }
 
     return extracted;
-  }
+  },
+
+  this.extractFontHeader = function t1_extractFontProgram(stream) {
+    var headerString = "";
+    for (var i = 0; i < stream.length; i++)
+      headerString += String.fromCharCode(stream[i]);
+
+    var info = {
+      textMatrix: null
+    };
+
+    function readNumberArray(str, index) {
+      var start = ++index;
+      var count = 0;
+      while ((c = str[index++]) != "]")
+        count++;
+
+      var array = str.substr(start, count).split(" ");
+      for (var i = 0; i < array.length; i++)
+        array[i] = parseFloat(array[i]);
+      return array;
+    };
+
+    var token = "";
+    var count = headerString.length;
+    for (var i = 0; i < count; i++) {
+      var c = headerString[i];
+      if (c == " " || c == "\n") {
+        switch (token) {
+          case "/FontMatrix":
+            var matrix = readNumberArray(headerString, i + 1);
+
+            // The FontMatrix is in unitPerEm, so make it pixels
+            for (var j = 0; j < matrix.length; j++)
+              matrix[j] *= 1000;
+
+            // Make the angle into the right direction
+            matrix[2] *= -1;
+
+            info.textMatrix = matrix;
+            break;
+        }
+        token = "";
+      } else {
+        token += c;
+      }
+    }
+
+    return info;
+  };
+
 };
 
 /**
@@ -1457,7 +1510,12 @@ var CFF = function(name, file, properties) {
   // Get the data block containing glyphs and subrs informations
   var length1 = file.dict.get("Length1");
   var length2 = file.dict.get("Length2");
-  file.skip(length1);
+
+  var headerBlock = file.getBytes(length1);
+  var header = type1Parser.extractFontHeader(headerBlock);
+  for (var info in header) {
+    properties[info] = header[info];
+  }
 
   // Decrypt the data blocks and retrieve it's content
   var eexecBlock = file.getBytes(length2);
@@ -1700,6 +1758,7 @@ CFF.prototype = {
       "charstrings": this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs), true),
 
       "private": (function(self) {
+          log(properties.stemSnapH);
         var data =
             "\x8b\x14" + // defaultWidth
             "\x8b\x15" + // nominalWidth
diff --git a/pdf.js b/pdf.js
index 3e3654087..f0e58b1b7 100644
--- a/pdf.js
+++ b/pdf.js
@@ -3544,7 +3544,8 @@ var CanvasGraphics = (function() {
                 capHeight: descriptor.get("CapHeight"),
                 flags: descriptor.get("Flags"),
                 italicAngle: descriptor.get("ItalicAngle"),
-                fixedPitch: false
+                fixedPitch: false,
+                textMatrix: IDENTITY_MATRIX.slice()
             };
 
             return {
@@ -3861,7 +3862,6 @@ var CanvasGraphics = (function() {
             // TODO: apply charSpacing, wordSpacing, textHScale
 
             this.ctx.save();
-            this.ctx.transform.apply(this.ctx, this.current.textMatrix);
             this.ctx.scale(1, -1);
 
             if (this.ctx.$showText) {
@@ -3869,6 +3869,8 @@ var CanvasGraphics = (function() {
             } else {
                 text = Fonts.charsToUnicode(text);
                 this.ctx.translate(this.current.x, -1 * this.current.y);
+                var matrix = Fonts.lookup(this.current.fontName).properties.textMatrix;
+                this.ctx.transform.apply(this.ctx, matrix);
                 this.ctx.fillText(text, 0, 0);
                 this.current.x += Fonts.measureText(text);
             }

From 22264c07c89f0539fc274fb6db0cf632b61adcc3 Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Fri, 1 Jul 2011 07:24:48 +0200
Subject: [PATCH 06/11] Fix TrueType bustage

---
 pdf.js | 1 +
 1 file changed, 1 insertion(+)

diff --git a/pdf.js b/pdf.js
index f0e58b1b7..12ab5acc3 100644
--- a/pdf.js
+++ b/pdf.js
@@ -3862,6 +3862,7 @@ var CanvasGraphics = (function() {
             // TODO: apply charSpacing, wordSpacing, textHScale
 
             this.ctx.save();
+            this.ctx.transform.apply(this.ctx, this.current.textMatrix);
             this.ctx.scale(1, -1);
 
             if (this.ctx.$showText) {

From 63e4f0293f6a0f39b8bb65ba3d0f60c87a973123 Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Fri, 1 Jul 2011 11:28:22 +0200
Subject: [PATCH 07/11] Add support for stemHW/stemVW/stemSnapH/stemSnapV

---
 fonts.js | 78 +++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 54 insertions(+), 24 deletions(-)

diff --git a/fonts.js b/fonts.js
index 1e32dfbc3..880480b29 100644
--- a/fonts.js
+++ b/fonts.js
@@ -1335,6 +1335,18 @@ var Type1Parser = function() {
    * Returns an object containing a Subrs array and a CharStrings array
    * extracted from and eexec encrypted block of data
    */
+  function readNumberArray(str, index) {
+    var start = ++index;
+    var count = 0;
+    while (str[index++] != "]")
+      count++;
+
+    var array = str.substr(start, count).split(" ");
+    for (var i = 0; i < array.length; i++)
+      array[i] = parseFloat(array[i] || 0);
+    return array;
+  };
+
   this.extractFontProgram = function t1_extractFontProgram(stream) {
     var eexec = decrypt(stream, kEexecEncryptionKey, 4);
     var eexecString = "";
@@ -1344,7 +1356,11 @@ var Type1Parser = function() {
     var glyphsSection = false, subrsSection = false;
     var extracted = {
       subrs: [],
-      charstrings: []
+      charstrings: [],
+      properties: {
+        stemSnapH: [0, 0],
+        stemSnapV: [0, 0]
+      }
     };
 
     var glyph = "";
@@ -1372,14 +1388,32 @@ var Type1Parser = function() {
           extracted.subrs.push(str.charstring);
         }
         i += length + 3;
-      } else if (c == " ") {
+      } else if (c == " " || c == "\n") {
         length = parseInt(token);
         token = "";
       } else {
         token += c;
         if (!glyphsSection) {
-          glyphsSection = token.indexOf("/CharString") != -1;
-          subrsSection = subrsSection || token.indexOf("Subrs") != -1;
+          switch (token) {
+            case "/CharString":
+              glyphsSection = true;
+              break;
+            case "/Subrs":
+              subrsSection = true;
+              break;
+            case "/StdHW":
+              extracted.properties.stdHW = readNumberArray(eexecString, i + 2)[0];
+              break;
+            case "/StdVW":
+              extracted.properties.stdVW = readNumberArray(eexecString, i + 2)[0];
+              break;
+            case "/StemSnapH":
+              extracted.properties.stemSnapH = readNumberArray(eexecString, i + 2);
+              break;
+            case "/StemSnapV":
+              extracted.properties.stemSnapV = readNumberArray(eexecString, i + 2);
+              break;
+          }
         } else if (c == "/") {
           token = glyph = "";
           while ((c = eexecString[++i]) != " ")
@@ -1400,18 +1434,6 @@ var Type1Parser = function() {
       textMatrix: null
     };
 
-    function readNumberArray(str, index) {
-      var start = ++index;
-      var count = 0;
-      while ((c = str[index++]) != "]")
-        count++;
-
-      var array = str.substr(start, count).split(" ");
-      for (var i = 0; i < array.length; i++)
-        array[i] = parseFloat(array[i]);
-      return array;
-    };
-
     var token = "";
     var count = headerString.length;
     for (var i = 0; i < count; i++) {
@@ -1439,7 +1461,6 @@ var Type1Parser = function() {
 
     return info;
   };
-
 };
 
 /**
@@ -1513,13 +1534,14 @@ var CFF = function(name, file, properties) {
 
   var headerBlock = file.getBytes(length1);
   var header = type1Parser.extractFontHeader(headerBlock);
-  for (var info in header) {
+  for (var info in header)
     properties[info] = header[info];
-  }
 
   // Decrypt the data blocks and retrieve it's content
   var eexecBlock = file.getBytes(length2);
   var data = type1Parser.extractFontProgram(eexecBlock);
+  for (var info in data.properties)
+    properties[info] = data.properties[info];
 
   var charstrings = this.getOrderedCharStrings(data.charstrings);
   var type2Charstrings = this.getType2Charstrings(charstrings);
@@ -1758,14 +1780,22 @@ CFF.prototype = {
       "charstrings": this.createCFFIndexHeader([[0x8B, 0x0E]].concat(glyphs), true),
 
       "private": (function(self) {
-          log(properties.stemSnapH);
         var data =
             "\x8b\x14" + // defaultWidth
             "\x8b\x15" + // nominalWidth
-            "\x8b\x0a" + // StdHW
-            "\x8b\x0a" + // StdVW
-            "\x8b\x8b\x0c\x0c" + // StemSnapH
-            "\x8b\x8b\x0c\x0d";  // StemSnapV
+            self.encodeNumber(properties.stdHW) + "\x0a" + // StdHW
+            self.encodeNumber(properties.stdVW) + "\x0b";  // StdVW
+
+        var stemH = properties.stemSnapH;
+        for (var i = 0; i < stemH.length; i++)
+          data += self.encodeNumber(stemH[i]);
+        data += "\x0c\x0c"; // StemSnapH
+
+        var stemV = properties.stemSnapV;
+        for (var i = 0; i < stemV.length; i++)
+          data += self.encodeNumber(stemV[i]);
+        data += "\x0c\x0d"; // StemSnapV
+
         data += self.encodeNumber(data.length + 4) + "\x13"; // Subrs offset
 
         return data;

From d10cf7c9298f5eccf7fff70a78b0b48f77375227 Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Sat, 2 Jul 2011 00:19:24 +0200
Subject: [PATCH 08/11] Reland commit 442d184 but make it works with
 uncompressed PDF

---
 fonts.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/fonts.js b/fonts.js
index 880480b29..afd48b401 100644
--- a/fonts.js
+++ b/fonts.js
@@ -624,6 +624,8 @@ var Font = (function () {
       };
 
       function replaceCMapTable(cmap, font, properties) {
+        font.pos = (font.start ? font.start : 0) + cmap.length;
+
         var version = FontsUtils.bytesToInteger(font.getBytes(2));
         var numTables = FontsUtils.bytesToInteger(font.getBytes(2));
 

From 3dcf65d9df5e9557b78727663ef51d3ae0f1b09b Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Sat, 2 Jul 2011 01:01:55 +0200
Subject: [PATCH 09/11] Fix a small issue in the waiting for font to load code

---
 fonts.js | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/fonts.js b/fonts.js
index afd48b401..e484bc5b3 100644
--- a/fonts.js
+++ b/fonts.js
@@ -38,11 +38,11 @@ var kDisableFonts = false;
 
 var Fonts = (function Fonts() {
   var kScalePrecision = 40;
-  var fonts = Object.create(null);  
+  var fonts = Object.create(null);
 
   if (!isWorker) {
     var ctx = document.createElement("canvas").getContext("2d");
-    ctx.scale(1 / kScalePrecision, 1);    
+    ctx.scale(1 / kScalePrecision, 1);
   }
 
   function Font(name, data, properties) {
@@ -77,9 +77,6 @@ var Fonts = (function Fonts() {
         measureCache = sizes[size] = Object.create(null);
       ctx.font = (size * kScalePrecision) + 'px "' + fontName + '"';
     },
-    getActive: function fonts_getActive() {
-      return current;
-    },
     charsToUnicode: function fonts_chars2Unicode(chars) {
       if (!charsCache)
         return chars;
@@ -477,10 +474,11 @@ var Font = (function () {
       startCount += string16(start);
       endCount += string16(end);
       idDeltas += string16(delta);
-	  idRangeOffsets += string16(0);
+	    idRangeOffsets += string16(0);
 
-      for (var j = 0; j < range.length; j++)
-        glyphsIds += String.fromCharCode(range[j]);
+      for (var j = start; j < end; j++) {
+        glyphsIds += string16(j);
+      }
     }
 
     startCount += "\xFF\xFF";
@@ -1034,8 +1032,9 @@ var Font = (function () {
       // different once the real font has loaded
       var textWidth = ctx.measureText(testString).width;
 
+      var start = Date.now();
       var interval = window.setInterval(function canvasInterval(self) {
-        this.start = this.start || Date.now();
+        this.start = start;
         ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial";
 
         // For some reasons the font has not loaded, so mark it loaded for the

From 3726686d22deac5d299b890bd0f7359053717956 Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Sat, 2 Jul 2011 02:44:57 +0200
Subject: [PATCH 10/11] Add a format100 table for Mac

---
 fonts.js             | 44 +++++++++++++++++++++++++++++---------------
 utils/fonts_utils.js |  6 +-----
 2 files changed, 30 insertions(+), 20 deletions(-)

diff --git a/fonts.js b/fonts.js
index e484bc5b3..ff25a08ee 100644
--- a/fonts.js
+++ b/fonts.js
@@ -437,6 +437,24 @@ var Font = (function () {
     glyphs.push({ unicode: 0x0000 });
     var ranges = getRanges(glyphs);
 
+    var numTables = 2;
+    var kFormat100ArraySize = 256;
+    var cmap = "\x00\x00" + // version
+               string16(numTables) +  // numTables
+               "\x00\x01" + // platformID
+               "\x00\x00" + // encodingID
+               string32(4 + numTables * 8) + // start of the table record
+               "\x00\x03" + // platformID
+               "\x00\x01" + // encodingID
+               string32(4 + numTables * 8 + 6 + kFormat100ArraySize); // start of the table record
+
+    var format100 = "\x00\x00" + // format
+                    string16(6 + kFormat100ArraySize) + // length
+                    "\x00\x00"; // language
+
+    for (var i = 0; i < kFormat100ArraySize; i++)
+      format100 += String.fromCharCode(i);
+
     var headerSize = (12 * 2 + (ranges.length * 4 * 2));
     var segCount = ranges.length + 1;
     var segCount2 = segCount * 2;
@@ -444,18 +462,13 @@ var Font = (function () {
     var searchEntry = Math.log(segCount) / Math.log(2);
     var rangeShift = 2 * segCount - searchRange;
 
-    var cmap = "\x00\x00" + // version
-               "\x00\x01" + // numTables
-               "\x00\x03" + // platformID
-               "\x00\x01" + // encodingID
-               "\x00\x00\x00\x0C" + // start of the table record
-               "\x00\x04" + // format
-               string16(headerSize) + // length
-               "\x00\x00" + // languages
-               string16(segCount2) +
-               string16(searchRange) +
-               string16(searchEntry) +
-               string16(rangeShift);
+    var format314 = "\x00\x04" + // format
+                    string16(headerSize) + // length
+                    "\x00\x00" + // language
+                    string16(segCount2) +
+                    string16(searchRange) +
+                    string16(searchEntry) +
+                    string16(rangeShift);
 
     // Fill up the 4 parallel arrays describing the segments.
     var startCount = "";
@@ -481,13 +494,14 @@ var Font = (function () {
       }
     }
 
-    startCount += "\xFF\xFF";
     endCount += "\xFF\xFF";
+    startCount += "\xFF\xFF";
     idDeltas += "\x00\x01";
     idRangeOffsets += "\x00\x00";
+    format314 += endCount + "\x00\x00" + startCount +
+                 idDeltas + idRangeOffsets + glyphsIds;
 
-    return stringToArray(cmap + endCount + "\x00\x00" + startCount +
-                         idDeltas + idRangeOffsets + glyphsIds);
+    return stringToArray(cmap + format100 + format314);
   };
 
   function createOS2Table(properties) {
diff --git a/utils/fonts_utils.js b/utils/fonts_utils.js
index 532853460..5bd5f2972 100644
--- a/utils/fonts_utils.js
+++ b/utils/fonts_utils.js
@@ -1,8 +1,6 @@
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 
-"use strict";
-
 /**
  * The Type2 reader code below is only used for debugging purpose since Type2
  * is only a CharString format and is never used directly as a Font file.
@@ -12,8 +10,6 @@
  * CharString or to understand the structure of the CFF format.
  */
 
-"use strict";
-
 /**
  * Build a charset by assigning the glyph name and the human readable form
  * of the glyph data.
@@ -388,7 +384,7 @@ function writeToFile(aBytes, aFilePath) {
 
   var stream = Cc["@mozilla.org/network/file-output-stream;1"]
                  .createInstance(Ci.nsIFileOutputStream);
-  stream.init(file, 0x04 | 0x08 | 0x20, 600, 0);
+  stream.init(file, 0x04 | 0x08 | 0x20, 0600, 0);
 
   var bos = Cc["@mozilla.org/binaryoutputstream;1"]
               .createInstance(Ci.nsIBinaryOutputStream);

From 3e78538c1c8a753bd56ab7f25362f936a1eee8f3 Mon Sep 17 00:00:00 2001
From: Vivien Nicolas <21@vingtetun.org>
Date: Sat, 2 Jul 2011 05:46:50 +0200
Subject: [PATCH 11/11] Remove cmap format 100, fixes some nits to merge with
 upstream

---
 fonts.js             | 27 ++++++++-------------------
 pdf.js               | 11 +++++++----
 utils/fonts_utils.js |  7 ++++++-
 3 files changed, 21 insertions(+), 24 deletions(-)

diff --git a/fonts.js b/fonts.js
index ff25a08ee..a871520ea 100644
--- a/fonts.js
+++ b/fonts.js
@@ -437,25 +437,14 @@ var Font = (function () {
     glyphs.push({ unicode: 0x0000 });
     var ranges = getRanges(glyphs);
 
-    var numTables = 2;
-    var kFormat100ArraySize = 256;
+    var numTables = 1;
     var cmap = "\x00\x00" + // version
                string16(numTables) +  // numTables
-               "\x00\x01" + // platformID
-               "\x00\x00" + // encodingID
-               string32(4 + numTables * 8) + // start of the table record
                "\x00\x03" + // platformID
                "\x00\x01" + // encodingID
-               string32(4 + numTables * 8 + 6 + kFormat100ArraySize); // start of the table record
+               string32(4 + numTables * 8); // start of the table record
 
-    var format100 = "\x00\x00" + // format
-                    string16(6 + kFormat100ArraySize) + // length
-                    "\x00\x00"; // language
-
-    for (var i = 0; i < kFormat100ArraySize; i++)
-      format100 += String.fromCharCode(i);
-
-    var headerSize = (12 * 2 + (ranges.length * 4 * 2));
+    var headerSize = (12 * 2 + (ranges.length * 5 * 2));
     var segCount = ranges.length + 1;
     var segCount2 = segCount * 2;
     var searchRange = FontsUtils.getMaxPower2(segCount) * 2;
@@ -481,7 +470,7 @@ var Font = (function () {
       var range = ranges[i];
       var start = range[0];
       var end = range[1];
-      var delta = (((start - 1) - bias) ^ 0xffff);
+      var delta = (bias - start) % 0xffff;
       bias += (end - start + 1);
 
       startCount += string16(start);
@@ -489,7 +478,7 @@ var Font = (function () {
       idDeltas += string16(delta);
 	    idRangeOffsets += string16(0);
 
-      for (var j = start; j < end; j++) {
+      for (var j = start; j <= end; j++) {
         glyphsIds += string16(j);
       }
     }
@@ -501,7 +490,7 @@ var Font = (function () {
     format314 += endCount + "\x00\x00" + startCount +
                  idDeltas + idRangeOffsets + glyphsIds;
 
-    return stringToArray(cmap + format100 + format314);
+    return stringToArray(cmap + format314);
   };
 
   function createOS2Table(properties) {
@@ -541,7 +530,7 @@ var Font = (function () {
            "\x02\x24" + // xAvgCharWidth
            "\x01\xF4" + // usWeightClass
            "\x00\x05" + // usWidthClass
-           "\x00\x02" + // fstype
+           "\x00\x00" + // fstype (0 to let the font loads via font-face on IE)
            "\x02\x8A" + // ySubscriptXSize
            "\x02\xBB" + // ySubscriptYSize
            "\x00\x00" + // ySubscriptXOffset
@@ -1075,7 +1064,7 @@ var Font = (function () {
       var url = "url(data:" + this.mimetype + ";base64," + window.btoa(data) + ");";
       var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}";
       var styleSheet = document.styleSheets[0];
-      styleSheet.insertRule(rule, styleSheet.length);
+      styleSheet.insertRule(rule, styleSheet.cssRules.length);
     }
   };
 
diff --git a/pdf.js b/pdf.js
index 12ab5acc3..493dd7ef0 100644
--- a/pdf.js
+++ b/pdf.js
@@ -3404,7 +3404,7 @@ var CanvasGraphics = (function() {
             BX: "beginCompat",
             EX: "endCompat",
         },
-      
+
         translateFont: function(fontDict, xref, resources) {
             var fd = fontDict.get("FontDescriptor");
             if (!fd)
@@ -3545,7 +3545,7 @@ var CanvasGraphics = (function() {
                 flags: descriptor.get("Flags"),
                 italicAngle: descriptor.get("ItalicAngle"),
                 fixedPitch: false,
-                textMatrix: IDENTITY_MATRIX.slice()
+                textMatrix: IDENTITY_MATRIX
             };
 
             return {
@@ -3870,8 +3870,11 @@ var CanvasGraphics = (function() {
             } else {
                 text = Fonts.charsToUnicode(text);
                 this.ctx.translate(this.current.x, -1 * this.current.y);
-                var matrix = Fonts.lookup(this.current.fontName).properties.textMatrix;
-                this.ctx.transform.apply(this.ctx, matrix);
+
+                var font = Fonts.lookup(this.current.fontName);
+                if (font)
+                  this.ctx.transform.apply(this.ctx, font.properties.textMatrix);
+
                 this.ctx.fillText(text, 0, 0);
                 this.current.x += Fonts.measureText(text);
             }
diff --git a/utils/fonts_utils.js b/utils/fonts_utils.js
index 5bd5f2972..bc0a8544c 100644
--- a/utils/fonts_utils.js
+++ b/utils/fonts_utils.js
@@ -1,6 +1,8 @@
 /* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- /
 /* vim: set shiftwidth=2 tabstop=2 autoindent cindent expandtab: */
 
+"use strict";
+
 /**
  * The Type2 reader code below is only used for debugging purpose since Type2
  * is only a CharString format and is never used directly as a Font file.
@@ -376,6 +378,9 @@ var Type2Parser = function(aFilePath) {
  * writeToFile(fontData, "/tmp/pdf.js." + fontCount + ".cff");
  */
 function writeToFile(aBytes, aFilePath) {
+  if (!("netscape" in window))
+    return;
+
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
   var Cc = Components.classes,
       Ci = Components.interfaces;
@@ -384,7 +389,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, 0x180, 0);
 
   var bos = Cc["@mozilla.org/binaryoutputstream;1"]
               .createInstance(Ci.nsIBinaryOutputStream);