Skip to content

Commit e46d624

Browse files
NickGerlemanfacebook-github-bot
authored andcommitted
Platform specific TextLayoutManager Headers
Summary: This effectively reverts D67064488 We are trying to smash together functions, variables, virtual or non-virtual, all required by different platforms, into a single header, often using #ifdefs that are not what we want (apart from a bad editor experience, `#ifdef ANDROID` may or may not be compiled into the react-native-cxx platform, and we cannot use it for the Android platform reliably). For Facsimile, we are going to be introducing more potential divergence, with the idea of `PreparedText`, where we can generate intermediate products as part of the layout process to be reused later. I'm planning to design that in a way which can be eventually reused across platforms, but not everywhere. I think the best path for this is going to be to allow each platform to have their own headers, instead of the current messieness, then allow shared code (e.g. in `ParagraphShadowNode`) to pick how to interact at compile time. I added an example of this as part of `TextLayoutManagerTraits`, to customize how we act if a `TextLayoutManager` chooses not to implement `measureLines`. Changelog: [Internal] Differential Revision: D73557126
1 parent ab622b6 commit e46d624

File tree

7 files changed

+193
-41
lines changed

7 files changed

+193
-41
lines changed

packages/react-native/ReactCommon/react/renderer/components/text/ParagraphShadowNode.cpp

+16-5
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <react/renderer/graphics/rounding.h>
1818
#include <react/renderer/telemetry/TransactionTelemetry.h>
1919
#include <react/renderer/textlayoutmanager/TextLayoutContext.h>
20+
#include <react/renderer/textlayoutmanager/TextLayoutManagerTraits.h>
2021

2122
#include "ParagraphState.h"
2223

@@ -215,8 +216,14 @@ Float ParagraphShadowNode::baseline(
215216

216217
AttributedStringBox attributedStringBox{attributedString};
217218

218-
return LineMeasurement::baseline(textLayoutManager_->measureLines(
219-
attributedStringBox, getConcreteProps().paragraphAttributes, size));
219+
if constexpr (TextLayoutManagerWithLineMeasurement<TextLayoutManager>) {
220+
return LineMeasurement::baseline(textLayoutManager_->measureLines(
221+
attributedStringBox, getConcreteProps().paragraphAttributes, size));
222+
} else {
223+
LOG(WARNING)
224+
<< "Baseline alignment is not supported by the current platform";
225+
return 0;
226+
}
220227
}
221228

222229
void ParagraphShadowNode::layout(LayoutContext layoutContext) {
@@ -239,9 +246,13 @@ void ParagraphShadowNode::layout(LayoutContext layoutContext) {
239246
AttributedStringBox attributedStringBox{content.attributedString};
240247

241248
if (getConcreteProps().onTextLayout) {
242-
auto linesMeasurements = textLayoutManager_->measureLines(
243-
attributedStringBox, content.paragraphAttributes, size);
244-
getConcreteEventEmitter().onTextLayout(linesMeasurements);
249+
if constexpr (TextLayoutManagerWithLineMeasurement<TextLayoutManager>) {
250+
auto linesMeasurements = textLayoutManager_->measureLines(
251+
attributedStringBox, content.paragraphAttributes, size);
252+
getConcreteEventEmitter().onTextLayout(linesMeasurements);
253+
} else {
254+
LOG(WARNING) << "onTextLayout is not supported by the current platform";
255+
}
245256
}
246257

247258
if (content.attachments.empty()) {

packages/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputShadowNode.h

+11-3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include <react/renderer/core/LayoutContext.h>
1919
#include <react/renderer/textlayoutmanager/TextLayoutContext.h>
2020
#include <react/renderer/textlayoutmanager/TextLayoutManager.h>
21+
#include <react/renderer/textlayoutmanager/TextLayoutManagerTraits.h>
2122
#include <react/utils/ContextContainer.h>
2223

2324
namespace facebook::react {
@@ -106,9 +107,16 @@ class BaseTextInputShadowNode : public ConcreteViewShadowNode<
106107
&(YogaLayoutableShadowNode::yogaNode_), YGEdgeTop);
107108

108109
AttributedStringBox attributedStringBox{attributedString};
109-
return LineMeasurement::baseline(textLayoutManager_->measureLines(
110-
attributedStringBox, props.paragraphAttributes, size)) +
111-
top;
110+
111+
if constexpr (TextLayoutManagerWithLineMeasurement<TextLayoutManager>) {
112+
return LineMeasurement::baseline(textLayoutManager_->measureLines(
113+
attributedStringBox, props.paragraphAttributes, size)) +
114+
top;
115+
} else {
116+
LOG(WARNING)
117+
<< "Baseline alignment is not supported by the current platform";
118+
return top;
119+
}
112120
}
113121

114122
/*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#pragma once
9+
10+
#include <react/renderer/attributedstring/AttributedStringBox.h>
11+
#include <react/renderer/attributedstring/ParagraphAttributes.h>
12+
#include <react/renderer/graphics/Size.h>
13+
#include <react/renderer/textlayoutmanager/TextLayoutManager.h>
14+
#include <react/renderer/textlayoutmanager/TextMeasureCache.h>
15+
16+
#include <concepts>
17+
#include <type_traits>
18+
19+
namespace facebook::react {
20+
21+
/**
22+
* Represents a platform TextLayoutManager which is capable of providing line
23+
* metrics
24+
*/
25+
template <typename TextLayoutManagerT>
26+
concept TextLayoutManagerWithLineMeasurement =
27+
std::is_same_v<TextLayoutManagerT, TextLayoutManager> &&
28+
requires(TextLayoutManagerT textLayoutManager) {
29+
{
30+
textLayoutManager.measureLines(
31+
AttributedStringBox{}, ParagraphAttributes{}, Size{})
32+
} -> std::same_as<LinesMeasurements>;
33+
};
34+
35+
} // namespace facebook::react

packages/react-native/ReactCommon/react/renderer/textlayoutmanager/TextLayoutManager.h renamed to packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/android/react/renderer/textlayoutmanager/TextLayoutManager.h

+3-17
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ class TextLayoutManager;
2626
class TextLayoutManager {
2727
public:
2828
TextLayoutManager(const ContextContainer::Shared& contextContainer);
29-
virtual ~TextLayoutManager() = default;
3029

3130
/*
3231
* Not copyable.
@@ -43,13 +42,12 @@ class TextLayoutManager {
4342
/*
4443
* Measures `attributedString` using native text rendering infrastructure.
4544
*/
46-
virtual TextMeasurement measure(
45+
TextMeasurement measure(
4746
const AttributedStringBox& attributedStringBox,
4847
const ParagraphAttributes& paragraphAttributes,
4948
const TextLayoutContext& layoutContext,
5049
const LayoutConstraints& layoutConstraints) const;
5150

52-
#ifdef ANDROID
5351
/**
5452
* Measures an AttributedString on the platform, as identified by some
5553
* opaque cache ID.
@@ -58,30 +56,18 @@ class TextLayoutManager {
5856
int64_t cacheId,
5957
const ParagraphAttributes& paragraphAttributes,
6058
const LayoutConstraints& layoutConstraints) const;
61-
#endif
6259

6360
/*
6461
* Measures lines of `attributedString` using native text rendering
6562
* infrastructure.
6663
*/
67-
virtual LinesMeasurements measureLines(
64+
LinesMeasurements measureLines(
6865
const AttributedStringBox& attributedStringBox,
6966
const ParagraphAttributes& paragraphAttributes,
7067
const Size& size) const;
7168

72-
#ifdef __APPLE__
73-
/*
74-
* Returns an opaque pointer to platform-specific TextLayoutManager.
75-
* Is used on a native views layer to delegate text rendering to the manager.
76-
*/
77-
std::shared_ptr<void> getNativeTextLayoutManager() const;
78-
#endif
79-
80-
protected:
69+
private:
8170
std::shared_ptr<const ContextContainer> contextContainer_;
82-
#ifdef __APPLE__
83-
std::shared_ptr<void> nativeTextLayoutManager_;
84-
#endif
8571
TextMeasureCache textMeasureCache_;
8672
LineMeasureCache lineMeasureCache_;
8773
};

packages/react-native/ReactCommon/react/renderer/textlayoutmanager/platform/cxx/TextLayoutManager.cpp

-16
Original file line numberDiff line numberDiff line change
@@ -29,20 +29,4 @@ TextMeasurement TextLayoutManager::measure(
2929
return TextMeasurement{{0, 0}, attachments};
3030
}
3131

32-
#ifdef ANDROID
33-
TextMeasurement TextLayoutManager::measureCachedSpannableById(
34-
int64_t /*cacheId*/,
35-
const ParagraphAttributes& /*paragraphAttributes*/,
36-
const LayoutConstraints& /*layoutConstraints*/) const {
37-
return {};
38-
}
39-
#endif
40-
41-
LinesMeasurements TextLayoutManager::measureLines(
42-
const AttributedStringBox& /*attributedStringBox*/,
43-
const ParagraphAttributes& /*paragraphAttributes*/,
44-
const Size& /*size*/) const {
45-
return {};
46-
};
47-
4832
} // namespace facebook::react
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#pragma once
9+
10+
#include <react/renderer/attributedstring/AttributedStringBox.h>
11+
#include <react/renderer/attributedstring/ParagraphAttributes.h>
12+
#include <react/renderer/core/LayoutConstraints.h>
13+
#include <react/renderer/textlayoutmanager/TextLayoutContext.h>
14+
#include <react/renderer/textlayoutmanager/TextMeasureCache.h>
15+
#include <react/utils/ContextContainer.h>
16+
#include <memory>
17+
18+
namespace facebook::react {
19+
20+
class TextLayoutManager;
21+
22+
/*
23+
* Cross platform facade for text measurement (e.g. Android-specific
24+
* TextLayoutManager)
25+
*/
26+
class TextLayoutManager {
27+
public:
28+
TextLayoutManager(const ContextContainer::Shared& contextContainer);
29+
virtual ~TextLayoutManager() = default;
30+
31+
/*
32+
* Not copyable.
33+
*/
34+
TextLayoutManager(const TextLayoutManager&) = delete;
35+
TextLayoutManager& operator=(const TextLayoutManager&) = delete;
36+
37+
/*
38+
* Not movable.
39+
*/
40+
TextLayoutManager(TextLayoutManager&&) = delete;
41+
TextLayoutManager& operator=(TextLayoutManager&&) = delete;
42+
43+
/*
44+
* Measures `attributedString` using native text rendering infrastructure.
45+
*/
46+
virtual TextMeasurement measure(
47+
const AttributedStringBox& attributedStringBox,
48+
const ParagraphAttributes& paragraphAttributes,
49+
const TextLayoutContext& layoutContext,
50+
const LayoutConstraints& layoutConstraints) const;
51+
52+
protected:
53+
std::shared_ptr<const ContextContainer> contextContainer_;
54+
TextMeasureCache textMeasureCache_;
55+
};
56+
57+
} // namespace facebook::react
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
#pragma once
9+
10+
#include <react/renderer/attributedstring/AttributedStringBox.h>
11+
#include <react/renderer/attributedstring/ParagraphAttributes.h>
12+
#include <react/renderer/core/LayoutConstraints.h>
13+
#include <react/renderer/textlayoutmanager/TextLayoutContext.h>
14+
#include <react/renderer/textlayoutmanager/TextMeasureCache.h>
15+
#include <react/utils/ContextContainer.h>
16+
#include <memory>
17+
18+
namespace facebook::react {
19+
20+
/*
21+
* Cross platform facade for text measurement (e.g. Android-specific
22+
* TextLayoutManager)
23+
*/
24+
class TextLayoutManager {
25+
public:
26+
TextLayoutManager(const ContextContainer::Shared& contextContainer);
27+
28+
/*
29+
* Not copyable.
30+
*/
31+
TextLayoutManager(const TextLayoutManager&) = delete;
32+
TextLayoutManager& operator=(const TextLayoutManager&) = delete;
33+
34+
/*
35+
* Not movable.
36+
*/
37+
TextLayoutManager(TextLayoutManager&&) = delete;
38+
TextLayoutManager& operator=(TextLayoutManager&&) = delete;
39+
40+
/*
41+
* Measures `attributedString` using native text rendering infrastructure.
42+
*/
43+
TextMeasurement measure(
44+
const AttributedStringBox& attributedStringBox,
45+
const ParagraphAttributes& paragraphAttributes,
46+
const TextLayoutContext& layoutContext,
47+
const LayoutConstraints& layoutConstraints) const;
48+
49+
/*
50+
* Measures lines of `attributedString` using native text rendering
51+
* infrastructure.
52+
*/
53+
LinesMeasurements measureLines(
54+
const AttributedStringBox& attributedStringBox,
55+
const ParagraphAttributes& paragraphAttributes,
56+
const Size& size) const;
57+
58+
/*
59+
* Returns an opaque pointer to platform-specific TextLayoutManager.
60+
* Is used on a native views layer to delegate text rendering to the manager.
61+
*/
62+
std::shared_ptr<void> getNativeTextLayoutManager() const;
63+
64+
protected:
65+
std::shared_ptr<const ContextContainer> contextContainer_;
66+
std::shared_ptr<void> nativeTextLayoutManager_;
67+
TextMeasureCache textMeasureCache_;
68+
LineMeasureCache lineMeasureCache_;
69+
};
70+
71+
} // namespace facebook::react

0 commit comments

Comments
 (0)