@shopify/react-native-skia 2.6.8 → 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 (146) 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 +20 -5
  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/SkiaCVPixelBufferUtils.mm +10 -0
  20. package/apple/SkiaPictureView.mm +1 -0
  21. package/apple/SkiaPictureViewManager.mm +5 -0
  22. package/apple/SkiaUIView.h +1 -0
  23. package/apple/SkiaUIView.mm +9 -0
  24. package/cpp/api/JsiSkSurface.h +8 -2
  25. package/cpp/rnskia/RNDawnContext.h +4 -3
  26. package/cpp/rnskia/RNDawnUtils.h +25 -6
  27. package/cpp/rnskia/RNDawnWindowContext.h +44 -10
  28. package/cpp/rnskia/RNMetalLayerColorSpace.h +16 -0
  29. package/cpp/rnskia/RNSkJsiViewApi.h +46 -24
  30. package/cpp/rnwgpu/SurfaceRegistry.h +10 -4
  31. package/lib/commonjs/Platform/Platform.web.js +2 -90
  32. package/lib/commonjs/Platform/Platform.web.js.map +1 -1
  33. package/lib/commonjs/mock/index.js +1 -0
  34. package/lib/commonjs/mock/index.js.map +1 -1
  35. package/lib/commonjs/renderer/Canvas.d.ts +10 -1
  36. package/lib/commonjs/renderer/Canvas.js +2 -0
  37. package/lib/commonjs/renderer/Canvas.js.map +1 -1
  38. package/lib/commonjs/skia/types/Surface/Surface.d.ts +5 -1
  39. package/lib/commonjs/skia/types/Surface/Surface.js.map +1 -1
  40. package/lib/commonjs/skia/web/JsiSkParagraphStyle.js +14 -3
  41. package/lib/commonjs/skia/web/JsiSkParagraphStyle.js.map +1 -1
  42. package/lib/commonjs/skia/web/JsiSkSurface.d.ts +1 -1
  43. package/lib/commonjs/skia/web/JsiSkSurface.js +2 -1
  44. package/lib/commonjs/skia/web/JsiSkSurface.js.map +1 -1
  45. package/lib/commonjs/sksg/Container.native.d.ts +1 -0
  46. package/lib/commonjs/sksg/Container.native.js +11 -0
  47. package/lib/commonjs/sksg/Container.native.js.map +1 -1
  48. package/lib/commonjs/sksg/Container.web.d.ts +1 -0
  49. package/lib/commonjs/sksg/Container.web.js +11 -0
  50. package/lib/commonjs/sksg/Container.web.js.map +1 -1
  51. package/lib/commonjs/specs/NativeSkiaModule.web.d.ts +2 -0
  52. package/lib/commonjs/specs/NativeSkiaModule.web.js +32 -7
  53. package/lib/commonjs/specs/NativeSkiaModule.web.js.map +1 -1
  54. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.d.ts +1 -0
  55. package/lib/commonjs/specs/SkiaPictureViewNativeComponent.js.map +1 -1
  56. package/lib/commonjs/views/SkiaPictureView.js +2 -0
  57. package/lib/commonjs/views/SkiaPictureView.js.map +1 -1
  58. package/lib/commonjs/views/SkiaPictureView.web.js +279 -94
  59. package/lib/commonjs/views/SkiaPictureView.web.js.map +1 -1
  60. package/lib/commonjs/views/formats.d.ts +1 -0
  61. package/lib/commonjs/views/formats.js +28 -0
  62. package/lib/commonjs/views/formats.js.map +1 -0
  63. package/lib/commonjs/views/index.d.ts +1 -0
  64. package/lib/commonjs/views/index.js +11 -0
  65. package/lib/commonjs/views/index.js.map +1 -1
  66. package/lib/commonjs/views/types.d.ts +6 -0
  67. package/lib/commonjs/views/types.js.map +1 -1
  68. package/lib/module/Platform/Platform.web.js +3 -91
  69. package/lib/module/Platform/Platform.web.js.map +1 -1
  70. package/lib/module/mock/index.js +1 -0
  71. package/lib/module/mock/index.js.map +1 -1
  72. package/lib/module/renderer/Canvas.d.ts +10 -1
  73. package/lib/module/renderer/Canvas.js +2 -0
  74. package/lib/module/renderer/Canvas.js.map +1 -1
  75. package/lib/module/skia/types/Surface/Surface.d.ts +5 -1
  76. package/lib/module/skia/types/Surface/Surface.js.map +1 -1
  77. package/lib/module/skia/web/JsiSkParagraphStyle.js +14 -3
  78. package/lib/module/skia/web/JsiSkParagraphStyle.js.map +1 -1
  79. package/lib/module/skia/web/JsiSkSurface.d.ts +1 -1
  80. package/lib/module/skia/web/JsiSkSurface.js +2 -1
  81. package/lib/module/skia/web/JsiSkSurface.js.map +1 -1
  82. package/lib/module/sksg/Container.native.d.ts +1 -0
  83. package/lib/module/sksg/Container.native.js +11 -0
  84. package/lib/module/sksg/Container.native.js.map +1 -1
  85. package/lib/module/sksg/Container.web.d.ts +1 -0
  86. package/lib/module/sksg/Container.web.js +11 -0
  87. package/lib/module/sksg/Container.web.js.map +1 -1
  88. package/lib/module/specs/NativeSkiaModule.web.d.ts +2 -0
  89. package/lib/module/specs/NativeSkiaModule.web.js +32 -7
  90. package/lib/module/specs/NativeSkiaModule.web.js.map +1 -1
  91. package/lib/module/specs/SkiaPictureViewNativeComponent.d.ts +1 -0
  92. package/lib/module/specs/SkiaPictureViewNativeComponent.js.map +1 -1
  93. package/lib/module/views/SkiaPictureView.js +2 -0
  94. package/lib/module/views/SkiaPictureView.js.map +1 -1
  95. package/lib/module/views/SkiaPictureView.web.js +280 -95
  96. package/lib/module/views/SkiaPictureView.web.js.map +1 -1
  97. package/lib/module/views/formats.d.ts +1 -0
  98. package/lib/module/views/formats.js +22 -0
  99. package/lib/module/views/formats.js.map +1 -0
  100. package/lib/module/views/index.d.ts +1 -0
  101. package/lib/module/views/index.js +1 -0
  102. package/lib/module/views/index.js.map +1 -1
  103. package/lib/module/views/types.d.ts +6 -0
  104. package/lib/module/views/types.js.map +1 -1
  105. package/lib/typescript/lib/commonjs/Platform/Platform.web.d.ts +1 -2
  106. package/lib/typescript/lib/commonjs/mock/index.d.ts +1 -0
  107. package/lib/typescript/lib/commonjs/renderer/Canvas.d.ts +2 -1
  108. package/lib/typescript/lib/commonjs/skia/web/JsiSkSurface.d.ts +1 -1
  109. package/lib/typescript/lib/commonjs/sksg/Container.native.d.ts +1 -1
  110. package/lib/typescript/lib/commonjs/sksg/Container.web.d.ts +1 -1
  111. package/lib/typescript/lib/commonjs/views/formats.d.ts +2 -0
  112. package/lib/typescript/lib/module/Platform/Platform.web.d.ts +1 -3
  113. package/lib/typescript/lib/module/mock/index.d.ts +2 -2
  114. package/lib/typescript/lib/module/renderer/Canvas.d.ts +2 -1
  115. package/lib/typescript/lib/module/skia/web/JsiSkSurface.d.ts +1 -1
  116. package/lib/typescript/lib/module/sksg/Container.native.d.ts +1 -1
  117. package/lib/typescript/lib/module/sksg/Container.web.d.ts +1 -1
  118. package/lib/typescript/lib/module/views/formats.d.ts +1 -0
  119. package/lib/typescript/lib/module/views/index.d.ts +1 -0
  120. package/lib/typescript/src/renderer/Canvas.d.ts +10 -1
  121. package/lib/typescript/src/skia/types/Surface/Surface.d.ts +5 -1
  122. package/lib/typescript/src/skia/web/JsiSkSurface.d.ts +1 -1
  123. package/lib/typescript/src/sksg/Container.native.d.ts +1 -0
  124. package/lib/typescript/src/sksg/Container.web.d.ts +1 -0
  125. package/lib/typescript/src/specs/NativeSkiaModule.web.d.ts +2 -0
  126. package/lib/typescript/src/specs/SkiaPictureViewNativeComponent.d.ts +1 -0
  127. package/lib/typescript/src/views/formats.d.ts +1 -0
  128. package/lib/typescript/src/views/index.d.ts +1 -0
  129. package/lib/typescript/src/views/types.d.ts +6 -0
  130. package/package.json +4 -1
  131. package/react-native-skia.podspec +1 -0
  132. package/src/Platform/Platform.web.tsx +7 -99
  133. package/src/mock/index.ts +1 -0
  134. package/src/renderer/Canvas.tsx +11 -0
  135. package/src/skia/types/Surface/Surface.ts +5 -1
  136. package/src/skia/web/JsiSkParagraphStyle.ts +16 -2
  137. package/src/skia/web/JsiSkSurface.ts +2 -1
  138. package/src/sksg/Container.native.ts +12 -0
  139. package/src/sksg/Container.web.ts +12 -0
  140. package/src/specs/NativeSkiaModule.web.ts +39 -7
  141. package/src/specs/SkiaPictureViewNativeComponent.ts +1 -0
  142. package/src/views/SkiaPictureView.tsx +2 -0
  143. package/src/views/SkiaPictureView.web.tsx +318 -106
  144. package/src/views/formats.ts +21 -0
  145. package/src/views/index.ts +1 -0
  146. package/src/views/types.ts +7 -0
@@ -1,104 +1,16 @@
1
- import type { RefObject, CSSProperties } from "react";
2
- import React, { useLayoutEffect, useMemo, useRef } from "react";
3
- import type { LayoutChangeEvent, ViewComponent, ViewProps } from "react-native";
1
+ import type { CSSProperties } from "react";
2
+ import React, { useMemo } from "react";
3
+ import type { ViewComponent, ViewProps } from "react-native";
4
4
 
5
5
  import type { DataModule } from "../skia/types";
6
6
  import { isRNModule } from "../skia/types";
7
7
 
8
8
  import type { IPlatform } from "./IPlatform";
9
9
 
10
- // https://github.com/necolas/react-native-web/blob/master/packages/react-native-web/src/modules/useElementLayout/index.js
11
- const DOM_LAYOUT_HANDLER_NAME = "__reactLayoutHandler";
12
- type OnLayout = ((event: LayoutChangeEvent) => void) | undefined;
13
- type Div = HTMLDivElement & {
14
- __reactLayoutHandler: OnLayout;
15
- };
16
-
17
- let resizeObserver: ResizeObserver | null = null;
18
-
19
- const getObserver = () => {
20
- if (resizeObserver == null) {
21
- resizeObserver = new window.ResizeObserver(function (entries) {
22
- entries.forEach((entry) => {
23
- const node = entry.target as Div;
24
- const { left, top, width, height } = entry.contentRect;
25
- const onLayout = node[DOM_LAYOUT_HANDLER_NAME];
26
- if (typeof onLayout === "function") {
27
- // setTimeout 0 is taken from react-native-web (UIManager)
28
- setTimeout(
29
- () =>
30
- onLayout({
31
- timeStamp: Date.now(),
32
- nativeEvent: { layout: { x: left, y: top, width, height } },
33
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
34
- // @ts-expect-error
35
- currentTarget: 0,
36
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
37
- // @ts-expect-error
38
- target: 0,
39
- bubbles: false,
40
- cancelable: false,
41
- defaultPrevented: false,
42
- eventPhase: 0,
43
- isDefaultPrevented() {
44
- throw new Error("Method not supported on web.");
45
- },
46
- isPropagationStopped() {
47
- throw new Error("Method not supported on web.");
48
- },
49
- persist() {
50
- throw new Error("Method not supported on web.");
51
- },
52
- preventDefault() {
53
- throw new Error("Method not supported on web.");
54
- },
55
- stopPropagation() {
56
- throw new Error("Method not supported on web.");
57
- },
58
- isTrusted: true,
59
- type: "",
60
- }),
61
- 0
62
- );
63
- }
64
- });
65
- });
66
- }
67
- return resizeObserver;
68
- };
69
-
70
- const useElementLayout = (ref: RefObject<Div>, onLayout: OnLayout) => {
71
- const observer = getObserver();
72
-
73
- useLayoutEffect(() => {
74
- const node = ref.current;
75
- if (node !== null) {
76
- node[DOM_LAYOUT_HANDLER_NAME] = onLayout;
77
- }
78
- }, [ref, onLayout]);
79
-
80
- useLayoutEffect(() => {
81
- const node = ref.current;
82
- if (node != null && observer != null) {
83
- if (typeof node[DOM_LAYOUT_HANDLER_NAME] === "function") {
84
- observer.observe(node);
85
- } else {
86
- observer.unobserve(node);
87
- }
88
- }
89
- return () => {
90
- if (node != null && observer != null) {
91
- observer.unobserve(node);
92
- }
93
- };
94
- }, [observer, ref]);
95
- };
96
-
97
- const View = (({ children, onLayout, style: rawStyle }: ViewProps) => {
10
+ // Layout is observed by the views themselves (see SkiaPictureView.web.tsx):
11
+ // this shim only reproduces react-native-web's default View styling.
12
+ const View = (({ children, style: rawStyle }: ViewProps) => {
98
13
  const style = useMemo(() => (rawStyle ?? {}) as CSSProperties, [rawStyle]);
99
- const ref = useRef<Div>(null);
100
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
101
- useElementLayout(ref as any, onLayout);
102
14
  const cssStyles = useMemo(() => {
103
15
  return {
104
16
  alignItems: "stretch" as const,
@@ -121,11 +33,7 @@ const View = (({ children, onLayout, style: rawStyle }: ViewProps) => {
121
33
  };
122
34
  }, [style]);
123
35
 
124
- return (
125
- <div ref={ref} style={cssStyles}>
126
- {children}
127
- </div>
128
- );
36
+ return <div style={cssStyles}>{children}</div>;
129
37
  }) as unknown as typeof ViewComponent;
130
38
 
131
39
  export const Platform: IPlatform = {
package/src/mock/index.ts CHANGED
@@ -24,6 +24,7 @@ export const Mock = (CanvasKit: CanvasKit) => {
24
24
  ...require("../dom/nodes"),
25
25
  Canvas: require("react-native").View,
26
26
  WebGPUCanvas: require("react-native").View,
27
+ getPreferredHighBitDepthCanvasFormat: () => "rgba16float",
27
28
  SkiaPictureView: require("react-native").View,
28
29
  JsiSkImage: JsiSkImage,
29
30
  drawAsPicture: Noop,
@@ -69,6 +69,15 @@ export interface CanvasProps extends Omit<ViewProps, "onLayout"> {
69
69
  opaque?: boolean;
70
70
  onSize?: SharedValue<SkSize>;
71
71
  colorSpace?: "p3" | "srgb";
72
+ /**
73
+ * Renders into a surface with more than 8 bits per channel (16-bit float on
74
+ * iOS, 10-bit on Android) to avoid banding in subtle gradients. Colors are
75
+ * identical to the default 8-bit surface, only with more precision (this is
76
+ * about bit depth, not HDR). On Android the extra precision survives
77
+ * composition only when combined with `opaque`, and the prop must be set
78
+ * before the canvas is mounted.
79
+ */
80
+ highBitDepth?: boolean;
72
81
  ref?: React.Ref<CanvasRef>;
73
82
  androidWarmup?: boolean;
74
83
  __destroyWebGLContextAfterRender?: boolean;
@@ -80,6 +89,7 @@ export const Canvas = ({
80
89
  children,
81
90
  onSize,
82
91
  colorSpace = "p3",
92
+ highBitDepth = false,
83
93
  androidWarmup = false,
84
94
  ref,
85
95
  onLayout,
@@ -180,6 +190,7 @@ export const Canvas = ({
180
190
  debug={debug}
181
191
  opaque={opaque}
182
192
  colorSpace={colorSpace}
193
+ highBitDepth={highBitDepth}
183
194
  androidWarmup={androidWarmup}
184
195
  onLayout={
185
196
  Platform.OS === "web" && (onSize || onLayout) ? onLayoutWeb : onLayout
@@ -39,8 +39,12 @@ export interface SkSurface extends SkJSIInstance<"Surface"> {
39
39
 
40
40
  /**
41
41
  * Make sure any queued draws are sent to the screen or the GPU.
42
+ * @param sync - When true, block until the GPU has finished executing the
43
+ * submitted work. Use this before reading the surface's texture from a native
44
+ * consumer on a different command queue (see {@link getNativeTextureUnstable}).
45
+ * Defaults to false.
42
46
  */
43
- flush(): void;
47
+ flush(sync?: boolean): void;
44
48
 
45
49
  /**
46
50
  * Returns the possibly scaled width of the surface.
@@ -1,8 +1,10 @@
1
- import type { CanvasKit, ParagraphStyle } from "canvaskit-wasm";
1
+ import type { CanvasKit, ParagraphStyle, TextStyle } from "canvaskit-wasm";
2
2
 
3
3
  import { TextDirection } from "../types";
4
4
  import type { SkParagraphStyle } from "../types";
5
5
 
6
+ import { JsiSkTextStyle } from "./JsiSkTextStyle";
7
+
6
8
  export class JsiSkParagraphStyle {
7
9
  static toParagraphStyle(
8
10
  ck: CanvasKit,
@@ -10,7 +12,19 @@ export class JsiSkParagraphStyle {
10
12
  ): ParagraphStyle {
11
13
  // Seems like we need to provide the textStyle.color value, otherwise
12
14
  // the constructor crashes.
13
- const ps = new ck.ParagraphStyle({ textStyle: { color: ck.BLACK } });
15
+ const textStyle: TextStyle = { color: ck.BLACK };
16
+ if (value.textStyle) {
17
+ // Only merge the properties that are set; toTextStyle() emits undefined
18
+ // for the others and the ParagraphStyle constructor requires a color.
19
+ Object.entries(JsiSkTextStyle.toTextStyle(value.textStyle)).forEach(
20
+ ([key, v]) => {
21
+ if (v !== undefined) {
22
+ (textStyle as Record<string, unknown>)[key] = v;
23
+ }
24
+ }
25
+ );
26
+ }
27
+ const ps = new ck.ParagraphStyle({ textStyle });
14
28
 
15
29
  ps.disableHinting = value.disableHinting ?? ps.disableHinting;
16
30
  ps.ellipsis = value.ellipsis ?? ps.ellipsis;
@@ -19,7 +19,8 @@ export class JsiSkSurface
19
19
  this.ref.dispose();
20
20
  }
21
21
 
22
- flush() {
22
+ flush(_sync?: boolean) {
23
+ // CanvasKit has no separate CPU sync; flush() is sufficient on the web backend.
23
24
  this.ref.flush();
24
25
  }
25
26
 
@@ -39,9 +39,21 @@ class NativeReanimatedContainer extends Container {
39
39
  this.picture = Skia.Picture.MakePicture(null)!;
40
40
  }
41
41
 
42
+ unmount() {
43
+ super.unmount();
44
+ if (this.mapperId !== null) {
45
+ // The mapper closure retains the recorder and its resources (e.g.
46
+ // images) on the UI runtime and keeps updating the picture of an
47
+ // unmounted view — stop it or it leaks for the lifetime of the app.
48
+ Rea.stopMapper(this.mapperId);
49
+ this.mapperId = null;
50
+ }
51
+ }
52
+
42
53
  redraw() {
43
54
  if (this.mapperId !== null) {
44
55
  Rea.stopMapper(this.mapperId);
56
+ this.mapperId = null;
45
57
  }
46
58
  if (this.unmounted) {
47
59
  return;
@@ -40,9 +40,21 @@ class ReanimatedContainer extends Container {
40
40
  super(Skia);
41
41
  }
42
42
 
43
+ unmount() {
44
+ super.unmount();
45
+ if (this.mapperId !== null) {
46
+ // The mapper closure retains the recording and keeps updating the
47
+ // picture of an unmounted view — stop it or it leaks for the
48
+ // lifetime of the app.
49
+ Rea.stopMapper(this.mapperId);
50
+ this.mapperId = null;
51
+ }
52
+ }
53
+
43
54
  redraw() {
44
55
  if (this.mapperId !== null) {
45
56
  Rea.stopMapper(this.mapperId);
57
+ this.mapperId = null;
46
58
  }
47
59
  if (this.unmounted) {
48
60
  return;
@@ -6,29 +6,45 @@ import type { SkiaPictureViewHandle } from "../views/SkiaPictureView.web";
6
6
  export type ISkiaViewApiWeb = ISkiaViewApi & {
7
7
  views: Record<string, SkiaPictureViewHandle>;
8
8
  deferedPictures: Record<string, SkPicture>;
9
+ unregisteredViews: Set<string>;
9
10
  registerView(nativeId: string, view: SkiaPictureViewHandle): void;
11
+ unregisterView(nativeId: string): void;
10
12
  };
11
13
 
12
14
  global.SkiaViewApi = {
13
15
  views: {},
14
16
  deferedPictures: {},
17
+ unregisteredViews: new Set<string>(),
15
18
  deferedOnSize: {},
16
19
  web: true,
17
20
  registerView(nativeId: string, view: SkiaPictureViewHandle) {
21
+ this.unregisteredViews.delete(nativeId);
18
22
  // Maybe a picture for this view was already set
19
23
  if (this.deferedPictures[nativeId]) {
20
24
  view.setPicture(this.deferedPictures[nativeId] as SkPicture);
25
+ delete this.deferedPictures[nativeId];
21
26
  }
22
27
  this.views[nativeId] = view;
23
28
  },
29
+ unregisterView(nativeId: string) {
30
+ // Views must be removed on unmount: the handle's closures capture the
31
+ // canvas element, so a stale entry retains the whole detached DOM tree.
32
+ this.unregisteredViews.add(nativeId);
33
+ delete this.views[nativeId];
34
+ delete this.deferedPictures[nativeId];
35
+ },
24
36
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
37
  setJsiProperty(nativeId: number, name: string, value: any) {
26
38
  if (name === "picture") {
27
- if (!this.views[`${nativeId}`]) {
28
- this.deferedPictures[`${nativeId}`] = value;
29
- } else {
30
- this.views[`${nativeId}`].setPicture(value);
39
+ const id = `${nativeId}`;
40
+ if (this.views[id]) {
41
+ this.views[id].setPicture(value);
42
+ } else if (!this.unregisteredViews.has(id)) {
43
+ this.deferedPictures[id] = value;
31
44
  }
45
+ // Otherwise the view has unmounted (e.g. a trailing animation frame):
46
+ // drop the picture instead of deferring it for an id that will never
47
+ // register again, which would retain it forever.
32
48
  }
33
49
  },
34
50
  size(nativeId: number) {
@@ -39,14 +55,30 @@ global.SkiaViewApi = {
39
55
  }
40
56
  },
41
57
  requestRedraw(nativeId: number) {
42
- this.views[`${nativeId}`].redraw();
58
+ // The view may already have unmounted (e.g. a trailing animation frame).
59
+ this.views[`${nativeId}`]?.redraw();
43
60
  },
44
61
  makeImageSnapshot(nativeId: number, rect?: SkRect) {
45
- return this.views[`${nativeId}`].makeImageSnapshot(rect);
62
+ const view = this.views[`${nativeId}`];
63
+ if (!view) {
64
+ throw new Error(
65
+ `Cannot make image snapshot: view with nativeID ${nativeId} is not registered (it may have unmounted)`
66
+ );
67
+ }
68
+ return view.makeImageSnapshot(rect);
46
69
  },
47
70
  makeImageSnapshotAsync(nativeId: number, rect?: SkRect) {
48
71
  return new Promise((resolve, reject) => {
49
- const result = this.views[`${nativeId}`].makeImageSnapshot(rect);
72
+ const view = this.views[`${nativeId}`];
73
+ if (!view) {
74
+ reject(
75
+ new Error(
76
+ `Cannot make image snapshot: view with nativeID ${nativeId} is not registered (it may have unmounted)`
77
+ )
78
+ );
79
+ return;
80
+ }
81
+ const result = view.makeImageSnapshot(rect);
50
82
  if (result) {
51
83
  resolve(result);
52
84
  } else {
@@ -7,6 +7,7 @@ export interface NativeProps extends ViewProps {
7
7
  debug?: boolean;
8
8
  opaque?: boolean;
9
9
  colorSpace?: string;
10
+ highBitDepth?: boolean;
10
11
  androidWarmup?: boolean;
11
12
  pointerEvents?: WithDefault<
12
13
  "auto" | "none" | "box-none" | "box-only",
@@ -87,6 +87,7 @@ export class SkiaPictureView extends React.Component<SkiaPictureViewProps> {
87
87
  mode,
88
88
  debug = false,
89
89
  opaque = false,
90
+ highBitDepth = false,
90
91
  androidWarmup = false,
91
92
  ...viewProps
92
93
  } = this.props;
@@ -96,6 +97,7 @@ export class SkiaPictureView extends React.Component<SkiaPictureViewProps> {
96
97
  nativeID={`${this._nativeId}`}
97
98
  debug={debug}
98
99
  opaque={opaque}
100
+ highBitDepth={highBitDepth}
99
101
  androidWarmup={androidWarmup}
100
102
  {...viewProps}
101
103
  />