mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-12 23:29:50 +00:00
fix(fonts): cover rendered case variants in subsets
This commit is contained in:
@@ -39,4 +39,47 @@ describe("Google Fonts text subsetting", () => {
|
||||
|
||||
expect(new URL(requestedUrl).searchParams.get("text")).toContain("旅行");
|
||||
});
|
||||
|
||||
it("includes case variants for transformed supplemental alias weights", async () => {
|
||||
let requestedUrl = "";
|
||||
const fetchImpl = (async (input: unknown) => {
|
||||
requestedUrl = String(input);
|
||||
return new Response("", { status: 400 });
|
||||
}) as unknown as typeof fetch;
|
||||
|
||||
await injectDeterministicFontFaces(
|
||||
`<!doctype html><html><head><style>
|
||||
h1 { font-family: "Inter", sans-serif; font-weight: 800; text-transform: uppercase; }
|
||||
</style></head><body><h1>Your Kidney Transplant:<br/>What Happens Next</h1></body></html>`,
|
||||
{ fetchImpl, allowSystemFontCapture: false },
|
||||
);
|
||||
|
||||
const text = new URL(requestedUrl).searchParams.get("text") ?? "";
|
||||
for (const character of new Set("YOUR KIDNEY TRANSPLANT:WHAT HAPPENS NEXT")) {
|
||||
expect(text).toContain(character);
|
||||
}
|
||||
});
|
||||
|
||||
it("falls back to the full font when case closure exceeds the text URL budget", async () => {
|
||||
let requestedUrl = "";
|
||||
const fetchImpl = (async (input: unknown) => {
|
||||
requestedUrl = String(input);
|
||||
return new Response("", { status: 400 });
|
||||
}) as unknown as typeof fetch;
|
||||
const caseChangingCharacters = Array.from({ length: 0x500 }, (_, index) =>
|
||||
String.fromCodePoint(index),
|
||||
)
|
||||
.filter((character) => character.toUpperCase() !== character.toLowerCase())
|
||||
.slice(0, 300)
|
||||
.join("");
|
||||
|
||||
await injectDeterministicFontFaces(
|
||||
`<!doctype html><html><head><style>
|
||||
p { font-family: "Inter", sans-serif; font-weight: 800; text-transform: uppercase; }
|
||||
</style></head><body><p>${caseChangingCharacters}</p></body></html>`,
|
||||
{ fetchImpl, allowSystemFontCapture: false },
|
||||
);
|
||||
|
||||
expect(new URL(requestedUrl).searchParams.has("text")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1193,18 +1193,26 @@ export interface InjectDeterministicFontFacesOptions {
|
||||
}
|
||||
|
||||
// Keep the complete CSS request under the broadly supported ~2 KB URL limit.
|
||||
// Using unique source characters covers static text plus strings authored in
|
||||
// scripts, while collapsing repeated prose and base64 assets to a tiny set.
|
||||
// Using unique source/decoded characters plus deterministic case variants covers
|
||||
// static text, strings authored in scripts, and CSS case transforms while
|
||||
// collapsing repeated prose and base64 assets to a tiny set.
|
||||
const GOOGLE_FONTS_TEXT_MAX_ENCODED_LENGTH = 1_700;
|
||||
|
||||
function extractGoogleFontsText(html: string): string | undefined {
|
||||
const { document } = parseHTML(html);
|
||||
const decodedBodyText = document.body?.textContent ?? "";
|
||||
const uniqueCharacters = [...new Set([...Array.from(html), ...Array.from(decodedBodyText)])].join(
|
||||
"",
|
||||
);
|
||||
return encodeURIComponent(uniqueCharacters).length <= GOOGLE_FONTS_TEXT_MAX_ENCODED_LENGTH
|
||||
? uniqueCharacters
|
||||
const characters = [...Array.from(html), ...Array.from(decodedBodyText)];
|
||||
const uniqueCharacters = new Set<string>();
|
||||
for (const character of characters) {
|
||||
uniqueCharacters.add(character);
|
||||
// CSS text-transform can render glyphs absent from the authored source.
|
||||
for (const variant of `${character.toUpperCase()}${character.toLowerCase()}`) {
|
||||
uniqueCharacters.add(variant);
|
||||
}
|
||||
}
|
||||
const fontText = [...uniqueCharacters].join("");
|
||||
return encodeURIComponent(fontText).length <= GOOGLE_FONTS_TEXT_MAX_ENCODED_LENGTH
|
||||
? fontText
|
||||
: undefined;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user