Browse Source

Merge pull request #4447 from nnethercote/object-reduction

Allocate fewer objects
Brendan Dahl 11 years ago
parent
commit
1802ffffb8
  1. 23
      src/core/bidi.js
  2. 14
      src/core/chunked_stream.js
  3. 6
      src/core/evaluator.js
  4. 129
      src/core/fonts.js
  5. 24
      src/core/stream.js

23
src/core/bidi.js

@ -140,21 +140,28 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
} }
} }
function BidiResult(str, isLTR, vertical) { function createBidiText(str, isLTR, vertical) {
this.str = str; return {
this.dir = (vertical ? 'ttb' : (isLTR ? 'ltr' : 'rtl')); str: str,
dir: (vertical ? 'ttb' : (isLTR ? 'ltr' : 'rtl'))
};
} }
// These are used in bidi(), which is called frequently. We re-use them on
// each call to avoid unnecessary allocations.
var chars = [];
var types = [];
function bidi(str, startLevel, vertical) { function bidi(str, startLevel, vertical) {
var isLTR = true; var isLTR = true;
var strLength = str.length; var strLength = str.length;
if (strLength === 0 || vertical) { if (strLength === 0 || vertical) {
return new BidiResult(str, isLTR, vertical); return createBidiText(str, isLTR, vertical);
} }
// Get types and fill arrays // Get types and fill arrays
var chars = []; chars.length = 0;
var types = []; types.length = 0;
var numBidi = 0; var numBidi = 0;
for (var i = 0; i < strLength; ++i) { for (var i = 0; i < strLength; ++i) {
@ -183,7 +190,7 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
// - If more than 30% chars are rtl then string is primarily rtl // - If more than 30% chars are rtl then string is primarily rtl
if (numBidi === 0) { if (numBidi === 0) {
isLTR = true; isLTR = true;
return new BidiResult(str, isLTR); return createBidiText(str, isLTR);
} }
if (startLevel == -1) { if (startLevel == -1) {
@ -448,7 +455,7 @@ var bidi = PDFJS.bidi = (function bidiClosure() {
result += ch; result += ch;
} }
} }
return new BidiResult(result, isLTR); return createBidiText(result, isLTR);
} }
return bidi; return bidi;

14
src/core/chunked_stream.js

@ -140,6 +140,20 @@ var ChunkedStream = (function ChunkedStreamClosure() {
return this.bytes[this.pos++]; 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 // returns subarray of original buffer
// should only be read // should only be read
getBytes: function ChunkedStream_getBytes(length) { getBytes: function ChunkedStream_getBytes(length) {

6
src/core/evaluator.js

@ -812,11 +812,7 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (chunkBuf.length > 0) { if (chunkBuf.length > 0) {
var chunk = chunkBuf.join(''); var chunk = chunkBuf.join('');
var bidiResult = PDFJS.bidi(chunk, -1, font.vertical); var bidiText = PDFJS.bidi(chunk, -1, font.vertical);
var bidiText = {
str: bidiResult.str,
dir: bidiResult.dir
};
var renderParams = textState.calcRenderParams(preprocessor.ctm); var renderParams = textState.calcRenderParams(preprocessor.ctm);
var fontHeight = textState.fontSize * renderParams.vScale; var fontHeight = textState.fontSize * renderParams.vScale;
var fontAscent = font.ascent ? font.ascent * fontHeight : var fontAscent = font.ascent ? font.ascent * fontHeight :

129
src/core/fonts.js

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

24
src/core/stream.js

@ -40,6 +40,18 @@ var Stream = (function StreamClosure() {
return -1; return -1;
return this.bytes[this.pos++]; 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 // returns subarray of original buffer
// should only be read // should only be read
getBytes: function Stream_getBytes(length) { getBytes: function Stream_getBytes(length) {
@ -143,6 +155,18 @@ var DecodeStream = (function DecodeStreamClosure() {
} }
return this.buffer[this.pos++]; 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) { getBytes: function DecodeStream_getBytes(length) {
var end, pos = this.pos; var end, pos = this.pos;

Loading…
Cancel
Save