@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.
- package/dist/src/core/CoreNode.d.ts +2 -1
- package/dist/src/core/CoreNode.js +42 -58
- package/dist/src/core/CoreNode.js.map +1 -1
- package/dist/src/core/CoreTextNode.d.ts +2 -0
- package/dist/src/core/CoreTextNode.js +35 -18
- package/dist/src/core/CoreTextNode.js.map +1 -1
- package/dist/src/core/CoreTextureManager.js +0 -1
- package/dist/src/core/CoreTextureManager.js.map +1 -1
- package/dist/src/core/TextureMemoryManager.d.ts +0 -13
- package/dist/src/core/TextureMemoryManager.js +0 -24
- package/dist/src/core/TextureMemoryManager.js.map +1 -1
- package/dist/src/core/animations/AnimationManager.d.ts +1 -0
- package/dist/src/core/animations/AnimationManager.js.map +1 -1
- package/dist/src/core/animations/CoreAnimation.d.ts +1 -0
- package/dist/src/core/animations/CoreAnimation.js +1 -0
- package/dist/src/core/animations/CoreAnimation.js.map +1 -1
- package/dist/src/core/renderers/webgl/WebGlRenderer.d.ts +15 -0
- package/dist/src/core/renderers/webgl/WebGlRenderer.js +35 -6
- package/dist/src/core/renderers/webgl/WebGlRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/CanvasTextRenderer.js +12 -1
- package/dist/src/core/text-rendering/CanvasTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/SdfFontHandler.js +5 -4
- package/dist/src/core/text-rendering/SdfFontHandler.js.map +1 -1
- package/dist/src/core/text-rendering/SdfTextRenderer.js +16 -6
- package/dist/src/core/text-rendering/SdfTextRenderer.js.map +1 -1
- package/dist/src/core/text-rendering/TextRenderer.d.ts +0 -31
- package/dist/src/main-api/Renderer.js +4 -2
- package/dist/src/main-api/Renderer.js.map +1 -1
- package/dist/tsconfig.dist.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/core/CoreNode.test.ts +47 -46
- package/src/core/CoreNode.ts +46 -57
- package/src/core/CoreTextNode.ts +38 -23
- package/src/core/CoreTextureManager.ts +0 -2
- package/src/core/TextureMemoryManager.ts +0 -27
- package/src/core/animations/AnimationManager.ts +1 -0
- package/src/core/animations/CoreAnimation.ts +2 -1
- package/src/core/renderers/webgl/WebGlRenderer.ts +37 -6
- package/src/core/text-rendering/CanvasTextRenderer.ts +14 -1
- package/src/core/text-rendering/SdfFontHandler.ts +6 -5
- package/src/core/text-rendering/SdfTextRenderer.ts +19 -6
- package/src/core/text-rendering/TextRenderer.ts +0 -31
- 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) | (
|
|
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
|
-
|
|
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
|
|
424
|
-
|
|
425
|
-
|
|
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
|
-
|
|
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,
|
|
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;
|
package/src/main-api/Renderer.ts
CHANGED
|
@@ -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
|
|
961
|
-
|
|
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
|
|