opentype.js
Advanced tools
Comparing version 0.6.1 to 0.6.2
{ | ||
"name": "opentype.js", | ||
"version": "0.6.1", | ||
"version": "0.6.2", | ||
"main": "dist/opentype.js", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
{ | ||
"name": "opentype.js", | ||
"description": "OpenType font parser", | ||
"version": "0.6.1", | ||
"version": "0.6.2", | ||
"author": { | ||
@@ -6,0 +6,0 @@ "name": "Frederik De Bleser", |
@@ -1,3 +0,7 @@ | ||
0.6.1 (February 20, 2015) | ||
0.6.2 (March 11, 2016) | ||
========================= | ||
* Improve table writing to support nested subtables. Thanks @fpirsch! | ||
0.6.1 (February 20, 2016) | ||
========================= | ||
* Left side bearing is now correctly reported. | ||
@@ -4,0 +8,0 @@ * Simplified code for including ascender / descender values. |
@@ -70,4 +70,6 @@ // opentype.js | ||
var tag = parse.getTag(data, p); | ||
var checksum = parse.getULong(data, p + 4); | ||
var offset = parse.getULong(data, p + 8); | ||
tableEntries.push({tag: tag, offset: offset, compression: false}); | ||
var length = parse.getULong(data, p + 12); | ||
tableEntries.push({tag: tag, checksum: checksum, offset: offset, length: length, compression: false}); | ||
p += 16; | ||
@@ -74,0 +76,0 @@ } |
@@ -5,3 +5,2 @@ // Table metadata | ||
var check = require('./check'); | ||
var encode = require('./types').encode; | ||
@@ -31,23 +30,2 @@ var sizeOf = require('./types').sizeOf; | ||
Table.prototype.sizeOf = function() { | ||
var v = 0; | ||
for (var i = 0; i < this.fields.length; i += 1) { | ||
var field = this.fields[i]; | ||
var value = this[field.name]; | ||
if (value === undefined) { | ||
value = field.value; | ||
} | ||
if (typeof value.sizeOf === 'function') { | ||
v += value.sizeOf(); | ||
} else { | ||
var sizeOfFunction = sizeOf[field.type]; | ||
check.assert(typeof sizeOfFunction === 'function', 'Could not find sizeOf function for field' + field.name); | ||
v += sizeOfFunction(value); | ||
} | ||
} | ||
return v; | ||
}; | ||
Table.prototype.encode = function() { | ||
@@ -57,2 +35,6 @@ return encode.TABLE(this); | ||
exports.Table = Table; | ||
Table.prototype.sizeOf = function() { | ||
return sizeOf.TABLE(this); | ||
}; | ||
exports.Record = exports.Table = Table; |
@@ -860,3 +860,3 @@ // The `CFF` table contains the glyph outlines in PostScript format. | ||
function makeHeader() { | ||
return new table.Table('Header', [ | ||
return new table.Record('Header', [ | ||
{name: 'major', type: 'Card8', value: 1}, | ||
@@ -870,3 +870,3 @@ {name: 'minor', type: 'Card8', value: 0}, | ||
function makeNameIndex(fontNames) { | ||
var t = new table.Table('Name INDEX', [ | ||
var t = new table.Record('Name INDEX', [ | ||
{name: 'names', type: 'INDEX', value: []} | ||
@@ -902,3 +902,3 @@ ]); | ||
function makeTopDict(attrs, strings) { | ||
var t = new table.Table('Top DICT', [ | ||
var t = new table.Record('Top DICT', [ | ||
{name: 'dict', type: 'DICT', value: {}} | ||
@@ -911,3 +911,3 @@ ]); | ||
function makeTopDictIndex(topDict) { | ||
var t = new table.Table('Top DICT INDEX', [ | ||
var t = new table.Record('Top DICT INDEX', [ | ||
{name: 'topDicts', type: 'INDEX', value: []} | ||
@@ -920,3 +920,3 @@ ]); | ||
function makeStringIndex(strings) { | ||
var t = new table.Table('String INDEX', [ | ||
var t = new table.Record('String INDEX', [ | ||
{name: 'strings', type: 'INDEX', value: []} | ||
@@ -934,3 +934,3 @@ ]); | ||
// Currently we don't use subroutines. | ||
return new table.Table('Global Subr INDEX', [ | ||
return new table.Record('Global Subr INDEX', [ | ||
{name: 'subrs', type: 'INDEX', value: []} | ||
@@ -941,3 +941,3 @@ ]); | ||
function makeCharsets(glyphNames, strings) { | ||
var t = new table.Table('Charsets', [ | ||
var t = new table.Record('Charsets', [ | ||
{name: 'format', type: 'Card8', value: 0} | ||
@@ -1024,3 +1024,3 @@ ]); | ||
function makeCharStringsIndex(glyphs) { | ||
var t = new table.Table('CharStrings INDEX', [ | ||
var t = new table.Record('CharStrings INDEX', [ | ||
{name: 'charStrings', type: 'INDEX', value: []} | ||
@@ -1039,3 +1039,3 @@ ]); | ||
function makePrivateDict(attrs, strings) { | ||
var t = new table.Table('Private DICT', [ | ||
var t = new table.Record('Private DICT', [ | ||
{name: 'dict', type: 'DICT', value: {}} | ||
@@ -1049,10 +1049,10 @@ ]); | ||
var t = new table.Table('CFF ', [ | ||
{name: 'header', type: 'TABLE'}, | ||
{name: 'nameIndex', type: 'TABLE'}, | ||
{name: 'topDictIndex', type: 'TABLE'}, | ||
{name: 'stringIndex', type: 'TABLE'}, | ||
{name: 'globalSubrIndex', type: 'TABLE'}, | ||
{name: 'charsets', type: 'TABLE'}, | ||
{name: 'charStringsIndex', type: 'TABLE'}, | ||
{name: 'privateDict', type: 'TABLE'} | ||
{name: 'header', type: 'RECORD'}, | ||
{name: 'nameIndex', type: 'RECORD'}, | ||
{name: 'topDictIndex', type: 'RECORD'}, | ||
{name: 'stringIndex', type: 'RECORD'}, | ||
{name: 'globalSubrIndex', type: 'RECORD'}, | ||
{name: 'charsets', type: 'RECORD'}, | ||
{name: 'charStringsIndex', type: 'RECORD'}, | ||
{name: 'privateDict', type: 'RECORD'} | ||
]); | ||
@@ -1059,0 +1059,0 @@ |
@@ -32,12 +32,12 @@ // The `fvar` table stores font variation axes and instances. | ||
function makeFvarAxis(axis, names) { | ||
function makeFvarAxis(n, axis, names) { | ||
var nameID = addName(axis.name, names); | ||
return new table.Table('fvarAxis', [ | ||
{name: 'tag', type: 'TAG', value: axis.tag}, | ||
{name: 'minValue', type: 'FIXED', value: axis.minValue << 16}, | ||
{name: 'defaultValue', type: 'FIXED', value: axis.defaultValue << 16}, | ||
{name: 'maxValue', type: 'FIXED', value: axis.maxValue << 16}, | ||
{name: 'flags', type: 'USHORT', value: 0}, | ||
{name: 'nameID', type: 'USHORT', value: nameID} | ||
]); | ||
return [ | ||
{name: 'tag_' + n, type: 'TAG', value: axis.tag}, | ||
{name: 'minValue_' + n, type: 'FIXED', value: axis.minValue << 16}, | ||
{name: 'defaultValue_' + n, type: 'FIXED', value: axis.defaultValue << 16}, | ||
{name: 'maxValue_' + n, type: 'FIXED', value: axis.maxValue << 16}, | ||
{name: 'flags_' + n, type: 'USHORT', value: 0}, | ||
{name: 'nameID_' + n, type: 'USHORT', value: nameID} | ||
]; | ||
} | ||
@@ -57,7 +57,7 @@ | ||
function makeFvarInstance(inst, axes, names) { | ||
function makeFvarInstance(n, inst, axes, names) { | ||
var nameID = addName(inst.name, names); | ||
var fields = [ | ||
{name: 'nameID', type: 'USHORT', value: nameID}, | ||
{name: 'flags', type: 'USHORT', value: 0} | ||
{name: 'nameID_' + n, type: 'USHORT', value: nameID}, | ||
{name: 'flags_' + n, type: 'USHORT', value: 0} | ||
]; | ||
@@ -68,3 +68,3 @@ | ||
fields.push({ | ||
name: 'axis ' + axisTag, | ||
name: 'axis_' + n + ' ' + axisTag, | ||
type: 'FIXED', | ||
@@ -75,3 +75,3 @@ value: inst.coordinates[axisTag] << 16 | ||
return new table.Table('fvarInstance', fields); | ||
return fields; | ||
} | ||
@@ -106,14 +106,7 @@ | ||
for (var i = 0; i < fvar.axes.length; i++) { | ||
result.fields.push({ | ||
name: 'axis ' + i, | ||
type: 'TABLE', | ||
value: makeFvarAxis(fvar.axes[i], names)}); | ||
result.fields = result.fields.concat(makeFvarAxis(i, fvar.axes[i], names)); | ||
} | ||
for (var j = 0; j < fvar.instances.length; j++) { | ||
result.fields.push({ | ||
name: 'instance ' + j, | ||
type: 'TABLE', | ||
value: makeFvarInstance(fvar.instances[j], fvar.axes, names) | ||
}); | ||
result.fields = result.fields.concat(makeFvarInstance(j, fvar.instances[j], fvar.axes, names)); | ||
} | ||
@@ -120,0 +113,0 @@ |
@@ -689,3 +689,3 @@ // The `name` naming table. | ||
function makeNameRecord(platformID, encodingID, languageID, nameID, length, offset) { | ||
return new table.Table('NameRecord', [ | ||
return new table.Record('NameRecord', [ | ||
{name: 'platformID', type: 'USHORT', value: platformID}, | ||
@@ -823,3 +823,3 @@ {name: 'encodingID', type: 'USHORT', value: encodingID}, | ||
for (var r = 0; r < nameRecords.length; r++) { | ||
t.fields.push({name: 'record_' + r, type: 'TABLE', value: nameRecords[r]}); | ||
t.fields.push({name: 'record_' + r, type: 'RECORD', value: nameRecords[r]}); | ||
} | ||
@@ -826,0 +826,0 @@ |
@@ -45,3 +45,3 @@ // The `sfnt` wrapper provides organization for the tables in the font. | ||
function makeTableRecord(tag, checkSum, offset, length) { | ||
return new table.Table('Table Record', [ | ||
return new table.Record('Table Record', [ | ||
{name: 'tag', type: 'TAG', value: tag !== undefined ? tag : ''}, | ||
@@ -83,4 +83,4 @@ {name: 'checkSum', type: 'ULONG', value: checkSum !== undefined ? checkSum : 0}, | ||
var tableRecord = makeTableRecord(t.tableName, computeCheckSum(t.encode()), offset, tableLength); | ||
recordFields.push({name: tableRecord.tag + ' Table Record', type: 'TABLE', value: tableRecord}); | ||
tableFields.push({name: t.tableName + ' table', type: 'TABLE', value: t}); | ||
recordFields.push({name: tableRecord.tag + ' Table Record', type: 'RECORD', value: tableRecord}); | ||
tableFields.push({name: t.tableName + ' table', type: 'RECORD', value: t}); | ||
offset += tableLength; | ||
@@ -87,0 +87,0 @@ check.argument(!isNaN(offset), 'Something went wrong calculating the offset.'); |
@@ -569,7 +569,10 @@ // Data types used in the OpenType font file. | ||
var length = table.fields.length; | ||
var subtables = []; | ||
var subtableOffsets = []; | ||
var i; | ||
for (var i = 0; i < length; i += 1) { | ||
for (i = 0; i < length; i += 1) { | ||
var field = table.fields[i]; | ||
var encodingFunction = encode[field.type]; | ||
check.argument(encodingFunction !== undefined, 'No encoding function for field type ' + field.type); | ||
check.argument(encodingFunction !== undefined, 'No encoding function for field type ' + field.type + ' (' + field.name + ')'); | ||
var value = table[field.name]; | ||
@@ -581,5 +584,21 @@ if (value === undefined) { | ||
var bytes = encodingFunction(value); | ||
d = d.concat(bytes); | ||
if (field.type === 'TABLE') { | ||
subtableOffsets.push(d.length); | ||
d = d.concat([0, 0]); | ||
subtables.push(bytes); | ||
} else { | ||
d = d.concat(bytes); | ||
} | ||
} | ||
for (i = 0; i < subtables.length; i += 1) { | ||
var o = subtableOffsets[i]; | ||
var offset = d.length; | ||
check.argument(offset < 65536, 'Table ' + table.tableName + ' too big.'); | ||
d[o] = offset >> 8; | ||
d[o + 1] = offset & 0xff; | ||
d = d.concat(subtables[i]); | ||
} | ||
return d; | ||
@@ -595,3 +614,3 @@ }; | ||
var sizeOfFunction = sizeOf[field.type]; | ||
check.argument(sizeOfFunction !== undefined, 'No sizeOf function for field type ' + field.type); | ||
check.argument(sizeOfFunction !== undefined, 'No sizeOf function for field type ' + field.type + ' (' + field.name + ')'); | ||
var value = table[field.name]; | ||
@@ -603,2 +622,7 @@ if (value === undefined) { | ||
numBytes += sizeOfFunction(value); | ||
// Subtables take 2 more bytes for offsets. | ||
if (field.type === 'TABLE') { | ||
numBytes += 2; | ||
} | ||
} | ||
@@ -609,2 +633,5 @@ | ||
encode.RECORD = encode.TABLE; | ||
sizeOf.RECORD = sizeOf.TABLE; | ||
// Merge in a list of bytes. | ||
@@ -611,0 +638,0 @@ encode.LITERAL = function(v) { |
@@ -31,11 +31,8 @@ 'use strict'; | ||
var text = testutil.unhex(name[1]); | ||
var record = new table.Table('NameRecord', [ | ||
{name: 'platformID', type: 'USHORT', value: name[2]}, | ||
{name: 'encodingID', type: 'USHORT', value: name[3]}, | ||
{name: 'languageID', type: 'USHORT', value: name[4]}, | ||
{name: 'nameID', type: 'USHORT', value: name[0]}, | ||
{name: 'length', type: 'USHORT', value: text.byteLength}, | ||
{name: 'offset', type: 'USHORT', value: stringPool.length} | ||
]); | ||
t.fields.push({name: 'record_' + i, type: 'TABLE', value: record}); | ||
t.fields.push({name: 'platformID_' + i, type: 'USHORT', value: name[2]}); | ||
t.fields.push({name: 'encodingID_' + i, type: 'USHORT', value: name[3]}); | ||
t.fields.push({name: 'languageID_' + i, type: 'USHORT', value: name[4]}); | ||
t.fields.push({name: 'nameID_' + i, type: 'USHORT', value: name[0]}); | ||
t.fields.push({name: 'length_' + i, type: 'USHORT', value: text.byteLength}); | ||
t.fields.push({name: 'offset_' + i, type: 'USHORT', value: stringPool.length}); | ||
for (var j = 0; j < text.byteLength; j++) { | ||
@@ -47,2 +44,3 @@ stringPool.push(text.getUint8(j)); | ||
t.fields.push({name: 'strings', type: 'LITERAL', value: stringPool}); | ||
var bytes = types.encode.TABLE(t); | ||
@@ -49,0 +47,0 @@ var data = new DataView(new ArrayBuffer(bytes.length), 0); |
@@ -458,2 +458,85 @@ 'use strict'; | ||
it('can handle subTABLEs', function() { | ||
var table = { | ||
fields: [ | ||
{name: 'version', type: 'FIXED', value: 0x01234567}, | ||
{name: 'subtable', type: 'TABLE', value: { | ||
fields: [ | ||
{name: 'flags', type: 'USHORT', value: 0xBEEF} | ||
] | ||
}} | ||
] | ||
}; | ||
assert.equal(hex(encode.TABLE(table)), '01 23 45 67 00 06 BE EF'); | ||
assert.equal(sizeOf.TABLE(table), 8); | ||
}); | ||
it('can handle deeply nested TABLEs', function() { | ||
// First 58 bytes of Roboto-Black.ttf GSUB table. | ||
var expected = '00 01 00 00 00 0A 00 20 00 3A ' + // header | ||
'00 01 44 46 4C 54 00 08 00 04 00 00 00 00 FF FF 00 02 00 00 00 01 ' + // script list | ||
'00 02 6C 69 67 61 00 0E 73 6D 63 70 00 14 00 00 00 01 00 01 00 00 00 01 00 00'; // feature list | ||
var table = { | ||
fields: [ | ||
{name: 'version', type: 'FIXED', value: 0x00010000}, | ||
{name: 'scriptList', type: 'TABLE'}, | ||
{name: 'featureList', type: 'TABLE'}, | ||
{name: 'lookupList', type: 'TABLE'} | ||
], | ||
scriptList: { fields: [ | ||
{name: 'scriptCount', type: 'USHORT', value: 1}, | ||
{name: 'scriptTag_0', type: 'TAG', value: 'DFLT'}, | ||
{name: 'script_0', type: 'TABLE', value: { fields: [ | ||
{name: 'defaultLangSys', type: 'TABLE', value: { fields: [ | ||
{name: 'lookupOrder', type: 'USHORT', value: 0}, | ||
{name: 'reqFeatureIndex', type: 'USHORT', value: 0xffff}, | ||
{name: 'featureCount', type: 'USHORT', value: 2}, | ||
{name: 'featureIndex_0', type: 'USHORT', value: 0}, | ||
{name: 'featureIndex_1', type: 'USHORT', value: 1} | ||
]}}, | ||
{name: 'langSysCount', type: 'USHORT', value: 0} | ||
]}} | ||
]}, | ||
featureList: { fields: [ | ||
{name: 'featureCount', type: 'USHORT', value: 2}, | ||
{name: 'featureTag_0', type: 'TAG', value: 'liga'}, | ||
{name: 'feature_0', type: 'TABLE', value: { fields: [ | ||
{name: 'featureParams', type: 'USHORT', value: 0}, | ||
{name: 'lookupCount', type: 'USHORT', value: 1}, | ||
{name: 'lookupListIndex', type: 'USHORT', value: 1} | ||
]}}, | ||
{name: 'featureTag_1', type: 'TAG', value: 'smcp'}, | ||
{name: 'feature_1', type: 'TABLE', value: { fields: [ | ||
{name: 'featureParams', type: 'USHORT', value: 0}, | ||
{name: 'lookupCount', type: 'USHORT', value: 1}, | ||
{name: 'lookupListIndex', type: 'USHORT', value: 0} | ||
]}} | ||
]}, | ||
lookupList: { fields: [] } | ||
}; | ||
assert.equal(hex(encode.TABLE(table)), expected); | ||
assert.equal(sizeOf.TABLE(table), 58); | ||
}); | ||
it('can handle RECORD', function() { | ||
var table = { | ||
fields: [ | ||
{name: 'version', type: 'FIXED', value: 0x01234567}, | ||
{name: 'record', type: 'RECORD'} | ||
] | ||
}; | ||
table.record = { | ||
fields: [ | ||
{name: 'flags_0', type: 'USHORT', value: 0xDEAF}, | ||
{name: 'flags_1', type: 'USHORT', value: 0xCAFE} | ||
] | ||
}; | ||
assert.equal(hex(encode.TABLE(table)), '01 23 45 67 DE AF CA FE'); | ||
assert.equal(sizeOf.TABLE(table), 8); | ||
}); | ||
it('can handle LITERAL', function() { | ||
@@ -460,0 +543,0 @@ assert.equal(hex(encode.LITERAL([])), ''); |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
670715
63
12815