@solidtv/renderer 1.0.5 → 1.0.7

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 (43) hide show
  1. package/dist/src/core/CoreNode.d.ts +2 -1
  2. package/dist/src/core/CoreNode.js +42 -58
  3. package/dist/src/core/CoreNode.js.map +1 -1
  4. package/dist/src/core/CoreTextNode.d.ts +2 -0
  5. package/dist/src/core/CoreTextNode.js +35 -18
  6. package/dist/src/core/CoreTextNode.js.map +1 -1
  7. package/dist/src/core/CoreTextureManager.js +0 -1
  8. package/dist/src/core/CoreTextureManager.js.map +1 -1
  9. package/dist/src/core/TextureMemoryManager.d.ts +0 -13
  10. package/dist/src/core/TextureMemoryManager.js +0 -24
  11. package/dist/src/core/TextureMemoryManager.js.map +1 -1
  12. package/dist/src/core/animations/AnimationManager.d.ts +1 -0
  13. package/dist/src/core/animations/AnimationManager.js.map +1 -1
  14. package/dist/src/core/animations/CoreAnimation.d.ts +1 -0
  15. package/dist/src/core/animations/CoreAnimation.js +1 -0
  16. package/dist/src/core/animations/CoreAnimation.js.map +1 -1
  17. package/dist/src/core/renderers/webgl/WebGlRenderer.d.ts +15 -0
  18. package/dist/src/core/renderers/webgl/WebGlRenderer.js +35 -6
  19. package/dist/src/core/renderers/webgl/WebGlRenderer.js.map +1 -1
  20. package/dist/src/core/text-rendering/CanvasTextRenderer.js +12 -1
  21. package/dist/src/core/text-rendering/CanvasTextRenderer.js.map +1 -1
  22. package/dist/src/core/text-rendering/SdfFontHandler.js +5 -4
  23. package/dist/src/core/text-rendering/SdfFontHandler.js.map +1 -1
  24. package/dist/src/core/text-rendering/SdfTextRenderer.js +16 -6
  25. package/dist/src/core/text-rendering/SdfTextRenderer.js.map +1 -1
  26. package/dist/src/core/text-rendering/TextRenderer.d.ts +0 -31
  27. package/dist/src/main-api/Renderer.js +4 -2
  28. package/dist/src/main-api/Renderer.js.map +1 -1
  29. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  30. package/package.json +1 -1
  31. package/src/core/CoreNode.test.ts +47 -46
  32. package/src/core/CoreNode.ts +46 -57
  33. package/src/core/CoreTextNode.ts +38 -23
  34. package/src/core/CoreTextureManager.ts +0 -2
  35. package/src/core/TextureMemoryManager.ts +0 -27
  36. package/src/core/animations/AnimationManager.ts +1 -0
  37. package/src/core/animations/CoreAnimation.ts +2 -1
  38. package/src/core/renderers/webgl/WebGlRenderer.ts +37 -6
  39. package/src/core/text-rendering/CanvasTextRenderer.ts +14 -1
  40. package/src/core/text-rendering/SdfFontHandler.ts +6 -5
  41. package/src/core/text-rendering/SdfTextRenderer.ts +19 -6
  42. package/src/core/text-rendering/TextRenderer.ts +0 -31
  43. package/src/main-api/Renderer.ts +4 -2
@@ -59,6 +59,21 @@ export class WebGlRenderer extends CoreRenderer {
59
59
  fQuadBuffer: Float32Array;
60
60
  uiQuadBuffer: Uint32Array;
61
61
  renderOps: WebGlRenderOp[] = [];
62
+ /**
63
+ * Deferred queue for SDF text render ops, used when RENDER_TEXT_BATCHING is
64
+ * true. All text encountered during the frame is collected here and appended
65
+ * to renderOps at the end (see flushTextRenderOps). This guarantees that all
66
+ * text in a frame draws in a single contiguous run of draw calls, which is
67
+ * the whole point of text batching.
68
+ *
69
+ * Side effect by design: text always draws on top of any non-text quads that
70
+ * came after it in tree order (unless those quads carry an explicit zIndex,
71
+ * which forces an early flush in addQuad). This is intentional — UI text
72
+ * sitting above adjacent backgrounds/icons is the common case, and the
73
+ * batching win is only worth taking if we don't break the run with mid-frame
74
+ * flushes. If you need a non-text quad to land above earlier text, give it
75
+ * a non-zero zIndex.
76
+ */
62
77
  coreTextRenderOps: WebGlRenderOp[] = [];
63
78
 
64
79
  //// Render Op / Buffer Filling State
@@ -361,10 +376,22 @@ export class WebGlRenderer extends CoreRenderer {
361
376
  const f = this.fQuadBuffer;
362
377
  const u = this.uiQuadBuffer;
363
378
 
379
+ // Explicit zIndex on a non-text quad opts out of the text-batching
380
+ // ordering: flush deferred text now so this quad lands above any text
381
+ // that came earlier in tree order. See coreTextRenderOps for the
382
+ // intentional default behavior.
364
383
  if (RENDER_TEXT_BATCHING === true && node.props.zIndex) {
365
384
  this.flushTextRenderOps();
366
385
  }
367
386
 
387
+ // With batching off, SDF ops live inside renderOps interleaved with quad
388
+ // ops. A non-text quad inserted here would otherwise still let the next
389
+ // text node extend the previous SDF op (same atlas/clipping), drawing
390
+ // those glyphs at the earlier position and getting overdrawn by this quad.
391
+ if (RENDER_TEXT_BATCHING === false) {
392
+ this.curSdfRenderOp = null;
393
+ }
394
+
368
395
  const reuse = this.reuseRenderOp(node);
369
396
 
370
397
  // During RTT rendering, always use sequential allocation and write data
@@ -600,18 +627,16 @@ export class WebGlRenderer extends CoreRenderer {
600
627
 
601
628
  // Pre-compute the merged color (with alpha) packed as ABGR for
602
629
  // UNSIGNED_BYTE normalized attribute.
630
+ // NOTE: Do NOT premultiply RGB by alpha here — the SDF fragment shader
631
+ // already multiplies v_color.rgb by the computed opacity (which includes
632
+ // v_color.a).
603
633
  const mergedColor = mergeColorAlpha(color, worldAlpha);
604
634
  const r = mergedColor >>> 24;
605
635
  const g = (mergedColor >>> 16) & 0xff;
606
636
  const b = (mergedColor >>> 8) & 0xff;
607
637
  const a = mergedColor & 0xff;
608
- // Premultiply alpha into RGB for correct blending
609
- const na = a / 255;
610
- const pr = (r * na) | 0;
611
- const pg = (g * na) | 0;
612
- const pb = (b * na) | 0;
613
638
  // Pack as ABGR uint32 (little-endian read as vec4(r,g,b,a) normalized)
614
- const packedColor = ((a << 24) | (pb << 16) | (pg << 8) | pr) >>> 0;
639
+ const packedColor = ((a << 24) | (b << 16) | (g << 8) | r) >>> 0;
615
640
 
616
641
  // Transform matrix components (column-major 3x3)
617
642
  // Pre-multiply fontScale here to save 4 multiplications per glyph in the hot loop
@@ -1083,6 +1108,12 @@ export class WebGlRenderer extends CoreRenderer {
1083
1108
  this.needsFullUpload = true;
1084
1109
  this.lastUploadedBufferSize = 0;
1085
1110
 
1111
+ // Clear merge anchors so the first addQuad / addSdfQuads in this pass
1112
+ // can't extend a stale op left over from the previous RTT pass (whose
1113
+ // node is no longer in renderOps and would silently swallow the draw).
1114
+ this.curRenderOp = null;
1115
+ this.curSdfRenderOp = null;
1116
+
1086
1117
  // Recursively render the full subtree into the RTT framebuffer.
1087
1118
  // The old code only called renderQuads on direct children, missing
1088
1119
  // grandchildren and deeper descendants.
@@ -77,6 +77,14 @@ const renderText = (props: CoreTextNodeProps): TextRenderInfo => {
77
77
  assertTruthy(canvas, 'Canvas is not initialized');
78
78
  assertTruthy(context, 'Canvas context is not available');
79
79
  assertTruthy(measureContext, 'Canvas measureContext is not available');
80
+
81
+ if (props.text.length === 0) {
82
+ return {
83
+ width: 0,
84
+ height: 0,
85
+ };
86
+ }
87
+
80
88
  // Extract already normalized properties
81
89
  const {
82
90
  text,
@@ -130,7 +138,12 @@ const renderText = (props: CoreTextNodeProps): TextRenderInfo => {
130
138
 
131
139
  canvas.width = canvasW;
132
140
  canvas.height = canvasH;
133
- context.fillStyle = 'white';
141
+ const color = props.color ?? 0xffffffff;
142
+ const r = (color >>> 24) & 0xff;
143
+ const g = (color >>> 16) & 0xff;
144
+ const b = (color >>> 8) & 0xff;
145
+ const a = color & 0xff;
146
+ context.fillStyle = `rgba(${r},${g},${b},${a / 255})`;
134
147
  context.font = font;
135
148
  context.textBaseline = 'hanging';
136
149
 
@@ -417,12 +417,13 @@ export const isFontLoaded = (fontFamily: string): boolean => {
417
417
  */
418
418
  export const getFontMetrics = (
419
419
  fontFamily: string,
420
-
421
420
  fontSize: number,
422
421
  ): NormalizedFontMetrics => {
423
- const out = normalizedMetrics.get(fontFamily);
424
- if (out !== undefined) {
425
- return out;
422
+ const label = fontFamily + '_' + fontSize;
423
+ const metricsCache = normalizedMetrics.get(label);
424
+
425
+ if (metricsCache !== undefined) {
426
+ return metricsCache;
426
427
  }
427
428
  let metrics = fontCache.get(fontFamily)!.metrics;
428
429
  return processFontMetrics(fontFamily, fontSize, metrics);
@@ -433,7 +434,7 @@ export const processFontMetrics = (
433
434
  fontSize: number,
434
435
  metrics: FontMetrics,
435
436
  ): NormalizedFontMetrics => {
436
- const label = fontFamily + fontSize;
437
+ const label = fontFamily + '_' + fontSize;
437
438
  const normalized = normalizeFontMetrics(metrics, fontSize);
438
439
  normalizedMetrics.set(label, normalized);
439
440
  return normalized;
@@ -32,6 +32,10 @@ const init = (stage: Stage): void => {
32
32
  };
33
33
 
34
34
  const font: FontHandler = SdfFontHandler;
35
+ const layoutCache = new Map<string, TextLayout>();
36
+
37
+ const getLayoutCacheKey = (props: CoreTextNodeProps): string =>
38
+ `${props.fontFamily}-${props.fontSize}-${props.letterSpacing}-${props.lineHeight}-${props.maxHeight}-${props.maxWidth}-${props.textAlign}-${props.text}`;
35
39
 
36
40
  /**
37
41
  * SDF text renderer using MSDF/SDF fonts with WebGL
@@ -49,6 +53,18 @@ const renderText = (props: CoreTextNodeProps): TextRenderInfo => {
49
53
  };
50
54
  }
51
55
 
56
+ const cacheKey = getLayoutCacheKey(props);
57
+ let layout = layoutCache.get(cacheKey);
58
+ if (layout !== undefined) {
59
+ return {
60
+ remainingLines: 0,
61
+ hasRemainingText: false,
62
+ width: layout.width,
63
+ height: layout.height,
64
+ layout,
65
+ };
66
+ }
67
+
52
68
  // Get font cache for this font family
53
69
  const fontData = SdfFontHandler.getFontData(props.fontFamily);
54
70
  if (fontData === undefined) {
@@ -60,7 +76,8 @@ const renderText = (props: CoreTextNodeProps): TextRenderInfo => {
60
76
  }
61
77
 
62
78
  // Calculate text layout and generate glyph data for caching
63
- const layout = generateTextLayout(props, fontData);
79
+ layout = generateTextLayout(props, fontData);
80
+ layoutCache.set(cacheKey, layout);
64
81
 
65
82
  // For SDF renderer, ImageData is null since we render via WebGL
66
83
  return {
@@ -68,7 +85,7 @@ const renderText = (props: CoreTextNodeProps): TextRenderInfo => {
68
85
  hasRemainingText: false,
69
86
  width: layout.width,
70
87
  height: layout.height,
71
- layout, // Cache layout for addQuads
88
+ layout,
72
89
  };
73
90
  };
74
91
 
@@ -302,14 +319,10 @@ const generateTextLayout = (
302
319
 
303
320
  // Calculate glyph position and atlas coordinates (in design units)
304
321
  const glyphLayout: GlyphLayout = {
305
- codepoint,
306
- glyphId: glyph.id,
307
322
  x: currentX + glyph.xoffset,
308
323
  y: currentY + glyph.yoffset,
309
324
  width: glyph.width,
310
325
  height: glyph.height,
311
- xOffset: glyph.xoffset,
312
- yOffset: glyph.yoffset,
313
326
  atlasX: glyph.x * invAtlasWidth,
314
327
  atlasY: glyph.y * invAtlasHeight,
315
328
  atlasWidth: glyph.width * invAtlasWidth,
@@ -236,41 +236,10 @@ export interface TrProps extends TrFontProps {
236
236
  * Glyph layout information for WebGL rendering
237
237
  */
238
238
  export interface GlyphLayout {
239
- /**
240
- * Unicode codepoint
241
- */
242
- codepoint: number;
243
- /**
244
- * Glyph ID in the font atlas
245
- */
246
- glyphId: number;
247
- /**
248
- * X position relative to text origin
249
- */
250
239
  x: number;
251
- /**
252
- * Y position relative to text origin
253
- */
254
240
  y: number;
255
- /**
256
- * Width of glyph in font units
257
- */
258
241
  width: number;
259
- /**
260
- * Height of glyph in font units
261
- */
262
242
  height: number;
263
- /**
264
- * X offset for glyph positioning
265
- */
266
- xOffset: number;
267
- /**
268
- * Y offset for glyph positioning
269
- */
270
- yOffset: number;
271
- /**
272
- * Atlas texture coordinates (normalized 0-1)
273
- */
274
243
  atlasX: number;
275
244
  atlasY: number;
276
245
  atlasWidth: number;
@@ -957,8 +957,10 @@ export class RendererMain extends EventEmitter {
957
957
  this.canvas.width = deviceLogicalWidth * devicePhysicalPixelRatio;
958
958
  this.canvas.height = deviceLogicalHeight * devicePhysicalPixelRatio;
959
959
 
960
- this.canvas.style.width = `${deviceLogicalWidth}px`;
961
- this.canvas.style.height = `${deviceLogicalHeight}px`;
960
+ if (this.canvas.style) {
961
+ this.canvas.style.width = `${deviceLogicalWidth}px`;
962
+ this.canvas.style.height = `${deviceLogicalHeight}px`;
963
+ }
962
964
 
963
965
  this.stage.renderer.updateViewport();
964
966