@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.
- package/android/cpp/jni/include/JniSkiaBaseView.h +6 -4
- package/android/cpp/jni/include/JniSkiaPictureView.h +8 -6
- package/android/cpp/rnskia-android/OpenGLContext.h +10 -1
- package/android/cpp/rnskia-android/RNSkAndroidView.h +8 -8
- package/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.cpp +9 -5
- package/android/cpp/rnskia-android/RNSkOpenGLCanvasProvider.h +4 -2
- package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseView.java +48 -12
- package/android/src/main/java/com/shopify/reactnative/skia/SkiaBaseViewManager.java +5 -0
- package/android/src/main/java/com/shopify/reactnative/skia/SkiaPictureView.java +2 -2
- package/android/src/main/java/com/shopify/reactnative/skia/ViewScreenshotService.java +11 -7
- package/apple/MetalContext.h +7 -6
- package/apple/MetalLayerColorSpace.mm +39 -0
- package/apple/MetalLayerColorSpaceUtils.h +34 -0
- package/apple/MetalWindowContext.h +3 -1
- package/apple/MetalWindowContext.mm +9 -8
- package/apple/RNSkAppleView.h +6 -0
- package/apple/RNSkMetalCanvasProvider.h +2 -0
- package/apple/RNSkMetalCanvasProvider.mm +15 -2
- package/apple/SkiaPictureView.mm +1 -0
- package/apple/SkiaPictureViewManager.mm +5 -0
- package/apple/SkiaUIView.h +1 -0
- package/apple/SkiaUIView.mm +9 -0
- package/cpp/api/JsiSkSurface.h +8 -2
- package/cpp/rnskia/RNDawnContext.h +4 -3
- package/cpp/rnskia/RNDawnUtils.h +25 -6
- package/cpp/rnskia/RNDawnWindowContext.h +44 -10
- package/cpp/rnskia/RNMetalLayerColorSpace.h +16 -0
- package/cpp/rnskia/RNSkJsiViewApi.h +46 -24
- package/cpp/rnwgpu/SurfaceRegistry.h +10 -4
- package/lib/commonjs/Platform/Platform.web.js +2 -90
- package/lib/commonjs/Platform/Platform.web.js.map +1 -1
- package/lib/commonjs/mock/index.js +1 -0
- package/lib/commonjs/mock/index.js.map +1 -1
- package/lib/commonjs/renderer/Canvas.d.ts +10 -1
- package/lib/commonjs/renderer/Canvas.js +2 -0
- package/lib/commonjs/renderer/Canvas.js.map +1 -1
- package/lib/commonjs/skia/types/Surface/Surface.d.ts +5 -1
- package/lib/commonjs/skia/types/Surface/Surface.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkParagraphStyle.js +14 -3
- package/lib/commonjs/skia/web/JsiSkParagraphStyle.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkSurface.d.ts +1 -1
- package/lib/commonjs/skia/web/JsiSkSurface.js +2 -1
- package/lib/commonjs/skia/web/JsiSkSurface.js.map +1 -1
- package/lib/commonjs/sksg/Container.native.d.ts +1 -0
- package/lib/commonjs/sksg/Container.native.js +11 -0
- package/lib/commonjs/sksg/Container.native.js.map +1 -1
- package/lib/commonjs/sksg/Container.web.d.ts +1 -0
- package/lib/commonjs/sksg/Container.web.js +11 -0
- package/lib/commonjs/sksg/Container.web.js.map +1 -1
- package/lib/commonjs/specs/NativeSkiaModule.web.d.ts +2 -0
- package/lib/commonjs/specs/NativeSkiaModule.web.js +32 -7
- package/lib/commonjs/specs/NativeSkiaModule.web.js.map +1 -1
- package/lib/commonjs/specs/SkiaPictureViewNativeComponent.d.ts +1 -0
- package/lib/commonjs/specs/SkiaPictureViewNativeComponent.js.map +1 -1
- package/lib/commonjs/views/SkiaPictureView.js +2 -0
- package/lib/commonjs/views/SkiaPictureView.js.map +1 -1
- package/lib/commonjs/views/SkiaPictureView.web.js +279 -94
- package/lib/commonjs/views/SkiaPictureView.web.js.map +1 -1
- package/lib/commonjs/views/formats.d.ts +1 -0
- package/lib/commonjs/views/formats.js +28 -0
- package/lib/commonjs/views/formats.js.map +1 -0
- package/lib/commonjs/views/index.d.ts +1 -0
- package/lib/commonjs/views/index.js +11 -0
- package/lib/commonjs/views/index.js.map +1 -1
- package/lib/commonjs/views/types.d.ts +6 -0
- package/lib/commonjs/views/types.js.map +1 -1
- package/lib/module/Platform/Platform.web.js +3 -91
- package/lib/module/Platform/Platform.web.js.map +1 -1
- package/lib/module/mock/index.js +1 -0
- package/lib/module/mock/index.js.map +1 -1
- package/lib/module/renderer/Canvas.d.ts +10 -1
- package/lib/module/renderer/Canvas.js +2 -0
- package/lib/module/renderer/Canvas.js.map +1 -1
- package/lib/module/skia/types/Surface/Surface.d.ts +5 -1
- package/lib/module/skia/types/Surface/Surface.js.map +1 -1
- package/lib/module/skia/web/JsiSkParagraphStyle.js +14 -3
- package/lib/module/skia/web/JsiSkParagraphStyle.js.map +1 -1
- package/lib/module/skia/web/JsiSkSurface.d.ts +1 -1
- package/lib/module/skia/web/JsiSkSurface.js +2 -1
- package/lib/module/skia/web/JsiSkSurface.js.map +1 -1
- package/lib/module/sksg/Container.native.d.ts +1 -0
- package/lib/module/sksg/Container.native.js +11 -0
- package/lib/module/sksg/Container.native.js.map +1 -1
- package/lib/module/sksg/Container.web.d.ts +1 -0
- package/lib/module/sksg/Container.web.js +11 -0
- package/lib/module/sksg/Container.web.js.map +1 -1
- package/lib/module/specs/NativeSkiaModule.web.d.ts +2 -0
- package/lib/module/specs/NativeSkiaModule.web.js +32 -7
- package/lib/module/specs/NativeSkiaModule.web.js.map +1 -1
- package/lib/module/specs/SkiaPictureViewNativeComponent.d.ts +1 -0
- package/lib/module/specs/SkiaPictureViewNativeComponent.js.map +1 -1
- package/lib/module/views/SkiaPictureView.js +2 -0
- package/lib/module/views/SkiaPictureView.js.map +1 -1
- package/lib/module/views/SkiaPictureView.web.js +280 -95
- package/lib/module/views/SkiaPictureView.web.js.map +1 -1
- package/lib/module/views/formats.d.ts +1 -0
- package/lib/module/views/formats.js +22 -0
- package/lib/module/views/formats.js.map +1 -0
- package/lib/module/views/index.d.ts +1 -0
- package/lib/module/views/index.js +1 -0
- package/lib/module/views/index.js.map +1 -1
- package/lib/module/views/types.d.ts +6 -0
- package/lib/module/views/types.js.map +1 -1
- package/lib/typescript/lib/commonjs/Platform/Platform.web.d.ts +1 -2
- package/lib/typescript/lib/commonjs/mock/index.d.ts +1 -0
- package/lib/typescript/lib/commonjs/renderer/Canvas.d.ts +2 -1
- package/lib/typescript/lib/commonjs/skia/web/JsiSkSurface.d.ts +1 -1
- package/lib/typescript/lib/commonjs/sksg/Container.native.d.ts +1 -1
- package/lib/typescript/lib/commonjs/sksg/Container.web.d.ts +1 -1
- package/lib/typescript/lib/commonjs/views/formats.d.ts +2 -0
- package/lib/typescript/lib/module/Platform/Platform.web.d.ts +1 -3
- package/lib/typescript/lib/module/mock/index.d.ts +2 -2
- package/lib/typescript/lib/module/renderer/Canvas.d.ts +2 -1
- package/lib/typescript/lib/module/skia/web/JsiSkSurface.d.ts +1 -1
- package/lib/typescript/lib/module/sksg/Container.native.d.ts +1 -1
- package/lib/typescript/lib/module/sksg/Container.web.d.ts +1 -1
- package/lib/typescript/lib/module/views/formats.d.ts +1 -0
- package/lib/typescript/lib/module/views/index.d.ts +1 -0
- package/lib/typescript/src/renderer/Canvas.d.ts +10 -1
- package/lib/typescript/src/skia/types/Surface/Surface.d.ts +5 -1
- package/lib/typescript/src/skia/web/JsiSkSurface.d.ts +1 -1
- package/lib/typescript/src/sksg/Container.native.d.ts +1 -0
- package/lib/typescript/src/sksg/Container.web.d.ts +1 -0
- package/lib/typescript/src/specs/NativeSkiaModule.web.d.ts +2 -0
- package/lib/typescript/src/specs/SkiaPictureViewNativeComponent.d.ts +1 -0
- package/lib/typescript/src/views/formats.d.ts +1 -0
- package/lib/typescript/src/views/index.d.ts +1 -0
- package/lib/typescript/src/views/types.d.ts +6 -0
- package/package.json +4 -1
- package/react-native-skia.podspec +1 -0
- package/src/Platform/Platform.web.tsx +7 -99
- package/src/mock/index.ts +1 -0
- package/src/renderer/Canvas.tsx +11 -0
- package/src/skia/types/Surface/Surface.ts +5 -1
- package/src/skia/web/JsiSkParagraphStyle.ts +16 -2
- package/src/skia/web/JsiSkSurface.ts +2 -1
- package/src/sksg/Container.native.ts +12 -0
- package/src/sksg/Container.web.ts +12 -0
- package/src/specs/NativeSkiaModule.web.ts +39 -7
- package/src/specs/SkiaPictureViewNativeComponent.ts +1 -0
- package/src/views/SkiaPictureView.tsx +2 -0
- package/src/views/SkiaPictureView.web.tsx +318 -106
- package/src/views/formats.ts +21 -0
- package/src/views/index.ts +1 -0
- 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
|
|
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
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
this.
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
116
|
-
surface
|
|
117
|
-
|
|
118
|
-
|
|
170
|
+
this.cleanupRenderResult({
|
|
171
|
+
surface,
|
|
172
|
+
tempCanvas,
|
|
173
|
+
grContext,
|
|
174
|
+
contextHandle
|
|
175
|
+
});
|
|
119
176
|
return null;
|
|
120
177
|
}
|
|
121
178
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
194
|
-
|
|
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 (
|
|
209
|
-
return
|
|
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
|
|
243
|
-
|
|
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
|
-
|
|
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
|
-
|
|
376
|
+
redrawPendingRef.current = false;
|
|
377
|
+
renderer.draw(pictureRef.current);
|
|
257
378
|
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
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
|
|
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
|
-
|
|
295
|
-
if (renderer.current) {
|
|
296
|
-
renderer.current.dispose();
|
|
297
|
-
renderer.current = null;
|
|
298
|
-
}
|
|
482
|
+
api.unregisterView(nativeID);
|
|
299
483
|
};
|
|
300
|
-
}, [
|
|
484
|
+
}, [setPicture, getSize, redraw, makeImageSnapshot, measure, measureInWindow, props.nativeID]);
|
|
301
485
|
(0, _react.useEffect)(() => {
|
|
302
|
-
if (
|
|
303
|
-
|
|
486
|
+
if (picture) {
|
|
487
|
+
setPicture(picture);
|
|
304
488
|
}
|
|
305
|
-
}, [
|
|
489
|
+
}, [setPicture, picture]);
|
|
306
490
|
const {
|
|
307
|
-
debug
|
|
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,
|
|
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",
|