diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp index 26f7e28e18b..c4835e55d4f 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp @@ -15,20 +15,24 @@ namespace react { char const ParagraphComponentName[] = "Paragraph"; -AttributedString ParagraphShadowNode::getAttributedString() const { - if (!cachedAttributedString_.has_value()) { - auto textAttributes = TextAttributes::defaultTextAttributes(); - textAttributes.apply(getConcreteProps().textAttributes); - - auto attributedString = AttributedString{}; - auto attachments = Attachments{}; - BaseTextShadowNode::buildAttributedString( - textAttributes, *this, attributedString, attachments); - - cachedAttributedString_ = attributedString; +ParagraphShadowNode::Content const &ParagraphShadowNode::getContent() const { + if (content_.has_value()) { + return content_.value(); } - return cachedAttributedString_.value(); + ensureUnsealed(); + + auto textAttributes = TextAttributes::defaultTextAttributes(); + textAttributes.apply(getConcreteProps().textAttributes); + + auto attributedString = AttributedString{}; + auto attachments = Attachments{}; + buildAttributedString(textAttributes, *this, attributedString, attachments); + + content_ = Content{ + attributedString, getConcreteProps().paragraphAttributes, attachments}; + + return content_.value(); } void ParagraphShadowNode::setTextLayoutManager( @@ -37,44 +41,43 @@ void ParagraphShadowNode::setTextLayoutManager( textLayoutManager_ = textLayoutManager; } -void ParagraphShadowNode::updateStateIfNeeded() { +void ParagraphShadowNode::updateStateIfNeeded(Content const &content) { ensureUnsealed(); - auto attributedString = getAttributedString(); - auto const &state = getStateData(); + auto &state = getStateData(); assert(textLayoutManager_); assert( (!state.layoutManager || state.layoutManager == textLayoutManager_) && "`StateData` refers to a different `TextLayoutManager`"); - if (state.attributedString == attributedString && + if (state.attributedString == content.attributedString && state.layoutManager == textLayoutManager_) { return; } - setStateData(ParagraphState{attributedString, - getConcreteProps().paragraphAttributes, + setStateData(ParagraphState{content.attributedString, + content.paragraphAttributes, textLayoutManager_}); } #pragma mark - LayoutableShadowNode Size ParagraphShadowNode::measure(LayoutConstraints layoutConstraints) const { - AttributedString attributedString = getAttributedString(); + auto content = getContent(); - if (attributedString.isEmpty()) { + if (content.attributedString.isEmpty()) { return layoutConstraints.clamp({0, 0}); } return textLayoutManager_->measure( - AttributedStringBox{attributedString}, - getConcreteProps().paragraphAttributes, + AttributedStringBox{content.attributedString}, + content.paragraphAttributes, layoutConstraints); } void ParagraphShadowNode::layout(LayoutContext layoutContext) { - updateStateIfNeeded(); + updateStateIfNeeded(getContent()); ConcreteViewShadowNode::layout(layoutContext); } diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h index a2ef23dc68e..b5874d01391 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.h @@ -45,11 +45,6 @@ class ParagraphShadowNode : public ConcreteViewShadowNode< return traits; } - /* - * Returns a `AttributedString` which represents text content of the node. - */ - AttributedString getAttributedString() const; - /* * Associates a shared TextLayoutManager with the node. * `ParagraphShadowNode` uses the manager to measure text content @@ -63,19 +58,34 @@ class ParagraphShadowNode : public ConcreteViewShadowNode< Size measure(LayoutConstraints layoutConstraints) const override; private: + /* + * Internal representation of the nested content of the node in a format + * suitable for future processing. + */ + class Content final { + public: + AttributedString attributedString; + ParagraphAttributes paragraphAttributes; + Attachments attachments; + }; + + /* + * Builds (if needed) and returns a reference to a `Content` object. + */ + Content const &getContent() const; + /* * Creates a `State` object (with `AttributedText` and * `TextLayoutManager`) if needed. */ - void updateStateIfNeeded(); + void updateStateIfNeeded(Content const &content); SharedTextLayoutManager textLayoutManager_; /* - * Cached attributed string that represents the content of the subtree started - * from the node. + * Cached content of the subtree started from the node. */ - mutable folly::Optional cachedAttributedString_{}; + mutable better::optional content_{}; }; } // namespace react