From 6ec19aba4eb908b0005af7e577ce91432176ef6f Mon Sep 17 00:00:00 2001 From: Eric Lewis Date: Mon, 20 May 2019 09:46:23 -0700 Subject: [PATCH] use state in paragraph component (#24873) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Updates the paragraph component to use State instead of Local Data, part of the path to a Fabric TextInput 💯 ## Changelog [General] [Changed] - Fabric: Use State instead of Local Data for Paragraph Pull Request resolved: https://github.com/facebook/react-native/pull/24873 Differential Revision: D15410979 Pulled By: shergin fbshipit-source-id: 3c9517d2495a64c4dbd213b6efb5ff55287900e3 --- .../Text/RCTParagraphComponentView.mm | 28 ++++----- .../paragraph/ParagraphComponentDescriptor.h | 2 +- .../text/paragraph/ParagraphLocalData.cpp | 58 ------------------- .../text/paragraph/ParagraphLocalData.h | 58 ------------------- .../text/paragraph/ParagraphProps.cpp | 8 +-- .../text/paragraph/ParagraphProps.h | 6 +- .../text/paragraph/ParagraphShadowNode.cpp | 28 ++++----- .../text/paragraph/ParagraphShadowNode.h | 16 ++--- .../text/paragraph/ParagraphState.cpp | 23 ++++++++ .../text/paragraph/ParagraphState.h | 52 +++++++++++++++++ .../components/text/paragraph/conversions.h | 15 ++--- .../text/tests/ParagraphLocalDataTest.cpp | 10 ++-- 12 files changed, 129 insertions(+), 175 deletions(-) delete mode 100644 ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.cpp delete mode 100644 ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.h create mode 100644 ReactCommon/fabric/components/text/paragraph/ParagraphState.cpp create mode 100644 ReactCommon/fabric/components/text/paragraph/ParagraphState.h diff --git a/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm b/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm index 9a64f5c30d..9497b406f5 100644 --- a/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm +++ b/React/Fabric/Mounting/ComponentViews/Text/RCTParagraphComponentView.mm @@ -8,8 +8,8 @@ #import "RCTParagraphComponentView.h" #import -#import #import +#import #import #import #import @@ -21,7 +21,7 @@ using namespace facebook::react; @implementation RCTParagraphComponentView { - SharedParagraphLocalData _paragraphLocalData; + ParagraphShadowNode::ConcreteState::Shared _state; ParagraphAttributes _paragraphAttributes; } @@ -63,32 +63,32 @@ using namespace facebook::react; _paragraphAttributes = paragraphProps->paragraphAttributes; } -- (void)updateLocalData:(SharedLocalData)localData oldLocalData:(SharedLocalData)oldLocalData +- (void)updateState:(State::Shared)state oldState:(State::Shared)oldState { - _paragraphLocalData = std::static_pointer_cast(localData); - assert(_paragraphLocalData); + _state = std::static_pointer_cast(state); + assert(_state); [self setNeedsDisplay]; } - (void)prepareForRecycle { [super prepareForRecycle]; - _paragraphLocalData.reset(); + _state.reset(); } - (void)drawRect:(CGRect)rect { - if (!_paragraphLocalData) { + if (!_state) { return; } - SharedTextLayoutManager textLayoutManager = _paragraphLocalData->getTextLayoutManager(); + SharedTextLayoutManager textLayoutManager = _state->getData().layoutManager; RCTTextLayoutManager *nativeTextLayoutManager = (__bridge RCTTextLayoutManager *)textLayoutManager->getNativeTextLayoutManager(); CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame()); - [nativeTextLayoutManager drawAttributedString:_paragraphLocalData->getAttributedString() + [nativeTextLayoutManager drawAttributedString:_state->getData().attributedString paragraphAttributes:_paragraphAttributes frame:frame]; } @@ -102,26 +102,26 @@ using namespace facebook::react; return superAccessibilityLabel; } - if (!_paragraphLocalData) { + if (!_state) { return nil; } - return RCTNSStringFromString(_paragraphLocalData->getAttributedString().getString()); + return RCTNSStringFromString(_state->getData().attributedString.getString()); } - (SharedTouchEventEmitter)touchEventEmitterAtPoint:(CGPoint)point { - if (!_paragraphLocalData) { + if (!_state) { return _eventEmitter; } - SharedTextLayoutManager textLayoutManager = _paragraphLocalData->getTextLayoutManager(); + SharedTextLayoutManager textLayoutManager = _state->getData().layoutManager; RCTTextLayoutManager *nativeTextLayoutManager = (__bridge RCTTextLayoutManager *)textLayoutManager->getNativeTextLayoutManager(); CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame()); SharedEventEmitter eventEmitter = - [nativeTextLayoutManager getEventEmitterWithAttributeString:_paragraphLocalData->getAttributedString() + [nativeTextLayoutManager getEventEmitterWithAttributeString:_state->getData().attributedString paragraphAttributes:_paragraphAttributes frame:frame atPoint:point]; diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h b/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h index 83a5292392..a0dd2abff7 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphComponentDescriptor.h @@ -64,7 +64,7 @@ class ParagraphComponentDescriptor final private: SharedTextLayoutManager textLayoutManager_; - std::unique_ptr measureCache_; + std::unique_ptr measureCache_; }; } // namespace react diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.cpp b/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.cpp deleted file mode 100644 index fb9426da99..0000000000 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.cpp +++ /dev/null @@ -1,58 +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 "ParagraphLocalData.h" - -#include -#include - -namespace facebook { -namespace react { - -AttributedString ParagraphLocalData::getAttributedString() const { - return attributedString_; -} - -void ParagraphLocalData::setAttributedString( - AttributedString attributedString) { - ensureUnsealed(); - attributedString_ = attributedString; -} - -SharedTextLayoutManager ParagraphLocalData::getTextLayoutManager() const { - return textLayoutManager_; -} - -void ParagraphLocalData::setTextLayoutManager( - SharedTextLayoutManager textLayoutManager) { - ensureUnsealed(); - textLayoutManager_ = textLayoutManager; -} - -#ifdef ANDROID - -folly::dynamic ParagraphLocalData::getDynamic() const { - return toDynamic(*this); -} - -#endif - -#pragma mark - DebugStringConvertible - -#if RN_DEBUG_STRING_CONVERTIBLE -std::string ParagraphLocalData::getDebugName() const { - return "ParagraphLocalData"; -} - -SharedDebugStringConvertibleList ParagraphLocalData::getDebugProps() const { - return { - debugStringConvertibleItem("attributedString", attributedString_, "")}; -} -#endif - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.h b/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.h deleted file mode 100644 index 15e3705735..0000000000 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphLocalData.h +++ /dev/null @@ -1,58 +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 ParagraphLocalData; - -using SharedParagraphLocalData = std::shared_ptr; - -/* - * LocalData for component. - * Represents what to render and how to render. - */ -class ParagraphLocalData : public LocalData { - public: - /* - * All content of component represented as an `AttributedString`. - */ - AttributedString getAttributedString() const; - void setAttributedString(AttributedString attributedString); - - /* - * `TextLayoutManager` provides a connection to platform-specific - * text rendering infrastructure which is capable to render the - * `AttributedString`. - */ - SharedTextLayoutManager getTextLayoutManager() const; - void setTextLayoutManager(SharedTextLayoutManager textLayoutManager); - -#ifdef ANDROID - folly::dynamic getDynamic() const override; -#endif - -#pragma mark - DebugStringConvertible - -#if RN_DEBUG_STRING_CONVERTIBLE - std::string getDebugName() const override; - SharedDebugStringConvertibleList getDebugProps() const override; -#endif - - private: - AttributedString attributedString_; - SharedTextLayoutManager textLayoutManager_; -}; - -} // namespace react -} // namespace facebook diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphProps.cpp b/ReactCommon/fabric/components/text/paragraph/ParagraphProps.cpp index d8135cd845..da79a25a1a 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphProps.cpp +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphProps.cpp @@ -15,8 +15,8 @@ namespace facebook { namespace react { static ParagraphAttributes convertRawProp( - const RawProps &rawProps, - const ParagraphAttributes &defaultParagraphAttributes) { + RawProps const &rawProps, + ParagraphAttributes const &defaultParagraphAttributes) { auto paragraphAttributes = ParagraphAttributes{}; paragraphAttributes.maximumNumberOfLines = convertRawProp( @@ -44,8 +44,8 @@ static ParagraphAttributes convertRawProp( } ParagraphProps::ParagraphProps( - const ParagraphProps &sourceProps, - const RawProps &rawProps) + ParagraphProps const &sourceProps, + RawProps const &rawProps) : ViewProps(sourceProps, rawProps), BaseTextProps(sourceProps, rawProps), paragraphAttributes( diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphProps.h b/ReactCommon/fabric/components/text/paragraph/ParagraphProps.h index 1e1ca67e15..c796eef638 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphProps.h +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphProps.h @@ -26,7 +26,7 @@ namespace react { class ParagraphProps : public ViewProps, public BaseTextProps { public: ParagraphProps() = default; - ParagraphProps(const ParagraphProps &sourceProps, const RawProps &rawProps); + ParagraphProps(ParagraphProps const &sourceProps, RawProps const &rawProps); #pragma mark - Props @@ -34,12 +34,12 @@ class ParagraphProps : public ViewProps, public BaseTextProps { * Contains all prop values that affect visual representation of the * paragraph. */ - const ParagraphAttributes paragraphAttributes{}; + ParagraphAttributes const paragraphAttributes{}; /* * Defines can the text be selected (and copied) or not. */ - const bool isSelectable{}; + bool const isSelectable{}; #pragma mark - DebugStringConvertible diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp index 028652ca5c..ec7f4af6be 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp @@ -6,13 +6,13 @@ */ #include "ParagraphShadowNode.h" -#include "ParagraphLocalData.h" #include "ParagraphMeasurementCache.h" +#include "ParagraphState.h" namespace facebook { namespace react { -const char ParagraphComponentName[] = "Paragraph"; +char const ParagraphComponentName[] = "Paragraph"; AttributedString ParagraphShadowNode::getAttributedString() const { if (!cachedAttributedString_.has_value()) { @@ -33,26 +33,21 @@ void ParagraphShadowNode::setTextLayoutManager( } void ParagraphShadowNode::setMeasureCache( - const ParagraphMeasurementCache *cache) { + ParagraphMeasurementCache const *cache) { ensureUnsealed(); measureCache_ = cache; } -void ParagraphShadowNode::updateLocalDataIfNeeded() { +void ParagraphShadowNode::updateStateIfNeeded() { ensureUnsealed(); auto attributedString = getAttributedString(); - auto currentLocalData = - std::static_pointer_cast(getLocalData()); - if (currentLocalData && - currentLocalData->getAttributedString() == attributedString) { + auto const &state = getStateData(); + if (state.attributedString == attributedString) { return; } - auto localData = std::make_shared(); - localData->setAttributedString(std::move(attributedString)); - localData->setTextLayoutManager(textLayoutManager_); - setLocalData(localData); + setStateData(ParagraphState{attributedString, textLayoutManager_}); } #pragma mark - LayoutableShadowNode @@ -64,15 +59,16 @@ Size ParagraphShadowNode::measure(LayoutConstraints layoutConstraints) const { return {0, 0}; } - const ParagraphAttributes paragraphAttributes = + ParagraphAttributes const paragraphAttributes = getProps()->paragraphAttributes; // Cache results of this function so we don't need to call measure() // repeatedly. if (measureCache_) { return measureCache_->get( - ParagraphMeasurementCacheKey{attributedString, paragraphAttributes, layoutConstraints}, - [&](const ParagraphMeasurementCacheKey &key) { + ParagraphMeasurementCacheKey{ + attributedString, paragraphAttributes, layoutConstraints}, + [&](ParagraphMeasurementCacheKey const &key) { return textLayoutManager_->measure( attributedString, paragraphAttributes, layoutConstraints); }); @@ -83,7 +79,7 @@ Size ParagraphShadowNode::measure(LayoutConstraints layoutConstraints) const { } void ParagraphShadowNode::layout(LayoutContext layoutContext) { - updateLocalDataIfNeeded(); + updateStateIfNeeded(); ConcreteViewShadowNode::layout(layoutContext); } diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h index 9d03af4a3a..dd738f169c 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -20,7 +21,7 @@ namespace facebook { namespace react { -extern const char ParagraphComponentName[]; +extern char const ParagraphComponentName[]; using ParagraphEventEmitter = ViewEventEmitter; @@ -32,7 +33,8 @@ using ParagraphEventEmitter = ViewEventEmitter; class ParagraphShadowNode : public ConcreteViewShadowNode< ParagraphComponentName, ParagraphProps, - ParagraphEventEmitter>, + ParagraphEventEmitter, + ParagraphState>, public BaseTextShadowNode { public: using ConcreteViewShadowNode::ConcreteViewShadowNode; @@ -45,7 +47,7 @@ class ParagraphShadowNode : public ConcreteViewShadowNode< /* * Associates a shared TextLayoutManager with the node. * `ParagraphShadowNode` uses the manager to measure text content - * and construct `ParagraphLocalData` objects. + * and construct `ParagraphState` objects. */ void setTextLayoutManager(SharedTextLayoutManager textLayoutManager); @@ -56,7 +58,7 @@ class ParagraphShadowNode : public ConcreteViewShadowNode< * By design, the ParagraphComponentDescriptor outlives all * shadow nodes, so it's safe for this to be a raw pointer. */ - void setMeasureCache(const ParagraphMeasurementCache *cache); + void setMeasureCache(ParagraphMeasurementCache const *cache); #pragma mark - LayoutableShadowNode @@ -65,13 +67,13 @@ class ParagraphShadowNode : public ConcreteViewShadowNode< private: /* - * Creates a `LocalData` object (with `AttributedText` and + * Creates a `State` object (with `AttributedText` and * `TextLayoutManager`) if needed. */ - void updateLocalDataIfNeeded(); + void updateStateIfNeeded(); SharedTextLayoutManager textLayoutManager_; - const ParagraphMeasurementCache *measureCache_; + ParagraphMeasurementCache const *measureCache_; /* * Cached attributed string that represents the content of the subtree started diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphState.cpp b/ReactCommon/fabric/components/text/paragraph/ParagraphState.cpp new file mode 100644 index 0000000000..89a7c442c1 --- /dev/null +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphState.cpp @@ -0,0 +1,23 @@ +/** + * 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 "ParagraphState.h" + +#include +#include + +namespace facebook { +namespace react { + +#ifdef ANDROID +folly::dynamic ParagraphState::getDynamic() const { + return toDynamic(*this); +} +#endif + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphState.h b/ReactCommon/fabric/components/text/paragraph/ParagraphState.h new file mode 100644 index 0000000000..e5ae4be756 --- /dev/null +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphState.h @@ -0,0 +1,52 @@ +/** + * 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 + +#ifdef ANDROID +#include +#endif + +namespace facebook { +namespace react { + +/* + * State for component. + * Represents what to render and how to render. + */ +class ParagraphState final { + public: + /* + * All content of component represented as an `AttributedString`. + */ + AttributedString attributedString; + + /* + * `TextLayoutManager` provides a connection to platform-specific + * text rendering infrastructure which is capable to render the + * `AttributedString`. + */ + SharedTextLayoutManager layoutManager; + +#ifdef ANDROID + ParagraphState( + AttributedString const &attributedString, + SharedTextLayoutManager const &layoutManager) + : attributedString(attributedString), layoutManager(layoutManager) {} + ParagraphState() = default; + ParagraphState(folly::dynamic const &data) { + assert(false && "Not supported"); + }; + folly::dynamic getDynamic() const; +#endif +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/text/paragraph/conversions.h b/ReactCommon/fabric/components/text/paragraph/conversions.h index dd507cefa0..12d53b1d54 100644 --- a/ReactCommon/fabric/components/text/paragraph/conversions.h +++ b/ReactCommon/fabric/components/text/paragraph/conversions.h @@ -5,21 +5,18 @@ #include #include -#include +#include namespace facebook { namespace react { #ifdef ANDROID - -inline folly::dynamic toDynamic(const ParagraphLocalData ¶graphLocalData) { - folly::dynamic newLocalData = folly::dynamic::object(); - newLocalData["attributedString"] = - toDynamic(paragraphLocalData.getAttributedString()); - newLocalData["hash"] = newLocalData["attributedString"]["hash"]; - return newLocalData; +inline folly::dynamic toDynamic(ParagraphState const ¶graphState) { + folly::dynamic newState = folly::dynamic::object(); + newState["attributedString"] = toDynamic(paragraphState.attributedString); + newState["hash"] = newState["attributedString"]["hash"]; + return newState; } - #endif } // namespace react diff --git a/ReactCommon/fabric/components/text/tests/ParagraphLocalDataTest.cpp b/ReactCommon/fabric/components/text/tests/ParagraphLocalDataTest.cpp index accf32c0b7..48b09cc6d3 100644 --- a/ReactCommon/fabric/components/text/tests/ParagraphLocalDataTest.cpp +++ b/ReactCommon/fabric/components/text/tests/ParagraphLocalDataTest.cpp @@ -12,7 +12,7 @@ #include #include #include -#include +#include #include namespace facebook { @@ -21,7 +21,7 @@ namespace react { #ifdef ANDROID TEST(ParagraphLocalDataTest, testSomething) { - auto attString = AttributedString(); + auto attributedString = AttributedString(); auto fragment = AttributedString::Fragment(); fragment.string = "test"; @@ -35,10 +35,10 @@ TEST(ParagraphLocalDataTest, testSomething) { fragment.textAttributes = text; attString.prependFragment(fragment); - auto paragraphLocalData = ParagraphLocalData(); - paragraphLocalData.setAttributedString(attString); + auto paragraphState = ParagraphState{}; + paragraphLocalData.attributedString = attributedString; - auto result = toDynamic(paragraphLocalData)["attributedString"]; + auto result = toDynamic(paragraphState)["attributedString"]; assert(result["string"] == fragment.string); auto textAttribute = result["fragments"][0]["textAttributes"];