Merge pull request #164 from vingtetun/master
Let Chrome (and others?) handle Type1 Fonts (TrueType not working yet)
This commit is contained in:
		
						commit
						637708cf1a
					
				
							
								
								
									
										234
									
								
								fonts.js
									
									
									
									
									
								
							
							
						
						
									
										234
									
								
								fonts.js
									
									
									
									
									
								
							@ -466,6 +466,29 @@ var Font = (function () {
 | 
			
		||||
    return array;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  function int16(bytes) {
 | 
			
		||||
    return (bytes[0] << 8) + (bytes[1] & 0xff);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  function int32(bytes) {
 | 
			
		||||
    return (bytes[0] << 24) + (bytes[1] << 16) +
 | 
			
		||||
           (bytes[2] << 8) + (bytes[3] & 0xff);
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  function getMaxPower2(number) {
 | 
			
		||||
    var maxPower = 0;
 | 
			
		||||
    var value = number;
 | 
			
		||||
    while (value >= 2) {
 | 
			
		||||
      value /= 2;
 | 
			
		||||
      maxPower++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    value = 2;
 | 
			
		||||
    for (var i = 1; i < maxPower; i++)
 | 
			
		||||
      value *= 2;
 | 
			
		||||
    return value;
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  function string16(value) {
 | 
			
		||||
    return String.fromCharCode((value >> 8) & 0xff) +
 | 
			
		||||
           String.fromCharCode(value & 0xff);
 | 
			
		||||
@ -486,7 +509,7 @@ var Font = (function () {
 | 
			
		||||
    header += string16(numTables);
 | 
			
		||||
 | 
			
		||||
    // searchRange (2 bytes)
 | 
			
		||||
    var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables);
 | 
			
		||||
    var tablesMaxPower2 = getMaxPower2(numTables);
 | 
			
		||||
    var searchRange = tablesMaxPower2 * 16;
 | 
			
		||||
    header += string16(searchRange);
 | 
			
		||||
 | 
			
		||||
@ -518,7 +541,7 @@ var Font = (function () {
 | 
			
		||||
    // checksum
 | 
			
		||||
    var checksum = 0;
 | 
			
		||||
    for (var i = 0; i < length; i+=4)
 | 
			
		||||
      checksum += FontsUtils.bytesToInteger([data[i], data[i+1], data[i+2], data[i+3]]);
 | 
			
		||||
      checksum += int16([data[i], data[i+1], data[i+2], data[i+3]]);
 | 
			
		||||
 | 
			
		||||
    var tableEntry = tag + string32(checksum) + string32(offset) + string32(length);
 | 
			
		||||
    tableEntry = stringToArray(tableEntry);
 | 
			
		||||
@ -565,7 +588,7 @@ var Font = (function () {
 | 
			
		||||
    var headerSize = (12 * 2 + (ranges.length * 5 * 2));
 | 
			
		||||
    var segCount = ranges.length + 1;
 | 
			
		||||
    var segCount2 = segCount * 2;
 | 
			
		||||
    var searchRange = FontsUtils.getMaxPower2(segCount) * 2;
 | 
			
		||||
    var searchRange = getMaxPower2(segCount) * 2;
 | 
			
		||||
    var searchEntry = Math.log(segCount) / Math.log(2);
 | 
			
		||||
    var rangeShift = 2 * segCount - searchRange;
 | 
			
		||||
 | 
			
		||||
@ -712,9 +735,9 @@ var Font = (function () {
 | 
			
		||||
              String.fromCharCode(tag[2]) +
 | 
			
		||||
              String.fromCharCode(tag[3]);
 | 
			
		||||
 | 
			
		||||
        var checksum = FontsUtils.bytesToInteger(file.getBytes(4));
 | 
			
		||||
        var offset = FontsUtils.bytesToInteger(file.getBytes(4));
 | 
			
		||||
        var length = FontsUtils.bytesToInteger(file.getBytes(4));
 | 
			
		||||
        var checksum = int32(file.getBytes(4));
 | 
			
		||||
        var offset = int32(file.getBytes(4));
 | 
			
		||||
        var length = int32(file.getBytes(4));
 | 
			
		||||
 | 
			
		||||
        // Read the table associated data
 | 
			
		||||
        var previousPosition = file.pos;
 | 
			
		||||
@ -735,26 +758,26 @@ var Font = (function () {
 | 
			
		||||
      function readOpenTypeHeader(ttf) {
 | 
			
		||||
        return {
 | 
			
		||||
          version: ttf.getBytes(4),
 | 
			
		||||
          numTables: FontsUtils.bytesToInteger(ttf.getBytes(2)),
 | 
			
		||||
          searchRange: FontsUtils.bytesToInteger(ttf.getBytes(2)),
 | 
			
		||||
          entrySelector: FontsUtils.bytesToInteger(ttf.getBytes(2)),
 | 
			
		||||
          rangeShift: FontsUtils.bytesToInteger(ttf.getBytes(2))
 | 
			
		||||
          numTables: int16(ttf.getBytes(2)),
 | 
			
		||||
          searchRange: int16(ttf.getBytes(2)),
 | 
			
		||||
          entrySelector: int16(ttf.getBytes(2)),
 | 
			
		||||
          rangeShift: int16(ttf.getBytes(2))
 | 
			
		||||
        }
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      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));
 | 
			
		||||
        var version = int16(font.getBytes(2));
 | 
			
		||||
        var numTables = int16(font.getBytes(2));
 | 
			
		||||
 | 
			
		||||
        for (var i = 0; i < numTables; i++) {
 | 
			
		||||
          var platformID = FontsUtils.bytesToInteger(font.getBytes(2));
 | 
			
		||||
          var encodingID = FontsUtils.bytesToInteger(font.getBytes(2));
 | 
			
		||||
          var offset = FontsUtils.bytesToInteger(font.getBytes(4));
 | 
			
		||||
          var format = FontsUtils.bytesToInteger(font.getBytes(2));
 | 
			
		||||
          var length = FontsUtils.bytesToInteger(font.getBytes(2));
 | 
			
		||||
          var language = FontsUtils.bytesToInteger(font.getBytes(2));
 | 
			
		||||
          var platformID = int16(font.getBytes(2));
 | 
			
		||||
          var encodingID = int16(font.getBytes(2));
 | 
			
		||||
          var offset = int32(font.getBytes(4));
 | 
			
		||||
          var format = int16(font.getBytes(2));
 | 
			
		||||
          var length = int16(font.getBytes(2));
 | 
			
		||||
          var language = int16(font.getBytes(2));
 | 
			
		||||
 | 
			
		||||
          if ((format == 0 && numTables == 1) ||
 | 
			
		||||
              (format == 6 && numTables == 1 && !properties.encoding.empty)) {
 | 
			
		||||
@ -776,13 +799,13 @@ var Font = (function () {
 | 
			
		||||
            // table. (This looks weird, so I can have missed something), this
 | 
			
		||||
            // works on Linux but seems to fails on Mac so let's rewrite the
 | 
			
		||||
            // cmap table to a 3-1-4 style
 | 
			
		||||
            var firstCode = FontsUtils.bytesToInteger(font.getBytes(2));
 | 
			
		||||
            var entryCount = FontsUtils.bytesToInteger(font.getBytes(2));
 | 
			
		||||
            var firstCode = int16(font.getBytes(2));
 | 
			
		||||
            var entryCount = int16(font.getBytes(2));
 | 
			
		||||
 | 
			
		||||
            var glyphs = [];
 | 
			
		||||
            var min = 0xffff, max = 0;
 | 
			
		||||
            for (var j = 0; j < entryCount; j++) {
 | 
			
		||||
              var charcode = FontsUtils.bytesToInteger(font.getBytes(2));
 | 
			
		||||
              var charcode = int16(font.getBytes(2));
 | 
			
		||||
              glyphs.push(charcode);
 | 
			
		||||
 | 
			
		||||
              if (charcode < min)
 | 
			
		||||
@ -882,7 +905,7 @@ var Font = (function () {
 | 
			
		||||
 | 
			
		||||
        // Tables needs to be written by ascendant alphabetic order
 | 
			
		||||
        tables.sort(function tables_sort(a, b) {
 | 
			
		||||
          return a.tag > b.tag;
 | 
			
		||||
          return (a.tag > b.tag) - (a.tag < b.tag);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // rewrite the tables but tweak offsets
 | 
			
		||||
@ -921,8 +944,6 @@ var Font = (function () {
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
    convert: function font_convert(fontName, font, properties) {
 | 
			
		||||
      var otf = new Uint8Array(kMaxFontFileSize);
 | 
			
		||||
 | 
			
		||||
      function createNameTable(name) {
 | 
			
		||||
  	    // All the strings of the name table should be an odd number of bytes
 | 
			
		||||
        if (name.length % 2)
 | 
			
		||||
@ -994,46 +1015,34 @@ var Font = (function () {
 | 
			
		||||
		    return true;
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      // Required Tables
 | 
			
		||||
      var CFF =
 | 
			
		||||
        font.data,   // PostScript Font Program
 | 
			
		||||
        OS2,         // OS/2 and Windows Specific metrics
 | 
			
		||||
        cmap,        // Character to glyphs mapping
 | 
			
		||||
        head,        // Font header
 | 
			
		||||
        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 kRequiredTablesCount = 9;
 | 
			
		||||
      var offsets = {
 | 
			
		||||
        currentOffset: 0,
 | 
			
		||||
        virtualOffset: tables.length * (4 * 4)
 | 
			
		||||
        virtualOffset: 9 * (4 * 4)
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      // It there is only one font, offset table is the first bytes of the file
 | 
			
		||||
      createOpenTypeHeader("\x4F\x54\x54\x4F", otf, offsets, tables.length);
 | 
			
		||||
      var otf = new Uint8Array(kMaxFontFileSize);
 | 
			
		||||
      createOpenTypeHeader("\x4F\x54\x54\x4F", otf, offsets, 9);
 | 
			
		||||
 | 
			
		||||
      /** CFF */
 | 
			
		||||
      createTableEntry(otf, offsets, "CFF ", CFF);
 | 
			
		||||
 | 
			
		||||
      /** OS/2 */
 | 
			
		||||
	    var charstrings = font.charstrings;
 | 
			
		||||
	    properties.fixedPitch = isFixedPitch(charstrings);
 | 
			
		||||
      OS2 = stringToArray(createOS2Table(properties));
 | 
			
		||||
      createTableEntry(otf, offsets, "OS/2", OS2);
 | 
			
		||||
      var fields = {
 | 
			
		||||
        // PostScript Font Program
 | 
			
		||||
        "CFF ": font.data,
 | 
			
		||||
 | 
			
		||||
      /** CMAP */
 | 
			
		||||
      cmap = createCMapTable(charstrings.slice());
 | 
			
		||||
      createTableEntry(otf, offsets, "cmap", cmap);
 | 
			
		||||
        // OS/2 and Windows Specific metrics
 | 
			
		||||
        "OS/2": stringToArray(createOS2Table(properties)),
 | 
			
		||||
 | 
			
		||||
      /** HEAD */
 | 
			
		||||
      head = stringToArray(
 | 
			
		||||
        // Character to glyphs mapping
 | 
			
		||||
        "cmap": createCMapTable(charstrings.slice()),
 | 
			
		||||
 | 
			
		||||
        // Font header
 | 
			
		||||
        "head": (function() {
 | 
			
		||||
          return stringToArray(
 | 
			
		||||
              "\x00\x01\x00\x00" + // Version number
 | 
			
		||||
              "\x00\x00\x10\x00" + // fontRevision
 | 
			
		||||
              "\x00\x00\x00\x00" + // checksumAdjustement
 | 
			
		||||
@ -1050,12 +1059,12 @@ var Font = (function () {
 | 
			
		||||
              "\x00\x11" + // lowestRecPPEM
 | 
			
		||||
              "\x00\x00" + // fontDirectionHint
 | 
			
		||||
              "\x00\x00" + // indexToLocFormat
 | 
			
		||||
              "\x00\x00"   // glyphDataFormat
 | 
			
		||||
      );
 | 
			
		||||
      createTableEntry(otf, offsets, "head", head);
 | 
			
		||||
              "\x00\x00");  // glyphDataFormat
 | 
			
		||||
        })(),
 | 
			
		||||
 | 
			
		||||
      /** HHEA */
 | 
			
		||||
      hhea = stringToArray(
 | 
			
		||||
        // Horizontal header
 | 
			
		||||
        "hhea": (function() {
 | 
			
		||||
          return stringToArray(
 | 
			
		||||
              "\x00\x01\x00\x00" + // Version number
 | 
			
		||||
              string16(properties.ascent) + // Typographic Ascent
 | 
			
		||||
              string16(properties.descent) + // Typographic Descent
 | 
			
		||||
@ -1072,41 +1081,37 @@ var Font = (function () {
 | 
			
		||||
              "\x00\x00" + // -reserved-
 | 
			
		||||
              "\x00\x00" + // -reserved-
 | 
			
		||||
              "\x00\x00" + // metricDataFormat
 | 
			
		||||
                 string16(charstrings.length + 1) // Number of HMetrics
 | 
			
		||||
      );
 | 
			
		||||
      createTableEntry(otf, offsets, "hhea", hhea);
 | 
			
		||||
              string16(charstrings.length + 1)); // Number of HMetrics
 | 
			
		||||
        })(),
 | 
			
		||||
 | 
			
		||||
      /** HMTX */
 | 
			
		||||
      /* For some reasons, probably related to how the backend handle fonts,
 | 
			
		||||
      * Linux seems to ignore this file and prefer the data from the CFF itself
 | 
			
		||||
      * while Windows use this data. So be careful if you hack on Linux and
 | 
			
		||||
      * have to touch the 'hmtx' table
 | 
			
		||||
      */
 | 
			
		||||
      hmtx = "\x00\x00\x00\x00"; // Fake .notdef
 | 
			
		||||
        // Horizontal metrics
 | 
			
		||||
        "hmtx": (function() {
 | 
			
		||||
          var hmtx = "\x00\x00\x00\x00"; // Fake .notdef
 | 
			
		||||
          for (var i = 0; i < charstrings.length; i++) {
 | 
			
		||||
            hmtx += string16(charstrings[i].width) + string16(0);
 | 
			
		||||
          }
 | 
			
		||||
      hmtx = stringToArray(hmtx);
 | 
			
		||||
      createTableEntry(otf, offsets, "hmtx", hmtx);
 | 
			
		||||
          return stringToArray(hmtx);
 | 
			
		||||
        })(),
 | 
			
		||||
 | 
			
		||||
      /** MAXP */
 | 
			
		||||
      maxp = "\x00\x00\x50\x00" + // Version number
 | 
			
		||||
             string16(charstrings.length + 1); // Num of glyphs
 | 
			
		||||
      maxp = stringToArray(maxp);
 | 
			
		||||
      createTableEntry(otf, offsets, "maxp", maxp);
 | 
			
		||||
        // Maximum profile
 | 
			
		||||
        "maxp": (function() {
 | 
			
		||||
          return stringToArray(
 | 
			
		||||
              "\x00\x00\x50\x00" + // Version number
 | 
			
		||||
             string16(charstrings.length + 1)); // Num of glyphs
 | 
			
		||||
        })(),
 | 
			
		||||
 | 
			
		||||
      /** NAME */
 | 
			
		||||
      name = stringToArray(createNameTable(fontName));
 | 
			
		||||
      createTableEntry(otf, offsets, "name", name);
 | 
			
		||||
        // Naming tables
 | 
			
		||||
        "name": stringToArray(createNameTable(fontName)),
 | 
			
		||||
 | 
			
		||||
      /** POST */
 | 
			
		||||
      post = stringToArray(createPostTable(properties));
 | 
			
		||||
      createTableEntry(otf, offsets, "post", post);
 | 
			
		||||
        // PostScript informations
 | 
			
		||||
        "post": stringToArray(createPostTable(properties))
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      // 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];
 | 
			
		||||
      for (var field in fields)
 | 
			
		||||
        createTableEntry(otf, offsets, field, fields[field]);
 | 
			
		||||
 | 
			
		||||
      for (var field in fields) {
 | 
			
		||||
        var table = fields[field];
 | 
			
		||||
        otf.set(table, offsets.currentOffset);
 | 
			
		||||
        offsets.currentOffset += table.length;
 | 
			
		||||
      }
 | 
			
		||||
@ -1144,54 +1149,6 @@ var Font = (function () {
 | 
			
		||||
  return constructor;
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * FontsUtils is a static class dedicated to hold codes that are not related
 | 
			
		||||
 * to fonts in particular and needs to be share between them.
 | 
			
		||||
 */
 | 
			
		||||
var FontsUtils = {
 | 
			
		||||
  _bytesArray: new Uint8Array(4),
 | 
			
		||||
  integerToBytes: function fu_integerToBytes(value, bytesCount) {
 | 
			
		||||
    var bytes = this._bytesArray;
 | 
			
		||||
 | 
			
		||||
    if (bytesCount == 1) {
 | 
			
		||||
      bytes.set([value]);
 | 
			
		||||
      return bytes[0];
 | 
			
		||||
    } else if (bytesCount == 2) {
 | 
			
		||||
      bytes.set([value >> 8, value & 0xff]);
 | 
			
		||||
      return [bytes[0], bytes[1]];
 | 
			
		||||
    } else if (bytesCount == 4) {
 | 
			
		||||
      bytes.set([value >> 24, value >> 16, value >> 8, value]);
 | 
			
		||||
      return [bytes[0], bytes[1], bytes[2], bytes[3]];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    error("This number of bytes " + bytesCount + " is not supported");
 | 
			
		||||
    return null;
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  bytesToInteger: function fu_bytesToInteger(bytesArray) {
 | 
			
		||||
    var value = 0;
 | 
			
		||||
    for (var i = 0; i < bytesArray.length; i++)
 | 
			
		||||
      value = (value << 8) + bytesArray[i];
 | 
			
		||||
    return value;
 | 
			
		||||
  },
 | 
			
		||||
 | 
			
		||||
  getMaxPower2: function fu_getMaxPower2(number) {
 | 
			
		||||
    var maxPower = 0;
 | 
			
		||||
    var value = number;
 | 
			
		||||
    while (value >= 2) {
 | 
			
		||||
      value /= 2;
 | 
			
		||||
      maxPower++;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    value = 2;
 | 
			
		||||
    for (var i = 1; i < maxPower; i++)
 | 
			
		||||
      value *= 2;
 | 
			
		||||
    return value;
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Type1Parser encapsulate the needed code for parsing a Type1 font
 | 
			
		||||
 * program.
 | 
			
		||||
@ -1638,10 +1595,7 @@ CFF.prototype = {
 | 
			
		||||
    if (count == 0)
 | 
			
		||||
      return "\x00\x00\x00";
 | 
			
		||||
 | 
			
		||||
    var data = "";
 | 
			
		||||
    var bytes = FontsUtils.integerToBytes(count, 2);
 | 
			
		||||
    for (var i = 0; i < bytes.length; i++)
 | 
			
		||||
      data += String.fromCharCode(bytes[i]);
 | 
			
		||||
    var data = String.fromCharCode(count >> 8, count & 0xff);
 | 
			
		||||
 | 
			
		||||
    // 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
 | 
			
		||||
@ -1651,9 +1605,8 @@ CFF.prototype = {
 | 
			
		||||
    // 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 += String.fromCharCode(bytes[j]);
 | 
			
		||||
      data += String.fromCharCode(relativeOffset >> 24, relativeOffset >> 16,
 | 
			
		||||
                                  relativeOffset >> 8, relativeOffset & 0xff);
 | 
			
		||||
 | 
			
		||||
      if (objects[i])
 | 
			
		||||
        relativeOffset += objects[i].length;
 | 
			
		||||
@ -1703,7 +1656,7 @@ CFF.prototype = {
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    charstrings.sort(function charstrings_sort(a, b) {
 | 
			
		||||
      return a.unicode > b.unicode;
 | 
			
		||||
      return a.unicode - b.unicode;
 | 
			
		||||
    });
 | 
			
		||||
    return charstrings;
 | 
			
		||||
  },
 | 
			
		||||
@ -1848,8 +1801,7 @@ CFF.prototype = {
 | 
			
		||||
          if (index == -1)
 | 
			
		||||
            index = 0;
 | 
			
		||||
 | 
			
		||||
          var bytes = FontsUtils.integerToBytes(index, 2);
 | 
			
		||||
          charset += String.fromCharCode(bytes[0]) + String.fromCharCode(bytes[1]);
 | 
			
		||||
          charset += String.fromCharCode(index >> 8, index & 0xff);
 | 
			
		||||
        }
 | 
			
		||||
        return charset;
 | 
			
		||||
      })(this),
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user