@weasel-js/text 1.15.0 → 1.15.1

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,5 +1,5 @@
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
4
 
5
5
  var __defProp = Object.defineProperty;
@@ -134,16 +134,20 @@ function registerShaper(shaper) {
134
134
  function registeredShaper() {
135
135
  return registered;
136
136
  }
137
- var bytesOf = /* @__PURE__ */ new WeakMap();
138
- function shapeableBytes(resolved2) {
139
- const face = resolved2.outlineFace;
137
+ var embeddingOf = /* @__PURE__ */ new WeakMap();
138
+ function shapingFace(resolved2) {
139
+ const { family, weight, style } = resolved2.resolved;
140
+ const face = resolved2.outlineFace ?? (resolved2.source === "outline" ? void 0 : outlineMetrics(family, weight, style === "italic" ? "italic" : "normal"));
140
141
  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);
142
+ let embedding = embeddingOf.get(face);
143
+ if (embedding === void 0) {
144
+ embedding = face.embedding?.() ?? null;
145
+ embeddingOf.set(face, embedding);
145
146
  }
146
- return bytes;
147
+ return embedding;
148
+ }
149
+ function shapeableBytes(resolved2) {
150
+ return shapingFace(resolved2)?.sfnt ?? null;
147
151
  }
148
152
  function shapesWithFeature(family, weight, style, tag, shaper = registered) {
149
153
  if (shaper === null) return false;
@@ -1122,19 +1126,23 @@ function graphemeCount(text) {
1122
1126
  var NOTHING_DRAWN = Object.freeze({ d: null, key: "", glyphs: Object.freeze([]), rtl: false, text: "" });
1123
1127
  var COVERED = Object.freeze({ cluster: NOTHING_DRAWN, advance: 0 });
1124
1128
  var slotsOf = /* @__PURE__ */ new WeakMap();
1129
+ var atlasSlotsOf = /* @__PURE__ */ new WeakMap();
1125
1130
  var fmt = (v) => String(Math.round(v * 1e5) / 1e5);
1126
1131
  function shapeRun(run, resolved2, shaper) {
1127
1132
  if (shaper === null) return null;
1128
- const face = shapeableBytes(resolved2);
1129
- if (face === null) return null;
1133
+ const embedding = shapingFace(resolved2);
1134
+ if (embedding === null) return null;
1135
+ const face = embedding.sfnt;
1130
1136
  const glyphs = shaper.shape(face, run.text, run.fontFeatures, run.lang);
1131
- let slots2 = slotsOf.get(glyphs);
1137
+ const cache2 = resolved2.source === "outline" ? slotsOf : atlasSlotsOf;
1138
+ let slots2 = cache2.get(glyphs);
1132
1139
  if (slots2) return slots2;
1133
- slots2 = slotsFor(shaper, face, run.text, glyphs);
1134
- slotsOf.set(glyphs, slots2);
1140
+ const plain2 = resolved2.source === "outline" ? null : (cp2) => embedding.glyphIndexOf(cp2);
1141
+ slots2 = slotsFor(shaper, face, run.text, glyphs, plain2);
1142
+ cache2.set(glyphs, slots2);
1135
1143
  return slots2;
1136
1144
  }
1137
- function slotsFor(shaper, face, text, glyphs) {
1145
+ function slotsFor(shaper, face, text, glyphs, plain2) {
1138
1146
  const slots2 = new Array(text.length);
1139
1147
  const ends = graphemeEnds(text);
1140
1148
  let g = 0;
@@ -1147,7 +1155,7 @@ function slotsFor(shaper, face, text, glyphs) {
1147
1155
  while (g < ends.length && ends[g] <= start2) g++;
1148
1156
  let inner = 0;
1149
1157
  for (let k = g; k < ends.length && ends[k] < end; k++) inner++;
1150
- if (!holdsNotdef(glyphs, i, j)) {
1158
+ if (!holdsNotdef(glyphs, i, j) && !(plain2 && isPlain(glyphs[i], j - i, text, start2, end, plain2))) {
1151
1159
  const total = advanceOf(glyphs, i, j);
1152
1160
  const share = total / (inner + 1);
1153
1161
  const shift = glyphs[i].rtl ? share - total : 0;
@@ -1163,6 +1171,11 @@ function slotsFor(shaper, face, text, glyphs) {
1163
1171
  }
1164
1172
  return slots2;
1165
1173
  }
1174
+ function isPlain(first, count, text, start2, end, plain2) {
1175
+ if (count !== 1 || first.dx !== 0 || first.dy !== 0) return false;
1176
+ const cp2 = text.codePointAt(start2);
1177
+ return end - start2 === (cp2 > 65535 ? 2 : 1) && plain2(cp2) === first.gid;
1178
+ }
1166
1179
  function advanceOf(glyphs, from, to) {
1167
1180
  let sum2 = 0;
1168
1181
  for (let k = from; k < to; k++) sum2 += glyphs[k].advance;
@@ -1180,7 +1193,7 @@ function clusterSlot(shaper, face, glyphs, from, to, text, shift, advance) {
1180
1193
  for (let k = from; k < to; k++) {
1181
1194
  const g = glyphs[k];
1182
1195
  const x = pen + g.dx, y = g.dy;
1183
- placed2.push({ gid: g.gid, x, y });
1196
+ placed2.push({ gid: g.gid, x, y, advance: g.advance });
1184
1197
  d += shaper.glyphD(face, g.gid, x, y) ?? "";
1185
1198
  key += `${k === from ? "" : ";"}${g.gid}${x === 0 && y === 0 ? "" : `@${fmt(x)},${fmt(y)}`}`;
1186
1199
  pen += g.advance;
@@ -1359,7 +1372,7 @@ function mirrorEntries(entries2, levels, mirror, runs) {
1359
1372
  const odd = levels[pos] % 2 === 1;
1360
1373
  if (entry.shaped !== null && entry.shaped.rtl !== odd) {
1361
1374
  const flipped = mirror(entry.cp);
1362
- if (flipped !== null && flipped !== entry.cp) entry = { ...entry, shaped: null };
1375
+ if (flipped !== null && flipped !== entry.cp) entry = unshaped(entry, runs[entry.run]);
1363
1376
  }
1364
1377
  if (!odd) return entry;
1365
1378
  if (entry.shaped !== null) return entry;
@@ -1372,6 +1385,11 @@ function mirrorEntries(entries2, levels, mirror, runs) {
1372
1385
  return { ...entry, cp: cp2, resolved: hit.resolved, metrics: hit.metrics, font: hit.font, glyph: hit.glyph };
1373
1386
  });
1374
1387
  }
1388
+ function unshaped(entry, run) {
1389
+ if (entry.resolved.source === "outline") return { ...entry, shaped: null };
1390
+ const hit = resolveGlyph(entry.resolved, run.fontFamily, run.fontWeight, run.fontStyle, entry.cp, false);
1391
+ return hit ? { ...entry, shaped: null, resolved: hit.resolved, metrics: hit.metrics, font: hit.font, glyph: hit.glyph } : { ...entry, shaped: null };
1392
+ }
1375
1393
 
1376
1394
  // src/layout/lineBreak/wrapLines.ts
1377
1395
  var hangs = (cp2) => cp2 === 32 || cp2 === 9;
@@ -1876,9 +1894,9 @@ function takeGroups(out) {
1876
1894
  }
1877
1895
 
1878
1896
  // src/layout/paintRuns.ts
1879
- function glyphOutlineD(g, run, minSize) {
1897
+ function glyphOutlineD(g, run, minSize, ungated = false) {
1880
1898
  const outlineOnly = g.resolved.source === "outline";
1881
- if (!outlineOnly) {
1899
+ if (!outlineOnly && !ungated) {
1882
1900
  if (minSize === void 0) return null;
1883
1901
  if (run.fontSize < minSize && !strokeHasInk(run.stroke)) return null;
1884
1902
  }
@@ -1897,6 +1915,14 @@ function faceOutlineD(g) {
1897
1915
  if (g.resolved.source !== "outline" && g.glyph === null) return null;
1898
1916
  return glyphOutline(family, weight, style, g.cp);
1899
1917
  }
1918
+ function shapedQuadGlyph(g) {
1919
+ const face = g.resolved.dynamicFace;
1920
+ const shaped = g.shaped;
1921
+ if (!face || shaped.d === null) return null;
1922
+ const glyph = face.requestShaped(shaped.key, shaped.d);
1923
+ if (!glyph || glyph.page < 0 || glyph.width === 0) return null;
1924
+ return { ...g, font: face.font, glyph };
1925
+ }
1900
1926
  function runFaces(runs) {
1901
1927
  const faces = runs.map((r) => faceMetricsOf(cachedFontVariant(r.fontFamily, r.fontWeight, r.fontStyle)));
1902
1928
  return (run) => faces[run];
@@ -1937,7 +1963,13 @@ function paintRunsInto(laid, runs, opts, out) {
1937
1963
  rules?.add(g);
1938
1964
  const run = runs[g.run];
1939
1965
  const inks = cols !== null ? cols.drawsInk(start2, pos) : line.cells[g.cell].drawsInk;
1940
- const outline = inks ? glyphOutlineD(g, run, opts.outlineMinSize) : null;
1966
+ let outline = inks ? glyphOutlineD(g, run, opts.outlineMinSize) : null;
1967
+ let q = g;
1968
+ if (inks && outline === null && g.shaped) {
1969
+ const baked = shapedQuadGlyph(g);
1970
+ if (baked) q = baked;
1971
+ else outline = glyphOutlineD(g, run, opts.outlineMinSize, true);
1972
+ }
1941
1973
  if (!fillHasInk(run.fill) && !(outline !== null && strokeHasInk(run.stroke))) continue;
1942
1974
  if (outline !== null) {
1943
1975
  const placed2 = { ...outline, x: g.x, baselineY: g.baselineY, scale: g.fontSize };
@@ -1945,8 +1977,8 @@ function paintRunsInto(laid, runs, opts, out) {
1945
1977
  groupFor(runs, g, "outline").glyphs.push(placed2);
1946
1978
  continue;
1947
1979
  }
1948
- if (!hasGlyphQuad(g)) continue;
1949
- const group = groupFor(runs, g, g.glyph.color ? "color" : g.resolved.source);
1980
+ if (!hasGlyphQuad(q)) continue;
1981
+ const group = groupFor(runs, q, q.glyph.color ? "color" : q.resolved.source);
1950
1982
  if (sized === null) {
1951
1983
  sized = group;
1952
1984
  group.quadData = buf;
@@ -1954,12 +1986,12 @@ function paintRunsInto(laid, runs, opts, out) {
1954
1986
  let quads = group.quadData;
1955
1987
  if (quads === NO_QUADS) group.quadData = quads = [];
1956
1988
  if (group === sized) {
1957
- writeGlyphQuad(g, quads, sizedAt);
1989
+ writeGlyphQuad(q, quads, sizedAt);
1958
1990
  sizedAt += QUAD_STRIDE;
1959
1991
  } else {
1960
- writeGlyphQuad(g, quads, quads.length);
1992
+ writeGlyphQuad(q, quads, quads.length);
1961
1993
  }
1962
- group.colorGlyphs?.push(g.glyph);
1994
+ group.colorGlyphs?.push(q.glyph);
1963
1995
  }
1964
1996
  if (!rules) continue;
1965
1997
  for (const rule of rules.end()) {
@@ -2388,5 +2420,5 @@ function _resetLayoutCacheForTests() {
2388
2420
  }
2389
2421
 
2390
2422
  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
2423
+ //# sourceMappingURL=chunk-WUFANHTE.js.map
2424
+ //# sourceMappingURL=chunk-WUFANHTE.js.map