function createHeadTable(font) { var buf = new ByteBuffer(54); // fixed table length buf.writeInt32(0x10000); // version buf.writeInt32(font.revision * 0x10000); // fontRevision buf.writeUint32(0); // checkSumAdjustment buf.writeUint32(0x5F0F3CF5); // magicNumber // FLag meanings: // Bit 0: Baseline for font at y=0; // Bit 1: Left sidebearing point at x=0; // Bit 3: Force ppem to integer values for all internal scaler math; may use fractional ppem sizes if this bit is clear; buf.writeUint16(0x000B); // flags buf.writeUint16(font.unitsPerEm); // unitsPerEm buf.writeUint64(dateToUInt64(font.createdDate)); // created buf.writeUint64(dateToUInt64(font.modifiedDate)); // modified buf.writeInt16(font.xMin); // xMin buf.writeInt16(font.yMin); // yMin buf.writeInt16(font.xMax); // xMax buf.writeInt16(font.yMax); // yMax buf.writeUint16(font.macStyle); //macStyle buf.writeUint16(font.lowestRecPPEM); // lowestRecPPEM buf.writeInt16(2); // fontDirectionHint buf.writeInt16(font.ttf_glyph_size < 0x20000 ? 0 : 1); // indexToLocFormat, 0 for short offsets, 1 for long offsets buf.writeInt16(0); // glyphDataFormat return buf; }
// Write one feature containing all ligatures function createFeatureList() { var header = (0 + 2 // FeatureCount + 4 // FeatureTag[0] + 2 // Feature Offset[0] ); var length = (0 + header + 2 // FeatureParams[0] + 2 // LookupCount[0] + 2 // Lookup[0] LookupListIndex[0] ); var buffer = new ByteBuffer(length); // FeatureCount buffer.writeUint16(1); // FeatureTag[0] buffer.writeUint32(identifier('liga')); // Feature Offset[0] buffer.writeUint16(header); // FeatureParams[0] buffer.writeUint16(0); // LookupCount[0] buffer.writeUint16(1); // Index into lookup table. Since we only have ligatures, the index is always 0 buffer.writeUint16(0); return buffer; }
function createScriptList() { var header = (0 + 2 // Script count + 4 // Tag[0] + 2 // Offset[0] ); var scriptRecord = (0 + 2 // Script[0] DefaultLangSys Offset + 2 // Script[0] LangSysCount (0) ); var langSys = (0 + 2 // Script[0] DefaultLangSys LookupOrder + 2 // Script[0] DefaultLangSys ReqFeatureIndex + 2 // Script[0] DefaultLangSys FeatureCount (0?) + 2 // Script[0] Optional Feature Index[0] ); var length = (0 + header + scriptRecord + langSys ); var buffer = new ByteBuffer(length); // Script count buffer.writeUint16(1); // Script identifier DFLT buffer.writeUint32(identifier('DFLT')); // Offset to the ScriptRecord buffer.writeUint16(header); // Script Record // Offset to the start of langSys from the start of scriptRecord buffer.writeUint16(scriptRecord); // DefaultLangSys // Number of LangSys entries other than the default buffer.writeUint16(0); // LangSys record // LookupOrder buffer.writeUint16(0); // ReqFeatureIndex -> only one required feature: all ligatures buffer.writeUint16(0); // Number of FeatureIndex values for this language system (excludes the required feature) buffer.writeUint16(1); // FeatureIndex for the first optional feature // Note: Adding the same feature to both the optional // and the required features is a clear violation of the spec // but it fixes IE not displaying the ligatures. // See http://partners.adobe.com/public/developer/opentype/index_table_formats.html, Section “Language System Table” // “FeatureCount: Number of FeatureIndex values for this language system-*excludes the required feature*” (emphasis added) buffer.writeUint16(0); return buffer; }
function createGSUB(font) { var scriptList = createScriptList(); var featureList = createFeatureList(); var lookupList = createLookupList(font); var lists = [scriptList, featureList, lookupList]; var offset = (0 + 4 // Version + 2 * lists.length // List offsets ); // Calculate offsets _.forEach(lists, function(list) { list._listOffset = offset; offset += list.length; }); var length = offset; var buffer = new ByteBuffer(length); // Version buffer.writeUint32(0x00010000); // Offsets _.forEach(lists, function(list) { buffer.writeUint16(list._listOffset); }); // List contents _.forEach(lists, function(list) { buffer.writeBytes(list.buffer); }); return buffer; }