@pixldocs/canvas-renderer 0.5.155 → 0.5.157

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svgTextToPath-7fhL08qs.cjs","sources":["../../../src/lib/pdfFonts.ts","../../../src/lib/harfbuzzShaper.ts","../../../src/lib/svgTextToPath.ts"],"sourcesContent":["// Utility for loading local TTF fonts into jsPDF for vector PDF rendering\n\nconst fontCache: Map<string, string> = new Map();\n/** Cache for raw font bytes (used by HarfBuzz / opentype.js for path conversion) */\nconst fontBytesCache: Map<string, Uint8Array> = new Map();\n/** Cache for Google Fonts CSS-parsed TTF URLs (so we don't re-fetch CSS for every weight) */\nconst googleFontUrlCache: Map<string, string> = new Map();\n/** Negative cache — specific Google Font variants known not to exist; don't keep retrying */\nconst googleFontNotFound: Set<string> = new Set();\n/**\n * Negative cache for the Supabase font-proxy edge function. Once a specific\n * (family, weight, italic, source) tuple returns a non-OK / fallback response\n * we never probe again for the lifetime of this module — eliminates the\n * hundreds of 4xx/5xx requests in DevTools when a template references font\n * families that don't exist on Google Fonts or Fontshare.\n */\nconst proxyNotFound: Set<string> = new Set();\n/**\n * Family-level short-circuit cache. If the base (family, 400, upright) probe\n * fails on BOTH google and fontshare, the family doesn't exist on either CDN\n * — skip every subsequent weight/italic probe for the same family.\n */\nconst familyNotOnAnyCdn: Set<string> = new Set();\nconst familyConfirmedOnSomeCdn: Set<string> = new Set();\n\nconst proxyKey = (family: string, weight: number, isItalic: boolean, source: string): string =>\n `${source}|${family}|${weight}|${isItalic ? 'i' : 'n'}`;\n\n// ── localStorage persistence ──\n// Negative caches survive page reloads so the FIRST export of a new tab\n// doesn't pay the full font-probe ladder for families known to be missing\n// from previous sessions. Positive cache (`familyConfirmedOnSomeCdn`) is\n// also persisted so we can short-circuit \"family exists, only this variant\n// is missing\" decisions without a probe.\nconst LS_KEY = 'pdfFonts.negCache.v1';\nconst LS_VERSION = 1;\nfunction loadPersistedCaches(): void {\n try {\n if (typeof localStorage === 'undefined') return;\n const raw = localStorage.getItem(LS_KEY);\n if (!raw) return;\n const obj = JSON.parse(raw);\n if (!obj || obj.v !== LS_VERSION) return;\n (obj.proxyNotFound || []).forEach((k: string) => proxyNotFound.add(k));\n (obj.familyNotOnAnyCdn || []).forEach((k: string) => familyNotOnAnyCdn.add(k));\n (obj.familyConfirmedOnSomeCdn || []).forEach((k: string) => familyConfirmedOnSomeCdn.add(k));\n } catch { /* ignore corrupt cache */ }\n}\nlet persistTimer: any = null;\nfunction persistCaches(): void {\n try {\n if (typeof localStorage === 'undefined') return;\n if (persistTimer) clearTimeout(persistTimer);\n persistTimer = setTimeout(() => {\n try {\n localStorage.setItem(LS_KEY, JSON.stringify({\n v: LS_VERSION,\n proxyNotFound: Array.from(proxyNotFound),\n familyNotOnAnyCdn: Array.from(familyNotOnAnyCdn),\n familyConfirmedOnSomeCdn: Array.from(familyConfirmedOnSomeCdn),\n }));\n } catch { /* quota exceeded — ignore */ }\n }, 250);\n } catch { /* ignore */ }\n}\nloadPersistedCaches();\n\n/** Force-clear all negative caches (useful for debugging). Not called automatically. */\nexport const resetPdfFontProbeCaches = (): void => {\n proxyNotFound.clear();\n familyNotOnAnyCdn.clear();\n familyConfirmedOnSomeCdn.clear();\n googleFontNotFound.clear();\n try { if (typeof localStorage !== 'undefined') localStorage.removeItem(LS_KEY); } catch {}\n};\n/** Runtime registry of families successfully embedded into the active jsPDF bundle. */\nconst registeredFamilies: Set<string> = new Set();\n/** Runtime glyph coverage for each embedded (family, weight, italic) variant. */\nconst registeredVariantCoverage: Map<string, Set<number>> = new Map();\n\nexport const isFamilyEmbedded = (family: string): boolean => registeredFamilies.has(family);\n\n/**\n * Per-variant registry: which (family, weight, italic) tuples were actually\n * registered into the active jsPDF document. The SVG rewriter uses this to\n * avoid emitting a font-family like \"DMSerifDisplay-Bold\" when only the\n * Regular variant was embedded — emitting an unregistered name causes jsPDF\n * to silently fall back to Helvetica, breaking visual font parity with the\n * canvas preview.\n */\nconst registeredVariants: Set<string> = new Set();\n\nconst variantKey = (family: string, weight: number, italic: boolean): string =>\n `${family}|${weight}|${italic ? 'i' : 'n'}`;\n\nconst remoteVariantKey = (family: string, weight: number, italic: boolean): string =>\n `${family}|${resolveFontWeight(weight)}|${italic ? 'i' : 'n'}`;\n\nexport const resetPdfFontRegistry = (): void => {\n registeredFamilies.clear();\n registeredVariants.clear();\n registeredVariantCoverage.clear();\n};\n\nexport const isVariantEmbedded = (family: string, weight: number, italic: boolean): boolean =>\n registeredVariants.has(variantKey(family, resolveFontWeight(weight), italic));\n\n/**\n * Diagnostic: returns the sorted list of (family, weight, italic) variants\n * that were actually registered into the active jsPDF document. Useful for\n * comparing client vs server embed sets to diagnose file-size diffs.\n */\nexport const getEmbeddedVariantsList = (): string[] => {\n return Array.from(registeredVariants).sort();\n};\n\nexport const doesVariantSupportChar = (\n family: string,\n weight: number,\n italic: boolean,\n char: string,\n): boolean => {\n const cp = char.codePointAt(0);\n if (cp == null) return false;\n return registeredVariantCoverage.get(variantKey(family, resolveFontWeight(weight), italic))?.has(cp) === true;\n};\n\n/**\n * Pick the closest registered (weight, italic) variant for a family. Used by\n * the SVG-to-jsPDF rewriter when the requested exact variant isn't embedded\n * (e.g. user requested Bold but the family has no real Bold and Google's\n * fallback fetch returned 404). Returns null if the family has no registered\n * variants at all.\n */\nexport const resolveBestRegisteredVariant = (\n family: string,\n weight: number,\n italic: boolean,\n): { weight: number; italic: boolean } | null => {\n const want = resolveFontWeight(weight);\n const weights = [300, 400, 500, 600, 700];\n // 1. Exact match\n if (registeredVariants.has(variantKey(family, want, italic))) {\n return { weight: want, italic };\n }\n // 2. Same italic, nearest weight (prefer heavier when bold requested)\n const sortedByDistance = [...weights].sort((a, b) => {\n const da = Math.abs(a - want);\n const db = Math.abs(b - want);\n if (da !== db) return da - db;\n // tie: when wanting bold, prefer heavier; when wanting light, prefer lighter\n return want >= 500 ? b - a : a - b;\n });\n for (const w of sortedByDistance) {\n if (registeredVariants.has(variantKey(family, w, italic))) {\n return { weight: w, italic };\n }\n }\n // 3. Opposite italic, nearest weight\n for (const w of sortedByDistance) {\n if (registeredVariants.has(variantKey(family, w, !italic))) {\n return { weight: w, italic: !italic };\n }\n }\n return null;\n};\n\n// Server-side font proxy: needed because the browser sends modern UA hints\n// (sec-ch-ua) that override our custom User-Agent header, so Google Fonts\n// returns WOFF2 instead of TTF. The edge function spoofs a legacy UA and\n// returns embeddable TTF bytes for any Google Font / Fontshare family.\n//\n// Resolved LAZILY so this module works in two contexts:\n// 1. Client app — reads `import.meta.env.VITE_SUPABASE_URL` at build time.\n// 2. Server harness (`@pixldocs/canvas-renderer` browser bundle running\n// inside Puppeteer on EC2) — Vite does NOT inline VITE_SUPABASE_URL into\n// that standalone bundle, so we fall back to `window.__PIXLDOCS_SUPABASE_URL`,\n// which the harness HTML sets from the request payload before running.\nfunction resolveFontProxyUrl(): string {\n const fromEnv = (() => {\n try {\n return (import.meta as any).env?.VITE_SUPABASE_URL ?? '';\n } catch {\n return '';\n }\n })();\n const fromWindow = (() => {\n try {\n return (typeof window !== 'undefined' && (window as any).__PIXLDOCS_SUPABASE_URL) || '';\n } catch {\n return '';\n }\n })();\n const base = fromEnv || fromWindow || '';\n return base ? `${base}/functions/v1/font-proxy` : '';\n}\n\nasync function fetchTtfViaProxy(\n family: string,\n weight: number,\n isItalic: boolean,\n source: 'google' | 'fontshare',\n): Promise<Uint8Array | null> {\n const proxyUrl = resolveFontProxyUrl();\n if (!proxyUrl) return null;\n // Negative caches — skip probes that previously failed.\n const key = proxyKey(family, weight, isItalic, source);\n if (proxyNotFound.has(key)) return null;\n // Family short-circuit: if base variant failed on every CDN, skip everything.\n if (familyNotOnAnyCdn.has(family)) return null;\n try {\n const url = `${proxyUrl}?family=${encodeURIComponent(family)}&weight=${weight}&italic=${isItalic ? 1 : 0}&source=${source}`;\n const res = await fetch(url);\n if (!res.ok) {\n proxyNotFound.add(key);\n persistCaches();\n return null;\n }\n // Edge function may now return 200 + JSON `{fallback:true}` for upstream\n // misses (so DevTools doesn't flash red on every probe). Detect that\n // shape via Content-Type and treat as a miss.\n const ct = res.headers.get('content-type') || '';\n if (ct.startsWith('application/json')) {\n try {\n const j = await res.json();\n if (j && (j.fallback || j.error)) proxyNotFound.add(key);\n } catch {\n proxyNotFound.add(key);\n }\n persistCaches();\n return null;\n }\n const buf = await res.arrayBuffer();\n const bytes = new Uint8Array(buf);\n if (bytes.byteLength < 64) {\n proxyNotFound.add(key);\n persistCaches();\n return null;\n }\n familyConfirmedOnSomeCdn.add(family);\n persistCaches();\n return bytes;\n } catch {\n proxyNotFound.add(key);\n persistCaches();\n return null;\n }\n}\n\n/**\n * Probe the base (family, 400, upright) variant on both Google and Fontshare\n * before fetching every weight/italic combination. If both miss, mark the\n * family as missing so all subsequent variant probes are skipped.\n * Returns true if the family is available on at least one CDN.\n */\nexport async function familyProbe(family: string): Promise<boolean> {\n if (familyConfirmedOnSomeCdn.has(family)) return true;\n if (familyNotOnAnyCdn.has(family)) return false;\n // Reuse fetchTtfViaProxy for the base probe — populates negative caches and\n // the bytes cache as a side-effect, so the subsequent 400-regular embed\n // doesn't re-fetch.\n const g = await fetchTtfViaProxy(family, 400, false, 'google');\n if (g) return true;\n const f = await fetchTtfViaProxy(family, 400, false, 'fontshare');\n if (f) return true;\n familyNotOnAnyCdn.add(family);\n return false;\n}\n\n// Weight labels for jsPDF font names (editor uses 300, 400, 500, 600, 700)\nexport const FONT_WEIGHT_LABELS: Record<number, string> = {\n 300: 'Light',\n 400: 'Regular',\n 500: 'Medium',\n 600: 'SemiBold',\n 700: 'Bold',\n};\n\n// Resolve numeric weight to the closest supported key (300, 400, 500, 600, 700)\nexport function resolveFontWeight(weight: number): number {\n if (weight <= 350) return 300;\n if (weight <= 450) return 400;\n if (weight <= 550) return 500;\n if (weight <= 650) return 600;\n return 700;\n}\n\n// Font file mapping - maps font names to optional weight-specific TTF paths\nexport type FontWeightFiles = {\n regular: string;\n bold?: string;\n light?: string;\n medium?: string;\n semibold?: string;\n // Italic variants\n italic?: string;\n boldItalic?: string;\n lightItalic?: string;\n mediumItalic?: string;\n semiboldItalic?: string;\n};\n\n/** Font used for symbols (● ◆ ★ etc.) when the main font lacks the glyph. Must be in FONT_FILES. */\nexport const FONT_FALLBACK_SYMBOLS = 'Noto Sans';\n\n/** Tertiary fallback for math operators / arrows (≠ ≤ ≥ ≈ ∞ → ← × ÷ ∑ √ ∈ …)\n * that are not present in the main font OR in FONT_FALLBACK_SYMBOLS. Must be in FONT_FILES. */\nexport const FONT_FALLBACK_MATH = 'Noto Sans Math';\n\n/** Font used for Devanagari / Hindi script when the main font lacks the glyphs. Must be in FONT_FILES. */\nexport const FONT_FALLBACK_DEVANAGARI = 'Hind';\n\n// List paths under public/fonts.\n// All entries now use static (per-weight) TTF files for reliable PDF export.\n// Variable font files are kept in fonts.css for browser rendering only.\nexport const FONT_FILES: Record<string, FontWeightFiles> = {\n 'Playfair Display': {\n regular: '/fonts/PlayfairDisplay-Regular.ttf',\n bold: '/fonts/PlayfairDisplay-Bold.ttf',\n italic: '/fonts/PlayfairDisplay-Italic.ttf',\n boldItalic: '/fonts/PlayfairDisplay-BoldItalic.ttf',\n },\n 'Merriweather': {\n regular: '/fonts/Merriweather-Regular.ttf',\n bold: '/fonts/Merriweather-Bold.ttf',\n light: '/fonts/Merriweather-Light.ttf',\n italic: '/fonts/Merriweather-Italic.ttf',\n boldItalic: '/fonts/Merriweather-BoldItalic.ttf',\n lightItalic: '/fonts/Merriweather-LightItalic.ttf',\n },\n 'Lora': {\n regular: '/fonts/Lora-Regular.ttf',\n bold: '/fonts/Lora-Bold.ttf',\n italic: '/fonts/Lora-Italic.ttf',\n boldItalic: '/fonts/Lora-BoldItalic.ttf',\n },\n 'Montserrat': {\n regular: '/fonts/Montserrat-Regular.ttf',\n bold: '/fonts/Montserrat-Bold.ttf',\n light: '/fonts/Montserrat-Light.ttf',\n medium: '/fonts/Montserrat-Medium.ttf',\n semibold: '/fonts/Montserrat-SemiBold.ttf',\n italic: '/fonts/Montserrat-Italic.ttf',\n boldItalic: '/fonts/Montserrat-BoldItalic.ttf',\n lightItalic: '/fonts/Montserrat-LightItalic.ttf',\n mediumItalic: '/fonts/Montserrat-MediumItalic.ttf',\n semiboldItalic: '/fonts/Montserrat-SemiBoldItalic.ttf',\n },\n 'Open Sans': {\n regular: '/fonts/OpenSans-Regular.ttf',\n bold: '/fonts/OpenSans-Bold.ttf',\n light: '/fonts/OpenSans-Light.ttf',\n semibold: '/fonts/OpenSans-SemiBold.ttf',\n italic: '/fonts/OpenSans-Italic.ttf',\n boldItalic: '/fonts/OpenSans-BoldItalic.ttf',\n lightItalic: '/fonts/OpenSans-LightItalic.ttf',\n semiboldItalic: '/fonts/OpenSans-SemiBoldItalic.ttf',\n },\n 'Roboto': {\n regular: '/fonts/Roboto-Regular.ttf',\n bold: '/fonts/Roboto-Bold.ttf',\n light: '/fonts/Roboto-Light.ttf',\n medium: '/fonts/Roboto-Medium.ttf',\n italic: '/fonts/Roboto-Italic.ttf',\n boldItalic: '/fonts/Roboto-BoldItalic.ttf',\n lightItalic: '/fonts/Roboto-LightItalic.ttf',\n mediumItalic: '/fonts/Roboto-MediumItalic.ttf',\n },\n 'Lato': {\n regular: '/fonts/Lato-Regular.ttf',\n bold: '/fonts/Lato-Bold.ttf',\n light: '/fonts/Lato-Light.ttf',\n italic: '/fonts/Lato-Italic.ttf',\n boldItalic: '/fonts/Lato-BoldItalic.ttf',\n lightItalic: '/fonts/Lato-LightItalic.ttf',\n },\n 'Raleway': {\n regular: '/fonts/Raleway-Regular.ttf',\n bold: '/fonts/Raleway-Bold.ttf',\n light: '/fonts/Raleway-Light.ttf',\n medium: '/fonts/Raleway-Medium.ttf',\n semibold: '/fonts/Raleway-SemiBold.ttf',\n italic: '/fonts/Raleway-Italic.ttf',\n boldItalic: '/fonts/Raleway-BoldItalic.ttf',\n lightItalic: '/fonts/Raleway-LightItalic.ttf',\n },\n 'Poppins': {\n regular: '/fonts/Poppins-Regular.ttf',\n bold: '/fonts/Poppins-Bold.ttf',\n light: '/fonts/Poppins-Light.ttf',\n medium: '/fonts/Poppins-Medium.ttf',\n semibold: '/fonts/Poppins-SemiBold.ttf',\n italic: '/fonts/Poppins-Italic.ttf',\n boldItalic: '/fonts/Poppins-BoldItalic.ttf',\n lightItalic: '/fonts/Poppins-LightItalic.ttf',\n mediumItalic: '/fonts/Poppins-MediumItalic.ttf',\n semiboldItalic: '/fonts/Poppins-SemiBoldItalic.ttf',\n },\n 'Inter': {\n regular: '/fonts/Inter-Regular.ttf',\n bold: '/fonts/Inter-Bold.ttf',\n italic: '/fonts/Inter-Italic.ttf',\n boldItalic: '/fonts/Inter-BoldItalic.ttf',\n },\n 'Nunito': {\n regular: '/fonts/Nunito-Regular.ttf',\n bold: '/fonts/Nunito-Bold.ttf',\n light: '/fonts/Nunito-Light.ttf',\n medium: '/fonts/Nunito-Medium.ttf',\n semibold: '/fonts/Nunito-SemiBold.ttf',\n italic: '/fonts/Nunito-Italic.ttf',\n boldItalic: '/fonts/Nunito-BoldItalic.ttf',\n },\n 'Source Sans Pro': {\n regular: '/fonts/SourceSansPro-Regular.ttf',\n bold: '/fonts/SourceSansPro-Bold.ttf',\n light: '/fonts/SourceSansPro-Light.ttf',\n italic: '/fonts/SourceSansPro-Italic.ttf',\n boldItalic: '/fonts/SourceSansPro-BoldItalic.ttf',\n },\n 'Work Sans': {\n regular: '/fonts/WorkSans-Regular.ttf',\n bold: '/fonts/WorkSans-Bold.ttf',\n italic: '/fonts/WorkSans-Italic.ttf',\n boldItalic: '/fonts/WorkSans-BoldItalic.ttf',\n },\n 'Oswald': { regular: '/fonts/Oswald-Regular.ttf', bold: '/fonts/Oswald-Bold.ttf' },\n 'Bebas Neue': { regular: '/fonts/BebasNeue-Regular.ttf' },\n 'Abril Fatface': { regular: '/fonts/AbrilFatface-Regular.ttf' },\n 'Dancing Script': { regular: '/fonts/DancingScript-Regular.ttf', bold: '/fonts/DancingScript-Bold.ttf' },\n 'Pacifico': { regular: '/fonts/Pacifico-Regular.ttf' },\n 'Great Vibes': { regular: '/fonts/GreatVibes-Regular.ttf' },\n\n // ── Previously variable-only fonts — now with static per-weight TTFs for PDF export ──\n 'DM Sans': {\n regular: '/fonts/DMSans-Regular.ttf',\n bold: '/fonts/DMSans-Bold.ttf',\n light: '/fonts/DMSans-Light.ttf',\n medium: '/fonts/DMSans-Medium.ttf',\n semibold: '/fonts/DMSans-SemiBold.ttf',\n italic: '/fonts/DMSans-RegularItalic.ttf',\n boldItalic: '/fonts/DMSans-BoldItalic.ttf',\n lightItalic: '/fonts/DMSans-LightItalic.ttf',\n mediumItalic: '/fonts/DMSans-MediumItalic.ttf',\n semiboldItalic: '/fonts/DMSans-SemiBoldItalic.ttf',\n },\n 'Outfit': {\n regular: '/fonts/Outfit-Regular.ttf',\n bold: '/fonts/Outfit-Bold.ttf',\n light: '/fonts/Outfit-Light.ttf',\n medium: '/fonts/Outfit-Medium.ttf',\n semibold: '/fonts/Outfit-SemiBold.ttf',\n },\n 'Figtree': {\n regular: '/fonts/Figtree-Regular.ttf',\n bold: '/fonts/Figtree-Bold.ttf',\n light: '/fonts/Figtree-Light.ttf',\n medium: '/fonts/Figtree-Medium.ttf',\n semibold: '/fonts/Figtree-SemiBold.ttf',\n italic: '/fonts/Figtree-RegularItalic.ttf',\n boldItalic: '/fonts/Figtree-BoldItalic.ttf',\n lightItalic: '/fonts/Figtree-LightItalic.ttf',\n mediumItalic: '/fonts/Figtree-MediumItalic.ttf',\n semiboldItalic: '/fonts/Figtree-SemiBoldItalic.ttf',\n },\n 'Manrope': {\n regular: '/fonts/Manrope-Regular.ttf',\n bold: '/fonts/Manrope-Bold.ttf',\n light: '/fonts/Manrope-Light.ttf',\n medium: '/fonts/Manrope-Medium.ttf',\n semibold: '/fonts/Manrope-SemiBold.ttf',\n },\n 'Space Grotesk': {\n regular: '/fonts/SpaceGrotesk-Regular.ttf',\n bold: '/fonts/SpaceGrotesk-Bold.ttf',\n light: '/fonts/SpaceGrotesk-Light.ttf',\n medium: '/fonts/SpaceGrotesk-Medium.ttf',\n semibold: '/fonts/SpaceGrotesk-SemiBold.ttf',\n },\n 'League Spartan': {\n regular: '/fonts/LeagueSpartan-Regular.ttf',\n bold: '/fonts/LeagueSpartan-Bold.ttf',\n light: '/fonts/LeagueSpartan-Light.ttf',\n medium: '/fonts/LeagueSpartan-Medium.ttf',\n semibold: '/fonts/LeagueSpartan-SemiBold.ttf',\n },\n 'EB Garamond': {\n regular: '/fonts/EBGaramond-Regular.ttf',\n bold: '/fonts/EBGaramond-Bold.ttf',\n medium: '/fonts/EBGaramond-Medium.ttf',\n semibold: '/fonts/EBGaramond-SemiBold.ttf',\n italic: '/fonts/EBGaramond-RegularItalic.ttf',\n boldItalic: '/fonts/EBGaramond-BoldItalic.ttf',\n mediumItalic: '/fonts/EBGaramond-MediumItalic.ttf',\n semiboldItalic: '/fonts/EBGaramond-SemiBoldItalic.ttf',\n },\n 'Libre Baskerville': {\n regular: '/fonts/LibreBaskerville-Regular.ttf',\n bold: '/fonts/LibreBaskerville-Bold.ttf',\n italic: '/fonts/LibreBaskerville-RegularItalic.ttf',\n boldItalic: '/fonts/LibreBaskerville-BoldItalic.ttf',\n },\n 'Crimson Text': {\n regular: '/fonts/CrimsonText-Regular.ttf',\n bold: '/fonts/CrimsonText-Bold.ttf',\n italic: '/fonts/CrimsonText-Italic.ttf',\n boldItalic: '/fonts/CrimsonText-BoldItalic.ttf',\n },\n 'DM Serif Display': {\n regular: '/fonts/DMSerifDisplay-Regular.ttf',\n italic: '/fonts/DMSerifDisplay-Italic.ttf',\n },\n 'Libre Franklin': {\n regular: '/fonts/LibreFranklin-Regular.ttf',\n bold: '/fonts/LibreFranklin-Bold.ttf',\n light: '/fonts/LibreFranklin-Light.ttf',\n medium: '/fonts/LibreFranklin-Medium.ttf',\n semibold: '/fonts/LibreFranklin-SemiBold.ttf',\n italic: '/fonts/LibreFranklin-RegularItalic.ttf',\n boldItalic: '/fonts/LibreFranklin-BoldItalic.ttf',\n lightItalic: '/fonts/LibreFranklin-LightItalic.ttf',\n mediumItalic: '/fonts/LibreFranklin-MediumItalic.ttf',\n semiboldItalic: '/fonts/LibreFranklin-SemiBoldItalic.ttf',\n },\n 'Mulish': {\n regular: '/fonts/Mulish-Regular.ttf',\n bold: '/fonts/Mulish-Bold.ttf',\n light: '/fonts/Mulish-Light.ttf',\n medium: '/fonts/Mulish-Medium.ttf',\n semibold: '/fonts/Mulish-SemiBold.ttf',\n italic: '/fonts/Mulish-RegularItalic.ttf',\n boldItalic: '/fonts/Mulish-BoldItalic.ttf',\n lightItalic: '/fonts/Mulish-LightItalic.ttf',\n mediumItalic: '/fonts/Mulish-MediumItalic.ttf',\n semiboldItalic: '/fonts/Mulish-SemiBoldItalic.ttf',\n },\n 'Quicksand': {\n regular: '/fonts/Quicksand-Regular.ttf',\n bold: '/fonts/Quicksand-Bold.ttf',\n light: '/fonts/Quicksand-Light.ttf',\n medium: '/fonts/Quicksand-Medium.ttf',\n semibold: '/fonts/Quicksand-SemiBold.ttf',\n },\n 'Rubik': {\n regular: '/fonts/Rubik-Regular.ttf',\n bold: '/fonts/Rubik-Bold.ttf',\n light: '/fonts/Rubik-Light.ttf',\n medium: '/fonts/Rubik-Medium.ttf',\n semibold: '/fonts/Rubik-SemiBold.ttf',\n italic: '/fonts/Rubik-RegularItalic.ttf',\n boldItalic: '/fonts/Rubik-BoldItalic.ttf',\n lightItalic: '/fonts/Rubik-LightItalic.ttf',\n mediumItalic: '/fonts/Rubik-MediumItalic.ttf',\n semiboldItalic: '/fonts/Rubik-SemiBoldItalic.ttf',\n },\n 'Karla': {\n regular: '/fonts/Karla-Regular.ttf',\n bold: '/fonts/Karla-Bold.ttf',\n light: '/fonts/Karla-Light.ttf',\n medium: '/fonts/Karla-Medium.ttf',\n semibold: '/fonts/Karla-SemiBold.ttf',\n italic: '/fonts/Karla-RegularItalic.ttf',\n boldItalic: '/fonts/Karla-BoldItalic.ttf',\n lightItalic: '/fonts/Karla-LightItalic.ttf',\n mediumItalic: '/fonts/Karla-MediumItalic.ttf',\n semiboldItalic: '/fonts/Karla-SemiBoldItalic.ttf',\n },\n 'Plus Jakarta Sans': {\n regular: '/fonts/PlusJakartaSans-Regular.ttf',\n bold: '/fonts/PlusJakartaSans-Bold.ttf',\n light: '/fonts/PlusJakartaSans-Light.ttf',\n medium: '/fonts/PlusJakartaSans-Medium.ttf',\n semibold: '/fonts/PlusJakartaSans-SemiBold.ttf',\n italic: '/fonts/PlusJakartaSans-RegularItalic.ttf',\n boldItalic: '/fonts/PlusJakartaSans-BoldItalic.ttf',\n lightItalic: '/fonts/PlusJakartaSans-LightItalic.ttf',\n mediumItalic: '/fonts/PlusJakartaSans-MediumItalic.ttf',\n semiboldItalic: '/fonts/PlusJakartaSans-SemiBoldItalic.ttf',\n },\n 'Sora': {\n regular: '/fonts/Sora-Regular.ttf',\n bold: '/fonts/Sora-Bold.ttf',\n light: '/fonts/Sora-Light.ttf',\n medium: '/fonts/Sora-Medium.ttf',\n semibold: '/fonts/Sora-SemiBold.ttf',\n },\n 'Urbanist': {\n regular: '/fonts/Urbanist-Regular.ttf',\n bold: '/fonts/Urbanist-Bold.ttf',\n light: '/fonts/Urbanist-Light.ttf',\n medium: '/fonts/Urbanist-Medium.ttf',\n semibold: '/fonts/Urbanist-SemiBold.ttf',\n italic: '/fonts/Urbanist-RegularItalic.ttf',\n boldItalic: '/fonts/Urbanist-BoldItalic.ttf',\n lightItalic: '/fonts/Urbanist-LightItalic.ttf',\n mediumItalic: '/fonts/Urbanist-MediumItalic.ttf',\n semiboldItalic: '/fonts/Urbanist-SemiBoldItalic.ttf',\n },\n 'Lexend': {\n regular: '/fonts/Lexend-Regular.ttf',\n bold: '/fonts/Lexend-Bold.ttf',\n light: '/fonts/Lexend-Light.ttf',\n medium: '/fonts/Lexend-Medium.ttf',\n semibold: '/fonts/Lexend-SemiBold.ttf',\n },\n 'Albert Sans': {\n regular: '/fonts/AlbertSans-Regular.ttf',\n bold: '/fonts/AlbertSans-Bold.ttf',\n light: '/fonts/AlbertSans-Light.ttf',\n medium: '/fonts/AlbertSans-Medium.ttf',\n semibold: '/fonts/AlbertSans-SemiBold.ttf',\n italic: '/fonts/AlbertSans-RegularItalic.ttf',\n boldItalic: '/fonts/AlbertSans-BoldItalic.ttf',\n lightItalic: '/fonts/AlbertSans-LightItalic.ttf',\n mediumItalic: '/fonts/AlbertSans-MediumItalic.ttf',\n semiboldItalic: '/fonts/AlbertSans-SemiBoldItalic.ttf',\n },\n 'Noto Sans': {\n regular: '/fonts/NotoSans-Regular.ttf',\n bold: '/fonts/NotoSans-Bold.ttf',\n light: '/fonts/NotoSans-Light.ttf',\n medium: '/fonts/NotoSans-Medium.ttf',\n semibold: '/fonts/NotoSans-SemiBold.ttf',\n italic: '/fonts/NotoSans-RegularItalic.ttf',\n boldItalic: '/fonts/NotoSans-BoldItalic.ttf',\n lightItalic: '/fonts/NotoSans-LightItalic.ttf',\n mediumItalic: '/fonts/NotoSans-MediumItalic.ttf',\n semiboldItalic: '/fonts/NotoSans-SemiBoldItalic.ttf',\n },\n 'Cabin': {\n regular: '/fonts/Cabin-Regular.ttf',\n bold: '/fonts/Cabin-Bold.ttf',\n medium: '/fonts/Cabin-Medium.ttf',\n semibold: '/fonts/Cabin-SemiBold.ttf',\n italic: '/fonts/Cabin-RegularItalic.ttf',\n boldItalic: '/fonts/Cabin-BoldItalic.ttf',\n mediumItalic: '/fonts/Cabin-MediumItalic.ttf',\n semiboldItalic: '/fonts/Cabin-SemiBoldItalic.ttf',\n },\n 'Barlow': {\n regular: '/fonts/Barlow-Regular.ttf',\n bold: '/fonts/Barlow-Bold.ttf',\n light: '/fonts/Barlow-Light.ttf',\n medium: '/fonts/Barlow-Medium.ttf',\n semibold: '/fonts/Barlow-SemiBold.ttf',\n italic: '/fonts/Barlow-Italic.ttf',\n boldItalic: '/fonts/Barlow-BoldItalic.ttf',\n },\n 'Josefin Sans': {\n regular: '/fonts/JosefinSans-Regular.ttf',\n bold: '/fonts/JosefinSans-Bold.ttf',\n light: '/fonts/JosefinSans-Light.ttf',\n medium: '/fonts/JosefinSans-Medium.ttf',\n semibold: '/fonts/JosefinSans-SemiBold.ttf',\n italic: '/fonts/JosefinSans-RegularItalic.ttf',\n boldItalic: '/fonts/JosefinSans-BoldItalic.ttf',\n lightItalic: '/fonts/JosefinSans-LightItalic.ttf',\n mediumItalic: '/fonts/JosefinSans-MediumItalic.ttf',\n semiboldItalic: '/fonts/JosefinSans-SemiBoldItalic.ttf',\n },\n 'Archivo': {\n regular: '/fonts/Archivo-Regular.ttf',\n bold: '/fonts/Archivo-Bold.ttf',\n light: '/fonts/Archivo-Light.ttf',\n medium: '/fonts/Archivo-Medium.ttf',\n semibold: '/fonts/Archivo-SemiBold.ttf',\n italic: '/fonts/Archivo-RegularItalic.ttf',\n boldItalic: '/fonts/Archivo-BoldItalic.ttf',\n lightItalic: '/fonts/Archivo-LightItalic.ttf',\n mediumItalic: '/fonts/Archivo-MediumItalic.ttf',\n semiboldItalic: '/fonts/Archivo-SemiBoldItalic.ttf',\n },\n 'Overpass': {\n regular: '/fonts/Overpass-Regular.ttf',\n bold: '/fonts/Overpass-Bold.ttf',\n light: '/fonts/Overpass-Light.ttf',\n medium: '/fonts/Overpass-Medium.ttf',\n semibold: '/fonts/Overpass-SemiBold.ttf',\n italic: '/fonts/Overpass-RegularItalic.ttf',\n boldItalic: '/fonts/Overpass-BoldItalic.ttf',\n lightItalic: '/fonts/Overpass-LightItalic.ttf',\n mediumItalic: '/fonts/Overpass-MediumItalic.ttf',\n semiboldItalic: '/fonts/Overpass-SemiBoldItalic.ttf',\n },\n 'Exo 2': {\n regular: '/fonts/Exo2-Regular.ttf',\n bold: '/fonts/Exo2-Bold.ttf',\n light: '/fonts/Exo2-Light.ttf',\n medium: '/fonts/Exo2-Medium.ttf',\n semibold: '/fonts/Exo2-SemiBold.ttf',\n italic: '/fonts/Exo2-RegularItalic.ttf',\n boldItalic: '/fonts/Exo2-BoldItalic.ttf',\n lightItalic: '/fonts/Exo2-LightItalic.ttf',\n mediumItalic: '/fonts/Exo2-MediumItalic.ttf',\n semiboldItalic: '/fonts/Exo2-SemiBoldItalic.ttf',\n },\n 'Roboto Mono': {\n regular: '/fonts/RobotoMono-Regular.ttf',\n bold: '/fonts/RobotoMono-Bold.ttf',\n light: '/fonts/RobotoMono-Light.ttf',\n medium: '/fonts/RobotoMono-Medium.ttf',\n semibold: '/fonts/RobotoMono-SemiBold.ttf',\n italic: '/fonts/RobotoMono-RegularItalic.ttf',\n boldItalic: '/fonts/RobotoMono-BoldItalic.ttf',\n lightItalic: '/fonts/RobotoMono-LightItalic.ttf',\n mediumItalic: '/fonts/RobotoMono-MediumItalic.ttf',\n semiboldItalic: '/fonts/RobotoMono-SemiBoldItalic.ttf',\n },\n 'Fira Code': {\n regular: '/fonts/FiraCode-Regular.ttf',\n bold: '/fonts/FiraCode-Bold.ttf',\n light: '/fonts/FiraCode-Light.ttf',\n medium: '/fonts/FiraCode-Medium.ttf',\n semibold: '/fonts/FiraCode-SemiBold.ttf',\n },\n 'JetBrains Mono': {\n regular: '/fonts/JetBrainsMono-Regular.ttf',\n bold: '/fonts/JetBrainsMono-Bold.ttf',\n light: '/fonts/JetBrainsMono-Light.ttf',\n medium: '/fonts/JetBrainsMono-Medium.ttf',\n semibold: '/fonts/JetBrainsMono-SemiBold.ttf',\n italic: '/fonts/JetBrainsMono-RegularItalic.ttf',\n boldItalic: '/fonts/JetBrainsMono-BoldItalic.ttf',\n lightItalic: '/fonts/JetBrainsMono-LightItalic.ttf',\n mediumItalic: '/fonts/JetBrainsMono-MediumItalic.ttf',\n semiboldItalic: '/fonts/JetBrainsMono-SemiBoldItalic.ttf',\n },\n 'Source Code Pro': {\n regular: '/fonts/SourceCodePro-Regular.ttf',\n bold: '/fonts/SourceCodePro-Bold.ttf',\n light: '/fonts/SourceCodePro-Light.ttf',\n medium: '/fonts/SourceCodePro-Medium.ttf',\n semibold: '/fonts/SourceCodePro-SemiBold.ttf',\n italic: '/fonts/SourceCodePro-RegularItalic.ttf',\n boldItalic: '/fonts/SourceCodePro-BoldItalic.ttf',\n lightItalic: '/fonts/SourceCodePro-LightItalic.ttf',\n mediumItalic: '/fonts/SourceCodePro-MediumItalic.ttf',\n semiboldItalic: '/fonts/SourceCodePro-SemiBoldItalic.ttf',\n },\n 'IBM Plex Mono': {\n regular: '/fonts/IBMPlexMono-Regular.ttf',\n bold: '/fonts/IBMPlexMono-Bold.ttf',\n },\n 'Space Mono': {\n regular: '/fonts/SpaceMono-Regular.ttf',\n bold: '/fonts/SpaceMono-Bold.ttf',\n italic: '/fonts/SpaceMono-Italic.ttf',\n boldItalic: '/fonts/SpaceMono-BoldItalic.ttf',\n },\n 'Sacramento': { regular: '/fonts/Sacramento-Regular.ttf' },\n 'Alex Brush': { regular: '/fonts/AlexBrush-Regular.ttf' },\n 'Allura': { regular: '/fonts/Allura-Regular.ttf' },\n 'Caveat': {\n regular: '/fonts/Caveat-Regular.ttf',\n bold: '/fonts/Caveat-Bold.ttf',\n medium: '/fonts/Caveat-Medium.ttf',\n semibold: '/fonts/Caveat-SemiBold.ttf',\n },\n 'Lobster': { regular: '/fonts/Lobster-Regular.ttf' },\n 'Comfortaa': {\n regular: '/fonts/Comfortaa-Regular.ttf',\n bold: '/fonts/Comfortaa-Bold.ttf',\n light: '/fonts/Comfortaa-Light.ttf',\n medium: '/fonts/Comfortaa-Medium.ttf',\n semibold: '/fonts/Comfortaa-SemiBold.ttf',\n },\n 'Anton': { regular: '/fonts/Anton-Regular.ttf' },\n 'Teko': {\n regular: '/fonts/Teko-Regular.ttf',\n bold: '/fonts/Teko-Bold.ttf',\n light: '/fonts/Teko-Light.ttf',\n medium: '/fonts/Teko-Medium.ttf',\n semibold: '/fonts/Teko-SemiBold.ttf',\n },\n // ── Indic Script Fallback Fonts ──\n 'Noto Sans Devanagari': {\n regular: '/fonts/NotoSansDevanagari-Regular.ttf',\n bold: '/fonts/NotoSansDevanagari-Bold.ttf',\n light: '/fonts/NotoSansDevanagari-Light.ttf',\n medium: '/fonts/NotoSansDevanagari-Medium.ttf',\n semibold: '/fonts/NotoSansDevanagari-SemiBold.ttf',\n },\n 'Hind': {\n regular: '/fonts/Hind-Regular.ttf',\n bold: '/fonts/Hind-Bold.ttf',\n light: '/fonts/Hind-Light.ttf',\n medium: '/fonts/Hind-Medium.ttf',\n semibold: '/fonts/Hind-SemiBold.ttf',\n },\n // ── Math / Operator Symbol Fallback ──\n // Carries glyphs that NotoSans-Regular's Latin subset is missing\n // (≠ ≤ ≥ ≈ ∞ → ← × ÷ ∑ √ ∈ ∀ ∃ etc.). Used as a tertiary fallback\n // ONLY for chars classified as 'math' that the main font + Noto Sans\n // both lack.\n 'Noto Sans Math': {\n regular: '/fonts/NotoSansMath-Regular.ttf',\n },\n};\n\n// Convert font file to Base64\nconst fontToBase64 = async (url: string): Promise<string> => {\n const response = await fetch(url);\n if (!response.ok) {\n throw new Error(`Failed to fetch font: ${response.statusText}`);\n }\n const arrayBuffer = await response.arrayBuffer();\n \n // Convert ArrayBuffer to Base64\n const bytes = new Uint8Array(arrayBuffer);\n if (!isJsPdfEmbeddableTrueType(bytes)) {\n throw new Error(`Font is not a jsPDF-compatible TrueType file: ${url}`);\n }\n let binary = '';\n for (let i = 0; i < bytes.length; i++) {\n binary += String.fromCharCode(bytes[i]);\n }\n return btoa(binary);\n};\n\nfunction isJsPdfEmbeddableTrueType(bytes: Uint8Array): boolean {\n if (bytes.length < 12) return false;\n const signature = String.fromCharCode(bytes[0], bytes[1], bytes[2], bytes[3]);\n if (signature !== '\\x00\\x01\\x00\\x00' && signature !== 'true') return false;\n\n const u16 = (offset: number) => (bytes[offset] << 8) | bytes[offset + 1];\n const u32 = (offset: number) => ((bytes[offset] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3]) >>> 0;\n const tableCount = u16(4);\n for (let i = 0; i < tableCount; i++) {\n const recordOffset = 12 + i * 16;\n if (recordOffset + 16 > bytes.length) return false;\n const tag = String.fromCharCode(bytes[recordOffset], bytes[recordOffset + 1], bytes[recordOffset + 2], bytes[recordOffset + 3]);\n if (tag !== 'cmap') continue;\n const cmapOffset = u32(recordOffset + 8);\n const cmapLength = u32(recordOffset + 12);\n if (cmapOffset + Math.min(cmapLength, 4) > bytes.length) return false;\n const subtables = u16(cmapOffset + 2);\n for (let j = 0; j < subtables; j++) {\n const encOffset = cmapOffset + 4 + j * 8;\n if (encOffset + 8 > bytes.length) return false;\n const platform = u16(encOffset);\n const encoding = u16(encOffset + 2);\n if (platform === 0 || (platform === 3 && (encoding === 1 || encoding === 10))) return true;\n }\n return false;\n }\n return false;\n}\n\nfunction extractSupportedCodePointsFromTtf(bytes: Uint8Array): Set<number> {\n const supported = new Set<number>();\n if (bytes.length < 12) return supported;\n const u16 = (offset: number) => (bytes[offset] << 8) | bytes[offset + 1];\n const i16 = (offset: number) => {\n const value = u16(offset);\n return value & 0x8000 ? value - 0x10000 : value;\n };\n const u32 = (offset: number) => ((bytes[offset] << 24) | (bytes[offset + 1] << 16) | (bytes[offset + 2] << 8) | bytes[offset + 3]) >>> 0;\n const tableCount = u16(4);\n let cmapOffset = 0;\n for (let i = 0; i < tableCount; i++) {\n const recordOffset = 12 + i * 16;\n if (recordOffset + 16 > bytes.length) return supported;\n if (String.fromCharCode(bytes[recordOffset], bytes[recordOffset + 1], bytes[recordOffset + 2], bytes[recordOffset + 3]) === 'cmap') {\n cmapOffset = u32(recordOffset + 8);\n break;\n }\n }\n if (!cmapOffset || cmapOffset + 4 > bytes.length) return supported;\n const subtables = u16(cmapOffset + 2);\n const candidates: Array<{ format: number; offset: number; score: number }> = [];\n for (let j = 0; j < subtables; j++) {\n const encOffset = cmapOffset + 4 + j * 8;\n if (encOffset + 8 > bytes.length) continue;\n const platform = u16(encOffset);\n const encoding = u16(encOffset + 2);\n const subOffset = cmapOffset + u32(encOffset + 4);\n if (subOffset + 2 > bytes.length) continue;\n const format = u16(subOffset);\n const score = format === 12 ? 40 : format === 4 ? 30 : 0;\n if (score) candidates.push({ format, offset: subOffset, score: score + (platform === 3 && encoding === 10 ? 2 : platform === 0 ? 1 : 0) });\n }\n candidates.sort((a, b) => b.score - a.score);\n const best = candidates[0];\n if (!best) return supported;\n if (best.format === 12 && best.offset + 16 <= bytes.length) {\n const nGroups = u32(best.offset + 12);\n for (let i = 0; i < nGroups; i++) {\n const off = best.offset + 16 + i * 12;\n if (off + 12 > bytes.length) break;\n const start = u32(off);\n const end = u32(off + 4);\n for (let cp = start; cp <= end && cp <= 0x10FFFF; cp++) supported.add(cp);\n }\n } else if (best.format === 4 && best.offset + 14 <= bytes.length) {\n const segCount = u16(best.offset + 6) / 2;\n const endCodes = best.offset + 14;\n const startCodes = endCodes + segCount * 2 + 2;\n const idDeltas = startCodes + segCount * 2;\n const idRangeOffsets = idDeltas + segCount * 2;\n for (let i = 0; i < segCount; i++) {\n const start = u16(startCodes + i * 2);\n const end = u16(endCodes + i * 2);\n const delta = i16(idDeltas + i * 2);\n const rangeOffset = u16(idRangeOffsets + i * 2);\n for (let cp = start; cp <= end && cp !== 0xFFFF; cp++) {\n if (rangeOffset === 0) {\n if (((cp + delta) & 0xffff) !== 0) supported.add(cp);\n } else {\n const glyphOffset = idRangeOffsets + i * 2 + rangeOffset + (cp - start) * 2;\n if (glyphOffset + 2 <= bytes.length && u16(glyphOffset) !== 0) supported.add(cp);\n }\n }\n }\n }\n return supported;\n}\n\nfunction base64ToBytes(base64: string): Uint8Array {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n return bytes;\n}\n\n// Get jsPDF-compatible font name (sanitized - no spaces)\nexport const getJsPDFFontName = (fontName: string): string => {\n return fontName.replace(/\\s+/g, '');\n};\n\n// Weight → file key and fallback order for resolving TTF path (normal style)\nconst WEIGHT_TO_KEYS: Record<number, (keyof FontWeightFiles)[]> = {\n 300: ['light', 'regular'],\n 400: ['regular'],\n 500: ['medium', 'regular'],\n 600: ['semibold', 'bold', 'regular'],\n 700: ['bold', 'regular'],\n};\n\n// Weight → file key and fallback order for resolving TTF path (italic style)\nconst WEIGHT_TO_ITALIC_KEYS: Record<number, (keyof FontWeightFiles)[]> = {\n 300: ['lightItalic', 'italic', 'light', 'regular'],\n 400: ['italic', 'regular'],\n 500: ['mediumItalic', 'italic', 'medium', 'regular'],\n 600: ['semiboldItalic', 'boldItalic', 'italic', 'semibold', 'bold', 'regular'],\n 700: ['boldItalic', 'italic', 'bold', 'regular'],\n};\n\nfunction getFontPathForWeight(fontFiles: FontWeightFiles, resolvedWeight: number, isItalic = false): string {\n const keys = isItalic ? WEIGHT_TO_ITALIC_KEYS[resolvedWeight] : WEIGHT_TO_KEYS[resolvedWeight];\n if (!keys) return fontFiles.regular;\n for (const k of keys) {\n const path = fontFiles[k];\n if (path) return path;\n }\n return fontFiles.regular;\n}\n\n/**\n * True when the path resolved by getFontPathForWeight is actually the file for\n * the requested (weight, italic) — not a fallback (e.g. resolving Bold to\n * Regular because the family has no Bold file). Used so we can avoid\n * registering Regular bytes under a \"Bold\" name (which makes jsPDF render\n * inline bold spans in regular weight).\n */\nfunction isExactWeightItalicMatch(\n fontFiles: FontWeightFiles,\n resolvedWeight: number,\n isItalic: boolean,\n resolvedPath: string,\n): boolean {\n const exactKey: keyof FontWeightFiles | null = isItalic\n ? resolvedWeight === 300 ? 'lightItalic'\n : resolvedWeight === 500 ? 'mediumItalic'\n : resolvedWeight === 600 ? 'semiboldItalic'\n : resolvedWeight === 700 ? 'boldItalic'\n : 'italic'\n : resolvedWeight === 300 ? 'light'\n : resolvedWeight === 500 ? 'medium'\n : resolvedWeight === 600 ? 'semibold'\n : resolvedWeight === 700 ? 'bold'\n : 'regular';\n return !!exactKey && fontFiles[exactKey] === resolvedPath;\n}\n\n/** Check if the resolved path is actually an italic-specific file */\nfunction isItalicPath(fontFiles: FontWeightFiles, path: string): boolean {\n return path === fontFiles.italic ||\n path === fontFiles.boldItalic ||\n path === fontFiles.lightItalic ||\n path === fontFiles.mediumItalic ||\n path === fontFiles.semiboldItalic;\n}\n\n// Returns the jsPDF font name used when embedding; includes italic suffix when applicable\nexport const getEmbeddedJsPDFFontName = (fontName: string, weight: number, isItalic = false): string => {\n const resolved = resolveFontWeight(weight);\n const label = FONT_WEIGHT_LABELS[resolved];\n const italicSuffix = isItalic ? 'Italic' : '';\n return `${getJsPDFFontName(fontName)}-${label}${italicSuffix}`;\n};\n\n// Load and embed a font into jsPDF from local TTF files (one jsPDF font per weight+style, style always \"normal\")\nexport const embedFont = async (\n pdf: any,\n fontName: string,\n weight: number = 400,\n isItalic = false,\n): Promise<boolean> => {\n const fontFiles = FONT_FILES[fontName];\n if (!fontFiles) {\n console.warn(`Font ${fontName} not found in local fonts`);\n return false;\n }\n\n const resolvedWeight = resolveFontWeight(weight);\n const fontPath = getFontPathForWeight(fontFiles, resolvedWeight, isItalic);\n if (!fontPath) return false;\n\n // If the local family lacks a TTF for this exact (weight, italic) and would\n // fall back to Regular, refuse — let embedFontWithGoogleFallback fetch a\n // real variant from Google Fonts / Fontshare. Registering Regular bytes\n // under e.g. \"DMSerifDisplay-Bold\" makes jsPDF render bold spans in\n // regular weight, breaking inline bold/italic in selectable PDFs.\n if (!isExactWeightItalicMatch(fontFiles, resolvedWeight, isItalic, fontPath)) {\n return false;\n }\n\n const label = FONT_WEIGHT_LABELS[resolvedWeight];\n const italicSuffix = isItalic ? 'Italic' : '';\n const cacheKey = `${fontName}-${resolvedWeight}${isItalic ? '-italic' : ''}`;\n const jsPdfFontName = getEmbeddedJsPDFFontName(fontName, weight, isItalic);\n\n try {\n let base64Font = fontCache.get(cacheKey);\n if (!base64Font) {\n const response = await fetch(fontPath);\n if (!response.ok) throw new Error(`Failed to fetch font: ${response.statusText}`);\n const arrayBuffer = await response.arrayBuffer();\n const bytes = new Uint8Array(arrayBuffer);\n if (!isJsPdfEmbeddableTrueType(bytes)) throw new Error(`Font is not a jsPDF-compatible TrueType file: ${fontPath}`);\n registeredVariantCoverage.set(variantKey(fontName, resolvedWeight, isItalic), extractSupportedCodePointsFromTtf(bytes));\n let binary = '';\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);\n base64Font = btoa(binary);\n fontCache.set(cacheKey, base64Font);\n } else if (!registeredVariantCoverage.has(variantKey(fontName, resolvedWeight, isItalic))) {\n // The registry is reset per PDF export, but `fontCache` persists across\n // exports. Rebuild glyph coverage directly from the cached TTF bytes;\n // otherwise supported glyphs like Karla's `≠` are treated as missing and\n // incorrectly rewritten to Noto Sans Math in selectable PDFs.\n registeredVariantCoverage.set(variantKey(fontName, resolvedWeight, isItalic), extractSupportedCodePointsFromTtf(base64ToBytes(base64Font)));\n }\n\n const fileName = `${getJsPDFFontName(fontName)}-${label}${italicSuffix}.ttf`;\n pdf.addFileToVFS(fileName, base64Font);\n pdf.addFont(fileName, jsPdfFontName, 'normal');\n if (fontName !== jsPdfFontName) {\n try {\n pdf.addFont(fileName, fontName, 'normal');\n } catch {\n // Ignore duplicate alias registration; svg2pdf only needs one successful alias.\n }\n }\n registeredFamilies.add(fontName);\n registeredVariants.add(variantKey(fontName, resolvedWeight, isItalic));\n return true;\n } catch (error) {\n console.error(`Failed to embed font ${fontName} (weight ${weight}, italic=${isItalic}):`, error);\n return false;\n }\n};\n\n// Pre-load all font weights into cache (can be called at app start for faster PDF export)\nexport const preloadFonts = async (): Promise<void> => {\n const loadPromises: Promise<void>[] = [];\n const weights = [300, 400, 500, 600, 700] as const;\n\n for (const [fontName, files] of Object.entries(FONT_FILES)) {\n for (const w of weights) {\n // Normal\n const path = getFontPathForWeight(files as FontWeightFiles, w);\n if (path) {\n const cacheKey = `${fontName}-${w}`;\n loadPromises.push(\n fontToBase64(path)\n .then(base64 => { fontCache.set(cacheKey, base64); })\n .catch(err => console.warn(`Failed to preload ${fontName} weight ${w}:`, err))\n );\n }\n // Italic\n const italicPath = getFontPathForWeight(files as FontWeightFiles, w, true);\n if (italicPath && italicPath !== path) {\n const cacheKeyItalic = `${fontName}-${w}-italic`;\n loadPromises.push(\n fontToBase64(italicPath)\n .then(base64 => { fontCache.set(cacheKeyItalic, base64); })\n .catch(err => console.warn(`Failed to preload ${fontName} weight ${w} italic:`, err))\n );\n }\n }\n }\n\n await Promise.all(loadPromises);\n};\n\n// Check if a font is available locally\nexport const isFontAvailable = (fontName: string): boolean => {\n return fontName in FONT_FILES;\n};\n\n// Check if a font has an italic variant for the given weight\nexport const hasItalicVariant = (fontName: string, weight: number = 400): boolean => {\n const files = FONT_FILES[fontName];\n if (!files) return false;\n const resolvedWeight = resolveFontWeight(weight);\n const normalPath = getFontPathForWeight(files, resolvedWeight, false);\n const italicPath = getFontPathForWeight(files, resolvedWeight, true);\n return italicPath !== normalPath && isItalicPath(files, italicPath);\n};\n\n// Get all available font names\nexport const getAvailableFonts = (): string[] => {\n return Object.keys(FONT_FILES);\n};\n\n/**\n * Get available font weights for a given font family.\n * Returns only weights that have a dedicated TTF file (not fallbacks).\n */\nexport const getAvailableWeights = (fontFamily: string): number[] => {\n const files = FONT_FILES[fontFamily];\n if (!files) return [400]; // Fallback: at least regular\n\n const weights: number[] = [];\n if (files.light) weights.push(300);\n // regular always exists\n weights.push(400);\n if (files.medium) weights.push(500);\n if (files.semibold) weights.push(600);\n if (files.bold) weights.push(700);\n\n return weights;\n};\n\n/**\n * Check if a font has any italic variant at all.\n */\nexport const hasAnyItalicVariant = (fontFamily: string): boolean => {\n const files = FONT_FILES[fontFamily];\n if (!files) return false;\n return !!(files.italic || files.boldItalic || files.lightItalic || files.mediumItalic || files.semiboldItalic);\n};\n\n// ═══════════════════════════════════════════════════════════════\n// Google Fonts dynamic TTF fetching (parity with EC2 server)\n// ═══════════════════════════════════════════════════════════════\n\n/** Fetch a TTF (as base64) for any Google Font. Caches per (family, weight, style). */\nexport async function fetchGoogleFontTTF(\n fontFamily: string,\n weight: number = 400,\n isItalic = false,\n): Promise<string | null> {\n const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? 'i' : 'n'}`;\n if (fontCache.has(cacheKey)) return fontCache.get(cacheKey)!;\n const notFoundKey = remoteVariantKey(fontFamily, weight, isItalic);\n if (googleFontNotFound.has(notFoundKey)) return null;\n // Try the server-side proxy first — it reliably returns TTF since the edge\n // function can spoof a legacy UA. Direct browser fetch is unreliable because\n // sec-ch-ua client hints override our custom User-Agent.\n const proxyBytes = await fetchTtfViaProxy(fontFamily, weight, isItalic, 'google');\n if (proxyBytes && isJsPdfEmbeddableTrueType(proxyBytes)) {\n fontBytesCache.set(cacheKey, proxyBytes);\n let binary = '';\n for (let i = 0; i < proxyBytes.length; i++) binary += String.fromCharCode(proxyBytes[i]);\n const b64 = btoa(binary);\n fontCache.set(cacheKey, b64);\n return b64;\n }\n if (resolveFontProxyUrl()) return null;\n try {\n const ital = isItalic ? '1' : '0';\n const cssUrl = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(\n fontFamily,\n )}:ital,wght@${ital},${weight}&display=swap`;\n // The User-Agent below tricks Google Fonts into returning legacy TTF (not WOFF2),\n // matching what the EC2 server does so jsPDF can consume it.\n const cssRes = await fetch(cssUrl, {\n headers: {\n 'User-Agent':\n 'Mozilla/5.0 (Linux; U; Android 2.2; en-us) AppleWebKit/533.1 (KHTML, like Gecko)',\n },\n });\n if (!cssRes.ok) {\n if (cssRes.status === 400 || cssRes.status === 404) googleFontNotFound.add(notFoundKey);\n return null;\n }\n const css = await cssRes.text();\n const urlMatch = css.match(/url\\(([^)]+)\\)\\s+format\\(['\"]?truetype['\"]?\\)/i)\n || css.match(/url\\(([^)]+)\\)/);\n if (!urlMatch) return null;\n const ttfUrl = urlMatch[1].replace(/['\"]/g, '');\n googleFontUrlCache.set(cacheKey, ttfUrl);\n const ttfRes = await fetch(ttfUrl);\n if (!ttfRes.ok) return null;\n const buf = await ttfRes.arrayBuffer();\n const bytes = new Uint8Array(buf);\n if (!isJsPdfEmbeddableTrueType(bytes)) {\n console.warn(`[pdfFonts] Google Fonts returned a non-TTF font for ${fontFamily} (${weight}); skipping jsPDF embed`);\n return null;\n }\n fontBytesCache.set(cacheKey, bytes);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);\n const b64 = btoa(binary);\n fontCache.set(cacheKey, b64);\n return b64;\n } catch (err) {\n console.warn(`[pdfFonts] fetchGoogleFontTTF failed for ${fontFamily} (${weight}):`, err);\n return null;\n }\n}\n\n/** Get raw TTF bytes for a Google Font (used by opentype.js / HarfBuzz). */\nexport async function getGoogleFontBytes(\n fontFamily: string,\n weight: number = 400,\n isItalic = false,\n): Promise<Uint8Array | null> {\n const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? 'i' : 'n'}`;\n if (fontBytesCache.has(cacheKey)) return fontBytesCache.get(cacheKey)!;\n await fetchGoogleFontTTF(fontFamily, weight, isItalic);\n return fontBytesCache.get(cacheKey) || null;\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Fontshare dynamic TTF fetching (Satoshi, Clash Display, etc.)\n// ═══════════════════════════════════════════════════════════════\n\nconst fontshareNotFound: Set<string> = new Set();\n\n/** Convert a font family display name to the slug Fontshare's API expects. */\nfunction toFontshareSlug(family: string): string {\n return family.trim().toLowerCase().replace(/\\s+/g, '-');\n}\n\n/**\n * Fetch a TTF (as base64) for a Fontshare family. Mirrors `fetchGoogleFontTTF`:\n * pulls the CSS for the requested weight/style, picks the `format('truetype')`\n * URL, downloads the bytes, validates, and caches under the same key shape used\n * for Google Fonts so all downstream consumers work without changes.\n */\nexport async function fetchFontshareTTF(\n fontFamily: string,\n weight: number = 400,\n isItalic = false,\n slug?: string,\n): Promise<string | null> {\n const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? 'i' : 'n'}`;\n if (fontCache.has(cacheKey)) return fontCache.get(cacheKey)!;\n const notFoundKey = remoteVariantKey(fontFamily, weight, isItalic);\n if (fontshareNotFound.has(notFoundKey)) return null;\n const proxyBytes = await fetchTtfViaProxy(fontFamily, weight, isItalic, 'fontshare');\n if (proxyBytes && isJsPdfEmbeddableTrueType(proxyBytes)) {\n fontBytesCache.set(cacheKey, proxyBytes);\n let binary = '';\n for (let i = 0; i < proxyBytes.length; i++) binary += String.fromCharCode(proxyBytes[i]);\n const b64 = btoa(binary);\n fontCache.set(cacheKey, b64);\n return b64;\n }\n if (resolveFontProxyUrl()) return null;\n const finalSlug = slug || toFontshareSlug(fontFamily);\n try {\n const styleSuffix = isItalic ? 'i' : '';\n const cssUrl = `https://api.fontshare.com/v2/css?f[]=${finalSlug}@${weight}${styleSuffix}&display=swap`;\n const cssRes = await fetch(cssUrl);\n if (!cssRes.ok) {\n if (cssRes.status === 400 || cssRes.status === 404) fontshareNotFound.add(notFoundKey);\n return null;\n }\n const css = await cssRes.text();\n // Fontshare CSS includes woff2/woff/ttf; pick truetype explicitly.\n const ttMatch = css.match(/url\\(([^)]+)\\)\\s+format\\(['\"]?truetype['\"]?\\)/i);\n if (!ttMatch) {\n fontshareNotFound.add(notFoundKey);\n return null;\n }\n let ttfUrl = ttMatch[1].replace(/['\"]/g, '').trim();\n if (ttfUrl.startsWith('//')) ttfUrl = `https:${ttfUrl}`;\n const ttfRes = await fetch(ttfUrl);\n if (!ttfRes.ok) return null;\n const buf = await ttfRes.arrayBuffer();\n const bytes = new Uint8Array(buf);\n if (!isJsPdfEmbeddableTrueType(bytes)) {\n console.warn(`[pdfFonts] Fontshare returned a non-TTF font for ${fontFamily} (${weight}); skipping jsPDF embed`);\n return null;\n }\n fontBytesCache.set(cacheKey, bytes);\n let binary = '';\n for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);\n const b64 = btoa(binary);\n fontCache.set(cacheKey, b64);\n return b64;\n } catch (err) {\n console.warn(`[pdfFonts] fetchFontshareTTF failed for ${fontFamily} (${weight}):`, err);\n return null;\n }\n}\n\n/** Get raw TTF bytes for a Fontshare font (used by opentype.js / HarfBuzz). */\nexport async function getFontshareFontBytes(\n fontFamily: string,\n weight: number = 400,\n isItalic = false,\n slug?: string,\n): Promise<Uint8Array | null> {\n const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? 'i' : 'n'}`;\n if (fontBytesCache.has(cacheKey)) return fontBytesCache.get(cacheKey)!;\n await fetchFontshareTTF(fontFamily, weight, isItalic, slug);\n return fontBytesCache.get(cacheKey) || null;\n}\n\n/**\n * Embed a font into jsPDF — local TTF if available, otherwise Google Fonts.\n * Returns true on success. Registers under the SAME jsPDF font name as\n * `getEmbeddedJsPDFFontName(...)` so SVG rewriting matches.\n */\nexport const embedFontWithGoogleFallback = async (\n pdf: any,\n fontName: string,\n weight: number = 400,\n isItalic = false,\n): Promise<boolean> => {\n // 1. Local first\n if (FONT_FILES[fontName]) {\n const ok = await embedFont(pdf, fontName, weight, isItalic);\n if (ok) return true;\n }\n\n // Family short-circuit: if base 400-regular missed on every CDN already,\n // skip the variant ladder entirely. Saves 6–8 wasted edge-function calls\n // per missing family (massive DevTools spam reduction + faster export).\n if (familyNotOnAnyCdn.has(fontName)) return false;\n\n // 2. Try the requested variant first on Fontshare, then Google. Many\n // decorative families on Google Fonts and Fontshare ship a SINGLE\n // weight (e.g. Pacifico, Frijole, Stardom only at 400). The canvas\n // fakes bold/semibold via synthetic-bold rendering — the PDF must do\n // the same: when the requested weight is unavailable, fall back\n // through a weight ladder so the family still embeds with its real\n // glyphs and svg2pdf can match by family. Without this fallback,\n // bold display fonts silently substitute Helvetica/Times in the PDF.\n const resolved = resolveFontWeight(weight);\n const weightLadder: number[] = [resolved];\n for (const w of [400, 500, 700, 600, 300]) {\n if (!weightLadder.includes(w)) weightLadder.push(w);\n }\n\n const tryFetch = async (w: number, italic: boolean): Promise<string | null> => {\n const fs = await fetchFontshareTTF(fontName, w, italic);\n if (fs) return fs;\n const g = await fetchGoogleFontTTF(fontName, w, italic);\n return g;\n };\n\n let b64: string | null = null;\n let usedItalic = isItalic;\n let usedWeight = resolved;\n for (const w of weightLadder) {\n b64 = await tryFetch(w, isItalic);\n if (b64) { usedWeight = w; break; }\n }\n // If italic was requested but no italic variant exists at any weight,\n // fall back to upright bytes so the family still renders. svg2pdf will\n // skew via the existing synthetic-italic transform path in the rewriter.\n if (!b64 && isItalic) {\n for (const w of weightLadder) {\n b64 = await tryFetch(w, false);\n if (b64) { usedItalic = false; usedWeight = w; break; }\n }\n }\n if (!b64) {\n // Both CDNs missed for this variant. If the base 400-regular also failed\n // for both (meaning the family doesn't exist anywhere), seed the family\n // short-circuit so subsequent variant requests skip the ladder.\n if (\n !familyConfirmedOnSomeCdn.has(fontName) &&\n proxyNotFound.has(proxyKey(fontName, 400, false, 'google')) &&\n proxyNotFound.has(proxyKey(fontName, 400, false, 'fontshare'))\n ) {\n familyNotOnAnyCdn.add(fontName);\n persistCaches();\n }\n // For italic requests, do NOT silently register upright bytes under the\n // italic variant key — that previously caused inline italic spans to\n // render in upright glyphs in the PDF. Instead we let\n // `resolveBestRegisteredVariant` (in the SVG rewriter) fall back to a\n // lighter italic weight that actually carries italic glyphs, with\n // synthetic bold (stroke) applied for the weight delta.\n return false;\n }\n // Register the bytes under the ACTUAL weight whose glyphs we fetched.\n // This is critical for visual parity with the canvas: when the requested\n // weight (e.g. 700) is not available and we fell back to 400, the SVG\n // rewriter's `resolveBestRegisteredVariant` will return weight=400, and\n // `needsSyntheticBold(700, 400)` will trigger the stroke-based synthetic\n // bold path — matching what the browser does on <canvas> for\n // single-weight families like Pacifico/Stardom/Frijole.\n return registerJsPdfFont(pdf, fontName, usedWeight, usedItalic, b64);\n};\n\n/** Register a base64 TTF inside jsPDF under the canonical embedded name + alias. */\nfunction registerJsPdfFont(\n pdf: any,\n fontName: string,\n resolvedWeight: number,\n isItalic: boolean,\n base64: string,\n): boolean {\n const label = FONT_WEIGHT_LABELS[resolvedWeight];\n const italicSuffix = isItalic ? 'Italic' : '';\n const jsPdfFontName = getEmbeddedJsPDFFontName(fontName, resolvedWeight, isItalic);\n const fileName = `${getJsPDFFontName(fontName)}-${label}${italicSuffix}.ttf`;\n try {\n try {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);\n registeredVariantCoverage.set(variantKey(fontName, resolvedWeight, isItalic), extractSupportedCodePointsFromTtf(bytes));\n } catch {\n // Coverage is an optimization for choosing fallbacks; font registration can still proceed.\n }\n pdf.addFileToVFS(fileName, base64);\n pdf.addFont(fileName, jsPdfFontName, 'normal');\n if (fontName !== jsPdfFontName) {\n try {\n pdf.addFont(fileName, fontName, 'normal');\n } catch {\n /* duplicate alias; ignore */\n }\n }\n registeredFamilies.add(fontName);\n registeredVariants.add(variantKey(fontName, resolvedWeight, isItalic));\n return true;\n } catch (err) {\n console.warn(`[pdfFonts] registerJsPdfFont failed for ${fontName}:`, err);\n return false;\n }\n}\n\n// ═══════════════════════════════════════════════════════════════\n// Latin → Devanagari font sibling mapping\n// ═══════════════════════════════════════════════════════════════\n\n/**\n * Map of Latin Google Fonts → their Devanagari sibling family on Google Fonts.\n * When a user picks a Latin font and types Hindi, we use the matching Devanagari\n * family for path conversion so the visual style is preserved (instead of always\n * falling back to Hind). Sourced from Google's own family pairings.\n */\nexport const LATIN_TO_DEVANAGARI: Record<string, string> = {\n // Direct Devanagari subsets — same family carries both scripts\n 'Poppins': 'Poppins',\n 'Noto Sans': 'Noto Sans Devanagari',\n 'Noto Serif': 'Noto Serif Devanagari',\n 'Hind': 'Hind',\n 'Mukta': 'Mukta',\n\n // Curated visual matches (Google's own recommendations)\n 'Montserrat': 'Mukta',\n 'Open Sans': 'Mukta',\n 'Lato': 'Mukta',\n 'Roboto': 'Mukta',\n 'Inter': 'Mukta',\n 'Nunito': 'Mukta',\n 'Source Sans Pro': 'Mukta',\n 'Work Sans': 'Mukta',\n 'DM Sans': 'Mukta',\n 'Outfit': 'Mukta',\n 'Figtree': 'Mukta',\n 'Manrope': 'Mukta',\n 'Plus Jakarta Sans': 'Mukta',\n 'Sora': 'Mukta',\n 'Urbanist': 'Mukta',\n 'Lexend': 'Mukta',\n 'Albert Sans': 'Mukta',\n 'Cabin': 'Mukta',\n 'Karla': 'Mukta',\n 'Mulish': 'Mukta',\n 'Rubik': 'Mukta',\n 'Quicksand': 'Mukta',\n 'Libre Franklin': 'Mukta',\n 'Barlow': 'Mukta',\n 'Archivo': 'Mukta',\n 'Overpass': 'Mukta',\n 'Josefin Sans': 'Mukta',\n 'Exo 2': 'Mukta',\n 'Space Grotesk': 'Mukta',\n\n // Display / heavy\n 'Oswald': 'Teko',\n 'Bebas Neue': 'Teko',\n 'Anton': 'Teko',\n 'Teko': 'Teko',\n 'League Spartan': 'Teko',\n\n // Serifs → Tiro Devanagari Hindi (a refined Devanagari serif)\n 'Playfair Display': 'Tiro Devanagari Hindi',\n 'Merriweather': 'Tiro Devanagari Hindi',\n 'Lora': 'Tiro Devanagari Hindi',\n 'EB Garamond': 'Tiro Devanagari Hindi',\n 'Libre Baskerville': 'Tiro Devanagari Hindi',\n 'Crimson Text': 'Tiro Devanagari Hindi',\n 'DM Serif Display': 'Tiro Devanagari Sanskrit',\n 'Abril Fatface': 'Tiro Devanagari Sanskrit',\n\n // Handwriting → Kalam (the only serious Devanagari handwriting family on GF)\n 'Dancing Script': 'Kalam',\n 'Pacifico': 'Kalam',\n 'Great Vibes': 'Kalam',\n 'Sacramento': 'Kalam',\n 'Alex Brush': 'Kalam',\n 'Allura': 'Kalam',\n 'Caveat': 'Kalam',\n 'Lobster': 'Kalam',\n 'Comfortaa': 'Mukta',\n\n // Monospace → there's no proper Devanagari mono; fall back to Mukta\n 'Roboto Mono': 'Mukta',\n 'Fira Code': 'Mukta',\n 'JetBrains Mono': 'Mukta',\n 'Source Code Pro': 'Mukta',\n 'IBM Plex Mono': 'Mukta',\n 'Space Mono': 'Mukta',\n};\n\n/** Pick the best Devanagari family for a given Latin font (returns FONT_FALLBACK_DEVANAGARI as last resort). */\nexport function resolveDevanagariSibling(latinFont: string | null | undefined): string {\n if (!latinFont) return FONT_FALLBACK_DEVANAGARI;\n return LATIN_TO_DEVANAGARI[latinFont] || FONT_FALLBACK_DEVANAGARI;\n}\n","/**\n * HarfBuzz Shaper — Browser-side complex-script text shaping for vector PDF export.\n *\n * `opentype.js`'s `getPath()` only does naive codepoint→glyph mapping with very\n * limited GSUB support. That breaks complex scripts like Devanagari (Hindi /\n * Marathi / Sanskrit) where glyphs require:\n * - Conjuncts (क्ष, ज्ञ, त्र — multi-consonant ligatures)\n * - Reph (र above following consonant)\n * - Half-forms before virama\n * - Matra reordering (कि — इ matra rendered before क but typed after)\n * - Indic-specific GSUB lookups (nukt, akhn, rphf, blwf, half, pstf, vatu,\n * cjct, pres, abvs, blws, psts, haln, rkrf)\n *\n * The browser canvas preview works because the browser's text renderer uses\n * HarfBuzz internally. Our EC2 PDF works because Puppeteer also uses HarfBuzz.\n * The client-side vector PDF was the only path missing a real shaper.\n *\n * This module wraps `harfbuzzjs` (HarfBuzz compiled to WASM, ~400KB) and\n * returns a single shaped SVG path string per text run, ready to drop into\n * the SVG that we hand to svg2pdf.js.\n *\n * Lazy-loaded — the WASM is only fetched the first time a Devanagari (or other\n * complex-script) string is encountered during PDF export.\n */\n\n// hb.wasm is served from /public/wasm/hb.wasm\nconst HB_WASM_URL = '/wasm/hb.wasm';\n\ntype HBFont = {\n ptr: number;\n setScale: (x: number, y: number) => void;\n glyphToPath: (glyphId: number) => string;\n destroy: () => void;\n};\n\ntype HBBuffer = {\n addText: (text: string) => void;\n guessSegmentProperties: () => void;\n setDirection: (dir: 'ltr' | 'rtl' | 'ttb' | 'btt') => void;\n setScript: (script: string) => void;\n setLanguage: (lang: string) => void;\n json: () => Array<{\n g: number;\n cl: number;\n ax: number;\n ay: number;\n dx: number;\n dy: number;\n flags?: number;\n }>;\n destroy: () => void;\n};\n\ntype HBInstance = {\n createBlob: (data: Uint8Array | ArrayBuffer) => { destroy: () => void };\n createFace: (blob: any, index: number) => { upem?: number; destroy: () => void; getUpem?: () => number };\n createFont: (face: any) => HBFont;\n createBuffer: () => HBBuffer;\n shape: (font: HBFont, buffer: HBBuffer, features?: string) => void;\n};\n\nlet hbInstancePromise: Promise<HBInstance> | null = null;\n\n/** Lazy-load and initialize HarfBuzz WASM. Idempotent. */\nasync function getHB(): Promise<HBInstance> {\n if (hbInstancePromise) return hbInstancePromise;\n\n hbInstancePromise = (async () => {\n // Dynamically import to keep HarfBuzz out of the main bundle.\n // hb.js is an Emscripten module that exports a `createHarfBuzz` factory.\n // It looks up the .wasm file via Module.locateFile.\n const [{ default: createHarfBuzz }, { default: hbjs }] = await Promise.all([\n import('harfbuzzjs/hb.js'),\n import('harfbuzzjs/hbjs.js'),\n ]);\n\n const moduleInstance = await createHarfBuzz({\n locateFile: (path: string) => {\n if (path.endsWith('.wasm')) return HB_WASM_URL;\n return path;\n },\n });\n\n return hbjs(moduleInstance) as HBInstance;\n })();\n\n return hbInstancePromise;\n}\n\n/** Per-font cache: parsed face/font ready for repeated shaping calls. */\nconst hbFontCache = new Map<string, { face: any; font: HBFont; upem: number }>();\n\n/**\n * Register (or fetch from cache) a font with HarfBuzz.\n * `cacheKey` should uniquely identify the font binary (e.g. `family|weight`).\n * `fontDataLoader` is only invoked on cache miss.\n */\nasync function getHBFont(\n cacheKey: string,\n fontDataLoader: () => Promise<Uint8Array>,\n): Promise<{ font: HBFont; upem: number }> {\n const cached = hbFontCache.get(cacheKey);\n if (cached) return { font: cached.font, upem: cached.upem };\n\n const hb = await getHB();\n const fontData = await fontDataLoader();\n const blob = hb.createBlob(fontData);\n const face = hb.createFace(blob, 0);\n const font = hb.createFont(face);\n\n // Use the font's native upem so glyphToPath coordinates are in font units.\n // `setScale(upem, upem)` keeps the natural EM-square coordinates.\n const upem = (face.getUpem ? face.getUpem() : (face.upem ?? 1000)) || 1000;\n font.setScale(upem, upem);\n\n // Blob can be destroyed; face/font hold their own references.\n blob.destroy();\n\n hbFontCache.set(cacheKey, { face, font, upem });\n return { font, upem };\n}\n\nexport interface ShapedRun {\n /** SVG path data ready to drop into a <path d=\"...\"> element. */\n pathData: string;\n /** Total advance width of the run, in user-space units (matching `fontSize`). */\n width: number;\n}\n\n/**\n * Shape `text` with `fontData` at `fontSize` and return a single SVG path\n * positioned starting at (`x`, `y`) on the SVG baseline.\n *\n * `fontSize` is the rendered point size (matches CSS `font-size`).\n * `cacheKey` must uniquely identify `fontData` so subsequent calls hit cache.\n */\nexport async function shapeRunToSvgPath(\n fontData: Uint8Array | (() => Promise<Uint8Array>),\n cacheKey: string,\n text: string,\n x: number,\n y: number,\n fontSize: number,\n opts?: { script?: string; language?: string; direction?: 'ltr' | 'rtl' },\n): Promise<ShapedRun> {\n const hb = await getHB();\n const loader = typeof fontData === 'function'\n ? (fontData as () => Promise<Uint8Array>)\n : async () => fontData as Uint8Array;\n\n const { font, upem } = await getHBFont(cacheKey, loader);\n\n const buffer = hb.createBuffer();\n buffer.addText(text);\n // Setting script + direction explicitly is more reliable than guess for\n // Indic mixed-content runs.\n if (opts?.direction) buffer.setDirection(opts.direction);\n if (opts?.script) buffer.setScript(opts.script);\n if (opts?.language) buffer.setLanguage(opts.language);\n buffer.guessSegmentProperties();\n\n hb.shape(font, buffer);\n const glyphs = buffer.json();\n\n // HarfBuzz coordinate system: Y is UP, units are font units (we set scale\n // to upem so 1 unit == 1 font-design-unit). Convert to SVG user-space:\n // svgUnits = fontUnits * (fontSize / upem)\n // and flip Y.\n const scale = fontSize / upem;\n\n // Pen position, in font units.\n let penX = 0;\n let penY = 0;\n const pieces: string[] = [];\n\n for (const g of glyphs) {\n const rawPath = font.glyphToPath(g.g);\n if (rawPath) {\n // Transform glyph path:\n // 1. Translate to (penX + dx, penY + dy) in font units\n // 2. Flip Y (since HB Y-up, SVG Y-down)\n // 3. Scale by `scale`\n // 4. Translate by (x, y) in user units\n const ox = (penX + g.dx) * scale + x;\n const oy = (penY + g.dy) * -scale + y;\n pieces.push(transformPathData(rawPath, scale, -scale, ox, oy));\n }\n penX += g.ax;\n penY += g.ay;\n }\n\n buffer.destroy();\n\n return {\n pathData: pieces.join(''),\n width: penX * scale,\n };\n}\n\n/**\n * Apply an affine transform (sx, sy, tx, ty) to an SVG path's absolute\n * coordinates. The path emitted by HarfBuzz uses only absolute commands\n * (M, L, C, Q, Z), so we only need to transform numeric coordinate pairs.\n */\nfunction transformPathData(d: string, sx: number, sy: number, tx: number, ty: number): string {\n // Tokenize into commands and number pairs.\n // HB output format: \"M x,y\", \"L x,y\", \"C cx1,cy1 cx2,cy2 x,y\", \"Q cx,cy x,y\", \"Z\"\n // Numbers may be negative or fractional.\n let out = '';\n let i = 0;\n const n = d.length;\n while (i < n) {\n const c = d[i];\n if (c === 'M' || c === 'L' || c === 'C' || c === 'Q') {\n out += c;\n i++;\n // Read remaining coordinate pairs until next command letter or end.\n // Pairs are separated by space or comma.\n let pairsBuf = '';\n while (i < n && d[i] !== 'M' && d[i] !== 'L' && d[i] !== 'C' && d[i] !== 'Q' && d[i] !== 'Z') {\n pairsBuf += d[i];\n i++;\n }\n // pairsBuf now holds something like \"12.5,30.2 -4,5 0,0\"\n const nums = pairsBuf.trim().split(/[ ,]+/).filter(Boolean).map(Number);\n for (let k = 0; k < nums.length; k += 2) {\n const px = nums[k] * sx + tx;\n const py = nums[k + 1] * sy + ty;\n if (k > 0) out += ' ';\n out += `${round(px)},${round(py)}`;\n }\n } else if (c === 'Z') {\n out += 'Z';\n i++;\n } else {\n // Skip unexpected character (e.g. stray whitespace)\n i++;\n }\n }\n return out;\n}\n\nfunction round(n: number): string {\n // 2 decimal places — same precision as opentype.js fallback.\n return (Math.round(n * 100) / 100).toString();\n}\n\n/**\n * Pre-warm HarfBuzz WASM so the first PDF export doesn't pay the load cost.\n * Safe to call multiple times.\n */\nexport function preloadHarfBuzz(): Promise<HBInstance> {\n return getHB();\n}\n","/**\n * SVG Text-to-Path Conversion (universal outlining)\n *\n * Converts EVERY <text> element to <path> elements using the actual font the\n * browser is rendering. This guarantees 100% visual parity between the canvas\n * preview and the downloaded vector PDF — what you see is what you get, for\n * any font (Google Fonts, local TTFs) and any script (Latin, Devanagari, etc.).\n *\n * Tradeoffs vs. leaving text as <text>:\n * + Pixel-perfect parity for any font, including unknown weights, custom kerns,\n * ligatures, and complex Indic shaping.\n * - Text is no longer selectable/searchable in the PDF.\n * - PDF file size grows ~30-50% (paths are bigger than text + embedded TTF).\n *\n * Mechanics:\n * - Latin runs → opentype.js getPath() (uses font's own metrics)\n * - Devanagari → HarfBuzz shaping for proper conjuncts/matra reordering\n * - Mixed runs → split by script, advance cursor between runs\n * - text-anchor → run width measured via the font; offset applied\n * - Failure → keep original <text> so the user still sees something\n */\n\nimport * as opentype from 'opentype.js';\nimport {\n FONT_FILES,\n FONT_FALLBACK_SYMBOLS,\n FONT_FALLBACK_DEVANAGARI,\n FONT_FALLBACK_MATH,\n resolveFontWeight,\n resolveDevanagariSibling,\n getGoogleFontBytes,\n getFontshareFontBytes,\n} from '@/lib/pdfFonts';\nimport type { FontWeightFiles } from '@/lib/pdfFonts';\nimport { shapeRunToSvgPath } from '@/lib/harfbuzzShaper';\n\n// Cache parsed fonts to avoid re-fetching\nconst fontCache = new Map<string, opentype.Font>();\n/** Raw font bytes cache — shared between opentype.js and HarfBuzz */\nconst fontBytesCache = new Map<string, Uint8Array>();\n\n/** True if the character is in the Devanagari Unicode block */\nfunction isDevanagari(char: string): boolean {\n const c = char.codePointAt(0) ?? 0;\n return (c >= 0x0900 && c <= 0x097F) || (c >= 0xA8E0 && c <= 0xA8FF) || (c >= 0x1CD0 && c <= 0x1CFF);\n}\n\n/** Check if a string contains any Devanagari characters */\nfunction containsDevanagari(text: string): boolean {\n if (!text) return false;\n for (const char of text) {\n if (isDevanagari(char)) return true;\n }\n return false;\n}\n\n/** True if the character is in Basic Latin, Latin-1, or Latin Extended. */\nfunction isBasicLatinOrLatinExtended(char: string): boolean {\n const c = char.codePointAt(0) ?? 0;\n return c <= 0x024F;\n}\n\ntype FontRunType = 'main' | 'devanagari' | 'math' | 'symbol';\n\n/** Math operators / arrows (≠ ≤ ≥ ≈ ∞ → ← ∑ √ ∈ …) — typically missing from\n * Latin fonts AND from the Noto Sans symbol fallback subset, so they need\n * the dedicated Noto Sans Math fallback to render correctly. */\nfunction isMathOperatorChar(char: string): boolean {\n const c = char.codePointAt(0) ?? 0;\n if (c >= 0x2190 && c <= 0x21FF) return true; // Arrows\n if (c >= 0x2200 && c <= 0x22FF) return true; // Mathematical Operators\n if (c >= 0x2300 && c <= 0x23FF) return true; // Misc Technical\n if (c >= 0x27C0 && c <= 0x27EF) return true; // Misc Math Symbols-A\n if (c >= 0x2980 && c <= 0x29FF) return true; // Misc Math Symbols-B\n if (c >= 0x2A00 && c <= 0x2AFF) return true; // Supplemental Math Operators\n if (c >= 0x2B00 && c <= 0x2B59) return true;\n return false;\n}\n\nfunction classifyCharForFontRun(char: string): FontRunType {\n if (isBasicLatinOrLatinExtended(char)) return 'main';\n if (isDevanagari(char)) return 'devanagari';\n if (isMathOperatorChar(char)) return 'math';\n return 'symbol';\n}\n\n/** Neutral marks/punctuation that don't need their own glyph coverage decision. */\nfunction isIgnorableForCoverage(char: string): boolean {\n return /\\s/.test(char) || /[\\u0964\\u0965\\u200c\\u200d]/u.test(char);\n}\n\n/** True when the parsed font can actually draw every relevant glyph in this run. */\nfunction fontSupportsRun(font: opentype.Font | null, text: string, runType: FontRunType): boolean {\n if (!font) return false;\n for (const char of text) {\n if (isIgnorableForCoverage(char)) continue;\n if (runType === 'devanagari' && !isDevanagari(char)) continue;\n if (runType === 'symbol' && classifyCharForFontRun(char) !== 'symbol') continue;\n if (runType === 'math' && classifyCharForFontRun(char) !== 'math') continue;\n const glyph = font.charToGlyph(char);\n if (!glyph || glyph.index === 0) return false;\n }\n return true;\n}\n\nconst browserMeasureCanvas: HTMLCanvasElement | null = typeof document !== 'undefined'\n ? document.createElement('canvas')\n : null;\n\n/** Measure with the browser's real canvas fallback stack — this is our preview truth source. */\nfunction measureBrowserWidth(fontFamily: string, weight: number, fontSize: number, text: string): number | null {\n const ctx = browserMeasureCanvas?.getContext('2d');\n if (!ctx) return null;\n ctx.font = `normal normal ${weight} ${fontSize}px \"${fontFamily}\"`;\n return ctx.measureText(text).width;\n}\n\nfunction uniqueFamilies(families: Array<string | null | undefined>): string[] {\n const seen = new Set<string>();\n const out: string[] = [];\n for (const family of families) {\n const clean = family?.trim();\n if (!clean || seen.has(clean)) continue;\n seen.add(clean);\n out.push(clean);\n }\n return out;\n}\n\nfunction fontLooksItalic(font: opentype.Font | null | undefined): boolean {\n if (!font) return false;\n const names = font.names as unknown as Record<string, Record<string, string> | undefined>;\n const candidates = [\n names.fontSubfamily?.en,\n names.typographicSubfamily?.en,\n names.fullName?.en,\n names.postScriptName?.en,\n ].filter(Boolean).join(' ');\n return /italic|oblique/i.test(candidates);\n}\n\nfunction syntheticItalicTransform(anchorX: number, baselineY: number): string {\n return `translate(${anchorX} ${baselineY}) skewX(-12) translate(${-anchorX} ${-baselineY})`;\n}\n\n/** Get the font file path for a given weight */\nfunction getFontPath(\n fontFiles: FontWeightFiles,\n weight: number,\n isItalic = false,\n): string | null {\n const resolved = resolveFontWeight(weight);\n const uprightMap: Record<number, (keyof FontWeightFiles)[]> = {\n 300: ['light', 'regular'],\n 400: ['regular'],\n 500: ['medium', 'regular'],\n 600: ['semibold', 'bold'],\n 700: ['bold', 'semibold', 'regular'],\n };\n // Italic/oblique: prefer the matching italic variant, then fall back through\n // other italic variants, then upright as a last resort. Without this italic\n // tspans (e.g. *italic* markdown) silently rendered as upright in the PDF.\n const italicMap: Record<number, (keyof FontWeightFiles)[]> = {\n 300: ['lightItalic', 'italic', 'light', 'regular'],\n 400: ['italic', 'regular'],\n 500: ['mediumItalic', 'italic', 'medium', 'regular'],\n 600: ['semiboldItalic', 'boldItalic', 'italic', 'semibold', 'bold', 'regular'],\n 700: ['boldItalic', 'semiboldItalic', 'italic', 'bold', 'semibold', 'regular'],\n };\n const map = isItalic ? italicMap : uprightMap;\n for (const key of map[resolved] || ['regular']) {\n if (fontFiles[key]) return fontFiles[key]!;\n }\n return fontFiles.regular || null;\n}\n\n/** Build a fetchable font URL without accidentally producing /fonts/fonts/*. */\nfunction resolveFontUrl(fileName: string, fontBaseUrl: string): string {\n if (/^https?:\\/\\//i.test(fileName) || fileName.startsWith('data:')) return fileName;\n if (fileName.startsWith('/')) {\n return typeof window !== 'undefined' ? new URL(fileName, window.location.origin).toString() : fileName;\n }\n const baseUrl = fontBaseUrl.endsWith('/') ? fontBaseUrl : fontBaseUrl + '/';\n return new URL(fileName, baseUrl).toString();\n}\n\n/** Load and cache a font via opentype.js */\nasync function loadFont(fontFamily: string, weight: number, fontBaseUrl: string, isItalic = false): Promise<opentype.Font | null> {\n const cacheKey = `${fontFamily}__${weight}__${isItalic ? 'i' : 'n'}`;\n if (fontCache.has(cacheKey)) return fontCache.get(cacheKey)!;\n\n const fontFiles = FONT_FILES[fontFamily];\n\n // ── Local TTF path ──\n // Use local files for both upright and italic variants when available.\n // (Previously italic always fell through to Google/Fontshare and silently\n // dropped to the regular weight when those lookups failed, so *italic*\n // markdown text rendered upright in the vector PDF.)\n if (fontFiles) {\n const fileName = getFontPath(fontFiles, weight, isItalic);\n if (!fileName) return null;\n const url = resolveFontUrl(fileName, fontBaseUrl);\n try {\n const response = await fetch(url);\n if (!response.ok) {\n console.warn(`[text-to-path] Failed to fetch font ${url}: ${response.status}`);\n return null;\n }\n const buffer = await response.arrayBuffer();\n const bytes = new Uint8Array(buffer);\n fontBytesCache.set(cacheKey, bytes);\n const font = opentype.parse(buffer);\n fontCache.set(cacheKey, font);\n return font;\n } catch (err) {\n console.warn(`[text-to-path] Failed to load local font ${fontFamily}:`, err);\n return null;\n }\n }\n\n // ── Google Fonts fallback (e.g. Mukta, Tiro Devanagari Hindi, Kalam) ──\n try {\n const resolvedWeight = resolveFontWeight(weight);\n // Try Google first, then Fontshare. Both populate the same byte cache shape\n // (`gf:${family}:${weight}:n|i`) so downstream HarfBuzz lookups still hit.\n let bytes = await getGoogleFontBytes(fontFamily, resolvedWeight, isItalic);\n if (!bytes) {\n bytes = await getFontshareFontBytes(fontFamily, resolvedWeight, isItalic);\n }\n // For italic, fall back to upright if italic variant is unavailable so\n // the bold/italic combo still renders the right family.\n if (!bytes && isItalic) {\n bytes = await getGoogleFontBytes(fontFamily, resolvedWeight, false);\n if (!bytes) bytes = await getFontshareFontBytes(fontFamily, resolvedWeight, false);\n }\n if (!bytes) {\n console.warn(`[text-to-path] No TTF available for ${fontFamily} (${weight}) on Google Fonts or Fontshare`);\n return null;\n }\n fontBytesCache.set(cacheKey, bytes);\n // opentype.parse needs an ArrayBuffer (not a typed-array view).\n const ab = bytes.buffer.slice(bytes.byteOffset, bytes.byteOffset + bytes.byteLength) as ArrayBuffer;\n const font = opentype.parse(ab);\n fontCache.set(cacheKey, font);\n return font;\n } catch (err) {\n console.warn(`[text-to-path] Failed to load Google font ${fontFamily}:`, err);\n return null;\n }\n}\n\n/** Get raw font bytes (loads via opentype path if not yet cached). */\nasync function getFontBytes(\n fontFamily: string,\n weight: number,\n fontBaseUrl: string,\n isItalic = false,\n): Promise<{ bytes: Uint8Array; cacheKey: string } | null> {\n const cacheKey = `${fontFamily}__${weight}__${isItalic ? 'i' : 'n'}`;\n if (!fontBytesCache.has(cacheKey)) {\n // Triggers fetch + populates fontBytesCache as a side-effect.\n await loadFont(fontFamily, weight, fontBaseUrl, isItalic);\n }\n const bytes = fontBytesCache.get(cacheKey);\n return bytes ? { bytes, cacheKey } : null;\n}\n\n/** Measure run advance width using opentype's own metrics (kerning enabled). */\nfunction measureRunWidth(font: opentype.Font, text: string, fontSize: number): number {\n try {\n return font.getAdvanceWidth(text, fontSize, { kerning: true });\n } catch {\n try { return font.getAdvanceWidth(text, fontSize); } catch { return text.length * fontSize * 0.5; }\n }\n}\n\n/**\n * Split a string into consecutive runs by script/fallback font,\n * preserving order. Whitespace stays with its preceding run.\n */\nfunction splitByFontRun(text: string): Array<{ text: string; runType: FontRunType }> {\n if (!text) return [];\n const runs: Array<{ text: string; runType: FontRunType }> = [];\n let buf = '';\n let bufType = classifyCharForFontRun(text[0]);\n for (const ch of text) {\n const chType = classifyCharForFontRun(ch);\n // Whitespace and punctuation stick to the current run to avoid breaking shaping.\n const isNeutral = /\\s/.test(ch);\n if (chType === bufType || isNeutral) {\n buf += ch;\n } else {\n if (buf) runs.push({ text: buf, runType: bufType });\n buf = ch;\n bufType = chType;\n }\n }\n if (buf) runs.push({ text: buf, runType: bufType });\n return runs;\n}\n\n/**\n * Generate an SVG path `d` string for a text run using the appropriate engine.\n * Returns { pathData, advance } or null on failure.\n */\nasync function shapeRunToPath(\n run: string,\n isDeva: boolean,\n primaryFont: opentype.Font,\n primaryBytes: { bytes: Uint8Array; cacheKey: string } | null,\n devaFont: opentype.Font | null,\n devaBytes: { bytes: Uint8Array; cacheKey: string } | null,\n x: number,\n y: number,\n fontSize: number,\n): Promise<{ pathData: string; advance: number } | null> {\n // Devanagari → HarfBuzz with the resolved Devanagari font (sibling of the chosen Latin font)\n if (isDeva && devaBytes && devaFont) {\n try {\n const shaped = await shapeRunToSvgPath(\n devaBytes.bytes,\n devaBytes.cacheKey,\n run,\n x,\n y,\n fontSize,\n { script: 'deva', language: 'hin', direction: 'ltr' },\n );\n if (shaped.pathData) {\n const advance = measureRunWidth(devaFont, run, fontSize);\n return { pathData: shaped.pathData, advance };\n }\n } catch (err) {\n console.warn(`[text-to-path] HarfBuzz failed for \"${run}\":`, err);\n }\n // Fall through to opentype.js fallback below using devaFont.\n try {\n const path = devaFont.getPath(run, x, y, fontSize);\n const d = path.toPathData(2);\n if (d && d !== 'M0 0') return { pathData: d, advance: measureRunWidth(devaFont, run, fontSize) };\n } catch { /* noop */ }\n return null;\n }\n\n // Latin / non-Indic → opentype.js getPath with the actual chosen font\n try {\n const path = primaryFont.getPath(run, x, y, fontSize, { kerning: true });\n const d = path.toPathData(2);\n if (d && d !== 'M0 0') return { pathData: d, advance: measureRunWidth(primaryFont, run, fontSize) };\n return { pathData: '', advance: measureRunWidth(primaryFont, run, fontSize) };\n } catch (err) {\n console.warn(`[text-to-path] opentype getPath failed for \"${run}\":`, err);\n return null;\n }\n}\n\n/** Parse a CSS-style transform attribute to extract translate values */\nfunction parseTranslate(transform: string | null): { tx: number; ty: number } {\n if (!transform) return { tx: 0, ty: 0 };\n const m = transform.match(/translate\\(\\s*([-\\d.]+)[ \\s,]+([-\\d.]+)\\s*\\)/);\n if (m) return { tx: parseFloat(m[1]), ty: parseFloat(m[2]) };\n // matrix(a,b,c,d,e,f) — e=tx, f=ty\n const mm = transform.match(/matrix\\(\\s*([-\\d.]+)[ \\s,]+([-\\d.]+)[ \\s,]+([-\\d.]+)[ \\s,]+([-\\d.]+)[ \\s,]+([-\\d.]+)[ \\s,]+([-\\d.]+)\\s*\\)/);\n if (mm) return { tx: parseFloat(mm[5]), ty: parseFloat(mm[6]) };\n return { tx: 0, ty: 0 };\n}\n\n/** Heuristic: does this text need shaping (complex script) we can't trust the PDF font embedder for? */\nfunction needsComplexShaping(text: string): boolean {\n if (!text) return false;\n for (const ch of text) {\n const c = ch.codePointAt(0) ?? 0;\n // Devanagari + extensions\n if ((c >= 0x0900 && c <= 0x097F) || (c >= 0xA8E0 && c <= 0xA8FF) || (c >= 0x1CD0 && c <= 0x1CFF)) return true;\n // Bengali, Gurmukhi, Gujarati, Oriya, Tamil, Telugu, Kannada, Malayalam, Sinhala\n if (c >= 0x0980 && c <= 0x0DFF) return true;\n // Thai, Lao, Tibetan, Myanmar, Khmer\n if (c >= 0x0E00 && c <= 0x0FFF) return true;\n if (c >= 0x1000 && c <= 0x109F) return true;\n if (c >= 0x1780 && c <= 0x17FF) return true;\n // Arabic, Hebrew (RTL + shaping)\n if (c >= 0x0590 && c <= 0x06FF) return true;\n if (c >= 0x0700 && c <= 0x074F) return true;\n // CJK\n if (c >= 0x3000 && c <= 0x9FFF) return true;\n if (c >= 0xAC00 && c <= 0xD7AF) return true;\n // Emoji / supplementary\n if (c >= 0x1F000) return true;\n // Math operators / arrows / misc technical — Latin fonts almost never\n // contain these glyphs, so jsPDF renders them as `.notdef` (backtick).\n // Treat as complex-shaping so they get outlined via the math fallback.\n if (c >= 0x2190 && c <= 0x21FF) return true; // Arrows\n if (c >= 0x2200 && c <= 0x22FF) return true; // Mathematical Operators\n if (c >= 0x2300 && c <= 0x23FF) return true; // Misc Technical\n if (c >= 0x27C0 && c <= 0x27EF) return true; // Misc Math Symbols-A\n if (c >= 0x2980 && c <= 0x29FF) return true; // Misc Math Symbols-B\n if (c >= 0x2A00 && c <= 0x2AFF) return true; // Supplemental Math Operators\n if (c >= 0x2B00 && c <= 0x2B59) return true;\n }\n return false;\n}\n\n/**\n * Decorative / script Latin fonts whose jsPDF text embedding (svg2pdf path)\n * is unreliable in production: either the local TTF isn't shipped under\n * `/fonts/` and the Google Fonts fallback is silently rejected, or the font\n * is single-weight with custom kerning that jsPDF does not honor. Symptom:\n * the PDF shows a generic Times/Helvetica fallback instead of the actual\n * decorative face the user sees on the canvas preview.\n *\n * In `auto` mode we outline these via opentype.js (which fetches the same\n * TTF the browser uses, with Google Fonts fallback) so the downloaded PDF\n * matches the canvas pixel-for-pixel. Body fonts (Inter, Roboto, Montserrat,\n * Open Sans, etc.) stay selectable.\n *\n * Match is case- and space-insensitive against the resolved CSS family.\n */\nconst DECORATIVE_OUTLINE_FAMILIES = new Set<string>([\n 'greatvibes', 'great vibes',\n 'cinzel', 'cinzeldecorative', 'cinzel decorative',\n 'pacifico',\n 'allura',\n 'alexbrush', 'alex brush',\n 'abrilfatface', 'abril fatface',\n 'cormorant', 'cormorantgaramond', 'cormorant garamond',\n 'dancingscript', 'dancing script',\n 'sacramento',\n 'lobster',\n 'satisfy',\n 'kaushanscript', 'kaushan script',\n 'parisienne',\n 'tangerine',\n 'yellowtail',\n 'shadowsintolight', 'shadows into light',\n 'amaticsc', 'amatic sc',\n 'caveat',\n 'playball',\n 'marckscript', 'marck script',\n 'courgette',\n]);\n\nfunction isDecorativeFamily(family: string | null | undefined): boolean {\n if (!family) return false;\n const k = family.replace(/['\"]/g, '').replace(/\\s+/g, ' ').trim().toLowerCase();\n if (DECORATIVE_OUTLINE_FAMILIES.has(k)) return true;\n // Also match the no-space variant (e.g. \"GreatVibes\" CSS keyword).\n return DECORATIVE_OUTLINE_FAMILIES.has(k.replace(/\\s+/g, ''));\n}\n\n/**\n * Read the resolved font-family of a `<text>` element, walking up the\n * inheritance chain across both attribute and style declarations.\n */\nfunction readResolvedFontFamily(textEl: Element): string | null {\n const readStyleToken = (style: string, prop: string): string | null => {\n const m = style.match(new RegExp(`${prop}\\\\s*:\\\\s*([^;]+)`, 'i'));\n return m?.[1]?.trim() || null;\n };\n let current: Element | null = textEl;\n while (current) {\n const a = current.getAttribute('font-family')?.trim();\n if (a) return a.split(',')[0]?.replace(/['\"]/g, '').trim() || null;\n const s = readStyleToken(current.getAttribute('style') || '', 'font-family');\n if (s) return s.split(',')[0]?.replace(/['\"]/g, '').trim() || null;\n current = current.parentElement;\n }\n return null;\n}\n\nexport interface OutlineTextOptions {\n /**\n * - 'all' (default): outline every <text> for pixel-perfect parity.\n * - 'complex-only': only outline text that contains complex scripts (Indic, Arabic, CJK, emoji);\n * leave Latin text as <text> so it stays selectable in the PDF.\n * - 'mixed-style-only': only outline <text> elements whose tspans override\n * font-weight / font-style / fill (i.e. inline markdown formatting like\n * **bold**, *italic*, [c=primary]color[/c]). Plain text stays selectable\n * while formatted runs render as paths so bold/italic/colored spans don't\n * silently lose their styling because jsPDF only embedded one font weight.\n */\n /**\n * Additional mode (v0.5.130 PARITY):\n * - 'shadow-bound' → outline only <text> nodes whose nearest Fabric\n * textbox <g> ancestor carries `data-pd-shadow-blur` (set by\n * textBackgroundRenderer when a non-zero-blur shadow is emitted) OR\n * <text> nodes that live inside a `g.__pdShadowRaster` marker. Visible\n * text and shadow silhouette text then share IDENTICAL glyph outlines,\n * so the rasterized shadow PNG aligns pixel-perfect with the\n * svg2pdf-drawn vector text — fixing the small horizontal drift that\n * appeared on centered text with shadow > 0 in both client and server\n * PDF exports.\n */\n mode?: 'all' | 'complex-only' | 'mixed-style-only' | 'shadow-bound';\n}\n\n/**\n * Convert EVERY <text> element in the SVG to <path> elements using the actual\n * font (Latin → opentype, Devanagari → HarfBuzz). Guarantees 100% font parity\n * between the canvas preview and the downloaded PDF.\n *\n * Name kept as `convertDevanagariTextToPath` for backwards compatibility with\n * existing callers (UsePackage.tsx). The behaviour is now universal — name is\n * a misnomer.\n *\n * @param svgStr - The SVG string from Fabric's toSVG()\n * @param fontBaseUrl - Base URL where TTF font files are served (e.g., '/fonts/')\n * @param options - Outline mode controls (default: outline all)\n * @returns Modified SVG string with text converted to paths\n */\nexport async function convertDevanagariTextToPath(\n svgStr: string,\n fontBaseUrl?: string,\n options: OutlineTextOptions = {},\n): Promise<string> {\n const baseUrl = fontBaseUrl ?? (typeof window !== 'undefined' ? window.location.origin + '/fonts/' : '/fonts/');\n const mode = options.mode ?? 'all';\n\n const parser = new DOMParser();\n const doc = parser.parseFromString(svgStr, 'image/svg+xml');\n\n // Find all top-level <text> elements (not nested tspans)\n const textEls = doc.querySelectorAll('text');\n let convertedCount = 0;\n let skippedCount = 0;\n\n for (const textEl of textEls) {\n // Invisible accessibility/selectability clones are deliberately kept as\n // live text while the matching visible glyphs are outlined for visual\n // parity. Never convert these clones to paths.\n if ((textEl as any).closest?.('[data-pd-selectable-layer=\"1\"]')) {\n skippedCount++;\n continue;\n }\n\n // Universal mode: process every <text>, not just Devanagari ones.\n const fullText = textEl.textContent || '';\n if (!fullText.trim()) continue;\n\n // 'shadow-bound' mode: outline only text bound to a PDF-sensitive decoration.\n // We accept text that lives directly inside a __pdShadowRaster marker\n // (the silhouette layer) AND text whose nearest Fabric textbox <g> ancestor\n // was tagged for blurred shadow or text background (the visible layer).\n if (mode === 'shadow-bound') {\n const inShadowMarker =\n !!textEl.closest && !!(textEl as any).closest('g.__pdShadowRaster');\n let inTaggedTextbox = false;\n let cur: Element | null = textEl.parentElement;\n while (cur) {\n if (cur.tagName.toLowerCase() === 'g' && (cur.hasAttribute('data-pd-shadow-blur') || cur.hasAttribute('data-pd-text-bg'))) {\n inTaggedTextbox = true;\n break;\n }\n cur = cur.parentElement;\n }\n if (!inShadowMarker && !inTaggedTextbox) {\n skippedCount++;\n continue;\n }\n }\n\n // Helper: does any tspan override formatting (markdown bold/italic/color/decoration)?\n const hasMixedStyleTspans = (): boolean => {\n const tspansAll = textEl.querySelectorAll('tspan');\n const readProp = (el: Element, prop: string): string => {\n const attr = (el.getAttribute(prop) || '').trim();\n if (attr) return attr;\n const style = el.getAttribute('style') || '';\n const m = style.match(new RegExp(`(?:^|;)\\\\s*${prop}\\\\s*:\\\\s*([^;]+)`, 'i'));\n return m ? m[1].trim() : '';\n };\n const baseWeight = readProp(textEl, 'font-weight');\n const baseStyle = readProp(textEl, 'font-style');\n const baseFill = readProp(textEl, 'fill');\n const baseDeco = readProp(textEl, 'text-decoration');\n for (const ts of tspansAll) {\n const tw = readProp(ts, 'font-weight');\n const tst = readProp(ts, 'font-style');\n const tFill = readProp(ts, 'fill');\n const tDeco = readProp(ts, 'text-decoration');\n const tBg = (ts.getAttribute('style') || '').match(/background|text-background/i);\n if (\n (tw && tw !== baseWeight) ||\n (tst && tst !== baseStyle) ||\n (tFill && tFill !== baseFill) ||\n (tDeco && tDeco !== baseDeco) ||\n tBg\n ) {\n return true;\n }\n }\n return false;\n };\n\n // 'complex-only' mode: leave plain Latin text as real selectable text,\n // BUT still outline (a) anything with markdown formatting (mixed-style\n // tspans) since svg2pdf only embeds one font weight per element, and\n // (b) text rendered in a known decorative / script Latin family whose\n // jsPDF embedding is unreliable (GreatVibes, Cinzel, Pacifico, etc.).\n // Without (b) the downloaded PDF silently falls back to Times/Helvetica\n // for those fonts even though the canvas preview shows the real face.\n if (mode === 'complex-only') {\n const resolvedFamily = readResolvedFontFamily(textEl);\n const decorative = isDecorativeFamily(resolvedFamily);\n if (\n !needsComplexShaping(fullText) &&\n !hasMixedStyleTspans() &&\n !decorative\n ) {\n skippedCount++;\n continue;\n }\n }\n\n // 'mixed-style-only' mode: only outline <text> elements that have any\n // tspan with formatting overrides relative to the parent <text> (different\n // font-weight, font-style, fill, or text-decoration). These come from\n // inline markdown — bold/italic/highlight/color runs that svg2pdf can't\n // render correctly because jsPDF only has the element's base font embedded.\n if (mode === 'mixed-style-only' && !hasMixedStyleTspans()) {\n skippedCount++;\n continue;\n }\n\n // Resolve font properties\n const readStyleToken = (style: string, prop: string): string | null => {\n const m = style.match(new RegExp(`${prop}\\\\s*:\\\\s*([^;]+)`, 'i'));\n return m?.[1]?.trim() || null;\n };\n\n const getAttrOrStyle = (el: Element, attr: string): string | null => {\n let current: Element | null = el;\n while (current) {\n const attrVal = current.getAttribute(attr)?.trim();\n if (attrVal) return attrVal;\n const styleVal = readStyleToken(current.getAttribute('style') || '', attr);\n if (styleVal) return styleVal;\n current = current.parentElement;\n }\n return null;\n };\n\n const fontFamily = getAttrOrStyle(textEl, 'font-family')\n ?.split(',')[0]\n ?.replace(/['\"]/g, '')\n .trim();\n\n const fontSizeStr = getAttrOrStyle(textEl, 'font-size') || '16';\n const fontSize = parseFloat(fontSizeStr);\n\n const fontWeightStr = getAttrOrStyle(textEl, 'font-weight') || '400';\n const fontWeight = Number.parseInt(fontWeightStr, 10) || 400;\n\n const fillColor = getAttrOrStyle(textEl, 'fill') || '#000000';\n const fillOpacity = getAttrOrStyle(textEl, 'fill-opacity') || '1';\n\n if (!fontFamily) {\n skippedCount++;\n continue;\n }\n\n // ── Load the PRIMARY font (the exact font shown in the preview) ──\n const primaryFont = await loadFont(fontFamily, fontWeight, baseUrl);\n const primaryBytes = await getFontBytes(fontFamily, fontWeight, baseUrl);\n\n // ── Devanagari font resolution ──\n // The browser canvas does NOT use curated siblings when a Latin font lacks\n // Hindi glyphs. It uses the CSS/font fallback stack; in our preview path\n // that fallback is Hind. For parity, pick the candidate whose shaped width\n // matches browser canvas measurement, with the chosen family itself first\n // for fonts like Poppins that genuinely include Devanagari glyphs.\n const hasDeva = containsDevanagari(fullText);\n const hasSymbol = [...fullText].some((char) => classifyCharForFontRun(char) === 'symbol');\n const hasMath = [...fullText].some((char) => classifyCharForFontRun(char) === 'math');\n const devaCandidateFamilies = hasDeva\n ? uniqueFamilies([fontFamily, FONT_FALLBACK_DEVANAGARI, resolveDevanagariSibling(fontFamily)])\n : [];\n type ResolvedRunFont = { family: string; font: opentype.Font; bytes: { bytes: Uint8Array; cacheKey: string } };\n const devaRunFontCache = new Map<string, Promise<ResolvedRunFont | null>>();\n const resolveDevaFontForRun = (runText: string, runFontSize: number): Promise<ResolvedRunFont | null> => {\n const cacheKey = `${runText}__${runFontSize}`;\n const cached = devaRunFontCache.get(cacheKey);\n if (cached) return cached;\n\n const promise = (async () => {\n const browserWidth = measureBrowserWidth(fontFamily, fontWeight, runFontSize, runText);\n let best: (ResolvedRunFont & { diff: number }) | null = null;\n\n for (const family of devaCandidateFamilies) {\n const font = family === fontFamily ? primaryFont : await loadFont(family, fontWeight, baseUrl);\n const bytes = family === fontFamily ? primaryBytes : await getFontBytes(family, fontWeight, baseUrl);\n if (!font || !bytes || !fontSupportsRun(font, runText, 'devanagari')) continue;\n\n const width = measureRunWidth(font, runText, runFontSize);\n const diff = browserWidth == null ? 0 : Math.abs(width - browserWidth);\n if (!best || diff < best.diff) best = { family, font, bytes, diff };\n\n // Exact/near-exact match to canvas measurement — no need to keep trying.\n if (browserWidth != null && diff <= 0.25) break;\n }\n\n if (best) {\n console.log('[text-to-path] Devanagari font resolved', {\n requestedFamily: fontFamily,\n resolvedFamily: best.family,\n browserWidth,\n diff: Math.round(best.diff * 100) / 100,\n });\n }\n return best;\n })();\n\n devaRunFontCache.set(cacheKey, promise);\n return promise;\n };\n\n const symbolRunFontPromise: Promise<ResolvedRunFont | null> | null = hasSymbol\n ? (async () => {\n const symbolFont = await loadFont(FONT_FALLBACK_SYMBOLS, 400, baseUrl);\n const symbolBytes = await getFontBytes(FONT_FALLBACK_SYMBOLS, 400, baseUrl);\n return symbolFont && symbolBytes ? { family: FONT_FALLBACK_SYMBOLS, font: symbolFont, bytes: symbolBytes } : null;\n })()\n : null;\n const mathRunFontPromise: Promise<ResolvedRunFont | null> | null = hasMath\n ? (async () => {\n const mathFont = await loadFont(FONT_FALLBACK_MATH, 400, baseUrl);\n const mathBytes = await getFontBytes(FONT_FALLBACK_MATH, 400, baseUrl);\n return mathFont && mathBytes ? { family: FONT_FALLBACK_MATH, font: mathFont, bytes: mathBytes } : null;\n })()\n : null;\n\n // If we have NEITHER a primary font nor (for Devanagari) a fallback font,\n // we can't outline this element — leave the original <text> in place so\n // the user still sees something rather than nothing.\n if (!primaryFont && !hasDeva && !hasSymbol && !hasMath) {\n console.warn(`[text-to-path] No font available for \"${fontFamily}\", leaving as <text>`);\n skippedCount++;\n continue;\n }\n\n // Resolve text-anchor (Fabric uses 'middle' for centered text). We measure the\n // run width and apply a leftward shift so the anchor point matches.\n const textAnchorRaw = (getAttrOrStyle(textEl, 'text-anchor') || 'start').toLowerCase();\n const baseTextAnchor: 'start' | 'middle' | 'end' =\n textAnchorRaw === 'middle' ? 'middle' : textAnchorRaw === 'end' ? 'end' : 'start';\n\n // Process tspan children or direct text\n const tspans = textEl.querySelectorAll('tspan');\n const elementsToProcess = tspans.length > 0 ? Array.from(tspans) : [textEl];\n\n // Create a <g> group to replace the <text> element\n const group = doc.createElementNS('http://www.w3.org/2000/svg', 'g');\n\n // Copy transform from <text> to <g>\n const textTransform = textEl.getAttribute('transform');\n if (textTransform) group.setAttribute('transform', textTransform);\n\n // Get base x/y from the <text> element\n const baseX = parseFloat(textEl.getAttribute('x') || '0');\n const baseY = parseFloat(textEl.getAttribute('y') || '0');\n\n for (const elem of elementsToProcess) {\n const text = elem.textContent || '';\n if (!text.trim()) continue;\n\n // Get element-specific position\n const elemX = parseFloat(elem.getAttribute('x') || String(baseX));\n const elemY = parseFloat(elem.getAttribute('y') || String(baseY));\n const elemAnchorRaw = (getAttrOrStyle(elem, 'text-anchor') || baseTextAnchor).toLowerCase();\n const elemTextAnchor: 'start' | 'middle' | 'end' =\n elemAnchorRaw === 'middle' ? 'middle' : elemAnchorRaw === 'end' ? 'end' : 'start';\n\n // Get element-specific transform\n const elemTransform = elem !== textEl ? parseTranslate(elem.getAttribute('transform')) : { tx: 0, ty: 0 };\n let x = elemX + elemTransform.tx;\n const y = elemY + elemTransform.ty;\n\n // Get element-specific fill\n const elemFill = getAttrOrStyle(elem, 'fill') || fillColor;\n const elemFillOpacity = getAttrOrStyle(elem, 'fill-opacity') || fillOpacity;\n\n // Get element-specific font size\n const elemFontSizeStr = getAttrOrStyle(elem, 'font-size') || String(fontSize);\n const elemFontSize = parseFloat(elemFontSizeStr);\n\n // ── Per-element font weight / style (markdown bold/italic support) ──\n // Each tspan may override font-weight (e.g. **bold**) and font-style\n // (e.g. *italic*). Resolve per-element so we load the matching font\n // variant for outlining instead of always using the parent font.\n const elemWeightStr = getAttrOrStyle(elem, 'font-weight') || String(fontWeight);\n const elemWeight = Number.parseInt(elemWeightStr, 10) || (/bold/i.test(elemWeightStr) ? 700 : fontWeight);\n const elemStyleRaw = (getAttrOrStyle(elem, 'font-style') || 'normal').toLowerCase();\n const elemItalic = /italic|oblique/i.test(elemStyleRaw);\n const sameAsPrimary = elemWeight === fontWeight && !elemItalic;\n const elemFont = sameAsPrimary\n ? primaryFont\n : await loadFont(fontFamily, elemWeight, baseUrl, elemItalic);\n const elemBytes = sameAsPrimary\n ? primaryBytes\n : await getFontBytes(fontFamily, elemWeight, baseUrl, elemItalic);\n // If the variant didn't load, fall back to the primary font so we still\n // render something — better than dropping the tspan entirely.\n const fontForElem = elemFont || primaryFont;\n const bytesForElem = elemBytes || primaryBytes;\n\n // Split into font runs so each run uses the appropriate font/shaper.\n const runs = splitByFontRun(text);\n\n // First pass — measure total advance for text-anchor alignment.\n // We can only compute this if every run has a font; otherwise skip and\n // assume start-anchor (Fabric defaults to start for left-aligned text).\n let totalAdvance = 0;\n let canMeasureAll = true;\n for (const r of runs) {\n if (r.runType === 'devanagari') {\n const resolved = await resolveDevaFontForRun(r.text, elemFontSize);\n if (resolved) totalAdvance += measureRunWidth(resolved.font, r.text, elemFontSize);\n else canMeasureAll = false;\n } else if (r.runType === 'symbol') {\n const resolved = await symbolRunFontPromise;\n if (resolved && fontSupportsRun(resolved.font, r.text, 'symbol')) totalAdvance += measureRunWidth(resolved.font, r.text, elemFontSize);\n else canMeasureAll = false;\n } else if (r.runType === 'math') {\n const resolved = await mathRunFontPromise;\n if (resolved && fontSupportsRun(resolved.font, r.text, 'math')) totalAdvance += measureRunWidth(resolved.font, r.text, elemFontSize);\n else canMeasureAll = false;\n } else {\n if (fontForElem) totalAdvance += measureRunWidth(fontForElem, r.text, elemFontSize);\n else canMeasureAll = false;\n }\n }\n\n if (canMeasureAll) {\n if (elemTextAnchor === 'middle') x -= totalAdvance / 2;\n else if (elemTextAnchor === 'end') x -= totalAdvance;\n }\n\n // Second pass — emit a <path> per run.\n let cursor = x;\n let elemConverted = false;\n for (const r of runs) {\n // Pick the font that matches the browser-rendered canvas for this run.\n const resolvedDeva = r.runType === 'devanagari' ? await resolveDevaFontForRun(r.text, elemFontSize) : null;\n const resolvedSymbol = r.runType === 'symbol' ? await symbolRunFontPromise : null;\n const resolvedMath = r.runType === 'math' ? await mathRunFontPromise : null;\n const useDeva = !!resolvedDeva;\n const fontForRun = resolvedDeva?.font ?? resolvedSymbol?.font ?? resolvedMath?.font ?? fontForElem;\n const bytesForRun = resolvedDeva?.bytes ?? resolvedSymbol?.bytes ?? resolvedMath?.bytes ?? bytesForElem;\n if (!fontForRun) continue;\n\n const result = await shapeRunToPath(\n r.text,\n !!useDeva,\n fontForRun,\n bytesForRun,\n resolvedDeva?.font ?? null,\n resolvedDeva?.bytes ?? null,\n cursor,\n y,\n elemFontSize,\n );\n\n if (result && result.pathData) {\n const pathEl = doc.createElementNS('http://www.w3.org/2000/svg', 'path');\n pathEl.setAttribute('d', result.pathData);\n pathEl.setAttribute('fill', elemFill);\n if (elemItalic && !fontLooksItalic(fontForRun)) {\n // Families like Excon have no italic file; the browser preview uses\n // synthetic oblique, so skew the outlined glyph paths to match it.\n pathEl.setAttribute('transform', syntheticItalicTransform(cursor, y));\n }\n if (elemFillOpacity !== '1') {\n pathEl.setAttribute('fill-opacity', elemFillOpacity);\n }\n group.appendChild(pathEl);\n elemConverted = true;\n }\n if (result) cursor += result.advance;\n }\n\n if (elemConverted) {\n convertedCount++;\n } else {\n // Couldn't outline — keep original element so something renders.\n if (elem === textEl) {\n const clone = elem.cloneNode(true) as Element;\n if (textTransform) clone.removeAttribute('transform');\n group.appendChild(clone);\n } else {\n const newText = doc.createElementNS('http://www.w3.org/2000/svg', 'text');\n newText.setAttribute('x', String(elemX));\n newText.setAttribute('y', String(elemY));\n if (elem.getAttribute('style')) newText.setAttribute('style', elem.getAttribute('style')!);\n if (elem.getAttribute('font-family')) newText.setAttribute('font-family', elem.getAttribute('font-family')!);\n if (elem.getAttribute('font-size')) newText.setAttribute('font-size', elem.getAttribute('font-size')!);\n if (elem.getAttribute('font-weight')) newText.setAttribute('font-weight', elem.getAttribute('font-weight')!);\n newText.textContent = text;\n group.appendChild(newText);\n }\n }\n }\n\n // Replace <text> with <g> containing paths\n if (group.childNodes.length > 0) {\n textEl.parentNode?.replaceChild(group, textEl);\n }\n }\n\n console.log(\n `[text-to-path] Universal outline complete: converted=${convertedCount} skipped=${skippedCount}`,\n );\n\n return new XMLSerializer().serializeToString(doc.documentElement);\n}\n\n/**\n * Alias for `convertDevanagariTextToPath` with a clearer name. Both call the\n * same universal outliner — the older name is kept for backwards compatibility.\n */\nexport const convertAllTextToPath = convertDevanagariTextToPath;\n\n/**\n * Pre-warm the font cache for Devanagari fonts.\n * Call this early to avoid latency during PDF export.\n */\nexport async function preloadDevanagariFont(fontBaseUrl?: string): Promise<void> {\n const baseUrl = fontBaseUrl ?? (typeof window !== 'undefined' ? window.location.origin + '/fonts/' : '/fonts/');\n for (const weight of [300, 400, 500, 600, 700]) {\n await loadFont(FONT_FALLBACK_DEVANAGARI, weight, baseUrl);\n }\n}\n"],"names":["fontCache","fontBytesCache","opentype","_a"],"mappings":"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"}