Strip TT programs if it's invalid
This commit is contained in:
parent
78ad4d4eaf
commit
cc5cba8bec
98
src/fonts.js
98
src/fonts.js
@ -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 = [];
|
||||||
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -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
BIN
test/pdfs/issue2956.pdf
Normal file
Binary file not shown.
@ -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",
|
||||||
|
Loading…
Reference in New Issue
Block a user