Extend Text to support measurement of empty Texts

Summary:
This diff extends the measurement of Text components in order to support empty strings.
This is required for parity with Paper.
I created a follow up task to analyze support of empty string as part of the Text infrastructure of Fabric in the future.

changelog: [Internal]

Reviewed By: sammy-SC

Differential Revision: D21761171

fbshipit-source-id: d2aa074052b09732af5d35723f19014090fcabbf
This commit is contained in:
David Vacca
2020-05-28 15:10:47 -07:00
committed by Facebook GitHub Bot
parent 34b23c1220
commit 4b596fd5b3
5 changed files with 28 additions and 6 deletions
@@ -20,6 +20,7 @@ import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.LayoutDirection;
import android.util.LruCache;
import android.view.View;
import androidx.annotation.Nullable;
import com.facebook.common.logging.FLog;
import com.facebook.react.bridge.ReadableArray;
@@ -86,7 +87,7 @@ public class TextLayoutManager {
sb.append(TextTransform.apply(fragment.getString("string"), textAttributes.mTextTransform));
int end = sb.length();
int reactTag = fragment.getInt("reactTag");
int reactTag = fragment.hasKey("reactTag") ? fragment.getInt("reactTag") : View.NO_ID;
if (fragment.hasKey(ViewProps.IS_ATTACHMENT)
&& fragment.getBoolean(ViewProps.IS_ATTACHMENT)) {
float width = PixelUtil.toPixelFromSP(fragment.getDouble(ViewProps.WIDTH));
@@ -57,6 +57,13 @@ class BaseTextShadowNode {
ShadowNode const &parentNode,
AttributedString &outAttributedString,
Attachments &outAttachments);
/**
* Returns a character used to measure empty strings in native platforms.
*/
inline static std::string getEmptyPlaceholder() {
return "I";
}
};
} // namespace react
@@ -120,13 +120,21 @@ Size ParagraphShadowNode::measure(LayoutConstraints layoutConstraints) const {
auto content =
getContentWithMeasuredAttachments(LayoutContext{}, layoutConstraints);
if (content.attributedString.isEmpty()) {
return layoutConstraints.clamp({0, 0});
auto attributedString = content.attributedString;
if (attributedString.isEmpty()) {
// Note: `zero-width space` is insufficient in some cases (e.g. when we need
// to measure the "height" of the font).
// TODO T67606511: We will redefine the measurement of empty strings as part
// of T67606511
auto string = BaseTextShadowNode::getEmptyPlaceholder();
auto textAttributes = TextAttributes::defaultTextAttributes();
textAttributes.apply(getConcreteProps().textAttributes);
attributedString.appendFragment({string, textAttributes, {}});
}
return textLayoutManager_
->measure(
AttributedStringBox{content.attributedString},
AttributedStringBox{attributedString},
content.paragraphAttributes,
layoutConstraints)
.size;
@@ -62,6 +62,8 @@ AttributedString AndroidTextInputShadowNode::getAttributedString() const {
// single character in the string so that the measured height is greater
// than zero. Otherwise, empty TextInputs with no placeholder don't
// display at all.
// TODO T67606511: We will redefine the measurement of empty strings as part
// of T67606511
AttributedString AndroidTextInputShadowNode::getPlaceholderAttributedString()
const {
// Return placeholder text, since text and children are empty.
@@ -70,7 +72,7 @@ AttributedString AndroidTextInputShadowNode::getPlaceholderAttributedString()
fragment.string = getConcreteProps().placeholder;
if (fragment.string.empty()) {
fragment.string = " ";
fragment.string = BaseTextShadowNode::getEmptyPlaceholder();
}
auto textAttributes = TextAttributes::defaultTextAttributes();
@@ -38,7 +38,11 @@ AttributedStringBox TextInputShadowNode::attributedStringBoxToMeasure() const {
auto placeholder = getConcreteProps().placeholder;
// Note: `zero-width space` is insufficient in some cases (e.g. when we need
// to measure the "hight" of the font).
auto string = !placeholder.empty() ? placeholder : "I";
// TODO T67606511: We will redefine the measurement of empty strings as part
// of T67606511
auto string = !placeholder.empty()
? placeholder
: BaseTextShadowNode::getEmptyPlaceholder();
auto textAttributes = getConcreteProps().getEffectiveTextAttributes();
attributedString.appendFragment({string, textAttributes, {}});
}