Allocate fewer objects when parsing 2 and 4 byte chunks.

This is achieved by adding getBytes2() and getBytes4() to streams, and by
changing int16() and int32() to take multiple scalar args instead of an array
arg.
This commit is contained in:
Nicholas Nethercote 2014-03-11 21:09:49 -07:00
parent e5cd75083f
commit 6a75e45309
3 changed files with 101 additions and 64 deletions

View File

@ -140,6 +140,20 @@ var ChunkedStream = (function ChunkedStreamClosure() {
return this.bytes[this.pos++];
},
getUint16: function ChunkedStream_getUint16() {
var b0 = this.getByte();
var b1 = this.getByte();
return (b0 << 8) + b1;
},
getUint32: function ChunkedStream_getUint32() {
var b0 = this.getByte();
var b1 = this.getByte();
var b2 = this.getByte();
var b3 = this.getByte();
return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
},
// returns subarray of original buffer
// should only be read
getBytes: function ChunkedStream_getBytes(length) {

View File

@ -2312,13 +2312,12 @@ var Font = (function FontClosure() {
return strBuf.join('');
}
function int16(bytes) {
return (bytes[0] << 8) + (bytes[1] & 0xff);
function int16(b0, b1) {
return (b0 << 8) + b1;
}
function int32(bytes) {
return (bytes[0] << 24) + (bytes[1] << 16) +
(bytes[2] << 8) + (bytes[3] & 0xff);
function int32(b0, b1, b2, b3) {
return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
}
function getMaxPower2(number) {
@ -2397,8 +2396,8 @@ var Font = (function FontClosure() {
// checksum
var checksum = 0, n = data.length;
for (var i = 0; i < n; i += 4)
checksum = (checksum + int32([data[i], data[i + 1], data[i + 2],
data[i + 3]])) | 0;
checksum = (checksum + int32(data[i], data[i + 1], data[i + 2],
data[i + 3])) | 0;
var tableEntry = (tag + string32(checksum) +
string32(offset) + string32(length));
@ -2626,21 +2625,21 @@ var Font = (function FontClosure() {
function validateOS2Table(os2) {
var stream = new Stream(os2.data);
var version = int16(stream.getBytes(2));
var version = stream.getUint16();
// TODO verify all OS/2 tables fields, but currently we validate only those
// that give us issues
stream.getBytes(60); // skipping type, misc sizes, panose, unicode ranges
var selection = int16(stream.getBytes(2));
var selection = stream.getUint16();
if (version < 4 && (selection & 0x0300)) {
return false;
}
var firstChar = int16(stream.getBytes(2));
var lastChar = int16(stream.getBytes(2));
var firstChar = stream.getUint16();
var lastChar = stream.getUint16();
if (firstChar > lastChar) {
return false;
}
stream.getBytes(6); // skipping sTypoAscender/Descender/LineGap
var usWinAscent = int16(stream.getBytes(2));
var usWinAscent = stream.getUint16();
if (usWinAscent === 0) { // makes font unreadable by windows
return false;
}
@ -2859,9 +2858,9 @@ var Font = (function FontClosure() {
String.fromCharCode(tag[2]) +
String.fromCharCode(tag[3]);
var checksum = int32(file.getBytes(4));
var offset = int32(file.getBytes(4));
var length = int32(file.getBytes(4));
var checksum = file.getUint32();
var offset = file.getUint32();
var length = file.getUint32();
// Read the table associated data
var previousPosition = file.pos;
@ -2888,10 +2887,10 @@ var Font = (function FontClosure() {
function readOpenTypeHeader(ttf) {
return {
version: arrayToString(ttf.getBytes(4)),
numTables: int16(ttf.getBytes(2)),
searchRange: int16(ttf.getBytes(2)),
entrySelector: int16(ttf.getBytes(2)),
rangeShift: int16(ttf.getBytes(2))
numTables: ttf.getUint16(),
searchRange: ttf.getUint16(),
entrySelector: ttf.getUint16(),
rangeShift: ttf.getUint16()
};
}
@ -2903,8 +2902,8 @@ var Font = (function FontClosure() {
var start = (font.start ? font.start : 0) + cmap.offset;
font.pos = start;
var version = int16(font.getBytes(2));
var numTables = int16(font.getBytes(2));
var version = font.getUint16();
var numTables = font.getUint16();
var potentialTable;
var canBreak = false;
@ -2915,9 +2914,9 @@ var Font = (function FontClosure() {
// The following takes advantage of the fact that the tables are sorted
// to work.
for (var i = 0; i < numTables; i++) {
var platformId = int16(font.getBytes(2));
var encodingId = int16(font.getBytes(2));
var offset = int32(font.getBytes(4));
var platformId = font.getUint16();
var encodingId = font.getUint16();
var offset = font.getUint32();
var useTable = false;
if (platformId == 1 && encodingId === 0) {
@ -2950,9 +2949,9 @@ var Font = (function FontClosure() {
}
font.pos = start + potentialTable.offset;
var format = int16(font.getBytes(2));
var length = int16(font.getBytes(2));
var language = int16(font.getBytes(2));
var format = font.getUint16();
var length = font.getUint16();
var language = font.getUint16();
var hasShortCmap = false;
var mappings = [];
@ -2973,25 +2972,25 @@ var Font = (function FontClosure() {
} else if (format === 4) {
// re-creating the table in format 4 since the encoding
// might be changed
var segCount = (int16(font.getBytes(2)) >> 1);
var segCount = (font.getUint16() >> 1);
font.getBytes(6); // skipping range fields
var segIndex, segments = [];
for (segIndex = 0; segIndex < segCount; segIndex++) {
segments.push({ end: int16(font.getBytes(2)) });
segments.push({ end: font.getUint16() });
}
font.getBytes(2);
font.getUint16();
for (segIndex = 0; segIndex < segCount; segIndex++) {
segments[segIndex].start = int16(font.getBytes(2));
segments[segIndex].start = font.getUint16();
}
for (segIndex = 0; segIndex < segCount; segIndex++) {
segments[segIndex].delta = int16(font.getBytes(2));
segments[segIndex].delta = font.getUint16();
}
var offsetsCount = 0;
for (segIndex = 0; segIndex < segCount; segIndex++) {
var segment = segments[segIndex];
var rangeOffset = int16(font.getBytes(2));
var rangeOffset = font.getUint16();
if (!rangeOffset) {
segment.offsetIndex = -1;
continue;
@ -3005,7 +3004,7 @@ var Font = (function FontClosure() {
var offsets = [];
for (var j = 0; j < offsetsCount; j++) {
offsets.push(int16(font.getBytes(2)));
offsets.push(font.getUint16());
}
for (segIndex = 0; segIndex < segCount; segIndex++) {
@ -3036,13 +3035,13 @@ var Font = (function FontClosure() {
// table. (This looks weird, so I can have missed something), this
// works on Linux but seems to fails on Mac so let's rewrite the
// cmap table to a 3-1-4 style
var firstCode = int16(font.getBytes(2));
var entryCount = int16(font.getBytes(2));
var firstCode = font.getUint16();
var entryCount = font.getUint16();
var glyphs = [];
var ids = [];
for (var j = 0; j < entryCount; j++) {
var glyphId = int16(font.getBytes(2));
var glyphId = font.getUint16();
var charCode = firstCode + j;
mappings.push({
@ -3083,7 +3082,7 @@ var Font = (function FontClosure() {
font.pos = (font.start ? font.start : 0) + header.offset;
font.pos += header.length - 2;
var numOfMetrics = int16(font.getBytes(2));
var numOfMetrics = font.getUint16();
if (numOfMetrics > numGlyphs) {
info('The numOfMetrics (' + numOfMetrics + ') should not be ' +
@ -3187,7 +3186,7 @@ var Font = (function FontClosure() {
// Validate version:
// Should always be 0x00010000
var version = int32([data[0], data[1], data[2], data[3]]);
var version = int32(data[0], data[1], data[2], data[3]);
if (version >> 16 !== 1) {
info('Attempting to fix invalid version in head table: ' + version);
data[0] = 0;
@ -3196,7 +3195,7 @@ var Font = (function FontClosure() {
data[3] = 0;
}
var indexToLocFormat = int16([data[50], data[51]]);
var indexToLocFormat = int16(data[50], data[51]);
if (indexToLocFormat < 0 || indexToLocFormat > 1) {
info('Attempting to fix invalid indexToLocFormat in head table: ' +
indexToLocFormat);
@ -3321,7 +3320,7 @@ var Font = (function FontClosure() {
font.pos = start;
var length = post.length, end = start + length;
var version = int32(font.getBytes(4));
var version = font.getUint32();
// skip rest to the tables
font.getBytes(28);
@ -3332,14 +3331,14 @@ var Font = (function FontClosure() {
glyphNames = MacStandardGlyphOrdering;
break;
case 0x00020000:
var numGlyphs = int16(font.getBytes(2));
var numGlyphs = font.getUint16();
if (numGlyphs != maxpNumGlyphs) {
valid = false;
break;
}
var glyphNameIndexes = [];
for (var i = 0; i < numGlyphs; ++i) {
var index = int16(font.getBytes(2));
var index = font.getUint16();
if (index >= 32768) {
valid = false;
break;
@ -3385,25 +3384,25 @@ var Font = (function FontClosure() {
var names = [[], []];
var length = nameTable.length, end = start + length;
var format = int16(font.getBytes(2));
var format = font.getUint16();
var FORMAT_0_HEADER_LENGTH = 6;
if (format !== 0 || length < FORMAT_0_HEADER_LENGTH) {
// unsupported name table format or table "too" small
return names;
}
var numRecords = int16(font.getBytes(2));
var stringsStart = int16(font.getBytes(2));
var numRecords = font.getUint16();
var stringsStart = font.getUint16();
var records = [];
var NAME_RECORD_LENGTH = 12;
for (var i = 0; i < numRecords &&
font.pos + NAME_RECORD_LENGTH <= end; i++) {
var r = {
platform: int16(font.getBytes(2)),
encoding: int16(font.getBytes(2)),
language: int16(font.getBytes(2)),
name: int16(font.getBytes(2)),
length: int16(font.getBytes(2)),
offset: int16(font.getBytes(2))
platform: font.getUint16(),
encoding: font.getUint16(),
language: font.getUint16(),
name: font.getUint16(),
length: font.getUint16(),
offset: font.getUint16()
};
// using only Macintosh and Windows platform/encoding names
if ((r.platform == 1 && r.encoding === 0 && r.language === 0) ||
@ -3424,7 +3423,7 @@ var Font = (function FontClosure() {
// unicode
var str = '';
for (var j = 0, jj = record.length; j < jj; j += 2) {
str += String.fromCharCode(int16(font.getBytes(2)));
str += String.fromCharCode(font.getUint16());
}
names[1][nameIndex] = str;
} else {
@ -3719,19 +3718,19 @@ var Font = (function FontClosure() {
}
font.pos = (font.start || 0) + tables.maxp.offset;
var version = int32(font.getBytes(4));
var numGlyphs = int16(font.getBytes(2));
var version = font.getUint32();
var numGlyphs = font.getUint16();
var maxFunctionDefs = 0;
if (version >= 0x00010000 && tables.maxp.length >= 22) {
// maxZones can be invalid
font.pos += 8;
var maxZones = int16(font.getBytes(2));
var maxZones = font.getUint16();
if (maxZones > 2) { // reset to 2 if font has invalid maxZones
tables.maxp.data[14] = 0;
tables.maxp.data[15] = 2;
}
font.pos += 4;
maxFunctionDefs = int16(font.getBytes(2));
maxFunctionDefs = font.getUint16();
}
var dupFirstEntry = false;
@ -3781,8 +3780,8 @@ var Font = (function FontClosure() {
sanitizeHead(tables.head, numGlyphs, isTrueType ? tables.loca.length : 0);
if (isTrueType) {
var isGlyphLocationsLong = int16([tables.head.data[50],
tables.head.data[51]]);
var isGlyphLocationsLong = int16(tables.head.data[50],
tables.head.data[51]);
sanitizeGlyphLocations(tables.loca, tables.glyf, numGlyphs,
isGlyphLocationsLong, hintsValid, dupFirstEntry);
}
@ -3926,11 +3925,11 @@ var Font = (function FontClosure() {
// extract some more font properties from the OpenType head and
// hhea tables; yMin and descent value are always negative
var override = {
unitsPerEm: int16([tables.head.data[18], tables.head.data[19]]),
yMax: int16([tables.head.data[42], tables.head.data[43]]),
yMin: int16([tables.head.data[38], tables.head.data[39]]) - 0x10000,
ascent: int16([tables.hhea.data[4], tables.hhea.data[5]]),
descent: int16([tables.hhea.data[6], tables.hhea.data[7]]) - 0x10000
unitsPerEm: int16(tables.head.data[18], tables.head.data[19]),
yMax: int16(tables.head.data[42], tables.head.data[43]),
yMin: int16(tables.head.data[38], tables.head.data[39]) - 0x10000,
ascent: int16(tables.hhea.data[4], tables.hhea.data[5]),
descent: int16(tables.hhea.data[6], tables.hhea.data[7]) - 0x10000
};
tables['OS/2'] = {

View File

@ -40,6 +40,18 @@ var Stream = (function StreamClosure() {
return -1;
return this.bytes[this.pos++];
},
getUint16: function Stream_getUint16() {
var b0 = this.getByte();
var b1 = this.getByte();
return (b0 << 8) + b1;
},
getUint32: function Stream_getUint32() {
var b0 = this.getByte();
var b1 = this.getByte();
var b2 = this.getByte();
var b3 = this.getByte();
return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
},
// returns subarray of original buffer
// should only be read
getBytes: function Stream_getBytes(length) {
@ -143,6 +155,18 @@ var DecodeStream = (function DecodeStreamClosure() {
}
return this.buffer[this.pos++];
},
getUint16: function DecodeStream_getUint16() {
var b0 = this.getByte();
var b1 = this.getByte();
return (b0 << 8) + b1;
},
getUint32: function DecodeStream_getUint32() {
var b0 = this.getByte();
var b1 = this.getByte();
var b2 = this.getByte();
var b3 = this.getByte();
return (b0 << 24) + (b1 << 16) + (b2 << 8) + b3;
},
getBytes: function DecodeStream_getBytes(length) {
var end, pos = this.pos;