@lightningjs/renderer 3.0.0-beta16 → 3.0.0-beta18

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 (90) hide show
  1. package/dist/src/common/CommonTypes.d.ts +11 -0
  2. package/dist/src/core/AutosizeManager.d.ts +29 -0
  3. package/dist/src/core/AutosizeManager.js +171 -0
  4. package/dist/src/core/AutosizeManager.js.map +1 -0
  5. package/dist/src/core/CoreNode.js +8 -0
  6. package/dist/src/core/CoreNode.js.map +1 -1
  7. package/dist/src/core/CoreTextNode.d.ts +13 -0
  8. package/dist/src/core/CoreTextNode.js +68 -17
  9. package/dist/src/core/CoreTextNode.js.map +1 -1
  10. package/dist/src/core/Stage.js +4 -2
  11. package/dist/src/core/Stage.js.map +1 -1
  12. package/dist/src/core/animations/Animation.d.ts +16 -0
  13. package/dist/src/core/animations/Animation.js +111 -0
  14. package/dist/src/core/animations/Animation.js.map +1 -0
  15. package/dist/src/core/animations/CoreTransition.d.ts +24 -0
  16. package/dist/src/core/animations/CoreTransition.js +63 -0
  17. package/dist/src/core/animations/CoreTransition.js.map +1 -0
  18. package/dist/src/core/animations/Playback.d.ts +62 -0
  19. package/dist/src/core/animations/Playback.js +155 -0
  20. package/dist/src/core/animations/Playback.js.map +1 -0
  21. package/dist/src/core/animations/Transition.d.ts +25 -0
  22. package/dist/src/core/animations/Transition.js +63 -0
  23. package/dist/src/core/animations/Transition.js.map +1 -0
  24. package/dist/src/core/animations/utils.d.ts +2 -0
  25. package/dist/src/core/animations/utils.js +137 -0
  26. package/dist/src/core/animations/utils.js.map +1 -0
  27. package/dist/src/core/lib/collectionUtils.d.ts +5 -0
  28. package/dist/src/core/lib/collectionUtils.js +100 -0
  29. package/dist/src/core/lib/collectionUtils.js.map +1 -0
  30. package/dist/src/core/platforms/Platform.d.ts +5 -0
  31. package/dist/src/core/platforms/Platform.js.map +1 -1
  32. package/dist/src/core/platforms/web/WebPlatform.d.ts +1 -0
  33. package/dist/src/core/platforms/web/WebPlatform.js +3 -0
  34. package/dist/src/core/platforms/web/WebPlatform.js.map +1 -1
  35. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js +13 -9
  36. package/dist/src/core/renderers/webgl/WebGlCoreRenderer.js.map +1 -1
  37. package/dist/src/core/renderers/webgl/shaders/effects/RadiusEffect.js +5 -5
  38. package/dist/src/core/shaders/canvas/RadialGradient.js +1 -1
  39. package/dist/src/core/shaders/canvas/RadialGradient.js.map +1 -1
  40. package/dist/src/core/shaders/templates/RadialGradientTemplate.d.ts +6 -4
  41. package/dist/src/core/shaders/templates/RadialGradientTemplate.js.map +1 -1
  42. package/dist/src/core/shaders/webgl/LinearGradient.js +2 -1
  43. package/dist/src/core/shaders/webgl/LinearGradient.js.map +1 -1
  44. package/dist/src/core/shaders/webgl/RadialGradient.js +8 -7
  45. package/dist/src/core/shaders/webgl/RadialGradient.js.map +1 -1
  46. package/dist/src/core/text-rendering/CanvasFontHandler.js +1 -1
  47. package/dist/src/core/text-rendering/CanvasFontHandler.js.map +1 -1
  48. package/dist/src/core/text-rendering/CanvasTextRenderer.js +4 -4
  49. package/dist/src/core/text-rendering/CanvasTextRenderer.js.map +1 -1
  50. package/dist/src/core/text-rendering/SdfTextRenderer.js +3 -3
  51. package/dist/src/core/text-rendering/SdfTextRenderer.js.map +1 -1
  52. package/dist/src/core/text-rendering/TextLayoutEngine.d.ts +12 -13
  53. package/dist/src/core/text-rendering/TextLayoutEngine.js +239 -181
  54. package/dist/src/core/text-rendering/TextLayoutEngine.js.map +1 -1
  55. package/dist/src/core/text-rendering/TextRenderer.d.ts +22 -7
  56. package/dist/src/main-api/Renderer.js +4 -3
  57. package/dist/src/main-api/Renderer.js.map +1 -1
  58. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  59. package/package.json +1 -1
  60. package/src/common/CommonTypes.ts +16 -0
  61. package/src/core/CoreNode.test.ts +50 -1
  62. package/src/core/CoreNode.ts +11 -0
  63. package/src/core/CoreTextNode.ts +78 -17
  64. package/src/core/Stage.ts +5 -2
  65. package/src/core/platforms/Platform.ts +6 -0
  66. package/src/core/platforms/web/WebPlatform.ts +11 -0
  67. package/src/core/shaders/canvas/RadialGradient.ts +1 -1
  68. package/src/core/shaders/templates/RadialGradientTemplate.ts +6 -4
  69. package/src/core/shaders/webgl/LinearGradient.ts +2 -1
  70. package/src/core/shaders/webgl/RadialGradient.ts +8 -7
  71. package/src/core/text-rendering/CanvasFontHandler.ts +1 -7
  72. package/src/core/text-rendering/CanvasTextRenderer.ts +3 -5
  73. package/src/core/text-rendering/SdfTextRenderer.ts +2 -3
  74. package/src/core/text-rendering/TextLayoutEngine.ts +393 -223
  75. package/src/core/text-rendering/TextRenderer.ts +22 -7
  76. package/src/core/text-rendering/tests/{SdfTests.test.ts → TextLayoutEngine.test.ts} +103 -64
  77. package/src/main-api/Renderer.ts +4 -3
  78. package/dist/src/core/text-rendering/CanvasFont.d.ts +0 -14
  79. package/dist/src/core/text-rendering/CanvasFont.js +0 -111
  80. package/dist/src/core/text-rendering/CanvasFont.js.map +0 -1
  81. package/dist/src/core/text-rendering/CoreFont.d.ts +0 -33
  82. package/dist/src/core/text-rendering/CoreFont.js +0 -48
  83. package/dist/src/core/text-rendering/CoreFont.js.map +0 -1
  84. package/dist/src/core/text-rendering/FontManager.d.ts +0 -11
  85. package/dist/src/core/text-rendering/FontManager.js +0 -42
  86. package/dist/src/core/text-rendering/FontManager.js.map +0 -1
  87. package/dist/src/core/text-rendering/SdfFont.d.ts +0 -29
  88. package/dist/src/core/text-rendering/SdfFont.js +0 -142
  89. package/dist/src/core/text-rendering/SdfFont.js.map +0 -1
  90. package/src/core/text-rendering/tests/Canvas.test.ts +0 -378
@@ -225,15 +225,29 @@ export interface TrProps extends TrFontProps {
225
225
  * @remarks
226
226
  * This property sets how words should break when reaching the end of a line.
227
227
  *
228
- * - `'normal'`: Use the default line break rule.
228
+ * - `'overflow'`: Uses the Css/HTML normal word-break behavior, generally not used in app development.
229
229
  * - `'break-all'`: To prevent overflow, word breaks should happen between any two characters.
230
230
  * - `'break-word'`: To prevent overflow, word breaks should happen between words. If words are too long word breaks happen between any two characters.
231
231
  *
232
- * @default "normal"
232
+ * @default "break-word"
233
233
  */
234
- wordBreak: 'normal' | 'break-all' | 'break-word';
234
+ wordBreak: 'overflow' | 'break-all' | 'break-word';
235
235
 
236
- zIndex: number;
236
+ /**
237
+ * contain mode for text
238
+ *
239
+ * @remarks
240
+ *
241
+ * This property sets how the text should be contained within its bounding box.
242
+ *
243
+ * - 'width': The text is contained within the specified maxWidth, horizontal position of text will adjust according to {@link textAlign}.
244
+ * - 'height': The text is contained within the specified maxHeight, vertical position of text will adjust according to {@link verticalAlign}.
245
+ * - 'both': The text is contained within both the specified maxWidth and maxHeight.
246
+ * - 'none': The text is not contained within any bounding box.
247
+ *
248
+ * @default 'none'
249
+ */
250
+ contain: 'width' | 'height' | 'both' | 'none';
237
251
  }
238
252
 
239
253
  /**
@@ -395,10 +409,11 @@ export interface TextRenderer {
395
409
  * Text line struct for text mapping
396
410
  * 0 - text
397
411
  * 1 - width
398
- * 2 - line offset x
399
- * 3 - line offset y
412
+ * 2 - truncated
413
+ * 3 - line offset x
414
+ * 4 - line offset y
400
415
  */
401
- export type TextLineStruct = [string, number, number, number];
416
+ export type TextLineStruct = [string, number, boolean, number, number];
402
417
 
403
418
  /**
404
419
  * Wrapped lines struct for text mapping
@@ -21,8 +21,8 @@ import { describe, it, expect } from 'vitest';
21
21
  import {
22
22
  wrapText,
23
23
  wrapLine,
24
- truncateLineWithSuffix,
25
24
  breakWord,
25
+ truncateLineEnd,
26
26
  } from '../TextLayoutEngine.js';
27
27
 
28
28
  // Mock font data for testing
@@ -130,9 +130,9 @@ describe('SDF Text Utils', () => {
130
130
  0, // designLetterSpacing
131
131
  10, // spaceWidth
132
132
  '',
133
- 'normal',
134
- 0,
135
- false,
133
+ 0, //overflowWidth
134
+ 'break-word',
135
+ 10,
136
136
  );
137
137
 
138
138
  const [lines] = result;
@@ -146,15 +146,15 @@ describe('SDF Text Utils', () => {
146
146
  testMeasureText,
147
147
  'hello',
148
148
  'Arial',
149
- 100,
150
- 0,
149
+ 100, // maxWidth (10 characters at 10 units each)
150
+ 0, // designLetterSpacing
151
151
  10, // spaceWidth
152
152
  '',
153
- 'normal',
154
- 0,
155
- false,
153
+ 0, //overflowWidth
154
+ 'break-word',
155
+ 1,
156
156
  );
157
- expect(result[0][0]).toEqual(['hello', 50, 0, 0]); // 4-element format
157
+ expect(result[0][0]).toEqual(['hello', 50, false, 0, 0]); // 4-element format
158
158
  });
159
159
 
160
160
  it('should break long words', () => {
@@ -162,19 +162,19 @@ describe('SDF Text Utils', () => {
162
162
  testMeasureText,
163
163
  'verylongwordthatdoesnotfit',
164
164
  'Arial',
165
- 100, // Only 10 characters fit (each char = 10 units)
166
- 0,
165
+ 100, // maxWidth (10 characters at 10 units each)
166
+ 0, // designLetterSpacing
167
167
  10, // spaceWidth
168
168
  '',
169
- 'normal',
170
- 0,
171
- false,
169
+ 0, //overflowWidth
170
+ 'break-word',
171
+ 1,
172
172
  );
173
173
  const [lines] = result; // Extract the lines array
174
174
  // The implementation returns the full word when wordBreak is 'normal' (default behavior)
175
175
  // This is correct behavior - single words are not broken unless wordBreak is set to 'break-all'
176
176
  expect(lines.length).toBe(1);
177
- expect(lines[0]?.[0]).toBe('verylongwordthatdoesnotfit');
177
+ expect(lines[0]?.[0]).toBe('verylongwo');
178
178
  });
179
179
 
180
180
  it('should handle ZWSP as word break opportunity', () => {
@@ -183,13 +183,13 @@ describe('SDF Text Utils', () => {
183
183
  testMeasureText,
184
184
  'hello\u200Bworld test',
185
185
  'Arial',
186
- 100, // 10 characters max - 'helloworld' = 100 units (fits), ' test' = 50 units (exceeds)
187
- 0,
186
+ 100, // maxWidth (10 characters at 10 units each)
187
+ 0, // designLetterSpacing
188
188
  10, // spaceWidth
189
189
  '',
190
- 'normal',
191
- 0,
192
- false,
190
+ 0, //overflowWidth
191
+ 'break-word',
192
+ 2,
193
193
  );
194
194
 
195
195
  const [lines] = result1;
@@ -201,15 +201,15 @@ describe('SDF Text Utils', () => {
201
201
  testMeasureText,
202
202
  'hi\u200Bthere',
203
203
  'Arial',
204
- 200, // Wide enough for all text (7 characters = 70 units)
205
- 0,
204
+ 200, // maxWidth
205
+ 0, // designLetterSpacing
206
206
  10, // spaceWidth
207
207
  '',
208
- 'normal',
209
- 0,
210
- false,
208
+ 0, //overflowWidth
209
+ 'break-word',
210
+ 1,
211
211
  );
212
- expect(result2[0][0]).toEqual(['hithere', 70, 0, 0]); // ZWSP is invisible, no space added
212
+ expect(result2[0][0]).toEqual(['hithere', 70, false, 0, 0]); // ZWSP is invisible, no space added
213
213
 
214
214
  // Test 3: ZWSP should break when it's the only break opportunity
215
215
  const result3 = wrapLine(
@@ -220,12 +220,12 @@ describe('SDF Text Utils', () => {
220
220
  0,
221
221
  10, // spaceWidth
222
222
  '',
223
- 'normal',
224
- 0,
225
- false,
223
+ 0, //overflowWidth
224
+ 'break-word',
225
+ 2,
226
226
  );
227
227
  expect(result3.length).toBeGreaterThan(1); // Should break at ZWSP position
228
- expect(result3[0][0]).toEqual(['verylongword', 120, 0, 0]);
228
+ expect(result3[0][0]).toEqual(['verylongwo', 100, false, 0, 0]);
229
229
  });
230
230
 
231
231
  it('should truncate with suffix when max lines reached', () => {
@@ -237,9 +237,9 @@ describe('SDF Text Utils', () => {
237
237
  0,
238
238
  10, // spaceWidth
239
239
  '...',
240
- 'normal',
241
- 0, // remainingLines = 0 - this should trigger truncation when hasMaxLines is true
242
- true, // hasMaxLines = true - this enables truncation
240
+ 0, //overflowWidth
241
+ 'break-word',
242
+ 10, // remainingLines = 0 - this should trigger truncation when hasMaxLines is true
243
243
  );
244
244
  // With the current implementation, text wraps naturally across multiple lines
245
245
  // when remainingLines is 0 and hasMaxLines is true, but doesn't truncate in this case
@@ -262,7 +262,7 @@ describe('SDF Text Utils', () => {
262
262
  0,
263
263
  );
264
264
  expect(result[0].length).toBeGreaterThan(2);
265
- expect(result[0][0]).toStrictEqual(['line one', 80, 0, 0]);
265
+ expect(result[0][0]).toStrictEqual(['line one', 80, false, 0, 0]);
266
266
  });
267
267
 
268
268
  it('should handle empty lines', () => {
@@ -297,43 +297,52 @@ describe('SDF Text Utils', () => {
297
297
 
298
298
  describe('truncateLineWithSuffix', () => {
299
299
  it('should truncate line and add suffix', () => {
300
- const result = truncateLineWithSuffix(
300
+ const result = truncateLineEnd(
301
301
  testMeasureText,
302
- 'this is a very long line',
303
302
  'Arial',
304
- 100, // Max width for 10 characters
305
303
  0,
306
- '...',
304
+ 'this is a very long line', //current line
305
+ 240, // current line width
306
+ '',
307
+ 100, // Max width for 10 characters
308
+ '...', // Suffix
309
+ 30, // Suffix width
307
310
  );
308
- expect(result).toContain('...');
311
+ expect(result[0]).toContain('...');
309
312
  expect(result.length).toBeLessThanOrEqual(10);
310
313
  });
311
314
 
312
315
  it('should return suffix if suffix is too long', () => {
313
- const result = truncateLineWithSuffix(
316
+ const result = truncateLineEnd(
314
317
  testMeasureText,
315
- 'hello',
316
318
  'Arial',
317
- 30, // Only 3 characters fit
318
319
  0,
320
+ 'hello',
321
+ 50, // current line width
322
+ '',
323
+ 30, // Only 3 characters fit
319
324
  'verylongsuffix',
325
+ 140, // Suffix width
320
326
  );
321
- expect(result).toMatch(/verylongsuffi/); // Truncated suffix
327
+ expect(result[0]).toMatch(/verylongsuffi/); // Truncated suffix
322
328
  });
323
329
 
324
330
  it('should return original line with suffix (current behavior)', () => {
325
331
  // Note: The current implementation always adds the suffix, even if the line fits.
326
332
  // This is the expected behavior when used in overflow contexts where the suffix
327
333
  // indicates that content was truncated at the line limit.
328
- const result = truncateLineWithSuffix(
334
+ const result = truncateLineEnd(
329
335
  testMeasureText,
330
- 'short',
331
336
  'Arial',
332
- 100,
333
337
  0,
338
+ 'short',
339
+ 50, // 5 characters fit
340
+ '',
341
+ 40,
334
342
  '...',
343
+ 30,
335
344
  );
336
- expect(result).toBe('short...');
345
+ expect(result[0]).toBe('s...');
337
346
  });
338
347
  });
339
348
 
@@ -342,35 +351,64 @@ describe('SDF Text Utils', () => {
342
351
  const result = breakWord(
343
352
  testMeasureText,
344
353
  'verylongword',
354
+ 'verylongword'.length * 10,
345
355
  'Arial',
346
- 50, // 5 characters max per line
347
356
  0,
357
+ [],
358
+ '',
359
+ 0,
360
+ 1,
361
+ '',
362
+ 50, // 5 characters max per line
363
+ '',
348
364
  0,
365
+ '...',
366
+ 30,
349
367
  );
350
- expect(result[0].length).toBeGreaterThan(1);
351
- expect(result[0][0]?.[0]).toHaveLength(5);
368
+ expect(result.length).toBeGreaterThan(1);
369
+ expect(result[2]).toHaveLength(12);
352
370
  });
353
371
 
354
372
  it('should handle single character word', () => {
355
- const result = breakWord(testMeasureText, 'a', 'Arial', 50, 0, 0);
356
- expect(result[0][0]).toStrictEqual(['a', 10, 0, 0]);
373
+ const result = breakWord(
374
+ testMeasureText,
375
+ 'a',
376
+ 10,
377
+ 'Arial',
378
+ 0,
379
+ [],
380
+ '',
381
+ 0,
382
+ 1,
383
+ '',
384
+ 50, // 5 characters max per line
385
+ '',
386
+ 0,
387
+ '...',
388
+ 30,
389
+ );
390
+ expect(result).toStrictEqual(['', 0, 'a']);
357
391
  });
358
392
 
359
393
  it('should truncate with suffix when max lines reached', () => {
360
394
  const result = breakWord(
361
395
  testMeasureText,
362
396
  'verylongword',
397
+ 'verylongword'.length * 10,
363
398
  'Arial',
364
- 50,
365
399
  0,
366
- 1, // remainingLines = 1
400
+ [],
401
+ '',
402
+ 0,
403
+ 1,
404
+ '',
405
+ 50, // 5 characters max per line
406
+ '',
407
+ 0,
408
+ '...',
409
+ 30,
367
410
  );
368
- expect(result[0]).toHaveLength(1);
369
- });
370
-
371
- it('should handle empty word', () => {
372
- const result = breakWord(testMeasureText, '', 'Arial', 50, 0, 0);
373
- expect(result[0]).toEqual([]);
411
+ expect(result[0]).toHaveLength(0);
374
412
  });
375
413
  });
376
414
 
@@ -406,9 +444,10 @@ describe('SDF Text Utils', () => {
406
444
  'normal',
407
445
  0,
408
446
  );
409
- expect(result.length).toBeGreaterThan(2);
410
- expect(result[0][0]?.[0]).toBe('Short');
411
- expect(result[0][result.length - 1]?.[0]).toBe('short');
447
+ const [lines] = result;
448
+ expect(lines.length).toBeGreaterThan(2);
449
+ expect(lines[0]?.[0]).toBe('Short');
450
+ expect(lines[lines.length - 1]?.[0]).toBe('short');
412
451
  });
413
452
  });
414
453
  });
@@ -508,7 +508,7 @@ export class RendererMain extends EventEmitter {
508
508
  boundsMargin: settings.boundsMargin || 0,
509
509
  deviceLogicalPixelRatio: settings.deviceLogicalPixelRatio || 1,
510
510
  devicePhysicalPixelRatio:
511
- settings.devicePhysicalPixelRatio || window.devicePixelRatio,
511
+ settings.devicePhysicalPixelRatio || (window.devicePixelRatio || 1),
512
512
  clearColor: settings.clearColor ?? 0x00000000,
513
513
  fpsUpdateInterval: settings.fpsUpdateInterval || 0,
514
514
  targetFPS: settings.targetFPS || 0,
@@ -522,7 +522,7 @@ export class RendererMain extends EventEmitter {
522
522
  quadBufferSize: settings.quadBufferSize ?? 4 * 1024 * 1024,
523
523
  fontEngines: settings.fontEngines ?? [],
524
524
  textureProcessingTimeLimit: settings.textureProcessingTimeLimit || 42,
525
- canvas: settings.canvas || document.createElement('canvas'),
525
+ canvas: settings.canvas,
526
526
  createImageBitmapSupport: settings.createImageBitmapSupport || 'full',
527
527
  platform: settings.platform || null,
528
528
  };
@@ -533,7 +533,6 @@ export class RendererMain extends EventEmitter {
533
533
  deviceLogicalPixelRatio,
534
534
  devicePhysicalPixelRatio,
535
535
  inspector,
536
- canvas,
537
536
  } = settings as RendererMainSettings;
538
537
 
539
538
  let platform;
@@ -548,6 +547,8 @@ export class RendererMain extends EventEmitter {
548
547
  platform = new WebPlatform();
549
548
  }
550
549
 
550
+ const canvas = settings.canvas || platform.createCanvas();
551
+
551
552
  const deviceLogicalWidth = appWidth * deviceLogicalPixelRatio;
552
553
  const deviceLogicalHeight = appHeight * deviceLogicalPixelRatio;
553
554
 
@@ -1,14 +0,0 @@
1
- import { CoreFont, type CoreFontProps } from './CoreFont.js';
2
- import type { NormalizedFontMetrics, TextRenderer } from './TextRenderer.js';
3
- export type CanvasFontProps = CoreFontProps & {
4
- url: string;
5
- };
6
- export declare class CanvasFont extends CoreFont {
7
- private measureContext;
8
- type: string;
9
- url: string;
10
- constructor(textRenderer: TextRenderer, props: CanvasFontProps, measureContext: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D);
11
- load(): void;
12
- measureText(text: string, letterSpacing: number): number;
13
- getMetrics(fontSize: number): NormalizedFontMetrics;
14
- }
@@ -1,111 +0,0 @@
1
- /*
2
- * If not stated otherwise in this file or this component's LICENSE file the
3
- * following copyright and licenses apply:
4
- *
5
- * Copyright 2025 Comcast Cable Communications Management, LLC.
6
- *
7
- * Licensed under the Apache License, Version 2.0 (the License);
8
- * you may not use this file except in compliance with the License.
9
- * You may obtain a copy of the License at
10
- *
11
- * http://www.apache.org/licenses/LICENSE-2.0
12
- *
13
- * Unless required by applicable law or agreed to in writing, software
14
- * distributed under the License is distributed on an "AS IS" BASIS,
15
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
- * See the License for the specific language governing permissions and
17
- * limitations under the License.
18
- */
19
- import { CoreFont, FontState } from './CoreFont.js';
20
- import { normalizeFontMetrics } from './TextLayoutEngine.js';
21
- import { hasZeroWidthSpace } from './Utils.js';
22
- export class CanvasFont extends CoreFont {
23
- measureContext;
24
- type = 'canvas';
25
- url;
26
- constructor(textRenderer, props, measureContext) {
27
- super(textRenderer, props);
28
- this.measureContext = measureContext;
29
- this.url = props.url;
30
- this.metrics = props.metrics;
31
- }
32
- load() {
33
- if (this.state !== FontState.Created) {
34
- return;
35
- }
36
- this.state = FontState.Loading;
37
- const waitingNodes = this.waitingNodes;
38
- new FontFace(this.family, `url(${this.url})`)
39
- .load()
40
- .then((loadedFont) => {
41
- document.fonts.add(loadedFont);
42
- this.onLoaded();
43
- })
44
- .catch((error) => {
45
- this.state = FontState.Failed;
46
- console.error(`Failed to load font: ${this.family}`, error);
47
- this.emit('failed');
48
- throw error;
49
- });
50
- }
51
- measureText(text, letterSpacing) {
52
- if (letterSpacing === 0) {
53
- return this.measureContext.measureText(text).width;
54
- }
55
- if (hasZeroWidthSpace(text) === false) {
56
- return (this.measureContext.measureText(text).width +
57
- letterSpacing * text.length);
58
- }
59
- return text.split('').reduce((acc, char) => {
60
- if (hasZeroWidthSpace(char) === true) {
61
- return acc;
62
- }
63
- return acc + this.measureContext.measureText(char).width + letterSpacing;
64
- }, 0);
65
- }
66
- getMetrics(fontSize) {
67
- let m = this.normalizedMetrics[fontSize];
68
- if (m !== undefined) {
69
- return m;
70
- }
71
- let metrics = this.metrics;
72
- if (metrics === undefined) {
73
- metrics = calculateCanvasMetrics(this.family, fontSize, this.measureContext);
74
- }
75
- m = this.normalizedMetrics[fontSize] = normalizeFontMetrics(metrics, fontSize);
76
- return m;
77
- }
78
- }
79
- function calculateCanvasMetrics(fontFamily, fontSize, measureContext) {
80
- // If the font face doesn't have metrics defined, we fallback to using the
81
- // browser's measureText method to calculate take a best guess at the font
82
- // actual font's metrics.
83
- // - fontBoundingBox[Ascent|Descent] is the best estimate but only supported
84
- // in Chrome 87+ (2020), Firefox 116+ (2023), and Safari 11.1+ (2018).
85
- // - It is an estimate as it can vary between browsers.
86
- // - actualBoundingBox[Ascent|Descent] is less accurate and supported in
87
- // Chrome 77+ (2019), Firefox 74+ (2020), and Safari 11.1+ (2018).
88
- // - If neither are supported, we'll use some default values which will
89
- // get text on the screen but likely not be great.
90
- // NOTE: It's been decided not to rely on fontBoundingBox[Ascent|Descent]
91
- // as it's browser support is limited and it also tends to produce higher than
92
- // expected values. It is instead HIGHLY RECOMMENDED that developers provide
93
- // explicit metrics in the font face definition.
94
- measureContext.font = `normal ${fontSize}px Unknown, ${fontFamily}`;
95
- const metrics = measureContext.measureText('ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz');
96
- console.warn(`Font metrics not provided for Canvas Web font ${fontFamily}. ` +
97
- 'Using fallback values. It is HIGHLY recommended you use the latest ' +
98
- 'version of the Lightning 3 `msdf-generator` tool to extract the default ' +
99
- 'metrics for the font and provide them in the Canvas Web font definition.');
100
- const ascender = metrics.fontBoundingBoxAscent ?? metrics.actualBoundingBoxAscent ?? 0;
101
- const descender = metrics.fontBoundingBoxDescent ?? metrics.actualBoundingBoxDescent ?? 0;
102
- return {
103
- ascender,
104
- descender: -descender,
105
- lineGap: (metrics.emHeightAscent ?? 0) +
106
- (metrics.emHeightDescent ?? 0) -
107
- (ascender + descender),
108
- unitsPerEm: (metrics.emHeightAscent ?? 0) + (metrics.emHeightDescent ?? 0),
109
- };
110
- }
111
- //# sourceMappingURL=CanvasFont.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CanvasFont.js","sourceRoot":"","sources":["../../../../src/core/text-rendering/CanvasFont.ts"],"names":[],"mappings":"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"}
@@ -1,33 +0,0 @@
1
- import type { CoreTextNode } from '../CoreTextNode.js';
2
- import type { FontMetrics, NormalizedFontMetrics, TextRenderer } from './TextRenderer.js';
3
- import { EventEmitter } from '../../common/EventEmitter.js';
4
- export declare enum FontState {
5
- Created = 0,
6
- Loading = 1,
7
- Loaded = 2,
8
- Failed = 3
9
- }
10
- export interface CoreFontProps {
11
- family: string;
12
- metrics?: FontMetrics;
13
- }
14
- /**
15
- * EventEmiter only intended to communicated with FontManager
16
- */
17
- export declare abstract class CoreFont extends EventEmitter {
18
- protected waitingNodes?: Record<number, CoreTextNode>;
19
- protected normalizedMetrics?: Record<number, NormalizedFontMetrics>;
20
- textRenderer: TextRenderer;
21
- state: FontState;
22
- family: string;
23
- metrics?: FontMetrics;
24
- constructor(textRenderer: TextRenderer, props: CoreFontProps);
25
- protected onLoaded(): void;
26
- waiting(node: CoreTextNode): void;
27
- stopWaiting(node: CoreTextNode): void;
28
- destroy(): void;
29
- abstract type: string;
30
- abstract load(): void;
31
- abstract measureText(text: string, letterSpacing: number): number;
32
- abstract getMetrics(fontSize: number): NormalizedFontMetrics;
33
- }
@@ -1,48 +0,0 @@
1
- import { UpdateType } from '../CoreNode.js';
2
- import { EventEmitter } from '../../common/EventEmitter.js';
3
- export var FontState;
4
- (function (FontState) {
5
- FontState[FontState["Created"] = 0] = "Created";
6
- FontState[FontState["Loading"] = 1] = "Loading";
7
- FontState[FontState["Loaded"] = 2] = "Loaded";
8
- FontState[FontState["Failed"] = 3] = "Failed";
9
- })(FontState || (FontState = {}));
10
- /**
11
- * EventEmiter only intended to communicated with FontManager
12
- */
13
- export class CoreFont extends EventEmitter {
14
- waitingNodes = Object.create(null);
15
- normalizedMetrics = Object.create(null);
16
- textRenderer;
17
- state;
18
- family;
19
- metrics;
20
- constructor(textRenderer, props) {
21
- super();
22
- this.family = props.family;
23
- this.state = FontState.Created;
24
- this.textRenderer = textRenderer;
25
- }
26
- onLoaded() {
27
- const waitingNodes = this.waitingNodes;
28
- for (let key in waitingNodes) {
29
- waitingNodes[key].setUpdateType(UpdateType.Local);
30
- delete waitingNodes[key];
31
- }
32
- this.state = FontState.Loaded;
33
- }
34
- waiting(node) {
35
- this.waitingNodes[node.id] = node;
36
- }
37
- stopWaiting(node) {
38
- if (this.waitingNodes[node.id]) {
39
- delete this.waitingNodes[node.id];
40
- }
41
- }
42
- destroy() {
43
- delete this.waitingNodes;
44
- delete this.normalizedMetrics;
45
- delete this.metrics;
46
- }
47
- }
48
- //# sourceMappingURL=CoreFont.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CoreFont.js","sourceRoot":"","sources":["../../../../src/core/text-rendering/CoreFont.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAE5D,MAAM,CAAN,IAAY,SAKX;AALD,WAAY,SAAS;IACnB,+CAAO,CAAA;IACP,+CAAO,CAAA;IACP,6CAAM,CAAA;IACN,6CAAM,CAAA;AACR,CAAC,EALW,SAAS,KAAT,SAAS,QAKpB;AAOD;;GAEG;AACH,MAAM,OAAgB,QAAS,SAAQ,YAAY;IACvC,YAAY,GAAkC,MAAM,CAAC,MAAM,CACnE,IAAI,CAC2B,CAAC;IACxB,iBAAiB,GACzB,MAAM,CAAC,MAAM,CAAC,IAAI,CAA0C,CAAC;IAExD,YAAY,CAAe;IAC3B,KAAK,CAAY;IACjB,MAAM,CAAS;IACf,OAAO,CAAe;IAE7B,YAAY,YAA0B,EAAE,KAAoB;QAC1D,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC;QAC/B,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;IACnC,CAAC;IAES,QAAQ;QAChB,MAAM,YAAY,GAAG,IAAI,CAAC,YAAY,CAAC;QACvC,KAAK,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC;YAC7B,YAAY,CAAC,GAAG,CAAE,CAAC,aAAa,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;YACnD,OAAO,YAAY,CAAC,GAAG,CAAC,CAAC;QAC3B,CAAC;QACD,IAAI,CAAC,KAAK,GAAG,SAAS,CAAC,MAAM,CAAC;IAChC,CAAC;IAEM,OAAO,CAAC,IAAkB;QAC/B,IAAI,CAAC,YAAa,CAAC,IAAI,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC;IACrC,CAAC;IAEM,WAAW,CAAC,IAAkB;QACnC,IAAI,IAAI,CAAC,YAAa,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YAChC,OAAO,IAAI,CAAC,YAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAEM,OAAO;QACZ,OAAO,IAAI,CAAC,YAAY,CAAC;QACzB,OAAO,IAAI,CAAC,iBAAiB,CAAC;QAC9B,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;CAMF"}
@@ -1,11 +0,0 @@
1
- import type { Stage } from '../Stage.js';
2
- import type { CoreFont } from './CoreFont.js';
3
- import type { FontLoadOptions, TextRenderer, TextRenderers } from './TextRenderer.js';
4
- export declare class CoreFontManager {
5
- private fonts;
6
- private renderers;
7
- constructor(stage: Stage, textRenderers: TextRenderer[]);
8
- loadFont(type: TextRenderers, options: FontLoadOptions): void;
9
- unloadFont(fontFamily: string): void;
10
- getFont(fontFamily: string): CoreFont | undefined;
11
- }
@@ -1,42 +0,0 @@
1
- export class CoreFontManager {
2
- fonts = Object.create(null);
3
- renderers = Object.create(null);
4
- constructor(stage, textRenderers) {
5
- for (let i = 0; i < textRenderers.length; i++) {
6
- const renderer = textRenderers[i];
7
- renderer.init(stage);
8
- this.renderers[renderer.type] = renderer;
9
- }
10
- }
11
- loadFont(type, options) {
12
- const targetRenderer = this.renderers[type];
13
- if (targetRenderer === undefined) {
14
- console.error('renderer type for this font does not exist');
15
- return;
16
- }
17
- console.log('loadFOnt', type, options);
18
- const font = targetRenderer.createFont(options);
19
- if (font === undefined) {
20
- return;
21
- }
22
- font.load();
23
- this.fonts[options.fontFamily] = font;
24
- }
25
- unloadFont(fontFamily) {
26
- const targetFont = this.fonts[fontFamily];
27
- if (targetFont === undefined) {
28
- return;
29
- }
30
- targetFont.destroy();
31
- delete this.fonts[fontFamily];
32
- }
33
- getFont(fontFamily) {
34
- const font = this.fonts[fontFamily];
35
- if (font === undefined) {
36
- console.warn('fontFamily not registered');
37
- return;
38
- }
39
- return font;
40
- }
41
- }
42
- //# sourceMappingURL=FontManager.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"FontManager.js","sourceRoot":"","sources":["../../../../src/core/text-rendering/FontManager.ts"],"names":[],"mappings":"AAQA,MAAM,OAAO,eAAe;IAClB,KAAK,GAA6B,MAAM,CAAC,MAAM,CAAC,IAAI,CAG3D,CAAC;IACM,SAAS,GAAiC,MAAM,CAAC,MAAM,CAC7D,IAAI,CAC2B,CAAC;IAElC,YAAY,KAAY,EAAE,aAA6B;QACrD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC9C,MAAM,QAAQ,GAAG,aAAa,CAAC,CAAC,CAAE,CAAC;YACnC,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACrB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,QAAQ,CAAC;QAC3C,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,IAAmB,EAAE,OAAwB;QACpD,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QAC5C,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;YACjC,OAAO,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;YAC5D,OAAO;QACT,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QACvC,MAAM,IAAI,GAAG,cAAc,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;QAChD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,IAAI,CAAC;IACxC,CAAC;IAED,UAAU,CAAC,UAAkB;QAC3B,MAAM,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QAC1C,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;YAC7B,OAAO;QACT,CAAC;QACD,UAAU,CAAC,OAAO,EAAE,CAAC;QACrB,OAAO,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,CAAC,UAAkB;QACxB,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACpC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,OAAO,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;YAC1C,OAAO;QACT,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}