diff --git a/src/core/fonts.js b/src/core/fonts.js index 36cbb13ce04c7..ecd68f8f9d138 100644 --- a/src/core/fonts.js +++ b/src/core/fonts.js @@ -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'); } diff --git a/test/pdfs/.gitignore b/test/pdfs/.gitignore index feb4db9b5895e..e152161213ae9 100644 --- a/test/pdfs/.gitignore +++ b/test/pdfs/.gitignore @@ -40,6 +40,7 @@ !issue7446.pdf !issue7492.pdf !issue7544.pdf +!issue7507.pdf !issue7580.pdf !issue7598.pdf !issue7665.pdf diff --git a/test/pdfs/issue7507.pdf b/test/pdfs/issue7507.pdf new file mode 100644 index 0000000000000..cac44fbaad3d4 Binary files /dev/null and b/test/pdfs/issue7507.pdf differ diff --git a/test/test_manifest.json b/test/test_manifest.json index c724c35d7caf4..5285e0febab7d 100644 --- a/test/test_manifest.json +++ b/test/test_manifest.json @@ -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",