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) { if (sourceEnd - sourceStart <= 12) {
// glyph with data less than 12 is invalid one // glyph with data less than 12 is invalid one
return 0; return 0;
@ -3361,8 +3362,10 @@ var Font = (function FontClosure() {
j += 2; j += 2;
} }
// skipping instructions // skipping instructions
var instructionsStart = j;
var instructionsLength = (glyf[j] << 8) | glyf[j + 1]; var instructionsLength = (glyf[j] << 8) | glyf[j + 1];
j += 2 + instructionsLength; j += 2 + instructionsLength;
var instructionsEnd = j;
// validating flags // validating flags
var coordinatesLength = 0; var coordinatesLength = 0;
for (var i = 0; i < flagsCount; i++) { for (var i = 0; i < flagsCount; i++) {
@ -3385,6 +3388,17 @@ var Font = (function FontClosure() {
// not enough data for coordinates // not enough data for coordinates
return 0; 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) { if (glyf.length - glyphDataLength > 3) {
// truncating and aligning to 4 bytes the long glyph data // truncating and aligning to 4 bytes the long glyph data
glyphDataLength = (glyphDataLength + 3) & ~3; glyphDataLength = (glyphDataLength + 3) & ~3;
@ -3441,7 +3455,7 @@ var Font = (function FontClosure() {
} }
function sanitizeGlyphLocations(loca, glyf, numGlyphs, function sanitizeGlyphLocations(loca, glyf, numGlyphs,
isGlyphLocationsLong) { isGlyphLocationsLong, hintsValid) {
var itemSize, itemDecode, itemEncode; var itemSize, itemDecode, itemEncode;
if (isGlyphLocationsLong) { if (isGlyphLocationsLong) {
itemSize = 4; itemSize = 4;
@ -3483,7 +3497,7 @@ var Font = (function FontClosure() {
} }
var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset, var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset,
newGlyfData, writeOffset); newGlyfData, writeOffset, hintsValid);
writeOffset += newLength; writeOffset += newLength;
itemEncode(locaData, j, writeOffset); itemEncode(locaData, j, writeOffset);
startOffset = endOffset; 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, 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, -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, 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, 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, -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, -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); foldTTTable(table, content);
} }
function addTTDummyFunctions(table, ttContext, maxFunctionDefs) { function checkInvalidFunctions(ttContext, maxFunctionDefs) {
var content = [table.data]; if (ttContext.tooComplexToFollowFunctions) {
if (!ttContext.tooComplexToFollowFunctions) { return;
var undefinedFunctions = []; }
for (var j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) { for (var j = 0, jj = ttContext.functionsUsed.length; j < jj; j++) {
if (!ttContext.functionsUsed[j] || ttContext.functionsDefined[j]) { if (j > maxFunctionDefs) {
continue; warn('TT: invalid function id: ' + j);
ttContext.hintsValid = false;
return;
} }
undefinedFunctions.push(j); if (ttContext.functionsUsed[j] && !ttContext.functionsDefined[j]) {
if (j >= maxFunctionDefs) { warn('TT: undefined function: ' + j);
continue; ttContext.hintsValid = false;
} return;
// 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 (undefinedFunctions.length > 0) {
warn('TT: undefined functions: ' + undefinedFunctions);
}
}
foldTTTable(table, content);
} }
function foldTTTable(table, content) { function foldTTTable(table, content) {
@ -3854,7 +3857,8 @@ var Font = (function FontClosure() {
functionsDefined: [], functionsDefined: [],
functionsUsed: [], functionsUsed: [],
functionsStackDeltas: [], functionsStackDeltas: [],
tooComplexToFollowFunctions: false tooComplexToFollowFunctions: false,
hintsValid: true
}; };
if (fpgm) { if (fpgm) {
sanitizeTTProgram(fpgm, ttContext); sanitizeTTProgram(fpgm, ttContext);
@ -3863,8 +3867,9 @@ var Font = (function FontClosure() {
sanitizeTTProgram(prep, ttContext); sanitizeTTProgram(prep, ttContext);
} }
if (fpgm) { if (fpgm) {
addTTDummyFunctions(fpgm, ttContext, maxFunctionDefs); checkInvalidFunctions(ttContext, maxFunctionDefs);
} }
return ttContext.hintsValid;
} }
// Check that required tables are present // Check that required tables are present
@ -3916,6 +3921,25 @@ var Font = (function FontClosure() {
tables.push(table); 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; var numTables = tables.length + requiredTables.length;
// header and new offsets. Table entry information is appended to the // header and new offsets. Table entry information is appended to the
@ -3930,28 +3954,16 @@ var Font = (function FontClosure() {
// of missing tables // of missing tables
createOpenTypeHeader(header.version, ttf, numTables); 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); sanitizeMetrics(font, hhea, hmtx, numGlyphs);
sanitizeTTPrograms(fpgm, prep, maxFunctionDefs);
if (head) { if (head) {
sanitizeHead(head, numGlyphs, loca.length); sanitizeHead(head, numGlyphs, loca.length);
} }
var isGlyphLocationsLong = int16([head.data[50], head.data[51]]); var isGlyphLocationsLong = int16([head.data[50], head.data[51]]);
if (head && loca && glyf) { if (head && loca && glyf) {
sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong); sanitizeGlyphLocations(loca, glyf, numGlyphs, isGlyphLocationsLong,
hintsValid);
} }
var emptyGlyphIds = []; var emptyGlyphIds = [];

View File

@ -48,3 +48,4 @@
!noembed-sjis.pdf !noembed-sjis.pdf
!vertical.pdf !vertical.pdf
!issue2099-1.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, "rounds": 1,
"type": "eq" "type": "eq"
}, },
{ "id": "issue2956",
"file": "pdfs/issue2956.pdf",
"md5": "d8f68cbbb4bf54cde9f7f878acb6d7cd",
"rounds": 1,
"type": "eq"
},
{ "id": "issue2177-eq", { "id": "issue2177-eq",
"file": "pdfs/issue2177.pdf", "file": "pdfs/issue2177.pdf",
"md5": "48a808278bf31de8414c4e03ecd0900a", "md5": "48a808278bf31de8414c4e03ecd0900a",