@weasel-js/text 1.9.2 → 1.9.4
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/{chunk-JQPOFIGT.js → chunk-VZNK3C6F.js} +215 -46
- package/dist/chunk-VZNK3C6F.js.map +1 -0
- package/dist/index.d.ts +24 -6
- package/dist/index.js +25 -10
- package/dist/index.js.map +1 -1
- package/dist/{test-seams-DbGu8K5F.d.ts → test-seams-Czz9ua7X.d.ts} +44 -18
- package/dist/test-seams.d.ts +1 -1
- package/dist/test-seams.js +1 -1
- package/package.json +5 -5
- package/dist/chunk-JQPOFIGT.js.map +0 -1
|
@@ -1,11 +1,34 @@
|
|
|
1
1
|
import { resolveScreenLength } from '@weasel-js/paint';
|
|
2
|
-
import { resolveFontVariant, faceMetricsOf, fontPending, glyphGeneration, glyphOutline, resolveGlyphFallback } from '@weasel-js/font';
|
|
2
|
+
import { cssFamilyName, resolveFontVariant, faceMetricsOf, fontPending, glyphGeneration, glyphOutline, resolveGlyphFallback } from '@weasel-js/font';
|
|
3
3
|
|
|
4
4
|
var __defProp = Object.defineProperty;
|
|
5
5
|
var __export = (target, all) => {
|
|
6
6
|
for (var name in all)
|
|
7
7
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
8
8
|
};
|
|
9
|
+
|
|
10
|
+
// src/layout/tabStops.ts
|
|
11
|
+
var DEFAULT_TAB_SIZE = 8;
|
|
12
|
+
function tabAdvance(x, stop, min) {
|
|
13
|
+
if (!(stop > 0)) return 0;
|
|
14
|
+
const toNext = (Math.floor(x / stop) + 1) * stop - x;
|
|
15
|
+
return toNext < min ? toNext + stop : toNext;
|
|
16
|
+
}
|
|
17
|
+
function widthWithTabs(start, end, tabs, stopOf, flatWidth) {
|
|
18
|
+
let x = 0;
|
|
19
|
+
let from = start;
|
|
20
|
+
for (const t of tabs) {
|
|
21
|
+
if (t < start) continue;
|
|
22
|
+
if (t >= end) break;
|
|
23
|
+
if (t > from) x += flatWidth(from, t);
|
|
24
|
+
const { stop, min } = stopOf(t);
|
|
25
|
+
x += tabAdvance(x, stop, min);
|
|
26
|
+
from = t + 1;
|
|
27
|
+
}
|
|
28
|
+
return from < end ? x + flatWidth(from, end) : x;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// src/textStyle.ts
|
|
9
32
|
function resolveAlign(align, direction) {
|
|
10
33
|
if (align === "start" || align === "justify") return direction === "rtl" ? "right" : "left";
|
|
11
34
|
if (align === "end") return direction === "rtl" ? "left" : "right";
|
|
@@ -24,8 +47,9 @@ var DEFAULT_TEXT_STYLE = {
|
|
|
24
47
|
fontWeight: 400,
|
|
25
48
|
fontStyle: "normal",
|
|
26
49
|
align: "left",
|
|
27
|
-
direction: "
|
|
50
|
+
direction: "auto",
|
|
28
51
|
lineHeight: 1.2,
|
|
52
|
+
tabSize: DEFAULT_TAB_SIZE,
|
|
29
53
|
wrap: false,
|
|
30
54
|
fill: DEFAULT_FILL,
|
|
31
55
|
caretColor: paintColor(DEFAULT_FILL),
|
|
@@ -67,6 +91,7 @@ function resolveTextStyle(style, paint, scale = 1) {
|
|
|
67
91
|
align: style.align ?? DEFAULT_TEXT_STYLE.align,
|
|
68
92
|
direction: style.direction ?? DEFAULT_TEXT_STYLE.direction,
|
|
69
93
|
lineHeight: style.lineHeight ?? DEFAULT_TEXT_STYLE.lineHeight,
|
|
94
|
+
tabSize: style.tabSize ?? DEFAULT_TEXT_STYLE.tabSize,
|
|
70
95
|
wrap: style.wrap ?? DEFAULT_TEXT_STYLE.wrap,
|
|
71
96
|
fill,
|
|
72
97
|
caretColor,
|
|
@@ -83,7 +108,7 @@ function resolveTextStyle(style, paint, scale = 1) {
|
|
|
83
108
|
};
|
|
84
109
|
}
|
|
85
110
|
function fontString(s) {
|
|
86
|
-
return `${s.fontStyle} ${s.fontWeight} ${s.fontSize}px ${s.fontFamily}`;
|
|
111
|
+
return `${s.fontStyle} ${s.fontWeight} ${s.fontSize}px ${cssFamilyName(s.fontFamily)}`;
|
|
87
112
|
}
|
|
88
113
|
|
|
89
114
|
// src/layout/decorationMetrics.ts
|
|
@@ -468,8 +493,112 @@ function lineBreakOpportunities(cps) {
|
|
|
468
493
|
}
|
|
469
494
|
}
|
|
470
495
|
|
|
496
|
+
// src/layout/bidiRegistry.ts
|
|
497
|
+
var registered = null;
|
|
498
|
+
function registerBidi(engine) {
|
|
499
|
+
registered = engine;
|
|
500
|
+
return () => {
|
|
501
|
+
if (registered === engine) registered = null;
|
|
502
|
+
};
|
|
503
|
+
}
|
|
504
|
+
function registeredBidi() {
|
|
505
|
+
return registered;
|
|
506
|
+
}
|
|
507
|
+
function directionOfLevel(level) {
|
|
508
|
+
return level % 2 === 1 ? "rtl" : "ltr";
|
|
509
|
+
}
|
|
510
|
+
function paragraphDirection(text, direction = "auto", engine = registered) {
|
|
511
|
+
if (direction !== "auto") return direction;
|
|
512
|
+
if (engine === null) return "ltr";
|
|
513
|
+
const cps = [];
|
|
514
|
+
for (const ch of text) {
|
|
515
|
+
const cp = ch.codePointAt(0);
|
|
516
|
+
if (isHardLineBreak(cp)) break;
|
|
517
|
+
cps.push(cp);
|
|
518
|
+
}
|
|
519
|
+
return directionOfLevel(engine.baseLevel(engine.analyze(cps, "auto")));
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// src/layout/bidiLines.ts
|
|
523
|
+
function analyzeParagraphs(engine, codePoints, isBreak, direction) {
|
|
524
|
+
const paragraphs = [];
|
|
525
|
+
let start = 0;
|
|
526
|
+
for (let i = 0; i <= codePoints.length; i++) {
|
|
527
|
+
if (i < codePoints.length && !isBreak(i)) continue;
|
|
528
|
+
if (i > start) {
|
|
529
|
+
paragraphs.push({ start, end: i, analysis: engine.analyze(codePoints.slice(start, i), direction) });
|
|
530
|
+
}
|
|
531
|
+
start = i + 1;
|
|
532
|
+
}
|
|
533
|
+
const holding = (at) => {
|
|
534
|
+
let lo = 0;
|
|
535
|
+
let hi = paragraphs.length - 1;
|
|
536
|
+
while (lo < hi) {
|
|
537
|
+
const mid = lo + hi >> 1;
|
|
538
|
+
if (paragraphs[mid].end <= at) lo = mid + 1;
|
|
539
|
+
else hi = mid;
|
|
540
|
+
}
|
|
541
|
+
const p = paragraphs[lo];
|
|
542
|
+
return p !== void 0 && at >= p.start && at < p.end ? p : void 0;
|
|
543
|
+
};
|
|
544
|
+
return {
|
|
545
|
+
reorder(from, to) {
|
|
546
|
+
const p = holding(from);
|
|
547
|
+
if (p === void 0 || to > p.end) return { order: [], levels: [] };
|
|
548
|
+
const r = engine.reorder(p.analysis, from - p.start, to - p.start);
|
|
549
|
+
return { order: r.order.map((i) => i + p.start), levels: r.levels };
|
|
550
|
+
},
|
|
551
|
+
baseLevel(at) {
|
|
552
|
+
const p = holding(at);
|
|
553
|
+
return p === void 0 ? 0 : engine.baseLevel(p.analysis);
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
function restoreRemoved(order, count, rtl) {
|
|
558
|
+
if (order.length === count) return [...order];
|
|
559
|
+
const kept = new Set(order);
|
|
560
|
+
const leading = [];
|
|
561
|
+
const following = /* @__PURE__ */ new Map();
|
|
562
|
+
let anchor = -1;
|
|
563
|
+
let firstKept = -1;
|
|
564
|
+
for (let k = 0; k < count; k++) {
|
|
565
|
+
if (kept.has(k)) {
|
|
566
|
+
anchor = k;
|
|
567
|
+
if (firstKept < 0) firstKept = k;
|
|
568
|
+
} else if (anchor < 0) {
|
|
569
|
+
leading.push(k);
|
|
570
|
+
} else {
|
|
571
|
+
const list = following.get(anchor);
|
|
572
|
+
if (list) list.push(k);
|
|
573
|
+
else following.set(anchor, [k]);
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
if (firstKept < 0) return leading;
|
|
577
|
+
const out = [];
|
|
578
|
+
for (const p of order) {
|
|
579
|
+
const after = following.get(p) ?? [];
|
|
580
|
+
const before = p === firstKept ? leading : [];
|
|
581
|
+
if (rtl(p)) out.push(...[...after].reverse(), p, ...[...before].reverse());
|
|
582
|
+
else out.push(...before, p, ...after);
|
|
583
|
+
}
|
|
584
|
+
return out;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
// src/layout/refId.ts
|
|
588
|
+
var nextRefId = 1;
|
|
589
|
+
var refIds = /* @__PURE__ */ new WeakMap();
|
|
590
|
+
function refId(o) {
|
|
591
|
+
let id = refIds.get(o);
|
|
592
|
+
if (id === void 0) {
|
|
593
|
+
id = nextRefId++;
|
|
594
|
+
refIds.set(o, id);
|
|
595
|
+
}
|
|
596
|
+
return id;
|
|
597
|
+
}
|
|
598
|
+
|
|
471
599
|
// src/measure/graphemes.ts
|
|
472
600
|
var segmenter;
|
|
601
|
+
var NEEDS_SEGMENTING = /[\r\u0300-\uffff]/;
|
|
473
602
|
function graphemeSegmenter() {
|
|
474
603
|
if (segmenter === void 0) {
|
|
475
604
|
segmenter = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
|
|
@@ -478,6 +607,10 @@ function graphemeSegmenter() {
|
|
|
478
607
|
}
|
|
479
608
|
function graphemeEnds(text) {
|
|
480
609
|
const out = [];
|
|
610
|
+
if (!NEEDS_SEGMENTING.test(text)) {
|
|
611
|
+
for (let i = 1; i <= text.length; i++) out.push(i);
|
|
612
|
+
return out;
|
|
613
|
+
}
|
|
481
614
|
const seg = graphemeSegmenter();
|
|
482
615
|
if (seg) {
|
|
483
616
|
for (const s of seg.segment(text)) out.push(s.index + s.segment.length);
|
|
@@ -492,7 +625,7 @@ function graphemeCount(text) {
|
|
|
492
625
|
}
|
|
493
626
|
|
|
494
627
|
// src/layout/lineBreak/wrapLines.ts
|
|
495
|
-
var
|
|
628
|
+
var hangs = (cp) => cp === 32 || cp === 9;
|
|
496
629
|
function wrapLines(cps, maxWidth, widthOf) {
|
|
497
630
|
const n = cps.length;
|
|
498
631
|
const breaks = Number.isFinite(maxWidth) ? lineBreakOpportunities(cps) : null;
|
|
@@ -507,14 +640,14 @@ function wrapLines(cps, maxWidth, widthOf) {
|
|
|
507
640
|
start = i;
|
|
508
641
|
continue;
|
|
509
642
|
}
|
|
510
|
-
if (cp
|
|
643
|
+
if (hangs(cp)) {
|
|
511
644
|
i++;
|
|
512
645
|
continue;
|
|
513
646
|
}
|
|
514
647
|
let j = i + 1;
|
|
515
648
|
let ink = i + 1;
|
|
516
649
|
while (j < n && !isHardLineBreak(cps[j]) && (!breaks || breaks[j] === NO_BREAK)) {
|
|
517
|
-
if (cps[j]
|
|
650
|
+
if (!hangs(cps[j])) ink = j + 1;
|
|
518
651
|
j++;
|
|
519
652
|
}
|
|
520
653
|
if (breaks && i > start && widthOf(start, ink) > maxWidth) {
|
|
@@ -542,7 +675,7 @@ function atlasMetrics(font) {
|
|
|
542
675
|
function fillKey(p) {
|
|
543
676
|
if (p === null) return "none";
|
|
544
677
|
if ("color" in p) return `s:${p.color}:${p.opacity ?? 1}`;
|
|
545
|
-
return `nx:${
|
|
678
|
+
return `nx:${refId(p)}`;
|
|
546
679
|
}
|
|
547
680
|
function sameFill(a, b) {
|
|
548
681
|
if (a === b) return true;
|
|
@@ -609,7 +742,7 @@ function getOrCreateGroup(ctx, run, resolved2, page, sourceOverride) {
|
|
|
609
742
|
}
|
|
610
743
|
return g;
|
|
611
744
|
}
|
|
612
|
-
function resolveGlyph(run, font, resolved2, cp) {
|
|
745
|
+
function resolveGlyph(run, font, resolved2, cp, warn = true) {
|
|
613
746
|
const direct = font.charMap.get(cp);
|
|
614
747
|
if (direct) return { glyph: direct, font, resolved: resolved2 };
|
|
615
748
|
const fallback = resolveGlyphFallback(run.fontFamily, run.fontWeight, run.fontStyle);
|
|
@@ -620,7 +753,7 @@ function resolveGlyph(run, font, resolved2, cp) {
|
|
|
620
753
|
return { glyph, font: face.font, resolved: fallback };
|
|
621
754
|
}
|
|
622
755
|
}
|
|
623
|
-
warnMissingGlyphOnce(resolved2.resolved.family, cp);
|
|
756
|
+
if (warn) warnMissingGlyphOnce(resolved2.resolved.family, cp);
|
|
624
757
|
return null;
|
|
625
758
|
}
|
|
626
759
|
var RTL_BLOCKS = [
|
|
@@ -639,7 +772,7 @@ function warnLogicalRtlOnce() {
|
|
|
639
772
|
console.warn(
|
|
640
773
|
// Naming the import in `from "<pkg>"` form would trip labkit's
|
|
641
774
|
// consumer smoke test, which greps dist for that exact shape.
|
|
642
|
-
"weasel layoutRuns: this text contains right-to-left characters but no `bidi` engine
|
|
775
|
+
"weasel layoutRuns: this text contains right-to-left characters but no `bidi` engine is registered, so it is being laid out in logical order \u2014 the glyphs will appear reversed. Import `bidi` out of the `@weasel-js/bidi` package and call `registerBidi(bidi)` once at startup."
|
|
643
776
|
);
|
|
644
777
|
}
|
|
645
778
|
var warnedMissingGlyphs = /* @__PURE__ */ new Set();
|
|
@@ -663,8 +796,10 @@ function warnNoMetricsOnce(family, weight, style) {
|
|
|
663
796
|
}
|
|
664
797
|
function layoutRuns(runs, opts) {
|
|
665
798
|
const ctx = { groups: /* @__PURE__ */ new Map() };
|
|
666
|
-
const
|
|
799
|
+
const bidi = opts.bidi ?? registeredBidi();
|
|
800
|
+
const direction = opts.direction ?? "auto";
|
|
667
801
|
const justify = opts.justify === true || opts.align === "justify";
|
|
802
|
+
const tabSize = opts.tabSize ?? DEFAULT_TAB_SIZE;
|
|
668
803
|
const lineSize = (e) => Math.max(e.run.fontSize, e.run.strutSize ?? 0);
|
|
669
804
|
const aboveBaseline = (e) => {
|
|
670
805
|
const k = lineSize(e) / e.metrics.size;
|
|
@@ -673,6 +808,7 @@ function layoutRuns(runs, opts) {
|
|
|
673
808
|
return (lineSize(e) * opts.lineHeight - ascent - e.metrics.descent * k) / 2 + ascent;
|
|
674
809
|
};
|
|
675
810
|
const entries = [];
|
|
811
|
+
const closesCluster = [];
|
|
676
812
|
const runFaces = /* @__PURE__ */ new Map();
|
|
677
813
|
let prevCp;
|
|
678
814
|
let prevMetrics;
|
|
@@ -706,12 +842,14 @@ function layoutRuns(runs, opts) {
|
|
|
706
842
|
const sizes = run.sizeMap;
|
|
707
843
|
let at = 0;
|
|
708
844
|
const runTracking = run.letterSpacing;
|
|
709
|
-
const clusterEnds =
|
|
845
|
+
const clusterEnds = new Set(graphemeEnds(run.text));
|
|
710
846
|
for (const ch of [...run.text]) {
|
|
711
847
|
const cp = ch.codePointAt(0);
|
|
712
848
|
const fontSize = sizes ? sizes[at] : run.fontSize;
|
|
713
849
|
const scale = fontSize / metrics.size;
|
|
714
|
-
const
|
|
850
|
+
const clusterEnd = clusterEnds.has(at + ch.length);
|
|
851
|
+
closesCluster.push(clusterEnd);
|
|
852
|
+
const tracking = clusterEnd ? runTracking : 0;
|
|
715
853
|
const isNewline = isHardLineBreak(cp);
|
|
716
854
|
const isSpace = cp === 32;
|
|
717
855
|
const srcStart = map ? runBase + map.starts[at] : runBase + at;
|
|
@@ -743,10 +881,36 @@ function layoutRuns(runs, opts) {
|
|
|
743
881
|
prevFontSize = void 0;
|
|
744
882
|
continue;
|
|
745
883
|
}
|
|
746
|
-
|
|
884
|
+
const isTab = cp === 9;
|
|
885
|
+
if (isSpace || isTab) {
|
|
747
886
|
const spaceGlyph = resolved2.dynamicFace ? resolved2.dynamicFace.requestGlyph(32) : font?.charMap.get(32) ?? null;
|
|
748
887
|
const spaceAdvance = spaceGlyph ? spaceGlyph.xadvance : metrics.advanceOf(32);
|
|
749
888
|
const advance = spaceAdvance !== null ? spaceAdvance * scale : fontSize * 0.25;
|
|
889
|
+
if (isTab) {
|
|
890
|
+
entries.push({
|
|
891
|
+
run,
|
|
892
|
+
font,
|
|
893
|
+
metrics,
|
|
894
|
+
glyph: { id: cp, x: 0, y: 0, width: 0, height: 0, xoffset: 0, yoffset: 0, xadvance: 0, page: 0 },
|
|
895
|
+
cp,
|
|
896
|
+
advance: 0,
|
|
897
|
+
tracking: 0,
|
|
898
|
+
kerningBefore: 0,
|
|
899
|
+
isSpace: false,
|
|
900
|
+
isNewline: false,
|
|
901
|
+
tab: { stop: tabSize * (advance + runTracking), min: advance / 2 },
|
|
902
|
+
drawsInk: false,
|
|
903
|
+
resolved: resolved2,
|
|
904
|
+
fontSize,
|
|
905
|
+
srcIndex: srcStart,
|
|
906
|
+
srcEnd,
|
|
907
|
+
flat: 0
|
|
908
|
+
});
|
|
909
|
+
prevCp = void 0;
|
|
910
|
+
prevMetrics = void 0;
|
|
911
|
+
prevFontSize = void 0;
|
|
912
|
+
continue;
|
|
913
|
+
}
|
|
750
914
|
let kerningBefore2 = 0;
|
|
751
915
|
if (prevCp !== void 0 && prevMetrics !== void 0 && prevFontSize !== void 0) {
|
|
752
916
|
kerningBefore2 = prevMetrics.kernOf(prevCp, cp) * (prevFontSize / prevMetrics.size);
|
|
@@ -883,17 +1047,22 @@ function layoutRuns(runs, opts) {
|
|
|
883
1047
|
}
|
|
884
1048
|
}
|
|
885
1049
|
for (let i = 0; i < entries.length; i++) entries[i].flat = i;
|
|
886
|
-
const
|
|
887
|
-
if (!
|
|
1050
|
+
const paragraphs = bidi ? analyzeParagraphs(bidi, entries.map((e) => e.cp), (i) => entries[i].isNewline, direction) : null;
|
|
1051
|
+
if (!bidi && entries.some((e) => RTL_BLOCKS.some(([lo, hi]) => e.cp >= lo && e.cp <= hi))) {
|
|
888
1052
|
warnLogicalRtlOnce();
|
|
889
1053
|
}
|
|
890
|
-
const openingWidth = (e) => e.
|
|
1054
|
+
const openingWidth = (e) => e.advance + e.tracking;
|
|
891
1055
|
const sum = new Float64Array(entries.length + 1);
|
|
892
1056
|
for (let k = 0; k < entries.length; k++) {
|
|
893
1057
|
const e = entries[k];
|
|
894
1058
|
sum[k + 1] = sum[k] + e.kerningBefore + e.advance + e.tracking;
|
|
895
1059
|
}
|
|
896
|
-
const
|
|
1060
|
+
const flatWidth = (start, end) => openingWidth(entries[start]) + sum[end] - sum[start + 1];
|
|
1061
|
+
const tabs = [];
|
|
1062
|
+
entries.forEach((e, k) => {
|
|
1063
|
+
if (e.tab) tabs.push(k);
|
|
1064
|
+
});
|
|
1065
|
+
const widthOf = tabs.length === 0 ? flatWidth : (start, end) => widthWithTabs(start, end, tabs, (k) => entries[k].tab, flatWidth);
|
|
897
1066
|
const lines = [];
|
|
898
1067
|
for (const span2 of wrapLines(entries.map((e) => e.cp), opts.maxWidth, widthOf)) {
|
|
899
1068
|
const line = { entries: [], width: 0, height: 0, ...span2.wrapped ? { wrapped: true } : {} };
|
|
@@ -904,7 +1073,8 @@ function layoutRuns(runs, opts) {
|
|
|
904
1073
|
}
|
|
905
1074
|
for (let k = span2.start; k < span2.end; k++) {
|
|
906
1075
|
const e = entries[k];
|
|
907
|
-
const
|
|
1076
|
+
const opened = k > span2.start ? e : { ...e, kerningBefore: 0 };
|
|
1077
|
+
const placed = e.tab ? { ...opened, advance: tabAdvance(line.width, e.tab.stop, e.tab.min) } : opened;
|
|
908
1078
|
line.entries.push(placed);
|
|
909
1079
|
line.width += placed.kerningBefore + placed.advance + placed.tracking;
|
|
910
1080
|
line.height = Math.max(line.height, lineSize(e) * opts.lineHeight);
|
|
@@ -943,7 +1113,7 @@ function layoutRuns(runs, opts) {
|
|
|
943
1113
|
let hung = 0;
|
|
944
1114
|
for (let k = line.entries.length - 1; k >= 0; k--) {
|
|
945
1115
|
const e = line.entries[k];
|
|
946
|
-
if (!e.isSpace) break;
|
|
1116
|
+
if (!e.isSpace && !e.tab) break;
|
|
947
1117
|
hung += e.kerningBefore + e.advance + e.tracking;
|
|
948
1118
|
}
|
|
949
1119
|
const inkWidth = line.width - hung;
|
|
@@ -958,6 +1128,7 @@ function layoutRuns(runs, opts) {
|
|
|
958
1128
|
if (gaps.size > 0) gapExtra = (alignWidth - inkWidth) / gaps.size;
|
|
959
1129
|
}
|
|
960
1130
|
const spread = gapExtra * gaps.size;
|
|
1131
|
+
const align = resolveAlign(opts.align, direction !== "auto" ? direction : directionOfLevel(line.entries.length > 0 ? paragraphs?.baseLevel(line.entries[0].flat) ?? 0 : 0));
|
|
961
1132
|
const alignShift = (() => {
|
|
962
1133
|
if (spread > 0) return 0;
|
|
963
1134
|
if (align === "left") return 0;
|
|
@@ -978,10 +1149,10 @@ function layoutRuns(runs, opts) {
|
|
|
978
1149
|
flatOf.forEach((f, pos) => posOfFlat.set(f, pos));
|
|
979
1150
|
let visual = line.entries.map((_, k) => k);
|
|
980
1151
|
let levelOf = () => 0;
|
|
981
|
-
if (
|
|
1152
|
+
if (paragraphs !== null && line.entries.length > 0) {
|
|
982
1153
|
const from = flatOf[0];
|
|
983
1154
|
const to = flatOf[flatOf.length - 1] + 1;
|
|
984
|
-
const r =
|
|
1155
|
+
const r = paragraphs.reorder(from, to);
|
|
985
1156
|
const seen = /* @__PURE__ */ new Set();
|
|
986
1157
|
const ordered = [];
|
|
987
1158
|
for (const f of r.order) {
|
|
@@ -991,28 +1162,34 @@ function layoutRuns(runs, opts) {
|
|
|
991
1162
|
seen.add(pos);
|
|
992
1163
|
}
|
|
993
1164
|
}
|
|
994
|
-
for (let k = 0; k < line.entries.length; k++) if (!seen.has(k)) ordered.push(k);
|
|
995
|
-
visual = ordered;
|
|
996
1165
|
levelOf = (pos) => {
|
|
997
1166
|
const l = r.levels[flatOf[pos] - from];
|
|
998
1167
|
return typeof l === "number" && l >= 0 ? l : 0;
|
|
999
1168
|
};
|
|
1169
|
+
visual = restoreRemoved(ordered, line.entries.length, (pos) => levelOf(pos) % 2 === 1);
|
|
1000
1170
|
}
|
|
1001
|
-
if (
|
|
1171
|
+
if (bidi) {
|
|
1002
1172
|
for (let pos = 0; pos < line.entries.length; pos++) {
|
|
1003
1173
|
if (levelOf(pos) % 2 === 0) continue;
|
|
1004
1174
|
const e = line.entries[pos];
|
|
1005
|
-
const m =
|
|
1175
|
+
const m = bidi.mirror(e.cp);
|
|
1006
1176
|
if (m === null || m === e.cp) continue;
|
|
1007
1177
|
if (e.font !== null) {
|
|
1008
|
-
const hit = resolveGlyph(e.run, e.font, e.resolved, m);
|
|
1178
|
+
const hit = resolveGlyph(e.run, e.font, e.resolved, m, false);
|
|
1009
1179
|
if (!hit) continue;
|
|
1180
|
+
if (hit.font !== e.font) {
|
|
1181
|
+
e.font = hit.font;
|
|
1182
|
+
e.metrics = atlasMetrics(hit.font);
|
|
1183
|
+
e.resolved = hit.resolved;
|
|
1184
|
+
}
|
|
1010
1185
|
e.glyph = hit.glyph;
|
|
1011
1186
|
}
|
|
1012
1187
|
e.cp = m;
|
|
1013
1188
|
}
|
|
1014
1189
|
}
|
|
1015
|
-
|
|
1190
|
+
const hangsLeft = hung > 0 && levelOf(line.entries.length - 1) % 2 === 1;
|
|
1191
|
+
const lineLeft = hangsLeft ? lineX0 - hung : lineX0;
|
|
1192
|
+
let penX = lineLeft;
|
|
1016
1193
|
let prevPos = -1;
|
|
1017
1194
|
for (const pos of visual) {
|
|
1018
1195
|
const e = line.entries[pos];
|
|
@@ -1026,7 +1203,8 @@ function layoutRuns(runs, opts) {
|
|
|
1026
1203
|
x: penX,
|
|
1027
1204
|
advance: step,
|
|
1028
1205
|
level: levelOf(pos),
|
|
1029
|
-
drawsInk: e.drawsInk
|
|
1206
|
+
drawsInk: e.drawsInk,
|
|
1207
|
+
clusterEnd: closesCluster[e.flat]
|
|
1030
1208
|
};
|
|
1031
1209
|
cells[pos] = cell;
|
|
1032
1210
|
const scale = e.fontSize / e.metrics.size;
|
|
@@ -1094,9 +1272,9 @@ function layoutRuns(runs, opts) {
|
|
|
1094
1272
|
const lastCell = line.entries[line.entries.length - 1];
|
|
1095
1273
|
const srcEnd = lastCell ? lastCell.srcEnd : line.blank?.srcIndex ?? 0;
|
|
1096
1274
|
lineBoxes.push({
|
|
1097
|
-
x0:
|
|
1275
|
+
x0: lineLeft,
|
|
1098
1276
|
y0: penY,
|
|
1099
|
-
x1:
|
|
1277
|
+
x1: lineLeft + line.width + spread,
|
|
1100
1278
|
y1: penY + line.height,
|
|
1101
1279
|
baselineY: lineBaselineY,
|
|
1102
1280
|
cells,
|
|
@@ -1128,17 +1306,8 @@ function outlineBucket(runs, min) {
|
|
|
1128
1306
|
function variantKey(runs, opts) {
|
|
1129
1307
|
const alignWidth = opts.alignWidth ?? opts.maxWidth;
|
|
1130
1308
|
const justify = opts.justify === true || opts.align === "justify";
|
|
1131
|
-
|
|
1132
|
-
}
|
|
1133
|
-
var nextRefId = 1;
|
|
1134
|
-
var refIds = /* @__PURE__ */ new WeakMap();
|
|
1135
|
-
function refId(o) {
|
|
1136
|
-
let id = refIds.get(o);
|
|
1137
|
-
if (id === void 0) {
|
|
1138
|
-
id = nextRefId++;
|
|
1139
|
-
refIds.set(o, id);
|
|
1140
|
-
}
|
|
1141
|
-
return id;
|
|
1309
|
+
const bidi = opts.bidi ?? registeredBidi();
|
|
1310
|
+
return `${opts.maxWidth}|${alignWidth}|${opts.lineHeight}|${opts.align}|${justify ? "j" : ""}|${outlineBucket(runs, opts.outlineMinSize)}|${opts.direction ?? ""}|${bidi ? refId(bidi) : ""}|${opts.tabSize ?? ""}`;
|
|
1142
1311
|
}
|
|
1143
1312
|
function paintKey(p) {
|
|
1144
1313
|
if (p === null) return "none";
|
|
@@ -1160,7 +1329,7 @@ function strokeKey2(s) {
|
|
|
1160
1329
|
function runsKey(runs) {
|
|
1161
1330
|
let out = "";
|
|
1162
1331
|
for (const r of runs) {
|
|
1163
|
-
out += `${r.text.length}:${r.text}|${r.fontFamily.length}:${r.fontFamily}|${r.fontSize}|${r.fontWeight}|${r.fontStyle}|${r.letterSpacing}|${r.underline ? 1 : 0}${r.strikethrough ? 1 : 0}${r.overline ? 1 : 0}|${r.baselineShift}|${paintKey(r.fill)}|${strokeKey2(r.stroke)}|${r.srcMap ? `${r.srcMap.length}:${r.srcMap.starts.join(",")}` : ""}|${r.sizeMap ? r.sizeMap.join(",") : ""}|`;
|
|
1332
|
+
out += `${r.text.length}:${r.text}|${r.fontFamily.length}:${r.fontFamily}|${r.fontSize}|${r.fontWeight}|${r.fontStyle}|${r.letterSpacing}|${r.underline ? 1 : 0}${r.strikethrough ? 1 : 0}${r.overline ? 1 : 0}|${r.baselineShift}|${r.strutSize ?? ""}|${paintKey(r.fill)}|${strokeKey2(r.stroke)}|${r.srcMap ? `${r.srcMap.length}:${r.srcMap.starts.join(",")}` : ""}|${r.sizeMap ? r.sizeMap.join(",") : ""}|`;
|
|
1164
1333
|
}
|
|
1165
1334
|
return out;
|
|
1166
1335
|
}
|
|
@@ -1202,6 +1371,6 @@ function _resetLayoutCacheForTests() {
|
|
|
1202
1371
|
structuralGeneration = -1;
|
|
1203
1372
|
}
|
|
1204
1373
|
|
|
1205
|
-
export { BREAK_ALLOWED, BREAK_MANDATORY, DECORATION_KINDS, DEFAULT_DECORATION_METRICS, DEFAULT_TEXT_STYLE, LAYOUT_CACHE_STRUCTURAL_LIMIT, LAYOUT_CACHE_VARIANT_LIMIT, NO_BREAK, _resetLayoutCacheForTests, cachedLayoutRuns, decorationMetrics, decorationRule, fontString, graphemeCount, isHardLineBreak, layoutRuns, lineBreakOpportunities, resolveAlign, resolveTextStyle, wrapLines };
|
|
1206
|
-
//# sourceMappingURL=chunk-
|
|
1207
|
-
//# sourceMappingURL=chunk-
|
|
1374
|
+
export { BREAK_ALLOWED, BREAK_MANDATORY, DECORATION_KINDS, DEFAULT_DECORATION_METRICS, DEFAULT_TEXT_STYLE, LAYOUT_CACHE_STRUCTURAL_LIMIT, LAYOUT_CACHE_VARIANT_LIMIT, NO_BREAK, _resetLayoutCacheForTests, cachedLayoutRuns, decorationMetrics, decorationRule, fontString, graphemeCount, hangs, isHardLineBreak, layoutRuns, lineBreakOpportunities, paragraphDirection, registerBidi, resolveAlign, resolveTextStyle, wrapLines };
|
|
1375
|
+
//# sourceMappingURL=chunk-VZNK3C6F.js.map
|
|
1376
|
+
//# sourceMappingURL=chunk-VZNK3C6F.js.map
|