]> git.parisson.com Git - pdf.js.git/commitdiff
add a closure around Font so we can hide helper functions in it
authorAndreas Gal <andreas.gal@gmail.com>
Sun, 19 Jun 2011 22:46:58 +0000 (15:46 -0700)
committerAndreas Gal <andreas.gal@gmail.com>
Sun, 19 Jun 2011 22:46:58 +0000 (15:46 -0700)
fonts.js

index e018061e9d9bb76cdc0c5ba9244977374a2f50e9..85a5c199d532ceaac447d79359256f08b46cb06e 100644 (file)
--- a/fonts.js
+++ b/fonts.js
@@ -84,17 +84,18 @@ var Fonts = {
  *   var type1Font = new Font("MyFontName", binaryFile, propertiesObject);
  *   type1Font.bind();
  */
-var Font = function(aName, aFile, aProperties) {
-  this.name = aName;
-
-  // If the font has already been decoded simply return it
-  if (Fonts[aName]) {
-    this.font = Fonts[aName].data;
-    return;
-  }
-  fontCount++;
+var Font = (function () {
+  var constructor = function(aName, aFile, aProperties) {
+    this.name = aName;
+
+    // If the font has already been decoded simply return it
+    if (Fonts[aName]) {
+      this.font = Fonts[aName].data;
+      return;
+    }
+    fontCount++;
 
-  switch (aProperties.type) {
+    switch (aProperties.type) {
     case "Type1":
       var cff = new CFF(aName, aFile, aProperties);
       this.mimetype = "font/otf";
@@ -124,448 +125,450 @@ var Font = function(aName, aFile, aProperties) {
     default:
       warn("Font " + aProperties.type + " is not supported");
       break;
-  }
-
-  Fonts[aName] = {
-    data: this.font,
-    properties: aProperties,
-    loading: true,
-    cache: Object.create(null)
-  }
-
-  // Attach the font to the document
-  this.bind();
-};
-
-
-/**
- * A bunch of the OpenType code is duplicate between this class and the
- * TrueType code, this is intentional and will merge in a future version
- * where all the code relative to OpenType will probably have its own
- * class and will take decision without the Fonts consent.
- * But at the moment it allows to develop around the TrueType rewriting
- * on the fly without messing up with the 'regular' Type1 to OTF conversion.
- */
-Font.prototype = {
-  name: null,
-  font: null,
-  mimetype: null,
-
-  bind: function font_bind() {
-    var data = this.font;
-
-    // Get the base64 encoding of the binary font data
-    var str = "";
-    var length = data.length;
-    for (var i = 0; i < length; ++i)
-      str += String.fromCharCode(data[i]);
-
-    var dataBase64 = window.btoa(str);
-    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;
-
-    if (debug) {
-      var name = document.createElement("font");
-      name.setAttribute("style", "position: absolute; left: 20px; top: " +
-                                 (100 * fontCount + 60) + "px");
-      name.innerHTML = fontName;
-      document.body.appendChild(name);
     }
 
-    var canvas = document.createElement("canvas");
-    var style = "border: 1px solid black; position:absolute; top: " +
-                (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px";
-    canvas.setAttribute("style", style);
-    canvas.setAttribute("width", 340);
-    canvas.setAttribute("heigth", 100);
-    document.body.appendChild(canvas);
-
-    // Retrieve font charset
-    var charset = Fonts[fontName].charset || [];
-    // if the charset is too small make it repeat a few times
-    var count = 30;
-    while (count-- && charset.length <= 30)
-     charset = charset.concat(charset.slice());
-
-    // Get the font size canvas think it will be for 'spaces'
-    var ctx = canvas.getContext("2d");
-    var testString = "     ";
-
-    // When debugging use the characters provided by the charsets to visually
-    // see what's happening
-    if (debug) {
-      for (var i = 0; i < charset.length; i++) {
-        var unicode = GlyphsUnicode[charset[i]];
-        if (!unicode)
-          error("Unicode for " + charset[i] + " is has not been found in the glyphs list");
-        testString += String.fromCharCode(unicode);
-      }
+    Fonts[aName] = {
+      data: this.font,
+      properties: aProperties,
+      loading: true,
+      cache: Object.create(null)
     }
-    ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial";
-    var textWidth = ctx.measureText(testString).width;
 
-    if (debug)
-      ctx.fillText(testString, 20, 20);
+    // Attach the font to the document
+    this.bind();
+  };
 
-    var start = Date.now();
-    var interval = window.setInterval(function canvasInterval(self) {
-      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
-      if ((Date.now() - start) >= kMaxWaitForFontFace) {
-        window.clearInterval(interval);
-        Fonts[fontName].loading = false;
-        warn("Is " + fontName + " for charset: " + charset + " loaded?");
-      } else if (textWidth != ctx.measureText(testString).width) {
-        window.clearInterval(interval);
-        Fonts[fontName].loading = false;
+  /**
+   * A bunch of the OpenType code is duplicate between this class and the
+   * TrueType code, this is intentional and will merge in a future version
+   * where all the code relative to OpenType will probably have its own
+   * class and will take decision without the Fonts consent.
+   * But at the moment it allows to develop around the TrueType rewriting
+   * on the fly without messing up with the 'regular' Type1 to OTF conversion.
+   */
+  constructor.prototype = {
+    name: null,
+    font: null,
+    mimetype: null,
+
+    bind: function font_bind() {
+      var data = this.font;
+
+      // Get the base64 encoding of the binary font data
+      var str = "";
+      var length = data.length;
+      for (var i = 0; i < length; ++i)
+        str += String.fromCharCode(data[i]);
+
+      var dataBase64 = window.btoa(str);
+      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;
+
+      if (debug) {
+        var name = document.createElement("font");
+        name.setAttribute("style", "position: absolute; left: 20px; top: " +
+                          (100 * fontCount + 60) + "px");
+        name.innerHTML = fontName;
+        document.body.appendChild(name);
       }
 
-      if (debug)
-        ctx.fillText(testString, 20, 50);
-    }, 50, 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:'" + fontName + "';src:" + url + "}";
-    var styleSheet = document.styleSheets[0];
-    styleSheet.insertRule(rule, styleSheet.length);
-  },
-
-  _createOpenTypeHeader: function font_createOpenTypeHeader(aFile, aOffsets, aNumTables) {
-    // sfnt version (4 bytes)
-    var version = [0x4F, 0x54, 0x54, 0X4F];
-
-    // numTables (2 bytes)
-    var numTables = aNumTables;
-
-    // searchRange (2 bytes)
-    var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables);
-    var searchRange = tablesMaxPower2 * 16;
-
-    // entrySelector (2 bytes)
-    var entrySelector = Math.log(tablesMaxPower2) / Math.log(2);
-
-    // rangeShift (2 bytes)
-    var rangeShift = numTables * 16 - searchRange;
+      var canvas = document.createElement("canvas");
+      var style = "border: 1px solid black; position:absolute; top: " +
+                   (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px";
+      canvas.setAttribute("style", style);
+      canvas.setAttribute("width", 340);
+      canvas.setAttribute("heigth", 100);
+      document.body.appendChild(canvas);
+
+      // Retrieve font charset
+      var charset = Fonts[fontName].charset || [];
+      // if the charset is too small make it repeat a few times
+      var count = 30;
+      while (count-- && charset.length <= 30)
+        charset = charset.concat(charset.slice());
+
+      // Get the font size canvas think it will be for 'spaces'
+      var ctx = canvas.getContext("2d");
+      var testString = "     ";
+
+      // When debugging use the characters provided by the charsets to visually
+      // see what's happening
+      if (debug) {
+        for (var i = 0; i < charset.length; i++) {
+          var unicode = GlyphsUnicode[charset[i]];
+          if (!unicode)
+            error("Unicode for " + charset[i] + " is has not been found in the glyphs list");
+          testString += String.fromCharCode(unicode);
+        }
+      }
+      ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial";
+      var textWidth = ctx.measureText(testString).width;
 
-    var header = [].concat(version,
-                           FontsUtils.integerToBytes(numTables, 2),
-                           FontsUtils.integerToBytes(searchRange, 2),
-                           FontsUtils.integerToBytes(entrySelector, 2),
-                           FontsUtils.integerToBytes(rangeShift, 2));
-    aFile.set(header, aOffsets.currentOffset);
-    aOffsets.currentOffset += header.length;
-    aOffsets.virtualOffset += header.length;
-  },
+      if (debug)
+        ctx.fillText(testString, 20, 20);
+
+      var start = Date.now();
+      var interval = window.setInterval(function canvasInterval(self) {
+          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
+          if ((Date.now() - start) >= kMaxWaitForFontFace) {
+            window.clearInterval(interval);
+            Fonts[fontName].loading = false;
+            warn("Is " + fontName + " for charset: " + charset + " loaded?");
+          } else if (textWidth != ctx.measureText(testString).width) {
+            window.clearInterval(interval);
+            Fonts[fontName].loading = false;
+          }
+
+          if (debug)
+            ctx.fillText(testString, 20, 50);
+        }, 50, 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:'" + fontName + "';src:" + url + "}";
+      var styleSheet = document.styleSheets[0];
+      styleSheet.insertRule(rule, styleSheet.length);
+    },
 
-  _createTableEntry: function font_createTableEntry(aFile, aOffsets, aTag, aData) {
-    // tag
-    var tag = [
-      aTag.charCodeAt(0),
-      aTag.charCodeAt(1),
-      aTag.charCodeAt(2),
-      aTag.charCodeAt(3)
-    ];
+    _createOpenTypeHeader: function font_createOpenTypeHeader(aFile, aOffsets, aNumTables) {
+      // sfnt version (4 bytes)
+      var version = [0x4F, 0x54, 0x54, 0X4F];
 
-    // offset
-    var offset = aOffsets.virtualOffset;
+      // numTables (2 bytes)
+      var numTables = aNumTables;
 
-    // Per spec tables must be 4-bytes align so add some 0x00 if needed
-    while (aData.length & 3)
-      aData.push(0x00);
+      // searchRange (2 bytes)
+      var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables);
+      var searchRange = tablesMaxPower2 * 16;
 
-    // length
-    var length = aData.length;
+      // entrySelector (2 bytes)
+      var entrySelector = Math.log(tablesMaxPower2) / Math.log(2);
 
-    // checksum
-    var checksum = FontsUtils.bytesToInteger(tag) + offset + length;
+      // rangeShift (2 bytes)
+      var rangeShift = numTables * 16 - searchRange;
 
-    var tableEntry = [].concat(tag,
-                               FontsUtils.integerToBytes(checksum, 4),
-                               FontsUtils.integerToBytes(offset, 4),
-                               FontsUtils.integerToBytes(length, 4));
-    aFile.set(tableEntry, aOffsets.currentOffset);
-    aOffsets.currentOffset += tableEntry.length;
-    aOffsets.virtualOffset += aData.length;
-  },
+      var header = [].concat(version,
+                             FontsUtils.integerToBytes(numTables, 2),
+                             FontsUtils.integerToBytes(searchRange, 2),
+                             FontsUtils.integerToBytes(entrySelector, 2),
+                             FontsUtils.integerToBytes(rangeShift, 2));
+      aFile.set(header, aOffsets.currentOffset);
+      aOffsets.currentOffset += header.length;
+      aOffsets.virtualOffset += header.length;
+    },
 
-  _createCMAPTable: function font_createCMAPTable(aGlyphs) {
-    var characters = new Uint16Array(kMaxGlyphsCount);
-    for (var i = 0; i < aGlyphs.length; i++)
-      characters[aGlyphs[i].unicode] = i + 1;
+    _createTableEntry: function font_createTableEntry(aFile, aOffsets, aTag, aData) {
+      // tag
+      var tag = [
+                 aTag.charCodeAt(0),
+                 aTag.charCodeAt(1),
+                 aTag.charCodeAt(2),
+                 aTag.charCodeAt(3)
+                 ];
+
+      // offset
+      var offset = aOffsets.virtualOffset;
+
+      // Per spec tables must be 4-bytes align so add some 0x00 if needed
+      while (aData.length & 3)
+        aData.push(0x00);
+
+      // length
+      var length = aData.length;
+
+      // checksum
+      var checksum = FontsUtils.bytesToInteger(tag) + offset + length;
+
+      var tableEntry = [].concat(tag,
+                                 FontsUtils.integerToBytes(checksum, 4),
+                                 FontsUtils.integerToBytes(offset, 4),
+                                 FontsUtils.integerToBytes(length, 4));
+      aFile.set(tableEntry, aOffsets.currentOffset);
+      aOffsets.currentOffset += tableEntry.length;
+      aOffsets.virtualOffset += aData.length;
+    },
 
-    // Separate the glyphs into continuous range of codes, aka segment.
-    var ranges = [];
-    var range = [];
-    var count = characters.length;
-    for (var i = 0; i < count; i++) {
-      if (characters[i]) {
-        range.push(i);
-      } else if (range.length) {
-        ranges.push(range.slice());
-        range = [];
+    _createCMAPTable: function font_createCMAPTable(aGlyphs) {
+      var characters = new Uint16Array(kMaxGlyphsCount);
+      for (var i = 0; i < aGlyphs.length; i++)
+        characters[aGlyphs[i].unicode] = i + 1;
+
+      // Separate the glyphs into continuous range of codes, aka segment.
+      var ranges = [];
+      var range = [];
+      var count = characters.length;
+      for (var i = 0; i < count; i++) {
+        if (characters[i]) {
+          range.push(i);
+        } else if (range.length) {
+          ranges.push(range.slice());
+          range = [];
+        }
       }
-    }
 
-    // The size in bytes of the header is equal to the size of the
-    // different fields * length of a short + (size of the 4 parallels arrays
-    // describing segments * length of a short).
-    var headerSize = (12 * 2 + (ranges.length * 4 * 2));
-
-    var segCount = ranges.length + 1;
-    var segCount2 = segCount * 2;
-    var searchRange = FontsUtils.getMaxPower2(segCount) * 2;
-    var searchEntry = Math.log(segCount) / Math.log(2);
-    var rangeShift = 2 * segCount - searchRange;
-    var cmap = [].concat(
-      [
-        0x00, 0x00, // version
-        0x00, 0x01, // numTables
-        0x00, 0x03, // platformID
-        0x00, 0x01, // encodingID
-        0x00, 0x00, 0x00, 0x0C, // start of the table record
-        0x00, 0x04  // format
-      ],
-      FontsUtils.integerToBytes(headerSize, 2), // length
-      [0x00, 0x00], // language
-      FontsUtils.integerToBytes(segCount2, 2),
-      FontsUtils.integerToBytes(searchRange, 2),
-      FontsUtils.integerToBytes(searchEntry, 2),
-      FontsUtils.integerToBytes(rangeShift, 2)
-    );
-
-    // Fill up the 4 parallel arrays describing the segments.
-    var startCount = [];
-    var endCount = [];
-    var idDeltas = [];
-    var idRangeOffsets = [];
-    var glyphsIdsArray = [];
-    var bias = 0;
-    for (var i = 0; i < segCount - 1; i++) {
-      var range = ranges[i];
-      var start = FontsUtils.integerToBytes(range[0], 2);
-      var end = FontsUtils.integerToBytes(range[range.length - 1], 2);
-
-      var delta = FontsUtils.integerToBytes(((range[0] - 1) - bias) % 65536, 2);
-      bias += range.length;
-
-      // deltas are signed shorts
-      delta[0] ^= 0xFF;
-      delta[1] ^= 0xFF;
-      delta[1] += 1;
-
-      startCount.push(start[0], start[1]);
-      endCount.push(end[0], end[1]);
-      idDeltas.push(delta[0], delta[1]);
+      // The size in bytes of the header is equal to the size of the
+      // different fields * length of a short + (size of the 4 parallels arrays
+      // describing segments * length of a short).
+      var headerSize = (12 * 2 + (ranges.length * 4 * 2));
+
+      var segCount = ranges.length + 1;
+      var segCount2 = segCount * 2;
+      var searchRange = FontsUtils.getMaxPower2(segCount) * 2;
+      var searchEntry = Math.log(segCount) / Math.log(2);
+      var rangeShift = 2 * segCount - searchRange;
+      var cmap = [].concat(
+                           [
+                            0x00, 0x00, // version
+                            0x00, 0x01, // numTables
+                            0x00, 0x03, // platformID
+                            0x00, 0x01, // encodingID
+                            0x00, 0x00, 0x00, 0x0C, // start of the table record
+                            0x00, 0x04  // format
+                            ],
+                           FontsUtils.integerToBytes(headerSize, 2), // length
+                           [0x00, 0x00], // language
+                           FontsUtils.integerToBytes(segCount2, 2),
+                           FontsUtils.integerToBytes(searchRange, 2),
+                           FontsUtils.integerToBytes(searchEntry, 2),
+                           FontsUtils.integerToBytes(rangeShift, 2)
+                           );
+
+      // Fill up the 4 parallel arrays describing the segments.
+      var startCount = [];
+      var endCount = [];
+      var idDeltas = [];
+      var idRangeOffsets = [];
+      var glyphsIdsArray = [];
+      var bias = 0;
+      for (var i = 0; i < segCount - 1; i++) {
+        var range = ranges[i];
+        var start = FontsUtils.integerToBytes(range[0], 2);
+        var end = FontsUtils.integerToBytes(range[range.length - 1], 2);
+
+        var delta = FontsUtils.integerToBytes(((range[0] - 1) - bias) % 65536, 2);
+        bias += range.length;
+
+        // deltas are signed shorts
+        delta[0] ^= 0xFF;
+        delta[1] ^= 0xFF;
+        delta[1] += 1;
+
+        startCount.push(start[0], start[1]);
+        endCount.push(end[0], end[1]);
+        idDeltas.push(delta[0], delta[1]);
+        idRangeOffsets.push(0x00, 0x00);
+
+        for (var j = 0; j < range.length; j++)
+          glyphsIdsArray.push(range[j]);
+      }
+      startCount.push(0xFF, 0xFF);
+      endCount.push(0xFF, 0xFF);
+      idDeltas.push(0x00, 0x01);
       idRangeOffsets.push(0x00, 0x00);
 
-      for (var j = 0; j < range.length; j++)
-        glyphsIdsArray.push(range[j]);
-    }
-    startCount.push(0xFF, 0xFF);
-    endCount.push(0xFF, 0xFF);
-    idDeltas.push(0x00, 0x01);
-    idRangeOffsets.push(0x00, 0x00);
-
-    return cmap.concat(endCount, [0x00, 0x00], startCount,
-                       idDeltas, idRangeOffsets, glyphsIdsArray);
-  },
-
-  cover: function font_cover(aFont, aProperties) {
-    var otf = new Uint8Array(kMaxFontFileSize);
-
-    // Required Tables
-    var CFF = aFont.data, // PostScript Font Program
-        OS2 = [],         // OS/2 and Windows Specific metrics
-        cmap = [],        // Character to glyphs mapping
-        head = [],        // Font eader
-        hhea = [],        // Horizontal header
-        hmtx = [],        // Horizontal metrics
-        maxp = [],        // Maximum profile
-        name = [],        // Naming tables
-        post = [];        // PostScript informations
-    var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post];
-
-    // The offsets object holds at the same time a representation of where
-    // to write the table entry information about a table and another offset
-    // representing the offset where to draw the actual data of a particular
-    // table
-    var offsets = {
-      currentOffset: 0,
-      virtualOffset: tables.length * (4 * 4)
-    };
-
-    // For files with only one font the offset table is the first thing of the
-    // file
-    this._createOpenTypeHeader(otf, offsets, tables.length);
-
-    // XXX It is probable that in a future we want to get rid of this glue
-    // between the CFF and the OTF format in order to be able to embed TrueType
-    // data.
-    this._createTableEntry(otf, offsets, "CFF ", CFF);
-
-    /** OS/2 */
-    OS2 = [
-      0x00, 0x03, // version
-      0x02, 0x24, // xAvgCharWidth
-      0x01, 0xF4, // usWeightClass
-      0x00, 0x05, // usWidthClass
-      0x00, 0x00, // fstype
-      0x02, 0x8A, // ySubscriptXSize
-      0x02, 0xBB, // ySubscriptYSize
-      0x00, 0x00, // ySubscriptXOffset
-      0x00, 0x8C, // ySubscriptYOffset
-      0x02, 0x8A, // ySuperScriptXSize
-      0x02, 0xBB, // ySuperScriptYSize
-      0x00, 0x00, // ySuperScriptXOffset
-      0x01, 0xDF, // ySuperScriptYOffset
-      0x00, 0x31, // yStrikeOutSize
-      0x01, 0x02, // yStrikeOutPosition
-      0x00, 0x00, // sFamilyClass
-      0x02, 0x00, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Panose
-      0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 0-31)
-      0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 32-63)
-      0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 64-95)
-      0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 96-127)
-      0x2A, 0x32, 0x31, 0x2A, // achVendID
-      0x00, 0x20, // fsSelection
-      0x00, 0x2D, // usFirstCharIndex
-      0x00, 0x7A, // usLastCharIndex
-      0x00, 0x03, // sTypoAscender
-      0x00, 0x20, // sTypeDescender
-      0x00, 0x38, // sTypoLineGap
-      0x00, 0x5A, // usWinAscent
-      0x02, 0xB4, // usWinDescent
-      0x00, 0xCE, 0x00, 0x00, // ulCodePageRange1 (Bits 0-31)
-      0x00, 0x01, 0x00, 0x00, // ulCodePageRange2 (Bits 32-63)
-      0x00, 0x00, // sxHeight
-      0x00, 0x00, // sCapHeight
-      0x00, 0x01, // usDefaultChar
-      0x00, 0xCD, // usBreakChar
-      0x00, 0x02  // usMaxContext
-    ];
-    this._createTableEntry(otf, offsets, "OS/2", OS2);
-
-    //XXX Getting charstrings here seems wrong since this is another CFF glue
-    var charstrings = aFont.getOrderedCharStrings(aProperties.glyphs);
-
-    /** CMAP */
-    cmap = this._createCMAPTable(charstrings);
-    this._createTableEntry(otf, offsets, "cmap", cmap);
-
-    /** HEAD */
-    head = [
-      0x00, 0x01, 0x00, 0x00, // Version number
-      0x00, 0x00, 0x50, 0x00, // fontRevision
-      0x00, 0x00, 0x00, 0x00, // checksumAdjustement
-      0x5F, 0x0F, 0x3C, 0xF5, // magicNumber
-      0x00, 0x00, // Flags
-      0x03, 0xE8, // unitsPerEM (defaulting to 1000)
-      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // creation date
-      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // modifification date
-      0x00, 0x00, // xMin
-      0x00, 0x00, // yMin
-      0x00, 0x00, // xMax
-      0x00, 0x00, // yMax
-      0x00, 0x00, // macStyle
-      0x00, 0x00, // lowestRecPPEM
-      0x00, 0x00, // fontDirectionHint
-      0x00, 0x00, // indexToLocFormat
-      0x00, 0x00  // glyphDataFormat
-    ];
-    this._createTableEntry(otf, offsets, "head", head);
+      return cmap.concat(endCount, [0x00, 0x00], startCount,
+                         idDeltas, idRangeOffsets, glyphsIdsArray);
+    },
 
-    /** HHEA */
-    hhea = [].concat(
-      [
-        0x00, 0x01, 0x00, 0x00, // Version number
-        0x00, 0x00, // Typographic Ascent
-        0x00, 0x00, // Typographic Descent
-        0x00, 0x00, // Line Gap
-        0xFF, 0xFF, // advanceWidthMax
-        0x00, 0x00, // minLeftSidebearing
-        0x00, 0x00, // minRightSidebearing
-        0x00, 0x00, // xMaxExtent
-        0x00, 0x00, // caretSlopeRise
-        0x00, 0x00, // caretSlopeRun
-        0x00, 0x00, // caretOffset
-        0x00, 0x00, // -reserved-
-        0x00, 0x00, // -reserved-
-        0x00, 0x00, // -reserved-
-        0x00, 0x00, // -reserved-
-        0x00, 0x00 // metricDataFormat
-      ],
-      FontsUtils.integerToBytes(charstrings.length, 2) // numberOfHMetrics
-    );
-    this._createTableEntry(otf, offsets, "hhea", hhea);
-
-    /** HMTX */
-    hmtx = [0x01, 0xF4, 0x00, 0x00];
-    for (var i = 0; i < charstrings.length; i++) {
-      var charstring = charstrings[i].charstring;
-      var width = FontsUtils.integerToBytes(charstring[1], 2);
-      var lsb = FontsUtils.integerToBytes(charstring[0], 2);
-      hmtx = hmtx.concat(width, lsb);
-    }
-    this._createTableEntry(otf, offsets, "hmtx", hmtx);
+    cover: function font_cover(aFont, aProperties) {
+      var otf = new Uint8Array(kMaxFontFileSize);
+
+      // Required Tables
+      var CFF = aFont.data, // PostScript Font Program
+      OS2 = [],         // OS/2 and Windows Specific metrics
+      cmap = [],        // Character to glyphs mapping
+      head = [],        // Font eader
+      hhea = [],        // Horizontal header
+      hmtx = [],        // Horizontal metrics
+      maxp = [],        // Maximum profile
+      name = [],        // Naming tables
+      post = [];        // PostScript informations
+      var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post];
+
+      // The offsets object holds at the same time a representation of where
+      // to write the table entry information about a table and another offset
+      // representing the offset where to draw the actual data of a particular
+      // table
+      var offsets = {
+        currentOffset: 0,
+        virtualOffset: tables.length * (4 * 4)
+      };
 
-    /** MAXP */
-    maxp = [].concat(
-      [
-        0x00, 0x00, 0x50, 0x00, // Version number
-      ],
-      FontsUtils.integerToBytes(charstrings.length + 1, 2) // Num of glyphs (+1 to pass the sanitizer...)
-    );
-    this._createTableEntry(otf, offsets, "maxp", maxp);
-
-    /** NAME */
-    name = [
-      0x00, 0x00, // format
-      0x00, 0x00, // Number of names Record
-      0x00, 0x00  // Storage
-    ];
-    this._createTableEntry(otf, offsets, "name", name);
-
-    /** POST */
-    // FIXME Get those informations from the FontInfo structure
-    post = [
-      0x00, 0x03, 0x00, 0x00, // Version number
-      0x00, 0x00, 0x01, 0x00, // italicAngle
-      0x00, 0x00, // underlinePosition
-      0x00, 0x00, // underlineThickness
-      0x00, 0x00, 0x00, 0x00, // isFixedPitch
-      0x00, 0x00, 0x00, 0x00, // minMemType42
-      0x00, 0x00, 0x00, 0x00, // maxMemType42
-      0x00, 0x00, 0x00, 0x00, // minMemType1
-      0x00, 0x00, 0x00, 0x00  // maxMemType1
-    ];
-    this._createTableEntry(otf, offsets, "post", post);
+      // For files with only one font the offset table is the first thing of the
+      // file
+      this._createOpenTypeHeader(otf, offsets, tables.length);
+
+      // XXX It is probable that in a future we want to get rid of this glue
+      // between the CFF and the OTF format in order to be able to embed TrueType
+      // data.
+      this._createTableEntry(otf, offsets, "CFF ", CFF);
+
+      /** OS/2 */
+      OS2 = [
+             0x00, 0x03, // version
+             0x02, 0x24, // xAvgCharWidth
+             0x01, 0xF4, // usWeightClass
+             0x00, 0x05, // usWidthClass
+             0x00, 0x00, // fstype
+             0x02, 0x8A, // ySubscriptXSize
+             0x02, 0xBB, // ySubscriptYSize
+             0x00, 0x00, // ySubscriptXOffset
+             0x00, 0x8C, // ySubscriptYOffset
+             0x02, 0x8A, // ySuperScriptXSize
+             0x02, 0xBB, // ySuperScriptYSize
+             0x00, 0x00, // ySuperScriptXOffset
+             0x01, 0xDF, // ySuperScriptYOffset
+             0x00, 0x31, // yStrikeOutSize
+             0x01, 0x02, // yStrikeOutPosition
+             0x00, 0x00, // sFamilyClass
+             0x02, 0x00, 0x06, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Panose
+             0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 0-31)
+             0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 32-63)
+             0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 64-95)
+             0xFF, 0xFF, 0xFF, 0xFF, // ulUnicodeRange1 (Bits 96-127)
+             0x2A, 0x32, 0x31, 0x2A, // achVendID
+             0x00, 0x20, // fsSelection
+             0x00, 0x2D, // usFirstCharIndex
+             0x00, 0x7A, // usLastCharIndex
+             0x00, 0x03, // sTypoAscender
+             0x00, 0x20, // sTypeDescender
+             0x00, 0x38, // sTypoLineGap
+             0x00, 0x5A, // usWinAscent
+             0x02, 0xB4, // usWinDescent
+             0x00, 0xCE, 0x00, 0x00, // ulCodePageRange1 (Bits 0-31)
+             0x00, 0x01, 0x00, 0x00, // ulCodePageRange2 (Bits 32-63)
+             0x00, 0x00, // sxHeight
+             0x00, 0x00, // sCapHeight
+             0x00, 0x01, // usDefaultChar
+             0x00, 0xCD, // usBreakChar
+             0x00, 0x02  // usMaxContext
+             ];
+      this._createTableEntry(otf, offsets, "OS/2", OS2);
+
+      //XXX Getting charstrings here seems wrong since this is another CFF glue
+      var charstrings = aFont.getOrderedCharStrings(aProperties.glyphs);
+
+      /** CMAP */
+      cmap = this._createCMAPTable(charstrings);
+      this._createTableEntry(otf, offsets, "cmap", cmap);
+
+      /** HEAD */
+      head = [
+              0x00, 0x01, 0x00, 0x00, // Version number
+              0x00, 0x00, 0x50, 0x00, // fontRevision
+              0x00, 0x00, 0x00, 0x00, // checksumAdjustement
+              0x5F, 0x0F, 0x3C, 0xF5, // magicNumber
+              0x00, 0x00, // Flags
+              0x03, 0xE8, // unitsPerEM (defaulting to 1000)
+              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // creation date
+              0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // modifification date
+              0x00, 0x00, // xMin
+              0x00, 0x00, // yMin
+              0x00, 0x00, // xMax
+              0x00, 0x00, // yMax
+              0x00, 0x00, // macStyle
+              0x00, 0x00, // lowestRecPPEM
+              0x00, 0x00, // fontDirectionHint
+              0x00, 0x00, // indexToLocFormat
+              0x00, 0x00  // glyphDataFormat
+              ];
+      this._createTableEntry(otf, offsets, "head", head);
+
+      /** HHEA */
+      hhea = [].concat(
+                       [
+                        0x00, 0x01, 0x00, 0x00, // Version number
+                        0x00, 0x00, // Typographic Ascent
+                        0x00, 0x00, // Typographic Descent
+                        0x00, 0x00, // Line Gap
+                        0xFF, 0xFF, // advanceWidthMax
+                        0x00, 0x00, // minLeftSidebearing
+                        0x00, 0x00, // minRightSidebearing
+                        0x00, 0x00, // xMaxExtent
+                        0x00, 0x00, // caretSlopeRise
+                        0x00, 0x00, // caretSlopeRun
+                        0x00, 0x00, // caretOffset
+                        0x00, 0x00, // -reserved-
+                        0x00, 0x00, // -reserved-
+                        0x00, 0x00, // -reserved-
+                        0x00, 0x00, // -reserved-
+                        0x00, 0x00 // metricDataFormat
+                        ],
+                       FontsUtils.integerToBytes(charstrings.length, 2) // numberOfHMetrics
+                       );
+      this._createTableEntry(otf, offsets, "hhea", hhea);
+
+      /** HMTX */
+      hmtx = [0x01, 0xF4, 0x00, 0x00];
+      for (var i = 0; i < charstrings.length; i++) {
+        var charstring = charstrings[i].charstring;
+        var width = FontsUtils.integerToBytes(charstring[1], 2);
+        var lsb = FontsUtils.integerToBytes(charstring[0], 2);
+        hmtx = hmtx.concat(width, lsb);
+      }
+      this._createTableEntry(otf, offsets, "hmtx", hmtx);
+
+      /** MAXP */
+      maxp = [].concat(
+                       [
+                        0x00, 0x00, 0x50, 0x00, // Version number
+                        ],
+                       FontsUtils.integerToBytes(charstrings.length + 1, 2) // Num of glyphs (+1 to pass the sanitizer...)
+                       );
+      this._createTableEntry(otf, offsets, "maxp", maxp);
+
+      /** NAME */
+      name = [
+              0x00, 0x00, // format
+              0x00, 0x00, // Number of names Record
+              0x00, 0x00  // Storage
+              ];
+      this._createTableEntry(otf, offsets, "name", name);
+
+      /** POST */
+      // FIXME Get those informations from the FontInfo structure
+      post = [
+              0x00, 0x03, 0x00, 0x00, // Version number
+              0x00, 0x00, 0x01, 0x00, // italicAngle
+              0x00, 0x00, // underlinePosition
+              0x00, 0x00, // underlineThickness
+              0x00, 0x00, 0x00, 0x00, // isFixedPitch
+              0x00, 0x00, 0x00, 0x00, // minMemType42
+              0x00, 0x00, 0x00, 0x00, // maxMemType42
+              0x00, 0x00, 0x00, 0x00, // minMemType1
+              0x00, 0x00, 0x00, 0x00  // maxMemType1
+              ];
+      this._createTableEntry(otf, offsets, "post", post);
+
+      // Once all the table entries header are written, dump the data!
+      var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post];
+      for (var i = 0; i < tables.length; i++) {
+        var table = tables[i];
+        otf.set(table, offsets.currentOffset);
+        offsets.currentOffset += table.length;
+      }
 
-    // Once all the table entries header are written, dump the data!
-    var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post];
-    for (var i = 0; i < tables.length; i++) {
-      var table = tables[i];
-      otf.set(table, offsets.currentOffset);
-      offsets.currentOffset += table.length;
+      var fontData = [];
+      for (var i = 0; i < offsets.currentOffset; i++)
+        fontData.push(otf[i]);
+      return fontData;
     }
+  };
 
-    var fontData = [];
-    for (var i = 0; i < offsets.currentOffset; i++)
-      fontData.push(otf[i]);
-    return fontData;
-  }
-};
-
+  return constructor;
+})();
 
 /**
  * FontsUtils is a static class dedicated to hold codes that are not related