@shotstack/shotstack-canvas 1.0.7 → 1.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/entry.web.js CHANGED
@@ -155,13 +155,32 @@ var FontRegistry = class {
155
155
  __publicField(this, "fonts", /* @__PURE__ */ new Map());
156
156
  __publicField(this, "blobs", /* @__PURE__ */ new Map());
157
157
  __publicField(this, "wasmBaseURL");
158
+ __publicField(this, "initPromise");
158
159
  this.wasmBaseURL = wasmBaseURL;
159
160
  }
160
161
  async init() {
161
- if (!this.hb) this.hb = await initHB(this.wasmBaseURL);
162
+ if (this.initPromise) {
163
+ await this.initPromise;
164
+ return;
165
+ }
166
+ if (this.hb) {
167
+ return;
168
+ }
169
+ this.initPromise = this._doInit();
170
+ await this.initPromise;
171
+ }
172
+ async _doInit() {
173
+ try {
174
+ this.hb = await initHB(this.wasmBaseURL);
175
+ } catch (error) {
176
+ this.initPromise = void 0;
177
+ throw error;
178
+ }
162
179
  }
163
- getHB() {
164
- if (!this.hb) throw new Error("FontRegistry not initialized - call init() first");
180
+ async getHB() {
181
+ if (!this.hb) {
182
+ await this.init();
183
+ }
165
184
  return this.hb;
166
185
  }
167
186
  key(desc) {
@@ -180,23 +199,24 @@ var FontRegistry = class {
180
199
  this.faces.set(k, face);
181
200
  this.fonts.set(k, font);
182
201
  }
183
- getFont(desc) {
202
+ async getFont(desc) {
203
+ if (!this.hb) await this.init();
184
204
  const k = this.key(desc);
185
205
  const f = this.fonts.get(k);
186
206
  if (!f) throw new Error(`Font not registered for ${k}`);
187
207
  return f;
188
208
  }
189
- getFace(desc) {
209
+ async getFace(desc) {
210
+ if (!this.hb) await this.init();
190
211
  const k = this.key(desc);
191
212
  return this.faces.get(k);
192
213
  }
193
- /** NEW: expose units-per-em for scaling glyph paths to px */
194
- getUnitsPerEm(desc) {
195
- const face = this.getFace(desc);
214
+ async getUnitsPerEm(desc) {
215
+ const face = await this.getFace(desc);
196
216
  return face?.upem || 1e3;
197
217
  }
198
- glyphPath(desc, glyphId) {
199
- const font = this.getFont(desc);
218
+ async glyphPath(desc, glyphId) {
219
+ const font = await this.getFont(desc);
200
220
  const path = font.glyphToPath(glyphId);
201
221
  return path && path !== "" ? path : "M 0 0";
202
222
  }
@@ -207,6 +227,8 @@ var FontRegistry = class {
207
227
  this.fonts.clear();
208
228
  this.faces.clear();
209
229
  this.blobs.clear();
230
+ this.hb = void 0;
231
+ this.initPromise = void 0;
210
232
  }
211
233
  };
212
234
 
@@ -227,13 +249,13 @@ var LayoutEngine = class {
227
249
  return t;
228
250
  }
229
251
  }
230
- shapeFull(text, desc) {
231
- const hb = this.fonts.getHB();
252
+ async shapeFull(text, desc) {
253
+ const hb = await this.fonts.getHB();
232
254
  const buffer = hb.createBuffer();
233
255
  buffer.addText(text);
234
256
  buffer.guessSegmentProperties();
235
- const font = this.fonts.getFont(desc);
236
- const face = this.fonts.getFace(desc);
257
+ const font = await this.fonts.getFont(desc);
258
+ const face = await this.fonts.getFace(desc);
237
259
  const upem = face?.upem || 1e3;
238
260
  font.setScale(upem, upem);
239
261
  hb.shape(font, buffer);
@@ -241,17 +263,17 @@ var LayoutEngine = class {
241
263
  buffer.destroy();
242
264
  return result;
243
265
  }
244
- layout(params) {
266
+ async layout(params) {
245
267
  const { textTransform, desc, fontSize, letterSpacing, width } = params;
246
268
  const input = this.transformText(params.text, textTransform);
247
269
  if (!input || input.length === 0) {
248
270
  return [];
249
271
  }
250
- const shaped = this.shapeFull(input, desc);
251
- const face = this.fonts.getFace(desc);
272
+ const shaped = await this.shapeFull(input, desc);
273
+ const face = await this.fonts.getFace(desc);
252
274
  const upem = face?.upem || 1e3;
253
275
  const scale = fontSize / upem;
254
- const glyphs = shaped.map((g, i) => {
276
+ const glyphs = shaped.map((g) => {
255
277
  const charIndex = g.cl;
256
278
  let char;
257
279
  if (charIndex >= 0 && charIndex < input.length) {
@@ -355,7 +377,7 @@ function decorationGeometry(kind, p) {
355
377
  }
356
378
 
357
379
  // src/core/drawops.ts
358
- function buildDrawOps(p) {
380
+ async function buildDrawOps(p) {
359
381
  const ops = [];
360
382
  ops.push({
361
383
  op: "BeginFrame",
@@ -366,7 +388,7 @@ function buildDrawOps(p) {
366
388
  bg: p.background ? { color: p.background.color, opacity: p.background.opacity, radius: p.background.borderRadius } : void 0
367
389
  });
368
390
  if (p.lines.length === 0) return ops;
369
- const upem = Math.max(1, p.getUnitsPerEm?.() ?? 1e3);
391
+ const upem = Math.max(1, await p.getUnitsPerEm());
370
392
  const scale = p.font.size / upem;
371
393
  const blockHeight = p.lines[p.lines.length - 1].y;
372
394
  let blockY;
@@ -402,7 +424,7 @@ function buildDrawOps(p) {
402
424
  let xCursor = lineX;
403
425
  const baselineY = blockY + line.y - p.font.size;
404
426
  for (const glyph of line.glyphs) {
405
- const path = p.glyphPathProvider(glyph.id);
427
+ const path = await p.glyphPathProvider(glyph.id);
406
428
  if (!path || path === "M 0 0") {
407
429
  xCursor += glyph.xAdvance;
408
430
  continue;
@@ -1180,6 +1202,7 @@ async function createTextEngine(opts = {}) {
1180
1202
  const wasmBaseURL = opts.wasmBaseURL;
1181
1203
  const fonts = new FontRegistry(wasmBaseURL);
1182
1204
  const layout = new LayoutEngine(fonts);
1205
+ await fonts.init();
1183
1206
  async function ensureFonts(asset) {
1184
1207
  if (asset.customFonts) {
1185
1208
  for (const cf of asset.customFonts) {
@@ -1226,7 +1249,7 @@ async function createTextEngine(opts = {}) {
1226
1249
  async renderFrame(asset, tSeconds) {
1227
1250
  const main = await ensureFonts(asset);
1228
1251
  const desc = { family: main.family, weight: `${main.weight}`, style: main.style };
1229
- const lines = layout.layout({
1252
+ const lines = await layout.layout({
1230
1253
  text: asset.text,
1231
1254
  width: asset.width ?? width,
1232
1255
  letterSpacing: asset.style?.letterSpacing ?? 0,
@@ -1236,7 +1259,7 @@ async function createTextEngine(opts = {}) {
1236
1259
  textTransform: asset.style?.textTransform ?? "none"
1237
1260
  });
1238
1261
  const textRect = { x: 0, y: 0, width: asset.width ?? width, height: asset.height ?? height };
1239
- const ops0 = buildDrawOps({
1262
+ const ops0 = await buildDrawOps({
1240
1263
  canvas: { width, height, pixelRatio },
1241
1264
  textRect,
1242
1265
  lines,
@@ -1258,7 +1281,6 @@ async function createTextEngine(opts = {}) {
1258
1281
  align: asset.align ?? { horizontal: "left", vertical: "middle" },
1259
1282
  background: asset.background,
1260
1283
  glyphPathProvider: (gid) => fonts.glyphPath(desc, gid),
1261
- /** NEW: provide UPEM so drawops can compute scale */
1262
1284
  getUnitsPerEm: () => fonts.getUnitsPerEm(desc)
1263
1285
  });
1264
1286
  const ops = applyAnimation(ops0, lines, {
@@ -1276,6 +1298,9 @@ async function createTextEngine(opts = {}) {
1276
1298
  },
1277
1299
  createRenderer(canvas) {
1278
1300
  return createWebPainter(canvas);
1301
+ },
1302
+ destroy() {
1303
+ fonts.destroy();
1279
1304
  }
1280
1305
  };
1281
1306
  }