@unmade/text-renderer 1.2.0 → 1.3.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.
@@ -0,0 +1,77 @@
1
+ import { LoadedFont } from '../loading';
2
+ import { PathEntry } from '../rendering';
3
+ import { BaselineConfig, BaselineType, BoxDimensions, ColourMap, HorizontalTextAlignmentValues, MeasurementUnits, PhysicalSize, TextSpacing, VerticalTextAlignmentValues } from '../types';
4
+ export interface LayoutTextOptions {
5
+ font: LoadedFont;
6
+ text: string;
7
+ boxDimensions: BoxDimensions;
8
+ physicalSize: PhysicalSize;
9
+ /** When provided, bypasses the physicalSize → font size calculation. */
10
+ fontSize?: number;
11
+ spacing?: TextSpacing;
12
+ baseline?: BaselineType | BaselineConfig;
13
+ horizontalAlignment?: HorizontalTextAlignmentValues;
14
+ verticalAlignment?: VerticalTextAlignmentValues;
15
+ colourMap?: ColourMap;
16
+ }
17
+ export interface TextLayout {
18
+ fontSize: number;
19
+ /** Lines as laid out — curved and custom baselines collapse to one. */
20
+ lines: string[];
21
+ /** Every glyph, positioned. Rendering draws these; measuring bounds them. */
22
+ paths: PathEntry[];
23
+ spacing: TextSpacing;
24
+ tallestHeight: number;
25
+ totalHeight: number;
26
+ maxBaseline: number;
27
+ }
28
+ /**
29
+ * Position every glyph of `text` within `boxDimensions`.
30
+ *
31
+ * Shared by rendering and measuring so the two cannot disagree: what gets
32
+ * measured is the same set of positioned glyphs that gets drawn. The
33
+ * configuration engine has two independent measurement paths that have drifted
34
+ * apart over time, which is the outcome this exists to prevent.
35
+ */
36
+ export declare const layoutText: (options: LayoutTextOptions) => TextLayout;
37
+ export interface MeasuredLine {
38
+ text: string;
39
+ width: number;
40
+ height: number;
41
+ baseline: number;
42
+ }
43
+ export interface TextMeasurement {
44
+ fontSize: number;
45
+ /** Bounds of the drawn glyphs, in the box's pixel coordinates. */
46
+ bbox: {
47
+ x: number;
48
+ y: number;
49
+ width: number;
50
+ height: number;
51
+ };
52
+ physicalWidth: number;
53
+ physicalHeight: number;
54
+ physicalUnits: MeasurementUnits;
55
+ /**
56
+ * Physical height of a standard capital at this font size — the cap height.
57
+ *
58
+ * Not derivable from `physicalHeight`: that measures the glyphs actually
59
+ * present, so it moves with descenders and accents, whereas cap height is a
60
+ * property of the font and size alone. It is persisted with the design and
61
+ * reaches the factory, so it has to be reported rather than inferred.
62
+ */
63
+ physicalCapHeight: number;
64
+ lines: MeasuredLine[];
65
+ }
66
+ /**
67
+ * Measure text as it would be drawn.
68
+ *
69
+ * Bounds the same positioned glyphs `renderText` draws, rather than
70
+ * re-deriving dimensions from font metrics — so a measurement can't disagree
71
+ * with the artwork it describes. In particular a curved line's bounds follow
72
+ * the arch, which a flat metrics calculation cannot know about.
73
+ *
74
+ * Throws where `renderText` would throw, for the same reasons. If this
75
+ * succeeds, rendering the same options will too.
76
+ */
77
+ export declare const measureText: (options: LayoutTextOptions) => TextMeasurement;
@@ -1,5 +1,8 @@
1
1
  import { RenderTextOptions } from './types';
2
2
  /**
3
3
  * Synchronous text renderer. Requires a pre-loaded font.
4
+ *
5
+ * Positioning lives in layoutText, shared with measureText so that what is
6
+ * measured is the same set of glyphs that gets drawn.
4
7
  */
5
8
  export declare const renderText: (options: RenderTextOptions) => string;
@@ -1,5 +1,8 @@
1
1
  import { RenderTextOptions } from './types';
2
2
  /**
3
3
  * Synchronous text renderer. Requires a pre-loaded font.
4
+ *
5
+ * Positioning lives in layoutText, shared with measureText so that what is
6
+ * measured is the same set of glyphs that gets drawn.
4
7
  */
5
8
  export declare const renderText: (options: RenderTextOptions) => string;
@@ -67,9 +67,9 @@ export interface FitAndTruncateTextToBoxResult extends FitTextToBoxResult {
67
67
  /**
68
68
  * Calculate the font size at which `text` fills `boxDimensions` as closely
69
69
  * as possible without overflowing, for any baseline shape. This replaces
70
- * binary-searching for a fitting font size: for flat and custom baselines
71
- * it's a direct O(1) calculation; for curved baselines it's a bounded
72
- * numeric solve (see solveCurvedFit).
70
+ * binary-searching for a fitting font size: flat and custom baselines are
71
+ * solved in one step, from a single measurement, while curved baselines need
72
+ * a bounded numeric solve (see solveCurvedFit).
73
73
  *
74
74
  * `fits: false` means the text doesn't fit even at minFontSize — the caller
75
75
  * (e.g. fitAndTruncateTextToBox) should either shorten the text or accept
@@ -3,6 +3,7 @@ export { type GenerateCurvedBaselineOptions, type GenerateFlatBaselineOptions, g
3
3
  export { DEFAULT_OUTLINE_FACTOR, DEFAULT_SPACING, LINE_HEIGHT, } from './constants';
4
4
  export { type FitAndTruncateTextToBoxResult, type FitConstraint, type FitSize, type FitTextToBoxOptions, type FitTextToBoxResult, fitAndTruncateTextToBox, getFontSizeToFitBox, } from './fitting';
5
5
  export { getFontColours } from './glyph/svg-glyph-converter';
6
+ export { type LayoutTextOptions, layoutText, type MeasuredLine, measureText, type TextLayout, type TextMeasurement, } from './layout';
6
7
  export { getFontCache, type LoadedFont, loadFont } from './loading';
7
8
  export { type GetFontSizeFromPhysicalSizeOptions, type GetTextMetricsAtFontSizeOptions, getFontSizeFromPhysicalSize, getTextMetricsAtFontSize, } from './measuring';
8
9
  export type { GetTextAsPathDataOptions, SvgGlyphEntry } from './rendering';