Fabric: Using ShadowView instad of ShadowNode inside AttributedString

Summary:
That's generally better because:
 * Avoids exposing ShadowNode to mounting layer;
 * Enables hashing and comparing the AttributedString based on actual meaningful data (not on just a pointer to ShadowNode).

Reviewed By: mdvacca

Differential Revision: D13205230

fbshipit-source-id: 7b79c1aad97b10d81e3faa10408be61b74f815cf
This commit is contained in:
Valentin Shergin
2018-11-27 18:29:39 -08:00
committed by Facebook Github Bot
parent 6c3b05f343
commit 7197aa026b
6 changed files with 21 additions and 26 deletions

View File

@@ -18,12 +18,12 @@ using Fragments = AttributedString::Fragments;
#pragma mark - Fragment
bool Fragment::operator==(const Fragment &rhs) const {
return std::tie(string, textAttributes, shadowNode, parentShadowNode) ==
return std::tie(string, textAttributes, shadowView, parentShadowView) ==
std::tie(
rhs.string,
rhs.textAttributes,
rhs.shadowNode,
rhs.parentShadowNode);
rhs.shadowView,
rhs.parentShadowView);
}
bool Fragment::operator!=(const Fragment &rhs) const {
@@ -90,11 +90,6 @@ SharedDebugStringConvertibleList AttributedString::getDebugChildren() const {
auto propsList =
fragment.textAttributes.DebugStringConvertible::getDebugProps();
if (fragment.shadowNode) {
propsList.push_back(std::make_shared<DebugStringConvertibleItem>(
"shadowNode", fragment.shadowNode->getDebugDescription()));
}
list.push_back(std::make_shared<DebugStringConvertibleItem>(
"Fragment",
fragment.string,

View File

@@ -15,6 +15,7 @@
#include <react/core/Sealable.h>
#include <react/core/ShadowNode.h>
#include <react/debug/DebugStringConvertible.h>
#include <react/mounting/ShadowView.h>
namespace facebook {
namespace react {
@@ -35,8 +36,8 @@ class AttributedString : public Sealable, public DebugStringConvertible {
public:
std::string string;
TextAttributes textAttributes;
SharedShadowNode shadowNode;
SharedShadowNode parentShadowNode;
ShadowView shadowView;
ShadowView parentShadowView;
bool operator==(const Fragment &rhs) const;
bool operator!=(const Fragment &rhs) const;
@@ -89,7 +90,11 @@ struct hash<facebook::react::AttributedString::Fragment> {
size_t operator()(
const facebook::react::AttributedString::Fragment &fragment) const {
return std::hash<decltype(fragment.string)>{}(fragment.string) +
std::hash<decltype(fragment.textAttributes)>{}(fragment.textAttributes);
std::hash<decltype(fragment.textAttributes)>{}(
fragment.textAttributes) +
std::hash<decltype(fragment.shadowView)>{}(fragment.shadowView) +
std::hash<decltype(fragment.parentShadowView)>{}(
fragment.parentShadowView);
}
};

View File

@@ -59,6 +59,7 @@ rn_xplat_cxx_library(
react_native_xplat_target("fabric/debug:debug"),
react_native_xplat_target("fabric/core:core"),
react_native_xplat_target("fabric/graphics:graphics"),
react_native_xplat_target("fabric/mounting:mounting"),
],
)

View File

@@ -478,8 +478,8 @@ inline folly::dynamic toDynamic(const AttributedString &attributedString) {
for (auto fragment : attributedString.getFragments()) {
folly::dynamic dynamicFragment = folly::dynamic::object();
dynamicFragment["string"] = fragment.string;
if (fragment.parentShadowNode) {
dynamicFragment["reactTag"] = fragment.parentShadowNode->getTag();
if (fragment.parentShadowView.componentHandle) {
dynamicFragment["reactTag"] = fragment.parentShadowView.tag;
}
dynamicFragment["textAttributes"] = toDynamic(fragment.textAttributes);
fragments.push_back(dynamicFragment);

View File

@@ -12,6 +12,7 @@
#include <react/components/text/TextProps.h>
#include <react/components/text/TextShadowNode.h>
#include <react/debug/DebugStringConvertibleItem.h>
#include <react/mounting/ShadowView.h>
namespace facebook {
namespace react {
@@ -34,10 +35,7 @@ AttributedString BaseTextShadowNode::getAttributedString(
// `attributedString` causes a retain cycle (besides that fact that we
// don't need it at all). Storing a `ShadowView` instance instead of
// `ShadowNode` should properly fix this problem.
fragment.parentShadowNode =
std::dynamic_pointer_cast<const TextShadowNode>(parentNode)
? parentNode
: nullptr;
fragment.parentShadowView = ShadowView(*parentNode);
attributedString.appendFragment(fragment);
continue;
}
@@ -56,7 +54,7 @@ AttributedString BaseTextShadowNode::getAttributedString(
// Any other kind of ShadowNode
auto fragment = AttributedString::Fragment{};
fragment.shadowNode = childNode;
fragment.shadowView = ShadowView(*childNode);
fragment.textAttributes = textAttributes;
attributedString.appendFragment(fragment);
}

View File

@@ -229,12 +229,9 @@ NSAttributedString *RCTNSAttributedStringFromAttributedString(
for (auto fragment : attributedString.getFragments()) {
NSAttributedString *nsAttributedStringFragment;
auto layoutableShadowNode =
std::dynamic_pointer_cast<const LayoutableShadowNode>(
fragment.shadowNode);
auto layoutMetrics = fragment.shadowView.layoutMetrics;
if (layoutableShadowNode) {
auto layoutMetrics = layoutableShadowNode->getLayoutMetrics();
if (layoutMetrics != EmptyLayoutMetrics) {
CGRect bounds = {.origin = {.x = layoutMetrics.frame.origin.x,
.y = layoutMetrics.frame.origin.y},
.size = {.width = layoutMetrics.frame.size.width,
@@ -259,11 +256,10 @@ NSAttributedString *RCTNSAttributedStringFromAttributedString(
[[NSMutableAttributedString alloc]
initWithAttributedString:nsAttributedStringFragment];
if (fragment.parentShadowNode) {
if (fragment.parentShadowView.componentHandle) {
RCTWeakEventEmitterWrapper *eventEmitterWrapper =
[RCTWeakEventEmitterWrapper new];
eventEmitterWrapper.eventEmitter =
fragment.parentShadowNode->getEventEmitter();
eventEmitterWrapper.eventEmitter = fragment.parentShadowView.eventEmitter;
NSDictionary<NSAttributedStringKey, id> *additionalTextAttributes =
@{RCTAttributedStringEventEmitterKey : eventEmitterWrapper};