refactor(Font): use pretext layout() directly in row size resolver

createFontRowSizeResolver was reaching into TextLayoutEngine, which
internally called pretext's heavy layoutWithLines and then walked
per-grapheme cursors to build chars arrays. The resolver discarded all
that work and used only totalHeight.

Replace with direct prepare + layout from @chenglou/pretext — pretext
docs explicitly recommend layout() (not layoutWithLines) for the resize
hot path: pure arithmetic on cached segment widths, no canvas calls, no
string allocations.

Test spies on TextLayoutEngine.prototype.layout migrated to vi.mock-ed
pretext layout (pretext's ESM exports are frozen — vi.spyOn fails with
"Cannot redefine property").

TextLayoutEngine marked @deprecated since it has no remaining
consumers; slated for removal after a release cycle.
This commit is contained in:
Ilia Mashkov
2026-05-24 20:12:48 +03:00
parent 728380498b
commit f92577608a
3 changed files with 36 additions and 10 deletions
@@ -1,7 +1,19 @@
// @vitest-environment jsdom
import { TextLayoutEngine } from '$shared/lib';
import { installCanvasMock } from '$shared/lib/helpers/__mocks__/canvas';
import { clearCache } from '@chenglou/pretext';
import {
clearCache,
layout,
} from '@chenglou/pretext';
// Wrap pretext's `layout` in a spy-able mock so tests can assert call counts.
// `vi.mock` is hoisted, so the import above receives the mocked module.
vi.mock('@chenglou/pretext', async () => {
const actual = await vi.importActual<typeof import('@chenglou/pretext')>('@chenglou/pretext');
return {
...actual,
layout: vi.fn(actual.layout),
};
});
import {
beforeEach,
describe,
@@ -112,13 +124,13 @@ describe('createFontRowSizeResolver', () => {
const { resolver } = makeResolver();
statusMap.set('inter@400', 'loaded');
const layoutSpy = vi.spyOn(TextLayoutEngine.prototype, 'layout');
const layoutSpy = vi.mocked(layout);
layoutSpy.mockClear();
resolver(0);
resolver(0);
expect(layoutSpy).toHaveBeenCalledTimes(1);
layoutSpy.mockRestore();
});
it('calls layout() again when containerWidth changes (cache miss)', () => {
@@ -126,14 +138,14 @@ describe('createFontRowSizeResolver', () => {
const { resolver } = makeResolver({ getContainerWidth: () => width });
statusMap.set('inter@400', 'loaded');
const layoutSpy = vi.spyOn(TextLayoutEngine.prototype, 'layout');
const layoutSpy = vi.mocked(layout);
layoutSpy.mockClear();
resolver(0);
width = 100;
resolver(0);
expect(layoutSpy).toHaveBeenCalledTimes(2);
layoutSpy.mockRestore();
});
it('returns greater height when container narrows (more wrapping)', () => {