@weasel-js/text 1.15.0 → 1.15.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.
@@ -1,6 +1,7 @@
1
1
  import { isSolidPaint, resolveFill, resolveScreenLength, fillHasInk, strokeHasInk, paintKey, strokeKey } from '@weasel-js/paint';
2
- import { cssFamilyName, cachedFontVariant, syntheticBoldGrowth, glyphOutline, faceMetricsOf, glyphGeneration, faceGeneration, metricsOf, warnNoMetrics, resolveColorCluster, glyphIn, resolveGlyph } from '@weasel-js/font';
2
+ import { cssFamilyName, cachedFontVariant, syntheticBoldGrowth, glyphOutline, faceMetricsOf, glyphGeneration, faceGeneration, metricsOf, warnNoMetrics, resolveColorCluster, glyphIn, resolveGlyph, outlineMetrics } from '@weasel-js/font';
3
3
  import { mergeRegion, growRegion, pathToD, pathFromD } from '@weasel-js/geom';
4
+ import { sameList } from '@weasel-js/registry';
4
5
 
5
6
  var __defProp = Object.defineProperty;
6
7
  var __export = (target, all) => {
@@ -134,16 +135,20 @@ function registerShaper(shaper) {
134
135
  function registeredShaper() {
135
136
  return registered;
136
137
  }
137
- var bytesOf = /* @__PURE__ */ new WeakMap();
138
- function shapeableBytes(resolved2) {
139
- const face = resolved2.outlineFace;
138
+ var embeddingOf = /* @__PURE__ */ new WeakMap();
139
+ function shapingFace(resolved2) {
140
+ const { family, weight, style } = resolved2.resolved;
141
+ const face = resolved2.outlineFace ?? (resolved2.source === "outline" ? void 0 : outlineMetrics(family, weight, style === "italic" ? "italic" : "normal"));
140
142
  if (!face) return null;
141
- let bytes = bytesOf.get(face);
142
- if (bytes === void 0) {
143
- bytes = face.embedding?.().sfnt ?? null;
144
- bytesOf.set(face, bytes);
143
+ let embedding = embeddingOf.get(face);
144
+ if (embedding === void 0) {
145
+ embedding = face.embedding?.() ?? null;
146
+ embeddingOf.set(face, embedding);
145
147
  }
146
- return bytes;
148
+ return embedding;
149
+ }
150
+ function shapeableBytes(resolved2) {
151
+ return shapingFace(resolved2)?.sfnt ?? null;
147
152
  }
148
153
  function shapesWithFeature(family, weight, style, tag, shaper = registered) {
149
154
  if (shaper === null) return false;
@@ -1122,19 +1127,23 @@ function graphemeCount(text) {
1122
1127
  var NOTHING_DRAWN = Object.freeze({ d: null, key: "", glyphs: Object.freeze([]), rtl: false, text: "" });
1123
1128
  var COVERED = Object.freeze({ cluster: NOTHING_DRAWN, advance: 0 });
1124
1129
  var slotsOf = /* @__PURE__ */ new WeakMap();
1130
+ var atlasSlotsOf = /* @__PURE__ */ new WeakMap();
1125
1131
  var fmt = (v) => String(Math.round(v * 1e5) / 1e5);
1126
1132
  function shapeRun(run, resolved2, shaper) {
1127
1133
  if (shaper === null) return null;
1128
- const face = shapeableBytes(resolved2);
1129
- if (face === null) return null;
1134
+ const embedding = shapingFace(resolved2);
1135
+ if (embedding === null) return null;
1136
+ const face = embedding.sfnt;
1130
1137
  const glyphs = shaper.shape(face, run.text, run.fontFeatures, run.lang);
1131
- let slots2 = slotsOf.get(glyphs);
1138
+ const cache2 = resolved2.source === "outline" ? slotsOf : atlasSlotsOf;
1139
+ let slots2 = cache2.get(glyphs);
1132
1140
  if (slots2) return slots2;
1133
- slots2 = slotsFor(shaper, face, run.text, glyphs);
1134
- slotsOf.set(glyphs, slots2);
1141
+ const plain2 = resolved2.source === "outline" ? null : (cp2) => embedding.glyphIndexOf(cp2);
1142
+ slots2 = slotsFor(shaper, face, run.text, glyphs, plain2);
1143
+ cache2.set(glyphs, slots2);
1135
1144
  return slots2;
1136
1145
  }
1137
- function slotsFor(shaper, face, text, glyphs) {
1146
+ function slotsFor(shaper, face, text, glyphs, plain2) {
1138
1147
  const slots2 = new Array(text.length);
1139
1148
  const ends = graphemeEnds(text);
1140
1149
  let g = 0;
@@ -1147,7 +1156,7 @@ function slotsFor(shaper, face, text, glyphs) {
1147
1156
  while (g < ends.length && ends[g] <= start2) g++;
1148
1157
  let inner = 0;
1149
1158
  for (let k = g; k < ends.length && ends[k] < end; k++) inner++;
1150
- if (!holdsNotdef(glyphs, i, j)) {
1159
+ if (!holdsNotdef(glyphs, i, j) && !(plain2 && isPlain(glyphs[i], j - i, text, start2, end, plain2))) {
1151
1160
  const total = advanceOf(glyphs, i, j);
1152
1161
  const share = total / (inner + 1);
1153
1162
  const shift = glyphs[i].rtl ? share - total : 0;
@@ -1163,6 +1172,11 @@ function slotsFor(shaper, face, text, glyphs) {
1163
1172
  }
1164
1173
  return slots2;
1165
1174
  }
1175
+ function isPlain(first, count, text, start2, end, plain2) {
1176
+ if (count !== 1 || first.dx !== 0 || first.dy !== 0) return false;
1177
+ const cp2 = text.codePointAt(start2);
1178
+ return end - start2 === (cp2 > 65535 ? 2 : 1) && plain2(cp2) === first.gid;
1179
+ }
1166
1180
  function advanceOf(glyphs, from, to) {
1167
1181
  let sum2 = 0;
1168
1182
  for (let k = from; k < to; k++) sum2 += glyphs[k].advance;
@@ -1180,7 +1194,7 @@ function clusterSlot(shaper, face, glyphs, from, to, text, shift, advance) {
1180
1194
  for (let k = from; k < to; k++) {
1181
1195
  const g = glyphs[k];
1182
1196
  const x = pen + g.dx, y = g.dy;
1183
- placed2.push({ gid: g.gid, x, y });
1197
+ placed2.push({ gid: g.gid, x, y, advance: g.advance });
1184
1198
  d += shaper.glyphD(face, g.gid, x, y) ?? "";
1185
1199
  key += `${k === from ? "" : ";"}${g.gid}${x === 0 && y === 0 ? "" : `@${fmt(x)},${fmt(y)}`}`;
1186
1200
  pen += g.advance;
@@ -1359,7 +1373,7 @@ function mirrorEntries(entries2, levels, mirror, runs) {
1359
1373
  const odd = levels[pos] % 2 === 1;
1360
1374
  if (entry.shaped !== null && entry.shaped.rtl !== odd) {
1361
1375
  const flipped = mirror(entry.cp);
1362
- if (flipped !== null && flipped !== entry.cp) entry = { ...entry, shaped: null };
1376
+ if (flipped !== null && flipped !== entry.cp) entry = unshaped(entry, runs[entry.run]);
1363
1377
  }
1364
1378
  if (!odd) return entry;
1365
1379
  if (entry.shaped !== null) return entry;
@@ -1372,6 +1386,11 @@ function mirrorEntries(entries2, levels, mirror, runs) {
1372
1386
  return { ...entry, cp: cp2, resolved: hit.resolved, metrics: hit.metrics, font: hit.font, glyph: hit.glyph };
1373
1387
  });
1374
1388
  }
1389
+ function unshaped(entry, run) {
1390
+ if (entry.resolved.source === "outline") return { ...entry, shaped: null };
1391
+ const hit = resolveGlyph(entry.resolved, run.fontFamily, run.fontWeight, run.fontStyle, entry.cp, false);
1392
+ return hit ? { ...entry, shaped: null, resolved: hit.resolved, metrics: hit.metrics, font: hit.font, glyph: hit.glyph } : { ...entry, shaped: null };
1393
+ }
1375
1394
 
1376
1395
  // src/layout/lineBreak/wrapLines.ts
1377
1396
  var hangs = (cp2) => cp2 === 32 || cp2 === 9;
@@ -1876,9 +1895,9 @@ function takeGroups(out) {
1876
1895
  }
1877
1896
 
1878
1897
  // src/layout/paintRuns.ts
1879
- function glyphOutlineD(g, run, minSize) {
1898
+ function glyphOutlineD(g, run, minSize, ungated = false) {
1880
1899
  const outlineOnly = g.resolved.source === "outline";
1881
- if (!outlineOnly) {
1900
+ if (!outlineOnly && !ungated) {
1882
1901
  if (minSize === void 0) return null;
1883
1902
  if (run.fontSize < minSize && !strokeHasInk(run.stroke)) return null;
1884
1903
  }
@@ -1897,6 +1916,14 @@ function faceOutlineD(g) {
1897
1916
  if (g.resolved.source !== "outline" && g.glyph === null) return null;
1898
1917
  return glyphOutline(family, weight, style, g.cp);
1899
1918
  }
1919
+ function shapedQuadGlyph(g) {
1920
+ const face = g.resolved.dynamicFace;
1921
+ const shaped = g.shaped;
1922
+ if (!face || shaped.d === null) return null;
1923
+ const glyph = face.requestShaped(shaped.key, shaped.d);
1924
+ if (!glyph || glyph.page < 0 || glyph.width === 0) return null;
1925
+ return { ...g, font: face.font, glyph };
1926
+ }
1900
1927
  function runFaces(runs) {
1901
1928
  const faces = runs.map((r) => faceMetricsOf(cachedFontVariant(r.fontFamily, r.fontWeight, r.fontStyle)));
1902
1929
  return (run) => faces[run];
@@ -1937,7 +1964,13 @@ function paintRunsInto(laid, runs, opts, out) {
1937
1964
  rules?.add(g);
1938
1965
  const run = runs[g.run];
1939
1966
  const inks = cols !== null ? cols.drawsInk(start2, pos) : line.cells[g.cell].drawsInk;
1940
- const outline = inks ? glyphOutlineD(g, run, opts.outlineMinSize) : null;
1967
+ let outline = inks ? glyphOutlineD(g, run, opts.outlineMinSize) : null;
1968
+ let q = g;
1969
+ if (inks && outline === null && g.shaped) {
1970
+ const baked = shapedQuadGlyph(g);
1971
+ if (baked) q = baked;
1972
+ else outline = glyphOutlineD(g, run, opts.outlineMinSize, true);
1973
+ }
1941
1974
  if (!fillHasInk(run.fill) && !(outline !== null && strokeHasInk(run.stroke))) continue;
1942
1975
  if (outline !== null) {
1943
1976
  const placed2 = { ...outline, x: g.x, baselineY: g.baselineY, scale: g.fontSize };
@@ -1945,8 +1978,8 @@ function paintRunsInto(laid, runs, opts, out) {
1945
1978
  groupFor(runs, g, "outline").glyphs.push(placed2);
1946
1979
  continue;
1947
1980
  }
1948
- if (!hasGlyphQuad(g)) continue;
1949
- const group = groupFor(runs, g, g.glyph.color ? "color" : g.resolved.source);
1981
+ if (!hasGlyphQuad(q)) continue;
1982
+ const group = groupFor(runs, q, q.glyph.color ? "color" : q.resolved.source);
1950
1983
  if (sized === null) {
1951
1984
  sized = group;
1952
1985
  group.quadData = buf;
@@ -1954,12 +1987,12 @@ function paintRunsInto(laid, runs, opts, out) {
1954
1987
  let quads = group.quadData;
1955
1988
  if (quads === NO_QUADS) group.quadData = quads = [];
1956
1989
  if (group === sized) {
1957
- writeGlyphQuad(g, quads, sizedAt);
1990
+ writeGlyphQuad(q, quads, sizedAt);
1958
1991
  sizedAt += QUAD_STRIDE;
1959
1992
  } else {
1960
- writeGlyphQuad(g, quads, quads.length);
1993
+ writeGlyphQuad(q, quads, quads.length);
1961
1994
  }
1962
- group.colorGlyphs?.push(g.glyph);
1995
+ group.colorGlyphs?.push(q.glyph);
1963
1996
  }
1964
1997
  if (!rules) continue;
1965
1998
  for (const rule of rules.end()) {
@@ -2254,18 +2287,11 @@ function runsHash(runs) {
2254
2287
  }
2255
2288
  return h & 1073741823;
2256
2289
  }
2290
+ var NO_STRS = [];
2257
2291
  function sameNums(a, b) {
2258
- if (a === b) return true;
2259
- if (a === void 0 || b === void 0 || a.length !== b.length) return false;
2260
- for (let i = 0; i < a.length; i++) if (!same(a[i], b[i])) return false;
2261
- return true;
2262
- }
2263
- function sameStrs(a, b) {
2264
- if (a === b) return true;
2265
- if ((a?.length ?? 0) !== (b?.length ?? 0)) return false;
2266
- for (let i = 0; i < (a?.length ?? 0); i++) if (a[i] !== b[i]) return false;
2267
- return true;
2292
+ return a === b || a !== void 0 && b !== void 0 && sameList(a, b, same);
2268
2293
  }
2294
+ var sameStrs = (a, b) => sameList(a ?? NO_STRS, b ?? NO_STRS);
2269
2295
  function sameRuns(a, b) {
2270
2296
  if (a.length !== b.length) return false;
2271
2297
  for (let i = 0; i < a.length; i++) {
@@ -2388,5 +2414,5 @@ function _resetLayoutCacheForTests() {
2388
2414
  }
2389
2415
 
2390
2416
  export { BREAK_ALLOWED, BREAK_MANDATORY, DECORATION_KINDS, DEFAULT_DECORATION_METRICS, DEFAULT_TAB_SIZE, DEFAULT_TEXT_FILL, DEFAULT_TEXT_STYLE, LAYOUT_CACHE_STRUCTURAL_LIMIT, LAYOUT_CACHE_VARIANT_LIMIT, NO_BREAK, QUAD_STRIDE, _resetBidiWarningForTests, _resetLayoutCacheForTests, cachedLayoutRuns, cachedPaintRuns, clearRuns, decorationMetrics, decorationRule, dropRuns, emboldenGlyph, emboldenGlyphD, faceOutlineD, fontString, graphemeCount, hangs, hasGlyphQuad, isHardLineBreak, layoutRuns, lineBreakOpportunities, lineDecorations, paintRuns, paragraphDirection, registerBidi, registerShaper, registeredBidi, resolveAlign, resolveTextStyle, resolveTextStyleInto, runFaces, shapesWithFeature, syntheticBoldOffset, tabAdvance, warnRtlWithoutEngine, widthWithTabs, wrapLines };
2391
- //# sourceMappingURL=chunk-ZNSU5C43.js.map
2392
- //# sourceMappingURL=chunk-ZNSU5C43.js.map
2417
+ //# sourceMappingURL=chunk-VBLWNCSV.js.map
2418
+ //# sourceMappingURL=chunk-VBLWNCSV.js.map