diff --git a/src/entities/Font/lib/dualFontLayout/DualFontLayout/DualFontLayout.ts b/src/entities/Font/lib/dualFontLayout/DualFontLayout/DualFontLayout.ts index 29e43e9..a572979 100644 --- a/src/entities/Font/lib/dualFontLayout/DualFontLayout/DualFontLayout.ts +++ b/src/entities/Font/lib/dualFontLayout/DualFontLayout/DualFontLayout.ts @@ -9,43 +9,6 @@ import { */ const DEFAULT_RENDER_SIZE_PX = 16; -/** - * Internal shape of pretext's PreparedTextWithSegments — only `segments` is in - * pretext's public TS type; the numeric arrays exist at runtime but are not in - * the published signature. Verified against node_modules/@chenglou/pretext/src/layout.ts. - */ -interface PretextInternals { - /** - * Per-segment text. - */ - segments: string[]; - /** - * Per-segment full width in pixels. - */ - widths: number[]; - /** - * Per-segment per-grapheme advance widths, or null when the segment is a single grapheme. - */ - breakableFitAdvances: (number[] | null)[]; - /** - * Per-segment line-end fit advance. - */ - lineEndFitAdvances: number[]; - /** - * Per-segment line-end paint advance. - */ - lineEndPaintAdvances: number[]; -} - -/** - * Asserts pretext's runtime shape. The public TS type exposes only `segments`; - * the numeric arrays exist at runtime but are absent from the published signature. - * Centralizing the cast keeps the engine body free of `as any`. - */ -function asPretextInternals(prepared: PreparedTextWithSegments): PretextInternals { - return prepared as unknown as PretextInternals; -} - /** * Per-grapheme data computed during dual-font layout. Internal to the engine; * consumed by computeLineRenderModel to derive the per-frame render model. @@ -114,6 +77,10 @@ export interface ComparisonResult { * of font A and font B. This guarantees that both fonts wrap at exactly the same * positions, making side-by-side or slider comparison visually coherent. * + * Relies on pretext's published structural fields on `PreparedTextWithSegments` + * (`widths`, `breakableFitAdvances`, `lineEndFitAdvances`, `lineEndPaintAdvances`) + * which are exposed via the `PreparedCore` intersection in `@chenglou/pretext@0.0.6`. + * * **Two-level caching strategy** * 1. Font-change cache (`#preparedA`, `#preparedB`, `#unifiedPrepared`): rebuilt only * when `text`, `fontA`, or `fontB` changes. `prepareWithSegments` is expensive @@ -129,9 +96,9 @@ export class DualFontLayout { #segmenter: Intl.Segmenter; // Cached prepared data - #preparedA: PretextInternals | null = null; - #preparedB: PretextInternals | null = null; - #unifiedPrepared: PretextInternals | null = null; + #preparedA: PreparedTextWithSegments | null = null; + #preparedB: PreparedTextWithSegments | null = null; + #unifiedPrepared: PreparedTextWithSegments | null = null; #lastText = ''; #lastFontA = ''; @@ -192,8 +159,8 @@ export class DualFontLayout { // 1. Prepare (or use cache) if (isFontChange) { - this.#preparedA = asPretextInternals(prepareWithSegments(text, fontA)); - this.#preparedB = asPretextInternals(prepareWithSegments(text, fontB)); + this.#preparedA = prepareWithSegments(text, fontA); + this.#preparedB = prepareWithSegments(text, fontB); this.#unifiedPrepared = this.#createUnifiedPrepared(this.#preparedA, this.#preparedB, spacingPx); this.#lastText = text; @@ -207,13 +174,7 @@ export class DualFontLayout { return { lines: [], totalHeight: 0 }; } - // pretext's `layoutWithLines` is typed against its public surface; pass the - // runtime-internal shape through with one boundary cast. - const { lines, height } = layoutWithLines( - this.#unifiedPrepared as unknown as PreparedTextWithSegments, - width, - lineHeight, - ); + const { lines, height } = layoutWithLines(this.#unifiedPrepared, width, lineHeight); // 3. Map results back to both fonts const preparedA = this.#preparedA; @@ -284,11 +245,11 @@ export class DualFontLayout { * across both fonts, with `spacingPx` added to model letter-spacing. */ #createUnifiedPrepared( - a: PretextInternals, - b: PretextInternals, + a: PreparedTextWithSegments, + b: PreparedTextWithSegments, spacingPx: number = 0, - ): PretextInternals { - const unified: PretextInternals = { ...a }; + ): PreparedTextWithSegments { + const unified: PreparedTextWithSegments = { ...a }; unified.widths = a.widths.map((w, i) => Math.max(w, b.widths[i]) + spacingPx); unified.lineEndFitAdvances = a.lineEndFitAdvances.map((w, i) =>