mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Cache NSTextStorage
Summary: changelog: [internal] This diff introduces a mechanism to cache NSTextStorage on Paragraph's state. The old renderer already has caching for NSTextStorage: https://github.com/facebook/react-native/blob/main/Libraries/Text/Text/RCTTextShadowView.m#L21 Fabric will store `NSTextStorage` inside `ParagraphLayoutManager` which is owned by state. There is one notable change which is not gated: Paragraph's state strongly owns `TextLayoutManager`, not `ParagraphShadowNode` like previously. This shouldn't change anything Reviewed By: mdvacca Differential Revision: D43692171 fbshipit-source-id: efe6077222a30ab6d89abd9916534b9a96e745d4
This commit is contained in:
1 parent
a5bc6f0574
commit
d41e95fb1a
20 files changed
+279
-90
No files matched your search
@@ -116,11 +116,8 @@ using namespace facebook::react;
|
||||
return;
|
||||
}
|
||||
|
||||
auto textLayoutManager = _state->getData().layoutManager.lock();
|
||||
|
||||
if (!textLayoutManager) {
|
||||
return;
|
||||
}
|
||||
auto textLayoutManager = _state->getData().paragraphLayoutManager.getTextLayoutManager();
|
||||
auto nsTextStorage = _state->getData().paragraphLayoutManager.getHostTextStorage();
|
||||
|
||||
RCTTextLayoutManager *nativeTextLayoutManager =
|
||||
(RCTTextLayoutManager *)unwrapManagedObject(textLayoutManager->getNativeTextLayoutManager());
|
||||
@@ -129,7 +126,8 @@ using namespace facebook::react;
|
||||
|
||||
[nativeTextLayoutManager drawAttributedString:_state->getData().attributedString
|
||||
paragraphAttributes:_paragraphAttributes
|
||||
frame:frame];
|
||||
frame:frame
|
||||
textStorage:unwrapManagedObject(nsTextStorage)];
|
||||
}
|
||||
|
||||
#pragma mark - Accessibility
|
||||
@@ -161,18 +159,15 @@ using namespace facebook::react;
|
||||
auto &data = _state->getData();
|
||||
|
||||
if (![_accessibilityProvider isUpToDate:data.attributedString]) {
|
||||
auto textLayoutManager = data.layoutManager.lock();
|
||||
if (textLayoutManager) {
|
||||
RCTTextLayoutManager *nativeTextLayoutManager =
|
||||
(RCTTextLayoutManager *)unwrapManagedObject(textLayoutManager->getNativeTextLayoutManager());
|
||||
CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
|
||||
_accessibilityProvider =
|
||||
[[RCTParagraphComponentAccessibilityProvider alloc] initWithString:data.attributedString
|
||||
layoutManager:nativeTextLayoutManager
|
||||
paragraphAttributes:data.paragraphAttributes
|
||||
frame:frame
|
||||
view:self];
|
||||
}
|
||||
auto textLayoutManager = data.paragraphLayoutManager.getTextLayoutManager();
|
||||
RCTTextLayoutManager *nativeTextLayoutManager =
|
||||
(RCTTextLayoutManager *)unwrapManagedObject(textLayoutManager->getNativeTextLayoutManager());
|
||||
CGRect frame = RCTCGRectFromRect(_layoutMetrics.getContentFrame());
|
||||
_accessibilityProvider = [[RCTParagraphComponentAccessibilityProvider alloc] initWithString:data.attributedString
|
||||
layoutManager:nativeTextLayoutManager
|
||||
paragraphAttributes:data.paragraphAttributes
|
||||
frame:frame
|
||||
view:self];
|
||||
}
|
||||
|
||||
return _accessibilityProvider.accessibilityElements;
|
||||
@@ -191,11 +186,7 @@ using namespace facebook::react;
|
||||
return _eventEmitter;
|
||||
}
|
||||
|
||||
auto textLayoutManager = _state->getData().layoutManager.lock();
|
||||
|
||||
if (!textLayoutManager) {
|
||||
return _eventEmitter;
|
||||
}
|
||||
auto textLayoutManager = _state->getData().paragraphLayoutManager.getTextLayoutManager();
|
||||
|
||||
RCTTextLayoutManager *nativeTextLayoutManager =
|
||||
(RCTTextLayoutManager *)unwrapManagedObject(textLayoutManager->getNativeTextLayoutManager());
|
||||
|
||||
@@ -281,6 +281,10 @@ static BackgroundExecutor RCTGetBackgroundExecutor()
|
||||
CoreFeatures::useNativeState = true;
|
||||
}
|
||||
|
||||
if (reactNativeConfig && reactNativeConfig->getBool("react_fabric:enable_nstextstorage_caching")) {
|
||||
CoreFeatures::cacheNSTextStorage = true;
|
||||
}
|
||||
|
||||
auto componentRegistryFactory =
|
||||
[factory = wrapManagedObject(_mountingManager.componentViewRegistry.componentViewFactory)](
|
||||
EventDispatcher::Weak const &eventDispatcher, ContextContainer::Shared const &contextContainer) {
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
#include "ParagraphLayoutManager.h"
|
||||
#include <folly/Hash.h>
|
||||
#include <react/renderer/core/CoreFeatures.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
TextMeasurement ParagraphLayoutManager::measure(
|
||||
AttributedString const &attributedString,
|
||||
ParagraphAttributes const ¶graphAttributes,
|
||||
LayoutConstraints layoutConstraints) const {
|
||||
if (CoreFeatures::cacheNSTextStorage) {
|
||||
size_t newHash = folly::hash::hash_combine(
|
||||
0,
|
||||
textAttributedStringHashLayoutWise(attributedString),
|
||||
paragraphAttributes);
|
||||
|
||||
if (!hostTextStorage_ || newHash != hash_) {
|
||||
hostTextStorage_ = textLayoutManager_->getHostTextStorage(
|
||||
attributedString, paragraphAttributes, layoutConstraints);
|
||||
hash_ = newHash;
|
||||
}
|
||||
}
|
||||
|
||||
return textLayoutManager_->measure(
|
||||
AttributedStringBox(attributedString),
|
||||
paragraphAttributes,
|
||||
layoutConstraints,
|
||||
hostTextStorage_);
|
||||
}
|
||||
|
||||
LinesMeasurements ParagraphLayoutManager::measureLines(
|
||||
AttributedString const &attributedString,
|
||||
ParagraphAttributes const ¶graphAttributes,
|
||||
Size size) const {
|
||||
return textLayoutManager_->measureLines(
|
||||
attributedString, paragraphAttributes, size);
|
||||
}
|
||||
|
||||
void ParagraphLayoutManager::setTextLayoutManager(
|
||||
std::shared_ptr<TextLayoutManager const> textLayoutManager) const {
|
||||
textLayoutManager_ = std::move(textLayoutManager);
|
||||
}
|
||||
|
||||
std::shared_ptr<TextLayoutManager const>
|
||||
ParagraphLayoutManager::getTextLayoutManager() const {
|
||||
return textLayoutManager_;
|
||||
}
|
||||
|
||||
std::shared_ptr<void> ParagraphLayoutManager::getHostTextStorage() const {
|
||||
return hostTextStorage_;
|
||||
}
|
||||
} // namespace facebook::react
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and 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/renderer/attributedstring/AttributedString.h>
|
||||
#include <react/renderer/attributedstring/ParagraphAttributes.h>
|
||||
#include <react/renderer/core/LayoutConstraints.h>
|
||||
#include <react/renderer/textlayoutmanager/TextLayoutManager.h>
|
||||
|
||||
namespace facebook::react {
|
||||
|
||||
/*
|
||||
* Serves as a middle man between `ParagraphShadowNode` and `TextLayoutManager`.
|
||||
* On iOS, caches `NSTextStorage` for individual `ParagraphShadowNode` to make
|
||||
* sure only one `NSTextStorage` is created for every string. `NSTextStorage`
|
||||
* can be re created on native views layer but it is expensive. On Android, this
|
||||
* class does not cache anything.
|
||||
*/
|
||||
class ParagraphLayoutManager {
|
||||
public:
|
||||
TextMeasurement measure(
|
||||
AttributedString const &attributedString,
|
||||
ParagraphAttributes const ¶graphAttributes,
|
||||
LayoutConstraints layoutConstraints) const;
|
||||
|
||||
LinesMeasurements measureLines(
|
||||
AttributedString const &attributedString,
|
||||
ParagraphAttributes const ¶graphAttributes,
|
||||
Size size) const;
|
||||
|
||||
void setTextLayoutManager(
|
||||
std::shared_ptr<TextLayoutManager const> textLayoutManager) const;
|
||||
|
||||
/*
|
||||
* Returns an opaque pointer to platform-specific `TextLayoutManager`.
|
||||
* Is used on a native views layer to delegate text rendering to the manager.
|
||||
*/
|
||||
std::shared_ptr<TextLayoutManager const> getTextLayoutManager() const;
|
||||
|
||||
/*
|
||||
* Returns opaque shared_ptr holding `NSTextStorage`.
|
||||
* May be nullptr.
|
||||
* Is used on a native views layer to prevent `NSTextStorage` from being
|
||||
* created twice.
|
||||
*/
|
||||
std::shared_ptr<void> getHostTextStorage() const;
|
||||
|
||||
private:
|
||||
std::shared_ptr<TextLayoutManager const> mutable textLayoutManager_{};
|
||||
std::shared_ptr<void> mutable hostTextStorage_{};
|
||||
|
||||
size_t mutable hash_{};
|
||||
};
|
||||
} // namespace facebook::react
|
||||
@@ -95,7 +95,8 @@ Content ParagraphShadowNode::getContentWithMeasuredAttachments(
|
||||
void ParagraphShadowNode::setTextLayoutManager(
|
||||
std::shared_ptr<TextLayoutManager const> textLayoutManager) {
|
||||
ensureUnsealed();
|
||||
textLayoutManager_ = std::move(textLayoutManager);
|
||||
getStateData().paragraphLayoutManager.setTextLayoutManager(
|
||||
std::move(textLayoutManager));
|
||||
}
|
||||
|
||||
void ParagraphShadowNode::updateStateIfNeeded(Content const &content) {
|
||||
@@ -103,7 +104,7 @@ void ParagraphShadowNode::updateStateIfNeeded(Content const &content) {
|
||||
|
||||
auto &state = getStateData();
|
||||
|
||||
react_native_assert(textLayoutManager_);
|
||||
react_native_assert(state.paragraphLayoutManager.getTextLayoutManager());
|
||||
|
||||
if (state.attributedString == content.attributedString) {
|
||||
return;
|
||||
@@ -112,7 +113,7 @@ void ParagraphShadowNode::updateStateIfNeeded(Content const &content) {
|
||||
setStateData(ParagraphState{
|
||||
content.attributedString,
|
||||
content.paragraphAttributes,
|
||||
textLayoutManager_});
|
||||
state.paragraphLayoutManager});
|
||||
}
|
||||
|
||||
#pragma mark - LayoutableShadowNode
|
||||
@@ -136,11 +137,9 @@ Size ParagraphShadowNode::measureContent(
|
||||
attributedString.appendFragment({string, textAttributes, {}});
|
||||
}
|
||||
|
||||
return textLayoutManager_
|
||||
->measure(
|
||||
AttributedStringBox{attributedString},
|
||||
content.paragraphAttributes,
|
||||
layoutConstraints)
|
||||
return getStateData()
|
||||
.paragraphLayoutManager
|
||||
.measure(attributedString, content.paragraphAttributes, layoutConstraints)
|
||||
.size;
|
||||
}
|
||||
|
||||
@@ -157,13 +156,11 @@ void ParagraphShadowNode::layout(LayoutContext layoutContext) {
|
||||
|
||||
updateStateIfNeeded(content);
|
||||
|
||||
auto measurement = textLayoutManager_->measure(
|
||||
AttributedStringBox{content.attributedString},
|
||||
content.paragraphAttributes,
|
||||
layoutConstraints);
|
||||
auto measurement = getStateData().paragraphLayoutManager.measure(
|
||||
content.attributedString, content.paragraphAttributes, layoutConstraints);
|
||||
|
||||
if (getConcreteProps().onTextLayout) {
|
||||
auto linesMeasurements = textLayoutManager_->measureLines(
|
||||
auto linesMeasurements = getStateData().paragraphLayoutManager.measureLines(
|
||||
content.attributedString,
|
||||
content.paragraphAttributes,
|
||||
measurement.size);
|
||||
|
||||
@@ -7,15 +7,14 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <react/renderer/components/text/BaseTextShadowNode.h>
|
||||
#include <react/renderer/components/text/ParagraphEventEmitter.h>
|
||||
#include <react/renderer/components/text/ParagraphLayoutManager.h>
|
||||
#include <react/renderer/components/text/ParagraphProps.h>
|
||||
#include <react/renderer/components/text/ParagraphState.h>
|
||||
#include <react/renderer/components/text/TextShadowNode.h>
|
||||
#include <react/renderer/components/view/ConcreteViewShadowNode.h>
|
||||
#include <react/renderer/core/ConcreteShadowNode.h>
|
||||
#include <react/renderer/core/LayoutContext.h>
|
||||
#include <react/renderer/core/ShadowNode.h>
|
||||
#include <react/renderer/textlayoutmanager/TextLayoutManager.h>
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
@@ -96,8 +95,6 @@ class ParagraphShadowNode final : public ConcreteViewShadowNode<
|
||||
*/
|
||||
void updateStateIfNeeded(Content const &content);
|
||||
|
||||
std::shared_ptr<TextLayoutManager const> textLayoutManager_;
|
||||
|
||||
/*
|
||||
* Cached content of the subtree started from the node.
|
||||
*/
|
||||
|
||||
@@ -10,15 +10,14 @@
|
||||
#include <react/debug/react_native_assert.h>
|
||||
#include <react/renderer/attributedstring/AttributedString.h>
|
||||
#include <react/renderer/attributedstring/ParagraphAttributes.h>
|
||||
#include <react/renderer/textlayoutmanager/TextLayoutManager.h>
|
||||
#include <react/renderer/components/text/ParagraphLayoutManager.h>
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <folly/dynamic.h>
|
||||
#include <react/renderer/mapbuffer/MapBuffer.h>
|
||||
#endif
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
namespace facebook::react {
|
||||
|
||||
#ifdef ANDROID
|
||||
// constants for Text State serialization
|
||||
@@ -33,8 +32,7 @@ constexpr static MapBuffer::Key TX_STATE_KEY_MOST_RECENT_EVENT_COUNT = 3;
|
||||
* State for <Paragraph> component.
|
||||
* Represents what to render and how to render.
|
||||
*/
|
||||
class ParagraphState final {
|
||||
public:
|
||||
struct ParagraphState {
|
||||
/*
|
||||
* All content of <Paragraph> component represented as an `AttributedString`.
|
||||
*/
|
||||
@@ -47,22 +45,22 @@ class ParagraphState final {
|
||||
ParagraphAttributes paragraphAttributes;
|
||||
|
||||
/*
|
||||
* `TextLayoutManager` provides a connection to platform-specific
|
||||
* `ParagraphLayoutManager` provides a connection to platform-specific
|
||||
* text rendering infrastructure which is capable to render the
|
||||
* `AttributedString`.
|
||||
* This is not on every platform. This is not used on Android, but is
|
||||
* used on the iOS mounting layer.
|
||||
*/
|
||||
std::weak_ptr<TextLayoutManager const> layoutManager;
|
||||
ParagraphLayoutManager paragraphLayoutManager;
|
||||
|
||||
#ifdef ANDROID
|
||||
ParagraphState(
|
||||
AttributedString const &attributedString,
|
||||
ParagraphAttributes const ¶graphAttributes,
|
||||
std::weak_ptr<const TextLayoutManager> const &layoutManager)
|
||||
ParagraphLayoutManager const ¶graphLayoutManager)
|
||||
: attributedString(attributedString),
|
||||
paragraphAttributes(paragraphAttributes),
|
||||
layoutManager(layoutManager) {}
|
||||
paragraphLayoutManager(paragraphLayoutManager) {}
|
||||
ParagraphState() = default;
|
||||
ParagraphState(
|
||||
ParagraphState const &previousState,
|
||||
@@ -74,5 +72,4 @@ class ParagraphState final {
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
} // namespace facebook::react
|
||||
+2
-1
@@ -197,7 +197,8 @@ Size AndroidTextInputShadowNode::measureContent(
|
||||
->measure(
|
||||
AttributedStringBox{attributedString},
|
||||
getConcreteProps().paragraphAttributes,
|
||||
layoutConstraints)
|
||||
layoutConstraints,
|
||||
nullptr)
|
||||
.size;
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -110,7 +110,8 @@ Size TextInputShadowNode::measureContent(
|
||||
->measure(
|
||||
attributedStringBoxToMeasure(layoutContext),
|
||||
getConcreteProps().getEffectiveParagraphAttributes(),
|
||||
layoutConstraints)
|
||||
layoutConstraints,
|
||||
nullptr)
|
||||
.size;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ bool CoreFeatures::enablePropIteratorSetter = false;
|
||||
bool CoreFeatures::enableMapBuffer = false;
|
||||
bool CoreFeatures::blockPaintForUseLayoutEffect = false;
|
||||
bool CoreFeatures::useNativeState = false;
|
||||
bool CoreFeatures::cacheNSTextStorage = false;
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
@@ -34,6 +34,11 @@ class CoreFeatures {
|
||||
// Whether to use Hermes' NativeState instead of HostObject
|
||||
// in simple data passing scenarios with JS
|
||||
static bool useNativeState;
|
||||
|
||||
// Creating NSTextStorage is relatively expensive operation and we were
|
||||
// creating it twice. Once when measuring text and once when rendering it.
|
||||
// This flag caches it inside ParagraphState.
|
||||
static bool cacheNSTextStorage;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <folly/Hash.h>
|
||||
#include <react/renderer/attributedstring/AttributedString.h>
|
||||
#include <react/renderer/attributedstring/ParagraphAttributes.h>
|
||||
#include <react/renderer/core/LayoutConstraints.h>
|
||||
|
||||
+9
-2
@@ -154,8 +154,9 @@ void *TextLayoutManager::getNativeTextLayoutManager() const {
|
||||
|
||||
TextMeasurement TextLayoutManager::measure(
|
||||
AttributedStringBox const &attributedStringBox,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const {
|
||||
ParagraphAttributes const ¶graphAttributes,
|
||||
LayoutConstraints layoutConstraints,
|
||||
std::shared_ptr<void> /* hostTextStorage */) const {
|
||||
auto &attributedString = attributedStringBox.getValue();
|
||||
|
||||
auto measurement = measureCache_.get(
|
||||
@@ -179,6 +180,12 @@ TextMeasurement TextLayoutManager::measure(
|
||||
measurement.size = layoutConstraints.clamp(measurement.size);
|
||||
return measurement;
|
||||
}
|
||||
std::shared_ptr<void> TextLayoutManager::getHostTextStorage(
|
||||
AttributedString const & /* attributedStringBox */,
|
||||
ParagraphAttributes const & /* paragraphAttributes */,
|
||||
LayoutConstraints /* layoutConstraints */) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
TextMeasurement TextLayoutManager::measureCachedSpannableById(
|
||||
int64_t cacheId,
|
||||
|
||||
+7
-1
@@ -45,7 +45,13 @@ class TextLayoutManager {
|
||||
*/
|
||||
TextMeasurement measure(
|
||||
AttributedStringBox const &attributedStringBox,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
ParagraphAttributes const ¶graphAttributes,
|
||||
LayoutConstraints layoutConstraints,
|
||||
std::shared_ptr<void> /* hostTextStorage */) const;
|
||||
|
||||
std::shared_ptr<void> getHostTextStorage(
|
||||
AttributedString const &attributedString,
|
||||
ParagraphAttributes const ¶graphAttributes,
|
||||
LayoutConstraints layoutConstraints) const;
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,8 @@ void *TextLayoutManager::getNativeTextLayoutManager() const {
|
||||
TextMeasurement TextLayoutManager::measure(
|
||||
AttributedStringBox attributedStringBox,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const {
|
||||
LayoutConstraints layoutConstraints,
|
||||
std::shared_ptr<void>) const {
|
||||
TextMeasurement::Attachments attachments;
|
||||
for (auto const &fragment : attributedStringBox.getValue().getFragments()) {
|
||||
if (fragment.isAttachment()) {
|
||||
@@ -35,5 +36,12 @@ LinesMeasurements TextLayoutManager::measureLines(
|
||||
return {};
|
||||
};
|
||||
|
||||
std::shared_ptr<void> TextLayoutManager::getHostTextStorage(
|
||||
AttributedString attributedString,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace react
|
||||
} // namespace facebook
|
||||
@@ -36,7 +36,8 @@ class TextLayoutManager {
|
||||
TextMeasurement measure(
|
||||
AttributedStringBox attributedStringBox,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const;
|
||||
LayoutConstraints layoutConstraints,
|
||||
std::shared_ptr<void>) const;
|
||||
|
||||
/*
|
||||
* Measures lines of `attributedString` using native text rendering
|
||||
@@ -52,6 +53,11 @@ class TextLayoutManager {
|
||||
* Is used on a native views layer to delegate text rendering to the manager.
|
||||
*/
|
||||
void *getNativeTextLayoutManager() const;
|
||||
|
||||
std::shared_ptr<void> getHostTextStorage(
|
||||
AttributedString attributedStringBox,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const;
|
||||
};
|
||||
|
||||
} // namespace react
|
||||
|
||||
+10
-3
@@ -28,15 +28,22 @@ using RCTTextLayoutFragmentEnumerationBlock =
|
||||
|
||||
- (facebook::react::TextMeasurement)measureAttributedString:(facebook::react::AttributedString)attributedString
|
||||
paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes
|
||||
layoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints;
|
||||
layoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints
|
||||
textStorage:(NSTextStorage *_Nullable)textStorage;
|
||||
|
||||
- (facebook::react::TextMeasurement)measureNSAttributedString:(NSAttributedString *)attributedString
|
||||
paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes
|
||||
layoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints;
|
||||
layoutConstraints:(facebook::react::LayoutConstraints)layoutConstraints
|
||||
textStorage:(NSTextStorage *_Nullable)textStorage;
|
||||
|
||||
- (NSTextStorage *)textStorageForAttributesString:(facebook::react::AttributedString)attributedString
|
||||
paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes
|
||||
size:(CGSize)size;
|
||||
|
||||
- (void)drawAttributedString:(facebook::react::AttributedString)attributedString
|
||||
paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes
|
||||
frame:(CGRect)frame;
|
||||
frame:(CGRect)frame
|
||||
textStorage:(NSTextStorage *_Nullable)textStorage;
|
||||
|
||||
- (facebook::react::LinesMeasurements)getLinesForAttributedString:(facebook::react::AttributedString)attributedString
|
||||
paragraphAttributes:
|
||||
|
||||
+38
-23
@@ -37,6 +37,7 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
|
||||
- (TextMeasurement)measureNSAttributedString:(NSAttributedString *)attributedString
|
||||
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
||||
layoutConstraints:(LayoutConstraints)layoutConstraints
|
||||
textStorage:(NSTextStorage *_Nullable)textStorage
|
||||
{
|
||||
if (attributedString.length == 0) {
|
||||
// This is not really an optimization because that should be checked much earlier on the call stack.
|
||||
@@ -47,9 +48,13 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
|
||||
|
||||
CGSize maximumSize = CGSize{layoutConstraints.maximumSize.width, CGFLOAT_MAX};
|
||||
|
||||
NSTextStorage *textStorage = [self _textStorageAndLayoutManagerWithAttributesString:attributedString
|
||||
paragraphAttributes:paragraphAttributes
|
||||
size:maximumSize];
|
||||
if (!textStorage) {
|
||||
textStorage = [self _textStorageForNSAttributesString:attributedString
|
||||
paragraphAttributes:paragraphAttributes
|
||||
size:maximumSize];
|
||||
} else {
|
||||
textStorage.layoutManagers.firstObject.textContainers.firstObject.size = maximumSize;
|
||||
}
|
||||
|
||||
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
|
||||
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
|
||||
@@ -93,20 +98,24 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
|
||||
- (TextMeasurement)measureAttributedString:(AttributedString)attributedString
|
||||
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
||||
layoutConstraints:(LayoutConstraints)layoutConstraints
|
||||
textStorage:(NSTextStorage *_Nullable)textStorage
|
||||
{
|
||||
return [self measureNSAttributedString:[self _nsAttributedStringFromAttributedString:attributedString]
|
||||
paragraphAttributes:paragraphAttributes
|
||||
layoutConstraints:layoutConstraints];
|
||||
layoutConstraints:layoutConstraints
|
||||
textStorage:textStorage];
|
||||
}
|
||||
|
||||
- (void)drawAttributedString:(AttributedString)attributedString
|
||||
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
||||
frame:(CGRect)frame
|
||||
textStorage:(NSTextStorage *_Nullable)textStorage
|
||||
{
|
||||
NSTextStorage *textStorage = [self
|
||||
_textStorageAndLayoutManagerWithAttributesString:[self _nsAttributedStringFromAttributedString:attributedString]
|
||||
if (!textStorage) {
|
||||
textStorage = [self textStorageForAttributesString:attributedString
|
||||
paragraphAttributes:paragraphAttributes
|
||||
size:frame.size];
|
||||
}
|
||||
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
|
||||
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
|
||||
|
||||
@@ -125,14 +134,13 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
|
||||
#endif
|
||||
}
|
||||
|
||||
- (LinesMeasurements)getLinesForAttributedString:(facebook::react::AttributedString)attributedString
|
||||
paragraphAttributes:(facebook::react::ParagraphAttributes)paragraphAttributes
|
||||
- (LinesMeasurements)getLinesForAttributedString:(AttributedString)attributedString
|
||||
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
||||
size:(CGSize)size
|
||||
{
|
||||
NSTextStorage *textStorage = [self
|
||||
_textStorageAndLayoutManagerWithAttributesString:[self _nsAttributedStringFromAttributedString:attributedString]
|
||||
paragraphAttributes:paragraphAttributes
|
||||
size:size];
|
||||
NSTextStorage *textStorage = [self textStorageForAttributesString:attributedString
|
||||
paragraphAttributes:paragraphAttributes
|
||||
size:size];
|
||||
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
|
||||
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
|
||||
|
||||
@@ -170,9 +178,9 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
|
||||
return paragraphLines;
|
||||
}
|
||||
|
||||
- (NSTextStorage *)_textStorageAndLayoutManagerWithAttributesString:(NSAttributedString *)attributedString
|
||||
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
||||
size:(CGSize)size
|
||||
- (NSTextStorage *)_textStorageForNSAttributesString:(NSAttributedString *)attributedString
|
||||
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
||||
size:(CGSize)size
|
||||
{
|
||||
NSTextContainer *textContainer = [[NSTextContainer alloc] initWithSize:size];
|
||||
|
||||
@@ -199,15 +207,23 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
|
||||
return textStorage;
|
||||
}
|
||||
|
||||
- (NSTextStorage *)textStorageForAttributesString:(AttributedString)attributedString
|
||||
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
||||
size:(CGSize)size
|
||||
{
|
||||
return [self _textStorageForNSAttributesString:[self _nsAttributedStringFromAttributedString:attributedString]
|
||||
paragraphAttributes:paragraphAttributes
|
||||
size:size];
|
||||
}
|
||||
|
||||
- (SharedEventEmitter)getEventEmitterWithAttributeString:(AttributedString)attributedString
|
||||
paragraphAttributes:(ParagraphAttributes)paragraphAttributes
|
||||
frame:(CGRect)frame
|
||||
atPoint:(CGPoint)point
|
||||
{
|
||||
NSTextStorage *textStorage = [self
|
||||
_textStorageAndLayoutManagerWithAttributesString:[self _nsAttributedStringFromAttributedString:attributedString]
|
||||
paragraphAttributes:paragraphAttributes
|
||||
size:frame.size];
|
||||
NSTextStorage *textStorage = [self textStorageForAttributesString:attributedString
|
||||
paragraphAttributes:paragraphAttributes
|
||||
size:frame.size];
|
||||
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
|
||||
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
|
||||
|
||||
@@ -245,10 +261,9 @@ static NSLineBreakMode RCTNSLineBreakModeFromEllipsizeMode(EllipsizeMode ellipsi
|
||||
frame:(CGRect)frame
|
||||
usingBlock:(RCTTextLayoutFragmentEnumerationBlock)block
|
||||
{
|
||||
NSTextStorage *textStorage = [self
|
||||
_textStorageAndLayoutManagerWithAttributesString:[self _nsAttributedStringFromAttributedString:attributedString]
|
||||
paragraphAttributes:paragraphAttributes
|
||||
size:frame.size];
|
||||
NSTextStorage *textStorage = [self textStorageForAttributesString:attributedString
|
||||
paragraphAttributes:paragraphAttributes
|
||||
size:frame.size];
|
||||
|
||||
NSLayoutManager *layoutManager = textStorage.layoutManagers.firstObject;
|
||||
NSTextContainer *textContainer = layoutManager.textContainers.firstObject;
|
||||
|
||||
+7
-1
@@ -33,7 +33,8 @@ class TextLayoutManager {
|
||||
TextMeasurement measure(
|
||||
AttributedStringBox attributedStringBox,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const;
|
||||
LayoutConstraints layoutConstraints,
|
||||
std::shared_ptr<void> hostTextStorage) const;
|
||||
|
||||
/*
|
||||
* Measures lines of `attributedString` using native text rendering
|
||||
@@ -44,6 +45,11 @@ class TextLayoutManager {
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
Size size) const;
|
||||
|
||||
std::shared_ptr<void> getHostTextStorage(
|
||||
AttributedString attributedString,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const;
|
||||
|
||||
/*
|
||||
* Returns an opaque pointer to platform-specific TextLayoutManager.
|
||||
* Is used on a native views layer to delegate text rendering to the manager.
|
||||
|
||||
+25
-4
@@ -25,12 +25,31 @@ std::shared_ptr<void> TextLayoutManager::getNativeTextLayoutManager() const
|
||||
return self_;
|
||||
}
|
||||
|
||||
TextMeasurement TextLayoutManager::measure(
|
||||
AttributedStringBox attributedStringBox,
|
||||
std::shared_ptr<void> TextLayoutManager::getHostTextStorage(
|
||||
AttributedString attributedString,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const
|
||||
{
|
||||
RCTTextLayoutManager *textLayoutManager = (RCTTextLayoutManager *)unwrapManagedObject(self_);
|
||||
CGSize maximumSize = CGSize{layoutConstraints.maximumSize.width, CGFLOAT_MAX};
|
||||
|
||||
NSTextStorage *textStorage = [textLayoutManager textStorageForAttributesString:attributedString
|
||||
paragraphAttributes:paragraphAttributes
|
||||
size:maximumSize];
|
||||
return wrapManagedObject(textStorage);
|
||||
}
|
||||
|
||||
TextMeasurement TextLayoutManager::measure(
|
||||
AttributedStringBox attributedStringBox,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints,
|
||||
std::shared_ptr<void> hostTextStorage) const
|
||||
{
|
||||
RCTTextLayoutManager *textLayoutManager = (RCTTextLayoutManager *)unwrapManagedObject(self_);
|
||||
NSTextStorage *textStorage;
|
||||
if (hostTextStorage) {
|
||||
textStorage = unwrapManagedObject(hostTextStorage);
|
||||
}
|
||||
|
||||
auto measurement = TextMeasurement{};
|
||||
|
||||
@@ -47,7 +66,8 @@ TextMeasurement TextLayoutManager::measure(
|
||||
|
||||
auto measurement = [textLayoutManager measureAttributedString:attributedString
|
||||
paragraphAttributes:paragraphAttributes
|
||||
layoutConstraints:layoutConstraints];
|
||||
layoutConstraints:layoutConstraints
|
||||
textStorage:textStorage];
|
||||
|
||||
if (telemetry) {
|
||||
telemetry->didMeasureText();
|
||||
@@ -69,7 +89,8 @@ TextMeasurement TextLayoutManager::measure(
|
||||
|
||||
measurement = [textLayoutManager measureNSAttributedString:nsAttributedString
|
||||
paragraphAttributes:paragraphAttributes
|
||||
layoutConstraints:layoutConstraints];
|
||||
layoutConstraints:layoutConstraints
|
||||
textStorage:textStorage];
|
||||
|
||||
if (telemetry) {
|
||||
telemetry->didMeasureText();
|
||||
|
||||
Reference in new issue
Block a user