diff --git a/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm b/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm index 7b64046fd37..bb811e260e2 100644 --- a/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/Image/RCTImageComponentView.mm @@ -11,7 +11,6 @@ #import #import #import -#import #import #import #import @@ -26,7 +25,7 @@ @implementation RCTImageComponentView { UIImageView *_imageView; - SharedImageLocalData _imageLocalData; + ImageShadowNode::ConcreteState::Shared _state; ImageResponseObserverCoordinator const *_coordinator; RCTImageResponseObserverProxy _imageResponseObserverProxy; } @@ -80,34 +79,28 @@ [super updateProps:props oldProps:oldProps]; } -- (void)updateLocalData:(SharedLocalData)localData oldLocalData:(SharedLocalData)oldLocalData +- (void)updateState:(facebook::react::State::Shared const &)state + oldState:(facebook::react::State::Shared const &)oldState { - auto imageLocalData = std::static_pointer_cast(localData); + _state = std::static_pointer_cast(state); + auto _oldState = std::static_pointer_cast(oldState); + auto data = _state->getData(); - // This call (setting `coordinator`) must be unconditional (at the same block as setting `LocalData`) - // because the setter stores a raw pointer to object that `LocalData` owns. - self.coordinator = imageLocalData ? &imageLocalData->getImageRequest().getObserverCoordinator() : nullptr; + // This call (setting `coordinator`) must be unconditional (at the same block as setting `State`) + // because the setter stores a raw pointer to object that `State` owns. + self.coordinator = &data.getImageRequest().getObserverCoordinator(); - auto previousData = _imageLocalData; - _imageLocalData = imageLocalData; + bool havePreviousData = _oldState && _oldState->getData().getImageSource() != ImageSource{}; - if (!_imageLocalData) { - // This might happen in very rare cases (e.g. inside a subtree inside a node with `display: none`). - // That's quite normal. - return; - } - - bool havePreviousData = previousData != nullptr; - - if (!havePreviousData || _imageLocalData->getImageSource() != previousData->getImageSource()) { + if (!havePreviousData || data.getImageSource() != _oldState->getData().getImageSource()) { // Loading actually starts a little before this, but this is the first time we know // the image is loading and can fire an event from this component std::static_pointer_cast(_eventEmitter)->onLoadStart(); // TODO (T58941612): Tracking for visibility should be done directly on this class. // For now, we consolidate instrumentation logic in the image loader, so that pre-Fabric gets the same treatment. - auto instrumentation = std::static_pointer_cast( - _imageLocalData->getImageRequest().getSharedImageInstrumentation()); + auto instrumentation = std::static_pointer_cast( + data.getImageRequest().getSharedImageInstrumentation()); instrumentation->trackNativeImageView(self); } } @@ -128,7 +121,7 @@ [super prepareForRecycle]; self.coordinator = nullptr; _imageView.image = nil; - _imageLocalData.reset(); + _state.reset(); } - (void)dealloc @@ -171,7 +164,7 @@ self->_imageView.layer.minificationFilter = kCAFilterTrilinear; self->_imageView.layer.magnificationFilter = kCAFilterTrilinear; - _imageLocalData->getImageRequest().getImageInstrumentation().didSetImage(); + _state->getData().getImageRequest().getImageInstrumentation().didSetImage(); } - (void)didReceiveProgress:(float)progress fromObserver:(void const *)observer diff --git a/ReactCommon/fabric/components/image/ImageLocalData.cpp b/ReactCommon/fabric/components/image/ImageLocalData.cpp deleted file mode 100644 index c81fe1296b7..00000000000 --- a/ReactCommon/fabric/components/image/ImageLocalData.cpp +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its affiliates. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -#include "ImageLocalData.h" - -#include -#include - -namespace facebook { -namespace react { - -ImageSource ImageLocalData::getImageSource() const { - return imageSource_; -} - -const ImageRequest &ImageLocalData::getImageRequest() const { - return imageRequest_; -} - -#pragma mark - DebugStringConvertible - -#if RN_DEBUG_STRING_CONVERTIBLE -std::string ImageLocalData::getDebugName() const { - return "ImageLocalData"; -} - -SharedDebugStringConvertibleList ImageLocalData::getDebugProps() const { - return {debugStringConvertibleItem("imageSource", imageSource_)}; -} -#endif - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/fabric/components/image/ImageLocalData.h b/ReactCommon/fabric/components/image/ImageLocalData.h deleted file mode 100644 index 5ec88b985e8..00000000000 --- a/ReactCommon/fabric/components/image/ImageLocalData.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) Facebook, Inc. and its 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 -#include -#include - -namespace facebook { -namespace react { - -class ImageLocalData; - -using SharedImageLocalData = std::shared_ptr; - -/* - * LocalData for component. - * Represents the image request state and (possible) retrieved image bitmap. - */ -class ImageLocalData : public LocalData { - public: - ImageLocalData(const ImageSource &imageSource, ImageRequest imageRequest) - : imageSource_(imageSource), imageRequest_(std::move(imageRequest)){}; - - /* - * Returns stored ImageSource object. - */ - ImageSource getImageSource() const; - - /* - * Exposes for reading stored `ImageRequest` object. - * `ImageRequest` object cannot be copied or moved from `ImageLocalData`. - */ - const ImageRequest &getImageRequest() const; - -#pragma mark - DebugStringConvertible - -#if RN_DEBUG_STRING_CONVERTIBLE - std::string getDebugName() const override; - SharedDebugStringConvertibleList getDebugProps() const override; -#endif - - private: - ImageSource imageSource_; - ImageRequest imageRequest_; -}; - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/fabric/components/image/ImageShadowNode.cpp b/ReactCommon/fabric/components/image/ImageShadowNode.cpp index 52f1fadb0b9..91ae574856c 100644 --- a/ReactCommon/fabric/components/image/ImageShadowNode.cpp +++ b/ReactCommon/fabric/components/image/ImageShadowNode.cpp @@ -8,9 +8,9 @@ #include #include -#include #include #include +#include "ImageState.h" namespace facebook { namespace react { @@ -22,27 +22,19 @@ void ImageShadowNode::setImageManager(const SharedImageManager &imageManager) { imageManager_ = imageManager; } -void ImageShadowNode::updateLocalData() { - const auto &imageSource = getImageSource(); - const auto ¤tLocalData = getLocalData(); - if (currentLocalData) { - assert(std::dynamic_pointer_cast(currentLocalData)); - auto currentImageLocalData = - std::static_pointer_cast(currentLocalData); - if (currentImageLocalData->getImageSource() == imageSource) { - // Same `imageSource` is already in `localData`, - // no need to (re)request an image resource. - return; - } - } - - // Now we are about to mutate the Shadow Node. +void ImageShadowNode::updateStateIfNeeded() { ensureUnsealed(); - auto imageRequest = imageManager_->requestImage(imageSource, getSurfaceId()); - auto imageLocalData = - std::make_shared(imageSource, std::move(imageRequest)); - setLocalData(imageLocalData); + auto const &imageSource = getImageSource(); + auto const ¤tState = getStateData(); + + if (currentState.getImageSource() == imageSource) { + return; + } + + auto state = ImageState{ + imageSource, imageManager_->requestImage(imageSource, getSurfaceId())}; + setStateData(std::move(state)); } ImageSource ImageShadowNode::getImageSource() const { @@ -86,7 +78,7 @@ ImageSource ImageShadowNode::getImageSource() const { #pragma mark - LayoutableShadowNode void ImageShadowNode::layout(LayoutContext layoutContext) { - updateLocalData(); + updateStateIfNeeded(); ConcreteViewShadowNode::layout(layoutContext); } diff --git a/ReactCommon/fabric/components/image/ImageShadowNode.h b/ReactCommon/fabric/components/image/ImageShadowNode.h index ae4bb4307aa..0dbd5f8990b 100644 --- a/ReactCommon/fabric/components/image/ImageShadowNode.h +++ b/ReactCommon/fabric/components/image/ImageShadowNode.h @@ -9,6 +9,7 @@ #include #include +#include #include #include #include @@ -24,7 +25,8 @@ extern const char ImageComponentName[]; class ImageShadowNode final : public ConcreteViewShadowNode< ImageComponentName, ImageProps, - ImageEventEmitter> { + ImageEventEmitter, + ImageState> { public: using ConcreteViewShadowNode::ConcreteViewShadowNode; @@ -38,14 +40,11 @@ class ImageShadowNode final : public ConcreteViewShadowNode< void layout(LayoutContext layoutContext) override; private: - /* - * (Re)Creates a `LocalData` object (with `ImageRequest`) if needed. - */ - void updateLocalData(); - ImageSource getImageSource() const; SharedImageManager imageManager_; + + void updateStateIfNeeded(); }; } // namespace react diff --git a/ReactCommon/fabric/components/image/ImageState.cpp b/ReactCommon/fabric/components/image/ImageState.cpp new file mode 100644 index 00000000000..3521716d0b7 --- /dev/null +++ b/ReactCommon/fabric/components/image/ImageState.cpp @@ -0,0 +1,22 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include "ImageState.h" + +namespace facebook { +namespace react { + +ImageSource ImageState::getImageSource() const { + return imageSource_; +} + +ImageRequest const &ImageState::getImageRequest() const { + return *imageRequest_; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/image/ImageState.h b/ReactCommon/fabric/components/image/ImageState.h new file mode 100644 index 00000000000..8d591af4d42 --- /dev/null +++ b/ReactCommon/fabric/components/image/ImageState.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) Facebook, Inc. and its 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 +#include +#include + +namespace facebook { +namespace react { + +/* + * State for component. + */ +class ImageState final { + public: + ImageState(ImageSource const &imageSource, ImageRequest imageRequest) + : imageSource_(imageSource), + imageRequest_( + std::make_shared(std::move(imageRequest))){}; + + ImageState() = default; + + /* + * Returns stored ImageSource object. + */ + ImageSource getImageSource() const; + + /* + * Exposes for reading stored `ImageRequest` object. + * `ImageRequest` object cannot be copied or moved from `ImageLocalData`. + */ + ImageRequest const &getImageRequest() const; + +#ifdef ANDROID + ImageState(ImageState const &previousState, folly::dynamic data){}; + + /* + * Empty implementation for Android because it doesn't use this class. + */ + folly::dynamic getDynamic() const { + return {}; + }; +#endif + + private: + ImageSource imageSource_; + std::shared_ptr imageRequest_; +}; + +} // namespace react +} // namespace facebook