use state in paragraph component (#24873)

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
This commit is contained in:
Eric Lewis 2019-05-20 09:46:23 -07:00 коммит произвёл Facebook Github Bot
Родитель c59da6eae8
Коммит 6ec19aba4e
12 изменённых файлов: 129 добавлений и 175 удалений

Просмотреть файл

@ -8,8 +8,8 @@
#import "RCTParagraphComponentView.h"
#import <react/components/text/ParagraphComponentDescriptor.h>
#import <react/components/text/ParagraphLocalData.h>
#import <react/components/text/ParagraphProps.h>
#import <react/components/text/ParagraphState.h>
#import <react/components/text/RawTextComponentDescriptor.h>
#import <react/components/text/TextComponentDescriptor.h>
#import <react/core/LocalData.h>
@ -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<const ParagraphLocalData>(localData);
assert(_paragraphLocalData);
_state = std::static_pointer_cast<ParagraphShadowNode::ConcreteState const>(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];

Просмотреть файл

@ -64,7 +64,7 @@ class ParagraphComponentDescriptor final
private:
SharedTextLayoutManager textLayoutManager_;
std::unique_ptr<const ParagraphMeasurementCache> measureCache_;
std::unique_ptr<ParagraphMeasurementCache const> measureCache_;
};
} // namespace react

Просмотреть файл

@ -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 <react/components/text/conversions.h>
#include <react/debug/debugStringConvertibleUtils.h>
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

Просмотреть файл

@ -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 <react/attributedstring/AttributedString.h>
#include <react/core/LocalData.h>
#include <react/textlayoutmanager/TextLayoutManager.h>
namespace facebook {
namespace react {
class ParagraphLocalData;
using SharedParagraphLocalData = std::shared_ptr<const ParagraphLocalData>;
/*
* LocalData for <Paragraph> component.
* Represents what to render and how to render.
*/
class ParagraphLocalData : public LocalData {
public:
/*
* All content of <Paragraph> 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

Просмотреть файл

@ -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(

Просмотреть файл

@ -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

Просмотреть файл

@ -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<const ParagraphLocalData>(getLocalData());
if (currentLocalData &&
currentLocalData->getAttributedString() == attributedString) {
auto const &state = getStateData();
if (state.attributedString == attributedString) {
return;
}
auto localData = std::make_shared<ParagraphLocalData>();
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);
}

Просмотреть файл

@ -10,6 +10,7 @@
#include <folly/Optional.h>
#include <react/components/text/ParagraphMeasurementCache.h>
#include <react/components/text/ParagraphProps.h>
#include <react/components/text/ParagraphState.h>
#include <react/components/text/TextShadowNode.h>
#include <react/components/view/ConcreteViewShadowNode.h>
#include <react/core/ConcreteShadowNode.h>
@ -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

Просмотреть файл

@ -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 <react/components/text/conversions.h>
#include <react/debug/debugStringConvertibleUtils.h>
namespace facebook {
namespace react {
#ifdef ANDROID
folly::dynamic ParagraphState::getDynamic() const {
return toDynamic(*this);
}
#endif
} // namespace react
} // namespace facebook

Просмотреть файл

@ -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 <react/attributedstring/AttributedString.h>
#include <react/textlayoutmanager/TextLayoutManager.h>
#ifdef ANDROID
#include <folly/dynamic.h>
#endif
namespace facebook {
namespace react {
/*
* State for <Paragraph> component.
* Represents what to render and how to render.
*/
class ParagraphState final {
public:
/*
* All content of <Paragraph> 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

Просмотреть файл

@ -5,21 +5,18 @@
#include <folly/dynamic.h>
#include <react/attributedstring/conversions.h>
#include <react/components/text/ParagraphLocalData.h>
#include <react/components/text/ParagraphState.h>
namespace facebook {
namespace react {
#ifdef ANDROID
inline folly::dynamic toDynamic(const ParagraphLocalData &paragraphLocalData) {
folly::dynamic newLocalData = folly::dynamic::object();
newLocalData["attributedString"] =
toDynamic(paragraphLocalData.getAttributedString());
newLocalData["hash"] = newLocalData["attributedString"]["hash"];
return newLocalData;
inline folly::dynamic toDynamic(ParagraphState const &paragraphState) {
folly::dynamic newState = folly::dynamic::object();
newState["attributedString"] = toDynamic(paragraphState.attributedString);
newState["hash"] = newState["attributedString"]["hash"];
return newState;
}
#endif
} // namespace react

Просмотреть файл

@ -12,7 +12,7 @@
#include <react/attributedstring/AttributedString.h>
#include <react/attributedstring/TextAttributes.h>
#include <react/attributedstring/primitives.h>
#include <react/components/text/ParagraphLocalData.h>
#include <react/components/text/ParagraphState.h>
#include <react/components/text/conversions.h>
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"];