Fix how we detect and handle missing glyph data.
This commit is contained in:
parent
f2fcf2a59c
commit
6d4f748fb1
@ -801,7 +801,7 @@ var Font = (function FontClosure() {
|
|||||||
* font that we build
|
* font that we build
|
||||||
* 'charCodeToGlyphId' - maps the new font char codes to glyph ids
|
* 'charCodeToGlyphId' - maps the new font char codes to glyph ids
|
||||||
*/
|
*/
|
||||||
function adjustMapping(charCodeToGlyphId, properties) {
|
function adjustMapping(charCodeToGlyphId, properties, missingGlyphs) {
|
||||||
var toUnicode = properties.toUnicode;
|
var toUnicode = properties.toUnicode;
|
||||||
var isSymbolic = !!(properties.flags & FontFlags.Symbolic);
|
var isSymbolic = !!(properties.flags & FontFlags.Symbolic);
|
||||||
var isIdentityUnicode =
|
var isIdentityUnicode =
|
||||||
@ -831,7 +831,8 @@ var Font = (function FontClosure() {
|
|||||||
// font was symbolic and there is only an identity unicode map since the
|
// font was symbolic and there is only an identity unicode map since the
|
||||||
// characters probably aren't in the correct position (fixes an issue
|
// characters probably aren't in the correct position (fixes an issue
|
||||||
// with firefox and thuluthfont).
|
// with firefox and thuluthfont).
|
||||||
if ((usedFontCharCodes[fontCharCode] !== undefined ||
|
if (!missingGlyphs[glyphId] &&
|
||||||
|
(usedFontCharCodes[fontCharCode] !== undefined ||
|
||||||
isProblematicUnicodeLocation(fontCharCode) ||
|
isProblematicUnicodeLocation(fontCharCode) ||
|
||||||
(isSymbolic && !hasUnicodeValue)) &&
|
(isSymbolic && !hasUnicodeValue)) &&
|
||||||
nextAvailableFontCharCode <= PRIVATE_USE_OFFSET_END) { // Room left.
|
nextAvailableFontCharCode <= PRIVATE_USE_OFFSET_END) { // Room left.
|
||||||
@ -1686,9 +1687,15 @@ var Font = (function FontClosure() {
|
|||||||
var startOffset = itemDecode(locaData, 0);
|
var startOffset = itemDecode(locaData, 0);
|
||||||
var writeOffset = 0;
|
var writeOffset = 0;
|
||||||
var missingGlyphData = Object.create(null);
|
var missingGlyphData = Object.create(null);
|
||||||
|
// Glyph zero should be notdef which isn't drawn. Sometimes this is a
|
||||||
|
// valid glyph but, then it is duplicated.
|
||||||
|
missingGlyphData[0] = true;
|
||||||
itemEncode(locaData, 0, writeOffset);
|
itemEncode(locaData, 0, writeOffset);
|
||||||
var i, j;
|
var i, j;
|
||||||
for (i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
|
// When called with dupFirstEntry the number of glyphs has already been
|
||||||
|
// increased but there isn't data yet for the duplicated glyph.
|
||||||
|
var locaCount = dupFirstEntry ? numGlyphs - 1 : numGlyphs;
|
||||||
|
for (i = 0, j = itemSize; i < locaCount; i++, j += itemSize) {
|
||||||
var endOffset = itemDecode(locaData, j);
|
var endOffset = itemDecode(locaData, j);
|
||||||
if (endOffset > oldGlyfDataLength &&
|
if (endOffset > oldGlyfDataLength &&
|
||||||
((oldGlyfDataLength + 3) & ~3) === endOffset) {
|
((oldGlyfDataLength + 3) & ~3) === endOffset) {
|
||||||
@ -1698,17 +1705,14 @@ var Font = (function FontClosure() {
|
|||||||
}
|
}
|
||||||
if (endOffset > oldGlyfDataLength) {
|
if (endOffset > oldGlyfDataLength) {
|
||||||
// glyph end offset points outside glyf data, rejecting the glyph
|
// glyph end offset points outside glyf data, rejecting the glyph
|
||||||
itemEncode(locaData, j, writeOffset);
|
|
||||||
startOffset = endOffset;
|
startOffset = endOffset;
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (startOffset === endOffset) {
|
|
||||||
missingGlyphData[i] = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset,
|
var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset,
|
||||||
newGlyfData, writeOffset, hintsValid);
|
newGlyfData, writeOffset, hintsValid);
|
||||||
|
if (newLength === 0) {
|
||||||
|
missingGlyphData[i] = true;
|
||||||
|
}
|
||||||
writeOffset += newLength;
|
writeOffset += newLength;
|
||||||
itemEncode(locaData, j, writeOffset);
|
itemEncode(locaData, j, writeOffset);
|
||||||
startOffset = endOffset;
|
startOffset = endOffset;
|
||||||
@ -2271,24 +2275,10 @@ var Font = (function FontClosure() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var charCodeToGlyphId = [], charCode;
|
var charCodeToGlyphId = [], charCode;
|
||||||
var toUnicode = properties.toUnicode, widths = properties.widths;
|
|
||||||
var skipToUnicode = (toUnicode instanceof IdentityToUnicodeMap ||
|
|
||||||
toUnicode.length === 0x10000);
|
|
||||||
|
|
||||||
// Helper function to try to skip mapping of empty glyphs.
|
// Helper function to try to skip mapping of empty glyphs.
|
||||||
// Note: In some cases, just relying on the glyph data doesn't work,
|
function hasGlyph(glyphId) {
|
||||||
// hence we also use a few heuristics to fix various PDF files.
|
return !missingGlyphs[glyphId];
|
||||||
function hasGlyph(glyphId, charCode, widthCode) {
|
|
||||||
if (!missingGlyphs[glyphId]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!skipToUnicode && charCode >= 0 && toUnicode.has(charCode)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (widths && widthCode >= 0 && isNum(widths[widthCode])) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (properties.composite) {
|
if (properties.composite) {
|
||||||
@ -2304,8 +2294,7 @@ var Font = (function FontClosure() {
|
|||||||
glyphId = cidToGidMap[cid];
|
glyphId = cidToGidMap[cid];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (glyphId >= 0 && glyphId < numGlyphs &&
|
if (glyphId >= 0 && glyphId < numGlyphs && hasGlyph(glyphId)) {
|
||||||
hasGlyph(glyphId, charCode, cid)) {
|
|
||||||
charCodeToGlyphId[charCode] = glyphId;
|
charCodeToGlyphId[charCode] = glyphId;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -2361,10 +2350,9 @@ var Font = (function FontClosure() {
|
|||||||
// Ensure that non-standard glyph names are resolved to valid ones.
|
// Ensure that non-standard glyph names are resolved to valid ones.
|
||||||
standardGlyphName = recoverGlyphName(glyphName, glyphsUnicodeMap);
|
standardGlyphName = recoverGlyphName(glyphName, glyphsUnicodeMap);
|
||||||
|
|
||||||
var unicodeOrCharCode, isUnicode = false;
|
var unicodeOrCharCode;
|
||||||
if (cmapPlatformId === 3 && cmapEncodingId === 1) {
|
if (cmapPlatformId === 3 && cmapEncodingId === 1) {
|
||||||
unicodeOrCharCode = glyphsUnicodeMap[standardGlyphName];
|
unicodeOrCharCode = glyphsUnicodeMap[standardGlyphName];
|
||||||
isUnicode = true;
|
|
||||||
} else if (cmapPlatformId === 1 && cmapEncodingId === 0) {
|
} else if (cmapPlatformId === 1 && cmapEncodingId === 0) {
|
||||||
// TODO: the encoding needs to be updated with mac os table.
|
// TODO: the encoding needs to be updated with mac os table.
|
||||||
unicodeOrCharCode = MacRomanEncoding.indexOf(standardGlyphName);
|
unicodeOrCharCode = MacRomanEncoding.indexOf(standardGlyphName);
|
||||||
@ -2375,8 +2363,7 @@ var Font = (function FontClosure() {
|
|||||||
if (cmapMappings[i].charCode !== unicodeOrCharCode) {
|
if (cmapMappings[i].charCode !== unicodeOrCharCode) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
var code = isUnicode ? charCode : unicodeOrCharCode;
|
if (hasGlyph(cmapMappings[i].glyphId)) {
|
||||||
if (hasGlyph(cmapMappings[i].glyphId, code, -1)) {
|
|
||||||
charCodeToGlyphId[charCode] = cmapMappings[i].glyphId;
|
charCodeToGlyphId[charCode] = cmapMappings[i].glyphId;
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
@ -2390,7 +2377,7 @@ var Font = (function FontClosure() {
|
|||||||
if (glyphId === -1 && standardGlyphName !== glyphName) {
|
if (glyphId === -1 && standardGlyphName !== glyphName) {
|
||||||
glyphId = properties.glyphNames.indexOf(standardGlyphName);
|
glyphId = properties.glyphNames.indexOf(standardGlyphName);
|
||||||
}
|
}
|
||||||
if (glyphId > 0 && hasGlyph(glyphId, -1, -1)) {
|
if (glyphId > 0 && hasGlyph(glyphId)) {
|
||||||
charCodeToGlyphId[charCode] = glyphId;
|
charCodeToGlyphId[charCode] = glyphId;
|
||||||
found = true;
|
found = true;
|
||||||
}
|
}
|
||||||
@ -2432,7 +2419,8 @@ var Font = (function FontClosure() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Converting glyphs and ids into font's cmap table
|
// Converting glyphs and ids into font's cmap table
|
||||||
var newMapping = adjustMapping(charCodeToGlyphId, properties);
|
var newMapping = adjustMapping(charCodeToGlyphId, properties,
|
||||||
|
missingGlyphs);
|
||||||
this.toFontChar = newMapping.toFontChar;
|
this.toFontChar = newMapping.toFontChar;
|
||||||
tables['cmap'] = {
|
tables['cmap'] = {
|
||||||
tag: 'cmap',
|
tag: 'cmap',
|
||||||
@ -2499,7 +2487,7 @@ var Font = (function FontClosure() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var mapping = font.getGlyphMapping(properties);
|
var mapping = font.getGlyphMapping(properties);
|
||||||
var newMapping = adjustMapping(mapping, properties);
|
var newMapping = adjustMapping(mapping, properties, Object.create(null));
|
||||||
this.toFontChar = newMapping.toFontChar;
|
this.toFontChar = newMapping.toFontChar;
|
||||||
var numGlyphs = font.numGlyphs;
|
var numGlyphs = font.numGlyphs;
|
||||||
|
|
||||||
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -53,6 +53,7 @@
|
|||||||
!issue8372.pdf
|
!issue8372.pdf
|
||||||
!issue8424.pdf
|
!issue8424.pdf
|
||||||
!issue8480.pdf
|
!issue8480.pdf
|
||||||
|
!issue8570.pdf
|
||||||
!bad-PageLabels.pdf
|
!bad-PageLabels.pdf
|
||||||
!filled-background.pdf
|
!filled-background.pdf
|
||||||
!ArabicCIDTrueType.pdf
|
!ArabicCIDTrueType.pdf
|
||||||
|
BIN
test/pdfs/issue8570.pdf
Normal file
BIN
test/pdfs/issue8570.pdf
Normal file
Binary file not shown.
@ -1156,6 +1156,13 @@
|
|||||||
"link": false,
|
"link": false,
|
||||||
"type": "eq"
|
"type": "eq"
|
||||||
},
|
},
|
||||||
|
{ "id": "issue8570",
|
||||||
|
"file": "pdfs/issue8570.pdf",
|
||||||
|
"md5": "0355731adb72df233eaa10464dcc8c51",
|
||||||
|
"rounds": 1,
|
||||||
|
"link": false,
|
||||||
|
"type": "eq"
|
||||||
|
},
|
||||||
{ "id": "tutorial",
|
{ "id": "tutorial",
|
||||||
"file": "pdfs/tutorial.pdf",
|
"file": "pdfs/tutorial.pdf",
|
||||||
"md5": "6e122f618c27f3aa9a689423e3be6b8d",
|
"md5": "6e122f618c27f3aa9a689423e3be6b8d",
|
||||||
|
Loading…
Reference in New Issue
Block a user