@pixldocs/canvas-renderer 0.5.117 → 0.5.119

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.
Files changed (33) hide show
  1. package/dist/index-81pAjQOk.cjs +18489 -0
  2. package/dist/index-81pAjQOk.cjs.map +1 -0
  3. package/dist/index-CuTWdeXZ.js +18474 -0
  4. package/dist/index-CuTWdeXZ.js.map +1 -0
  5. package/dist/index.cjs +36 -18109
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.d.ts +19 -1
  8. package/dist/index.js +36 -18092
  9. package/dist/index.js.map +1 -1
  10. package/dist/pdfFonts-CB5z77qO.js +1014 -0
  11. package/dist/pdfFonts-CB5z77qO.js.map +1 -0
  12. package/dist/{svgTextToPath-CQ2Tp03U.js → pdfFonts-CHHpRsRK.cjs} +304 -645
  13. package/dist/pdfFonts-CHHpRsRK.cjs.map +1 -0
  14. package/dist/pdfWatermark-CewmS9qQ.js +36 -0
  15. package/dist/pdfWatermark-CewmS9qQ.js.map +1 -0
  16. package/dist/pdfWatermark-DdBUt6s5.cjs +36 -0
  17. package/dist/pdfWatermark-DdBUt6s5.cjs.map +1 -0
  18. package/dist/{svgColorUtils-BkKZ8cyd.js → svgColorUtils-CIehRL4U.js} +262 -1
  19. package/dist/{svgColorUtils-BkKZ8cyd.js.map → svgColorUtils-CIehRL4U.js.map} +1 -1
  20. package/dist/{svgColorUtils-DQN6fbIM.cjs → svgColorUtils-DKcCq1sO.cjs} +262 -1
  21. package/dist/{svgColorUtils-DQN6fbIM.cjs.map → svgColorUtils-DKcCq1sO.cjs.map} +1 -1
  22. package/dist/svgTextToPath-B6FmPvcr.js +626 -0
  23. package/dist/svgTextToPath-B6FmPvcr.js.map +1 -0
  24. package/dist/svgTextToPath-B77kYzHp.cjs +665 -0
  25. package/dist/svgTextToPath-B77kYzHp.cjs.map +1 -0
  26. package/dist/vectorPdfExport-BrHHt_7L.js +4749 -0
  27. package/dist/vectorPdfExport-BrHHt_7L.js.map +1 -0
  28. package/dist/vectorPdfExport-CyJXH2cR.cjs +4766 -0
  29. package/dist/vectorPdfExport-CyJXH2cR.cjs.map +1 -0
  30. package/package.json +1 -1
  31. package/dist/svgTextToPath-4Y_THSBg.cjs +0 -1393
  32. package/dist/svgTextToPath-4Y_THSBg.cjs.map +0 -1
  33. package/dist/svgTextToPath-CQ2Tp03U.js.map +0 -1
@@ -0,0 +1,1014 @@
1
+ const __vite_import_meta_env__ = { "BASE_URL": "/", "DEV": false, "MODE": "production", "PROD": true, "SSR": false };
2
+ const fontCache = /* @__PURE__ */ new Map();
3
+ const fontBytesCache = /* @__PURE__ */ new Map();
4
+ const googleFontUrlCache = /* @__PURE__ */ new Map();
5
+ const googleFontNotFound = /* @__PURE__ */ new Set();
6
+ const registeredFamilies = /* @__PURE__ */ new Set();
7
+ const registeredVariantCoverage = /* @__PURE__ */ new Map();
8
+ const isFamilyEmbedded = (family) => registeredFamilies.has(family);
9
+ const registeredVariants = /* @__PURE__ */ new Set();
10
+ const variantKey = (family, weight, italic) => `${family}|${weight}|${italic ? "i" : "n"}`;
11
+ const remoteVariantKey = (family, weight, italic) => `${family}|${resolveFontWeight(weight)}|${italic ? "i" : "n"}`;
12
+ const doesVariantSupportChar = (family, weight, italic, char) => {
13
+ var _a;
14
+ const cp = char.codePointAt(0);
15
+ if (cp == null) return false;
16
+ return ((_a = registeredVariantCoverage.get(variantKey(family, resolveFontWeight(weight), italic))) == null ? void 0 : _a.has(cp)) === true;
17
+ };
18
+ const resolveBestRegisteredVariant = (family, weight, italic) => {
19
+ const want = resolveFontWeight(weight);
20
+ const weights = [300, 400, 500, 600, 700];
21
+ if (registeredVariants.has(variantKey(family, want, italic))) {
22
+ return { weight: want, italic };
23
+ }
24
+ const sortedByDistance = [...weights].sort((a, b) => {
25
+ const da = Math.abs(a - want);
26
+ const db = Math.abs(b - want);
27
+ if (da !== db) return da - db;
28
+ return want >= 500 ? b - a : a - b;
29
+ });
30
+ for (const w of sortedByDistance) {
31
+ if (registeredVariants.has(variantKey(family, w, italic))) {
32
+ return { weight: w, italic };
33
+ }
34
+ }
35
+ for (const w of sortedByDistance) {
36
+ if (registeredVariants.has(variantKey(family, w, !italic))) {
37
+ return { weight: w, italic: !italic };
38
+ }
39
+ }
40
+ return null;
41
+ };
42
+ function resolveFontProxyUrl() {
43
+ const fromEnv = (() => {
44
+ try {
45
+ return (__vite_import_meta_env__ == null ? void 0 : __vite_import_meta_env__.VITE_SUPABASE_URL) ?? "";
46
+ } catch {
47
+ return "";
48
+ }
49
+ })();
50
+ const fromWindow = (() => {
51
+ try {
52
+ return typeof window !== "undefined" && window.__PIXLDOCS_SUPABASE_URL || "";
53
+ } catch {
54
+ return "";
55
+ }
56
+ })();
57
+ const base = fromEnv || fromWindow || "";
58
+ return base ? `${base}/functions/v1/font-proxy` : "";
59
+ }
60
+ async function fetchTtfViaProxy(family, weight, isItalic, source) {
61
+ const proxyUrl = resolveFontProxyUrl();
62
+ if (!proxyUrl) return null;
63
+ try {
64
+ const url = `${proxyUrl}?family=${encodeURIComponent(family)}&weight=${weight}&italic=${isItalic ? 1 : 0}&source=${source}`;
65
+ const res = await fetch(url);
66
+ if (!res.ok) return null;
67
+ const buf = await res.arrayBuffer();
68
+ return new Uint8Array(buf);
69
+ } catch {
70
+ return null;
71
+ }
72
+ }
73
+ const FONT_WEIGHT_LABELS = {
74
+ 300: "Light",
75
+ 400: "Regular",
76
+ 500: "Medium",
77
+ 600: "SemiBold",
78
+ 700: "Bold"
79
+ };
80
+ function resolveFontWeight(weight) {
81
+ if (weight <= 350) return 300;
82
+ if (weight <= 450) return 400;
83
+ if (weight <= 550) return 500;
84
+ if (weight <= 650) return 600;
85
+ return 700;
86
+ }
87
+ const FONT_FALLBACK_SYMBOLS = "Noto Sans";
88
+ const FONT_FALLBACK_MATH = "Noto Sans Math";
89
+ const FONT_FALLBACK_DEVANAGARI = "Hind";
90
+ const FONT_FILES = {
91
+ "Playfair Display": {
92
+ regular: "/fonts/PlayfairDisplay-Regular.ttf",
93
+ bold: "/fonts/PlayfairDisplay-Bold.ttf",
94
+ italic: "/fonts/PlayfairDisplay-Italic.ttf",
95
+ boldItalic: "/fonts/PlayfairDisplay-BoldItalic.ttf"
96
+ },
97
+ "Merriweather": {
98
+ regular: "/fonts/Merriweather-Regular.ttf",
99
+ bold: "/fonts/Merriweather-Bold.ttf",
100
+ light: "/fonts/Merriweather-Light.ttf",
101
+ italic: "/fonts/Merriweather-Italic.ttf",
102
+ boldItalic: "/fonts/Merriweather-BoldItalic.ttf",
103
+ lightItalic: "/fonts/Merriweather-LightItalic.ttf"
104
+ },
105
+ "Lora": {
106
+ regular: "/fonts/Lora-Regular.ttf",
107
+ bold: "/fonts/Lora-Bold.ttf",
108
+ italic: "/fonts/Lora-Italic.ttf",
109
+ boldItalic: "/fonts/Lora-BoldItalic.ttf"
110
+ },
111
+ "Montserrat": {
112
+ regular: "/fonts/Montserrat-Regular.ttf",
113
+ bold: "/fonts/Montserrat-Bold.ttf",
114
+ light: "/fonts/Montserrat-Light.ttf",
115
+ medium: "/fonts/Montserrat-Medium.ttf",
116
+ semibold: "/fonts/Montserrat-SemiBold.ttf",
117
+ italic: "/fonts/Montserrat-Italic.ttf",
118
+ boldItalic: "/fonts/Montserrat-BoldItalic.ttf",
119
+ lightItalic: "/fonts/Montserrat-LightItalic.ttf",
120
+ mediumItalic: "/fonts/Montserrat-MediumItalic.ttf",
121
+ semiboldItalic: "/fonts/Montserrat-SemiBoldItalic.ttf"
122
+ },
123
+ "Open Sans": {
124
+ regular: "/fonts/OpenSans-Regular.ttf",
125
+ bold: "/fonts/OpenSans-Bold.ttf",
126
+ light: "/fonts/OpenSans-Light.ttf",
127
+ semibold: "/fonts/OpenSans-SemiBold.ttf",
128
+ italic: "/fonts/OpenSans-Italic.ttf",
129
+ boldItalic: "/fonts/OpenSans-BoldItalic.ttf",
130
+ lightItalic: "/fonts/OpenSans-LightItalic.ttf",
131
+ semiboldItalic: "/fonts/OpenSans-SemiBoldItalic.ttf"
132
+ },
133
+ "Roboto": {
134
+ regular: "/fonts/Roboto-Regular.ttf",
135
+ bold: "/fonts/Roboto-Bold.ttf",
136
+ light: "/fonts/Roboto-Light.ttf",
137
+ medium: "/fonts/Roboto-Medium.ttf",
138
+ italic: "/fonts/Roboto-Italic.ttf",
139
+ boldItalic: "/fonts/Roboto-BoldItalic.ttf",
140
+ lightItalic: "/fonts/Roboto-LightItalic.ttf",
141
+ mediumItalic: "/fonts/Roboto-MediumItalic.ttf"
142
+ },
143
+ "Lato": {
144
+ regular: "/fonts/Lato-Regular.ttf",
145
+ bold: "/fonts/Lato-Bold.ttf",
146
+ light: "/fonts/Lato-Light.ttf",
147
+ italic: "/fonts/Lato-Italic.ttf",
148
+ boldItalic: "/fonts/Lato-BoldItalic.ttf",
149
+ lightItalic: "/fonts/Lato-LightItalic.ttf"
150
+ },
151
+ "Raleway": {
152
+ regular: "/fonts/Raleway-Regular.ttf",
153
+ bold: "/fonts/Raleway-Bold.ttf",
154
+ light: "/fonts/Raleway-Light.ttf",
155
+ medium: "/fonts/Raleway-Medium.ttf",
156
+ semibold: "/fonts/Raleway-SemiBold.ttf",
157
+ italic: "/fonts/Raleway-Italic.ttf",
158
+ boldItalic: "/fonts/Raleway-BoldItalic.ttf",
159
+ lightItalic: "/fonts/Raleway-LightItalic.ttf"
160
+ },
161
+ "Poppins": {
162
+ regular: "/fonts/Poppins-Regular.ttf",
163
+ bold: "/fonts/Poppins-Bold.ttf",
164
+ light: "/fonts/Poppins-Light.ttf",
165
+ medium: "/fonts/Poppins-Medium.ttf",
166
+ semibold: "/fonts/Poppins-SemiBold.ttf",
167
+ italic: "/fonts/Poppins-Italic.ttf",
168
+ boldItalic: "/fonts/Poppins-BoldItalic.ttf",
169
+ lightItalic: "/fonts/Poppins-LightItalic.ttf",
170
+ mediumItalic: "/fonts/Poppins-MediumItalic.ttf",
171
+ semiboldItalic: "/fonts/Poppins-SemiBoldItalic.ttf"
172
+ },
173
+ "Inter": {
174
+ regular: "/fonts/Inter-Regular.ttf",
175
+ bold: "/fonts/Inter-Bold.ttf",
176
+ italic: "/fonts/Inter-Italic.ttf",
177
+ boldItalic: "/fonts/Inter-BoldItalic.ttf"
178
+ },
179
+ "Nunito": {
180
+ regular: "/fonts/Nunito-Regular.ttf",
181
+ bold: "/fonts/Nunito-Bold.ttf",
182
+ light: "/fonts/Nunito-Light.ttf",
183
+ medium: "/fonts/Nunito-Medium.ttf",
184
+ semibold: "/fonts/Nunito-SemiBold.ttf",
185
+ italic: "/fonts/Nunito-Italic.ttf",
186
+ boldItalic: "/fonts/Nunito-BoldItalic.ttf"
187
+ },
188
+ "Source Sans Pro": {
189
+ regular: "/fonts/SourceSansPro-Regular.ttf",
190
+ bold: "/fonts/SourceSansPro-Bold.ttf",
191
+ light: "/fonts/SourceSansPro-Light.ttf",
192
+ italic: "/fonts/SourceSansPro-Italic.ttf",
193
+ boldItalic: "/fonts/SourceSansPro-BoldItalic.ttf"
194
+ },
195
+ "Work Sans": {
196
+ regular: "/fonts/WorkSans-Regular.ttf",
197
+ bold: "/fonts/WorkSans-Bold.ttf",
198
+ italic: "/fonts/WorkSans-Italic.ttf",
199
+ boldItalic: "/fonts/WorkSans-BoldItalic.ttf"
200
+ },
201
+ "Oswald": { regular: "/fonts/Oswald-Regular.ttf", bold: "/fonts/Oswald-Bold.ttf" },
202
+ "Bebas Neue": { regular: "/fonts/BebasNeue-Regular.ttf" },
203
+ "Abril Fatface": { regular: "/fonts/AbrilFatface-Regular.ttf" },
204
+ "Dancing Script": { regular: "/fonts/DancingScript-Regular.ttf", bold: "/fonts/DancingScript-Bold.ttf" },
205
+ "Pacifico": { regular: "/fonts/Pacifico-Regular.ttf" },
206
+ "Great Vibes": { regular: "/fonts/GreatVibes-Regular.ttf" },
207
+ // ── Previously variable-only fonts — now with static per-weight TTFs for PDF export ──
208
+ "DM Sans": {
209
+ regular: "/fonts/DMSans-Regular.ttf",
210
+ bold: "/fonts/DMSans-Bold.ttf",
211
+ light: "/fonts/DMSans-Light.ttf",
212
+ medium: "/fonts/DMSans-Medium.ttf",
213
+ semibold: "/fonts/DMSans-SemiBold.ttf",
214
+ italic: "/fonts/DMSans-RegularItalic.ttf",
215
+ boldItalic: "/fonts/DMSans-BoldItalic.ttf",
216
+ lightItalic: "/fonts/DMSans-LightItalic.ttf",
217
+ mediumItalic: "/fonts/DMSans-MediumItalic.ttf",
218
+ semiboldItalic: "/fonts/DMSans-SemiBoldItalic.ttf"
219
+ },
220
+ "Outfit": {
221
+ regular: "/fonts/Outfit-Regular.ttf",
222
+ bold: "/fonts/Outfit-Bold.ttf",
223
+ light: "/fonts/Outfit-Light.ttf",
224
+ medium: "/fonts/Outfit-Medium.ttf",
225
+ semibold: "/fonts/Outfit-SemiBold.ttf"
226
+ },
227
+ "Figtree": {
228
+ regular: "/fonts/Figtree-Regular.ttf",
229
+ bold: "/fonts/Figtree-Bold.ttf",
230
+ light: "/fonts/Figtree-Light.ttf",
231
+ medium: "/fonts/Figtree-Medium.ttf",
232
+ semibold: "/fonts/Figtree-SemiBold.ttf",
233
+ italic: "/fonts/Figtree-RegularItalic.ttf",
234
+ boldItalic: "/fonts/Figtree-BoldItalic.ttf",
235
+ lightItalic: "/fonts/Figtree-LightItalic.ttf",
236
+ mediumItalic: "/fonts/Figtree-MediumItalic.ttf",
237
+ semiboldItalic: "/fonts/Figtree-SemiBoldItalic.ttf"
238
+ },
239
+ "Manrope": {
240
+ regular: "/fonts/Manrope-Regular.ttf",
241
+ bold: "/fonts/Manrope-Bold.ttf",
242
+ light: "/fonts/Manrope-Light.ttf",
243
+ medium: "/fonts/Manrope-Medium.ttf",
244
+ semibold: "/fonts/Manrope-SemiBold.ttf"
245
+ },
246
+ "Space Grotesk": {
247
+ regular: "/fonts/SpaceGrotesk-Regular.ttf",
248
+ bold: "/fonts/SpaceGrotesk-Bold.ttf",
249
+ light: "/fonts/SpaceGrotesk-Light.ttf",
250
+ medium: "/fonts/SpaceGrotesk-Medium.ttf",
251
+ semibold: "/fonts/SpaceGrotesk-SemiBold.ttf"
252
+ },
253
+ "League Spartan": {
254
+ regular: "/fonts/LeagueSpartan-Regular.ttf",
255
+ bold: "/fonts/LeagueSpartan-Bold.ttf",
256
+ light: "/fonts/LeagueSpartan-Light.ttf",
257
+ medium: "/fonts/LeagueSpartan-Medium.ttf",
258
+ semibold: "/fonts/LeagueSpartan-SemiBold.ttf"
259
+ },
260
+ "EB Garamond": {
261
+ regular: "/fonts/EBGaramond-Regular.ttf",
262
+ bold: "/fonts/EBGaramond-Bold.ttf",
263
+ medium: "/fonts/EBGaramond-Medium.ttf",
264
+ semibold: "/fonts/EBGaramond-SemiBold.ttf",
265
+ italic: "/fonts/EBGaramond-RegularItalic.ttf",
266
+ boldItalic: "/fonts/EBGaramond-BoldItalic.ttf",
267
+ mediumItalic: "/fonts/EBGaramond-MediumItalic.ttf",
268
+ semiboldItalic: "/fonts/EBGaramond-SemiBoldItalic.ttf"
269
+ },
270
+ "Libre Baskerville": {
271
+ regular: "/fonts/LibreBaskerville-Regular.ttf",
272
+ bold: "/fonts/LibreBaskerville-Bold.ttf",
273
+ italic: "/fonts/LibreBaskerville-RegularItalic.ttf",
274
+ boldItalic: "/fonts/LibreBaskerville-BoldItalic.ttf"
275
+ },
276
+ "Crimson Text": {
277
+ regular: "/fonts/CrimsonText-Regular.ttf",
278
+ bold: "/fonts/CrimsonText-Bold.ttf",
279
+ italic: "/fonts/CrimsonText-Italic.ttf",
280
+ boldItalic: "/fonts/CrimsonText-BoldItalic.ttf"
281
+ },
282
+ "DM Serif Display": {
283
+ regular: "/fonts/DMSerifDisplay-Regular.ttf",
284
+ italic: "/fonts/DMSerifDisplay-Italic.ttf"
285
+ },
286
+ "Libre Franklin": {
287
+ regular: "/fonts/LibreFranklin-Regular.ttf",
288
+ bold: "/fonts/LibreFranklin-Bold.ttf",
289
+ light: "/fonts/LibreFranklin-Light.ttf",
290
+ medium: "/fonts/LibreFranklin-Medium.ttf",
291
+ semibold: "/fonts/LibreFranklin-SemiBold.ttf",
292
+ italic: "/fonts/LibreFranklin-RegularItalic.ttf",
293
+ boldItalic: "/fonts/LibreFranklin-BoldItalic.ttf",
294
+ lightItalic: "/fonts/LibreFranklin-LightItalic.ttf",
295
+ mediumItalic: "/fonts/LibreFranklin-MediumItalic.ttf",
296
+ semiboldItalic: "/fonts/LibreFranklin-SemiBoldItalic.ttf"
297
+ },
298
+ "Mulish": {
299
+ regular: "/fonts/Mulish-Regular.ttf",
300
+ bold: "/fonts/Mulish-Bold.ttf",
301
+ light: "/fonts/Mulish-Light.ttf",
302
+ medium: "/fonts/Mulish-Medium.ttf",
303
+ semibold: "/fonts/Mulish-SemiBold.ttf",
304
+ italic: "/fonts/Mulish-RegularItalic.ttf",
305
+ boldItalic: "/fonts/Mulish-BoldItalic.ttf",
306
+ lightItalic: "/fonts/Mulish-LightItalic.ttf",
307
+ mediumItalic: "/fonts/Mulish-MediumItalic.ttf",
308
+ semiboldItalic: "/fonts/Mulish-SemiBoldItalic.ttf"
309
+ },
310
+ "Quicksand": {
311
+ regular: "/fonts/Quicksand-Regular.ttf",
312
+ bold: "/fonts/Quicksand-Bold.ttf",
313
+ light: "/fonts/Quicksand-Light.ttf",
314
+ medium: "/fonts/Quicksand-Medium.ttf",
315
+ semibold: "/fonts/Quicksand-SemiBold.ttf"
316
+ },
317
+ "Rubik": {
318
+ regular: "/fonts/Rubik-Regular.ttf",
319
+ bold: "/fonts/Rubik-Bold.ttf",
320
+ light: "/fonts/Rubik-Light.ttf",
321
+ medium: "/fonts/Rubik-Medium.ttf",
322
+ semibold: "/fonts/Rubik-SemiBold.ttf",
323
+ italic: "/fonts/Rubik-RegularItalic.ttf",
324
+ boldItalic: "/fonts/Rubik-BoldItalic.ttf",
325
+ lightItalic: "/fonts/Rubik-LightItalic.ttf",
326
+ mediumItalic: "/fonts/Rubik-MediumItalic.ttf",
327
+ semiboldItalic: "/fonts/Rubik-SemiBoldItalic.ttf"
328
+ },
329
+ "Karla": {
330
+ regular: "/fonts/Karla-Regular.ttf",
331
+ bold: "/fonts/Karla-Bold.ttf",
332
+ light: "/fonts/Karla-Light.ttf",
333
+ medium: "/fonts/Karla-Medium.ttf",
334
+ semibold: "/fonts/Karla-SemiBold.ttf",
335
+ italic: "/fonts/Karla-RegularItalic.ttf",
336
+ boldItalic: "/fonts/Karla-BoldItalic.ttf",
337
+ lightItalic: "/fonts/Karla-LightItalic.ttf",
338
+ mediumItalic: "/fonts/Karla-MediumItalic.ttf",
339
+ semiboldItalic: "/fonts/Karla-SemiBoldItalic.ttf"
340
+ },
341
+ "Plus Jakarta Sans": {
342
+ regular: "/fonts/PlusJakartaSans-Regular.ttf",
343
+ bold: "/fonts/PlusJakartaSans-Bold.ttf",
344
+ light: "/fonts/PlusJakartaSans-Light.ttf",
345
+ medium: "/fonts/PlusJakartaSans-Medium.ttf",
346
+ semibold: "/fonts/PlusJakartaSans-SemiBold.ttf",
347
+ italic: "/fonts/PlusJakartaSans-RegularItalic.ttf",
348
+ boldItalic: "/fonts/PlusJakartaSans-BoldItalic.ttf",
349
+ lightItalic: "/fonts/PlusJakartaSans-LightItalic.ttf",
350
+ mediumItalic: "/fonts/PlusJakartaSans-MediumItalic.ttf",
351
+ semiboldItalic: "/fonts/PlusJakartaSans-SemiBoldItalic.ttf"
352
+ },
353
+ "Sora": {
354
+ regular: "/fonts/Sora-Regular.ttf",
355
+ bold: "/fonts/Sora-Bold.ttf",
356
+ light: "/fonts/Sora-Light.ttf",
357
+ medium: "/fonts/Sora-Medium.ttf",
358
+ semibold: "/fonts/Sora-SemiBold.ttf"
359
+ },
360
+ "Urbanist": {
361
+ regular: "/fonts/Urbanist-Regular.ttf",
362
+ bold: "/fonts/Urbanist-Bold.ttf",
363
+ light: "/fonts/Urbanist-Light.ttf",
364
+ medium: "/fonts/Urbanist-Medium.ttf",
365
+ semibold: "/fonts/Urbanist-SemiBold.ttf",
366
+ italic: "/fonts/Urbanist-RegularItalic.ttf",
367
+ boldItalic: "/fonts/Urbanist-BoldItalic.ttf",
368
+ lightItalic: "/fonts/Urbanist-LightItalic.ttf",
369
+ mediumItalic: "/fonts/Urbanist-MediumItalic.ttf",
370
+ semiboldItalic: "/fonts/Urbanist-SemiBoldItalic.ttf"
371
+ },
372
+ "Lexend": {
373
+ regular: "/fonts/Lexend-Regular.ttf",
374
+ bold: "/fonts/Lexend-Bold.ttf",
375
+ light: "/fonts/Lexend-Light.ttf",
376
+ medium: "/fonts/Lexend-Medium.ttf",
377
+ semibold: "/fonts/Lexend-SemiBold.ttf"
378
+ },
379
+ "Albert Sans": {
380
+ regular: "/fonts/AlbertSans-Regular.ttf",
381
+ bold: "/fonts/AlbertSans-Bold.ttf",
382
+ light: "/fonts/AlbertSans-Light.ttf",
383
+ medium: "/fonts/AlbertSans-Medium.ttf",
384
+ semibold: "/fonts/AlbertSans-SemiBold.ttf",
385
+ italic: "/fonts/AlbertSans-RegularItalic.ttf",
386
+ boldItalic: "/fonts/AlbertSans-BoldItalic.ttf",
387
+ lightItalic: "/fonts/AlbertSans-LightItalic.ttf",
388
+ mediumItalic: "/fonts/AlbertSans-MediumItalic.ttf",
389
+ semiboldItalic: "/fonts/AlbertSans-SemiBoldItalic.ttf"
390
+ },
391
+ "Noto Sans": {
392
+ regular: "/fonts/NotoSans-Regular.ttf",
393
+ bold: "/fonts/NotoSans-Bold.ttf",
394
+ light: "/fonts/NotoSans-Light.ttf",
395
+ medium: "/fonts/NotoSans-Medium.ttf",
396
+ semibold: "/fonts/NotoSans-SemiBold.ttf",
397
+ italic: "/fonts/NotoSans-RegularItalic.ttf",
398
+ boldItalic: "/fonts/NotoSans-BoldItalic.ttf",
399
+ lightItalic: "/fonts/NotoSans-LightItalic.ttf",
400
+ mediumItalic: "/fonts/NotoSans-MediumItalic.ttf",
401
+ semiboldItalic: "/fonts/NotoSans-SemiBoldItalic.ttf"
402
+ },
403
+ "Cabin": {
404
+ regular: "/fonts/Cabin-Regular.ttf",
405
+ bold: "/fonts/Cabin-Bold.ttf",
406
+ medium: "/fonts/Cabin-Medium.ttf",
407
+ semibold: "/fonts/Cabin-SemiBold.ttf",
408
+ italic: "/fonts/Cabin-RegularItalic.ttf",
409
+ boldItalic: "/fonts/Cabin-BoldItalic.ttf",
410
+ mediumItalic: "/fonts/Cabin-MediumItalic.ttf",
411
+ semiboldItalic: "/fonts/Cabin-SemiBoldItalic.ttf"
412
+ },
413
+ "Barlow": {
414
+ regular: "/fonts/Barlow-Regular.ttf",
415
+ bold: "/fonts/Barlow-Bold.ttf",
416
+ light: "/fonts/Barlow-Light.ttf",
417
+ medium: "/fonts/Barlow-Medium.ttf",
418
+ semibold: "/fonts/Barlow-SemiBold.ttf",
419
+ italic: "/fonts/Barlow-Italic.ttf",
420
+ boldItalic: "/fonts/Barlow-BoldItalic.ttf"
421
+ },
422
+ "Josefin Sans": {
423
+ regular: "/fonts/JosefinSans-Regular.ttf",
424
+ bold: "/fonts/JosefinSans-Bold.ttf",
425
+ light: "/fonts/JosefinSans-Light.ttf",
426
+ medium: "/fonts/JosefinSans-Medium.ttf",
427
+ semibold: "/fonts/JosefinSans-SemiBold.ttf",
428
+ italic: "/fonts/JosefinSans-RegularItalic.ttf",
429
+ boldItalic: "/fonts/JosefinSans-BoldItalic.ttf",
430
+ lightItalic: "/fonts/JosefinSans-LightItalic.ttf",
431
+ mediumItalic: "/fonts/JosefinSans-MediumItalic.ttf",
432
+ semiboldItalic: "/fonts/JosefinSans-SemiBoldItalic.ttf"
433
+ },
434
+ "Archivo": {
435
+ regular: "/fonts/Archivo-Regular.ttf",
436
+ bold: "/fonts/Archivo-Bold.ttf",
437
+ light: "/fonts/Archivo-Light.ttf",
438
+ medium: "/fonts/Archivo-Medium.ttf",
439
+ semibold: "/fonts/Archivo-SemiBold.ttf",
440
+ italic: "/fonts/Archivo-RegularItalic.ttf",
441
+ boldItalic: "/fonts/Archivo-BoldItalic.ttf",
442
+ lightItalic: "/fonts/Archivo-LightItalic.ttf",
443
+ mediumItalic: "/fonts/Archivo-MediumItalic.ttf",
444
+ semiboldItalic: "/fonts/Archivo-SemiBoldItalic.ttf"
445
+ },
446
+ "Overpass": {
447
+ regular: "/fonts/Overpass-Regular.ttf",
448
+ bold: "/fonts/Overpass-Bold.ttf",
449
+ light: "/fonts/Overpass-Light.ttf",
450
+ medium: "/fonts/Overpass-Medium.ttf",
451
+ semibold: "/fonts/Overpass-SemiBold.ttf",
452
+ italic: "/fonts/Overpass-RegularItalic.ttf",
453
+ boldItalic: "/fonts/Overpass-BoldItalic.ttf",
454
+ lightItalic: "/fonts/Overpass-LightItalic.ttf",
455
+ mediumItalic: "/fonts/Overpass-MediumItalic.ttf",
456
+ semiboldItalic: "/fonts/Overpass-SemiBoldItalic.ttf"
457
+ },
458
+ "Exo 2": {
459
+ regular: "/fonts/Exo2-Regular.ttf",
460
+ bold: "/fonts/Exo2-Bold.ttf",
461
+ light: "/fonts/Exo2-Light.ttf",
462
+ medium: "/fonts/Exo2-Medium.ttf",
463
+ semibold: "/fonts/Exo2-SemiBold.ttf",
464
+ italic: "/fonts/Exo2-RegularItalic.ttf",
465
+ boldItalic: "/fonts/Exo2-BoldItalic.ttf",
466
+ lightItalic: "/fonts/Exo2-LightItalic.ttf",
467
+ mediumItalic: "/fonts/Exo2-MediumItalic.ttf",
468
+ semiboldItalic: "/fonts/Exo2-SemiBoldItalic.ttf"
469
+ },
470
+ "Roboto Mono": {
471
+ regular: "/fonts/RobotoMono-Regular.ttf",
472
+ bold: "/fonts/RobotoMono-Bold.ttf",
473
+ light: "/fonts/RobotoMono-Light.ttf",
474
+ medium: "/fonts/RobotoMono-Medium.ttf",
475
+ semibold: "/fonts/RobotoMono-SemiBold.ttf",
476
+ italic: "/fonts/RobotoMono-RegularItalic.ttf",
477
+ boldItalic: "/fonts/RobotoMono-BoldItalic.ttf",
478
+ lightItalic: "/fonts/RobotoMono-LightItalic.ttf",
479
+ mediumItalic: "/fonts/RobotoMono-MediumItalic.ttf",
480
+ semiboldItalic: "/fonts/RobotoMono-SemiBoldItalic.ttf"
481
+ },
482
+ "Fira Code": {
483
+ regular: "/fonts/FiraCode-Regular.ttf",
484
+ bold: "/fonts/FiraCode-Bold.ttf",
485
+ light: "/fonts/FiraCode-Light.ttf",
486
+ medium: "/fonts/FiraCode-Medium.ttf",
487
+ semibold: "/fonts/FiraCode-SemiBold.ttf"
488
+ },
489
+ "JetBrains Mono": {
490
+ regular: "/fonts/JetBrainsMono-Regular.ttf",
491
+ bold: "/fonts/JetBrainsMono-Bold.ttf",
492
+ light: "/fonts/JetBrainsMono-Light.ttf",
493
+ medium: "/fonts/JetBrainsMono-Medium.ttf",
494
+ semibold: "/fonts/JetBrainsMono-SemiBold.ttf",
495
+ italic: "/fonts/JetBrainsMono-RegularItalic.ttf",
496
+ boldItalic: "/fonts/JetBrainsMono-BoldItalic.ttf",
497
+ lightItalic: "/fonts/JetBrainsMono-LightItalic.ttf",
498
+ mediumItalic: "/fonts/JetBrainsMono-MediumItalic.ttf",
499
+ semiboldItalic: "/fonts/JetBrainsMono-SemiBoldItalic.ttf"
500
+ },
501
+ "Source Code Pro": {
502
+ regular: "/fonts/SourceCodePro-Regular.ttf",
503
+ bold: "/fonts/SourceCodePro-Bold.ttf",
504
+ light: "/fonts/SourceCodePro-Light.ttf",
505
+ medium: "/fonts/SourceCodePro-Medium.ttf",
506
+ semibold: "/fonts/SourceCodePro-SemiBold.ttf",
507
+ italic: "/fonts/SourceCodePro-RegularItalic.ttf",
508
+ boldItalic: "/fonts/SourceCodePro-BoldItalic.ttf",
509
+ lightItalic: "/fonts/SourceCodePro-LightItalic.ttf",
510
+ mediumItalic: "/fonts/SourceCodePro-MediumItalic.ttf",
511
+ semiboldItalic: "/fonts/SourceCodePro-SemiBoldItalic.ttf"
512
+ },
513
+ "IBM Plex Mono": {
514
+ regular: "/fonts/IBMPlexMono-Regular.ttf",
515
+ bold: "/fonts/IBMPlexMono-Bold.ttf"
516
+ },
517
+ "Space Mono": {
518
+ regular: "/fonts/SpaceMono-Regular.ttf",
519
+ bold: "/fonts/SpaceMono-Bold.ttf",
520
+ italic: "/fonts/SpaceMono-Italic.ttf",
521
+ boldItalic: "/fonts/SpaceMono-BoldItalic.ttf"
522
+ },
523
+ "Sacramento": { regular: "/fonts/Sacramento-Regular.ttf" },
524
+ "Alex Brush": { regular: "/fonts/AlexBrush-Regular.ttf" },
525
+ "Allura": { regular: "/fonts/Allura-Regular.ttf" },
526
+ "Caveat": {
527
+ regular: "/fonts/Caveat-Regular.ttf",
528
+ bold: "/fonts/Caveat-Bold.ttf",
529
+ medium: "/fonts/Caveat-Medium.ttf",
530
+ semibold: "/fonts/Caveat-SemiBold.ttf"
531
+ },
532
+ "Lobster": { regular: "/fonts/Lobster-Regular.ttf" },
533
+ "Comfortaa": {
534
+ regular: "/fonts/Comfortaa-Regular.ttf",
535
+ bold: "/fonts/Comfortaa-Bold.ttf",
536
+ light: "/fonts/Comfortaa-Light.ttf",
537
+ medium: "/fonts/Comfortaa-Medium.ttf",
538
+ semibold: "/fonts/Comfortaa-SemiBold.ttf"
539
+ },
540
+ "Anton": { regular: "/fonts/Anton-Regular.ttf" },
541
+ "Teko": {
542
+ regular: "/fonts/Teko-Regular.ttf",
543
+ bold: "/fonts/Teko-Bold.ttf",
544
+ light: "/fonts/Teko-Light.ttf",
545
+ medium: "/fonts/Teko-Medium.ttf",
546
+ semibold: "/fonts/Teko-SemiBold.ttf"
547
+ },
548
+ // ── Indic Script Fallback Fonts ──
549
+ "Noto Sans Devanagari": {
550
+ regular: "/fonts/NotoSansDevanagari-Regular.ttf",
551
+ bold: "/fonts/NotoSansDevanagari-Bold.ttf",
552
+ light: "/fonts/NotoSansDevanagari-Light.ttf",
553
+ medium: "/fonts/NotoSansDevanagari-Medium.ttf",
554
+ semibold: "/fonts/NotoSansDevanagari-SemiBold.ttf"
555
+ },
556
+ "Hind": {
557
+ regular: "/fonts/Hind-Regular.ttf",
558
+ bold: "/fonts/Hind-Bold.ttf",
559
+ light: "/fonts/Hind-Light.ttf",
560
+ medium: "/fonts/Hind-Medium.ttf",
561
+ semibold: "/fonts/Hind-SemiBold.ttf"
562
+ },
563
+ // ── Math / Operator Symbol Fallback ──
564
+ // Carries glyphs that NotoSans-Regular's Latin subset is missing
565
+ // (≠ ≤ ≥ ≈ ∞ → ← × ÷ ∑ √ ∈ ∀ ∃ etc.). Used as a tertiary fallback
566
+ // ONLY for chars classified as 'math' that the main font + Noto Sans
567
+ // both lack.
568
+ "Noto Sans Math": {
569
+ regular: "/fonts/NotoSansMath-Regular.ttf"
570
+ }
571
+ };
572
+ function isJsPdfEmbeddableTrueType(bytes) {
573
+ if (bytes.length < 12) return false;
574
+ const signature = String.fromCharCode(bytes[0], bytes[1], bytes[2], bytes[3]);
575
+ if (signature !== "\0\0\0" && signature !== "true") return false;
576
+ const u16 = (offset) => bytes[offset] << 8 | bytes[offset + 1];
577
+ const u32 = (offset) => (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
578
+ const tableCount = u16(4);
579
+ for (let i = 0; i < tableCount; i++) {
580
+ const recordOffset = 12 + i * 16;
581
+ if (recordOffset + 16 > bytes.length) return false;
582
+ const tag = String.fromCharCode(bytes[recordOffset], bytes[recordOffset + 1], bytes[recordOffset + 2], bytes[recordOffset + 3]);
583
+ if (tag !== "cmap") continue;
584
+ const cmapOffset = u32(recordOffset + 8);
585
+ const cmapLength = u32(recordOffset + 12);
586
+ if (cmapOffset + Math.min(cmapLength, 4) > bytes.length) return false;
587
+ const subtables = u16(cmapOffset + 2);
588
+ for (let j = 0; j < subtables; j++) {
589
+ const encOffset = cmapOffset + 4 + j * 8;
590
+ if (encOffset + 8 > bytes.length) return false;
591
+ const platform = u16(encOffset);
592
+ const encoding = u16(encOffset + 2);
593
+ if (platform === 0 || platform === 3 && (encoding === 1 || encoding === 10)) return true;
594
+ }
595
+ return false;
596
+ }
597
+ return false;
598
+ }
599
+ function extractSupportedCodePointsFromTtf(bytes) {
600
+ const supported = /* @__PURE__ */ new Set();
601
+ if (bytes.length < 12) return supported;
602
+ const u16 = (offset) => bytes[offset] << 8 | bytes[offset + 1];
603
+ const i16 = (offset) => {
604
+ const value = u16(offset);
605
+ return value & 32768 ? value - 65536 : value;
606
+ };
607
+ const u32 = (offset) => (bytes[offset] << 24 | bytes[offset + 1] << 16 | bytes[offset + 2] << 8 | bytes[offset + 3]) >>> 0;
608
+ const tableCount = u16(4);
609
+ let cmapOffset = 0;
610
+ for (let i = 0; i < tableCount; i++) {
611
+ const recordOffset = 12 + i * 16;
612
+ if (recordOffset + 16 > bytes.length) return supported;
613
+ if (String.fromCharCode(bytes[recordOffset], bytes[recordOffset + 1], bytes[recordOffset + 2], bytes[recordOffset + 3]) === "cmap") {
614
+ cmapOffset = u32(recordOffset + 8);
615
+ break;
616
+ }
617
+ }
618
+ if (!cmapOffset || cmapOffset + 4 > bytes.length) return supported;
619
+ const subtables = u16(cmapOffset + 2);
620
+ const candidates = [];
621
+ for (let j = 0; j < subtables; j++) {
622
+ const encOffset = cmapOffset + 4 + j * 8;
623
+ if (encOffset + 8 > bytes.length) continue;
624
+ const platform = u16(encOffset);
625
+ const encoding = u16(encOffset + 2);
626
+ const subOffset = cmapOffset + u32(encOffset + 4);
627
+ if (subOffset + 2 > bytes.length) continue;
628
+ const format = u16(subOffset);
629
+ const score = format === 12 ? 40 : format === 4 ? 30 : 0;
630
+ if (score) candidates.push({ format, offset: subOffset, score: score + (platform === 3 && encoding === 10 ? 2 : platform === 0 ? 1 : 0) });
631
+ }
632
+ candidates.sort((a, b) => b.score - a.score);
633
+ const best = candidates[0];
634
+ if (!best) return supported;
635
+ if (best.format === 12 && best.offset + 16 <= bytes.length) {
636
+ const nGroups = u32(best.offset + 12);
637
+ for (let i = 0; i < nGroups; i++) {
638
+ const off = best.offset + 16 + i * 12;
639
+ if (off + 12 > bytes.length) break;
640
+ const start = u32(off);
641
+ const end = u32(off + 4);
642
+ for (let cp = start; cp <= end && cp <= 1114111; cp++) supported.add(cp);
643
+ }
644
+ } else if (best.format === 4 && best.offset + 14 <= bytes.length) {
645
+ const segCount = u16(best.offset + 6) / 2;
646
+ const endCodes = best.offset + 14;
647
+ const startCodes = endCodes + segCount * 2 + 2;
648
+ const idDeltas = startCodes + segCount * 2;
649
+ const idRangeOffsets = idDeltas + segCount * 2;
650
+ for (let i = 0; i < segCount; i++) {
651
+ const start = u16(startCodes + i * 2);
652
+ const end = u16(endCodes + i * 2);
653
+ const delta = i16(idDeltas + i * 2);
654
+ const rangeOffset = u16(idRangeOffsets + i * 2);
655
+ for (let cp = start; cp <= end && cp !== 65535; cp++) {
656
+ if (rangeOffset === 0) {
657
+ if ((cp + delta & 65535) !== 0) supported.add(cp);
658
+ } else {
659
+ const glyphOffset = idRangeOffsets + i * 2 + rangeOffset + (cp - start) * 2;
660
+ if (glyphOffset + 2 <= bytes.length && u16(glyphOffset) !== 0) supported.add(cp);
661
+ }
662
+ }
663
+ }
664
+ }
665
+ return supported;
666
+ }
667
+ function base64ToBytes(base64) {
668
+ const binary = atob(base64);
669
+ const bytes = new Uint8Array(binary.length);
670
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
671
+ return bytes;
672
+ }
673
+ const getJsPDFFontName = (fontName) => {
674
+ return fontName.replace(/\s+/g, "");
675
+ };
676
+ const WEIGHT_TO_KEYS = {
677
+ 300: ["light", "regular"],
678
+ 400: ["regular"],
679
+ 500: ["medium", "regular"],
680
+ 600: ["semibold", "bold", "regular"],
681
+ 700: ["bold", "regular"]
682
+ };
683
+ const WEIGHT_TO_ITALIC_KEYS = {
684
+ 300: ["lightItalic", "italic", "light", "regular"],
685
+ 400: ["italic", "regular"],
686
+ 500: ["mediumItalic", "italic", "medium", "regular"],
687
+ 600: ["semiboldItalic", "boldItalic", "italic", "semibold", "bold", "regular"],
688
+ 700: ["boldItalic", "italic", "bold", "regular"]
689
+ };
690
+ function getFontPathForWeight(fontFiles, resolvedWeight, isItalic = false) {
691
+ const keys = isItalic ? WEIGHT_TO_ITALIC_KEYS[resolvedWeight] : WEIGHT_TO_KEYS[resolvedWeight];
692
+ if (!keys) return fontFiles.regular;
693
+ for (const k of keys) {
694
+ const path = fontFiles[k];
695
+ if (path) return path;
696
+ }
697
+ return fontFiles.regular;
698
+ }
699
+ function isExactWeightItalicMatch(fontFiles, resolvedWeight, isItalic, resolvedPath) {
700
+ const exactKey = isItalic ? resolvedWeight === 300 ? "lightItalic" : resolvedWeight === 500 ? "mediumItalic" : resolvedWeight === 600 ? "semiboldItalic" : resolvedWeight === 700 ? "boldItalic" : "italic" : resolvedWeight === 300 ? "light" : resolvedWeight === 500 ? "medium" : resolvedWeight === 600 ? "semibold" : resolvedWeight === 700 ? "bold" : "regular";
701
+ return fontFiles[exactKey] === resolvedPath;
702
+ }
703
+ const getEmbeddedJsPDFFontName = (fontName, weight, isItalic = false) => {
704
+ const resolved = resolveFontWeight(weight);
705
+ const label = FONT_WEIGHT_LABELS[resolved];
706
+ const italicSuffix = isItalic ? "Italic" : "";
707
+ return `${getJsPDFFontName(fontName)}-${label}${italicSuffix}`;
708
+ };
709
+ const embedFont = async (pdf, fontName, weight = 400, isItalic = false) => {
710
+ const fontFiles = FONT_FILES[fontName];
711
+ if (!fontFiles) {
712
+ console.warn(`Font ${fontName} not found in local fonts`);
713
+ return false;
714
+ }
715
+ const resolvedWeight = resolveFontWeight(weight);
716
+ const fontPath = getFontPathForWeight(fontFiles, resolvedWeight, isItalic);
717
+ if (!fontPath) return false;
718
+ if (!isExactWeightItalicMatch(fontFiles, resolvedWeight, isItalic, fontPath)) {
719
+ return false;
720
+ }
721
+ const label = FONT_WEIGHT_LABELS[resolvedWeight];
722
+ const italicSuffix = isItalic ? "Italic" : "";
723
+ const cacheKey = `${fontName}-${resolvedWeight}${isItalic ? "-italic" : ""}`;
724
+ const jsPdfFontName = getEmbeddedJsPDFFontName(fontName, weight, isItalic);
725
+ try {
726
+ let base64Font = fontCache.get(cacheKey);
727
+ if (!base64Font) {
728
+ const response = await fetch(fontPath);
729
+ if (!response.ok) throw new Error(`Failed to fetch font: ${response.statusText}`);
730
+ const arrayBuffer = await response.arrayBuffer();
731
+ const bytes = new Uint8Array(arrayBuffer);
732
+ if (!isJsPdfEmbeddableTrueType(bytes)) throw new Error(`Font is not a jsPDF-compatible TrueType file: ${fontPath}`);
733
+ registeredVariantCoverage.set(variantKey(fontName, resolvedWeight, isItalic), extractSupportedCodePointsFromTtf(bytes));
734
+ let binary = "";
735
+ for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
736
+ base64Font = btoa(binary);
737
+ fontCache.set(cacheKey, base64Font);
738
+ } else if (!registeredVariantCoverage.has(variantKey(fontName, resolvedWeight, isItalic))) {
739
+ registeredVariantCoverage.set(variantKey(fontName, resolvedWeight, isItalic), extractSupportedCodePointsFromTtf(base64ToBytes(base64Font)));
740
+ }
741
+ const fileName = `${getJsPDFFontName(fontName)}-${label}${italicSuffix}.ttf`;
742
+ pdf.addFileToVFS(fileName, base64Font);
743
+ pdf.addFont(fileName, jsPdfFontName, "normal");
744
+ if (fontName !== jsPdfFontName) {
745
+ try {
746
+ pdf.addFont(fileName, fontName, "normal");
747
+ } catch {
748
+ }
749
+ }
750
+ registeredFamilies.add(fontName);
751
+ registeredVariants.add(variantKey(fontName, resolvedWeight, isItalic));
752
+ return true;
753
+ } catch (error) {
754
+ console.error(`Failed to embed font ${fontName} (weight ${weight}, italic=${isItalic}):`, error);
755
+ return false;
756
+ }
757
+ };
758
+ const isFontAvailable = (fontName) => {
759
+ return fontName in FONT_FILES;
760
+ };
761
+ async function fetchGoogleFontTTF(fontFamily, weight = 400, isItalic = false) {
762
+ const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? "i" : "n"}`;
763
+ if (fontCache.has(cacheKey)) return fontCache.get(cacheKey);
764
+ const notFoundKey = remoteVariantKey(fontFamily, weight, isItalic);
765
+ if (googleFontNotFound.has(notFoundKey)) return null;
766
+ const proxyBytes = await fetchTtfViaProxy(fontFamily, weight, isItalic, "google");
767
+ if (proxyBytes && isJsPdfEmbeddableTrueType(proxyBytes)) {
768
+ fontBytesCache.set(cacheKey, proxyBytes);
769
+ let binary = "";
770
+ for (let i = 0; i < proxyBytes.length; i++) binary += String.fromCharCode(proxyBytes[i]);
771
+ const b64 = btoa(binary);
772
+ fontCache.set(cacheKey, b64);
773
+ return b64;
774
+ }
775
+ try {
776
+ const ital = isItalic ? "1" : "0";
777
+ const cssUrl = `https://fonts.googleapis.com/css2?family=${encodeURIComponent(
778
+ fontFamily
779
+ )}:ital,wght@${ital},${weight}&display=swap`;
780
+ const cssRes = await fetch(cssUrl, {
781
+ headers: {
782
+ "User-Agent": "Mozilla/5.0 (Linux; U; Android 2.2; en-us) AppleWebKit/533.1 (KHTML, like Gecko)"
783
+ }
784
+ });
785
+ if (!cssRes.ok) {
786
+ if (cssRes.status === 400 || cssRes.status === 404) googleFontNotFound.add(notFoundKey);
787
+ return null;
788
+ }
789
+ const css = await cssRes.text();
790
+ const urlMatch = css.match(/url\(([^)]+)\)\s+format\(['"]?truetype['"]?\)/i) || css.match(/url\(([^)]+)\)/);
791
+ if (!urlMatch) return null;
792
+ const ttfUrl = urlMatch[1].replace(/['"]/g, "");
793
+ googleFontUrlCache.set(cacheKey, ttfUrl);
794
+ const ttfRes = await fetch(ttfUrl);
795
+ if (!ttfRes.ok) return null;
796
+ const buf = await ttfRes.arrayBuffer();
797
+ const bytes = new Uint8Array(buf);
798
+ if (!isJsPdfEmbeddableTrueType(bytes)) {
799
+ console.warn(`[pdfFonts] Google Fonts returned a non-TTF font for ${fontFamily} (${weight}); skipping jsPDF embed`);
800
+ return null;
801
+ }
802
+ fontBytesCache.set(cacheKey, bytes);
803
+ let binary = "";
804
+ for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
805
+ const b64 = btoa(binary);
806
+ fontCache.set(cacheKey, b64);
807
+ return b64;
808
+ } catch (err) {
809
+ console.warn(`[pdfFonts] fetchGoogleFontTTF failed for ${fontFamily} (${weight}):`, err);
810
+ return null;
811
+ }
812
+ }
813
+ async function getGoogleFontBytes(fontFamily, weight = 400, isItalic = false) {
814
+ const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? "i" : "n"}`;
815
+ if (fontBytesCache.has(cacheKey)) return fontBytesCache.get(cacheKey);
816
+ await fetchGoogleFontTTF(fontFamily, weight, isItalic);
817
+ return fontBytesCache.get(cacheKey) || null;
818
+ }
819
+ const fontshareNotFound = /* @__PURE__ */ new Set();
820
+ function toFontshareSlug(family) {
821
+ return family.trim().toLowerCase().replace(/\s+/g, "-");
822
+ }
823
+ async function fetchFontshareTTF(fontFamily, weight = 400, isItalic = false, slug) {
824
+ const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? "i" : "n"}`;
825
+ if (fontCache.has(cacheKey)) return fontCache.get(cacheKey);
826
+ if (fontshareNotFound.has(fontFamily)) return null;
827
+ const proxyBytes = await fetchTtfViaProxy(fontFamily, weight, isItalic, "fontshare");
828
+ if (proxyBytes && isJsPdfEmbeddableTrueType(proxyBytes)) {
829
+ fontBytesCache.set(cacheKey, proxyBytes);
830
+ let binary = "";
831
+ for (let i = 0; i < proxyBytes.length; i++) binary += String.fromCharCode(proxyBytes[i]);
832
+ const b64 = btoa(binary);
833
+ fontCache.set(cacheKey, b64);
834
+ return b64;
835
+ }
836
+ const finalSlug = toFontshareSlug(fontFamily);
837
+ try {
838
+ const styleSuffix = isItalic ? "i" : "";
839
+ const cssUrl = `https://api.fontshare.com/v2/css?f[]=${finalSlug}@${weight}${styleSuffix}&display=swap`;
840
+ const cssRes = await fetch(cssUrl);
841
+ if (!cssRes.ok) {
842
+ if (cssRes.status === 400 || cssRes.status === 404) fontshareNotFound.add(fontFamily);
843
+ return null;
844
+ }
845
+ const css = await cssRes.text();
846
+ const ttMatch = css.match(/url\(([^)]+)\)\s+format\(['"]?truetype['"]?\)/i);
847
+ if (!ttMatch) {
848
+ fontshareNotFound.add(fontFamily);
849
+ return null;
850
+ }
851
+ let ttfUrl = ttMatch[1].replace(/['"]/g, "").trim();
852
+ if (ttfUrl.startsWith("//")) ttfUrl = `https:${ttfUrl}`;
853
+ const ttfRes = await fetch(ttfUrl);
854
+ if (!ttfRes.ok) return null;
855
+ const buf = await ttfRes.arrayBuffer();
856
+ const bytes = new Uint8Array(buf);
857
+ if (!isJsPdfEmbeddableTrueType(bytes)) {
858
+ console.warn(`[pdfFonts] Fontshare returned a non-TTF font for ${fontFamily} (${weight}); skipping jsPDF embed`);
859
+ return null;
860
+ }
861
+ fontBytesCache.set(cacheKey, bytes);
862
+ let binary = "";
863
+ for (let i = 0; i < bytes.length; i++) binary += String.fromCharCode(bytes[i]);
864
+ const b64 = btoa(binary);
865
+ fontCache.set(cacheKey, b64);
866
+ return b64;
867
+ } catch (err) {
868
+ console.warn(`[pdfFonts] fetchFontshareTTF failed for ${fontFamily} (${weight}):`, err);
869
+ return null;
870
+ }
871
+ }
872
+ async function getFontshareFontBytes(fontFamily, weight = 400, isItalic = false, slug) {
873
+ const cacheKey = `gf:${fontFamily}:${weight}:${isItalic ? "i" : "n"}`;
874
+ if (fontBytesCache.has(cacheKey)) return fontBytesCache.get(cacheKey);
875
+ await fetchFontshareTTF(fontFamily, weight, isItalic);
876
+ return fontBytesCache.get(cacheKey) || null;
877
+ }
878
+ const embedFontWithGoogleFallback = async (pdf, fontName, weight = 400, isItalic = false) => {
879
+ if (FONT_FILES[fontName]) {
880
+ const ok = await embedFont(pdf, fontName, weight, isItalic);
881
+ if (ok) return true;
882
+ }
883
+ const resolvedFs = resolveFontWeight(weight);
884
+ const fsB64 = await fetchFontshareTTF(fontName, resolvedFs, isItalic);
885
+ if (fsB64) {
886
+ return registerJsPdfFont(pdf, fontName, resolvedFs, isItalic, fsB64);
887
+ }
888
+ const resolved = resolveFontWeight(weight);
889
+ const b64 = await fetchGoogleFontTTF(fontName, resolved, isItalic);
890
+ if (!b64) {
891
+ return false;
892
+ }
893
+ return registerJsPdfFont(pdf, fontName, resolved, isItalic, b64);
894
+ };
895
+ function registerJsPdfFont(pdf, fontName, resolvedWeight, isItalic, base64) {
896
+ const label = FONT_WEIGHT_LABELS[resolvedWeight];
897
+ const italicSuffix = isItalic ? "Italic" : "";
898
+ const jsPdfFontName = getEmbeddedJsPDFFontName(fontName, resolvedWeight, isItalic);
899
+ const fileName = `${getJsPDFFontName(fontName)}-${label}${italicSuffix}.ttf`;
900
+ try {
901
+ try {
902
+ const binary = atob(base64);
903
+ const bytes = new Uint8Array(binary.length);
904
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
905
+ registeredVariantCoverage.set(variantKey(fontName, resolvedWeight, isItalic), extractSupportedCodePointsFromTtf(bytes));
906
+ } catch {
907
+ }
908
+ pdf.addFileToVFS(fileName, base64);
909
+ pdf.addFont(fileName, jsPdfFontName, "normal");
910
+ if (fontName !== jsPdfFontName) {
911
+ try {
912
+ pdf.addFont(fileName, fontName, "normal");
913
+ } catch {
914
+ }
915
+ }
916
+ registeredFamilies.add(fontName);
917
+ registeredVariants.add(variantKey(fontName, resolvedWeight, isItalic));
918
+ return true;
919
+ } catch (err) {
920
+ console.warn(`[pdfFonts] registerJsPdfFont failed for ${fontName}:`, err);
921
+ return false;
922
+ }
923
+ }
924
+ const LATIN_TO_DEVANAGARI = {
925
+ // Direct Devanagari subsets — same family carries both scripts
926
+ "Poppins": "Poppins",
927
+ "Noto Sans": "Noto Sans Devanagari",
928
+ "Noto Serif": "Noto Serif Devanagari",
929
+ "Hind": "Hind",
930
+ "Mukta": "Mukta",
931
+ // Curated visual matches (Google's own recommendations)
932
+ "Montserrat": "Mukta",
933
+ "Open Sans": "Mukta",
934
+ "Lato": "Mukta",
935
+ "Roboto": "Mukta",
936
+ "Inter": "Mukta",
937
+ "Nunito": "Mukta",
938
+ "Source Sans Pro": "Mukta",
939
+ "Work Sans": "Mukta",
940
+ "DM Sans": "Mukta",
941
+ "Outfit": "Mukta",
942
+ "Figtree": "Mukta",
943
+ "Manrope": "Mukta",
944
+ "Plus Jakarta Sans": "Mukta",
945
+ "Sora": "Mukta",
946
+ "Urbanist": "Mukta",
947
+ "Lexend": "Mukta",
948
+ "Albert Sans": "Mukta",
949
+ "Cabin": "Mukta",
950
+ "Karla": "Mukta",
951
+ "Mulish": "Mukta",
952
+ "Rubik": "Mukta",
953
+ "Quicksand": "Mukta",
954
+ "Libre Franklin": "Mukta",
955
+ "Barlow": "Mukta",
956
+ "Archivo": "Mukta",
957
+ "Overpass": "Mukta",
958
+ "Josefin Sans": "Mukta",
959
+ "Exo 2": "Mukta",
960
+ "Space Grotesk": "Mukta",
961
+ // Display / heavy
962
+ "Oswald": "Teko",
963
+ "Bebas Neue": "Teko",
964
+ "Anton": "Teko",
965
+ "Teko": "Teko",
966
+ "League Spartan": "Teko",
967
+ // Serifs → Tiro Devanagari Hindi (a refined Devanagari serif)
968
+ "Playfair Display": "Tiro Devanagari Hindi",
969
+ "Merriweather": "Tiro Devanagari Hindi",
970
+ "Lora": "Tiro Devanagari Hindi",
971
+ "EB Garamond": "Tiro Devanagari Hindi",
972
+ "Libre Baskerville": "Tiro Devanagari Hindi",
973
+ "Crimson Text": "Tiro Devanagari Hindi",
974
+ "DM Serif Display": "Tiro Devanagari Sanskrit",
975
+ "Abril Fatface": "Tiro Devanagari Sanskrit",
976
+ // Handwriting → Kalam (the only serious Devanagari handwriting family on GF)
977
+ "Dancing Script": "Kalam",
978
+ "Pacifico": "Kalam",
979
+ "Great Vibes": "Kalam",
980
+ "Sacramento": "Kalam",
981
+ "Alex Brush": "Kalam",
982
+ "Allura": "Kalam",
983
+ "Caveat": "Kalam",
984
+ "Lobster": "Kalam",
985
+ "Comfortaa": "Mukta",
986
+ // Monospace → there's no proper Devanagari mono; fall back to Mukta
987
+ "Roboto Mono": "Mukta",
988
+ "Fira Code": "Mukta",
989
+ "JetBrains Mono": "Mukta",
990
+ "Source Code Pro": "Mukta",
991
+ "IBM Plex Mono": "Mukta",
992
+ "Space Mono": "Mukta"
993
+ };
994
+ function resolveDevanagariSibling(latinFont) {
995
+ if (!latinFont) return FONT_FALLBACK_DEVANAGARI;
996
+ return LATIN_TO_DEVANAGARI[latinFont] || FONT_FALLBACK_DEVANAGARI;
997
+ }
998
+ export {
999
+ FONT_FALLBACK_SYMBOLS as F,
1000
+ FONT_FALLBACK_MATH as a,
1001
+ FONT_FALLBACK_DEVANAGARI as b,
1002
+ isFamilyEmbedded as c,
1003
+ resolveFontWeight as d,
1004
+ embedFontWithGoogleFallback as e,
1005
+ doesVariantSupportChar as f,
1006
+ getEmbeddedJsPDFFontName as g,
1007
+ getGoogleFontBytes as h,
1008
+ isFontAvailable as i,
1009
+ getFontshareFontBytes as j,
1010
+ FONT_FILES as k,
1011
+ resolveDevanagariSibling as l,
1012
+ resolveBestRegisteredVariant as r
1013
+ };
1014
+ //# sourceMappingURL=pdfFonts-CB5z77qO.js.map