@revideo/2d 0.5.3-alpha.1049 → 0.5.3-alpha.1054

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.
@@ -821,6 +821,7 @@ export class Layout extends Node {
821
821
  }
822
822
 
823
823
  protected override async draw(context: CanvasRenderingContext2D) {
824
+ await document.fonts?.ready;
824
825
  if (this.clip()) {
825
826
  const size = this.computedSize();
826
827
  if (size.width === 0 || size.height === 0) {
@@ -991,13 +992,25 @@ export class Layout extends Node {
991
992
 
992
993
  if (this.textWrap.isInitial()) {
993
994
  this.element.style.whiteSpace = '';
994
- } else {
995
- const wrap = this.textWrap();
996
- if (typeof wrap === 'boolean') {
997
- this.element.style.whiteSpace = wrap ? 'normal' : 'nowrap';
998
- } else {
999
- this.element.style.whiteSpace = wrap;
1000
- }
995
+ return;
996
+ }
997
+
998
+ const wrap = this.textWrap();
999
+
1000
+ if (typeof wrap === 'boolean') {
1001
+ this.element.style.whiteSpace = wrap ? 'normal' : 'nowrap';
1002
+ return;
1003
+ }
1004
+
1005
+ if (wrap === 'pre') {
1006
+ this.element.style.whiteSpace = wrap;
1007
+ return;
1008
+ }
1009
+
1010
+ if (wrap === 'balance') {
1011
+ this.element.style.whiteSpace = 'normal';
1012
+ this.element.style.textWrap = wrap;
1013
+ return;
1001
1014
  }
1002
1015
  }
1003
1016
 
@@ -82,13 +82,14 @@ export class Rive extends Asset {
82
82
 
83
83
  protected override async draw(context: CanvasRenderingContext2D) {
84
84
  this.drawShape(context);
85
- const {rive, renderer, canvas, artboard, animation} = await this.rive();
86
- const box = BBox.fromSizeCentered(this.computedSize());
87
85
 
88
86
  this.currentTime = this.time();
89
87
  const timeToAdvance = this.currentTime - this.lastTime;
90
88
  this.lastTime = this.currentTime;
91
89
 
90
+ const {rive, renderer, canvas, artboard, animation} = await this.rive();
91
+ const box = BBox.fromSizeCentered(this.computedSize());
92
+
92
93
  const renderPromise = new Promise<void>(resolve => {
93
94
  function renderLoop() {
94
95
  renderer.clear();
@@ -105,6 +105,7 @@ export class Txt extends Shape {
105
105
  timingFunction: TimingFunction,
106
106
  interpolationFunction: InterpolationFunction<string>,
107
107
  ): ThreadGenerator {
108
+ yield document.fonts?.ready;
108
109
  const children = this.children();
109
110
  if (children.length !== 1 || !(children[0] instanceof TxtLeaf)) {
110
111
  this.text.save();
@@ -178,6 +179,7 @@ export class Txt extends Shape {
178
179
  }
179
180
 
180
181
  protected override async draw(context: CanvasRenderingContext2D) {
182
+ await document.fonts?.ready;
181
183
  await this.drawChildren(context);
182
184
  }
183
185
  }
@@ -61,6 +61,7 @@ export class TxtLeaf extends Shape {
61
61
  }
62
62
 
63
63
  protected override async draw(context: CanvasRenderingContext2D) {
64
+ await document.fonts?.ready;
64
65
  this.requestFontUpdate();
65
66
  this.applyStyle(context);
66
67
  this.applyText(context);
@@ -106,7 +107,6 @@ export class TxtLeaf extends Shape {
106
107
  text: string,
107
108
  box: BBox,
108
109
  ) {
109
- await new Promise(resolve => document.fonts.ready.then(resolve));
110
110
  const y = box.y + box.height / 2;
111
111
  context.save();
112
112
  context.textBaseline = 'middle';
@@ -252,10 +252,6 @@ export class Video extends Media {
252
252
  }
253
253
 
254
254
  protected async seekFunction() {
255
- if (!this.fileTypeWasDetected) {
256
- this.detectedFileType = await this.detectFileType();
257
- this.fileTypeWasDetected = true;
258
- }
259
255
  const playbackState = this.view().playbackState();
260
256
 
261
257
  // During playback
@@ -283,6 +279,10 @@ export class Video extends Media {
283
279
  return this.webcodecSeekedVideo();
284
280
  }
285
281
 
282
+ if (!this.fileTypeWasDetected) {
283
+ this.detectFileType();
284
+ }
285
+
286
286
  // If not set explicitly, use detected file type to determine decoder
287
287
  if (this.detectedFileType === 'webm') {
288
288
  return this.ffmpegSeekedVideo();
@@ -333,41 +333,78 @@ export class Video extends Media {
333
333
  return this;
334
334
  }
335
335
 
336
- private async detectFileType(): Promise<
337
- 'mp4' | 'webm' | 'hls' | 'mov' | 'unknown'
338
- > {
339
- if (this.fullSource().split('?')[0].endsWith('.mp4')) return 'mp4';
340
- if (this.fullSource().split('?')[0].endsWith('.webm')) return 'webm';
341
- if (this.fullSource().split('?')[0].endsWith('.m3u8')) return 'hls';
342
- if (this.fullSource().split('?')[0].endsWith('.mov')) return 'mov';
336
+ private handleUnknownFileType(src: string) {
337
+ console.warn(
338
+ `WARNING: Could not detect file type of video (${src}), will default to using mp4 decoder. If your video file is not an mp4 file, this will lead to an error - to fix this, reencode your video as an mp4 file (better performance) or specify a different decoder: https://docs.re.video/common-issues/slow-rendering#use-mp4-decoder`,
339
+ );
340
+ this.detectedFileType = 'unknown';
341
+ this.fileTypeWasDetected = true;
342
+ }
343
+
344
+ private detectFileType() {
345
+ return DependencyContext.collectPromise(
346
+ (async () => {
347
+ const src = this.fullSource();
348
+ const extension = src.split('?')[0].split('.').pop()?.toLowerCase();
349
+
350
+ if (
351
+ extension === 'mp4' ||
352
+ extension === 'webm' ||
353
+ extension === 'mov'
354
+ ) {
355
+ this.detectedFileType = extension;
356
+ this.fileTypeWasDetected = true;
357
+ return;
358
+ }
343
359
 
344
- if (
345
- this.fullSource().startsWith('http://') ||
346
- this.fullSource().startsWith('https://')
347
- ) {
348
- try {
349
- const response = await fetch(this.fullSource(), {method: 'HEAD'});
360
+ if (extension === 'm3u8') {
361
+ this.detectedFileType = 'hls';
362
+ this.fileTypeWasDetected = true;
363
+ return;
364
+ }
365
+
366
+ if (!src.startsWith('http://') && !src.startsWith('https://')) {
367
+ this.handleUnknownFileType(src);
368
+ return;
369
+ }
370
+
371
+ const response = await fetch(src, {method: 'HEAD'});
350
372
  const contentType = response.headers.get('Content-Type');
351
373
 
352
- if (contentType) {
353
- if (contentType.includes('video/mp4')) return 'mp4';
354
- if (contentType.includes('video/webm')) return 'webm';
355
- if (contentType.includes('video/quicktime')) return 'mov';
356
- if (
357
- contentType.includes('application/vnd.apple.mpegurl') ||
358
- contentType.includes('application/x-mpegURL')
359
- ) {
360
- return 'hls';
361
- }
374
+ if (!contentType) {
375
+ this.handleUnknownFileType(src);
376
+ return;
362
377
  }
363
- } catch (error) {
364
- // do nothing
365
- }
366
- }
367
378
 
368
- console.warn(
369
- `WARNING: Could not detect file type of video (${this.fullSource()}), will default to using mp4 decoder. If your video file is no mp4 file, this will lead to an error - to fix this, reencode your video as an mp4 file (better performance) or specify a different decoder: https://docs.re.video/common-issues/slow-rendering#use-mp4-decoder`,
379
+ if (contentType.includes('video/mp4')) {
380
+ this.detectedFileType = 'mp4';
381
+ this.fileTypeWasDetected = true;
382
+ return;
383
+ }
384
+
385
+ if (contentType.includes('video/webm')) {
386
+ this.detectedFileType = 'webm';
387
+ this.fileTypeWasDetected = true;
388
+ return;
389
+ }
390
+
391
+ if (contentType.includes('video/quicktime')) {
392
+ this.detectedFileType = 'mov';
393
+ this.fileTypeWasDetected = true;
394
+ return;
395
+ }
396
+
397
+ if (
398
+ contentType.includes('application/vnd.apple.mpegurl') ||
399
+ contentType.includes('application/x-mpegURL')
400
+ ) {
401
+ this.detectedFileType = 'hls';
402
+ this.fileTypeWasDetected = true;
403
+ return;
404
+ }
405
+
406
+ this.handleUnknownFileType(src);
407
+ })(),
370
408
  );
371
- return 'unknown';
372
409
  }
373
410
  }
@@ -25,7 +25,7 @@ export type FlexContent =
25
25
 
26
26
  export type FlexItems = 'center' | 'start' | 'end' | 'stretch' | 'baseline';
27
27
 
28
- export type TextWrap = boolean | 'pre';
28
+ export type TextWrap = boolean | 'pre' | 'balance';
29
29
 
30
30
  export type LayoutMode = boolean | null;
31
31