68 lines
2.2 KiB
TypeScript
68 lines
2.2 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { decodeEmbedding, inspectDirectory } from "../../src/core/sfnt";
|
|
|
|
describe("SFNT directory validation", () => {
|
|
it("inventories bounded TrueType tables", () => {
|
|
const report = inspectDirectory(sfnt(["head", "cmap", "OS/2"]));
|
|
expect(report.container).toBe("truetype");
|
|
expect(report.tables.map((table) => table.tag)).toEqual([
|
|
"head",
|
|
"cmap",
|
|
"OS/2",
|
|
]);
|
|
expect(report.tables[2]?.description).toContain("embedding");
|
|
});
|
|
|
|
it("rejects unsupported and out-of-bounds containers before library parsing", () => {
|
|
expect(() => inspectDirectory(signature("wOF2"))).toThrow(/WOFF2/u);
|
|
const invalid = sfnt(["head"]),
|
|
view = new DataView(invalid);
|
|
view.setUint32(12 + 8, invalid.byteLength - 2, false);
|
|
view.setUint32(12 + 12, 12, false);
|
|
expect(() => inspectDirectory(invalid)).toThrow(/file boundary/u);
|
|
});
|
|
});
|
|
|
|
describe("embedding flags", () => {
|
|
it("decodes and enforces subsetting restrictions", () => {
|
|
expect(decodeEmbedding(0).subsetAllowed).toBe(true);
|
|
expect(decodeEmbedding(0x0002).level).toBe("restricted");
|
|
expect(decodeEmbedding(0x0100)).toMatchObject({
|
|
noSubsetting: true,
|
|
subsetAllowed: false,
|
|
});
|
|
expect(decodeEmbedding(0x0208)).toMatchObject({
|
|
level: "editable",
|
|
bitmapOnly: true,
|
|
subsetAllowed: false,
|
|
});
|
|
});
|
|
});
|
|
|
|
function signature(value: string) {
|
|
const bytes = new Uint8Array(4);
|
|
[...value].forEach(
|
|
(character, index) => (bytes[index] = character.charCodeAt(0)),
|
|
);
|
|
return bytes.buffer;
|
|
}
|
|
|
|
function sfnt(tags: string[]) {
|
|
const directoryBytes = 12 + tags.length * 16,
|
|
tableBytes = 12,
|
|
buffer = new ArrayBuffer(directoryBytes + tags.length * tableBytes),
|
|
view = new DataView(buffer);
|
|
view.setUint32(0, 0x0001_0000, false);
|
|
view.setUint16(4, tags.length, false);
|
|
tags.forEach((tag, index) => {
|
|
const base = 12 + index * 16;
|
|
[...tag].forEach((character, offset) =>
|
|
view.setUint8(base + offset, character.charCodeAt(0)),
|
|
);
|
|
view.setUint32(base + 4, index + 1, false);
|
|
view.setUint32(base + 8, directoryBytes + index * tableBytes, false);
|
|
view.setUint32(base + 12, tableBytes, false);
|
|
});
|
|
return buffer;
|
|
}
|