Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Embedded Arimo font widths and used that when fonts are missing #11191

Closed
wants to merge 3 commits into from
Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
180 changes: 136 additions & 44 deletions src/core/evaluator.js
Original file line number Diff line number Diff line change
Expand Up @@ -723,29 +723,70 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
return errorFont();
}
}
let fallbackFont = false;
let fallbackFontProperties = false;
if (!fontRef) {
warn('fontRef not available');
return errorFont();
// warn('fontRef not available');
// return errorFont();

// fallback to some default font
let widthsWithNulls = [null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null,
null, null, null, null, null, null, null, null, null, null, null,
null, null, null, 278, 278, 355, 556, 556, 889, 667, 191, 333,
333, 389, 584, 278, 333, 278, 278, 556, 556, 556, 556, 556, 556,
556, 556, 556, 556, 278, 278, 584, 584, 584, 556, 1015, 667, 667,
722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778,
667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278,
278, 469, 556, 333, 556, 556, 500, 556, 556, 278, 556, 556, 222,
222, 500, 222, 833, 556, 556, 556, 556, 333, 500, 278, 556, 500,
722, 500, 500, 500, 334, 260, 334, 584];
let widthsWithoutNulls = [];
for (let i = 0; i < widthsWithNulls.length; i++) {
if (widthsWithNulls[i] !== null) {
widthsWithoutNulls[i] = widthsWithNulls[i];
}
}
fallbackFontProperties = {
fallbackFont: true,
firstChar: 0,
name: 'BCDEEE+Arimo',
type: 'TrueType',
widths: widthsWithoutNulls,
defaultEncoding: [],
toUnicode: new ToUnicodeMap([]),
differences: [],
};
fallbackFont = new Font(fallbackFontProperties.name, null,
fallbackFontProperties);
}

if (this.fontCache.has(fontRef)) {
if (!fallbackFont && this.fontCache.has(fontRef)) {
return this.fontCache.get(fontRef);
}

font = xref.fetchIfRef(fontRef);
if (!isDict(font)) {
if (fallbackFont) {
font = fallbackFont;
}
if (!isDict(font) && !fallbackFont) {
return errorFont();
}

// We are holding `font.translated` references just for `fontRef`s that
// are not actually `Ref`s, but rather `Dict`s. See explanation below.
if (font.translated) {
if (!fallbackFont && font.translated) {
return font.translated;
}

var fontCapability = createPromiseCapability();

var preEvaluatedFont = this.preEvaluateFont(font);
let preEvaluatedFont;
if (!fallbackFont) {
preEvaluatedFont = this.preEvaluateFont(font);
} else {
preEvaluatedFont = { descriptor: null, hash: null, };
}
const { descriptor, hash, } = preEvaluatedFont;

var fontRefIsRef = isRef(fontRef), fontID;
Expand Down Expand Up @@ -814,7 +855,11 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// TODO move promises into translate font
var translatedPromise;
try {
translatedPromise = this.translateFont(preEvaluatedFont);
if (fallbackFont) {
translatedPromise = this.translateFont(font, fallbackFontProperties);
} else {
translatedPromise = this.translateFont(preEvaluatedFont);
}
} catch (e) {
translatedPromise = Promise.reject(e);
}
Expand Down Expand Up @@ -1863,7 +1908,12 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
properties) {
let xref = this.xref, cidToGidBytes;
// 9.10.2
var toUnicode = (dict.get('ToUnicode') || baseDict.get('ToUnicode'));
let toUnicode;
if (properties.fallbackFont) {
toUnicode = false;
} else {
toUnicode = (dict.get('ToUnicode') || baseDict.get('ToUnicode'));
}
var toUnicodePromise = toUnicode ?
this.readToUnicode(toUnicode) : Promise.resolve(undefined);

Expand All @@ -1890,10 +1940,15 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// glyph mapping in the font.
// TODO: Loading the built in encoding in the font would allow the
// differences to be merged in here not require us to hold on to it.
var differences = [];
let differences;
if (properties.fallbackFont && properties.differences) {
differences = properties.differences;
} else {
differences = [];
}
var baseEncodingName = null;
var encoding;
if (dict.has('Encoding')) {
if (!properties.fallbackFont && dict.has('Encoding')) {
encoding = dict.get('Encoding');
if (isDict(encoding)) {
baseEncodingName = encoding.get('BaseEncoding');
Expand Down Expand Up @@ -1961,6 +2016,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
properties.hasEncoding = !!baseEncodingName || differences.length > 0;
properties.dict = dict;
return toUnicodePromise.then((toUnicode) => {
if (properties.fallbackFont) {
return properties.toUnicode;
}
properties.toUnicode = toUnicode;
return this.buildToUnicode(properties);
}).then((toUnicode) => {
Expand Down Expand Up @@ -2260,13 +2318,22 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
} else {
var firstChar = properties.firstChar;
widths = dict.get('Widths');
if (properties.fallbackFont) {
widths = properties.widths;
} else {
widths = dict.get('Widths');
}

if (widths) {
j = firstChar;
for (i = 0, ii = widths.length; i < ii; i++) {
glyphsWidths[j++] = xref.fetchIfRef(widths[i]);
}
defaultWidth = (parseFloat(descriptor.get('MissingWidth')) || 0);
if (properties.fallbackFont) {
defaultWidth = 0;
} else {
defaultWidth = (parseFloat(descriptor.get('MissingWidth')) || 0);
}
} else {
// Trying get the BaseFont metrics (see comment above).
var baseFontName = dict.get('BaseFont');
Expand Down Expand Up @@ -2461,7 +2528,8 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
};
},

translateFont: function PartialEvaluator_translateFont(preEvaluatedFont) {
translateFont: function PartialEvaluator_translateFont(preEvaluatedFont,
fallbackFontProperties = false) {
var baseDict = preEvaluatedFont.baseDict;
var dict = preEvaluatedFont.dict;
var composite = preEvaluatedFont.composite;
Expand All @@ -2470,7 +2538,13 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
var maxCharIndex = (composite ? 0xFFFF : 0xFF);
var properties;

if (!descriptor) {
if (fallbackFontProperties) {
baseDict = {};
dict = {};
descriptor = {};
}

if (!descriptor && !fallbackFontProperties) {
if (type === 'Type3') {
// FontDescriptor is only required for Type3 fonts when the document
// is a tagged pdf. Create a barbebones one to get by.
Expand Down Expand Up @@ -2521,11 +2595,20 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
// to ignore this rule when a variant of a standard font is used.
// TODO Fill the width array depending on which of the base font this is
// a variant.
var firstChar = (dict.get('FirstChar') || 0);
var lastChar = (dict.get('LastChar') || maxCharIndex);
let firstChar, lastChar, fontName, baseFont;
if (fallbackFontProperties) {
firstChar = fallbackFontProperties.firstChar;
lastChar = fallbackFontProperties.lastChar || maxCharIndex;

fontName = new Name(preEvaluatedFont.name);
baseFont = new Name(preEvaluatedFont.name);
} else {
firstChar = (dict.get('FirstChar') || 0);
lastChar = (dict.get('LastChar') || maxCharIndex);

var fontName = descriptor.get('FontName');
var baseFont = dict.get('BaseFont');
fontName = descriptor.get('FontName');
baseFont = dict.get('BaseFont');
}
// Some bad PDFs have a string as the font name.
if (isString(fontName)) {
fontName = Name.get(fontName);
Expand Down Expand Up @@ -2554,8 +2637,10 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
throw new FormatError('invalid font name');
}

var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3');
if (fontFile) {
if (!fallbackFontProperties) {
var fontFile = descriptor.get('FontFile', 'FontFile2', 'FontFile3');
}
if (fontFile && !fallbackFontProperties) {
if (fontFile.dict) {
var subtype = fontFile.dict.get('Subtype');
if (subtype) {
Expand All @@ -2567,30 +2652,34 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
}
}

properties = {
type,
name: fontName.name,
subtype,
file: fontFile,
length1,
length2,
length3,
loadedName: baseDict.loadedName,
composite,
wideChars: composite,
fixedPitch: false,
fontMatrix: (dict.getArray('FontMatrix') || FONT_IDENTITY_MATRIX),
firstChar: firstChar || 0,
lastChar: (lastChar || maxCharIndex),
bbox: descriptor.getArray('FontBBox'),
ascent: descriptor.get('Ascent'),
descent: descriptor.get('Descent'),
xHeight: descriptor.get('XHeight'),
capHeight: descriptor.get('CapHeight'),
flags: descriptor.get('Flags'),
italicAngle: descriptor.get('ItalicAngle'),
isType3Font: false,
};
if (!fallbackFontProperties) {
properties = {
type,
name: fontName.name,
subtype,
file: fontFile,
length1,
length2,
length3,
loadedName: baseDict.loadedName,
composite,
wideChars: composite,
fixedPitch: false,
fontMatrix: (dict.getArray('FontMatrix') || FONT_IDENTITY_MATRIX),
firstChar: firstChar || 0,
lastChar: (lastChar || maxCharIndex),
bbox: descriptor.getArray('FontBBox'),
ascent: descriptor.get('Ascent'),
descent: descriptor.get('Descent'),
xHeight: descriptor.get('XHeight'),
capHeight: descriptor.get('CapHeight'),
flags: descriptor.get('Flags'),
italicAngle: descriptor.get('ItalicAngle'),
isType3Font: false,
};
} else {
properties = fallbackFontProperties;
}

var cMapPromise;
if (composite) {
Expand Down Expand Up @@ -2618,6 +2707,9 @@ var PartialEvaluator = (function PartialEvaluatorClosure() {
if (type === 'Type3') {
properties.isType3Font = true;
}
if (fallbackFontProperties) {
return new Font(fontName.name, null, properties);
}
return new Font(fontName.name, fontFile, properties);
});
},
Expand Down