@zumer/snapdom 1.9.12-dev.4 → 1.9.13
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/README.md +58 -27
- package/dist/snapdom.js +620 -336
- package/dist/snapdom.min.js +8 -5
- package/dist/snapdom.min.mjs +8 -5
- package/dist/snapdom.mjs +608 -331
- package/package.json +7 -2
- package/types/snapdom.d.ts +18 -0
package/dist/snapdom.js
CHANGED
|
@@ -858,6 +858,65 @@
|
|
|
858
858
|
delete snap["block-size"];
|
|
859
859
|
}
|
|
860
860
|
|
|
861
|
+
// src/modules/CSSVar.js
|
|
862
|
+
function resolveCSSVars(sourceEl, cloneEl) {
|
|
863
|
+
var _a, _b, _c;
|
|
864
|
+
if (!(sourceEl instanceof Element) || !(cloneEl instanceof Element)) return;
|
|
865
|
+
const styleAttr = (_a = sourceEl.getAttribute) == null ? void 0 : _a.call(sourceEl, "style");
|
|
866
|
+
let hasVar = !!(styleAttr && styleAttr.includes("var("));
|
|
867
|
+
if (!hasVar && ((_b = sourceEl.attributes) == null ? void 0 : _b.length)) {
|
|
868
|
+
const attrs = sourceEl.attributes;
|
|
869
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
870
|
+
const a = attrs[i];
|
|
871
|
+
if (a && typeof a.value === "string" && a.value.includes("var(")) {
|
|
872
|
+
hasVar = true;
|
|
873
|
+
break;
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
if (!hasVar) return;
|
|
878
|
+
let cs;
|
|
879
|
+
try {
|
|
880
|
+
cs = getComputedStyle(sourceEl);
|
|
881
|
+
} catch (e) {
|
|
882
|
+
return;
|
|
883
|
+
}
|
|
884
|
+
const author = sourceEl.style;
|
|
885
|
+
if (author && author.length) {
|
|
886
|
+
for (let i = 0; i < author.length; i++) {
|
|
887
|
+
const prop = author[i];
|
|
888
|
+
const val = author.getPropertyValue(prop);
|
|
889
|
+
if (!val || !val.includes("var(")) continue;
|
|
890
|
+
const resolved = cs.getPropertyValue(prop);
|
|
891
|
+
if (resolved) {
|
|
892
|
+
try {
|
|
893
|
+
cloneEl.style.setProperty(prop, resolved.trim(), author.getPropertyPriority(prop));
|
|
894
|
+
} catch (e) {
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
if ((_c = sourceEl.attributes) == null ? void 0 : _c.length) {
|
|
900
|
+
const attrs = sourceEl.attributes;
|
|
901
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
902
|
+
const a = attrs[i];
|
|
903
|
+
if (!a || typeof a.value !== "string" || !a.value.includes("var(")) continue;
|
|
904
|
+
const propName = a.name;
|
|
905
|
+
let resolved = "";
|
|
906
|
+
try {
|
|
907
|
+
resolved = cs.getPropertyValue(propName);
|
|
908
|
+
} catch (e) {
|
|
909
|
+
}
|
|
910
|
+
if (resolved) {
|
|
911
|
+
try {
|
|
912
|
+
cloneEl.style.setProperty(propName, resolved.trim());
|
|
913
|
+
} catch (e) {
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
|
|
861
920
|
// src/core/clone.js
|
|
862
921
|
function idleCallback(childList, callback, fast) {
|
|
863
922
|
return Promise.all(childList.map((child) => {
|
|
@@ -879,7 +938,7 @@
|
|
|
879
938
|
function addNotSlottedRightmost(sel) {
|
|
880
939
|
sel = sel.trim();
|
|
881
940
|
if (!sel) return sel;
|
|
882
|
-
if (
|
|
941
|
+
if (/:not\(\s*\[data-sd-slotted\]\s*\)\s*$/.test(sel)) return sel;
|
|
883
942
|
return `${sel}:not([data-sd-slotted])`;
|
|
884
943
|
}
|
|
885
944
|
function wrapWithScope(selectorList, scopeSelector, excludeSlotted = true) {
|
|
@@ -1175,7 +1234,7 @@
|
|
|
1175
1234
|
inlineAllStyles(node, clone2, sessionCache, options);
|
|
1176
1235
|
const placeholder = document.createElement("div");
|
|
1177
1236
|
placeholder.textContent = node.getAttribute("data-placeholder-text") || "";
|
|
1178
|
-
placeholder.style.cssText =
|
|
1237
|
+
placeholder.style.cssText = "color:#666;font-size:12px;text-align:center;line-height:1.4;padding:0.5em;box-sizing:border-box;";
|
|
1179
1238
|
clone2.appendChild(placeholder);
|
|
1180
1239
|
return clone2;
|
|
1181
1240
|
}
|
|
@@ -1192,6 +1251,7 @@
|
|
|
1192
1251
|
let clone;
|
|
1193
1252
|
try {
|
|
1194
1253
|
clone = node.cloneNode(false);
|
|
1254
|
+
resolveCSSVars(node, clone);
|
|
1195
1255
|
sessionCache.nodeMap.set(clone, node);
|
|
1196
1256
|
if (node.tagName === "IMG") {
|
|
1197
1257
|
freezeImgSrcset(node, clone);
|
|
@@ -1247,7 +1307,7 @@
|
|
|
1247
1307
|
} else {
|
|
1248
1308
|
deepClone(child, sessionCache, options).then((clonedChild) => {
|
|
1249
1309
|
resolve(clonedChild || null);
|
|
1250
|
-
}).catch((
|
|
1310
|
+
}).catch(() => {
|
|
1251
1311
|
resolve(null);
|
|
1252
1312
|
});
|
|
1253
1313
|
}
|
|
@@ -1288,7 +1348,7 @@
|
|
|
1288
1348
|
markSlottedSubtree(clonedChild);
|
|
1289
1349
|
}
|
|
1290
1350
|
resolve(clonedChild || null);
|
|
1291
|
-
}).catch((
|
|
1351
|
+
}).catch(() => {
|
|
1292
1352
|
resolve(null);
|
|
1293
1353
|
});
|
|
1294
1354
|
};
|
|
@@ -1303,7 +1363,7 @@
|
|
|
1303
1363
|
if (clonedAssignedNodes.has(child)) return resolve(null);
|
|
1304
1364
|
deepClone(child, sessionCache, options).then((clonedChild) => {
|
|
1305
1365
|
resolve(clonedChild || null);
|
|
1306
|
-
}).catch((
|
|
1366
|
+
}).catch(() => {
|
|
1307
1367
|
resolve(null);
|
|
1308
1368
|
});
|
|
1309
1369
|
}
|
|
@@ -1368,7 +1428,10 @@
|
|
|
1368
1428
|
return __async(this, null, function* () {
|
|
1369
1429
|
fontFamily = fontFamily.replace(/^['"]+|['"]+$/g, "");
|
|
1370
1430
|
const dpr = window.devicePixelRatio || 1;
|
|
1371
|
-
|
|
1431
|
+
try {
|
|
1432
|
+
yield document.fonts.ready;
|
|
1433
|
+
} catch (e) {
|
|
1434
|
+
}
|
|
1372
1435
|
const span = document.createElement("span");
|
|
1373
1436
|
span.textContent = unicodeChar;
|
|
1374
1437
|
span.style.position = "absolute";
|
|
@@ -1386,8 +1449,8 @@
|
|
|
1386
1449
|
const height = Math.ceil(rect.height);
|
|
1387
1450
|
document.body.removeChild(span);
|
|
1388
1451
|
const canvas = document.createElement("canvas");
|
|
1389
|
-
canvas.width = width * dpr;
|
|
1390
|
-
canvas.height = height * dpr;
|
|
1452
|
+
canvas.width = Math.max(1, width * dpr);
|
|
1453
|
+
canvas.height = Math.max(1, height * dpr);
|
|
1391
1454
|
const ctx = canvas.getContext("2d");
|
|
1392
1455
|
ctx.scale(dpr, dpr);
|
|
1393
1456
|
ctx.font = fontWeight ? `${fontWeight} ${fontSize}px "${fontFamily}"` : `${fontSize}px "${fontFamily}"`;
|
|
@@ -1507,6 +1570,313 @@
|
|
|
1507
1570
|
}
|
|
1508
1571
|
return out;
|
|
1509
1572
|
}
|
|
1573
|
+
function rewriteRelativeUrls(cssText, baseHref) {
|
|
1574
|
+
if (!cssText) return cssText;
|
|
1575
|
+
return cssText.replace(
|
|
1576
|
+
/url\(\s*(['"]?)([^)'"]+)\1\s*\)/g,
|
|
1577
|
+
(m, q, u) => {
|
|
1578
|
+
const src = (u || "").trim();
|
|
1579
|
+
if (!src || /^data:|^blob:|^https?:|^file:|^about:/i.test(src)) return m;
|
|
1580
|
+
let abs = src;
|
|
1581
|
+
try {
|
|
1582
|
+
abs = new URL(src, baseHref || location.href).href;
|
|
1583
|
+
} catch (e) {
|
|
1584
|
+
}
|
|
1585
|
+
return `url("${abs}")`;
|
|
1586
|
+
}
|
|
1587
|
+
);
|
|
1588
|
+
}
|
|
1589
|
+
var IMPORT_ANY_RE = /@import\s+(?:url\(\s*(['"]?)([^)"']+)\1\s*\)|(['"])([^"']+)\3)([^;]*);/g;
|
|
1590
|
+
var MAX_IMPORT_DEPTH = 4;
|
|
1591
|
+
function inlineImportsAndRewrite(cssText, ownerHref, useProxy) {
|
|
1592
|
+
return __async(this, null, function* () {
|
|
1593
|
+
if (!cssText) return cssText;
|
|
1594
|
+
const visited = /* @__PURE__ */ new Set();
|
|
1595
|
+
function normalizeUrl(u, base) {
|
|
1596
|
+
try {
|
|
1597
|
+
return new URL(u, base || location.href).href;
|
|
1598
|
+
} catch (e) {
|
|
1599
|
+
return u;
|
|
1600
|
+
}
|
|
1601
|
+
}
|
|
1602
|
+
function resolveOnce(text, baseHref, depth = 0) {
|
|
1603
|
+
return __async(this, null, function* () {
|
|
1604
|
+
if (depth > MAX_IMPORT_DEPTH) {
|
|
1605
|
+
console.warn(`[snapDOM] @import depth exceeded (${MAX_IMPORT_DEPTH}) at ${baseHref}`);
|
|
1606
|
+
return text;
|
|
1607
|
+
}
|
|
1608
|
+
let out = "";
|
|
1609
|
+
let last = 0;
|
|
1610
|
+
let m;
|
|
1611
|
+
while (m = IMPORT_ANY_RE.exec(text)) {
|
|
1612
|
+
out += text.slice(last, m.index);
|
|
1613
|
+
last = IMPORT_ANY_RE.lastIndex;
|
|
1614
|
+
const rawUrl = (m[2] || m[4] || "").trim();
|
|
1615
|
+
const absUrl = normalizeUrl(rawUrl, baseHref);
|
|
1616
|
+
if (visited.has(absUrl)) {
|
|
1617
|
+
console.warn("[snapDOM] Skipping circular import");
|
|
1618
|
+
continue;
|
|
1619
|
+
}
|
|
1620
|
+
visited.add(absUrl);
|
|
1621
|
+
let imported = "";
|
|
1622
|
+
try {
|
|
1623
|
+
const r = yield snapFetch(absUrl, { as: "text", useProxy, silent: true });
|
|
1624
|
+
if (r.ok && typeof r.data === "string") imported = r.data;
|
|
1625
|
+
} catch (e) {
|
|
1626
|
+
}
|
|
1627
|
+
if (imported) {
|
|
1628
|
+
imported = rewriteRelativeUrls(imported, absUrl);
|
|
1629
|
+
imported = yield resolveOnce(imported, absUrl, depth + 1);
|
|
1630
|
+
out += `
|
|
1631
|
+
/* inlined: ${absUrl} */
|
|
1632
|
+
${imported}
|
|
1633
|
+
`;
|
|
1634
|
+
} else {
|
|
1635
|
+
out += m[0];
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
out += text.slice(last);
|
|
1639
|
+
return out;
|
|
1640
|
+
});
|
|
1641
|
+
}
|
|
1642
|
+
let rewritten = rewriteRelativeUrls(cssText, ownerHref || location.href);
|
|
1643
|
+
rewritten = yield resolveOnce(rewritten, ownerHref || location.href, 0);
|
|
1644
|
+
return rewritten;
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
var URL_RE = /url\((["']?)([^"')]+)\1\)/g;
|
|
1648
|
+
var FACE_RE = /@font-face[^{}]*\{[^}]*\}/g;
|
|
1649
|
+
function parseUnicodeRange(ur) {
|
|
1650
|
+
if (!ur) return [];
|
|
1651
|
+
const ranges = [];
|
|
1652
|
+
const parts = ur.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1653
|
+
for (const p of parts) {
|
|
1654
|
+
const m = p.match(/^U\+([0-9A-Fa-f?]+)(?:-([0-9A-Fa-f?]+))?$/);
|
|
1655
|
+
if (!m) continue;
|
|
1656
|
+
const a = m[1], b = m[2];
|
|
1657
|
+
const expand = (hex) => {
|
|
1658
|
+
if (!hex.includes("?")) return parseInt(hex, 16);
|
|
1659
|
+
const min = parseInt(hex.replace(/\?/g, "0"), 16);
|
|
1660
|
+
const max = parseInt(hex.replace(/\?/g, "F"), 16);
|
|
1661
|
+
return [min, max];
|
|
1662
|
+
};
|
|
1663
|
+
if (b) {
|
|
1664
|
+
const A = expand(a), B = expand(b);
|
|
1665
|
+
const min = Array.isArray(A) ? A[0] : A;
|
|
1666
|
+
const max = Array.isArray(B) ? B[1] : B;
|
|
1667
|
+
ranges.push([Math.min(min, max), Math.max(min, max)]);
|
|
1668
|
+
} else {
|
|
1669
|
+
const X = expand(a);
|
|
1670
|
+
if (Array.isArray(X)) ranges.push([X[0], X[1]]);
|
|
1671
|
+
else ranges.push([X, X]);
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
return ranges;
|
|
1675
|
+
}
|
|
1676
|
+
function unicodeIntersects(used, ranges) {
|
|
1677
|
+
if (!ranges.length) return true;
|
|
1678
|
+
if (!used || used.size === 0) return true;
|
|
1679
|
+
for (const cp of used) {
|
|
1680
|
+
for (const [a, b] of ranges) if (cp >= a && cp <= b) return true;
|
|
1681
|
+
}
|
|
1682
|
+
return false;
|
|
1683
|
+
}
|
|
1684
|
+
function extractSrcUrls(srcValue, baseHref) {
|
|
1685
|
+
const urls = [];
|
|
1686
|
+
if (!srcValue) return urls;
|
|
1687
|
+
for (const m of srcValue.matchAll(URL_RE)) {
|
|
1688
|
+
let u = (m[2] || "").trim();
|
|
1689
|
+
if (!u || u.startsWith("data:")) continue;
|
|
1690
|
+
if (!/^https?:/i.test(u)) {
|
|
1691
|
+
try {
|
|
1692
|
+
u = new URL(u, baseHref || location.href).href;
|
|
1693
|
+
} catch (e) {
|
|
1694
|
+
}
|
|
1695
|
+
}
|
|
1696
|
+
urls.push(u);
|
|
1697
|
+
}
|
|
1698
|
+
return urls;
|
|
1699
|
+
}
|
|
1700
|
+
function inlineUrlsInCssBlock(cssBlock, baseHref, useProxy = "") {
|
|
1701
|
+
return __async(this, null, function* () {
|
|
1702
|
+
var _a, _b, _c, _d, _e;
|
|
1703
|
+
let out = cssBlock;
|
|
1704
|
+
for (const m of cssBlock.matchAll(URL_RE)) {
|
|
1705
|
+
const raw = extractURL(m[0]);
|
|
1706
|
+
if (!raw) continue;
|
|
1707
|
+
let abs = raw;
|
|
1708
|
+
if (!abs.startsWith("http") && !abs.startsWith("data:")) {
|
|
1709
|
+
try {
|
|
1710
|
+
abs = new URL(abs, baseHref || location.href).href;
|
|
1711
|
+
} catch (e) {
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
if (isIconFont2(abs)) continue;
|
|
1715
|
+
if ((_a = cache.resource) == null ? void 0 : _a.has(abs)) {
|
|
1716
|
+
(_b = cache.font) == null ? void 0 : _b.add(abs);
|
|
1717
|
+
out = out.replace(m[0], `url(${cache.resource.get(abs)})`);
|
|
1718
|
+
continue;
|
|
1719
|
+
}
|
|
1720
|
+
if ((_c = cache.font) == null ? void 0 : _c.has(abs)) continue;
|
|
1721
|
+
try {
|
|
1722
|
+
const r = yield snapFetch(abs, { as: "dataURL", useProxy, silent: true });
|
|
1723
|
+
if (r.ok && typeof r.data === "string") {
|
|
1724
|
+
const b64 = r.data;
|
|
1725
|
+
(_d = cache.resource) == null ? void 0 : _d.set(abs, b64);
|
|
1726
|
+
(_e = cache.font) == null ? void 0 : _e.add(abs);
|
|
1727
|
+
out = out.replace(m[0], `url(${b64})`);
|
|
1728
|
+
}
|
|
1729
|
+
} catch (e) {
|
|
1730
|
+
console.warn("[snapDOM] Failed to fetch font resource:", abs);
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1733
|
+
return out;
|
|
1734
|
+
});
|
|
1735
|
+
}
|
|
1736
|
+
function subsetFromRanges(ranges) {
|
|
1737
|
+
if (!ranges.length) return null;
|
|
1738
|
+
const hit = (a, b) => ranges.some(([x, y]) => !(y < a || x > b));
|
|
1739
|
+
const latin = hit(0, 255) || hit(305, 305);
|
|
1740
|
+
const latinExt = hit(256, 591) || hit(7680, 7935);
|
|
1741
|
+
const greek = hit(880, 1023);
|
|
1742
|
+
const cyr = hit(1024, 1279);
|
|
1743
|
+
const viet = hit(7840, 7929) || hit(258, 259) || hit(416, 417) || hit(431, 432);
|
|
1744
|
+
if (viet) return "vietnamese";
|
|
1745
|
+
if (cyr) return "cyrillic";
|
|
1746
|
+
if (greek) return "greek";
|
|
1747
|
+
if (latinExt) return "latin-ext";
|
|
1748
|
+
if (latin) return "latin";
|
|
1749
|
+
return null;
|
|
1750
|
+
}
|
|
1751
|
+
function buildSimpleExcluder(ex = {}) {
|
|
1752
|
+
const famSet = new Set((ex.families || []).map((s) => String(s).toLowerCase()));
|
|
1753
|
+
const domSet = new Set((ex.domains || []).map((s) => String(s).toLowerCase()));
|
|
1754
|
+
const subSet = new Set((ex.subsets || []).map((s) => String(s).toLowerCase()));
|
|
1755
|
+
return (meta, parsedRanges) => {
|
|
1756
|
+
if (famSet.size && famSet.has(meta.family.toLowerCase())) return true;
|
|
1757
|
+
if (domSet.size) {
|
|
1758
|
+
for (const u of meta.srcUrls) {
|
|
1759
|
+
try {
|
|
1760
|
+
if (domSet.has(new URL(u).host.toLowerCase())) return true;
|
|
1761
|
+
} catch (e) {
|
|
1762
|
+
}
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
if (subSet.size) {
|
|
1766
|
+
const label = subsetFromRanges(parsedRanges);
|
|
1767
|
+
if (label && subSet.has(label)) return true;
|
|
1768
|
+
}
|
|
1769
|
+
return false;
|
|
1770
|
+
};
|
|
1771
|
+
}
|
|
1772
|
+
function dedupeFontFaces(cssText) {
|
|
1773
|
+
var _a, _b, _c, _d, _e, _f;
|
|
1774
|
+
if (!cssText) return cssText;
|
|
1775
|
+
const FACE_RE_G = /@font-face[^{}]*\{[^}]*\}/gi;
|
|
1776
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1777
|
+
const out = [];
|
|
1778
|
+
for (const block of cssText.match(FACE_RE_G) || []) {
|
|
1779
|
+
const familyRaw = ((_a = block.match(/font-family:\s*([^;]+);/i)) == null ? void 0 : _a[1]) || "";
|
|
1780
|
+
const family = pickPrimaryFamily(familyRaw);
|
|
1781
|
+
const weightSpec = (((_b = block.match(/font-weight:\s*([^;]+);/i)) == null ? void 0 : _b[1]) || "400").trim();
|
|
1782
|
+
const styleSpec = (((_c = block.match(/font-style:\s*([^;]+);/i)) == null ? void 0 : _c[1]) || "normal").trim();
|
|
1783
|
+
const stretchSpec = (((_d = block.match(/font-stretch:\s*([^;]+);/i)) == null ? void 0 : _d[1]) || "100%").trim();
|
|
1784
|
+
const urange = (((_e = block.match(/unicode-range:\s*([^;]+);/i)) == null ? void 0 : _e[1]) || "").trim();
|
|
1785
|
+
const srcRaw = (((_f = block.match(/src\s*:\s*([^;]+);/i)) == null ? void 0 : _f[1]) || "").trim();
|
|
1786
|
+
const urls = extractSrcUrls(srcRaw, location.href);
|
|
1787
|
+
const srcPart = urls.length ? urls.map((u) => String(u).toLowerCase()).sort().join("|") : srcRaw.toLowerCase();
|
|
1788
|
+
const key = [
|
|
1789
|
+
String(family || "").toLowerCase(),
|
|
1790
|
+
weightSpec,
|
|
1791
|
+
styleSpec,
|
|
1792
|
+
stretchSpec,
|
|
1793
|
+
urange.toLowerCase(),
|
|
1794
|
+
srcPart
|
|
1795
|
+
].join("|");
|
|
1796
|
+
if (!seen.has(key)) {
|
|
1797
|
+
seen.add(key);
|
|
1798
|
+
out.push(block);
|
|
1799
|
+
}
|
|
1800
|
+
}
|
|
1801
|
+
if (out.length === 0) return cssText;
|
|
1802
|
+
let i = 0;
|
|
1803
|
+
return cssText.replace(FACE_RE_G, () => out[i++] || "");
|
|
1804
|
+
}
|
|
1805
|
+
function buildFontsCacheKey(required, exclude, localFonts, useProxy) {
|
|
1806
|
+
const req = Array.from(required || []).sort().join("|");
|
|
1807
|
+
const ex = exclude ? JSON.stringify({
|
|
1808
|
+
families: (exclude.families || []).map((s) => String(s).toLowerCase()).sort(),
|
|
1809
|
+
domains: (exclude.domains || []).map((s) => String(s).toLowerCase()).sort(),
|
|
1810
|
+
subsets: (exclude.subsets || []).map((s) => String(s).toLowerCase()).sort()
|
|
1811
|
+
}) : "";
|
|
1812
|
+
const lf = (localFonts || []).map((f) => `${(f.family || "").toLowerCase()}::${f.weight || "normal"}::${f.style || "normal"}::${f.src || ""}`).sort().join("|");
|
|
1813
|
+
const px = useProxy || "";
|
|
1814
|
+
return `fonts-embed-css::req=${req}::ex=${ex}::lf=${lf}::px=${px}`;
|
|
1815
|
+
}
|
|
1816
|
+
function collectFacesFromSheet(sheet, baseHref, emitFace, ctx) {
|
|
1817
|
+
return __async(this, null, function* () {
|
|
1818
|
+
let rules;
|
|
1819
|
+
try {
|
|
1820
|
+
rules = sheet.cssRules || [];
|
|
1821
|
+
} catch (e) {
|
|
1822
|
+
return;
|
|
1823
|
+
}
|
|
1824
|
+
const normalizeUrl = (u, base) => {
|
|
1825
|
+
try {
|
|
1826
|
+
return new URL(u, base || location.href).href;
|
|
1827
|
+
} catch (e) {
|
|
1828
|
+
return u;
|
|
1829
|
+
}
|
|
1830
|
+
};
|
|
1831
|
+
for (const rule of rules) {
|
|
1832
|
+
if (rule.type === CSSRule.IMPORT_RULE && rule.styleSheet) {
|
|
1833
|
+
const childHref = rule.href ? normalizeUrl(rule.href, baseHref) : baseHref;
|
|
1834
|
+
if (ctx.depth >= MAX_IMPORT_DEPTH) {
|
|
1835
|
+
console.warn(`[snapDOM] CSSOM import depth exceeded (${MAX_IMPORT_DEPTH}) at ${childHref}`);
|
|
1836
|
+
continue;
|
|
1837
|
+
}
|
|
1838
|
+
if (childHref && ctx.visitedSheets.has(childHref)) {
|
|
1839
|
+
console.warn(`[snapDOM] Skipping circular CSSOM import: ${childHref}`);
|
|
1840
|
+
continue;
|
|
1841
|
+
}
|
|
1842
|
+
if (childHref) ctx.visitedSheets.add(childHref);
|
|
1843
|
+
const nextCtx = __spreadProps(__spreadValues({}, ctx), { depth: (ctx.depth || 0) + 1 });
|
|
1844
|
+
yield collectFacesFromSheet(rule.styleSheet, childHref, emitFace, nextCtx);
|
|
1845
|
+
continue;
|
|
1846
|
+
}
|
|
1847
|
+
if (rule.type === CSSRule.FONT_FACE_RULE) {
|
|
1848
|
+
const famRaw = (rule.style.getPropertyValue("font-family") || "").trim();
|
|
1849
|
+
const family = pickPrimaryFamily(famRaw);
|
|
1850
|
+
if (!family || isIconFont2(family)) continue;
|
|
1851
|
+
const weightSpec = (rule.style.getPropertyValue("font-weight") || "400").trim();
|
|
1852
|
+
const styleSpec = (rule.style.getPropertyValue("font-style") || "normal").trim();
|
|
1853
|
+
const stretchSpec = (rule.style.getPropertyValue("font-stretch") || "100%").trim();
|
|
1854
|
+
const srcRaw = (rule.style.getPropertyValue("src") || "").trim();
|
|
1855
|
+
const urange = (rule.style.getPropertyValue("unicode-range") || "").trim();
|
|
1856
|
+
if (!ctx.faceMatchesRequired(family, styleSpec, weightSpec, stretchSpec)) continue;
|
|
1857
|
+
const ranges = parseUnicodeRange(urange);
|
|
1858
|
+
if (!unicodeIntersects(ctx.usedCodepoints, ranges)) continue;
|
|
1859
|
+
const meta = {
|
|
1860
|
+
family,
|
|
1861
|
+
weightSpec,
|
|
1862
|
+
styleSpec,
|
|
1863
|
+
stretchSpec,
|
|
1864
|
+
unicodeRange: urange,
|
|
1865
|
+
srcRaw,
|
|
1866
|
+
srcUrls: extractSrcUrls(srcRaw, baseHref || location.href),
|
|
1867
|
+
href: baseHref || location.href
|
|
1868
|
+
};
|
|
1869
|
+
if (ctx.simpleExcluder && ctx.simpleExcluder(meta, ranges)) continue;
|
|
1870
|
+
if (/url\(/i.test(srcRaw)) {
|
|
1871
|
+
const inlinedSrc = yield inlineUrlsInCssBlock(srcRaw, baseHref || location.href, ctx.useProxy);
|
|
1872
|
+
yield emitFace(`@font-face{font-family:${family};src:${inlinedSrc};font-style:${styleSpec};font-weight:${weightSpec};font-stretch:${stretchSpec};${urange ? `unicode-range:${urange};` : ""}}`);
|
|
1873
|
+
} else {
|
|
1874
|
+
yield emitFace(`@font-face{font-family:${family};src:${srcRaw};font-style:${styleSpec};font-weight:${weightSpec};font-stretch:${stretchSpec};${urange ? `unicode-range:${urange};` : ""}}`);
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
});
|
|
1879
|
+
}
|
|
1510
1880
|
function embedCustomFonts() {
|
|
1511
1881
|
return __async(this, arguments, function* ({
|
|
1512
1882
|
required,
|
|
@@ -1526,9 +1896,6 @@
|
|
|
1526
1896
|
arr.push({ w: parseInt(w, 10), s, st: parseInt(st, 10) });
|
|
1527
1897
|
requiredIndex.set(fam, arr);
|
|
1528
1898
|
}
|
|
1529
|
-
const IMPORT_RE = /@import\s+url\(["']?([^"')]+)["']?\)/g;
|
|
1530
|
-
const URL_RE = /url\((["']?)([^"')]+)\1\)/g;
|
|
1531
|
-
const FACE_RE = /@font-face[^{}]*\{[^}]*\}/g;
|
|
1532
1899
|
function faceMatchesRequired(fam, styleSpec, weightSpec, stretchSpec) {
|
|
1533
1900
|
if (!requiredIndex.has(fam)) return false;
|
|
1534
1901
|
const need = requiredIndex.get(fam);
|
|
@@ -1554,192 +1921,23 @@
|
|
|
1554
1921
|
const sOk = styleOK(normStyle(r.s));
|
|
1555
1922
|
const tOk = r.st >= ts.min && r.st <= ts.max;
|
|
1556
1923
|
const nearWeight = Math.abs(faceSingleW - r.w) <= 300;
|
|
1557
|
-
if (nearWeight && sOk && tOk)
|
|
1558
|
-
return true;
|
|
1559
|
-
}
|
|
1924
|
+
if (nearWeight && sOk && tOk) return true;
|
|
1560
1925
|
}
|
|
1561
1926
|
}
|
|
1562
1927
|
return false;
|
|
1563
1928
|
}
|
|
1564
|
-
function parseUnicodeRange(ur) {
|
|
1565
|
-
if (!ur) return [];
|
|
1566
|
-
const ranges = [];
|
|
1567
|
-
const parts = ur.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1568
|
-
for (const p of parts) {
|
|
1569
|
-
const m = p.match(/^U\+([0-9A-Fa-f?]+)(?:-([0-9A-Fa-f?]+))?$/);
|
|
1570
|
-
if (!m) continue;
|
|
1571
|
-
const a = m[1], b = m[2];
|
|
1572
|
-
const expand = (hex) => {
|
|
1573
|
-
if (!hex.includes("?")) return parseInt(hex, 16);
|
|
1574
|
-
const min = parseInt(hex.replace(/\?/g, "0"), 16);
|
|
1575
|
-
const max = parseInt(hex.replace(/\?/g, "F"), 16);
|
|
1576
|
-
return [min, max];
|
|
1577
|
-
};
|
|
1578
|
-
if (b) {
|
|
1579
|
-
const A = expand(a), B = expand(b);
|
|
1580
|
-
const min = Array.isArray(A) ? A[0] : A;
|
|
1581
|
-
const max = Array.isArray(B) ? B[1] : B;
|
|
1582
|
-
ranges.push([Math.min(min, max), Math.max(min, max)]);
|
|
1583
|
-
} else {
|
|
1584
|
-
const X = expand(a);
|
|
1585
|
-
if (Array.isArray(X)) ranges.push([X[0], X[1]]);
|
|
1586
|
-
else ranges.push([X, X]);
|
|
1587
|
-
}
|
|
1588
|
-
}
|
|
1589
|
-
return ranges;
|
|
1590
|
-
}
|
|
1591
|
-
function unicodeIntersects(used, ranges) {
|
|
1592
|
-
if (!ranges.length) return true;
|
|
1593
|
-
if (!used || used.size === 0) return true;
|
|
1594
|
-
for (const cp of used) {
|
|
1595
|
-
for (const [a, b] of ranges) if (cp >= a && cp <= b) return true;
|
|
1596
|
-
}
|
|
1597
|
-
return false;
|
|
1598
|
-
}
|
|
1599
|
-
function extractSrcUrls(srcValue, baseHref) {
|
|
1600
|
-
const urls = [];
|
|
1601
|
-
if (!srcValue) return urls;
|
|
1602
|
-
for (const m of srcValue.matchAll(URL_RE)) {
|
|
1603
|
-
let u = (m[2] || "").trim();
|
|
1604
|
-
if (!u || u.startsWith("data:")) continue;
|
|
1605
|
-
if (!/^https?:/i.test(u)) {
|
|
1606
|
-
try {
|
|
1607
|
-
u = new URL(u, baseHref || location.href).href;
|
|
1608
|
-
} catch (e) {
|
|
1609
|
-
}
|
|
1610
|
-
}
|
|
1611
|
-
urls.push(u);
|
|
1612
|
-
}
|
|
1613
|
-
return urls;
|
|
1614
|
-
}
|
|
1615
|
-
function inlineUrlsInCssBlock(cssBlock, baseHref) {
|
|
1616
|
-
return __async(this, null, function* () {
|
|
1617
|
-
var _a2, _b2, _c2, _d2, _e2;
|
|
1618
|
-
let out = cssBlock;
|
|
1619
|
-
for (const m of cssBlock.matchAll(URL_RE)) {
|
|
1620
|
-
const raw = extractURL(m[0]);
|
|
1621
|
-
if (!raw) continue;
|
|
1622
|
-
let abs = raw;
|
|
1623
|
-
if (!abs.startsWith("http") && !abs.startsWith("data:")) {
|
|
1624
|
-
try {
|
|
1625
|
-
abs = new URL(abs, baseHref || location.href).href;
|
|
1626
|
-
} catch (e) {
|
|
1627
|
-
}
|
|
1628
|
-
}
|
|
1629
|
-
if (isIconFont2(abs)) continue;
|
|
1630
|
-
if ((_a2 = cache.resource) == null ? void 0 : _a2.has(abs)) {
|
|
1631
|
-
(_b2 = cache.font) == null ? void 0 : _b2.add(abs);
|
|
1632
|
-
out = out.replace(m[0], `url(${cache.resource.get(abs)})`);
|
|
1633
|
-
continue;
|
|
1634
|
-
}
|
|
1635
|
-
if ((_c2 = cache.font) == null ? void 0 : _c2.has(abs)) continue;
|
|
1636
|
-
try {
|
|
1637
|
-
const r = yield snapFetch(abs, { as: "dataURL", useProxy, silent: true });
|
|
1638
|
-
if (r.ok && typeof r.data === "string") {
|
|
1639
|
-
const b64 = r.data;
|
|
1640
|
-
(_d2 = cache.resource) == null ? void 0 : _d2.set(abs, b64);
|
|
1641
|
-
(_e2 = cache.font) == null ? void 0 : _e2.add(abs);
|
|
1642
|
-
out = out.replace(m[0], `url(${b64})`);
|
|
1643
|
-
}
|
|
1644
|
-
} catch (e) {
|
|
1645
|
-
console.warn("[snapDOM] Failed to fetch font resource:", abs);
|
|
1646
|
-
}
|
|
1647
|
-
}
|
|
1648
|
-
return out;
|
|
1649
|
-
});
|
|
1650
|
-
}
|
|
1651
|
-
function subsetFromRanges(ranges) {
|
|
1652
|
-
if (!ranges.length) return null;
|
|
1653
|
-
const hit = (a, b) => ranges.some(([x, y]) => !(y < a || x > b));
|
|
1654
|
-
const latin = hit(0, 255) || hit(305, 305);
|
|
1655
|
-
const latinExt = hit(256, 591) || hit(7680, 7935);
|
|
1656
|
-
const greek = hit(880, 1023);
|
|
1657
|
-
const cyr = hit(1024, 1279);
|
|
1658
|
-
const viet = hit(7840, 7929) || hit(258, 259) || hit(416, 417) || hit(431, 432);
|
|
1659
|
-
if (viet) return "vietnamese";
|
|
1660
|
-
if (cyr) return "cyrillic";
|
|
1661
|
-
if (greek) return "greek";
|
|
1662
|
-
if (latinExt) return "latin-ext";
|
|
1663
|
-
if (latin) return "latin";
|
|
1664
|
-
return null;
|
|
1665
|
-
}
|
|
1666
|
-
function buildSimpleExcluder(ex = {}) {
|
|
1667
|
-
const famSet = new Set((ex.families || []).map((s) => String(s).toLowerCase()));
|
|
1668
|
-
const domSet = new Set((ex.domains || []).map((s) => String(s).toLowerCase()));
|
|
1669
|
-
const subSet = new Set((ex.subsets || []).map((s) => String(s).toLowerCase()));
|
|
1670
|
-
return (meta, parsedRanges) => {
|
|
1671
|
-
if (famSet.size && famSet.has(meta.family.toLowerCase())) return true;
|
|
1672
|
-
if (domSet.size) {
|
|
1673
|
-
for (const u of meta.srcUrls) {
|
|
1674
|
-
try {
|
|
1675
|
-
if (domSet.has(new URL(u).host.toLowerCase())) return true;
|
|
1676
|
-
} catch (e) {
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1679
|
-
}
|
|
1680
|
-
if (subSet.size) {
|
|
1681
|
-
const label = subsetFromRanges(parsedRanges);
|
|
1682
|
-
if (label && subSet.has(label)) return true;
|
|
1683
|
-
}
|
|
1684
|
-
return false;
|
|
1685
|
-
};
|
|
1686
|
-
}
|
|
1687
1929
|
const simpleExcluder = buildSimpleExcluder(exclude);
|
|
1688
|
-
|
|
1689
|
-
var _a2, _b2, _c2, _d2, _e2, _f2;
|
|
1690
|
-
if (!cssText) return cssText;
|
|
1691
|
-
const FACE_RE2 = /@font-face[^{}]*\{[^}]*\}/gi;
|
|
1692
|
-
const seen = /* @__PURE__ */ new Set();
|
|
1693
|
-
const out = [];
|
|
1694
|
-
for (const block of cssText.match(FACE_RE2) || []) {
|
|
1695
|
-
const familyRaw = ((_a2 = block.match(/font-family:\s*([^;]+);/i)) == null ? void 0 : _a2[1]) || "";
|
|
1696
|
-
const family = pickPrimaryFamily(familyRaw);
|
|
1697
|
-
const weightSpec = (((_b2 = block.match(/font-weight:\s*([^;]+);/i)) == null ? void 0 : _b2[1]) || "400").trim();
|
|
1698
|
-
const styleSpec = (((_c2 = block.match(/font-style:\s*([^;]+);/i)) == null ? void 0 : _c2[1]) || "normal").trim();
|
|
1699
|
-
const stretchSpec = (((_d2 = block.match(/font-stretch:\s*([^;]+);/i)) == null ? void 0 : _d2[1]) || "100%").trim();
|
|
1700
|
-
const urange = (((_e2 = block.match(/unicode-range:\s*([^;]+);/i)) == null ? void 0 : _e2[1]) || "").trim();
|
|
1701
|
-
const srcRaw = (((_f2 = block.match(/src\s*:\s*([^;]+);/i)) == null ? void 0 : _f2[1]) || "").trim();
|
|
1702
|
-
const urls = extractSrcUrls(srcRaw, location.href);
|
|
1703
|
-
const srcPart = urls.length ? urls.map((u) => String(u).toLowerCase()).sort().join("|") : srcRaw.toLowerCase();
|
|
1704
|
-
const key = [
|
|
1705
|
-
String(family || "").toLowerCase(),
|
|
1706
|
-
weightSpec,
|
|
1707
|
-
styleSpec,
|
|
1708
|
-
stretchSpec,
|
|
1709
|
-
urange.toLowerCase(),
|
|
1710
|
-
srcPart
|
|
1711
|
-
].join("|");
|
|
1712
|
-
if (!seen.has(key)) {
|
|
1713
|
-
seen.add(key);
|
|
1714
|
-
out.push(block);
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
if (out.length === 0) return cssText;
|
|
1718
|
-
let i = 0;
|
|
1719
|
-
return cssText.replace(FACE_RE2, () => out[i++] || "");
|
|
1720
|
-
}
|
|
1721
|
-
function buildFontsCacheKey() {
|
|
1722
|
-
const req = Array.from(required || []).sort().join("|");
|
|
1723
|
-
const ex = exclude ? JSON.stringify({
|
|
1724
|
-
families: (exclude.families || []).map((s) => String(s).toLowerCase()).sort(),
|
|
1725
|
-
domains: (exclude.domains || []).map((s) => String(s).toLowerCase()).sort(),
|
|
1726
|
-
subsets: (exclude.subsets || []).map((s) => String(s).toLowerCase()).sort()
|
|
1727
|
-
}) : "";
|
|
1728
|
-
const lf = (localFonts || []).map((f) => `${(f.family || "").toLowerCase()}::${f.weight || "normal"}::${f.style || "normal"}::${f.src || ""}`).sort().join("|");
|
|
1729
|
-
const px = useProxy || "";
|
|
1730
|
-
return `fonts-embed-css::req=${req}::ex=${ex}::lf=${lf}::px=${px}`;
|
|
1731
|
-
}
|
|
1732
|
-
const cacheKey = buildFontsCacheKey();
|
|
1930
|
+
const cacheKey = buildFontsCacheKey(required, exclude, localFonts, useProxy);
|
|
1733
1931
|
if ((_a = cache.resource) == null ? void 0 : _a.has(cacheKey)) {
|
|
1734
|
-
|
|
1735
|
-
return css;
|
|
1932
|
+
return cache.resource.get(cacheKey);
|
|
1736
1933
|
}
|
|
1737
1934
|
const requiredFamilies = familiesFromRequired(required);
|
|
1738
1935
|
const importUrls = [];
|
|
1936
|
+
const IMPORT_ANY_RE_LOCAL = IMPORT_ANY_RE;
|
|
1739
1937
|
for (const styleTag of document.querySelectorAll("style")) {
|
|
1740
1938
|
const cssText = styleTag.textContent || "";
|
|
1741
|
-
for (const m of cssText.matchAll(
|
|
1742
|
-
const u = m[
|
|
1939
|
+
for (const m of cssText.matchAll(IMPORT_ANY_RE_LOCAL)) {
|
|
1940
|
+
const u = (m[2] || m[4] || "").trim();
|
|
1743
1941
|
if (!u || isIconFont2(u)) continue;
|
|
1744
1942
|
const hasLink = !!document.querySelector(`link[rel="stylesheet"][href="${u}"]`);
|
|
1745
1943
|
if (!hasLink) importUrls.push(u);
|
|
@@ -1786,65 +1984,53 @@
|
|
|
1786
1984
|
cssText = res.data;
|
|
1787
1985
|
if (isIconFont2(link.href)) continue;
|
|
1788
1986
|
}
|
|
1987
|
+
cssText = yield inlineImportsAndRewrite(cssText, link.href, useProxy);
|
|
1789
1988
|
let facesOut = "";
|
|
1790
1989
|
for (const face of cssText.match(FACE_RE) || []) {
|
|
1791
1990
|
const famRaw = (((_b = face.match(/font-family:\s*([^;]+);/i)) == null ? void 0 : _b[1]) || "").trim();
|
|
1792
1991
|
const family = pickPrimaryFamily(famRaw);
|
|
1793
|
-
if (!family || isIconFont2(family))
|
|
1794
|
-
continue;
|
|
1795
|
-
}
|
|
1992
|
+
if (!family || isIconFont2(family)) continue;
|
|
1796
1993
|
const weightSpec = (((_c = face.match(/font-weight:\s*([^;]+);/i)) == null ? void 0 : _c[1]) || "400").trim();
|
|
1797
1994
|
const styleSpec = (((_d = face.match(/font-style:\s*([^;]+);/i)) == null ? void 0 : _d[1]) || "normal").trim();
|
|
1798
1995
|
const stretchSpec = (((_e = face.match(/font-stretch:\s*([^;]+);/i)) == null ? void 0 : _e[1]) || "100%").trim();
|
|
1799
1996
|
const urange = (((_f = face.match(/unicode-range:\s*([^;]+);/i)) == null ? void 0 : _f[1]) || "").trim();
|
|
1800
1997
|
const srcRaw = (((_g = face.match(/src\s*:\s*([^;]+);/i)) == null ? void 0 : _g[1]) || "").trim();
|
|
1801
1998
|
const srcUrls = extractSrcUrls(srcRaw, link.href);
|
|
1802
|
-
if (!faceMatchesRequired(family, styleSpec, weightSpec, stretchSpec))
|
|
1803
|
-
continue;
|
|
1804
|
-
}
|
|
1999
|
+
if (!faceMatchesRequired(family, styleSpec, weightSpec, stretchSpec)) continue;
|
|
1805
2000
|
const ranges = parseUnicodeRange(urange);
|
|
1806
|
-
if (!unicodeIntersects(usedCodepoints, ranges))
|
|
1807
|
-
continue;
|
|
1808
|
-
}
|
|
2001
|
+
if (!unicodeIntersects(usedCodepoints, ranges)) continue;
|
|
1809
2002
|
const meta = { family, weightSpec, styleSpec, stretchSpec, unicodeRange: urange, srcRaw, srcUrls, href: link.href };
|
|
1810
|
-
if (exclude && simpleExcluder(meta, ranges))
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
const newFace = /url\(/i.test(srcRaw) ? yield inlineUrlsInCssBlock(face, link.href) : face;
|
|
1814
|
-
facesOut += newFace + "";
|
|
2003
|
+
if (exclude && simpleExcluder(meta, ranges)) continue;
|
|
2004
|
+
const newFace = /url\(/i.test(srcRaw) ? yield inlineUrlsInCssBlock(face, link.href, useProxy) : face;
|
|
2005
|
+
facesOut += newFace;
|
|
1815
2006
|
}
|
|
1816
|
-
if (facesOut.trim()) finalCSS += facesOut
|
|
2007
|
+
if (facesOut.trim()) finalCSS += facesOut;
|
|
1817
2008
|
} catch (e) {
|
|
1818
|
-
console.warn("[
|
|
2009
|
+
console.warn("[snapDOM] Failed to process stylesheet:", link.href);
|
|
1819
2010
|
}
|
|
1820
2011
|
}
|
|
2012
|
+
const ctx = {
|
|
2013
|
+
requiredIndex,
|
|
2014
|
+
usedCodepoints,
|
|
2015
|
+
faceMatchesRequired,
|
|
2016
|
+
simpleExcluder: exclude ? buildSimpleExcluder(exclude) : null,
|
|
2017
|
+
useProxy,
|
|
2018
|
+
visitedSheets: /* @__PURE__ */ new Set(),
|
|
2019
|
+
depth: 0
|
|
2020
|
+
};
|
|
1821
2021
|
for (const sheet of document.styleSheets) {
|
|
2022
|
+
if (sheet.href && linkNodes.some((l) => l.href === sheet.href)) continue;
|
|
1822
2023
|
try {
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
const srcRaw = (rule.style.getPropertyValue("src") || "").trim();
|
|
1834
|
-
const urange = (rule.style.getPropertyValue("unicode-range") || "").trim();
|
|
1835
|
-
const srcUrls = extractSrcUrls(srcRaw, sheet.href || location.href);
|
|
1836
|
-
if (!faceMatchesRequired(family, styleSpec, weightSpec, stretchSpec)) continue;
|
|
1837
|
-
const ranges = parseUnicodeRange(urange);
|
|
1838
|
-
if (!unicodeIntersects(usedCodepoints, ranges)) continue;
|
|
1839
|
-
const meta = { family, weightSpec, styleSpec, stretchSpec, unicodeRange: urange, srcRaw, srcUrls, href: sheet.href || location.href };
|
|
1840
|
-
if (exclude && simpleExcluder(meta, ranges)) continue;
|
|
1841
|
-
if (/url\(/i.test(srcRaw)) {
|
|
1842
|
-
const inlinedSrc = yield inlineUrlsInCssBlock(srcRaw, sheet.href || location.href);
|
|
1843
|
-
finalCSS += `@font-face{font-family:${family};src:${inlinedSrc};font-style:${styleSpec};font-weight:${weightSpec};font-stretch:${stretchSpec};${urange ? `unicode-range:${urange};` : ""}}`;
|
|
1844
|
-
} else {
|
|
1845
|
-
finalCSS += `@font-face{font-family:${family};src:${srcRaw};font-style:${styleSpec};font-weight:${weightSpec};font-stretch:${stretchSpec};${urange ? `unicode-range:${urange};` : ""}}`;
|
|
1846
|
-
}
|
|
1847
|
-
}
|
|
2024
|
+
const rootHref = sheet.href || location.href;
|
|
2025
|
+
if (rootHref) ctx.visitedSheets.add(rootHref);
|
|
2026
|
+
yield collectFacesFromSheet(
|
|
2027
|
+
sheet,
|
|
2028
|
+
rootHref,
|
|
2029
|
+
(faceCss) => __async(null, null, function* () {
|
|
2030
|
+
finalCSS += faceCss;
|
|
2031
|
+
}),
|
|
2032
|
+
ctx
|
|
2033
|
+
);
|
|
1848
2034
|
} catch (e) {
|
|
1849
2035
|
}
|
|
1850
2036
|
}
|
|
@@ -1873,7 +2059,7 @@
|
|
|
1873
2059
|
continue;
|
|
1874
2060
|
}
|
|
1875
2061
|
} catch (e) {
|
|
1876
|
-
console.warn("[
|
|
2062
|
+
console.warn("[snapDOM] Failed to fetch dynamic font src:", f._snapdomSrc);
|
|
1877
2063
|
continue;
|
|
1878
2064
|
}
|
|
1879
2065
|
}
|
|
@@ -1908,7 +2094,7 @@
|
|
|
1908
2094
|
continue;
|
|
1909
2095
|
}
|
|
1910
2096
|
} catch (e) {
|
|
1911
|
-
console.warn("[
|
|
2097
|
+
console.warn("[snapDOM] Failed to fetch localFonts src:", src);
|
|
1912
2098
|
continue;
|
|
1913
2099
|
}
|
|
1914
2100
|
}
|
|
@@ -1999,7 +2185,7 @@
|
|
|
1999
2185
|
if (fams.length === 0) return;
|
|
2000
2186
|
const warmupOnce = () => {
|
|
2001
2187
|
const container = document.createElement("div");
|
|
2002
|
-
container.style.cssText =
|
|
2188
|
+
container.style.cssText = "position:absolute!important;left:-9999px!important;top:0!important;opacity:0!important;pointer-events:none!important;contain:layout size style;";
|
|
2003
2189
|
for (const fam of fams) {
|
|
2004
2190
|
const span = document.createElement("span");
|
|
2005
2191
|
span.textContent = "AaBbGg1234\xC1\xC9\xCD\xD3\xDA\xE7\xF1\u2014\u221E";
|
|
@@ -2360,9 +2546,6 @@
|
|
|
2360
2546
|
const fontSize = parseInt(style.fontSize) || 32;
|
|
2361
2547
|
const fontWeight = parseInt(style.fontWeight) || false;
|
|
2362
2548
|
const color = style.color || "#000";
|
|
2363
|
-
const display = style.display;
|
|
2364
|
-
const width = parseFloat(style.width);
|
|
2365
|
-
const height = parseFloat(style.height);
|
|
2366
2549
|
const borderStyle = style.borderStyle;
|
|
2367
2550
|
const borderWidth = parseFloat(style.borderWidth);
|
|
2368
2551
|
const transform = style.transform;
|
|
@@ -2370,14 +2553,13 @@
|
|
|
2370
2553
|
const hasExplicitContent = rawContent !== "none" && cleanContent !== "";
|
|
2371
2554
|
const hasBg = bg && bg !== "none";
|
|
2372
2555
|
const hasBgColor = bgColor && bgColor !== "transparent" && bgColor !== "rgba(0, 0, 0, 0)";
|
|
2373
|
-
const hasBox2 = display !== "inline" && (width > 0 || height > 0);
|
|
2374
2556
|
const hasBorder = borderStyle && borderStyle !== "none" && borderWidth > 0;
|
|
2375
2557
|
const hasTransform = transform && transform !== "none";
|
|
2376
2558
|
const shouldRender = hasExplicitContent || hasBg || hasBgColor || hasBorder || hasTransform;
|
|
2377
2559
|
if (!shouldRender) {
|
|
2378
2560
|
if (incs && incs.length && source.parentElement) {
|
|
2379
2561
|
const map = __siblingCounters.get(source.parentElement) || /* @__PURE__ */ new Map();
|
|
2380
|
-
for (const { name
|
|
2562
|
+
for (const { name } of incs) {
|
|
2381
2563
|
if (!name) continue;
|
|
2382
2564
|
const baseWithSibs = withSiblingOverrides(source, counterCtx);
|
|
2383
2565
|
const derived = deriveCounterCtxForPseudo(source, getComputedStyle(source, pseudo), baseWithSibs);
|
|
@@ -3079,19 +3261,50 @@
|
|
|
3079
3261
|
}
|
|
3080
3262
|
|
|
3081
3263
|
// src/core/capture.js
|
|
3264
|
+
function stripRootShadows(originalEl, cloneRoot) {
|
|
3265
|
+
if (!originalEl || !cloneRoot || !cloneRoot.style) return;
|
|
3266
|
+
const cs = getComputedStyle(originalEl);
|
|
3267
|
+
try {
|
|
3268
|
+
cloneRoot.style.boxShadow = "none";
|
|
3269
|
+
} catch (e) {
|
|
3270
|
+
}
|
|
3271
|
+
try {
|
|
3272
|
+
cloneRoot.style.textShadow = "none";
|
|
3273
|
+
} catch (e) {
|
|
3274
|
+
}
|
|
3275
|
+
try {
|
|
3276
|
+
cloneRoot.style.outline = "none";
|
|
3277
|
+
} catch (e) {
|
|
3278
|
+
}
|
|
3279
|
+
const f = cs.filter || "";
|
|
3280
|
+
const cleaned = f.replace(/\bblur\([^()]*\)\s*/gi, "").replace(/\bdrop-shadow\([^()]*\)\s*/gi, "").trim().replace(/\s+/g, " ");
|
|
3281
|
+
try {
|
|
3282
|
+
cloneRoot.style.filter = cleaned.length ? cleaned : "none";
|
|
3283
|
+
} catch (e) {
|
|
3284
|
+
}
|
|
3285
|
+
}
|
|
3082
3286
|
function captureDOM(element, options) {
|
|
3083
3287
|
return __async(this, null, function* () {
|
|
3084
3288
|
if (!element) throw new Error("Element cannot be null or undefined");
|
|
3085
3289
|
applyCachePolicy(options.cache);
|
|
3086
3290
|
const fast = options.fast;
|
|
3291
|
+
const straighten = !!options.straighten;
|
|
3292
|
+
const noShadows = !!options.noShadows;
|
|
3087
3293
|
let clone, classCSS, styleCache;
|
|
3088
3294
|
let fontsCSS = "";
|
|
3089
3295
|
let baseCSS = "";
|
|
3090
3296
|
let dataURL;
|
|
3091
3297
|
let svgString;
|
|
3298
|
+
let rootTransform2D = null;
|
|
3092
3299
|
const undoClamp = lineClamp(element);
|
|
3093
3300
|
try {
|
|
3094
3301
|
({ clone, classCSS, styleCache } = yield prepareClone(element, options));
|
|
3302
|
+
if (straighten && clone) {
|
|
3303
|
+
rootTransform2D = normalizeRootTransforms(element, clone);
|
|
3304
|
+
}
|
|
3305
|
+
if (noShadows && clone) {
|
|
3306
|
+
stripRootShadows(element, clone);
|
|
3307
|
+
}
|
|
3095
3308
|
} finally {
|
|
3096
3309
|
undoClamp();
|
|
3097
3310
|
}
|
|
@@ -3116,7 +3329,7 @@
|
|
|
3116
3329
|
const families = new Set(
|
|
3117
3330
|
Array.from(required).map((k) => String(k).split("__")[0]).filter(Boolean)
|
|
3118
3331
|
);
|
|
3119
|
-
yield ensureFontsReady(families,
|
|
3332
|
+
yield ensureFontsReady(families, 1);
|
|
3120
3333
|
}
|
|
3121
3334
|
fontsCSS = yield embedCustomFonts({
|
|
3122
3335
|
required,
|
|
@@ -3165,61 +3378,7 @@
|
|
|
3165
3378
|
b = Math.max(b, extY + Math.max(oy, 0));
|
|
3166
3379
|
t = Math.max(t, extY + Math.max(-oy, 0));
|
|
3167
3380
|
}
|
|
3168
|
-
return {
|
|
3169
|
-
bleed: { top: Math.ceil(t), right: Math.ceil(r), bottom: Math.ceil(b), left: Math.ceil(l) },
|
|
3170
|
-
has: found
|
|
3171
|
-
};
|
|
3172
|
-
}
|
|
3173
|
-
function parseBoxShadow(cs) {
|
|
3174
|
-
var _a;
|
|
3175
|
-
const v = cs.boxShadow || "";
|
|
3176
|
-
if (!v || v === "none") return { top: 0, right: 0, bottom: 0, left: 0 };
|
|
3177
|
-
const parts = v.split(/\),(?=(?:[^()]*\([^()]*\))*[^()]*$)/).map((s) => s.trim());
|
|
3178
|
-
let t = 0, r = 0, b2 = 0, l = 0;
|
|
3179
|
-
for (const part of parts) {
|
|
3180
|
-
const nums = ((_a = part.match(/-?\d+(\.\d+)?px/g)) == null ? void 0 : _a.map((n) => parseFloat(n))) || [];
|
|
3181
|
-
if (nums.length < 2) continue;
|
|
3182
|
-
const [ox2, oy2, blur = 0, spread = 0] = nums;
|
|
3183
|
-
const extX = Math.abs(ox2) + blur + spread;
|
|
3184
|
-
const extY = Math.abs(oy2) + blur + spread;
|
|
3185
|
-
r = Math.max(r, extX + Math.max(ox2, 0));
|
|
3186
|
-
l = Math.max(l, extX + Math.max(-ox2, 0));
|
|
3187
|
-
b2 = Math.max(b2, extY + Math.max(oy2, 0));
|
|
3188
|
-
t = Math.max(t, extY + Math.max(-oy2, 0));
|
|
3189
|
-
}
|
|
3190
|
-
return { top: Math.ceil(t), right: Math.ceil(r), bottom: Math.ceil(b2), left: Math.ceil(l) };
|
|
3191
|
-
}
|
|
3192
|
-
function parseFilterBlur(cs) {
|
|
3193
|
-
const m = (cs.filter || "").match(/blur\(\s*([0-9.]+)px\s*\)/);
|
|
3194
|
-
const b2 = m ? Math.ceil(parseFloat(m[1]) || 0) : 0;
|
|
3195
|
-
return { top: b2, right: b2, bottom: b2, left: b2 };
|
|
3196
|
-
}
|
|
3197
|
-
function parseOutline(cs) {
|
|
3198
|
-
if ((cs.outlineStyle || "none") === "none") return { top: 0, right: 0, bottom: 0, left: 0 };
|
|
3199
|
-
const w2 = Math.ceil(parseFloat(cs.outlineWidth || "0") || 0);
|
|
3200
|
-
return { top: w2, right: w2, bottom: w2, left: w2 };
|
|
3201
|
-
}
|
|
3202
|
-
function bboxWithOriginFull(w2, h2, M, ox2, oy2) {
|
|
3203
|
-
const a2 = M.a, b2 = M.b, c2 = M.c, d2 = M.d, e2 = M.e || 0, f2 = M.f || 0;
|
|
3204
|
-
function pt(x, y) {
|
|
3205
|
-
let X = x - ox2, Y = y - oy2;
|
|
3206
|
-
let X2 = a2 * X + c2 * Y, Y2 = b2 * X + d2 * Y;
|
|
3207
|
-
X2 += ox2 + e2;
|
|
3208
|
-
Y2 += oy2 + f2;
|
|
3209
|
-
return [X2, Y2];
|
|
3210
|
-
}
|
|
3211
|
-
const P = [pt(0, 0), pt(w2, 0), pt(0, h2), pt(w2, h2)];
|
|
3212
|
-
let minX2 = Infinity, minY2 = Infinity, maxX2 = -Infinity, maxY2 = -Infinity;
|
|
3213
|
-
for (const [X, Y] of P) {
|
|
3214
|
-
if (X < minX2) minX2 = X;
|
|
3215
|
-
if (Y < minY2) minY2 = Y;
|
|
3216
|
-
if (X > maxX2) maxX2 = X;
|
|
3217
|
-
if (Y > maxY2) maxY2 = Y;
|
|
3218
|
-
}
|
|
3219
|
-
return { minX: minX2, minY: minY2, maxX: maxX2, maxY: maxY2, width: maxX2 - minX2, height: maxY2 - minY2 };
|
|
3220
|
-
}
|
|
3221
|
-
function hasTFBBox(el) {
|
|
3222
|
-
return hasBBoxAffectingTransform(el);
|
|
3381
|
+
return { bleed: { top: Math.ceil(t), right: Math.ceil(r), bottom: Math.ceil(b), left: Math.ceil(l) }, has: found };
|
|
3223
3382
|
}
|
|
3224
3383
|
const rect = element.getBoundingClientRect();
|
|
3225
3384
|
const w0 = Math.max(1, Math.ceil(element.offsetWidth || parseFloat(csEl.width) || rect.width || 1));
|
|
@@ -3248,28 +3407,38 @@
|
|
|
3248
3407
|
h = h0;
|
|
3249
3408
|
}
|
|
3250
3409
|
let minX = 0, minY = 0, maxX = w0, maxY = h0;
|
|
3251
|
-
if (
|
|
3252
|
-
const
|
|
3253
|
-
const
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3410
|
+
if (straighten && rootTransform2D && Number.isFinite(rootTransform2D.a)) {
|
|
3411
|
+
const M2 = { a: rootTransform2D.a, b: rootTransform2D.b || 0, c: rootTransform2D.c || 0, d: rootTransform2D.d || 1, e: 0, f: 0 };
|
|
3412
|
+
const bb2 = bboxWithOriginFull(w0, h0, M2, 0, 0);
|
|
3413
|
+
minX = bb2.minX;
|
|
3414
|
+
minY = bb2.minY;
|
|
3415
|
+
maxX = bb2.maxX;
|
|
3416
|
+
maxY = bb2.maxY;
|
|
3417
|
+
} else {
|
|
3418
|
+
const useTFBBox = !straighten && hasTFBBox(element);
|
|
3419
|
+
if (useTFBBox) {
|
|
3420
|
+
const baseTransform2 = csEl.transform && csEl.transform !== "none" ? csEl.transform : "";
|
|
3421
|
+
const ind2 = readIndividualTransforms(element);
|
|
3422
|
+
const TOTAL = readTotalTransformMatrix({
|
|
3423
|
+
baseTransform: baseTransform2,
|
|
3424
|
+
rotate: ind2.rotate || "0deg",
|
|
3425
|
+
scale: ind2.scale,
|
|
3426
|
+
translate: ind2.translate
|
|
3427
|
+
});
|
|
3428
|
+
const { ox: ox2, oy: oy2 } = parseTransformOriginPx(csEl, w0, h0);
|
|
3429
|
+
const M = TOTAL.is2D ? TOTAL : new DOMMatrix(TOTAL.toString());
|
|
3430
|
+
const bb = bboxWithOriginFull(w0, h0, M, ox2, oy2);
|
|
3431
|
+
minX = bb.minX;
|
|
3432
|
+
minY = bb.minY;
|
|
3433
|
+
maxX = bb.maxX;
|
|
3434
|
+
maxY = bb.maxY;
|
|
3435
|
+
}
|
|
3267
3436
|
}
|
|
3268
3437
|
const bleedShadow = parseBoxShadow(csEl);
|
|
3269
3438
|
const bleedBlur = parseFilterBlur(csEl);
|
|
3270
3439
|
const bleedOutline = parseOutline(csEl);
|
|
3271
3440
|
const drop = parseFilterDropShadows(csEl);
|
|
3272
|
-
const bleed = {
|
|
3441
|
+
const bleed = noShadows ? { top: 0, right: 0, bottom: 0, left: 0 } : {
|
|
3273
3442
|
top: bleedShadow.top + bleedBlur.top + bleedOutline.top + drop.bleed.top,
|
|
3274
3443
|
right: bleedShadow.right + bleedBlur.right + bleedOutline.right + drop.bleed.right,
|
|
3275
3444
|
bottom: bleedShadow.bottom + bleedBlur.bottom + bleedOutline.bottom + drop.bleed.bottom,
|
|
@@ -3284,7 +3453,9 @@
|
|
|
3284
3453
|
const outW = Math.max(1, Math.round(vbW0 * (hasW || hasH ? w / w0 : 1)));
|
|
3285
3454
|
const outH = Math.max(1, Math.round(vbH0 * (hasH || hasW ? h / h0 : 1)));
|
|
3286
3455
|
const svgNS = "http://www.w3.org/2000/svg";
|
|
3287
|
-
const
|
|
3456
|
+
const basePad = isSafari() ? 1 : 0;
|
|
3457
|
+
const extraPad = straighten ? 1 : 0;
|
|
3458
|
+
const pad = basePad + extraPad;
|
|
3288
3459
|
const fo = document.createElementNS(svgNS, "foreignObject");
|
|
3289
3460
|
const vbMinX = Math.floor(minX);
|
|
3290
3461
|
const vbMinY = Math.floor(minY);
|
|
@@ -3309,20 +3480,7 @@
|
|
|
3309
3480
|
const vbW = vbW0 + pad * 2;
|
|
3310
3481
|
const vbH = vbH0 + pad * 2;
|
|
3311
3482
|
const wantsSize = hasW || hasH;
|
|
3312
|
-
options.meta = {
|
|
3313
|
-
w0,
|
|
3314
|
-
// ancho natural del elemento
|
|
3315
|
-
h0,
|
|
3316
|
-
// alto natural
|
|
3317
|
-
vbW,
|
|
3318
|
-
// ancho del viewBox
|
|
3319
|
-
vbH,
|
|
3320
|
-
// alto del viewBox
|
|
3321
|
-
targetW: w,
|
|
3322
|
-
// ancho deseado según options.width
|
|
3323
|
-
targetH: h
|
|
3324
|
-
// alto deseado según options.height
|
|
3325
|
-
};
|
|
3483
|
+
options.meta = { w0, h0, vbW, vbH, targetW: w, targetH: h };
|
|
3326
3484
|
const svgOutW = isSafari() && wantsSize ? vbW : outW + pad * 2;
|
|
3327
3485
|
const svgOutH = isSafari() && wantsSize ? vbH : outH + pad * 2;
|
|
3328
3486
|
const svgHeader = `<svg xmlns="${svgNS}" width="${svgOutW}" height="${svgOutH}" viewBox="0 0 ${vbW} ${vbH}">`;
|
|
@@ -3337,6 +3495,116 @@
|
|
|
3337
3495
|
return dataURL;
|
|
3338
3496
|
});
|
|
3339
3497
|
}
|
|
3498
|
+
function normalizeRootTransforms(originalEl, cloneRoot) {
|
|
3499
|
+
if (!originalEl || !cloneRoot || !cloneRoot.style) return null;
|
|
3500
|
+
const cs = getComputedStyle(originalEl);
|
|
3501
|
+
try {
|
|
3502
|
+
cloneRoot.style.transformOrigin = "0 0";
|
|
3503
|
+
} catch (e) {
|
|
3504
|
+
}
|
|
3505
|
+
try {
|
|
3506
|
+
if ("translate" in cloneRoot.style) cloneRoot.style.translate = "none";
|
|
3507
|
+
if ("rotate" in cloneRoot.style) cloneRoot.style.rotate = "none";
|
|
3508
|
+
} catch (e) {
|
|
3509
|
+
}
|
|
3510
|
+
const tr = cs.transform || "none";
|
|
3511
|
+
if (!tr || tr === "none") {
|
|
3512
|
+
try {
|
|
3513
|
+
const M = matrixFromComputed(originalEl);
|
|
3514
|
+
if (M.a === 1 && M.b === 0 && M.c === 0 && M.d === 1) {
|
|
3515
|
+
cloneRoot.style.transform = "none";
|
|
3516
|
+
return { a: 1, b: 0, c: 0, d: 1 };
|
|
3517
|
+
}
|
|
3518
|
+
} catch (e) {
|
|
3519
|
+
}
|
|
3520
|
+
}
|
|
3521
|
+
const m2d = tr.match(/^matrix\(\s*([^)]+)\)$/i);
|
|
3522
|
+
if (m2d) {
|
|
3523
|
+
const nums = m2d[1].split(",").map((v) => parseFloat(v.trim()));
|
|
3524
|
+
if (nums.length === 6 && nums.every(Number.isFinite)) {
|
|
3525
|
+
const [a, b, c, d] = nums;
|
|
3526
|
+
const scaleX = Math.sqrt(a * a + b * b) || 0;
|
|
3527
|
+
let a1 = 0, b1 = 0, shear = 0, c2 = 0, d2 = 0, scaleY = 0;
|
|
3528
|
+
if (scaleX > 0) {
|
|
3529
|
+
a1 = a / scaleX;
|
|
3530
|
+
b1 = b / scaleX;
|
|
3531
|
+
shear = a1 * c + b1 * d;
|
|
3532
|
+
c2 = c - a1 * shear;
|
|
3533
|
+
d2 = d - b1 * shear;
|
|
3534
|
+
scaleY = Math.sqrt(c2 * c2 + d2 * d2) || 0;
|
|
3535
|
+
if (scaleY > 0) shear = shear / scaleY;
|
|
3536
|
+
else shear = 0;
|
|
3537
|
+
}
|
|
3538
|
+
const aP = scaleX;
|
|
3539
|
+
const bP = 0;
|
|
3540
|
+
const cP = shear * scaleY;
|
|
3541
|
+
const dP = scaleY;
|
|
3542
|
+
try {
|
|
3543
|
+
cloneRoot.style.transform = `matrix(${aP}, ${bP}, ${cP}, ${dP}, 0, 0)`;
|
|
3544
|
+
} catch (e) {
|
|
3545
|
+
}
|
|
3546
|
+
return { a: aP, b: bP, c: cP, d: dP };
|
|
3547
|
+
}
|
|
3548
|
+
}
|
|
3549
|
+
try {
|
|
3550
|
+
const legacy = String(tr).trim();
|
|
3551
|
+
cloneRoot.style.transform = legacy + " translate(0px, 0px) rotate(0deg)";
|
|
3552
|
+
return null;
|
|
3553
|
+
} catch (e) {
|
|
3554
|
+
return null;
|
|
3555
|
+
}
|
|
3556
|
+
}
|
|
3557
|
+
function parseBoxShadow(cs) {
|
|
3558
|
+
var _a;
|
|
3559
|
+
const v = cs.boxShadow || "";
|
|
3560
|
+
if (!v || v === "none") return { top: 0, right: 0, bottom: 0, left: 0 };
|
|
3561
|
+
const parts = v.split(/\),(?=(?:[^()]*\([^()]*\))*[^()]*$)/).map((s) => s.trim());
|
|
3562
|
+
let t = 0, r = 0, b2 = 0, l = 0;
|
|
3563
|
+
for (const part of parts) {
|
|
3564
|
+
const nums = ((_a = part.match(/-?\d+(\.\d+)?px/g)) == null ? void 0 : _a.map((n) => parseFloat(n))) || [];
|
|
3565
|
+
if (nums.length < 2) continue;
|
|
3566
|
+
const [ox2, oy2, blur = 0, spread = 0] = nums;
|
|
3567
|
+
const extX = Math.abs(ox2) + blur + spread;
|
|
3568
|
+
const extY = Math.abs(oy2) + blur + spread;
|
|
3569
|
+
r = Math.max(r, extX + Math.max(ox2, 0));
|
|
3570
|
+
l = Math.max(l, extX + Math.max(-ox2, 0));
|
|
3571
|
+
b2 = Math.max(b2, extY + Math.max(oy2, 0));
|
|
3572
|
+
t = Math.max(t, extY + Math.max(-oy2, 0));
|
|
3573
|
+
}
|
|
3574
|
+
return { top: Math.ceil(t), right: Math.ceil(r), bottom: Math.ceil(b2), left: Math.ceil(l) };
|
|
3575
|
+
}
|
|
3576
|
+
function parseFilterBlur(cs) {
|
|
3577
|
+
const m = (cs.filter || "").match(/blur\(\s*([0-9.]+)px\s*\)/);
|
|
3578
|
+
const b2 = m ? Math.ceil(parseFloat(m[1]) || 0) : 0;
|
|
3579
|
+
return { top: b2, right: b2, bottom: b2, left: b2 };
|
|
3580
|
+
}
|
|
3581
|
+
function parseOutline(cs) {
|
|
3582
|
+
if ((cs.outlineStyle || "none") === "none") return { top: 0, right: 0, bottom: 0, left: 0 };
|
|
3583
|
+
const w2 = Math.ceil(parseFloat(cs.outlineWidth || "0") || 0);
|
|
3584
|
+
return { top: w2, right: w2, bottom: w2, left: w2 };
|
|
3585
|
+
}
|
|
3586
|
+
function bboxWithOriginFull(w2, h2, M, ox2, oy2) {
|
|
3587
|
+
const a2 = M.a, b2 = M.b, c2 = M.c, d2 = M.d, e2 = M.e || 0, f2 = M.f || 0;
|
|
3588
|
+
function pt(x, y) {
|
|
3589
|
+
let X = x - ox2, Y = y - oy2;
|
|
3590
|
+
let X2 = a2 * X + c2 * Y, Y2 = b2 * X + d2 * Y;
|
|
3591
|
+
X2 += ox2 + e2;
|
|
3592
|
+
Y2 += oy2 + f2;
|
|
3593
|
+
return [X2, Y2];
|
|
3594
|
+
}
|
|
3595
|
+
const P = [pt(0, 0), pt(w2, 0), pt(0, h2), pt(w2, h2)];
|
|
3596
|
+
let minX2 = Infinity, minY2 = Infinity, maxX2 = -Infinity, maxY2 = -Infinity;
|
|
3597
|
+
for (const [X, Y] of P) {
|
|
3598
|
+
if (X < minX2) minX2 = X;
|
|
3599
|
+
if (Y < minY2) minY2 = Y;
|
|
3600
|
+
if (X > maxX2) maxX2 = X;
|
|
3601
|
+
if (Y > maxY2) maxY2 = Y;
|
|
3602
|
+
}
|
|
3603
|
+
return { minX: minX2, minY: minY2, maxX: maxX2, maxY: maxY2, width: maxX2 - minX2, height: maxY2 - minY2 };
|
|
3604
|
+
}
|
|
3605
|
+
function hasTFBBox(el) {
|
|
3606
|
+
return hasBBoxAffectingTransform(el);
|
|
3607
|
+
}
|
|
3340
3608
|
function matrixFromComputed(el) {
|
|
3341
3609
|
const tr = getComputedStyle(el).transform;
|
|
3342
3610
|
if (!tr || tr === "none") return new DOMMatrix();
|
|
@@ -3478,7 +3746,7 @@
|
|
|
3478
3746
|
return "soft";
|
|
3479
3747
|
}
|
|
3480
3748
|
function createContext(options = {}) {
|
|
3481
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r;
|
|
3749
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t;
|
|
3482
3750
|
const resolvedFormat = (_a = options.format) != null ? _a : "png";
|
|
3483
3751
|
const cachePolicy = normalizeCachePolicy(options.cache);
|
|
3484
3752
|
return {
|
|
@@ -3491,20 +3759,20 @@
|
|
|
3491
3759
|
excludeMode: (_f = options.excludeMode) != null ? _f : "hide",
|
|
3492
3760
|
filter: (_g = options.filter) != null ? _g : null,
|
|
3493
3761
|
filterMode: (_h = options.filterMode) != null ? _h : "hide",
|
|
3762
|
+
// Placeholders
|
|
3494
3763
|
placeholders: options.placeholders !== false,
|
|
3495
3764
|
// default true
|
|
3496
|
-
//
|
|
3765
|
+
// Fonts
|
|
3497
3766
|
embedFonts: (_i = options.embedFonts) != null ? _i : false,
|
|
3498
3767
|
iconFonts: Array.isArray(options.iconFonts) ? options.iconFonts : options.iconFonts ? [options.iconFonts] : [],
|
|
3499
3768
|
localFonts: Array.isArray(options.localFonts) ? options.localFonts : [],
|
|
3500
3769
|
excludeFonts: (_j = options.excludeFonts) != null ? _j : void 0,
|
|
3501
3770
|
fallbackURL: (_k = options.fallbackURL) != null ? _k : void 0,
|
|
3502
|
-
/** Cache policy (disabled|full|auto|soft). Default: "soft" */
|
|
3503
3771
|
/** @type {CachePolicy} */
|
|
3504
3772
|
cache: cachePolicy,
|
|
3505
|
-
//
|
|
3773
|
+
// Network
|
|
3506
3774
|
useProxy: typeof options.useProxy === "string" ? options.useProxy : "",
|
|
3507
|
-
//
|
|
3775
|
+
// Output
|
|
3508
3776
|
width: (_l = options.width) != null ? _l : null,
|
|
3509
3777
|
height: (_m = options.height) != null ? _m : null,
|
|
3510
3778
|
format: resolvedFormat,
|
|
@@ -3512,8 +3780,11 @@
|
|
|
3512
3780
|
quality: (_o = options.quality) != null ? _o : 0.92,
|
|
3513
3781
|
dpr: (_p = options.dpr) != null ? _p : window.devicePixelRatio || 1,
|
|
3514
3782
|
backgroundColor: (_q = options.backgroundColor) != null ? _q : ["jpg", "jpeg", "webp"].includes(resolvedFormat) ? "#ffffff" : null,
|
|
3515
|
-
filename: (_r = options.filename) != null ? _r : "snapDOM"
|
|
3516
|
-
//
|
|
3783
|
+
filename: (_r = options.filename) != null ? _r : "snapDOM",
|
|
3784
|
+
// NEW flags (user-friendly)
|
|
3785
|
+
straighten: (_s = options.straighten) != null ? _s : false,
|
|
3786
|
+
noShadows: (_t = options.noShadows) != null ? _t : false
|
|
3787
|
+
// Plugins (reservado)
|
|
3517
3788
|
// plugins: normalizePlugins(...),
|
|
3518
3789
|
};
|
|
3519
3790
|
}
|
|
@@ -3708,9 +3979,20 @@
|
|
|
3708
3979
|
const k = height / Math.max(1, refH);
|
|
3709
3980
|
img.style.height = `${height}px`;
|
|
3710
3981
|
img.style.width = `${Math.round(refW * k)}px`;
|
|
3711
|
-
} else
|
|
3712
|
-
|
|
3713
|
-
|
|
3982
|
+
} else {
|
|
3983
|
+
const cssW = Math.round(img.naturalWidth * scale);
|
|
3984
|
+
const cssH = Math.round(img.naturalHeight * scale);
|
|
3985
|
+
img.style.width = `${cssW}px`;
|
|
3986
|
+
img.style.height = `${cssH}px`;
|
|
3987
|
+
if (typeof url === "string" && url.startsWith("data:image/svg+xml")) {
|
|
3988
|
+
try {
|
|
3989
|
+
const decoded = decodeURIComponent(url.split(",")[1]);
|
|
3990
|
+
const patched = decoded.replace(/width="[^"]*"/, `width="${cssW}"`).replace(/height="[^"]*"/, `height="${cssH}"`);
|
|
3991
|
+
url = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(patched)}`;
|
|
3992
|
+
img.src = url;
|
|
3993
|
+
} catch (e) {
|
|
3994
|
+
}
|
|
3995
|
+
}
|
|
3714
3996
|
}
|
|
3715
3997
|
return img;
|
|
3716
3998
|
});
|
|
@@ -3772,7 +4054,7 @@
|
|
|
3772
4054
|
yield safariWarmup(element, userOptions);
|
|
3773
4055
|
console.log("Iteraci\xF3n n\xFAmero:", i);
|
|
3774
4056
|
_safariWarmup = false;
|
|
3775
|
-
} catch (
|
|
4057
|
+
} catch (e) {
|
|
3776
4058
|
}
|
|
3777
4059
|
}
|
|
3778
4060
|
}
|
|
@@ -3780,7 +4062,7 @@
|
|
|
3780
4062
|
if (!context.snap) {
|
|
3781
4063
|
context.snap = {
|
|
3782
4064
|
toPng: (el, opts) => snapdom.toPng(el, opts),
|
|
3783
|
-
|
|
4065
|
+
toSvg: (el, opts) => snapdom.toSvg(el, opts)
|
|
3784
4066
|
};
|
|
3785
4067
|
}
|
|
3786
4068
|
return snapdom.capture(element, context, INTERNAL_TOKEN);
|
|
@@ -3803,6 +4085,7 @@
|
|
|
3803
4085
|
url,
|
|
3804
4086
|
toRaw: () => url,
|
|
3805
4087
|
toImg: (opts) => toImg(url, ensureContext(opts)),
|
|
4088
|
+
toSvg: (opts) => toImg(url, ensureContext(opts)),
|
|
3806
4089
|
toCanvas: (opts) => toCanvas(url, ensureContext(opts)),
|
|
3807
4090
|
toBlob: (opts) => toBlob(url, ensureContext(opts)),
|
|
3808
4091
|
toPng: withFormat("png"),
|
|
@@ -3813,6 +4096,7 @@
|
|
|
3813
4096
|
});
|
|
3814
4097
|
snapdom.toRaw = (el, options) => snapdom(el, options).then((result) => result.toRaw());
|
|
3815
4098
|
snapdom.toImg = (el, options) => snapdom(el, options).then((result) => result.toImg());
|
|
4099
|
+
snapdom.toSvg = (el, options) => snapdom(el, options).then((result) => result.toSvg());
|
|
3816
4100
|
snapdom.toCanvas = (el, options) => snapdom(el, options).then((result) => result.toCanvas());
|
|
3817
4101
|
snapdom.toBlob = (el, options) => snapdom(el, options).then((result) => result.toBlob());
|
|
3818
4102
|
snapdom.toPng = (el, options) => snapdom(el, __spreadProps(__spreadValues({}, options), { format: "png" })).then((result) => result.toPng());
|
|
@@ -3954,7 +4238,7 @@
|
|
|
3954
4238
|
const families = new Set(
|
|
3955
4239
|
Array.from(required).map((k) => String(k).split("__")[0]).filter(Boolean)
|
|
3956
4240
|
);
|
|
3957
|
-
yield ensureFontsReady(families,
|
|
4241
|
+
yield ensureFontsReady(families, 3);
|
|
3958
4242
|
}
|
|
3959
4243
|
yield embedCustomFonts({
|
|
3960
4244
|
required,
|