* 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";
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