react-native-advanced-text 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
#include <algorithm>
|
|
13
13
|
#include <cctype>
|
|
14
|
+
#include <limits>
|
|
14
15
|
#include <string>
|
|
15
16
|
|
|
16
17
|
#include <react/renderer/attributedstring/AttributedStringBox.h>
|
|
@@ -32,6 +33,10 @@ std::string toLowerAscii(std::string value) {
|
|
|
32
33
|
return value;
|
|
33
34
|
}
|
|
34
35
|
|
|
36
|
+
// Fallback only: an approximate ratio of a single line's natural height to
|
|
37
|
+
// its font size, used if a real measurement (Android) isn't available/valid.
|
|
38
|
+
constexpr Float kLineHeightFudgeFactor = 1.2;
|
|
39
|
+
|
|
35
40
|
} // namespace
|
|
36
41
|
|
|
37
42
|
AdvancedTextViewShadowNode::AdvancedTextViewShadowNode(
|
|
@@ -42,7 +47,47 @@ AdvancedTextViewShadowNode::AdvancedTextViewShadowNode(
|
|
|
42
47
|
static_cast<const AdvancedTextViewShadowNode&>(sourceShadowNode)
|
|
43
48
|
.textLayoutManager_) {}
|
|
44
49
|
|
|
45
|
-
|
|
50
|
+
#if defined(ANDROID)
|
|
51
|
+
Float AdvancedTextViewShadowNode::measureNaturalSingleLineHeight(
|
|
52
|
+
const LayoutContext& layoutContext,
|
|
53
|
+
const TextAttributes& baseTextAttributes) const {
|
|
54
|
+
// Same font/size/weight/style as the real fragment, but with `lineHeight`
|
|
55
|
+
// cleared so this reports the font's own, unscaled single-line height --
|
|
56
|
+
// exactly what Android's `setLineSpacing(0, multiplier)` multiplies.
|
|
57
|
+
auto probeAttributes = baseTextAttributes;
|
|
58
|
+
probeAttributes.lineHeight = std::numeric_limits<Float>::quiet_NaN();
|
|
59
|
+
|
|
60
|
+
auto probe = AttributedString{};
|
|
61
|
+
probe.appendFragment(AttributedString::Fragment{
|
|
62
|
+
.string = "M",
|
|
63
|
+
.textAttributes = probeAttributes,
|
|
64
|
+
.parentShadowView = ShadowView(*this),
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
auto paragraphAttributes = ParagraphAttributes{};
|
|
68
|
+
|
|
69
|
+
auto textLayoutContext = TextLayoutContext{};
|
|
70
|
+
textLayoutContext.pointScaleFactor = layoutContext.pointScaleFactor;
|
|
71
|
+
textLayoutContext.surfaceId = getSurfaceId();
|
|
72
|
+
|
|
73
|
+
// Unconstrained so a single glyph can never be forced to wrap.
|
|
74
|
+
auto unconstrainedLayoutConstraints = LayoutConstraints{
|
|
75
|
+
{0, 0},
|
|
76
|
+
{std::numeric_limits<Float>::infinity(),
|
|
77
|
+
std::numeric_limits<Float>::infinity()}};
|
|
78
|
+
|
|
79
|
+
auto measurement = textLayoutManager_->measure(
|
|
80
|
+
AttributedStringBox{probe},
|
|
81
|
+
paragraphAttributes,
|
|
82
|
+
textLayoutContext,
|
|
83
|
+
unconstrainedLayoutConstraints);
|
|
84
|
+
|
|
85
|
+
return measurement.size.height;
|
|
86
|
+
}
|
|
87
|
+
#endif
|
|
88
|
+
|
|
89
|
+
AttributedString AdvancedTextViewShadowNode::getAttributedString(
|
|
90
|
+
const LayoutContext& layoutContext) const {
|
|
46
91
|
const auto& props = getConcreteProps();
|
|
47
92
|
|
|
48
93
|
auto textAttributes = TextAttributes::defaultTextAttributes();
|
|
@@ -68,13 +113,32 @@ AttributedString AdvancedTextViewShadowNode::getAttributedString() const {
|
|
|
68
113
|
textAttributes.letterSpacing = props.letterSpacing;
|
|
69
114
|
}
|
|
70
115
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
116
|
+
// The component treats `lineHeight` as a multiple of the font's own
|
|
117
|
+
// natural line height (see setLineSpacing(0, multiplier) in
|
|
118
|
+
// AdvancedTextView.kt / the NSParagraphStyle-based spacing in
|
|
119
|
+
// AdvancedTextView.mm) -- NOT the absolute per-line value
|
|
120
|
+
// `TextAttributes.lineHeight` expects. A multiplier of 1 *is* the natural
|
|
121
|
+
// line height, so there is nothing to override in that case (and
|
|
122
|
+
// overriding it with an approximation, as this used to do unconditionally,
|
|
123
|
+
// made even the "no lineHeight override" case measure taller or shorter
|
|
124
|
+
// than the real render).
|
|
125
|
+
if (props.lineHeight > 0 && props.lineHeight != 1.0) {
|
|
126
|
+
#if defined(ANDROID)
|
|
127
|
+
// Android's natural single-line height depends on the resolved
|
|
128
|
+
// font/size/weight and isn't a fixed ratio of fontSize, so a constant
|
|
129
|
+
// approximation drifts from AdvancedTextView.kt's real
|
|
130
|
+
// setLineSpacing()-based layout by an amount that compounds with every
|
|
131
|
+
// wrapped line -- which is why the error scaled with paragraph length.
|
|
132
|
+
// Measure the real natural height for these exact attributes instead.
|
|
133
|
+
auto naturalLineHeight =
|
|
134
|
+
measureNaturalSingleLineHeight(layoutContext, textAttributes);
|
|
135
|
+
textAttributes.lineHeight = naturalLineHeight > 0
|
|
136
|
+
? props.lineHeight * naturalLineHeight
|
|
137
|
+
: props.lineHeight * textAttributes.fontSize * kLineHeightFudgeFactor;
|
|
138
|
+
#else
|
|
76
139
|
textAttributes.lineHeight =
|
|
77
|
-
props.lineHeight * textAttributes.fontSize *
|
|
140
|
+
props.lineHeight * textAttributes.fontSize * kLineHeightFudgeFactor;
|
|
141
|
+
#endif
|
|
78
142
|
}
|
|
79
143
|
|
|
80
144
|
auto attributedString = AttributedString{};
|
|
@@ -109,7 +173,7 @@ Size AdvancedTextViewShadowNode::measureContent(
|
|
|
109
173
|
textLayoutContext.surfaceId = getSurfaceId();
|
|
110
174
|
|
|
111
175
|
auto measurement = textLayoutManager_->measure(
|
|
112
|
-
AttributedStringBox{getAttributedString()},
|
|
176
|
+
AttributedStringBox{getAttributedString(layoutContext)},
|
|
113
177
|
paragraphAttributes,
|
|
114
178
|
textLayoutContext,
|
|
115
179
|
layoutConstraints);
|
|
@@ -86,7 +86,20 @@ class AdvancedTextViewShadowNode final : public ConcreteViewShadowNode<
|
|
|
86
86
|
* Builds a single-fragment `AttributedString` from the component props
|
|
87
87
|
* (text + font attributes), mirroring how the native views render it.
|
|
88
88
|
*/
|
|
89
|
-
AttributedString getAttributedString() const;
|
|
89
|
+
AttributedString getAttributedString(const LayoutContext& layoutContext) const;
|
|
90
|
+
|
|
91
|
+
#if defined(ANDROID)
|
|
92
|
+
/*
|
|
93
|
+
* Measures the natural (multiplier == 1) height of a single line set in
|
|
94
|
+
* `baseTextAttributes`, by measuring a single glyph with `lineHeight`
|
|
95
|
+
* cleared. Used to turn the component's `lineHeight` multiplier prop into
|
|
96
|
+
* the absolute value `TextAttributes.lineHeight` expects, using this
|
|
97
|
+
* font's *real* metrics instead of an approximation.
|
|
98
|
+
*/
|
|
99
|
+
Float measureNaturalSingleLineHeight(
|
|
100
|
+
const LayoutContext& layoutContext,
|
|
101
|
+
const TextAttributes& baseTextAttributes) const;
|
|
102
|
+
#endif
|
|
90
103
|
|
|
91
104
|
// Lazily created on first measure, then reused / copied across clones.
|
|
92
105
|
mutable std::shared_ptr<const TextLayoutManager> textLayoutManager_;
|
package/package.json
CHANGED