@weasel-js/text 1.7.0 → 1.7.2

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.
@@ -0,0 +1,1207 @@
1
+ import { resolveScreenLength } from '@weasel-js/paint';
2
+ import { resolveFontVariant, faceMetricsOf, fontPending, glyphGeneration, glyphOutline, resolveGlyphFallback } from '@weasel-js/font';
3
+
4
+ var __defProp = Object.defineProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ function resolveAlign(align, direction) {
10
+ if (align === "start" || align === "justify") return direction === "rtl" ? "right" : "left";
11
+ if (align === "end") return direction === "rtl" ? "left" : "right";
12
+ return align;
13
+ }
14
+ var DEFAULT_FILL = { fill: "solid", color: "#000" };
15
+ function paintColor(p) {
16
+ return p !== null && "color" in p ? p.color : "#000";
17
+ }
18
+ function defaultSelectionBackground(textColor) {
19
+ return `color-mix(in srgb, ${textColor} 25%, transparent)`;
20
+ }
21
+ var DEFAULT_TEXT_STYLE = {
22
+ fontSize: 16,
23
+ fontFamily: "sans-serif",
24
+ fontWeight: 400,
25
+ fontStyle: "normal",
26
+ align: "left",
27
+ direction: "ltr",
28
+ lineHeight: 1.2,
29
+ wrap: false,
30
+ fill: DEFAULT_FILL,
31
+ caretColor: paintColor(DEFAULT_FILL),
32
+ selectionBackground: defaultSelectionBackground(paintColor(DEFAULT_FILL)),
33
+ selectionColor: null,
34
+ letterSpacing: 0,
35
+ underline: false,
36
+ strikethrough: false,
37
+ overline: false,
38
+ textTransform: "none",
39
+ fontVariantCaps: "normal"
40
+ };
41
+ function resolveTextStyle(style, paint, scale = 1) {
42
+ const fill = paint?.fill === void 0 ? DEFAULT_TEXT_STYLE.fill : paint.fill;
43
+ const stroke = paint?.stroke ?? void 0;
44
+ if (!style) {
45
+ return fill === DEFAULT_TEXT_STYLE.fill && stroke === void 0 ? DEFAULT_TEXT_STYLE : {
46
+ ...DEFAULT_TEXT_STYLE,
47
+ fill,
48
+ caretColor: paintColor(fill),
49
+ selectionBackground: defaultSelectionBackground(paintColor(fill)),
50
+ ...stroke !== void 0 ? { stroke } : {}
51
+ };
52
+ }
53
+ const caretColor = style.caretColor ?? paintColor(fill);
54
+ let selectionBackground;
55
+ if (style.selectionBackground === "none") {
56
+ selectionBackground = null;
57
+ } else if (style.selectionBackground != null) {
58
+ selectionBackground = style.selectionBackground;
59
+ } else {
60
+ selectionBackground = defaultSelectionBackground(caretColor);
61
+ }
62
+ return {
63
+ fontSize: resolveScreenLength(style.fontSize ?? DEFAULT_TEXT_STYLE.fontSize, scale),
64
+ fontFamily: style.fontFamily ?? DEFAULT_TEXT_STYLE.fontFamily,
65
+ fontWeight: style.fontWeight ?? DEFAULT_TEXT_STYLE.fontWeight,
66
+ fontStyle: style.fontStyle ?? DEFAULT_TEXT_STYLE.fontStyle,
67
+ align: style.align ?? DEFAULT_TEXT_STYLE.align,
68
+ direction: style.direction ?? DEFAULT_TEXT_STYLE.direction,
69
+ lineHeight: style.lineHeight ?? DEFAULT_TEXT_STYLE.lineHeight,
70
+ wrap: style.wrap ?? DEFAULT_TEXT_STYLE.wrap,
71
+ fill,
72
+ caretColor,
73
+ selectionBackground,
74
+ selectionColor: style.selectionColor ?? null,
75
+ letterSpacing: resolveScreenLength(style.letterSpacing ?? DEFAULT_TEXT_STYLE.letterSpacing, scale),
76
+ underline: style.underline ?? DEFAULT_TEXT_STYLE.underline,
77
+ strikethrough: style.strikethrough ?? DEFAULT_TEXT_STYLE.strikethrough,
78
+ overline: style.overline ?? DEFAULT_TEXT_STYLE.overline,
79
+ textTransform: style.textTransform ?? DEFAULT_TEXT_STYLE.textTransform,
80
+ fontVariantCaps: style.fontVariantCaps ?? DEFAULT_TEXT_STYLE.fontVariantCaps,
81
+ ...style.script !== void 0 ? { script: style.script } : {},
82
+ ...stroke !== void 0 ? { stroke } : {}
83
+ };
84
+ }
85
+ function fontString(s) {
86
+ return `${s.fontStyle} ${s.fontWeight} ${s.fontSize}px ${s.fontFamily}`;
87
+ }
88
+
89
+ // src/layout/decorationMetrics.ts
90
+ var DECORATION_KINDS = ["underline", "strikethrough", "overline"];
91
+ var DEFAULT_DECORATION_METRICS = Object.freeze({
92
+ underline: Object.freeze({ offset: 0.1, thickness: 0.05 }),
93
+ strikethrough: Object.freeze({ offset: -0.3, thickness: 0.05 }),
94
+ overline: Object.freeze({ offset: -0.9, thickness: 0.05 })
95
+ });
96
+ var resolved = /* @__PURE__ */ new WeakMap();
97
+ function decorationMetrics(face) {
98
+ if (!face) return DEFAULT_DECORATION_METRICS;
99
+ let out = resolved.get(face);
100
+ if (!out) {
101
+ const underline = face.underline ?? DEFAULT_DECORATION_METRICS.underline;
102
+ out = Object.freeze({
103
+ underline,
104
+ strikethrough: face.strikethrough ?? DEFAULT_DECORATION_METRICS.strikethrough,
105
+ overline: Object.freeze({ offset: DEFAULT_DECORATION_METRICS.overline.offset, thickness: underline.thickness })
106
+ });
107
+ resolved.set(face, out);
108
+ }
109
+ return out;
110
+ }
111
+ function decorationRule(kind, baselineY, fontSize, face) {
112
+ const m = decorationMetrics(face)[kind];
113
+ const y0 = baselineY + fontSize * m.offset;
114
+ return { y0, y1: y0 + fontSize * m.thickness };
115
+ }
116
+
117
+ // src/layout/lineBreak/lineBreakTable.ts
118
+ var lineBreakTable_exports = {};
119
+ __export(lineBreakTable_exports, {
120
+ AK: () => AK,
121
+ AL: () => AL,
122
+ AP: () => AP,
123
+ AS: () => AS,
124
+ B2: () => B2,
125
+ BA: () => BA,
126
+ BB: () => BB,
127
+ BK: () => BK,
128
+ CB: () => CB,
129
+ CL: () => CL,
130
+ CLASS_MASK: () => CLASS_MASK,
131
+ CM: () => CM,
132
+ CP: () => CP,
133
+ CR: () => CR,
134
+ EAST_ASIAN: () => EAST_ASIAN,
135
+ EB: () => EB,
136
+ EM: () => EM,
137
+ EX: () => EX,
138
+ GL: () => GL,
139
+ H2: () => H2,
140
+ H3: () => H3,
141
+ HL: () => HL,
142
+ HY: () => HY,
143
+ ID: () => ID,
144
+ IN: () => IN,
145
+ IS: () => IS,
146
+ JL: () => JL,
147
+ JT: () => JT,
148
+ JV: () => JV,
149
+ LF: () => LF,
150
+ NL: () => NL,
151
+ NS: () => NS,
152
+ NU: () => NU,
153
+ OP: () => OP,
154
+ PICTOGRAPHIC_CN: () => PICTOGRAPHIC_CN,
155
+ PO: () => PO,
156
+ PR: () => PR,
157
+ QU: () => QU,
158
+ QU_PF: () => QU_PF,
159
+ QU_PI: () => QU_PI,
160
+ RI: () => RI,
161
+ SP: () => SP,
162
+ SY: () => SY,
163
+ UNICODE_VERSION: () => UNICODE_VERSION,
164
+ VF: () => VF,
165
+ VI: () => VI,
166
+ WJ: () => WJ,
167
+ ZW: () => ZW,
168
+ ZWJ: () => ZWJ,
169
+ lineBreakPropsOf: () => lineBreakPropsOf
170
+ });
171
+ var UNICODE_VERSION = "16.0.0";
172
+ var BK = 0;
173
+ var CR = 1;
174
+ var LF = 2;
175
+ var NL = 3;
176
+ var SP = 4;
177
+ var ZW = 5;
178
+ var ZWJ = 6;
179
+ var CM = 7;
180
+ var WJ = 8;
181
+ var GL = 9;
182
+ var BA = 10;
183
+ var BB = 11;
184
+ var B2 = 12;
185
+ var HY = 13;
186
+ var CB = 14;
187
+ var CL = 15;
188
+ var CP = 16;
189
+ var EX = 17;
190
+ var IN = 18;
191
+ var NS = 19;
192
+ var OP = 20;
193
+ var QU = 21;
194
+ var IS = 22;
195
+ var NU = 23;
196
+ var PO = 24;
197
+ var PR = 25;
198
+ var SY = 26;
199
+ var AL = 27;
200
+ var HL = 28;
201
+ var ID = 29;
202
+ var EB = 30;
203
+ var EM = 31;
204
+ var H2 = 32;
205
+ var H3 = 33;
206
+ var JL = 34;
207
+ var JV = 35;
208
+ var JT = 36;
209
+ var RI = 37;
210
+ var AK = 38;
211
+ var AP = 39;
212
+ var AS = 40;
213
+ var VF = 41;
214
+ var VI = 42;
215
+ var QU_PI = 43;
216
+ var QU_PF = 44;
217
+ var CLASS_MASK = 63;
218
+ var EAST_ASIAN = 64;
219
+ var PICTOGRAPHIC_CN = 128;
220
+ var ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz!#$%&()*+,-./:;<=>?@[]^_{|}~";
221
+ var PALETTE = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 71, 73, 74, 79, 81, 82, 83, 84, 88, 89, 91, 93, 94, 95, 96, 97, 98, 155, 157];
222
+ var RUNS = 2787;
223
+ var PACKED = "9H1K1C2A1B18H1E1R1V1b1Z1Y1b1V1U1Q1b1Z1W1N1W1a10X2W3b1R27b1U1Z1Q29b1U1K1P1b6H1D26H1J1U1Y3Z5b1n1b1K2b1Y1Z2b1L6b1o3b1U520b1L3b1L18b1L32b79H1J12H7J13H14b1W260b7H255b1W1K4b1Z1b45H1K1H1b2H1b2H1R1H8b27c4b4c13b6X3b3Y2W2b11H1R1H3R43b21H10X1Y2X3b1H99b1R1b7H1X1b6H2b2H1b4H2b10X23b1H30b27H91b11H15b10X33b9H4b1W1R3b1H2Z22b4H1b9H1b3H1b5H43b3H52b2X5b9H42b24H1X33H54b3H1b18H1b7H10b2H2K10X17b3H56b1H1b7H2b2H2b3H9b1H10b2H2b10X2b2Y5b1Y1b1Z2b1H2b3H56b1H1b5H4b2H2b3H3b1H20b10X2H3b1H11b3H56b1H1b8H1b3H1b3H20b2H2b10X1b1Z8b6H1b3H56b1H1b7H2b2H2b3H7b3H10b2H2b10X18b1H59b5H3b3H1b4H9b1H14b10X9b1Z6b5H55b1H1b7H1b3H1b4H7b2H11b2H2b10X7b1L9b3H1L55b1H1b7H1b3H1b4H7b2H11b2H2b10X3b1H12b4H55b2H1b7H1b3H1b4H9b1H10b2H2b10X9b1Y7b3H70b1H4b6H1b1H1b8H6b10X2b2H61b1H2b7H4b1Z7b8H1b10X2K85b1H2b9H11b7H1b10X39b4L1b2L1J2L1K1J5R1J1b1R3b2H6b10X10b1K1H1b1H1b1H1U1P1U1P2H49b14H1K5H1K2H5b11H1b36H1b2K6b1H9b2L1K1L5b2J80b20H1b10X2K10b4H4b3H1b3H2b7H3b4H13b12H1b1H10X4H98b96(72f88g349b3H1b1K158b1K639b1K26b1U1P78b3K36b4H28b3H2K27b2H30b2H64b32H2K1T1b1K1b1K1Z1b1H2b10X24b2R2K1L1b2R1b3H1J1H10X107b2H34b1H118b12H4b12H8b2R10X128b11X60b5H57b10H1b29H2b1H10X6b10X22b31H49b5H47i16H1m8i1b2K10k2K1d4K10d9H9d3K3H30b13H2b10X6b38k12H2l48b20H3b5K10X6b10X36b2K80b3H1b21H4b1H6b1H2b3H198b13H1J46H1J3H509b1L2b7K1J3K1F1H1G2H1K1J2K1M3b1n1o1U2n1o1U1n4b3S1K2A5H1J8Y1b1n1o1b2T6b1W1U1P3T12b1K1Y4K1b3K1I5b10H13b1U1P14b1U1P17b7Z1Y1Z1y12Z1Y4Z1Y2Z1Y1Z1Y15Z33H18b1Y5b1Y12b1Z251b2Z219b1S24b1U1P1U1P14b2!13b1w1s190b4z3b1!2d1!521b2z1b4d16b2!2b1d1b3d1e2d16b8z1b3d12b12z20b1d22b1!10b6z3b1z13b1z8b2z17b2!5d2!3d4b1d1z3d1b1d1!3b2d2b1d2b3d8b1!6b1d2!1d1!1b2d1e1!2b1!7d1z2b2d2#2e26b1z35b1z1b1z4b3z1b1z3b6V1b2R1d3b1U1P1U1P1U1P1U1P1U1P1U1P1U1P31b3z24b1z14b1z5b1U1P31b1U1P1U1P1U1P1U1P1U1P403b1U1P1U1P1U1P1U1P1U1P1U1P1U1P1U1P1U1P1U1P1U1P63b1U1P1U1P32b1U1P285b2z51b1z4b1z409b3H7b1R3K1b1R1K112b1K14b1H96b32H2V1n1o1n1o3V1n1o1V1n1o8K1b1K1U1K2b1n1o2b1n1o1U1P1U1P1U1P1U1P4K1R1b2K1b2K5b2M3K1b2K1U8K1b1K1b2K3b2R1U1Q1U1Q1U1Q1U1Q1K34b26!1b89!12b214!26b16!1r2s2!1v2!1w1s1w1s1w1s1w1s1w1s2!1w1s1w1s1w1s1w1s1v1w2s10!6p5!1p5!2v2!1d1b1v1!1v1!1v1!1v1!1v25!1v31!1v1!1v1!1v6!1v6!2v2b2p4v1!2v1!1v1!1v1!1v1!1v25!1v31!1v1!1v1!1v6!1v6!2v4!4v1!5b43!1b94!1b86!9b1!16v31!1b40!8b7024!64z21013!1v1143!3b55!55b2K269b1K1R1K16b10X69b4H1b10H32b2H80b2H1b5K266b1H3b1H4b1H23b5H4b1H11b1Y59b2L2R8b2H50b18H8b2K10X6b18H10b1L2b1H10X28b8H2K23b13H12b29(3b4H47i13H1m6d3K4d1b1K10k4b2d5b1H10b10X6b41k14H9b3K1H8K2H2b10k2b1d3K27b3H50b1H1b3H2b2H5b2H1b1H41b5H2K3b2H236b8H1K2H2b10X6b1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&1%27&12b23f4b49g8452b512!29b1c1H10c1b13c1b5c1b1c1b2c1b2c1b10c494b1P1U188b1Y3b16H3s2v2t1w1s1u6b1J1H1J1H1J1H2J1H1J1H1J1H2J1H5!1w1s1w1s1w1s1w1s1w1s1w1s1w1s1w1s2!1w1s7!1s1!1s1b2v2t1!1w1s1w1s1w1s8!1b1!1y1x1!147b1I1b1t2!1y1x2!1w1s2!1s1!1s11!2v3!1t27!1w1!1s29!1w1!1s1!1w2s1w2s1v1!10v45!2v31!3b6!2b6!2b6!2b3!3b1x1y3!2y1b7z10b3H1O259b3K250b1H226b1H149b5H36b1K48b1K207b10X941b1K199b1K225b3H1b2H5b4H40b3H4b1H16b8K141b2H9b6K1S66b7K484b4H8b10X6b10X31b5H1K316b2H1K78b4H70b11H49b4H122b3H2j51i14H1m2K5d4b20d10k1H2i2H1i9b1J3H45b11H2b1X4K1H10b1X34b10X6b3H36b14H1b10X4K1b2H44b1H1b1L10b3H48b14H4b2K1b1K4H1b2H10X1b1L1b3K76b12H2K1b2K1b1H2b1H103b1K53b12H5b10X6b4H1b8i2b2i2b22i1b7i1b2i1b5i1b2H1K7H2b2H2b2H1m2b1k6b1H5b1K2k2i2H2b7H3b5H11b10k1b1k2b1k1b2k36i1b1d9H1b1H2b1H1b4H1b4H1m1j1H3d1b2d8b2H82b18H4b4K1b10X2K2b1H81b20H12b10X213b7H2b9H1L2K2R3b15K4b2H82b17H2K13b10X6b13L62b13H8b10X6b20X57b15H4b10X2b3K237b15H165b10X22b7i2b1i2b8i1b2i1b24i6H1b2H2b3H1m1j1H1j2H3K9b10k119b7H2b7H1b1L1b1H28b10H40b7H1b4H1L1b4K1L1b1H9b11H46b16H3K1b3L2K93b10L230b10X53b8H1b8H1b5K10b10X22b1L1R32b22H1b14H122b6H3b1H1b2H1b7H1b1H8b10X48b5H1b2H1b5H8b10X310b18k1K4H2K7b2H1j1H13i1b34i7H3b4H1m2K11d10k1H130b4Y30b1K1136b5K3555b3U3P36b1P3b1U1P1U1P239b1U2P179b1U7J1U1P3J1U1P1U1P1H6b15H4472b1U1P6960b30k18H10k2342b10X4b2K80b10X38b5H1K58b7H3K10b1K11b10X532b2K10X285b2K182b1H1b55H7b4H77b4v1q11b2p14b6136!8b768!470z41b1z9!8935b4z1b7z1b2z1b291!15b1v29b3v2b1v14b4v8b396!2465b2H1K4H4172b10X518b46H2b23H542b5H3b22H2b7H30b4H148b3H187b87z9b23z1111b50X512b55H4b50H8b1H14b1H2b4K16b5H1b15H1360b7H1b17H2b7H1b2H1b5H100b1H160b7H9b10X356b1H61b4H10X5b1Z492b4H10X244b2H1b10X725b7H109b7H5b10X4b2U844b1Y3b1Y847b4d1!39d4*100d12*15d2*15d1*14d1!1*37d10*142b1z2b10z19b56*26h3!13*44!4*9!7*2!14*6!154*33!12d9!1d70!1d7!1#14!8d2b2d21!2z5!1z5!3#2!1#2!1#2e2d5!12d17!3d1!3d3!5$63!1d1!1d2#2!11#21!19#3!1#4!3#1!3#7!1#1!1#14!1z1!1z1!1z5!1#4!1z1!2z74!2d1!7z16!14z13!12z12b1d4!1d24!12d2e4d1#21d1e4d2#13d1!47d8b24d6b1d74!3#3!5#38b3V3T4b35!1#16!3#9!1#5!6d1#3d3!2d3!4*4!11d2!3*4d9!3*116b3d4*5d85b5d6*12!4*1!15*12b4)56b8)10b6)40b8)30b2)12b4)2b62)12b1#2!1#8!8#6!1#9!10#1!1d3#7!1d48!1#61!2#1!2#1!1#17!3#1!13#34!84b12*14d2*13!3*10!5*52!3#1!7*15!2*11!6*9#7*240b10X6b1022*2b65534!2b65534!655363b1H30b96H128b240H196112b";
224
+ var bmp = null;
225
+ var astralStarts = null;
226
+ var astralValues = null;
227
+ function decode() {
228
+ const direct = new Uint8Array(65536);
229
+ const starts = new Int32Array(RUNS);
230
+ const values = new Uint8Array(RUNS);
231
+ const slot = new Uint8Array(128);
232
+ for (let i = 0; i < ALPHABET.length; i++) slot[ALPHABET.charCodeAt(i)] = PALETTE[i];
233
+ let cp = 0;
234
+ let run = 0;
235
+ let len = 0;
236
+ for (let i = 0; i < PACKED.length; i++) {
237
+ const code = PACKED.charCodeAt(i);
238
+ if (code <= 57 && code >= 48) len = len * 10 + code - 48;
239
+ else {
240
+ const v = slot[code];
241
+ starts[run] = cp;
242
+ values[run] = v;
243
+ if (cp < 65536) direct.fill(v, cp, Math.min(cp + len, 65536));
244
+ run++;
245
+ cp += len;
246
+ len = 0;
247
+ }
248
+ }
249
+ bmp = direct;
250
+ astralStarts = starts;
251
+ astralValues = values;
252
+ }
253
+ function lineBreakPropsOf(cp) {
254
+ if (bmp === null) decode();
255
+ if (cp < 65536) return bmp[cp];
256
+ if (cp > 1114111) return AL;
257
+ const starts = astralStarts;
258
+ let lo = 0;
259
+ let hi = starts.length - 1;
260
+ while (lo < hi) {
261
+ const mid = lo + hi + 1 >> 1;
262
+ if (starts[mid] <= cp) lo = mid;
263
+ else hi = mid - 1;
264
+ }
265
+ return astralValues[lo];
266
+ }
267
+
268
+ // src/layout/lineBreak/lineBreaks.ts
269
+ var {
270
+ lineBreakPropsOf: lineBreakPropsOf2,
271
+ CLASS_MASK: CLASS_MASK2,
272
+ EAST_ASIAN: EAST_ASIAN2,
273
+ PICTOGRAPHIC_CN: PICTOGRAPHIC_CN2,
274
+ BK: BK2,
275
+ CR: CR2,
276
+ LF: LF2,
277
+ NL: NL2,
278
+ SP: SP2,
279
+ ZW: ZW2,
280
+ ZWJ: ZWJ2,
281
+ CM: CM2,
282
+ WJ: WJ2,
283
+ GL: GL2,
284
+ BA: BA2,
285
+ BB: BB2,
286
+ B2: B22,
287
+ HY: HY2,
288
+ CB: CB2,
289
+ CL: CL2,
290
+ CP: CP2,
291
+ EX: EX2,
292
+ IN: IN2,
293
+ NS: NS2,
294
+ OP: OP2,
295
+ QU: QU2,
296
+ IS: IS2,
297
+ NU: NU2,
298
+ PO: PO2,
299
+ PR: PR2,
300
+ SY: SY2,
301
+ AL: AL2,
302
+ HL: HL2,
303
+ ID: ID2,
304
+ EB: EB2,
305
+ EM: EM2,
306
+ H2: H22,
307
+ H3: H32,
308
+ JL: JL2,
309
+ JV: JV2,
310
+ JT: JT2,
311
+ RI: RI2,
312
+ AK: AK2,
313
+ AP: AP2,
314
+ AS: AS2,
315
+ VF: VF2,
316
+ VI: VI2,
317
+ QU_PI: QU_PI2,
318
+ QU_PF: QU_PF2
319
+ } = lineBreakTable_exports;
320
+ var NO_BREAK = 0;
321
+ var BREAK_ALLOWED = 1;
322
+ var BREAK_MANDATORY = 2;
323
+ var HYPHEN = 8208;
324
+ var DOTTED_CIRCLE = 9676;
325
+ var isQU = (c) => c === QU2 || c === QU_PI2 || c === QU_PF2;
326
+ var isHard = (c) => c === BK2 || c === CR2 || c === LF2 || c === NL2;
327
+ function isHardLineBreak(cp) {
328
+ return isHard(lineBreakPropsOf2(cp) & CLASS_MASK2);
329
+ }
330
+ var isAlpha = (c) => c === AL2 || c === HL2;
331
+ var isKorean = (c) => c === JL2 || c === JV2 || c === JT2 || c === H22 || c === H32;
332
+ var isIdeoLike = (c) => c === ID2 || c === EB2 || c === EM2;
333
+ function lineBreakOpportunities(cps) {
334
+ const n = cps.length;
335
+ const out = new Uint8Array(n + 1);
336
+ if (n === 0) return out;
337
+ out[n] = BREAK_MANDATORY;
338
+ const cls = new Uint8Array(n);
339
+ const ea = new Uint8Array(n);
340
+ const pict = new Uint8Array(n);
341
+ const cp = new Int32Array(n);
342
+ const start = new Int32Array(n);
343
+ let u = 0;
344
+ for (let i = 0; i < n; i++) {
345
+ const props = lineBreakPropsOf2(cps[i]);
346
+ const c = props & CLASS_MASK2;
347
+ if ((c === CM2 || c === ZWJ2) && u > 0) {
348
+ const base = cls[u - 1];
349
+ if (!isHard(base) && base !== SP2 && base !== ZW2) continue;
350
+ }
351
+ if (c === CM2 || c === ZWJ2) {
352
+ cls[u] = AL2;
353
+ ea[u] = 0;
354
+ pict[u] = 0;
355
+ } else {
356
+ cls[u] = c;
357
+ ea[u] = props & EAST_ASIAN2 ? 1 : 0;
358
+ pict[u] = props & PICTOGRAPHIC_CN2 ? 1 : 0;
359
+ }
360
+ cp[u] = cps[i];
361
+ start[u] = i;
362
+ u++;
363
+ }
364
+ const units = u;
365
+ const prevIsZWJ = (b) => (lineBreakPropsOf2(cps[start[b] - 1]) & CLASS_MASK2) === ZWJ2;
366
+ const beforeSpaces = (k) => {
367
+ while (k >= 0 && cls[k] === SP2) k--;
368
+ return k;
369
+ };
370
+ for (let b = 1; b < units; b++) {
371
+ out[start[b]] = decide(b);
372
+ }
373
+ return out;
374
+ function decide(b) {
375
+ const a = b - 1;
376
+ const A = cls[a];
377
+ const B = cls[b];
378
+ if (A === CR2 && B === LF2) return NO_BREAK;
379
+ if (isHard(A)) return BREAK_MANDATORY;
380
+ if (isHard(B) || B === SP2 || B === ZW2) return NO_BREAK;
381
+ const s = beforeSpaces(a);
382
+ if (s >= 0 && cls[s] === ZW2) return BREAK_ALLOWED;
383
+ if (prevIsZWJ(b)) return NO_BREAK;
384
+ if (A === WJ2 || B === WJ2 || A === GL2) return NO_BREAK;
385
+ if (B === GL2 && A !== SP2 && A !== BA2 && A !== HY2) return NO_BREAK;
386
+ if (B === CL2 || B === CP2 || B === EX2 || B === SY2) return NO_BREAK;
387
+ const S = s >= 0 ? cls[s] : -1;
388
+ if (S === OP2) return NO_BREAK;
389
+ if (S === QU_PI2) {
390
+ const p = s - 1;
391
+ if (p < 0) return NO_BREAK;
392
+ const P = cls[p];
393
+ if (isHard(P) || P === OP2 || isQU(P) || P === GL2 || P === SP2 || P === ZW2) return NO_BREAK;
394
+ }
395
+ if (B === QU_PF2) {
396
+ if (b + 1 >= units) return NO_BREAK;
397
+ const N = cls[b + 1];
398
+ if (N === SP2 || N === GL2 || N === WJ2 || N === CL2 || isQU(N) || N === CP2 || N === EX2 || N === IS2 || N === SY2 || isHard(N) || N === ZW2) return NO_BREAK;
399
+ }
400
+ if (A === SP2 && B === IS2 && b + 1 < units && cls[b + 1] === NU2) return BREAK_ALLOWED;
401
+ if (B === IS2) return NO_BREAK;
402
+ if ((S === CL2 || S === CP2) && B === NS2) return NO_BREAK;
403
+ if (S === B22 && B === B22) return NO_BREAK;
404
+ if (A === SP2) return BREAK_ALLOWED;
405
+ if (B === QU2 || B === QU_PF2) return NO_BREAK;
406
+ if (A === QU2 || A === QU_PI2) return NO_BREAK;
407
+ if (isQU(B)) {
408
+ if (!ea[a]) return NO_BREAK;
409
+ if (b + 1 >= units || !ea[b + 1]) return NO_BREAK;
410
+ }
411
+ if (isQU(A)) {
412
+ if (!ea[b]) return NO_BREAK;
413
+ if (a === 0 || !ea[a - 1]) return NO_BREAK;
414
+ }
415
+ if (A === CB2 || B === CB2) return BREAK_ALLOWED;
416
+ if ((A === HY2 || cp[a] === HYPHEN) && B === AL2) {
417
+ if (a === 0) return NO_BREAK;
418
+ const P = cls[a - 1];
419
+ if (isHard(P) || P === SP2 || P === ZW2 || P === CB2 || P === GL2) return NO_BREAK;
420
+ }
421
+ if (B === BA2 || B === HY2 || B === NS2 || A === BB2) return NO_BREAK;
422
+ if (a > 0 && cls[a - 1] === HL2 && (A === HY2 || A === BA2 && !ea[a]) && B !== HL2) return NO_BREAK;
423
+ if (A === SY2 && B === HL2) return NO_BREAK;
424
+ if (B === IN2) return NO_BREAK;
425
+ if (isAlpha(A) && B === NU2 || A === NU2 && isAlpha(B)) return NO_BREAK;
426
+ if (A === PR2 && isIdeoLike(B) || isIdeoLike(A) && B === PO2) return NO_BREAK;
427
+ if ((A === PR2 || A === PO2) && isAlpha(B) || isAlpha(A) && (B === PR2 || B === PO2)) return NO_BREAK;
428
+ if (B === PO2 || B === PR2) {
429
+ let k = A === CL2 || A === CP2 ? a - 1 : a;
430
+ while (k >= 0 && (cls[k] === SY2 || cls[k] === IS2)) k--;
431
+ if (k >= 0 && cls[k] === NU2) return NO_BREAK;
432
+ }
433
+ if (A === PO2 || A === PR2) {
434
+ if (B === NU2) return NO_BREAK;
435
+ if (B === OP2 && b + 1 < units) {
436
+ const N = cls[b + 1];
437
+ if (N === NU2) return NO_BREAK;
438
+ if (N === IS2 && b + 2 < units && cls[b + 2] === NU2) return NO_BREAK;
439
+ }
440
+ }
441
+ if ((A === HY2 || A === IS2) && B === NU2) return NO_BREAK;
442
+ if (B === NU2) {
443
+ let k = a;
444
+ while (k >= 0 && (cls[k] === SY2 || cls[k] === IS2)) k--;
445
+ if (k >= 0 && cls[k] === NU2) return NO_BREAK;
446
+ }
447
+ if (A === JL2 && (B === JL2 || B === JV2 || B === H22 || B === H32)) return NO_BREAK;
448
+ if ((A === JV2 || A === H22) && (B === JV2 || B === JT2)) return NO_BREAK;
449
+ if ((A === JT2 || A === H32) && B === JT2) return NO_BREAK;
450
+ if (isKorean(A) && B === PO2 || A === PR2 && isKorean(B)) return NO_BREAK;
451
+ if (isAlpha(A) && isAlpha(B)) return NO_BREAK;
452
+ const aksaraA = A === AK2 || A === AS2 || cp[a] === DOTTED_CIRCLE;
453
+ const aksaraB = B === AK2 || B === AS2 || cp[b] === DOTTED_CIRCLE;
454
+ if (A === AP2 && aksaraB) return NO_BREAK;
455
+ if (aksaraA && (B === VF2 || B === VI2)) return NO_BREAK;
456
+ if (A === VI2 && a > 0 && (cls[a - 1] === AK2 || cls[a - 1] === AS2 || cp[a - 1] === DOTTED_CIRCLE) && (B === AK2 || cp[b] === DOTTED_CIRCLE)) return NO_BREAK;
457
+ if (aksaraA && aksaraB && b + 1 < units && cls[b + 1] === VF2) return NO_BREAK;
458
+ if (A === IS2 && isAlpha(B)) return NO_BREAK;
459
+ if ((isAlpha(A) || A === NU2) && B === OP2 && !ea[b]) return NO_BREAK;
460
+ if (A === CP2 && !ea[a] && (isAlpha(B) || B === NU2)) return NO_BREAK;
461
+ if (A === RI2 && B === RI2) {
462
+ let k = a;
463
+ while (k >= 0 && cls[k] === RI2) k--;
464
+ if ((a - k) % 2 === 1) return NO_BREAK;
465
+ }
466
+ if (B === EM2 && (A === EB2 || pict[a])) return NO_BREAK;
467
+ return BREAK_ALLOWED;
468
+ }
469
+ }
470
+
471
+ // src/measure/graphemes.ts
472
+ var segmenter;
473
+ function graphemeSegmenter() {
474
+ if (segmenter === void 0) {
475
+ segmenter = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter(void 0, { granularity: "grapheme" }) : null;
476
+ }
477
+ return segmenter;
478
+ }
479
+ function graphemeEnds(text) {
480
+ const out = [];
481
+ const seg = graphemeSegmenter();
482
+ if (seg) {
483
+ for (const s of seg.segment(text)) out.push(s.index + s.segment.length);
484
+ return out;
485
+ }
486
+ let at = 0;
487
+ for (const ch of text) out.push(at += ch.length);
488
+ return out;
489
+ }
490
+ function graphemeCount(text) {
491
+ return graphemeEnds(text).length;
492
+ }
493
+
494
+ // src/layout/lineBreak/wrapLines.ts
495
+ var SPACE = 32;
496
+ function wrapLines(cps, maxWidth, widthOf) {
497
+ const n = cps.length;
498
+ const breaks = Number.isFinite(maxWidth) ? lineBreakOpportunities(cps) : null;
499
+ const lines = [];
500
+ let start = 0;
501
+ let i = 0;
502
+ while (i < n) {
503
+ const cp = cps[i];
504
+ if (isHardLineBreak(cp)) {
505
+ lines.push({ start, end: i, wrapped: false });
506
+ i += cp === 13 && cps[i + 1] === 10 ? 2 : 1;
507
+ start = i;
508
+ continue;
509
+ }
510
+ if (cp === SPACE) {
511
+ i++;
512
+ continue;
513
+ }
514
+ let j = i + 1;
515
+ let ink = i + 1;
516
+ while (j < n && !isHardLineBreak(cps[j]) && (!breaks || breaks[j] === NO_BREAK)) {
517
+ if (cps[j] !== SPACE) ink = j + 1;
518
+ j++;
519
+ }
520
+ if (breaks && i > start && widthOf(start, ink) > maxWidth) {
521
+ lines.push({ start, end: i, wrapped: true });
522
+ start = i;
523
+ }
524
+ i = j;
525
+ }
526
+ if (start < n) lines.push({ start, end: n, wrapped: false });
527
+ return lines;
528
+ }
529
+
530
+ // src/layout/layoutRuns.ts
531
+ function atlasMetrics(font) {
532
+ const size = font.info.size;
533
+ const { ascent, descent } = font.faceMetrics ?? {};
534
+ return {
535
+ size,
536
+ base: font.common.base,
537
+ ...ascent !== void 0 && descent !== void 0 ? { ascent: ascent * size, descent: descent * size } : { ascent: font.common.base },
538
+ advanceOf: (cp) => font.charMap.get(cp)?.xadvance ?? null,
539
+ kernOf: (l, r) => font.kerningMap.get(l)?.get(r) ?? 0
540
+ };
541
+ }
542
+ function fillKey(p) {
543
+ if (p === null) return "none";
544
+ if ("color" in p) return `s:${p.color}:${p.opacity ?? 1}`;
545
+ return `nx:${Math.random()}`;
546
+ }
547
+ function sameFill(a, b) {
548
+ if (a === b) return true;
549
+ if (a !== null && b !== null && "color" in a && "color" in b) {
550
+ return a.color === b.color && (a.opacity ?? 1) === (b.opacity ?? 1);
551
+ }
552
+ return false;
553
+ }
554
+ function strokePaints(s) {
555
+ if (s?.paint === void 0) return false;
556
+ const w = s.width ?? 1;
557
+ return (typeof w === "number" ? w : w.px) > 0;
558
+ }
559
+ function strokeKey(s) {
560
+ if (!strokePaints(s)) return "-";
561
+ const width = s.width ?? 1;
562
+ return [
563
+ // A screen-pixel width keys apart from the equal world-unit number: the two
564
+ // resolve to different ribbons, so they must not share a draw call.
565
+ fillKey(s.paint),
566
+ typeof width === "number" ? width : `px${width.px}`,
567
+ s.join ?? "miter",
568
+ s.cap ?? "butt",
569
+ s.miterLimit ?? "",
570
+ s.align ?? "center",
571
+ (s.dash ?? []).join(",")
572
+ ].join(":");
573
+ }
574
+ function groupKey(family, weight, style, synthetic, fill, stroke, source, page) {
575
+ return `${family}|${weight}|${style}|${synthetic.bold ? 1 : 0}${synthetic.italic ? 1 : 0}|${fillKey(fill)}|${strokeKey(stroke)}|${source}|${page}`;
576
+ }
577
+ function getOrCreateGroup(ctx, run, resolved2, page, sourceOverride) {
578
+ const atlasFamily = resolved2.resolved.family;
579
+ const resolvedWeight = resolved2.resolved.weight;
580
+ const resolvedStyle = resolved2.resolved.style;
581
+ const source = sourceOverride ?? resolved2.source;
582
+ const key = groupKey(
583
+ atlasFamily,
584
+ resolvedWeight,
585
+ resolvedStyle,
586
+ resolved2.synthetic,
587
+ run.fill,
588
+ source === "outline" && strokePaints(run.stroke) ? run.stroke : void 0,
589
+ source,
590
+ page
591
+ );
592
+ let g = ctx.groups.get(key);
593
+ if (!g) {
594
+ g = {
595
+ family: atlasFamily,
596
+ weight: resolvedWeight,
597
+ style: resolvedStyle,
598
+ synthetic: { ...resolved2.synthetic },
599
+ source,
600
+ page,
601
+ fill: run.fill,
602
+ // Only the outline tier can paint it, and carrying it on an SDF group
603
+ // would be a promise the renderer cannot keep.
604
+ ...source === "outline" && strokePaints(run.stroke) ? { stroke: run.stroke } : {},
605
+ quads: [],
606
+ glyphs: []
607
+ };
608
+ ctx.groups.set(key, g);
609
+ }
610
+ return g;
611
+ }
612
+ function resolveGlyph(run, font, resolved2, cp) {
613
+ const direct = font.charMap.get(cp);
614
+ if (direct) return { glyph: direct, font, resolved: resolved2 };
615
+ const fallback = resolveGlyphFallback(run.fontFamily, run.fontWeight, run.fontStyle);
616
+ const face = fallback?.dynamicFace;
617
+ if (fallback && face) {
618
+ const glyph = face.requestGlyph(cp);
619
+ if (glyph.xadvance > 0 || glyph.width > 0) {
620
+ return { glyph, font: face.font, resolved: fallback };
621
+ }
622
+ }
623
+ warnMissingGlyphOnce(resolved2.resolved.family, cp);
624
+ return null;
625
+ }
626
+ var RTL_BLOCKS = [
627
+ [1424, 1535],
628
+ [1536, 1983],
629
+ [2144, 2303],
630
+ [64285, 65023],
631
+ [65136, 65279],
632
+ [67584, 69631],
633
+ [124928, 126975]
634
+ ];
635
+ var warnedLogicalRtl = false;
636
+ function warnLogicalRtlOnce() {
637
+ if (warnedLogicalRtl) return;
638
+ warnedLogicalRtl = true;
639
+ console.warn(
640
+ // Naming the import in `from "<pkg>"` form would trip labkit's
641
+ // consumer smoke test, which greps dist for that exact shape.
642
+ "weasel layoutRuns: this text contains right-to-left characters but no `bidi` engine was supplied, 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 add it to the layout options."
643
+ );
644
+ }
645
+ var warnedMissingGlyphs = /* @__PURE__ */ new Set();
646
+ function warnMissingGlyphOnce(family, cp) {
647
+ const key = `${family}|${cp}`;
648
+ if (warnedMissingGlyphs.has(key)) return;
649
+ warnedMissingGlyphs.add(key);
650
+ const ch = String.fromCodePoint(cp);
651
+ console.warn(
652
+ `weasel layoutRuns: no glyph for U+${cp.toString(16).toUpperCase().padStart(4, "0")} (${JSON.stringify(ch)}) in "${family}", and the dynamic tier could not rasterize it \u2014 skipping the character. Bake it into the atlas, or call registerCanvasFont("${family}") to serve missing codepoints from installed fonts.`
653
+ );
654
+ }
655
+ var warnedNoMetrics = /* @__PURE__ */ new Set();
656
+ function warnNoMetricsOnce(family, weight, style) {
657
+ const key = `${family}|${weight}|${style}`;
658
+ if (warnedNoMetrics.has(key)) return;
659
+ warnedNoMetrics.add(key);
660
+ console.warn(
661
+ `weasel layoutRuns: no metrics for "${family}" ${weight}/${style} \u2014 neither an atlas nor an outline face resolved, so every run set in it lays out as nothing. Register it with registerFont / registerCanvasFont / registerFontOutlines. If you did, check for a duplicated @weasel-js/font in node_modules \u2014 its registry is module state, so a second copy is a second, empty one.`
662
+ );
663
+ }
664
+ function layoutRuns(runs, opts) {
665
+ const ctx = { groups: /* @__PURE__ */ new Map() };
666
+ const align = resolveAlign(opts.align, opts.direction ?? "ltr");
667
+ const justify = opts.justify === true || opts.align === "justify";
668
+ const lineSize = (e) => Math.max(e.run.fontSize, e.run.strutSize ?? 0);
669
+ const aboveBaseline = (e) => {
670
+ const k = lineSize(e) / e.metrics.size;
671
+ const ascent = e.metrics.ascent * k;
672
+ if (e.metrics.descent === void 0) return ascent;
673
+ return (lineSize(e) * opts.lineHeight - ascent - e.metrics.descent * k) / 2 + ascent;
674
+ };
675
+ const entries = [];
676
+ const runFaces = /* @__PURE__ */ new Map();
677
+ let prevCp;
678
+ let prevMetrics;
679
+ let prevFontSize;
680
+ let srcIndex = 0;
681
+ for (const run of runs) {
682
+ const resolved2 = resolveFontVariant(run.fontFamily, run.fontWeight, run.fontStyle);
683
+ runFaces.set(run, faceMetricsOf(resolved2));
684
+ const outlineFace = resolved2.outlineFace;
685
+ const font = resolved2.entry?.font ?? resolved2.dynamicFace?.font ?? null;
686
+ const metrics = outlineFace ? {
687
+ size: 1,
688
+ base: outlineFace.ascender,
689
+ ascent: outlineFace.faceMetrics?.ascent ?? outlineFace.ascender,
690
+ ...outlineFace.faceMetrics?.descent !== void 0 ? { descent: outlineFace.faceMetrics.descent } : {},
691
+ advanceOf: (cp) => outlineFace.advanceOf(cp),
692
+ kernOf: (l, r) => outlineFace.kernOf(l, r)
693
+ } : font ? atlasMetrics(font) : void 0;
694
+ if (!metrics) {
695
+ if (!fontPending(run.fontFamily, run.fontWeight, run.fontStyle)) {
696
+ warnNoMetricsOnce(run.fontFamily, run.fontWeight, run.fontStyle);
697
+ }
698
+ srcIndex += run.srcMap?.length ?? run.text.length;
699
+ prevCp = void 0;
700
+ prevMetrics = void 0;
701
+ prevFontSize = void 0;
702
+ continue;
703
+ }
704
+ const runBase = srcIndex;
705
+ const map = run.srcMap;
706
+ const sizes = run.sizeMap;
707
+ let at = 0;
708
+ const runTracking = run.letterSpacing;
709
+ const clusterEnds = runTracking === 0 ? null : new Set(graphemeEnds(run.text));
710
+ for (const ch of [...run.text]) {
711
+ const cp = ch.codePointAt(0);
712
+ const fontSize = sizes ? sizes[at] : run.fontSize;
713
+ const scale = fontSize / metrics.size;
714
+ const tracking = clusterEnds === null || clusterEnds.has(at + ch.length) ? runTracking : 0;
715
+ const isNewline = isHardLineBreak(cp);
716
+ const isSpace = cp === 32;
717
+ const srcStart = map ? runBase + map.starts[at] : runBase + at;
718
+ const srcEnd = map ? runBase + map.ends[at] : runBase + at + ch.length;
719
+ at += ch.length;
720
+ srcIndex = map ? runBase + map.length : srcEnd;
721
+ if (isNewline) {
722
+ entries.push({
723
+ run,
724
+ font,
725
+ metrics,
726
+ glyph: { id: cp, x: 0, y: 0, width: 0, height: 0, xoffset: 0, yoffset: 0, xadvance: 0, page: 0 },
727
+ // A newline consumes no advance, so it takes no tracking either.
728
+ cp,
729
+ advance: 0,
730
+ tracking: 0,
731
+ kerningBefore: 0,
732
+ isSpace: false,
733
+ isNewline: true,
734
+ drawsInk: false,
735
+ resolved: resolved2,
736
+ fontSize,
737
+ srcIndex: srcStart,
738
+ srcEnd,
739
+ flat: 0
740
+ });
741
+ prevCp = void 0;
742
+ prevMetrics = void 0;
743
+ prevFontSize = void 0;
744
+ continue;
745
+ }
746
+ if (isSpace) {
747
+ const spaceGlyph = resolved2.dynamicFace ? resolved2.dynamicFace.requestGlyph(32) : font?.charMap.get(32) ?? null;
748
+ const spaceAdvance = spaceGlyph ? spaceGlyph.xadvance : metrics.advanceOf(32);
749
+ const advance = spaceAdvance !== null ? spaceAdvance * scale : fontSize * 0.25;
750
+ let kerningBefore2 = 0;
751
+ if (prevCp !== void 0 && prevMetrics !== void 0 && prevFontSize !== void 0) {
752
+ kerningBefore2 = prevMetrics.kernOf(prevCp, cp) * (prevFontSize / prevMetrics.size);
753
+ }
754
+ entries.push({
755
+ run,
756
+ font,
757
+ metrics,
758
+ glyph: spaceGlyph ?? { id: 32, x: 0, y: 0, width: 0, height: 0, xoffset: 0, yoffset: 0, xadvance: 0, page: 0 },
759
+ cp,
760
+ advance,
761
+ tracking,
762
+ kerningBefore: kerningBefore2,
763
+ isSpace: true,
764
+ isNewline: false,
765
+ drawsInk: false,
766
+ resolved: resolved2,
767
+ fontSize,
768
+ srcIndex: srcStart,
769
+ srcEnd,
770
+ flat: 0
771
+ });
772
+ prevCp = cp;
773
+ prevMetrics = metrics;
774
+ prevFontSize = fontSize;
775
+ continue;
776
+ }
777
+ if (outlineFace) {
778
+ const adv = metrics.advanceOf(cp);
779
+ if (adv === null) {
780
+ entries.push({
781
+ run,
782
+ font: null,
783
+ metrics,
784
+ glyph: null,
785
+ cp,
786
+ advance: 0,
787
+ tracking: 0,
788
+ kerningBefore: 0,
789
+ isSpace,
790
+ isNewline: false,
791
+ drawsInk: false,
792
+ resolved: resolved2,
793
+ fontSize,
794
+ srcIndex: srcStart,
795
+ srcEnd,
796
+ flat: 0
797
+ });
798
+ prevCp = cp;
799
+ prevMetrics = metrics;
800
+ prevFontSize = fontSize;
801
+ continue;
802
+ }
803
+ let kerningBefore2 = 0;
804
+ if (prevCp !== void 0 && prevMetrics !== void 0 && prevFontSize !== void 0) {
805
+ kerningBefore2 = prevMetrics.kernOf(prevCp, cp) * (prevFontSize / prevMetrics.size);
806
+ }
807
+ entries.push({
808
+ run,
809
+ font: null,
810
+ metrics,
811
+ glyph: null,
812
+ cp,
813
+ advance: adv * scale,
814
+ tracking,
815
+ kerningBefore: kerningBefore2,
816
+ isSpace,
817
+ isNewline: false,
818
+ drawsInk: !isSpace,
819
+ resolved: resolved2,
820
+ fontSize,
821
+ srcIndex: srcStart,
822
+ srcEnd,
823
+ flat: 0
824
+ });
825
+ prevCp = cp;
826
+ prevMetrics = metrics;
827
+ prevFontSize = fontSize;
828
+ continue;
829
+ }
830
+ const hit = resolved2.dynamicFace ? { glyph: resolved2.dynamicFace.requestGlyph(cp), font, resolved: resolved2 } : resolveGlyph(run, font, resolved2, cp);
831
+ if (!hit) {
832
+ entries.push({
833
+ run,
834
+ font: null,
835
+ metrics,
836
+ glyph: null,
837
+ cp,
838
+ advance: 0,
839
+ tracking: 0,
840
+ kerningBefore: 0,
841
+ isSpace,
842
+ isNewline: false,
843
+ drawsInk: false,
844
+ resolved: resolved2,
845
+ fontSize,
846
+ srcIndex: srcStart,
847
+ srcEnd,
848
+ flat: 0
849
+ });
850
+ prevCp = cp;
851
+ prevMetrics = metrics;
852
+ prevFontSize = fontSize;
853
+ continue;
854
+ }
855
+ const glyphFont = hit.font;
856
+ const glyphMetrics = glyphFont === font ? metrics : atlasMetrics(glyphFont);
857
+ const glyphScale = fontSize / glyphFont.info.size;
858
+ let kerningBefore = 0;
859
+ if (prevCp !== void 0 && prevMetrics !== void 0 && prevFontSize !== void 0) {
860
+ kerningBefore = prevMetrics.kernOf(prevCp, cp) * (prevFontSize / prevMetrics.size);
861
+ }
862
+ entries.push({
863
+ run,
864
+ font: glyphFont,
865
+ metrics: glyphMetrics,
866
+ glyph: hit.glyph,
867
+ cp,
868
+ advance: hit.glyph.xadvance * glyphScale,
869
+ tracking,
870
+ kerningBefore,
871
+ isSpace,
872
+ isNewline: false,
873
+ drawsInk: !isSpace,
874
+ resolved: hit.resolved,
875
+ fontSize,
876
+ srcIndex: srcStart,
877
+ srcEnd,
878
+ flat: 0
879
+ });
880
+ prevCp = cp;
881
+ prevMetrics = glyphMetrics;
882
+ prevFontSize = fontSize;
883
+ }
884
+ }
885
+ for (let i = 0; i < entries.length; i++) entries[i].flat = i;
886
+ const analysis = opts.bidi ? opts.bidi.analyze(entries.map((e) => e.cp), opts.direction ?? "auto") : null;
887
+ if (!opts.bidi && entries.some((e) => RTL_BLOCKS.some(([lo, hi]) => e.cp >= lo && e.cp <= hi))) {
888
+ warnLogicalRtlOnce();
889
+ }
890
+ const openingWidth = (e) => e.isSpace ? 0 : e.advance + e.tracking;
891
+ const sum = new Float64Array(entries.length + 1);
892
+ for (let k = 0; k < entries.length; k++) {
893
+ const e = entries[k];
894
+ sum[k + 1] = sum[k] + e.kerningBefore + e.advance + e.tracking;
895
+ }
896
+ const widthOf = (start, end) => openingWidth(entries[start]) + sum[end] - sum[start + 1];
897
+ const lines = [];
898
+ for (const span2 of wrapLines(entries.map((e) => e.cp), opts.maxWidth, widthOf)) {
899
+ const line = { entries: [], width: 0, height: 0, ...span2.wrapped ? { wrapped: true } : {} };
900
+ if (span2.start === span2.end) {
901
+ const brk = entries[span2.end];
902
+ line.height = lineSize(brk) * opts.lineHeight;
903
+ line.blank = brk;
904
+ }
905
+ for (let k = span2.start; k < span2.end; k++) {
906
+ const e = entries[k];
907
+ const placed = k > span2.start ? e : e.isSpace ? { ...e, kerningBefore: 0, advance: 0, tracking: 0 } : { ...e, kerningBefore: 0 };
908
+ line.entries.push(placed);
909
+ line.width += placed.kerningBefore + placed.advance + placed.tracking;
910
+ line.height = Math.max(line.height, lineSize(e) * opts.lineHeight);
911
+ }
912
+ lines.push(line);
913
+ }
914
+ function outlineFor(e) {
915
+ const r0 = e.resolved.resolved;
916
+ if (e.resolved.source === "outline") {
917
+ return glyphOutline(r0.family, r0.weight, r0.style, e.cp);
918
+ }
919
+ const min = opts.outlineMinSize;
920
+ if (min === void 0) return null;
921
+ if (e.run.fontSize < min && !strokePaints(e.run.stroke)) return null;
922
+ if (e.resolved.synthetic.bold) return null;
923
+ const r = e.resolved.resolved;
924
+ return glyphOutline(r.family, r.weight, r.style, e.cp);
925
+ }
926
+ const decorations = [];
927
+ let span = null;
928
+ function flushSpan() {
929
+ const s = span;
930
+ span = null;
931
+ if (!s || s.x1 <= s.x0) return;
932
+ for (const kind of DECORATION_KINDS) {
933
+ if (!s[kind]) continue;
934
+ const { y0, y1 } = decorationRule(kind, s.baselineY, s.fontSize, s.face);
935
+ decorations.push({ kind, x0: s.x0, y0, x1: s.x1, y1, fill: s.fill });
936
+ }
937
+ }
938
+ const lineBoxes = [];
939
+ let penY = 0;
940
+ let maxLineWidth = 0;
941
+ const alignWidth = opts.alignWidth ?? opts.maxWidth;
942
+ for (const line of lines) {
943
+ let hung = 0;
944
+ for (let k = line.entries.length - 1; k >= 0; k--) {
945
+ const e = line.entries[k];
946
+ if (!e.isSpace) break;
947
+ hung += e.kerningBefore + e.advance + e.tracking;
948
+ }
949
+ const inkWidth = line.width - hung;
950
+ const gaps = /* @__PURE__ */ new Set();
951
+ let gapExtra = 0;
952
+ if (justify && line.wrapped && Number.isFinite(alignWidth) && alignWidth > inkWidth) {
953
+ let first = 0;
954
+ while (first < line.entries.length && line.entries[first].isSpace) first++;
955
+ let last = line.entries.length - 1;
956
+ while (last > first && line.entries[last].isSpace) last--;
957
+ for (let k = first + 1; k < last; k++) if (line.entries[k].isSpace) gaps.add(k);
958
+ if (gaps.size > 0) gapExtra = (alignWidth - inkWidth) / gaps.size;
959
+ }
960
+ const spread = gapExtra * gaps.size;
961
+ const alignShift = (() => {
962
+ if (spread > 0) return 0;
963
+ if (align === "left") return 0;
964
+ if (!Number.isFinite(alignWidth)) {
965
+ return align === "center" ? -inkWidth / 2 : -inkWidth;
966
+ }
967
+ const slack = alignWidth - inkWidth;
968
+ return align === "center" ? slack / 2 : slack;
969
+ })();
970
+ const lineX0 = alignShift;
971
+ let lineAscent = 0;
972
+ for (const e of line.entries) lineAscent = Math.max(lineAscent, aboveBaseline(e));
973
+ if (line.entries.length === 0 && line.blank) lineAscent = aboveBaseline(line.blank);
974
+ const lineBaselineY = penY + lineAscent;
975
+ const cells = new Array(line.entries.length);
976
+ const flatOf = line.entries.map((e) => e.flat);
977
+ const posOfFlat = /* @__PURE__ */ new Map();
978
+ flatOf.forEach((f, pos) => posOfFlat.set(f, pos));
979
+ let visual = line.entries.map((_, k) => k);
980
+ let levelOf = () => 0;
981
+ if (opts.bidi && analysis !== null && line.entries.length > 0) {
982
+ const from = flatOf[0];
983
+ const to = flatOf[flatOf.length - 1] + 1;
984
+ const r = opts.bidi.reorder(analysis, from, to);
985
+ const seen = /* @__PURE__ */ new Set();
986
+ const ordered = [];
987
+ for (const f of r.order) {
988
+ const pos = posOfFlat.get(f);
989
+ if (pos !== void 0 && !seen.has(pos)) {
990
+ ordered.push(pos);
991
+ seen.add(pos);
992
+ }
993
+ }
994
+ for (let k = 0; k < line.entries.length; k++) if (!seen.has(k)) ordered.push(k);
995
+ visual = ordered;
996
+ levelOf = (pos) => {
997
+ const l = r.levels[flatOf[pos] - from];
998
+ return typeof l === "number" && l >= 0 ? l : 0;
999
+ };
1000
+ }
1001
+ if (opts.bidi) {
1002
+ for (let pos = 0; pos < line.entries.length; pos++) {
1003
+ if (levelOf(pos) % 2 === 0) continue;
1004
+ const e = line.entries[pos];
1005
+ const m = opts.bidi.mirror(e.cp);
1006
+ if (m === null || m === e.cp) continue;
1007
+ if (e.font !== null) {
1008
+ const hit = resolveGlyph(e.run, e.font, e.resolved, m);
1009
+ if (!hit) continue;
1010
+ e.glyph = hit.glyph;
1011
+ }
1012
+ e.cp = m;
1013
+ }
1014
+ }
1015
+ let penX = lineX0;
1016
+ let prevPos = -1;
1017
+ for (const pos of visual) {
1018
+ const e = line.entries[pos];
1019
+ penX += prevPos < 0 ? 0 : pos === prevPos + 1 ? e.kerningBefore : prevPos === pos + 1 ? line.entries[prevPos].kerningBefore : 0;
1020
+ prevPos = pos;
1021
+ const step = e.advance + e.tracking + (gaps.has(pos) ? gapExtra : 0);
1022
+ const cell = {
1023
+ srcIndex: e.srcIndex,
1024
+ srcEnd: e.srcEnd,
1025
+ cp: e.cp,
1026
+ x: penX,
1027
+ advance: step,
1028
+ level: levelOf(pos),
1029
+ drawsInk: e.drawsInk
1030
+ };
1031
+ cells[pos] = cell;
1032
+ const scale = e.fontSize / e.metrics.size;
1033
+ const baselineY = lineBaselineY - (e.run.baselineShift ?? 0);
1034
+ const decoFill = e.run.fill;
1035
+ if (decoFill !== null && (e.run.underline || e.run.strikethrough || e.run.overline)) {
1036
+ const face = runFaces.get(e.run);
1037
+ if (span !== null && span.underline === e.run.underline && span.strikethrough === e.run.strikethrough && span.overline === e.run.overline && span.fontSize === e.run.fontSize && span.face === face && span.baselineY === baselineY && sameFill(span.fill, e.run.fill)) {
1038
+ span.x1 = penX + step;
1039
+ } else {
1040
+ flushSpan();
1041
+ span = {
1042
+ underline: e.run.underline,
1043
+ strikethrough: e.run.strikethrough,
1044
+ overline: e.run.overline,
1045
+ fill: decoFill,
1046
+ // The run's size, not the glyph's: a small-caps word is one rule.
1047
+ fontSize: e.run.fontSize,
1048
+ face,
1049
+ baselineY,
1050
+ x0: penX,
1051
+ x1: penX + step
1052
+ };
1053
+ }
1054
+ } else {
1055
+ flushSpan();
1056
+ }
1057
+ const outlineD = outlineFor(e);
1058
+ if (e.run.fill === null && !(outlineD !== null && strokePaints(e.run.stroke))) {
1059
+ penX += step;
1060
+ continue;
1061
+ }
1062
+ if (outlineD !== null) {
1063
+ const group2 = getOrCreateGroup(ctx, e.run, e.resolved, 0, "outline");
1064
+ group2.glyphs.push({
1065
+ d: outlineD,
1066
+ key: `${e.resolved.resolved.family}|${e.resolved.resolved.weight}|${e.resolved.resolved.style}|${e.cp}`,
1067
+ x: penX,
1068
+ baselineY,
1069
+ // Em space is unit-scale, so world units per em is just the size.
1070
+ scale: e.fontSize
1071
+ });
1072
+ penX += step;
1073
+ continue;
1074
+ }
1075
+ if (e.font === null || e.glyph === null || e.advance === 0 || e.glyph.width === 0 || e.glyph.page < 0) {
1076
+ penX += step;
1077
+ continue;
1078
+ }
1079
+ const group = getOrCreateGroup(ctx, e.run, e.resolved, e.glyph.page);
1080
+ const atlasW = e.font.common.scaleW;
1081
+ const atlasH = e.font.common.scaleH;
1082
+ const qx0 = penX + e.glyph.xoffset * scale;
1083
+ const qy0 = baselineY + (e.glyph.yoffset - e.metrics.base) * scale;
1084
+ const qx1 = qx0 + e.glyph.width * scale;
1085
+ const qy1 = qy0 + e.glyph.height * scale;
1086
+ const u0 = e.glyph.x / atlasW;
1087
+ const v0 = e.glyph.y / atlasH;
1088
+ const u1 = (e.glyph.x + e.glyph.width) / atlasW;
1089
+ const v1 = (e.glyph.y + e.glyph.height) / atlasH;
1090
+ group.quads.push({ x0: qx0, y0: qy0, x1: qx1, y1: qy1, u0, v0, u1, v1, baselineY });
1091
+ penX += step;
1092
+ }
1093
+ flushSpan();
1094
+ const lastCell = line.entries[line.entries.length - 1];
1095
+ const srcEnd = lastCell ? lastCell.srcEnd : line.blank?.srcIndex ?? 0;
1096
+ lineBoxes.push({
1097
+ x0: lineX0,
1098
+ y0: penY,
1099
+ x1: lineX0 + line.width + spread,
1100
+ y1: penY + line.height,
1101
+ baselineY: lineBaselineY,
1102
+ cells,
1103
+ srcEnd
1104
+ });
1105
+ maxLineWidth = Math.max(maxLineWidth, inkWidth + spread);
1106
+ penY += line.height;
1107
+ }
1108
+ return {
1109
+ groups: [...ctx.groups.values()],
1110
+ decorations,
1111
+ lines: lineBoxes,
1112
+ bounds: { width: maxLineWidth, height: penY }
1113
+ };
1114
+ }
1115
+ var LAYOUT_CACHE_VARIANT_LIMIT = 8;
1116
+ var LAYOUT_CACHE_STRUCTURAL_LIMIT = 64;
1117
+ var cache = /* @__PURE__ */ new WeakMap();
1118
+ var structural = /* @__PURE__ */ new Map();
1119
+ var structuralGeneration = -1;
1120
+ function outlineBucket(runs, min) {
1121
+ if (min === void 0) return -1;
1122
+ const sizes = /* @__PURE__ */ new Set();
1123
+ for (const r of runs) sizes.add(r.fontSize);
1124
+ let n = 0;
1125
+ for (const size of sizes) if (size >= min) n++;
1126
+ return n;
1127
+ }
1128
+ function variantKey(runs, opts) {
1129
+ const alignWidth = opts.alignWidth ?? opts.maxWidth;
1130
+ const justify = opts.justify === true || opts.align === "justify";
1131
+ return `${opts.maxWidth}|${alignWidth}|${opts.lineHeight}|${opts.align}|${justify ? "j" : ""}|${outlineBucket(runs, opts.outlineMinSize)}`;
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;
1142
+ }
1143
+ function paintKey(p) {
1144
+ if (p === null) return "none";
1145
+ return "color" in p ? `s${p.color}:${p.opacity ?? 1}` : `#${refId(p)}`;
1146
+ }
1147
+ function strokeKey2(s) {
1148
+ if (!s?.paint) return "-";
1149
+ const width = s.width ?? 1;
1150
+ return [
1151
+ paintKey(s.paint),
1152
+ typeof width === "number" ? width : `px${width.px}`,
1153
+ s.join ?? "miter",
1154
+ s.cap ?? "butt",
1155
+ s.miterLimit ?? "",
1156
+ s.align ?? "center",
1157
+ (s.dash ?? []).join(",")
1158
+ ].join(":");
1159
+ }
1160
+ function runsKey(runs) {
1161
+ let out = "";
1162
+ 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(",") : ""}|`;
1164
+ }
1165
+ return out;
1166
+ }
1167
+ function cachedLayoutRuns(runs, opts) {
1168
+ const fonts = glyphGeneration();
1169
+ let entry = cache.get(runs);
1170
+ if (entry === void 0) {
1171
+ entry = { generation: fonts, byVariant: /* @__PURE__ */ new Map() };
1172
+ cache.set(runs, entry);
1173
+ } else if (entry.generation !== fonts) {
1174
+ entry.generation = fonts;
1175
+ entry.byVariant.clear();
1176
+ }
1177
+ const key = variantKey(runs, opts);
1178
+ const hit = entry.byVariant.get(key);
1179
+ if (hit !== void 0) return hit;
1180
+ if (structuralGeneration !== fonts) {
1181
+ structural.clear();
1182
+ structuralGeneration = fonts;
1183
+ }
1184
+ const structuralK = `${runsKey(runs)}\0${key}`;
1185
+ let laid = structural.get(structuralK);
1186
+ if (laid !== void 0) {
1187
+ structural.delete(structuralK);
1188
+ } else {
1189
+ laid = layoutRuns(runs, opts);
1190
+ if (structural.size >= LAYOUT_CACHE_STRUCTURAL_LIMIT) {
1191
+ structural.delete(structural.keys().next().value);
1192
+ }
1193
+ }
1194
+ structural.set(structuralK, laid);
1195
+ if (entry.byVariant.size >= LAYOUT_CACHE_VARIANT_LIMIT) entry.byVariant.clear();
1196
+ entry.byVariant.set(key, laid);
1197
+ return laid;
1198
+ }
1199
+ function _resetLayoutCacheForTests() {
1200
+ cache = /* @__PURE__ */ new WeakMap();
1201
+ structural = /* @__PURE__ */ new Map();
1202
+ structuralGeneration = -1;
1203
+ }
1204
+
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-JQPOFIGT.js.map
1207
+ //# sourceMappingURL=chunk-JQPOFIGT.js.map