@weasel-js/font 1.14.2 → 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.
@@ -447,6 +447,18 @@ function _resetBakeQueueForTests() {
447
447
  // src/dynamic/glyphRasterizer.ts
448
448
  var BAKE_SIZE = 48;
449
449
  var PAD = 8;
450
+ function pathBounds(d) {
451
+ const b = [Infinity, Infinity, -Infinity, -Infinity];
452
+ const nums = d.match(/-?\d*\.?\d+(?:e-?\d+)?/gi) ?? [];
453
+ for (let k = 0; k + 1 < nums.length; k += 2) {
454
+ const x = Number(nums[k]), y = Number(nums[k + 1]);
455
+ if (x < b[0]) b[0] = x;
456
+ if (y < b[1]) b[1] = y;
457
+ if (x > b[2]) b[2] = x;
458
+ if (y > b[3]) b[3] = y;
459
+ }
460
+ return b;
461
+ }
450
462
  var COLORED_BELOW = 240;
451
463
  function premultipliedColor(data) {
452
464
  const out = new Uint8ClampedArray(data.length);
@@ -533,6 +545,28 @@ function createCanvasRasterizer() {
533
545
  for (let i = 0; i < alpha.length; i++) alpha[i] = data[i * 4 + 3];
534
546
  return { ...box, alpha };
535
547
  },
548
+ rasterizePath(d) {
549
+ const [minX, minY, maxX, maxY] = pathBounds(d);
550
+ const blank = { width: 0, height: 0, alpha: new Uint8ClampedArray(0), left: 0, top: 0, advance: 0 };
551
+ if (!(maxX > minX && maxY > minY)) return blank;
552
+ const x0 = Math.floor(minX * BAKE_SIZE), y0 = Math.floor(minY * BAKE_SIZE);
553
+ const w = Math.ceil(maxX * BAKE_SIZE) - x0 + 2 * PAD;
554
+ const h = Math.ceil(maxY * BAKE_SIZE) - y0 + 2 * PAD;
555
+ if (canvas.width < w || canvas.height < h) {
556
+ canvas.width = Math.max(canvas.width, w);
557
+ canvas.height = Math.max(canvas.height, h);
558
+ }
559
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
560
+ ctx.clearRect(0, 0, w, h);
561
+ ctx.setTransform(BAKE_SIZE, 0, 0, BAKE_SIZE, PAD - x0, PAD - y0);
562
+ ctx.fillStyle = "#fff";
563
+ ctx.fill(new Path2D(d));
564
+ ctx.setTransform(1, 0, 0, 1, 0, 0);
565
+ const data = ctx.getImageData(0, 0, w, h).data;
566
+ const alpha = new Uint8ClampedArray(w * h);
567
+ for (let i = 0; i < alpha.length; i++) alpha[i] = data[i * 4 + 3];
568
+ return { width: w, height: h, alpha, left: x0 - PAD, top: PAD - y0, advance: 0 };
569
+ },
536
570
  rasterizeColor(family, weight, style, text, size) {
537
571
  const { data, ...box } = draw(family, weight, style, text, size);
538
572
  const rgba = premultipliedColor(data);
@@ -627,6 +661,7 @@ function forgetGlyphs2(face) {
627
661
  face.font.charMap.clear();
628
662
  face.font.chars.length = 0;
629
663
  face.clusters.clear();
664
+ face.shaped.clear();
630
665
  }
631
666
  onPagesEmptied(() => {
632
667
  for (const face of faces2.values()) forgetGlyphs2(face);
@@ -696,12 +731,14 @@ function getDynamicFace(family, weight, style) {
696
731
  page: -1
697
732
  });
698
733
  const clusters = /* @__PURE__ */ new Map();
734
+ const shaped = /* @__PURE__ */ new Map();
699
735
  const face = {
700
736
  family,
701
737
  weight,
702
738
  style,
703
739
  font,
704
740
  clusters,
741
+ shaped,
705
742
  requestGlyph(cp) {
706
743
  const cached = font.charMap.get(cp);
707
744
  if (cached) return cached;
@@ -723,6 +760,15 @@ function getDynamicFace(family, weight, style) {
723
760
  addSharpSource(char, font.common.base, (size) => r.rasterizeColor?.(family, weight, style, text, size) ?? null);
724
761
  }
725
762
  return char;
763
+ },
764
+ requestShaped(key2, d) {
765
+ const cached = shaped.get(key2);
766
+ if (cached !== void 0) return cached;
767
+ const raster = typeof Path2D === "undefined" ? null : r.rasterizePath?.(d) ?? null;
768
+ const char = raster && record(0, raster);
769
+ shaped.set(key2, char);
770
+ if (char && raster) requestBake(char, raster);
771
+ return char;
726
772
  }
727
773
  };
728
774
  measureFace(face);
@@ -748,6 +794,7 @@ function refreshFamilies(families) {
748
794
  for (const face of faces2.values()) {
749
795
  if (keys && !face.family.split(",").some((name) => keys.has(familyKey(name)))) continue;
750
796
  for (const char of face.font.chars) dropped.add(char);
797
+ for (const char of face.shaped.values()) if (char) dropped.add(char);
751
798
  for (const char of face.clusters.values()) {
752
799
  if (!char) continue;
753
800
  dropped.add(char);
@@ -1357,6 +1404,23 @@ function variantKey(weight, style) {
1357
1404
  }
1358
1405
  return key;
1359
1406
  }
1407
+
1408
+ // src/atlasResult.ts
1409
+ function atlasResult(entry, family, weight, style, bold, italic) {
1410
+ return { entry, resolved: { family, weight, style }, synthetic: { bold, italic }, source: "atlas" };
1411
+ }
1412
+ var exactResults = /* @__PURE__ */ new WeakMap();
1413
+ function sharedExactResult(entry, family, weight, style) {
1414
+ const hit = exactResults.get(entry);
1415
+ if (hit !== void 0 && hit.resolved.family === family && hit.resolved.weight === weight && hit.resolved.style === style) return hit;
1416
+ const r = atlasResult(entry, family, weight, style, false, false);
1417
+ Object.freeze(r.resolved);
1418
+ Object.freeze(r.synthetic);
1419
+ exactResults.set(entry, Object.freeze(r));
1420
+ return r;
1421
+ }
1422
+
1423
+ // src/registerFont.ts
1360
1424
  var registry = createReflectable();
1361
1425
  var fontRegistry = registry.reflection;
1362
1426
  function normalizeVariant(v) {
@@ -1584,7 +1648,7 @@ function missResolveResult(family, weight, style, suppressWarn = false) {
1584
1648
  const fallback = getDefaultFontFamily() ?? firstRegisteredFamily();
1585
1649
  if (fallback !== null && fallback !== family) {
1586
1650
  if (registry.has(fallback) || isCanvasFont(fallback) || atlasPending(fallback)) {
1587
- const result = resolveFontVariantInternal(fallback, weight, style, true);
1651
+ const result = resolveFontVariantInternal(fallback, weight, style, true, false);
1588
1652
  if (result.entry !== null || result.dynamicFace !== void 0) {
1589
1653
  if (!suppressWarn) warnMissingFamilyOnce(family, weight, style, fallback);
1590
1654
  return { ...result, substituted: { requested: family, resolved: fallback } };
@@ -1653,7 +1717,10 @@ function weightBucket(w) {
1653
1717
  return w >= 600 ? "bold" : "regular";
1654
1718
  }
1655
1719
  function resolveFontVariant(family, weight, style) {
1656
- return resolveFontVariantInternal(family, weight, style, false);
1720
+ return resolveFontVariantInternal(family, weight, style, false, false);
1721
+ }
1722
+ function cachedFontVariant(family, weight, style) {
1723
+ return resolveFontVariantInternal(family, weight, style, false, true);
1657
1724
  }
1658
1725
  function resolveGlyphFallback(family, weight, style) {
1659
1726
  if (getFontFallbackPolicy() === "none") return null;
@@ -1671,7 +1738,7 @@ function resolveGlyphFallback(family, weight, style) {
1671
1738
  return null;
1672
1739
  }
1673
1740
  }
1674
- function resolveFontVariantInternal(family, weight, style, suppressWarn) {
1741
+ function resolveFontVariantInternal(family, weight, style, suppressWarn, shared) {
1675
1742
  wakeDeclared(family, weight, style);
1676
1743
  const exactKey = variantKey(weight, style);
1677
1744
  if (loads.size > 0 && loads.has(`${family}|${exactKey}`) && !registry.get(family)?.has(exactKey)) {
@@ -1684,12 +1751,7 @@ function resolveFontVariantInternal(family, weight, style, suppressWarn) {
1684
1751
  }
1685
1752
  const exact = familyMap.get(exactKey);
1686
1753
  if (exact) {
1687
- return {
1688
- entry: exact,
1689
- resolved: { family, weight, style },
1690
- synthetic: { bold: false, italic: false },
1691
- source: "atlas"
1692
- };
1754
+ return shared ? sharedExactResult(exact, family, weight, style) : atlasResult(exact, family, weight, style, false, false);
1693
1755
  }
1694
1756
  const requestedBucket = weightBucket(weight);
1695
1757
  let bestSameStyle = null;
@@ -1703,38 +1765,11 @@ function resolveFontVariantInternal(family, weight, style, suppressWarn) {
1703
1765
  bestSameStyle = { entry, weight: w, distance };
1704
1766
  }
1705
1767
  }
1706
- if (bestSameStyle) {
1707
- return {
1708
- entry: bestSameStyle.entry,
1709
- resolved: { family, weight: bestSameStyle.weight, style },
1710
- synthetic: { bold: false, italic: false },
1711
- source: "atlas"
1712
- };
1713
- }
1768
+ if (bestSameStyle) return atlasResult(bestSameStyle.entry, family, bestSameStyle.weight, style, false, false);
1714
1769
  const sameStyleRegular = familyMap.get(variantKey(400, style));
1715
- if (sameStyleRegular) {
1716
- return {
1717
- entry: sameStyleRegular,
1718
- resolved: { family, weight: 400, style },
1719
- synthetic: {
1720
- bold: weight >= 600,
1721
- italic: false
1722
- },
1723
- source: "atlas"
1724
- };
1725
- }
1770
+ if (sameStyleRegular) return atlasResult(sameStyleRegular, family, 400, style, weight >= 600, false);
1726
1771
  const sameWeightNormal = familyMap.get(variantKey(weight, "normal"));
1727
- if (sameWeightNormal) {
1728
- return {
1729
- entry: sameWeightNormal,
1730
- resolved: { family, weight, style: "normal" },
1731
- synthetic: {
1732
- bold: false,
1733
- italic: style === "italic"
1734
- },
1735
- source: "atlas"
1736
- };
1737
- }
1772
+ if (sameWeightNormal) return atlasResult(sameWeightNormal, family, weight, "normal", false, style === "italic");
1738
1773
  let bestNormal = null;
1739
1774
  for (const [key, entry] of familyMap) {
1740
1775
  const [wStr, s] = key.split("|");
@@ -1747,28 +1782,10 @@ function resolveFontVariantInternal(family, weight, style, suppressWarn) {
1747
1782
  }
1748
1783
  }
1749
1784
  if (bestNormal) {
1750
- return {
1751
- entry: bestNormal.entry,
1752
- resolved: { family, weight: bestNormal.weight, style: "normal" },
1753
- synthetic: {
1754
- bold: false,
1755
- italic: style === "italic"
1756
- },
1757
- source: "atlas"
1758
- };
1785
+ return atlasResult(bestNormal.entry, family, bestNormal.weight, "normal", false, style === "italic");
1759
1786
  }
1760
1787
  const regular = familyMap.get(variantKey(400, "normal"));
1761
- if (regular) {
1762
- return {
1763
- entry: regular,
1764
- resolved: { family, weight: 400, style: "normal" },
1765
- synthetic: {
1766
- bold: weight >= 600,
1767
- italic: style === "italic"
1768
- },
1769
- source: "atlas"
1770
- };
1771
- }
1788
+ if (regular) return atlasResult(regular, family, 400, "normal", weight >= 600, style === "italic");
1772
1789
  return missResolveResult(family, weight, style, suppressWarn);
1773
1790
  }
1774
1791
 
@@ -1873,6 +1890,6 @@ function _resetDomFacesForTests() {
1873
1890
  warned3.clear();
1874
1891
  }
1875
1892
 
1876
- export { BAKE_SIZE, DEFAULT_BAKE_BUDGET, MAX_SHARP_LEVEL, PAGE_SIZE, SDF_RADIUS, __setGlyphRasterizerForTests, _getPagesForTests, _resetDomFacesForTests, _resetDynamicFontsForTests, _resetFallbackForTests, _resetFontOutlinesForTests, _resetFontRegistryForTests, claimFallbackWarning, colorPageTextureId, createOpenTypeParser, cssFontFamily, cssFontFamilyLoading, dynamicPageTextureId, ensureFontTexture, faceGeneration, faceMetricsFor, fallbackWarningClaimed, fontOutlineRegistry, fontPending, fontRegistry, getDefaultFontFamily, getFont, getFontFallbackPolicy, glyphGeneration, glyphOutline, hasFontOutlines, isCanvasFont, listCanvasFonts, listFontOutlines, listFontWeights, listFonts, loadFontOutlines, markAllFontsNotUploaded, outlineMetrics, outlineStatus, refreshCanvasFont, registerCanvasFont, registerFont, registerFontOutlines, resetBakeBudget, resolveFontVariant, resolveGlyphFallback, setDefaultFontFamily, setFontFallbackPolicy, sharpColorPageTextureId, sharperColorGlyph, subscribeGlyphReady, syncColorPageTexture, syncDynamicPageTexture, syncSharpColorPageTexture, textureCacheKey, unregisterCanvasFont, unregisterFontOutlines, warmFonts };
1877
- //# sourceMappingURL=chunk-EQD3U7KB.js.map
1878
- //# sourceMappingURL=chunk-EQD3U7KB.js.map
1893
+ export { BAKE_SIZE, DEFAULT_BAKE_BUDGET, MAX_SHARP_LEVEL, PAGE_SIZE, SDF_RADIUS, __setGlyphRasterizerForTests, _getPagesForTests, _resetDomFacesForTests, _resetDynamicFontsForTests, _resetFallbackForTests, _resetFontOutlinesForTests, _resetFontRegistryForTests, cachedFontVariant, claimFallbackWarning, colorPageTextureId, createOpenTypeParser, cssFontFamily, cssFontFamilyLoading, dynamicPageTextureId, ensureFontTexture, faceGeneration, faceMetricsFor, fallbackWarningClaimed, fontOutlineRegistry, fontPending, fontRegistry, getDefaultFontFamily, getFont, getFontFallbackPolicy, glyphGeneration, glyphOutline, hasFontOutlines, isCanvasFont, listCanvasFonts, listFontOutlines, listFontWeights, listFonts, loadFontOutlines, markAllFontsNotUploaded, outlineMetrics, outlineStatus, refreshCanvasFont, registerCanvasFont, registerFont, registerFontOutlines, resetBakeBudget, resolveFontVariant, resolveGlyphFallback, setDefaultFontFamily, setFontFallbackPolicy, sharpColorPageTextureId, sharperColorGlyph, subscribeGlyphReady, syncColorPageTexture, syncDynamicPageTexture, syncSharpColorPageTexture, textureCacheKey, unregisterCanvasFont, unregisterFontOutlines, warmFonts };
1894
+ //# sourceMappingURL=chunk-I7OQG2DF.js.map
1895
+ //# sourceMappingURL=chunk-I7OQG2DF.js.map