Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
97 changes: 89 additions & 8 deletions packages/fallbacks/fallbacks.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,15 +54,15 @@ describe("getFallbackDecision", () => {
});

test("a measured 'no open font' is distinct from an unknown font", () => {
// The whole point of the decision API: docfonts MEASURED Aptos and Verdana; it never heard of "Foo".
// The whole point of the decision API: docfonts measured Aptos and Candara; it never heard of "Foo".
expect(getFallbackDecision("Aptos")).toEqual({
kind: "customer_supplied",
evidenceId: "aptos",
generic: "sans-serif",
});
expect(getFallbackDecision("Verdana")).toEqual({
expect(getFallbackDecision("Candara")).toEqual({
kind: "no_recommended_fallback",
evidenceId: "verdana",
evidenceId: "candara",
generic: "sans-serif",
});
expect(getFallbackDecision("Cambria Math")).toEqual({
Expand Down Expand Up @@ -106,13 +106,19 @@ describe("getRenderableFallback", () => {
}
});

test("a monospace cell_width_only substitute is lineBreakSafe (advances match)", () => {
// Consolas -> Inconsolata SemiExpanded: glyph shapes differ, but cell width (every advance) matches.
const fb = getRenderableFallback("Consolas", {
test("a monospace cell_width_only face is lineBreakSafe (advances match)", () => {
// Consolas -> Inconsolata SemiExpanded: glyph shapes differ, but real R/B cell widths match.
const family = getRenderableFallback("Consolas", {
canRenderFamily: () => true,
});
expect(fb?.verdict).toBe("cell_width_only");
expect(fb?.lineBreakSafe).toBe(true);
expect(family?.verdict).toBe("visual_only");
expect(family?.lineBreakSafe).toBe(false);

const regular = getRenderableFallbackForFace("Consolas", "regular", {
canRenderFamily: () => true,
});
expect(regular?.verdict).toBe("cell_width_only");
expect(regular?.lineBreakSafe).toBe(true);
});
});

Expand Down Expand Up @@ -328,9 +334,11 @@ describe("selected visual fallback rows", () => {
["Comic Sans MS", "Comic Relief", "category_fallback"],
["Garamond", "Cardo", "category_fallback"],
["Gill Sans MT Condensed", "PT Sans Narrow", "category_fallback"],
["ITC Bookman", "TeX Gyre Bonum", "substitute"],
["Lucida Console", "Noto Sans Mono", "category_fallback"],
["Tahoma", "Noto Sans", "category_fallback"],
["Trebuchet MS", "PT Sans", "category_fallback"],
["Verdana", "Noto Sans", "category_fallback"],
] as const;

for (const [logical, physical, policyAction] of expected) {
Expand Down Expand Up @@ -419,6 +427,79 @@ describe("selected visual fallback rows", () => {
});
}
});

test("Consolas keeps cell-width evidence for real Inconsolata SemiExpanded faces", () => {
for (const face of ["regular", "bold"] as const) {
expect(
getRenderableFallbackForFace("Consolas", face, renderAll),
`Consolas ${face}`,
).toMatchObject({
substituteFamily: "Inconsolata SemiExpanded",
verdict: "cell_width_only",
lineBreakSafe: true,
});
expect(
getRenderableFallbackForFace("Consolas", face, renderAll)?.faceSource,
).toBeUndefined();
}

expect(
getRenderableFallbackForFace("Consolas", "italic", renderAll),
).toMatchObject({
substituteFamily: "Inconsolata SemiExpanded",
verdict: "visual_only",
lineBreakSafe: false,
faceSource: { kind: "synthetic", from: "regular" },
});
expect(
getRenderableFallbackForFace("Consolas", "boldItalic", renderAll),
).toMatchObject({
substituteFamily: "Inconsolata SemiExpanded",
verdict: "visual_only",
lineBreakSafe: false,
faceSource: { kind: "synthetic", from: "bold" },
});
});

test("Century rows expose measured safe faces without advertising the whole family as safe", () => {
expect(getRenderableFallback("Century", renderAll)).toMatchObject({
substituteFamily: "C059",
verdict: "visual_only",
lineBreakSafe: false,
});
expect(
getRenderableFallbackForFace("Century", "regular", renderAll),
).toMatchObject({
substituteFamily: "C059",
verdict: "metric_safe",
lineBreakSafe: true,
glyphExceptions: [{ slot: "regular", codepoint: 0x00af }],
});

expect(
getRenderableFallbackForFace("Century Schoolbook", "regular", renderAll),
).toMatchObject({
substituteFamily: "C059",
verdict: "metric_safe",
lineBreakSafe: true,
glyphExceptions: [{ slot: "regular", codepoint: 0x00af }],
});
expect(
getRenderableFallbackForFace("Century Schoolbook", "bold", renderAll),
).toMatchObject({
substituteFamily: "C059",
verdict: "metric_safe",
lineBreakSafe: true,
glyphExceptions: [{ slot: "bold", codepoint: 0x00af }],
});
expect(
getRenderableFallbackForFace("Century Schoolbook", "italic", renderAll),
).toMatchObject({
substituteFamily: "C059",
verdict: "visual_only",
lineBreakSafe: false,
});
});
});

describe("candidate license metadata", () => {
Expand Down
139 changes: 115 additions & 24 deletions packages/fallbacks/records.json
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,31 @@
"exportRule": "preserve_original_name",
"candidateLicense": "LicenseRef-GUST-Font-License-1.0"
},
{
"evidenceId": "itc-bookman",
"generic": "serif",
"logicalFamily": "ITC Bookman",
"physicalFamily": "TeX Gyre Bonum",
"verdict": "visual_only",
"faces": {
"regular": true,
"bold": true,
"italic": true,
"boldItalic": true
},
"gates": {
"static": "pass",
"metric": "fail",
"layout": "not_run",
"ship": "fail"
},
"policyAction": "substitute",
"measurementRefs": [
"itc-bookman__tex-gyre-bonum#alias_of_bookman-old-style#2026-06-10"
],
"exportRule": "preserve_original_name",
"candidateLicense": "LicenseRef-GUST-Font-License-1.0"
},
{
"evidenceId": "century",
"generic": "serif",
Expand All @@ -388,14 +413,33 @@
},
"gates": {
"static": "pass",
"metric": "fail",
"metric": "pass",
"layout": "not_run",
"ship": "fail"
},
"policyAction": "substitute",
"measurementRefs": ["century__c059#visual_review#2026-06-09"],
"measurementRefs": [
"century_regular__c059#regular#w400#analytic_advance#2026-06-10",
"century__c059#visual_review#2026-06-09"
],
"exportRule": "preserve_original_name",
"candidateLicense": "AGPL-3.0-only WITH PS-or-PDF-font-exception-20170817"
"candidateLicense": "AGPL-3.0-only WITH PS-or-PDF-font-exception-20170817",
"advance": {
"basis": "latin_full",
"meanDelta": 0.00293647,
"maxDelta": 0.167
},
"faceVerdicts": {
"regular": "metric_safe"
},
"glyphExceptions": [
{
"slot": "regular",
"codepoint": 175,
"advanceDelta": 0.167,
"note": "Century Regular vs C059 Roman: macron (U+00AF) advance differs ~16.7%; yen (U+00A5), plus-minus (U+00B1), division sign (U+00F7), and middle dot (U+00B7) also exceed the direct threshold. Body-text Latin sample is metric_safe."
}
]
},
{
"evidenceId": "century-schoolbook",
Expand All @@ -416,9 +460,40 @@
"ship": "fail"
},
"policyAction": "substitute",
"measurementRefs": ["century-schoolbook__c059#visual_review#2026-06-09"],
"measurementRefs": [
"century-schoolbook_regular__c059#regular#w400#analytic_advance#2026-06-10",
"century-schoolbook_bold__c059#bold#w700#analytic_advance#2026-06-10",
"century-schoolbook_italic__c059#italic#w400#analytic_advance#2026-06-10",
"century-schoolbook_boldItalic__c059#boldItalic#w700#analytic_advance#2026-06-10",
"century-schoolbook__c059#visual_review#2026-06-09"
],
"exportRule": "preserve_original_name",
"candidateLicense": "AGPL-3.0-only WITH PS-or-PDF-font-exception-20170817"
"candidateLicense": "AGPL-3.0-only WITH PS-or-PDF-font-exception-20170817",
"advance": {
"basis": "latin_full",
"meanDelta": 0.00337127,
"maxDelta": 0.167
},
"faceVerdicts": {
"regular": "metric_safe",
"bold": "metric_safe",
"italic": "visual_only",
"boldItalic": "visual_only"
},
"glyphExceptions": [
{
"slot": "regular",
"codepoint": 175,
"advanceDelta": 0.167,
"note": "Century Schoolbook Regular vs C059 Roman: macron (U+00AF) advance differs ~16.7%; yen (U+00A5), plus-minus (U+00B1), division sign (U+00F7), and middle dot (U+00B7) also exceed the direct threshold. Body-text Latin sample is metric_safe."
},
{
"slot": "bold",
"codepoint": 175,
"advanceDelta": 0.167,
"note": "Century Schoolbook Bold vs C059 Bold: macron (U+00AF) advance differs ~16.7%; yen (U+00A5), micro sign (U+00B5), plus-minus (U+00B1), and division sign (U+00F7) also exceed the direct threshold. Body-text Latin sample is metric_safe."
}
]
},
{
"evidenceId": "garamond",
Expand Down Expand Up @@ -457,53 +532,69 @@
"generic": "monospace",
"logicalFamily": "Consolas",
"physicalFamily": "Inconsolata SemiExpanded",
"verdict": "cell_width_only",
"verdict": "visual_only",
"faces": {
"regular": false,
"bold": false,
"regular": true,
"bold": true,
"italic": false,
"boldItalic": false
},
"gates": {
"static": "not_run",
"metric": "not_run",
"static": "pass",
"metric": "pass",
"layout": "not_run",
"ship": "not_run"
"ship": "fail"
},
"policyAction": "category_fallback",
"measurementRefs": [
"consolas__inconsolata-semiexpanded#analytic_advance#2026-06-03"
"consolas__inconsolata-semiexpanded#monospace_cell#analytic_advance#2026-06-10"
],
"exportRule": "preserve_original_name",
"advance": {
"basis": "monospace_cell",
"meanDelta": 0.00035999999999999997,
"maxDelta": 0.00035999999999999997
"meanDelta": 0.00019531,
"maxDelta": 0.00019531
},
"candidateLicense": "OFL-1.1"
"candidateLicense": "OFL-1.1",
"faceSources": {
"italic": {
"kind": "synthetic",
"from": "regular"
},
"boldItalic": {
"kind": "synthetic",
"from": "bold"
}
},
"faceVerdicts": {
"regular": "cell_width_only",
"bold": "cell_width_only",
"italic": "visual_only",
"boldItalic": "visual_only"
}
},
{
"evidenceId": "verdana",
"generic": "sans-serif",
"logicalFamily": "Verdana",
"physicalFamily": null,
"physicalFamily": "Noto Sans",
"verdict": "visual_only",
"faces": {
"regular": false,
"bold": false,
"italic": false,
"boldItalic": false
"regular": true,
"bold": true,
"italic": true,
"boldItalic": true
},
"gates": {
"static": "not_run",
"static": "pass",
"metric": "fail",
"layout": "not_run",
"ship": "not_run"
"ship": "fail"
},
"policyAction": "category_fallback",
"measurementRefs": ["verdana#top_candidates#2026-06-03"],
"measurementRefs": ["verdana__noto-sans#visual_review#2026-06-10"],
"exportRule": "preserve_original_name",
"candidateLicense": null
"candidateLicense": "OFL-1.1"
},
{
"evidenceId": "tahoma",
Expand Down
Loading
Loading