From 0b0704755d6888f8bc8b2fe5bbc76d3217727eb3 Mon Sep 17 00:00:00 2001 From: Mackenzie Salisbury Date: Tue, 16 Dec 2025 16:02:11 +0800 Subject: [PATCH 1/7] WIP: Support in for saveLayerFlags e.g. SaveLayerInitWithPrevious --- packages/skia/cpp/api/recorder/JsiRecorder.h | 2 +- packages/skia/cpp/api/recorder/Paint.h | 45 ++++++++++++++++--- packages/skia/cpp/api/recorder/RNRecorder.h | 10 ++--- packages/skia/src/dom/types/Common.ts | 7 ++- .../skia/src/renderer/components/Group.tsx | 17 +++++-- packages/skia/src/skia/types/Recorder.ts | 3 +- packages/skia/src/sksg/Elements.tsx | 3 +- packages/skia/src/sksg/Recorder/Core.ts | 2 + .../src/sksg/Recorder/ReanimatedRecorder.ts | 5 ++- packages/skia/src/sksg/Recorder/Recorder.ts | 5 ++- packages/skia/src/sksg/Recorder/Visitor.ts | 2 +- .../skia/src/sksg/Recorder/commands/CTM.ts | 10 ++--- 12 files changed, 81 insertions(+), 30 deletions(-) diff --git a/packages/skia/cpp/api/recorder/JsiRecorder.h b/packages/skia/cpp/api/recorder/JsiRecorder.h index 46ca09ecd0..76ad19b2c5 100644 --- a/packages/skia/cpp/api/recorder/JsiRecorder.h +++ b/packages/skia/cpp/api/recorder/JsiRecorder.h @@ -184,7 +184,7 @@ class JsiRecorder : public JsiSkWrappingSharedPtrHostObject { } JSI_HOST_FUNCTION(saveLayer) { - getObject()->saveLayer(); + getObject()->saveLayer(runtime, arguments[0].asObject(runtime)); return jsi::Value::undefined(); } diff --git a/packages/skia/cpp/api/recorder/Paint.h b/packages/skia/cpp/api/recorder/Paint.h index 160eff6458..093e6eeaf5 100644 --- a/packages/skia/cpp/api/recorder/Paint.h +++ b/packages/skia/cpp/api/recorder/Paint.h @@ -8,6 +8,8 @@ #include "Convertor.h" #include "DrawingCtx.h" +#include "include/core/SkCanvas.h" + namespace RNSkia { struct TransformProps { @@ -38,7 +40,35 @@ SkMatrix processTransform(std::optional &matrix, return m3; } -struct CTMCmdProps : TransformProps { +struct SaveLayerProps { + std::optional saveLayerFlags; +} + +class SaveLayerCmd : public Command { +private: + SaveLayerProps props; + +public: + SaveLayerCmd(jsi::Runtime &runtime, const jsi::Object &object, + Variables &variables) + : Command(CommandType::SaveLayer) { + convertProperty(runtime, object, "saveLayerFlags", props.saveLayerFlags, + variables); + } + + void saveLayer(DrawingCtx *ctx) { + ctx->materializePaint(); + auto paint = ctx->paintDeclarations.back(); + ctx->paintDeclarations.pop_back(); + + SkCanvas::SaveLayerRec layerRec(nullptr, &paint, nullptr, + props.saveLayerFlags.value_or(0)); + ctx->canvas->saveLayer(layerRec); + } +} + +struct CTMCmdProps : TransformProps, + SaveLayerProps { std::optional clip; std::optional invertClip; std::optional layer; @@ -58,12 +88,15 @@ class SaveCTMCmd : public Command { convertProperty(runtime, object, "clip", props.clip, variables); convertProperty(runtime, object, "invertClip", props.invertClip, variables); convertProperty(runtime, object, "layer", props.layer, variables); + convertProperty(runtime, object, "saveLayerFlags", props.saveLayerFlags, + variables); } void saveCTM(DrawingCtx *ctx) { auto clip = props.clip; auto invertClip = props.invertClip; auto layer = props.layer; + auto saveLayerFlags = props.saveLayerFlags; auto hasTransform = props.matrix.has_value() || props.transform.has_value(); auto hasClip = clip.has_value(); auto op = invertClip.has_value() && invertClip.value() @@ -73,12 +106,12 @@ class SaveCTMCmd : public Command { SkMatrix m3 = processTransform(props.matrix, props.transform, props.origin); if (shouldSave) { if (layer.has_value()) { - if (std::holds_alternative(layer.value())) { - ctx->canvas->saveLayer(nullptr, nullptr); - } else { - auto paint = std::get(layer.value()); - ctx->canvas->saveLayer(nullptr, &paint); + SkCanvas::SaveLayerRec layerRec; + layerRec.fPaint = std::get_if(layer.value()); + if (saveLayerFlags.has_value()) { + layerRec.fSaveLayerFlags = saveLayerFlags.value(); } + ctx->canvas->saveLayer(layerRec); } else { ctx->canvas->save(); } diff --git a/packages/skia/cpp/api/recorder/RNRecorder.h b/packages/skia/cpp/api/recorder/RNRecorder.h index d96331f088..28d5692223 100644 --- a/packages/skia/cpp/api/recorder/RNRecorder.h +++ b/packages/skia/cpp/api/recorder/RNRecorder.h @@ -355,8 +355,8 @@ class Recorder { std::make_unique(CommandType::RestorePaintDeclaration)); } - void saveLayer() { - pushCommand(std::make_unique(CommandType::SaveLayer)); + void saveLayer(jsi::Runtime &runtime, const jsi::Object &props) { + pushCommand(std::make_unique(runtime, props, variables)); } void saveBackdropFilter() { @@ -418,10 +418,8 @@ inline void Recorder::playCommand(DrawingCtx *ctx, Command *cmd) { break; } case CommandType::SaveLayer: { - ctx->materializePaint(); - auto paint = ctx->paintDeclarations.back(); - ctx->paintDeclarations.pop_back(); - ctx->canvas->saveLayer(SkCanvas::SaveLayerRec(nullptr, &paint, nullptr, 0)); + auto *saveCTMCmd = static_cast(cmd); + saveCTMCmd->saveCTM(ctx); break; } case CommandType::MaterializePaint: { diff --git a/packages/skia/src/dom/types/Common.ts b/packages/skia/src/dom/types/Common.ts index feb53adde5..b138c6c739 100644 --- a/packages/skia/src/dom/types/Common.ts +++ b/packages/skia/src/dom/types/Common.ts @@ -6,6 +6,7 @@ import type { InputMatrix, InputRRect, PaintStyle, + SaveLayerFlag, SkPaint, SkPath, SkRect, @@ -70,7 +71,11 @@ export interface TransformProps { matrix?: InputMatrix; } -export interface CTMProps extends TransformProps { +export interface SaveLayerProps { + saveLayerFlags?: SaveLayerFlag; +} + +export interface CTMProps extends TransformProps, SaveLayerProps { clip?: ClipDef; invertClip?: boolean; layer?: SkPaint | boolean; diff --git a/packages/skia/src/renderer/components/Group.tsx b/packages/skia/src/renderer/components/Group.tsx index 0461ede111..99d7d94b88 100644 --- a/packages/skia/src/renderer/components/Group.tsx +++ b/packages/skia/src/renderer/components/Group.tsx @@ -8,14 +8,25 @@ export interface PublicGroupProps extends Omit { layer?: GroupProps["layer"] | ChildrenProps["children"]; } -export const Group = ({ layer, ...props }: SkiaProps) => { +export const Group = ({ + layer, + saveLayerFlags, + ...props +}: SkiaProps) => { if (isValidElement(layer) && typeof layer === "object") { return ( - + // keep the saveLayerFlags on whichever node triggers saveLayer + {layer} ); } - return ; + return ( + + ); }; diff --git a/packages/skia/src/skia/types/Recorder.ts b/packages/skia/src/skia/types/Recorder.ts index 008814e3ef..4fb74ce56f 100644 --- a/packages/skia/src/skia/types/Recorder.ts +++ b/packages/skia/src/skia/types/Recorder.ts @@ -28,6 +28,7 @@ import type { VerticesProps, SkottieProps, DrawingNodeProps, + SaveLayerProps, } from "../../dom/types"; import type { AnimatedProps } from "../../renderer/processors/Animations/Animations"; @@ -61,7 +62,7 @@ export interface BaseRecorder { saveCTM(props: AnimatedProps): void; restoreCTM(): void; drawPaint(): void; - saveLayer(): void; + saveLayer(props: AnimatedProps): void; saveBackdropFilter(): void; drawBox( boxProps: AnimatedProps, diff --git a/packages/skia/src/sksg/Elements.tsx b/packages/skia/src/sksg/Elements.tsx index dd598e41cc..1d3a8d9e29 100644 --- a/packages/skia/src/sksg/Elements.tsx +++ b/packages/skia/src/sksg/Elements.tsx @@ -53,6 +53,7 @@ import type { BlendProps, SkottieProps, ImageFilterProps, + SaveLayerProps, } from "../dom/types"; import type { SkiaProps } from "../renderer"; @@ -60,7 +61,7 @@ declare module "react" { namespace JSX { interface IntrinsicElements { skGroup: SkiaProps; - skLayer: SkiaProps; + skLayer: SkiaProps; skPaint: SkiaProps; // Drawings diff --git a/packages/skia/src/sksg/Recorder/Core.ts b/packages/skia/src/sksg/Recorder/Core.ts index da0106467a..621af20c80 100644 --- a/packages/skia/src/sksg/Recorder/Core.ts +++ b/packages/skia/src/sksg/Recorder/Core.ts @@ -22,6 +22,7 @@ import type { AtlasProps, DrawingNodeProps, SkottieProps, + SaveLayerProps, } from "../../dom/types"; export enum CommandType { @@ -107,6 +108,7 @@ interface Props { [CommandType.DrawImage]: ImageProps; [CommandType.DrawCircle]: CircleProps; [CommandType.SaveCTM]: CTMProps; + [CommandType.SaveLayer]: SaveLayerProps; [CommandType.SavePaint]: DrawingNodeProps; [CommandType.PushBlurMaskFilter]: BlurMaskFilterProps; [CommandType.DrawPoints]: PointsProps; diff --git a/packages/skia/src/sksg/Recorder/ReanimatedRecorder.ts b/packages/skia/src/sksg/Recorder/ReanimatedRecorder.ts index c18d5e272a..cd9a635974 100644 --- a/packages/skia/src/sksg/Recorder/ReanimatedRecorder.ts +++ b/packages/skia/src/sksg/Recorder/ReanimatedRecorder.ts @@ -29,6 +29,7 @@ import type { AtlasProps, SkottieProps, DrawingNodeProps, + SaveLayerProps, } from "../../dom/types"; import type { AnimatedProps } from "../../renderer"; import { isSharedValue } from "../utils"; @@ -165,8 +166,8 @@ export class ReanimatedRecorder implements BaseRecorder { this.recorder.drawPaint(); } - saveLayer(): void { - this.recorder.saveLayer(); + saveLayer(props: AnimatedProps): void { + this.recorder.saveLayer(props); } saveBackdropFilter(): void { diff --git a/packages/skia/src/sksg/Recorder/Recorder.ts b/packages/skia/src/sksg/Recorder/Recorder.ts index 1a0b548791..c68861c2dc 100644 --- a/packages/skia/src/sksg/Recorder/Recorder.ts +++ b/packages/skia/src/sksg/Recorder/Recorder.ts @@ -28,6 +28,7 @@ import type { BoxShadowProps, SkottieProps, DrawingNodeProps, + SaveLayerProps, } from "../../dom/types"; import type { AnimatedProps } from "../../renderer"; import { isSharedValue } from "../utils"; @@ -196,8 +197,8 @@ export class Recorder implements BaseRecorder { this.add({ type: CommandType.DrawPaint }); } - saveLayer() { - this.add({ type: CommandType.SaveLayer }); + saveLayer(props: AnimatedProps) { + this.add({ type: CommandType.SaveLayer, props }); } saveBackdropFilter() { diff --git a/packages/skia/src/sksg/Recorder/Visitor.ts b/packages/skia/src/sksg/Recorder/Visitor.ts index 2842b4b388..ec427f9540 100644 --- a/packages/skia/src/sksg/Recorder/Visitor.ts +++ b/packages/skia/src/sksg/Recorder/Visitor.ts @@ -252,7 +252,7 @@ const visitNode = (recorder: BaseRecorder, node: Node) => { } pushPaints(recorder, paints); if (node.type === NodeType.Layer) { - recorder.saveLayer(); + recorder.saveLayer(node.props); } const ctm = processCTM(props); const shouldRestore = !!ctm || node.type === NodeType.Layer; diff --git a/packages/skia/src/sksg/Recorder/commands/CTM.ts b/packages/skia/src/sksg/Recorder/commands/CTM.ts index f16b55cdf5..1f12602c4f 100644 --- a/packages/skia/src/sksg/Recorder/commands/CTM.ts +++ b/packages/skia/src/sksg/Recorder/commands/CTM.ts @@ -39,7 +39,8 @@ export const saveCTM = (ctx: DrawingContext, props: CTMProps) => { transform, origin, layer, - } = props as CTMProps; + saveLayerFlags, + } = props; const hasTransform = matrix !== undefined || transform !== undefined; const clip = computeClip(Skia, rawClip); const hasClip = clip !== undefined; @@ -48,11 +49,8 @@ export const saveCTM = (ctx: DrawingContext, props: CTMProps) => { const shouldSave = hasTransform || hasClip || !!layer; if (shouldSave) { if (layer) { - if (typeof layer === "boolean") { - canvas.saveLayer(); - } else { - canvas.saveLayer(layer); - } + const paint = typeof layer === "boolean" ? undefined : layer; + canvas.saveLayer(paint, null, null, saveLayerFlags); } else { canvas.save(); } From 9ed6d93051dd24440ca1ca81401bdc6e9f59329d Mon Sep 17 00:00:00 2001 From: Mackenzie Salisbury Date: Fri, 19 Dec 2025 02:46:11 +0800 Subject: [PATCH 2/7] Add tests to show bloom implemented with saveLayer --- apps/docs/static/img/group/bloom.png | Bin 0 -> 44393 bytes apps/docs/static/img/group/bloom2.png | Bin 0 -> 32414 bytes .../src/renderer/__tests__/e2e/Group.spec.tsx | 76 ++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 apps/docs/static/img/group/bloom.png create mode 100644 apps/docs/static/img/group/bloom2.png diff --git a/apps/docs/static/img/group/bloom.png b/apps/docs/static/img/group/bloom.png new file mode 100644 index 0000000000000000000000000000000000000000..fac734545f150f6030a265c3dadef2b65995f6da GIT binary patch literal 44393 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 aprCx;X*iJT=mUPN0F9@*PfAp*-u(}Y4@O=9 literal 0 HcmV?d00001 diff --git a/packages/skia/src/renderer/__tests__/e2e/Group.spec.tsx b/packages/skia/src/renderer/__tests__/e2e/Group.spec.tsx index b12518a6ac..540ba72f30 100644 --- a/packages/skia/src/renderer/__tests__/e2e/Group.spec.tsx +++ b/packages/skia/src/renderer/__tests__/e2e/Group.spec.tsx @@ -125,4 +125,80 @@ describe("Group", () => { ); checkImage(img, docPath("group/scale-path.png")); }); + it("Copies a layer and adds new content to it", async () => { + const { width, height } = surface; + const centreY = height / 2; + const { BlendMode, TileMode, SaveLayerFlag, ClipOp, rect } = importSkia(); + const img = await surface.drawOffscreen( + (Skia, canvas, _ctx) => { + canvas.clear(Skia.Color("black")); + + const bluePaint = Skia.Paint(); + bluePaint.setColor(Skia.Color([0, 0, 0.6, 1])); + canvas.drawRect( + { x: 0, y: centreY - 0.1 * height, width, height: 0.2 * height }, + bluePaint + ); + + const redPaint = Skia.Paint(); + redPaint.setColor(Skia.Color([0.8, 0, 0, 1])); + canvas.drawCircle(0.25 * width, centreY, 0.2 * width, redPaint); + + const layerRestorePaint = Skia.Paint(); + layerRestorePaint.setBlendMode(BlendMode.Screen); + layerRestorePaint.setImageFilter( + Skia.ImageFilter.MakeBlur(width * 0.05, width * 0.05, TileMode.Decal) + ); + // show the difference between top and bottom halves + canvas.clipRect(rect(0, 0, width, centreY), ClipOp.Intersect, false); + canvas.saveLayer( + layerRestorePaint, + null, + null, + SaveLayerFlag.SaveLayerInitWithPrevious + ); + canvas.drawCircle(0.75 * width, centreY, 0.2 * width, redPaint); + canvas.restore(); + }, + { width: surface.width } + ); + checkImage(img, docPath("group/bloom.png")); + }); + it("Copies a layer through a backdrop filter and adds new content to it", async () => { + const { width, height } = surface; + const centreY = height / 2; + const { BlendMode, TileMode, SaveLayerFlag, ClipOp, rect } = importSkia(); + const img = await surface.drawOffscreen( + (Skia, canvas, _ctx) => { + canvas.clear(Skia.Color("black")); + + const bluePaint = Skia.Paint(); + bluePaint.setColor(Skia.Color([0, 0, 0.6, 1])); + canvas.drawRect( + { x: 0, y: centreY - 0.1 * height, width, height: 0.2 * height }, + bluePaint + ); + + const redPaint = Skia.Paint(); + redPaint.setColor(Skia.Color([0.8, 0, 0, 1])); + canvas.drawCircle(0.25 * width, centreY, 0.2 * width, redPaint); + + const layerRestorePaint = Skia.Paint(); + layerRestorePaint.setBlendMode(BlendMode.Screen); + + // show the difference between top and bottom halves + canvas.clipRect(rect(0, 0, width, centreY), ClipOp.Intersect, false); + canvas.saveLayer( + layerRestorePaint, + null, + Skia.ImageFilter.MakeBlur(width * 0.05, width * 0.05, TileMode.Decal), + SaveLayerFlag.SaveLayerInitWithPrevious + ); + canvas.drawCircle(0.75 * width, centreY, 0.2 * width, redPaint); + canvas.restore(); + }, + { width: surface.width } + ); + checkImage(img, docPath("group/bloom2.png")); + }); }); From 9741173a4078689f90a5e880d0039c75dc829ff3 Mon Sep 17 00:00:00 2001 From: Mackenzie Salisbury Date: Tue, 23 Dec 2025 16:32:09 +0800 Subject: [PATCH 3/7] Add missing handling of saveLayerFlags in Player.ts --- packages/skia/src/sksg/Recorder/Player.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/skia/src/sksg/Recorder/Player.ts b/packages/skia/src/sksg/Recorder/Player.ts index 698e5ead2e..95efbb00f3 100644 --- a/packages/skia/src/sksg/Recorder/Player.ts +++ b/packages/skia/src/sksg/Recorder/Player.ts @@ -117,10 +117,10 @@ const play = (ctx: DrawingContext, _command: Command) => { const command = materializeCommand(_command); if (isCommand(command, CommandType.SaveBackdropFilter)) { ctx.saveBackdropFilter(); - } else if (isCommand(command, CommandType.SaveLayer)) { + } else if (isDrawCommand(command, CommandType.SaveLayer)) { ctx.materializePaint(); const paint = ctx.paintDeclarations.pop(); - ctx.canvas.saveLayer(paint); + ctx.canvas.saveLayer(paint, null, null, command.props.saveLayerFlags); } else if (isDrawCommand(command, CommandType.SavePaint)) { if (command.props.paint) { ctx.paints.push(command.props.paint); From 5263be90e44abe6c9f98eb0c2e30ab4eb9aadbec Mon Sep 17 00:00:00 2001 From: Mackenzie Salisbury Date: Tue, 23 Dec 2025 16:59:33 +0800 Subject: [PATCH 4/7] Remove redundant savelayerflag from test --- packages/skia/src/renderer/__tests__/e2e/Group.spec.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/skia/src/renderer/__tests__/e2e/Group.spec.tsx b/packages/skia/src/renderer/__tests__/e2e/Group.spec.tsx index 540ba72f30..79c4ce4136 100644 --- a/packages/skia/src/renderer/__tests__/e2e/Group.spec.tsx +++ b/packages/skia/src/renderer/__tests__/e2e/Group.spec.tsx @@ -167,7 +167,7 @@ describe("Group", () => { it("Copies a layer through a backdrop filter and adds new content to it", async () => { const { width, height } = surface; const centreY = height / 2; - const { BlendMode, TileMode, SaveLayerFlag, ClipOp, rect } = importSkia(); + const { BlendMode, TileMode, ClipOp, rect } = importSkia(); const img = await surface.drawOffscreen( (Skia, canvas, _ctx) => { canvas.clear(Skia.Color("black")); @@ -191,8 +191,7 @@ describe("Group", () => { canvas.saveLayer( layerRestorePaint, null, - Skia.ImageFilter.MakeBlur(width * 0.05, width * 0.05, TileMode.Decal), - SaveLayerFlag.SaveLayerInitWithPrevious + Skia.ImageFilter.MakeBlur(width * 0.05, width * 0.05, TileMode.Decal) ); canvas.drawCircle(0.75 * width, centreY, 0.2 * width, redPaint); canvas.restore(); From 399d86ba9bab5f4f294d9285c668f02ecae98d02 Mon Sep 17 00:00:00 2001 From: Mackenzie Salisbury Date: Tue, 23 Dec 2025 17:01:11 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=F0=9F=A7=AA=20convert=20new=20group=20test?= =?UTF-8?q?s=20to=20declarative;=20savelayer=20is=20passing,=20backdrop=20?= =?UTF-8?q?filtering=20is=20not?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/skia/src/dom/types/Common.ts | 2 + .../src/renderer/__tests__/e2e/Group.spec.tsx | 96 ++++++++++++++++++- 2 files changed, 97 insertions(+), 1 deletion(-) diff --git a/packages/skia/src/dom/types/Common.ts b/packages/skia/src/dom/types/Common.ts index b138c6c739..6449c82621 100644 --- a/packages/skia/src/dom/types/Common.ts +++ b/packages/skia/src/dom/types/Common.ts @@ -7,6 +7,7 @@ import type { InputRRect, PaintStyle, SaveLayerFlag, + SkImageFilter, SkPaint, SkPath, SkRect, @@ -72,6 +73,7 @@ export interface TransformProps { } export interface SaveLayerProps { + backdropFilter?: SkImageFilter; saveLayerFlags?: SaveLayerFlag; } diff --git a/packages/skia/src/renderer/__tests__/e2e/Group.spec.tsx b/packages/skia/src/renderer/__tests__/e2e/Group.spec.tsx index 79c4ce4136..97fb13c417 100644 --- a/packages/skia/src/renderer/__tests__/e2e/Group.spec.tsx +++ b/packages/skia/src/renderer/__tests__/e2e/Group.spec.tsx @@ -1,7 +1,17 @@ import React from "react"; import { checkImage, docPath } from "../../../__tests__/setup"; -import { Image, Group, Fill, FitBox, Path } from "../../components"; +import { + Image, + Group, + Fill, + FitBox, + Path, + Rect, + Circle, + Paint, + Blur, +} from "../../components"; import { images, importSkia, PIXEL_RATIO, surface } from "../setup"; describe("Group", () => { @@ -164,6 +174,48 @@ describe("Group", () => { ); checkImage(img, docPath("group/bloom.png")); }); + it("Copies a layer and adds new content to it (decl)", async () => { + const { width, height } = surface; + const centreY = height / 2; + const { SaveLayerFlag, rect } = importSkia(); + const img = await surface.draw( + <> + + + + + + + + } + > + + + + + ); + + checkImage(img, docPath("group/bloom.png")); + }); it("Copies a layer through a backdrop filter and adds new content to it", async () => { const { width, height } = surface; const centreY = height / 2; @@ -200,4 +252,46 @@ describe("Group", () => { ); checkImage(img, docPath("group/bloom2.png")); }); + it("Copies a layer through a backdrop filter and adds new content to it (decl)", async () => { + const { width, height } = surface; + const centreY = height / 2; + const { TileMode, rect, Skia } = importSkia(); + const img = await surface.draw( + <> + + + + + } + backdropFilter={Skia.ImageFilter.MakeBlur( + width * 0.05, + width * 0.05, + TileMode.Decal + )} + > + + + + + ); + + checkImage(img, docPath("group/bloom2.png")); + }); }); From fc6edf3c0117abccc80385ce7febbdbb5bb32bd8 Mon Sep 17 00:00:00 2001 From: Mackenzie Salisbury Date: Tue, 23 Dec 2025 17:03:08 +0800 Subject: [PATCH 6/7] Implement Group backdropFilter prop Only supports SkImageFilter objects, not child nodes for now --- packages/skia/cpp/api/recorder/Paint.h | 6 +++++- packages/skia/src/renderer/components/Group.tsx | 4 +++- packages/skia/src/sksg/Recorder/Player.ts | 7 ++++++- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/skia/cpp/api/recorder/Paint.h b/packages/skia/cpp/api/recorder/Paint.h index 093e6eeaf5..7644618b93 100644 --- a/packages/skia/cpp/api/recorder/Paint.h +++ b/packages/skia/cpp/api/recorder/Paint.h @@ -42,6 +42,7 @@ SkMatrix processTransform(std::optional &matrix, struct SaveLayerProps { std::optional saveLayerFlags; + std::optional> backdropFilter; } class SaveLayerCmd : public Command { @@ -54,6 +55,8 @@ class SaveLayerCmd : public Command { : Command(CommandType::SaveLayer) { convertProperty(runtime, object, "saveLayerFlags", props.saveLayerFlags, variables); + convertProperty(runtime, object, "backdropFilter", props.backdropFilter, + variables); } void saveLayer(DrawingCtx *ctx) { @@ -61,7 +64,8 @@ class SaveLayerCmd : public Command { auto paint = ctx->paintDeclarations.back(); ctx->paintDeclarations.pop_back(); - SkCanvas::SaveLayerRec layerRec(nullptr, &paint, nullptr, + SkCanvas::SaveLayerRec layerRec(nullptr, &paint, + props.backdropFilter.value_or(nullptr), props.saveLayerFlags.value_or(0)); ctx->canvas->saveLayer(layerRec); } diff --git a/packages/skia/src/renderer/components/Group.tsx b/packages/skia/src/renderer/components/Group.tsx index 99d7d94b88..8d67ae651c 100644 --- a/packages/skia/src/renderer/components/Group.tsx +++ b/packages/skia/src/renderer/components/Group.tsx @@ -10,13 +10,14 @@ export interface PublicGroupProps extends Omit { export const Group = ({ layer, + backdropFilter, saveLayerFlags, ...props }: SkiaProps) => { if (isValidElement(layer) && typeof layer === "object") { return ( // keep the saveLayerFlags on whichever node triggers saveLayer - + {layer} @@ -25,6 +26,7 @@ export const Group = ({ return ( diff --git a/packages/skia/src/sksg/Recorder/Player.ts b/packages/skia/src/sksg/Recorder/Player.ts index 95efbb00f3..0d2fa2863a 100644 --- a/packages/skia/src/sksg/Recorder/Player.ts +++ b/packages/skia/src/sksg/Recorder/Player.ts @@ -120,7 +120,12 @@ const play = (ctx: DrawingContext, _command: Command) => { } else if (isDrawCommand(command, CommandType.SaveLayer)) { ctx.materializePaint(); const paint = ctx.paintDeclarations.pop(); - ctx.canvas.saveLayer(paint, null, null, command.props.saveLayerFlags); + ctx.canvas.saveLayer( + paint, + null, + command.props.backdropFilter, + command.props.saveLayerFlags + ); } else if (isDrawCommand(command, CommandType.SavePaint)) { if (command.props.paint) { ctx.paints.push(command.props.paint); From e4be3c12465604cee83a643e1920e487883a3bd7 Mon Sep 17 00:00:00 2001 From: Mackenzie Salisbury Date: Tue, 23 Dec 2025 17:28:44 +0800 Subject: [PATCH 7/7] Add missing backdrop handling in CTM cmd; more consistent ordering of savelayer props for readability --- packages/skia/cpp/api/recorder/Paint.h | 15 +++++++++------ packages/skia/src/renderer/components/Group.tsx | 2 +- packages/skia/src/sksg/Recorder/commands/CTM.ts | 3 ++- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/skia/cpp/api/recorder/Paint.h b/packages/skia/cpp/api/recorder/Paint.h index 7644618b93..88b4f8c9e3 100644 --- a/packages/skia/cpp/api/recorder/Paint.h +++ b/packages/skia/cpp/api/recorder/Paint.h @@ -41,8 +41,8 @@ SkMatrix processTransform(std::optional &matrix, } struct SaveLayerProps { - std::optional saveLayerFlags; std::optional> backdropFilter; + std::optional saveLayerFlags; } class SaveLayerCmd : public Command { @@ -53,10 +53,10 @@ class SaveLayerCmd : public Command { SaveLayerCmd(jsi::Runtime &runtime, const jsi::Object &object, Variables &variables) : Command(CommandType::SaveLayer) { - convertProperty(runtime, object, "saveLayerFlags", props.saveLayerFlags, - variables); convertProperty(runtime, object, "backdropFilter", props.backdropFilter, variables); + convertProperty(runtime, object, "saveLayerFlags", props.saveLayerFlags, + variables); } void saveLayer(DrawingCtx *ctx) { @@ -92,6 +92,8 @@ class SaveCTMCmd : public Command { convertProperty(runtime, object, "clip", props.clip, variables); convertProperty(runtime, object, "invertClip", props.invertClip, variables); convertProperty(runtime, object, "layer", props.layer, variables); + convertProperty(runtime, object, "backdropFilter", props.backdropFilter, + variables); convertProperty(runtime, object, "saveLayerFlags", props.saveLayerFlags, variables); } @@ -100,6 +102,7 @@ class SaveCTMCmd : public Command { auto clip = props.clip; auto invertClip = props.invertClip; auto layer = props.layer; + auto backdropFilter = props.backdropFilter; auto saveLayerFlags = props.saveLayerFlags; auto hasTransform = props.matrix.has_value() || props.transform.has_value(); auto hasClip = clip.has_value(); @@ -112,9 +115,9 @@ class SaveCTMCmd : public Command { if (layer.has_value()) { SkCanvas::SaveLayerRec layerRec; layerRec.fPaint = std::get_if(layer.value()); - if (saveLayerFlags.has_value()) { - layerRec.fSaveLayerFlags = saveLayerFlags.value(); - } + layerRec.fBackdropFilter = backdropFilter.value_or(nullptr); + layerRec.fSaveLayerFlags = saveLayerFlags.value_or(0); + ctx->canvas->saveLayer(layerRec); } else { ctx->canvas->save(); diff --git a/packages/skia/src/renderer/components/Group.tsx b/packages/skia/src/renderer/components/Group.tsx index 8d67ae651c..ec97842fa8 100644 --- a/packages/skia/src/renderer/components/Group.tsx +++ b/packages/skia/src/renderer/components/Group.tsx @@ -17,7 +17,7 @@ export const Group = ({ if (isValidElement(layer) && typeof layer === "object") { return ( // keep the saveLayerFlags on whichever node triggers saveLayer - + {layer} diff --git a/packages/skia/src/sksg/Recorder/commands/CTM.ts b/packages/skia/src/sksg/Recorder/commands/CTM.ts index 1f12602c4f..73c1327884 100644 --- a/packages/skia/src/sksg/Recorder/commands/CTM.ts +++ b/packages/skia/src/sksg/Recorder/commands/CTM.ts @@ -39,6 +39,7 @@ export const saveCTM = (ctx: DrawingContext, props: CTMProps) => { transform, origin, layer, + backdropFilter, saveLayerFlags, } = props; const hasTransform = matrix !== undefined || transform !== undefined; @@ -50,7 +51,7 @@ export const saveCTM = (ctx: DrawingContext, props: CTMProps) => { if (shouldSave) { if (layer) { const paint = typeof layer === "boolean" ? undefined : layer; - canvas.saveLayer(paint, null, null, saveLayerFlags); + canvas.saveLayer(paint, null, backdropFilter, saveLayerFlags); } else { canvas.save(); }