@weasel-js/text 1.5.1 → 1.6.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/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- import { resolveTextStyle, resolveAlign, cachedLayoutRuns } from './chunk-JFOVI73B.js';
2
- export { DEFAULT_TEXT_STYLE, LAYOUT_CACHE_STRUCTURAL_LIMIT, LAYOUT_CACHE_VARIANT_LIMIT, cachedLayoutRuns, fontString, layoutRuns, resolveAlign, resolveTextStyle } from './chunk-JFOVI73B.js';
1
+ import { resolveTextStyle, resolveAlign, cachedLayoutRuns, DECORATION_KINDS, decorationRule } from './chunk-GNAAPRO5.js';
2
+ export { DEFAULT_TEXT_STYLE, LAYOUT_CACHE_STRUCTURAL_LIMIT, LAYOUT_CACHE_VARIANT_LIMIT, cachedLayoutRuns, fontString, layoutRuns, resolveAlign, resolveTextStyle } from './chunk-GNAAPRO5.js';
3
3
  import { resolveScreenLength } from '@weasel-js/paint';
4
4
 
5
5
  // src/runs.ts
@@ -118,6 +118,122 @@ function markdownToRuns(input, grammar = MARKDOWN_RUN_GRAMMAR) {
118
118
  flush();
119
119
  return runs;
120
120
  }
121
+
122
+ // src/runs/textTransform.ts
123
+ var TITLE = /* @__PURE__ */ new Map([
124
+ [223, "Ss"],
125
+ [452, "\u01C5"],
126
+ [453, "\u01C5"],
127
+ [454, "\u01C5"],
128
+ [455, "\u01C8"],
129
+ [456, "\u01C8"],
130
+ [457, "\u01C8"],
131
+ [458, "\u01CB"],
132
+ [459, "\u01CB"],
133
+ [460, "\u01CB"],
134
+ [497, "\u01F2"],
135
+ [498, "\u01F2"],
136
+ [499, "\u01F2"],
137
+ [1415, "\u0535\u0582"],
138
+ [64256, "Ff"],
139
+ [64257, "Fi"],
140
+ [64258, "Fl"],
141
+ [64259, "Ffi"],
142
+ [64260, "Ffl"],
143
+ [64261, "St"],
144
+ [64262, "St"],
145
+ [64275, "\u0544\u0576"],
146
+ [64276, "\u0544\u0565"],
147
+ [64277, "\u0544\u056B"],
148
+ [64278, "\u054E\u0576"],
149
+ [64279, "\u0544\u056D"],
150
+ [8115, "\u1FBC"],
151
+ [8124, "\u1FBC"],
152
+ [8131, "\u1FCC"],
153
+ [8140, "\u1FCC"],
154
+ [8179, "\u1FFC"],
155
+ [8188, "\u1FFC"],
156
+ [8114, "\u1FBA\u0345"],
157
+ [8116, "\u0386\u0345"],
158
+ [8119, "\u0391\u0342\u0345"],
159
+ [8130, "\u1FCA\u0345"],
160
+ [8132, "\u0389\u0345"],
161
+ [8135, "\u0397\u0342\u0345"],
162
+ [8178, "\u1FFA\u0345"],
163
+ [8180, "\u038F\u0345"],
164
+ [8183, "\u03A9\u0342\u0345"]
165
+ ]);
166
+ function titlecase(ch) {
167
+ const cp = ch.codePointAt(0);
168
+ if (cp >= 8064 && cp <= 8111) return String.fromCodePoint(cp | 8);
169
+ return TITLE.get(cp) ?? ch.toUpperCase();
170
+ }
171
+ var WORD_FALLBACK = /[\p{L}\p{N}][\p{L}\p{N}\p{M}\p{Pc}'’]*/gu;
172
+ function wordStarts(text) {
173
+ const out = /* @__PURE__ */ new Set();
174
+ if (typeof Intl !== "undefined" && "Segmenter" in Intl) {
175
+ const seg = new Intl.Segmenter(void 0, { granularity: "word" });
176
+ for (const s of seg.segment(text)) if (s.isWordLike) out.add(s.index);
177
+ return out;
178
+ }
179
+ for (const m of text.matchAll(WORD_FALLBACK)) out.add(m.index);
180
+ return out;
181
+ }
182
+ function alignsPerCodePoint(texts, whole, map) {
183
+ let n = 0;
184
+ for (const t of texts) for (const ch of t) n += map(ch).length;
185
+ return n === whole.length;
186
+ }
187
+ var upper = (ch) => ch.toUpperCase();
188
+ var lower = (ch) => ch.toLowerCase();
189
+ function transformRunTexts(texts, transforms) {
190
+ if (transforms.every((t) => t === "none")) return texts.map((text) => ({ text }));
191
+ const full = texts.join("");
192
+ const wholeUpper = transforms.includes("uppercase") ? full.toUpperCase() : "";
193
+ const wholeLower = transforms.includes("lowercase") ? full.toLowerCase() : "";
194
+ const upperAligned = wholeUpper !== "" && alignsPerCodePoint(texts, wholeUpper, upper);
195
+ const lowerAligned = wholeLower !== "" && alignsPerCodePoint(texts, wholeLower, lower);
196
+ const starts = transforms.includes("capitalize") ? wordStarts(full) : null;
197
+ const out = [];
198
+ let base = 0;
199
+ let upOff = 0;
200
+ let lowOff = 0;
201
+ for (let i = 0; i < texts.length; i++) {
202
+ const source = texts[i];
203
+ const t = transforms[i] ?? "none";
204
+ let text = "";
205
+ const srcStarts = [];
206
+ const srcEnds = [];
207
+ let resized = false;
208
+ let local = 0;
209
+ for (const ch of source) {
210
+ const up = upper(ch);
211
+ const lo = lower(ch);
212
+ let piece = ch;
213
+ if (t === "uppercase") {
214
+ piece = upperAligned ? wholeUpper.slice(upOff, upOff + up.length) : up;
215
+ } else if (t === "lowercase") {
216
+ piece = lowerAligned ? wholeLower.slice(lowOff, lowOff + lo.length) : lo;
217
+ } else if (t === "capitalize" && starts.has(base + local) && up !== ch) {
218
+ piece = titlecase(ch);
219
+ }
220
+ upOff += up.length;
221
+ lowOff += lo.length;
222
+ if (piece.length !== ch.length) resized = true;
223
+ text += piece;
224
+ for (let k = 0; k < piece.length; k++) {
225
+ srcStarts.push(local);
226
+ srcEnds.push(local + ch.length);
227
+ }
228
+ local += ch.length;
229
+ }
230
+ out.push(resized ? { text, srcMap: { length: source.length, starts: srcStarts, ends: srcEnds } } : { text });
231
+ base += source.length;
232
+ }
233
+ return out;
234
+ }
235
+
236
+ // src/runs/resolveRuns.ts
121
237
  var SCRIPT_METRICS = Object.freeze({
122
238
  super: Object.freeze({ size: 0.583, shift: 0.333 }),
123
239
  sub: Object.freeze({ size: 0.583, shift: -0.333 })
@@ -132,12 +248,19 @@ function numericWeight(w) {
132
248
  function resolveRuns(runs, style, viewScale = 1) {
133
249
  const out = [];
134
250
  const baseWeight = numericWeight(style.fontWeight);
135
- for (const run of runs) {
251
+ const shown = transformRunTexts(
252
+ runs.map((r) => r.text),
253
+ runs.map((r) => r.textTransform ?? style.textTransform)
254
+ );
255
+ for (let i = 0; i < runs.length; i++) {
256
+ const run = runs[i];
257
+ const { text, srcMap } = shown[i];
136
258
  const script = run.script ? SCRIPT_METRICS[run.script] : void 0;
137
259
  const shiftEm = run.baselineShift ?? script?.shift ?? 0;
138
260
  const scale = run.fontScale ?? script?.size ?? 1;
139
261
  out.push({
140
- text: run.text,
262
+ text,
263
+ ...srcMap ? { srcMap } : {},
141
264
  fontFamily: run.fontFamily ?? style.fontFamily,
142
265
  // An absolute size wins over a relative one; naming both is a consumer
143
266
  // saying "this size exactly", which a multiplier cannot improve on.
@@ -265,8 +388,21 @@ function textLineBoxes(pose, opts = {}) {
265
388
  }
266
389
  return out;
267
390
  }
391
+ function runMetrics(run, fontSize) {
392
+ const script = run.script ? SCRIPT_METRICS[run.script] : void 0;
393
+ const scale = run.fontScale ?? script?.size ?? 1;
394
+ const shiftEm = run.baselineShift ?? script?.shift ?? 0;
395
+ return {
396
+ size: run.fontSize !== void 0 ? resolveScreenLength(run.fontSize, 1) : fontSize * scale,
397
+ // Canvas y grows downward; a positive shift is a rise. Guarded so an
398
+ // unshifted run reports 0 rather than -0.
399
+ y: shiftEm === 0 ? 0 : -shiftEm * fontSize
400
+ };
401
+ }
268
402
  function layoutMarkdown(runs, maxWidth, fontSize, measure, lineHeightFactor = 1.3) {
269
403
  if (runs.length === 0) return { lines: [], width: 0, height: 0 };
404
+ const shown = transformRunTexts(runs.map((r) => r.text), runs.map((r) => r.textTransform ?? "none"));
405
+ runs = runs.map((r, i) => shown[i].text === r.text ? r : { ...r, text: shown[i].text });
270
406
  const lines = [];
271
407
  let currentRuns = [];
272
408
  let lineX = 0;
@@ -280,11 +416,11 @@ function layoutMarkdown(runs, maxWidth, fontSize, measure, lineHeightFactor = 1.
280
416
  lineMaxSize = 0;
281
417
  }
282
418
  function processSegment(segRun) {
283
- const effectiveSize = resolveScreenLength(segRun.fontSize ?? fontSize, 1);
419
+ const { size: effectiveSize, y: runY } = runMetrics(segRun, fontSize);
284
420
  lineMaxSize = Math.max(lineMaxSize, effectiveSize);
285
421
  if (maxWidth === Infinity) {
286
422
  const w = measure(segRun.text, effectiveSize, segRun.bold ?? false, segRun.italic ?? false);
287
- currentRuns.push({ ...segRun, x: lineX });
423
+ currentRuns.push({ ...segRun, x: lineX, width: w, y: runY, size: effectiveSize });
288
424
  lineX += w;
289
425
  return;
290
426
  }
@@ -297,7 +433,7 @@ function layoutMarkdown(runs, maxWidth, fontSize, measure, lineHeightFactor = 1.
297
433
  if (lineX + candidateW > maxWidth && (lineX > 0 || wordBuf.length > 0)) {
298
434
  if (wordBuf.length > 0) {
299
435
  const w = measure(wordBuf, effectiveSize, segRun.bold ?? false, segRun.italic ?? false);
300
- currentRuns.push({ ...segRun, text: wordBuf, x: lineX });
436
+ currentRuns.push({ ...segRun, text: wordBuf, x: lineX, width: w, y: runY, size: effectiveSize });
301
437
  lineX += w;
302
438
  }
303
439
  commitLine();
@@ -309,7 +445,7 @@ function layoutMarkdown(runs, maxWidth, fontSize, measure, lineHeightFactor = 1.
309
445
  }
310
446
  if (wordBuf.length > 0) {
311
447
  const w = measure(wordBuf, effectiveSize, segRun.bold ?? false, segRun.italic ?? false);
312
- currentRuns.push({ ...segRun, text: wordBuf, x: lineX });
448
+ currentRuns.push({ ...segRun, text: wordBuf, x: lineX, width: w, y: runY, size: effectiveSize });
313
449
  lineX += w;
314
450
  }
315
451
  }
@@ -345,38 +481,93 @@ function canvasMeasure(ctx, opts = {}) {
345
481
  return ctx.measureText(text).width;
346
482
  };
347
483
  }
484
+ function alphabeticBaselineBelow(ctx) {
485
+ const current = ctx.textBaseline;
486
+ if (current === "alphabetic") return 0;
487
+ const here = ctx.measureText("").fontBoundingBoxAscent;
488
+ ctx.textBaseline = "alphabetic";
489
+ const alphabetic = ctx.measureText("").fontBoundingBoxAscent;
490
+ ctx.textBaseline = current;
491
+ const d = alphabetic - here;
492
+ return Number.isFinite(d) ? d : 0;
493
+ }
494
+ function blockLeft(ctx, x, width) {
495
+ const rtl = ctx.direction === "rtl";
496
+ switch (ctx.textAlign) {
497
+ case "center":
498
+ return x - width / 2;
499
+ case "right":
500
+ return x - width;
501
+ case "end":
502
+ return rtl ? x : x - width;
503
+ case "start":
504
+ return rtl ? x - width : x;
505
+ default:
506
+ return x;
507
+ }
508
+ }
348
509
  function createMarkdownRenderer(ctx, text, fontSize, maxWidth = Infinity, fontOpts = {}) {
349
510
  const measure = canvasMeasure(ctx, fontOpts);
350
- const parsed = markdownToRuns(text);
511
+ const parsed = typeof text === "string" ? markdownToRuns(text) : text;
351
512
  const layout = layoutMarkdown(parsed, maxWidth, fontSize, measure, fontOpts.lineHeight);
352
- const renderer = (_ctx, _text, x, y) => {
513
+ function walk(c, x, y, drawRun) {
514
+ const align = c.textAlign;
515
+ const left = blockLeft(c, x, layout.width);
516
+ c.textAlign = "left";
353
517
  let lineY = y;
354
- for (const line of layout.lines) {
518
+ layout.lines.forEach((line, li) => {
519
+ const lineLeft = left + (layout.width - line.width) / 2;
355
520
  for (const run of line.runs) {
356
- const effSize = resolveScreenLength(run.fontSize ?? fontSize, 1);
357
- _ctx.font = buildFont(effSize, run.bold ?? false, run.italic ?? false, fontOpts);
358
- _ctx.fillStyle = fontOpts.color ?? (run.italic && !run.bold ? "rgba(255, 255, 255, 0.7)" : "#FFFFFF");
359
- const lineOffset = (layout.width - line.width) / 2;
360
- _ctx.fillText(run.text, x + lineOffset + run.x, lineY);
521
+ c.font = buildFont(run.size, run.bold ?? false, run.italic ?? false, fontOpts);
522
+ drawRun(run, lineLeft + run.x, lineY + run.y, li);
361
523
  }
362
524
  lineY += line.height;
363
- }
525
+ });
526
+ c.textAlign = align;
527
+ }
528
+ const renderer = (_ctx, _text, x, y) => {
529
+ let span = null;
530
+ const flush = () => {
531
+ const s = span;
532
+ span = null;
533
+ if (!s || s.x1 <= s.x0) return;
534
+ _ctx.fillStyle = s.fill;
535
+ for (const kind of DECORATION_KINDS) {
536
+ if (!s.flags[kind]) continue;
537
+ const { y0, y1 } = decorationRule(kind, s.baselineY, s.size);
538
+ _ctx.fillRect(s.x0, y0, s.x1 - s.x0, y1 - y0);
539
+ }
540
+ };
541
+ walk(_ctx, x, y, (run, rx, ry, line) => {
542
+ const fill = fontOpts.color ?? (run.italic && !run.bold ? "rgba(255, 255, 255, 0.7)" : "#FFFFFF");
543
+ _ctx.fillStyle = fill;
544
+ _ctx.fillText(run.text, rx, ry);
545
+ if (!(run.underline || run.strikethrough || run.overline)) {
546
+ flush();
547
+ return;
548
+ }
549
+ const flags = {
550
+ underline: run.underline ?? false,
551
+ strikethrough: run.strikethrough ?? false,
552
+ overline: run.overline ?? false
553
+ };
554
+ const baselineY = ry + alphabeticBaselineBelow(_ctx);
555
+ const open = span;
556
+ if (open !== null && open.line === line && open.x1 === rx && open.fill === fill && open.size === run.size && open.baselineY === baselineY && DECORATION_KINDS.every((k) => open.flags[k] === flags[k])) {
557
+ open.x1 = rx + run.width;
558
+ } else {
559
+ flush();
560
+ span = { flags, fill, size: run.size, baselineY, line, x0: rx, x1: rx + run.width };
561
+ }
562
+ });
563
+ flush();
364
564
  };
365
565
  const strokeRenderer = (_ctx, _text, x, y) => {
366
- let lineY = y;
367
- for (const line of layout.lines) {
368
- for (const run of line.runs) {
369
- const effSize = resolveScreenLength(run.fontSize ?? fontSize, 1);
370
- _ctx.font = buildFont(effSize, run.bold ?? false, run.italic ?? false, fontOpts);
371
- const lineOffset = (layout.width - line.width) / 2;
372
- _ctx.strokeText(run.text, x + lineOffset + run.x, lineY);
373
- }
374
- lineY += line.height;
375
- }
566
+ walk(_ctx, x, y, (run, rx, ry) => _ctx.strokeText(run.text, rx, ry));
376
567
  };
377
568
  return { renderer, strokeRenderer, width: layout.width, height: layout.height };
378
569
  }
379
570
 
380
- export { MARKDOWN_RUN_GRAMMAR, SCRIPT_METRICS, createMarkdownRenderer, layoutMarkdown, layoutTextPose, markdownToRuns, measureText, measureTextBounds, measuredWidth, resolveRuns, runsToMarkdown, runsToPlainText, textLineBoxes, textPoseLayoutInput, toRuns, verticalAlignOffset };
571
+ export { MARKDOWN_RUN_GRAMMAR, SCRIPT_METRICS, createMarkdownRenderer, layoutMarkdown, layoutTextPose, markdownToRuns, measureText, measureTextBounds, measuredWidth, resolveRuns, runsToMarkdown, runsToPlainText, textLineBoxes, textPoseLayoutInput, toRuns, transformRunTexts, verticalAlignOffset };
381
572
  //# sourceMappingURL=index.js.map
382
573
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/runs.ts","../src/runs/resolveRuns.ts","../src/measure/verticalAlign.ts","../src/layout/textPoseLayout.ts","../src/measure/measureText.ts","../src/measure/measureTextBounds.ts","../src/measure/lineBoxes.ts","../src/markdownText.ts"],"names":["resolveScreenLength"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Canonical inline-styling primitive for text nodes. A node's text is\n * either a plain `string` (treated as a single-run, default-styled fragment)\n * or `StyledRun[]` for rich content. `toRuns` is the funnel that normalizes\n * either form into the array shape used by the renderer.\n *\n * Every field except `text` is optional; missing fields fall back to the\n * node-level `TextStyle`. `bold`/`italic` are toggles; richer weight axes\n * (300/500/900) are out of scope for slice 1.\n */\n\nimport type { FillStyle, ScreenLength, Stroke } from '@weasel-js/paint';\n\n/** A span of text with its own styling, as authored. Fields left absent\n * inherit from the node's text style — this is the difference between a run\n * and a fully resolved one. */\nexport interface StyledRun {\n text: string;\n bold?: boolean;\n italic?: boolean;\n fontFamily?: string;\n /** World units, or `{ px }` for screen pixels — resolved against the view\n * scale `resolveRuns` is given, like `TextStyle.fontSize`. */\n fontSize?: ScreenLength;\n fill?: FillStyle;\n /** Outline over this run's glyphs. Overrides the node's own `data.stroke`;\n * absent inherits it. Only painted on the outline tier. */\n stroke?: Stroke;\n /** World units, or `{ px }` for screen pixels. */\n letterSpacing?: ScreenLength;\n underline?: boolean;\n strikethrough?: boolean;\n /** Draw a rule above this run's ascent. Additive over the node style. */\n overline?: boolean;\n /**\n * Set this run as a superscript or subscript — a raised or lowered baseline\n * and a smaller size together, which is the pair `<sup>` and `<sub>` imply.\n *\n * A preset over the two primitives below, not a third mechanism: it supplies\n * a `baselineShift` and a `fontScale`, and naming either of those directly\n * overrides that half while leaving the other alone. The numbers are in\n * {@link SCRIPT_METRICS}.\n */\n script?: 'super' | 'sub';\n /**\n * Raise (positive) or lower (negative) this run off the line's shared\n * baseline, in ems of the *inherited* font size — so a run's rise does not\n * shrink along with the run when `fontScale` also applies.\n */\n baselineShift?: number;\n /**\n * Multiplier on the inherited font size. The relative counterpart to\n * `fontSize`, which pins an absolute size and wins over this when both are\n * present.\n */\n fontScale?: number;\n}\n\n/** Normalize the two accepted spellings of text content — a plain string or\n * an array of runs — to runs. Throws on a run with no string `text`. */\nexport function toRuns(input: string | StyledRun[]): StyledRun[] {\n if (typeof input === 'string') {\n return input.length === 0 ? [] : [{ text: input }];\n }\n for (let i = 0; i < input.length; i++) {\n const r = input[i];\n if (typeof r?.text !== 'string') {\n throw new Error(`toRuns: run at index ${i} is missing string \\`text\\``);\n }\n }\n return input;\n}\n\n/** Concatenate runs, dropping all styling. */\nexport function runsToPlainText(runs: readonly StyledRun[]): string {\n let out = '';\n for (const r of runs) out += r.text;\n return out;\n}\n\n/** A run flag an inline marker can toggle. The additive style toggles on\n * `StyledRun`; the valued fields (family, size, paint, `script`) have no\n * inline spelling and are not addressable this way. */\nexport type RunFlag = 'bold' | 'italic' | 'underline' | 'strikethrough' | 'overline';\n\n/** One inline marker: a delimiter repeated `repeat` times, and the flags it\n * turns on between its opening and closing occurrence. */\nexport interface RunMarker {\n delimiter: string;\n repeat: number;\n flags: readonly RunFlag[];\n}\n\n/**\n * The inline grammar `runsToMarkdown` writes and `markdownToRuns` reads.\n *\n * Markers sharing a delimiter are matched longest-first, which is what lets\n * `***` mean something other than `**` followed by `*`. A backslash escapes\n * any delimiter character and itself, in both directions.\n */\nexport interface RunGrammar {\n markers: readonly RunMarker[];\n}\n\n/**\n * The markdown subset the kit reads and writes: `**bold**`, `*italic*`,\n * `***both***`.\n *\n * Deliberately not the whole of markdown, and deliberately silent on\n * `underline` / `strikethrough` — the two run flags with no entry here are\n * dropped by `runsToMarkdown`, as they always have been. A grammar that wants\n * `~~struck~~` adds one marker; nothing else has to change.\n */\nexport const MARKDOWN_RUN_GRAMMAR: RunGrammar = {\n markers: [\n { delimiter: '*', repeat: 3, flags: ['bold', 'italic'] },\n { delimiter: '*', repeat: 2, flags: ['bold'] },\n { delimiter: '*', repeat: 1, flags: ['italic'] },\n ],\n};\n\n/** Delimiter characters of a grammar, plus the backslash that escapes them. */\nfunction escapees(grammar: RunGrammar): Set<string> {\n const out = new Set<string>(['\\\\']);\n for (const m of grammar.markers) out.add(m.delimiter);\n return out;\n}\n\nfunction escapeFor(text: string, chars: ReadonlySet<string>): string {\n let out = '';\n for (const ch of text) out += chars.has(ch) ? `\\\\${ch}` : ch;\n return out;\n}\n\n/** The flags a run turns on, in the grammar's own marker order so two runs\n * with the same flags always serialize identically. */\nfunction flagsOf(run: StyledRun, grammar: RunGrammar): Set<RunFlag> {\n const on = new Set<RunFlag>();\n for (const m of grammar.markers) {\n for (const f of m.flags) if (run[f]) on.add(f);\n }\n return on;\n}\n\nfunction sameFlags(a: ReadonlySet<RunFlag>, b: readonly RunFlag[]): boolean {\n return a.size === b.length && b.every((f) => a.has(f));\n}\n\n/**\n * Render runs in `grammar`, defaulting to the markdown subset. The flavor\n * written to the clipboard alongside the plain-text one.\n *\n * A run whose flags exactly match one marker takes it; otherwise the markers\n * that cover them nest. Flags no marker spells are dropped — the text still\n * round-trips, without that styling.\n */\nexport function runsToMarkdown(\n runs: readonly StyledRun[],\n grammar: RunGrammar = MARKDOWN_RUN_GRAMMAR,\n): string {\n const chars = escapees(grammar);\n let out = '';\n for (const r of runs) {\n const escaped = escapeFor(r.text, chars);\n const on = flagsOf(r, grammar);\n if (on.size === 0) { out += escaped; continue; }\n\n const exact = grammar.markers.find((m) => sameFlags(on, m.flags));\n if (exact) {\n const d = exact.delimiter.repeat(exact.repeat);\n out += `${d}${escaped}${d}`;\n continue;\n }\n // No single marker says all of it: nest the ones that each say part.\n const covering = grammar.markers.filter(\n (m) => m.flags.length === 1 && on.has(m.flags[0]),\n );\n const open = covering.map((m) => m.delimiter.repeat(m.repeat)).join('');\n const close = [...covering].reverse().map((m) => m.delimiter.repeat(m.repeat)).join('');\n out += `${open}${escaped}${close}`;\n }\n return out;\n}\n\n/**\n * Parse `input` in `grammar`, defaulting to the markdown subset, into styled\n * runs. Newlines are preserved as literal characters inside a run — they are\n * not run-boundary markers in this format.\n */\nexport function markdownToRuns(\n input: string,\n grammar: RunGrammar = MARKDOWN_RUN_GRAMMAR,\n): StyledRun[] {\n const chars = escapees(grammar);\n // Longest-first per delimiter, so `***` is tried before `**` before `*`.\n const byDelimiter = new Map<string, RunMarker[]>();\n for (const m of grammar.markers) {\n const list = byDelimiter.get(m.delimiter) ?? [];\n list.push(m);\n byDelimiter.set(m.delimiter, list);\n }\n for (const list of byDelimiter.values()) list.sort((a, b) => b.repeat - a.repeat);\n\n const runs: StyledRun[] = [];\n const active = new Set<RunFlag>();\n let buf = '';\n let i = 0;\n\n function flush(): void {\n if (buf.length === 0) return;\n const run: StyledRun = { text: buf };\n for (const f of active) run[f] = true;\n runs.push(run);\n buf = '';\n }\n\n while (i < input.length) {\n const ch = input[i];\n\n if (ch === '\\\\' && i + 1 < input.length && chars.has(input[i + 1])) {\n buf += input[i + 1];\n i += 2;\n continue;\n }\n\n const markers = byDelimiter.get(ch);\n if (markers) {\n let count = 0;\n while (i + count < input.length && input[i + count] === ch) count++;\n // The longest marker the delimiter run can pay for. A run shorter than\n // every marker still matches the shortest, which is how a lone `*`\n // toggles italic where `***` toggles both.\n const marker = markers.find((m) => m.repeat <= count) ?? markers[markers.length - 1];\n flush();\n for (const f of marker.flags) {\n if (active.has(f)) active.delete(f);\n else active.add(f);\n }\n i += marker.repeat;\n continue;\n }\n\n buf += ch;\n i++;\n }\n\n flush();\n return runs;\n}\n","/**\n * Apply node-level `ResolvedTextStyle` defaults to each `StyledRun`,\n * producing a fully-resolved run with every styling field set. Downstream\n * layout and draw never re-resolve defaults — `ResolvedRun` is the\n * canonical shape the renderer consumes.\n *\n * `bold`/`italic` toggles on a run are folded into `fontWeight`/`fontStyle`:\n * `bold: true` → fontWeight 700, `italic: true` → fontStyle 'italic'.\n * Explicit `fontFamily` / `fontSize` / `fill` / `letterSpacing` on the run\n * override the node-level value (`letterSpacing: 0` on a run is an override,\n * not an absence — it zeroes inherited tracking).\n *\n * `underline` / `strikethrough` / `overline` are *additive*, like\n * `bold`/`italic`: a run can turn a decoration on but never off, so they\n * resolve as `run.x || style.x` and not `run.x ?? style.x`. See the header of\n * `runs/rangeStyle.ts` for why the model collapses the tri-state.\n *\n * `script` is folded the same way the toggles are, into the two primitives it\n * is a preset over: `baselineShift` and `fontScale`. Both come out as one\n * world-unit `baselineShift` and a final `fontSize`, so layout never learns\n * that superscripts exist — it places a run against a baseline and an offset.\n */\n\nimport type { FillStyle, Stroke } from '@weasel-js/paint';\nimport { resolveScreenLength } from '@weasel-js/paint';\nimport type { StyledRun } from '../runs';\nimport type { ResolvedTextStyle } from '../textStyle';\n\n/** A run with every style resolved against the node's text style — no\n * optional inheritance left. This is what layout and painting consume. */\nexport interface ResolvedRun {\n text: string;\n fontFamily: string;\n fontSize: number;\n fontWeight: number;\n fontStyle: 'normal' | 'italic';\n /** `null` is an explicit no-fill: the glyphs are painted by `stroke` alone,\n * which only the outline tier can do. Nothing is emitted for a run with\n * neither. */\n fill: FillStyle | null;\n /** Outline over this run's glyphs, or absent for none. Painted only on the\n * outline tier — a distance field has no geometry to stroke. */\n stroke?: Stroke;\n /** Extra advance added after each glyph of this run, in world units. */\n letterSpacing: number;\n /** Draw a rule below this run's baseline. Additive over the node style. */\n underline: boolean;\n /** Draw a rule through this run's x-height. Additive over the node style. */\n strikethrough: boolean;\n /** Draw a rule above this run's ascent. Additive over the node style. */\n overline: boolean;\n /**\n * How far this run sits off the line's shared baseline, in world units;\n * positive raises. 0 for ordinary text.\n *\n * Already multiplied out against the inherited font size, and already\n * carrying whatever `script` asked for — layout adds it to a baseline and\n * asks nothing about where it came from.\n */\n baselineShift: number;\n}\n\n/**\n * What `script: 'super'` and `script: 'sub'` expand to, as fractions of the\n * inherited font size: `size` scales it, `shift` raises (positive) or lowers\n * (negative) the baseline.\n *\n * These are Adobe's defaults — InDesign and Illustrator ship 58.3% size and\n * 33.3% position for both — chosen because a drawing tool's users have those\n * numbers in their fingers already. They are not read from the font: the\n * `OS/2` table carries real `ySuperscript*` / `ySubscript*` metrics, but the\n * baked atlas tier has no slot for them (see `layoutRuns`'s note on the\n * decoration constants, which are derived for the same reason), and metrics\n * that applied on one glyph tier and not the other would reflow text as it\n * crossed the size threshold.\n *\n * Exported so a consumer building a character panel can show the percentages\n * it is about to apply. Override either half per run with `baselineShift` /\n * `fontScale`.\n */\nexport const SCRIPT_METRICS: Readonly<\n Record<'super' | 'sub', Readonly<{ size: number; shift: number }>>\n> = Object.freeze({\n super: Object.freeze({ size: 0.583, shift: 0.333 }),\n sub: Object.freeze({ size: 0.583, shift: -0.333 }),\n});\n\nfunction numericWeight(w: number | string): number {\n if (typeof w === 'number') return w;\n if (w === 'bold') return 700;\n if (w === 'normal') return 400;\n const parsed = Number(w);\n return Number.isFinite(parsed) ? parsed : 400;\n}\n\n/** Resolve each run's styling against the node's text style, filling in\n * everything the run left inherited. `viewScale` resolves a run's own\n * `{ px }` size or spacing; the inherited ones arrived already resolved on\n * `style`. */\nexport function resolveRuns(\n runs: readonly StyledRun[],\n style: ResolvedTextStyle,\n viewScale = 1,\n): ResolvedRun[] {\n const out: ResolvedRun[] = [];\n const baseWeight = numericWeight(style.fontWeight);\n for (const run of runs) {\n const script = run.script ? SCRIPT_METRICS[run.script] : undefined;\n // Against the inherited size, not the run's own: a superscript that also\n // shrank its rise would climb less the smaller it got.\n const shiftEm = run.baselineShift ?? script?.shift ?? 0;\n const scale = run.fontScale ?? script?.size ?? 1;\n out.push({\n text: run.text,\n fontFamily: run.fontFamily ?? style.fontFamily,\n // An absolute size wins over a relative one; naming both is a consumer\n // saying \"this size exactly\", which a multiplier cannot improve on.\n fontSize: run.fontSize !== undefined\n ? resolveScreenLength(run.fontSize, viewScale)\n : style.fontSize * scale,\n fontWeight: run.bold ? 700 : baseWeight,\n fontStyle: run.italic ? 'italic' : style.fontStyle,\n fill: run.fill ?? style.fill,\n // Unlike the decorations below, a run's stroke *replaces* the node's\n // rather than adding to it — there is only one outline to paint.\n ...((run.stroke ?? style.stroke) !== undefined\n ? { stroke: run.stroke ?? style.stroke }\n : {}),\n letterSpacing: run.letterSpacing !== undefined\n ? resolveScreenLength(run.letterSpacing, viewScale)\n : style.letterSpacing,\n // `||`, not `??`: run-level decorations are additive over the node style.\n underline: run.underline || style.underline,\n strikethrough: run.strikethrough || style.strikethrough,\n overline: run.overline || style.overline,\n baselineShift: shiftEm * style.fontSize,\n });\n }\n return out;\n}\n","/**\n * Box vertical alignment for text draw commands. Given the command's box\n * `height` and the laid-out text block's height, returns the Y offset to\n * apply to every quad. `'top'` (or an undefined `align`, or a missing box\n * `height`) is the legacy behavior: offset 0.\n */\nexport type TextVerticalAlign = 'top' | 'center' | 'bottom';\n\n/** How far to shift laid-out text down inside a box of `boxHeight` to satisfy\n * a vertical alignment. Zero when the box height is unknown or alignment is\n * top. */\nexport function verticalAlignOffset(\n align: TextVerticalAlign | undefined,\n boxHeight: number | undefined,\n textHeight: number,\n): number {\n if (align === undefined || align === 'top' || boxHeight === undefined) return 0;\n const slack = boxHeight - textHeight;\n return align === 'center' ? slack / 2 : slack;\n}\n","/**\n * How a text pose lays out — the one decision every consumer of a text node\n * reads: the painters (`kit:text`, `createTextLayer`), picking\n * (`textLineBoxes`), the caret (`caretIndexAt`), fitting (`fitTextPose`) and\n * the DOM edit overlay.\n *\n * The pose width is always the box `align` resolves within. It is the wrap\n * width only when the style declares `wrap`; otherwise a line runs as long as\n * its text, whichever of them is asking.\n */\nimport type { LaidOutRuns, LayoutRunsOpts } from './layoutRuns';\nimport { cachedLayoutRuns } from './layoutCache';\nimport { resolveAlign, resolveTextStyle, type ResolvedTextStyle } from '../textStyle';\nimport { resolveRuns, type ResolvedRun } from '../runs/resolveRuns';\nimport { toRuns } from '../runs';\nimport { verticalAlignOffset } from '../measure/verticalAlign';\nimport type { TextPose } from '../pose';\n\n/** What {@link layoutTextPose} hands `cachedLayoutRuns`. */\nexport interface TextPoseLayoutInput {\n style: ResolvedTextStyle;\n runs: ResolvedRun[];\n opts: LayoutRunsOpts & { align: 'left' | 'center' | 'right' };\n}\n\n/**\n * The resolved runs and layout options for `pose`. A text draw command built\n * from these lays out, in the renderer, into exactly the lines\n * {@link layoutTextPose} reports.\n *\n * `scale` is the view scale a `{ px }` `fontSize` or `letterSpacing` resolves\n * against. Everything past this point is world units, so a caller that\n * measures, hit-tests or paints one pose has to pass the same scale to each\n * or they disagree.\n */\nexport function textPoseLayoutInput(pose: TextPose, scale = 1): TextPoseLayoutInput {\n const style = resolveTextStyle(pose.style, { fill: pose.fill, stroke: pose.stroke }, scale);\n // Empty runs are not a styling, so they fall back to the plain string\n // rather than lay out nothing.\n const source = pose.runs && pose.runs.length > 0 ? pose.runs : pose.text;\n return {\n style,\n runs: resolveRuns(toRuns(source), style, scale),\n opts: {\n maxWidth: style.wrap ? pose.width : Infinity,\n alignWidth: pose.width,\n lineHeight: style.lineHeight,\n align: resolveAlign(style.align, style.direction),\n },\n };\n}\n\n/** A text pose laid out. */\nexport interface TextPoseLayout {\n /** Origin-relative, shared with the layout cache — treat as immutable. */\n laid: LaidOutRuns;\n /** World position of the layout's origin: `pose.x`, and `pose.y` shifted by\n * `verticalAlign` within the pose height. */\n x: number;\n y: number;\n}\n\n/** The lines `pose` lays out into, and where they sit in world space. */\nexport function layoutTextPose(pose: TextPose, scale = 1): TextPoseLayout {\n const { runs, opts } = textPoseLayoutInput(pose, scale);\n const laid = cachedLayoutRuns(runs, opts);\n return {\n laid,\n x: pose.x,\n y: pose.y + verticalAlignOffset(pose.verticalAlign, pose.height, laid.bounds.height),\n };\n}\n","/**\n * Wrap-aware text measurement. Greedy word-wrap against `maxWidth` using\n * `ctx.measureText`. Lines explicitly broken by `\\n` are preserved; long\n * single words that exceed `maxWidth` are emitted on their own line without\n * mid-word breaking (caller can decide to clip).\n *\n * Returns the laid-out lines, the total block height in world units\n * (`lines.length * fontSize * lineHeight`), and per-line `lineStarts` —\n * the offset of each line's first character in the original `text`. The\n * starts are used by `caretIndexAt` to map a clicked (x, y) back to a\n * character offset in the source string. Trailing whitespace consumed by\n * the wrap is not included in `lines[i]` but is implicit in the gap\n * between `lineStarts[i] + lines[i].length` and `lineStarts[i + 1]`.\n *\n * The caller owns the `ctx.font` setup — pass a context whose `font`\n * already matches `style` (use `fontString(style)`).\n */\n\nimport type { ResolvedTextStyle } from '../textStyle';\n\n/**\n * Advance width of `text` in world units, tracking included.\n *\n * `letter-spacing` is not part of the CSS `font` shorthand, so a context\n * whose `font` was set from `fontString(style)` measures glyphs only. The\n * GL path (`layoutRuns`) adds `letterSpacing` after **every** code point\n * including the last, matching CSS, so this does too — and every 2D-side\n * width has to go through here or the two paths disagree about where a line\n * breaks.\n */\nexport function measuredWidth(\n ctx: CanvasRenderingContext2D,\n text: string,\n style: ResolvedTextStyle,\n): number {\n return ctx.measureText(text).width + text.length * style.letterSpacing;\n}\n\n/** Result of `measureText`: wrapped lines, per-line source offsets, and total block height. */\nexport interface MeasuredText {\n lines: string[];\n lineStarts: number[];\n height: number;\n}\n\n/** Greedy word-wrap text measurement against `maxWidth`; preserves explicit `\\n` breaks. */\nexport function measureText(\n ctx: CanvasRenderingContext2D,\n text: string,\n maxWidth: number,\n style: ResolvedTextStyle,\n): MeasuredText {\n const lines: string[] = [];\n const lineStarts: number[] = [];\n const paragraphs = text.split('\\n');\n\n let pos = 0;\n for (let pi = 0; pi < paragraphs.length; pi++) {\n if (pi > 0) pos += 1; // step past the '\\n' between paragraphs\n const paragraph = paragraphs[pi];\n if (paragraph === '') {\n lines.push('');\n lineStarts.push(pos);\n continue;\n }\n const words = paragraph.split(/(\\s+)/).filter((w) => w.length > 0);\n let current = '';\n let currentStart = pos;\n let consumed = 0; // chars of `paragraph` we've already accounted for\n for (const word of words) {\n if (current === '') currentStart = pos + consumed;\n const candidate = current + word;\n if (current === '' || measuredWidth(ctx, candidate, style) <= maxWidth) {\n current = candidate;\n } else {\n lines.push(current.trimEnd());\n lineStarts.push(currentStart);\n if (/^\\s+$/.test(word)) {\n current = '';\n } else {\n current = word;\n currentStart = pos + consumed;\n }\n }\n consumed += word.length;\n }\n lines.push(current.trimEnd());\n lineStarts.push(currentStart);\n pos += paragraph.length;\n }\n\n const height = lines.length * style.fontSize * style.lineHeight;\n return { lines, lineStarts, height };\n}\n","import type { TextStyle } from '../textStyle';\nimport { resolveTextStyle } from '../textStyle';\nimport { resolveRuns } from '../runs/resolveRuns';\nimport { cachedLayoutRuns } from '../layout/layoutCache';\n\n/** Options for `measureTextBounds`. */\nexport interface MeasureTextBoundsOpts {\n /** Wrap width; words exceeding it start a new line. Default `Infinity` (no wrap). */\n maxWidth?: number;\n /** Overrides `style`'s `lineHeight` multiplier for this measurement. */\n lineHeight?: number;\n /** View scale any `{ px }` size in `style` resolves against. Default 1,\n * which measures a `{ px }` size as that many world units. */\n scale?: number;\n}\n\n/**\n * Measure how the GL/MSDF renderer will lay out a single plain-text string,\n * using the registered font atlas metrics. Mirrors {@link textCommand} exactly\n * (`resolveTextStyle` → `resolveRuns` → `cachedLayoutRuns`), so the returned\n * bounds match what actually gets drawn — use it to size backgrounds/pills, place\n * labels, or test overlap without guessing widths.\n *\n * Pass `opts.maxWidth` to measure word-wrapped height (e.g. for a fixed-width\n * text box); omitting it measures the unwrapped single-line width. `opts.lineHeight`\n * overrides the style's multiplier without changing `style` itself.\n *\n * Returns `{ width, height }` in the same units as `style.fontSize`. The font\n * must already be registered via `registerFont`; an unregistered family falls\n * back to the atlas fallback glyph (and warns), so register fonts at app boot\n * before measuring.\n */\nexport function measureTextBounds(\n text: string,\n style?: TextStyle,\n opts?: MeasureTextBoundsOpts,\n): { width: number; height: number } {\n const resolved = resolveTextStyle(style, undefined, opts?.scale);\n const runs = resolveRuns([{ text }], resolved, opts?.scale);\n const { bounds } = cachedLayoutRuns(runs, {\n maxWidth: opts?.maxWidth ?? Infinity,\n lineHeight: opts?.lineHeight ?? resolved.lineHeight,\n align: resolved.align,\n });\n // Copied: the layout behind it is shared, and handing a caller a mutable\n // reference into a cache entry is how one measurement corrupts the next.\n return { width: bounds.width, height: bounds.height };\n}\n","/**\n * Where a text node's lines actually sit inside its pose box.\n *\n * A text pose is a layout box, not a bounding box: `\"Away\"` in a 309-unit-wide\n * box leaves most of the box empty, and anything that treats the pose as the\n * node's extent — picking, lasso, clipping, SVG export — claims that empty\n * space. `textLineBoxes` returns the per-line rectangles instead.\n *\n * The numbers come from `layoutTextPose`, the layout every painter of a text\n * pose draws, so the boxes cannot drift from what is painted — they wrap only\n * where the style declares `wrap`, and honor `align` and `verticalAlign`.\n *\n * These are line boxes, not ink boxes: each is `fontSize * lineHeight` tall\n * from the pen's line top. Ink can escape vertically at a `lineHeight` low\n * enough — see the `bounds` note at the end of `layoutRuns` — which is the\n * right trade for hit-testing, where a box that hugged the ink would make\n * an `x` harder to click than an `X`.\n */\n\nimport type { Rect } from '@weasel-js/geom';\nimport { layoutTextPose } from '../layout/textPoseLayout';\nimport type { TextPose } from '../pose';\n\n/** Options for {@link textLineBoxes}. */\nexport interface TextLineBoxesOpts {\n /** Grow every box by this much on all four sides (world units). Default 0.\n * Picking wants a little slack so a single hairline row of text is still\n * grabbable; clipping and export want none. */\n padding?: number;\n /** Keep boxes for blank lines (zero width). Default `false` — a blank line\n * covers no area, so for hit-testing and silhouettes it is noise. Pass\n * `true` when the indices have to line up with the laid-out lines. */\n includeEmpty?: boolean;\n}\n\n/** Per-line rectangles for a text pose, in world units, in layout order. */\nexport function textLineBoxes(pose: TextPose, opts: TextLineBoxesOpts = {}): Rect[] {\n const padding = opts.padding ?? 0;\n const { laid, x: dx, y: dy } = layoutTextPose(pose);\n\n const out: Rect[] = [];\n for (const line of laid.lines) {\n if (!opts.includeEmpty && line.x1 <= line.x0) continue;\n out.push({\n x: line.x0 + dx - padding,\n y: line.y0 + dy - padding,\n width: line.x1 - line.x0 + padding * 2,\n height: line.y1 - line.y0 + padding * 2,\n });\n }\n return out;\n}\n","import { resolveScreenLength } from '@weasel-js/paint';\nimport { markdownToRuns, type StyledRun } from './runs';\n\nexport type { StyledRun };\n\n/** Width-measurement strategy for `layoutMarkdown`; canvas-backed default supplied by `createMarkdownRenderer`. */\nexport type MeasureFn = (text: string, fontSize: number, bold: boolean, italic: boolean) => number;\n\n/** A `StyledRun` with its computed x-offset relative to the start of its line. */\nexport interface PositionedRun extends StyledRun {\n x: number;\n}\n\n/** A single laid-out line of text: its positioned runs, total width, and computed line height. */\nexport interface LayoutLine {\n runs: PositionedRun[];\n width: number;\n height: number;\n}\n\n/** Output of `layoutMarkdown`: per-line breakdown plus overall block dimensions. */\nexport interface LayoutResult {\n lines: LayoutLine[];\n width: number;\n height: number;\n}\n\n/** Word-wrap parsed runs into lines bounded by `maxWidth`; pass `Infinity` for single-line layout. */\nexport function layoutMarkdown(\n runs: StyledRun[],\n maxWidth: number,\n fontSize: number,\n measure: MeasureFn,\n lineHeightFactor: number = 1.3,\n): LayoutResult {\n if (runs.length === 0) return { lines: [], width: 0, height: 0 };\n\n const lines: LayoutLine[] = [];\n let currentRuns: PositionedRun[] = [];\n let lineX = 0;\n let lineMaxSize = 0;\n\n function commitLine() {\n const effectiveFontSize = lineMaxSize > 0 ? lineMaxSize : fontSize;\n const lineHeight = effectiveFontSize * lineHeightFactor;\n lines.push({ runs: currentRuns, width: lineX, height: lineHeight });\n currentRuns = [];\n lineX = 0;\n lineMaxSize = 0;\n }\n\n function processSegment(segRun: StyledRun) {\n // Already a screen-pixel layout, so a run's `{ px }` size is its size.\n const effectiveSize = resolveScreenLength(segRun.fontSize ?? fontSize, 1);\n lineMaxSize = Math.max(lineMaxSize, effectiveSize);\n\n if (maxWidth === Infinity) {\n const w = measure(segRun.text, effectiveSize, segRun.bold ?? false, segRun.italic ?? false);\n currentRuns.push({ ...segRun, x: lineX });\n lineX += w;\n return;\n }\n\n // Word-wrap: split run text by spaces\n const words = segRun.text.split(/ /);\n let wordBuf = '';\n\n for (let wi = 0; wi < words.length; wi++) {\n const word = words[wi];\n const candidate = wordBuf.length > 0 ? wordBuf + ' ' + word : word;\n const candidateW = measure(candidate, effectiveSize, segRun.bold ?? false, segRun.italic ?? false);\n\n if (lineX + candidateW > maxWidth && (lineX > 0 || wordBuf.length > 0)) {\n // Flush current wordBuf as a run on the current line\n if (wordBuf.length > 0) {\n const w = measure(wordBuf, effectiveSize, segRun.bold ?? false, segRun.italic ?? false);\n currentRuns.push({ ...segRun, text: wordBuf, x: lineX });\n lineX += w;\n }\n commitLine();\n lineMaxSize = Math.max(lineMaxSize, effectiveSize);\n wordBuf = word;\n } else {\n // Either fits, or is an oversized single word starting a fresh line — accept it\n wordBuf = candidate;\n }\n }\n\n // Flush remaining wordBuf\n if (wordBuf.length > 0) {\n const w = measure(wordBuf, effectiveSize, segRun.bold ?? false, segRun.italic ?? false);\n currentRuns.push({ ...segRun, text: wordBuf, x: lineX });\n lineX += w;\n }\n }\n\n for (const run of runs) {\n // markdownToRuns embeds newlines inside runs; split on '\\n' so each\n // segment becomes its own line via commitLine().\n const segments = run.text.split('\\n');\n for (let si = 0; si < segments.length; si++) {\n if (si > 0) commitLine();\n const seg = segments[si];\n if (seg.length > 0) {\n processSegment({ ...run, text: seg });\n }\n }\n }\n\n // Commit final line\n if (currentRuns.length > 0) {\n commitLine();\n }\n\n const width = Math.max(...lines.map((l) => l.width));\n const height = lines.reduce((sum, l) => sum + l.height, 0);\n return { lines, width, height };\n}\n\n/** Pluggable text-painting strategy. The default fills white at `(x, y)`; markdown renderers replace this. */\nexport type TextRenderer = (\n ctx: CanvasRenderingContext2D,\n text: string,\n x: number,\n y: number,\n) => void;\n\n/** Font styling options threaded through `createMarkdownRenderer`. */\nexport interface MarkdownFontOptions {\n /** Font-family spec (e.g. `'\"Iowan Old Style\", Georgia, serif'`). Defaults to `sans-serif`. */\n family?: string;\n /** Numeric weight applied to non-bold runs. Bold runs always use `bold`. Default `normal`. */\n weight?: string | number;\n /** Override fill color. When set, used for all runs (italic and bold). */\n color?: string;\n /** Multiplier applied to font size for line height. Default 1.3. */\n lineHeight?: number;\n}\n\nfunction buildFont(\n fontSize: number,\n bold: boolean,\n italic: boolean,\n opts: MarkdownFontOptions = {},\n): string {\n const family = opts.family ?? 'sans-serif';\n const weight = bold ? 'bold' : (opts.weight !== undefined ? String(opts.weight) : 'normal');\n const parts: string[] = [];\n if (italic) parts.push('italic');\n parts.push(weight);\n parts.push(`${fontSize}px ${family}`);\n return parts.join(' ');\n}\n\nfunction canvasMeasure(ctx: CanvasRenderingContext2D, opts: MarkdownFontOptions = {}): MeasureFn {\n return (text, fontSize, bold, italic) => {\n ctx.font = buildFont(fontSize, bold, italic, opts);\n return ctx.measureText(text).width;\n };\n}\n\n/** Build a fill+stroke `TextRenderer` pair for a markdown string at the given size; pre-computes layout once. */\nexport function createMarkdownRenderer(\n ctx: CanvasRenderingContext2D,\n text: string,\n fontSize: number,\n maxWidth: number = Infinity,\n fontOpts: MarkdownFontOptions = {},\n): { renderer: TextRenderer; strokeRenderer: TextRenderer; width: number; height: number } {\n const measure = canvasMeasure(ctx, fontOpts);\n const parsed = markdownToRuns(text);\n const layout = layoutMarkdown(parsed, maxWidth, fontSize, measure, fontOpts.lineHeight);\n\n const renderer: TextRenderer = (_ctx, _text, x, y) => {\n let lineY = y;\n for (const line of layout.lines) {\n for (const run of line.runs) {\n const effSize = resolveScreenLength(run.fontSize ?? fontSize, 1);\n _ctx.font = buildFont(effSize, run.bold ?? false, run.italic ?? false, fontOpts);\n _ctx.fillStyle = fontOpts.color\n ?? (run.italic && !run.bold ? 'rgba(255, 255, 255, 0.7)' : '#FFFFFF');\n const lineOffset = (layout.width - line.width) / 2;\n _ctx.fillText(run.text, x + lineOffset + run.x, lineY);\n }\n lineY += line.height;\n }\n };\n\n const strokeRenderer: TextRenderer = (_ctx, _text, x, y) => {\n let lineY = y;\n for (const line of layout.lines) {\n for (const run of line.runs) {\n const effSize = resolveScreenLength(run.fontSize ?? fontSize, 1);\n _ctx.font = buildFont(effSize, run.bold ?? false, run.italic ?? false, fontOpts);\n const lineOffset = (layout.width - line.width) / 2;\n _ctx.strokeText(run.text, x + lineOffset + run.x, lineY);\n }\n lineY += line.height;\n }\n };\n\n return { renderer, strokeRenderer, width: layout.width, height: layout.height };\n}\n"]}
1
+ {"version":3,"sources":["../src/runs.ts","../src/runs/textTransform.ts","../src/runs/resolveRuns.ts","../src/measure/verticalAlign.ts","../src/layout/textPoseLayout.ts","../src/measure/measureText.ts","../src/measure/measureTextBounds.ts","../src/measure/lineBoxes.ts","../src/markdownText.ts"],"names":["resolveScreenLength"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Canonical inline-styling primitive for text nodes. A node's text is\n * either a plain `string` (treated as a single-run, default-styled fragment)\n * or `StyledRun[]` for rich content. `toRuns` is the funnel that normalizes\n * either form into the array shape used by the renderer.\n *\n * Every field except `text` is optional; missing fields fall back to the\n * node-level `TextStyle`. `bold`/`italic` are toggles; richer weight axes\n * (300/500/900) are out of scope for slice 1.\n */\n\nimport type { FillStyle, ScreenLength, Stroke } from '@weasel-js/paint';\nimport type { TextTransform } from './runs/textTransform';\n\n/** A span of text with its own styling, as authored. Fields left absent\n * inherit from the node's text style — this is the difference between a run\n * and a fully resolved one. */\nexport interface StyledRun {\n text: string;\n bold?: boolean;\n italic?: boolean;\n fontFamily?: string;\n /** World units, or `{ px }` for screen pixels — resolved against the view\n * scale `resolveRuns` is given, like `TextStyle.fontSize`. */\n fontSize?: ScreenLength;\n fill?: FillStyle;\n /** Outline over this run's glyphs. Overrides the node's own `data.stroke`;\n * absent inherits it. Only painted on the outline tier. */\n stroke?: Stroke;\n /** World units, or `{ px }` for screen pixels. */\n letterSpacing?: ScreenLength;\n underline?: boolean;\n strikethrough?: boolean;\n /** Draw a rule above this run's ascent. Additive over the node style. */\n overline?: boolean;\n /**\n * Set this run as a superscript or subscript — a raised or lowered baseline\n * and a smaller size together, which is the pair `<sup>` and `<sub>` imply.\n *\n * A preset over the two primitives below, not a third mechanism: it supplies\n * a `baselineShift` and a `fontScale`, and naming either of those directly\n * overrides that half while leaving the other alone. The numbers are in\n * {@link SCRIPT_METRICS}.\n */\n script?: 'super' | 'sub';\n /**\n * Raise (positive) or lower (negative) this run off the line's shared\n * baseline, in ems of the *inherited* font size — so a run's rise does not\n * shrink along with the run when `fontScale` also applies.\n */\n baselineShift?: number;\n /**\n * Multiplier on the inherited font size. The relative counterpart to\n * `fontSize`, which pins an absolute size and wins over this when both are\n * present.\n */\n fontScale?: number;\n /**\n * CSS `text-transform` for this run's display. The run's `text` stays as\n * authored — carets, selections and edits address it — and only what is\n * drawn changes. Overrides the node's own; `'none'` turns an inherited one\n * off.\n */\n textTransform?: TextTransform;\n}\n\n/** Normalize the two accepted spellings of text content — a plain string or\n * an array of runs — to runs. Throws on a run with no string `text`. */\nexport function toRuns(input: string | StyledRun[]): StyledRun[] {\n if (typeof input === 'string') {\n return input.length === 0 ? [] : [{ text: input }];\n }\n for (let i = 0; i < input.length; i++) {\n const r = input[i];\n if (typeof r?.text !== 'string') {\n throw new Error(`toRuns: run at index ${i} is missing string \\`text\\``);\n }\n }\n return input;\n}\n\n/** Concatenate runs, dropping all styling. */\nexport function runsToPlainText(runs: readonly StyledRun[]): string {\n let out = '';\n for (const r of runs) out += r.text;\n return out;\n}\n\n/** A run flag an inline marker can toggle. The additive style toggles on\n * `StyledRun`; the valued fields (family, size, paint, `script`) have no\n * inline spelling and are not addressable this way. */\nexport type RunFlag = 'bold' | 'italic' | 'underline' | 'strikethrough' | 'overline';\n\n/** One inline marker: a delimiter repeated `repeat` times, and the flags it\n * turns on between its opening and closing occurrence. */\nexport interface RunMarker {\n delimiter: string;\n repeat: number;\n flags: readonly RunFlag[];\n}\n\n/**\n * The inline grammar `runsToMarkdown` writes and `markdownToRuns` reads.\n *\n * Markers sharing a delimiter are matched longest-first, which is what lets\n * `***` mean something other than `**` followed by `*`. A backslash escapes\n * any delimiter character and itself, in both directions.\n */\nexport interface RunGrammar {\n markers: readonly RunMarker[];\n}\n\n/**\n * The markdown subset the kit reads and writes: `**bold**`, `*italic*`,\n * `***both***`.\n *\n * Deliberately not the whole of markdown, and deliberately silent on\n * `underline` / `strikethrough` — the two run flags with no entry here are\n * dropped by `runsToMarkdown`, as they always have been. A grammar that wants\n * `~~struck~~` adds one marker; nothing else has to change.\n */\nexport const MARKDOWN_RUN_GRAMMAR: RunGrammar = {\n markers: [\n { delimiter: '*', repeat: 3, flags: ['bold', 'italic'] },\n { delimiter: '*', repeat: 2, flags: ['bold'] },\n { delimiter: '*', repeat: 1, flags: ['italic'] },\n ],\n};\n\n/** Delimiter characters of a grammar, plus the backslash that escapes them. */\nfunction escapees(grammar: RunGrammar): Set<string> {\n const out = new Set<string>(['\\\\']);\n for (const m of grammar.markers) out.add(m.delimiter);\n return out;\n}\n\nfunction escapeFor(text: string, chars: ReadonlySet<string>): string {\n let out = '';\n for (const ch of text) out += chars.has(ch) ? `\\\\${ch}` : ch;\n return out;\n}\n\n/** The flags a run turns on, in the grammar's own marker order so two runs\n * with the same flags always serialize identically. */\nfunction flagsOf(run: StyledRun, grammar: RunGrammar): Set<RunFlag> {\n const on = new Set<RunFlag>();\n for (const m of grammar.markers) {\n for (const f of m.flags) if (run[f]) on.add(f);\n }\n return on;\n}\n\nfunction sameFlags(a: ReadonlySet<RunFlag>, b: readonly RunFlag[]): boolean {\n return a.size === b.length && b.every((f) => a.has(f));\n}\n\n/**\n * Render runs in `grammar`, defaulting to the markdown subset. The flavor\n * written to the clipboard alongside the plain-text one.\n *\n * A run whose flags exactly match one marker takes it; otherwise the markers\n * that cover them nest. Flags no marker spells are dropped — the text still\n * round-trips, without that styling.\n */\nexport function runsToMarkdown(\n runs: readonly StyledRun[],\n grammar: RunGrammar = MARKDOWN_RUN_GRAMMAR,\n): string {\n const chars = escapees(grammar);\n let out = '';\n for (const r of runs) {\n const escaped = escapeFor(r.text, chars);\n const on = flagsOf(r, grammar);\n if (on.size === 0) { out += escaped; continue; }\n\n const exact = grammar.markers.find((m) => sameFlags(on, m.flags));\n if (exact) {\n const d = exact.delimiter.repeat(exact.repeat);\n out += `${d}${escaped}${d}`;\n continue;\n }\n // No single marker says all of it: nest the ones that each say part.\n const covering = grammar.markers.filter(\n (m) => m.flags.length === 1 && on.has(m.flags[0]),\n );\n const open = covering.map((m) => m.delimiter.repeat(m.repeat)).join('');\n const close = [...covering].reverse().map((m) => m.delimiter.repeat(m.repeat)).join('');\n out += `${open}${escaped}${close}`;\n }\n return out;\n}\n\n/**\n * Parse `input` in `grammar`, defaulting to the markdown subset, into styled\n * runs. Newlines are preserved as literal characters inside a run — they are\n * not run-boundary markers in this format.\n */\nexport function markdownToRuns(\n input: string,\n grammar: RunGrammar = MARKDOWN_RUN_GRAMMAR,\n): StyledRun[] {\n const chars = escapees(grammar);\n // Longest-first per delimiter, so `***` is tried before `**` before `*`.\n const byDelimiter = new Map<string, RunMarker[]>();\n for (const m of grammar.markers) {\n const list = byDelimiter.get(m.delimiter) ?? [];\n list.push(m);\n byDelimiter.set(m.delimiter, list);\n }\n for (const list of byDelimiter.values()) list.sort((a, b) => b.repeat - a.repeat);\n\n const runs: StyledRun[] = [];\n const active = new Set<RunFlag>();\n let buf = '';\n let i = 0;\n\n function flush(): void {\n if (buf.length === 0) return;\n const run: StyledRun = { text: buf };\n for (const f of active) run[f] = true;\n runs.push(run);\n buf = '';\n }\n\n while (i < input.length) {\n const ch = input[i];\n\n if (ch === '\\\\' && i + 1 < input.length && chars.has(input[i + 1])) {\n buf += input[i + 1];\n i += 2;\n continue;\n }\n\n const markers = byDelimiter.get(ch);\n if (markers) {\n let count = 0;\n while (i + count < input.length && input[i + count] === ch) count++;\n // The longest marker the delimiter run can pay for. A run shorter than\n // every marker still matches the shortest, which is how a lone `*`\n // toggles italic where `***` toggles both.\n const marker = markers.find((m) => m.repeat <= count) ?? markers[markers.length - 1];\n flush();\n for (const f of marker.flags) {\n if (active.has(f)) active.delete(f);\n else active.add(f);\n }\n i += marker.repeat;\n continue;\n }\n\n buf += ch;\n i++;\n }\n\n flush();\n return runs;\n}\n","/**\n * CSS `text-transform` over styled runs: `uppercase`, `lowercase` and\n * `capitalize`, with the source offsets each transformed character came from.\n *\n * Case mapping is not length-preserving — `'ß'.toUpperCase()` is `'SS'` — and\n * every caret, selection and hit-test in the kit addresses the *source* text.\n * So a transform that changes a code point's length reports a\n * {@link RunSourceMap} alongside the text, and layout reads each cell's source\n * span off it instead of counting the characters it drew.\n */\n\n/** The CSS `text-transform` keywords the run model carries. `none` is an\n * explicit override: a run can turn off a transform it would inherit. */\nexport type TextTransform = 'none' | 'uppercase' | 'lowercase' | 'capitalize';\n\n/**\n * Where each UTF-16 unit of a transformed run's text came from in its source,\n * as run-relative offsets. `starts[i]` / `ends[i]` bound the source code point\n * that produced output unit `i`, so the two units `ß` uppercases to share one\n * span. `length` is the source run's own length.\n */\nexport interface RunSourceMap {\n length: number;\n starts: readonly number[];\n ends: readonly number[];\n}\n\n/** A run's text after its transform. `srcMap` is present only when some code\n * point changed length — otherwise output offsets are source offsets. */\nexport interface TransformedRunText {\n text: string;\n srcMap?: RunSourceMap;\n}\n\n/** Title-case mappings that differ from the uppercase one (UnicodeData and\n * SpecialCasing). Everything absent titlecases as it uppercases. */\nconst TITLE: ReadonlyMap<number, string> = new Map<number, string>([\n [0x00df, 'Ss'],\n [0x01c4, 'Dž'], [0x01c5, 'Dž'], [0x01c6, 'Dž'],\n [0x01c7, 'Lj'], [0x01c8, 'Lj'], [0x01c9, 'Lj'],\n [0x01ca, 'Nj'], [0x01cb, 'Nj'], [0x01cc, 'Nj'],\n [0x01f1, 'Dz'], [0x01f2, 'Dz'], [0x01f3, 'Dz'],\n [0x0587, 'Եւ'],\n [0xfb00, 'Ff'], [0xfb01, 'Fi'], [0xfb02, 'Fl'], [0xfb03, 'Ffi'], [0xfb04, 'Ffl'],\n [0xfb05, 'St'], [0xfb06, 'St'],\n [0xfb13, 'Մն'], [0xfb14, 'Մե'], [0xfb15, 'Մի'],\n [0xfb16, 'Վն'], [0xfb17, 'Մխ'],\n [0x1fb3, 'ᾼ'], [0x1fbc, 'ᾼ'],\n [0x1fc3, 'ῌ'], [0x1fcc, 'ῌ'],\n [0x1ff3, 'ῼ'], [0x1ffc, 'ῼ'],\n [0x1fb2, 'Ὰͅ'], [0x1fb4, 'Άͅ'], [0x1fb7, 'ᾼ͂'],\n [0x1fc2, 'Ὴͅ'], [0x1fc4, 'Ήͅ'], [0x1fc7, 'ῌ͂'],\n [0x1ff2, 'Ὼͅ'], [0x1ff4, 'Ώͅ'], [0x1ff7, 'ῼ͂'],\n]);\n\nfunction titlecase(ch: string): string {\n const cp = ch.codePointAt(0)!;\n // Greek with ypogegrammeni: the titlecase form keeps the iota subscript,\n // where uppercase spells it out as a capital iota.\n if (cp >= 0x1f80 && cp <= 0x1faf) return String.fromCodePoint(cp | 0x8);\n return TITLE.get(cp) ?? ch.toUpperCase();\n}\n\nconst WORD_FALLBACK = /[\\p{L}\\p{N}][\\p{L}\\p{N}\\p{M}\\p{Pc}'’]*/gu;\n\n/** Source offsets at which a word begins, by the same UAX #29 word boundaries\n * browsers use for `capitalize`. */\nfunction wordStarts(text: string): Set<number> {\n const out = new Set<number>();\n if (typeof Intl !== 'undefined' && 'Segmenter' in Intl) {\n const seg = new Intl.Segmenter(undefined, { granularity: 'word' });\n for (const s of seg.segment(text)) if (s.isWordLike) out.add(s.index);\n return out;\n }\n for (const m of text.matchAll(WORD_FALLBACK)) out.add(m.index!);\n return out;\n}\n\n/** Whether mapping `full` per code point, run by run, produces exactly the\n * units `whole` does — true unless a mapping spans a run boundary. */\nfunction alignsPerCodePoint(\n texts: readonly string[], whole: string, map: (ch: string) => string,\n): boolean {\n let n = 0;\n for (const t of texts) for (const ch of t) n += map(ch).length;\n return n === whole.length;\n}\n\nconst upper = (ch: string): string => ch.toUpperCase();\nconst lower = (ch: string): string => ch.toLowerCase();\n\n/**\n * Apply each run's transform to its text. `texts[i]` is transformed by\n * `transforms[i]`; the runs are read as one paragraph, so final sigma and\n * `capitalize`'s word starts see across run boundaries — a word split by\n * styling still gets one capital.\n *\n * Mappings are the locale-independent ones JavaScript's `toUpperCase` /\n * `toLowerCase` implement, which include `ß` → `SS` and final sigma.\n * `capitalize` titlecases the first code point of each word when it has a\n * case to change, and leaves every other character as it was.\n */\nexport function transformRunTexts(\n texts: readonly string[],\n transforms: readonly TextTransform[],\n): TransformedRunText[] {\n if (transforms.every((t) => t === 'none')) return texts.map((text) => ({ text }));\n\n const full = texts.join('');\n // Lowercasing is contextual (final sigma), so the per-code-point pieces are\n // read out of the whole paragraph's mapping wherever the two align.\n const wholeUpper = transforms.includes('uppercase') ? full.toUpperCase() : '';\n const wholeLower = transforms.includes('lowercase') ? full.toLowerCase() : '';\n const upperAligned = wholeUpper !== '' && alignsPerCodePoint(texts, wholeUpper, upper);\n const lowerAligned = wholeLower !== '' && alignsPerCodePoint(texts, wholeLower, lower);\n const starts = transforms.includes('capitalize') ? wordStarts(full) : null;\n\n const out: TransformedRunText[] = [];\n let base = 0;\n let upOff = 0;\n let lowOff = 0;\n for (let i = 0; i < texts.length; i++) {\n const source = texts[i];\n const t = transforms[i] ?? 'none';\n let text = '';\n const srcStarts: number[] = [];\n const srcEnds: number[] = [];\n let resized = false;\n let local = 0;\n for (const ch of source) {\n const up = upper(ch);\n const lo = lower(ch);\n let piece = ch;\n if (t === 'uppercase') {\n piece = upperAligned ? wholeUpper.slice(upOff, upOff + up.length) : up;\n } else if (t === 'lowercase') {\n piece = lowerAligned ? wholeLower.slice(lowOff, lowOff + lo.length) : lo;\n } else if (t === 'capitalize' && starts!.has(base + local) && up !== ch) {\n piece = titlecase(ch);\n }\n upOff += up.length;\n lowOff += lo.length;\n if (piece.length !== ch.length) resized = true;\n text += piece;\n for (let k = 0; k < piece.length; k++) {\n srcStarts.push(local);\n srcEnds.push(local + ch.length);\n }\n local += ch.length;\n }\n out.push(resized\n ? { text, srcMap: { length: source.length, starts: srcStarts, ends: srcEnds } }\n : { text });\n base += source.length;\n }\n return out;\n}\n","/**\n * Apply node-level `ResolvedTextStyle` defaults to each `StyledRun`,\n * producing a fully-resolved run with every styling field set. Downstream\n * layout and draw never re-resolve defaults — `ResolvedRun` is the\n * canonical shape the renderer consumes.\n *\n * `bold`/`italic` toggles on a run are folded into `fontWeight`/`fontStyle`:\n * `bold: true` → fontWeight 700, `italic: true` → fontStyle 'italic'.\n * Explicit `fontFamily` / `fontSize` / `fill` / `letterSpacing` on the run\n * override the node-level value (`letterSpacing: 0` on a run is an override,\n * not an absence — it zeroes inherited tracking).\n *\n * `underline` / `strikethrough` / `overline` are *additive*, like\n * `bold`/`italic`: a run can turn a decoration on but never off, so they\n * resolve as `run.x || style.x` and not `run.x ?? style.x`. See the header of\n * `runs/rangeStyle.ts` for why the model collapses the tri-state.\n *\n * `script` is folded the same way the toggles are, into the two primitives it\n * is a preset over: `baselineShift` and `fontScale`. Both come out as one\n * world-unit `baselineShift` and a final `fontSize`, so layout never learns\n * that superscripts exist — it places a run against a baseline and an offset.\n *\n * `textTransform` is applied here too, so `text` is what gets drawn. When a\n * transform changes a length, `srcMap` says which source characters each\n * drawn one came from; see `textTransform.ts`.\n */\n\nimport type { FillStyle, Stroke } from '@weasel-js/paint';\nimport { resolveScreenLength } from '@weasel-js/paint';\nimport type { StyledRun } from '../runs';\nimport type { ResolvedTextStyle } from '../textStyle';\nimport { transformRunTexts, type RunSourceMap } from './textTransform';\n\n/** A run with every style resolved against the node's text style — no\n * optional inheritance left. This is what layout and painting consume. */\nexport interface ResolvedRun {\n /** The text as drawn — after `textTransform`, so not necessarily the\n * run's source text. */\n text: string;\n /** Present when `text` differs in length from the source it was\n * transformed from: where each of its UTF-16 units came from. Absent\n * means `text`'s offsets are the source's. */\n srcMap?: RunSourceMap;\n fontFamily: string;\n fontSize: number;\n fontWeight: number;\n fontStyle: 'normal' | 'italic';\n /** `null` is an explicit no-fill: the glyphs are painted by `stroke` alone,\n * which only the outline tier can do. Nothing is emitted for a run with\n * neither. */\n fill: FillStyle | null;\n /** Outline over this run's glyphs, or absent for none. Painted only on the\n * outline tier — a distance field has no geometry to stroke. */\n stroke?: Stroke;\n /** Extra advance added after each glyph of this run, in world units. */\n letterSpacing: number;\n /** Draw a rule below this run's baseline. Additive over the node style. */\n underline: boolean;\n /** Draw a rule through this run's x-height. Additive over the node style. */\n strikethrough: boolean;\n /** Draw a rule above this run's ascent. Additive over the node style. */\n overline: boolean;\n /**\n * How far this run sits off the line's shared baseline, in world units;\n * positive raises. 0 for ordinary text.\n *\n * Already multiplied out against the inherited font size, and already\n * carrying whatever `script` asked for — layout adds it to a baseline and\n * asks nothing about where it came from.\n */\n baselineShift: number;\n}\n\n/**\n * What `script: 'super'` and `script: 'sub'` expand to, as fractions of the\n * inherited font size: `size` scales it, `shift` raises (positive) or lowers\n * (negative) the baseline.\n *\n * These are Adobe's defaults — InDesign and Illustrator ship 58.3% size and\n * 33.3% position for both — chosen because a drawing tool's users have those\n * numbers in their fingers already. They are not read from the font: the\n * `OS/2` table carries real `ySuperscript*` / `ySubscript*` metrics, but the\n * baked atlas tier has no slot for them (see `layoutRuns`'s note on the\n * decoration constants, which are derived for the same reason), and metrics\n * that applied on one glyph tier and not the other would reflow text as it\n * crossed the size threshold.\n *\n * Exported so a consumer building a character panel can show the percentages\n * it is about to apply. Override either half per run with `baselineShift` /\n * `fontScale`.\n */\nexport const SCRIPT_METRICS: Readonly<\n Record<'super' | 'sub', Readonly<{ size: number; shift: number }>>\n> = Object.freeze({\n super: Object.freeze({ size: 0.583, shift: 0.333 }),\n sub: Object.freeze({ size: 0.583, shift: -0.333 }),\n});\n\nfunction numericWeight(w: number | string): number {\n if (typeof w === 'number') return w;\n if (w === 'bold') return 700;\n if (w === 'normal') return 400;\n const parsed = Number(w);\n return Number.isFinite(parsed) ? parsed : 400;\n}\n\n/** Resolve each run's styling against the node's text style, filling in\n * everything the run left inherited. `viewScale` resolves a run's own\n * `{ px }` size or spacing; the inherited ones arrived already resolved on\n * `style`. */\nexport function resolveRuns(\n runs: readonly StyledRun[],\n style: ResolvedTextStyle,\n viewScale = 1,\n): ResolvedRun[] {\n const out: ResolvedRun[] = [];\n const baseWeight = numericWeight(style.fontWeight);\n const shown = transformRunTexts(\n runs.map((r) => r.text),\n runs.map((r) => r.textTransform ?? style.textTransform),\n );\n for (let i = 0; i < runs.length; i++) {\n const run = runs[i];\n const { text, srcMap } = shown[i];\n const script = run.script ? SCRIPT_METRICS[run.script] : undefined;\n // Against the inherited size, not the run's own: a superscript that also\n // shrank its rise would climb less the smaller it got.\n const shiftEm = run.baselineShift ?? script?.shift ?? 0;\n const scale = run.fontScale ?? script?.size ?? 1;\n out.push({\n text,\n ...(srcMap ? { srcMap } : {}),\n fontFamily: run.fontFamily ?? style.fontFamily,\n // An absolute size wins over a relative one; naming both is a consumer\n // saying \"this size exactly\", which a multiplier cannot improve on.\n fontSize: run.fontSize !== undefined\n ? resolveScreenLength(run.fontSize, viewScale)\n : style.fontSize * scale,\n fontWeight: run.bold ? 700 : baseWeight,\n fontStyle: run.italic ? 'italic' : style.fontStyle,\n fill: run.fill ?? style.fill,\n // Unlike the decorations below, a run's stroke *replaces* the node's\n // rather than adding to it — there is only one outline to paint.\n ...((run.stroke ?? style.stroke) !== undefined\n ? { stroke: run.stroke ?? style.stroke }\n : {}),\n letterSpacing: run.letterSpacing !== undefined\n ? resolveScreenLength(run.letterSpacing, viewScale)\n : style.letterSpacing,\n // `||`, not `??`: run-level decorations are additive over the node style.\n underline: run.underline || style.underline,\n strikethrough: run.strikethrough || style.strikethrough,\n overline: run.overline || style.overline,\n baselineShift: shiftEm * style.fontSize,\n });\n }\n return out;\n}\n","/**\n * Box vertical alignment for text draw commands. Given the command's box\n * `height` and the laid-out text block's height, returns the Y offset to\n * apply to every quad. `'top'` (or an undefined `align`, or a missing box\n * `height`) is the legacy behavior: offset 0.\n */\nexport type TextVerticalAlign = 'top' | 'center' | 'bottom';\n\n/** How far to shift laid-out text down inside a box of `boxHeight` to satisfy\n * a vertical alignment. Zero when the box height is unknown or alignment is\n * top. */\nexport function verticalAlignOffset(\n align: TextVerticalAlign | undefined,\n boxHeight: number | undefined,\n textHeight: number,\n): number {\n if (align === undefined || align === 'top' || boxHeight === undefined) return 0;\n const slack = boxHeight - textHeight;\n return align === 'center' ? slack / 2 : slack;\n}\n","/**\n * How a text pose lays out — the one decision every consumer of a text node\n * reads: the painters (`kit:text`, `createTextLayer`), picking\n * (`textLineBoxes`), the caret (`caretIndexAt`), fitting (`fitTextPose`) and\n * the DOM edit overlay.\n *\n * The pose width is always the box `align` resolves within. It is the wrap\n * width only when the style declares `wrap`; otherwise a line runs as long as\n * its text, whichever of them is asking.\n */\nimport type { LaidOutRuns, LayoutRunsOpts } from './layoutRuns';\nimport { cachedLayoutRuns } from './layoutCache';\nimport { resolveAlign, resolveTextStyle, type ResolvedTextStyle } from '../textStyle';\nimport { resolveRuns, type ResolvedRun } from '../runs/resolveRuns';\nimport { toRuns } from '../runs';\nimport { verticalAlignOffset } from '../measure/verticalAlign';\nimport type { TextPose } from '../pose';\n\n/** What {@link layoutTextPose} hands `cachedLayoutRuns`. */\nexport interface TextPoseLayoutInput {\n style: ResolvedTextStyle;\n runs: ResolvedRun[];\n opts: LayoutRunsOpts & { align: 'left' | 'center' | 'right' };\n}\n\n/**\n * The resolved runs and layout options for `pose`. A text draw command built\n * from these lays out, in the renderer, into exactly the lines\n * {@link layoutTextPose} reports.\n *\n * `scale` is the view scale a `{ px }` `fontSize` or `letterSpacing` resolves\n * against. Everything past this point is world units, so a caller that\n * measures, hit-tests or paints one pose has to pass the same scale to each\n * or they disagree.\n */\nexport function textPoseLayoutInput(pose: TextPose, scale = 1): TextPoseLayoutInput {\n const style = resolveTextStyle(pose.style, { fill: pose.fill, stroke: pose.stroke }, scale);\n // Empty runs are not a styling, so they fall back to the plain string\n // rather than lay out nothing.\n const source = pose.runs && pose.runs.length > 0 ? pose.runs : pose.text;\n return {\n style,\n runs: resolveRuns(toRuns(source), style, scale),\n opts: {\n maxWidth: style.wrap ? pose.width : Infinity,\n alignWidth: pose.width,\n lineHeight: style.lineHeight,\n align: resolveAlign(style.align, style.direction),\n },\n };\n}\n\n/** A text pose laid out. */\nexport interface TextPoseLayout {\n /** Origin-relative, shared with the layout cache — treat as immutable. */\n laid: LaidOutRuns;\n /** World position of the layout's origin: `pose.x`, and `pose.y` shifted by\n * `verticalAlign` within the pose height. */\n x: number;\n y: number;\n}\n\n/** The lines `pose` lays out into, and where they sit in world space. */\nexport function layoutTextPose(pose: TextPose, scale = 1): TextPoseLayout {\n const { runs, opts } = textPoseLayoutInput(pose, scale);\n const laid = cachedLayoutRuns(runs, opts);\n return {\n laid,\n x: pose.x,\n y: pose.y + verticalAlignOffset(pose.verticalAlign, pose.height, laid.bounds.height),\n };\n}\n","/**\n * Wrap-aware text measurement. Greedy word-wrap against `maxWidth` using\n * `ctx.measureText`. Lines explicitly broken by `\\n` are preserved; long\n * single words that exceed `maxWidth` are emitted on their own line without\n * mid-word breaking (caller can decide to clip).\n *\n * Returns the laid-out lines, the total block height in world units\n * (`lines.length * fontSize * lineHeight`), and per-line `lineStarts` —\n * the offset of each line's first character in the original `text`. The\n * starts are used by `caretIndexAt` to map a clicked (x, y) back to a\n * character offset in the source string. Trailing whitespace consumed by\n * the wrap is not included in `lines[i]` but is implicit in the gap\n * between `lineStarts[i] + lines[i].length` and `lineStarts[i + 1]`.\n *\n * The caller owns the `ctx.font` setup — pass a context whose `font`\n * already matches `style` (use `fontString(style)`).\n */\n\nimport type { ResolvedTextStyle } from '../textStyle';\n\n/**\n * Advance width of `text` in world units, tracking included.\n *\n * `letter-spacing` is not part of the CSS `font` shorthand, so a context\n * whose `font` was set from `fontString(style)` measures glyphs only. The\n * GL path (`layoutRuns`) adds `letterSpacing` after **every** code point\n * including the last, matching CSS, so this does too — and every 2D-side\n * width has to go through here or the two paths disagree about where a line\n * breaks.\n */\nexport function measuredWidth(\n ctx: CanvasRenderingContext2D,\n text: string,\n style: ResolvedTextStyle,\n): number {\n return ctx.measureText(text).width + text.length * style.letterSpacing;\n}\n\n/** Result of `measureText`: wrapped lines, per-line source offsets, and total block height. */\nexport interface MeasuredText {\n lines: string[];\n lineStarts: number[];\n height: number;\n}\n\n/** Greedy word-wrap text measurement against `maxWidth`; preserves explicit `\\n` breaks. */\nexport function measureText(\n ctx: CanvasRenderingContext2D,\n text: string,\n maxWidth: number,\n style: ResolvedTextStyle,\n): MeasuredText {\n const lines: string[] = [];\n const lineStarts: number[] = [];\n const paragraphs = text.split('\\n');\n\n let pos = 0;\n for (let pi = 0; pi < paragraphs.length; pi++) {\n if (pi > 0) pos += 1; // step past the '\\n' between paragraphs\n const paragraph = paragraphs[pi];\n if (paragraph === '') {\n lines.push('');\n lineStarts.push(pos);\n continue;\n }\n const words = paragraph.split(/(\\s+)/).filter((w) => w.length > 0);\n let current = '';\n let currentStart = pos;\n let consumed = 0; // chars of `paragraph` we've already accounted for\n for (const word of words) {\n if (current === '') currentStart = pos + consumed;\n const candidate = current + word;\n if (current === '' || measuredWidth(ctx, candidate, style) <= maxWidth) {\n current = candidate;\n } else {\n lines.push(current.trimEnd());\n lineStarts.push(currentStart);\n if (/^\\s+$/.test(word)) {\n current = '';\n } else {\n current = word;\n currentStart = pos + consumed;\n }\n }\n consumed += word.length;\n }\n lines.push(current.trimEnd());\n lineStarts.push(currentStart);\n pos += paragraph.length;\n }\n\n const height = lines.length * style.fontSize * style.lineHeight;\n return { lines, lineStarts, height };\n}\n","import type { TextStyle } from '../textStyle';\nimport { resolveTextStyle } from '../textStyle';\nimport { resolveRuns } from '../runs/resolveRuns';\nimport { cachedLayoutRuns } from '../layout/layoutCache';\n\n/** Options for `measureTextBounds`. */\nexport interface MeasureTextBoundsOpts {\n /** Wrap width; words exceeding it start a new line. Default `Infinity` (no wrap). */\n maxWidth?: number;\n /** Overrides `style`'s `lineHeight` multiplier for this measurement. */\n lineHeight?: number;\n /** View scale any `{ px }` size in `style` resolves against. Default 1,\n * which measures a `{ px }` size as that many world units. */\n scale?: number;\n}\n\n/**\n * Measure how the GL/MSDF renderer will lay out a single plain-text string,\n * using the registered font atlas metrics. Mirrors {@link textCommand} exactly\n * (`resolveTextStyle` → `resolveRuns` → `cachedLayoutRuns`), so the returned\n * bounds match what actually gets drawn — use it to size backgrounds/pills, place\n * labels, or test overlap without guessing widths.\n *\n * Pass `opts.maxWidth` to measure word-wrapped height (e.g. for a fixed-width\n * text box); omitting it measures the unwrapped single-line width. `opts.lineHeight`\n * overrides the style's multiplier without changing `style` itself.\n *\n * Returns `{ width, height }` in the same units as `style.fontSize`. The font\n * must already be registered via `registerFont`; an unregistered family falls\n * back to the atlas fallback glyph (and warns), so register fonts at app boot\n * before measuring.\n */\nexport function measureTextBounds(\n text: string,\n style?: TextStyle,\n opts?: MeasureTextBoundsOpts,\n): { width: number; height: number } {\n const resolved = resolveTextStyle(style, undefined, opts?.scale);\n const runs = resolveRuns([{ text }], resolved, opts?.scale);\n const { bounds } = cachedLayoutRuns(runs, {\n maxWidth: opts?.maxWidth ?? Infinity,\n lineHeight: opts?.lineHeight ?? resolved.lineHeight,\n align: resolved.align,\n });\n // Copied: the layout behind it is shared, and handing a caller a mutable\n // reference into a cache entry is how one measurement corrupts the next.\n return { width: bounds.width, height: bounds.height };\n}\n","/**\n * Where a text node's lines actually sit inside its pose box.\n *\n * A text pose is a layout box, not a bounding box: `\"Away\"` in a 309-unit-wide\n * box leaves most of the box empty, and anything that treats the pose as the\n * node's extent — picking, lasso, clipping, SVG export — claims that empty\n * space. `textLineBoxes` returns the per-line rectangles instead.\n *\n * The numbers come from `layoutTextPose`, the layout every painter of a text\n * pose draws, so the boxes cannot drift from what is painted — they wrap only\n * where the style declares `wrap`, and honor `align` and `verticalAlign`.\n *\n * These are line boxes, not ink boxes: each is `fontSize * lineHeight` tall\n * from the pen's line top. Ink can escape vertically at a `lineHeight` low\n * enough — see the `bounds` note at the end of `layoutRuns` — which is the\n * right trade for hit-testing, where a box that hugged the ink would make\n * an `x` harder to click than an `X`.\n */\n\nimport type { Rect } from '@weasel-js/geom';\nimport { layoutTextPose } from '../layout/textPoseLayout';\nimport type { TextPose } from '../pose';\n\n/** Options for {@link textLineBoxes}. */\nexport interface TextLineBoxesOpts {\n /** Grow every box by this much on all four sides (world units). Default 0.\n * Picking wants a little slack so a single hairline row of text is still\n * grabbable; clipping and export want none. */\n padding?: number;\n /** Keep boxes for blank lines (zero width). Default `false` — a blank line\n * covers no area, so for hit-testing and silhouettes it is noise. Pass\n * `true` when the indices have to line up with the laid-out lines. */\n includeEmpty?: boolean;\n}\n\n/** Per-line rectangles for a text pose, in world units, in layout order. */\nexport function textLineBoxes(pose: TextPose, opts: TextLineBoxesOpts = {}): Rect[] {\n const padding = opts.padding ?? 0;\n const { laid, x: dx, y: dy } = layoutTextPose(pose);\n\n const out: Rect[] = [];\n for (const line of laid.lines) {\n if (!opts.includeEmpty && line.x1 <= line.x0) continue;\n out.push({\n x: line.x0 + dx - padding,\n y: line.y0 + dy - padding,\n width: line.x1 - line.x0 + padding * 2,\n height: line.y1 - line.y0 + padding * 2,\n });\n }\n return out;\n}\n","import { resolveScreenLength } from '@weasel-js/paint';\nimport { markdownToRuns, type StyledRun } from './runs';\nimport { SCRIPT_METRICS } from './runs/resolveRuns';\nimport { DECORATION_KINDS, decorationRule, type DecorationKind } from './layout/decorationMetrics';\nimport { transformRunTexts } from './runs/textTransform';\n\nexport type { StyledRun };\n\n/** Width-measurement strategy for `layoutMarkdown`; canvas-backed default supplied by `createMarkdownRenderer`. */\nexport type MeasureFn = (text: string, fontSize: number, bold: boolean, italic: boolean) => number;\n\n/** A `StyledRun` with its resolved size and its position relative to the\n * start of its line: `x` along the line, `y` off its baseline. */\nexport interface PositionedRun extends StyledRun {\n x: number;\n /** Advance width, as the layout's `MeasureFn` measured it. */\n width: number;\n /** Baseline offset, positive down — a superscript's is negative. Add it to\n * the line's baseline when painting. */\n y: number;\n /** The run's font size in px, with `fontScale` and `script` already folded\n * in. Resolved once here so layout and paint cannot disagree about it. */\n size: number;\n}\n\n/**\n * A run's size and baseline offset, resolved the way `resolveRuns` resolves\n * them for the GL path: an absolute `fontSize` wins over a multiplier, and\n * the rise is measured against the *inherited* size so it does not shrink\n * along with the run.\n */\nfunction runMetrics(run: StyledRun, fontSize: number): { size: number; y: number } {\n const script = run.script ? SCRIPT_METRICS[run.script] : undefined;\n const scale = run.fontScale ?? script?.size ?? 1;\n const shiftEm = run.baselineShift ?? script?.shift ?? 0;\n return {\n size: run.fontSize !== undefined\n ? resolveScreenLength(run.fontSize, 1)\n : fontSize * scale,\n // Canvas y grows downward; a positive shift is a rise. Guarded so an\n // unshifted run reports 0 rather than -0.\n y: shiftEm === 0 ? 0 : -shiftEm * fontSize,\n };\n}\n\n/** A single laid-out line of text: its positioned runs, total width, and computed line height. */\nexport interface LayoutLine {\n runs: PositionedRun[];\n width: number;\n height: number;\n}\n\n/** Output of `layoutMarkdown`: per-line breakdown plus overall block dimensions. */\nexport interface LayoutResult {\n lines: LayoutLine[];\n width: number;\n height: number;\n}\n\n/** Word-wrap parsed runs into lines bounded by `maxWidth`; pass `Infinity` for single-line layout. */\nexport function layoutMarkdown(\n runs: StyledRun[],\n maxWidth: number,\n fontSize: number,\n measure: MeasureFn,\n lineHeightFactor: number = 1.3,\n): LayoutResult {\n if (runs.length === 0) return { lines: [], width: 0, height: 0 };\n // No caret reads this layout, so the transformed text simply replaces the source.\n const shown = transformRunTexts(runs.map((r) => r.text), runs.map((r) => r.textTransform ?? 'none'));\n runs = runs.map((r, i) => (shown[i].text === r.text ? r : { ...r, text: shown[i].text }));\n\n const lines: LayoutLine[] = [];\n let currentRuns: PositionedRun[] = [];\n let lineX = 0;\n let lineMaxSize = 0;\n\n function commitLine() {\n const effectiveFontSize = lineMaxSize > 0 ? lineMaxSize : fontSize;\n const lineHeight = effectiveFontSize * lineHeightFactor;\n lines.push({ runs: currentRuns, width: lineX, height: lineHeight });\n currentRuns = [];\n lineX = 0;\n lineMaxSize = 0;\n }\n\n function processSegment(segRun: StyledRun) {\n // Already a screen-pixel layout, so a run's `{ px }` size is its size.\n const { size: effectiveSize, y: runY } = runMetrics(segRun, fontSize);\n lineMaxSize = Math.max(lineMaxSize, effectiveSize);\n\n if (maxWidth === Infinity) {\n const w = measure(segRun.text, effectiveSize, segRun.bold ?? false, segRun.italic ?? false);\n currentRuns.push({ ...segRun, x: lineX, width: w, y: runY, size: effectiveSize });\n lineX += w;\n return;\n }\n\n // Word-wrap: split run text by spaces\n const words = segRun.text.split(/ /);\n let wordBuf = '';\n\n for (let wi = 0; wi < words.length; wi++) {\n const word = words[wi];\n const candidate = wordBuf.length > 0 ? wordBuf + ' ' + word : word;\n const candidateW = measure(candidate, effectiveSize, segRun.bold ?? false, segRun.italic ?? false);\n\n if (lineX + candidateW > maxWidth && (lineX > 0 || wordBuf.length > 0)) {\n // Flush current wordBuf as a run on the current line\n if (wordBuf.length > 0) {\n const w = measure(wordBuf, effectiveSize, segRun.bold ?? false, segRun.italic ?? false);\n currentRuns.push({ ...segRun, text: wordBuf, x: lineX, width: w, y: runY, size: effectiveSize });\n lineX += w;\n }\n commitLine();\n lineMaxSize = Math.max(lineMaxSize, effectiveSize);\n wordBuf = word;\n } else {\n // Either fits, or is an oversized single word starting a fresh line — accept it\n wordBuf = candidate;\n }\n }\n\n // Flush remaining wordBuf\n if (wordBuf.length > 0) {\n const w = measure(wordBuf, effectiveSize, segRun.bold ?? false, segRun.italic ?? false);\n currentRuns.push({ ...segRun, text: wordBuf, x: lineX, width: w, y: runY, size: effectiveSize });\n lineX += w;\n }\n }\n\n for (const run of runs) {\n // markdownToRuns embeds newlines inside runs; split on '\\n' so each\n // segment becomes its own line via commitLine().\n const segments = run.text.split('\\n');\n for (let si = 0; si < segments.length; si++) {\n if (si > 0) commitLine();\n const seg = segments[si];\n if (seg.length > 0) {\n processSegment({ ...run, text: seg });\n }\n }\n }\n\n // Commit final line\n if (currentRuns.length > 0) {\n commitLine();\n }\n\n const width = Math.max(...lines.map((l) => l.width));\n const height = lines.reduce((sum, l) => sum + l.height, 0);\n return { lines, width, height };\n}\n\n/** Pluggable text-painting strategy. The default fills white at `(x, y)`; markdown renderers replace this. */\nexport type TextRenderer = (\n ctx: CanvasRenderingContext2D,\n text: string,\n x: number,\n y: number,\n) => void;\n\n/** Font styling options threaded through `createMarkdownRenderer`. */\nexport interface MarkdownFontOptions {\n /** Font-family spec (e.g. `'\"Iowan Old Style\", Georgia, serif'`). Defaults to `sans-serif`. */\n family?: string;\n /** Numeric weight applied to non-bold runs. Bold runs always use `bold`. Default `normal`. */\n weight?: string | number;\n /** Override fill color. When set, used for all runs (italic and bold). */\n color?: string;\n /** Multiplier applied to font size for line height. Default 1.3. */\n lineHeight?: number;\n}\n\nfunction buildFont(\n fontSize: number,\n bold: boolean,\n italic: boolean,\n opts: MarkdownFontOptions = {},\n): string {\n const family = opts.family ?? 'sans-serif';\n const weight = bold ? 'bold' : (opts.weight !== undefined ? String(opts.weight) : 'normal');\n const parts: string[] = [];\n if (italic) parts.push('italic');\n parts.push(weight);\n parts.push(`${fontSize}px ${family}`);\n return parts.join(' ');\n}\n\nfunction canvasMeasure(ctx: CanvasRenderingContext2D, opts: MarkdownFontOptions = {}): MeasureFn {\n return (text, fontSize, bold, italic) => {\n ctx.font = buildFont(fontSize, bold, italic, opts);\n return ctx.measureText(text).width;\n };\n}\n\n/** Distance from the context's current `textBaseline` down to the alphabetic\n * baseline, for the font already set on it; 0 where the metric is missing. */\nfunction alphabeticBaselineBelow(ctx: CanvasRenderingContext2D): number {\n const current = ctx.textBaseline;\n if (current === 'alphabetic') return 0;\n const here = ctx.measureText('').fontBoundingBoxAscent;\n ctx.textBaseline = 'alphabetic';\n const alphabetic = ctx.measureText('').fontBoundingBoxAscent;\n ctx.textBaseline = current;\n const d = alphabetic - here;\n return Number.isFinite(d) ? d : 0;\n}\n\n/** Where a block `width` wide starts, given the x the context aligns it to. */\nfunction blockLeft(ctx: CanvasRenderingContext2D, x: number, width: number): number {\n const rtl = ctx.direction === 'rtl';\n switch (ctx.textAlign) {\n case 'center': return x - width / 2;\n case 'right': return x - width;\n case 'end': return rtl ? x : x - width;\n case 'start': return rtl ? x - width : x;\n default: return x;\n }\n}\n\n/**\n * Build a fill+stroke `TextRenderer` pair, laying the text out once.\n *\n * `text` is markdown, read by `markdownToRuns`, or runs already styled. The\n * block is placed by the context's `textAlign` and each run by its\n * `textBaseline`. The fill pass also paints underline, strikethrough and\n * overline in their run's fill, placed by the same metrics as the GL tier;\n * the stroke pass paints no rules, as on the GL tier.\n */\nexport function createMarkdownRenderer(\n ctx: CanvasRenderingContext2D,\n text: string | StyledRun[],\n fontSize: number,\n maxWidth: number = Infinity,\n fontOpts: MarkdownFontOptions = {},\n): { renderer: TextRenderer; strokeRenderer: TextRenderer; width: number; height: number } {\n const measure = canvasMeasure(ctx, fontOpts);\n const parsed = typeof text === 'string' ? markdownToRuns(text) : text;\n const layout = layoutMarkdown(parsed, maxWidth, fontSize, measure, fontOpts.lineHeight);\n\n /** Walk the layout, setting each run's font and handing over its\n * left-aligned paint position and the index of its line. */\n function walk(\n c: CanvasRenderingContext2D,\n x: number,\n y: number,\n drawRun: (run: PositionedRun, rx: number, ry: number, lineIndex: number) => void,\n ): void {\n const align = c.textAlign;\n const left = blockLeft(c, x, layout.width);\n c.textAlign = 'left';\n let lineY = y;\n layout.lines.forEach((line, li) => {\n const lineLeft = left + (layout.width - line.width) / 2;\n for (const run of line.runs) {\n c.font = buildFont(run.size, run.bold ?? false, run.italic ?? false, fontOpts);\n drawRun(run, lineLeft + run.x, lineY + run.y, li);\n }\n lineY += line.height;\n });\n c.textAlign = align;\n }\n\n const renderer: TextRenderer = (_ctx, _text, x, y) => {\n interface Span {\n flags: Record<DecorationKind, boolean>;\n fill: string;\n size: number;\n baselineY: number;\n line: number;\n x0: number;\n x1: number;\n }\n let span: Span | null = null;\n const flush = (): void => {\n const s = span;\n span = null;\n if (!s || s.x1 <= s.x0) return;\n _ctx.fillStyle = s.fill;\n for (const kind of DECORATION_KINDS) {\n if (!s.flags[kind]) continue;\n const { y0, y1 } = decorationRule(kind, s.baselineY, s.size);\n _ctx.fillRect(s.x0, y0, s.x1 - s.x0, y1 - y0);\n }\n };\n\n walk(_ctx, x, y, (run, rx, ry, line) => {\n const fill = fontOpts.color\n ?? (run.italic && !run.bold ? 'rgba(255, 255, 255, 0.7)' : '#FFFFFF');\n _ctx.fillStyle = fill;\n _ctx.fillText(run.text, rx, ry);\n\n if (!(run.underline || run.strikethrough || run.overline)) {\n flush();\n return;\n }\n const flags: Record<DecorationKind, boolean> = {\n underline: run.underline ?? false,\n strikethrough: run.strikethrough ?? false,\n overline: run.overline ?? false,\n };\n const baselineY = ry + alphabeticBaselineBelow(_ctx);\n const open = span;\n if (\n open !== null\n && open.line === line\n && open.x1 === rx\n && open.fill === fill\n && open.size === run.size\n && open.baselineY === baselineY\n && DECORATION_KINDS.every((k) => open.flags[k] === flags[k])\n ) {\n open.x1 = rx + run.width;\n } else {\n flush();\n span = { flags, fill, size: run.size, baselineY, line, x0: rx, x1: rx + run.width };\n }\n });\n flush();\n };\n\n const strokeRenderer: TextRenderer = (_ctx, _text, x, y) => {\n walk(_ctx, x, y, (run, rx, ry) => _ctx.strokeText(run.text, rx, ry));\n };\n\n return { renderer, strokeRenderer, width: layout.width, height: layout.height };\n}\n"]}