Strip TT programs if it's invalid

This commit is contained in:
vyv03354 2013-03-18 22:06:59 +09:00
parent 78ad4d4eaf
commit cc5cba8bec
4 changed files with 63 additions and 44 deletions

View File

@ -3341,7 +3341,8 @@ var Font = (function FontClosure() {
}
}
function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart) {
function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart,
hintsValid) {
if (sourceEnd - sourceStart <= 12) {
// glyph with data less than 12 is invalid one
return 0;
@ -3361,8 +3362,10 @@ var Font = (function FontClosure() {
j += 2;
}
// skipping instructions
var instructionsStart = j;
var instructionsLength = (glyf[j] << 8) | glyf[j + 1];
j += 2 + instructionsLength;
var instructionsEnd = j;
// validating flags
var coordinatesLength = 0;
for (var i = 0; i < flagsCount; i++) {
@ -3385,6 +3388,17 @@ var Font = (function FontClosure() {
// not enough data for coordinates
return 0;
}
if (!hintsValid && instructionsLength > 0) {
dest.set(glyf.subarray(0, instructionsStart), destStart);
dest.set([0, 0], destStart + instructionsStart);
dest.set(glyf.subarray(instructionsEnd, glyphDataLength),
destStart + instructionsStart + 2);
glyphDataLength -= instructionsLength;
if (glyf.length - glyphDataLength > 3) {
glyphDataLength = (glyphDataLength + 3) & ~3;
}
return glyphDataLength;
}
if (glyf.length - glyphDataLength > 3) {
// truncating and aligning to 4 bytes the long glyph data
glyphDataLength = (glyphDataLength + 3) & ~3;
@ -3441,7 +3455,7 @@ var Font = (function FontClosure() {
}
function sanitizeGlyphLocations(loca, glyf, numGlyphs,
isGlyphLocationsLong) {
isGlyphLocationsLong, hintsValid) {
var itemSize, itemDecode, itemEncode;
if (isGlyphLocationsLong) {
itemSize = 4;
@ -3483,7 +3497,7 @@ var Font = (function FontClosure() {
}
var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset,
newGlyfData, writeOffset);
newGlyfData, writeOffset, hintsValid);
writeOffset += newLength;
itemEncode(locaData, j, writeOffset);
startOffset = endOffset;
@ -3648,7 +3662,7 @@ var Font = (function FontClosure() {
0, 0, 0, 0, 0, 0, 0, 0, -2, -2, -2, -2, 0, 0, -2, -5,
-1, -1, -1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, -1, -1,
1, -1, -999, 0, 1, 0, -1, -2, 0, -1, -2, -1, -1, 0, -1, -1,
0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -2, 0, -2, -2,
0, 0, -999, -999, -1, -1, -1, -1, -2, -999, -2, -2, -999, 0, -2, -2,
0, 0, -2, 0, -2, 0, 0, 0, -2, -1, -1, 1, 1, 0, 0, -1,
-1, -1, -1, -1, -1, -1, 0, 0, -1, 0, -1, -1, 0, -999, -1, -1,
-1, -1, -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@ -3801,33 +3815,22 @@ var Font = (function FontClosure() {
foldTTTable(table, content);
}
function addTTDummyFunctions(table, ttContext, maxFunctionDefs) {
var content = [table.data];
if (!ttContext.tooComplexToFollowFunctions) {
var undefinedFunctions = [];
function checkInvalidFunctions(ttContext, maxFunctionDefs) {
if (ttContext.tooComplexToFollowFunctions) {
return;
}
for (var j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) {
if (!ttContext.functionsUsed[j] || ttContext.functionsDefined[j]) {
continue;
if (j > maxFunctionDefs) {
warn('TT: invalid function id: ' + j);
ttContext.hintsValid = false;
return;
}
undefinedFunctions.push(j);
if (j >= maxFunctionDefs) {
continue;
}
// function is used, but not defined
if (j < 256) {
// creating empty one [PUSHB, function-id, FDEF, ENDF]
content.push(new Uint8Array([0xB0, j, 0x2C, 0x2D]));
} else {
// creating empty one [PUSHW, function-id, FDEF, ENDF]
content.push(
new Uint8Array([0xB8, j >> 8, j & 255, 0x2C, 0x2D]));
if (ttContext.functionsUsed[j] && !ttContext.functionsDefined[j]) {
warn('TT: undefined function: ' + j);
ttContext.hintsValid = false;
return;
}
}
if (undefinedFunctions.length > 0) {
warn('TT: undefined functions: ' + undefinedFunctions);
}
}
foldTTTable(table, content);
}
function foldTTTable(table, content) {
@ -3854,7 +3857,8 @@ var Font = (function FontClosure() {
functionsDefined: [],
functionsUsed: [],
functionsStackDeltas: [],
tooComplexToFollowFunctions: false
tooComplexToFollowFunctions: false,
hintsValid: true
};
if (fpgm) {
sanitizeTTProgram(fpgm, ttContext);
@ -3863,8 +3867,9 @@ var Font = (function FontClosure() {
sanitizeTTProgram(prep, ttContext);
}
if (fpgm) {
addTTDummyFunctions(fpgm, ttContext, maxFunctionDefs);
checkInvalidFunctions(ttContext, maxFunctionDefs);
}
return ttContext.hintsValid;
}
// Check that required tables are present
@ -3916,6 +3921,25 @@ var Font = (function FontClosure() {
tables.push(table);
}
// Ensure the hmtx table contains the advance width and
// sidebearings information for numGlyphs in the maxp table
font.pos = (font.start || 0) + maxp.offset;
var version = int32(font.getBytes(4));
var numGlyphs = int16(font.getBytes(2));
var maxFunctionDefs = 0;
if (version >= 0x00010000 && maxp.length >= 22) {
font.pos += 14;
var maxFunctionDefs = int16(font.getBytes(2));
}
var hintsValid = sanitizeTTPrograms(fpgm, prep, maxFunctionDefs);
if (!hintsValid) {
tables.splice(tables.indexOf(fpgm), 1);
fpgm = null;
tables.splice(tables.indexOf(prep), 1);
prep = null;
}
var numTables = tables.length + requiredTables.length;
// header and new offsets. Table entry information is appended to the
@ -3930,28 +3954,16 @@ var Font = (function FontClosure() {
// of missing tables
createOpenTypeHeader(header.version, ttf, numTables);
// Ensure the hmtx table contains the advance width and
// sidebearings information for numGlyphs in the maxp table
font.pos = (font.start || 0) + maxp.offset;
var version = int32(font.getBytes(4));
var numGlyphs = int16(font.getBytes(2));
var maxFunctionDefs = 0;
if (version >= 0x00010000 && maxp.length >= 22) {
font.pos += 14;
var maxFunctionDefs = int16(font.getBytes(2));
}
sanitizeMetrics(font, hhea, hmtx, numGlyphs);
sanitizeTTPrograms(fpgm, prep, maxFunctionDefs);
if (head) {
sanitizeHead(head, numGlyphs, loca.length);
}
var isGlyphLocationsLong = int16([head.data[50], head.data[51]]);
if (head && loca && glyf) {
sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong);
sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong,
hintsValid);
}
var emptyGlyphIds = [];

View File

@ -48,3 +48,4 @@
!noembed-sjis.pdf
!vertical.pdf
!issue2099-1.pdf
!issue2956.pdf

BIN
test/pdfs/issue2956.pdf Normal file

Binary file not shown.

View File

@ -1120,6 +1120,12 @@
"rounds": 1,
"type": "eq"
},
{ "id": "issue2956",
"file": "pdfs/issue2956.pdf",
"md5": "d8f68cbbb4bf54cde9f7f878acb6d7cd",
"rounds": 1,
"type": "eq"
},
{ "id": "issue2177-eq",
"file": "pdfs/issue2177.pdf",
"md5": "48a808278bf31de8414c4e03ecd0900a",