mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Migrate TextAttributes to Kotlin (#51448)
Summary: Migrate com.facebook.react.views.text.TextAttributes to Kotlin. `TextTransform` is exposed in the `textTransform` var setter, and there doesn't seem to be a clean way to avoid having to make the `TextTransform` class public again. I have limited its companion to keep it internal as much as possible. ## Changelog: [INTERNAL] - Migrate com.facebook.react.views.text.TextAttributes to Kotlin Pull Request resolved: https://github.com/facebook/react-native/pull/51448 Test Plan: ```bash yarn test-android yarn android ``` Reviewed By: cortinico Differential Revision: D74978129 Pulled By: rshest fbshipit-source-id: ea0594f01738b8c8f4696434fe76974bbb9ff661
This commit is contained in:
committed by
Facebook GitHub Bot
parent
dc737cb909
commit
bcfa5ca474
@@ -6451,28 +6451,26 @@ public class com/facebook/react/views/text/TextAttributeProps {
|
||||
public fun isUnderlineTextDecorationSet ()Z
|
||||
}
|
||||
|
||||
public class com/facebook/react/views/text/TextAttributes {
|
||||
public final class com/facebook/react/views/text/TextAttributes {
|
||||
public static final field DEFAULT_MAX_FONT_SIZE_MULTIPLIER F
|
||||
public fun <init> ()V
|
||||
public fun applyChild (Lcom/facebook/react/views/text/TextAttributes;)Lcom/facebook/react/views/text/TextAttributes;
|
||||
public fun getAllowFontScaling ()Z
|
||||
public fun getEffectiveFontSize ()I
|
||||
public fun getEffectiveLetterSpacing ()F
|
||||
public fun getEffectiveLineHeight ()F
|
||||
public fun getEffectiveMaxFontSizeMultiplier ()F
|
||||
public fun getFontSize ()F
|
||||
public fun getHeightOfTallestInlineViewOrImage ()F
|
||||
public fun getLetterSpacing ()F
|
||||
public fun getLineHeight ()F
|
||||
public fun getMaxFontSizeMultiplier ()F
|
||||
public fun getTextTransform ()Lcom/facebook/react/views/text/TextTransform;
|
||||
public fun setAllowFontScaling (Z)V
|
||||
public fun setFontSize (F)V
|
||||
public fun setHeightOfTallestInlineViewOrImage (F)V
|
||||
public fun setLetterSpacing (F)V
|
||||
public fun setLineHeight (F)V
|
||||
public fun setMaxFontSizeMultiplier (F)V
|
||||
public fun setTextTransform (Lcom/facebook/react/views/text/TextTransform;)V
|
||||
public final fun applyChild (Lcom/facebook/react/views/text/TextAttributes;)Lcom/facebook/react/views/text/TextAttributes;
|
||||
public final fun getAllowFontScaling ()Z
|
||||
public final fun getEffectiveFontSize ()I
|
||||
public final fun getEffectiveLetterSpacing ()F
|
||||
public final fun getEffectiveLineHeight ()F
|
||||
public final fun getEffectiveMaxFontSizeMultiplier ()F
|
||||
public final fun getFontSize ()F
|
||||
public final fun getHeightOfTallestInlineViewOrImage ()F
|
||||
public final fun getLetterSpacing ()F
|
||||
public final fun getLineHeight ()F
|
||||
public final fun getMaxFontSizeMultiplier ()F
|
||||
public final fun setAllowFontScaling (Z)V
|
||||
public final fun setFontSize (F)V
|
||||
public final fun setHeightOfTallestInlineViewOrImage (F)V
|
||||
public final fun setLetterSpacing (F)V
|
||||
public final fun setLineHeight (F)V
|
||||
public final fun setMaxFontSizeMultiplier (F)V
|
||||
public fun toString ()Ljava/lang/String;
|
||||
}
|
||||
|
||||
|
||||
+9
-9
@@ -109,7 +109,7 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
|
||||
if (child instanceof ReactRawTextShadowNode) {
|
||||
String childText = ((ReactRawTextShadowNode) child).getText();
|
||||
if (childText != null) {
|
||||
sb.append(TextTransform.applyNonNull(childText, textAttributes.getTextTransform()));
|
||||
sb.append(TextTransform.applyNonNull(childText, textAttributes.textTransform));
|
||||
}
|
||||
} else if (child instanceof ReactBaseTextShadowNode) {
|
||||
buildSpannedFromShadowNode(
|
||||
@@ -264,8 +264,7 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
|
||||
if (text != null) {
|
||||
// Handle text that is provided via a prop (e.g. the `value` and `defaultValue` props on
|
||||
// TextInput).
|
||||
sb.append(
|
||||
TextTransform.applyNonNull(text, textShadowNode.mTextAttributes.getTextTransform()));
|
||||
sb.append(TextTransform.applyNonNull(text, textShadowNode.mTextAttributes.textTransform));
|
||||
}
|
||||
|
||||
buildSpannedFromShadowNode(textShadowNode, sb, ops, null, supportsInlineViews, inlineViews, 0);
|
||||
@@ -633,20 +632,21 @@ public abstract class ReactBaseTextShadowNode extends LayoutShadowNode {
|
||||
|
||||
@ReactProp(name = PROP_TEXT_TRANSFORM)
|
||||
public void setTextTransform(@Nullable String textTransform) {
|
||||
TextTransform textTransformEnum = TextTransform.UNSET;
|
||||
if (textTransform == null) {
|
||||
mTextAttributes.setTextTransform(TextTransform.UNSET);
|
||||
textTransformEnum = TextTransform.UNSET;
|
||||
} else if ("none".equals(textTransform)) {
|
||||
mTextAttributes.setTextTransform(TextTransform.NONE);
|
||||
textTransformEnum = TextTransform.NONE;
|
||||
} else if ("uppercase".equals(textTransform)) {
|
||||
mTextAttributes.setTextTransform(TextTransform.UPPERCASE);
|
||||
textTransformEnum = TextTransform.UPPERCASE;
|
||||
} else if ("lowercase".equals(textTransform)) {
|
||||
mTextAttributes.setTextTransform(TextTransform.LOWERCASE);
|
||||
textTransformEnum = TextTransform.LOWERCASE;
|
||||
} else if ("capitalize".equals(textTransform)) {
|
||||
mTextAttributes.setTextTransform(TextTransform.CAPITALIZE);
|
||||
textTransformEnum = TextTransform.CAPITALIZE;
|
||||
} else {
|
||||
FLog.w(ReactConstants.TAG, "Invalid textTransform: " + textTransform);
|
||||
mTextAttributes.setTextTransform(TextTransform.UNSET);
|
||||
}
|
||||
mTextAttributes.textTransform = textTransformEnum;
|
||||
markUpdated();
|
||||
}
|
||||
|
||||
|
||||
-208
@@ -1,208 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.text;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
import com.facebook.react.uimanager.ViewDefaults;
|
||||
|
||||
/*
|
||||
* Currently, TextAttributes consists of a subset of text props that need to be passed from parent
|
||||
* to child so inheritance can be implemented correctly. An example complexity that causes a prop
|
||||
* to end up in TextAttributes is when multiple props need to be considered together to determine
|
||||
* the rendered aka effective value. For example, to figure out the rendered/effective font size,
|
||||
* you need to take into account the fontSize, maxFontSizeMultiplier, and allowFontScaling props.
|
||||
*/
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class TextAttributes {
|
||||
// Setting the default to 0 indicates that there is no max.
|
||||
public static final float DEFAULT_MAX_FONT_SIZE_MULTIPLIER = 0.0f;
|
||||
|
||||
private boolean mAllowFontScaling = true;
|
||||
private float mFontSize = Float.NaN;
|
||||
private float mLineHeight = Float.NaN;
|
||||
private float mLetterSpacing = Float.NaN;
|
||||
private float mMaxFontSizeMultiplier = Float.NaN;
|
||||
private float mHeightOfTallestInlineViewOrImage = Float.NaN;
|
||||
|
||||
@NonNull private TextTransform mTextTransform = TextTransform.UNSET;
|
||||
|
||||
public TextAttributes() {}
|
||||
|
||||
public TextAttributes applyChild(TextAttributes child) {
|
||||
TextAttributes result = new TextAttributes();
|
||||
|
||||
// allowFontScaling is always determined by the root Text
|
||||
// component so don't allow the child to overwrite it.
|
||||
result.mAllowFontScaling = mAllowFontScaling;
|
||||
|
||||
result.mFontSize = !Float.isNaN(child.mFontSize) ? child.mFontSize : mFontSize;
|
||||
result.mLineHeight = !Float.isNaN(child.mLineHeight) ? child.mLineHeight : mLineHeight;
|
||||
result.mLetterSpacing =
|
||||
!Float.isNaN(child.mLetterSpacing) ? child.mLetterSpacing : mLetterSpacing;
|
||||
result.mMaxFontSizeMultiplier =
|
||||
!Float.isNaN(child.mMaxFontSizeMultiplier)
|
||||
? child.mMaxFontSizeMultiplier
|
||||
: mMaxFontSizeMultiplier;
|
||||
result.mHeightOfTallestInlineViewOrImage =
|
||||
!Float.isNaN(child.mHeightOfTallestInlineViewOrImage)
|
||||
? child.mHeightOfTallestInlineViewOrImage
|
||||
: mHeightOfTallestInlineViewOrImage;
|
||||
result.mTextTransform =
|
||||
child.mTextTransform != TextTransform.UNSET ? child.mTextTransform : mTextTransform;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Getters and setters
|
||||
//
|
||||
|
||||
public boolean getAllowFontScaling() {
|
||||
return mAllowFontScaling;
|
||||
}
|
||||
|
||||
public void setAllowFontScaling(boolean value) {
|
||||
mAllowFontScaling = value;
|
||||
}
|
||||
|
||||
public float getFontSize() {
|
||||
return mFontSize;
|
||||
}
|
||||
|
||||
public void setFontSize(float value) {
|
||||
mFontSize = value;
|
||||
}
|
||||
|
||||
public float getLineHeight() {
|
||||
return mLineHeight;
|
||||
}
|
||||
|
||||
public void setLineHeight(float value) {
|
||||
mLineHeight = value;
|
||||
}
|
||||
|
||||
public float getLetterSpacing() {
|
||||
return mLetterSpacing;
|
||||
}
|
||||
|
||||
public void setLetterSpacing(float value) {
|
||||
mLetterSpacing = value;
|
||||
}
|
||||
|
||||
public float getMaxFontSizeMultiplier() {
|
||||
return mMaxFontSizeMultiplier;
|
||||
}
|
||||
|
||||
public void setMaxFontSizeMultiplier(float maxFontSizeMultiplier) {
|
||||
if (maxFontSizeMultiplier != 0 && maxFontSizeMultiplier < 1) {
|
||||
FLog.w(ReactConstants.TAG, "maxFontSizeMultiplier must be NaN, 0, or >= 1");
|
||||
mMaxFontSizeMultiplier = Float.NaN;
|
||||
return;
|
||||
}
|
||||
mMaxFontSizeMultiplier = maxFontSizeMultiplier;
|
||||
}
|
||||
|
||||
public float getHeightOfTallestInlineViewOrImage() {
|
||||
return mHeightOfTallestInlineViewOrImage;
|
||||
}
|
||||
|
||||
public void setHeightOfTallestInlineViewOrImage(float value) {
|
||||
mHeightOfTallestInlineViewOrImage = value;
|
||||
}
|
||||
|
||||
public TextTransform getTextTransform() {
|
||||
return mTextTransform;
|
||||
}
|
||||
|
||||
public void setTextTransform(@NonNull TextTransform textTransform) {
|
||||
mTextTransform = textTransform;
|
||||
}
|
||||
|
||||
// Getters for effective values
|
||||
//
|
||||
// In general, these return `Float.NaN` if the property doesn't have a value.
|
||||
//
|
||||
|
||||
// Always returns a value because uses a hardcoded default as a fallback.
|
||||
public int getEffectiveFontSize() {
|
||||
float fontSize = !Float.isNaN(mFontSize) ? mFontSize : ViewDefaults.FONT_SIZE_SP;
|
||||
return mAllowFontScaling
|
||||
? (int) Math.ceil(PixelUtil.toPixelFromSP(fontSize, getEffectiveMaxFontSizeMultiplier()))
|
||||
: (int) Math.ceil(PixelUtil.toPixelFromDIP(fontSize));
|
||||
}
|
||||
|
||||
public float getEffectiveLineHeight() {
|
||||
if (Float.isNaN(mLineHeight)) {
|
||||
return Float.NaN;
|
||||
}
|
||||
|
||||
float lineHeight =
|
||||
mAllowFontScaling
|
||||
? PixelUtil.toPixelFromSP(mLineHeight, getEffectiveMaxFontSizeMultiplier())
|
||||
: PixelUtil.toPixelFromDIP(mLineHeight);
|
||||
|
||||
// Take into account the requested line height
|
||||
// and the height of the inline images.
|
||||
boolean useInlineViewHeight =
|
||||
!Float.isNaN(mHeightOfTallestInlineViewOrImage)
|
||||
&& mHeightOfTallestInlineViewOrImage > lineHeight;
|
||||
return useInlineViewHeight ? mHeightOfTallestInlineViewOrImage : lineHeight;
|
||||
}
|
||||
|
||||
public float getEffectiveLetterSpacing() {
|
||||
if (Float.isNaN(mLetterSpacing)) {
|
||||
return Float.NaN;
|
||||
}
|
||||
|
||||
float letterSpacingPixels =
|
||||
mAllowFontScaling
|
||||
? PixelUtil.toPixelFromSP(mLetterSpacing, getEffectiveMaxFontSizeMultiplier())
|
||||
: PixelUtil.toPixelFromDIP(mLetterSpacing);
|
||||
|
||||
// `letterSpacingPixels` and `getEffectiveFontSize` are both in pixels,
|
||||
// yielding an accurate em value.
|
||||
return letterSpacingPixels / getEffectiveFontSize();
|
||||
}
|
||||
|
||||
// Never returns NaN
|
||||
public float getEffectiveMaxFontSizeMultiplier() {
|
||||
return !Float.isNaN(mMaxFontSizeMultiplier)
|
||||
? mMaxFontSizeMultiplier
|
||||
: DEFAULT_MAX_FONT_SIZE_MULTIPLIER;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return ("TextAttributes {"
|
||||
+ "\n getAllowFontScaling(): "
|
||||
+ getAllowFontScaling()
|
||||
+ "\n getFontSize(): "
|
||||
+ getFontSize()
|
||||
+ "\n getEffectiveFontSize(): "
|
||||
+ getEffectiveFontSize()
|
||||
+ "\n getHeightOfTallestInlineViewOrImage(): "
|
||||
+ getHeightOfTallestInlineViewOrImage()
|
||||
+ "\n getLetterSpacing(): "
|
||||
+ getLetterSpacing()
|
||||
+ "\n getEffectiveLetterSpacing(): "
|
||||
+ getEffectiveLetterSpacing()
|
||||
+ "\n getLineHeight(): "
|
||||
+ getLineHeight()
|
||||
+ "\n getEffectiveLineHeight(): "
|
||||
+ getEffectiveLineHeight()
|
||||
+ "\n getTextTransform(): "
|
||||
+ getTextTransform()
|
||||
+ "\n getMaxFontSizeMultiplier(): "
|
||||
+ getMaxFontSizeMultiplier()
|
||||
+ "\n getEffectiveMaxFontSizeMultiplier(): "
|
||||
+ getEffectiveMaxFontSizeMultiplier()
|
||||
+ "\n}");
|
||||
}
|
||||
}
|
||||
+137
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.text
|
||||
|
||||
import com.facebook.common.logging.FLog
|
||||
import com.facebook.react.common.ReactConstants
|
||||
import com.facebook.react.uimanager.PixelUtil
|
||||
import com.facebook.react.uimanager.ViewDefaults
|
||||
|
||||
/*
|
||||
* Currently, TextAttributes consists of a subset of text props that need to be passed from parent
|
||||
* to child so inheritance can be implemented correctly. An example complexity that causes a prop
|
||||
* to end up in TextAttributes is when multiple props need to be considered together to determine
|
||||
* the rendered aka effective value. For example, to figure out the rendered/effective font size,
|
||||
* you need to take into account the fontSize, maxFontSizeMultiplier, and allowFontScaling props.
|
||||
*/
|
||||
public class TextAttributes {
|
||||
public var allowFontScaling: Boolean = true
|
||||
public var fontSize: Float = Float.NaN
|
||||
public var lineHeight: Float = Float.NaN
|
||||
public var letterSpacing: Float = Float.NaN
|
||||
public var heightOfTallestInlineViewOrImage: Float = Float.NaN
|
||||
|
||||
@JvmField internal var textTransform: TextTransform = TextTransform.UNSET
|
||||
|
||||
public fun applyChild(child: TextAttributes): TextAttributes {
|
||||
val result = TextAttributes()
|
||||
|
||||
// allowFontScaling is always determined by the root Text
|
||||
// component so don't allow the child to overwrite it.
|
||||
result.allowFontScaling = allowFontScaling
|
||||
|
||||
result.fontSize = if (!child.fontSize.isNaN()) child.fontSize else fontSize
|
||||
result.lineHeight = if (!child.lineHeight.isNaN()) child.lineHeight else lineHeight
|
||||
result.letterSpacing = if (!child.letterSpacing.isNaN()) child.letterSpacing else letterSpacing
|
||||
result.maxFontSizeMultiplier =
|
||||
if (!child.maxFontSizeMultiplier.isNaN()) child.maxFontSizeMultiplier
|
||||
else maxFontSizeMultiplier
|
||||
result.heightOfTallestInlineViewOrImage =
|
||||
if (!child.heightOfTallestInlineViewOrImage.isNaN()) child.heightOfTallestInlineViewOrImage
|
||||
else heightOfTallestInlineViewOrImage
|
||||
result.textTransform =
|
||||
if (child.textTransform != TextTransform.UNSET) child.textTransform else textTransform
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
public var maxFontSizeMultiplier: Float = Float.NaN
|
||||
set(maxFontSizeMultiplier) {
|
||||
if (maxFontSizeMultiplier != 0f &&
|
||||
maxFontSizeMultiplier < 1 &&
|
||||
!maxFontSizeMultiplier.isNaN()) {
|
||||
FLog.w(ReactConstants.TAG, "maxFontSizeMultiplier must be NaN, 0, or >= 1")
|
||||
field = Float.NaN
|
||||
return
|
||||
}
|
||||
field = maxFontSizeMultiplier
|
||||
}
|
||||
|
||||
public val effectiveFontSize: Int
|
||||
get() {
|
||||
val fontSize = if (!fontSize.isNaN()) fontSize else ViewDefaults.FONT_SIZE_SP
|
||||
return if (allowFontScaling) {
|
||||
Math.ceil(PixelUtil.toPixelFromSP(fontSize, effectiveMaxFontSizeMultiplier).toDouble())
|
||||
.toInt()
|
||||
} else {
|
||||
Math.ceil(PixelUtil.toPixelFromDIP(fontSize).toDouble()).toInt()
|
||||
}
|
||||
}
|
||||
|
||||
public val effectiveLineHeight: Float
|
||||
get() {
|
||||
if (lineHeight.isNaN()) {
|
||||
return Float.NaN
|
||||
}
|
||||
|
||||
val lineHeight: Float =
|
||||
if (allowFontScaling) PixelUtil.toPixelFromSP(lineHeight, effectiveMaxFontSizeMultiplier)
|
||||
else PixelUtil.toPixelFromDIP(lineHeight)
|
||||
|
||||
// Take into account the requested line height
|
||||
// and the height of the inline images.
|
||||
val useInlineViewHeight =
|
||||
!heightOfTallestInlineViewOrImage.isNaN() && heightOfTallestInlineViewOrImage > lineHeight
|
||||
return if (useInlineViewHeight) heightOfTallestInlineViewOrImage else lineHeight
|
||||
}
|
||||
|
||||
public val effectiveLetterSpacing: Float
|
||||
get() {
|
||||
if (letterSpacing.isNaN()) {
|
||||
return Float.NaN
|
||||
}
|
||||
|
||||
val letterSpacingPixels: Float =
|
||||
if (allowFontScaling)
|
||||
PixelUtil.toPixelFromSP(letterSpacing, effectiveMaxFontSizeMultiplier)
|
||||
else PixelUtil.toPixelFromDIP(letterSpacing)
|
||||
|
||||
// `letterSpacingPixels` and `getEffectiveFontSize` are both in pixels,
|
||||
// yielding an accurate em value.
|
||||
return letterSpacingPixels / effectiveFontSize
|
||||
}
|
||||
|
||||
public val effectiveMaxFontSizeMultiplier: Float
|
||||
// Never returns NaN
|
||||
get() =
|
||||
if (!maxFontSizeMultiplier.isNaN()) maxFontSizeMultiplier
|
||||
else DEFAULT_MAX_FONT_SIZE_MULTIPLIER
|
||||
|
||||
override fun toString(): String =
|
||||
"""
|
||||
TextAttributes {
|
||||
getAllowFontScaling(): $allowFontScaling
|
||||
getFontSize(): $fontSize
|
||||
getEffectiveFontSize(): $effectiveFontSize
|
||||
getHeightOfTallestInlineViewOrImage(): $heightOfTallestInlineViewOrImage
|
||||
getLetterSpacing(): $letterSpacing
|
||||
getEffectiveLetterSpacing(): $effectiveLetterSpacing
|
||||
getLineHeight(): $lineHeight
|
||||
getEffectiveLineHeight(): $effectiveLineHeight
|
||||
getTextTransform(): $textTransform
|
||||
getMaxFontSizeMultiplier(): $maxFontSizeMultiplier
|
||||
getEffectiveMaxFontSizeMultiplier(): $effectiveMaxFontSizeMultiplier
|
||||
}
|
||||
"""
|
||||
.trimIndent()
|
||||
|
||||
internal companion object {
|
||||
// Setting the default to 0 indicates that there is no max.
|
||||
public const val DEFAULT_MAX_FONT_SIZE_MULTIPLIER: Float = 0.0f
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -19,13 +19,13 @@ internal enum class TextTransform {
|
||||
CAPITALIZE,
|
||||
UNSET;
|
||||
|
||||
companion object {
|
||||
internal companion object {
|
||||
@JvmStatic
|
||||
fun apply(text: String?, textTransform: TextTransform?): String? =
|
||||
text?.applyTextTransform(textTransform)
|
||||
|
||||
@JvmStatic
|
||||
public fun applyNonNull(text: String, textTransform: TextTransform?): String =
|
||||
fun applyNonNull(text: String, textTransform: TextTransform?): String =
|
||||
text.applyTextTransform(textTransform)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user