UNPKG

opentype.features.js

Version:

Library to list opentype fonts optional features.

189 lines (188 loc) 7.67 kB
"use strict"; // Table metadata var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var check_1 = __importDefault(require("./check")); var types_1 = require("./types"); /** * @exports opentype.Table * @class * @param {string} tableName * @param {Array} fields * @param {Object} options * @constructor */ function Table(tableName, fields, options) { // For coverage tables with coverage format 2, we do not want to add the coverage data directly to the table object, // as this will result in wrong encoding order of the coverage data on serialization to bytes. // The fallback of using the field values directly when not present on the table is handled in types.encode.TABLE() already. if (fields.length && (fields[0].name !== 'coverageFormat' || fields[0].value === 1)) { for (var i = 0; i < fields.length; i += 1) { var field = fields[i]; this[field.name] = field.value; } } this.tableName = tableName; this.fields = fields; if (options) { var optionKeys = Object.keys(options); for (var i = 0; i < optionKeys.length; i += 1) { var k = optionKeys[i]; var v = options[k]; if (this[k] !== undefined) { this[k] = v; } } } } /** * Encodes the table and returns an array of bytes * @return {Array} */ Table.prototype.encode = function () { return types_1.encode.TABLE(this); }; /** * Get the size of the table. * @return {number} */ Table.prototype.sizeOf = function () { return types_1.sizeOf.TABLE(this); }; /** * @private */ function ushortList(itemName, list, count) { if (count === undefined) { count = list.length; } var fields = new Array(list.length + 1); fields[0] = { name: itemName + 'Count', type: 'USHORT', value: count }; for (var i = 0; i < list.length; i++) { fields[i + 1] = { name: itemName + i, type: 'USHORT', value: list[i] }; } return fields; } /** * @private */ function tableList(itemName, records, itemCallback) { var count = records.length; var fields = new Array(count + 1); fields[0] = { name: itemName + 'Count', type: 'USHORT', value: count }; for (var i = 0; i < count; i++) { fields[i + 1] = { name: itemName + i, type: 'TABLE', value: itemCallback(records[i], i) }; } return fields; } /** * @private */ function recordList(itemName, records, itemCallback) { var count = records.length; var fields = []; fields[0] = { name: itemName + 'Count', type: 'USHORT', value: count }; for (var i = 0; i < count; i++) { fields = fields.concat(itemCallback(records[i], i)); } return fields; } // Common Layout Tables /** * @exports opentype.Coverage * @class * @param {opentype.Table} * @constructor * @extends opentype.Table */ function Coverage(coverageTable) { if (coverageTable.format === 1) { Table.call(this, 'coverageTable', [{ name: 'coverageFormat', type: 'USHORT', value: 1 }] .concat(ushortList('glyph', coverageTable.glyphs))); } else if (coverageTable.format === 2) { Table.call(this, 'coverageTable', [{ name: 'coverageFormat', type: 'USHORT', value: 2 }] .concat(recordList('rangeRecord', coverageTable.ranges, function (RangeRecord) { return [ { name: 'startGlyphID', type: 'USHORT', value: RangeRecord.start }, { name: 'endGlyphID', type: 'USHORT', value: RangeRecord.end }, { name: 'startCoverageIndex', type: 'USHORT', value: RangeRecord.index }, ]; }))); } else { check_1.default.assert(false, 'Coverage format must be 1 or 2.'); } } Coverage.prototype = Object.create(Table.prototype); Coverage.prototype.constructor = Coverage; function ScriptList(scriptListTable) { Table.call(this, 'scriptListTable', recordList('scriptRecord', scriptListTable, function (scriptRecord, i) { var script = scriptRecord.script; var defaultLangSys = script.defaultLangSys; check_1.default.assert(!!defaultLangSys, 'Unable to write GSUB: script ' + scriptRecord.tag + ' has no default language system.'); return [ { name: 'scriptTag' + i, type: 'TAG', value: scriptRecord.tag }, { name: 'script' + i, type: 'TABLE', value: new Table('scriptTable', [ { name: 'defaultLangSys', type: 'TABLE', value: new Table('defaultLangSys', [ { name: 'lookupOrder', type: 'USHORT', value: 0 }, { name: 'reqFeatureIndex', type: 'USHORT', value: defaultLangSys.reqFeatureIndex } ] .concat(ushortList('featureIndex', defaultLangSys.featureIndexes))) } ].concat(recordList('langSys', script.langSysRecords, function (langSysRecord, i) { var langSys = langSysRecord.langSys; return [ { name: 'langSysTag' + i, type: 'TAG', value: langSysRecord.tag }, { name: 'langSys' + i, type: 'TABLE', value: new Table('langSys', [ { name: 'lookupOrder', type: 'USHORT', value: 0 }, { name: 'reqFeatureIndex', type: 'USHORT', value: langSys.reqFeatureIndex } ].concat(ushortList('featureIndex', langSys.featureIndexes))) } ]; }))) } ]; })); } ScriptList.prototype = Object.create(Table.prototype); ScriptList.prototype.constructor = ScriptList; /** * @exports opentype.FeatureList * @class * @param {opentype.Table} * @constructor * @extends opentype.Table */ function FeatureList(featureListTable) { Table.call(this, 'featureListTable', recordList('featureRecord', featureListTable, function (featureRecord, i) { var feature = featureRecord.feature; return [ { name: 'featureTag' + i, type: 'TAG', value: featureRecord.tag }, { name: 'feature' + i, type: 'TABLE', value: new Table('featureTable', [ { name: 'featureParams', type: 'USHORT', value: feature.featureParams }, ].concat(ushortList('lookupListIndex', feature.lookupListIndexes))) } ]; })); } FeatureList.prototype = Object.create(Table.prototype); FeatureList.prototype.constructor = FeatureList; /** * @exports opentype.LookupList * @class * @param {opentype.Table} * @param {Object} * @constructor * @extends opentype.Table */ function LookupList(lookupListTable, subtableMakers) { Table.call(this, 'lookupListTable', tableList('lookup', lookupListTable, function (lookupTable) { var subtableCallback = subtableMakers[lookupTable.lookupType]; check_1.default.assert(!!subtableCallback, 'Unable to write GSUB lookup type ' + lookupTable.lookupType + ' tables.'); return new Table('lookupTable', [ { name: 'lookupType', type: 'USHORT', value: lookupTable.lookupType }, { name: 'lookupFlag', type: 'USHORT', value: lookupTable.lookupFlag } ].concat(tableList('subtable', lookupTable.subtables, subtableCallback))); })); } LookupList.prototype = Object.create(Table.prototype); LookupList.prototype.constructor = LookupList;