mirror of
https://github.com/mozilla/pdf.js.git
synced 2026-05-31 07:11:00 +02:00
Recover CFF private dict defaults zeroed by Ghostscript
It fixes the issue #20633.
This commit is contained in:
parent
3450e95179
commit
cd8a78c4e2
@ -108,6 +108,11 @@ const CFFStandardStrings = [
|
||||
|
||||
const NUM_STANDARD_CFF_STRINGS = 391;
|
||||
|
||||
const DEFAULT_BLUE_SCALE = 0.039625;
|
||||
const DEFAULT_BLUE_SHIFT = 7;
|
||||
const DEFAULT_BLUE_FUZZ = 1;
|
||||
const DEFAULT_EXPANSION_FACTOR = 0.06;
|
||||
|
||||
const CharstringValidationData = [
|
||||
/* 0 */ null,
|
||||
/* 1 */ { id: "hstem", min: 2, stackClearing: true, stem: true },
|
||||
@ -262,8 +267,16 @@ class CFFParser {
|
||||
properties.fontMatrix = fontMatrix;
|
||||
}
|
||||
|
||||
const fontBBox = topDict.getByName("FontBBox");
|
||||
if (fontBBox) {
|
||||
let fontBBox = topDict.getByName("FontBBox");
|
||||
if (fontBBox?.every(coord => coord === 0) && properties.bbox) {
|
||||
fontBBox = Util.normalizeRect(
|
||||
properties.bbox.map(coord =>
|
||||
coord > 0x7fff && coord <= 0xffff ? coord - 0x10000 : coord
|
||||
)
|
||||
);
|
||||
topDict.setByName("FontBBox", fontBBox);
|
||||
}
|
||||
if (fontBBox?.some(coord => coord !== 0)) {
|
||||
// adjusting ascent/descent
|
||||
properties.ascent = Math.max(fontBBox[3], fontBBox[1]);
|
||||
properties.descent = Math.min(fontBBox[1], fontBBox[3]);
|
||||
@ -785,10 +798,28 @@ class CFFParser {
|
||||
);
|
||||
parentDict.privateDict = privateDict;
|
||||
|
||||
if (privateDict.getByName("ExpansionFactor") === 0) {
|
||||
const blueScale = privateDict.getByName("BlueScale");
|
||||
const blueShift = privateDict.getByName("BlueShift");
|
||||
const blueFuzz = privateDict.getByName("BlueFuzz");
|
||||
const expansionFactor = privateDict.getByName("ExpansionFactor");
|
||||
if (
|
||||
blueScale === 0 &&
|
||||
blueShift === 0 &&
|
||||
blueFuzz === 0 &&
|
||||
expansionFactor === 0
|
||||
) {
|
||||
// Ghostscript can fail to initialize Private DICT defaults before
|
||||
// writing them, which leaves omitted blue zone values as explicit
|
||||
// zeroes. This has been seen in FDArray entries.
|
||||
privateDict.setByName("BlueScale", DEFAULT_BLUE_SCALE);
|
||||
privateDict.setByName("BlueShift", DEFAULT_BLUE_SHIFT);
|
||||
privateDict.setByName("BlueFuzz", DEFAULT_BLUE_FUZZ);
|
||||
}
|
||||
|
||||
if (expansionFactor === 0) {
|
||||
// Firefox doesn't render correctly such a font on Windows (see issue
|
||||
// 15289), hence we just reset it to its default value.
|
||||
privateDict.setByName("ExpansionFactor", 0.06);
|
||||
privateDict.setByName("ExpansionFactor", DEFAULT_EXPANSION_FACTOR);
|
||||
}
|
||||
|
||||
// Parse the Subrs index also since it's relative to the private dict.
|
||||
@ -1247,16 +1278,16 @@ const CFFPrivateDictLayout = [
|
||||
[7, "OtherBlues", "delta", null],
|
||||
[8, "FamilyBlues", "delta", null],
|
||||
[9, "FamilyOtherBlues", "delta", null],
|
||||
[[12, 9], "BlueScale", "num", 0.039625],
|
||||
[[12, 10], "BlueShift", "num", 7],
|
||||
[[12, 11], "BlueFuzz", "num", 1],
|
||||
[[12, 9], "BlueScale", "num", DEFAULT_BLUE_SCALE],
|
||||
[[12, 10], "BlueShift", "num", DEFAULT_BLUE_SHIFT],
|
||||
[[12, 11], "BlueFuzz", "num", DEFAULT_BLUE_FUZZ],
|
||||
[10, "StdHW", "num", null],
|
||||
[11, "StdVW", "num", null],
|
||||
[[12, 12], "StemSnapH", "delta", null],
|
||||
[[12, 13], "StemSnapV", "delta", null],
|
||||
[[12, 14], "ForceBold", "num", 0],
|
||||
[[12, 17], "LanguageGroup", "num", 0],
|
||||
[[12, 18], "ExpansionFactor", "num", 0.06],
|
||||
[[12, 18], "ExpansionFactor", "num", DEFAULT_EXPANSION_FACTOR],
|
||||
[[12, 19], "initialRandomSeed", "num", 0],
|
||||
[20, "defaultWidthX", "num", 0],
|
||||
[21, "nominalWidthX", "num", 0],
|
||||
|
||||
@ -18,7 +18,9 @@ import {
|
||||
CFFCompiler,
|
||||
CFFFDSelect,
|
||||
CFFParser,
|
||||
CFFPrivateDict,
|
||||
CFFStrings,
|
||||
CFFTopDict,
|
||||
} from "../../src/core/cff_parser.js";
|
||||
import { SEAC_ANALYSIS_ENABLED } from "../../src/core/fonts_utils.js";
|
||||
import { Stream } from "../../src/core/stream.js";
|
||||
@ -112,6 +114,77 @@ describe("CFFParser", function () {
|
||||
expect(topDict.getByName("Private")).toEqual([45, 102]);
|
||||
});
|
||||
|
||||
it("ignores an empty FontBBox when adjusting ascent/descent", function () {
|
||||
cff.topDict.setByName("FontBBox", [0, 0, 0, 0]);
|
||||
const fontDataWithEmptyBBox = new CFFCompiler(cff).compile();
|
||||
|
||||
const properties = {
|
||||
ascent: 800,
|
||||
descent: -200,
|
||||
};
|
||||
new CFFParser(
|
||||
new Stream(fontDataWithEmptyBBox),
|
||||
properties,
|
||||
SEAC_ANALYSIS_ENABLED
|
||||
).parse();
|
||||
|
||||
expect(properties.ascent).toEqual(800);
|
||||
expect(properties.descent).toEqual(-200);
|
||||
expect(properties.ascentScaled).toBeUndefined();
|
||||
});
|
||||
|
||||
it("repairs an empty FontBBox from font descriptor data", function () {
|
||||
cff.topDict.setByName("FontBBox", [0, 0, 0, 0]);
|
||||
const fontDataWithEmptyBBox = new CFFCompiler(cff).compile();
|
||||
|
||||
const properties = {
|
||||
bbox: [2974, -300, 64236, 900],
|
||||
};
|
||||
const reparsedCff = new CFFParser(
|
||||
new Stream(fontDataWithEmptyBBox),
|
||||
properties,
|
||||
SEAC_ANALYSIS_ENABLED
|
||||
).parse();
|
||||
|
||||
expect(reparsedCff.topDict.getByName("FontBBox")).toEqual([
|
||||
-1300, -300, 2974, 900,
|
||||
]);
|
||||
expect(properties.ascent).toEqual(900);
|
||||
expect(properties.descent).toEqual(-300);
|
||||
expect(properties.ascentScaled).toEqual(true);
|
||||
});
|
||||
|
||||
it("repairs likely Ghostscript-zeroed FDArray private defaults", function () {
|
||||
cff.isCIDFont = true;
|
||||
cff.topDict.setByName("ROS", [0, 0, 0]);
|
||||
cff.topDict.setByName("FDSelect", 0);
|
||||
cff.topDict.setByName("FDArray", 0);
|
||||
|
||||
const fdDict = new CFFTopDict(cff.strings);
|
||||
fdDict.setByName("Private", [0, 0]);
|
||||
fdDict.privateDict = new CFFPrivateDict(cff.strings);
|
||||
fdDict.privateDict.setByName("BlueScale", 0);
|
||||
fdDict.privateDict.setByName("BlueShift", 0);
|
||||
fdDict.privateDict.setByName("BlueFuzz", 0);
|
||||
fdDict.privateDict.setByName("ExpansionFactor", 0);
|
||||
|
||||
cff.fdArray = [fdDict];
|
||||
cff.fdSelect = new CFFFDSelect(0, Array(cff.charStrings.count).fill(0));
|
||||
const fontDataWithBrokenFDPrivate = new CFFCompiler(cff).compile();
|
||||
|
||||
const reparsedCff = new CFFParser(
|
||||
new Stream(fontDataWithBrokenFDPrivate),
|
||||
{},
|
||||
SEAC_ANALYSIS_ENABLED
|
||||
).parse();
|
||||
const privateDict = reparsedCff.fdArray[0].privateDict;
|
||||
|
||||
expect(privateDict.getByName("BlueScale")).toEqual(0.039625);
|
||||
expect(privateDict.getByName("BlueShift")).toEqual(7);
|
||||
expect(privateDict.getByName("BlueFuzz")).toEqual(1);
|
||||
expect(privateDict.getByName("ExpansionFactor")).toEqual(0.06);
|
||||
});
|
||||
|
||||
it("refuses to add topDict key with invalid value (bug 1068432)", function () {
|
||||
const topDict = cff.topDict;
|
||||
const defaultValue = topDict.getByName("UnderlinePosition");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user