From defd7679cc2d7fb2088e20d6738e78afe2fc3a0d Mon Sep 17 00:00:00 2001 From: Vadivazhagan Vadivel <44602345+Grassper@users.noreply.github.com> Date: Thu, 6 Aug 2026 00:04:21 +0530 Subject: [PATCH 1/2] =?UTF-8?q?feat(=F0=9F=90=8E):=20drive=20multiple=20an?= =?UTF-8?q?imated=20props=20from=20a=20single=20shared=20value=20(select)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/docs/docs/animations/reanimated3.md | 36 +++ .../Reanimated/NullableGroupedValue.tsx | 51 +++++ .../Reanimated/SharedValueComparison.tsx | 208 ++++++++++++++++++ .../example/src/Examples/Reanimated/index.tsx | 4 + packages/skia/cpp/api/recorder/Convertor.h | 66 +++++- .../processors/Animations/Animations.ts | 35 ++- packages/skia/src/sksg/Recorder/Core.ts | 12 +- .../src/sksg/Recorder/ReanimatedRecorder.ts | 11 +- packages/skia/src/sksg/Recorder/Recorder.ts | 10 +- .../__tests__/SharedValueSelector.spec.ts | 107 +++++++++ packages/skia/src/sksg/utils.ts | 18 ++ 11 files changed, 543 insertions(+), 15 deletions(-) create mode 100644 apps/example/src/Examples/Reanimated/NullableGroupedValue.tsx create mode 100644 apps/example/src/Examples/Reanimated/SharedValueComparison.tsx create mode 100644 packages/skia/src/sksg/__tests__/SharedValueSelector.spec.ts diff --git a/apps/docs/docs/animations/reanimated3.md b/apps/docs/docs/animations/reanimated3.md index 5d2d7f6d91..9e34bb6a51 100644 --- a/apps/docs/docs/animations/reanimated3.md +++ b/apps/docs/docs/animations/reanimated3.md @@ -46,6 +46,42 @@ export const HelloWorld = () => { We offer some [Skia specific animation hooks](/docs/animations/hooks), especially for paths. +## Grouped values + +`select` lets a single shared value, whose value is an object, drive multiple props by binding each prop to one key of that object. + +```tsx +import { Canvas, Circle, select } from "@shopify/react-native-skia"; +import { useSharedValue, useFrameCallback } from "react-native-reanimated"; + +export const Grouped = () => { + // A single shared value holds every animated field. + const circle = useSharedValue({ cx: 0, cy: 0, r: 10 }); + useFrameCallback(({ timeSinceFirstFrame }) => { + "worklet"; + const t = timeSinceFirstFrame / 1000; + circle.value = { + cx: 100 + Math.cos(t) * 50, + cy: 100 + Math.sin(t) * 50, + r: 10 + (Math.sin(t * 2) + 1) * 5, + }; + }, true); + return ( + + + + ); +}; +``` +Here one shared value drives three props with a single subscription, instead of three derived values with three subscriptions. + +Reanimated only animates values assigned directly to a shared value's `.value`, not values nested inside an object. You therefore cannot place `withTiming`/`withSpring` on a key (e.g. `{ cx: withTiming(100) }`); assign plain values to the object (as above), or build the object in a `useDerivedValue` from individually animated shared values. + ## Colors For colors, React Native Skia uses a different storage format from Reanimated. diff --git a/apps/example/src/Examples/Reanimated/NullableGroupedValue.tsx b/apps/example/src/Examples/Reanimated/NullableGroupedValue.tsx new file mode 100644 index 0000000000..5b74a65d0e --- /dev/null +++ b/apps/example/src/Examples/Reanimated/NullableGroupedValue.tsx @@ -0,0 +1,51 @@ +import React from "react"; +import { StyleSheet } from "react-native"; +import { useFrameCallback, useSharedValue } from "react-native-reanimated"; +import { Canvas, Circle, Fill, select } from "@shopify/react-native-skia"; + +import { AnimationDemo } from "./Components"; + +interface CircleState { + cx: number; + cy: number; + r: number; +} + +export const NullableGroupedValue = () => { + const data = useSharedValue(null as unknown as CircleState); + + useFrameCallback(({ timeSinceFirstFrame }) => { + "worklet"; + if (timeSinceFirstFrame < 600) { + return; + } + const t = (timeSinceFirstFrame - 600) / 1000; + data.value = { + cx: 60 + Math.cos(t * 2) * 40, + cy: 60 + Math.sin(t * 2) * 30, + r: 20, + }; + }, true); + + return ( + + + + + + + ); +}; + +const styles = StyleSheet.create({ + canvas: { + height: 120, + width: "100%" as const, + backgroundColor: "#FEFEFE" as const, + }, +}); diff --git a/apps/example/src/Examples/Reanimated/SharedValueComparison.tsx b/apps/example/src/Examples/Reanimated/SharedValueComparison.tsx new file mode 100644 index 0000000000..483035beee --- /dev/null +++ b/apps/example/src/Examples/Reanimated/SharedValueComparison.tsx @@ -0,0 +1,208 @@ +import React, { useState } from "react"; +import { + Pressable, + StyleSheet, + Text, + View, + useWindowDimensions, +} from "react-native"; +import type { SharedValue } from "react-native-reanimated"; +import { + useDerivedValue, + useFrameCallback, + useSharedValue, +} from "react-native-reanimated"; +import { Canvas, Circle, Fill, select } from "@shopify/react-native-skia"; + +import { AnimationDemo } from "./Components"; + +// Demonstrates driving many animated props from a SINGLE shared value +// instead of one derived value per prop. Both modes render the exact same +// animation; only the wiring differs: +// +// • Grouped — one value holds every coordinate; each prop reads its own +// key from it. Reanimated subscribes once (1 mapper). +// • Per-prop — every prop gets its own derived value, so Reanimated +// subscribes once per prop (COUNT * 3 mappers). +// +// Grouping wins on: +// - performance fewer UI-thread mappers recomputing each frame +// - maintainability one source of truth per component, no hook-per-prop +// - locality a component's animated state lives in one value +const COUNT = 24; +const BASE_RADIUS = 6; +const CANVAS_HEIGHT = 280; +const COLORS = ["#8556E5", "#3EB489", "#FF7A1A", "#E5563F"]; + +// Motion of dot `i` at time `t`, shared by both approaches so the animation +// is visually identical — only the wiring underneath differs. +const dotX = (t: number, i: number, cx: number, orbit: number) => { + "worklet"; + const a = t + (i / COUNT) * Math.PI * 2; + const ring = 0.4 + 0.6 * ((i % 6) / 6); + return cx + Math.cos(a) * orbit * ring; +}; +const dotY = (t: number, i: number, cy: number, orbit: number) => { + "worklet"; + const a = t + (i / COUNT) * Math.PI * 2; + const ring = 0.4 + 0.6 * ((i % 6) / 6); + return cy + Math.sin(a) * orbit * ring; +}; +const dotR = (t: number, i: number) => { + "worklet"; + return BASE_RADIUS + (Math.sin(t * 2 + i) + 1) * 3; +}; + +interface SceneProps { + clock: SharedValue; + cx: number; + cy: number; + orbit: number; +} + +// "Separate prop" approach: every prop of every dot gets its own derived +// value, i.e. its own Reanimated mapper. COUNT * 3 mappers total. +const DerivedDot = ({ + clock, + i, + cx, + cy, + orbit, +}: SceneProps & { i: number }) => { + const x = useDerivedValue(() => dotX(clock.value, i, cx, orbit)); + const y = useDerivedValue(() => dotY(clock.value, i, cy, orbit)); + const r = useDerivedValue(() => dotR(clock.value, i)); + return ; +}; + +const DerivedScene = (props: SceneProps) => ( + <> + {new Array(COUNT).fill(0).map((_, i) => ( + + ))} + +); + +// "Single value" approach: ONE derived value computes every coordinate into +// an object, and each prop reads its own key from it. 1 mapper total. +const SingleValueScene = ({ clock, cx, cy, orbit }: SceneProps) => { + const data = useDerivedValue(() => { + const t = clock.value; + const obj: Record = {}; + for (let i = 0; i < COUNT; i++) { + obj[`x${i}`] = dotX(t, i, cx, orbit); + obj[`y${i}`] = dotY(t, i, cy, orbit); + obj[`r${i}`] = dotR(t, i); + } + return obj; + }); + return ( + <> + {new Array(COUNT).fill(0).map((_, i) => ( + + ))} + + ); +}; + +export const SharedValueComparison = () => { + const { width } = useWindowDimensions(); + const [single, setSingle] = useState(true); + + const clock = useSharedValue(0); + useFrameCallback(({ timeSinceFirstFrame }) => { + "worklet"; + clock.value = timeSinceFirstFrame / 1000; + }, true); + + const cx = width / 2; + const cy = CANVAS_HEIGHT / 2; + const orbit = Math.min(width, 360) / 2 - 24; + const mapperCount = single ? 1 : COUNT * 3; + + return ( + + + {`Same ${COUNT * 3}-prop animation, wired two ways. "Grouped" drives ` + + `every prop from one shared value; "Per-prop" gives each prop its ` + + `own derived value. Watch the Reanimated mapper count change.`} + + + setSingle(true)} + > + + Grouped + + + setSingle(false)} + > + + Per-prop + + + + + {`Reanimated mappers (animation subscriptions): ${mapperCount}`} + + + + {single ? ( + + ) : ( + + )} + + + ); +}; + +const styles = StyleSheet.create({ + subheading: { + color: "#444", + marginBottom: 12, + lineHeight: 18, + }, + row: { + flexDirection: "row", + marginBottom: 8, + }, + btn: { + flex: 1, + paddingVertical: 8, + borderRadius: 8, + borderWidth: 1, + borderColor: "#8556E5", + marginHorizontal: 4, + alignItems: "center", + }, + btnActive: { + backgroundColor: "#8556E5", + }, + btnText: { + color: "#8556E5", + fontWeight: "600", + }, + btnTextActive: { + color: "white", + }, + caption: { + color: "black", + marginBottom: 8, + fontVariant: ["tabular-nums"], + }, + canvas: { + height: CANVAS_HEIGHT, + width: "100%" as const, + backgroundColor: "#FEFEFE" as const, + }, +}); diff --git a/apps/example/src/Examples/Reanimated/index.tsx b/apps/example/src/Examples/Reanimated/index.tsx index ca9786bd07..35aea8553e 100644 --- a/apps/example/src/Examples/Reanimated/index.tsx +++ b/apps/example/src/Examples/Reanimated/index.tsx @@ -6,6 +6,8 @@ import { AnimateTextOnPath } from "./AnimateTextOnPath"; import { AnimationWithTouchHandler } from "./AnimationWithTouchHandler"; import { BokehExample } from "./BokehExample"; import { InterpolationWithEasing } from "./InterpolationWithEasing"; +import { NullableGroupedValue } from "./NullableGroupedValue"; +import { SharedValueComparison } from "./SharedValueComparison"; import { SimpleAnimation } from "./SimpleAnimation"; import { SpringBackTouchAnimation } from "./SpringBackTouch"; @@ -18,6 +20,8 @@ export const ReanimatedExample: React.FC = () => { + + ); }; diff --git a/packages/skia/cpp/api/recorder/Convertor.h b/packages/skia/cpp/api/recorder/Convertor.h index 6f15f3d904..f3c9e0c18a 100644 --- a/packages/skia/cpp/api/recorder/Convertor.h +++ b/packages/skia/cpp/api/recorder/Convertor.h @@ -69,7 +69,51 @@ template struct unwrap_optional> { template T getPropertyValue(jsi::Runtime &runtime, const jsi::Value &value); -// Base template for convertProperty +template +bool convertSelectorProperty(jsi::Runtime &runtime, const jsi::Value &prop, + Target &target, Variables &variables) { + if (!prop.isObject()) { + return false; + } + auto wrapper = prop.asObject(runtime); + if (!wrapper.hasProperty(runtime, "__sv") || + !wrapper.hasProperty(runtime, "__key")) { + return false; + } + auto svVal = wrapper.getProperty(runtime, "__sv"); + auto keyVal = wrapper.getProperty(runtime, "__key"); + if (!isSharedValue(runtime, svVal) || !keyVal.isString()) { + return false; + } + auto sharedValue = svVal.asObject(runtime); + auto key = keyVal.asString(runtime).utf8(runtime); + auto name = + sharedValue.getProperty(runtime, "name").asString(runtime).utf8(runtime); + + auto conv = [target = &target, key](jsi::Runtime &runtime, + const jsi::Object &val) { + auto value = val.getProperty(runtime, "value"); + if (!value.isObject()) { + return; + } + auto values = value.asObject(runtime); + if (!values.hasProperty(runtime, key.c_str())) { + return; + } + + auto selected = values.getProperty(runtime, key.c_str()); + if (selected.isUndefined() || selected.isNull() || + (selected.isObject() && selected.asObject(runtime).isFunction(runtime))) { + return; + } + *target = getPropertyValue(runtime, selected); + }; + + variables[name].push_back(conv); + conv(runtime, sharedValue); + return true; +} + template void convertPropertyImpl(jsi::Runtime &runtime, const jsi::Object &object, const std::string &propertyName, Target &target, @@ -78,13 +122,16 @@ void convertPropertyImpl(jsi::Runtime &runtime, const jsi::Object &object, return; } - auto property = object.getProperty(runtime, propertyName.c_str()); + auto prop = object.getProperty(runtime, propertyName.c_str()); + + if (convertSelectorProperty(runtime, prop, target, variables)) { + return; + } - if (isSharedValue(runtime, property)) { - auto sharedValue = property.asObject(runtime); - auto name = sharedValue.getProperty(runtime, "name") - .asString(runtime) - .utf8(runtime); + if (isSharedValue(runtime, prop)) { + auto sharedValue = prop.asObject(runtime); + auto name = + sharedValue.getProperty(runtime, "name").asString(runtime).utf8(runtime); auto conv = [target = &target](jsi::Runtime &runtime, const jsi::Object &val) { auto value = val.getProperty(runtime, "value"); @@ -92,9 +139,10 @@ void convertPropertyImpl(jsi::Runtime &runtime, const jsi::Object &object, }; variables[name].push_back(conv); conv(runtime, sharedValue); - } else { - target = getPropertyValue(runtime, property); + return; } + + target = getPropertyValue(runtime, prop); } // Main convertProperty template diff --git a/packages/skia/src/renderer/processors/Animations/Animations.ts b/packages/skia/src/renderer/processors/Animations/Animations.ts index 1fd34c79f1..229b155a40 100644 --- a/packages/skia/src/renderer/processors/Animations/Animations.ts +++ b/packages/skia/src/renderer/processors/Animations/Animations.ts @@ -1,4 +1,37 @@ -export type AnimatedProp = T | { value: T }; +import type { SharedValue } from "react-native-reanimated"; + +/** + * Binds a prop to a single key of a "grouped" shared value: one shared value + * whose `.value` is an object can drive many props (one key each) instead of + * requiring a separate shared value per prop. + * + * Created via {@link select}. `T` is the type of the selected value; `__type` + * is a phantom marker carrying that type and is never present at runtime. + */ +export type SharedValueSelector = { + __sv: { value: Record }; + __key: string; + readonly __type?: T; +}; + +export type AnimatedProp = T | { value: T } | SharedValueSelector; + +/** + * Selects a single key of a shared value so it can drive an animated prop. + * This lets one shared value (whose value is an object) drive multiple props + * — one per key — instead of using a separate shared value for each. + * + * @example + * const data = useSharedValue({ x: 0, y: 0, r: 10 }); + * + */ +export const select = ( + value: SharedValue, + key: K +): SharedValueSelector => ({ + __sv: value as unknown as { value: Record }, + __key: key, +}); export type AnimatedProps = { [K in keyof T]: K extends "children" diff --git a/packages/skia/src/sksg/Recorder/Core.ts b/packages/skia/src/sksg/Recorder/Core.ts index da0106467a..8ced233975 100644 --- a/packages/skia/src/sksg/Recorder/Core.ts +++ b/packages/skia/src/sksg/Recorder/Core.ts @@ -23,6 +23,7 @@ import type { DrawingNodeProps, SkottieProps, } from "../../dom/types"; +import { isSharedValueSelector } from "../utils"; export enum CommandType { // Context @@ -79,7 +80,16 @@ export const materializeCommand = (command: any) => { const newProps = { ...command.props }; if (command.animatedProps) { for (const key in command.animatedProps) { - newProps[key] = command.animatedProps[key].value; + const entry = command.animatedProps[key]; + if (isSharedValueSelector(entry)) { + const group = entry.__sv.value; + newProps[key] = + group && typeof group === "object" + ? (group as Record)[entry.__key] + : undefined; + } else { + newProps[key] = entry.value; + } } } return { ...command, props: newProps }; diff --git a/packages/skia/src/sksg/Recorder/ReanimatedRecorder.ts b/packages/skia/src/sksg/Recorder/ReanimatedRecorder.ts index c18d5e272a..2421981a28 100644 --- a/packages/skia/src/sksg/Recorder/ReanimatedRecorder.ts +++ b/packages/skia/src/sksg/Recorder/ReanimatedRecorder.ts @@ -31,7 +31,7 @@ import type { DrawingNodeProps, } from "../../dom/types"; import type { AnimatedProps } from "../../renderer"; -import { isSharedValue } from "../utils"; +import { isSharedValue, isSharedValueSelector } from "../utils"; /** * Currently the recorder only work if the GPU resources (e.g Images) are owned by the main thread. @@ -55,6 +55,15 @@ export class ReanimatedRecorder implements BaseRecorder { return; } Object.values(props).forEach((value) => { + if (isSharedValueSelector(value) && !this.values.has(value.__sv)) { + const sv = value.__sv; + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-expect-error + sv.name = `variable${this.values.size}`; + this.values.add(sv as SharedValue); + return; + } + if (isSharedValue(value) && !this.values.has(value)) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error diff --git a/packages/skia/src/sksg/Recorder/Recorder.ts b/packages/skia/src/sksg/Recorder/Recorder.ts index f80916cf71..a01f3ce4bb 100644 --- a/packages/skia/src/sksg/Recorder/Recorder.ts +++ b/packages/skia/src/sksg/Recorder/Recorder.ts @@ -30,7 +30,7 @@ import type { DrawingNodeProps, } from "../../dom/types"; import type { AnimatedProps } from "../../renderer"; -import { isSharedValue } from "../utils"; +import { isSharedValue, isSharedValueSelector } from "../utils"; import { isColorFilter, isImageFilter, isPathEffect, isShader } from "../Node"; import type { SkPaint, SkPicture, BaseRecorder } from "../../skia/types"; @@ -78,7 +78,7 @@ export class Recorder implements BaseRecorder { } private processProps(props: Record) { - const animatedProps: Record> = {}; + const animatedProps: Record = {}; let hasAnimatedProps = false; for (const key in props) { @@ -87,6 +87,10 @@ export class Recorder implements BaseRecorder { this.animationValues.add(prop); animatedProps[key] = prop; hasAnimatedProps = true; + } else if (isSharedValueSelector(prop)) { + this.animationValues.add(prop.__sv); + animatedProps[key] = prop; + hasAnimatedProps = true; } } @@ -222,7 +226,7 @@ export class Recorder implements BaseRecorder { boxProps: AnimatedProps, shadows: { props: BoxShadowProps; - animatedProps?: Record>; + animatedProps?: Record; }[] ) { shadows.forEach((shadow) => { diff --git a/packages/skia/src/sksg/__tests__/SharedValueSelector.spec.ts b/packages/skia/src/sksg/__tests__/SharedValueSelector.spec.ts new file mode 100644 index 0000000000..57dca67d5e --- /dev/null +++ b/packages/skia/src/sksg/__tests__/SharedValueSelector.spec.ts @@ -0,0 +1,107 @@ +import type { SharedValue } from "react-native-reanimated"; + +import { select } from "../../renderer/processors/Animations/Animations"; +import { isSharedValueSelector } from "../utils"; +import { materializeCommand, CommandType } from "../Recorder/Core"; +import { Recorder } from "../Recorder/Recorder"; + +// Minimal stand-in for a Reanimated shared value: the guard only checks the +// `_isReanimatedSharedValue` flag, so we don't need the Reanimated runtime. +const makeSharedValue = (value: T) => + ({ _isReanimatedSharedValue: true, value }) as unknown as SharedValue; + +describe("isSharedValueSelector", () => { + it("returns true for a selector", () => { + const sv = makeSharedValue({ x: 1 }); + expect(isSharedValueSelector({ __sv: sv, __key: "x" })).toBe(true); + }); + + it("returns false for a plain shared value", () => { + expect(isSharedValueSelector(makeSharedValue(1))).toBe(false); + }); + + it("returns false for invalid shapes", () => { + expect(isSharedValueSelector(null)).toBe(false); + expect(isSharedValueSelector(42)).toBe(false); + expect(isSharedValueSelector({})).toBe(false); + // __sv missing + expect(isSharedValueSelector({ __key: "x" })).toBe(false); + // __sv is not a shared value + expect(isSharedValueSelector({ __sv: { value: {} }, __key: "x" })).toBe( + false + ); + // __key missing + expect(isSharedValueSelector({ __sv: makeSharedValue({}) })).toBe(false); + // __key is not a string + expect(isSharedValueSelector({ __sv: makeSharedValue({}), __key: 3 })).toBe( + false + ); + }); +}); + +describe("select", () => { + it("creates a selector the guard recognizes", () => { + const sv = makeSharedValue({ x: 10, y: 20 }); + const selector = select(sv, "x"); + expect(selector).toEqual({ __sv: sv, __key: "x" }); + expect(isSharedValueSelector(selector)).toBe(true); + }); +}); + +describe("materializeCommand", () => { + it("resolves a plain shared value via .value", () => { + const command = { + type: CommandType.DrawCircle, + props: { r: 0 }, + animatedProps: { r: makeSharedValue(10) }, + }; + expect(materializeCommand(command).props.r).toBe(10); + }); + + it("resolves a selector via __sv.value[__key]", () => { + const sv = makeSharedValue({ x: 5, y: 8 }); + const command = { + type: CommandType.DrawCircle, + props: { cx: 0, cy: 0 }, + animatedProps: { cx: select(sv, "x"), cy: select(sv, "y") }, + }; + const { props } = materializeCommand(command); + expect(props.cx).toBe(5); + expect(props.cy).toBe(8); + }); + + it("does not crash when the grouped value is null", () => { + const sv = makeSharedValue<{ x: number }>(null as unknown as { x: number }); + const command = { + type: CommandType.DrawCircle, + props: { cx: 0 }, + animatedProps: { cx: select(sv, "x") }, + }; + expect(() => materializeCommand(command)).not.toThrow(); + expect(materializeCommand(command).props.cx).toBeUndefined(); + }); +}); + +describe("Recorder selector collection (web path)", () => { + it("registers one shared value for many selectors of the same value", () => { + const sv = makeSharedValue({ x: 1, y: 2 }); + const recorder = new Recorder(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const props: any = { cx: select(sv, "x"), cy: select(sv, "y"), r: 3 }; + recorder.drawCircle(props); + const { animationValues } = recorder.getRecording(); + expect(animationValues.size).toBe(1); + expect([...animationValues][0]).toBe(sv); + }); + + it("registers a plain shared value and a selector's underlying value", () => { + const grouped = makeSharedValue({ x: 1 }); + const plain = makeSharedValue(5); + const recorder = new Recorder(); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const props: any = { cx: select(grouped, "x"), r: plain }; + recorder.drawCircle(props); + const { animationValues } = recorder.getRecording(); + expect(animationValues.size).toBe(2); + }); +}); diff --git a/packages/skia/src/sksg/utils.ts b/packages/skia/src/sksg/utils.ts index 66945d036d..366f31321a 100644 --- a/packages/skia/src/sksg/utils.ts +++ b/packages/skia/src/sksg/utils.ts @@ -10,6 +10,17 @@ export const isSharedValue = ( return (value as Record)?._isReanimatedSharedValue === true; }; +export const isSharedValueSelector = ( + value: unknown +): value is { __sv: SharedValue; __key: string } => { + "worklet"; + if (!value || typeof value !== "object") { + return false; + } + const obj = value as Record; + return isSharedValue(obj.__sv) && typeof obj.__key === "string"; +}; + export const materialize = (props: T) => { "worklet"; const result: T = Object.assign({}, props); @@ -17,6 +28,13 @@ export const materialize = (props: T) => { const value = result[key]; if (isSharedValue(value)) { result[key] = value.value as never; + } else if (isSharedValueSelector(value)) { + const group = value.__sv.value; + result[key] = ( + group && typeof group === "object" + ? (group as Record)[value.__key] + : undefined + ) as never; } }); return result; From a1ed2f387bf7ae2ef6a8edae26e807919c1abce1 Mon Sep 17 00:00:00 2001 From: William Candillon Date: Wed, 5 Aug 2026 20:50:11 +0200 Subject: [PATCH 2/2] =?UTF-8?q?fix(=E2=AC=86=EF=B8=8F):=20upgrade=20to=20m?= =?UTF-8?q?152=20(#3993)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci-graphite.yml | 2 +- .gitmodules | 2 +- apps/example/ios/Podfile.lock | 148 +++++++++--------- externals/depot_tools | 2 +- externals/skia | 2 +- .../skia/cpp/api/third_party/SkottieUtils.cpp | 2 +- packages/skia/package.json | 14 +- packages/skia/scripts/build-skia.ts | 5 - .../skia/scripts/graphite-drawatlas.patch | 57 ------- .../skia/scripts/install-skia-graphite.ts | 23 +-- packages/skia/scripts/skia-configuration.ts | 32 ++-- yarn.lock | 40 ++--- 12 files changed, 138 insertions(+), 191 deletions(-) delete mode 100644 packages/skia/scripts/graphite-drawatlas.patch diff --git a/.github/workflows/ci-graphite.yml b/.github/workflows/ci-graphite.yml index 9f0f1a2323..a30982ac92 100644 --- a/.github/workflows/ci-graphite.yml +++ b/.github/workflows/ci-graphite.yml @@ -257,4 +257,4 @@ jobs: - name: Run e2e tests working-directory: packages/skia - run: CI=true yarn e2e --testPathIgnorePatterns "Paragraph|Atlas" + run: CI=true yarn e2e --testPathIgnorePatterns "Paragraph" diff --git a/.gitmodules b/.gitmodules index 7ce029cf77..66a508ee5c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,7 +1,7 @@ [submodule "externals/skia"] path = externals/skia url = https://chromium.googlesource.com/skia/ - branch = chrome/m150 + branch = chrome/m152 [submodule "externals/depot_tools"] path = externals/depot_tools url = https://chromium.googlesource.com/chromium/tools/depot_tools.git diff --git a/apps/example/ios/Podfile.lock b/apps/example/ios/Podfile.lock index bb216bdf52..c2ac90f9f2 100644 --- a/apps/example/ios/Podfile.lock +++ b/apps/example/ios/Podfile.lock @@ -2009,7 +2009,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - react-native-webgpu (0.7.1): + - react-native-webgpu (0.8.0): - boost - DoubleConversion - fast_float @@ -3238,90 +3238,90 @@ SPEC CHECKSUMS: FBLazyVector: 309703e71d3f2f1ed7dc7889d58309c9d77a95a4 fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd glog: 5683914934d5b6e4240e497e0f4a3b42d1854183 - hermes-engine: ad676c360175e5b8af471b8ce1389e6cf4f9e1ee - RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669 + hermes-engine: 11b010917f5f15150b2c015abddef1573d2bb05d + RCT-Folly: 59ec0ac1f2f39672a0c6e6cecdd39383b764646f RCTDeprecation: a41bbdd9af30bf2e5715796b313e44ec43eefff1 RCTRequired: 7be34aabb0b77c3cefe644528df0fa0afad4e4d0 RCTSwiftUI: a6c7271c39098bf00dbdad8f8ed997a59bbfbe44 - RCTSwiftUIWrapper: ff9098ccf7727e58218f2f8ea110349863f43438 + RCTSwiftUIWrapper: 5ec163e8fde163d3fba714a992b50a266e1ece37 RCTTypeSafety: 27927d0ca04e419ed9467578b3e6297e37210b5c React: 4bc1f928568ad4bcfd147260f907b4ea5873a03b React-callinvoker: 87f8728235a0dc62e9dc19b3851c829d9347d015 - React-Core: 76bed73b02821e5630e7f2cb2e82432ee964695d - React-CoreModules: 752dbfdaeb096658aa0adc4a03ba6214815a08df - React-cxxreact: b6798528aa601c6db66e6adc7e2da2b059c8be74 + React-Core: 19e0183e28d7a6613ecacebd7525fe6650efa3b6 + React-CoreModules: 73cc86f2a0ff84b93d6325073ad2e4874d21ad40 + React-cxxreact: 4bf734645c77c9b86e2f3e933e0411cf2f14d1ba React-debug: 8978deb306f6f38c28b5091e52b0ac9f942b157e - React-defaultsnativemodule: 682b77ef4acfb298017be15f4f93c1d998deb174 - React-domnativemodule: 4c4b44f7eb68dbc3a2218db088bef318a7302017 - React-Fabric: b6f82a4d8498ce4475586f71ca8397a771fe292d - React-FabricComponents: c8695f4b11918a127c4560d66f7d3fdb01a17986 - React-FabricImage: d64f48830f63830e8ffaaf69fa487116856fbbf1 - React-featureflags: 2a46b229903e906d33dbaf9207ce57c59306c369 - React-featureflagsnativemodule: cba6c0814051a0934f8bcee4a436ee2a6bcc9754 - React-graphics: 3d0435051e1ab8904d065f8ffbe981a9fc202841 - React-hermes: 32fc9c231c1aa5c2fcfe851b0d19ee9269f88f4c - React-idlecallbacksnativemodule: f8ee42581795c4844d97147596bcc2d824c0f188 - React-ImageManager: e8f7377ef0585fd2df05559a17e01a03e187d5cf - React-intersectionobservernativemodule: b1bea12ca29accdd2eda60c87605a6030b894eb9 - React-jserrorhandler: 1a86df895b4eaf4e771abe8cf34cbb26d821f771 - React-jsi: adf8527fec197ad9d0480cc5b8945eb56de627f0 - React-jsiexecutor: 315fa2f879b43e3a9ca08f5f4b733472f7e4e8a4 - React-jsinspector: b4fd1933666bcb2549b566b40656c1e45e9d7632 - React-jsinspectorcdp: 80141710f2668e5b8f00417298d9b76b4abf90fa - React-jsinspectornetwork: 1d3ea717dbbec316cd8c21a0af53928a7bf74901 - React-jsinspectortracing: 4ce745374d4b2bfbd164cce9f8de8383d3d818a0 - React-jsitooling: fc4ac4c3b1f3f9f7fedf0c777c6ff3f244f568bd - React-jsitracing: bff08a6faeef4a9bd286487da191f5e5329e21a9 - React-logger: b8483fa08e0d62e430c76d864309d90576ca2f68 - React-Mapbuffer: 7b72a669e94662359dad4f42b5af005eb24b4e83 - React-microtasksnativemodule: cdc02da075f2857803ed63f24f5f72fc40e094c0 - react-native-safe-area-context: c00143b4823773bba23f2f19f85663ae89ceb460 - react-native-skia: 398d81d07392758762cf114280cceb24ebc9b6f3 - react-native-webgpu: 763fca525e9f3186e3b12adc237d95c36984f1a7 - React-NativeModulesApple: a2c3d2cbec893956a5b3e4060322db2984fff75b - React-networking: 3f98bd96893a294376e7e03730947a08d474c380 + React-defaultsnativemodule: 724eb9ec388d494f1e2057d83355ee8fe6f1d780 + React-domnativemodule: 9068f41092f725acd09950233d2847364c731947 + React-Fabric: 945cc8abf08d9d0966acef605bffce7b501c49d9 + React-FabricComponents: 4c4ad6f0d16c964a68f945e029505e2eeec6654b + React-FabricImage: a8b628fd98db21b9f8588e06f14a9194dda11b40 + React-featureflags: 0937601c1af1cc125851ec5bbf4654285d47a3e7 + React-featureflagsnativemodule: ac1a3e0353e1a6e15411b17ed6c7122adb0468a4 + React-graphics: cca521e06463608be46207a4aa160f8a7f725f8b + React-hermes: ec50b9fcea2c3bfdd42f8cec845eac3f35888572 + React-idlecallbacksnativemodule: effcae5b7b4473211adb154aaa321d5d9e2fbcc9 + React-ImageManager: b38459e538f1840fa5c3e7612a4bcb0029a3c366 + React-intersectionobservernativemodule: 8d33366661971200cf2e151727f6fe007b62ae7b + React-jserrorhandler: f94c688a0dbe2e045b91b992722b92e97d56f77f + React-jsi: 3216c876cd4c571a57909e22d77c8fd9530aa067 + React-jsiexecutor: 475563c0042841a85930a455d3199f6b1483a5fe + React-jsinspector: bc484fb32bf1b9fed80afe8793e614eba4f7b39e + React-jsinspectorcdp: 5a574d1d35016968a67e78e6b8a7917473ffbb77 + React-jsinspectornetwork: dce3a5a1351b527ee8c28ad4a8bdd211507e1a45 + React-jsinspectortracing: 65f6b166bd67e5adc31eba027e1570bacf7a3cc7 + React-jsitooling: d5463f5489a31640b0fa0ec4e31566ca8aa86c13 + React-jsitracing: 3c7fc18821aba64855acb8658aa857ca6a7fddf6 + React-logger: 6ac901f5c7f7321d2be1a40b203bccc2e23411e3 + React-Mapbuffer: 2e0e7cc5b7064eaed9c8b8afc3a87621cb7ef5cd + React-microtasksnativemodule: dd4d33b251b57e5027c572c6d0b45cbfbcfaa386 + react-native-safe-area-context: 54d812805f3c4e08a4580ad086cbde1d8780c2e4 + react-native-skia: 765e9975e9ccde5ce3c9a0f740f195108c7d0280 + react-native-webgpu: d7021164f316160273312cc13d9d4e0ea0a1308b + React-NativeModulesApple: 7f2f2fed3f6c858889eb61d09941be965d52df58 + React-networking: 43e5e6773ac2ca2a93261a1388fed269c9fce092 React-oscompat: 80166b66da22e7af7fad94474e9997bd52d4c8c6 - React-perflogger: d6797918d2b1031e91a9d8f5e7fdd2c8728fb390 - React-performancecdpmetrics: 5570be61e2f97c4741c5d432c91570e8e5a39892 - React-performancetimeline: 5763499ae1991fc18dcf416e340ce7bc829bb298 + React-perflogger: 63c90e0d8c24df87ffa14dad01aeafc352847dd0 + React-performancecdpmetrics: 5a9b81c08f75045635127d626440d9ada01e774b + React-performancetimeline: 31cebfff69ec9174b3fb54b0606fcb12ef91cbad React-RCTActionSheet: 3bd5f5db9f983cf38d51bb9a7a198e2ebea94821 - React-RCTAnimation: 46a9978f27dc434dbeed16afa7b82619b690a9af - React-RCTAppDelegate: 62ecd60a2b2a8cae26ce6a066bfa59cfde97af01 - React-RCTBlob: 8285c859513023ee3cc8c806d9b59d4da078c4ba - React-RCTFabric: 05ed09347e938de985052f791a6a0698816d5761 - React-RCTFBReactNativeSpec: 83ba579fca9a51e774ac32578ef5dd3262edd7e2 - React-RCTImage: a5364d0f098692cfbf5bef1e8a63e7712ecb14b7 - React-RCTLinking: 34b63b0aa0e92d30f5d7aa2c255a8f95fa75ee8f - React-RCTNetwork: 1ef88b7a5310b8f915d3556b5b247def113191ed - React-RCTRuntime: ed29cf68a46782fec891e5afe1d8d758ca6ccd9b - React-RCTSettings: 2c45623d6c0f30851a123f621eb9d32298bcbb0c - React-RCTText: 0ee70f5dc18004b4d81b2c214267c6cbec058587 - React-RCTVibration: 88557e21e7cc3fe76b5b174cba28ff45c6def997 + React-RCTAnimation: 346865a809fa5132f6c594c8b376c6cf46b44e88 + React-RCTAppDelegate: b2d1e0d3663c987f49f45094883b9e36fcbf0181 + React-RCTBlob: 74759ebb7ff9077d19f60c301782c1f8c3eb2813 + React-RCTFabric: 7b4b14dad21ca99333ebcbc0bf5c205647a315a8 + React-RCTFBReactNativeSpec: 39151968adb68b8c59f29a8bd4223d4d7780a793 + React-RCTImage: 60763f56e8a5e45d861d7c4777e428bb820ec52a + React-RCTLinking: 52aee78b0b3163167c7fcf58f80a42943c03a056 + React-RCTNetwork: f5e1e8ae5eff6982efff6289b06ec0a76d0a6ac2 + React-RCTRuntime: 0e99199322afd372e74b95ae5c58f4e074cc2855 + React-RCTSettings: 298bb40d3412bf32e0b4f0797e48416b0b7278a1 + React-RCTText: dfb74800e27d792d1188fa975a3b9807c3362e3e + React-RCTVibration: ffe5fd4f50a835e353a3b6869eb005dab11eea44 React-rendererconsistency: d280314a3e7f0097152f89e815b4de821c2be8b9 - React-renderercss: f8cbf83d95c2c2bbf893d37fe50c73f046584411 - React-rendererdebug: 37216ddfcd38e49d1e92bf9052ea4bc9d7b932e5 - React-RuntimeApple: 1c0e7cb8e1c2c5775585afcaaa666ec151629a8d - React-RuntimeCore: 925fe2ca24cf8e6ed87586dbb92827306b93b83f - React-runtimeexecutor: 962dae024f6df760d029512a7d99e3f73d570935 - React-RuntimeHermes: 19a7c59ec1bc9908516f0bbc29b49425f6ec64ba - React-runtimescheduler: 62f21127cd97f4d8f164eee5150d3ce53dd36f66 - React-timing: 8757bf6fb96227c264f2d1609f4ba5c68217b8ce - React-utils: 8ab26781c2f5c2f7fafb2022c8ab39d39f231b80 - React-webperformancenativemodule: 7953b7fe519f76fa595111fe18ff3d5de131bfe9 - ReactAppDependencyProvider: 0eb286cc274abb059ee601b862ebddac2e681d01 - ReactCodegen: b8e56b780fffe6edd6405be0af4a1e3049a937f7 - ReactCommon: ac934cb340aee91282ecd6f273a26d24d4c55cae - ReactNativeHost: eef98ec49b55d88ad4cabf5a4378a12b42b551ee - ReactTestApp-DevSupport: ea18f446cff64b6c9a3e28788600c82ecf51bde6 + React-renderercss: 8a1a346f3665fd5ea7a7be7b3b9f95d4743e1180 + React-rendererdebug: af74afdfb3d6c5382ebab35562efd8eb9e690473 + React-RuntimeApple: 06e33d291e72fd0c73ac47046c3536d77d5aeedd + React-RuntimeCore: 99273d2af072062eb07f0b2d2d4a0f2de697ea14 + React-runtimeexecutor: 2063c03c18810ee57939d138142e6493333360ef + React-RuntimeHermes: 2253a7f4c8d56b449230b330b0b15383ed4b3df4 + React-runtimescheduler: ff37ac6720a943da91645c06274282ac46b71f23 + React-timing: 831d7e081ba4c332ca5cccf389b88e363f13f2b4 + React-utils: 25db6c17598c4fed22b5956d7551bb8bddf1f95b + React-webperformancenativemodule: 57e41e6193cfb815bde0b5534bef68673f1270eb + ReactAppDependencyProvider: bfb12ead469222b022a2024f32aba47ce50de512 + ReactCodegen: 9ca1bd49eee1eccf6e427e406d2163f49e9c48c0 + ReactCommon: 05ad684db7d88e194272ae26baddf6300e30b8b7 + ReactNativeHost: e7e0a518b0120f0070b3e1f13c7006d3e0e8ee13 + ReactTestApp-DevSupport: 6994b53b5b81139a8ce63e0776c726c95de079a1 ReactTestApp-Resources: 1bd9ff10e4c24f2ad87101a32023721ae923bccf - RNGestureHandler: cd4be101cfa17ea6bbd438710caa02e286a84381 - RNReanimated: c26dfcd831add485c2ed93de9d7bfb90b035eeaa - RNScreens: 714e10b6b554f7dc7ad9f78dcf36dc8e3fc73415 - RNSVG: 11354d28dd6cb71a59570b68c91ba6772a2d781d - RNWorklets: b89b501d37972e6419d6f87effe41d6d76157648 + RNGestureHandler: 77eecab5fd636666ca73a55bb61e2f1a685b7e84 + RNReanimated: d1a7a4c20eefc371e062990ce1debeaff4f1b9be + RNScreens: b2a5c76af24a02a2fd71bfce42780fdd9c79cc6d + RNSVG: ea9cbf6dcdbebdfff5822b0ad9311bbc4510a0b7 + RNWorklets: 5f6e5664c1819eac103ca75cc2f36191f55aa110 SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 - Yoga: 5456bb010373068fc92221140921b09d126b116e + Yoga: 5bd0956bf9cb16f75101e78b5e852c7577bc5a45 -PODFILE CHECKSUM: 7b64fbddf0a0f7c0c19eaa9ca71bc7cdf4e2c959 +PODFILE CHECKSUM: d3796f1f719a0788265d1cd391be0a04200ce6cd -COCOAPODS: 1.16.2 +COCOAPODS: 1.15.2 diff --git a/externals/depot_tools b/externals/depot_tools index c46c2e9057..6afa997717 160000 --- a/externals/depot_tools +++ b/externals/depot_tools @@ -1 +1 @@ -Subproject commit c46c2e905741fa94ce6870f9c95978117b8a7917 +Subproject commit 6afa997717b2c0e1382e1465bedbe1a6855b9388 diff --git a/externals/skia b/externals/skia index a7fb0b3c2e..2a9b593bab 160000 --- a/externals/skia +++ b/externals/skia @@ -1 +1 @@ -Subproject commit a7fb0b3c2e109e4e68f50bf823cf6b8d524c4a0c +Subproject commit 2a9b593bab4b2fd019fa494c8d401ff1fab0b883 diff --git a/packages/skia/cpp/api/third_party/SkottieUtils.cpp b/packages/skia/cpp/api/third_party/SkottieUtils.cpp index 98d8156e3f..c5657b881c 100644 --- a/packages/skia/cpp/api/third_party/SkottieUtils.cpp +++ b/packages/skia/cpp/api/third_party/SkottieUtils.cpp @@ -10,7 +10,7 @@ #include "include/core/SkData.h" #include "include/core/SkRect.h" #include "include/core/SkSize.h" -#include "include/private/base/SkAssert.h" +#include "include/private/SkAssert.h" #include "modules/skottie/include/Skottie.h" #include "modules/skresources/include/SkResources.h" diff --git a/packages/skia/package.json b/packages/skia/package.json index b8694e1685..815dcb70bc 100644 --- a/packages/skia/package.json +++ b/packages/skia/package.json @@ -139,16 +139,16 @@ }, "dependencies": { "canvaskit-wasm": "0.41.0", - "react-native-skia-android": "150.0.0", - "react-native-skia-apple-ios": "150.0.0", - "react-native-skia-apple-macos": "150.0.0", - "react-native-skia-apple-tvos": "150.0.0", + "react-native-skia-android": "152.0.0", + "react-native-skia-apple-ios": "152.0.0", + "react-native-skia-apple-macos": "152.0.0", + "react-native-skia-apple-tvos": "152.0.0", "react-reconciler": "0.31.0" }, "graphiteDependencies": { - "react-native-skia-graphite-android": "150.0.0", - "react-native-skia-graphite-apple-ios": "150.0.0", - "react-native-skia-graphite-apple-macos": "150.0.0" + "react-native-skia-graphite-android": "152.0.0", + "react-native-skia-graphite-apple-ios": "152.0.0", + "react-native-skia-graphite-apple-macos": "152.0.0" }, "eslintIgnore": [ "node_modules/", diff --git a/packages/skia/scripts/build-skia.ts b/packages/skia/scripts/build-skia.ts index 8761213e8a..7d667b8ace 100644 --- a/packages/skia/scripts/build-skia.ts +++ b/packages/skia/scripts/build-skia.ts @@ -310,11 +310,6 @@ const buildXCFramework = (platformName: ApplePlatformName) => { const arm64ePatchFile = path.join(__dirname, "dawn-arm64e-simulator.patch"); $(`cd ${SkiaSrc} && git apply ${arm64ePatchFile}`); - // Implement drawAtlas for the Graphite backend (removes the no-op override - // so the inherited drawVertices-based default lights up the API). - const drawAtlasPatchFile = path.join(__dirname, "graphite-drawatlas.patch"); - $(`cd ${SkiaSrc} && git apply ${drawAtlasPatchFile}`); - // Remove arm64e arch flags (not available on simulator) { const filePath = `${SkiaSrc}/gn/skia/BUILD.gn`; diff --git a/packages/skia/scripts/graphite-drawatlas.patch b/packages/skia/scripts/graphite-drawatlas.patch deleted file mode 100644 index 07eae3acc8..0000000000 --- a/packages/skia/scripts/graphite-drawatlas.patch +++ /dev/null @@ -1,57 +0,0 @@ -../../packages/skia/scripts/graphite-drawatlas.patch From 4d25f90dae867435707631ce0e16d2f8899ae29d Mon Sep 17 00:00:00 2001 -From: Claude -Date: Fri, 19 Jun 2026 13:54:32 +0000 -Subject: [PATCH] Implement drawAtlas for the Graphite backend - -The Graphite Device overrode SkDevice::drawAtlas() with an empty no-op, -so SkCanvas::drawAtlas() silently drew nothing on Graphite. - -drawAtlas is definitionally "drawVertices with an image shader": the -canvas layer (SkCanvas::onDrawAtlas2) already installs the atlas image -as the paint's shader, and SkDevice's default drawAtlas() expands the -RSXform/tex/color spans into an SkVertices and forwards to drawVertices(). -Graphite already fully implements drawVertices() (per-vertex colors, -primitive blender, and shader-sourced texture coordinates), so removing -the no-op override lets the inherited implementation light the API up. - -This mirrors how Graphite already defers drawRegion and drawPatch to -their default drawVertices/drawPath/drawRect routing instead of -specializing them. - -Co-Authored-By: Claude Opus 4.8 -Claude-Session: https://claude.ai/code/session_01LDRiP7kX2Wa8pD7ewEuhFf ---- - src/gpu/graphite/Device.h | 8 +++----- - 1 file changed, 3 insertions(+), 5 deletions(-) - -diff --git a/src/gpu/graphite/Device.h b/src/gpu/graphite/Device.h -index c5669d2..8b5e9ad 100644 ---- a/src/gpu/graphite/Device.h -+++ b/src/gpu/graphite/Device.h -@@ -210,8 +210,8 @@ public: - void drawPath(const SkPath& path, const SkPaint&) override; - void drawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint&) override; - -- // No need to specialize drawRegion or drawPatch as the default impls all route to drawPath, -- // drawRect, or drawVertices as desired. -+ // No need to specialize drawRegion, drawPatch, or drawAtlas as the default impls all route to -+ // drawPath, drawRect, or drawVertices as desired. - - void drawEdgeAAQuad(const SkRect& rect, const SkPoint clip[4], - SkCanvas::QuadAAFlags aaFlags, const SkColor4f& color, -@@ -234,11 +234,9 @@ public: - const SkSamplingOptions&, - const SkPaint&, - SkCanvas::SrcRectConstraint) override; -- // TODO: Implement these using per-edge AA quads and an inlined image shader program. -+ // TODO: Implement this using per-edge AA quads and an inlined image shader program. - void drawImageLattice(const SkImage*, const SkCanvas::Lattice&, - const SkRect& dst, SkFilterMode, const SkPaint&) override {} -- void drawAtlas(SkSpan, SkSpan, SkSpan, -- sk_sp, const SkPaint&) override {} - - void drawDrawable(SkCanvas*, SkDrawable*, const SkMatrix*) override {} - void drawMesh(const SkMesh&, sk_sp, const SkPaint&) override {} --- -2.43.0 - diff --git a/packages/skia/scripts/install-skia-graphite.ts b/packages/skia/scripts/install-skia-graphite.ts index e8056fabf0..d177a95b01 100644 --- a/packages/skia/scripts/install-skia-graphite.ts +++ b/packages/skia/scripts/install-skia-graphite.ts @@ -29,27 +29,32 @@ import { fileOps } from "./utils"; // Graphite configuration const GRAPHITE_CONFIG = { - version: "m150", + version: "m152", checksums: { "android-armeabi-v7a": - "c8a1f9d259599280b737497a914e6fcb1b47fbf6e59537cffe3e3ebbc3aa0394", + "edc363fb63d3e629d7023d63d505c2d075030dfc40e04890d988eaff5c31c2fc", "android-arm64-v8a": - "21667587386ebbaba1b61926f81dc1562443eefec5d1489b9278084f18ebb8e4", + "cefc18191d46deec3e164f3b717b06c6ae7845eeec21fe11cca53339063cf1e2", "android-x86": - "0679a34612b98b5397180e027f7592026eb4af950b36e55bf7882ea86e2cb1e3", + "78041f4d58fafda1821c96f83e4818cce492a7047b16f267527e3e140d0b4c0d", "android-x86_64": - "eec546cf240e76129e9e6d16e51c61acfd62b7c00d655b133eddfab890c3488b", + "8cfcd40b87b42aa0aaaba89852aa51f3316c90debcdf24dcc5a9b7b562a8aa6f", "apple-ios-xcframeworks": - "0ad5434961b22a59541c0364be20a54c5cde599c1ffd4d6b653fefb19c2119fc", + "9a64915dd95bf22ab3f38624ac2fc7e4a14cfd155f218170317ccef6ab9dfc69", "apple-macos-xcframeworks": - "e3861d45386309dfed851488293027f3026a35684007595071426f4e46bef023", + "995cc77d575368d2df08a16ed0345395ba66308b00ba57ef190e70eb710d74f9", }, } as const; // Dawn prebuilt binaries. These are the exact artifacts react-native-webgpu // links; both packages must consume the same Dawn build so that only one Dawn -// copy exists in an app that installs both. The Dawn commit is the one from -// this Skia milestone's DEPS. +// copy exists in an app that installs both, which is why the release tag is +// pinned here rather than derived from GRAPHITE_CONFIG.version. +// +// STALE: this is still the m150 Dawn (63f25feec51e9351fb25222b6d5de1af791d7c4f) +// while m152's DEPS pins 1e897275172a23f27b0022fa6beae3084ed54a9b. Bump this to +// dawn-chrome-m152 (with new checksums) once react-native-webgpu publishes that +// release; until then Graphite installs pair m152 Skia with m150 Dawn. const DAWN_CONFIG = { releaseTag: "dawn-chrome-m150", baseUrl: diff --git a/packages/skia/scripts/skia-configuration.ts b/packages/skia/scripts/skia-configuration.ts index eb7a0377ca..ccbb9de98a 100644 --- a/packages/skia/scripts/skia-configuration.ts +++ b/packages/skia/scripts/skia-configuration.ts @@ -88,6 +88,11 @@ export const commonArgs = [ //["skia_enable_ganesh", !GRAPHITE], ["skia_enable_graphite", GRAPHITE], ["skia_use_dawn", GRAPHITE], + // m152 turns PartitionAlloc on by default for clang builds, which leaves + // raw_ptr/PartitionAddressSpace symbols undefined when linking against the + // prebuilt libskia.a (the allocator lives in its own target we don't ship). + // Skia's noop raw_ptr shims are used instead. + ["skia_use_partition_alloc", false], // C++20 is required for Graphite builds (Dawn uses C++20 concepts) // Passed via extra_cflags_cc per-target instead of skia_use_cpp20 (not available in all Skia versions) ]; @@ -635,31 +640,30 @@ export const copyHeaders = () => { console.log("✅ Skia headers copied successfully"); - // Copy src/base files - fileOps.mkdir("./cpp/skia/src/base"); + // These used to live in src/base; they were folded into src/core in m152. fileOps.cp( - "../../externals/skia/src/base/SkTLazy.h", - "./cpp/skia/src/base/SkTLazy.h" + "../../externals/skia/src/core/SkTLazy.h", + "./cpp/skia/src/core/SkTLazy.h" ); fileOps.cp( - "../../externals/skia/src/base/SkMathPriv.h", - "./cpp/skia/src/base/SkMathPriv.h" + "../../externals/skia/src/core/SkMathPriv.h", + "./cpp/skia/src/core/SkMathPriv.h" ); fileOps.cp( - "../../externals/skia/src/base/SkTInternalLList.h", - "./cpp/skia/src/base/SkTInternalLList.h" + "../../externals/skia/src/core/SkTInternalLList.h", + "./cpp/skia/src/core/SkTInternalLList.h" ); fileOps.cp( - "../../externals/skia/src/base/SkUTF.h", - "./cpp/skia/src/base/SkUTF.h" + "../../externals/skia/src/core/SkUTF.h", + "./cpp/skia/src/core/SkUTF.h" ); fileOps.cp( - "../../externals/skia/src/base/SkArenaAlloc.h", - "./cpp/skia/src/base/SkArenaAlloc.h" + "../../externals/skia/src/core/SkArenaAlloc.h", + "./cpp/skia/src/core/SkArenaAlloc.h" ); fileOps.cp( - "../../externals/skia/src/base/SkAutoLocaleSetter.h", - "./cpp/skia/src/base/SkAutoLocaleSetter.h" + "../../externals/skia/src/core/SkAutoLocaleSetter.h", + "./cpp/skia/src/core/SkAutoLocaleSetter.h" ); // Copy skunicode diff --git a/yarn.lock b/yarn.lock index c749fbdce0..fda999bd1c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -9102,10 +9102,10 @@ __metadata: react-native: 0.83.1 react-native-builder-bob: 0.18.2 react-native-reanimated: 4.3.1 - react-native-skia-android: 150.0.0 - react-native-skia-apple-ios: 150.0.0 - react-native-skia-apple-macos: 150.0.0 - react-native-skia-apple-tvos: 150.0.0 + react-native-skia-android: 152.0.0 + react-native-skia-apple-ios: 152.0.0 + react-native-skia-apple-macos: 152.0.0 + react-native-skia-apple-tvos: 152.0.0 react-native-worklets: 0.8.3 react-reconciler: 0.31.0 rimraf: 3.0.2 @@ -27158,31 +27158,31 @@ __metadata: languageName: node linkType: hard -"react-native-skia-android@npm:150.0.0": - version: 150.0.0 - resolution: "react-native-skia-android@npm:150.0.0" - checksum: e33eecf360925bc0402c1d6b0db5845f2a38d19244f9c128b7c208abb7dc2c07158cdfcd0c998c31271075ce8ad8a3b1bed329cd010a9df9a3ae58a752e8fded +"react-native-skia-android@npm:152.0.0": + version: 152.0.0 + resolution: "react-native-skia-android@npm:152.0.0" + checksum: c01ae79040ea04997340861828d79fb4591ad922a50a94cbcdb1b4d7f4e7fa1ad9a892cdb87f40a059489350cb2cfdd647448570d109dcab25342d9d287d1bbc languageName: node linkType: hard -"react-native-skia-apple-ios@npm:150.0.0": - version: 150.0.0 - resolution: "react-native-skia-apple-ios@npm:150.0.0" - checksum: d96bfdf9b5bd8eb038b29b4949f591acd9064b00e8d4229f8932b8a9e7bbcf206c6e57a32f1ad0ba6b58ff033388a6dbe059f73d9eb91686afb0f8a3742e5392 +"react-native-skia-apple-ios@npm:152.0.0": + version: 152.0.0 + resolution: "react-native-skia-apple-ios@npm:152.0.0" + checksum: 42ef9929664d197eaf1116e172573ad1ed68944b7349ee692bb542761fd4aa6d171d23a293ee64b0a1f0d0bf3c6cd2f1f32ef8bda2b4dd1749466af5f25dd8a3 languageName: node linkType: hard -"react-native-skia-apple-macos@npm:150.0.0": - version: 150.0.0 - resolution: "react-native-skia-apple-macos@npm:150.0.0" - checksum: 0963df1f238a03a6390e9c11eb3cc662a81db5ad2daee77eb7555f35f4ccf06ac32e94c37d42704a33bf8b09d1ebb31193361a5183662df29b9e28f10aa6937d +"react-native-skia-apple-macos@npm:152.0.0": + version: 152.0.0 + resolution: "react-native-skia-apple-macos@npm:152.0.0" + checksum: d8e220ce0ac0f41c35916c5b416cbdb6436ad4189884a70524949949df8990a43c5d116865932dd244dad412e77cab368f3f820e1400b3bd00736ee37435810b languageName: node linkType: hard -"react-native-skia-apple-tvos@npm:150.0.0": - version: 150.0.0 - resolution: "react-native-skia-apple-tvos@npm:150.0.0" - checksum: c96428599c75febf5f0ea9a9282d28dd100be1ddc5953cbd6afc845379ef24de2fd3e8f3643a16c1d864b395ce225f01e35621e613e88edcb5b0b9ba78011a3e +"react-native-skia-apple-tvos@npm:152.0.0": + version: 152.0.0 + resolution: "react-native-skia-apple-tvos@npm:152.0.0" + checksum: ae80993eb127b5ee4502b0428204b980347d6cf31444de74984ae64373e1bc4a992b79ddae0aa9983cd3a6e5b979ae5d810f88eca92976b40907fdb578b508d5 languageName: node linkType: hard