Clean up a bit the code to generate an OTF

This commit is contained in:
Vivien Nicolas 2011-06-13 04:37:53 +02:00
parent cebdda3f35
commit c6f5385d15

View File

@ -95,7 +95,7 @@ Font.prototype = {
styleSheet.insertRule(rule, styleSheet.length); styleSheet.insertRule(rule, styleSheet.length);
}, },
_createOpenTypeHeader: function font_createOpenTypeHeader(aNumTables) { _createOpenTypeHeader: function font_createOpenTypeHeader(aFile, aOffsets, aNumTables) {
// sfnt version (4 bytes) // sfnt version (4 bytes)
var version = [0x4F, 0x54, 0x54, 0X4F]; var version = [0x4F, 0x54, 0x54, 0X4F];
@ -112,14 +112,17 @@ Font.prototype = {
// rangeShift (2 bytes) // rangeShift (2 bytes)
var rangeShift = numTables * 16 - searchRange; var rangeShift = numTables * 16 - searchRange;
return [].concat(version, var header = [].concat(version,
FontsUtils.integerToBytes(numTables, 2), FontsUtils.integerToBytes(numTables, 2),
FontsUtils.integerToBytes(searchRange, 2), FontsUtils.integerToBytes(searchRange, 2),
FontsUtils.integerToBytes(entrySelector, 2), FontsUtils.integerToBytes(entrySelector, 2),
FontsUtils.integerToBytes(rangeShift, 2)); FontsUtils.integerToBytes(rangeShift, 2));
aFile.set(header, aOffsets.currentOffset);
aOffsets.currentOffset += header.length;
aOffsets.virtualOffset += header.length;
}, },
_createTableEntry: function font_createTableEntry(aTag, aOffset, aData) { _createTableEntry: function font_createTableEntry(aFile, aOffsets, aTag, aData) {
// tag // tag
var tag = [ var tag = [
aTag.charCodeAt(0), aTag.charCodeAt(0),
@ -129,7 +132,7 @@ Font.prototype = {
]; ];
// offset // offset
var offset = aOffset; var offset = aOffsets.virtualOffset;
// Per spec tables must be 4-bytes align so add some 0x00 if needed // Per spec tables must be 4-bytes align so add some 0x00 if needed
while (aData.length & 3) while (aData.length & 3)
@ -141,10 +144,13 @@ Font.prototype = {
// checksum // checksum
var checksum = FontsUtils.bytesToInteger(tag) + offset + length; var checksum = FontsUtils.bytesToInteger(tag) + offset + length;
return [].concat(tag, var tableEntry = [].concat(tag,
FontsUtils.integerToBytes(checksum, 4), FontsUtils.integerToBytes(checksum, 4),
FontsUtils.integerToBytes(offset, 4), FontsUtils.integerToBytes(offset, 4),
FontsUtils.integerToBytes(length, 4)); FontsUtils.integerToBytes(length, 4));
aFile.set(tableEntry, aOffsets.currentOffset);
aOffsets.currentOffset += tableEntry.length;
aOffsets.virtualOffset += aData.length;
}, },
_createCMAPTable: function font_createCMAPTable(aGlyphs) { _createCMAPTable: function font_createCMAPTable(aGlyphs) {
@ -230,23 +236,39 @@ Font.prototype = {
cover: function font_cover(aFont) { cover: function font_cover(aFont) {
var otf = new Uint8Array(kMaxFontFileSize); var otf = new Uint8Array(kMaxFontFileSize);
var aFontData = aFont.data;
var currentOffset = 0;
var numTables = 9; // Required Tables
//var tables = [OS2, cmap, head, hhea, hmtx, maxp, name, post]; var CFF = aFont.data,
var header = this._createOpenTypeHeader(numTables); OS2 = [],
otf.set(header, currentOffset); cmap = [],
currentOffset += header.length; head = [],
hhea = [],
hmtx = [],
maxp = [],
name = [],
post = [];
var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post];
var baseOffset = numTables * (4 * 4) + currentOffset; // The offsets object holds at the same time a representation of where
var virtualOffset = baseOffset; // to write the table entry information about a table and another offset
var tableEntry = this._createTableEntry("CFF ", virtualOffset, aFontData); // representing the offset where to draw the actual data of a particular
otf.set(tableEntry, currentOffset); // table
currentOffset += tableEntry.length; var offsets = {
virtualOffset += aFontData.length; currentOffset: 0,
virtualOffset: tables.length * (4 * 4)
};
var OS2 = [ // 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 0x00, 0x03, // version
0x02, 0x24, // xAvgCharWidth 0x02, 0x24, // xAvgCharWidth
0x01, 0xF4, // usWeightClass 0x01, 0xF4, // usWeightClass
@ -268,7 +290,7 @@ Font.prototype = {
0x00, 0x00, 0x00, 0x00, // ulUnicodeRange2 (Bits 32-63) 0x00, 0x00, 0x00, 0x00, // ulUnicodeRange2 (Bits 32-63)
0x00, 0x00, 0x00, 0x00, // ulUnicodeRange3 (Bits 64-95) 0x00, 0x00, 0x00, 0x00, // ulUnicodeRange3 (Bits 64-95)
0x00, 0x00, 0x00, 0x00, // ulUnicodeRange4 (Bits 96-127) 0x00, 0x00, 0x00, 0x00, // ulUnicodeRange4 (Bits 96-127)
0x47, 0x49, 0x60, 0x20, // achVendID 0x2A, 0x32, 0x31, 0x2A, // achVendID
0x00, 0x20, // fsSelection 0x00, 0x20, // fsSelection
0x00, 0x2D, // usFirstCharIndex 0x00, 0x2D, // usFirstCharIndex
0x00, 0x7A, // usLastCharIndex 0x00, 0x7A, // usLastCharIndex
@ -285,25 +307,17 @@ Font.prototype = {
0x00, 0xCD, // usBreakChar 0x00, 0xCD, // usBreakChar
0x00, 0x02 // usMaxContext 0x00, 0x02 // usMaxContext
]; ];
this._createTableEntry(otf, offsets, "OS/2", OS2);
var tableEntry = this._createTableEntry("OS/2", virtualOffset, OS2); //XXX Getting charstrings here seems wrong since this is another CFF glue
otf.set(tableEntry, currentOffset);
currentOffset += tableEntry.length;
virtualOffset += OS2.length;
/** CMAP */
var charstrings = aFont.getOrderedCharStrings(aFont.font); var charstrings = aFont.getOrderedCharStrings(aFont.font);
var cmap = this._createCMAPTable(charstrings); /** CMAP */
var tableEntry = this._createTableEntry("cmap", virtualOffset, cmap); cmap = this._createCMAPTable(charstrings);
otf.set(tableEntry, currentOffset); this._createTableEntry(otf, offsets, "cmap", cmap);
currentOffset += tableEntry.length;
virtualOffset += cmap.length;
/** HEAD */ /** HEAD */
head = [
var head = [
0x00, 0x01, 0x00, 0x00, // Version number 0x00, 0x01, 0x00, 0x00, // Version number
0x00, 0x00, 0x50, 0x00, // fontRevision 0x00, 0x00, 0x50, 0x00, // fontRevision
0x00, 0x00, 0x00, 0x00, // checksumAdjustement 0x00, 0x00, 0x00, 0x00, // checksumAdjustement
@ -322,15 +336,11 @@ Font.prototype = {
0x00, 0x00, // indexToLocFormat 0x00, 0x00, // indexToLocFormat
0x00, 0x00 // glyphDataFormat 0x00, 0x00 // glyphDataFormat
]; ];
var tableEntry = this._createTableEntry("head", virtualOffset, head); this._createTableEntry(otf, offsets, "head", head);
otf.set(tableEntry, currentOffset);
currentOffset += tableEntry.length;
virtualOffset += head.length;
/** HHEA */ /** HHEA */
hhea = [].concat(
var hhea = [ [
0x00, 0x01, 0x00, 0x00, // Version number 0x00, 0x01, 0x00, 0x00, // Version number
0x00, 0x00, // Typographic Ascent 0x00, 0x00, // Typographic Ascent
0x00, 0x00, // Typographic Descent 0x00, 0x00, // Typographic Descent
@ -347,59 +357,42 @@ Font.prototype = {
0x00, 0x00, // -reserved- 0x00, 0x00, // -reserved-
0x00, 0x00, // -reserved- 0x00, 0x00, // -reserved-
0x00, 0x00 // metricDataFormat 0x00, 0x00 // metricDataFormat
]; ],
hhea = hhea.concat(FontsUtils.integerToBytes(charstrings.length, 2)); // numberOfHMetrics FontsUtils.integerToBytes(charstrings.length, 2) // numberOfHMetrics
);
var tableEntry = this._createTableEntry("hhea", virtualOffset, hhea); this._createTableEntry(otf, offsets, "hhea", hhea);
otf.set(tableEntry, currentOffset);
currentOffset += tableEntry.length;
virtualOffset += hhea.length;
/** HMTX */ /** HMTX */
hmtx = [0x01, 0xF4, 0x00, 0x00];
var hmtx = [0x01, 0xF4, 0x00, 0x00];
for (var i = 0; i < charstrings.length; i++) { for (var i = 0; i < charstrings.length; i++) {
// XXX this can easily broke
var charstring = charstrings[i].charstring; var charstring = charstrings[i].charstring;
var width = FontsUtils.integerToBytes(charstring[1], 2); var width = FontsUtils.integerToBytes(charstring[1], 2);
var lsb = FontsUtils.integerToBytes(charstring[0], 2); var lsb = FontsUtils.integerToBytes(charstring[0], 2);
hmtx = hmtx.concat(width, lsb); hmtx = hmtx.concat(width, lsb);
} }
this._createTableEntry(otf, offsets, "hmtx", hmtx);
var tableEntry = this._createTableEntry("hmtx", virtualOffset, hmtx);
otf.set(tableEntry, currentOffset);
currentOffset += tableEntry.length;
virtualOffset += hmtx.length;
/** MAXP */ /** MAXP */
maxp = [].concat(
var maxp = [ [
0x00, 0x00, 0x50, 0x00, // Version number 0x00, 0x00, 0x50, 0x00, // Version number
].concat(FontsUtils.integerToBytes(charstrings.length + 1, 2)); // Num of glyphs (+1 to pass the sanitizer...) ],
FontsUtils.integerToBytes(charstrings.length + 1, 2) // Num of glyphs (+1 to pass the sanitizer...)
var tableEntry = this._createTableEntry("maxp", virtualOffset, maxp); );
otf.set(tableEntry, currentOffset); this._createTableEntry(otf, offsets, "maxp", maxp);
currentOffset += tableEntry.length;
virtualOffset += maxp.length;
/** NAME */ /** NAME */
name = [
var name = [
0x00, 0x00, // format 0x00, 0x00, // format
0x00, 0x00, // Number of names Record 0x00, 0x00, // Number of names Record
0x00, 0x00 // Storage 0x00, 0x00 // Storage
]; ];
var tableEntry = this._createTableEntry("name", virtualOffset, name); this._createTableEntry(otf, offsets, "name", name);
otf.set(tableEntry, currentOffset);
currentOffset += tableEntry.length;
virtualOffset += name.length;
/** POST */ /** POST */
// XXX get those info from the Font dict! // XXX get those info from the Font dict!
var post = [ post = [
0x00, 0x03, 0x00, 0x00, // Version number 0x00, 0x03, 0x00, 0x00, // Version number
0x00, 0x00, 0x01, 0x00, // italicAngle 0x00, 0x00, 0x01, 0x00, // italicAngle
0x00, 0x00, // underlinePosition 0x00, 0x00, // underlinePosition
@ -410,24 +403,18 @@ Font.prototype = {
0x00, 0x00, 0x00, 0x00, // minMemType1 0x00, 0x00, 0x00, 0x00, // minMemType1
0x00, 0x00, 0x00, 0x00 // maxMemType1 0x00, 0x00, 0x00, 0x00 // maxMemType1
]; ];
var tableEntry = this._createTableEntry("post", virtualOffset, post); this._createTableEntry(otf, offsets, "post", post);
otf.set(tableEntry, currentOffset);
currentOffset += tableEntry.length;
virtualOffset += post.length;
// Set the CFF data // Once all the table entry are written, this is time to dump the data!
otf.set(aFontData, currentOffset); var tables = [CFF, OS2, cmap, head, hhea, hmtx, maxp, name, post];
currentOffset += aFontData.length;
var tables = [OS2, cmap, head, hhea, hmtx, maxp, name, post];
for (var i = 0; i < tables.length; i++) { for (var i = 0; i < tables.length; i++) {
var table = tables[i]; var table = tables[i];
otf.set(table, currentOffset); otf.set(table, offsets.currentOffset);
currentOffset += table.length; offsets.currentOffset += table.length;
} }
var fontData = []; var fontData = [];
for (var i = 0; i < currentOffset; i++) for (var i = 0; i < offsets.currentOffset; i++)
fontData.push(otf[i]); fontData.push(otf[i]);
writeToFile(fontData, "/tmp/pdf.js." + fontCount + ".otf"); writeToFile(fontData, "/tmp/pdf.js." + fontCount + ".otf");