@solidtv/renderer 1.0.0 → 1.0.2

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 (60) hide show
  1. package/dist/src/core/CoreNode.js +13 -11
  2. package/dist/src/core/CoreNode.js.map +1 -1
  3. package/dist/src/core/CoreTextNode.js +2 -1
  4. package/dist/src/core/CoreTextNode.js.map +1 -1
  5. package/dist/src/core/lib/utils.d.ts +2 -2
  6. package/dist/src/core/lib/utils.js +21 -21
  7. package/dist/src/core/lib/utils.js.map +1 -1
  8. package/dist/src/core/renderers/CoreRenderer.d.ts +0 -30
  9. package/dist/src/core/renderers/CoreRenderer.js.map +1 -1
  10. package/dist/src/core/renderers/canvas/CanvasRenderer.d.ts +2 -1
  11. package/dist/src/core/renderers/canvas/CanvasRenderer.js +128 -47
  12. package/dist/src/core/renderers/canvas/CanvasRenderer.js.map +1 -1
  13. package/dist/src/core/renderers/canvas/CanvasShaderNode.d.ts +1 -2
  14. package/dist/src/core/renderers/canvas/CanvasShaderNode.js.map +1 -1
  15. package/dist/src/core/renderers/webgl/SdfRenderOp.d.ts +5 -5
  16. package/dist/src/core/renderers/webgl/SdfRenderOp.js +8 -8
  17. package/dist/src/core/renderers/webgl/SdfRenderOp.js.map +1 -1
  18. package/dist/src/core/renderers/webgl/WebGlShaderProgram.js +3 -4
  19. package/dist/src/core/renderers/webgl/WebGlShaderProgram.js.map +1 -1
  20. package/dist/src/core/shaders/canvas/Border.js +8 -11
  21. package/dist/src/core/shaders/canvas/Border.js.map +1 -1
  22. package/dist/src/core/shaders/canvas/HolePunch.js +2 -1
  23. package/dist/src/core/shaders/canvas/HolePunch.js.map +1 -1
  24. package/dist/src/core/shaders/canvas/LinearGradient.js +23 -4
  25. package/dist/src/core/shaders/canvas/LinearGradient.js.map +1 -1
  26. package/dist/src/core/shaders/canvas/RadialGradient.js +7 -5
  27. package/dist/src/core/shaders/canvas/RadialGradient.js.map +1 -1
  28. package/dist/src/core/shaders/canvas/Rounded.js +2 -2
  29. package/dist/src/core/shaders/canvas/Rounded.js.map +1 -1
  30. package/dist/src/core/shaders/canvas/RoundedWithBorder.js +2 -2
  31. package/dist/src/core/shaders/canvas/RoundedWithBorder.js.map +1 -1
  32. package/dist/src/core/shaders/canvas/RoundedWithBorderAndShadow.js +5 -4
  33. package/dist/src/core/shaders/canvas/RoundedWithBorderAndShadow.js.map +1 -1
  34. package/dist/src/core/shaders/canvas/RoundedWithShadow.js +5 -4
  35. package/dist/src/core/shaders/canvas/RoundedWithShadow.js.map +1 -1
  36. package/dist/src/core/shaders/canvas/Shadow.js +4 -2
  37. package/dist/src/core/shaders/canvas/Shadow.js.map +1 -1
  38. package/dist/src/core/shaders/canvas/utils/render.js +0 -15
  39. package/dist/src/core/shaders/canvas/utils/render.js.map +1 -1
  40. package/dist/tsconfig.dist.tsbuildinfo +1 -1
  41. package/package.json +1 -1
  42. package/src/core/CoreNode.test.ts +2 -2
  43. package/src/core/CoreNode.ts +13 -11
  44. package/src/core/CoreTextNode.ts +3 -1
  45. package/src/core/lib/utils.ts +23 -25
  46. package/src/core/renderers/CoreRenderer.ts +0 -31
  47. package/src/core/renderers/canvas/CanvasRenderer.ts +158 -63
  48. package/src/core/renderers/canvas/CanvasShaderNode.ts +1 -2
  49. package/src/core/renderers/webgl/SdfRenderOp.ts +7 -7
  50. package/src/core/renderers/webgl/WebGlShaderProgram.ts +3 -6
  51. package/src/core/shaders/canvas/Border.ts +11 -15
  52. package/src/core/shaders/canvas/HolePunch.ts +2 -1
  53. package/src/core/shaders/canvas/LinearGradient.ts +26 -7
  54. package/src/core/shaders/canvas/RadialGradient.ts +7 -10
  55. package/src/core/shaders/canvas/Rounded.ts +5 -5
  56. package/src/core/shaders/canvas/RoundedWithBorder.ts +5 -5
  57. package/src/core/shaders/canvas/RoundedWithBorderAndShadow.ts +9 -8
  58. package/src/core/shaders/canvas/RoundedWithShadow.ts +6 -5
  59. package/src/core/shaders/canvas/Shadow.ts +7 -5
  60. package/src/core/shaders/canvas/utils/render.ts +0 -18
@@ -63,8 +63,8 @@ export function getRgbaString(color: RGBA) {
63
63
  export interface Rect {
64
64
  x: number;
65
65
  y: number;
66
- width: number;
67
- height: number;
66
+ w: number;
67
+ h: number;
68
68
  }
69
69
 
70
70
  export interface RectWithValid extends Rect {
@@ -140,15 +140,15 @@ export function convertBoundToRect(bound: Bound, out?: Rect): Rect {
140
140
  if (out) {
141
141
  out.x = bound.x1;
142
142
  out.y = bound.y1;
143
- out.width = bound.x2 - bound.x1;
144
- out.height = bound.y2 - bound.y1;
143
+ out.w = bound.x2 - bound.x1;
144
+ out.h = bound.y2 - bound.y1;
145
145
  return out;
146
146
  }
147
147
  return {
148
148
  x: bound.x1,
149
149
  y: bound.y1,
150
- width: bound.x2 - bound.x1,
151
- height: bound.y2 - bound.y1,
150
+ w: bound.x2 - bound.x1,
151
+ h: bound.y2 - bound.y1,
152
152
  };
153
153
  }
154
154
 
@@ -161,35 +161,35 @@ export function intersectRect<T extends Rect = Rect>(
161
161
  export function intersectRect(a: Rect, b: Rect, out?: Rect): Rect {
162
162
  const x = Math.max(a.x, b.x);
163
163
  const y = Math.max(a.y, b.y);
164
- const width = Math.min(a.x + a.width, b.x + b.width) - x;
165
- const height = Math.min(a.y + a.height, b.y + b.height) - y;
166
- if (width > 0 && height > 0) {
164
+ const w = Math.min(a.x + a.w, b.x + b.w) - x;
165
+ const h = Math.min(a.y + a.h, b.y + b.h) - y;
166
+ if (w > 0 && h > 0) {
167
167
  if (out) {
168
168
  out.x = x;
169
169
  out.y = y;
170
- out.width = width;
171
- out.height = height;
170
+ out.w = w;
171
+ out.h = h;
172
172
  return out;
173
173
  }
174
174
  return {
175
175
  x,
176
176
  y,
177
- width,
178
- height,
177
+ w,
178
+ h,
179
179
  };
180
180
  }
181
181
  if (out) {
182
182
  out.x = 0;
183
183
  out.y = 0;
184
- out.width = 0;
185
- out.height = 0;
184
+ out.w = 0;
185
+ out.h = 0;
186
186
  return out;
187
187
  }
188
188
  return {
189
189
  x: 0,
190
190
  y: 0,
191
- width: 0,
192
- height: 0,
191
+ w: 0,
192
+ h: 0,
193
193
  };
194
194
  }
195
195
 
@@ -199,15 +199,15 @@ export function copyRect(a: Rect, out?: Rect): Rect {
199
199
  if (out) {
200
200
  out.x = a.x;
201
201
  out.y = a.y;
202
- out.width = a.width;
203
- out.height = a.height;
202
+ out.w = a.w;
203
+ out.h = a.h;
204
204
  return out;
205
205
  }
206
206
  return {
207
207
  x: a.x,
208
208
  y: a.y,
209
- width: a.width,
210
- height: a.height,
209
+ w: a.w,
210
+ h: a.h,
211
211
  };
212
212
  }
213
213
 
@@ -218,9 +218,7 @@ export function compareRect(a: Rect | null, b: Rect | null): boolean {
218
218
  if (a === null || b === null) {
219
219
  return false;
220
220
  }
221
- return (
222
- a.x === b.x && a.y === b.y && a.width === b.width && a.height === b.height
223
- );
221
+ return a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h;
224
222
  }
225
223
 
226
224
  export function boundInsideBound(bound1: Bound, bound2: Bound) {
@@ -250,7 +248,7 @@ export function isBoundPositive(bound: Bound): boolean {
250
248
  }
251
249
 
252
250
  export function isRectPositive(rect: Rect): boolean {
253
- return rect.width > 0 && rect.height > 0;
251
+ return rect.w > 0 && rect.h > 0;
254
252
  }
255
253
 
256
254
  /**
@@ -1,42 +1,11 @@
1
- import type { Dimensions } from '../../common/CommonTypes.js';
2
1
  import type { CoreNode } from '../CoreNode.js';
3
- import type { TextureOptions } from '../CoreTextureManager.js';
4
2
  import type { Stage } from '../Stage.js';
5
3
  import type { ContextSpy } from '../lib/ContextSpy.js';
6
- import type { RenderCoords } from '../lib/RenderCoords.js';
7
- import type { RectWithValid } from '../lib/utils.js';
8
4
  import type { CoreShaderProgram } from './CoreShaderProgram.js';
9
5
  import type { Texture, TextureCoords } from '../textures/Texture.js';
10
6
  import { CoreContextTexture } from './CoreContextTexture.js';
11
7
  import type { CoreShaderType, CoreShaderNode } from './CoreShaderNode.js';
12
8
 
13
- export interface QuadOptions {
14
- width: number;
15
- height: number;
16
- colorTl: number;
17
- colorTr: number;
18
- colorBl: number;
19
- colorBr: number;
20
- texture: Texture | null;
21
- textureOptions: TextureOptions | null;
22
- textureCoords: TextureCoords | undefined;
23
- zIndex: number;
24
- shader: CoreShaderNode | null;
25
- alpha: number;
26
- clippingRect: RectWithValid;
27
- tx: number;
28
- ty: number;
29
- ta: number;
30
- tb: number;
31
- tc: number;
32
- td: number;
33
- renderCoords?: RenderCoords;
34
- rtt: boolean;
35
- parentHasRenderTexture: boolean;
36
- framebufferDimensions: Dimensions | null;
37
- time?: number | null;
38
- }
39
-
40
9
  export interface CoreRendererOptions {
41
10
  stage: Stage;
42
11
  canvas: HTMLCanvasElement | OffscreenCanvas;
@@ -2,11 +2,7 @@ import type { CoreNode } from '../../CoreNode.js';
2
2
  import { SubTexture } from '../../textures/SubTexture.js';
3
3
  import { TextureType, type Texture } from '../../textures/Texture.js';
4
4
  import type { CoreContextTexture } from '../CoreContextTexture.js';
5
- import {
6
- CoreRenderer,
7
- type CoreRendererOptions,
8
- type QuadOptions,
9
- } from '../CoreRenderer.js';
5
+ import { CoreRenderer, type CoreRendererOptions } from '../CoreRenderer.js';
10
6
  import { CanvasTexture } from './CanvasTexture.js';
11
7
  import { parseColor } from '../../lib/colorParser.js';
12
8
  import { CanvasShaderNode, type CanvasShaderType } from './CanvasShaderNode.js';
@@ -52,7 +48,7 @@ export class CanvasRenderer extends CoreRenderer {
52
48
  const ctx = this.context;
53
49
  const { tx, ty, ta, tb, tc, td } = node.globalTransform!;
54
50
  const clippingRect = node.clippingRect;
55
- let texture = node.renderTexture;
51
+ let texture = (node.props.texture || this.stage.defaultTexture) as Texture;
56
52
  // The Canvas2D renderer only supports image textures, no textures are used for color blocks
57
53
  if (texture !== null) {
58
54
  const textureType = texture.type;
@@ -67,7 +63,7 @@ export class CanvasRenderer extends CoreRenderer {
67
63
  }
68
64
 
69
65
  const hasTransform = ta !== 1;
70
- const hasClipping = clippingRect.width !== 0 && clippingRect.height !== 0;
66
+ const hasClipping = clippingRect.w !== 0 && clippingRect.h !== 0;
71
67
  const shader = node.props.shader;
72
68
  const hasShader = shader !== null;
73
69
 
@@ -82,8 +78,8 @@ export class CanvasRenderer extends CoreRenderer {
82
78
 
83
79
  if (hasClipping === true) {
84
80
  const path = new Path2D();
85
- const { x, y, width, height } = clippingRect;
86
- path.rect(x, y, width, height);
81
+ const { x, y, w, h } = clippingRect;
82
+ path.rect(x, y, w, h);
87
83
  ctx.clip(path);
88
84
  }
89
85
 
@@ -104,40 +100,13 @@ export class CanvasRenderer extends CoreRenderer {
104
100
 
105
101
  if (hasShader === true) {
106
102
  let renderContext: (() => void) | null = () => {
107
- this.renderContext(node);
108
- };
109
- const quad: QuadOptions = {
110
- width: node.props.w,
111
- height: node.props.h,
112
- colorTl: node.premultipliedColorTl,
113
- colorTr: node.premultipliedColorTr,
114
- colorBl: node.premultipliedColorBl,
115
- colorBr: node.premultipliedColorBr,
116
- texture: texture,
117
- textureOptions: node.props.textureOptions,
118
- textureCoords: node.renderTextureCoords,
119
- zIndex: node.zIndex, // zIndex usage?
120
- shader: shader,
121
- alpha: node.worldAlpha,
122
- clippingRect: clippingRect,
123
- tx,
124
- ty,
125
- ta,
126
- tb,
127
- tc,
128
- td,
129
- renderCoords: node.renderCoords,
130
- rtt: node.props.rtt,
131
- parentHasRenderTexture: node.parentHasRenderTexture,
132
- framebufferDimensions: node.parentHasRenderTexture
133
- ? node.parentFramebufferDimensions
134
- : null,
103
+ this.renderContext(node, texture);
135
104
  };
136
105
 
137
- (shader as CanvasShaderNode).render(ctx, quad, renderContext);
106
+ (shader as CanvasShaderNode).render(ctx, node, renderContext);
138
107
  renderContext = null;
139
108
  } else {
140
- this.renderContext(node);
109
+ this.renderContext(node, texture);
141
110
  }
142
111
 
143
112
  if (saveAndRestore) {
@@ -145,9 +114,8 @@ export class CanvasRenderer extends CoreRenderer {
145
114
  }
146
115
  }
147
116
 
148
- renderContext(node: CoreNode) {
117
+ renderContext(node: CoreNode, texture: Texture) {
149
118
  const color = node.premultipliedColorTl;
150
- const texture = node.renderTexture!;
151
119
  const textureType = texture.type;
152
120
  const tx = node.globalTransform!.tx;
153
121
  const ty = node.globalTransform!.ty;
@@ -156,30 +124,57 @@ export class CanvasRenderer extends CoreRenderer {
156
124
 
157
125
  if (textureType !== TextureType.color) {
158
126
  const tintColor = parseColor(color);
159
- if (textureType !== TextureType.subTexture) {
160
- const image = (texture.ctxTexture as CanvasTexture).getImage(tintColor);
161
- this.context.globalAlpha = tintColor.a ?? node.worldAlpha;
162
- this.context.drawImage(image, tx, ty, width, height);
163
- this.context.globalAlpha = 1;
164
- return;
127
+ let image: ImageBitmap | HTMLCanvasElement | HTMLImageElement;
128
+
129
+ if (textureType === TextureType.subTexture) {
130
+ image = (
131
+ (texture as SubTexture).parentTexture.ctxTexture as CanvasTexture
132
+ ).getImage(tintColor);
133
+ } else {
134
+ image = (texture.ctxTexture as CanvasTexture).getImage(tintColor);
165
135
  }
166
- const image = (
167
- (texture as SubTexture).parentTexture.ctxTexture as CanvasTexture
168
- ).getImage(tintColor);
169
- const props = (texture as SubTexture).props;
170
136
 
171
137
  this.context.globalAlpha = tintColor.a ?? node.worldAlpha;
172
- this.context.drawImage(
173
- image,
174
- props.x,
175
- props.y,
176
- props.w,
177
- props.h,
178
- tx,
179
- ty,
180
- width,
181
- height,
182
- );
138
+
139
+ const txCoords = node.textureCoords;
140
+ if (txCoords) {
141
+ const ix = image.width;
142
+ const iy = image.height;
143
+
144
+ let sx = txCoords.x1 * ix;
145
+ let sy = txCoords.y1 * iy;
146
+ let sw = (txCoords.x2 - txCoords.x1) * ix;
147
+ let sh = (txCoords.y2 - txCoords.y1) * iy;
148
+
149
+ let flipX = false;
150
+ let flipY = false;
151
+
152
+ if (sw < 0) {
153
+ flipX = true;
154
+ sx += sw;
155
+ sw = Math.abs(sw);
156
+ }
157
+ if (sh < 0) {
158
+ flipY = true;
159
+ sy += sh;
160
+ sh = Math.abs(sh);
161
+ }
162
+
163
+ if (flipX || flipY) {
164
+ this.context.save();
165
+ this.context.translate(
166
+ tx + (flipX ? width : 0),
167
+ ty + (flipY ? height : 0),
168
+ );
169
+ this.context.scale(flipX ? -1 : 1, flipY ? -1 : 1);
170
+ this.context.drawImage(image, sx, sy, sw, sh, 0, 0, width, height);
171
+ this.context.restore();
172
+ } else {
173
+ this.context.drawImage(image, sx, sy, sw, sh, tx, ty, width, height);
174
+ }
175
+ } else {
176
+ this.context.drawImage(image, tx, ty, width, height);
177
+ }
183
178
  this.context.globalAlpha = 1;
184
179
  return;
185
180
  }
@@ -201,8 +196,22 @@ export class CanvasRenderer extends CoreRenderer {
201
196
  endY = ty;
202
197
  endColor = node.premultipliedColorTr;
203
198
  }
199
+
200
+ let startColor = color;
201
+ const startAlpha = (startColor >>> 24) & 0xff;
202
+ const endAlpha = (endColor >>> 24) & 0xff;
203
+
204
+ // if one of the colors has 0 alpha, we want to match the RGB channels
205
+ // to the other color to prevent white bleed during zero alpha interpolation.
206
+ if (startAlpha === 0 && endAlpha > 0) {
207
+ startColor =
208
+ ((startColor & 0xff000000) | (endColor & 0x00ffffff)) >>> 0;
209
+ } else if (endAlpha === 0 && startAlpha > 0) {
210
+ endColor = ((endColor & 0xff000000) | (startColor & 0x00ffffff)) >>> 0;
211
+ }
212
+
204
213
  const gradient = this.context.createLinearGradient(tx, ty, endX, endY);
205
- gradient.addColorStop(0, normalizeCanvasColor(color));
214
+ gradient.addColorStop(0, normalizeCanvasColor(startColor));
206
215
  gradient.addColorStop(1, normalizeCanvasColor(endColor));
207
216
  this.context.fillStyle = gradient;
208
217
  this.context.fillRect(tx, ty, width, height);
@@ -264,6 +273,92 @@ export class CanvasRenderer extends CoreRenderer {
264
273
  this.clearColor = normalizeCanvasColor(color);
265
274
  }
266
275
 
276
+ override getTextureCoords(
277
+ node: CoreNode,
278
+ ): import('../../textures/Texture.js').TextureCoords | undefined {
279
+ const texture = node.texture;
280
+ if (texture === null) {
281
+ return undefined;
282
+ }
283
+
284
+ const ctxTexture =
285
+ texture.type === TextureType.subTexture
286
+ ? (texture as SubTexture).parentTexture.ctxTexture
287
+ : texture.ctxTexture;
288
+ if (ctxTexture === undefined) {
289
+ return undefined;
290
+ }
291
+
292
+ const textureOptions = node.props.textureOptions;
293
+
294
+ // early exit for textures with no options unless its a subtexture
295
+ if (
296
+ texture.type !== TextureType.subTexture &&
297
+ textureOptions === undefined
298
+ ) {
299
+ return { x1: 0, y1: 0, x2: 1, y2: 1 };
300
+ }
301
+
302
+ let x1 = 0,
303
+ y1 = 0,
304
+ x2 = 1,
305
+ y2 = 1;
306
+ if (texture.type === TextureType.subTexture) {
307
+ const { w: parentW, h: parentH } = (texture as SubTexture).parentTexture
308
+ .dimensions!;
309
+ const { x, y, w, h } = (texture as SubTexture).props;
310
+ x1 = x / parentW;
311
+ y1 = y / parentH;
312
+ x2 = x1 + w / parentW;
313
+ y2 = y1 + h / parentH;
314
+ }
315
+
316
+ if (textureOptions !== undefined && textureOptions !== null) {
317
+ const resizeMode = textureOptions.resizeMode;
318
+ if (
319
+ resizeMode !== undefined &&
320
+ resizeMode.type === 'cover' &&
321
+ texture.dimensions !== null
322
+ ) {
323
+ const dimensions =
324
+ texture.dimensions as import('../../../common/CommonTypes.js').Dimensions;
325
+ const w = node.props.w;
326
+ const h = node.props.h;
327
+ const scaleX = w / dimensions.w;
328
+ const scaleY = h / dimensions.h;
329
+ const scale = Math.max(scaleX, scaleY);
330
+ const precision = 1 / scale;
331
+
332
+ // Determine based on width
333
+ if (scaleX < scale) {
334
+ const desiredSize = precision * node.props.w;
335
+ x1 = (1 - desiredSize / dimensions.w) * (resizeMode.clipX ?? 0.5);
336
+ x2 = x1 + desiredSize / dimensions.w;
337
+ }
338
+ // Determine based on height
339
+ if (scaleY < scale) {
340
+ const desiredSize = precision * node.props.h;
341
+ y1 = (1 - desiredSize / dimensions.h) * (resizeMode.clipY ?? 0.5);
342
+ y2 = y1 + desiredSize / dimensions.h;
343
+ }
344
+ }
345
+
346
+ if (textureOptions.flipX === true) {
347
+ [x1, x2] = [x2, x1];
348
+ }
349
+ if (textureOptions.flipY === true) {
350
+ [y1, y2] = [y2, y1];
351
+ }
352
+ }
353
+
354
+ return {
355
+ x1,
356
+ y1,
357
+ x2,
358
+ y2,
359
+ };
360
+ }
361
+
267
362
  override updateViewport(): void {
268
363
  // noop
269
364
  }
@@ -1,7 +1,6 @@
1
1
  import type { CoreNode } from '../../CoreNode.js';
2
2
  import { normalizeCanvasColor } from '../../lib/colorCache.js';
3
3
  import type { Stage } from '../../Stage.js';
4
- import type { QuadOptions } from '../CoreRenderer.js';
5
4
  import { CoreShaderNode, type CoreShaderType } from '../CoreShaderNode.js';
6
5
 
7
6
  export type CanvasShaderType<
@@ -11,7 +10,7 @@ export type CanvasShaderType<
11
10
  render: (
12
11
  this: CanvasShaderNode<T, C>,
13
12
  ctx: CanvasRenderingContext2D,
14
- quad: QuadOptions,
13
+ node: CoreNode,
15
14
  renderContext: () => void,
16
15
  ) => void;
17
16
  update?: (this: CanvasShaderNode<T, C>, node: CoreNode) => void;
@@ -33,10 +33,10 @@ export class SdfRenderOp extends CoreRenderOp {
33
33
  readonly renderer: WebGlRenderer,
34
34
  readonly shader: WebGlShaderNode,
35
35
  readonly quadBufferCollection: BufferCollection,
36
- public worldAlpha: number,
37
- public clippingRect: RectWithValid,
38
- readonly width: number,
39
- readonly height: number,
36
+ readonly worldAlpha: number,
37
+ readonly clippingRect: RectWithValid,
38
+ readonly w: number,
39
+ readonly h: number,
40
40
  readonly rtt: boolean,
41
41
  public parentHasRenderTexture: boolean,
42
42
  public framebufferDimensions: Dimensions | null,
@@ -70,8 +70,8 @@ export class SdfRenderOp extends CoreRenderOp {
70
70
  const pixelRatio =
71
71
  USE_RTT && this.parentHasRenderTexture ? 1 : stage.pixelRatio;
72
72
  const clipX = Math.round(this.clippingRect.x * pixelRatio);
73
- const clipWidth = Math.round(this.clippingRect.width * pixelRatio);
74
- const clipHeight = Math.round(this.clippingRect.height * pixelRatio);
73
+ const clipWidth = Math.round(this.clippingRect.w * pixelRatio);
74
+ const clipHeight = Math.round(this.clippingRect.h * pixelRatio);
75
75
  let clipY = Math.round(
76
76
  options.canvas.height - clipHeight - this.clippingRect.y * pixelRatio,
77
77
  );
@@ -79,7 +79,7 @@ export class SdfRenderOp extends CoreRenderOp {
79
79
  // to be relative to the parent's framebuffer
80
80
  if (USE_RTT && this.parentHasRenderTexture) {
81
81
  clipY = this.framebufferDimensions
82
- ? this.framebufferDimensions.h - this.height
82
+ ? this.framebufferDimensions.h - this.h
83
83
  : 0;
84
84
  }
85
85
 
@@ -134,7 +134,7 @@ export class WebGlShaderProgram implements CoreShaderProgram {
134
134
  return this.lifecycle.canBatch(node, currentRenderOp);
135
135
  }
136
136
 
137
- const { time, worldAlpha, width, height } = node;
137
+ const { time, worldAlpha, w, h } = node;
138
138
 
139
139
  if (this.useTimeValue === true) {
140
140
  if (time !== currentRenderOp.time) {
@@ -149,10 +149,7 @@ export class WebGlShaderProgram implements CoreShaderProgram {
149
149
  }
150
150
 
151
151
  if (this.useSystemDimensions === true) {
152
- if (
153
- width !== currentRenderOp.width ||
154
- height !== currentRenderOp.height
155
- ) {
152
+ if (w !== currentRenderOp.w || h !== currentRenderOp.h) {
156
153
  return false;
157
154
  }
158
155
  }
@@ -235,7 +232,7 @@ export class WebGlShaderProgram implements CoreShaderProgram {
235
232
  }
236
233
 
237
234
  if (this.useSystemDimensions === true) {
238
- this.glw.uniform2f('u_dimensions', renderOp.width, renderOp.height);
235
+ this.glw.uniform2f('u_dimensions', renderOp.w, renderOp.h);
239
236
  }
240
237
 
241
238
  const shader = renderOp.shader as WebGlShaderNode;
@@ -72,39 +72,35 @@ export const Border: CanvasShaderType<BorderProps, ComputedBorderValues> = {
72
72
  this.computed.innerW = outerW - l - r;
73
73
  this.computed.innerH = outerH - t - b;
74
74
  },
75
- render(ctx, quad, renderContext) {
75
+ render(ctx, node, renderContext) {
76
76
  renderContext();
77
77
  const computed = this.computed as ComputedBorderValues;
78
+ const { tx, ty } = node.globalTransform!;
79
+ const { w, h } = node.props;
78
80
  ctx.strokeStyle = computed.borderColor!;
79
81
  if (computed.borderAsym === false && this.props!.w[0] > 0) {
80
82
  ctx.lineWidth = this.props!.w[0];
81
83
  ctx.beginPath();
82
84
  ctx.strokeRect(
83
- quad.tx + computed.outerX,
84
- quad.ty + computed.outerY,
85
- quad.width + computed.outerW,
86
- quad.height + computed.outerH,
85
+ tx + computed.outerX,
86
+ ty + computed.outerY,
87
+ w + computed.outerW,
88
+ h + computed.outerH,
87
89
  );
88
90
  return;
89
91
  }
90
92
 
91
- // Pre-calculate common values
92
- const tx = quad.tx;
93
- const ty = quad.ty;
94
- const width = quad.width;
95
- const height = quad.height;
96
-
97
93
  // Calculate outer rectangle (including border)
98
94
  const outerX = tx + computed.outerX;
99
95
  const outerY = ty + computed.outerY;
100
- const outerW = width + computed.outerW;
101
- const outerH = height + computed.outerH;
96
+ const outerW = w + computed.outerW;
97
+ const outerH = h + computed.outerH;
102
98
 
103
99
  // Calculate inner rectangle (excluding border)
104
100
  const innerX = tx + computed.innerX;
105
101
  const innerY = ty + computed.innerY;
106
- const innerW = width + computed.innerW;
107
- const innerH = height + computed.innerH;
102
+ const innerW = w + computed.innerW;
103
+ const innerH = h + computed.innerH;
108
104
 
109
105
  // Use clip to subtract inner from outer
110
106
  ctx.save();
@@ -27,8 +27,9 @@ export const HolePunch: CanvasShaderType<
27
27
  ctx.save();
28
28
  renderContext();
29
29
  const { x, y, w, h } = this.props!;
30
+ const gt = quad.globalTransform!;
30
31
  ctx.beginPath();
31
- roundRect(ctx, quad.tx + x, quad.ty + y, w, h, this.computed.radius!);
32
+ roundRect(ctx, gt.tx + x, gt.ty + y, w, h, this.computed.radius!);
32
33
  ctx.closePath();
33
34
  ctx.fillStyle = 'black';
34
35
  ctx.globalCompositeOperation = 'destination-out';
@@ -31,17 +31,36 @@ export const LinearGradient: CanvasShaderType<
31
31
  y0: line * Math.sin(angle) + nHeight * 0.5,
32
32
  x1: line * Math.cos(angle + Math.PI) + nWidth * 0.5,
33
33
  y1: line * Math.sin(angle + Math.PI) + nHeight * 0.5,
34
- colors: this.props!.colors.map((value) => this.toColorString(value)),
34
+ colors: this.props!.colors.map((value, i, arr) => {
35
+ const alpha = (value >>> 24) & 0xff;
36
+ if (alpha === 0) {
37
+ let nearestRGB = value & 0x00ffffff;
38
+ for (let step = 1; step < arr.length; step++) {
39
+ if (i - step >= 0 && ((arr[i - step]! >>> 24) & 0xff) > 0) {
40
+ nearestRGB = arr[i - step]! & 0x00ffffff;
41
+ break;
42
+ }
43
+ if (i + step < arr.length && ((arr[i + step]! >>> 24) & 0xff) > 0) {
44
+ nearestRGB = arr[i + step]! & 0x00ffffff;
45
+ break;
46
+ }
47
+ }
48
+ value = (value & 0xff000000) | nearestRGB;
49
+ }
50
+ return this.toColorString(value);
51
+ }),
35
52
  };
36
53
  },
37
- render(ctx, quad, renderContext) {
54
+ render(ctx, node, renderContext) {
38
55
  renderContext();
39
56
  const computed = this.computed as ComputedLinearGradientValues;
57
+ const { tx, ty } = node.globalTransform!;
58
+ const { w, h } = node.props;
40
59
  const gradient = ctx.createLinearGradient(
41
- quad.tx + computed.x0,
42
- quad.ty + computed.y0,
43
- quad.tx + computed.x1,
44
- quad.ty + computed.y1,
60
+ tx + computed.x0,
61
+ ty + computed.y0,
62
+ tx + computed.x1,
63
+ ty + computed.y1,
45
64
  );
46
65
  const colors = computed.colors;
47
66
  const stops = this.props!.stops;
@@ -49,6 +68,6 @@ export const LinearGradient: CanvasShaderType<
49
68
  gradient.addColorStop(stops[i]!, colors[i]!);
50
69
  }
51
70
  ctx.fillStyle = gradient;
52
- ctx.fillRect(quad.tx, quad.ty, quad.width, quad.height);
71
+ ctx.fillRect(tx, ty, w, h);
53
72
  },
54
73
  };
@@ -39,12 +39,14 @@ export const RadialGradient: CanvasShaderType<
39
39
  colors: props.colors.map((value) => this.toColorString(value)),
40
40
  };
41
41
  },
42
- render(ctx, quad, renderContext) {
42
+ render(ctx, node, renderContext) {
43
43
  renderContext();
44
44
  const { scaleX, scaleY, pivotX, pivotY, colors, size } = this
45
45
  .computed as ComputedRadialGradientValues;
46
- let x = quad.tx + pivotX;
47
- let y = quad.ty + pivotY;
46
+ const { tx, ty } = node.globalTransform!;
47
+ const { w, h } = node.props;
48
+ let x = tx + pivotX;
49
+ let y = ty + pivotY;
48
50
  const stops = this.props!.stops;
49
51
 
50
52
  if (scaleX === scaleY) {
@@ -55,7 +57,7 @@ export const RadialGradient: CanvasShaderType<
55
57
  }
56
58
 
57
59
  ctx.fillStyle = gradient;
58
- ctx.fillRect(quad.tx, quad.ty, quad.width, quad.height);
60
+ ctx.fillRect(tx, ty, w, h);
59
61
  return;
60
62
  }
61
63
 
@@ -70,12 +72,7 @@ export const RadialGradient: CanvasShaderType<
70
72
  }
71
73
 
72
74
  ctx.fillStyle = gradient;
73
- ctx.fillRect(
74
- quad.tx / scaleX,
75
- quad.ty / scaleY,
76
- quad.width / scaleX,
77
- quad.height / scaleY,
78
- );
75
+ ctx.fillRect(tx / scaleX, ty / scaleY, w / scaleX, h / scaleY);
79
76
 
80
77
  ctx.restore();
81
78
  },