Merge pull request #21462 from calixteman/bluescale-small-zones

Don't clamp BlueScale up when a font genuinely has small zones
This commit is contained in:
calixteman 2026-06-16 21:52:25 +02:00 committed by GitHub
commit eae42379f2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 43 additions and 1 deletions

View File

@ -894,8 +894,17 @@ class CFFParser {
}
}
if (maxZoneHeight > 0) {
// The lower bound of AFDKO's valid window is `0.5 / maxZoneHeight`.
// When that bound is itself above the default BlueScale the font simply
// has small zones (e.g. Eurostile LT Std, or the SofiaPro fonts shipped
// with a near-default 0.037): even the default 0.039625 would be
// flagged as out-of-range, so this is the rendered intent and forcing
// BlueScale up only misaligns/collapses overshooting glyphs (notably
// with macOS's Core Text rasterizer). Only apply the lower clamp when
// its target does not exceed the default.
const lowerBound = 0.5 / maxZoneHeight;
const minBlueScale =
blueScale < DEFAULT_BLUE_SCALE ? 0.5 / maxZoneHeight : -Infinity;
lowerBound <= DEFAULT_BLUE_SCALE ? lowerBound : -Infinity;
const maxBlueScale = 1 / maxZoneHeight;
const clamped = MathClamp(blueScale, minBlueScale, maxBlueScale);
if (clamped !== blueScale) {

View File

@ -937,3 +937,4 @@
!checkbox_no_appearance.pdf
!opt_demo.pdf
!bug1873345.pdf
!cff_bluescale_small_zones.pdf

Binary file not shown.

View File

@ -22,6 +22,9 @@ import {
CFFStrings,
CFFTopDict,
} from "../../src/core/cff_parser.js";
import { DefaultFileReaderFactory, TEST_PDFS_PATH } from "./test_utils.js";
import { PDFDocument } from "../../src/core/document.js";
import { Ref } from "../../src/core/primitives.js";
import { SEAC_ANALYSIS_ENABLED } from "../../src/core/fonts_utils.js";
import { Stream } from "../../src/core/stream.js";
@ -357,6 +360,35 @@ describe("CFFParser", function () {
);
});
it("preserves the BlueScale of an embedded CID font with small zones", async function () {
// The embedded CID-keyed CFF pairs a near-default BlueScale of 0.037 with
// 12-unit zones; clamping it up to the lower bound breaks rendering on
// macOS only, so it's guarded here rather than with a reference image.
const data = await DefaultFileReaderFactory.fetch({
path: TEST_PDFS_PATH + "cff_bluescale_small_zones.pdf",
});
const pdfManager = {
evaluatorOptions: { isOffscreenCanvasSupported: false },
password: null,
};
const pdfDocument = new PDFDocument(pdfManager, new Stream(data));
pdfDocument.parseStartXRef();
pdfDocument.xref.parse();
// Object 8 is the `/FontFile3` (`/CIDFontType0C`) stream in the fixture.
const fontProgram = pdfDocument.xref.fetch(Ref.get(8, 0)).getBytes();
const embeddedCff = new CFFParser(
new Stream(fontProgram),
{},
SEAC_ANALYSIS_ENABLED
).parse();
expect(embeddedCff.isCIDFont).toEqual(true);
expect(embeddedCff.fdArray[0].privateDict.getByName("BlueScale")).toEqual(
0.037
);
});
it("refuses to add topDict key with invalid value (bug 1068432)", function () {
const topDict = cff.topDict;
const defaultValue = topDict.getByName("UnderlinePosition");