Overwrite maxSizeOfInstructions in maxp with computed value.
In issue #7507 the value is less than the actuall max size of the glyph instructions causing OTS to fail the font.
This commit is contained in:
parent
a1f5c26f54
commit
18e2321845
@ -1568,16 +1568,21 @@ var Font = (function FontClosure() {
|
||||
|
||||
function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart,
|
||||
hintsValid) {
|
||||
var glyphProfile = {
|
||||
length: 0,
|
||||
sizeOfInstructions: 0,
|
||||
};
|
||||
if (sourceEnd - sourceStart <= 12) {
|
||||
// glyph with data less than 12 is invalid one
|
||||
return 0;
|
||||
return glyphProfile;
|
||||
}
|
||||
var glyf = source.subarray(sourceStart, sourceEnd);
|
||||
var contoursCount = (glyf[0] << 8) | glyf[1];
|
||||
if (contoursCount & 0x8000) {
|
||||
// complex glyph, writing as is
|
||||
dest.set(glyf, destStart);
|
||||
return glyf.length;
|
||||
glyphProfile.length = glyf.length;
|
||||
return glyphProfile;
|
||||
}
|
||||
|
||||
var i, j = 10, flagsCount = 0;
|
||||
@ -1589,6 +1594,7 @@ var Font = (function FontClosure() {
|
||||
// skipping instructions
|
||||
var instructionsStart = j;
|
||||
var instructionsLength = (glyf[j] << 8) | glyf[j + 1];
|
||||
glyphProfile.sizeOfInstructions = instructionsLength;
|
||||
j += 2 + instructionsLength;
|
||||
var instructionsEnd = j;
|
||||
// validating flags
|
||||
@ -1610,12 +1616,12 @@ var Font = (function FontClosure() {
|
||||
}
|
||||
// glyph without coordinates will be rejected
|
||||
if (coordinatesLength === 0) {
|
||||
return 0;
|
||||
return glyphProfile;
|
||||
}
|
||||
var glyphDataLength = j + coordinatesLength;
|
||||
if (glyphDataLength > glyf.length) {
|
||||
// not enough data for coordinates
|
||||
return 0;
|
||||
return glyphProfile;
|
||||
}
|
||||
if (!hintsValid && instructionsLength > 0) {
|
||||
dest.set(glyf.subarray(0, instructionsStart), destStart);
|
||||
@ -1626,17 +1632,20 @@ var Font = (function FontClosure() {
|
||||
if (glyf.length - glyphDataLength > 3) {
|
||||
glyphDataLength = (glyphDataLength + 3) & ~3;
|
||||
}
|
||||
return glyphDataLength;
|
||||
glyphProfile.length = glyphDataLength;
|
||||
return glyphProfile;
|
||||
}
|
||||
if (glyf.length - glyphDataLength > 3) {
|
||||
// truncating and aligning to 4 bytes the long glyph data
|
||||
glyphDataLength = (glyphDataLength + 3) & ~3;
|
||||
dest.set(glyf.subarray(0, glyphDataLength), destStart);
|
||||
return glyphDataLength;
|
||||
glyphProfile.length = glyphDataLength;
|
||||
return glyphProfile;
|
||||
}
|
||||
// glyph data is fine
|
||||
dest.set(glyf, destStart);
|
||||
return glyf.length;
|
||||
glyphProfile.length = glyf.length;
|
||||
return glyphProfile;
|
||||
}
|
||||
|
||||
function sanitizeHead(head, numGlyphs, locaLength) {
|
||||
@ -1686,7 +1695,7 @@ var Font = (function FontClosure() {
|
||||
|
||||
function sanitizeGlyphLocations(loca, glyf, numGlyphs,
|
||||
isGlyphLocationsLong, hintsValid,
|
||||
dupFirstEntry) {
|
||||
dupFirstEntry, maxSizeOfInstructions) {
|
||||
var itemSize, itemDecode, itemEncode;
|
||||
if (isGlyphLocationsLong) {
|
||||
itemSize = 4;
|
||||
@ -1724,7 +1733,7 @@ var Font = (function FontClosure() {
|
||||
var newGlyfData = new Uint8Array(oldGlyfDataLength);
|
||||
var startOffset = itemDecode(locaData, 0);
|
||||
var writeOffset = 0;
|
||||
var missingGlyphData = Object.create(null);
|
||||
var missingGlyphs = Object.create(null);
|
||||
itemEncode(locaData, 0, writeOffset);
|
||||
var i, j;
|
||||
// When called with dupFirstEntry the number of glyphs has already been
|
||||
@ -1743,10 +1752,15 @@ var Font = (function FontClosure() {
|
||||
startOffset = endOffset;
|
||||
}
|
||||
|
||||
var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset,
|
||||
newGlyfData, writeOffset, hintsValid);
|
||||
var glyphProfile = sanitizeGlyph(oldGlyfData, startOffset, endOffset,
|
||||
newGlyfData, writeOffset,
|
||||
hintsValid);
|
||||
var newLength = glyphProfile.length;
|
||||
if (newLength === 0) {
|
||||
missingGlyphData[i] = true;
|
||||
missingGlyphs[i] = true;
|
||||
}
|
||||
if (glyphProfile.sizeOfInstructions > maxSizeOfInstructions) {
|
||||
maxSizeOfInstructions = glyphProfile.sizeOfInstructions;
|
||||
}
|
||||
writeOffset += newLength;
|
||||
itemEncode(locaData, j, writeOffset);
|
||||
@ -1762,10 +1776,7 @@ var Font = (function FontClosure() {
|
||||
itemEncode(locaData, j, simpleGlyph.length);
|
||||
}
|
||||
glyf.data = simpleGlyph;
|
||||
return missingGlyphData;
|
||||
}
|
||||
|
||||
if (dupFirstEntry) {
|
||||
} else if (dupFirstEntry) {
|
||||
var firstEntryLength = itemDecode(locaData, itemSize);
|
||||
if (newGlyfData.length > firstEntryLength + writeOffset) {
|
||||
glyf.data = newGlyfData.subarray(0, firstEntryLength + writeOffset);
|
||||
@ -1779,7 +1790,10 @@ var Font = (function FontClosure() {
|
||||
} else {
|
||||
glyf.data = newGlyfData.subarray(0, writeOffset);
|
||||
}
|
||||
return missingGlyphData;
|
||||
return {
|
||||
missingGlyphs,
|
||||
maxSizeOfInstructions,
|
||||
};
|
||||
}
|
||||
|
||||
function readPostScriptTable(post, properties, maxpNumGlyphs) {
|
||||
@ -2226,6 +2240,7 @@ var Font = (function FontClosure() {
|
||||
var version = font.getInt32();
|
||||
var numGlyphs = font.getUint16();
|
||||
var maxFunctionDefs = 0;
|
||||
var maxSizeOfInstructions = 0;
|
||||
if (version >= 0x00010000 && tables['maxp'].length >= 22) {
|
||||
// maxZones can be invalid
|
||||
font.pos += 8;
|
||||
@ -2236,6 +2251,8 @@ var Font = (function FontClosure() {
|
||||
}
|
||||
font.pos += 4;
|
||||
maxFunctionDefs = font.getUint16();
|
||||
font.pos += 6;
|
||||
maxSizeOfInstructions = font.getUint16();
|
||||
}
|
||||
|
||||
var dupFirstEntry = false;
|
||||
@ -2271,11 +2288,19 @@ var Font = (function FontClosure() {
|
||||
if (isTrueType) {
|
||||
var isGlyphLocationsLong = int16(tables['head'].data[50],
|
||||
tables['head'].data[51]);
|
||||
missingGlyphs = sanitizeGlyphLocations(tables['loca'], tables['glyf'],
|
||||
numGlyphs, isGlyphLocationsLong,
|
||||
hintsValid, dupFirstEntry);
|
||||
}
|
||||
var glyphsInfo = sanitizeGlyphLocations(tables['loca'], tables['glyf'],
|
||||
numGlyphs, isGlyphLocationsLong,
|
||||
hintsValid, dupFirstEntry,
|
||||
maxSizeOfInstructions);
|
||||
missingGlyphs = glyphsInfo.missingGlyphs;
|
||||
|
||||
// Some fonts have incorrect maxSizeOfInstructions values, so we use
|
||||
// the computed value instead.
|
||||
if (version >= 0x00010000 && tables['maxp'].length >= 22) {
|
||||
tables['maxp'].data[26] = glyphsInfo.maxSizeOfInstructions >> 8;
|
||||
tables['maxp'].data[27] = glyphsInfo.maxSizeOfInstructions & 255;
|
||||
}
|
||||
}
|
||||
if (!tables['hhea']) {
|
||||
throw new FormatError('Required "hhea" table is not found');
|
||||
}
|
||||
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -40,6 +40,7 @@
|
||||
!issue7446.pdf
|
||||
!issue7492.pdf
|
||||
!issue7544.pdf
|
||||
!issue7507.pdf
|
||||
!issue7580.pdf
|
||||
!issue7598.pdf
|
||||
!issue7665.pdf
|
||||
|
BIN
test/pdfs/issue7507.pdf
Normal file
BIN
test/pdfs/issue7507.pdf
Normal file
Binary file not shown.
@ -684,6 +684,13 @@
|
||||
"link": false,
|
||||
"type": "load"
|
||||
},
|
||||
{ "id": "issue7507",
|
||||
"file": "pdfs/issue7507.pdf",
|
||||
"md5": "f7aeaafe0c89b94436e94eaa63307303",
|
||||
"rounds": 1,
|
||||
"link": false,
|
||||
"type": "eq"
|
||||
},
|
||||
{ "id": "issue5501",
|
||||
"file": "pdfs/issue5501.pdf",
|
||||
"md5": "55a60699728fc92f491a2d7d490474e4",
|
||||
|
Loading…
Reference in New Issue
Block a user