@weasel-js/text 1.12.0 → 1.13.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/{chunk-ADRQIIHS.js → chunk-DOTR55MR.js} +197 -41
- package/dist/chunk-DOTR55MR.js.map +1 -0
- package/dist/index.d.ts +14 -4
- package/dist/index.js +101 -45
- package/dist/index.js.map +1 -1
- package/dist/test-seams.js +1 -1
- package/package.json +6 -6
- package/dist/chunk-ADRQIIHS.js.map +0 -1
|
@@ -619,6 +619,180 @@ function orderLine(paragraphs, start, count) {
|
|
|
619
619
|
return { visual: restoreRemoved([...kept], count, (pos) => levels[pos] % 2 === 1), levels };
|
|
620
620
|
}
|
|
621
621
|
|
|
622
|
+
// src/layout/layoutColumns.ts
|
|
623
|
+
var NUM = 12;
|
|
624
|
+
var X = 0;
|
|
625
|
+
var STEP = 1;
|
|
626
|
+
var ADVANCE = 2;
|
|
627
|
+
var FONT_SIZE = 3;
|
|
628
|
+
var BASELINE = 4;
|
|
629
|
+
var SRC_INDEX = 5;
|
|
630
|
+
var SRC_END = 6;
|
|
631
|
+
var CP3 = 7;
|
|
632
|
+
var LEVEL = 8;
|
|
633
|
+
var FLAGS = 9;
|
|
634
|
+
var RUN = 10;
|
|
635
|
+
var VISUAL = 11;
|
|
636
|
+
var DRAWS_INK = 1;
|
|
637
|
+
var CLUSTER_END = 2;
|
|
638
|
+
var REF = 4;
|
|
639
|
+
var TEMPLATE_LIMIT = 1 << 16;
|
|
640
|
+
var template = [0.5];
|
|
641
|
+
function doubles(n) {
|
|
642
|
+
if (n > TEMPLATE_LIMIT) return new Array(n).fill(0.5);
|
|
643
|
+
while (template.length < n) template = template.concat(template);
|
|
644
|
+
return template.slice(0, n);
|
|
645
|
+
}
|
|
646
|
+
var LayoutColumns = class {
|
|
647
|
+
num;
|
|
648
|
+
ref;
|
|
649
|
+
constructor(size) {
|
|
650
|
+
this.num = doubles(size * NUM);
|
|
651
|
+
this.ref = new Array(size * REF);
|
|
652
|
+
}
|
|
653
|
+
/** Store code point `i`: entry `e`, set at `x` on a baseline at `baselineY`,
|
|
654
|
+
* moving the pen `step`. */
|
|
655
|
+
set(i, e, level, x, step, baselineY) {
|
|
656
|
+
const n = i * NUM, r = i * REF;
|
|
657
|
+
const { num, ref } = this;
|
|
658
|
+
num[n + X] = x;
|
|
659
|
+
num[n + STEP] = step;
|
|
660
|
+
num[n + ADVANCE] = e.advance;
|
|
661
|
+
num[n + FONT_SIZE] = e.fontSize;
|
|
662
|
+
num[n + BASELINE] = baselineY;
|
|
663
|
+
num[n + SRC_INDEX] = e.srcIndex;
|
|
664
|
+
num[n + SRC_END] = e.srcEnd;
|
|
665
|
+
num[n + CP3] = e.cp;
|
|
666
|
+
num[n + LEVEL] = level;
|
|
667
|
+
num[n + RUN] = e.run;
|
|
668
|
+
num[n + FLAGS] = (e.drawsInk ? DRAWS_INK : 0) | (e.clusterEnd ? CLUSTER_END : 0);
|
|
669
|
+
ref[r] = e.resolved;
|
|
670
|
+
ref[r + 1] = e.metrics;
|
|
671
|
+
ref[r + 2] = e.font;
|
|
672
|
+
ref[r + 3] = e.glyph;
|
|
673
|
+
}
|
|
674
|
+
/** Record that the `slot`-th code point the pen reaches on the line starting
|
|
675
|
+
* at `start` is the line's `pos`-th in logical order. */
|
|
676
|
+
setVisual(start, slot, pos) {
|
|
677
|
+
this.num[(start + slot) * NUM + VISUAL] = pos;
|
|
678
|
+
}
|
|
679
|
+
/** Logical index, within its line, of the glyph at visual `slot`. */
|
|
680
|
+
visual(start, slot) {
|
|
681
|
+
return this.num[(start + slot) * NUM + VISUAL];
|
|
682
|
+
}
|
|
683
|
+
/** Fill `out` with code point `start + pos`'s placed glyph and return it.
|
|
684
|
+
* Every field is overwritten, so one object can walk a whole layout. */
|
|
685
|
+
glyph(start, pos, out) {
|
|
686
|
+
const i = start + pos;
|
|
687
|
+
const n = i * NUM, r = i * REF;
|
|
688
|
+
const { num, ref } = this;
|
|
689
|
+
out.run = num[n + RUN];
|
|
690
|
+
out.cell = pos;
|
|
691
|
+
out.cp = num[n + CP3];
|
|
692
|
+
out.fontSize = num[n + FONT_SIZE];
|
|
693
|
+
out.resolved = ref[r];
|
|
694
|
+
out.metrics = ref[r + 1];
|
|
695
|
+
out.font = ref[r + 2];
|
|
696
|
+
out.glyph = ref[r + 3];
|
|
697
|
+
out.x = num[n + X];
|
|
698
|
+
out.baselineY = num[n + BASELINE];
|
|
699
|
+
out.advance = num[n + ADVANCE];
|
|
700
|
+
out.step = num[n + STEP];
|
|
701
|
+
return out;
|
|
702
|
+
}
|
|
703
|
+
/** Code point `start + pos`'s cell, as a new object. */
|
|
704
|
+
cell(start, pos) {
|
|
705
|
+
const n = (start + pos) * NUM;
|
|
706
|
+
const { num } = this;
|
|
707
|
+
const flags = num[n + FLAGS];
|
|
708
|
+
return {
|
|
709
|
+
srcIndex: num[n + SRC_INDEX],
|
|
710
|
+
srcEnd: num[n + SRC_END],
|
|
711
|
+
cp: num[n + CP3],
|
|
712
|
+
x: num[n + X],
|
|
713
|
+
advance: num[n + STEP],
|
|
714
|
+
level: num[n + LEVEL],
|
|
715
|
+
drawsInk: (flags & DRAWS_INK) !== 0,
|
|
716
|
+
clusterEnd: (flags & CLUSTER_END) !== 0
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
};
|
|
720
|
+
function blankGlyph() {
|
|
721
|
+
return {
|
|
722
|
+
run: 0,
|
|
723
|
+
cell: 0,
|
|
724
|
+
cp: 0,
|
|
725
|
+
fontSize: 0.5,
|
|
726
|
+
resolved: null,
|
|
727
|
+
metrics: null,
|
|
728
|
+
font: null,
|
|
729
|
+
glyph: null,
|
|
730
|
+
x: 0.5,
|
|
731
|
+
baselineY: 0.5,
|
|
732
|
+
advance: 0.5,
|
|
733
|
+
step: 0.5
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
var LineBox = class _LineBox {
|
|
737
|
+
x0;
|
|
738
|
+
y0;
|
|
739
|
+
x1;
|
|
740
|
+
y1;
|
|
741
|
+
baselineY;
|
|
742
|
+
srcEnd;
|
|
743
|
+
justified;
|
|
744
|
+
#cols;
|
|
745
|
+
#start;
|
|
746
|
+
#count;
|
|
747
|
+
constructor(f, cols, start, count) {
|
|
748
|
+
this.x0 = f.x0;
|
|
749
|
+
this.y0 = f.y0;
|
|
750
|
+
this.x1 = f.x1;
|
|
751
|
+
this.y1 = f.y1;
|
|
752
|
+
this.baselineY = f.baselineY;
|
|
753
|
+
this.srcEnd = f.srcEnd;
|
|
754
|
+
this.justified = f.justified;
|
|
755
|
+
this.#cols = cols;
|
|
756
|
+
this.#start = start;
|
|
757
|
+
this.#count = count;
|
|
758
|
+
Object.defineProperties(this, _LineBox.#views);
|
|
759
|
+
}
|
|
760
|
+
/** The line's code points in its layout's columns, for a reader that walks
|
|
761
|
+
* them without building the views; null for a line built by hand. */
|
|
762
|
+
static span(line) {
|
|
763
|
+
return line instanceof _LineBox ? { cols: line.#cols, start: line.#start, count: line.#count } : null;
|
|
764
|
+
}
|
|
765
|
+
/** How many code points the line holds, without building a view. */
|
|
766
|
+
static count(line) {
|
|
767
|
+
return line instanceof _LineBox ? line.#count : line.glyphs.length;
|
|
768
|
+
}
|
|
769
|
+
static #views = {
|
|
770
|
+
cells: lazy("cells", (l) => {
|
|
771
|
+
const out = new Array(l.#count);
|
|
772
|
+
for (let pos = 0; pos < l.#count; pos++) out[pos] = l.#cols.cell(l.#start, pos);
|
|
773
|
+
return out;
|
|
774
|
+
}),
|
|
775
|
+
glyphs: lazy("glyphs", (l) => {
|
|
776
|
+
const out = new Array(l.#count);
|
|
777
|
+
for (let slot = 0; slot < l.#count; slot++) {
|
|
778
|
+
out[slot] = l.#cols.glyph(l.#start, l.#cols.visual(l.#start, slot), blankGlyph());
|
|
779
|
+
}
|
|
780
|
+
return out;
|
|
781
|
+
})
|
|
782
|
+
};
|
|
783
|
+
};
|
|
784
|
+
function lazy(key, build) {
|
|
785
|
+
return {
|
|
786
|
+
enumerable: true,
|
|
787
|
+
configurable: true,
|
|
788
|
+
get() {
|
|
789
|
+
const value = build(this);
|
|
790
|
+
Object.defineProperty(this, key, { value, enumerable: true, configurable: true, writable: false });
|
|
791
|
+
return value;
|
|
792
|
+
}
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
|
|
622
796
|
// src/measure/graphemes.ts
|
|
623
797
|
var segmenter;
|
|
624
798
|
var NEEDS_SEGMENTING = /[\r\u0300-\uffff]/;
|
|
@@ -808,8 +982,9 @@ function aboveBaseline(e, lineHeight) {
|
|
|
808
982
|
if (e.metrics.descent === void 0) return ascent;
|
|
809
983
|
return (e.lineSize * lineHeight - ascent - e.metrics.descent * k) / 2 + ascent;
|
|
810
984
|
}
|
|
811
|
-
function breakLines(entries, maxWidth, lineHeight) {
|
|
812
|
-
const sum =
|
|
985
|
+
function breakLines(entries, cps, maxWidth, lineHeight) {
|
|
986
|
+
const sum = doubles(entries.length + 1);
|
|
987
|
+
sum[0] = 0;
|
|
813
988
|
const tabs = [];
|
|
814
989
|
entries.forEach((e, k) => {
|
|
815
990
|
sum[k + 1] = sum[k] + e.kerningBefore + e.advance + e.tracking;
|
|
@@ -817,7 +992,7 @@ function breakLines(entries, maxWidth, lineHeight) {
|
|
|
817
992
|
});
|
|
818
993
|
const flatWidth = (start, end) => entries[start].advance + entries[start].tracking + sum[end] - sum[start + 1];
|
|
819
994
|
const widthOf = tabs.length === 0 ? flatWidth : (start, end) => widthWithTabs(start, end, tabs, (k) => entries[k].tab, flatWidth);
|
|
820
|
-
return wrapLines(
|
|
995
|
+
return wrapLines(cps, maxWidth, widthOf).map((span) => {
|
|
821
996
|
const line = {
|
|
822
997
|
start: span.start,
|
|
823
998
|
entries: [],
|
|
@@ -870,66 +1045,41 @@ function alignOffset(align, alignWidth, inkWidth) {
|
|
|
870
1045
|
const slack = alignWidth - inkWidth;
|
|
871
1046
|
return align === "center" ? slack / 2 : slack;
|
|
872
1047
|
}
|
|
873
|
-
|
|
1048
|
+
var NO_GAPS = /* @__PURE__ */ new Set();
|
|
1049
|
+
function placeLine(line, y, order, align, alignWidth, justify, cols, start) {
|
|
874
1050
|
const { entries } = line;
|
|
875
1051
|
const hung = hungWidth(entries);
|
|
876
1052
|
const inkWidth = line.width - hung;
|
|
877
1053
|
const slack = alignWidth - inkWidth;
|
|
878
|
-
const gaps = justify && line.wrapped && Number.isFinite(alignWidth) && slack > 0 ? wordGaps(entries) :
|
|
1054
|
+
const gaps = justify && line.wrapped && Number.isFinite(alignWidth) && slack > 0 ? wordGaps(entries) : NO_GAPS;
|
|
879
1055
|
const gapExtra = gaps.size > 0 ? slack / gaps.size : 0;
|
|
880
1056
|
const spread = gapExtra * gaps.size;
|
|
881
1057
|
const inkLeft = spread > 0 ? 0 : alignOffset(align, alignWidth, inkWidth);
|
|
882
1058
|
const hangsLeft = hung > 0 && order.levels[entries.length - 1] % 2 === 1;
|
|
883
1059
|
const left = hangsLeft ? inkLeft - hung : inkLeft;
|
|
884
1060
|
const lineBaselineY = y + line.ascent;
|
|
885
|
-
const cells = new Array(entries.length);
|
|
886
|
-
const glyphs = [];
|
|
887
1061
|
let penX = left;
|
|
888
1062
|
let prevPos = -1;
|
|
1063
|
+
let slot = 0;
|
|
889
1064
|
for (const pos of order.visual) {
|
|
890
1065
|
const e = entries[pos];
|
|
891
1066
|
penX += prevPos < 0 ? 0 : pos === prevPos + 1 ? e.kerningBefore : prevPos === pos + 1 ? entries[prevPos].kerningBefore : 0;
|
|
892
1067
|
prevPos = pos;
|
|
893
1068
|
const step = e.advance + e.tracking + (gaps.has(pos) ? gapExtra : 0);
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
srcEnd: e.srcEnd,
|
|
897
|
-
cp: e.cp,
|
|
898
|
-
x: penX,
|
|
899
|
-
advance: step,
|
|
900
|
-
level: order.levels[pos],
|
|
901
|
-
drawsInk: e.drawsInk,
|
|
902
|
-
clusterEnd: e.clusterEnd
|
|
903
|
-
};
|
|
904
|
-
glyphs.push({
|
|
905
|
-
run: e.run,
|
|
906
|
-
cell: pos,
|
|
907
|
-
cp: e.cp,
|
|
908
|
-
fontSize: e.fontSize,
|
|
909
|
-
resolved: e.resolved,
|
|
910
|
-
metrics: e.metrics,
|
|
911
|
-
font: e.font,
|
|
912
|
-
glyph: e.glyph,
|
|
913
|
-
x: penX,
|
|
914
|
-
// Positive raises, and y grows down, so the shift subtracts.
|
|
915
|
-
baselineY: lineBaselineY - e.baselineShift,
|
|
916
|
-
advance: e.advance,
|
|
917
|
-
step
|
|
918
|
-
});
|
|
1069
|
+
cols.set(start + pos, e, order.levels[pos], penX, step, lineBaselineY - e.baselineShift);
|
|
1070
|
+
cols.setVisual(start, slot++, pos);
|
|
919
1071
|
penX += step;
|
|
920
1072
|
}
|
|
921
1073
|
return {
|
|
922
|
-
box: {
|
|
1074
|
+
box: new LineBox({
|
|
923
1075
|
x0: left,
|
|
924
1076
|
y0: y,
|
|
925
1077
|
x1: left + line.width + spread,
|
|
926
1078
|
y1: y + line.height,
|
|
927
1079
|
baselineY: lineBaselineY,
|
|
928
|
-
cells,
|
|
929
|
-
glyphs,
|
|
930
1080
|
srcEnd: line.srcEnd,
|
|
931
1081
|
justified: spread > 0
|
|
932
|
-
},
|
|
1082
|
+
}, cols, start, entries.length),
|
|
933
1083
|
inkWidth: inkWidth + spread
|
|
934
1084
|
};
|
|
935
1085
|
}
|
|
@@ -956,14 +1106,20 @@ function layoutRuns(runs, opts) {
|
|
|
956
1106
|
const { bidi } = o;
|
|
957
1107
|
const paragraphs = bidi ? analyzeParagraphs(bidi, cps, (i) => isHardLineBreak(cps[i]), o.direction) : null;
|
|
958
1108
|
if (!bidi) warnRtlWithoutEngine(cps);
|
|
1109
|
+
const broken = breakLines(entries, cps, o.maxWidth, o.lineHeight);
|
|
1110
|
+
let size = 0;
|
|
1111
|
+
for (const line of broken) size += line.entries.length;
|
|
1112
|
+
const cols = new LayoutColumns(size);
|
|
959
1113
|
const lines = [];
|
|
960
1114
|
let y = 0;
|
|
961
1115
|
let width = 0;
|
|
962
|
-
|
|
1116
|
+
let start = 0;
|
|
1117
|
+
for (const line of broken) {
|
|
963
1118
|
const order = orderLine(paragraphs, line.start, line.entries.length);
|
|
964
1119
|
if (bidi) line.entries = mirrorEntries(line.entries, order.levels, (cp) => bidi.mirror(cp), runs);
|
|
965
1120
|
const reads = o.direction !== "auto" ? o.direction : directionOfLevel(line.entries.length > 0 ? paragraphs?.baseLevel(line.start) ?? 0 : 0);
|
|
966
|
-
const placed = placeLine(line, y, order, resolveAlign(o.align, reads), o.alignWidth, o.justify);
|
|
1121
|
+
const placed = placeLine(line, y, order, resolveAlign(o.align, reads), o.alignWidth, o.justify, cols, start);
|
|
1122
|
+
start += line.entries.length;
|
|
967
1123
|
lines.push(placed.box);
|
|
968
1124
|
width = Math.max(width, placed.inkWidth);
|
|
969
1125
|
y += line.height;
|
|
@@ -1038,6 +1194,6 @@ function _resetLayoutCacheForTests() {
|
|
|
1038
1194
|
structuralGeneration = -1;
|
|
1039
1195
|
}
|
|
1040
1196
|
|
|
1041
|
-
export { BREAK_ALLOWED, BREAK_MANDATORY, DEFAULT_TAB_SIZE, DEFAULT_TEXT_FILL, DEFAULT_TEXT_STYLE, LAYOUT_CACHE_STRUCTURAL_LIMIT, LAYOUT_CACHE_VARIANT_LIMIT, NO_BREAK, _resetBidiWarningForTests, _resetLayoutCacheForTests, cachedLayoutRuns, fontString, graphemeCount, hangs, isHardLineBreak, layoutRuns, lineBreakOpportunities, paragraphDirection, registerBidi, resolveAlign, resolveTextStyle, tabAdvance, widthWithTabs, wrapLines };
|
|
1042
|
-
//# sourceMappingURL=chunk-
|
|
1043
|
-
//# sourceMappingURL=chunk-
|
|
1197
|
+
export { BREAK_ALLOWED, BREAK_MANDATORY, DEFAULT_TAB_SIZE, DEFAULT_TEXT_FILL, DEFAULT_TEXT_STYLE, LAYOUT_CACHE_STRUCTURAL_LIMIT, LAYOUT_CACHE_VARIANT_LIMIT, LineBox, NO_BREAK, _resetBidiWarningForTests, _resetLayoutCacheForTests, blankGlyph, cachedLayoutRuns, doubles, fontString, graphemeCount, hangs, isHardLineBreak, layoutRuns, lazy, lineBreakOpportunities, paragraphDirection, registerBidi, resolveAlign, resolveTextStyle, tabAdvance, widthWithTabs, wrapLines };
|
|
1198
|
+
//# sourceMappingURL=chunk-DOTR55MR.js.map
|
|
1199
|
+
//# sourceMappingURL=chunk-DOTR55MR.js.map
|