jassub 1.5.2 → 1.5.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.
package/dist/jassub.es.js CHANGED
@@ -1,516 +1,606 @@
1
- var __defProp = Object.defineProperty;
2
- var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
- var __publicField = (obj, key, value) => {
4
- __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
- return value;
6
- };
7
- if (!("requestVideoFrameCallback" in HTMLVideoElement.prototype) && "getVideoPlaybackQuality" in HTMLVideoElement.prototype) {
8
- HTMLVideoElement.prototype._rvfcpolyfillmap = {};
9
- HTMLVideoElement.prototype.requestVideoFrameCallback = function(callback) {
10
- const quality = this.getVideoPlaybackQuality();
11
- const baseline = this.mozPresentedFrames || this.mozPaintedFrames || quality.totalVideoFrames - quality.droppedVideoFrames;
12
- const check = (old, now2) => {
13
- const newquality = this.getVideoPlaybackQuality();
14
- const presentedFrames = this.mozPresentedFrames || this.mozPaintedFrames || newquality.totalVideoFrames - newquality.droppedVideoFrames;
15
- if (presentedFrames > baseline) {
16
- const processingDuration = this.mozFrameDelay || newquality.totalFrameDelay - quality.totalFrameDelay || 0;
17
- const timediff = now2 - old;
18
- callback(now2, {
19
- presentationTime: now2 + processingDuration * 1e3,
20
- expectedDisplayTime: now2 + timediff,
21
- width: this.videoWidth,
22
- height: this.videoHeight,
23
- mediaTime: Math.max(0, this.currentTime || 0) + timediff / 1e3,
24
- presentedFrames,
25
- processingDuration
26
- });
27
- delete this._rvfcpolyfillmap[handle];
28
- } else {
29
- this._rvfcpolyfillmap[handle] = requestAnimationFrame((newer) => check(now2, newer));
30
- }
31
- };
32
- const handle = Date.now();
33
- const now = performance.now();
34
- this._rvfcpolyfillmap[handle] = requestAnimationFrame((newer) => check(now, newer));
35
- return handle;
36
- };
37
- HTMLVideoElement.prototype.cancelVideoFrameCallback = function(handle) {
38
- cancelAnimationFrame(this._rvfcpolyfillmap[handle]);
39
- delete this._rvfcpolyfillmap[handle];
40
- };
41
- }
42
- const _JASSUB = class extends EventTarget {
43
- constructor(options = {}) {
44
- var _a, _b, _c;
45
- super();
46
- if (!globalThis.Worker) {
47
- this.destroy("Worker not supported");
48
- }
49
- _JASSUB._test();
50
- const blendMode = options.blendMode || "js";
51
- const asyncRender = typeof createImageBitmap !== "undefined" && ((_a = options.asyncRender) != null ? _a : true);
52
- const offscreenRender = typeof OffscreenCanvas !== "undefined" && ((_b = options.offscreenRender) != null ? _b : true);
53
- this._onDemandRender = "requestVideoFrameCallback" in HTMLVideoElement.prototype && ((_c = options.onDemandRender) != null ? _c : true);
54
- this.timeOffset = options.timeOffset || 0;
55
- this._video = options.video;
56
- this._videoHeight = 0;
57
- this._videoWidth = 0;
58
- this._canvas = options.canvas;
59
- if (this._video && !this._canvas) {
60
- this._canvasParent = document.createElement("div");
61
- this._canvasParent.className = "JASSUB";
62
- this._canvasParent.style.position = "relative";
63
- this._canvas = document.createElement("canvas");
64
- this._canvas.style.display = "block";
65
- this._canvas.style.position = "absolute";
66
- this._canvas.style.pointerEvents = "none";
67
- this._canvasParent.appendChild(this._canvas);
68
- if (this._video.nextSibling) {
69
- this._video.parentNode.insertBefore(this._canvasParent, this._video.nextSibling);
70
- } else {
71
- this._video.parentNode.appendChild(this._canvasParent);
72
- }
73
- } else if (!this._canvas) {
74
- this.destroy("Don't know where to render: you should give video or canvas in options.");
75
- }
76
- this._bufferCanvas = document.createElement("canvas");
77
- this._bufferCtx = this._bufferCanvas.getContext("2d", { desynchronized: true, willReadFrequently: true });
78
- this._canvasctrl = offscreenRender ? this._canvas.transferControlToOffscreen() : this._canvas;
79
- this._ctx = !offscreenRender && this._canvasctrl.getContext("2d", { desynchronized: true });
80
- this._lastRenderTime = 0;
81
- this.debug = !!options.debug;
82
- this.prescaleFactor = options.prescaleFactor || 1;
83
- this.prescaleHeightLimit = options.prescaleHeightLimit || 1080;
84
- this.maxRenderHeight = options.maxRenderHeight || 0;
85
- this._worker = new Worker(_JASSUB._supportsWebAssembly ? options.workerUrl || "jassub-worker.js" : options.legacyWorkerUrl || "jassub-worker-legacy.js");
86
- this._worker.onmessage = (e) => this._onmessage(e);
87
- this._worker.onerror = (e) => this._error(e);
88
- this._loaded = new Promise((resolve) => {
89
- this._init = () => {
90
- var _a2, _b2;
91
- if (this._destroyed)
92
- return;
93
- this._worker.postMessage({
94
- target: "init",
95
- asyncRender,
96
- onDemandRender: this._onDemandRender,
97
- width: this._canvasctrl.width,
98
- height: this._canvasctrl.height,
99
- preMain: true,
100
- blendMode,
101
- subUrl: options.subUrl,
102
- subContent: options.subContent || null,
103
- fonts: options.fonts || [],
104
- availableFonts: options.availableFonts || { "liberation sans": "./default.woff2" },
105
- fallbackFont: options.fallbackFont || "liberation sans",
106
- debug: this.debug,
107
- targetFps: options.targetFps || 24,
108
- dropAllAnimations: options.dropAllAnimations,
109
- libassMemoryLimit: options.libassMemoryLimit || 0,
110
- libassGlyphLimit: options.libassGlyphLimit || 0,
111
- hasAlphaBug: _JASSUB._hasAlphaBug,
112
- useLocalFonts: "queryLocalFonts" in self && ((_a2 = options.useLocalFonts) != null ? _a2 : true)
113
- });
114
- if (offscreenRender === true)
115
- this.sendMessage("offscreenCanvas", null, [this._canvasctrl]);
116
- this._boundResize = this.resize.bind(this);
117
- this._boundTimeUpdate = this._timeupdate.bind(this);
118
- this._boundSetRate = this.setRate.bind(this);
119
- if (this._video)
120
- this.setVideo(options.video);
121
- if (this._onDemandRender) {
122
- this.busy = false;
123
- this._lastDemandTime = null;
124
- (_b2 = this._video) == null ? void 0 : _b2.requestVideoFrameCallback(this._handleRVFC.bind(this));
125
- }
126
- resolve();
127
- };
128
- });
129
- }
130
- static _test() {
131
- if (_JASSUB._supportsWebAssembly !== null)
132
- return null;
133
- const canvas1 = document.createElement("canvas");
134
- const ctx1 = canvas1.getContext("2d", { willReadFrequently: true });
135
- if (typeof ImageData.prototype.constructor === "function") {
136
- try {
137
- new ImageData(new Uint8ClampedArray([0, 0, 0, 0]), 1, 1);
138
- } catch (e) {
139
- console.log("detected that ImageData is not constructable despite browser saying so");
140
- self.ImageData = function(data, width, height) {
141
- const imageData = ctx1.createImageData(width, height);
142
- if (data)
143
- imageData.data.set(data);
144
- return imageData;
145
- };
146
- }
147
- }
148
- try {
149
- if (typeof WebAssembly === "object" && typeof WebAssembly.instantiate === "function") {
150
- const module = new WebAssembly.Module(Uint8Array.of(0, 97, 115, 109, 1, 0, 0, 0));
151
- if (module instanceof WebAssembly.Module)
152
- _JASSUB._supportsWebAssembly = new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
153
- }
154
- } catch (e) {
155
- _JASSUB._supportsWebAssembly = false;
156
- }
157
- const canvas2 = document.createElement("canvas");
158
- const ctx2 = canvas2.getContext("2d", { willReadFrequently: true });
159
- canvas1.width = canvas2.width = 1;
160
- canvas1.height = canvas2.height = 1;
161
- ctx1.clearRect(0, 0, 1, 1);
162
- ctx2.clearRect(0, 0, 1, 1);
163
- const prePut = ctx2.getImageData(0, 0, 1, 1).data;
164
- ctx1.putImageData(new ImageData(new Uint8ClampedArray([0, 255, 0, 0]), 1, 1), 0, 0);
165
- ctx2.drawImage(canvas1, 0, 0);
166
- const postPut = ctx2.getImageData(0, 0, 1, 1).data;
167
- _JASSUB._hasAlphaBug = prePut[1] !== postPut[1];
168
- if (_JASSUB._hasAlphaBug)
169
- console.log("Detected a browser having issue with transparent pixels, applying workaround");
170
- canvas1.remove();
171
- canvas2.remove();
172
- }
173
- resize(width = 0, height = 0, top = 0, left = 0, force = ((_a) => (_a = this._video) == null ? void 0 : _a.paused)()) {
174
- if ((!width || !height) && this._video) {
175
- const videoSize = this._getVideoPosition();
176
- let renderSize = null;
177
- if (this._videoWidth) {
178
- const widthRatio = this._video.videoWidth / this._videoWidth;
179
- const heightRatio = this._video.videoHeight / this._videoHeight;
180
- renderSize = this._computeCanvasSize((videoSize.width || 0) / widthRatio, (videoSize.height || 0) / heightRatio);
181
- } else {
182
- renderSize = this._computeCanvasSize(videoSize.width || 0, videoSize.height || 0);
183
- }
184
- width = renderSize.width;
185
- height = renderSize.height;
186
- if (this._canvasParent) {
187
- top = videoSize.y - (this._canvasParent.getBoundingClientRect().top - this._video.getBoundingClientRect().top);
188
- left = videoSize.x;
189
- }
190
- this._canvas.style.width = videoSize.width + "px";
191
- this._canvas.style.height = videoSize.height + "px";
192
- }
193
- this._canvas.style.top = top + "px";
194
- this._canvas.style.left = left + "px";
195
- this.sendMessage("canvas", { width, height, force: force && this.busy === false });
196
- }
197
- _getVideoPosition(width = this._video.videoWidth, height = this._video.videoHeight) {
198
- const videoRatio = width / height;
199
- const { offsetWidth, offsetHeight } = this._video;
200
- const elementRatio = offsetWidth / offsetHeight;
201
- width = offsetWidth;
202
- height = offsetHeight;
203
- if (elementRatio > videoRatio) {
204
- width = Math.floor(offsetHeight * videoRatio);
205
- } else {
206
- height = Math.floor(offsetWidth / videoRatio);
207
- }
208
- const x = (offsetWidth - width) / 2;
209
- const y = (offsetHeight - height) / 2;
210
- return { width, height, x, y };
211
- }
212
- _computeCanvasSize(width = 0, height = 0) {
213
- const scalefactor = this.prescaleFactor <= 0 ? 1 : this.prescaleFactor;
214
- const ratio = self.devicePixelRatio || 1;
215
- width = width * ratio;
216
- height = height * ratio;
217
- if (height <= 0 || width <= 0) {
218
- width = 0;
219
- height = 0;
220
- } else {
221
- const sgn = scalefactor < 1 ? -1 : 1;
222
- let newH = height * ratio;
223
- if (sgn * newH * scalefactor <= sgn * this.prescaleHeightLimit) {
224
- newH *= scalefactor;
225
- } else if (sgn * newH < sgn * this.prescaleHeightLimit) {
226
- newH = this.prescaleHeightLimit;
227
- }
228
- if (this.maxRenderHeight > 0 && newH > this.maxRenderHeight)
229
- newH = this.maxRenderHeight;
230
- width *= newH / height;
231
- height = newH;
232
- }
233
- return { width, height };
234
- }
235
- _timeupdate({ type }) {
236
- const eventmap = {
237
- seeking: true,
238
- waiting: true,
239
- playing: false
240
- };
241
- const playing = eventmap[type];
242
- if (playing != null)
243
- this._playstate = playing;
244
- this.setCurrentTime(this._video.paused || this._playstate, this._video.currentTime + this.timeOffset);
245
- }
246
- setVideo(video) {
247
- if (video instanceof HTMLVideoElement) {
248
- this._removeListeners();
249
- this._video = video;
250
- if (this._onDemandRender) {
251
- this._video.requestVideoFrameCallback(this._handleRVFC.bind(this));
252
- } else {
253
- this._playstate = video.paused;
254
- video.addEventListener("timeupdate", this._boundTimeUpdate, false);
255
- video.addEventListener("progress", this._boundTimeUpdate, false);
256
- video.addEventListener("waiting", this._boundTimeUpdate, false);
257
- video.addEventListener("seeking", this._boundTimeUpdate, false);
258
- video.addEventListener("playing", this._boundTimeUpdate, false);
259
- video.addEventListener("ratechange", this._boundSetRate, false);
260
- video.addEventListener("resize", this._boundResize);
261
- }
262
- if (video.videoWidth > 0)
263
- this.resize();
264
- if (typeof ResizeObserver !== "undefined") {
265
- if (!this._ro)
266
- this._ro = new ResizeObserver(() => this.resize());
267
- this._ro.observe(video);
268
- }
269
- } else {
270
- this._error("Video element invalid!");
271
- }
272
- }
273
- runBenchmark() {
274
- this.sendMessage("runBenchmark");
275
- }
276
- setTrackByUrl(url) {
277
- this.sendMessage("setTrackByUrl", { url });
278
- }
279
- setTrack(content) {
280
- this.sendMessage("setTrack", { content });
281
- }
282
- freeTrack() {
283
- this.sendMessage("freeTrack");
284
- }
285
- setIsPaused(isPaused) {
286
- this.sendMessage("video", { isPaused });
287
- }
288
- setRate(rate) {
289
- this.sendMessage("video", { rate });
290
- }
291
- setCurrentTime(isPaused, currentTime, rate) {
292
- this.sendMessage("video", { isPaused, currentTime, rate });
293
- }
294
- createEvent(event) {
295
- this.sendMessage("createEvent", { event });
296
- }
297
- setEvent(event, index) {
298
- this.sendMessage("setEvent", { event, index });
299
- }
300
- removeEvent(index) {
301
- this.sendMessage("removeEvent", { index });
302
- }
303
- getEvents(callback) {
304
- this._fetchFromWorker({
305
- target: "getEvents"
306
- }, (err, { events }) => {
307
- callback(err, events);
308
- });
309
- }
310
- createStyle(style) {
311
- this.sendMessage("createStyle", { style });
312
- }
313
- setStyle(event, index) {
314
- this.sendMessage("setStyle", { event, index });
315
- }
316
- removeStyle(index) {
317
- this.sendMessage("removeStyle", { index });
318
- }
319
- getStyles(callback) {
320
- this._fetchFromWorker({
321
- target: "getStyles"
322
- }, (err, { styles }) => {
323
- callback(err, styles);
324
- });
325
- }
326
- addFont(font) {
327
- this.sendMessage("addFont", { font });
328
- }
329
- _sendLocalFont(name) {
330
- try {
331
- queryLocalFonts().then((fontData) => {
332
- const font = fontData == null ? void 0 : fontData.find((obj) => obj.fullName.toLowerCase() === name);
333
- if (font) {
334
- font.blob().then((blob) => {
335
- blob.arrayBuffer().then((buffer) => {
336
- this.addFont(new Uint8Array(buffer));
337
- });
338
- });
339
- }
340
- });
341
- } catch (e) {
342
- console.warn("Local fonts API:", e);
343
- }
344
- }
345
- _getLocalFont({ font }) {
346
- var _a;
347
- try {
348
- if ((_a = navigator == null ? void 0 : navigator.permissions) == null ? void 0 : _a.query) {
349
- navigator.permissions.query({ name: "local-fonts" }).then((permission) => {
350
- if (permission.state === "granted") {
351
- this._sendLocalFont(font);
352
- }
353
- });
354
- } else {
355
- this._sendLocalFont(font);
356
- }
357
- } catch (e) {
358
- console.warn("Local fonts API:", e);
359
- }
360
- }
361
- _unbusy() {
362
- if (this._lastDemandTime) {
363
- this._demandRender(this._lastDemandTime);
364
- } else {
365
- this.busy = false;
366
- }
367
- }
368
- _handleRVFC(now, { mediaTime, width, height }) {
369
- if (this._destroyed)
370
- return null;
371
- if (this.busy) {
372
- this._lastDemandTime = { mediaTime, width, height };
373
- } else {
374
- this.busy = true;
375
- this._demandRender({ mediaTime, width, height });
376
- }
377
- this._video.requestVideoFrameCallback(this._handleRVFC.bind(this));
378
- }
379
- _demandRender({ mediaTime, width, height }) {
380
- this._lastDemandTime = null;
381
- if (width !== this._videoWidth || height !== this._videoHeight) {
382
- this._videoWidth = width;
383
- this._videoHeight = height;
384
- this.resize();
385
- }
386
- this.sendMessage("demand", { time: mediaTime + this.timeOffset });
387
- }
388
- _render({ images, async, times, width, height }) {
389
- this._unbusy();
390
- const drawStartTime = Date.now();
391
- if (this._canvasctrl.width !== width || this._canvasctrl.height !== height) {
392
- this._canvasctrl.width = width;
393
- this._canvasctrl.height = height;
394
- }
395
- this._ctx.clearRect(0, 0, this._canvasctrl.width, this._canvasctrl.height);
396
- for (const image of images) {
397
- if (image.image) {
398
- if (async) {
399
- this._ctx.drawImage(image.image, image.x, image.y);
400
- image.image.close();
401
- } else {
402
- this._bufferCanvas.width = image.w;
403
- this._bufferCanvas.height = image.h;
404
- this._bufferCtx.putImageData(new ImageData(this._fixAlpha(new Uint8ClampedArray(image.image)), image.w, image.h), 0, 0);
405
- this._ctx.drawImage(this._bufferCanvas, image.x, image.y);
406
- }
407
- }
408
- }
409
- if (this.debug) {
410
- times.drawTime = Date.now() - drawStartTime;
411
- let total = 0;
412
- for (const key in times)
413
- total += times[key];
414
- console.log("Bitmaps: " + images.length + " Total: " + Math.round(total) + "ms", times);
415
- }
416
- }
417
- _fixAlpha(uint8) {
418
- if (_JASSUB._hasAlphaBug) {
419
- for (let j = 3; j < uint8.length; j += 4) {
420
- uint8[j] = uint8[j] > 1 ? uint8[j] : 1;
421
- }
422
- }
423
- return uint8;
424
- }
425
- _ready() {
426
- this._init();
427
- this.dispatchEvent(new CustomEvent("ready"));
428
- }
429
- async sendMessage(target, data = {}, transferable) {
430
- await this._loaded;
431
- if (transferable) {
432
- this._worker.postMessage({
433
- target,
434
- transferable,
435
- ...data
436
- }, [...transferable]);
437
- } else {
438
- this._worker.postMessage({
439
- target,
440
- ...data
441
- });
442
- }
443
- }
444
- _fetchFromWorker(workerOptions, callback) {
445
- try {
446
- const target = workerOptions.target;
447
- const timeout = setTimeout(() => {
448
- reject(new Error("Error: Timeout while try to fetch " + target));
449
- }, 5e3);
450
- const resolve = ({ data }) => {
451
- if (data.target === target) {
452
- callback(null, data);
453
- this._worker.removeEventListener("message", resolve);
454
- this._worker.removeEventListener("error", reject);
455
- clearTimeout(timeout);
456
- }
457
- };
458
- const reject = (event) => {
459
- callback(event);
460
- this._worker.removeEventListener("message", resolve);
461
- this._worker.removeEventListener("error", reject);
462
- clearTimeout(timeout);
463
- };
464
- this._worker.addEventListener("message", resolve);
465
- this._worker.addEventListener("error", reject);
466
- this._worker.postMessage(workerOptions);
467
- } catch (error) {
468
- this._error(error);
469
- }
470
- }
471
- _console({ content, command }) {
472
- console[command].apply(console, JSON.parse(content));
473
- }
474
- _onmessage({ data }) {
475
- if (this["_" + data.target])
476
- this["_" + data.target](data);
477
- }
478
- _error(err) {
479
- this.dispatchEvent(err instanceof ErrorEvent ? new ErrorEvent(err.type, err) : new ErrorEvent("error", { cause: err instanceof Error ? err.cause : err }));
480
- if (!(err instanceof Error)) {
481
- if (err instanceof ErrorEvent) {
482
- err = err.error;
483
- } else {
484
- err = new Error("error", { cause: err });
485
- }
486
- }
487
- console.error(err);
488
- }
489
- _removeListeners() {
490
- if (this._video) {
491
- if (this._ro)
492
- this._ro.unobserve(this._video);
493
- this._video.removeEventListener("timeupdate", this._boundTimeUpdate);
494
- this._video.removeEventListener("progress", this._boundTimeUpdate);
495
- this._video.removeEventListener("waiting", this._boundTimeUpdate);
496
- this._video.removeEventListener("seeking", this._boundTimeUpdate);
497
- this._video.removeEventListener("playing", this._boundTimeUpdate);
498
- this._video.removeEventListener("ratechange", this._boundSetRate);
499
- this._video.removeEventListener("resize", this._boundResize);
500
- }
501
- }
502
- destroy(err) {
503
- if (err)
504
- this._error(err);
505
- if (this._video && this._canvasParent)
506
- this._video.parentNode.removeChild(this._canvasParent);
507
- this._destroyed = true;
508
- this._removeListeners();
509
- this.sendMessage("destroy");
510
- this._worker.terminate();
511
- }
512
- };
513
- let JASSUB = _JASSUB;
514
- __publicField(JASSUB, "_supportsWebAssembly", null);
515
- __publicField(JASSUB, "_hasAlphaBug", null);
516
- export { JASSUB as default };
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => {
4
+ __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
+ return value;
6
+ };
7
+ if (!("requestVideoFrameCallback" in HTMLVideoElement.prototype) && "getVideoPlaybackQuality" in HTMLVideoElement.prototype) {
8
+ HTMLVideoElement.prototype._rvfcpolyfillmap = {};
9
+ HTMLVideoElement.prototype.requestVideoFrameCallback = function(callback) {
10
+ const quality = this.getVideoPlaybackQuality();
11
+ const baseline = this.mozPresentedFrames || this.mozPaintedFrames || quality.totalVideoFrames - quality.droppedVideoFrames;
12
+ const check = (old, now2) => {
13
+ const newquality = this.getVideoPlaybackQuality();
14
+ const presentedFrames = this.mozPresentedFrames || this.mozPaintedFrames || newquality.totalVideoFrames - newquality.droppedVideoFrames;
15
+ if (presentedFrames > baseline) {
16
+ const processingDuration = this.mozFrameDelay || newquality.totalFrameDelay - quality.totalFrameDelay || 0;
17
+ const timediff = now2 - old;
18
+ callback(now2, {
19
+ presentationTime: now2 + processingDuration * 1e3,
20
+ expectedDisplayTime: now2 + timediff,
21
+ width: this.videoWidth,
22
+ height: this.videoHeight,
23
+ mediaTime: Math.max(0, this.currentTime || 0) + timediff / 1e3,
24
+ presentedFrames,
25
+ processingDuration
26
+ });
27
+ delete this._rvfcpolyfillmap[handle];
28
+ } else {
29
+ this._rvfcpolyfillmap[handle] = requestAnimationFrame((newer) => check(now2, newer));
30
+ }
31
+ };
32
+ const handle = Date.now();
33
+ const now = performance.now();
34
+ this._rvfcpolyfillmap[handle] = requestAnimationFrame((newer) => check(now, newer));
35
+ return handle;
36
+ };
37
+ HTMLVideoElement.prototype.cancelVideoFrameCallback = function(handle) {
38
+ cancelAnimationFrame(this._rvfcpolyfillmap[handle]);
39
+ delete this._rvfcpolyfillmap[handle];
40
+ };
41
+ }
42
+ var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
43
+ const root = typeof globalThis !== "undefined" && globalThis || typeof self !== "undefined" && self || typeof commonjsGlobal !== "undefined" && commonjsGlobal;
44
+ function isConstructor(fn) {
45
+ try {
46
+ new fn();
47
+ } catch (error) {
48
+ return false;
49
+ }
50
+ return true;
51
+ }
52
+ if (typeof root.Event !== "function" || !isConstructor(root.Event)) {
53
+ root.Event = function() {
54
+ function Event2(type, options) {
55
+ this.bubbles = !!options && !!options.bubbles;
56
+ this.cancelable = !!options && !!options.cancelable;
57
+ this.composed = !!options && !!options.composed;
58
+ this.type = type;
59
+ }
60
+ return Event2;
61
+ }();
62
+ }
63
+ if (typeof root.EventTarget === "undefined" || !isConstructor(root.Event)) {
64
+ root.EventTarget = function() {
65
+ function EventTarget2() {
66
+ this.__listeners = /* @__PURE__ */ new Map();
67
+ }
68
+ EventTarget2.prototype = Object.create(Object.prototype);
69
+ EventTarget2.prototype.addEventListener = function(type, listener, options) {
70
+ if (arguments.length < 2) {
71
+ throw new TypeError(
72
+ `TypeError: Failed to execute 'addEventListener' on 'EventTarget': 2 arguments required, but only ${arguments.length} present.`
73
+ );
74
+ }
75
+ const __listeners = this.__listeners;
76
+ const actualType = type.toString();
77
+ if (!__listeners.has(actualType)) {
78
+ __listeners.set(actualType, /* @__PURE__ */ new Map());
79
+ }
80
+ const listenersForType = __listeners.get(actualType);
81
+ if (!listenersForType.has(listener)) {
82
+ listenersForType.set(listener, options);
83
+ }
84
+ };
85
+ EventTarget2.prototype.removeEventListener = function(type, listener, _options) {
86
+ if (arguments.length < 2) {
87
+ throw new TypeError(
88
+ `TypeError: Failed to execute 'addEventListener' on 'EventTarget': 2 arguments required, but only ${arguments.length} present.`
89
+ );
90
+ }
91
+ const __listeners = this.__listeners;
92
+ const actualType = type.toString();
93
+ if (__listeners.has(actualType)) {
94
+ const listenersForType = __listeners.get(actualType);
95
+ if (listenersForType.has(listener)) {
96
+ listenersForType.delete(listener);
97
+ }
98
+ }
99
+ };
100
+ EventTarget2.prototype.dispatchEvent = function(event) {
101
+ if (!(event instanceof Event)) {
102
+ throw new TypeError(
103
+ `Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1 is not of type 'Event'.`
104
+ );
105
+ }
106
+ const type = event.type;
107
+ const __listeners = this.__listeners;
108
+ const listenersForType = __listeners.get(type);
109
+ if (listenersForType) {
110
+ for (const [listener, options] of listenersForType.entries()) {
111
+ try {
112
+ if (typeof listener === "function") {
113
+ listener.call(this, event);
114
+ } else if (listener && typeof listener.handleEvent === "function") {
115
+ listener.handleEvent(event);
116
+ }
117
+ } catch (err) {
118
+ setTimeout(() => {
119
+ throw err;
120
+ });
121
+ }
122
+ if (options && options.once) {
123
+ listenersForType.delete(listener);
124
+ }
125
+ }
126
+ }
127
+ return true;
128
+ };
129
+ return EventTarget2;
130
+ }();
131
+ }
132
+ const _JASSUB = class extends EventTarget {
133
+ constructor(options = {}) {
134
+ var _a, _b, _c;
135
+ super();
136
+ if (!globalThis.Worker) {
137
+ this.destroy("Worker not supported");
138
+ }
139
+ _JASSUB._test();
140
+ const blendMode = options.blendMode || "js";
141
+ const asyncRender = typeof createImageBitmap !== "undefined" && ((_a = options.asyncRender) != null ? _a : true);
142
+ const offscreenRender = typeof OffscreenCanvas !== "undefined" && ((_b = options.offscreenRender) != null ? _b : true);
143
+ this._onDemandRender = "requestVideoFrameCallback" in HTMLVideoElement.prototype && ((_c = options.onDemandRender) != null ? _c : true);
144
+ this.timeOffset = options.timeOffset || 0;
145
+ this._video = options.video;
146
+ this._videoHeight = 0;
147
+ this._videoWidth = 0;
148
+ this._canvas = options.canvas;
149
+ if (this._video && !this._canvas) {
150
+ this._canvasParent = document.createElement("div");
151
+ this._canvasParent.className = "JASSUB";
152
+ this._canvasParent.style.position = "relative";
153
+ this._canvas = document.createElement("canvas");
154
+ this._canvas.style.display = "block";
155
+ this._canvas.style.position = "absolute";
156
+ this._canvas.style.pointerEvents = "none";
157
+ this._canvasParent.appendChild(this._canvas);
158
+ if (this._video.nextSibling) {
159
+ this._video.parentNode.insertBefore(this._canvasParent, this._video.nextSibling);
160
+ } else {
161
+ this._video.parentNode.appendChild(this._canvasParent);
162
+ }
163
+ } else if (!this._canvas) {
164
+ this.destroy("Don't know where to render: you should give video or canvas in options.");
165
+ }
166
+ this._bufferCanvas = document.createElement("canvas");
167
+ this._bufferCtx = this._bufferCanvas.getContext("2d", { desynchronized: true, willReadFrequently: true });
168
+ this._canvasctrl = offscreenRender ? this._canvas.transferControlToOffscreen() : this._canvas;
169
+ this._ctx = !offscreenRender && this._canvasctrl.getContext("2d", { desynchronized: true });
170
+ this._lastRenderTime = 0;
171
+ this.debug = !!options.debug;
172
+ this.prescaleFactor = options.prescaleFactor || 1;
173
+ this.prescaleHeightLimit = options.prescaleHeightLimit || 1080;
174
+ this.maxRenderHeight = options.maxRenderHeight || 0;
175
+ this._worker = new Worker(_JASSUB._supportsWebAssembly ? options.workerUrl || "jassub-worker.js" : options.legacyWorkerUrl || "jassub-worker-legacy.js");
176
+ this._worker.onmessage = (e) => this._onmessage(e);
177
+ this._worker.onerror = (e) => this._error(e);
178
+ this._loaded = new Promise((resolve) => {
179
+ this._init = () => {
180
+ var _a2, _b2;
181
+ if (this._destroyed)
182
+ return;
183
+ this._worker.postMessage({
184
+ target: "init",
185
+ asyncRender,
186
+ onDemandRender: this._onDemandRender,
187
+ width: this._canvasctrl.width,
188
+ height: this._canvasctrl.height,
189
+ preMain: true,
190
+ blendMode,
191
+ subUrl: options.subUrl,
192
+ subContent: options.subContent || null,
193
+ fonts: options.fonts || [],
194
+ availableFonts: options.availableFonts || { "liberation sans": "./default.woff2" },
195
+ fallbackFont: options.fallbackFont || "liberation sans",
196
+ debug: this.debug,
197
+ targetFps: options.targetFps || 24,
198
+ dropAllAnimations: options.dropAllAnimations,
199
+ libassMemoryLimit: options.libassMemoryLimit || 0,
200
+ libassGlyphLimit: options.libassGlyphLimit || 0,
201
+ hasAlphaBug: _JASSUB._hasAlphaBug,
202
+ useLocalFonts: "queryLocalFonts" in self && ((_a2 = options.useLocalFonts) != null ? _a2 : true)
203
+ });
204
+ if (offscreenRender === true)
205
+ this.sendMessage("offscreenCanvas", null, [this._canvasctrl]);
206
+ this._boundResize = this.resize.bind(this);
207
+ this._boundTimeUpdate = this._timeupdate.bind(this);
208
+ this._boundSetRate = this.setRate.bind(this);
209
+ if (this._video)
210
+ this.setVideo(options.video);
211
+ if (this._onDemandRender) {
212
+ this.busy = false;
213
+ this._lastDemandTime = null;
214
+ (_b2 = this._video) == null ? void 0 : _b2.requestVideoFrameCallback(this._handleRVFC.bind(this));
215
+ }
216
+ resolve();
217
+ };
218
+ });
219
+ }
220
+ static _test() {
221
+ if (_JASSUB._supportsWebAssembly !== null)
222
+ return null;
223
+ const canvas1 = document.createElement("canvas");
224
+ const ctx1 = canvas1.getContext("2d", { willReadFrequently: true });
225
+ if (typeof ImageData.prototype.constructor === "function") {
226
+ try {
227
+ new ImageData(new Uint8ClampedArray([0, 0, 0, 0]), 1, 1);
228
+ } catch (e) {
229
+ console.log("detected that ImageData is not constructable despite browser saying so");
230
+ self.ImageData = function(data, width, height) {
231
+ const imageData = ctx1.createImageData(width, height);
232
+ if (data)
233
+ imageData.data.set(data);
234
+ return imageData;
235
+ };
236
+ }
237
+ }
238
+ try {
239
+ if (typeof WebAssembly === "object" && typeof WebAssembly.instantiate === "function") {
240
+ const module = new WebAssembly.Module(Uint8Array.of(0, 97, 115, 109, 1, 0, 0, 0));
241
+ if (module instanceof WebAssembly.Module)
242
+ _JASSUB._supportsWebAssembly = new WebAssembly.Instance(module) instanceof WebAssembly.Instance;
243
+ }
244
+ } catch (e) {
245
+ _JASSUB._supportsWebAssembly = false;
246
+ }
247
+ const canvas2 = document.createElement("canvas");
248
+ const ctx2 = canvas2.getContext("2d", { willReadFrequently: true });
249
+ canvas1.width = canvas2.width = 1;
250
+ canvas1.height = canvas2.height = 1;
251
+ ctx1.clearRect(0, 0, 1, 1);
252
+ ctx2.clearRect(0, 0, 1, 1);
253
+ const prePut = ctx2.getImageData(0, 0, 1, 1).data;
254
+ ctx1.putImageData(new ImageData(new Uint8ClampedArray([0, 255, 0, 0]), 1, 1), 0, 0);
255
+ ctx2.drawImage(canvas1, 0, 0);
256
+ const postPut = ctx2.getImageData(0, 0, 1, 1).data;
257
+ _JASSUB._hasAlphaBug = prePut[1] !== postPut[1];
258
+ if (_JASSUB._hasAlphaBug)
259
+ console.log("Detected a browser having issue with transparent pixels, applying workaround");
260
+ canvas1.remove();
261
+ canvas2.remove();
262
+ }
263
+ resize(width = 0, height = 0, top = 0, left = 0, force = ((_a) => (_a = this._video) == null ? void 0 : _a.paused)()) {
264
+ if ((!width || !height) && this._video) {
265
+ const videoSize = this._getVideoPosition();
266
+ let renderSize = null;
267
+ if (this._videoWidth) {
268
+ const widthRatio = this._video.videoWidth / this._videoWidth;
269
+ const heightRatio = this._video.videoHeight / this._videoHeight;
270
+ renderSize = this._computeCanvasSize((videoSize.width || 0) / widthRatio, (videoSize.height || 0) / heightRatio);
271
+ } else {
272
+ renderSize = this._computeCanvasSize(videoSize.width || 0, videoSize.height || 0);
273
+ }
274
+ width = renderSize.width;
275
+ height = renderSize.height;
276
+ if (this._canvasParent) {
277
+ top = videoSize.y - (this._canvasParent.getBoundingClientRect().top - this._video.getBoundingClientRect().top);
278
+ left = videoSize.x;
279
+ }
280
+ this._canvas.style.width = videoSize.width + "px";
281
+ this._canvas.style.height = videoSize.height + "px";
282
+ }
283
+ this._canvas.style.top = top + "px";
284
+ this._canvas.style.left = left + "px";
285
+ this.sendMessage("canvas", { width, height, force: force && this.busy === false });
286
+ }
287
+ _getVideoPosition(width = this._video.videoWidth, height = this._video.videoHeight) {
288
+ const videoRatio = width / height;
289
+ const { offsetWidth, offsetHeight } = this._video;
290
+ const elementRatio = offsetWidth / offsetHeight;
291
+ width = offsetWidth;
292
+ height = offsetHeight;
293
+ if (elementRatio > videoRatio) {
294
+ width = Math.floor(offsetHeight * videoRatio);
295
+ } else {
296
+ height = Math.floor(offsetWidth / videoRatio);
297
+ }
298
+ const x = (offsetWidth - width) / 2;
299
+ const y = (offsetHeight - height) / 2;
300
+ return { width, height, x, y };
301
+ }
302
+ _computeCanvasSize(width = 0, height = 0) {
303
+ const scalefactor = this.prescaleFactor <= 0 ? 1 : this.prescaleFactor;
304
+ const ratio = self.devicePixelRatio || 1;
305
+ width = width * ratio;
306
+ height = height * ratio;
307
+ if (height <= 0 || width <= 0) {
308
+ width = 0;
309
+ height = 0;
310
+ } else {
311
+ const sgn = scalefactor < 1 ? -1 : 1;
312
+ let newH = height * ratio;
313
+ if (sgn * newH * scalefactor <= sgn * this.prescaleHeightLimit) {
314
+ newH *= scalefactor;
315
+ } else if (sgn * newH < sgn * this.prescaleHeightLimit) {
316
+ newH = this.prescaleHeightLimit;
317
+ }
318
+ if (this.maxRenderHeight > 0 && newH > this.maxRenderHeight)
319
+ newH = this.maxRenderHeight;
320
+ width *= newH / height;
321
+ height = newH;
322
+ }
323
+ return { width, height };
324
+ }
325
+ _timeupdate({ type }) {
326
+ const eventmap = {
327
+ seeking: true,
328
+ waiting: true,
329
+ playing: false
330
+ };
331
+ const playing = eventmap[type];
332
+ if (playing != null)
333
+ this._playstate = playing;
334
+ this.setCurrentTime(this._video.paused || this._playstate, this._video.currentTime + this.timeOffset);
335
+ }
336
+ setVideo(video) {
337
+ if (video instanceof HTMLVideoElement) {
338
+ this._removeListeners();
339
+ this._video = video;
340
+ if (this._onDemandRender) {
341
+ this._video.requestVideoFrameCallback(this._handleRVFC.bind(this));
342
+ } else {
343
+ this._playstate = video.paused;
344
+ video.addEventListener("timeupdate", this._boundTimeUpdate, false);
345
+ video.addEventListener("progress", this._boundTimeUpdate, false);
346
+ video.addEventListener("waiting", this._boundTimeUpdate, false);
347
+ video.addEventListener("seeking", this._boundTimeUpdate, false);
348
+ video.addEventListener("playing", this._boundTimeUpdate, false);
349
+ video.addEventListener("ratechange", this._boundSetRate, false);
350
+ video.addEventListener("resize", this._boundResize);
351
+ }
352
+ if (video.videoWidth > 0)
353
+ this.resize();
354
+ if (typeof ResizeObserver !== "undefined") {
355
+ if (!this._ro)
356
+ this._ro = new ResizeObserver(() => this.resize());
357
+ this._ro.observe(video);
358
+ }
359
+ } else {
360
+ this._error("Video element invalid!");
361
+ }
362
+ }
363
+ runBenchmark() {
364
+ this.sendMessage("runBenchmark");
365
+ }
366
+ setTrackByUrl(url) {
367
+ this.sendMessage("setTrackByUrl", { url });
368
+ }
369
+ setTrack(content) {
370
+ this.sendMessage("setTrack", { content });
371
+ }
372
+ freeTrack() {
373
+ this.sendMessage("freeTrack");
374
+ }
375
+ setIsPaused(isPaused) {
376
+ this.sendMessage("video", { isPaused });
377
+ }
378
+ setRate(rate) {
379
+ this.sendMessage("video", { rate });
380
+ }
381
+ setCurrentTime(isPaused, currentTime, rate) {
382
+ this.sendMessage("video", { isPaused, currentTime, rate });
383
+ }
384
+ createEvent(event) {
385
+ this.sendMessage("createEvent", { event });
386
+ }
387
+ setEvent(event, index) {
388
+ this.sendMessage("setEvent", { event, index });
389
+ }
390
+ removeEvent(index) {
391
+ this.sendMessage("removeEvent", { index });
392
+ }
393
+ getEvents(callback) {
394
+ this._fetchFromWorker({
395
+ target: "getEvents"
396
+ }, (err, { events }) => {
397
+ callback(err, events);
398
+ });
399
+ }
400
+ createStyle(style) {
401
+ this.sendMessage("createStyle", { style });
402
+ }
403
+ setStyle(event, index) {
404
+ this.sendMessage("setStyle", { event, index });
405
+ }
406
+ removeStyle(index) {
407
+ this.sendMessage("removeStyle", { index });
408
+ }
409
+ getStyles(callback) {
410
+ this._fetchFromWorker({
411
+ target: "getStyles"
412
+ }, (err, { styles }) => {
413
+ callback(err, styles);
414
+ });
415
+ }
416
+ addFont(font) {
417
+ this.sendMessage("addFont", { font });
418
+ }
419
+ _sendLocalFont(name) {
420
+ try {
421
+ queryLocalFonts().then((fontData) => {
422
+ const font = fontData == null ? void 0 : fontData.find((obj) => obj.fullName.toLowerCase() === name);
423
+ if (font) {
424
+ font.blob().then((blob) => {
425
+ blob.arrayBuffer().then((buffer) => {
426
+ this.addFont(new Uint8Array(buffer));
427
+ });
428
+ });
429
+ }
430
+ });
431
+ } catch (e) {
432
+ console.warn("Local fonts API:", e);
433
+ }
434
+ }
435
+ _getLocalFont({ font }) {
436
+ var _a;
437
+ try {
438
+ if ((_a = navigator == null ? void 0 : navigator.permissions) == null ? void 0 : _a.query) {
439
+ navigator.permissions.query({ name: "local-fonts" }).then((permission) => {
440
+ if (permission.state === "granted") {
441
+ this._sendLocalFont(font);
442
+ }
443
+ });
444
+ } else {
445
+ this._sendLocalFont(font);
446
+ }
447
+ } catch (e) {
448
+ console.warn("Local fonts API:", e);
449
+ }
450
+ }
451
+ _unbusy() {
452
+ if (this._lastDemandTime) {
453
+ this._demandRender(this._lastDemandTime);
454
+ } else {
455
+ this.busy = false;
456
+ }
457
+ }
458
+ _handleRVFC(now, { mediaTime, width, height }) {
459
+ if (this._destroyed)
460
+ return null;
461
+ if (this.busy) {
462
+ this._lastDemandTime = { mediaTime, width, height };
463
+ } else {
464
+ this.busy = true;
465
+ this._demandRender({ mediaTime, width, height });
466
+ }
467
+ this._video.requestVideoFrameCallback(this._handleRVFC.bind(this));
468
+ }
469
+ _demandRender({ mediaTime, width, height }) {
470
+ this._lastDemandTime = null;
471
+ if (width !== this._videoWidth || height !== this._videoHeight) {
472
+ this._videoWidth = width;
473
+ this._videoHeight = height;
474
+ this.resize();
475
+ }
476
+ this.sendMessage("demand", { time: mediaTime + this.timeOffset });
477
+ }
478
+ _render({ images, async, times, width, height }) {
479
+ this._unbusy();
480
+ const drawStartTime = Date.now();
481
+ if (this._canvasctrl.width !== width || this._canvasctrl.height !== height) {
482
+ this._canvasctrl.width = width;
483
+ this._canvasctrl.height = height;
484
+ }
485
+ this._ctx.clearRect(0, 0, this._canvasctrl.width, this._canvasctrl.height);
486
+ for (const image of images) {
487
+ if (image.image) {
488
+ if (async) {
489
+ this._ctx.drawImage(image.image, image.x, image.y);
490
+ image.image.close();
491
+ } else {
492
+ this._bufferCanvas.width = image.w;
493
+ this._bufferCanvas.height = image.h;
494
+ this._bufferCtx.putImageData(new ImageData(this._fixAlpha(new Uint8ClampedArray(image.image)), image.w, image.h), 0, 0);
495
+ this._ctx.drawImage(this._bufferCanvas, image.x, image.y);
496
+ }
497
+ }
498
+ }
499
+ if (this.debug) {
500
+ times.drawTime = Date.now() - drawStartTime;
501
+ let total = 0;
502
+ for (const key in times)
503
+ total += times[key];
504
+ console.log("Bitmaps: " + images.length + " Total: " + Math.round(total) + "ms", times);
505
+ }
506
+ }
507
+ _fixAlpha(uint8) {
508
+ if (_JASSUB._hasAlphaBug) {
509
+ for (let j = 3; j < uint8.length; j += 4) {
510
+ uint8[j] = uint8[j] > 1 ? uint8[j] : 1;
511
+ }
512
+ }
513
+ return uint8;
514
+ }
515
+ _ready() {
516
+ this._init();
517
+ this.dispatchEvent(new CustomEvent("ready"));
518
+ }
519
+ async sendMessage(target, data = {}, transferable) {
520
+ await this._loaded;
521
+ if (transferable) {
522
+ this._worker.postMessage({
523
+ target,
524
+ transferable,
525
+ ...data
526
+ }, [...transferable]);
527
+ } else {
528
+ this._worker.postMessage({
529
+ target,
530
+ ...data
531
+ });
532
+ }
533
+ }
534
+ _fetchFromWorker(workerOptions, callback) {
535
+ try {
536
+ const target = workerOptions.target;
537
+ const timeout = setTimeout(() => {
538
+ reject(new Error("Error: Timeout while try to fetch " + target));
539
+ }, 5e3);
540
+ const resolve = ({ data }) => {
541
+ if (data.target === target) {
542
+ callback(null, data);
543
+ this._worker.removeEventListener("message", resolve);
544
+ this._worker.removeEventListener("error", reject);
545
+ clearTimeout(timeout);
546
+ }
547
+ };
548
+ const reject = (event) => {
549
+ callback(event);
550
+ this._worker.removeEventListener("message", resolve);
551
+ this._worker.removeEventListener("error", reject);
552
+ clearTimeout(timeout);
553
+ };
554
+ this._worker.addEventListener("message", resolve);
555
+ this._worker.addEventListener("error", reject);
556
+ this._worker.postMessage(workerOptions);
557
+ } catch (error) {
558
+ this._error(error);
559
+ }
560
+ }
561
+ _console({ content, command }) {
562
+ console[command].apply(console, JSON.parse(content));
563
+ }
564
+ _onmessage({ data }) {
565
+ if (this["_" + data.target])
566
+ this["_" + data.target](data);
567
+ }
568
+ _error(err) {
569
+ this.dispatchEvent(err instanceof ErrorEvent ? new ErrorEvent(err.type, err) : new ErrorEvent("error", { cause: err instanceof Error ? err.cause : err }));
570
+ if (!(err instanceof Error)) {
571
+ if (err instanceof ErrorEvent) {
572
+ err = err.error;
573
+ } else {
574
+ err = new Error("error", { cause: err });
575
+ }
576
+ }
577
+ console.error(err);
578
+ }
579
+ _removeListeners() {
580
+ if (this._video) {
581
+ if (this._ro)
582
+ this._ro.unobserve(this._video);
583
+ this._video.removeEventListener("timeupdate", this._boundTimeUpdate);
584
+ this._video.removeEventListener("progress", this._boundTimeUpdate);
585
+ this._video.removeEventListener("waiting", this._boundTimeUpdate);
586
+ this._video.removeEventListener("seeking", this._boundTimeUpdate);
587
+ this._video.removeEventListener("playing", this._boundTimeUpdate);
588
+ this._video.removeEventListener("ratechange", this._boundSetRate);
589
+ this._video.removeEventListener("resize", this._boundResize);
590
+ }
591
+ }
592
+ destroy(err) {
593
+ if (err)
594
+ this._error(err);
595
+ if (this._video && this._canvasParent)
596
+ this._video.parentNode.removeChild(this._canvasParent);
597
+ this._destroyed = true;
598
+ this._removeListeners();
599
+ this.sendMessage("destroy");
600
+ this._worker.terminate();
601
+ }
602
+ };
603
+ let JASSUB = _JASSUB;
604
+ __publicField(JASSUB, "_supportsWebAssembly", null);
605
+ __publicField(JASSUB, "_hasAlphaBug", null);
606
+ export { JASSUB as default };
@@ -1 +1 @@
1
- (function(d,o){typeof exports=="object"&&typeof module!="undefined"?module.exports=o():typeof define=="function"&&define.amd?define(o):(d=typeof globalThis!="undefined"?globalThis:d||self,d.JASSUB=o())})(this,function(){"use strict";var v=Object.defineProperty;var f=(d,o,c)=>o in d?v(d,o,{enumerable:!0,configurable:!0,writable:!0,value:c}):d[o]=c;var u=(d,o,c)=>(f(d,typeof o!="symbol"?o+"":o,c),c);!("requestVideoFrameCallback"in HTMLVideoElement.prototype)&&"getVideoPlaybackQuality"in HTMLVideoElement.prototype&&(HTMLVideoElement.prototype._rvfcpolyfillmap={},HTMLVideoElement.prototype.requestVideoFrameCallback=function(c){const e=this.getVideoPlaybackQuality(),t=this.mozPresentedFrames||this.mozPaintedFrames||e.totalVideoFrames-e.droppedVideoFrames,s=(n,i)=>{const h=this.getVideoPlaybackQuality(),m=this.mozPresentedFrames||this.mozPaintedFrames||h.totalVideoFrames-h.droppedVideoFrames;if(m>t){const l=this.mozFrameDelay||h.totalFrameDelay-e.totalFrameDelay||0,_=i-n;c(i,{presentationTime:i+l*1e3,expectedDisplayTime:i+_,width:this.videoWidth,height:this.videoHeight,mediaTime:Math.max(0,this.currentTime||0)+_/1e3,presentedFrames:m,processingDuration:l}),delete this._rvfcpolyfillmap[a]}else this._rvfcpolyfillmap[a]=requestAnimationFrame(l=>s(i,l))},a=Date.now(),r=performance.now();return this._rvfcpolyfillmap[a]=requestAnimationFrame(n=>s(r,n)),a},HTMLVideoElement.prototype.cancelVideoFrameCallback=function(c){cancelAnimationFrame(this._rvfcpolyfillmap[c]),delete this._rvfcpolyfillmap[c]});const o=class extends EventTarget{constructor(e={}){var r,n,i;super(),globalThis.Worker||this.destroy("Worker not supported"),o._test();const t=e.blendMode||"js",s=typeof createImageBitmap!="undefined"&&((r=e.asyncRender)!=null?r:!0),a=typeof OffscreenCanvas!="undefined"&&((n=e.offscreenRender)!=null?n:!0);this._onDemandRender="requestVideoFrameCallback"in HTMLVideoElement.prototype&&((i=e.onDemandRender)!=null?i:!0),this.timeOffset=e.timeOffset||0,this._video=e.video,this._videoHeight=0,this._videoWidth=0,this._canvas=e.canvas,this._video&&!this._canvas?(this._canvasParent=document.createElement("div"),this._canvasParent.className="JASSUB",this._canvasParent.style.position="relative",this._canvas=document.createElement("canvas"),this._canvas.style.display="block",this._canvas.style.position="absolute",this._canvas.style.pointerEvents="none",this._canvasParent.appendChild(this._canvas),this._video.nextSibling?this._video.parentNode.insertBefore(this._canvasParent,this._video.nextSibling):this._video.parentNode.appendChild(this._canvasParent)):this._canvas||this.destroy("Don't know where to render: you should give video or canvas in options."),this._bufferCanvas=document.createElement("canvas"),this._bufferCtx=this._bufferCanvas.getContext("2d",{desynchronized:!0,willReadFrequently:!0}),this._canvasctrl=a?this._canvas.transferControlToOffscreen():this._canvas,this._ctx=!a&&this._canvasctrl.getContext("2d",{desynchronized:!0}),this._lastRenderTime=0,this.debug=!!e.debug,this.prescaleFactor=e.prescaleFactor||1,this.prescaleHeightLimit=e.prescaleHeightLimit||1080,this.maxRenderHeight=e.maxRenderHeight||0,this._worker=new Worker(o._supportsWebAssembly?e.workerUrl||"jassub-worker.js":e.legacyWorkerUrl||"jassub-worker-legacy.js"),this._worker.onmessage=h=>this._onmessage(h),this._worker.onerror=h=>this._error(h),this._loaded=new Promise(h=>{this._init=()=>{var m,l;this._destroyed||(this._worker.postMessage({target:"init",asyncRender:s,onDemandRender:this._onDemandRender,width:this._canvasctrl.width,height:this._canvasctrl.height,preMain:!0,blendMode:t,subUrl:e.subUrl,subContent:e.subContent||null,fonts:e.fonts||[],availableFonts:e.availableFonts||{"liberation sans":"./default.woff2"},fallbackFont:e.fallbackFont||"liberation sans",debug:this.debug,targetFps:e.targetFps||24,dropAllAnimations:e.dropAllAnimations,libassMemoryLimit:e.libassMemoryLimit||0,libassGlyphLimit:e.libassGlyphLimit||0,hasAlphaBug:o._hasAlphaBug,useLocalFonts:"queryLocalFonts"in self&&((m=e.useLocalFonts)!=null?m:!0)}),a===!0&&this.sendMessage("offscreenCanvas",null,[this._canvasctrl]),this._boundResize=this.resize.bind(this),this._boundTimeUpdate=this._timeupdate.bind(this),this._boundSetRate=this.setRate.bind(this),this._video&&this.setVideo(e.video),this._onDemandRender&&(this.busy=!1,this._lastDemandTime=null,(l=this._video)==null||l.requestVideoFrameCallback(this._handleRVFC.bind(this))),h())}})}static _test(){if(o._supportsWebAssembly!==null)return null;const e=document.createElement("canvas"),t=e.getContext("2d",{willReadFrequently:!0});if(typeof ImageData.prototype.constructor=="function")try{new ImageData(new Uint8ClampedArray([0,0,0,0]),1,1)}catch{console.log("detected that ImageData is not constructable despite browser saying so"),self.ImageData=function(h,m,l){const _=t.createImageData(m,l);return h&&_.data.set(h),_}}try{if(typeof WebAssembly=="object"&&typeof WebAssembly.instantiate=="function"){const i=new WebAssembly.Module(Uint8Array.of(0,97,115,109,1,0,0,0));i instanceof WebAssembly.Module&&(o._supportsWebAssembly=new WebAssembly.Instance(i)instanceof WebAssembly.Instance)}}catch{o._supportsWebAssembly=!1}const s=document.createElement("canvas"),a=s.getContext("2d",{willReadFrequently:!0});e.width=s.width=1,e.height=s.height=1,t.clearRect(0,0,1,1),a.clearRect(0,0,1,1);const r=a.getImageData(0,0,1,1).data;t.putImageData(new ImageData(new Uint8ClampedArray([0,255,0,0]),1,1),0,0),a.drawImage(e,0,0);const n=a.getImageData(0,0,1,1).data;o._hasAlphaBug=r[1]!==n[1],o._hasAlphaBug&&console.log("Detected a browser having issue with transparent pixels, applying workaround"),e.remove(),s.remove()}resize(e=0,t=0,s=0,a=0,r=(n=>(n=this._video)==null?void 0:n.paused)()){if((!e||!t)&&this._video){const i=this._getVideoPosition();let h=null;if(this._videoWidth){const m=this._video.videoWidth/this._videoWidth,l=this._video.videoHeight/this._videoHeight;h=this._computeCanvasSize((i.width||0)/m,(i.height||0)/l)}else h=this._computeCanvasSize(i.width||0,i.height||0);e=h.width,t=h.height,this._canvasParent&&(s=i.y-(this._canvasParent.getBoundingClientRect().top-this._video.getBoundingClientRect().top),a=i.x),this._canvas.style.width=i.width+"px",this._canvas.style.height=i.height+"px"}this._canvas.style.top=s+"px",this._canvas.style.left=a+"px",this.sendMessage("canvas",{width:e,height:t,force:r&&this.busy===!1})}_getVideoPosition(e=this._video.videoWidth,t=this._video.videoHeight){const s=e/t,{offsetWidth:a,offsetHeight:r}=this._video,n=a/r;e=a,t=r,n>s?e=Math.floor(r*s):t=Math.floor(a/s);const i=(a-e)/2,h=(r-t)/2;return{width:e,height:t,x:i,y:h}}_computeCanvasSize(e=0,t=0){const s=this.prescaleFactor<=0?1:this.prescaleFactor,a=self.devicePixelRatio||1;if(e=e*a,t=t*a,t<=0||e<=0)e=0,t=0;else{const r=s<1?-1:1;let n=t*a;r*n*s<=r*this.prescaleHeightLimit?n*=s:r*n<r*this.prescaleHeightLimit&&(n=this.prescaleHeightLimit),this.maxRenderHeight>0&&n>this.maxRenderHeight&&(n=this.maxRenderHeight),e*=n/t,t=n}return{width:e,height:t}}_timeupdate({type:e}){const s={seeking:!0,waiting:!0,playing:!1}[e];s!=null&&(this._playstate=s),this.setCurrentTime(this._video.paused||this._playstate,this._video.currentTime+this.timeOffset)}setVideo(e){e instanceof HTMLVideoElement?(this._removeListeners(),this._video=e,this._onDemandRender?this._video.requestVideoFrameCallback(this._handleRVFC.bind(this)):(this._playstate=e.paused,e.addEventListener("timeupdate",this._boundTimeUpdate,!1),e.addEventListener("progress",this._boundTimeUpdate,!1),e.addEventListener("waiting",this._boundTimeUpdate,!1),e.addEventListener("seeking",this._boundTimeUpdate,!1),e.addEventListener("playing",this._boundTimeUpdate,!1),e.addEventListener("ratechange",this._boundSetRate,!1),e.addEventListener("resize",this._boundResize)),e.videoWidth>0&&this.resize(),typeof ResizeObserver!="undefined"&&(this._ro||(this._ro=new ResizeObserver(()=>this.resize())),this._ro.observe(e))):this._error("Video element invalid!")}runBenchmark(){this.sendMessage("runBenchmark")}setTrackByUrl(e){this.sendMessage("setTrackByUrl",{url:e})}setTrack(e){this.sendMessage("setTrack",{content:e})}freeTrack(){this.sendMessage("freeTrack")}setIsPaused(e){this.sendMessage("video",{isPaused:e})}setRate(e){this.sendMessage("video",{rate:e})}setCurrentTime(e,t,s){this.sendMessage("video",{isPaused:e,currentTime:t,rate:s})}createEvent(e){this.sendMessage("createEvent",{event:e})}setEvent(e,t){this.sendMessage("setEvent",{event:e,index:t})}removeEvent(e){this.sendMessage("removeEvent",{index:e})}getEvents(e){this._fetchFromWorker({target:"getEvents"},(t,{events:s})=>{e(t,s)})}createStyle(e){this.sendMessage("createStyle",{style:e})}setStyle(e,t){this.sendMessage("setStyle",{event:e,index:t})}removeStyle(e){this.sendMessage("removeStyle",{index:e})}getStyles(e){this._fetchFromWorker({target:"getStyles"},(t,{styles:s})=>{e(t,s)})}addFont(e){this.sendMessage("addFont",{font:e})}_sendLocalFont(e){try{queryLocalFonts().then(t=>{const s=t==null?void 0:t.find(a=>a.fullName.toLowerCase()===e);s&&s.blob().then(a=>{a.arrayBuffer().then(r=>{this.addFont(new Uint8Array(r))})})})}catch(t){console.warn("Local fonts API:",t)}}_getLocalFont({font:e}){var t;try{(t=navigator==null?void 0:navigator.permissions)!=null&&t.query?navigator.permissions.query({name:"local-fonts"}).then(s=>{s.state==="granted"&&this._sendLocalFont(e)}):this._sendLocalFont(e)}catch(s){console.warn("Local fonts API:",s)}}_unbusy(){this._lastDemandTime?this._demandRender(this._lastDemandTime):this.busy=!1}_handleRVFC(e,{mediaTime:t,width:s,height:a}){if(this._destroyed)return null;this.busy?this._lastDemandTime={mediaTime:t,width:s,height:a}:(this.busy=!0,this._demandRender({mediaTime:t,width:s,height:a})),this._video.requestVideoFrameCallback(this._handleRVFC.bind(this))}_demandRender({mediaTime:e,width:t,height:s}){this._lastDemandTime=null,(t!==this._videoWidth||s!==this._videoHeight)&&(this._videoWidth=t,this._videoHeight=s,this.resize()),this.sendMessage("demand",{time:e+this.timeOffset})}_render({images:e,async:t,times:s,width:a,height:r}){this._unbusy();const n=Date.now();(this._canvasctrl.width!==a||this._canvasctrl.height!==r)&&(this._canvasctrl.width=a,this._canvasctrl.height=r),this._ctx.clearRect(0,0,this._canvasctrl.width,this._canvasctrl.height);for(const i of e)i.image&&(t?(this._ctx.drawImage(i.image,i.x,i.y),i.image.close()):(this._bufferCanvas.width=i.w,this._bufferCanvas.height=i.h,this._bufferCtx.putImageData(new ImageData(this._fixAlpha(new Uint8ClampedArray(i.image)),i.w,i.h),0,0),this._ctx.drawImage(this._bufferCanvas,i.x,i.y)));if(this.debug){s.drawTime=Date.now()-n;let i=0;for(const h in s)i+=s[h];console.log("Bitmaps: "+e.length+" Total: "+Math.round(i)+"ms",s)}}_fixAlpha(e){if(o._hasAlphaBug)for(let t=3;t<e.length;t+=4)e[t]=e[t]>1?e[t]:1;return e}_ready(){this._init(),this.dispatchEvent(new CustomEvent("ready"))}async sendMessage(e,t={},s){await this._loaded,s?this._worker.postMessage({target:e,transferable:s,...t},[...s]):this._worker.postMessage({target:e,...t})}_fetchFromWorker(e,t){try{const s=e.target,a=setTimeout(()=>{n(new Error("Error: Timeout while try to fetch "+s))},5e3),r=({data:i})=>{i.target===s&&(t(null,i),this._worker.removeEventListener("message",r),this._worker.removeEventListener("error",n),clearTimeout(a))},n=i=>{t(i),this._worker.removeEventListener("message",r),this._worker.removeEventListener("error",n),clearTimeout(a)};this._worker.addEventListener("message",r),this._worker.addEventListener("error",n),this._worker.postMessage(e)}catch(s){this._error(s)}}_console({content:e,command:t}){console[t].apply(console,JSON.parse(e))}_onmessage({data:e}){this["_"+e.target]&&this["_"+e.target](e)}_error(e){this.dispatchEvent(e instanceof ErrorEvent?new ErrorEvent(e.type,e):new ErrorEvent("error",{cause:e instanceof Error?e.cause:e})),e instanceof Error||(e instanceof ErrorEvent?e=e.error:e=new Error("error",{cause:e})),console.error(e)}_removeListeners(){this._video&&(this._ro&&this._ro.unobserve(this._video),this._video.removeEventListener("timeupdate",this._boundTimeUpdate),this._video.removeEventListener("progress",this._boundTimeUpdate),this._video.removeEventListener("waiting",this._boundTimeUpdate),this._video.removeEventListener("seeking",this._boundTimeUpdate),this._video.removeEventListener("playing",this._boundTimeUpdate),this._video.removeEventListener("ratechange",this._boundSetRate),this._video.removeEventListener("resize",this._boundResize))}destroy(e){e&&this._error(e),this._video&&this._canvasParent&&this._video.parentNode.removeChild(this._canvasParent),this._destroyed=!0,this._removeListeners(),this.sendMessage("destroy"),this._worker.terminate()}};let d=o;return u(d,"_supportsWebAssembly",null),u(d,"_hasAlphaBug",null),d});
1
+ (function(l,d){typeof exports=="object"&&typeof module!="undefined"?module.exports=d():typeof define=="function"&&define.amd?define(d):(l=typeof globalThis!="undefined"?globalThis:l||self,l.JASSUB=d())})(this,function(){"use strict";var g=Object.defineProperty;var y=(l,d,u)=>d in l?g(l,d,{enumerable:!0,configurable:!0,writable:!0,value:u}):l[d]=u;var p=(l,d,u)=>(y(l,typeof d!="symbol"?d+"":d,u),u);!("requestVideoFrameCallback"in HTMLVideoElement.prototype)&&"getVideoPlaybackQuality"in HTMLVideoElement.prototype&&(HTMLVideoElement.prototype._rvfcpolyfillmap={},HTMLVideoElement.prototype.requestVideoFrameCallback=function(h){const e=this.getVideoPlaybackQuality(),t=this.mozPresentedFrames||this.mozPaintedFrames||e.totalVideoFrames-e.droppedVideoFrames,s=(r,n)=>{const o=this.getVideoPlaybackQuality(),m=this.mozPresentedFrames||this.mozPaintedFrames||o.totalVideoFrames-o.droppedVideoFrames;if(m>t){const f=this.mozFrameDelay||o.totalFrameDelay-e.totalFrameDelay||0,v=n-r;h(n,{presentationTime:n+f*1e3,expectedDisplayTime:n+v,width:this.videoWidth,height:this.videoHeight,mediaTime:Math.max(0,this.currentTime||0)+v/1e3,presentedFrames:m,processingDuration:f}),delete this._rvfcpolyfillmap[i]}else this._rvfcpolyfillmap[i]=requestAnimationFrame(f=>s(n,f))},i=Date.now(),a=performance.now();return this._rvfcpolyfillmap[i]=requestAnimationFrame(r=>s(a,r)),i},HTMLVideoElement.prototype.cancelVideoFrameCallback=function(h){cancelAnimationFrame(this._rvfcpolyfillmap[h]),delete this._rvfcpolyfillmap[h]});var l=typeof globalThis!="undefined"?globalThis:typeof window!="undefined"?window:typeof global!="undefined"?global:typeof self!="undefined"?self:{};const d=typeof globalThis!="undefined"&&globalThis||typeof self!="undefined"&&self||typeof l!="undefined"&&l;function u(h){try{new h}catch{return!1}return!0}(typeof d.Event!="function"||!u(d.Event))&&(d.Event=function(){function h(e,t){this.bubbles=!!t&&!!t.bubbles,this.cancelable=!!t&&!!t.cancelable,this.composed=!!t&&!!t.composed,this.type=e}return h}()),(typeof d.EventTarget=="undefined"||!u(d.Event))&&(d.EventTarget=function(){function h(){this.__listeners=new Map}return h.prototype=Object.create(Object.prototype),h.prototype.addEventListener=function(e,t,s){if(arguments.length<2)throw new TypeError(`TypeError: Failed to execute 'addEventListener' on 'EventTarget': 2 arguments required, but only ${arguments.length} present.`);const i=this.__listeners,a=e.toString();i.has(a)||i.set(a,new Map);const r=i.get(a);r.has(t)||r.set(t,s)},h.prototype.removeEventListener=function(e,t,s){if(arguments.length<2)throw new TypeError(`TypeError: Failed to execute 'addEventListener' on 'EventTarget': 2 arguments required, but only ${arguments.length} present.`);const i=this.__listeners,a=e.toString();if(i.has(a)){const r=i.get(a);r.has(t)&&r.delete(t)}},h.prototype.dispatchEvent=function(e){if(!(e instanceof Event))throw new TypeError("Failed to execute 'dispatchEvent' on 'EventTarget': parameter 1 is not of type 'Event'.");const t=e.type,i=this.__listeners.get(t);if(i)for(const[a,r]of i.entries()){try{typeof a=="function"?a.call(this,e):a&&typeof a.handleEvent=="function"&&a.handleEvent(e)}catch(n){setTimeout(()=>{throw n})}r&&r.once&&i.delete(a)}return!0},h}());const c=class extends EventTarget{constructor(e={}){var a,r,n;super(),globalThis.Worker||this.destroy("Worker not supported"),c._test();const t=e.blendMode||"js",s=typeof createImageBitmap!="undefined"&&((a=e.asyncRender)!=null?a:!0),i=typeof OffscreenCanvas!="undefined"&&((r=e.offscreenRender)!=null?r:!0);this._onDemandRender="requestVideoFrameCallback"in HTMLVideoElement.prototype&&((n=e.onDemandRender)!=null?n:!0),this.timeOffset=e.timeOffset||0,this._video=e.video,this._videoHeight=0,this._videoWidth=0,this._canvas=e.canvas,this._video&&!this._canvas?(this._canvasParent=document.createElement("div"),this._canvasParent.className="JASSUB",this._canvasParent.style.position="relative",this._canvas=document.createElement("canvas"),this._canvas.style.display="block",this._canvas.style.position="absolute",this._canvas.style.pointerEvents="none",this._canvasParent.appendChild(this._canvas),this._video.nextSibling?this._video.parentNode.insertBefore(this._canvasParent,this._video.nextSibling):this._video.parentNode.appendChild(this._canvasParent)):this._canvas||this.destroy("Don't know where to render: you should give video or canvas in options."),this._bufferCanvas=document.createElement("canvas"),this._bufferCtx=this._bufferCanvas.getContext("2d",{desynchronized:!0,willReadFrequently:!0}),this._canvasctrl=i?this._canvas.transferControlToOffscreen():this._canvas,this._ctx=!i&&this._canvasctrl.getContext("2d",{desynchronized:!0}),this._lastRenderTime=0,this.debug=!!e.debug,this.prescaleFactor=e.prescaleFactor||1,this.prescaleHeightLimit=e.prescaleHeightLimit||1080,this.maxRenderHeight=e.maxRenderHeight||0,this._worker=new Worker(c._supportsWebAssembly?e.workerUrl||"jassub-worker.js":e.legacyWorkerUrl||"jassub-worker-legacy.js"),this._worker.onmessage=o=>this._onmessage(o),this._worker.onerror=o=>this._error(o),this._loaded=new Promise(o=>{this._init=()=>{var m,f;this._destroyed||(this._worker.postMessage({target:"init",asyncRender:s,onDemandRender:this._onDemandRender,width:this._canvasctrl.width,height:this._canvasctrl.height,preMain:!0,blendMode:t,subUrl:e.subUrl,subContent:e.subContent||null,fonts:e.fonts||[],availableFonts:e.availableFonts||{"liberation sans":"./default.woff2"},fallbackFont:e.fallbackFont||"liberation sans",debug:this.debug,targetFps:e.targetFps||24,dropAllAnimations:e.dropAllAnimations,libassMemoryLimit:e.libassMemoryLimit||0,libassGlyphLimit:e.libassGlyphLimit||0,hasAlphaBug:c._hasAlphaBug,useLocalFonts:"queryLocalFonts"in self&&((m=e.useLocalFonts)!=null?m:!0)}),i===!0&&this.sendMessage("offscreenCanvas",null,[this._canvasctrl]),this._boundResize=this.resize.bind(this),this._boundTimeUpdate=this._timeupdate.bind(this),this._boundSetRate=this.setRate.bind(this),this._video&&this.setVideo(e.video),this._onDemandRender&&(this.busy=!1,this._lastDemandTime=null,(f=this._video)==null||f.requestVideoFrameCallback(this._handleRVFC.bind(this))),o())}})}static _test(){if(c._supportsWebAssembly!==null)return null;const e=document.createElement("canvas"),t=e.getContext("2d",{willReadFrequently:!0});if(typeof ImageData.prototype.constructor=="function")try{new ImageData(new Uint8ClampedArray([0,0,0,0]),1,1)}catch{console.log("detected that ImageData is not constructable despite browser saying so"),self.ImageData=function(o,m,f){const v=t.createImageData(m,f);return o&&v.data.set(o),v}}try{if(typeof WebAssembly=="object"&&typeof WebAssembly.instantiate=="function"){const n=new WebAssembly.Module(Uint8Array.of(0,97,115,109,1,0,0,0));n instanceof WebAssembly.Module&&(c._supportsWebAssembly=new WebAssembly.Instance(n)instanceof WebAssembly.Instance)}}catch{c._supportsWebAssembly=!1}const s=document.createElement("canvas"),i=s.getContext("2d",{willReadFrequently:!0});e.width=s.width=1,e.height=s.height=1,t.clearRect(0,0,1,1),i.clearRect(0,0,1,1);const a=i.getImageData(0,0,1,1).data;t.putImageData(new ImageData(new Uint8ClampedArray([0,255,0,0]),1,1),0,0),i.drawImage(e,0,0);const r=i.getImageData(0,0,1,1).data;c._hasAlphaBug=a[1]!==r[1],c._hasAlphaBug&&console.log("Detected a browser having issue with transparent pixels, applying workaround"),e.remove(),s.remove()}resize(e=0,t=0,s=0,i=0,a=(r=>(r=this._video)==null?void 0:r.paused)()){if((!e||!t)&&this._video){const n=this._getVideoPosition();let o=null;if(this._videoWidth){const m=this._video.videoWidth/this._videoWidth,f=this._video.videoHeight/this._videoHeight;o=this._computeCanvasSize((n.width||0)/m,(n.height||0)/f)}else o=this._computeCanvasSize(n.width||0,n.height||0);e=o.width,t=o.height,this._canvasParent&&(s=n.y-(this._canvasParent.getBoundingClientRect().top-this._video.getBoundingClientRect().top),i=n.x),this._canvas.style.width=n.width+"px",this._canvas.style.height=n.height+"px"}this._canvas.style.top=s+"px",this._canvas.style.left=i+"px",this.sendMessage("canvas",{width:e,height:t,force:a&&this.busy===!1})}_getVideoPosition(e=this._video.videoWidth,t=this._video.videoHeight){const s=e/t,{offsetWidth:i,offsetHeight:a}=this._video,r=i/a;e=i,t=a,r>s?e=Math.floor(a*s):t=Math.floor(i/s);const n=(i-e)/2,o=(a-t)/2;return{width:e,height:t,x:n,y:o}}_computeCanvasSize(e=0,t=0){const s=this.prescaleFactor<=0?1:this.prescaleFactor,i=self.devicePixelRatio||1;if(e=e*i,t=t*i,t<=0||e<=0)e=0,t=0;else{const a=s<1?-1:1;let r=t*i;a*r*s<=a*this.prescaleHeightLimit?r*=s:a*r<a*this.prescaleHeightLimit&&(r=this.prescaleHeightLimit),this.maxRenderHeight>0&&r>this.maxRenderHeight&&(r=this.maxRenderHeight),e*=r/t,t=r}return{width:e,height:t}}_timeupdate({type:e}){const s={seeking:!0,waiting:!0,playing:!1}[e];s!=null&&(this._playstate=s),this.setCurrentTime(this._video.paused||this._playstate,this._video.currentTime+this.timeOffset)}setVideo(e){e instanceof HTMLVideoElement?(this._removeListeners(),this._video=e,this._onDemandRender?this._video.requestVideoFrameCallback(this._handleRVFC.bind(this)):(this._playstate=e.paused,e.addEventListener("timeupdate",this._boundTimeUpdate,!1),e.addEventListener("progress",this._boundTimeUpdate,!1),e.addEventListener("waiting",this._boundTimeUpdate,!1),e.addEventListener("seeking",this._boundTimeUpdate,!1),e.addEventListener("playing",this._boundTimeUpdate,!1),e.addEventListener("ratechange",this._boundSetRate,!1),e.addEventListener("resize",this._boundResize)),e.videoWidth>0&&this.resize(),typeof ResizeObserver!="undefined"&&(this._ro||(this._ro=new ResizeObserver(()=>this.resize())),this._ro.observe(e))):this._error("Video element invalid!")}runBenchmark(){this.sendMessage("runBenchmark")}setTrackByUrl(e){this.sendMessage("setTrackByUrl",{url:e})}setTrack(e){this.sendMessage("setTrack",{content:e})}freeTrack(){this.sendMessage("freeTrack")}setIsPaused(e){this.sendMessage("video",{isPaused:e})}setRate(e){this.sendMessage("video",{rate:e})}setCurrentTime(e,t,s){this.sendMessage("video",{isPaused:e,currentTime:t,rate:s})}createEvent(e){this.sendMessage("createEvent",{event:e})}setEvent(e,t){this.sendMessage("setEvent",{event:e,index:t})}removeEvent(e){this.sendMessage("removeEvent",{index:e})}getEvents(e){this._fetchFromWorker({target:"getEvents"},(t,{events:s})=>{e(t,s)})}createStyle(e){this.sendMessage("createStyle",{style:e})}setStyle(e,t){this.sendMessage("setStyle",{event:e,index:t})}removeStyle(e){this.sendMessage("removeStyle",{index:e})}getStyles(e){this._fetchFromWorker({target:"getStyles"},(t,{styles:s})=>{e(t,s)})}addFont(e){this.sendMessage("addFont",{font:e})}_sendLocalFont(e){try{queryLocalFonts().then(t=>{const s=t==null?void 0:t.find(i=>i.fullName.toLowerCase()===e);s&&s.blob().then(i=>{i.arrayBuffer().then(a=>{this.addFont(new Uint8Array(a))})})})}catch(t){console.warn("Local fonts API:",t)}}_getLocalFont({font:e}){var t;try{(t=navigator==null?void 0:navigator.permissions)!=null&&t.query?navigator.permissions.query({name:"local-fonts"}).then(s=>{s.state==="granted"&&this._sendLocalFont(e)}):this._sendLocalFont(e)}catch(s){console.warn("Local fonts API:",s)}}_unbusy(){this._lastDemandTime?this._demandRender(this._lastDemandTime):this.busy=!1}_handleRVFC(e,{mediaTime:t,width:s,height:i}){if(this._destroyed)return null;this.busy?this._lastDemandTime={mediaTime:t,width:s,height:i}:(this.busy=!0,this._demandRender({mediaTime:t,width:s,height:i})),this._video.requestVideoFrameCallback(this._handleRVFC.bind(this))}_demandRender({mediaTime:e,width:t,height:s}){this._lastDemandTime=null,(t!==this._videoWidth||s!==this._videoHeight)&&(this._videoWidth=t,this._videoHeight=s,this.resize()),this.sendMessage("demand",{time:e+this.timeOffset})}_render({images:e,async:t,times:s,width:i,height:a}){this._unbusy();const r=Date.now();(this._canvasctrl.width!==i||this._canvasctrl.height!==a)&&(this._canvasctrl.width=i,this._canvasctrl.height=a),this._ctx.clearRect(0,0,this._canvasctrl.width,this._canvasctrl.height);for(const n of e)n.image&&(t?(this._ctx.drawImage(n.image,n.x,n.y),n.image.close()):(this._bufferCanvas.width=n.w,this._bufferCanvas.height=n.h,this._bufferCtx.putImageData(new ImageData(this._fixAlpha(new Uint8ClampedArray(n.image)),n.w,n.h),0,0),this._ctx.drawImage(this._bufferCanvas,n.x,n.y)));if(this.debug){s.drawTime=Date.now()-r;let n=0;for(const o in s)n+=s[o];console.log("Bitmaps: "+e.length+" Total: "+Math.round(n)+"ms",s)}}_fixAlpha(e){if(c._hasAlphaBug)for(let t=3;t<e.length;t+=4)e[t]=e[t]>1?e[t]:1;return e}_ready(){this._init(),this.dispatchEvent(new CustomEvent("ready"))}async sendMessage(e,t={},s){await this._loaded,s?this._worker.postMessage({target:e,transferable:s,...t},[...s]):this._worker.postMessage({target:e,...t})}_fetchFromWorker(e,t){try{const s=e.target,i=setTimeout(()=>{r(new Error("Error: Timeout while try to fetch "+s))},5e3),a=({data:n})=>{n.target===s&&(t(null,n),this._worker.removeEventListener("message",a),this._worker.removeEventListener("error",r),clearTimeout(i))},r=n=>{t(n),this._worker.removeEventListener("message",a),this._worker.removeEventListener("error",r),clearTimeout(i)};this._worker.addEventListener("message",a),this._worker.addEventListener("error",r),this._worker.postMessage(e)}catch(s){this._error(s)}}_console({content:e,command:t}){console[t].apply(console,JSON.parse(e))}_onmessage({data:e}){this["_"+e.target]&&this["_"+e.target](e)}_error(e){this.dispatchEvent(e instanceof ErrorEvent?new ErrorEvent(e.type,e):new ErrorEvent("error",{cause:e instanceof Error?e.cause:e})),e instanceof Error||(e instanceof ErrorEvent?e=e.error:e=new Error("error",{cause:e})),console.error(e)}_removeListeners(){this._video&&(this._ro&&this._ro.unobserve(this._video),this._video.removeEventListener("timeupdate",this._boundTimeUpdate),this._video.removeEventListener("progress",this._boundTimeUpdate),this._video.removeEventListener("waiting",this._boundTimeUpdate),this._video.removeEventListener("seeking",this._boundTimeUpdate),this._video.removeEventListener("playing",this._boundTimeUpdate),this._video.removeEventListener("ratechange",this._boundSetRate),this._video.removeEventListener("resize",this._boundResize))}destroy(e){e&&this._error(e),this._video&&this._canvasParent&&this._video.parentNode.removeChild(this._canvasParent),this._destroyed=!0,this._removeListeners(),this.sendMessage("destroy"),this._worker.terminate()}};let _=c;return p(_,"_supportsWebAssembly",null),p(_,"_hasAlphaBug",null),_});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jassub",
3
- "version": "1.5.2",
3
+ "version": "1.5.3",
4
4
  "description": "libass Subtitle Renderer and Parser library for browsers",
5
5
  "main": "src/jassub.js",
6
6
  "files": [