@weasel-js/text 1.9.3 → 1.10.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.
- package/README.md +11 -9
- package/dist/{chunk-L6UJ4RQK.js → chunk-Z6YRJ33J.js} +481 -649
- package/dist/chunk-Z6YRJ33J.js.map +1 -0
- package/dist/index.d.ts +519 -52
- package/dist/index.js +796 -21
- package/dist/index.js.map +1 -1
- package/dist/{test-seams-DbGu8K5F.d.ts → test-seams-CuLNcDew.d.ts} +214 -348
- package/dist/test-seams.d.ts +1 -1
- package/dist/test-seams.js +1 -1
- package/package.json +6 -5
- package/dist/chunk-L6UJ4RQK.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ScreenLength,
|
|
2
|
-
import { FaceMetrics, FontStyle,
|
|
1
|
+
import { ScreenLength, Fill, Stroke } from '@weasel-js/paint';
|
|
2
|
+
import { FaceMetrics, FontStyle, ResolveResult, GlyphMetrics, BmFont, BmFontChar } from '@weasel-js/font';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* CSS `text-transform` over styled runs: `uppercase`, `lowercase` and
|
|
@@ -113,7 +113,9 @@ interface StyledRun {
|
|
|
113
113
|
/** World units, or `{ px }` for screen pixels — resolved against the view
|
|
114
114
|
* scale `resolveRuns` is given, like `TextStyle.fontSize`. */
|
|
115
115
|
fontSize?: ScreenLength;
|
|
116
|
-
fill
|
|
116
|
+
/** This run's ink. `null` is no fill at all, leaving the glyphs to `stroke`
|
|
117
|
+
* alone; absent inherits the node's. */
|
|
118
|
+
fill?: Fill | null;
|
|
117
119
|
/** Outline over this run's glyphs. Overrides the node's own `data.stroke`;
|
|
118
120
|
* absent inherits it. Only painted on the outline tier. */
|
|
119
121
|
stroke?: Stroke;
|
|
@@ -214,15 +216,12 @@ declare function runsToMarkdown(runs: readonly StyledRun[], grammar?: RunGrammar
|
|
|
214
216
|
declare function markdownToRuns(input: string, grammar?: RunGrammar): StyledRun[];
|
|
215
217
|
|
|
216
218
|
/**
|
|
217
|
-
* Typography for `TextPose` and friends.
|
|
218
|
-
* pass `{}` or override the few they care about. Defaults live in
|
|
219
|
+
* Typography for `TextPose` and friends. Defaults live in
|
|
219
220
|
* `DEFAULT_TEXT_STYLE` and are applied at render/measure time, never written
|
|
220
221
|
* back to the pose.
|
|
221
222
|
*
|
|
222
|
-
* Paint
|
|
223
|
-
*
|
|
224
|
-
* kind uses; `resolveTextStyle` takes them as its second argument and
|
|
225
|
-
* `StyledRun.fill` / `.stroke` override them per range.
|
|
223
|
+
* Paint does not live here. A text node carries its fill and stroke in
|
|
224
|
+
* `data.fill` / `data.stroke`, the slots every other node kind uses.
|
|
226
225
|
*/
|
|
227
226
|
|
|
228
227
|
/**
|
|
@@ -236,11 +235,9 @@ type TextAlign = 'left' | 'center' | 'right' | 'start' | 'end' | 'justify';
|
|
|
236
235
|
type TextDirection = 'ltr' | 'rtl';
|
|
237
236
|
/**
|
|
238
237
|
* Collapse a possibly reading-order-relative alignment to an absolute edge.
|
|
239
|
-
*
|
|
240
|
-
*
|
|
241
|
-
* `
|
|
242
|
-
* is where it sets every line it does not spread; whether to spread is carried
|
|
243
|
-
* separately, as `LayoutRunsOpts.justify`.
|
|
238
|
+
* `justify` collapses to the start edge, which is where it sets every line it
|
|
239
|
+
* does not spread; whether to spread is carried separately, as
|
|
240
|
+
* `LayoutRunsOpts.justify`.
|
|
244
241
|
*/
|
|
245
242
|
declare function resolveAlign(align: TextAlign, direction: TextDirection): 'left' | 'center' | 'right';
|
|
246
243
|
/** User-facing text style. All fields optional; defaults applied at render time via `resolveTextStyle`. */
|
|
@@ -259,10 +256,16 @@ interface TextStyle {
|
|
|
259
256
|
fontStyle?: 'normal' | 'italic';
|
|
260
257
|
/** Default `'left'`. Pass `'start'` to align by reading order instead. */
|
|
261
258
|
align?: TextAlign;
|
|
262
|
-
/**
|
|
263
|
-
|
|
259
|
+
/**
|
|
260
|
+
* Reading direction: the base direction of bidi reordering, and what
|
|
261
|
+
* `align: 'start' | 'end'` resolve against. Default `'auto'`, each
|
|
262
|
+
* paragraph's own first strong character.
|
|
263
|
+
*/
|
|
264
|
+
direction?: TextDirection | 'auto';
|
|
264
265
|
/** Multiplier applied to `fontSize`. Default 1.2. */
|
|
265
266
|
lineHeight?: number;
|
|
267
|
+
/** Distance between tab stops, in spaces, as CSS `tab-size`. Default 8. */
|
|
268
|
+
tabSize?: number;
|
|
266
269
|
/**
|
|
267
270
|
* Break lines where they would pass the box width, at the break
|
|
268
271
|
* opportunities of Unicode's line breaking algorithm (UAX #14) — between
|
|
@@ -301,9 +304,8 @@ interface TextStyle {
|
|
|
301
304
|
fontVariantCaps?: FontVariantCaps;
|
|
302
305
|
/**
|
|
303
306
|
* Set the node's text as a superscript or subscript — the default every run
|
|
304
|
-
* inherits
|
|
305
|
-
*
|
|
306
|
-
* Absent is ordinary text.
|
|
307
|
+
* inherits. The lines keep the height and baseline the unscripted text would
|
|
308
|
+
* have had. Absent is ordinary text.
|
|
307
309
|
*/
|
|
308
310
|
script?: 'super' | 'sub';
|
|
309
311
|
}
|
|
@@ -315,12 +317,13 @@ interface ResolvedTextStyle {
|
|
|
315
317
|
fontStyle: 'normal' | 'italic';
|
|
316
318
|
/** Still relative if the author wrote it that way — `direction` resolves it. */
|
|
317
319
|
align: TextAlign;
|
|
318
|
-
direction: TextDirection;
|
|
320
|
+
direction: TextDirection | 'auto';
|
|
319
321
|
lineHeight: number;
|
|
322
|
+
tabSize: number;
|
|
320
323
|
wrap: boolean;
|
|
321
324
|
/** `null` is an explicit no-fill, the way it is on every other node kind:
|
|
322
325
|
* outline-only text, painted by its stroke alone. */
|
|
323
|
-
fill:
|
|
326
|
+
fill: Fill | null;
|
|
324
327
|
caretColor: string;
|
|
325
328
|
selectionBackground: string | null;
|
|
326
329
|
selectionColor: string | null;
|
|
@@ -338,27 +341,19 @@ interface ResolvedTextStyle {
|
|
|
338
341
|
}
|
|
339
342
|
/** Default resolved style used when a `TextPose` omits `style`. */
|
|
340
343
|
declare const DEFAULT_TEXT_STYLE: ResolvedTextStyle;
|
|
341
|
-
/**
|
|
342
|
-
* The paint a text node hands its glyphs — `data.fill` and `data.stroke`,
|
|
343
|
-
* read straight off the node. Runs inherit these when they name none of
|
|
344
|
-
* their own.
|
|
345
|
-
*/
|
|
344
|
+
/** The paint a text node hands its glyphs — `data.fill` and `data.stroke`. Runs inherit these when they name none of their own. */
|
|
346
345
|
interface TextPaint {
|
|
347
346
|
/** `null` is an explicit no-fill and absent takes the default black — the
|
|
348
347
|
* reading every other node kind gives `data.fill`. Unfilled text paints
|
|
349
348
|
* through its stroke and nothing else, so it needs one to be visible. */
|
|
350
|
-
fill?:
|
|
349
|
+
fill?: Fill | null;
|
|
351
350
|
/**
|
|
352
|
-
* Outline painted over the glyph fill. Absent means no outline
|
|
353
|
-
* no such thing as a default text stroke.
|
|
351
|
+
* Outline painted over the glyph fill. Absent means no outline.
|
|
354
352
|
*
|
|
355
|
-
* Only glyphs on the outline tier are stroked:
|
|
356
|
-
* `textOutlineMinScreenSize` a glyph is a
|
|
357
|
-
*
|
|
358
|
-
*
|
|
359
|
-
* stroke, and it renders unstroked rather than approximated. `width` is in
|
|
360
|
-
* world units, like every other stroke in the kit — it does not scale with
|
|
361
|
-
* `fontSize`.
|
|
353
|
+
* Only glyphs on the outline tier are stroked: below
|
|
354
|
+
* `textOutlineMinScreenSize` a glyph is a sampled distance field with no
|
|
355
|
+
* geometry to stroke, and it renders unstroked. `width` is in world units —
|
|
356
|
+
* it does not scale with `fontSize`.
|
|
362
357
|
*/
|
|
363
358
|
stroke?: Stroke | null;
|
|
364
359
|
}
|
|
@@ -367,10 +362,7 @@ interface TextPaint {
|
|
|
367
362
|
* taking the glyph paint from the node rather than from the style.
|
|
368
363
|
*
|
|
369
364
|
* `scale` is the view scale any `{ px }` size resolves against — the same
|
|
370
|
-
* mean-of-the-axes factor `resolveStrokeWidth` takes.
|
|
371
|
-
* here, at the entry to layout, rather than at draw time: a screen-pixel size
|
|
372
|
-
* changes the glyph advances, the wrap points and the measured bounds, and
|
|
373
|
-
* everything downstream of `ResolvedTextStyle` reads a plain world number.
|
|
365
|
+
* mean-of-the-axes factor `resolveStrokeWidth` takes.
|
|
374
366
|
*/
|
|
375
367
|
declare function resolveTextStyle(style?: TextStyle, paint?: TextPaint, scale?: number): ResolvedTextStyle;
|
|
376
368
|
/** Build a CSS `font` shorthand suitable for `ctx.font`. */
|
|
@@ -378,35 +370,17 @@ declare function fontString(s: ResolvedTextStyle): string;
|
|
|
378
370
|
|
|
379
371
|
/**
|
|
380
372
|
* Apply node-level `ResolvedTextStyle` defaults to each `StyledRun`,
|
|
381
|
-
* producing a
|
|
382
|
-
* layout and draw never re-resolve defaults — `ResolvedRun` is the
|
|
383
|
-
* canonical shape the renderer consumes.
|
|
384
|
-
*
|
|
385
|
-
* `bold`/`italic` toggles on a run are folded into `fontWeight`/`fontStyle`:
|
|
386
|
-
* `bold: true` → fontWeight 700, `italic: true` → fontStyle 'italic'. A run's
|
|
387
|
-
* own numeric `fontWeight` is the primitive `bold` is a preset over, so it
|
|
388
|
-
* wins over both the flag and the node weight.
|
|
389
|
-
* Explicit `fontFamily` / `fontSize` / `fill` / `letterSpacing` on the run
|
|
390
|
-
* override the node-level value (`letterSpacing: 0` on a run is an override,
|
|
391
|
-
* not an absence — it zeroes inherited tracking).
|
|
392
|
-
*
|
|
393
|
-
* `underline` / `strikethrough` / `overline` are *additive*, like
|
|
394
|
-
* `bold`/`italic`: a run can turn a decoration on but never off, so they
|
|
395
|
-
* resolve as `run.x || style.x` and not `run.x ?? style.x`. See the header of
|
|
396
|
-
* `runs/rangeStyle.ts` for why the model collapses the tri-state.
|
|
397
|
-
*
|
|
398
|
-
* `script` is folded the same way the toggles are, into the two primitives it
|
|
399
|
-
* is a preset over: `baselineShift` and `fontScale`. Both come out as one
|
|
400
|
-
* world-unit `baselineShift` and a final `fontSize`, so layout never learns
|
|
401
|
-
* that superscripts exist — it places a run against a baseline and an offset.
|
|
373
|
+
* producing a `ResolvedRun` with every styling field set.
|
|
402
374
|
*
|
|
403
|
-
* `
|
|
404
|
-
*
|
|
405
|
-
*
|
|
375
|
+
* `bold`/`italic` on a run fold into `fontWeight`/`fontStyle`; a run's own
|
|
376
|
+
* numeric `fontWeight` wins over both the flag and the node weight.
|
|
377
|
+
* `letterSpacing: 0` on a run is an override, not an absence — it zeroes
|
|
378
|
+
* inherited tracking. The decorations are *additive*: a run can turn one on
|
|
379
|
+
* but never off, so they resolve as `run.x || style.x`.
|
|
406
380
|
*
|
|
407
|
-
* `
|
|
408
|
-
*
|
|
409
|
-
*
|
|
381
|
+
* `script` folds into the two primitives it is a preset over, and comes out
|
|
382
|
+
* as one world-unit `baselineShift` and a final `fontSize`. `textTransform`
|
|
383
|
+
* is applied here, then small caps over the transformed text.
|
|
410
384
|
*/
|
|
411
385
|
|
|
412
386
|
/** A run with every style resolved against the node's text style — no
|
|
@@ -431,7 +405,7 @@ interface ResolvedRun {
|
|
|
431
405
|
/** `null` is an explicit no-fill: the glyphs are painted by `stroke` alone,
|
|
432
406
|
* which only the outline tier can do. Nothing is emitted for a run with
|
|
433
407
|
* neither. */
|
|
434
|
-
fill:
|
|
408
|
+
fill: Fill | null;
|
|
435
409
|
/** Outline over this run's glyphs, or absent for none. Painted only on the
|
|
436
410
|
* outline tier — a distance field has no geometry to stroke. */
|
|
437
411
|
stroke?: Stroke;
|
|
@@ -445,11 +419,8 @@ interface ResolvedRun {
|
|
|
445
419
|
overline: boolean;
|
|
446
420
|
/**
|
|
447
421
|
* How far this run sits off the line's shared baseline, in world units;
|
|
448
|
-
* positive raises. 0 for ordinary text.
|
|
449
|
-
*
|
|
450
|
-
* Already multiplied out against the inherited font size, and already
|
|
451
|
-
* carrying whatever `script` asked for — layout adds it to a baseline and
|
|
452
|
-
* asks nothing about where it came from.
|
|
422
|
+
* positive raises. 0 for ordinary text. Already carries whatever `script`
|
|
423
|
+
* asked for.
|
|
453
424
|
*/
|
|
454
425
|
baselineShift: number;
|
|
455
426
|
/**
|
|
@@ -469,11 +440,8 @@ type ScriptPreset = Readonly<{
|
|
|
469
440
|
* What `script: 'super'` and `script: 'sub'` expand to for a face that states
|
|
470
441
|
* no script metrics of its own, as fractions of the inherited font size:
|
|
471
442
|
* `size` scales it, `shift` raises (positive) or lowers (negative) the
|
|
472
|
-
* baseline.
|
|
473
|
-
*
|
|
474
|
-
* These are Adobe's defaults — InDesign and Illustrator ship 58.3% size and
|
|
475
|
-
* 33.3% position for both. A face that carries `OS/2` script metrics uses
|
|
476
|
-
* those instead; {@link scriptMetricsFor} is what a run actually gets.
|
|
443
|
+
* baseline. These are Adobe's defaults. A face that carries `OS/2` script
|
|
444
|
+
* metrics uses those instead; {@link scriptMetricsFor} is what a run gets.
|
|
477
445
|
*/
|
|
478
446
|
declare const SCRIPT_METRICS: Readonly<Record<'super' | 'sub', ScriptPreset>>;
|
|
479
447
|
/** The script presets for a face: its own `OS/2` values where it states
|
|
@@ -481,10 +449,8 @@ declare const SCRIPT_METRICS: Readonly<Record<'super' | 'sub', ScriptPreset>>;
|
|
|
481
449
|
declare function scriptMetrics(face?: FaceMetrics): Readonly<Record<'super' | 'sub', ScriptPreset>>;
|
|
482
450
|
/**
|
|
483
451
|
* The script presets a run set in `(family, weight, style)` gets — resolved
|
|
484
|
-
* through the font registry exactly as layout resolves the run
|
|
485
|
-
*
|
|
486
|
-
* the canvas draws with. Override either half per run with `baselineShift` /
|
|
487
|
-
* `fontScale`.
|
|
452
|
+
* through the font registry exactly as layout resolves the run. Override
|
|
453
|
+
* either half per run with `baselineShift` / `fontScale`.
|
|
488
454
|
*/
|
|
489
455
|
declare function scriptMetricsFor(family: string, weight: number, style: FontStyle): Readonly<Record<'super' | 'sub', ScriptPreset>>;
|
|
490
456
|
/** A `TextStyle.fontWeight` as a number: the CSS keywords `bold` and
|
|
@@ -506,29 +472,6 @@ declare function resolveRunFace(run: StyledRun, style: Pick<ResolvedTextStyle, '
|
|
|
506
472
|
* `style`. */
|
|
507
473
|
declare function resolveRuns(runs: readonly StyledRun[], style: ResolvedTextStyle, viewScale?: number): ResolvedRun[];
|
|
508
474
|
|
|
509
|
-
/** The three text decoration rules, in the order every tier paints them. */
|
|
510
|
-
type DecorationKind = 'underline' | 'strikethrough' | 'overline';
|
|
511
|
-
/**
|
|
512
|
-
* Decoration placement and weight for a face that states none, as fractions
|
|
513
|
-
* of the run's `fontSize`. Offsets are the *top* edge of the rule, measured
|
|
514
|
-
* down from the baseline — so the two rules that sit above it are negative.
|
|
515
|
-
*
|
|
516
|
-
* Derived, not measured: they apply to an atlas baked before `gen-font`
|
|
517
|
-
* recorded `faceMetrics`, a custom outline parser that reports none, and the
|
|
518
|
-
* canvas tier, which has no font tables to read.
|
|
519
|
-
*/
|
|
520
|
-
declare const DEFAULT_DECORATION_METRICS: Readonly<Record<DecorationKind, FaceRuleMetrics>>;
|
|
521
|
-
/**
|
|
522
|
-
* Where each rule sits for a face, in ems: the face's own underline and
|
|
523
|
-
* strikeout where it states them, the defaults where it does not. No font
|
|
524
|
-
* table places an overline, so it keeps the default offset and takes the
|
|
525
|
-
* underline's weight, as browsers draw it.
|
|
526
|
-
*
|
|
527
|
-
* Every text tier places its rules through this, so one face puts a rule in
|
|
528
|
-
* the same place whichever tier paints it.
|
|
529
|
-
*/
|
|
530
|
-
declare function decorationMetrics(face?: FaceMetrics): Readonly<Record<DecorationKind, FaceRuleMetrics>>;
|
|
531
|
-
|
|
532
475
|
/**
|
|
533
476
|
* The bidi contract, declared here and implemented elsewhere.
|
|
534
477
|
*
|
|
@@ -554,8 +497,8 @@ interface BidiReordering {
|
|
|
554
497
|
levels: ArrayLike<number>;
|
|
555
498
|
}
|
|
556
499
|
/**
|
|
557
|
-
* A bidi engine, passed to `layoutRuns` as
|
|
558
|
-
* `bidi` object satisfies it. `reorder`'s `start` / `end` index the code points
|
|
500
|
+
* A bidi engine, registered with `registerBidi` or passed to `layoutRuns` as
|
|
501
|
+
* `opts.bidi`. `@weasel-js/bidi`'s `bidi` object satisfies it. `reorder`'s `start` / `end` index the code points
|
|
559
502
|
* `analyze` was given.
|
|
560
503
|
*/
|
|
561
504
|
interface BidiResolver {
|
|
@@ -563,154 +506,90 @@ interface BidiResolver {
|
|
|
563
506
|
reorder(analysis: BidiAnalysis, start: number, end: number): BidiReordering;
|
|
564
507
|
/** L4 — the mirrored form for a character in a right-to-left run, or null. */
|
|
565
508
|
mirror(cp: number): number | null;
|
|
509
|
+
/** The level the analysed paragraph reads at: even left to right, odd right
|
|
510
|
+
* to left. What `'auto'` resolved to, for aligning `start` and `end`. */
|
|
511
|
+
baseLevel(analysis: BidiAnalysis): number;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
/** Options for `layoutRuns`. */
|
|
515
|
+
interface LayoutRunsOpts {
|
|
516
|
+
/** Wrap width. `Infinity` never wraps. */
|
|
517
|
+
maxWidth: number;
|
|
518
|
+
/**
|
|
519
|
+
* Width of the box `center` / `right` resolve within, with `x = 0` its left
|
|
520
|
+
* edge. Default `maxWidth`. Separate from it so a box can align text it does
|
|
521
|
+
* not wrap. When both are infinite a line anchors on its own width instead:
|
|
522
|
+
* `x = 0` is its midpoint (`center`) or right edge (`right`).
|
|
523
|
+
*/
|
|
524
|
+
alignWidth?: number;
|
|
525
|
+
lineHeight: number;
|
|
526
|
+
/**
|
|
527
|
+
* `start` / `end` resolve against `direction`; `left` / `right` are absolute
|
|
528
|
+
* and ignore it, the way CSS `text-align` treats the same values. `justify`
|
|
529
|
+
* is `justify: true` with the start edge.
|
|
530
|
+
*/
|
|
531
|
+
align: TextAlign;
|
|
532
|
+
/**
|
|
533
|
+
* Spread each line that wrapped across `alignWidth`, widening its word gaps
|
|
534
|
+
* (spaces between words; not leading or hanging trailing ones) by equal
|
|
535
|
+
* shares of the slack. A line that closes its paragraph, or has no gap, or
|
|
536
|
+
* no slack, keeps `align` — so `align` is CSS `text-align-last` here.
|
|
537
|
+
* Implied by `align: 'justify'`. Default `false`.
|
|
538
|
+
*/
|
|
539
|
+
justify?: boolean;
|
|
540
|
+
/**
|
|
541
|
+
* Bidi engine. Default: the one given to `registerBidi`. With neither, the
|
|
542
|
+
* text lays out in logical order, which is correct for left-to-right text
|
|
543
|
+
* and wrong for right-to-left text — see the warning this emits when it
|
|
544
|
+
* detects the latter without one.
|
|
545
|
+
*/
|
|
546
|
+
bidi?: BidiResolver;
|
|
547
|
+
/**
|
|
548
|
+
* Reading direction: the base direction of the bidi analysis, and what
|
|
549
|
+
* `start` / `end` resolve against. Default `'auto'`, each paragraph's own
|
|
550
|
+
* first strong character, which only an engine can find: with none, `'auto'`
|
|
551
|
+
* reads left to right.
|
|
552
|
+
*/
|
|
553
|
+
direction?: TextDirection | 'auto';
|
|
554
|
+
/**
|
|
555
|
+
* Distance between tab stops, in spaces of the tab's own run (its advance
|
|
556
|
+
* plus the run's tracking), as CSS `tab-size` counts it. A tab advances to
|
|
557
|
+
* the next stop from the start of its line. Default 8.
|
|
558
|
+
*/
|
|
559
|
+
tabSize?: number;
|
|
566
560
|
}
|
|
567
561
|
|
|
568
562
|
/**
|
|
569
|
-
* Runs-aware
|
|
570
|
-
*
|
|
571
|
-
*
|
|
572
|
-
* run
|
|
573
|
-
* `(family, resolvedWeight, resolvedStyle, syntheticBold, syntheticItalic, fillKey)`
|
|
574
|
-
* so the renderer issues one draw call per atlas+color group.
|
|
563
|
+
* Runs-aware text layout: wraps `ResolvedRun[]` into lines and places every
|
|
564
|
+
* glyph on them. What to draw for the result — which glyphs share a draw,
|
|
565
|
+
* which tier paints each, where the decoration rules go — is `paintRuns`'.
|
|
566
|
+
* Nothing here reads a run's paint, so recoloring text never lays it out again.
|
|
575
567
|
*
|
|
576
568
|
* A run's `letterSpacing` (world units, so it does not scale with `fontSize`)
|
|
577
569
|
* is added to the advance *after* every grapheme cluster of that run,
|
|
578
|
-
* including the last one on a line — the CSS `letter-spacing` rule
|
|
579
|
-
*
|
|
580
|
-
*
|
|
581
|
-
* before the gap opens. Clusters are segmented per run. Trailing tracking
|
|
582
|
-
* therefore widens the measured line width and counts toward wrapping. Spaces
|
|
583
|
-
* are tracked like any other character; a newline is not (it consumes no
|
|
584
|
-
* advance).
|
|
570
|
+
* including the last one on a line — the CSS `letter-spacing` rule. Trailing
|
|
571
|
+
* tracking therefore widens the measured line width and counts toward
|
|
572
|
+
* wrapping. Spaces are tracked like any other character; a newline is not.
|
|
585
573
|
*
|
|
586
|
-
* Word wrap is applied when `maxWidth` is finite
|
|
587
|
-
*
|
|
588
|
-
* exceed the current line width. Forced line breaks are emitted at UAX #14's
|
|
589
|
-
* hard breaks — `\n`, CR, CRLF as one, VT, FF, NEL, U+2028 and U+2029 — none
|
|
574
|
+
* Word wrap is applied when `maxWidth` is finite, at UAX #14 break
|
|
575
|
+
* opportunities. Forced line breaks are emitted at UAX #14's hard breaks, none
|
|
590
576
|
* of which lays out a cell. Every run on a line shares one baseline, sunk to
|
|
591
|
-
* clear whichever run reaches highest above it
|
|
592
|
-
* them the way inline text aligns everywhere else; line height is
|
|
577
|
+
* clear whichever run reaches highest above it; line height is
|
|
593
578
|
* `max(fontSize * lineHeight)` across the line. A face that states its ascent
|
|
594
579
|
* and descent sits in its line the way CSS sets it — half the leading above the
|
|
595
580
|
* ascent, negative when the face is taller than the line, so its glyphs overflow
|
|
596
581
|
* the box rather than growing it. A run a relative size shrank
|
|
597
|
-
* measures at its `strutSize` for both
|
|
598
|
-
* strut under a `<sup>`.
|
|
599
|
-
*
|
|
600
|
-
* A run may also sit off that shared baseline: `ResolvedRun.baselineShift`
|
|
601
|
-
* displaces it, which is what `script: 'super' | 'sub'` resolves to. The shift
|
|
602
|
-
* moves the run's glyphs, its outline geometry and its own decoration rules
|
|
603
|
-
* together, and deliberately does not feed back into the line's baseline or
|
|
604
|
-
* its height — a superscript rides on the line rather than reflowing it.
|
|
605
|
-
*
|
|
606
|
-
* Underline, strikethrough and overline come out on a second channel,
|
|
607
|
-
* `decorations` —
|
|
608
|
-
* solid rectangles, not textured glyphs, so they cannot ride in a group's
|
|
609
|
-
* `quads` (which upload UVs into an MSDF program). They are accumulated
|
|
610
|
-
* during the same per-line pen walk that emits quads, *not* reconstructed
|
|
611
|
-
* from quad extents afterwards: quads exist only for glyphs with ink, so a
|
|
612
|
-
* decorated span's spaces would punch holes in a rule derived from them.
|
|
582
|
+
* measures at its `strutSize` for both.
|
|
613
583
|
*
|
|
614
|
-
*
|
|
584
|
+
* `ResolvedRun.baselineShift` displaces a run off that shared baseline. The
|
|
585
|
+
* shift moves the run's glyphs and its own decoration rules together, and does
|
|
586
|
+
* not feed back into the line's baseline or its height.
|
|
615
587
|
*
|
|
616
|
-
* Every coordinate out of here is measured from the text's own top-left
|
|
617
|
-
*
|
|
618
|
-
*
|
|
619
|
-
* the position in its key and miss on every frame of the drag — and it costs
|
|
620
|
-
* the caller one addition per vertex, inside loops already walking every one.
|
|
621
|
-
* Alignment, wrapping, tracking and decoration placement all read widths and
|
|
622
|
-
* pen deltas, never an absolute coordinate, so the translation is exact.
|
|
588
|
+
* Every coordinate out of here is measured from the text's own top-left: the
|
|
589
|
+
* caller translates. That is what lets a text node be dragged without
|
|
590
|
+
* re-laying out.
|
|
623
591
|
*/
|
|
624
592
|
|
|
625
|
-
/** One textured glyph quad, origin-relative — see the header. */
|
|
626
|
-
interface LaidOutQuad {
|
|
627
|
-
x0: number;
|
|
628
|
-
y0: number;
|
|
629
|
-
x1: number;
|
|
630
|
-
y1: number;
|
|
631
|
-
u0: number;
|
|
632
|
-
v0: number;
|
|
633
|
-
u1: number;
|
|
634
|
-
v1: number;
|
|
635
|
-
/** Y coordinate of the line's baseline (penY at quad emission). Used by the
|
|
636
|
-
* synthetic-italic vertex skew so above-baseline vertices lean right. */
|
|
637
|
-
baselineY: number;
|
|
638
|
-
}
|
|
639
|
-
/**
|
|
640
|
-
* One glyph the renderer should tessellate rather than sample: real font
|
|
641
|
-
* outline geometry, for text large enough that a distance field shows the
|
|
642
|
-
* raster it was reconstructed from.
|
|
643
|
-
*
|
|
644
|
-
* `d` is em-space SVG path data straight from `@weasel-js/font`'s outline
|
|
645
|
-
* registry — 1 unit is 1 em, y grows down, origin on the baseline at the pen.
|
|
646
|
-
* Placing it is therefore a uniform scale by `scale` (world units per em)
|
|
647
|
-
* followed by a translate to `(x, baselineY)`, and nothing here depends on
|
|
648
|
-
* zoom: the same glyph at the same size in two places is the same geometry
|
|
649
|
-
* twice, which is what lets the renderer tessellate it once and cache it.
|
|
650
|
-
*
|
|
651
|
-
* `key` identifies that cached tessellation — face identity plus codepoint,
|
|
652
|
-
* assembled here because layout is where both are in hand.
|
|
653
|
-
*/
|
|
654
|
-
interface LaidOutOutlineGlyph {
|
|
655
|
-
d: string;
|
|
656
|
-
key: string;
|
|
657
|
-
/** Pen position: where em-space x = 0 lands, in world units. */
|
|
658
|
-
x: number;
|
|
659
|
-
/** The line's baseline: where em-space y = 0 lands, in world units. */
|
|
660
|
-
baselineY: number;
|
|
661
|
-
/** World units per em — the run's `fontSize`, since em space is unit-scale. */
|
|
662
|
-
scale: number;
|
|
663
|
-
}
|
|
664
|
-
/** Glyphs that share a resolved face, glyph source and paint — one draw call's worth. */
|
|
665
|
-
interface LaidOutGroup {
|
|
666
|
-
/** Resolved atlas family — may differ from the requested family when the
|
|
667
|
-
* cross-family fallback policy substituted a default. This is what the
|
|
668
|
-
* renderer looks the atlas up by, so it must be the one that resolves. */
|
|
669
|
-
family: string;
|
|
670
|
-
/** Resolved variant — matches the registered atlas and the texture-cache key. */
|
|
671
|
-
weight: number;
|
|
672
|
-
style: FontStyle;
|
|
673
|
-
/** Gap between the request and the resolved match. Drives shader uniforms. */
|
|
674
|
-
synthetic: {
|
|
675
|
-
bold: boolean;
|
|
676
|
-
italic: boolean;
|
|
677
|
-
};
|
|
678
|
-
/** Which glyph source (and therefore shader/texture) this group binds:
|
|
679
|
-
* baked MSDF atlas, the runtime canvas-SDF dynamic atlas, or tessellated
|
|
680
|
-
* font outlines. */
|
|
681
|
-
source: 'atlas' | 'canvas' | 'outline';
|
|
682
|
-
/** Dynamic-atlas page index for 'canvas' groups; 0 for the others. */
|
|
683
|
-
page: number;
|
|
684
|
-
/** `null` for an unfilled run: the group's glyphs are painted by `stroke`
|
|
685
|
-
* alone. Only ever null on an `'outline'` group carrying a stroke, since
|
|
686
|
-
* nothing else can put ink down without a fill. */
|
|
687
|
-
fill: FillStyle | null;
|
|
688
|
-
/** Outline painted over the glyphs, or absent for none. Only ever set on
|
|
689
|
-
* an `'outline'` group — the SDF tiers have no geometry to stroke, which
|
|
690
|
-
* is why a stroke pulls its run onto the outline tier at any size. A run
|
|
691
|
-
* the tier cannot serve at all (no registered outlines, synthetic bold)
|
|
692
|
-
* stays on the atlas and carries the request no further. */
|
|
693
|
-
stroke?: Stroke;
|
|
694
|
-
/** Textured glyph quads. Always empty for an `'outline'` group. */
|
|
695
|
-
quads: LaidOutQuad[];
|
|
696
|
-
/** Outline geometry. Always empty for an `'atlas'` / `'canvas'` group —
|
|
697
|
-
* the two channels are exclusive, since the group is also the draw call
|
|
698
|
-
* and one draw call binds one program. */
|
|
699
|
-
glyphs: LaidOutOutlineGlyph[];
|
|
700
|
-
}
|
|
701
|
-
/**
|
|
702
|
-
* One decoration rule: an axis-aligned solid rectangle in the same world
|
|
703
|
-
* space as `LaidOutQuad`. Never spans a line break, and carries the fill of
|
|
704
|
-
* the run(s) it decorates so the rule follows the text colour.
|
|
705
|
-
*/
|
|
706
|
-
interface LaidOutDecoration {
|
|
707
|
-
kind: DecorationKind;
|
|
708
|
-
x0: number;
|
|
709
|
-
y0: number;
|
|
710
|
-
x1: number;
|
|
711
|
-
y1: number;
|
|
712
|
-
fill: FillStyle;
|
|
713
|
-
}
|
|
714
593
|
/**
|
|
715
594
|
* One advance cell: a single code point's slot on a line.
|
|
716
595
|
*
|
|
@@ -727,7 +606,7 @@ interface LaidOutCell {
|
|
|
727
606
|
/** One past that source character — `srcIndex + 2` for an astral one. */
|
|
728
607
|
srcEnd: number;
|
|
729
608
|
cp: number;
|
|
730
|
-
/** Left edge of the cell, post-alignment, origin-relative
|
|
609
|
+
/** Left edge of the cell, post-alignment, origin-relative.
|
|
731
610
|
*
|
|
732
611
|
* **Not monotonic across `cells`** once a bidi engine reorders a line: cells
|
|
733
612
|
* stay in logical order and their x values do not. Sort on `x` for visual
|
|
@@ -743,6 +622,8 @@ interface LaidOutCell {
|
|
|
743
622
|
* Whether this code point can put ink on the page. False for a space and
|
|
744
623
|
* for a code point no tier could serve — each of which still holds its
|
|
745
624
|
* slot. A zero-advance combining mark is `true`: it inks without advancing.
|
|
625
|
+
* An emoji drawn as one color glyph inks from its cluster's closing code
|
|
626
|
+
* point, which holds the whole advance; the ones before it are `false`.
|
|
746
627
|
*
|
|
747
628
|
* A property of the character and the face, not of this call: it does not
|
|
748
629
|
* change when a dynamic bake lands or the outline threshold is crossed. A
|
|
@@ -750,17 +631,51 @@ interface LaidOutCell {
|
|
|
750
631
|
* read the quad or outline geometry for exact ink extents.
|
|
751
632
|
*/
|
|
752
633
|
drawsInk: boolean;
|
|
634
|
+
/**
|
|
635
|
+
* Whether this code point closes a grapheme cluster. A caret stops only
|
|
636
|
+
* after a cell that does: never between a letter and its combining mark,
|
|
637
|
+
* inside a joined emoji, or before a variation selector.
|
|
638
|
+
*/
|
|
639
|
+
clusterEnd: boolean;
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* One code point where the pen put it, with what a painter needs to draw it:
|
|
643
|
+
* the tier that serves it and its record there. Carries no paint.
|
|
644
|
+
*/
|
|
645
|
+
interface PlacedGlyph {
|
|
646
|
+
/** Index of its run in the runs laid out. */
|
|
647
|
+
run: number;
|
|
648
|
+
cp: number;
|
|
649
|
+
/** The glyph's own size, which small caps sets below its run's. */
|
|
650
|
+
fontSize: number;
|
|
651
|
+
/** The tier serving the glyph, which is not its run's own when the code
|
|
652
|
+
* point escalated to the dynamic tier, and that tier's metrics. */
|
|
653
|
+
resolved: ResolveResult;
|
|
654
|
+
metrics: GlyphMetrics;
|
|
655
|
+
/** The atlas to sample and the glyph's record in it. Both null on the
|
|
656
|
+
* outline tier and for a slot with nothing to draw. A dynamic glyph's
|
|
657
|
+
* record gains its atlas rect in place when its bake lands. */
|
|
658
|
+
font: BmFont | null;
|
|
659
|
+
glyph: BmFontChar | null;
|
|
660
|
+
/** Pen position: the left edge of the glyph's slot. */
|
|
661
|
+
x: number;
|
|
662
|
+
/** Its line's baseline, raised by its run's `baselineShift`. */
|
|
663
|
+
baselineY: number;
|
|
664
|
+
/** The glyph's own advance. */
|
|
665
|
+
advance: number;
|
|
666
|
+
/** How far the pen moved past it: `advance`, its run's tracking, and a
|
|
667
|
+
* justified gap's share of the slack. */
|
|
668
|
+
step: number;
|
|
753
669
|
}
|
|
754
670
|
/**
|
|
755
|
-
* One laid-out line's box
|
|
671
|
+
* One laid-out line's box.
|
|
756
672
|
*
|
|
757
673
|
* `[x0, x1]` is the line's own advance width *after* alignment — not the
|
|
758
674
|
* wrap box — so a short centered line reports the span it actually occupies.
|
|
759
|
-
* `[y0, y1]` is the full line box: `y0` is the pen's line top,
|
|
760
|
-
*
|
|
761
|
-
*
|
|
762
|
-
*
|
|
763
|
-
* box, not an ink bounding box.
|
|
675
|
+
* `[y0, y1]` is the full line box: `y0` is the pen's line top, and the box is
|
|
676
|
+
* as tall as its tallest run's `lineHeight` times that run's size, or the
|
|
677
|
+
* larger size a shrunken run inherited. Ink can escape it vertically; this is
|
|
678
|
+
* the typographic box, not an ink bounding box.
|
|
764
679
|
*
|
|
765
680
|
* Emitted for every line including empty ones, so indices line up with the
|
|
766
681
|
* wrap. An empty line has `x0 === x1`.
|
|
@@ -773,16 +688,18 @@ interface LaidOutLineBox {
|
|
|
773
688
|
/** The line's baseline, for callers placing carets or rules against it. */
|
|
774
689
|
baselineY: number;
|
|
775
690
|
/**
|
|
776
|
-
* One cell per code point on this line,
|
|
777
|
-
* line covers has exactly one, drawn or not; only a newline has none,
|
|
778
|
-
* it separates cells rather than being one. The code points are the
|
|
779
|
-
* ones, after `textTransform`, so an uppercased `ß` has two cells.
|
|
691
|
+
* One cell per code point on this line, in logical order. Every code point
|
|
692
|
+
* the line covers has exactly one, drawn or not; only a newline has none,
|
|
693
|
+
* since it separates cells rather than being one. The code points are the
|
|
694
|
+
* drawn ones, after `textTransform`, so an uppercased `ß` has two cells.
|
|
780
695
|
*
|
|
781
696
|
* A caret stop is a cell's `x`, and the stop closing the line is `x1` /
|
|
782
697
|
* `srcEnd` — there is one more stop than cell, except that cells sharing a
|
|
783
698
|
* source span have no stop between them.
|
|
784
699
|
*/
|
|
785
700
|
cells: LaidOutCell[];
|
|
701
|
+
/** The same code points as placed glyphs, in visual order, left to right. */
|
|
702
|
+
glyphs: PlacedGlyph[];
|
|
786
703
|
/**
|
|
787
704
|
* Source offset just past this line's last cell — the closing caret stop's
|
|
788
705
|
* index, and the only source offset a blank line carries.
|
|
@@ -791,86 +708,22 @@ interface LaidOutLineBox {
|
|
|
791
708
|
}
|
|
792
709
|
/** What {@link layoutRuns} returns. Every coordinate is relative to the text's own top-left. */
|
|
793
710
|
interface LaidOutRuns {
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
* strikethrough then overline. Empty when nothing is decorated. */
|
|
797
|
-
decorations: LaidOutDecoration[];
|
|
798
|
-
/** Per-line boxes in layout order. Lets a caller reason about where the
|
|
799
|
-
* text actually sits inside its wrap box without re-running the wrap —
|
|
800
|
-
* `textLineBoxes` builds the text silhouette from these, so picking and
|
|
801
|
-
* painting cannot drift apart. */
|
|
711
|
+
/** Per-line boxes in layout order: where the text actually sits inside its
|
|
712
|
+
* wrap box. */
|
|
802
713
|
lines: LaidOutLineBox[];
|
|
803
|
-
/** The text's
|
|
714
|
+
/** The text's box. `width` is the widest line measured to its last
|
|
804
715
|
* non-space cell — a trailing space hangs past the aligned edge, so a
|
|
805
|
-
* block wrapped at `maxWidth` never reports wider than it.
|
|
716
|
+
* block wrapped at `maxWidth` never reports wider than it. `height` is the
|
|
717
|
+
* line boxes stacked. Not an ink box: a decoration rule, or a run shifted
|
|
718
|
+
* off the baseline, can fall outside it. */
|
|
806
719
|
bounds: {
|
|
807
720
|
width: number;
|
|
808
721
|
height: number;
|
|
809
722
|
};
|
|
810
723
|
}
|
|
811
|
-
/** Options for {@link layoutRuns}. */
|
|
812
|
-
interface LayoutRunsOpts {
|
|
813
|
-
/** Wrap width. `Infinity` never wraps. */
|
|
814
|
-
maxWidth: number;
|
|
815
|
-
/**
|
|
816
|
-
* Width of the box `center` / `right` resolve within, with `x = 0` its left
|
|
817
|
-
* edge. Default `maxWidth`. Separate from it so a box can align text it does
|
|
818
|
-
* not wrap. When both are infinite a line anchors on its own width instead:
|
|
819
|
-
* `x = 0` is its midpoint (`center`) or right edge (`right`).
|
|
820
|
-
*/
|
|
821
|
-
alignWidth?: number;
|
|
822
|
-
lineHeight: number;
|
|
823
|
-
/**
|
|
824
|
-
* `start` / `end` resolve against `direction`; `left` / `right` are absolute
|
|
825
|
-
* and ignore it, the way CSS `text-align` treats the same values. `justify`
|
|
826
|
-
* is `justify: true` with the start edge.
|
|
827
|
-
*/
|
|
828
|
-
align: TextAlign;
|
|
829
|
-
/**
|
|
830
|
-
* Spread each line that wrapped across `alignWidth`, widening its word gaps
|
|
831
|
-
* (spaces between words; not leading or hanging trailing ones) by equal
|
|
832
|
-
* shares of the slack. A line that closes its paragraph, or has no gap, or
|
|
833
|
-
* no slack, keeps `align` — so `align` is CSS `text-align-last` here.
|
|
834
|
-
* Implied by `align: 'justify'`. Default `false`.
|
|
835
|
-
*/
|
|
836
|
-
justify?: boolean;
|
|
837
|
-
/**
|
|
838
|
-
* Bidi engine. Omit and the text lays out in logical order, which is correct
|
|
839
|
-
* for left-to-right text and wrong for right-to-left text — see the warning
|
|
840
|
-
* this emits when it detects the latter without one.
|
|
841
|
-
*/
|
|
842
|
-
bidi?: BidiResolver;
|
|
843
|
-
/**
|
|
844
|
-
* Reading direction, for resolving `start` / `end`. Default `'ltr'`.
|
|
845
|
-
*
|
|
846
|
-
* Taken as an input rather than sniffed: this package has no DOM, so a
|
|
847
|
-
* consumer reading `getComputedStyle(box).direction` passes what it found.
|
|
848
|
-
*/
|
|
849
|
-
direction?: TextDirection;
|
|
850
|
-
/**
|
|
851
|
-
* World-space `fontSize` at or above which glyphs are emitted as outline
|
|
852
|
-
* geometry, when the resolved face has outlines registered. Omit (the
|
|
853
|
-
* default) to keep every glyph on its SDF tier.
|
|
854
|
-
*
|
|
855
|
-
* A *world* size rather than a screen size because layout knows nothing
|
|
856
|
-
* about the view; `drawText` divides its screen-pixel threshold by the view
|
|
857
|
-
* scale before calling, so zooming in lowers the world size that qualifies.
|
|
858
|
-
*
|
|
859
|
-
* This is a rendering switch only. Advances, kerning, wrapping and
|
|
860
|
-
* baselines are identical either way — the outline tier changes what a
|
|
861
|
-
* glyph looks like, never where it sits — so measurement callers
|
|
862
|
-
* (`measureTextBounds`, `textLineBoxes`) leave it unset and still agree
|
|
863
|
-
* with the paint, and crossing the threshold cannot reflow text.
|
|
864
|
-
*
|
|
865
|
-
* Ignored for a family that resolved to the outline tier because it has no
|
|
866
|
-
* atlas: there the geometry is not an upgrade over another rendering, it is
|
|
867
|
-
* the only one, so the threshold has nothing to choose between.
|
|
868
|
-
*/
|
|
869
|
-
outlineMinSize?: number;
|
|
870
|
-
}
|
|
871
724
|
/**
|
|
872
|
-
* Lay out `runs` into
|
|
873
|
-
*
|
|
725
|
+
* Lay out `runs` into lines of placed glyphs. Wrapping, baselines and tracking
|
|
726
|
+
* follow the rules in this file's module doc.
|
|
874
727
|
*/
|
|
875
728
|
declare function layoutRuns(runs: readonly ResolvedRun[], opts: LayoutRunsOpts): LaidOutRuns;
|
|
876
729
|
|
|
@@ -880,11 +733,10 @@ declare function layoutRuns(runs: readonly ResolvedRun[], opts: LayoutRunsOpts):
|
|
|
880
733
|
* behind picking, and caret hit-testing all answer from this.
|
|
881
734
|
*
|
|
882
735
|
* `layoutRuns` is the most expensive derivation in the kit — it walks every
|
|
883
|
-
* codepoint, resolves a face per run, measures, wraps, aligns, and places
|
|
884
|
-
*
|
|
885
|
-
*
|
|
886
|
-
* 25.9 for 200 wrapped paragraphs.
|
|
887
|
-
* budget spent before a single triangle is drawn.
|
|
736
|
+
* codepoint, resolves a face per run, measures, wraps, aligns, and places
|
|
737
|
+
* every glyph — and `drawText` ran it per text command per frame. Measured,
|
|
738
|
+
* when it also built the draw groups: 2.0 ms/frame for 200 short labels, 9.3
|
|
739
|
+
* for 1000, and 25.9 for 200 wrapped paragraphs.
|
|
888
740
|
*
|
|
889
741
|
* ### Two keys, tried in order
|
|
890
742
|
*
|
|
@@ -902,30 +754,23 @@ declare function layoutRuns(runs: readonly ResolvedRun[], opts: LayoutRunsOpts):
|
|
|
902
754
|
* second: an identity hit never pays for it.
|
|
903
755
|
*
|
|
904
756
|
* Under either, one entry per distinct `(maxWidth, alignWidth, lineHeight,
|
|
905
|
-
* align,
|
|
906
|
-
* origin-relative geometry and `drawText` translates at
|
|
907
|
-
* dragged across the page keeps hitting the same entry.
|
|
908
|
-
*
|
|
909
|
-
*
|
|
910
|
-
*
|
|
911
|
-
* `outlineMinSize` is derived from the view scale, so recording it literally
|
|
912
|
-
* would miss on every frame of a zoom. It reaches `layoutRuns` through exactly
|
|
913
|
-
* one comparison (`run.fontSize < min`, in `outlineFor`), so what the layout
|
|
914
|
-
* actually depends on is *which runs clear the bar* — and since the test is a
|
|
915
|
-
* plain `>=` on size, that set is pinned by how many of the distinct run sizes
|
|
916
|
-
* clear it. Recording that count is exact, not a quantization: the entry stays
|
|
917
|
-
* valid across every zoom that doesn't cross a glyph size, and is dropped the
|
|
918
|
-
* moment one does.
|
|
757
|
+
* align, direction, bidi engine, tab size)`. Position is deliberately absent:
|
|
758
|
+
* `layoutRuns` emits origin-relative geometry and `drawText` translates at
|
|
759
|
+
* upload, so a text node dragged across the page keeps hitting the same entry.
|
|
760
|
+
* So is everything that only changes what is drawn — a run's fill, stroke and
|
|
761
|
+
* decorations, the outline threshold — which `cachedPaintRuns` keys on
|
|
762
|
+
* instead. Two runs arrays that differ only there share one layout.
|
|
919
763
|
*
|
|
920
764
|
* ### What the keys cannot see
|
|
921
765
|
*
|
|
922
766
|
* The font set. A face landing changes metrics with no change to the runs, so
|
|
923
|
-
* every lookup compares `
|
|
924
|
-
*
|
|
925
|
-
* everything when it moves.
|
|
926
|
-
*
|
|
927
|
-
*
|
|
928
|
-
*
|
|
767
|
+
* every lookup compares `faceGeneration()` — advanced by a registration, a
|
|
768
|
+
* load, a fallback policy, and the dynamic atlas measuring a face again or
|
|
769
|
+
* emptying its pages — and drops everything when it moves. A deferred bake
|
|
770
|
+
* landing does not advance it: that fills in a glyph record the layout
|
|
771
|
+
* already holds, and moves no pen. Polled rather than subscribed: a
|
|
772
|
+
* module-load subscription is a cross-package side effect that makes importing
|
|
773
|
+
* this package require the font package's whole surface.
|
|
929
774
|
*
|
|
930
775
|
* ### Bounds
|
|
931
776
|
*
|
|
@@ -955,4 +800,25 @@ declare function cachedLayoutRuns(runs: readonly ResolvedRun[], opts: LayoutRuns
|
|
|
955
800
|
/** Test helper. Do not call from product code. */
|
|
956
801
|
declare function _resetLayoutCacheForTests(): void;
|
|
957
802
|
|
|
958
|
-
|
|
803
|
+
/**
|
|
804
|
+
* Where the bidi engine arrives. This package cannot import one (see
|
|
805
|
+
* `bidiSeam.ts`), and most callers of `layoutRuns` are kit code a consumer
|
|
806
|
+
* never touches, so the consumer registers it once and every layout finds it.
|
|
807
|
+
*/
|
|
808
|
+
|
|
809
|
+
/**
|
|
810
|
+
* Give every text layout a bidi engine: `registerBidi(bidi)`, with `bidi`
|
|
811
|
+
* from `@weasel-js/bidi`. `layoutRuns` uses it whenever its options carry
|
|
812
|
+
* none. Pass `null`, or call the function returned, to take it out again.
|
|
813
|
+
*/
|
|
814
|
+
declare function registerBidi(engine: BidiResolver | null): () => void;
|
|
815
|
+
/**
|
|
816
|
+
* The direction `text`'s first paragraph reads in: `direction` when it states
|
|
817
|
+
* one, otherwise its first strong character's. Finding that takes an engine,
|
|
818
|
+
* so with none registered the answer is `'ltr'`.
|
|
819
|
+
*/
|
|
820
|
+
declare function paragraphDirection(text: string, direction?: TextDirection | 'auto', engine?: BidiResolver | null): TextDirection;
|
|
821
|
+
/** Test helper. Do not call from product code. */
|
|
822
|
+
declare function _resetBidiWarningForTests(): void;
|
|
823
|
+
|
|
824
|
+
export { _resetLayoutCacheForTests as $, markdownToRuns as A, type BidiAnalysis as B, numericWeight as C, DEFAULT_TEXT_STYLE as D, paragraphDirection as E, type FontVariantCaps as F, registerBidi as G, resolveAlign as H, resolveRunFace as I, resolveRuns as J, resolveTextStyle as K, type LaidOutRuns as L, MARKDOWN_RUN_GRAMMAR as M, runsToMarkdown as N, runsToPlainText as O, type PlacedGlyph as P, scriptMetrics as Q, type ResolvedTextStyle as R, type StyledRun as S, type TextStyle as T, scriptMetricsFor as U, smallCapsScale as V, smallCapsScaleFor as W, smallCapsText as X, toRuns as Y, transformRunTexts as Z, _resetBidiWarningForTests as _, type ResolvedRun as a, type LayoutRunsOpts as b, type TextPaint as c, type BidiReordering as d, type BidiResolver as e, LAYOUT_CACHE_STRUCTURAL_LIMIT as f, LAYOUT_CACHE_VARIANT_LIMIT as g, type LaidOutCell as h, type LaidOutLineBox as i, type RunFlag as j, type RunGrammar as k, type RunMarker as l, type RunSourceMap as m, SCRIPT_METRICS as n, SMALL_CAPS_SCALE as o, type ScriptPreset as p, type SmallCapsText as q, type TextAlign as r, type TextDirection as s, type TextTransform as t, type TransformedRunText as u, cachedLayoutRuns as v, fontString as w, isBoldWeight as x, isSmallCapsLetter as y, layoutRuns as z };
|