diff --git a/ReactCommon/fabric/attributedstring/AttributedStringBox.cpp b/ReactCommon/fabric/attributedstring/AttributedStringBox.cpp new file mode 100644 index 00000000000..d0846b7252d --- /dev/null +++ b/ReactCommon/fabric/attributedstring/AttributedStringBox.cpp @@ -0,0 +1,44 @@ +/* + * 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 "AttributedStringBox.h" + +namespace facebook { +namespace react { + +AttributedStringBox::AttributedStringBox() + : mode_(Mode::Value), + value_(std::make_shared(AttributedString{})), + opaquePointer_({}){}; + +AttributedStringBox::AttributedStringBox(AttributedString const &value) + : mode_(Mode::Value), + value_(std::make_shared(value)), + opaquePointer_({}){}; + +AttributedStringBox::AttributedStringBox( + std::shared_ptr const &opaquePointer) + : mode_(Mode::OpaquePointer), value_({}), opaquePointer_(opaquePointer) {} + +AttributedStringBox::Mode AttributedStringBox::getMode() const { + return mode_; +} + +AttributedString const &AttributedStringBox::getValue() const { + assert(mode_ == AttributedStringBox::Mode::Value); + assert(value_); + return *value_; +} + +std::shared_ptr AttributedStringBox::getOpaquePointer() const { + assert(mode_ == AttributedStringBox::Mode::OpaquePointer); + assert(opaquePointer_); + return opaquePointer_; +} + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/attributedstring/AttributedStringBox.h b/ReactCommon/fabric/attributedstring/AttributedStringBox.h new file mode 100644 index 00000000000..ee8cf099223 --- /dev/null +++ b/ReactCommon/fabric/attributedstring/AttributedStringBox.h @@ -0,0 +1,62 @@ +/* + * 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 + +namespace facebook { +namespace react { + +/* + * Represents an object storing a shared `AttributedString` or a shared pointer + * to some opaque platform-specific object that can be used as an attributed + * string. The class serves two main purposes: + * - Represent type-erased attributed string entity (which can be + * platform-specific or platform-independent); + * - Represent a container that can be copied with constant complexity. + */ +class AttributedStringBox final { + public: + enum class Mode { Value, OpaquePointer }; + + /* + * Default constructor constructs an empty string. + */ + AttributedStringBox(); + + /* + * Custom explicit constructors. + */ + explicit AttributedStringBox(AttributedString const &value); + explicit AttributedStringBox(std::shared_ptr const &opaquePointer); + + /* + * Movable, Copyable, Assignable. + */ + AttributedStringBox(AttributedStringBox const &other) = default; + AttributedStringBox(AttributedStringBox &&other) noexcept = default; + AttributedStringBox &operator=(AttributedStringBox const &other) = default; + AttributedStringBox &operator=(AttributedStringBox &&other) = default; + + /* + * Getters. + */ + Mode getMode() const; + AttributedString const &getValue() const; + std::shared_ptr getOpaquePointer() const; + + private: + Mode mode_; + std::shared_ptr value_; + std::shared_ptr opaquePointer_; +}; + +} // namespace react +} // namespace facebook diff --git a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp index e1a0be32944..de977c229d0 100644 --- a/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp +++ b/ReactCommon/fabric/components/text/paragraph/ParagraphShadowNode.cpp @@ -7,6 +7,7 @@ #include "ParagraphShadowNode.h" +#include #include "ParagraphState.h" namespace facebook { @@ -62,7 +63,9 @@ Size ParagraphShadowNode::measure(LayoutConstraints layoutConstraints) const { } return textLayoutManager_->measure( - attributedString, getProps()->paragraphAttributes, layoutConstraints); + AttributedStringBox{attributedString}, + getProps()->paragraphAttributes, + layoutConstraints); } void ParagraphShadowNode::layout(LayoutContext layoutContext) { diff --git a/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputShadowNode.cpp b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputShadowNode.cpp index 3affefe7f44..c0d7203a982 100644 --- a/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputShadowNode.cpp +++ b/ReactCommon/fabric/components/textinput/androidtextinput/AndroidTextInputShadowNode.cpp @@ -8,6 +8,7 @@ #include "AndroidTextInputShadowNode.h" #include +#include #include #include #include @@ -111,7 +112,9 @@ Size AndroidTextInputShadowNode::measure( } return textLayoutManager_->measure( - attributedString, getProps()->paragraphAttributes, layoutConstraints); + AttributedStringBox{attributedString}, + getProps()->paragraphAttributes, + layoutConstraints); } void AndroidTextInputShadowNode::layout(LayoutContext layoutContext) { diff --git a/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.cpp b/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.cpp index 88a7b161b18..9c96296129e 100644 --- a/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.cpp +++ b/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.cpp @@ -23,9 +23,11 @@ void *TextLayoutManager::getNativeTextLayoutManager() const { } Size TextLayoutManager::measure( - AttributedString attributedString, + AttributedStringBox attributedStringBox, ParagraphAttributes paragraphAttributes, LayoutConstraints layoutConstraints) const { + auto &attributedString = attributedStringBox.getValue(); + return measureCache_.get( MeasureCacheKey{attributedString, paragraphAttributes, layoutConstraints}, [&](MeasureCacheKey const &key) { diff --git a/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.h b/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.h index 1e126f311d5..06551d178d3 100644 --- a/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.h +++ b/ReactCommon/fabric/textlayoutmanager/platform/android/TextLayoutManager.h @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -35,7 +36,7 @@ class TextLayoutManager { * Measures `attributedString` using native text rendering infrastructure. */ Size measure( - AttributedString attributedString, + AttributedStringBox attributedStringBox, ParagraphAttributes paragraphAttributes, LayoutConstraints layoutConstraints) const; diff --git a/ReactCommon/fabric/textlayoutmanager/platform/ios/TextLayoutManager.h b/ReactCommon/fabric/textlayoutmanager/platform/ios/TextLayoutManager.h index 56ecc5f69a4..80a04e8e16c 100644 --- a/ReactCommon/fabric/textlayoutmanager/platform/ios/TextLayoutManager.h +++ b/ReactCommon/fabric/textlayoutmanager/platform/ios/TextLayoutManager.h @@ -9,7 +9,7 @@ #include -#include +#include #include #include #include @@ -34,7 +34,7 @@ class TextLayoutManager { * Measures `attributedString` using native text rendering infrastructure. */ Size measure( - AttributedString attributedString, + AttributedStringBox attributedStringBox, ParagraphAttributes paragraphAttributes, LayoutConstraints layoutConstraints) const; diff --git a/ReactCommon/fabric/textlayoutmanager/platform/ios/TextLayoutManager.mm b/ReactCommon/fabric/textlayoutmanager/platform/ios/TextLayoutManager.mm index 4d3f7ee861e..614c26e0f7b 100644 --- a/ReactCommon/fabric/textlayoutmanager/platform/ios/TextLayoutManager.mm +++ b/ReactCommon/fabric/textlayoutmanager/platform/ios/TextLayoutManager.mm @@ -30,10 +30,12 @@ void *TextLayoutManager::getNativeTextLayoutManager() const } Size TextLayoutManager::measure( - AttributedString attributedString, + AttributedStringBox attributedStringBox, ParagraphAttributes paragraphAttributes, LayoutConstraints layoutConstraints) const { + auto &attributedString = attributedStringBox.getValue(); + return measureCache_.get( MeasureCacheKey{attributedString, paragraphAttributes, layoutConstraints}, [&](MeasureCacheKey const &key) { RCTTextLayoutManager *textLayoutManager = (__bridge RCTTextLayoutManager *)self_;