@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.
- package/dist/chunk-JQPOFIGT.js +1207 -0
- package/dist/chunk-JQPOFIGT.js.map +1 -0
- package/dist/index.d.ts +61 -17
- package/dist/index.js +181 -109
- package/dist/index.js.map +1 -1
- package/dist/{test-seams-D0C8kEcX.d.ts → test-seams-DbGu8K5F.d.ts} +190 -49
- package/dist/test-seams.d.ts +1 -1
- package/dist/test-seams.js +1 -1
- package/package.json +5 -5
- package/dist/chunk-SXEHVOGE.js +0 -764
- package/dist/chunk-SXEHVOGE.js.map +0 -1
package/dist/chunk-SXEHVOGE.js
DELETED
|
@@ -1,764 +0,0 @@
|
|
|
1
|
-
import { resolveScreenLength } from '@weasel-js/paint';
|
|
2
|
-
import { resolveFontVariant, glyphGeneration, glyphOutline, resolveGlyphFallback } from '@weasel-js/font';
|
|
3
|
-
|
|
4
|
-
// src/textStyle.ts
|
|
5
|
-
function resolveAlign(align, direction) {
|
|
6
|
-
if (align === "start") return direction === "rtl" ? "right" : "left";
|
|
7
|
-
if (align === "end") return direction === "rtl" ? "left" : "right";
|
|
8
|
-
return align;
|
|
9
|
-
}
|
|
10
|
-
var DEFAULT_FILL = { fill: "solid", color: "#000" };
|
|
11
|
-
function paintColor(p) {
|
|
12
|
-
return p !== null && "color" in p ? p.color : "#000";
|
|
13
|
-
}
|
|
14
|
-
function defaultSelectionBackground(textColor) {
|
|
15
|
-
return `color-mix(in srgb, ${textColor} 25%, transparent)`;
|
|
16
|
-
}
|
|
17
|
-
var DEFAULT_TEXT_STYLE = {
|
|
18
|
-
fontSize: 16,
|
|
19
|
-
fontFamily: "sans-serif",
|
|
20
|
-
fontWeight: 400,
|
|
21
|
-
fontStyle: "normal",
|
|
22
|
-
align: "left",
|
|
23
|
-
direction: "ltr",
|
|
24
|
-
lineHeight: 1.2,
|
|
25
|
-
wrap: false,
|
|
26
|
-
fill: DEFAULT_FILL,
|
|
27
|
-
caretColor: paintColor(DEFAULT_FILL),
|
|
28
|
-
selectionBackground: defaultSelectionBackground(paintColor(DEFAULT_FILL)),
|
|
29
|
-
selectionColor: null,
|
|
30
|
-
letterSpacing: 0,
|
|
31
|
-
underline: false,
|
|
32
|
-
strikethrough: false,
|
|
33
|
-
overline: false,
|
|
34
|
-
textTransform: "none"
|
|
35
|
-
};
|
|
36
|
-
function resolveTextStyle(style, paint, scale = 1) {
|
|
37
|
-
const fill = paint?.fill === void 0 ? DEFAULT_TEXT_STYLE.fill : paint.fill;
|
|
38
|
-
const stroke = paint?.stroke ?? void 0;
|
|
39
|
-
if (!style) {
|
|
40
|
-
return fill === DEFAULT_TEXT_STYLE.fill && stroke === void 0 ? DEFAULT_TEXT_STYLE : {
|
|
41
|
-
...DEFAULT_TEXT_STYLE,
|
|
42
|
-
fill,
|
|
43
|
-
caretColor: paintColor(fill),
|
|
44
|
-
selectionBackground: defaultSelectionBackground(paintColor(fill)),
|
|
45
|
-
...stroke !== void 0 ? { stroke } : {}
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
const caretColor = style.caretColor ?? paintColor(fill);
|
|
49
|
-
let selectionBackground;
|
|
50
|
-
if (style.selectionBackground === "none") {
|
|
51
|
-
selectionBackground = null;
|
|
52
|
-
} else if (style.selectionBackground != null) {
|
|
53
|
-
selectionBackground = style.selectionBackground;
|
|
54
|
-
} else {
|
|
55
|
-
selectionBackground = defaultSelectionBackground(caretColor);
|
|
56
|
-
}
|
|
57
|
-
return {
|
|
58
|
-
fontSize: resolveScreenLength(style.fontSize ?? DEFAULT_TEXT_STYLE.fontSize, scale),
|
|
59
|
-
fontFamily: style.fontFamily ?? DEFAULT_TEXT_STYLE.fontFamily,
|
|
60
|
-
fontWeight: style.fontWeight ?? DEFAULT_TEXT_STYLE.fontWeight,
|
|
61
|
-
fontStyle: style.fontStyle ?? DEFAULT_TEXT_STYLE.fontStyle,
|
|
62
|
-
align: style.align ?? DEFAULT_TEXT_STYLE.align,
|
|
63
|
-
direction: style.direction ?? DEFAULT_TEXT_STYLE.direction,
|
|
64
|
-
lineHeight: style.lineHeight ?? DEFAULT_TEXT_STYLE.lineHeight,
|
|
65
|
-
wrap: style.wrap ?? DEFAULT_TEXT_STYLE.wrap,
|
|
66
|
-
fill,
|
|
67
|
-
caretColor,
|
|
68
|
-
selectionBackground,
|
|
69
|
-
selectionColor: style.selectionColor ?? null,
|
|
70
|
-
letterSpacing: resolveScreenLength(style.letterSpacing ?? DEFAULT_TEXT_STYLE.letterSpacing, scale),
|
|
71
|
-
underline: style.underline ?? DEFAULT_TEXT_STYLE.underline,
|
|
72
|
-
strikethrough: style.strikethrough ?? DEFAULT_TEXT_STYLE.strikethrough,
|
|
73
|
-
overline: style.overline ?? DEFAULT_TEXT_STYLE.overline,
|
|
74
|
-
textTransform: style.textTransform ?? DEFAULT_TEXT_STYLE.textTransform,
|
|
75
|
-
...style.script !== void 0 ? { script: style.script } : {},
|
|
76
|
-
...stroke !== void 0 ? { stroke } : {}
|
|
77
|
-
};
|
|
78
|
-
}
|
|
79
|
-
function fontString(s) {
|
|
80
|
-
return `${s.fontStyle} ${s.fontWeight} ${s.fontSize}px ${s.fontFamily}`;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// src/layout/decorationMetrics.ts
|
|
84
|
-
var DECORATION_KINDS = ["underline", "strikethrough", "overline"];
|
|
85
|
-
var UNDERLINE_OFFSET = 0.1;
|
|
86
|
-
var STRIKETHROUGH_OFFSET = -0.3;
|
|
87
|
-
var OVERLINE_OFFSET = -0.9;
|
|
88
|
-
var DECORATION_THICKNESS = 0.05;
|
|
89
|
-
var OFFSET = {
|
|
90
|
-
underline: UNDERLINE_OFFSET,
|
|
91
|
-
strikethrough: STRIKETHROUGH_OFFSET,
|
|
92
|
-
overline: OVERLINE_OFFSET
|
|
93
|
-
};
|
|
94
|
-
function decorationRule(kind, baselineY, fontSize) {
|
|
95
|
-
const y0 = baselineY + fontSize * OFFSET[kind];
|
|
96
|
-
return { y0, y1: y0 + fontSize * DECORATION_THICKNESS };
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// src/layout/layoutRuns.ts
|
|
100
|
-
function atlasMetrics(font) {
|
|
101
|
-
return {
|
|
102
|
-
size: font.info.size,
|
|
103
|
-
base: font.common.base,
|
|
104
|
-
advanceOf: (cp) => font.charMap.get(cp)?.xadvance ?? null,
|
|
105
|
-
kernOf: (l, r) => font.kerningMap.get(l)?.get(r) ?? 0
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
function fillKey(p) {
|
|
109
|
-
if (p === null) return "none";
|
|
110
|
-
if ("color" in p) return `s:${p.color}:${p.opacity ?? 1}`;
|
|
111
|
-
return `nx:${Math.random()}`;
|
|
112
|
-
}
|
|
113
|
-
function sameFill(a, b) {
|
|
114
|
-
if (a === b) return true;
|
|
115
|
-
if (a !== null && b !== null && "color" in a && "color" in b) {
|
|
116
|
-
return a.color === b.color && (a.opacity ?? 1) === (b.opacity ?? 1);
|
|
117
|
-
}
|
|
118
|
-
return false;
|
|
119
|
-
}
|
|
120
|
-
function strokePaints(s) {
|
|
121
|
-
if (s?.paint === void 0) return false;
|
|
122
|
-
const w = s.width ?? 1;
|
|
123
|
-
return (typeof w === "number" ? w : w.px) > 0;
|
|
124
|
-
}
|
|
125
|
-
function strokeKey(s) {
|
|
126
|
-
if (!strokePaints(s)) return "-";
|
|
127
|
-
const width = s.width ?? 1;
|
|
128
|
-
return [
|
|
129
|
-
// A screen-pixel width keys apart from the equal world-unit number: the two
|
|
130
|
-
// resolve to different ribbons, so they must not share a draw call.
|
|
131
|
-
fillKey(s.paint),
|
|
132
|
-
typeof width === "number" ? width : `px${width.px}`,
|
|
133
|
-
s.join ?? "miter",
|
|
134
|
-
s.cap ?? "butt",
|
|
135
|
-
s.miterLimit ?? "",
|
|
136
|
-
s.align ?? "center",
|
|
137
|
-
(s.dash ?? []).join(",")
|
|
138
|
-
].join(":");
|
|
139
|
-
}
|
|
140
|
-
function groupKey(family, weight, style, synthetic, fill, stroke, source, page) {
|
|
141
|
-
return `${family}|${weight}|${style}|${synthetic.bold ? 1 : 0}${synthetic.italic ? 1 : 0}|${fillKey(fill)}|${strokeKey(stroke)}|${source}|${page}`;
|
|
142
|
-
}
|
|
143
|
-
function getOrCreateGroup(ctx, run, resolved, page, sourceOverride) {
|
|
144
|
-
const atlasFamily = resolved.resolved.family;
|
|
145
|
-
const resolvedWeight = resolved.resolved.weight;
|
|
146
|
-
const resolvedStyle = resolved.resolved.style;
|
|
147
|
-
const source = sourceOverride ?? resolved.source;
|
|
148
|
-
const key = groupKey(
|
|
149
|
-
atlasFamily,
|
|
150
|
-
resolvedWeight,
|
|
151
|
-
resolvedStyle,
|
|
152
|
-
resolved.synthetic,
|
|
153
|
-
run.fill,
|
|
154
|
-
source === "outline" && strokePaints(run.stroke) ? run.stroke : void 0,
|
|
155
|
-
source,
|
|
156
|
-
page
|
|
157
|
-
);
|
|
158
|
-
let g = ctx.groups.get(key);
|
|
159
|
-
if (!g) {
|
|
160
|
-
g = {
|
|
161
|
-
family: atlasFamily,
|
|
162
|
-
weight: resolvedWeight,
|
|
163
|
-
style: resolvedStyle,
|
|
164
|
-
synthetic: { ...resolved.synthetic },
|
|
165
|
-
source,
|
|
166
|
-
page,
|
|
167
|
-
fill: run.fill,
|
|
168
|
-
// Only the outline tier can paint it, and carrying it on an SDF group
|
|
169
|
-
// would be a promise the renderer cannot keep.
|
|
170
|
-
...source === "outline" && strokePaints(run.stroke) ? { stroke: run.stroke } : {},
|
|
171
|
-
quads: [],
|
|
172
|
-
glyphs: []
|
|
173
|
-
};
|
|
174
|
-
ctx.groups.set(key, g);
|
|
175
|
-
}
|
|
176
|
-
return g;
|
|
177
|
-
}
|
|
178
|
-
function resolveGlyph(run, font, resolved, cp) {
|
|
179
|
-
const direct = font.charMap.get(cp);
|
|
180
|
-
if (direct) return { glyph: direct, font, resolved };
|
|
181
|
-
const fallback = resolveGlyphFallback(run.fontFamily, run.fontWeight, run.fontStyle);
|
|
182
|
-
const face = fallback?.dynamicFace;
|
|
183
|
-
if (fallback && face) {
|
|
184
|
-
const glyph = face.requestGlyph(cp);
|
|
185
|
-
if (glyph.xadvance > 0 || glyph.width > 0) {
|
|
186
|
-
return { glyph, font: face.font, resolved: fallback };
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
warnMissingGlyphOnce(resolved.resolved.family, cp);
|
|
190
|
-
return null;
|
|
191
|
-
}
|
|
192
|
-
var RTL_BLOCKS = [
|
|
193
|
-
[1424, 1535],
|
|
194
|
-
[1536, 1983],
|
|
195
|
-
[2144, 2303],
|
|
196
|
-
[64285, 65023],
|
|
197
|
-
[65136, 65279],
|
|
198
|
-
[67584, 69631],
|
|
199
|
-
[124928, 126975]
|
|
200
|
-
];
|
|
201
|
-
var warnedLogicalRtl = false;
|
|
202
|
-
function warnLogicalRtlOnce() {
|
|
203
|
-
if (warnedLogicalRtl) return;
|
|
204
|
-
warnedLogicalRtl = true;
|
|
205
|
-
console.warn(
|
|
206
|
-
// Naming the import in `from "<pkg>"` form would trip labkit's
|
|
207
|
-
// consumer smoke test, which greps dist for that exact shape.
|
|
208
|
-
"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."
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
var warnedMissingGlyphs = /* @__PURE__ */ new Set();
|
|
212
|
-
function warnMissingGlyphOnce(family, cp) {
|
|
213
|
-
const key = `${family}|${cp}`;
|
|
214
|
-
if (warnedMissingGlyphs.has(key)) return;
|
|
215
|
-
warnedMissingGlyphs.add(key);
|
|
216
|
-
const ch = String.fromCodePoint(cp);
|
|
217
|
-
console.warn(
|
|
218
|
-
`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.`
|
|
219
|
-
);
|
|
220
|
-
}
|
|
221
|
-
var warnedNoMetrics = /* @__PURE__ */ new Set();
|
|
222
|
-
function warnNoMetricsOnce(family, weight, style) {
|
|
223
|
-
const key = `${family}|${weight}|${style}`;
|
|
224
|
-
if (warnedNoMetrics.has(key)) return;
|
|
225
|
-
warnedNoMetrics.add(key);
|
|
226
|
-
console.warn(
|
|
227
|
-
`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.`
|
|
228
|
-
);
|
|
229
|
-
}
|
|
230
|
-
function layoutRuns(runs, opts) {
|
|
231
|
-
const ctx = { groups: /* @__PURE__ */ new Map() };
|
|
232
|
-
const align = resolveAlign(opts.align, opts.direction ?? "ltr");
|
|
233
|
-
const lineSize = (e) => Math.max(e.fontSize, e.run.strutSize ?? 0);
|
|
234
|
-
const entries = [];
|
|
235
|
-
let prevCp;
|
|
236
|
-
let prevMetrics;
|
|
237
|
-
let prevFontSize;
|
|
238
|
-
let srcIndex = 0;
|
|
239
|
-
for (const run of runs) {
|
|
240
|
-
const resolved = resolveFontVariant(run.fontFamily, run.fontWeight, run.fontStyle);
|
|
241
|
-
const outlineFace = resolved.outlineFace;
|
|
242
|
-
const font = resolved.entry?.font ?? resolved.dynamicFace?.font ?? null;
|
|
243
|
-
const metrics = outlineFace ? { size: 1, base: outlineFace.ascender, advanceOf: (cp) => outlineFace.advanceOf(cp), kernOf: (l, r) => outlineFace.kernOf(l, r) } : font ? atlasMetrics(font) : void 0;
|
|
244
|
-
if (!metrics) {
|
|
245
|
-
warnNoMetricsOnce(run.fontFamily, run.fontWeight, run.fontStyle);
|
|
246
|
-
srcIndex += run.srcMap?.length ?? run.text.length;
|
|
247
|
-
prevCp = void 0;
|
|
248
|
-
prevMetrics = void 0;
|
|
249
|
-
prevFontSize = void 0;
|
|
250
|
-
continue;
|
|
251
|
-
}
|
|
252
|
-
const runBase = srcIndex;
|
|
253
|
-
const map = run.srcMap;
|
|
254
|
-
let at = 0;
|
|
255
|
-
const scale = run.fontSize / metrics.size;
|
|
256
|
-
const tracking = run.letterSpacing;
|
|
257
|
-
for (const ch of [...run.text]) {
|
|
258
|
-
const cp = ch.codePointAt(0);
|
|
259
|
-
const isNewline = cp === 10;
|
|
260
|
-
const isSpace = cp === 32;
|
|
261
|
-
const srcStart = map ? runBase + map.starts[at] : runBase + at;
|
|
262
|
-
const srcEnd = map ? runBase + map.ends[at] : runBase + at + ch.length;
|
|
263
|
-
at += ch.length;
|
|
264
|
-
srcIndex = map ? runBase + map.length : srcEnd;
|
|
265
|
-
if (isNewline) {
|
|
266
|
-
entries.push({
|
|
267
|
-
run,
|
|
268
|
-
font,
|
|
269
|
-
metrics,
|
|
270
|
-
glyph: { id: cp, x: 0, y: 0, width: 0, height: 0, xoffset: 0, yoffset: 0, xadvance: 0, page: 0 },
|
|
271
|
-
// A newline consumes no advance, so it takes no tracking either.
|
|
272
|
-
cp,
|
|
273
|
-
advance: 0,
|
|
274
|
-
tracking: 0,
|
|
275
|
-
kerningBefore: 0,
|
|
276
|
-
isSpace: false,
|
|
277
|
-
isNewline: true,
|
|
278
|
-
drawsInk: false,
|
|
279
|
-
resolved,
|
|
280
|
-
fontSize: run.fontSize,
|
|
281
|
-
srcIndex: srcStart,
|
|
282
|
-
srcEnd,
|
|
283
|
-
flat: 0
|
|
284
|
-
});
|
|
285
|
-
prevCp = void 0;
|
|
286
|
-
prevMetrics = void 0;
|
|
287
|
-
prevFontSize = void 0;
|
|
288
|
-
continue;
|
|
289
|
-
}
|
|
290
|
-
if (isSpace) {
|
|
291
|
-
const spaceGlyph = resolved.dynamicFace ? resolved.dynamicFace.requestGlyph(32) : font?.charMap.get(32) ?? null;
|
|
292
|
-
const spaceAdvance = spaceGlyph ? spaceGlyph.xadvance : metrics.advanceOf(32);
|
|
293
|
-
const advance = spaceAdvance !== null ? spaceAdvance * scale : run.fontSize * 0.25;
|
|
294
|
-
let kerningBefore2 = 0;
|
|
295
|
-
if (prevCp !== void 0 && prevMetrics !== void 0 && prevFontSize !== void 0) {
|
|
296
|
-
kerningBefore2 = prevMetrics.kernOf(prevCp, cp) * (prevFontSize / prevMetrics.size);
|
|
297
|
-
}
|
|
298
|
-
entries.push({
|
|
299
|
-
run,
|
|
300
|
-
font,
|
|
301
|
-
metrics,
|
|
302
|
-
glyph: spaceGlyph ?? { id: 32, x: 0, y: 0, width: 0, height: 0, xoffset: 0, yoffset: 0, xadvance: 0, page: 0 },
|
|
303
|
-
cp,
|
|
304
|
-
advance,
|
|
305
|
-
tracking,
|
|
306
|
-
kerningBefore: kerningBefore2,
|
|
307
|
-
isSpace: true,
|
|
308
|
-
isNewline: false,
|
|
309
|
-
drawsInk: false,
|
|
310
|
-
resolved,
|
|
311
|
-
fontSize: run.fontSize,
|
|
312
|
-
srcIndex: srcStart,
|
|
313
|
-
srcEnd,
|
|
314
|
-
flat: 0
|
|
315
|
-
});
|
|
316
|
-
prevCp = cp;
|
|
317
|
-
prevMetrics = metrics;
|
|
318
|
-
prevFontSize = run.fontSize;
|
|
319
|
-
continue;
|
|
320
|
-
}
|
|
321
|
-
if (outlineFace) {
|
|
322
|
-
const adv = metrics.advanceOf(cp);
|
|
323
|
-
if (adv === null) {
|
|
324
|
-
entries.push({
|
|
325
|
-
run,
|
|
326
|
-
font: null,
|
|
327
|
-
metrics,
|
|
328
|
-
glyph: null,
|
|
329
|
-
cp,
|
|
330
|
-
advance: 0,
|
|
331
|
-
tracking: 0,
|
|
332
|
-
kerningBefore: 0,
|
|
333
|
-
isSpace,
|
|
334
|
-
isNewline: false,
|
|
335
|
-
drawsInk: false,
|
|
336
|
-
resolved,
|
|
337
|
-
fontSize: run.fontSize,
|
|
338
|
-
srcIndex: srcStart,
|
|
339
|
-
srcEnd,
|
|
340
|
-
flat: 0
|
|
341
|
-
});
|
|
342
|
-
prevCp = cp;
|
|
343
|
-
prevMetrics = metrics;
|
|
344
|
-
prevFontSize = run.fontSize;
|
|
345
|
-
continue;
|
|
346
|
-
}
|
|
347
|
-
let kerningBefore2 = 0;
|
|
348
|
-
if (prevCp !== void 0 && prevMetrics !== void 0 && prevFontSize !== void 0) {
|
|
349
|
-
kerningBefore2 = prevMetrics.kernOf(prevCp, cp) * (prevFontSize / prevMetrics.size);
|
|
350
|
-
}
|
|
351
|
-
entries.push({
|
|
352
|
-
run,
|
|
353
|
-
font: null,
|
|
354
|
-
metrics,
|
|
355
|
-
glyph: null,
|
|
356
|
-
cp,
|
|
357
|
-
advance: adv * scale,
|
|
358
|
-
tracking,
|
|
359
|
-
kerningBefore: kerningBefore2,
|
|
360
|
-
isSpace,
|
|
361
|
-
isNewline: false,
|
|
362
|
-
drawsInk: !isSpace,
|
|
363
|
-
resolved,
|
|
364
|
-
fontSize: run.fontSize,
|
|
365
|
-
srcIndex: srcStart,
|
|
366
|
-
srcEnd,
|
|
367
|
-
flat: 0
|
|
368
|
-
});
|
|
369
|
-
prevCp = cp;
|
|
370
|
-
prevMetrics = metrics;
|
|
371
|
-
prevFontSize = run.fontSize;
|
|
372
|
-
continue;
|
|
373
|
-
}
|
|
374
|
-
const hit = resolved.dynamicFace ? { glyph: resolved.dynamicFace.requestGlyph(cp), font, resolved } : resolveGlyph(run, font, resolved, cp);
|
|
375
|
-
if (!hit) {
|
|
376
|
-
entries.push({
|
|
377
|
-
run,
|
|
378
|
-
font: null,
|
|
379
|
-
metrics,
|
|
380
|
-
glyph: null,
|
|
381
|
-
cp,
|
|
382
|
-
advance: 0,
|
|
383
|
-
tracking: 0,
|
|
384
|
-
kerningBefore: 0,
|
|
385
|
-
isSpace,
|
|
386
|
-
isNewline: false,
|
|
387
|
-
drawsInk: false,
|
|
388
|
-
resolved,
|
|
389
|
-
fontSize: run.fontSize,
|
|
390
|
-
srcIndex: srcStart,
|
|
391
|
-
srcEnd,
|
|
392
|
-
flat: 0
|
|
393
|
-
});
|
|
394
|
-
prevCp = cp;
|
|
395
|
-
prevMetrics = metrics;
|
|
396
|
-
prevFontSize = run.fontSize;
|
|
397
|
-
continue;
|
|
398
|
-
}
|
|
399
|
-
const glyphFont = hit.font;
|
|
400
|
-
const glyphMetrics = glyphFont === font ? metrics : atlasMetrics(glyphFont);
|
|
401
|
-
const glyphScale = run.fontSize / glyphFont.info.size;
|
|
402
|
-
let kerningBefore = 0;
|
|
403
|
-
if (prevCp !== void 0 && prevMetrics !== void 0 && prevFontSize !== void 0) {
|
|
404
|
-
kerningBefore = prevMetrics.kernOf(prevCp, cp) * (prevFontSize / prevMetrics.size);
|
|
405
|
-
}
|
|
406
|
-
entries.push({
|
|
407
|
-
run,
|
|
408
|
-
font: glyphFont,
|
|
409
|
-
metrics: glyphMetrics,
|
|
410
|
-
glyph: hit.glyph,
|
|
411
|
-
cp,
|
|
412
|
-
advance: hit.glyph.xadvance * glyphScale,
|
|
413
|
-
tracking,
|
|
414
|
-
kerningBefore,
|
|
415
|
-
isSpace,
|
|
416
|
-
isNewline: false,
|
|
417
|
-
drawsInk: !isSpace,
|
|
418
|
-
resolved: hit.resolved,
|
|
419
|
-
fontSize: run.fontSize,
|
|
420
|
-
srcIndex: srcStart,
|
|
421
|
-
srcEnd,
|
|
422
|
-
flat: 0
|
|
423
|
-
});
|
|
424
|
-
prevCp = cp;
|
|
425
|
-
prevMetrics = glyphMetrics;
|
|
426
|
-
prevFontSize = run.fontSize;
|
|
427
|
-
}
|
|
428
|
-
}
|
|
429
|
-
for (let i2 = 0; i2 < entries.length; i2++) entries[i2].flat = i2;
|
|
430
|
-
const analysis = opts.bidi ? opts.bidi.analyze(entries.map((e) => e.cp), opts.direction ?? "auto") : null;
|
|
431
|
-
if (!opts.bidi && entries.some((e) => RTL_BLOCKS.some(([lo, hi]) => e.cp >= lo && e.cp <= hi))) {
|
|
432
|
-
warnLogicalRtlOnce();
|
|
433
|
-
}
|
|
434
|
-
const lines = [];
|
|
435
|
-
let cur = { entries: [], width: 0, height: 0 };
|
|
436
|
-
function commitLine() {
|
|
437
|
-
lines.push(cur);
|
|
438
|
-
cur = { entries: [], width: 0, height: 0 };
|
|
439
|
-
}
|
|
440
|
-
let i = 0;
|
|
441
|
-
while (i < entries.length) {
|
|
442
|
-
const e = entries[i];
|
|
443
|
-
if (e.isNewline) {
|
|
444
|
-
if (cur.entries.length === 0) {
|
|
445
|
-
cur.height = Math.max(cur.height, lineSize(e) * opts.lineHeight);
|
|
446
|
-
cur.blank = e;
|
|
447
|
-
}
|
|
448
|
-
commitLine();
|
|
449
|
-
i++;
|
|
450
|
-
continue;
|
|
451
|
-
}
|
|
452
|
-
if (e.isSpace) {
|
|
453
|
-
if (cur.entries.length > 0) {
|
|
454
|
-
cur.entries.push(e);
|
|
455
|
-
cur.width += e.kerningBefore + e.advance + e.tracking;
|
|
456
|
-
} else {
|
|
457
|
-
cur.entries.push({ ...e, kerningBefore: 0, advance: 0, tracking: 0 });
|
|
458
|
-
}
|
|
459
|
-
cur.height = Math.max(cur.height, lineSize(e) * opts.lineHeight);
|
|
460
|
-
i++;
|
|
461
|
-
continue;
|
|
462
|
-
}
|
|
463
|
-
let j = i;
|
|
464
|
-
let wordWidth = 0;
|
|
465
|
-
while (j < entries.length && !entries[j].isSpace && !entries[j].isNewline) {
|
|
466
|
-
const w = entries[j];
|
|
467
|
-
wordWidth += w.kerningBefore + w.advance + w.tracking;
|
|
468
|
-
j++;
|
|
469
|
-
}
|
|
470
|
-
if (Number.isFinite(opts.maxWidth) && cur.width + wordWidth > opts.maxWidth && cur.entries.length > 0) {
|
|
471
|
-
commitLine();
|
|
472
|
-
}
|
|
473
|
-
for (let k = i; k < j; k++) {
|
|
474
|
-
const w = entries[k];
|
|
475
|
-
const kerningBefore = cur.entries.length === 0 ? 0 : w.kerningBefore;
|
|
476
|
-
cur.entries.push({ ...w, kerningBefore });
|
|
477
|
-
cur.width += kerningBefore + w.advance + w.tracking;
|
|
478
|
-
cur.height = Math.max(cur.height, lineSize(w) * opts.lineHeight);
|
|
479
|
-
}
|
|
480
|
-
i = j;
|
|
481
|
-
}
|
|
482
|
-
if (cur.entries.length > 0) commitLine();
|
|
483
|
-
function outlineFor(e) {
|
|
484
|
-
const r0 = e.resolved.resolved;
|
|
485
|
-
if (e.resolved.source === "outline") {
|
|
486
|
-
return glyphOutline(r0.family, r0.weight, r0.style, e.cp);
|
|
487
|
-
}
|
|
488
|
-
const min = opts.outlineMinSize;
|
|
489
|
-
if (min === void 0) return null;
|
|
490
|
-
if (e.fontSize < min && !strokePaints(e.run.stroke)) return null;
|
|
491
|
-
if (e.resolved.synthetic.bold) return null;
|
|
492
|
-
const r = e.resolved.resolved;
|
|
493
|
-
return glyphOutline(r.family, r.weight, r.style, e.cp);
|
|
494
|
-
}
|
|
495
|
-
const decorations = [];
|
|
496
|
-
let span = null;
|
|
497
|
-
function flushSpan() {
|
|
498
|
-
const s = span;
|
|
499
|
-
span = null;
|
|
500
|
-
if (!s || s.x1 <= s.x0) return;
|
|
501
|
-
for (const kind of DECORATION_KINDS) {
|
|
502
|
-
if (!s[kind]) continue;
|
|
503
|
-
const { y0, y1 } = decorationRule(kind, s.baselineY, s.fontSize);
|
|
504
|
-
decorations.push({ kind, x0: s.x0, y0, x1: s.x1, y1, fill: s.fill });
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
const lineBoxes = [];
|
|
508
|
-
let penY = 0;
|
|
509
|
-
let maxLineWidth = 0;
|
|
510
|
-
const alignWidth = opts.alignWidth ?? opts.maxWidth;
|
|
511
|
-
for (const line of lines) {
|
|
512
|
-
let hung = 0;
|
|
513
|
-
for (let k = line.entries.length - 1; k >= 0; k--) {
|
|
514
|
-
const e = line.entries[k];
|
|
515
|
-
if (!e.isSpace) break;
|
|
516
|
-
hung += e.kerningBefore + e.advance + e.tracking;
|
|
517
|
-
}
|
|
518
|
-
const inkWidth = line.width - hung;
|
|
519
|
-
const alignShift = (() => {
|
|
520
|
-
if (align === "left") return 0;
|
|
521
|
-
if (!Number.isFinite(alignWidth)) {
|
|
522
|
-
return align === "center" ? -inkWidth / 2 : -inkWidth;
|
|
523
|
-
}
|
|
524
|
-
const slack = alignWidth - inkWidth;
|
|
525
|
-
return align === "center" ? slack / 2 : slack;
|
|
526
|
-
})();
|
|
527
|
-
const lineX0 = alignShift;
|
|
528
|
-
let lineAscent = 0;
|
|
529
|
-
for (const e of line.entries) {
|
|
530
|
-
lineAscent = Math.max(lineAscent, e.metrics.base * (lineSize(e) / e.metrics.size));
|
|
531
|
-
}
|
|
532
|
-
if (line.entries.length === 0 && line.blank) {
|
|
533
|
-
lineAscent = line.blank.metrics.base * (lineSize(line.blank) / line.blank.metrics.size);
|
|
534
|
-
}
|
|
535
|
-
const lineBaselineY = penY + lineAscent;
|
|
536
|
-
const cells = new Array(line.entries.length);
|
|
537
|
-
const flatOf = line.entries.map((e) => e.flat);
|
|
538
|
-
const posOfFlat = /* @__PURE__ */ new Map();
|
|
539
|
-
flatOf.forEach((f, pos) => posOfFlat.set(f, pos));
|
|
540
|
-
let visual = line.entries.map((_, k) => k);
|
|
541
|
-
let levelOf = () => 0;
|
|
542
|
-
if (opts.bidi && analysis !== null && line.entries.length > 0) {
|
|
543
|
-
const from = flatOf[0];
|
|
544
|
-
const to = flatOf[flatOf.length - 1] + 1;
|
|
545
|
-
const r = opts.bidi.reorder(analysis, from, to);
|
|
546
|
-
const seen = /* @__PURE__ */ new Set();
|
|
547
|
-
const ordered = [];
|
|
548
|
-
for (const f of r.order) {
|
|
549
|
-
const pos = posOfFlat.get(f);
|
|
550
|
-
if (pos !== void 0 && !seen.has(pos)) {
|
|
551
|
-
ordered.push(pos);
|
|
552
|
-
seen.add(pos);
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
for (let k = 0; k < line.entries.length; k++) if (!seen.has(k)) ordered.push(k);
|
|
556
|
-
visual = ordered;
|
|
557
|
-
levelOf = (pos) => {
|
|
558
|
-
const l = r.levels[flatOf[pos] - from];
|
|
559
|
-
return typeof l === "number" && l >= 0 ? l : 0;
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
|
-
if (opts.bidi) {
|
|
563
|
-
for (let pos = 0; pos < line.entries.length; pos++) {
|
|
564
|
-
if (levelOf(pos) % 2 === 0) continue;
|
|
565
|
-
const e = line.entries[pos];
|
|
566
|
-
const m = opts.bidi.mirror(e.cp);
|
|
567
|
-
if (m === null || m === e.cp) continue;
|
|
568
|
-
if (e.font !== null) {
|
|
569
|
-
const hit = resolveGlyph(e.run, e.font, e.resolved, m);
|
|
570
|
-
if (!hit) continue;
|
|
571
|
-
e.glyph = hit.glyph;
|
|
572
|
-
}
|
|
573
|
-
e.cp = m;
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
let penX = lineX0;
|
|
577
|
-
let prevPos = -1;
|
|
578
|
-
for (const pos of visual) {
|
|
579
|
-
const e = line.entries[pos];
|
|
580
|
-
penX += prevPos < 0 ? 0 : pos === prevPos + 1 ? e.kerningBefore : prevPos === pos + 1 ? line.entries[prevPos].kerningBefore : 0;
|
|
581
|
-
prevPos = pos;
|
|
582
|
-
const cell = {
|
|
583
|
-
srcIndex: e.srcIndex,
|
|
584
|
-
srcEnd: e.srcEnd,
|
|
585
|
-
cp: e.cp,
|
|
586
|
-
x: penX,
|
|
587
|
-
advance: e.advance + e.tracking,
|
|
588
|
-
level: levelOf(pos),
|
|
589
|
-
drawsInk: e.drawsInk
|
|
590
|
-
};
|
|
591
|
-
cells[pos] = cell;
|
|
592
|
-
const step = e.advance + e.tracking;
|
|
593
|
-
const scale = e.fontSize / e.metrics.size;
|
|
594
|
-
const baselineY = lineBaselineY - (e.run.baselineShift ?? 0);
|
|
595
|
-
const decoFill = e.run.fill;
|
|
596
|
-
if (decoFill !== null && (e.run.underline || e.run.strikethrough || e.run.overline)) {
|
|
597
|
-
if (span !== null && span.underline === e.run.underline && span.strikethrough === e.run.strikethrough && span.overline === e.run.overline && span.fontSize === e.fontSize && span.baselineY === baselineY && sameFill(span.fill, e.run.fill)) {
|
|
598
|
-
span.x1 = penX + step;
|
|
599
|
-
} else {
|
|
600
|
-
flushSpan();
|
|
601
|
-
span = {
|
|
602
|
-
underline: e.run.underline,
|
|
603
|
-
strikethrough: e.run.strikethrough,
|
|
604
|
-
overline: e.run.overline,
|
|
605
|
-
fill: decoFill,
|
|
606
|
-
fontSize: e.fontSize,
|
|
607
|
-
baselineY,
|
|
608
|
-
x0: penX,
|
|
609
|
-
x1: penX + step
|
|
610
|
-
};
|
|
611
|
-
}
|
|
612
|
-
} else {
|
|
613
|
-
flushSpan();
|
|
614
|
-
}
|
|
615
|
-
const outlineD = outlineFor(e);
|
|
616
|
-
if (e.run.fill === null && !(outlineD !== null && strokePaints(e.run.stroke))) {
|
|
617
|
-
penX += step;
|
|
618
|
-
continue;
|
|
619
|
-
}
|
|
620
|
-
if (outlineD !== null) {
|
|
621
|
-
const group2 = getOrCreateGroup(ctx, e.run, e.resolved, 0, "outline");
|
|
622
|
-
group2.glyphs.push({
|
|
623
|
-
d: outlineD,
|
|
624
|
-
key: `${e.resolved.resolved.family}|${e.resolved.resolved.weight}|${e.resolved.resolved.style}|${e.cp}`,
|
|
625
|
-
x: penX,
|
|
626
|
-
baselineY,
|
|
627
|
-
// Em space is unit-scale, so world units per em is just the size.
|
|
628
|
-
scale: e.fontSize
|
|
629
|
-
});
|
|
630
|
-
penX += step;
|
|
631
|
-
continue;
|
|
632
|
-
}
|
|
633
|
-
if (e.font === null || e.glyph === null || e.advance === 0 || e.glyph.width === 0 || e.glyph.page < 0) {
|
|
634
|
-
penX += step;
|
|
635
|
-
continue;
|
|
636
|
-
}
|
|
637
|
-
const group = getOrCreateGroup(ctx, e.run, e.resolved, e.glyph.page);
|
|
638
|
-
const atlasW = e.font.common.scaleW;
|
|
639
|
-
const atlasH = e.font.common.scaleH;
|
|
640
|
-
const qx0 = penX + e.glyph.xoffset * scale;
|
|
641
|
-
const qy0 = baselineY + (e.glyph.yoffset - e.metrics.base) * scale;
|
|
642
|
-
const qx1 = qx0 + e.glyph.width * scale;
|
|
643
|
-
const qy1 = qy0 + e.glyph.height * scale;
|
|
644
|
-
const u0 = e.glyph.x / atlasW;
|
|
645
|
-
const v0 = e.glyph.y / atlasH;
|
|
646
|
-
const u1 = (e.glyph.x + e.glyph.width) / atlasW;
|
|
647
|
-
const v1 = (e.glyph.y + e.glyph.height) / atlasH;
|
|
648
|
-
group.quads.push({ x0: qx0, y0: qy0, x1: qx1, y1: qy1, u0, v0, u1, v1, baselineY });
|
|
649
|
-
penX += step;
|
|
650
|
-
}
|
|
651
|
-
flushSpan();
|
|
652
|
-
const lastCell = line.entries[line.entries.length - 1];
|
|
653
|
-
const srcEnd = lastCell ? lastCell.srcEnd : line.blank?.srcIndex ?? 0;
|
|
654
|
-
lineBoxes.push({
|
|
655
|
-
x0: lineX0,
|
|
656
|
-
y0: penY,
|
|
657
|
-
x1: lineX0 + line.width,
|
|
658
|
-
y1: penY + line.height,
|
|
659
|
-
baselineY: lineBaselineY,
|
|
660
|
-
cells,
|
|
661
|
-
srcEnd
|
|
662
|
-
});
|
|
663
|
-
maxLineWidth = Math.max(maxLineWidth, inkWidth);
|
|
664
|
-
penY += line.height;
|
|
665
|
-
}
|
|
666
|
-
return {
|
|
667
|
-
groups: [...ctx.groups.values()],
|
|
668
|
-
decorations,
|
|
669
|
-
lines: lineBoxes,
|
|
670
|
-
bounds: { width: maxLineWidth, height: penY }
|
|
671
|
-
};
|
|
672
|
-
}
|
|
673
|
-
var LAYOUT_CACHE_VARIANT_LIMIT = 8;
|
|
674
|
-
var LAYOUT_CACHE_STRUCTURAL_LIMIT = 64;
|
|
675
|
-
var cache = /* @__PURE__ */ new WeakMap();
|
|
676
|
-
var structural = /* @__PURE__ */ new Map();
|
|
677
|
-
var structuralGeneration = -1;
|
|
678
|
-
function outlineBucket(runs, min) {
|
|
679
|
-
if (min === void 0) return -1;
|
|
680
|
-
const sizes = /* @__PURE__ */ new Set();
|
|
681
|
-
for (const r of runs) sizes.add(r.fontSize);
|
|
682
|
-
let n = 0;
|
|
683
|
-
for (const size of sizes) if (size >= min) n++;
|
|
684
|
-
return n;
|
|
685
|
-
}
|
|
686
|
-
function variantKey(runs, opts) {
|
|
687
|
-
const alignWidth = opts.alignWidth ?? opts.maxWidth;
|
|
688
|
-
return `${opts.maxWidth}|${alignWidth}|${opts.lineHeight}|${opts.align}|${outlineBucket(runs, opts.outlineMinSize)}`;
|
|
689
|
-
}
|
|
690
|
-
var nextRefId = 1;
|
|
691
|
-
var refIds = /* @__PURE__ */ new WeakMap();
|
|
692
|
-
function refId(o) {
|
|
693
|
-
let id = refIds.get(o);
|
|
694
|
-
if (id === void 0) {
|
|
695
|
-
id = nextRefId++;
|
|
696
|
-
refIds.set(o, id);
|
|
697
|
-
}
|
|
698
|
-
return id;
|
|
699
|
-
}
|
|
700
|
-
function paintKey(p) {
|
|
701
|
-
if (p === null) return "none";
|
|
702
|
-
return "color" in p ? `s${p.color}:${p.opacity ?? 1}` : `#${refId(p)}`;
|
|
703
|
-
}
|
|
704
|
-
function strokeKey2(s) {
|
|
705
|
-
if (!s?.paint) return "-";
|
|
706
|
-
const width = s.width ?? 1;
|
|
707
|
-
return [
|
|
708
|
-
paintKey(s.paint),
|
|
709
|
-
typeof width === "number" ? width : `px${width.px}`,
|
|
710
|
-
s.join ?? "miter",
|
|
711
|
-
s.cap ?? "butt",
|
|
712
|
-
s.miterLimit ?? "",
|
|
713
|
-
s.align ?? "center",
|
|
714
|
-
(s.dash ?? []).join(",")
|
|
715
|
-
].join(":");
|
|
716
|
-
}
|
|
717
|
-
function runsKey(runs) {
|
|
718
|
-
let out = "";
|
|
719
|
-
for (const r of runs) {
|
|
720
|
-
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(",")}` : ""}|`;
|
|
721
|
-
}
|
|
722
|
-
return out;
|
|
723
|
-
}
|
|
724
|
-
function cachedLayoutRuns(runs, opts) {
|
|
725
|
-
const fonts = glyphGeneration();
|
|
726
|
-
let entry = cache.get(runs);
|
|
727
|
-
if (entry === void 0) {
|
|
728
|
-
entry = { generation: fonts, byVariant: /* @__PURE__ */ new Map() };
|
|
729
|
-
cache.set(runs, entry);
|
|
730
|
-
} else if (entry.generation !== fonts) {
|
|
731
|
-
entry.generation = fonts;
|
|
732
|
-
entry.byVariant.clear();
|
|
733
|
-
}
|
|
734
|
-
const key = variantKey(runs, opts);
|
|
735
|
-
const hit = entry.byVariant.get(key);
|
|
736
|
-
if (hit !== void 0) return hit;
|
|
737
|
-
if (structuralGeneration !== fonts) {
|
|
738
|
-
structural.clear();
|
|
739
|
-
structuralGeneration = fonts;
|
|
740
|
-
}
|
|
741
|
-
const structuralK = `${runsKey(runs)}\0${key}`;
|
|
742
|
-
let laid = structural.get(structuralK);
|
|
743
|
-
if (laid !== void 0) {
|
|
744
|
-
structural.delete(structuralK);
|
|
745
|
-
} else {
|
|
746
|
-
laid = layoutRuns(runs, opts);
|
|
747
|
-
if (structural.size >= LAYOUT_CACHE_STRUCTURAL_LIMIT) {
|
|
748
|
-
structural.delete(structural.keys().next().value);
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
structural.set(structuralK, laid);
|
|
752
|
-
if (entry.byVariant.size >= LAYOUT_CACHE_VARIANT_LIMIT) entry.byVariant.clear();
|
|
753
|
-
entry.byVariant.set(key, laid);
|
|
754
|
-
return laid;
|
|
755
|
-
}
|
|
756
|
-
function _resetLayoutCacheForTests() {
|
|
757
|
-
cache = /* @__PURE__ */ new WeakMap();
|
|
758
|
-
structural = /* @__PURE__ */ new Map();
|
|
759
|
-
structuralGeneration = -1;
|
|
760
|
-
}
|
|
761
|
-
|
|
762
|
-
export { DECORATION_KINDS, DEFAULT_TEXT_STYLE, LAYOUT_CACHE_STRUCTURAL_LIMIT, LAYOUT_CACHE_VARIANT_LIMIT, _resetLayoutCacheForTests, cachedLayoutRuns, decorationRule, fontString, layoutRuns, resolveAlign, resolveTextStyle };
|
|
763
|
-
//# sourceMappingURL=chunk-SXEHVOGE.js.map
|
|
764
|
-
//# sourceMappingURL=chunk-SXEHVOGE.js.map
|