@weasel-js/text 1.11.0 → 1.11.1

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,10 +1,10 @@
1
- import { DEFAULT_TAB_SIZE, resolveTextStyle, cachedLayoutRuns, graphemeCount, wrapLines, hangs, tabAdvance, widthWithTabs, layoutRuns } from './chunk-HI4VEOYP.js';
2
- export { BREAK_ALLOWED, BREAK_MANDATORY, DEFAULT_TEXT_STYLE, LAYOUT_CACHE_STRUCTURAL_LIMIT, LAYOUT_CACHE_VARIANT_LIMIT, NO_BREAK, cachedLayoutRuns, fontString, isHardLineBreak, layoutRuns, lineBreakOpportunities, paragraphDirection, registerBidi, resolveAlign, resolveTextStyle } from './chunk-HI4VEOYP.js';
1
+ import { DEFAULT_TAB_SIZE, resolveTextStyle, cachedLayoutRuns, graphemeCount, wrapLines, hangs, tabAdvance, widthWithTabs, layoutRuns } from './chunk-JOVZEHBJ.js';
2
+ export { BREAK_ALLOWED, BREAK_MANDATORY, DEFAULT_TEXT_STYLE, LAYOUT_CACHE_STRUCTURAL_LIMIT, LAYOUT_CACHE_VARIANT_LIMIT, NO_BREAK, cachedLayoutRuns, fontString, isHardLineBreak, layoutRuns, lineBreakOpportunities, paragraphDirection, registerBidi, resolveAlign, resolveTextStyle } from './chunk-JOVZEHBJ.js';
3
3
  import { resolveScreenLength, fillHasInk, strokeHasInk, paintKey, strokeKey } from '@weasel-js/paint';
4
- import { faceMetricsOf, resolveFontVariant, glyphGeneration, loadFontOutlines, faceMetricsFor, glyphOutline, outlineStatus, cssFamilyName, syntheticBoldGrowth } from '@weasel-js/font';
4
+ import { faceMetricsOf, resolveFontVariant, syntheticBoldGrowth, glyphGeneration, loadFontOutlines, faceMetricsFor, glyphOutline, outlineStatus, cssFamilyName } from '@weasel-js/font';
5
+ import { pathToD, pathFromD, mergeRegion, growRegion, transformPath, poseFrameOf, pathSignedArea, reversePath, PATH_M, PATH_L, PATH_Z } from '@weasel-js/geom';
5
6
  import { MIXED, deepEqual } from '@weasel-js/registry';
6
7
  export { MIXED } from '@weasel-js/registry';
7
- import { transformPath, poseFrameOf, growRegion, pathFromD, pathSignedArea, reversePath, PATH_M, PATH_L, PATH_Z } from '@weasel-js/geom';
8
8
 
9
9
  // src/runs.ts
10
10
  function toRuns(input) {
@@ -413,8 +413,8 @@ function lineDecorations(glyphs, runs, faceOf, paintOf) {
413
413
  };
414
414
  for (const g of glyphs) {
415
415
  const style = runs[g.run];
416
- const paint = paintOf(g.run);
417
- if (paint === null || !DECORATION_KINDS.some((kind) => style[kind])) {
416
+ const paint = style.underline || style.strikethrough || style.overline ? paintOf(g.run) : null;
417
+ if (paint === null) {
418
418
  close();
419
419
  continue;
420
420
  }
@@ -465,13 +465,61 @@ function layoutTextPose(pose, scale = 1) {
465
465
  y: pose.y + verticalAlignOffset(pose.verticalAlign, pose.height, laid.bounds.height)
466
466
  };
467
467
  }
468
+ var SYNTHETIC_BOLD_TOLERANCE = 5e-4;
469
+ var CACHE_LIMIT = 4096;
470
+ var cache = /* @__PURE__ */ new Map();
471
+ var dCache = /* @__PURE__ */ new Map();
472
+ function syntheticBoldOffset(resolved2) {
473
+ if (!resolved2.synthetic.bold) return null;
474
+ const { source } = resolved2;
475
+ if (source !== "atlas" && source !== "canvas") return null;
476
+ const { family, weight, style } = resolved2.resolved;
477
+ const growth = syntheticBoldGrowth(source, family, weight, style);
478
+ if (growth === void 0 || !(growth > 0)) return null;
479
+ return { growth, join: source === "atlas" ? "miter" : "round" };
480
+ }
481
+ function emboldenGlyph(em, d, resolved2) {
482
+ const offset = syntheticBoldOffset(resolved2);
483
+ if (offset === null) return em;
484
+ const key = `${offset.growth}|${offset.join}|${d}`;
485
+ let grown = cache.get(key);
486
+ if (grown) return grown;
487
+ grown = mergeRegion(
488
+ growRegion(em, offset.growth, { join: offset.join, tolerance: SYNTHETIC_BOLD_TOLERANCE }),
489
+ { tolerance: SYNTHETIC_BOLD_TOLERANCE }
490
+ );
491
+ if (cache.size >= CACHE_LIMIT) cache.clear();
492
+ cache.set(key, grown);
493
+ return grown;
494
+ }
495
+ function emboldenGlyphD(d, resolved2) {
496
+ const offset = syntheticBoldOffset(resolved2);
497
+ if (offset === null) return null;
498
+ const tag = `bold:${offset.growth}:${offset.join}`;
499
+ const key = `${tag}|${d}`;
500
+ let grown = dCache.get(key);
501
+ if (grown === void 0) {
502
+ grown = pathToD(emboldenGlyph(pathFromD(d), d, resolved2));
503
+ if (dCache.size >= CACHE_LIMIT) dCache.clear();
504
+ dCache.set(key, grown);
505
+ }
506
+ return { d: grown, tag };
507
+ }
508
+
509
+ // src/layout/paintRuns.ts
468
510
  function glyphOutlineD(g, run, minSize) {
469
- if (g.resolved.source !== "outline") {
511
+ const outlineOnly = g.resolved.source === "outline";
512
+ if (!outlineOnly) {
470
513
  if (minSize === void 0) return null;
471
514
  if (run.fontSize < minSize && !strokeHasInk(run.stroke)) return null;
472
- if (g.resolved.synthetic.bold) return null;
473
515
  }
474
- return faceOutlineD(g);
516
+ const d = faceOutlineD(g);
517
+ if (d === null) return null;
518
+ const { family, weight, style } = g.resolved.resolved;
519
+ const key = `${family}|${weight}|${style}|${g.cp}`;
520
+ if (outlineOnly || !g.resolved.synthetic.bold) return { d, key };
521
+ const bold = emboldenGlyphD(d, g.resolved);
522
+ return bold && { d: bold.d, key: `${key}|${bold.tag}` };
475
523
  }
476
524
  function faceOutlineD(g) {
477
525
  if (g.glyph?.color) return null;
@@ -501,10 +549,13 @@ function runFaces(runs) {
501
549
  const faces = runs.map((r) => faceMetricsOf(resolveFontVariant(r.fontFamily, r.fontWeight, r.fontStyle)));
502
550
  return (run) => faces[run];
503
551
  }
504
- function groupFor(groups, g, run, source) {
552
+ function groupFor(groups, g, run, source, last) {
505
553
  const { family, weight, style } = g.resolved.resolved;
506
554
  const { synthetic } = g.resolved;
507
555
  const page = source === "outline" ? 0 : g.glyph.page;
556
+ if (last.group !== null && last.run === g.run && last.source === source && last.page === page && last.family === family && last.weight === weight && last.style === style && last.bold === synthetic.bold && last.italic === synthetic.italic) {
557
+ return last.group;
558
+ }
508
559
  const stroke = source === "outline" && strokeHasInk(run.stroke) ? run.stroke : void 0;
509
560
  const key = `${family}|${weight}|${style}|${synthetic.bold ? 1 : 0}${synthetic.italic ? 1 : 0}|${paintKey(run.fill?.paint)}|${strokeKey(stroke)}|${source}|${page}`;
510
561
  let group = groups.get(key);
@@ -523,23 +574,41 @@ function groupFor(groups, g, run, source) {
523
574
  };
524
575
  groups.set(key, group);
525
576
  }
577
+ last.group = group;
578
+ last.run = g.run;
579
+ last.family = family;
580
+ last.weight = weight;
581
+ last.style = style;
582
+ last.bold = synthetic.bold;
583
+ last.italic = synthetic.italic;
584
+ last.source = source;
585
+ last.page = page;
526
586
  return group;
527
587
  }
528
588
  function paintRuns(laid, runs, opts = {}) {
529
589
  const groups = /* @__PURE__ */ new Map();
590
+ const last = {
591
+ group: null,
592
+ run: -1,
593
+ family: "",
594
+ weight: 0,
595
+ style: "normal",
596
+ bold: false,
597
+ italic: false,
598
+ source: "atlas",
599
+ page: 0
600
+ };
530
601
  const decorations = [];
531
602
  const faceOf = runFaces(runs);
532
603
  const rulePaint = (run) => fillHasInk(runs[run].fill) ? paintKey(runs[run].fill.paint) : null;
533
604
  for (const line of laid.lines) {
534
605
  for (const g of line.glyphs) {
535
606
  const run = runs[g.run];
536
- const d = glyphOutlineD(g, run, opts.outlineMinSize);
537
- if (!fillHasInk(run.fill) && !(d !== null && strokeHasInk(run.stroke))) continue;
538
- if (d !== null) {
539
- const { family, weight, style } = g.resolved.resolved;
540
- groupFor(groups, g, run, "outline").glyphs.push({
541
- d,
542
- key: `${family}|${weight}|${style}|${g.cp}`,
607
+ const outline = glyphOutlineD(g, run, opts.outlineMinSize);
608
+ if (!fillHasInk(run.fill) && !(outline !== null && strokeHasInk(run.stroke))) continue;
609
+ if (outline !== null) {
610
+ groupFor(groups, g, run, "outline", last).glyphs.push({
611
+ ...outline,
543
612
  x: g.x,
544
613
  baselineY: g.baselineY,
545
614
  scale: g.fontSize
@@ -548,8 +617,8 @@ function paintRuns(laid, runs, opts = {}) {
548
617
  }
549
618
  const quad = glyphQuad(g);
550
619
  if (!quad) continue;
551
- if (g.glyph?.color) groupFor(groups, g, run, "color").quads.push({ ...quad, colorGlyph: g.glyph });
552
- else groupFor(groups, g, run, g.resolved.source).quads.push(quad);
620
+ if (g.glyph?.color) groupFor(groups, g, run, "color", last).quads.push({ ...quad, colorGlyph: g.glyph });
621
+ else groupFor(groups, g, run, g.resolved.source, last).quads.push(quad);
553
622
  }
554
623
  for (const rule of lineDecorations(line.glyphs, runs, faceOf, rulePaint)) {
555
624
  const { run, ...rect } = rule;
@@ -1233,34 +1302,6 @@ function effectiveRangeStyle(range, style, paint) {
1233
1302
 
1234
1303
  // src/syntheticItalic.ts
1235
1304
  var SYNTHETIC_ITALIC_RADIANS = 0.2094;
1236
- var SYNTHETIC_BOLD_TOLERANCE = 5e-4;
1237
- var CACHE_LIMIT = 4096;
1238
- var cache = /* @__PURE__ */ new Map();
1239
- function syntheticBoldOffset(resolved2) {
1240
- if (!resolved2.synthetic.bold) return null;
1241
- const { source } = resolved2;
1242
- if (source !== "atlas" && source !== "canvas") return null;
1243
- const { family, weight, style } = resolved2.resolved;
1244
- const growth = syntheticBoldGrowth(source, family, weight, style);
1245
- if (growth === void 0 || !(growth > 0)) return null;
1246
- return { growth, join: source === "atlas" ? "miter" : "round" };
1247
- }
1248
- function emboldenGlyph(em, d, resolved2) {
1249
- const offset = syntheticBoldOffset(resolved2);
1250
- if (offset === null) return em;
1251
- const key = `${offset.growth}|${offset.join}|${d}`;
1252
- let grown = cache.get(key);
1253
- if (grown) return grown;
1254
- grown = growRegion(em, offset.growth, {
1255
- join: offset.join,
1256
- tolerance: SYNTHETIC_BOLD_TOLERANCE
1257
- });
1258
- if (cache.size >= CACHE_LIMIT) cache.clear();
1259
- cache.set(key, grown);
1260
- return grown;
1261
- }
1262
-
1263
- // src/textToPath.ts
1264
1305
  var TextOutlinesError = class extends Error {
1265
1306
  reason;
1266
1307
  family;
@@ -1447,6 +1488,6 @@ async function loadTextOutlines(data, opts = {}) {
1447
1488
  await Promise.all(facesOf(runs).map((f) => loadFontOutlines(f.family, { weight: f.weight, style: f.style })));
1448
1489
  }
1449
1490
 
1450
- export { DEFAULT_DECORATION_METRICS, MARKDOWN_RUN_GRAMMAR, SCRIPT_METRICS, SMALL_CAPS_SCALE, SYNTHETIC_ITALIC_RADIANS, TextOutlinesError, applyStyleToRange, cachedPaintRuns, caretIndexAt, createMarkdownRenderer, decorationMetrics, defaultLabelTextRenderer, effectiveRangeStyle, fitTextPose, isBoldWeight, isSmallCapsLetter, isTextData, layoutMarkdown, layoutTextPose, loadTextOutlines, markdownToRuns, measureText, measureTextBounds, measuredWidth, nodeHasFlag, numericWeight, paintRuns, patchRangeStyle, pointInTextPose, rangeWeight, renderLabel, resolveRunFace, resolveRuns, runsCarryStyling, runsToMarkdown, runsToPlainText, scriptMetrics, scriptMetricsFor, setFlagOverRange, smallCapsScale, smallCapsScaleFor, smallCapsText, styleAtRange, supersededKey, textLineBoxes, textPoseLayoutInput, textToPath, textToPathsByPaint, toRuns, transformRunTexts, unboldPatch, verticalAlignOffset };
1491
+ export { DEFAULT_DECORATION_METRICS, MARKDOWN_RUN_GRAMMAR, SCRIPT_METRICS, SMALL_CAPS_SCALE, SYNTHETIC_ITALIC_RADIANS, TextOutlinesError, applyStyleToRange, cachedPaintRuns, caretIndexAt, createMarkdownRenderer, decorationMetrics, defaultLabelTextRenderer, effectiveRangeStyle, emboldenGlyphD, fitTextPose, isBoldWeight, isSmallCapsLetter, isTextData, layoutMarkdown, layoutTextPose, loadTextOutlines, markdownToRuns, measureText, measureTextBounds, measuredWidth, nodeHasFlag, numericWeight, paintRuns, patchRangeStyle, pointInTextPose, rangeWeight, renderLabel, resolveRunFace, resolveRuns, runsCarryStyling, runsToMarkdown, runsToPlainText, scriptMetrics, scriptMetricsFor, setFlagOverRange, smallCapsScale, smallCapsScaleFor, smallCapsText, styleAtRange, supersededKey, syntheticBoldOffset, textLineBoxes, textPoseLayoutInput, textToPath, textToPathsByPaint, toRuns, transformRunTexts, unboldPatch, verticalAlignOffset };
1451
1492
  //# sourceMappingURL=index.js.map
1452
1493
  //# sourceMappingURL=index.js.map