From 13da6274e20d96ca3ee3809e140a6c28c9a0a121 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ma=C5=82ecki?= Date: Thu, 1 Oct 2026 01:33:54 -0700 Subject: [PATCH 1/3] Add explicit renderer CSS dependencies (#58522) Summary: Declare direct CSS dependencies for renderer targets that consume CSS headers instead of relying on View or Graphics to expose them transitively. Cover Buck, CMake, CocoaPods, and SwiftPM without changing header visibility or runtime behavior. Changelog: [Internal] Reviewed By: javache Differential Revision: D119489856 --- packages/react-native/Package.swift | 15 ++++++++++++--- .../react-native/ReactCommon/React-Fabric.podspec | 2 ++ .../renderer/attributedstring/CMakeLists.txt | 1 + .../react/renderer/graphics/CMakeLists.txt | 1 + .../renderer/graphics/React-graphics.podspec | 1 + .../observers/intersection/CMakeLists.txt | 1 + 6 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/react-native/Package.swift b/packages/react-native/Package.swift index 0aeb2dff39c2..64a3a0484d08 100644 --- a/packages/react-native/Package.swift +++ b/packages/react-native/Package.swift @@ -288,13 +288,21 @@ let reactJsErrorHandler = RNTarget( dependencies: [.reactNativeDependencies, .jsi, .reactFeatureFlags, .reactDebug, .reactTurboModuleBridging] ) +/// React-renderercss.podspec +let reactRendererCss = RNTarget( + name: .reactRendererCss, + path: "ReactCommon/react/renderer/css", + excludedPaths: ["tests"], + dependencies: [.reactNativeDependencies, .reactDebug, .reactUtils] +) + /// React-graphicsApple /// This represents the React-graphicsApple BUCK module let reactGraphicsApple = RNTarget( name: .reactGraphicsApple, path: "ReactCommon/react/renderer/graphics/platform/ios", linkedFrameworks: ["UIKit", "CoreGraphics"], - dependencies: [.reactDebug, .jsi, .reactUtils, .reactNativeDependencies] + dependencies: [.reactDebug, .jsi, .reactUtils, .reactNativeDependencies, .reactRendererCss] ) /// React-graphics.podspec @@ -302,7 +310,7 @@ let reactGraphics = RNTarget( name: .reactGraphics, path: "ReactCommon/react/renderer/graphics", excludedPaths: ["platform", "tests"], - dependencies: [.reactNativeDependencies, .jsi, .reactJsiExecutor, .reactRendererDebug, .reactUtils, .reactGraphicsApple] + dependencies: [.reactNativeDependencies, .jsi, .reactJsiExecutor, .reactRendererDebug, .reactUtils, .reactGraphicsApple, .reactRendererCss] ) /// ReactCommon.podspec @@ -492,7 +500,7 @@ let reactFabric = RNTarget( "observers/resize/tests", "scheduler/tests", ], - dependencies: [.reactNativeDependencies, .reactJsiExecutor, .rctTypesafety, .reactTurboModuleCore, .jsi, .logger, .reactDebug, .reactFeatureFlags, .reactUtils, .reactRuntimeScheduler, .reactCxxReact, .reactRendererDebug, .reactGraphics, .yoga, .reactJsInspectorTracing], + dependencies: [.reactNativeDependencies, .reactJsiExecutor, .rctTypesafety, .reactTurboModuleCore, .jsi, .logger, .reactDebug, .reactFeatureFlags, .reactUtils, .reactRuntimeScheduler, .reactCxxReact, .reactRendererDebug, .reactGraphics, .reactRendererCss, .yoga, .reactJsInspectorTracing], sources: ["animated", "animationbackend", "animations", "attributedstring", "core", "componentregistry", "componentregistry/native", "components/root", "components/view", "components/view/platform/cxx", "components/scrollview", "components/scrollview/platform/cxx", "components/scrollview/platform/ios", "components/legacyviewmanagerinterop", "components/legacyviewmanagerinterop/platform/ios", "dom", "scheduler", "mounting", "observers/events", "observers/intersection", "observers/mutation", "observers/resize", "telemetry", "consistency", "leakchecker", "uimanager", "uimanager/consistency", "viewtransition"] ) @@ -714,6 +722,7 @@ let targets = [ reactPerformanceTimeline, reactRuntimeScheduler, rctTypesafety, + reactRendererCss, reactGraphics, reactGraphicsApple, reactImageManager, diff --git a/packages/react-native/ReactCommon/React-Fabric.podspec b/packages/react-native/ReactCommon/React-Fabric.podspec index a5033590847d..75cc50f008eb 100644 --- a/packages/react-native/ReactCommon/React-Fabric.podspec +++ b/packages/react-native/ReactCommon/React-Fabric.podspec @@ -77,6 +77,7 @@ Pod::Spec.new do |s| end s.subspec "attributedstring" do |ss| + ss.dependency "React-renderercss" ss.source_files = podspec_sources("react/renderer/attributedstring/**/*.{m,mm,cpp,h}", "react/renderer/attributedstring/**/*.{h}") ss.exclude_files = "react/renderer/attributedstring/tests" ss.header_dir = "react/renderer/attributedstring" @@ -224,6 +225,7 @@ Pod::Spec.new do |s| end ss.subspec "intersection" do |sss| + sss.dependency "React-renderercss" sss.source_files = podspec_sources("react/renderer/observers/intersection/**/*.{m,mm,cpp,h}", "react/renderer/observers/intersection/**/*.h") sss.exclude_files = "react/renderer/observers/intersection/tests" sss.header_dir = "react/renderer/observers/intersection" diff --git a/packages/react-native/ReactCommon/react/renderer/attributedstring/CMakeLists.txt b/packages/react-native/ReactCommon/react/renderer/attributedstring/CMakeLists.txt index a337c84bf388..1b6e6bbfae9b 100644 --- a/packages/react-native/ReactCommon/react/renderer/attributedstring/CMakeLists.txt +++ b/packages/react-native/ReactCommon/react/renderer/attributedstring/CMakeLists.txt @@ -21,6 +21,7 @@ target_link_libraries(react_renderer_attributedstring react_debug rrc_view react_renderer_core + react_renderer_css react_renderer_debug react_renderer_graphics react_renderer_mapbuffer diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/CMakeLists.txt b/packages/react-native/ReactCommon/react/renderer/graphics/CMakeLists.txt index b0b2bfe607dc..b501873adb85 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/CMakeLists.txt +++ b/packages/react-native/ReactCommon/react/renderer/graphics/CMakeLists.txt @@ -32,6 +32,7 @@ target_link_libraries(react_renderer_graphics folly_runtime react_cxxstableapi react_debug + react_renderer_css react_renderer_debug react_utils ) diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/React-graphics.podspec b/packages/react-native/ReactCommon/react/renderer/graphics/React-graphics.podspec index 65e1527bbcac..21beee0c7fba 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/React-graphics.podspec +++ b/packages/react-native/ReactCommon/react/renderer/graphics/React-graphics.podspec @@ -57,6 +57,7 @@ Pod::Spec.new do |s| s.dependency "React-utils" s.dependency "React-rendererdebug" s.dependency "React-cxxstableapi" + s.dependency "React-renderercss" depend_on_js_engine(s) add_rn_third_party_dependencies(s) diff --git a/packages/react-native/ReactCommon/react/renderer/observers/intersection/CMakeLists.txt b/packages/react-native/ReactCommon/react/renderer/observers/intersection/CMakeLists.txt index 8892e3bc70a1..701e87132f09 100644 --- a/packages/react-native/ReactCommon/react/renderer/observers/intersection/CMakeLists.txt +++ b/packages/react-native/ReactCommon/react/renderer/observers/intersection/CMakeLists.txt @@ -19,6 +19,7 @@ target_link_libraries(react_renderer_observers_intersection react_cxxstableapi react_debug react_renderer_core + react_renderer_css react_renderer_graphics react_renderer_mounting react_renderer_runtimescheduler From f743d211c76708d278af995e3108be0373ea9cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ma=C5=82ecki?= Date: Thu, 1 Oct 2026 01:33:54 -0700 Subject: [PATCH 2/3] Move renderer color parsing out of headers (#58521) Summary: Move shared and platform-specific Graphics color-parsing implementations from exported headers into owned source files across generic C++, Android, Apple, and Windows targets. Preserve the existing public entry points and parsing behavior. Update Buck source selection so default configurations link the generic C++ parser, and keep the React Native macOS and Windows mirrors synchronized. Changelog: [Internal] Reviewed By: javache Differential Revision: D119500849 --- .../renderer/graphics/fromRawValueShared.cpp | 78 +++++++++++ .../renderer/graphics/fromRawValueShared.h | 61 +-------- .../renderer/graphics/PlatformColorParser.cpp | 125 ++++++++++++++++++ .../renderer/graphics/PlatformColorParser.h | 99 +------------- .../renderer/graphics/PlatformColorParser.cpp | 25 ++++ .../renderer/graphics/PlatformColorParser.h | 13 +- .../renderer/graphics/PlatformColorParser.h | 2 - 7 files changed, 235 insertions(+), 168 deletions(-) create mode 100644 packages/react-native/ReactCommon/react/renderer/graphics/fromRawValueShared.cpp create mode 100644 packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/PlatformColorParser.cpp create mode 100644 packages/react-native/ReactCommon/react/renderer/graphics/platform/cxx/react/renderer/graphics/PlatformColorParser.cpp diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/fromRawValueShared.cpp b/packages/react-native/ReactCommon/react/renderer/graphics/fromRawValueShared.cpp new file mode 100644 index 000000000000..a4ea14b927cd --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/graphics/fromRawValueShared.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include +#include +#include +#include + +namespace facebook::react { + +void fromRawValueShared( + const ContextContainer& contextContainer, + int32_t surfaceId, + const RawValue& value, + SharedColor& result, + parsePlatformColorFn parsePlatformColor) { + ColorComponents colorComponents = { + .red = 0, .green = 0, .blue = 0, .alpha = 0}; + + if (ReactNativeFeatureFlags::enableNativeCSSParsing() && + value.hasType()) { + auto cssColor = parseCSSProperty((std::string)value); + if (std::holds_alternative(cssColor)) { + auto c = std::get(cssColor); + result = hostPlatformColorFromRGBA(c.r, c.g, c.b, c.a); + return; + } + // Unparseable string - fall through to parsePlatformColor + result = parsePlatformColor(contextContainer, surfaceId, value); + } else if (value.hasType()) { + auto argb = (int64_t)value; + auto ratio = 255.f; + colorComponents.alpha = ((argb >> 24) & 0xFF) / ratio; + colorComponents.red = ((argb >> 16) & 0xFF) / ratio; + colorComponents.green = ((argb >> 8) & 0xFF) / ratio; + colorComponents.blue = (argb & 0xFF) / ratio; + + result = colorFromComponents(colorComponents); + } else if (value.hasType>()) { + auto items = (std::vector)value; + auto length = items.size(); + react_native_expect(length == 3 || length == 4); + colorComponents.red = items.at(0); + colorComponents.green = items.at(1); + colorComponents.blue = items.at(2); + colorComponents.alpha = length == 4 ? items.at(3) : 1.0f; + + result = colorFromComponents(colorComponents); + } else { + if (value.hasType>()) { + const auto& items = (std::unordered_map)value; + if (items.find("space") != items.end()) { + colorComponents.red = (float)items.at("r"); + colorComponents.green = (float)items.at("g"); + colorComponents.blue = (float)items.at("b"); + colorComponents.alpha = (float)items.at("a"); + colorComponents.colorSpace = getDefaultColorSpace(); + std::string space = (std::string)items.at("space"); + if (space == "display-p3") { + colorComponents.colorSpace = ColorSpace::DisplayP3; + } else if (space == "srgb") { + colorComponents.colorSpace = ColorSpace::sRGB; + } + result = colorFromComponents(colorComponents); + return; + } + } + result = parsePlatformColor(contextContainer, surfaceId, value); + } +} + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/fromRawValueShared.h b/packages/react-native/ReactCommon/react/renderer/graphics/fromRawValueShared.h index 3cae3f91df6e..71cff8430265 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/fromRawValueShared.h +++ b/packages/react-native/ReactCommon/react/renderer/graphics/fromRawValueShared.h @@ -8,74 +8,19 @@ #pragma once #include -#include -#include #include -#include -#include #include #include namespace facebook::react { + using parsePlatformColorFn = SharedColor (*)(const ContextContainer &, int32_t, const RawValue &); -inline void fromRawValueShared( +void fromRawValueShared( const ContextContainer &contextContainer, int32_t surfaceId, const RawValue &value, SharedColor &result, - parsePlatformColorFn parsePlatformColor) -{ - ColorComponents colorComponents = {0, 0, 0, 0}; - - if (ReactNativeFeatureFlags_DO_NOT_USE::enableNativeCSSParsing() && value.hasType()) { - auto cssColor = parseCSSProperty((std::string)value); - if (std::holds_alternative(cssColor)) { - auto c = std::get(cssColor); - result = hostPlatformColorFromRGBA(c.r, c.g, c.b, c.a); - return; - } - // Unparseable string - fall through to parsePlatformColor - result = parsePlatformColor(contextContainer, surfaceId, value); - } else if (value.hasType()) { - auto argb = (int64_t)value; - auto ratio = 255.f; - colorComponents.alpha = ((argb >> 24) & 0xFF) / ratio; - colorComponents.red = ((argb >> 16) & 0xFF) / ratio; - colorComponents.green = ((argb >> 8) & 0xFF) / ratio; - colorComponents.blue = (argb & 0xFF) / ratio; - - result = colorFromComponents(colorComponents); - } else if (value.hasType>()) { - auto items = (std::vector)value; - auto length = items.size(); - react_native_expect(length == 3 || length == 4); - colorComponents.red = items.at(0); - colorComponents.green = items.at(1); - colorComponents.blue = items.at(2); - colorComponents.alpha = length == 4 ? items.at(3) : 1.0f; + parsePlatformColorFn parsePlatformColor); - result = colorFromComponents(colorComponents); - } else { - if (value.hasType>()) { - const auto &items = (std::unordered_map)value; - if (items.find("space") != items.end()) { - colorComponents.red = (float)items.at("r"); - colorComponents.green = (float)items.at("g"); - colorComponents.blue = (float)items.at("b"); - colorComponents.alpha = (float)items.at("a"); - colorComponents.colorSpace = getDefaultColorSpace(); - std::string space = (std::string)items.at("space"); - if (space == "display-p3") { - colorComponents.colorSpace = ColorSpace::DisplayP3; - } else if (space == "srgb") { - colorComponents.colorSpace = ColorSpace::sRGB; - } - result = colorFromComponents(colorComponents); - return; - } - } - result = parsePlatformColor(contextContainer, surfaceId, value); - } -} } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/PlatformColorParser.cpp b/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/PlatformColorParser.cpp new file mode 100644 index 000000000000..321b82c5d135 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/PlatformColorParser.cpp @@ -0,0 +1,125 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +#include "configurePlatformColorCacheInvalidationHook.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace facebook::react { + +size_t hashGetColourArguments( + int32_t surfaceId, + const std::vector& resourcePaths) { + size_t seed = std::hash{}(surfaceId); + for (const auto& path : resourcePaths) { + seed ^= + std::hash{}(path) + 0x9e3779b9 + (seed << 6) + (seed >> 2); + } + return seed; +} + +SharedColor parsePlatformColor( + const ContextContainer& contextContainer, + int32_t surfaceId, + const RawValue& value) { + Color color{}; + if (value.hasType>()) { + // Mixed array + string values, so read as a map of RawValue (a map of + // vector would assert on the fallback string). + auto map = (std::unordered_map)value; + + std::vector resourcePaths; + auto resourcePathsIt = map.find("resource_paths"); + if (resourcePathsIt != map.end() && + resourcePathsIt->second.hasType>()) { + resourcePaths = (std::vector)resourcePathsIt->second; + } + + bool resolved = false; + if (!resourcePaths.empty()) { + // Cache the (costly) JNI results. A cached nullopt is an explicit miss, + // distinct from a path that resolves to transparent (ARGB 0). + static std::mutex getColorCacheMutex; + static folly::EvictingCacheMap> + getColorCache(64); + + // Listen for appearance changes, which should invalidate the cache + static std::once_flag setupCacheInvalidation; + std::call_once( + setupCacheInvalidation, + configurePlatformColorCacheInvalidationHook, + [&] { + std::scoped_lock lock(getColorCacheMutex); + getColorCache.clear(); + }); + + auto hash = hashGetColourArguments(surfaceId, resourcePaths); + std::optional resolvedColor; + { + std::scoped_lock lock(getColorCacheMutex); + auto iterator = getColorCache.find(hash); + if (iterator != getColorCache.end()) { + resolvedColor = iterator->second; + } else { + const auto& fabricUIManager = + contextContainer.at>("FabricUIManager"); + // Boxed Integer: null is an explicit miss; a non-null value may be 0 + // (transparent black). + static auto getColorFromJava = + fabricUIManager->getClass() + ->getMethod)>("getColor"); + auto javaResourcePaths = + jni::JArrayClass::newArray(resourcePaths.size()); + + for (int i = 0; i < resourcePaths.size(); i++) { + javaResourcePaths->setElement( + i, *jni::make_jstring(resourcePaths[i])); + } + auto boxedColor = + getColorFromJava(fabricUIManager, surfaceId, *javaResourcePaths); + if (boxedColor) { + resolvedColor = static_cast(boxedColor->value()); + } + getColorCache.set(hash, resolvedColor); + } + } + if (resolvedColor.has_value()) { + color = *resolvedColor; + resolved = true; + } + } + + // No path resolved: parse the raw fallback with the shared CSS parser (the + // same parser iOS Fabric uses). + if (!resolved) { + auto fallbackIt = map.find("fallback"); + if (fallbackIt != map.end() && + fallbackIt->second.hasType()) { + auto cssColor = + parseCSSProperty((std::string)fallbackIt->second); + if (std::holds_alternative(cssColor)) { + const auto& c = std::get(cssColor); + color = hostPlatformColorFromRGBA(c.r, c.g, c.b, c.a); + } + } + } + } + + return color; +} + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/PlatformColorParser.h b/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/PlatformColorParser.h index 4ff0d7577c09..2f8457ac164a 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/PlatformColorParser.h +++ b/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/PlatformColorParser.h @@ -8,112 +8,19 @@ #pragma once #include - -#include "configurePlatformColorCacheInvalidationHook.h" - -#include -#include #include -#include -#include #include #include #include -#include -#include -#include +#include #include -#include #include namespace facebook::react { -inline size_t hashGetColourArguments(int32_t surfaceId, const std::vector &resourcePaths) -{ - size_t seed = std::hash{}(surfaceId); - for (const auto &path : resourcePaths) { - seed ^= std::hash{}(path) + 0x9e3779b9 + (seed << 6) + (seed >> 2); - } - return seed; -} - -inline SharedColor -parsePlatformColor(const ContextContainer &contextContainer, int32_t surfaceId, const RawValue &value) -{ - Color color{}; - if (value.hasType>()) { - // Mixed array + string values, so read as a map of RawValue (a map of - // vector would assert on the fallback string). - auto map = (std::unordered_map)value; - - std::vector resourcePaths; - auto resourcePathsIt = map.find("resource_paths"); - if (resourcePathsIt != map.end() && resourcePathsIt->second.hasType>()) { - resourcePaths = (std::vector)resourcePathsIt->second; - } +size_t hashGetColourArguments(int32_t surfaceId, const std::vector &resourcePaths); - bool resolved = false; - if (!resourcePaths.empty()) { - // Cache the (costly) JNI results. A cached nullopt is an explicit miss, - // distinct from a path that resolves to transparent (ARGB 0). - static std::mutex getColorCacheMutex; - static folly::EvictingCacheMap> getColorCache(64); - - // Listen for appearance changes, which should invalidate the cache - static std::once_flag setupCacheInvalidation; - std::call_once(setupCacheInvalidation, configurePlatformColorCacheInvalidationHook, [&] { - std::scoped_lock lock(getColorCacheMutex); - getColorCache.clear(); - }); - - auto hash = hashGetColourArguments(surfaceId, resourcePaths); - std::optional resolvedColor; - { - std::scoped_lock lock(getColorCacheMutex); - auto iterator = getColorCache.find(hash); - if (iterator != getColorCache.end()) { - resolvedColor = iterator->second; - } else { - const auto &fabricUIManager = contextContainer.at>("FabricUIManager"); - // Boxed Integer: null is an explicit miss; a non-null value may be 0 - // (transparent black). - static auto getColorFromJava = - fabricUIManager->getClass()->getMethod)>( - "getColor"); - auto javaResourcePaths = jni::JArrayClass::newArray(resourcePaths.size()); - - for (int i = 0; i < resourcePaths.size(); i++) { - javaResourcePaths->setElement(i, *jni::make_jstring(resourcePaths[i])); - } - auto boxedColor = getColorFromJava(fabricUIManager, surfaceId, *javaResourcePaths); - if (boxedColor) { - resolvedColor = static_cast(boxedColor->value()); - } - getColorCache.set(hash, resolvedColor); - } - } - if (resolvedColor.has_value()) { - color = *resolvedColor; - resolved = true; - } - } - - // No path resolved: parse the raw fallback with the shared CSS parser (the - // same parser iOS Fabric uses). - if (!resolved) { - auto fallbackIt = map.find("fallback"); - if (fallbackIt != map.end() && fallbackIt->second.hasType()) { - auto cssColor = parseCSSProperty((std::string)fallbackIt->second); - if (std::holds_alternative(cssColor)) { - const auto &c = std::get(cssColor); - color = hostPlatformColorFromRGBA(c.r, c.g, c.b, c.a); - } - } - } - } - - return color; -} +SharedColor parsePlatformColor(const ContextContainer &contextContainer, int32_t surfaceId, const RawValue &value); inline void fromRawValue(const ContextContainer &contextContainer, int32_t surfaceId, const RawValue &value, SharedColor &result) diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/platform/cxx/react/renderer/graphics/PlatformColorParser.cpp b/packages/react-native/ReactCommon/react/renderer/graphics/platform/cxx/react/renderer/graphics/PlatformColorParser.cpp new file mode 100644 index 000000000000..9a2cc748ffe9 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/graphics/platform/cxx/react/renderer/graphics/PlatformColorParser.cpp @@ -0,0 +1,25 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include + +namespace facebook::react { + +SharedColor parsePlatformColor( + const ContextContainer& /*contextContainer*/, + int32_t /*surfaceId*/, + const RawValue& /*value*/) { + float alpha = 0; + float red = 0; + float green = 0; + float blue = 0; + + return {colorFromComponents( + {.red = red, .green = green, .blue = blue, .alpha = alpha})}; +} + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/platform/cxx/react/renderer/graphics/PlatformColorParser.h b/packages/react-native/ReactCommon/react/renderer/graphics/platform/cxx/react/renderer/graphics/PlatformColorParser.h index 84b81fec280a..0a9f0e110cff 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/platform/cxx/react/renderer/graphics/PlatformColorParser.h +++ b/packages/react-native/ReactCommon/react/renderer/graphics/platform/cxx/react/renderer/graphics/PlatformColorParser.h @@ -8,8 +8,6 @@ #pragma once #include - -#include #include #include #include @@ -17,16 +15,7 @@ namespace facebook::react { -inline SharedColor -parsePlatformColor(const ContextContainer & /*contextContainer*/, int32_t /*surfaceId*/, const RawValue & /*value*/) -{ - float alpha = 0; - float red = 0; - float green = 0; - float blue = 0; - - return {colorFromComponents({red, green, blue, alpha})}; -} +SharedColor parsePlatformColor(const ContextContainer &contextContainer, int32_t surfaceId, const RawValue &value); inline void fromRawValue(const ContextContainer &contextContainer, int32_t surfaceId, const RawValue &value, SharedColor &result) diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/PlatformColorParser.h b/packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/PlatformColorParser.h index 28afc62d43f3..0a9f0e110cff 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/PlatformColorParser.h +++ b/packages/react-native/ReactCommon/react/renderer/graphics/platform/ios/react/renderer/graphics/PlatformColorParser.h @@ -8,8 +8,6 @@ #pragma once #include - -#include #include #include #include From d02ee885cc20d651b57e903ab7507e312d537ce1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dawid=20Ma=C5=82ecki?= Date: Thu, 1 Oct 2026 01:33:54 -0700 Subject: [PATCH 3/3] Seal renderer Graphics public boundary Summary: Keep the CSS-free color parsing helpers (`parsePlatformColorFn`, `fromRawValueShared`, and `parsePlatformColor`) in the public Graphics API so the platform `fromRawValue` wrappers remain inline. Move `hashGetColourArguments` and `configurePlatformColorCacheInvalidationHook` into private implementation scope. Stop exporting CSS, fbjni, and the Android cache library from the Buck target, and express implementation-only dependencies privately in Buck and CMake. The retained shared helper header depends only on `RawValue`, `Color`, and `ContextContainer`; CSS parsing headers remain confined to the implementation file. Regenerate C++ API snapshots to remove the private hash and cache declarations while retaining the public color parser helpers and inline `fromRawValue` entry point. Changelog: [Internal] Reviewed By: cipolleschi Differential Revision: D119500886 --- .../react/renderer/graphics/CMakeLists.txt | 19 +++++++------ .../renderer/graphics/PlatformColorParser.cpp | 21 +++++++++++++-- .../renderer/graphics/PlatformColorParser.h | 5 ---- ...gurePlatformColorCacheInvalidationHook.cpp | 27 ------------------- ...figurePlatformColorCacheInvalidationHook.h | 14 ---------- .../api-snapshots/ReactAndroidDebugCxx.api | 2 -- .../api-snapshots/ReactAndroidNewarchCxx.api | 2 -- .../api-snapshots/ReactAndroidReleaseCxx.api | 2 -- 8 files changed, 30 insertions(+), 62 deletions(-) delete mode 100644 packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/configurePlatformColorCacheInvalidationHook.cpp delete mode 100644 packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/configurePlatformColorCacheInvalidationHook.h diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/CMakeLists.txt b/packages/react-native/ReactCommon/react/renderer/graphics/CMakeLists.txt index b501873adb85..9d96421aaef6 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/CMakeLists.txt +++ b/packages/react-native/ReactCommon/react/renderer/graphics/CMakeLists.txt @@ -27,14 +27,17 @@ target_include_directories(react_renderer_graphics INTERFACE ${REACT_COMMON_DIR} react_native_android_selector(fbjni fbjni "") target_link_libraries(react_renderer_graphics - glog - ${fbjni} - folly_runtime - react_cxxstableapi - react_debug - react_renderer_css - react_renderer_debug - react_utils + PUBLIC + ${fbjni} + folly_runtime + react_cxxstableapi + react_renderer_debug + react_utils + PRIVATE + glog + react_debug + react_featureflags + react_renderer_css ) target_compile_reactnative_options(react_renderer_graphics PRIVATE) target_compile_options(react_renderer_graphics PRIVATE -Wpedantic) diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/PlatformColorParser.cpp b/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/PlatformColorParser.cpp index 321b82c5d135..5e82135e65b1 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/PlatformColorParser.cpp +++ b/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/PlatformColorParser.cpp @@ -7,8 +7,7 @@ #include -#include "configurePlatformColorCacheInvalidationHook.h" - +#include #include #include #include @@ -20,6 +19,22 @@ namespace facebook::react { +namespace { + +void configurePlatformColorCacheInvalidationHook(std::function&& hook) { + auto appearanceModuleClass = jni::findClassLocal( + "com/facebook/react/modules/appearance/AppearanceModule"); + if (appearanceModuleClass) { + auto callbackField = + appearanceModuleClass->getStaticField( + "invalidatePlatformColorCache"); + jni::local_ref invalidationCallback = + jni::JNativeRunnable::newObjectCxxArgs(std::move(hook)); + appearanceModuleClass->setStaticFieldValue( + callbackField, invalidationCallback.get()); + } +} + size_t hashGetColourArguments( int32_t surfaceId, const std::vector& resourcePaths) { @@ -31,6 +46,8 @@ size_t hashGetColourArguments( return seed; } +} // namespace + SharedColor parsePlatformColor( const ContextContainer& contextContainer, int32_t surfaceId, diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/PlatformColorParser.h b/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/PlatformColorParser.h index 2f8457ac164a..0a9f0e110cff 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/PlatformColorParser.h +++ b/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/PlatformColorParser.h @@ -12,14 +12,9 @@ #include #include #include -#include -#include -#include namespace facebook::react { -size_t hashGetColourArguments(int32_t surfaceId, const std::vector &resourcePaths); - SharedColor parsePlatformColor(const ContextContainer &contextContainer, int32_t surfaceId, const RawValue &value); inline void diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/configurePlatformColorCacheInvalidationHook.cpp b/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/configurePlatformColorCacheInvalidationHook.cpp deleted file mode 100644 index 29a39cfdebeb..000000000000 --- a/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/configurePlatformColorCacheInvalidationHook.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "configurePlatformColorCacheInvalidationHook.h" - -#include -#include - -namespace facebook::react { -void configurePlatformColorCacheInvalidationHook(std::function&& hook) { - auto appearanceModuleClass = jni::findClassLocal( - "com/facebook/react/modules/appearance/AppearanceModule"); - if (appearanceModuleClass) { - auto callbackField = - appearanceModuleClass->getStaticField( - "invalidatePlatformColorCache"); - jni::local_ref invalidationCallback = - jni::JNativeRunnable::newObjectCxxArgs(std::move(hook)); - appearanceModuleClass->setStaticFieldValue( - callbackField, invalidationCallback.get()); - } -} -} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/configurePlatformColorCacheInvalidationHook.h b/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/configurePlatformColorCacheInvalidationHook.h deleted file mode 100644 index ac6c743ccb0f..000000000000 --- a/packages/react-native/ReactCommon/react/renderer/graphics/platform/android/react/renderer/graphics/configurePlatformColorCacheInvalidationHook.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) Meta Platforms, Inc. and affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include - -#include - -namespace facebook::react { -void configurePlatformColorCacheInvalidationHook(std::function &&hook); -} // namespace facebook::react diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api index c61ae05c5935..0199222cba60 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidDebugCxx.api @@ -943,7 +943,6 @@ size_t facebook::react::attributedStringFragmentHashDisplayWise(const facebook:: size_t facebook::react::attributedStringFragmentHashLayoutWise(const facebook::react::AttributedString::Fragment& fragment); size_t facebook::react::attributedStringHashDisplayWise(const facebook::react::AttributedString& attributedString); size_t facebook::react::attributedStringHashLayoutWise(const facebook::react::AttributedString& attributedString); -size_t facebook::react::hashGetColourArguments(int32_t surfaceId, const std::vector& resourcePaths); size_t facebook::react::textAttributesHashLayoutWise(const facebook::react::TextAttributes& textAttributes); std::function facebook::react::makeCallback(std::weak_ptr instance, const folly::dynamic& callbackId); std::optional facebook::react::blendModeFromString(std::string_view blendModeName); @@ -1073,7 +1072,6 @@ void facebook::react::bindHasComponentProvider(facebook::jsi::Runtime& runtime, void facebook::react::bindNativeLogger(facebook::jsi::Runtime& runtime, facebook::react::Logger logger); void facebook::react::bindNativePerformanceNow(facebook::jsi::Runtime& runtime); void facebook::react::cloneProp(facebook::react::BaseViewProps& viewProps, const facebook::react::AnimatedPropBase& animatedProp); -void facebook::react::configurePlatformColorCacheInvalidationHook(std::function&& hook); void facebook::react::defineReadOnlyGlobal(facebook::jsi::Runtime& runtime, const std::string& propName, facebook::jsi::Value&& value); void facebook::react::ensureThreadDurationJNIEnvAttached(); void facebook::react::fromRawValue(const facebook::react::ContextContainer& contextContainer, int32_t surfaceId, const facebook::react::RawValue& value, facebook::react::SharedColor& result); diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api index 9d5008343459..06448f81e048 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidNewarchCxx.api @@ -942,7 +942,6 @@ size_t facebook::react::attributedStringFragmentHashDisplayWise(const facebook:: size_t facebook::react::attributedStringFragmentHashLayoutWise(const facebook::react::AttributedString::Fragment& fragment); size_t facebook::react::attributedStringHashDisplayWise(const facebook::react::AttributedString& attributedString); size_t facebook::react::attributedStringHashLayoutWise(const facebook::react::AttributedString& attributedString); -size_t facebook::react::hashGetColourArguments(int32_t surfaceId, const std::vector& resourcePaths); size_t facebook::react::textAttributesHashLayoutWise(const facebook::react::TextAttributes& textAttributes); std::optional facebook::react::blendModeFromString(std::string_view blendModeName); std::optional facebook::react::fromCSSShadow(const facebook::react::CSSShadow& cssShadow); @@ -1069,7 +1068,6 @@ void facebook::react::bindHasComponentProvider(facebook::jsi::Runtime& runtime, void facebook::react::bindNativeLogger(facebook::jsi::Runtime& runtime, facebook::react::Logger logger); void facebook::react::bindNativePerformanceNow(facebook::jsi::Runtime& runtime); void facebook::react::cloneProp(facebook::react::BaseViewProps& viewProps, const facebook::react::AnimatedPropBase& animatedProp); -void facebook::react::configurePlatformColorCacheInvalidationHook(std::function&& hook); void facebook::react::defineReadOnlyGlobal(facebook::jsi::Runtime& runtime, const std::string& propName, facebook::jsi::Value&& value); void facebook::react::ensureThreadDurationJNIEnvAttached(); void facebook::react::fromRawValue(const facebook::react::ContextContainer& contextContainer, int32_t surfaceId, const facebook::react::RawValue& value, facebook::react::SharedColor& result); diff --git a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api index 2470a7083fb9..077a54fdf865 100644 --- a/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api +++ b/scripts/cxx-api/api-snapshots/ReactAndroidReleaseCxx.api @@ -943,7 +943,6 @@ size_t facebook::react::attributedStringFragmentHashDisplayWise(const facebook:: size_t facebook::react::attributedStringFragmentHashLayoutWise(const facebook::react::AttributedString::Fragment& fragment); size_t facebook::react::attributedStringHashDisplayWise(const facebook::react::AttributedString& attributedString); size_t facebook::react::attributedStringHashLayoutWise(const facebook::react::AttributedString& attributedString); -size_t facebook::react::hashGetColourArguments(int32_t surfaceId, const std::vector& resourcePaths); size_t facebook::react::textAttributesHashLayoutWise(const facebook::react::TextAttributes& textAttributes); std::function facebook::react::makeCallback(std::weak_ptr instance, const folly::dynamic& callbackId); std::optional facebook::react::blendModeFromString(std::string_view blendModeName); @@ -1073,7 +1072,6 @@ void facebook::react::bindHasComponentProvider(facebook::jsi::Runtime& runtime, void facebook::react::bindNativeLogger(facebook::jsi::Runtime& runtime, facebook::react::Logger logger); void facebook::react::bindNativePerformanceNow(facebook::jsi::Runtime& runtime); void facebook::react::cloneProp(facebook::react::BaseViewProps& viewProps, const facebook::react::AnimatedPropBase& animatedProp); -void facebook::react::configurePlatformColorCacheInvalidationHook(std::function&& hook); void facebook::react::defineReadOnlyGlobal(facebook::jsi::Runtime& runtime, const std::string& propName, facebook::jsi::Value&& value); void facebook::react::ensureThreadDurationJNIEnvAttached(); void facebook::react::fromRawValue(const facebook::react::ContextContainer& contextContainer, int32_t surfaceId, const facebook::react::RawValue& value, facebook::react::SharedColor& result);