@vyaz/core 0.0.14 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/bin/vyaz.js +27 -0
  2. package/dist/cli/check.d.ts +12 -0
  3. package/dist/cli/check.d.ts.map +1 -0
  4. package/dist/cli/check.js +4077 -0
  5. package/dist/compile/ParagraphCompiler.d.ts +84 -0
  6. package/dist/compile/ParagraphCompiler.d.ts.map +1 -0
  7. package/dist/debug/lines-to-yaml.d.ts +14 -0
  8. package/dist/debug/lines-to-yaml.d.ts.map +1 -0
  9. package/dist/debug.d.ts +11 -0
  10. package/dist/debug.d.ts.map +1 -0
  11. package/dist/debug.js +4 -0
  12. package/dist/index.browser.d.ts +9 -4
  13. package/dist/index.browser.d.ts.map +1 -1
  14. package/dist/index.browser.js +3197 -5025
  15. package/dist/index.d.ts +12 -11
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +4714 -788
  18. package/dist/layout/AutoFitEngine.d.ts.map +1 -1
  19. package/dist/layout/LineBoxValidator.d.ts +5 -10
  20. package/dist/layout/LineBoxValidator.d.ts.map +1 -1
  21. package/dist/layout/ParagraphLayoutEngine.d.ts +13 -8
  22. package/dist/layout/ParagraphLayoutEngine.d.ts.map +1 -1
  23. package/dist/layout/PositioningEngine.d.ts +1 -1
  24. package/dist/layout/PositioningEngine.d.ts.map +1 -1
  25. package/dist/layout/TextFrameLayoutEngine.d.ts +84 -15
  26. package/dist/layout/TextFrameLayoutEngine.d.ts.map +1 -1
  27. package/dist/layout/create-engine.d.ts +32 -0
  28. package/dist/layout/create-engine.d.ts.map +1 -0
  29. package/dist/layout/resolve-font.d.ts +25 -0
  30. package/dist/layout/resolve-font.d.ts.map +1 -0
  31. package/dist/measure/FontEngine.d.ts +44 -1
  32. package/dist/measure/FontEngine.d.ts.map +1 -1
  33. package/dist/measure/FontMetricsProvider.d.ts +3 -10
  34. package/dist/measure/FontMetricsProvider.d.ts.map +1 -1
  35. package/dist/measure/FontkitMeasureContext.d.ts +109 -0
  36. package/dist/measure/FontkitMeasureContext.d.ts.map +1 -0
  37. package/dist/measure/canvas-polyfill.d.ts +7 -2
  38. package/dist/measure/canvas-polyfill.d.ts.map +1 -1
  39. package/dist/types/Document.d.ts +36 -23
  40. package/dist/types/Document.d.ts.map +1 -1
  41. package/dist/types/FontTypes.d.ts +1 -1
  42. package/dist/types/FontTypes.d.ts.map +1 -1
  43. package/dist/types/LayoutTypes.d.ts +19 -2
  44. package/dist/types/LayoutTypes.d.ts.map +1 -1
  45. package/package.json +16 -4
@@ -1 +1 @@
1
- {"version":3,"file":"AutoFitEngine.d.ts","sourceRoot":"","sources":["../../src/layout/AutoFitEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,sBAAsB;AACtB,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAqB;AACrB,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,MAAM,GACZ,SAAS,CAcX;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,SAAS,EACd,QAAQ,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EACrE,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EAC/C,OAAO,CAAC,EAAE,cAAc,GACvB,aAAa,CAoCf"}
1
+ {"version":3,"file":"AutoFitEngine.d.ts","sourceRoot":"","sources":["../../src/layout/AutoFitEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEtD,sBAAsB;AACtB,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,qBAAqB;AACrB,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,SAAS,EACd,KAAK,EAAE,MAAM,GACZ,SAAS,CAgBX;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,SAAS,EACd,QAAQ,EAAE,CAAC,SAAS,EAAE,SAAS,KAAK;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,EACrE,MAAM,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,EAC/C,OAAO,CAAC,EAAE,cAAc,GACvB,aAAa,CAoCf"}
@@ -1,10 +1,11 @@
1
1
  /**
2
- * LineBoxValidator.ts — invariant checks and YAML serialization.
2
+ * LineBoxValidator.ts — Parley-inspired line-box invariant checks.
3
3
  *
4
- * Parley-inspired invariant checks:
5
- * NO_OVERLAP, MONOTONIC_Y, INDEX_CONSIST, WIDTH_FIT, BASELINE_EQ
4
+ * Invariants: NO_OVERLAP, MONOTONIC_Y, INDEX_CONSIST, WIDTH_FIT, BASELINE_EQ.
6
5
  *
7
- * YAML snapshots: semantic data only (no metric noise).
6
+ * YAML snapshot serialization lives in `../debug/lines-to-yaml.ts` (pulled in
7
+ * only through the `@vyaz/core/debug` entry, so `js-yaml` stays out of the
8
+ * production bundle).
8
9
  */
9
10
  import type { Line } from '../types/LayoutTypes.js';
10
11
  export interface InvariantError {
@@ -17,10 +18,4 @@ export interface InvariantError {
17
18
  * Throws on first violation.
18
19
  */
19
20
  export declare function assertLineInvariants(lines: Line[], originalText: string, maxWidth: number): void;
20
- /**
21
- * Convert Line[] to YAML string for snapshots.
22
- * Only semantic data: text, x, width, style.
23
- * No glyphAdvances, fontMetrics (noise), inlineWidget.
24
- */
25
- export declare function linesToYAML(lines: Line[], paragraphWidth: number, paragraphHeight: number): string;
26
21
  //# sourceMappingURL=LineBoxValidator.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"LineBoxValidator.d.ts","sourceRoot":"","sources":["../../src/layout/LineBoxValidator.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,IAAI,EAA2B,MAAM,yBAAyB,CAAC;AAM7E,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,GAAG,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,IAAI,EAAE,EACb,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,IAAI,CAqFN;AAYD;;;;GAIG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,IAAI,EAAE,EACb,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,MAAM,GACtB,MAAM,CAwBR"}
1
+ {"version":3,"file":"LineBoxValidator.d.ts","sourceRoot":"","sources":["../../src/layout/LineBoxValidator.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAMpD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,GAAG,CAAC;CACf;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,IAAI,EAAE,EACb,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,GACf,IAAI,CAqFN"}
@@ -3,21 +3,28 @@
3
3
  *
4
4
  * Pipeline:
5
5
  * Paragraph
6
- * → compile (DocumentCompiler)
6
+ * → compile (ParagraphCompiler)
7
7
  * → prepareRichInline (pretext)
8
8
  * → walkRichInlineLineRanges + materializeRichInlineLineRange (pretext)
9
9
  * → positionLines (PositioningEngine)
10
- * → assertLineInvariants (LineInvariants)
10
+ *
11
+ * Line-box invariant checks live in `@vyaz/core/debug` (assertLineInvariants);
12
+ * they are not run on the layout hot path.
11
13
  *
12
14
  * Supports autofit via AutoFitEngine.findScale.
13
15
  * Caches PreparedRichInline per paragraph key (Parley LayoutContext pattern).
14
16
  */
15
- import '../measure/canvas-polyfill.js';
16
17
  import type { Paragraph, ListStyle } from '../types/Document.js';
17
18
  import type { IFontMetricsProvider } from '../types/FontTypes.js';
18
19
  import type { ParagraphLayoutResult } from '../types/LayoutTypes.js';
20
+ import { type OnMissingFont } from './resolve-font.js';
19
21
  export declare class ParagraphLayoutEngine {
22
+ /** LRU (Map insertion order) of PreparedRichInline keyed by {@link preparedCacheKey}. */
20
23
  private preparedCache;
24
+ private readonly cacheMax;
25
+ constructor(cacheMax?: number);
26
+ /** Drop all cached prepared-line data (e.g. on document close). */
27
+ clearCache(): void;
21
28
  /**
22
29
  * Layout a single paragraph — basic variant.
23
30
  *
@@ -26,12 +33,10 @@ export declare class ParagraphLayoutEngine {
26
33
  * @param fontProvider — optional metrics provider (default: fontMetricsProvider)
27
34
  * @returns ParagraphLayoutResult with Line[]
28
35
  */
29
- layout(paragraph: Paragraph, maxWidth: number, yOffset?: number, fontProvider?: IFontMetricsProvider, listStyle?: ListStyle, listIndex?: number, listMarkerWidth?: number): ParagraphLayoutResult;
36
+ layout(paragraph: Paragraph, maxWidth: number, yOffset?: number, fontProvider?: IFontMetricsProvider, listStyle?: ListStyle, listIndex?: number, listMarkerWidth?: number, wantGlyphAdvances?: boolean, mode?: 'browser' | 'office', onMissingFont?: OnMissingFont): ParagraphLayoutResult;
30
37
  /**
31
- * Layout with per-glyph advance widths (for SVG glyph mode).
32
- *
33
- * glyphAdvances are now filled by layout() automatically, so
34
- * this method is equivalent to layout(). Kept for API compatibility.
38
+ * Layout with per-glyph advance widths filled on every text span
39
+ * (SVG "glyph" preset, caret hit-testing).
35
40
  */
36
41
  layoutGlyph(paragraph: Paragraph, maxWidth: number, yOffset?: number): ParagraphLayoutResult;
37
42
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ParagraphLayoutEngine.d.ts","sourceRoot":"","sources":["../../src/layout/ParagraphLayoutEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,+BAA+B,CAAC;AAEvC,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAqCrE,qBAAa,qBAAqB;IAChC,OAAO,CAAC,aAAa,CAAyC;IAE9D;;;;;;;OAOG;IACH,MAAM,CACJ,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,MAAU,EACnB,YAAY,CAAC,EAAE,oBAAoB,EACnC,SAAS,CAAC,EAAE,SAAS,EACrB,SAAS,CAAC,EAAE,MAAM,EAClB,eAAe,CAAC,EAAE,MAAM,GACvB,qBAAqB;IA+HxB;;;;;OAKG;IACH,WAAW,CACT,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,MAAU,GAClB,qBAAqB;IAIxB;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;CAoC7B;AAED,gBAAgB;AAChB,eAAO,MAAM,qBAAqB,EAAE,qBAAmD,CAAC"}
1
+ {"version":3,"file":"ParagraphLayoutEngine.d.ts","sourceRoot":"","sources":["../../src/layout/ParagraphLayoutEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAEjE,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAClE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAQrE,OAAO,EAAqB,KAAK,aAAa,EAAE,MAAM,mBAAmB,CAAC;AA+E1E,qBAAa,qBAAqB;IAChC,yFAAyF;IACzF,OAAO,CAAC,aAAa,CAAyC;IAC9D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;gBAEtB,QAAQ,GAAE,MAAmC;IAIzD,mEAAmE;IACnE,UAAU,IAAI,IAAI;IAIlB;;;;;;;OAOG;IACH,MAAM,CACJ,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,MAAU,EACnB,YAAY,CAAC,EAAE,oBAAoB,EACnC,SAAS,CAAC,EAAE,SAAS,EACrB,SAAS,CAAC,EAAE,MAAM,EAClB,eAAe,CAAC,EAAE,MAAM,EACxB,iBAAiB,GAAE,OAAe,EAClC,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,EAC3B,aAAa,GAAE,aAAuB,GACrC,qBAAqB;IAgLxB;;;OAGG;IACH,WAAW,CACT,SAAS,EAAE,SAAS,EACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,MAAU,GAClB,qBAAqB;IAIxB;;;;;OAKG;IACH,OAAO,CAAC,oBAAoB;CAoC7B;AAED,gBAAgB;AAChB,eAAO,MAAM,qBAAqB,EAAE,qBAAmD,CAAC"}
@@ -18,7 +18,7 @@
18
18
  import type { ParagraphStyle, ListStyle } from '../types/Document.js';
19
19
  import type { FontMetrics } from '../types/FontTypes.js';
20
20
  import type { Line } from '../types/LayoutTypes.js';
21
- import type { PreparedRichInlineItem } from '../compile/DocumentCompiler.js';
21
+ import type { PreparedRichInlineItem } from '../compile/ParagraphCompiler.js';
22
22
  interface PretextFragment {
23
23
  itemIndex: number;
24
24
  text: string;
@@ -1 +1 @@
1
- {"version":3,"file":"PositioningEngine.d.ts","sourceRoot":"","sources":["../../src/layout/PositioningEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAgB,MAAM,sBAAsB,CAAC;AACpF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,IAAI,EAAyB,MAAM,yBAAyB,CAAC;AAC3E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AAO7E,UAAU,eAAe;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IACvD,GAAG,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;CACtD;AAED,UAAU,WAAW;IACnB,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;CACtD;AA8CD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,aAAa,CAC3B,YAAY,EAAE,WAAW,EAAE,EAC3B,KAAK,EAAE,sBAAsB,EAAE,EAC/B,aAAa,EAAE,CAAC,IAAI,EAAE,sBAAsB,KAAK,WAAW,EAC5D,KAAK,EAAE,cAAc,EACrB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,YAAI,EAClB,IAAI,EAAE,SAAS,GAAG,QAAQ,YAAY,EACtC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,MAAM,EACrH,GAAG,CAAC,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,SAAS,EACrB,SAAS,CAAC,EAAE,MAAM,EAClB,eAAe,CAAC,EAAE,MAAM,GACvB;IAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CA8ezC"}
1
+ {"version":3,"file":"PositioningEngine.d.ts","sourceRoot":"","sources":["../../src/layout/PositioningEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAgB,MAAM,sBAAsB,CAAC;AACpF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,KAAK,EAAE,IAAI,EAAyB,MAAM,yBAAyB,CAAC;AAC3E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,iCAAiC,CAAC;AAK9E,UAAU,eAAe;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;IACvD,GAAG,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;CACtD;AAED,UAAU,WAAW;IACnB,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE;QAAE,YAAY,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAA;KAAE,CAAC;CACtD;AAmDD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,aAAa,CAC3B,YAAY,EAAE,WAAW,EAAE,EAC3B,KAAK,EAAE,sBAAsB,EAAE,EAC/B,aAAa,EAAE,CAAC,IAAI,EAAE,sBAAsB,KAAK,WAAW,EAC5D,KAAK,EAAE,cAAc,EACrB,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,YAAI,EAClB,IAAI,EAAE,SAAS,GAAG,QAAQ,YAAY,EACtC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,KAAK,MAAM,EACrH,GAAG,CAAC,EAAE,MAAM,EACZ,SAAS,CAAC,EAAE,SAAS,EACrB,SAAS,CAAC,EAAE,MAAM,EAClB,eAAe,CAAC,EAAE,MAAM,GACvB;IAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CA6gBzC"}
@@ -21,7 +21,8 @@
21
21
  * 5. If no frame.height, columns are infinite (all lines stay in column 0)
22
22
  */
23
23
  import type { TextFrame } from '../types/Document.js';
24
- import type { Line } from '../types/LayoutTypes.js';
24
+ import type { Line, LayoutWarning } from '../types/LayoutTypes.js';
25
+ import { ParagraphLayoutEngine } from './ParagraphLayoutEngine.js';
25
26
  /**
26
27
  * Result of laying out a full TextFrame.
27
28
  *
@@ -31,21 +32,89 @@ import type { Line } from '../types/LayoutTypes.js';
31
32
  */
32
33
  export interface TextFrameLayoutResult {
33
34
  lines: Line[];
34
- /** Frame width (set when TextFrame.width was provided). */
35
- frameWidth?: number;
36
- /** Frame height (set when TextFrame.height was provided). */
37
- frameHeight?: number;
38
- /** Actual content width (may exceed frameWidth when wrap=false). */
39
- contentWidth: number;
40
- /** Actual content height (may exceed frameHeight). */
41
- contentHeight: number;
42
- /** Whether horizontal dimension should use frame or content size. */
43
- fitHorizontal: 'frame' | 'content';
44
- /** Whether vertical dimension should use frame or content size. */
45
- fitVertical: 'frame' | 'content';
35
+ /** Intrinsic content box the text bounding box. */
36
+ content: {
37
+ width: number;
38
+ height: number;
39
+ };
40
+ /** Frame box as given on the input; an axis is omitted when its size was not set. */
41
+ frame: {
42
+ width?: number;
43
+ height?: number;
44
+ };
45
+ /**
46
+ * Whether content spills past the frame on each axis. `false` for an axis
47
+ * with no frame size. Use it to decide auto-grow vs clip vs autofit.
48
+ */
49
+ overflow: {
50
+ horizontal: boolean;
51
+ vertical: boolean;
52
+ };
53
+ /**
54
+ * Which size a renderer should use per axis: `'frame'` when a frame size was
55
+ * provided, otherwise `'content'`.
56
+ */
57
+ fit: {
58
+ horizontal: 'frame' | 'content';
59
+ vertical: 'frame' | 'content';
60
+ };
61
+ /** Present when autofit ran — the scale applied and whether it bottomed out. */
62
+ autofit?: AutofitOutcome;
63
+ /** Non-fatal issues (font fallback / substitution). Omitted when empty. */
64
+ warnings?: LayoutWarning[];
65
+ }
66
+ /** Options for {@link layoutTextFrame}. */
67
+ export interface LayoutOptions {
68
+ /**
69
+ * Fill `Span.glyphAdvances` on every text span. Needed only by the SVG
70
+ * `glyph` preset and by caret hit-testing; off by default because it costs
71
+ * O(chars) font lookups + allocation on every layout.
72
+ */
73
+ glyphAdvances?: boolean;
74
+ /**
75
+ * Metric mode for this layout, overriding the provider's global mode:
76
+ * - `'browser'` (default) — CSS/Chrome line-box, hhea ascent/descent
77
+ * - `'office'` — PowerPoint/DrawingML line-box, OS/2 winAscent/winDescent
78
+ */
79
+ mode?: 'browser' | 'office';
80
+ /**
81
+ * Shrink every run's `fontSize` proportionally until the content fits the
82
+ * frame box. `true` uses defaults; an object bounds the minimum size.
83
+ * The chosen scale is reported on `result.autofit`.
84
+ */
85
+ autofit?: boolean | {
86
+ minFontSize?: number;
87
+ };
88
+ /**
89
+ * What to do when none of a run's `fontFamily` entries are registered:
90
+ * - `'throw'` (default) — raise `FontNotFoundError`
91
+ * - `'substitute'` — use any registered family and add a `result.warnings`
92
+ * entry instead of failing
93
+ */
94
+ onMissingFont?: 'throw' | 'substitute';
95
+ /**
96
+ * Measure widths through fontkit's `layout()` — GPOS kerning + GSUB ligatures,
97
+ * i.e. what a browser paints — instead of the default per-code-point advance
98
+ * sum. Applies to line breaking and positioning for this call only. Leave off
99
+ * unless the output is consumed by a browser (SVG `browser` preset).
100
+ */
101
+ shaping?: boolean;
102
+ }
103
+ /** Autofit outcome, present on the result when {@link LayoutOptions.autofit} was set. */
104
+ export interface AutofitOutcome {
105
+ /** Proportional font-size scale applied (1 = no shrink). */
106
+ scale: number;
107
+ /** True when the min-size floor was hit and content still overflows. */
108
+ clampedToMin: boolean;
46
109
  }
47
110
  /**
48
- * Layout a full TextFrame by stacking paragraphs with Y offset accumulation.
111
+ * Layout a full TextFrame (paragraphs stacked with Y-offset accumulation).
112
+ *
113
+ * Uses a shared default engine with its own bounded prepared-line cache. For
114
+ * isolation, an explicit cache bound, or `clearCache()`, make your own via
115
+ * {@link createLayoutEngine}.
49
116
  */
50
- export declare function layoutTextFrame(frame: TextFrame): TextFrameLayoutResult;
117
+ export declare function layoutTextFrame(frame: TextFrame, options?: LayoutOptions): TextFrameLayoutResult;
118
+ /** @internal Shared implementation, parameterised by the engine instance. */
119
+ export declare function runFlow(frame: TextFrame, options: LayoutOptions, engine: ParagraphLayoutEngine): TextFrameLayoutResult;
51
120
  //# sourceMappingURL=TextFrameLayoutEngine.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"TextFrameLayoutEngine.d.ts","sourceRoot":"","sources":["../../src/layout/TextFrameLayoutEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,SAAS,EAA2C,MAAM,sBAAsB,CAAC;AAC/F,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,yBAAyB,CAAC;AAKpD;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,2DAA2D;IAC3D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,oEAAoE;IACpE,YAAY,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,aAAa,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,aAAa,EAAE,OAAO,GAAG,SAAS,CAAC;IACnC,mEAAmE;IACnE,WAAW,EAAE,OAAO,GAAG,SAAS,CAAC;CAClC;AAmED;;GAEG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,GAAG,qBAAqB,CAoRvE"}
1
+ {"version":3,"file":"TextFrameLayoutEngine.d.ts","sourceRoot":"","sources":["../../src/layout/TextFrameLayoutEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,KAAK,EAAE,SAAS,EAA2C,MAAM,sBAAsB,CAAC;AAC/F,OAAO,KAAK,EAAE,IAAI,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AACnE,OAAO,EAAyB,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAM1F;;;;;;GAMG;AACH,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,qDAAqD;IACrD,OAAO,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,qFAAqF;IACrF,KAAK,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C;;;OAGG;IACH,QAAQ,EAAE;QAAE,UAAU,EAAE,OAAO,CAAC;QAAC,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAC;IACrD;;;OAGG;IACH,GAAG,EAAE;QAAE,UAAU,EAAE,OAAO,GAAG,SAAS,CAAC;QAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAA;KAAE,CAAC;IACxE,gFAAgF;IAChF,OAAO,CAAC,EAAE,cAAc,CAAC;IACzB,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,aAAa,EAAE,CAAC;CAC5B;AAmED,2CAA2C;AAC3C,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC5B;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C;;;;;OAKG;IACH,aAAa,CAAC,EAAE,OAAO,GAAG,YAAY,CAAC;IACvC;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,yFAAyF;AACzF,MAAM,WAAW,cAAc;IAC7B,4DAA4D;IAC5D,KAAK,EAAE,MAAM,CAAC;IACd,wEAAwE;IACxE,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,GAAE,aAAkB,GAAG,qBAAqB,CAEpG;AAED,6EAA6E;AAC7E,wBAAgB,OAAO,CACrB,KAAK,EAAE,SAAS,EAChB,OAAO,EAAE,aAAa,EACtB,MAAM,EAAE,qBAAqB,GAC5B,qBAAqB,CA0SvB"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * create-engine.ts — a layout engine you own.
3
+ *
4
+ * `layoutTextFrame` is a convenience wrapper over a shared default engine. When
5
+ * you need isolation (a per-document or per-request cache), an explicit cache
6
+ * bound, or the ability to drop the cache, create your own:
7
+ *
8
+ * ```ts
9
+ * const engine = createLayoutEngine({ cache: { max: 1024 } });
10
+ * const result = engine.layout(frame);
11
+ * engine.clearCache(); // e.g. on document close
12
+ * ```
13
+ */
14
+ import type { TextFrame } from '../types/Document.js';
15
+ import type { LayoutOptions, TextFrameLayoutResult } from './TextFrameLayoutEngine.js';
16
+ /** Configuration for {@link createLayoutEngine}. */
17
+ export interface LayoutEngineOptions {
18
+ /** Prepared-line cache bound (LRU entries). Default 4096. */
19
+ cache?: {
20
+ max?: number;
21
+ };
22
+ }
23
+ /** A layout engine with its own prepared-line cache. */
24
+ export interface LayoutEngine {
25
+ /** Lay out a full text frame. Same result shape as {@link layoutTextFrame}. */
26
+ layout(frame: TextFrame, options?: LayoutOptions): TextFrameLayoutResult;
27
+ /** Drop all cached prepared-line data. */
28
+ clearCache(): void;
29
+ }
30
+ /** Create a layout engine with an isolated, bounded prepared-line cache. */
31
+ export declare function createLayoutEngine(options?: LayoutEngineOptions): LayoutEngine;
32
+ //# sourceMappingURL=create-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-engine.d.ts","sourceRoot":"","sources":["../../src/layout/create-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AAGtD,OAAO,KAAK,EAAE,aAAa,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEvF,oDAAoD;AACpD,MAAM,WAAW,mBAAmB;IAClC,6DAA6D;IAC7D,KAAK,CAAC,EAAE;QAAE,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1B;AAED,wDAAwD;AACxD,MAAM,WAAW,YAAY;IAC3B,+EAA+E;IAC/E,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,qBAAqB,CAAC;IACzE,0CAA0C;IAC1C,UAAU,IAAI,IAAI,CAAC;CACpB;AAED,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,mBAAwB,GAAG,YAAY,CAMlF"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * resolve-font.ts — turn a `fontFamily` (single name or CSS-style fallback
3
+ * list) into one concrete registered family, per the `onMissingFont` policy.
4
+ *
5
+ * Everything downstream (positioning, rendering) sees a plain string.
6
+ */
7
+ import type { FontFace } from '../measure/FontEngine.js';
8
+ import type { LayoutWarning } from '../types/LayoutTypes.js';
9
+ /** How to react when none of a run's requested families are registered. */
10
+ export type OnMissingFont = 'throw' | 'substitute';
11
+ /** Minimal provider surface this module needs. */
12
+ export interface FontResolverLike {
13
+ getFont(family: string, weight?: string, style?: string): FontFace | undefined;
14
+ getRegisteredFamilies(): string[];
15
+ }
16
+ export interface ResolvedFamily {
17
+ family: string;
18
+ warning: Omit<LayoutWarning, 'runIndex'> | null;
19
+ }
20
+ /**
21
+ * @param family run's `fontFamily`: a name, or a fallback list
22
+ * @param onMissing policy when nothing matches (default `'throw'`)
23
+ */
24
+ export declare function resolveFontFamily(provider: FontResolverLike, family: string | string[], weight: string, style: string, onMissing?: OnMissingFont): ResolvedFamily;
25
+ //# sourceMappingURL=resolve-font.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-font.d.ts","sourceRoot":"","sources":["../../src/layout/resolve-font.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,2EAA2E;AAC3E,MAAM,MAAM,aAAa,GAAG,OAAO,GAAG,YAAY,CAAC;AAEnD,kDAAkD;AAClD,MAAM,WAAW,gBAAgB;IAC/B,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC/E,qBAAqB,IAAI,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,GAAG,IAAI,CAAC;CACjD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,gBAAgB,EAC1B,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,EACzB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,aAAuB,GACjC,cAAc,CAqBhB"}
@@ -11,6 +11,15 @@
11
11
  * is removed (or when the import is not blocked by stubs).
12
12
  */
13
13
  import type { FontMetrics } from '../types/FontTypes.js';
14
+ /**
15
+ * Factor used when a glyph is not present in the font.
16
+ * Multiplied by fontSize to estimate the missing glyph's advance.
17
+ *
18
+ * Lives here, in the fontkit facade, so every measurement path can share one
19
+ * definition without importing FontMetricsProvider (which installs globals as
20
+ * an import side effect).
21
+ */
22
+ export declare const MISSING_GLYPH_FACTOR = 0.5;
14
23
  /** Opaque font face handle returned by FontEngine.create() */
15
24
  export interface FontFace {
16
25
  /** fontkit font object (private — not meant for direct access) */
@@ -27,9 +36,43 @@ export interface FontFace {
27
36
  * Create a font face from a binary buffer.
28
37
  *
29
38
  * @param buffer Font file bytes (ArrayBuffer in browser, Uint8Array/Buffer in Node.js)
39
+ * @param opts.variation For a variable font, axis values to instance before use
40
+ * (e.g. `{ wght: 700, wdth: 100 }`). Ignored when the font has no axes. Every
41
+ * downstream call — `glyphForCodePoint`, `layout`, metric extraction — then
42
+ * sees the instanced master, matching what a browser renders for that weight.
30
43
  * @returns Opaque FontFace handle
31
44
  */
32
- export declare function createFontFace(buffer: ArrayBuffer | Uint8Array): Promise<FontFace>;
45
+ export declare function createFontFace(buffer: ArrayBuffer | Uint8Array, opts?: {
46
+ variation?: Record<string, number>;
47
+ }): Promise<FontFace>;
48
+ /** One shaped glyph: its id and its post-GPOS advance / offset, in font units. */
49
+ export interface ShapedGlyph {
50
+ glyphId: number;
51
+ xAdvance: number;
52
+ xOffset: number;
53
+ }
54
+ /** Result of {@link shapeRun}: total advance + per-glyph detail, in font units. */
55
+ export interface ShapedRun {
56
+ /** Sum of every glyph's xAdvance after kerning / ligature substitution. */
57
+ advanceWidth: number;
58
+ glyphs: ShapedGlyph[];
59
+ }
60
+ /**
61
+ * Shape `text` through fontkit's OpenType layout engine — the same GPOS kerning
62
+ * and GSUB substitutions (`liga`, `clig`, `calt`, `ccmp`) a browser applies by
63
+ * default. Use this instead of summing {@link getGlyphAdvance} when the measured
64
+ * width has to line up with what the browser will actually paint.
65
+ *
66
+ * Widths are in font units; multiply by `fontSize / unitsPerEm`.
67
+ *
68
+ * @param opts.features OpenType feature overrides, e.g. `{ liga: false }` to
69
+ * emulate `text-rendering: optimizeSpeed`. Omit for browser-default behaviour.
70
+ */
71
+ export declare function shapeRun(font: FontFace, text: string, opts?: {
72
+ features?: Record<string, boolean>;
73
+ script?: string;
74
+ language?: string;
75
+ }): ShapedRun;
33
76
  /**
34
77
  * Get the advance width (in font units) for a single code point.
35
78
  *
@@ -1 +1 @@
1
- {"version":3,"file":"FontEngine.d.ts","sourceRoot":"","sources":["../../src/measure/FontEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAKzD,8DAA8D;AAC9D,MAAM,WAAW,QAAQ;IACvB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC;IACnB,kDAAkD;IAClD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAkDD;;;;;GAKG;AACH,wBAAsB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,UAAU,GAAG,OAAO,CAAC,QAAQ,CAAC,CAQxF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIhF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,WAAW,CAqB7G;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO9D"}
1
+ {"version":3,"file":"FontEngine.d.ts","sourceRoot":"","sources":["../../src/measure/FontEngine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAIzD;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAKxC,8DAA8D;AAC9D,MAAM,WAAW,QAAQ;IACvB,kEAAkE;IAClE,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC;IACnB,kDAAkD;IAClD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CACpC;AAkDD;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,WAAW,GAAG,UAAU,EAChC,IAAI,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CAAE,GAC5C,OAAO,CAAC,QAAQ,CAAC,CAWnB;AAID,kFAAkF;AAClF,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,mFAAmF;AACnF,MAAM,WAAW,SAAS;IACxB,2EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,GAChF,SAAS,CAYX;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAIhF;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,WAAW,CAqB7G;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,OAAO,CAAC,CAO9D"}
@@ -14,11 +14,7 @@
14
14
  */
15
15
  import type { FontMetrics, IFontMetricsProvider } from '../types/FontTypes.js';
16
16
  import type { FontFace } from './FontEngine.js';
17
- /**
18
- * Factor used when a glyph is not found in the font.
19
- * Multiplied by fontSize to estimate the missing glyph width.
20
- */
21
- export declare const MISSING_GLYPH_FACTOR = 0.5;
17
+ export { MISSING_GLYPH_FACTOR } from './FontEngine.js';
22
18
  /**
23
19
  * Font metrics provider — registers, resolves, and measures fonts.
24
20
  *
@@ -58,10 +54,6 @@ export declare class FontMetricsProvider implements IFontMetricsProvider {
58
54
  setMode(mode: 'browser' | 'office'): void;
59
55
  /** Get current measurement mode. */
60
56
  getMode(): 'browser' | 'office';
61
- /**
62
- * @internal Flatten the nested registry for office mode.
63
- */
64
- private _flattenCache;
65
57
  /**
66
58
  * Register a binary font for use with fontkit.
67
59
  *
@@ -75,6 +67,7 @@ export declare class FontMetricsProvider implements IFontMetricsProvider {
75
67
  registerFont(family: string, options: {
76
68
  weight?: string;
77
69
  style?: string;
70
+ variation?: Record<string, number>;
78
71
  }, source: string | ArrayBuffer | Uint8Array, sourcePath?: string): Promise<void>;
79
72
  /** @internal Internal registration logic */
80
73
  private _registerFontInternal;
@@ -117,7 +110,7 @@ export declare class FontMetricsProvider implements IFontMetricsProvider {
117
110
  *
118
111
  * @throws FontNotFoundError when font is neither registered nor available via Canvas
119
112
  */
120
- getMetrics(fontFamily: string, fontSize: number, weight?: string, style?: string): FontMetrics;
113
+ getMetrics(fontFamily: string, fontSize: number, weight?: string, style?: string, mode?: 'browser' | 'office'): FontMetrics;
121
114
  }
122
115
  /** Singleton */
123
116
  export declare const fontMetricsProvider: FontMetricsProvider;
@@ -1 +1 @@
1
- {"version":3,"file":"FontMetricsProvider.d.ts","sourceRoot":"","sources":["../../src/measure/FontMetricsProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAMhD;;;GAGG;AACH,eAAO,MAAM,oBAAoB,MAAM,CAAC;AAyExC;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,mBAAoB,YAAW,oBAAoB;IAC9D,gEAAgE;IAChE,OAAO,CAAC,QAAQ,CAA4C;IAE5D,gEAAgE;IAChE,OAAO,CAAC,YAAY,CAAkC;IAEtD,gBAAgB;IAChB,OAAO,CAAC,IAAI,CAAmC;IAE/C,qFAAqF;IACrF,OAAO,CAAC,oBAAoB,CAA4B;IAExD,2EAA2E;IAC3E,OAAO,CAAC,cAAc,CAAoD;IAC1E,gBAAgB;IAChB,OAAO,CAAC,WAAW,CAA6E;IAEhG,wDAAwD;IACxD,OAAO,CAAC,kBAAkB;IAe1B;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,IAAI;IAWzC,oCAAoC;IACpC,OAAO,IAAI,SAAS,GAAG,QAAQ;IAI/B;;OAEG;IACH,OAAO,CAAC,aAAa;IAYrB;;;;;;;;;OASG;IACG,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,EAC5C,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,EACzC,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC;IAUhB,4CAA4C;YAC9B,qBAAqB;IAmCnC;;;;;OAKG;IACG,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC;IAMlD;;;;OAIG;IACH,qBAAqB,IAAI,MAAM,EAAE;IAIjC;;;;;OAKG;IACH,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;IAO3C;;;OAGG;IACH,OAAO,CACL,MAAM,EAAE,MAAM,EACd,MAAM,SAAW,EACjB,KAAK,SAAW,GACf,QAAQ,GAAG,SAAS;IAMvB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAsEpB;;;;;;;;OAQG;IACH,UAAU,CACR,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,SAAW,EACjB,KAAK,SAAW,GACf,WAAW;CA6Ef;AAED,gBAAgB;AAChB,eAAO,MAAM,mBAAmB,EAAE,mBAA+C,CAAC"}
1
+ {"version":3,"file":"FontMetricsProvider.d.ts","sourceRoot":"","sources":["../../src/measure/FontMetricsProvider.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC/E,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAQhD,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAyEvD;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,mBAAoB,YAAW,oBAAoB;IAC9D,gEAAgE;IAChE,OAAO,CAAC,QAAQ,CAA4C;IAE5D,gEAAgE;IAChE,OAAO,CAAC,YAAY,CAAkC;IAEtD,gBAAgB;IAChB,OAAO,CAAC,IAAI,CAAmC;IAE/C,qFAAqF;IACrF,OAAO,CAAC,oBAAoB,CAA4B;IAExD,2EAA2E;IAC3E,OAAO,CAAC,cAAc,CAAoD;IAC1E,gBAAgB;IAChB,OAAO,CAAC,WAAW,CAA6E;IAEhG,wDAAwD;IACxD,OAAO,CAAC,kBAAkB;IAe1B;;;;OAIG;IACH,OAAO,CAAC,IAAI,EAAE,SAAS,GAAG,QAAQ,GAAG,IAAI;IASzC,oCAAoC;IACpC,OAAO,IAAI,SAAS,GAAG,QAAQ;IAM/B;;;;;;;;;OASG;IACG,YAAY,CAChB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;KAAE,EAChF,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,UAAU,EACzC,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAAC,IAAI,CAAC;IAUhB,4CAA4C;YAC9B,qBAAqB;IAmCnC;;;;;OAKG;IACG,2BAA2B,IAAI,OAAO,CAAC,IAAI,CAAC;IAMlD;;;;OAIG;IACH,qBAAqB,IAAI,MAAM,EAAE;IAIjC;;;;;OAKG;IACH,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE;IAO3C;;;OAGG;IACH,OAAO,CACL,MAAM,EAAE,MAAM,EACd,MAAM,SAAW,EACjB,KAAK,SAAW,GACf,QAAQ,GAAG,SAAS;IAMvB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAsEpB;;;;;;;;OAQG;IACH,UAAU,CACR,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,MAAM,SAAW,EACjB,KAAK,SAAW,EAChB,IAAI,CAAC,EAAE,SAAS,GAAG,QAAQ,GAC1B,WAAW;CAgFf;AAED,gBAAgB;AAChB,eAAO,MAAM,mBAAmB,EAAE,mBAA+C,CAAC"}
@@ -0,0 +1,109 @@
1
+ /**
2
+ * FontkitMeasureContext.ts — the measurement seam for vendored pretext.
3
+ *
4
+ * `src/vendor/pretext/measurement.js` calls `getMeasureContext()` from this
5
+ * module instead of reaching for a canvas 2d context. That is the whole
6
+ * integration: pretext only ever uses two members of the object it gets back —
7
+ * `ctx.font = "..."` and `ctx.measureText(s).width` — so the contract is tiny.
8
+ * It draws nothing, and it reads no other property (letter-spacing is pretext's
9
+ * own arithmetic, not the canvas attribute).
10
+ *
11
+ * Backends:
12
+ *
13
+ * - fontkit (the default; installed by `ParagraphLayoutEngine` at module load
14
+ * via `setMeasureContext(createFontkitMeasureContext(...))`) — measures from
15
+ * the font tables. Same per-code-point advances and missing-glyph policy as
16
+ * glyph positioning, so line breaking and positioning agree.
17
+ * - canvas (`createCanvasMeasureContext`) — pretext's original behaviour, kept
18
+ * only as a browser-only escape hatch via `setMeasureContext(null)`. It
19
+ * needs a real `OffscreenCanvas`/`document`; in Node/Bun it now throws
20
+ * rather than pulling a canvas polyfill.
21
+ *
22
+ * Shaping (kerning, ligatures via `font.layout()`) is a separate, later change.
23
+ * Landing it at the same time would make the snapshot delta unreadable.
24
+ */
25
+ import type { FontFace } from './FontEngine.js';
26
+ /**
27
+ * The slice of `CanvasRenderingContext2D` that pretext actually consumes.
28
+ */
29
+ export interface MeasureContextLike {
30
+ font: string;
31
+ measureText(text: string): {
32
+ width: number;
33
+ };
34
+ }
35
+ /**
36
+ * Font lookup, structurally satisfied by `FontMetricsProvider`.
37
+ * Kept minimal so this module does not depend on the provider.
38
+ */
39
+ export interface FontResolver {
40
+ getFont(family: string, weight?: string, style?: string): FontFace | undefined;
41
+ }
42
+ /**
43
+ * How widths are computed from the font tables.
44
+ *
45
+ * - `'advance'` (default) — Σ per-code-point `advanceWidth`. Fast, and
46
+ * shaping-invariant, but ignores kerning and ligatures, so it drifts from
47
+ * what a browser paints (up to a few px per word on a kerned Latin font).
48
+ * - `'shape'` — fontkit `layout()` advance: GPOS kerning + GSUB (`liga`,
49
+ * `clig`, `calt`, `ccmp`), i.e. browser-default behaviour. Use for the SVG
50
+ * `browser` preset when on-screen width has to match the layout.
51
+ */
52
+ export interface MeasureProfile {
53
+ engine: 'advance' | 'shape';
54
+ /** `'shape'` only — OpenType feature overrides, e.g. `{ liga: false }`. */
55
+ features?: Record<string, boolean>;
56
+ }
57
+ /**
58
+ * Register a callback fired whenever {@link setMeasureProfile} changes the
59
+ * profile — used to drop pretext's per-segment width cache, which is keyed by
60
+ * text only and would otherwise serve `advance` widths to a `shape` layout.
61
+ */
62
+ export declare function setProfileChangeHook(fn: (() => void) | null): void;
63
+ /** Install the measurement profile used by every fontkit-backed measure path. */
64
+ export declare function setMeasureProfile(next: MeasureProfile): void;
65
+ /** The active measurement profile. */
66
+ export declare function getMeasureProfile(): MeasureProfile;
67
+ /**
68
+ * Install the measure context pretext will use.
69
+ *
70
+ * Pass `null` to fall back to canvas. Takes effect on the next measurement —
71
+ * unlike upstream, nothing is latched, so this is safe to flip in tests.
72
+ */
73
+ export declare function setMeasureContext(ctx: MeasureContextLike | null): void;
74
+ /** The currently installed context, or `null` when on the canvas fallback. */
75
+ export declare function getInstalledMeasureContext(): MeasureContextLike | null;
76
+ /**
77
+ * Called by vendored pretext on every measurement.
78
+ *
79
+ * Resolution is lazy and per-call rather than latched at module init, so there
80
+ * is no installation order to get wrong and no window in which a worker thread
81
+ * measures through the wrong backend.
82
+ */
83
+ export declare function getMeasureContext(): MeasureContextLike;
84
+ /**
85
+ * Reproduces pretext's original `getMeasureContext()`. Browser-only: needs a
86
+ * real `OffscreenCanvas` or `document`. Only reached after an explicit
87
+ * `setMeasureContext(null)`; the fontkit backend is the default everywhere.
88
+ */
89
+ export declare function createCanvasMeasureContext(): MeasureContextLike;
90
+ /**
91
+ * Build a measure context backed by the font tables.
92
+ *
93
+ * @param resolver - font lookup, normally the shared `fontMetricsProvider`
94
+ */
95
+ /**
96
+ * Pixel width of `text` under `profile`. Shared by the pretext measure context
97
+ * and `ParagraphLayoutEngine`'s fragment measurement so line breaking and
98
+ * positioning never disagree.
99
+ *
100
+ * - `advance` — Σ per-code-point `advanceWidth`, surrogate-aware, with the
101
+ * `MISSING_GLYPH_FACTOR · fontSize` estimate for absent glyphs.
102
+ * - `shape` — fontkit `layout()` advance (kerning + ligatures). Missing
103
+ * glyphs there fall back to the same per-code-point estimate for the
104
+ * stretch that produced no advance, so the two profiles agree on
105
+ * un-shapeable text.
106
+ */
107
+ export declare function measurePx(raw: any, scale: number, fontSize: number, text: string, prof?: MeasureProfile): number;
108
+ export declare function createFontkitMeasureContext(resolver: FontResolver): MeasureContextLike;
109
+ //# sourceMappingURL=FontkitMeasureContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FontkitMeasureContext.d.ts","sourceRoot":"","sources":["../../src/measure/FontkitMeasureContext.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAMhD;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9C;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;CAChF;AAID;;;;;;;;;GASG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAKD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI,CAElE;AAED,iFAAiF;AACjF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI,CAI5D;AAED,sCAAsC;AACtC,wBAAgB,iBAAiB,IAAI,cAAc,CAElD;AAOD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,kBAAkB,GAAG,IAAI,GAAG,IAAI,CAEtE;AAED,8EAA8E;AAC9E,wBAAgB,0BAA0B,IAAI,kBAAkB,GAAG,IAAI,CAEtE;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,IAAI,kBAAkB,CAItD;AAID;;;;GAIG;AACH,wBAAgB,0BAA0B,IAAI,kBAAkB,CAW/D;AAqDD;;;;GAIG;AACH;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CACvB,GAAG,EAAE,GAAG,EACR,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE,cAAwB,GAC7B,MAAM,CA8BR;AAED,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,YAAY,GAAG,kBAAkB,CA+CtF"}
@@ -11,8 +11,13 @@
11
11
  * Exports enableOfficeTextMeasure / disableOfficeTextMeasure —
12
12
  * ctx.measureText override for FontEngine-based measurements in Office mode.
13
13
  *
14
- * ⚠️ All Node.js built-in module imports are dynamic (lazy) to avoid
15
- * Vite/Webpack externalization errors in browser builds.
14
+ * ⚠️ Node.js built-in module access is synchronous via process.getBuiltinModule
15
+ * (Node ≥20.16 / ≥22, Bun ≥1.1) to avoid top-level await race conditions
16
+ * in worker threads (e.g. Piscina). The previous implementation used
17
+ * `await import('module')` which created a race window where layoutTextFrame
18
+ * could be called before the polyfill initialised, returning 0×0.
19
+ *
20
+ * @see https://nodejs.org/api/process.html#processgetbuiltinmoduleid
16
21
  */
17
22
  /**
18
23
  * Register a font with @napi-rs/canvas so ctx.measureText() works in Node.js.
@@ -1 +1 @@
1
- {"version":3,"file":"canvas-polyfill.d.ts","sourceRoot":"","sources":["../../src/measure/canvas-polyfill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAwLH;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAUzE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CASzE;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAS/C"}
1
+ {"version":3,"file":"canvas-polyfill.d.ts","sourceRoot":"","sources":["../../src/measure/canvas-polyfill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAwNH;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAUzE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CASzE;AAED;;GAEG;AACH,wBAAgB,wBAAwB,IAAI,IAAI,CAS/C"}