@shotstack/shotstack-canvas 1.1.1 → 1.1.3

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.
@@ -153,13 +153,17 @@ async function initHB(wasmBaseURL) {
153
153
  }
154
154
 
155
155
  // src/core/font-registry.ts
156
- var FontRegistry = class {
156
+ var FontRegistry = class _FontRegistry {
157
157
  hb;
158
158
  faces = /* @__PURE__ */ new Map();
159
159
  fonts = /* @__PURE__ */ new Map();
160
160
  blobs = /* @__PURE__ */ new Map();
161
161
  wasmBaseURL;
162
162
  initPromise;
163
+ static fallbackLoader;
164
+ static setFallbackLoader(loader) {
165
+ _FontRegistry.fallbackLoader = loader;
166
+ }
163
167
  constructor(wasmBaseURL) {
164
168
  this.wasmBaseURL = wasmBaseURL;
165
169
  }
@@ -168,9 +172,7 @@ var FontRegistry = class {
168
172
  await this.initPromise;
169
173
  return;
170
174
  }
171
- if (this.hb) {
172
- return;
173
- }
175
+ if (this.hb) return;
174
176
  this.initPromise = this._doInit();
175
177
  try {
176
178
  await this.initPromise;
@@ -222,11 +224,35 @@ var FontRegistry = class {
222
224
  );
223
225
  }
224
226
  }
227
+ async tryFallbackInstall(desc) {
228
+ const loader = _FontRegistry.fallbackLoader;
229
+ if (!loader) return false;
230
+ try {
231
+ const bytes = await loader({
232
+ family: desc.family,
233
+ weight: desc.weight ?? "400",
234
+ style: desc.style ?? "normal"
235
+ });
236
+ if (!bytes) return false;
237
+ await this.registerFromBytes(bytes, {
238
+ family: desc.family,
239
+ weight: desc.weight ?? "400",
240
+ style: desc.style ?? "normal"
241
+ });
242
+ return true;
243
+ } catch {
244
+ return false;
245
+ }
246
+ }
225
247
  async getFont(desc) {
226
248
  try {
227
249
  if (!this.hb) await this.init();
228
250
  const k = this.key(desc);
229
- const f = this.fonts.get(k);
251
+ let f = this.fonts.get(k);
252
+ if (!f) {
253
+ const installed = await this.tryFallbackInstall(desc);
254
+ f = installed ? this.fonts.get(k) : void 0;
255
+ }
230
256
  if (!f) throw new Error(`Font not registered for ${k}`);
231
257
  return f;
232
258
  } catch (err) {
@@ -242,7 +268,12 @@ var FontRegistry = class {
242
268
  try {
243
269
  if (!this.hb) await this.init();
244
270
  const k = this.key(desc);
245
- return this.faces.get(k);
271
+ let face = this.faces.get(k);
272
+ if (!face) {
273
+ const installed = await this.tryFallbackInstall(desc);
274
+ face = installed ? this.faces.get(k) : void 0;
275
+ }
276
+ return face;
246
277
  } catch (err) {
247
278
  throw new Error(
248
279
  `Failed to get face for "${desc.family}": ${err instanceof Error ? err.message : String(err)}`
@@ -498,7 +529,7 @@ async function buildDrawOps(p) {
498
529
  height: p.canvas.height,
499
530
  pixelRatio: p.canvas.pixelRatio,
500
531
  clear: true,
501
- bg: p.background ? { color: p.background.color, opacity: p.background.opacity, radius: p.background.borderRadius } : void 0
532
+ bg: p.background && p.background.color ? { color: p.background.color, opacity: p.background.opacity, radius: p.background.borderRadius } : void 0
502
533
  });
503
534
  if (p.lines.length === 0) return ops;
504
535
  const upem = Math.max(1, await p.getUnitsPerEm());
@@ -1128,6 +1159,7 @@ async function createNodePainter(opts) {
1128
1159
  const globalBox = computeGlobalTextBounds(ops);
1129
1160
  for (const op of ops) {
1130
1161
  if (op.op === "BeginFrame") {
1162
+ if (op.clear) ctx.clearRect(0, 0, op.width, op.height);
1131
1163
  const dpr = op.pixelRatio ?? opts.pixelRatio;
1132
1164
  const wantW = Math.floor(op.width * dpr);
1133
1165
  const wantH = Math.floor(op.height * dpr);
@@ -1136,8 +1168,10 @@ async function createNodePainter(opts) {
1136
1168
  canvas.height = wantH;
1137
1169
  }
1138
1170
  ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
1139
- if (op.clear) ctx.clearRect(0, 0, op.width, op.height);
1140
- if (op.bg) {
1171
+ ctx.save();
1172
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
1173
+ ctx.restore();
1174
+ if (op.bg && op.bg.color) {
1141
1175
  const { color, opacity, radius } = op.bg;
1142
1176
  if (color) {
1143
1177
  const c = parseHex6(color, opacity);