From 7b0e384c540c257a503e76759d88f2a8eeaad7fa Mon Sep 17 00:00:00 2001 From: Dmitry Rykun Date: Tue, 26 Nov 2024 01:47:59 -0800 Subject: [PATCH 1/2] [skip ci] Introduce Android ImageManger (#47721) Summary: This diff splits Cxx ImageManger into Cxx and Android variants. They both are currently no-op, but the Android one will be used for image prefetching, just as `RCTImageManager.mm` for iOS. Changelog: [Internal] Differential Revision: D65753319 --- .../platform/android/ImageManager.cpp | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 packages/react-native/ReactCommon/react/renderer/imagemanager/platform/android/ImageManager.cpp diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/android/ImageManager.cpp b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/android/ImageManager.cpp new file mode 100644 index 00000000000000..7d4380753a13a4 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/android/ImageManager.cpp @@ -0,0 +1,28 @@ +/* + * 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 "ImageManager.h" + +namespace facebook::react { + +ImageManager::ImageManager( + const ContextContainer::Shared& /*contextContainer*/) { + // Silence unused-private-field warning. + (void)self_; + // Not implemented. +} + +ImageManager::~ImageManager() = default; + +ImageRequest ImageManager::requestImage( + const ImageSource& imageSource, + SurfaceId /*surfaceId*/) const { + // Not implemented. + return {imageSource, nullptr, {}}; +} + +} // namespace facebook::react From 81965cfe6707b8888e27458449b00a6ba94d8611 Mon Sep 17 00:00:00 2001 From: Dmitry Rykun Date: Tue, 26 Nov 2024 01:47:59 -0800 Subject: [PATCH 2/2] Introduce ImageRequestParams (#47723) Summary: Identity of `ImageRequest` is based on `ImageSource` and a subset of `ImageProps`. If any of those change, the request must be recreated and resubmitted. Currently, the relevant subset of ImageProps is represented by a single `blurRadius` prop. This list will grow in the future. In order to simplify adding new props to the image request, we introduce the `ImageRequestParams` type that will wrap all the relevant props. The alternative approach to pass `ImageProps` directly to `ImageManager` is worse because it would introduce dependency cycle between `ImageManager` and the `Image` component, and also it would require to store the props in State, which is bad. Changelog: [Internal] Differential Revision: D66172570 --- .../ReactCommon/React-FabricImage.podspec | 5 +++- .../components/image/ImageShadowNode.cpp | 29 ++++++++++++------ .../components/image/ImageShadowNode.h | 2 +- .../renderer/components/image/ImageState.cpp | 5 ++-- .../renderer/components/image/ImageState.h | 15 ++++++---- .../renderer/imagemanager/ImageManager.h | 7 +++++ .../platform/android/ImageManager.cpp | 11 +++++-- .../platform/android/ImageRequestParams.h | 30 +++++++++++++++++++ .../renderer/imagemanager/ImageManager.cpp | 10 ++++++- .../imagemanager/ImageRequestParams.h | 30 +++++++++++++++++++ .../renderer/imagemanager/ImageManager.mm | 9 ++++++ .../imagemanager/ImageRequestParams.h | 30 +++++++++++++++++++ 12 files changed, 160 insertions(+), 23 deletions(-) create mode 100644 packages/react-native/ReactCommon/react/renderer/imagemanager/platform/android/ImageRequestParams.h create mode 100644 packages/react-native/ReactCommon/react/renderer/imagemanager/platform/cxx/react/renderer/imagemanager/ImageRequestParams.h create mode 100644 packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/ImageRequestParams.h diff --git a/packages/react-native/ReactCommon/React-FabricImage.podspec b/packages/react-native/ReactCommon/React-FabricImage.podspec index c8e975a3e0aa95..0fa0a4017e1284 100644 --- a/packages/react-native/ReactCommon/React-FabricImage.podspec +++ b/packages/react-native/ReactCommon/React-FabricImage.podspec @@ -79,10 +79,13 @@ Pod::Spec.new do |s| s.dependency "fast_float", "6.1.4" s.dependency "fmt", "11.0.2" s.dependency "React-featureflags" - s.dependency "React-ImageManager" s.dependency "React-utils" s.dependency "Yoga" + add_dependency(s, "React-ImageManager", :additional_framework_paths => [ + "react/renderer/components/view/platform/cxx", + "react/renderer/imagemanager/platform/ios", + ]) add_dependency(s, "ReactCommon", :subspec => "turbomodule/core") add_dependency(s, "React-graphics", :additional_framework_paths => ["react/renderer/graphics/platform/ios"]) add_dependency(s, "React-Fabric", :additional_framework_paths => [ diff --git a/packages/react-native/ReactCommon/react/renderer/components/image/ImageShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/components/image/ImageShadowNode.cpp index 5eb90ac2e4a083..b67fe6ed34043e 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/image/ImageShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/image/ImageShadowNode.cpp @@ -10,6 +10,7 @@ #include #include +#include #include "ImageState.h" namespace facebook::react { @@ -24,20 +25,30 @@ void ImageShadowNode::setImageManager(const SharedImageManager& imageManager) { void ImageShadowNode::updateStateIfNeeded() { ensureUnsealed(); - auto imageSource = getImageSource(); - const auto& currentState = getStateData(); - bool hasSameRadius = - getConcreteProps().blurRadius == currentState.getBlurRadius(); - bool hasSameImageSource = currentState.getImageSource() == imageSource; + const auto& savedState = getStateData(); + const auto& oldImageSource = savedState.getImageSource(); + auto newImageSource = getImageSource(); + const auto& oldImageRequestParams = savedState.getImageRequestParams(); + const auto& imageProps = getConcreteProps(); + const auto& newImageRequestParams = ImageRequestParams(imageProps.blurRadius); - if (hasSameImageSource && hasSameRadius) { + if (oldImageSource == newImageSource && + oldImageRequestParams == newImageRequestParams) { return; } auto state = ImageState{ - imageSource, - imageManager_->requestImage(imageSource, getSurfaceId()), - getConcreteProps().blurRadius}; + newImageSource, + imageManager_->requestImage( + newImageSource, + getSurfaceId() +#ifdef ANDROID + , + newImageRequestParams, + getTag() +#endif + ), + newImageRequestParams}; setStateData(std::move(state)); } diff --git a/packages/react-native/ReactCommon/react/renderer/components/image/ImageShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/image/ImageShadowNode.h index 1e9e8e73dc278c..9bf1a8023a56e3 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/image/ImageShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/components/image/ImageShadowNode.h @@ -46,7 +46,7 @@ class ImageShadowNode final : public ConcreteViewShadowNode< const ShadowNodeFamily::Shared& /*family*/, const ComponentDescriptor& componentDescriptor) { auto imageSource = ImageSource{ImageSource::Type::Invalid}; - return {imageSource, {imageSource, nullptr}, 0}; + return {imageSource, {imageSource, nullptr}, {}}; } #pragma mark - LayoutableShadowNode diff --git a/packages/react-native/ReactCommon/react/renderer/components/image/ImageState.cpp b/packages/react-native/ReactCommon/react/renderer/components/image/ImageState.cpp index 67e4cdd76cc640..619d2131ac85c1 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/image/ImageState.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/image/ImageState.cpp @@ -16,9 +16,8 @@ ImageSource ImageState::getImageSource() const { const ImageRequest& ImageState::getImageRequest() const { return *imageRequest_; } - -Float ImageState::getBlurRadius() const { - return blurRadius_; +const ImageRequestParams& ImageState::getImageRequestParams() const { + return imageRequestParams_; } } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/components/image/ImageState.h b/packages/react-native/ReactCommon/react/renderer/components/image/ImageState.h index c42d7b666cc32b..fac7d154b57e6a 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/image/ImageState.h +++ b/packages/react-native/ReactCommon/react/renderer/components/image/ImageState.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include #ifdef ANDROID @@ -26,10 +27,10 @@ class ImageState final { ImageState( const ImageSource& imageSource, ImageRequest imageRequest, - const Float blurRadius) + const ImageRequestParams& imageRequestParams) : imageSource_(imageSource), imageRequest_(std::make_shared(std::move(imageRequest))), - blurRadius_(blurRadius){}; + imageRequestParams_(imageRequestParams) {} /* * Returns stored ImageSource object. @@ -42,11 +43,13 @@ class ImageState final { */ const ImageRequest& getImageRequest() const; - Float getBlurRadius() const; - + /* + * Returns stored ImageRequestParams object. + */ + const ImageRequestParams& getImageRequestParams() const; #ifdef ANDROID ImageState(const ImageState& previousState, folly::dynamic data) - : blurRadius_{0} {}; + : imageRequestParams_{} {}; /* * Empty implementation for Android because it doesn't use this class. @@ -59,7 +62,7 @@ class ImageState final { private: ImageSource imageSource_; std::shared_ptr imageRequest_; - const Float blurRadius_; + ImageRequestParams imageRequestParams_; }; } // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/ImageManager.h b/packages/react-native/ReactCommon/react/renderer/imagemanager/ImageManager.h index 128be69838884a..4dd81e9fe9207d 100644 --- a/packages/react-native/ReactCommon/react/renderer/imagemanager/ImageManager.h +++ b/packages/react-native/ReactCommon/react/renderer/imagemanager/ImageManager.h @@ -11,6 +11,7 @@ #include #include +#include #include #include @@ -33,6 +34,12 @@ class ImageManager { const ImageSource& imageSource, SurfaceId surfaceId) const; + virtual ImageRequest requestImage( + const ImageSource& imageSource, + SurfaceId surfaceId, + const ImageRequestParams& imageRequestParams, + Tag tag) const; + private: void* self_{}; }; diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/android/ImageManager.cpp b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/android/ImageManager.cpp index 7d4380753a13a4..0dd43ae5faded4 100644 --- a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/android/ImageManager.cpp +++ b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/android/ImageManager.cpp @@ -20,8 +20,15 @@ ImageManager::~ImageManager() = default; ImageRequest ImageManager::requestImage( const ImageSource& imageSource, - SurfaceId /*surfaceId*/) const { - // Not implemented. + SurfaceId surfaceId) const { + return requestImage(imageSource, surfaceId, ImageRequestParams{}, {}); +} + +ImageRequest ImageManager::requestImage( + const ImageSource& imageSource, + SurfaceId /*surfaceId*/, + const ImageRequestParams& /*imageRequestParams*/, + Tag /* tag */) const { return {imageSource, nullptr, {}}; } diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/android/ImageRequestParams.h b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/android/ImageRequestParams.h new file mode 100644 index 00000000000000..84f3eba1750e4c --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/android/ImageRequestParams.h @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace facebook::react { + +class ImageRequestParams { + public: + ImageRequestParams() = default; + ImageRequestParams(Float blurRadius) : blurRadius(blurRadius) {} + + Float blurRadius{}; + + bool operator==(const ImageRequestParams& rhs) const { + return this->blurRadius == rhs.blurRadius; + } + + bool operator!=(const ImageRequestParams& rhs) const { + return !(*this == rhs); + } +}; + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/cxx/react/renderer/imagemanager/ImageManager.cpp b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/cxx/react/renderer/imagemanager/ImageManager.cpp index 0544bd636975e9..21a99b70f7a25e 100644 --- a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/cxx/react/renderer/imagemanager/ImageManager.cpp +++ b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/cxx/react/renderer/imagemanager/ImageManager.cpp @@ -22,7 +22,15 @@ ImageManager::~ImageManager() { ImageRequest ImageManager::requestImage( const ImageSource& imageSource, - SurfaceId /*surfaceId*/) const { + SurfaceId surfaceId) const { + return requestImage(imageSource, surfaceId, ImageRequestParams{}, {}); +} + +ImageRequest ImageManager::requestImage( + const ImageSource& imageSource, + SurfaceId /*surfaceId*/, + const ImageRequestParams& /*imageRequestParams*/, + Tag /*tag*/) const { // Not implemented. return {imageSource, nullptr, {}}; } diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/cxx/react/renderer/imagemanager/ImageRequestParams.h b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/cxx/react/renderer/imagemanager/ImageRequestParams.h new file mode 100644 index 00000000000000..8f1edd7ed96074 --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/cxx/react/renderer/imagemanager/ImageRequestParams.h @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace facebook::react { + +class ImageRequestParams { + public: + ImageRequestParams() = default; + explicit ImageRequestParams(Float blurRadius) : blurRadius(blurRadius) {} + + Float blurRadius{}; + + bool operator==(const ImageRequestParams& rhs) const { + return this->blurRadius == rhs.blurRadius; + } + + bool operator!=(const ImageRequestParams& rhs) const { + return !(*this == rhs); + } +}; + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/ImageManager.mm b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/ImageManager.mm index c8b41d05f8a276..0b1c63f3693419 100644 --- a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/ImageManager.mm +++ b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/ImageManager.mm @@ -35,6 +35,15 @@ } ImageRequest ImageManager::requestImage(const ImageSource &imageSource, SurfaceId surfaceId) const +{ + return requestImage(imageSource, surfaceId, ImageRequestParams{}, {}); +} + +ImageRequest ImageManager::requestImage( + const ImageSource &imageSource, + SurfaceId surfaceId, + const ImageRequestParams & /*imageRequestParams*/, + Tag /*tag*/) const { RCTImageManager *imageManager = (__bridge RCTImageManager *)self_; return [imageManager requestImage:imageSource surfaceId:surfaceId]; diff --git a/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/ImageRequestParams.h b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/ImageRequestParams.h new file mode 100644 index 00000000000000..b10d38148b638c --- /dev/null +++ b/packages/react-native/ReactCommon/react/renderer/imagemanager/platform/ios/react/renderer/imagemanager/ImageRequestParams.h @@ -0,0 +1,30 @@ +/* + * 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. + */ + +#pragma once + +#include + +namespace facebook::react { + +class ImageRequestParams { + public: + ImageRequestParams() {} + ImageRequestParams(Float blurRadius) : blurRadius(blurRadius) {} + + Float blurRadius{}; + + bool operator==(const ImageRequestParams& rhs) const { + return this->blurRadius == rhs.blurRadius; + } + + bool operator!=(const ImageRequestParams& rhs) const { + return !(*this == rhs); + } +}; + +} // namespace facebook::react