@solidtv/renderer 1.5.5 → 1.6.0
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/src/core/CoreNode.js +2 -2
- package/dist/src/core/CoreNode.js.map +1 -1
- package/dist/src/core/Stage.js +9 -1
- package/dist/src/core/Stage.js.map +1 -1
- package/dist/src/core/lib/WebGlContextWrapper.d.ts +17 -1
- package/dist/src/core/lib/WebGlContextWrapper.js +21 -0
- package/dist/src/core/lib/WebGlContextWrapper.js.map +1 -1
- package/dist/src/core/lib/colorParser.d.ts +4 -1
- package/dist/src/core/lib/colorParser.js +16 -6
- package/dist/src/core/lib/colorParser.js.map +1 -1
- package/dist/src/core/lib/validateImageBitmap.js +7 -0
- package/dist/src/core/lib/validateImageBitmap.js.map +1 -1
- package/dist/src/core/platforms/web/WebPlatform.js +39 -2
- package/dist/src/core/platforms/web/WebPlatform.js.map +1 -1
- package/dist/src/core/renderers/canvas/CanvasRenderer.d.ts +4 -0
- package/dist/src/core/renderers/canvas/CanvasRenderer.js +28 -13
- package/dist/src/core/renderers/canvas/CanvasRenderer.js.map +1 -1
- package/dist/src/core/renderers/canvas/CanvasShaderNode.js +1 -0
- package/dist/src/core/renderers/canvas/CanvasShaderNode.js.map +1 -1
- package/dist/src/core/renderers/webgl/SdfRenderOp.js +2 -2
- package/dist/src/core/renderers/webgl/SdfRenderOp.js.map +1 -1
- package/dist/src/core/renderers/webgl/WebGlRenderer.d.ts +43 -0
- package/dist/src/core/renderers/webgl/WebGlRenderer.js +109 -10
- package/dist/src/core/renderers/webgl/WebGlRenderer.js.map +1 -1
- package/dist/src/core/renderers/webgl/WebGlShaderProgram.js +21 -13
- package/dist/src/core/renderers/webgl/WebGlShaderProgram.js.map +1 -1
- package/dist/src/core/renderers/webgl/internal/ShaderUtils.d.ts +8 -3
- package/dist/src/core/renderers/webgl/internal/ShaderUtils.js +12 -11
- package/dist/src/core/renderers/webgl/internal/ShaderUtils.js.map +1 -1
- package/dist/src/core/shaders/canvas/Rounded.js +3 -3
- package/dist/src/core/shaders/canvas/Rounded.js.map +1 -1
- package/dist/src/core/shaders/canvas/RoundedWithShadow.js +3 -3
- package/dist/src/core/shaders/canvas/RoundedWithShadow.js.map +1 -1
- package/dist/src/core/shaders/canvas/utils/render.js +3 -3
- package/dist/src/core/shaders/canvas/utils/render.js.map +1 -1
- package/dist/src/core/shaders/webgl/Border.js +12 -11
- package/dist/src/core/shaders/webgl/Border.js.map +1 -1
- package/dist/src/core/shaders/webgl/HolePunch.js +12 -5
- package/dist/src/core/shaders/webgl/HolePunch.js.map +1 -1
- package/dist/src/core/shaders/webgl/LinearGradient.js +3 -19
- package/dist/src/core/shaders/webgl/LinearGradient.js.map +1 -1
- package/dist/src/core/shaders/webgl/RadialGradient.js +3 -20
- package/dist/src/core/shaders/webgl/RadialGradient.js.map +1 -1
- package/dist/src/core/shaders/webgl/RadialProgress.js +15 -23
- package/dist/src/core/shaders/webgl/RadialProgress.js.map +1 -1
- package/dist/src/core/shaders/webgl/RoundedWithBorder.js +35 -32
- package/dist/src/core/shaders/webgl/RoundedWithBorder.js.map +1 -1
- package/dist/src/core/shaders/webgl/RoundedWithBorderAndShadow.js +58 -45
- package/dist/src/core/shaders/webgl/RoundedWithBorderAndShadow.js.map +1 -1
- package/dist/src/core/shaders/webgl/RoundedWithShadow.js +15 -13
- package/dist/src/core/shaders/webgl/RoundedWithShadow.js.map +1 -1
- package/dist/src/core/shaders/webgl/Shadow.js +4 -5
- package/dist/src/core/shaders/webgl/Shadow.js.map +1 -1
- package/dist/src/core/text-rendering/SdfTextRenderer.js +23 -10
- package/dist/src/core/text-rendering/SdfTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/TextLayoutEngine.js +14 -2
- package/dist/src/core/text-rendering/TextLayoutEngine.js.map +1 -1
- package/dist/src/main-api/Renderer.d.ts +20 -0
- package/dist/src/main-api/Renderer.js +6 -0
- package/dist/src/main-api/Renderer.js.map +1 -1
- package/dist/src/utils.js +1 -1
- package/dist/src/utils.js.map +1 -1
- package/dist/tsconfig.dist.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/core/CoreNode.ts +2 -2
- package/src/core/Stage.renderListUpdate.test.ts +73 -0
- package/src/core/Stage.ts +11 -1
- package/src/core/lib/WebGlContextWrapper.test.ts +23 -1
- package/src/core/lib/WebGlContextWrapper.ts +23 -1
- package/src/core/lib/colorParser.test.ts +46 -0
- package/src/core/lib/colorParser.ts +17 -6
- package/src/core/lib/validateImageBitmap.test.ts +15 -0
- package/src/core/lib/validateImageBitmap.ts +8 -0
- package/src/core/platforms/web/WebPlatform.loopError.test.ts +145 -0
- package/src/core/platforms/web/WebPlatform.ts +39 -2
- package/src/core/renderers/canvas/CanvasRenderer.test.ts +230 -0
- package/src/core/renderers/canvas/CanvasRenderer.ts +29 -15
- package/src/core/renderers/canvas/CanvasShaderNode.test.ts +73 -0
- package/src/core/renderers/canvas/CanvasShaderNode.ts +1 -0
- package/src/core/renderers/webgl/SdfRenderOp.ts +2 -2
- package/src/core/renderers/webgl/WebGlRenderer.reuseRenderOp.test.ts +122 -0
- package/src/core/renderers/webgl/WebGlRenderer.sdfBuffer.test.ts +302 -0
- package/src/core/renderers/webgl/WebGlRenderer.ts +151 -11
- package/src/core/renderers/webgl/WebGlShaderProgram.reuseRenderOp.test.ts +150 -0
- package/src/core/renderers/webgl/WebGlShaderProgram.ts +27 -15
- package/src/core/renderers/webgl/WebGlShaderProgram.uniformDedup.test.ts +4 -2
- package/src/core/renderers/webgl/internal/ShaderUtils.test.ts +124 -0
- package/src/core/renderers/webgl/internal/ShaderUtils.ts +14 -13
- package/src/core/shaders/canvas/Rounded.ts +3 -3
- package/src/core/shaders/canvas/RoundedWithShadow.ts +3 -3
- package/src/core/shaders/canvas/utils/render.ts +3 -3
- package/src/core/shaders/webgl/Border.ts +12 -11
- package/src/core/shaders/webgl/HolePunch.ts +12 -5
- package/src/core/shaders/webgl/LinearGradient.ts +3 -19
- package/src/core/shaders/webgl/RadialGradient.ts +3 -20
- package/src/core/shaders/webgl/RadialProgress.ts +15 -23
- package/src/core/shaders/webgl/RoundedWithBorder.ts +35 -32
- package/src/core/shaders/webgl/RoundedWithBorderAndShadow.ts +58 -45
- package/src/core/shaders/webgl/RoundedWithShadow.ts +15 -13
- package/src/core/shaders/webgl/Shadow.ts +4 -5
- package/src/core/text-rendering/SdfTextRenderer.test.ts +177 -0
- package/src/core/text-rendering/SdfTextRenderer.ts +38 -10
- package/src/core/text-rendering/TextLayoutEngine.ts +15 -2
- package/src/core/text-rendering/tests/TextLayoutEngine.test.ts +99 -0
- package/src/main-api/Renderer.ts +28 -0
- package/src/utils.ts +1 -1
|
@@ -368,6 +368,13 @@ export const wrapLine = (
|
|
|
368
368
|
): WrappedLinesStruct => {
|
|
369
369
|
const words = line.split(spaceRegex);
|
|
370
370
|
const spaces = line.match(spaceRegex) || [];
|
|
371
|
+
// Leading whitespace splits into an empty token; fold it into the next
|
|
372
|
+
// word so it isn't dropped and re-applied after the first word instead.
|
|
373
|
+
if (words[0] === '' && words.length > 1) {
|
|
374
|
+
const leadingSpace = spaces.shift() ?? '';
|
|
375
|
+
words.shift();
|
|
376
|
+
words[0] = leadingSpace + (words[0] ?? '');
|
|
377
|
+
}
|
|
371
378
|
const wrappedLines: TextLineStruct[] = [];
|
|
372
379
|
let currentLine = '';
|
|
373
380
|
let currentLineWidth = 0;
|
|
@@ -454,8 +461,14 @@ export const wrapLine = (
|
|
|
454
461
|
continue;
|
|
455
462
|
}
|
|
456
463
|
const space = spaces[spaceIdx++] || '';
|
|
457
|
-
//
|
|
458
|
-
|
|
464
|
+
// Single ' ' is the dominant separator \u2014 reuse the precomputed width.
|
|
465
|
+
// Multi-space/ZWSP runs collapse into one match; measure those for real.
|
|
466
|
+
const effectiveSpaceWidth =
|
|
467
|
+
space === ' '
|
|
468
|
+
? spaceWidth
|
|
469
|
+
: space.length > 0
|
|
470
|
+
? measureText(space, fontFamily, letterSpacing)
|
|
471
|
+
: 0;
|
|
459
472
|
const totalWidth = currentLineWidth + effectiveSpaceWidth + wordWidth;
|
|
460
473
|
|
|
461
474
|
if (totalWidth < maxWidth) {
|
|
@@ -248,6 +248,105 @@ describe('SDF Text Utils', () => {
|
|
|
248
248
|
expect(result[0][0]?.[2]).toBe(true);
|
|
249
249
|
expect(result[1]).toBe(0);
|
|
250
250
|
});
|
|
251
|
+
|
|
252
|
+
it('should keep leading whitespace attached to the first word, not the word after it', () => {
|
|
253
|
+
// Regression test: a line starting with padding spaces (used e.g. to
|
|
254
|
+
// reserve room for an inline badge before the first word) used to have
|
|
255
|
+
// those spaces silently reassigned as the gap AFTER the first word.
|
|
256
|
+
const result = wrapLine(
|
|
257
|
+
testMeasureText,
|
|
258
|
+
' hello world',
|
|
259
|
+
'Arial',
|
|
260
|
+
1000,
|
|
261
|
+
0,
|
|
262
|
+
10, // spaceWidth
|
|
263
|
+
'',
|
|
264
|
+
0,
|
|
265
|
+
'break-word',
|
|
266
|
+
10,
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
const [lines] = result;
|
|
270
|
+
expect(lines).toHaveLength(1);
|
|
271
|
+
expect(lines[0]?.[0]).toBe(' hello world');
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('should count the full width of a multi-space separator when wrapping', () => {
|
|
275
|
+
// 'aa bb' really measures 60 (6 chars * 10). Counting the separator
|
|
276
|
+
// as a single spaceWidth (50) used to keep it on one line past maxWidth.
|
|
277
|
+
const result = wrapLine(
|
|
278
|
+
testMeasureText,
|
|
279
|
+
'aa bb',
|
|
280
|
+
'Arial',
|
|
281
|
+
55, // maxWidth — below the real 60, above the buggy 50
|
|
282
|
+
0,
|
|
283
|
+
10, // spaceWidth
|
|
284
|
+
'',
|
|
285
|
+
0,
|
|
286
|
+
'break-word',
|
|
287
|
+
10,
|
|
288
|
+
);
|
|
289
|
+
|
|
290
|
+
const [lines] = result;
|
|
291
|
+
expect(lines).toHaveLength(2);
|
|
292
|
+
expect(lines[0]).toEqual(['aa', 20, false, 0, 0]);
|
|
293
|
+
expect(lines[1]).toEqual(['bb', 20, false, 0, 0]);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('should preserve a multi-space separator and its width when the line fits', () => {
|
|
297
|
+
const result = wrapLine(
|
|
298
|
+
testMeasureText,
|
|
299
|
+
'aa bb',
|
|
300
|
+
'Arial',
|
|
301
|
+
1000,
|
|
302
|
+
0,
|
|
303
|
+
10, // spaceWidth
|
|
304
|
+
'',
|
|
305
|
+
0,
|
|
306
|
+
'break-word',
|
|
307
|
+
10,
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
expect(result[0][0]).toEqual(['aa bb', 60, false, 0, 0]);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('should treat a run of multiple ZWSPs as a zero-width separator', () => {
|
|
314
|
+
const result = wrapLine(
|
|
315
|
+
testMeasureText,
|
|
316
|
+
'aa\u200B\u200Bbb',
|
|
317
|
+
'Arial',
|
|
318
|
+
1000,
|
|
319
|
+
0,
|
|
320
|
+
10, // spaceWidth
|
|
321
|
+
'',
|
|
322
|
+
0,
|
|
323
|
+
'break-word',
|
|
324
|
+
10,
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
// Zero-width separator: no visible gap added, width is just the glyphs
|
|
328
|
+
expect(result[0][0]).toEqual(['aabb', 40, false, 0, 0]);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it('should use the precomputed spaceWidth for a single-space separator', () => {
|
|
332
|
+
// spaceWidth (4) deliberately differs from testMeasureText(' ') (10):
|
|
333
|
+
// the single-space fast path must reuse the precomputed value instead
|
|
334
|
+
// of re-measuring the separator.
|
|
335
|
+
const result = wrapLine(
|
|
336
|
+
testMeasureText,
|
|
337
|
+
'aa bb',
|
|
338
|
+
'Arial',
|
|
339
|
+
1000,
|
|
340
|
+
0,
|
|
341
|
+
4, // spaceWidth
|
|
342
|
+
'',
|
|
343
|
+
0,
|
|
344
|
+
'break-word',
|
|
345
|
+
10,
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
expect(result[0][0]).toEqual(['aa bb', 44, false, 0, 0]);
|
|
349
|
+
});
|
|
251
350
|
});
|
|
252
351
|
|
|
253
352
|
describe('wrapText', () => {
|
package/src/main-api/Renderer.ts
CHANGED
|
@@ -23,6 +23,9 @@ import type {
|
|
|
23
23
|
import { WebPlatform } from '../core/platforms/web/WebPlatform.js';
|
|
24
24
|
import { Platform } from '../core/platforms/Platform.js';
|
|
25
25
|
|
|
26
|
+
/** Shared default `handleLoopError` — swallows the error, keeping the loop alive. */
|
|
27
|
+
const noop = (): void => {};
|
|
28
|
+
|
|
26
29
|
/**
|
|
27
30
|
* FPS Update Event Data
|
|
28
31
|
*
|
|
@@ -661,6 +664,27 @@ export type RendererMainSettings = RendererRuntimeSettings & {
|
|
|
661
664
|
*
|
|
662
665
|
*/
|
|
663
666
|
maxRetryCount?: number;
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Render loop error handler — an escape hatch for `requestAnimationFrame` crashes
|
|
670
|
+
*
|
|
671
|
+
* @remarks
|
|
672
|
+
* The render loop runs client-supplied code every frame: synchronous event
|
|
673
|
+
* subscribers (`frameTick`, `idle`, `fpsUpdate`, etc.) and animation steps. If
|
|
674
|
+
* any of these throw, the exception would otherwise propagate out of the
|
|
675
|
+
* `requestAnimationFrame` callback and permanently stop the loop — freezing
|
|
676
|
+
* the entire app until reload.
|
|
677
|
+
*
|
|
678
|
+
* The loop catches such errors and never lets them stop it. By default the
|
|
679
|
+
* error is swallowed (the default handler is a no-op), so a single bad frame
|
|
680
|
+
* can't freeze the app. Provide your own handler to log/report the crash (and
|
|
681
|
+
* optionally recover); the loop still keeps running after it returns.
|
|
682
|
+
*
|
|
683
|
+
* @param error The error thrown during the frame
|
|
684
|
+
*
|
|
685
|
+
* @defaultValue a no-op (errors are swallowed; the loop keeps running)
|
|
686
|
+
*/
|
|
687
|
+
handleLoopError?: (error: unknown) => void;
|
|
664
688
|
};
|
|
665
689
|
|
|
666
690
|
/**
|
|
@@ -777,6 +801,9 @@ export class RendererMain extends EventEmitter {
|
|
|
777
801
|
: settings.premultiplyAlphaHonored,
|
|
778
802
|
platform: settings.platform || null,
|
|
779
803
|
maxRetryCount: settings.maxRetryCount ?? 5,
|
|
804
|
+
// Default to a no-op so a thrown frame is swallowed and the render loop
|
|
805
|
+
// never crashes; apps can override to log/report.
|
|
806
|
+
handleLoopError: settings.handleLoopError ?? noop,
|
|
780
807
|
};
|
|
781
808
|
|
|
782
809
|
const {
|
|
@@ -841,6 +868,7 @@ export class RendererMain extends EventEmitter {
|
|
|
841
868
|
premultiplyAlphaHonored: settings.premultiplyAlphaHonored,
|
|
842
869
|
platform,
|
|
843
870
|
maxRetryCount: settings.maxRetryCount ?? 5,
|
|
871
|
+
handleLoopError: settings.handleLoopError,
|
|
844
872
|
});
|
|
845
873
|
|
|
846
874
|
// Extract the root node
|
package/src/utils.ts
CHANGED
|
@@ -9,7 +9,7 @@ export function createWebGLContext(
|
|
|
9
9
|
alpha: true,
|
|
10
10
|
antialias: false,
|
|
11
11
|
depth: false,
|
|
12
|
-
stencil:
|
|
12
|
+
stencil: false,
|
|
13
13
|
desynchronized: false,
|
|
14
14
|
// Disabled because it prevents Visual Regression Tests from working
|
|
15
15
|
// failIfMajorPerformanceCaveat: true,
|