@shopify/react-native-skia
Version:
High-performance React Native Graphics using Skia
297 lines (249 loc) • 7.25 kB
text/typescript
import type { SharedValue } from "react-native-reanimated";
import type { BaseRecorder, JsiRecorder, Skia } from "../../skia/types";
import type {
PaintProps,
NodeType,
BlurMaskFilterProps,
CTMProps,
BoxProps,
BoxShadowProps,
ImageProps,
CircleProps,
PointsProps,
PathProps,
RectProps,
RoundedRectProps,
OvalProps,
LineProps,
PatchProps,
VerticesProps,
DiffRectProps,
TextProps,
TextPathProps,
TextBlobProps,
GlyphsProps,
PictureProps,
ImageSVGProps,
ParagraphProps,
AtlasProps,
SkottieProps,
DrawingNodeProps,
} from "../../dom/types";
import type { AnimatedProps } from "../../renderer";
import { isSharedValue } from "../utils";
/**
* Currently the recorder only work if the GPU resources (e.g Images) are owned by the main thread.
* It will crash otherwise on Ganesh (iOS/Android).
*/
export class ReanimatedRecorder implements BaseRecorder {
private values = new Set<SharedValue<unknown>>();
private recorder: JsiRecorder;
constructor(Skia: Skia) {
this.recorder = Skia.Recorder();
}
reset() {
this.values.clear();
this.recorder.reset();
}
private processAnimationValues(props?: Record<string, unknown>) {
if (!props) {
return;
}
Object.values(props).forEach((value) => {
if (isSharedValue(value) && !this.values.has(value)) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
value.name = `variable${this.values.size}`;
this.values.add(value as SharedValue<unknown>);
}
});
}
getRecorder() {
return this.recorder;
}
getSharedValues() {
return Array.from(this.values);
}
saveGroup(props?: AnimatedProps<Pick<DrawingNodeProps, "zIndex">>): void {
if (props) {
this.processAnimationValues(props);
this.recorder.saveGroup(props);
} else {
this.recorder.saveGroup();
}
}
restoreGroup(): void {
this.recorder.restoreGroup();
}
savePaint(props: AnimatedProps<PaintProps>, standalone: boolean): void {
this.processAnimationValues(props);
this.recorder.savePaint(props, standalone);
}
restorePaint(): void {
this.recorder.restorePaint();
}
restorePaintDeclaration(): void {
this.recorder.restorePaintDeclaration();
}
materializePaint(): void {
this.recorder.materializePaint();
}
pushPathEffect(
pathEffectType: NodeType,
props: AnimatedProps<unknown>
): void {
this.processAnimationValues(props);
this.recorder.pushPathEffect(pathEffectType, props);
}
pushImageFilter(
imageFilterType: NodeType,
props: AnimatedProps<unknown>
): void {
this.processAnimationValues(props);
this.recorder.pushImageFilter(imageFilterType, props);
}
pushColorFilter(
colorFilterType: NodeType,
props: AnimatedProps<unknown>
): void {
this.processAnimationValues(props);
this.recorder.pushColorFilter(colorFilterType, props);
}
pushShader(
shaderType: NodeType,
props: AnimatedProps<unknown>,
children: number
): void {
this.processAnimationValues(props);
this.recorder.pushShader(shaderType, props, children);
}
pushBlurMaskFilter(props: AnimatedProps<BlurMaskFilterProps>): void {
this.processAnimationValues(props);
this.recorder.pushBlurMaskFilter(props);
}
composePathEffect(): void {
this.recorder.composePathEffect();
}
composeColorFilter(): void {
this.recorder.composeColorFilter();
}
composeImageFilter(): void {
this.recorder.composeImageFilter();
}
saveCTM(props: AnimatedProps<CTMProps>): void {
this.processAnimationValues(props);
this.recorder.saveCTM(props);
}
restoreCTM(): void {
this.recorder.restoreCTM();
}
drawPaint(): void {
this.recorder.drawPaint();
}
saveLayer(): void {
this.recorder.saveLayer();
}
saveBackdropFilter(): void {
this.recorder.saveBackdropFilter();
}
drawBox(
boxProps: AnimatedProps<BoxProps>,
shadows: {
props: BoxShadowProps;
}[]
): void {
this.processAnimationValues(boxProps);
shadows.forEach((shadow) => {
this.processAnimationValues(
shadow.props as AnimatedProps<BoxShadowProps>
);
});
this.recorder.drawBox(
boxProps,
// TODO: Fix this type BaseRecorder.drawBox()
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
shadows.map((s) => s.props)
);
}
drawImage(props: AnimatedProps<ImageProps>): void {
this.processAnimationValues(props);
this.recorder.drawImage(props);
}
drawCircle(props: AnimatedProps<CircleProps>): void {
this.processAnimationValues(props);
this.recorder.drawCircle(props);
}
drawPoints(props: AnimatedProps<PointsProps>): void {
this.processAnimationValues(props);
this.recorder.drawPoints(props);
}
drawPath(props: AnimatedProps<PathProps>): void {
this.processAnimationValues(props);
this.recorder.drawPath(props);
}
drawRect(props: AnimatedProps<RectProps>): void {
this.processAnimationValues(props);
this.recorder.drawRect(props);
}
drawRRect(props: AnimatedProps<RoundedRectProps>): void {
this.processAnimationValues(props);
this.recorder.drawRRect(props);
}
drawOval(props: AnimatedProps<OvalProps>): void {
this.processAnimationValues(props);
this.recorder.drawOval(props);
}
drawLine(props: AnimatedProps<LineProps>): void {
this.processAnimationValues(props);
this.recorder.drawLine(props);
}
drawPatch(props: AnimatedProps<PatchProps>): void {
this.processAnimationValues(props);
this.recorder.drawPatch(props);
}
drawVertices(props: AnimatedProps<VerticesProps>): void {
this.processAnimationValues(props);
this.recorder.drawVertices(props);
}
drawDiffRect(props: AnimatedProps<DiffRectProps>): void {
this.processAnimationValues(props);
this.recorder.drawDiffRect(props);
}
drawText(props: AnimatedProps<TextProps>): void {
this.processAnimationValues(props);
this.recorder.drawText(props);
}
drawTextPath(props: AnimatedProps<TextPathProps>): void {
this.processAnimationValues(props);
this.recorder.drawTextPath(props);
}
drawTextBlob(props: AnimatedProps<TextBlobProps>): void {
this.processAnimationValues(props);
this.recorder.drawTextBlob(props);
}
drawGlyphs(props: AnimatedProps<GlyphsProps>): void {
this.processAnimationValues(props);
this.recorder.drawGlyphs(props);
}
drawPicture(props: AnimatedProps<PictureProps>): void {
this.processAnimationValues(props);
this.recorder.drawPicture(props);
}
drawImageSVG(props: AnimatedProps<ImageSVGProps>): void {
this.processAnimationValues(props);
this.recorder.drawImageSVG(props);
}
drawParagraph(props: AnimatedProps<ParagraphProps>): void {
this.processAnimationValues(props);
this.recorder.drawParagraph(props);
}
drawAtlas(props: AnimatedProps<AtlasProps>): void {
this.processAnimationValues(props);
this.recorder.drawAtlas(props);
}
drawSkottie(props: AnimatedProps<SkottieProps>): void {
this.processAnimationValues(props);
this.recorder.drawSkottie(props);
}
}