@pixldocs/canvas-renderer 0.4.3 → 0.4.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -2577,13 +2577,23 @@ const clearFabricCharCache = () => {
2577
2577
  };
2578
2578
  const clearFontCacheAndRerender = (canvas) => {
2579
2579
  clearFabricCharCache();
2580
- canvas.getObjects().forEach((obj) => {
2580
+ const fixTextbox = (obj) => {
2581
+ var _a;
2581
2582
  if (obj instanceof fabric__namespace.Textbox) {
2583
+ const savedWidth = obj.width;
2582
2584
  obj.dirty = true;
2583
2585
  obj.initDimensions();
2586
+ if (savedWidth != null && Math.abs((obj.width ?? 0) - savedWidth) > 0.01) {
2587
+ obj.width = savedWidth;
2588
+ }
2589
+ obj.setCoords();
2590
+ } else if (obj instanceof fabric__namespace.Group) {
2591
+ (_a = obj._objects) == null ? void 0 : _a.forEach(fixTextbox);
2592
+ obj.dirty = true;
2584
2593
  obj.setCoords();
2585
2594
  }
2586
- });
2595
+ };
2596
+ canvas.getObjects().forEach(fixTextbox);
2587
2597
  canvas.requestRenderAll();
2588
2598
  };
2589
2599
  const ensureFontLoaded = async (fontFamily) => {
@@ -11890,8 +11900,47 @@ async function embedFontsForConfig(pdf, config, fontBaseUrl) {
11890
11900
  console.log(`[pdf-fonts] Embedded ${embedded.size} font variants from config`);
11891
11901
  return embedded;
11892
11902
  }
11903
+ function isDevanagari(char) {
11904
+ const c = char.codePointAt(0) ?? 0;
11905
+ return c >= 2304 && c <= 2431 || c >= 43232 && c <= 43263 || c >= 7376 && c <= 7423;
11906
+ }
11907
+ function containsDevanagari(text) {
11908
+ if (!text) return false;
11909
+ for (const char of text) {
11910
+ if (isDevanagari(char)) return true;
11911
+ }
11912
+ return false;
11913
+ }
11914
+ function isBasicLatinOrLatin1(char) {
11915
+ const c = char.codePointAt(0) ?? 0;
11916
+ return c <= 591;
11917
+ }
11918
+ function classifyChar(char) {
11919
+ if (isBasicLatinOrLatin1(char)) return "main";
11920
+ if (isDevanagari(char)) return "devanagari";
11921
+ return "symbol";
11922
+ }
11923
+ function splitIntoRuns(text) {
11924
+ if (!text) return [];
11925
+ const runs = [];
11926
+ let currentType = null;
11927
+ let currentText = "";
11928
+ for (const char of text) {
11929
+ const type = classifyChar(char);
11930
+ if (type !== currentType && currentText) {
11931
+ runs.push({ text: currentText, runType: currentType });
11932
+ currentText = "";
11933
+ }
11934
+ currentType = type;
11935
+ currentText += char;
11936
+ }
11937
+ if (currentText && currentType) {
11938
+ runs.push({ text: currentText, runType: currentType });
11939
+ }
11940
+ return runs;
11941
+ }
11893
11942
  function rewriteSvgFontsForJsPDF(svgStr) {
11894
- var _a;
11943
+ var _a, _b;
11895
11944
  const parser = new DOMParser();
11896
11945
  const doc = parser.parseFromString(svgStr, "image/svg+xml");
11897
11946
  const textEls = doc.querySelectorAll("text, tspan, textPath");
@@ -11912,6 +11961,17 @@ function rewriteSvgFontsForJsPDF(svgStr) {
11912
11961
  }
11913
11962
  return null;
11914
11963
  };
11964
+ const resolveWeightNum = (weightRaw) => {
11965
+ const parsedWeight = Number.parseInt(weightRaw, 10);
11966
+ return Number.isFinite(parsedWeight) ? parsedWeight : /bold/i.test(weightRaw) ? 700 : /medium/i.test(weightRaw) ? 500 : /semi/i.test(weightRaw) ? 600 : /light/i.test(weightRaw) ? 300 : 400;
11967
+ };
11968
+ const buildStyleString = (existingStyle, fontName) => {
11969
+ const stylePairs = existingStyle.split(";").map((part) => part.trim()).filter(Boolean).filter((part) => !/^font-family\s*:/i.test(part) && !/^font-weight\s*:/i.test(part) && !/^font-style\s*:/i.test(part));
11970
+ stylePairs.push(`font-family: ${fontName}`);
11971
+ stylePairs.push(`font-weight: normal`);
11972
+ stylePairs.push(`font-style: normal`);
11973
+ return stylePairs.join("; ");
11974
+ };
11915
11975
  for (const el of textEls) {
11916
11976
  const inlineStyle = el.getAttribute("style") || "";
11917
11977
  const rawFf = resolveInheritedValue(el, "font-family");
@@ -11920,19 +11980,50 @@ function rewriteSvgFontsForJsPDF(svgStr) {
11920
11980
  if (!isFontAvailable(clean)) continue;
11921
11981
  const weightRaw = resolveInheritedValue(el, "font-weight") || "400";
11922
11982
  const styleRaw = resolveInheritedValue(el, "font-style") || "normal";
11923
- const parsedWeight = Number.parseInt(weightRaw, 10);
11924
- const weight = Number.isFinite(parsedWeight) ? parsedWeight : /bold/i.test(weightRaw) ? 700 : /medium/i.test(weightRaw) ? 500 : /semi/i.test(weightRaw) ? 600 : /light/i.test(weightRaw) ? 300 : 400;
11983
+ const weight = resolveWeightNum(weightRaw);
11925
11984
  const resolved = resolveFontWeight(weight);
11926
11985
  const isItalic = /italic|oblique/i.test(styleRaw);
11927
11986
  const jsPdfName = getEmbeddedJsPDFFontName(clean, resolved, isItalic);
11928
- el.setAttribute("font-family", jsPdfName);
11929
- el.setAttribute("font-weight", "normal");
11930
- el.setAttribute("font-style", "normal");
11931
- const stylePairs = inlineStyle.split(";").map((part) => part.trim()).filter(Boolean).filter((part) => !/^font-family\s*:/i.test(part) && !/^font-weight\s*:/i.test(part) && !/^font-style\s*:/i.test(part));
11932
- stylePairs.push(`font-family: ${jsPdfName}`);
11933
- stylePairs.push(`font-weight: normal`);
11934
- stylePairs.push(`font-style: normal`);
11935
- el.setAttribute("style", stylePairs.join("; "));
11987
+ const directText = Array.from(el.childNodes).filter((n) => n.nodeType === 3).map((n) => n.textContent || "").join("");
11988
+ const hasDevanagari = containsDevanagari(directText);
11989
+ if (hasDevanagari && directText.length > 0) {
11990
+ const devanagariWeight = resolveFontWeight(weight);
11991
+ const devanagariJsPdfName = getEmbeddedJsPDFFontName(FONT_FALLBACK_DEVANAGARI, devanagariWeight);
11992
+ const symbolJsPdfName = isFontAvailable(FONT_FALLBACK_SYMBOLS) ? getEmbeddedJsPDFFontName(FONT_FALLBACK_SYMBOLS, 400) : jsPdfName;
11993
+ const childNodes = Array.from(el.childNodes);
11994
+ for (const node of childNodes) {
11995
+ if (node.nodeType !== 3 || !node.textContent) continue;
11996
+ const runs = splitIntoRuns(node.textContent);
11997
+ if (runs.length <= 1 && ((_b = runs[0]) == null ? void 0 : _b.runType) !== "devanagari") continue;
11998
+ const fragment = doc.createDocumentFragment();
11999
+ for (const run of runs) {
12000
+ const tspan = doc.createElementNS("http://www.w3.org/2000/svg", "tspan");
12001
+ let runFont;
12002
+ if (run.runType === "devanagari") {
12003
+ runFont = devanagariJsPdfName;
12004
+ } else if (run.runType === "symbol") {
12005
+ runFont = symbolJsPdfName;
12006
+ } else {
12007
+ runFont = jsPdfName;
12008
+ }
12009
+ tspan.setAttribute("font-family", runFont);
12010
+ tspan.setAttribute("font-weight", "normal");
12011
+ tspan.setAttribute("font-style", "normal");
12012
+ tspan.textContent = run.text;
12013
+ fragment.appendChild(tspan);
12014
+ }
12015
+ el.replaceChild(fragment, node);
12016
+ }
12017
+ el.setAttribute("font-family", jsPdfName);
12018
+ el.setAttribute("font-weight", "normal");
12019
+ el.setAttribute("font-style", "normal");
12020
+ el.setAttribute("style", buildStyleString(inlineStyle, jsPdfName));
12021
+ } else {
12022
+ el.setAttribute("font-family", jsPdfName);
12023
+ el.setAttribute("font-weight", "normal");
12024
+ el.setAttribute("font-style", "normal");
12025
+ el.setAttribute("style", buildStyleString(inlineStyle, jsPdfName));
12026
+ }
11936
12027
  }
11937
12028
  return new XMLSerializer().serializeToString(doc.documentElement);
11938
12029
  }