@shopify/react-native-skia 2.6.9 → 2.7.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.
Files changed (145) hide show
  1. package/android/cpp/jni/include/JniSkiaBaseView.h +6 -4
  2. package/android/cpp/jni/include/JniSkiaPictureView.h +8 -6
  3. package/android/cpp/rnskia-android/OpenGLContext.h +10 -1
  4. package/android/cpp/rnskia-android/RNSkAndroidView.h +8 -8
  5. package/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp +9 -5
  6. package/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.h +4 -2
  7. package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseView.java +48 -12
  8. package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseViewManager.java +5 -0
  9. package/android/src/main/java/com/shopify/reactnative/skia/SkiaPictureView.java +2 -2
  10. package/android/src/main/java/com/shopify/reactnative/skia/ViewScreenshotService.java +11 -7
  11. package/apple/MetalContext.h +7 -6
  12. package/apple/MetalLayerColorSpace.mm +39 -0
  13. package/apple/MetalLayerColorSpaceUtils.h +34 -0
  14. package/apple/MetalWindowContext.h +3 -1
  15. package/apple/MetalWindowContext.mm +9 -8
  16. package/apple/RNSkAppleView.h +6 -0
  17. package/apple/RNSkMetalCanvasProvider.h +2 -0
  18. package/apple/RNSkMetalCanvasProvider.mm +15 -2
  19. package/apple/SkiaPictureView.mm +1 -0
  20. package/apple/SkiaPictureViewManager.mm +5 -0
  21. package/apple/SkiaUIView.h +1 -0
  22. package/apple/SkiaUIView.mm +9 -0
  23. package/cpp/api/JsiSkSurface.h +8 -2
  24. package/cpp/rnskia/RNDawnContext.h +4 -3
  25. package/cpp/rnskia/RNDawnUtils.h +25 -6
  26. package/cpp/rnskia/RNDawnWindowContext.h +44 -10
  27. package/cpp/rnskia/RNMetalLayerColorSpace.h +16 -0
  28. package/cpp/rnskia/RNSkJsiViewApi.h +46 -24
  29. package/cpp/rnwgpu/SurfaceRegistry.h +10 -4
  30. package/lib/commonjs/Platform/Platform.web.js +2 -90
  31. package/lib/commonjs/Platform/Platform.web.js.map +1 -1
  32. package/lib/commonjs/mock/index.js +1 -0
  33. package/lib/commonjs/mock/index.js.map +1 -1
  34. package/lib/commonjs/renderer/Canvas.d.ts +10 -1
  35. package/lib/commonjs/renderer/Canvas.js +2 -0
  36. package/lib/commonjs/renderer/Canvas.js.map +1 -1
  37. package/lib/commonjs/skia/types/Surface/Surface.d.ts +5 -1
  38. package/lib/commonjs/skia/types/Surface/Surface.js.map +1 -1
  39. package/lib/commonjs/skia/web/JsiSkParagraphStyle.js +14 -3
  40. package/lib/commonjs/skia/web/JsiSkParagraphStyle.js.map +1 -1
  41. package/lib/commonjs/skia/web/JsiSkSurface.d.ts +1 -1
  42. package/lib/commonjs/skia/web/JsiSkSurface.js +2 -1
  43. package/lib/commonjs/skia/web/JsiSkSurface.js.map +1 -1
  44. package/lib/commonjs/sksg/Container.native.d.ts +1 -0
  45. package/lib/commonjs/sksg/Container.native.js +11 -0
  46. package/lib/commonjs/sksg/Container.native.js.map +1 -1
  47. package/lib/commonjs/sksg/Container.web.d.ts +1 -0
  48. package/lib/commonjs/sksg/Container.web.js +11 -0
  49. package/lib/commonjs/sksg/Container.web.js.map +1 -1
  50. package/lib/commonjs/specs/NativeSkiaModule.web.d.ts +2 -0
  51. package/lib/commonjs/specs/NativeSkiaModule.web.js +32 -7
  52. package/lib/commonjs/specs/NativeSkiaModule.web.js.map +1 -1
  53. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.d.ts +1 -0
  54. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.js.map +1 -1
  55. package/lib/commonjs/views/SkiaPictureView.js +2 -0
  56. package/lib/commonjs/views/SkiaPictureView.js.map +1 -1
  57. package/lib/commonjs/views/SkiaPictureView.web.js +279 -94
  58. package/lib/commonjs/views/SkiaPictureView.web.js.map +1 -1
  59. package/lib/commonjs/views/formats.d.ts +1 -0
  60. package/lib/commonjs/views/formats.js +28 -0
  61. package/lib/commonjs/views/formats.js.map +1 -0
  62. package/lib/commonjs/views/index.d.ts +1 -0
  63. package/lib/commonjs/views/index.js +11 -0
  64. package/lib/commonjs/views/index.js.map +1 -1
  65. package/lib/commonjs/views/types.d.ts +6 -0
  66. package/lib/commonjs/views/types.js.map +1 -1
  67. package/lib/module/Platform/Platform.web.js +3 -91
  68. package/lib/module/Platform/Platform.web.js.map +1 -1
  69. package/lib/module/mock/index.js +1 -0
  70. package/lib/module/mock/index.js.map +1 -1
  71. package/lib/module/renderer/Canvas.d.ts +10 -1
  72. package/lib/module/renderer/Canvas.js +2 -0
  73. package/lib/module/renderer/Canvas.js.map +1 -1
  74. package/lib/module/skia/types/Surface/Surface.d.ts +5 -1
  75. package/lib/module/skia/types/Surface/Surface.js.map +1 -1
  76. package/lib/module/skia/web/JsiSkParagraphStyle.js +14 -3
  77. package/lib/module/skia/web/JsiSkParagraphStyle.js.map +1 -1
  78. package/lib/module/skia/web/JsiSkSurface.d.ts +1 -1
  79. package/lib/module/skia/web/JsiSkSurface.js +2 -1
  80. package/lib/module/skia/web/JsiSkSurface.js.map +1 -1
  81. package/lib/module/sksg/Container.native.d.ts +1 -0
  82. package/lib/module/sksg/Container.native.js +11 -0
  83. package/lib/module/sksg/Container.native.js.map +1 -1
  84. package/lib/module/sksg/Container.web.d.ts +1 -0
  85. package/lib/module/sksg/Container.web.js +11 -0
  86. package/lib/module/sksg/Container.web.js.map +1 -1
  87. package/lib/module/specs/NativeSkiaModule.web.d.ts +2 -0
  88. package/lib/module/specs/NativeSkiaModule.web.js +32 -7
  89. package/lib/module/specs/NativeSkiaModule.web.js.map +1 -1
  90. package/lib/module/specs/SkiaPictureViewNativeComponent.d.ts +1 -0
  91. package/lib/module/specs/SkiaPictureViewNativeComponent.js.map +1 -1
  92. package/lib/module/views/SkiaPictureView.js +2 -0
  93. package/lib/module/views/SkiaPictureView.js.map +1 -1
  94. package/lib/module/views/SkiaPictureView.web.js +280 -95
  95. package/lib/module/views/SkiaPictureView.web.js.map +1 -1
  96. package/lib/module/views/formats.d.ts +1 -0
  97. package/lib/module/views/formats.js +22 -0
  98. package/lib/module/views/formats.js.map +1 -0
  99. package/lib/module/views/index.d.ts +1 -0
  100. package/lib/module/views/index.js +1 -0
  101. package/lib/module/views/index.js.map +1 -1
  102. package/lib/module/views/types.d.ts +6 -0
  103. package/lib/module/views/types.js.map +1 -1
  104. package/lib/typescript/lib/commonjs/Platform/Platform.web.d.ts +1 -2
  105. package/lib/typescript/lib/commonjs/mock/index.d.ts +1 -0
  106. package/lib/typescript/lib/commonjs/renderer/Canvas.d.ts +2 -1
  107. package/lib/typescript/lib/commonjs/skia/web/JsiSkSurface.d.ts +1 -1
  108. package/lib/typescript/lib/commonjs/sksg/Container.native.d.ts +1 -1
  109. package/lib/typescript/lib/commonjs/sksg/Container.web.d.ts +1 -1
  110. package/lib/typescript/lib/commonjs/views/formats.d.ts +2 -0
  111. package/lib/typescript/lib/module/Platform/Platform.web.d.ts +1 -3
  112. package/lib/typescript/lib/module/mock/index.d.ts +2 -2
  113. package/lib/typescript/lib/module/renderer/Canvas.d.ts +2 -1
  114. package/lib/typescript/lib/module/skia/web/JsiSkSurface.d.ts +1 -1
  115. package/lib/typescript/lib/module/sksg/Container.native.d.ts +1 -1
  116. package/lib/typescript/lib/module/sksg/Container.web.d.ts +1 -1
  117. package/lib/typescript/lib/module/views/formats.d.ts +1 -0
  118. package/lib/typescript/lib/module/views/index.d.ts +1 -0
  119. package/lib/typescript/src/renderer/Canvas.d.ts +10 -1
  120. package/lib/typescript/src/skia/types/Surface/Surface.d.ts +5 -1
  121. package/lib/typescript/src/skia/web/JsiSkSurface.d.ts +1 -1
  122. package/lib/typescript/src/sksg/Container.native.d.ts +1 -0
  123. package/lib/typescript/src/sksg/Container.web.d.ts +1 -0
  124. package/lib/typescript/src/specs/NativeSkiaModule.web.d.ts +2 -0
  125. package/lib/typescript/src/specs/SkiaPictureViewNativeComponent.d.ts +1 -0
  126. package/lib/typescript/src/views/formats.d.ts +1 -0
  127. package/lib/typescript/src/views/index.d.ts +1 -0
  128. package/lib/typescript/src/views/types.d.ts +6 -0
  129. package/package.json +4 -1
  130. package/react-native-skia.podspec +1 -0
  131. package/src/Platform/Platform.web.tsx +7 -99
  132. package/src/mock/index.ts +1 -0
  133. package/src/renderer/Canvas.tsx +11 -0
  134. package/src/skia/types/Surface/Surface.ts +5 -1
  135. package/src/skia/web/JsiSkParagraphStyle.ts +16 -2
  136. package/src/skia/web/JsiSkSurface.ts +2 -1
  137. package/src/sksg/Container.native.ts +12 -0
  138. package/src/sksg/Container.web.ts +12 -0
  139. package/src/specs/NativeSkiaModule.web.ts +39 -7
  140. package/src/specs/SkiaPictureViewNativeComponent.ts +1 -0
  141. package/src/views/SkiaPictureView.tsx +2 -0
  142. package/src/views/SkiaPictureView.web.tsx +318 -106
  143. package/src/views/formats.ts +21 -0
  144. package/src/views/index.ts +1 -0
  145. package/src/views/types.ts +7 -0
@@ -9,10 +9,9 @@ var _JsiSkSurface = require("../skia/web/JsiSkSurface");
9
9
  var _Platform = require("../Platform");
10
10
  var _SkiaViewNativeId = require("./SkiaViewNativeId");
11
11
  function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
12
- function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
13
12
  function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
14
13
  function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
15
- function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /* global HTMLCanvasElement */
14
+ function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /* global HTMLCanvasElement, ResizeObserver, MediaQueryList */
16
15
  const dp2Pixel = (pd, rect) => {
17
16
  if (!rect) {
18
17
  return undefined;
@@ -25,10 +24,26 @@ const dp2Pixel = (pd, rect) => {
25
24
  };
26
25
  };
27
26
  class WebGLRenderer {
28
- constructor(canvas, pd) {
27
+ constructor(canvas) {
29
28
  this.canvas = canvas;
30
- this.pd = pd;
31
29
  _defineProperty(this, "surface", null);
30
+ _defineProperty(this, "grContext", null);
31
+ _defineProperty(this, "contextHandle", 0);
32
+ _defineProperty(this, "pd", 1);
33
+ this.contextHandle = CanvasKit.GetWebGLContext(canvas);
34
+ if (!this.contextHandle) {
35
+ throw new Error("Could not create a WebGL context");
36
+ }
37
+ this.grContext = CanvasKit.MakeWebGLContext(this.contextHandle);
38
+ if (!this.grContext) {
39
+ CanvasKit.deleteContext(this.contextHandle);
40
+ this.contextHandle = 0;
41
+ throw new Error("Could not create a graphics context");
42
+ }
43
+ const ctx = canvas.getContext("webgl2");
44
+ if (ctx) {
45
+ ctx.drawingBufferColorSpace = "display-p3";
46
+ }
32
47
  this.onResize();
33
48
  }
34
49
  makeImageSnapshot(picture, rect) {
@@ -42,17 +57,26 @@ class WebGLRenderer {
42
57
  return this.surface.makeImageSnapshot(dp2Pixel(this.pd, rect));
43
58
  }
44
59
  onResize() {
60
+ var _this$surface;
45
61
  const {
46
- canvas,
47
- pd
62
+ canvas
48
63
  } = this;
49
- canvas.width = canvas.clientWidth * pd;
50
- canvas.height = canvas.clientHeight * pd;
51
- const surface = CanvasKit.MakeWebGLCanvasSurface(canvas);
52
- const ctx = canvas.getContext("webgl2");
53
- if (ctx) {
54
- ctx.drawingBufferColorSpace = "display-p3";
64
+ if (!this.grContext) {
65
+ return;
66
+ }
67
+ this.pd = window.devicePixelRatio;
68
+ canvas.width = canvas.clientWidth * this.pd;
69
+ canvas.height = canvas.clientHeight * this.pd;
70
+ (_this$surface = this.surface) === null || _this$surface === void 0 || _this$surface.ref.delete();
71
+ this.surface = null;
72
+ if (canvas.width === 0 || canvas.height === 0) {
73
+ // The canvas hasn't been laid out yet (or is hidden). The view's
74
+ // ResizeObserver calls us again as soon as it has a size.
75
+ return;
55
76
  }
77
+ // Reuse the existing WebGL context and GrDirectContext: only the surface
78
+ // needs to be recreated when the canvas is resized.
79
+ const surface = CanvasKit.MakeOnScreenGLSurface(this.grContext, canvas.width, canvas.height, CanvasKit.ColorSpace.SRGB);
56
80
  if (!surface) {
57
81
  throw new Error("Could not create surface");
58
82
  }
@@ -63,39 +87,68 @@ class WebGLRenderer {
63
87
  const canvas = this.surface.getCanvas();
64
88
  canvas.clear(Float32Array.of(0, 0, 0, 0));
65
89
  canvas.save();
66
- canvas.scale(pd, pd);
90
+ canvas.scale(this.pd, this.pd);
67
91
  canvas.drawPicture(picture);
68
92
  canvas.restore();
69
93
  this.surface.ref.flush();
70
94
  }
71
95
  }
72
96
  dispose() {
73
- if (this.surface) {
74
- var _this$canvas;
75
- (_this$canvas = this.canvas) === null || _this$canvas === void 0 || (_this$canvas = _this$canvas.getContext("webgl2")) === null || _this$canvas === void 0 || (_this$canvas = _this$canvas.getExtension("WEBGL_lose_context")) === null || _this$canvas === void 0 || _this$canvas.loseContext();
76
- this.surface.ref.delete();
77
- this.surface = null;
97
+ var _this$surface2, _this$canvas;
98
+ (_this$surface2 = this.surface) === null || _this$surface2 === void 0 || _this$surface2.ref.delete();
99
+ this.surface = null;
100
+ if (this.grContext) {
101
+ this.grContext.releaseResourcesAndAbandonContext();
102
+ this.grContext.delete();
103
+ this.grContext = null;
104
+ }
105
+ (_this$canvas = this.canvas) === null || _this$canvas === void 0 || (_this$canvas = _this$canvas.getContext("webgl2")) === null || _this$canvas === void 0 || (_this$canvas = _this$canvas.getExtension("WEBGL_lose_context")) === null || _this$canvas === void 0 || _this$canvas.loseContext();
106
+ if (this.contextHandle) {
107
+ // Unregister the context from CanvasKit's internal registry, otherwise
108
+ // it retains the canvas element (and its detached DOM tree) forever.
109
+ CanvasKit.deleteContext(this.contextHandle);
110
+ // Making the now-deleted handle current clears CanvasKit's
111
+ // current-context globals (GLctx/Module.ctx), which would otherwise
112
+ // keep referencing the context (and the canvas) until another surface
113
+ // becomes current. With a deleted handle this is a no-op that returns
114
+ // null without creating anything.
115
+ CanvasKit.MakeWebGLContext(this.contextHandle);
116
+ this.contextHandle = 0;
78
117
  }
79
118
  }
80
119
  }
81
120
  class StaticWebGLRenderer {
82
- constructor(canvas, pd) {
121
+ constructor(canvas) {
83
122
  this.canvas = canvas;
84
- this.pd = pd;
85
123
  _defineProperty(this, "cachedImage", null);
124
+ _defineProperty(this, "pd", 1);
86
125
  }
87
126
  onResize() {
88
127
  this.cachedImage = null;
89
128
  }
90
129
  renderPictureToSurface(picture) {
130
+ this.pd = window.devicePixelRatio;
131
+ if (this.canvas.clientWidth === 0 || this.canvas.clientHeight === 0) {
132
+ return null;
133
+ }
91
134
  const tempCanvas = new OffscreenCanvas(this.canvas.clientWidth * this.pd, this.canvas.clientHeight * this.pd);
92
135
  let surface = null;
136
+ let grContext = null;
137
+ let contextHandle = 0;
93
138
  try {
94
- const webglSurface = CanvasKit.MakeWebGLCanvasSurface(tempCanvas);
139
+ contextHandle = CanvasKit.GetWebGLContext(tempCanvas);
140
+ if (!contextHandle) {
141
+ throw new Error("Could not create a WebGL context");
142
+ }
143
+ grContext = CanvasKit.MakeWebGLContext(contextHandle);
144
+ if (!grContext) {
145
+ throw new Error("Could not create a graphics context");
146
+ }
95
147
  const ctx = tempCanvas.getContext("webgl2");
96
148
  if (ctx) {
97
149
  ctx.drawingBufferColorSpace = "display-p3";
98
150
  }
151
+ const webglSurface = CanvasKit.MakeOnScreenGLSurface(grContext, tempCanvas.width, tempCanvas.height, CanvasKit.ColorSpace.SRGB);
99
152
  if (!webglSurface) {
100
153
  throw new Error("Could not create WebGL surface");
101
154
  }
@@ -109,23 +162,34 @@ class StaticWebGLRenderer {
109
162
  surface.ref.flush();
110
163
  return {
111
164
  surface,
112
- tempCanvas
165
+ tempCanvas,
166
+ grContext,
167
+ contextHandle
113
168
  };
114
169
  } catch (error) {
115
- if (surface) {
116
- surface.ref.delete();
117
- }
118
- this.cleanupWebGLContext(tempCanvas);
170
+ this.cleanupRenderResult({
171
+ surface,
172
+ tempCanvas,
173
+ grContext,
174
+ contextHandle
175
+ });
119
176
  return null;
120
177
  }
121
178
  }
122
- cleanupWebGLContext(tempCanvas) {
123
- const ctx = tempCanvas.getContext("webgl2");
124
- if (ctx) {
125
- const loseContext = ctx.getExtension("WEBGL_lose_context");
126
- if (loseContext) {
127
- loseContext.loseContext();
128
- }
179
+ cleanupRenderResult(result) {
180
+ var _result$surface, _result$tempCanvas$ge;
181
+ (_result$surface = result.surface) === null || _result$surface === void 0 || _result$surface.ref.delete();
182
+ if (result.grContext) {
183
+ result.grContext.releaseResourcesAndAbandonContext();
184
+ result.grContext.delete();
185
+ }
186
+ (_result$tempCanvas$ge = result.tempCanvas.getContext("webgl2")) === null || _result$tempCanvas$ge === void 0 || (_result$tempCanvas$ge = _result$tempCanvas$ge.getExtension("WEBGL_lose_context")) === null || _result$tempCanvas$ge === void 0 || _result$tempCanvas$ge.loseContext();
187
+ if (result.contextHandle) {
188
+ // Unregister the context from CanvasKit's internal registry, otherwise
189
+ // it retains the OffscreenCanvas forever.
190
+ CanvasKit.deleteContext(result.contextHandle);
191
+ // Clear CanvasKit's current-context globals (see WebGLRenderer.dispose).
192
+ CanvasKit.MakeWebGLContext(result.contextHandle);
129
193
  }
130
194
  }
131
195
  draw(picture) {
@@ -138,6 +202,7 @@ class StaticWebGLRenderer {
138
202
  } = renderResult;
139
203
  const ctx2d = this.canvas.getContext("2d");
140
204
  if (!ctx2d) {
205
+ this.cleanupRenderResult(renderResult);
141
206
  throw new Error("Could not get 2D context");
142
207
  }
143
208
 
@@ -147,7 +212,7 @@ class StaticWebGLRenderer {
147
212
 
148
213
  // Draw the tempCanvas scaled down to the display size
149
214
  ctx2d.drawImage(tempCanvas, 0, 0, tempCanvas.width, tempCanvas.height, 0, 0, this.canvas.clientWidth * this.pd, this.canvas.clientHeight * this.pd);
150
- this.cleanupWebGLContext(tempCanvas);
215
+ this.cleanupRenderResult(renderResult);
151
216
  }
152
217
  makeImageSnapshot(picture, rect) {
153
218
  if (!this.cachedImage) {
@@ -155,17 +220,12 @@ class StaticWebGLRenderer {
155
220
  if (!renderResult) {
156
221
  return null;
157
222
  }
158
- const {
159
- surface,
160
- tempCanvas
161
- } = renderResult;
162
223
  try {
163
- this.cachedImage = surface.makeImageSnapshot(dp2Pixel(this.pd, rect));
224
+ this.cachedImage = renderResult.surface.makeImageSnapshot(dp2Pixel(this.pd, rect));
164
225
  } catch (error) {
165
226
  console.error("Error creating image snapshot:", error);
166
227
  } finally {
167
- surface.ref.delete();
168
- this.cleanupWebGLContext(tempCanvas);
228
+ this.cleanupRenderResult(renderResult);
169
229
  }
170
230
  }
171
231
  return this.cachedImage;
@@ -176,23 +236,87 @@ class StaticWebGLRenderer {
176
236
  this.cachedImage = null;
177
237
  }
178
238
  }
179
- const pd = _Platform.Platform.PixelRatio;
239
+
240
+ // Mirrors the event react-native-web synthesizes for onLayout.
241
+ const makeLayoutEvent = (x, y, width, height) => ({
242
+ timeStamp: Date.now(),
243
+ nativeEvent: {
244
+ layout: {
245
+ x,
246
+ y,
247
+ width,
248
+ height
249
+ }
250
+ },
251
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
252
+ // @ts-expect-error
253
+ currentTarget: 0,
254
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
255
+ // @ts-expect-error
256
+ target: 0,
257
+ bubbles: false,
258
+ cancelable: false,
259
+ defaultPrevented: false,
260
+ eventPhase: 0,
261
+ isDefaultPrevented() {
262
+ throw new Error("Method not supported on web.");
263
+ },
264
+ isPropagationStopped() {
265
+ throw new Error("Method not supported on web.");
266
+ },
267
+ persist() {
268
+ throw new Error("Method not supported on web.");
269
+ },
270
+ preventDefault() {
271
+ throw new Error("Method not supported on web.");
272
+ },
273
+ stopPropagation() {
274
+ throw new Error("Method not supported on web.");
275
+ },
276
+ isTrusted: true,
277
+ type: ""
278
+ });
180
279
  const SkiaPictureView = props => {
181
280
  const {
182
- ref
183
- } = props;
184
- const canvasRef = (0, _react.useRef)(null);
185
- const renderer = (0, _react.useRef)(null);
186
- const redrawRequestsRef = (0, _react.useRef)(0);
187
- const requestIdRef = (0, _react.useRef)(0);
188
- const pictureRef = (0, _react.useRef)(null);
189
- const {
281
+ ref,
190
282
  picture,
191
283
  onLayout
192
284
  } = props;
193
- const redraw = (0, _react.useCallback)(() => {
194
- redrawRequestsRef.current++;
285
+ const canvasRef = (0, _react.useRef)(null);
286
+ const rendererRef = (0, _react.useRef)(null);
287
+ const pictureRef = (0, _react.useRef)(null);
288
+ // The rendering lifecycle deliberately does not depend on layout events:
289
+ // - The renderer is created synchronously on mount (the canvas element is
290
+ // guaranteed to exist in useLayoutEffect; a zero size at that point is
291
+ // fine, the surface is created once the canvas is measurable).
292
+ // - Redraw requests coalesce into a single animation frame. A picture
293
+ // dispatched before the canvas has a size stays in pictureRef (drawing
294
+ // while unmeasured is a no-op) and is painted by the resize path below
295
+ // once the canvas becomes measurable, so it is never lost.
296
+ // - A ResizeObserver on the canvas itself recreates the surface and repaints
297
+ // synchronously (its callbacks run after layout, before paint), and is
298
+ // also the source of the user-facing onLayout event.
299
+ const redrawPendingRef = (0, _react.useRef)(false);
300
+ const frameRef = (0, _react.useRef)(0);
301
+ const onLayoutRef = (0, _react.useRef)(onLayout);
302
+ (0, _react.useLayoutEffect)(() => {
303
+ onLayoutRef.current = onLayout;
304
+ }, [onLayout]);
305
+ const flushRedraw = (0, _react.useCallback)(() => {
306
+ frameRef.current = 0;
307
+ if (redrawPendingRef.current && rendererRef.current && pictureRef.current) {
308
+ redrawPendingRef.current = false;
309
+ rendererRef.current.draw(pictureRef.current);
310
+ }
311
+ // If the renderer or picture isn't available yet, the request stays
312
+ // pending and is flushed by whichever arrives last.
195
313
  }, []);
314
+ const redraw = (0, _react.useCallback)(() => {
315
+ redrawPendingRef.current = true;
316
+ if (frameRef.current === 0) {
317
+ frameRef.current = requestAnimationFrame(flushRedraw);
318
+ }
319
+ }, [flushRedraw]);
196
320
  const getSize = (0, _react.useCallback)(() => {
197
321
  var _canvasRef$current, _canvasRef$current2;
198
322
  return {
@@ -205,8 +329,8 @@ const SkiaPictureView = props => {
205
329
  redraw();
206
330
  }, [redraw]);
207
331
  const makeImageSnapshot = (0, _react.useCallback)(rect => {
208
- if (renderer.current && pictureRef.current) {
209
- return renderer.current.makeImageSnapshot(pictureRef.current, rect);
332
+ if (rendererRef.current && pictureRef.current) {
333
+ return rendererRef.current.makeImageSnapshot(pictureRef.current, rect);
210
334
  }
211
335
  return null;
212
336
  }, []);
@@ -239,27 +363,98 @@ const SkiaPictureView = props => {
239
363
  callback(x, y, rect.width, rect.height);
240
364
  }
241
365
  }, []);
242
- const tick = (0, _react.useCallback)(() => {
243
- if (redrawRequestsRef.current > 0) {
244
- redrawRequestsRef.current = 0;
245
- if (renderer.current && pictureRef.current) {
246
- renderer.current.draw(pictureRef.current);
247
- }
248
- }
249
- requestIdRef.current = requestAnimationFrame(tick);
250
- }, []);
251
- const onLayoutEvent = (0, _react.useCallback)(evt => {
366
+ const isStatic = props.__destroyWebGLContextAfterRender === true;
367
+ (0, _react.useLayoutEffect)(() => {
252
368
  const canvas = canvasRef.current;
253
- if (canvas) {
254
- renderer.current = props.__destroyWebGLContextAfterRender === true ? new StaticWebGLRenderer(canvas, pd) : new WebGLRenderer(canvas, pd);
369
+ if (!canvas) {
370
+ return undefined;
371
+ }
372
+ const renderer = isStatic ? new StaticWebGLRenderer(canvas) : new WebGLRenderer(canvas);
373
+ rendererRef.current = renderer;
374
+ const drawPicture = () => {
255
375
  if (pictureRef.current) {
256
- renderer.current.draw(pictureRef.current);
376
+ redrawPendingRef.current = false;
377
+ renderer.draw(pictureRef.current);
257
378
  }
258
- }
259
- if (onLayout) {
260
- onLayout(evt);
261
- }
262
- }, [onLayout, props.__destroyWebGLContextAfterRender]);
379
+ };
380
+
381
+ // The renderer constructor already sized the surface from the current
382
+ // layout, so the observer's initial delivery only repaints if the size
383
+ // changed in between.
384
+ let lastWidth = canvas.clientWidth;
385
+ let lastHeight = canvas.clientHeight;
386
+ let lastPixelDensity = window.devicePixelRatio;
387
+ const resizeIfNeeded = () => {
388
+ const width = canvas.clientWidth;
389
+ const height = canvas.clientHeight;
390
+ const pixelDensity = window.devicePixelRatio;
391
+ if (width === lastWidth && height === lastHeight && pixelDensity === lastPixelDensity) {
392
+ return;
393
+ }
394
+ lastWidth = width;
395
+ lastHeight = height;
396
+ lastPixelDensity = pixelDensity;
397
+ renderer.onResize();
398
+ drawPicture();
399
+ };
400
+ const observer = new ResizeObserver(entries => {
401
+ resizeIfNeeded();
402
+ const layoutHandler = onLayoutRef.current;
403
+ if (layoutHandler) {
404
+ const {
405
+ left,
406
+ top,
407
+ width,
408
+ height
409
+ } = entries[0].contentRect;
410
+ // setTimeout 0 is taken from react-native-web (UIManager)
411
+ setTimeout(() => layoutHandler(makeLayoutEvent(left, top, width, height)), 0);
412
+ }
413
+ });
414
+ observer.observe(canvas);
415
+
416
+ // A pixel-density change with no CSS size change (browser zoom, moving
417
+ // the window to another display) doesn't trigger the ResizeObserver:
418
+ // watch it via matchMedia, re-arming the query for each new density.
419
+ // This degrades gracefully where unsupported: without matchMedia or
420
+ // MediaQueryList.addEventListener (older Safari), or where the query
421
+ // never matches because the resolution feature is unknown (Safari < 16),
422
+ // density-only changes simply don't repaint — everything else still does.
423
+ let media = null;
424
+ const onPixelDensityChange = () => {
425
+ resizeIfNeeded();
426
+ watchPixelDensity();
427
+ };
428
+ const watchPixelDensity = () => {
429
+ var _media;
430
+ (_media = media) === null || _media === void 0 || _media.removeEventListener("change", onPixelDensityChange);
431
+ media = null;
432
+ if (typeof window.matchMedia === "function") {
433
+ const query = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
434
+ if (typeof query.addEventListener === "function") {
435
+ media = query;
436
+ media.addEventListener("change", onPixelDensityChange);
437
+ }
438
+ }
439
+ };
440
+ watchPixelDensity();
441
+
442
+ // Paint any picture that was dispatched before the renderer existed.
443
+ drawPicture();
444
+ return () => {
445
+ var _media2;
446
+ observer.disconnect();
447
+ (_media2 = media) === null || _media2 === void 0 || _media2.removeEventListener("change", onPixelDensityChange);
448
+ rendererRef.current = null;
449
+ renderer.dispose();
450
+ };
451
+ }, [isStatic]);
452
+ (0, _react.useEffect)(() => {
453
+ return () => {
454
+ cancelAnimationFrame(frameRef.current);
455
+ frameRef.current = 0;
456
+ };
457
+ }, []);
263
458
  (0, _react.useImperativeHandle)(ref, () => ({
264
459
  setPicture,
265
460
  getSize,
@@ -274,7 +469,8 @@ const SkiaPictureView = props => {
274
469
  (0, _react.useEffect)(() => {
275
470
  var _props$nativeID;
276
471
  const nativeID = (_props$nativeID = props.nativeID) !== null && _props$nativeID !== void 0 ? _props$nativeID : `${_SkiaViewNativeId.SkiaViewNativeId.current++}`;
277
- global.SkiaViewApi.registerView(nativeID, {
472
+ const api = global.SkiaViewApi;
473
+ api.registerView(nativeID, {
278
474
  setPicture,
279
475
  getSize,
280
476
  redraw,
@@ -282,35 +478,24 @@ const SkiaPictureView = props => {
282
478
  measure,
283
479
  measureInWindow
284
480
  });
285
- }, [setPicture, getSize, redraw, makeImageSnapshot, measure, measureInWindow, props.nativeID]);
286
- (0, _react.useEffect)(() => {
287
- if (props.picture) {
288
- setPicture(props.picture);
289
- }
290
- }, [setPicture, props.picture]);
291
- (0, _react.useEffect)(() => {
292
- tick();
293
481
  return () => {
294
- cancelAnimationFrame(requestIdRef.current);
295
- if (renderer.current) {
296
- renderer.current.dispose();
297
- renderer.current = null;
298
- }
482
+ api.unregisterView(nativeID);
299
483
  };
300
- }, [tick]);
484
+ }, [setPicture, getSize, redraw, makeImageSnapshot, measure, measureInWindow, props.nativeID]);
301
485
  (0, _react.useEffect)(() => {
302
- if (renderer.current && pictureRef.current) {
303
- renderer.current.draw(pictureRef.current);
486
+ if (picture) {
487
+ setPicture(picture);
304
488
  }
305
- }, [picture, redraw]);
489
+ }, [setPicture, picture]);
306
490
  const {
307
- debug = false,
491
+ debug: _debug,
308
492
  ref: _ref,
493
+ onLayout: _onLayout,
494
+ picture: _picture,
495
+ __destroyWebGLContextAfterRender: _isStatic,
309
496
  ...viewProps
310
497
  } = props;
311
- return /*#__PURE__*/_react.default.createElement(_Platform.Platform.View, _extends({}, viewProps, {
312
- onLayout: onLayoutEvent
313
- }), /*#__PURE__*/_react.default.createElement("canvas", {
498
+ return /*#__PURE__*/_react.default.createElement(_Platform.Platform.View, viewProps, /*#__PURE__*/_react.default.createElement("canvas", {
314
499
  ref: canvasRef,
315
500
  style: {
316
501
  display: "block",