mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Migrate TextAttributeProps to Kotlin (#52452)
Summary: Migrate com.facebook.react.views.text.TextAttributeProps to Kotlin. ## Changelog: [Android][Changed] - Migrated TextAttributeProps to Kotlin. You might need to update your property access to use camelCase instead of Hungarian notation. Pull Request resolved: https://github.com/facebook/react-native/pull/52452 Test Plan: ```bash yarn test-android yarn android ``` Reviewed By: rshest Differential Revision: D79341238 Pulled By: cortinico fbshipit-source-id: 455c7b48f47a0cf240aaf330e1fa3674798e7237
This commit is contained in:
committed by
Facebook GitHub Bot
parent
bf13ecba7f
commit
fa921b3c7b
@@ -6213,97 +6213,74 @@ public final class com/facebook/react/views/text/ReactTypefaceUtils {
|
||||
public static final fun parseFontWeight (Ljava/lang/String;)I
|
||||
}
|
||||
|
||||
public class com/facebook/react/views/text/TextAttributeProps {
|
||||
public static final field TA_KEY_ACCESSIBILITY_ROLE S
|
||||
public static final field TA_KEY_ALIGNMENT S
|
||||
public static final field TA_KEY_ALLOW_FONT_SCALING S
|
||||
public static final field TA_KEY_BACKGROUND_COLOR S
|
||||
public static final field TA_KEY_BEST_WRITING_DIRECTION S
|
||||
public static final field TA_KEY_FONT_FAMILY S
|
||||
public static final field TA_KEY_FONT_SIZE S
|
||||
public static final field TA_KEY_FONT_SIZE_MULTIPLIER S
|
||||
public static final field TA_KEY_FONT_STYLE S
|
||||
public static final field TA_KEY_FONT_VARIANT S
|
||||
public static final field TA_KEY_FONT_WEIGHT S
|
||||
public static final field TA_KEY_FOREGROUND_COLOR S
|
||||
public static final field TA_KEY_IS_HIGHLIGHTED S
|
||||
public static final field TA_KEY_LAYOUT_DIRECTION S
|
||||
public static final field TA_KEY_LETTER_SPACING S
|
||||
public static final field TA_KEY_LINE_BREAK_STRATEGY S
|
||||
public static final field TA_KEY_LINE_HEIGHT S
|
||||
public static final field TA_KEY_MAX_FONT_SIZE_MULTIPLIER S
|
||||
public static final field TA_KEY_OPACITY S
|
||||
public static final field TA_KEY_ROLE S
|
||||
public static final field TA_KEY_TEXT_DECORATION_COLOR S
|
||||
public static final field TA_KEY_TEXT_DECORATION_LINE S
|
||||
public static final field TA_KEY_TEXT_DECORATION_STYLE S
|
||||
public static final field TA_KEY_TEXT_SHADOW_COLOR S
|
||||
public static final field TA_KEY_TEXT_SHADOW_OFFSET_DX S
|
||||
public static final field TA_KEY_TEXT_SHADOW_OFFSET_DY S
|
||||
public static final field TA_KEY_TEXT_SHADOW_RADIUS S
|
||||
public static final field TA_KEY_TEXT_TRANSFORM S
|
||||
public final class com/facebook/react/views/text/TextAttributeProps {
|
||||
public static final field Companion Lcom/facebook/react/views/text/TextAttributeProps$Companion;
|
||||
public static final field TA_KEY_ACCESSIBILITY_ROLE I
|
||||
public static final field TA_KEY_ALIGNMENT I
|
||||
public static final field TA_KEY_ALLOW_FONT_SCALING I
|
||||
public static final field TA_KEY_BACKGROUND_COLOR I
|
||||
public static final field TA_KEY_BEST_WRITING_DIRECTION I
|
||||
public static final field TA_KEY_FONT_FAMILY I
|
||||
public static final field TA_KEY_FONT_SIZE I
|
||||
public static final field TA_KEY_FONT_SIZE_MULTIPLIER I
|
||||
public static final field TA_KEY_FONT_STYLE I
|
||||
public static final field TA_KEY_FONT_VARIANT I
|
||||
public static final field TA_KEY_FONT_WEIGHT I
|
||||
public static final field TA_KEY_FOREGROUND_COLOR I
|
||||
public static final field TA_KEY_IS_HIGHLIGHTED I
|
||||
public static final field TA_KEY_LAYOUT_DIRECTION I
|
||||
public static final field TA_KEY_LETTER_SPACING I
|
||||
public static final field TA_KEY_LINE_BREAK_STRATEGY I
|
||||
public static final field TA_KEY_LINE_HEIGHT I
|
||||
public static final field TA_KEY_MAX_FONT_SIZE_MULTIPLIER I
|
||||
public static final field TA_KEY_OPACITY I
|
||||
public static final field TA_KEY_ROLE I
|
||||
public static final field TA_KEY_TEXT_DECORATION_COLOR I
|
||||
public static final field TA_KEY_TEXT_DECORATION_LINE I
|
||||
public static final field TA_KEY_TEXT_DECORATION_STYLE I
|
||||
public static final field TA_KEY_TEXT_SHADOW_COLOR I
|
||||
public static final field TA_KEY_TEXT_SHADOW_OFFSET_DX I
|
||||
public static final field TA_KEY_TEXT_SHADOW_OFFSET_DY I
|
||||
public static final field TA_KEY_TEXT_SHADOW_RADIUS I
|
||||
public static final field TA_KEY_TEXT_TRANSFORM I
|
||||
public static final field UNSET I
|
||||
protected field mAccessibilityRole Lcom/facebook/react/uimanager/ReactAccessibilityDelegate$AccessibilityRole;
|
||||
protected field mAllowFontScaling Z
|
||||
protected field mBackgroundColor I
|
||||
protected field mColor I
|
||||
protected field mContainsImages Z
|
||||
protected field mFontFamily Ljava/lang/String;
|
||||
protected field mFontFeatureSettings Ljava/lang/String;
|
||||
protected field mFontSize I
|
||||
protected field mFontSizeInput F
|
||||
protected field mFontStyle I
|
||||
protected field mFontWeight I
|
||||
protected field mHeightOfTallestInlineImage F
|
||||
protected field mIncludeFontPadding Z
|
||||
protected field mIsBackgroundColorSet Z
|
||||
protected field mIsColorSet Z
|
||||
protected field mIsLineThroughTextDecorationSet Z
|
||||
protected field mIsUnderlineTextDecorationSet Z
|
||||
protected field mLayoutDirection I
|
||||
protected field mLetterSpacingInput F
|
||||
protected field mLineHeight F
|
||||
protected field mLineHeightInput F
|
||||
protected field mMaxFontSizeMultiplier F
|
||||
protected field mNumberOfLines I
|
||||
protected field mOpacity F
|
||||
protected field mRole Lcom/facebook/react/uimanager/ReactAccessibilityDelegate$Role;
|
||||
protected field mTextAlign I
|
||||
protected field mTextShadowColor I
|
||||
protected field mTextShadowOffsetDx F
|
||||
protected field mTextShadowOffsetDy F
|
||||
protected field mTextShadowRadius F
|
||||
protected field mTextTransform Lcom/facebook/react/views/text/TextTransform;
|
||||
public static fun fromMapBuffer (Lcom/facebook/react/common/mapbuffer/MapBuffer;)Lcom/facebook/react/views/text/TextAttributeProps;
|
||||
public static fun fromReadableMap (Lcom/facebook/react/uimanager/ReactStylesDiffMap;)Lcom/facebook/react/views/text/TextAttributeProps;
|
||||
public fun getAccessibilityRole ()Lcom/facebook/react/uimanager/ReactAccessibilityDelegate$AccessibilityRole;
|
||||
public fun getBackgroundColor ()I
|
||||
public fun getColor ()I
|
||||
public fun getEffectiveFontSize ()I
|
||||
public fun getEffectiveLetterSpacing ()F
|
||||
public fun getEffectiveLineHeight ()F
|
||||
public static fun getEllipsizeMode (Ljava/lang/String;)Landroid/text/TextUtils$TruncateAt;
|
||||
public fun getFontFamily ()Ljava/lang/String;
|
||||
public fun getFontFeatureSettings ()Ljava/lang/String;
|
||||
public fun getFontStyle ()I
|
||||
public fun getFontWeight ()I
|
||||
public static fun getHyphenationFrequency (Ljava/lang/String;)I
|
||||
public static fun getJustificationMode (Lcom/facebook/react/uimanager/ReactStylesDiffMap;I)I
|
||||
public static fun getLayoutDirection (Ljava/lang/String;)I
|
||||
public fun getLetterSpacing ()F
|
||||
public fun getOpacity ()F
|
||||
public fun getRole ()Lcom/facebook/react/uimanager/ReactAccessibilityDelegate$Role;
|
||||
public static fun getTextAlignment (Lcom/facebook/react/uimanager/ReactStylesDiffMap;ZI)I
|
||||
public static fun getTextBreakStrategy (Ljava/lang/String;)I
|
||||
public fun getTextShadowColor ()I
|
||||
public fun getTextShadowOffsetDx ()F
|
||||
public fun getTextShadowOffsetDy ()F
|
||||
public fun getTextShadowRadius ()F
|
||||
public fun getTextTransform ()Lcom/facebook/react/views/text/TextTransform;
|
||||
public fun isBackgroundColorSet ()Z
|
||||
public fun isColorSet ()Z
|
||||
public fun isLineThroughTextDecorationSet ()Z
|
||||
public fun isUnderlineTextDecorationSet ()Z
|
||||
public final fun getAccessibilityRole ()Lcom/facebook/react/uimanager/ReactAccessibilityDelegate$AccessibilityRole;
|
||||
public final fun getAllowFontScaling ()Z
|
||||
public final fun getBackgroundColor ()Ljava/lang/Integer;
|
||||
public final fun getColor ()Ljava/lang/Integer;
|
||||
public final fun getEffectiveLetterSpacing ()F
|
||||
public final fun getEffectiveLineHeight ()F
|
||||
public final fun getFontFamily ()Ljava/lang/String;
|
||||
public final fun getFontFeatureSettings ()Ljava/lang/String;
|
||||
public final fun getFontSize ()I
|
||||
public final fun getFontStyle ()I
|
||||
public final fun getFontWeight ()I
|
||||
public final fun getLayoutDirection ()I
|
||||
public final fun getLetterSpacing ()F
|
||||
public final fun getLineHeight ()F
|
||||
public final fun getMaxFontSizeMultiplier ()F
|
||||
public final fun getNumberOfLines ()I
|
||||
public final fun getOpacity ()F
|
||||
public final fun getRole ()Lcom/facebook/react/uimanager/ReactAccessibilityDelegate$Role;
|
||||
public final fun getTextShadowColor ()I
|
||||
public final fun getTextShadowOffsetDx ()F
|
||||
public final fun getTextShadowOffsetDy ()F
|
||||
public final fun getTextShadowRadius ()F
|
||||
public final fun isBackgroundColorSet ()Z
|
||||
public final fun isColorSet ()Z
|
||||
public final fun isLineThroughTextDecorationSet ()Z
|
||||
public final fun isUnderlineTextDecorationSet ()Z
|
||||
}
|
||||
|
||||
public final class com/facebook/react/views/text/TextAttributeProps$Companion {
|
||||
public final fun fromMapBuffer (Lcom/facebook/react/common/mapbuffer/MapBuffer;)Lcom/facebook/react/views/text/TextAttributeProps;
|
||||
public final fun fromReadableMap (Lcom/facebook/react/uimanager/ReactStylesDiffMap;)Lcom/facebook/react/views/text/TextAttributeProps;
|
||||
public final fun getEllipsizeMode (Ljava/lang/String;)Landroid/text/TextUtils$TruncateAt;
|
||||
public final fun getHyphenationFrequency (Ljava/lang/String;)I
|
||||
public final fun getJustificationMode (Lcom/facebook/react/uimanager/ReactStylesDiffMap;I)I
|
||||
public final fun getLayoutDirection (Ljava/lang/String;)I
|
||||
public final fun getTextAlignment (Lcom/facebook/react/uimanager/ReactStylesDiffMap;ZI)I
|
||||
public final fun getTextBreakStrategy (Ljava/lang/String;)I
|
||||
}
|
||||
|
||||
public final class com/facebook/react/views/text/TextAttributes {
|
||||
|
||||
-811
@@ -1,811 +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 android.os.Build;
|
||||
import android.text.Layout;
|
||||
import android.text.TextUtils;
|
||||
import android.util.LayoutDirection;
|
||||
import android.view.Gravity;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.infer.annotation.Nullsafe;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.common.mapbuffer.MapBuffer;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
import com.facebook.react.uimanager.ReactAccessibilityDelegate.AccessibilityRole;
|
||||
import com.facebook.react.uimanager.ReactAccessibilityDelegate.Role;
|
||||
import com.facebook.react.uimanager.ReactStylesDiffMap;
|
||||
import com.facebook.react.uimanager.ViewProps;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
// TODO: T63643819 refactor naming of TextAttributeProps to make explicit that this represents
|
||||
// TextAttributes and not TextProps. As part of this refactor extract methods that don't belong to
|
||||
// TextAttributeProps (e.g. TextAlign)
|
||||
@Nullsafe(Nullsafe.Mode.LOCAL)
|
||||
public class TextAttributeProps {
|
||||
|
||||
// constants for Text Attributes serialization
|
||||
public static final short TA_KEY_FOREGROUND_COLOR = 0;
|
||||
public static final short TA_KEY_BACKGROUND_COLOR = 1;
|
||||
public static final short TA_KEY_OPACITY = 2;
|
||||
public static final short TA_KEY_FONT_FAMILY = 3;
|
||||
public static final short TA_KEY_FONT_SIZE = 4;
|
||||
public static final short TA_KEY_FONT_SIZE_MULTIPLIER = 5;
|
||||
public static final short TA_KEY_FONT_WEIGHT = 6;
|
||||
public static final short TA_KEY_FONT_STYLE = 7;
|
||||
public static final short TA_KEY_FONT_VARIANT = 8;
|
||||
public static final short TA_KEY_ALLOW_FONT_SCALING = 9;
|
||||
public static final short TA_KEY_LETTER_SPACING = 10;
|
||||
public static final short TA_KEY_LINE_HEIGHT = 11;
|
||||
public static final short TA_KEY_ALIGNMENT = 12;
|
||||
public static final short TA_KEY_BEST_WRITING_DIRECTION = 13;
|
||||
public static final short TA_KEY_TEXT_DECORATION_COLOR = 14;
|
||||
public static final short TA_KEY_TEXT_DECORATION_LINE = 15;
|
||||
public static final short TA_KEY_TEXT_DECORATION_STYLE = 16;
|
||||
public static final short TA_KEY_TEXT_SHADOW_RADIUS = 18;
|
||||
public static final short TA_KEY_TEXT_SHADOW_COLOR = 19;
|
||||
public static final short TA_KEY_TEXT_SHADOW_OFFSET_DX = 20;
|
||||
public static final short TA_KEY_TEXT_SHADOW_OFFSET_DY = 21;
|
||||
public static final short TA_KEY_IS_HIGHLIGHTED = 22;
|
||||
public static final short TA_KEY_LAYOUT_DIRECTION = 23;
|
||||
public static final short TA_KEY_ACCESSIBILITY_ROLE = 24;
|
||||
public static final short TA_KEY_LINE_BREAK_STRATEGY = 25;
|
||||
public static final short TA_KEY_ROLE = 26;
|
||||
public static final short TA_KEY_TEXT_TRANSFORM = 27;
|
||||
public static final short TA_KEY_MAX_FONT_SIZE_MULTIPLIER = 29;
|
||||
|
||||
public static final int UNSET = -1;
|
||||
|
||||
private static final String PROP_SHADOW_OFFSET = "textShadowOffset";
|
||||
private static final String PROP_SHADOW_OFFSET_WIDTH = "width";
|
||||
private static final String PROP_SHADOW_OFFSET_HEIGHT = "height";
|
||||
private static final String PROP_SHADOW_RADIUS = "textShadowRadius";
|
||||
private static final String PROP_SHADOW_COLOR = "textShadowColor";
|
||||
|
||||
private static final String PROP_TEXT_TRANSFORM = "textTransform";
|
||||
|
||||
private static final int DEFAULT_TEXT_SHADOW_COLOR = 0x55000000;
|
||||
private static final int DEFAULT_JUSTIFICATION_MODE =
|
||||
(Build.VERSION.SDK_INT < Build.VERSION_CODES.O) ? 0 : Layout.JUSTIFICATION_MODE_NONE;
|
||||
private static final int DEFAULT_BREAK_STRATEGY = Layout.BREAK_STRATEGY_HIGH_QUALITY;
|
||||
private static final int DEFAULT_HYPHENATION_FREQUENCY = Layout.HYPHENATION_FREQUENCY_NONE;
|
||||
|
||||
protected float mLineHeight = Float.NaN;
|
||||
protected boolean mIsColorSet = false;
|
||||
protected boolean mAllowFontScaling = true;
|
||||
protected float mMaxFontSizeMultiplier = Float.NaN;
|
||||
protected int mColor;
|
||||
protected boolean mIsBackgroundColorSet = false;
|
||||
protected int mBackgroundColor;
|
||||
protected float mOpacity = Float.NaN;
|
||||
|
||||
protected int mNumberOfLines = ReactConstants.UNSET;
|
||||
protected int mFontSize = ReactConstants.UNSET;
|
||||
protected float mFontSizeInput = ReactConstants.UNSET;
|
||||
protected float mLineHeightInput = ReactConstants.UNSET;
|
||||
protected float mLetterSpacingInput = Float.NaN;
|
||||
protected int mTextAlign = Gravity.NO_GRAVITY;
|
||||
|
||||
// `ReactConstants.UNSET` is -1, same as `LayoutDirection.UNDEFINED` (which is a hidden symbol)
|
||||
protected int mLayoutDirection = ReactConstants.UNSET;
|
||||
|
||||
@NonNull protected TextTransform mTextTransform = TextTransform.NONE;
|
||||
|
||||
protected float mTextShadowOffsetDx = 0;
|
||||
protected float mTextShadowOffsetDy = 0;
|
||||
protected float mTextShadowRadius = 0;
|
||||
protected int mTextShadowColor = DEFAULT_TEXT_SHADOW_COLOR;
|
||||
|
||||
protected boolean mIsUnderlineTextDecorationSet = false;
|
||||
protected boolean mIsLineThroughTextDecorationSet = false;
|
||||
protected boolean mIncludeFontPadding = true;
|
||||
|
||||
protected @Nullable AccessibilityRole mAccessibilityRole = null;
|
||||
protected @Nullable Role mRole = null;
|
||||
|
||||
protected int mFontStyle = ReactConstants.UNSET;
|
||||
protected int mFontWeight = ReactConstants.UNSET;
|
||||
|
||||
/**
|
||||
* NB: If a font family is used that does not have a style in a certain Android version (ie.
|
||||
* monospace bold pre Android 5.0), that style (ie. bold) will not be inherited by nested Text
|
||||
* nodes. To retain that style, you have to add it to those nodes explicitly.
|
||||
*
|
||||
* <p>Example, Android 4.4:
|
||||
*
|
||||
* <pre>
|
||||
* <Text style={{fontFamily="serif" fontWeight="bold"}}>Bold Text</Text>
|
||||
* <Text style={{fontFamily="sans-serif"}}>Bold Text</Text>
|
||||
* <Text style={{fontFamily="serif}}>Bold Text</Text>
|
||||
*
|
||||
* <Text style={{fontFamily="monospace" fontWeight="bold"}}>Not Bold Text</Text>
|
||||
* <Text style={{fontFamily="sans-serif"}}>Not Bold Text</Text>
|
||||
* <Text style={{fontFamily="serif}}>Not Bold Text</Text>
|
||||
*
|
||||
* <Text style={{fontFamily="monospace" fontWeight="bold"}}>Not Bold Text</Text>
|
||||
* <Text style={{fontFamily="sans-serif" fontWeight="bold"}}>Bold Text</Text>
|
||||
* <Text style={{fontFamily="serif}}>Bold Text</Text>
|
||||
* </pre>
|
||||
*/
|
||||
protected @Nullable String mFontFamily = null;
|
||||
|
||||
/**
|
||||
* @see android.graphics.Paint#setFontFeatureSettings
|
||||
*/
|
||||
protected @Nullable String mFontFeatureSettings = null;
|
||||
|
||||
protected boolean mContainsImages = false;
|
||||
protected float mHeightOfTallestInlineImage = Float.NaN;
|
||||
|
||||
private TextAttributeProps() {}
|
||||
|
||||
/** Build a TextAttributeProps using data from the {@link MapBuffer} received as a parameter. */
|
||||
public static TextAttributeProps fromMapBuffer(MapBuffer props) {
|
||||
TextAttributeProps result = new TextAttributeProps();
|
||||
|
||||
// TODO T83483191: Review constants that are not being set!
|
||||
Iterator<MapBuffer.Entry> iterator = props.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
MapBuffer.Entry entry = iterator.next();
|
||||
switch (entry.getKey()) {
|
||||
case TA_KEY_FOREGROUND_COLOR:
|
||||
result.setColor(entry.getIntValue());
|
||||
break;
|
||||
case TA_KEY_BACKGROUND_COLOR:
|
||||
result.setBackgroundColor(entry.getIntValue());
|
||||
break;
|
||||
case TA_KEY_OPACITY:
|
||||
result.setOpacity((float) entry.getDoubleValue());
|
||||
break;
|
||||
case TA_KEY_FONT_FAMILY:
|
||||
result.setFontFamily(entry.getStringValue());
|
||||
break;
|
||||
case TA_KEY_FONT_SIZE:
|
||||
result.setFontSize((float) entry.getDoubleValue());
|
||||
break;
|
||||
case TA_KEY_FONT_SIZE_MULTIPLIER:
|
||||
break;
|
||||
case TA_KEY_FONT_WEIGHT:
|
||||
result.setFontWeight(entry.getStringValue());
|
||||
break;
|
||||
case TA_KEY_FONT_STYLE:
|
||||
result.setFontStyle(entry.getStringValue());
|
||||
break;
|
||||
case TA_KEY_FONT_VARIANT:
|
||||
result.setFontVariant(entry.getMapBufferValue());
|
||||
break;
|
||||
case TA_KEY_ALLOW_FONT_SCALING:
|
||||
result.setAllowFontScaling(entry.getBooleanValue());
|
||||
break;
|
||||
case TA_KEY_LETTER_SPACING:
|
||||
result.setLetterSpacing((float) entry.getDoubleValue());
|
||||
break;
|
||||
case TA_KEY_LINE_HEIGHT:
|
||||
result.setLineHeight((float) entry.getDoubleValue());
|
||||
break;
|
||||
case TA_KEY_ALIGNMENT:
|
||||
break;
|
||||
case TA_KEY_BEST_WRITING_DIRECTION:
|
||||
break;
|
||||
case TA_KEY_TEXT_DECORATION_COLOR:
|
||||
break;
|
||||
case TA_KEY_TEXT_DECORATION_LINE:
|
||||
result.setTextDecorationLine(entry.getStringValue());
|
||||
break;
|
||||
case TA_KEY_TEXT_DECORATION_STYLE:
|
||||
break;
|
||||
case TA_KEY_TEXT_SHADOW_RADIUS:
|
||||
result.setTextShadowRadius((float) entry.getDoubleValue());
|
||||
break;
|
||||
case TA_KEY_TEXT_SHADOW_COLOR:
|
||||
result.setTextShadowColor(entry.getIntValue());
|
||||
break;
|
||||
case TA_KEY_TEXT_SHADOW_OFFSET_DX:
|
||||
result.setTextShadowOffsetDx((float) entry.getDoubleValue());
|
||||
break;
|
||||
case TA_KEY_TEXT_SHADOW_OFFSET_DY:
|
||||
result.setTextShadowOffsetDy((float) entry.getDoubleValue());
|
||||
break;
|
||||
case TA_KEY_IS_HIGHLIGHTED:
|
||||
break;
|
||||
case TA_KEY_LAYOUT_DIRECTION:
|
||||
result.setLayoutDirection(entry.getStringValue());
|
||||
break;
|
||||
case TA_KEY_ACCESSIBILITY_ROLE:
|
||||
result.setAccessibilityRole(entry.getStringValue());
|
||||
break;
|
||||
case TA_KEY_ROLE:
|
||||
result.setRole(Role.values()[entry.getIntValue()]);
|
||||
break;
|
||||
case TA_KEY_TEXT_TRANSFORM:
|
||||
result.setTextTransform(entry.getStringValue());
|
||||
break;
|
||||
case TA_KEY_MAX_FONT_SIZE_MULTIPLIER:
|
||||
result.setMaxFontSizeMultiplier((float) entry.getDoubleValue());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO T83483191: Review why the following props are not serialized:
|
||||
// setNumberOfLines
|
||||
// setColor
|
||||
// setIncludeFontPadding
|
||||
return result;
|
||||
}
|
||||
|
||||
public static TextAttributeProps fromReadableMap(ReactStylesDiffMap props) {
|
||||
TextAttributeProps result = new TextAttributeProps();
|
||||
result.setNumberOfLines(getIntProp(props, ViewProps.NUMBER_OF_LINES, ReactConstants.UNSET));
|
||||
result.setLineHeight(getFloatProp(props, ViewProps.LINE_HEIGHT, ReactConstants.UNSET));
|
||||
result.setLetterSpacing(getFloatProp(props, ViewProps.LETTER_SPACING, Float.NaN));
|
||||
result.setAllowFontScaling(getBooleanProp(props, ViewProps.ALLOW_FONT_SCALING, true));
|
||||
result.setMaxFontSizeMultiplier(
|
||||
getFloatProp(props, ViewProps.MAX_FONT_SIZE_MULTIPLIER, Float.NaN));
|
||||
result.setFontSize(getFloatProp(props, ViewProps.FONT_SIZE, ReactConstants.UNSET));
|
||||
result.setColor(props.hasKey(ViewProps.COLOR) ? props.getInt(ViewProps.COLOR, 0) : null);
|
||||
result.setColor(
|
||||
props.hasKey(ViewProps.FOREGROUND_COLOR)
|
||||
? props.getInt(ViewProps.FOREGROUND_COLOR, 0)
|
||||
: null);
|
||||
result.setBackgroundColor(
|
||||
props.hasKey(ViewProps.BACKGROUND_COLOR)
|
||||
? props.getInt(ViewProps.BACKGROUND_COLOR, 0)
|
||||
: null);
|
||||
result.setOpacity(getFloatProp(props, ViewProps.OPACITY, Float.NaN));
|
||||
result.setFontFamily(getStringProp(props, ViewProps.FONT_FAMILY));
|
||||
result.setFontWeight(getStringProp(props, ViewProps.FONT_WEIGHT));
|
||||
result.setFontStyle(getStringProp(props, ViewProps.FONT_STYLE));
|
||||
result.setFontVariant(getArrayProp(props, ViewProps.FONT_VARIANT));
|
||||
result.setIncludeFontPadding(getBooleanProp(props, ViewProps.INCLUDE_FONT_PADDING, true));
|
||||
result.setTextDecorationLine(getStringProp(props, ViewProps.TEXT_DECORATION_LINE));
|
||||
result.setTextShadowOffset(
|
||||
props.hasKey(PROP_SHADOW_OFFSET) ? props.getMap(PROP_SHADOW_OFFSET) : null);
|
||||
result.setTextShadowRadius(getFloatProp(props, PROP_SHADOW_RADIUS, 1));
|
||||
result.setTextShadowColor(getIntProp(props, PROP_SHADOW_COLOR, DEFAULT_TEXT_SHADOW_COLOR));
|
||||
result.setTextTransform(getStringProp(props, PROP_TEXT_TRANSFORM));
|
||||
result.setLayoutDirection(getStringProp(props, ViewProps.LAYOUT_DIRECTION));
|
||||
result.setAccessibilityRole(getStringProp(props, ViewProps.ACCESSIBILITY_ROLE));
|
||||
result.setRole(getStringProp(props, ViewProps.ROLE));
|
||||
return result;
|
||||
}
|
||||
|
||||
public static int getTextAlignment(ReactStylesDiffMap props, boolean isRTL, int defaultValue) {
|
||||
if (!props.hasKey(ViewProps.TEXT_ALIGN)) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
String textAlignPropValue = props.getString(ViewProps.TEXT_ALIGN);
|
||||
if ("justify".equals(textAlignPropValue)) {
|
||||
return Gravity.LEFT;
|
||||
} else {
|
||||
if (textAlignPropValue == null || "auto".equals(textAlignPropValue)) {
|
||||
return Gravity.NO_GRAVITY;
|
||||
} else if ("left".equals(textAlignPropValue)) {
|
||||
return isRTL ? Gravity.RIGHT : Gravity.LEFT;
|
||||
} else if ("right".equals(textAlignPropValue)) {
|
||||
return isRTL ? Gravity.LEFT : Gravity.RIGHT;
|
||||
} else if ("center".equals(textAlignPropValue)) {
|
||||
return Gravity.CENTER_HORIZONTAL;
|
||||
} else {
|
||||
FLog.w(ReactConstants.TAG, "Invalid textAlign: " + textAlignPropValue);
|
||||
return Gravity.NO_GRAVITY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int getJustificationMode(ReactStylesDiffMap props, int defaultValue) {
|
||||
if (!props.hasKey(ViewProps.TEXT_ALIGN)) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
String textAlignPropValue = props.getString(ViewProps.TEXT_ALIGN);
|
||||
if ("justify".equals(textAlignPropValue) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
return Layout.JUSTIFICATION_MODE_INTER_WORD;
|
||||
}
|
||||
return DEFAULT_JUSTIFICATION_MODE;
|
||||
}
|
||||
|
||||
private static boolean getBooleanProp(
|
||||
ReactStylesDiffMap mProps, String name, boolean defaultValue) {
|
||||
if (mProps.hasKey(name)) {
|
||||
return mProps.getBoolean(name, defaultValue);
|
||||
} else {
|
||||
return defaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable String getStringProp(ReactStylesDiffMap mProps, String name) {
|
||||
if (mProps.hasKey(name)) {
|
||||
return mProps.getString(name);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getIntProp(ReactStylesDiffMap mProps, String name, int defaultvalue) {
|
||||
if (mProps.hasKey(name)) {
|
||||
return mProps.getInt(name, defaultvalue);
|
||||
} else {
|
||||
return defaultvalue;
|
||||
}
|
||||
}
|
||||
|
||||
private static float getFloatProp(ReactStylesDiffMap mProps, String name, float defaultvalue) {
|
||||
if (mProps.hasKey(name)) {
|
||||
return mProps.getFloat(name, defaultvalue);
|
||||
} else {
|
||||
return defaultvalue;
|
||||
}
|
||||
}
|
||||
|
||||
private static @Nullable ReadableArray getArrayProp(ReactStylesDiffMap mProps, String name) {
|
||||
if (mProps.hasKey(name)) {
|
||||
return mProps.getArray(name);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns a line height which takes into account the requested line height
|
||||
// and the height of the inline images.
|
||||
public float getEffectiveLineHeight() {
|
||||
boolean useInlineViewHeight =
|
||||
!Float.isNaN(mLineHeight)
|
||||
&& !Float.isNaN(mHeightOfTallestInlineImage)
|
||||
&& mHeightOfTallestInlineImage > mLineHeight;
|
||||
return useInlineViewHeight ? mHeightOfTallestInlineImage : mLineHeight;
|
||||
}
|
||||
|
||||
private void setNumberOfLines(int numberOfLines) {
|
||||
mNumberOfLines = numberOfLines == 0 ? ReactConstants.UNSET : numberOfLines;
|
||||
}
|
||||
|
||||
private void setLineHeight(float lineHeight) {
|
||||
mLineHeightInput = lineHeight;
|
||||
if (lineHeight == ReactConstants.UNSET) {
|
||||
mLineHeight = Float.NaN;
|
||||
} else {
|
||||
mLineHeight =
|
||||
mAllowFontScaling
|
||||
? PixelUtil.toPixelFromSP(lineHeight)
|
||||
: PixelUtil.toPixelFromDIP(lineHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private void setLetterSpacing(float letterSpacing) {
|
||||
mLetterSpacingInput = letterSpacing;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public TextTransform getTextTransform() {
|
||||
return mTextTransform;
|
||||
}
|
||||
|
||||
public float getLetterSpacing() {
|
||||
float letterSpacingPixels =
|
||||
mAllowFontScaling
|
||||
? PixelUtil.toPixelFromSP(mLetterSpacingInput)
|
||||
: PixelUtil.toPixelFromDIP(mLetterSpacingInput);
|
||||
|
||||
if (mFontSize <= 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"FontSize should be a positive value. Current value: " + mFontSize);
|
||||
}
|
||||
// `letterSpacingPixels` and `mFontSize` are both in pixels,
|
||||
// yielding an accurate em value.
|
||||
return letterSpacingPixels / mFontSize;
|
||||
}
|
||||
|
||||
public float getEffectiveLetterSpacing() {
|
||||
return getLetterSpacing();
|
||||
}
|
||||
|
||||
public int getEffectiveFontSize() {
|
||||
return mFontSize;
|
||||
}
|
||||
|
||||
private void setAllowFontScaling(boolean allowFontScaling) {
|
||||
if (allowFontScaling != mAllowFontScaling) {
|
||||
mAllowFontScaling = allowFontScaling;
|
||||
setFontSize(mFontSizeInput);
|
||||
setLineHeight(mLineHeightInput);
|
||||
}
|
||||
}
|
||||
|
||||
private void setMaxFontSizeMultiplier(float maxFontSizeMultiplier) {
|
||||
if (maxFontSizeMultiplier != mMaxFontSizeMultiplier) {
|
||||
mMaxFontSizeMultiplier = maxFontSizeMultiplier;
|
||||
setFontSize(mFontSizeInput);
|
||||
setLineHeight(mLineHeightInput);
|
||||
}
|
||||
}
|
||||
|
||||
private void setFontSize(float fontSize) {
|
||||
mFontSizeInput = fontSize;
|
||||
if (fontSize != ReactConstants.UNSET) {
|
||||
fontSize =
|
||||
mAllowFontScaling
|
||||
? (float) Math.ceil(PixelUtil.toPixelFromSP(fontSize, mMaxFontSizeMultiplier))
|
||||
: (float) Math.ceil(PixelUtil.toPixelFromDIP(fontSize));
|
||||
}
|
||||
mFontSize = (int) fontSize;
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return mColor;
|
||||
}
|
||||
|
||||
private void setColor(@Nullable Integer color) {
|
||||
mIsColorSet = (color != null);
|
||||
if (color != null) {
|
||||
mColor = color;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isColorSet() {
|
||||
return mIsColorSet;
|
||||
}
|
||||
|
||||
public int getBackgroundColor() {
|
||||
return mBackgroundColor;
|
||||
}
|
||||
|
||||
private void setBackgroundColor(@Nullable Integer color) {
|
||||
// TODO: Don't apply background color to anchor TextView since it will be applied on the View
|
||||
// directly
|
||||
// if (!isVirtualAnchor()) {
|
||||
mIsBackgroundColorSet = (color != null);
|
||||
if (color != null) {
|
||||
mBackgroundColor = color;
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
public float getOpacity() {
|
||||
return mOpacity;
|
||||
}
|
||||
|
||||
private void setOpacity(float opacity) {
|
||||
mOpacity = opacity;
|
||||
}
|
||||
|
||||
public boolean isBackgroundColorSet() {
|
||||
return mIsBackgroundColorSet;
|
||||
}
|
||||
|
||||
public int getFontStyle() {
|
||||
return mFontStyle;
|
||||
}
|
||||
|
||||
public @Nullable String getFontFamily() {
|
||||
return mFontFamily;
|
||||
}
|
||||
|
||||
private void setFontFamily(@Nullable String fontFamily) {
|
||||
mFontFamily = fontFamily;
|
||||
}
|
||||
|
||||
private void setFontVariant(@Nullable ReadableArray fontVariant) {
|
||||
mFontFeatureSettings = ReactTypefaceUtils.parseFontVariant(fontVariant);
|
||||
}
|
||||
|
||||
private void setFontVariant(@Nullable MapBuffer fontVariant) {
|
||||
if (fontVariant == null || fontVariant.getCount() == 0) {
|
||||
mFontFeatureSettings = null;
|
||||
return;
|
||||
}
|
||||
|
||||
List<String> features = new ArrayList<>();
|
||||
Iterator<MapBuffer.Entry> iterator = fontVariant.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
MapBuffer.Entry entry = iterator.next();
|
||||
String value = entry.getStringValue();
|
||||
if (value != null) {
|
||||
switch (value) {
|
||||
case "small-caps":
|
||||
features.add("'smcp'");
|
||||
break;
|
||||
case "oldstyle-nums":
|
||||
features.add("'onum'");
|
||||
break;
|
||||
case "lining-nums":
|
||||
features.add("'lnum'");
|
||||
break;
|
||||
case "tabular-nums":
|
||||
features.add("'tnum'");
|
||||
break;
|
||||
case "proportional-nums":
|
||||
features.add("'pnum'");
|
||||
break;
|
||||
case "stylistic-one":
|
||||
features.add("'ss01'");
|
||||
break;
|
||||
case "stylistic-two":
|
||||
features.add("'ss02'");
|
||||
break;
|
||||
case "stylistic-three":
|
||||
features.add("'ss03'");
|
||||
break;
|
||||
case "stylistic-four":
|
||||
features.add("'ss04'");
|
||||
break;
|
||||
case "stylistic-five":
|
||||
features.add("'ss05'");
|
||||
break;
|
||||
case "stylistic-six":
|
||||
features.add("'ss06'");
|
||||
break;
|
||||
case "stylistic-seven":
|
||||
features.add("'ss07'");
|
||||
break;
|
||||
case "stylistic-eight":
|
||||
features.add("'ss08'");
|
||||
break;
|
||||
case "stylistic-nine":
|
||||
features.add("'ss09'");
|
||||
break;
|
||||
case "stylistic-ten":
|
||||
features.add("'ss10'");
|
||||
break;
|
||||
case "stylistic-eleven":
|
||||
features.add("'ss11'");
|
||||
break;
|
||||
case "stylistic-twelve":
|
||||
features.add("'ss12'");
|
||||
break;
|
||||
case "stylistic-thirteen":
|
||||
features.add("'ss13'");
|
||||
break;
|
||||
case "stylistic-fourteen":
|
||||
features.add("'ss14'");
|
||||
break;
|
||||
case "stylistic-fifteen":
|
||||
features.add("'ss15'");
|
||||
break;
|
||||
case "stylistic-sixteen":
|
||||
features.add("'ss16'");
|
||||
break;
|
||||
case "stylistic-seventeen":
|
||||
features.add("'ss17'");
|
||||
break;
|
||||
case "stylistic-eighteen":
|
||||
features.add("'ss18'");
|
||||
break;
|
||||
case "stylistic-nineteen":
|
||||
features.add("'ss19'");
|
||||
break;
|
||||
case "stylistic-twenty":
|
||||
features.add("'ss20'");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
mFontFeatureSettings = TextUtils.join(", ", features);
|
||||
}
|
||||
|
||||
public @Nullable String getFontFeatureSettings() {
|
||||
return mFontFeatureSettings;
|
||||
}
|
||||
|
||||
public int getFontWeight() {
|
||||
return mFontWeight;
|
||||
}
|
||||
|
||||
private void setFontWeight(@Nullable String fontWeightString) {
|
||||
mFontWeight = ReactTypefaceUtils.parseFontWeight(fontWeightString);
|
||||
}
|
||||
|
||||
private void setFontStyle(@Nullable String fontStyleString) {
|
||||
mFontStyle = ReactTypefaceUtils.parseFontStyle(fontStyleString);
|
||||
}
|
||||
|
||||
private void setIncludeFontPadding(boolean includepad) {
|
||||
mIncludeFontPadding = includepad;
|
||||
}
|
||||
|
||||
private void setTextDecorationLine(@Nullable String textDecorationLineString) {
|
||||
mIsUnderlineTextDecorationSet = false;
|
||||
mIsLineThroughTextDecorationSet = false;
|
||||
if (textDecorationLineString != null) {
|
||||
for (String textDecorationLineSubString : textDecorationLineString.split("-")) {
|
||||
if ("underline".equals(textDecorationLineSubString)) {
|
||||
mIsUnderlineTextDecorationSet = true;
|
||||
} else if ("strikethrough".equals(textDecorationLineSubString)) {
|
||||
mIsLineThroughTextDecorationSet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isUnderlineTextDecorationSet() {
|
||||
return mIsUnderlineTextDecorationSet;
|
||||
}
|
||||
|
||||
public boolean isLineThroughTextDecorationSet() {
|
||||
return mIsLineThroughTextDecorationSet;
|
||||
}
|
||||
|
||||
private void setTextShadowOffset(@Nullable ReadableMap offsetMap) {
|
||||
mTextShadowOffsetDx = 0;
|
||||
mTextShadowOffsetDy = 0;
|
||||
|
||||
if (offsetMap != null) {
|
||||
if (offsetMap.hasKey(PROP_SHADOW_OFFSET_WIDTH)
|
||||
&& !offsetMap.isNull(PROP_SHADOW_OFFSET_WIDTH)) {
|
||||
mTextShadowOffsetDx =
|
||||
PixelUtil.toPixelFromDIP(offsetMap.getDouble(PROP_SHADOW_OFFSET_WIDTH));
|
||||
}
|
||||
if (offsetMap.hasKey(PROP_SHADOW_OFFSET_HEIGHT)
|
||||
&& !offsetMap.isNull(PROP_SHADOW_OFFSET_HEIGHT)) {
|
||||
mTextShadowOffsetDy =
|
||||
PixelUtil.toPixelFromDIP(offsetMap.getDouble(PROP_SHADOW_OFFSET_HEIGHT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public float getTextShadowOffsetDx() {
|
||||
return mTextShadowOffsetDx;
|
||||
}
|
||||
|
||||
private void setTextShadowOffsetDx(float dx) {
|
||||
mTextShadowOffsetDx = PixelUtil.toPixelFromDIP(dx);
|
||||
}
|
||||
|
||||
public float getTextShadowOffsetDy() {
|
||||
return mTextShadowOffsetDy;
|
||||
}
|
||||
|
||||
private void setTextShadowOffsetDy(float dy) {
|
||||
mTextShadowOffsetDy = PixelUtil.toPixelFromDIP(dy);
|
||||
}
|
||||
|
||||
public static int getLayoutDirection(@Nullable String layoutDirection) {
|
||||
int androidLayoutDirection;
|
||||
if (layoutDirection == null || "undefined".equals(layoutDirection)) {
|
||||
androidLayoutDirection = ReactConstants.UNSET;
|
||||
} else if ("rtl".equals(layoutDirection)) {
|
||||
androidLayoutDirection = LayoutDirection.RTL;
|
||||
} else if ("ltr".equals(layoutDirection)) {
|
||||
androidLayoutDirection = LayoutDirection.LTR;
|
||||
} else {
|
||||
FLog.w(ReactConstants.TAG, "Invalid layoutDirection: " + layoutDirection);
|
||||
androidLayoutDirection = ReactConstants.UNSET;
|
||||
}
|
||||
return androidLayoutDirection;
|
||||
}
|
||||
|
||||
private void setLayoutDirection(@Nullable String layoutDirection) {
|
||||
mLayoutDirection = getLayoutDirection(layoutDirection);
|
||||
}
|
||||
|
||||
public float getTextShadowRadius() {
|
||||
return mTextShadowRadius;
|
||||
}
|
||||
|
||||
private void setTextShadowRadius(float textShadowRadius) {
|
||||
if (textShadowRadius != mTextShadowRadius) {
|
||||
mTextShadowRadius = textShadowRadius;
|
||||
}
|
||||
}
|
||||
|
||||
public int getTextShadowColor() {
|
||||
return mTextShadowColor;
|
||||
}
|
||||
|
||||
private void setTextShadowColor(int textShadowColor) {
|
||||
if (textShadowColor != mTextShadowColor) {
|
||||
mTextShadowColor = textShadowColor;
|
||||
}
|
||||
}
|
||||
|
||||
private void setTextTransform(@Nullable String textTransform) {
|
||||
if (textTransform == null || "none".equals(textTransform)) {
|
||||
mTextTransform = TextTransform.NONE;
|
||||
} else if ("uppercase".equals(textTransform)) {
|
||||
mTextTransform = TextTransform.UPPERCASE;
|
||||
} else if ("lowercase".equals(textTransform)) {
|
||||
mTextTransform = TextTransform.LOWERCASE;
|
||||
} else if ("capitalize".equals(textTransform)) {
|
||||
mTextTransform = TextTransform.CAPITALIZE;
|
||||
} else {
|
||||
FLog.w(ReactConstants.TAG, "Invalid textTransform: " + textTransform);
|
||||
mTextTransform = TextTransform.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
public @Nullable AccessibilityRole getAccessibilityRole() {
|
||||
return mAccessibilityRole;
|
||||
}
|
||||
|
||||
private void setAccessibilityRole(@Nullable String accessibilityRole) {
|
||||
if (accessibilityRole == null) {
|
||||
mAccessibilityRole = null;
|
||||
} else {
|
||||
mAccessibilityRole = AccessibilityRole.fromValue(accessibilityRole);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Role getRole() {
|
||||
return mRole;
|
||||
}
|
||||
|
||||
private void setRole(@Nullable String role) {
|
||||
if (role == null) {
|
||||
mRole = null;
|
||||
} else {
|
||||
mRole = Role.fromValue(role);
|
||||
}
|
||||
}
|
||||
|
||||
private void setRole(Role role) {
|
||||
mRole = role;
|
||||
}
|
||||
|
||||
public static int getTextBreakStrategy(@Nullable String textBreakStrategy) {
|
||||
int androidTextBreakStrategy = DEFAULT_BREAK_STRATEGY;
|
||||
if (textBreakStrategy != null) {
|
||||
switch (textBreakStrategy) {
|
||||
case "simple":
|
||||
androidTextBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
|
||||
break;
|
||||
case "balanced":
|
||||
androidTextBreakStrategy = Layout.BREAK_STRATEGY_BALANCED;
|
||||
break;
|
||||
default:
|
||||
androidTextBreakStrategy = Layout.BREAK_STRATEGY_HIGH_QUALITY;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return androidTextBreakStrategy;
|
||||
}
|
||||
|
||||
public static int getHyphenationFrequency(@Nullable String hyphenationFrequency) {
|
||||
int androidHyphenationFrequency = DEFAULT_HYPHENATION_FREQUENCY;
|
||||
if (hyphenationFrequency != null) {
|
||||
switch (hyphenationFrequency) {
|
||||
case "none":
|
||||
androidHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
|
||||
break;
|
||||
case "normal":
|
||||
androidHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NORMAL;
|
||||
break;
|
||||
default:
|
||||
androidHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_FULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return androidHyphenationFrequency;
|
||||
}
|
||||
|
||||
public static @Nullable TextUtils.TruncateAt getEllipsizeMode(@Nullable String ellipsizeMode) {
|
||||
@Nullable TextUtils.TruncateAt truncateAt = null;
|
||||
if (ellipsizeMode != null) {
|
||||
switch (ellipsizeMode) {
|
||||
case "head":
|
||||
truncateAt = TextUtils.TruncateAt.START;
|
||||
break;
|
||||
case "middle":
|
||||
truncateAt = TextUtils.TruncateAt.MIDDLE;
|
||||
break;
|
||||
case "tail":
|
||||
truncateAt = TextUtils.TruncateAt.END;
|
||||
break;
|
||||
case "clip":
|
||||
truncateAt = null;
|
||||
}
|
||||
}
|
||||
return truncateAt;
|
||||
}
|
||||
}
|
||||
+569
@@ -0,0 +1,569 @@
|
||||
/*
|
||||
* 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 android.os.Build
|
||||
import android.text.Layout
|
||||
import android.text.TextUtils
|
||||
import android.text.TextUtils.TruncateAt
|
||||
import android.util.LayoutDirection
|
||||
import android.view.Gravity
|
||||
import com.facebook.common.logging.FLog
|
||||
import com.facebook.react.bridge.ReadableArray
|
||||
import com.facebook.react.bridge.ReadableMap
|
||||
import com.facebook.react.common.ReactConstants
|
||||
import com.facebook.react.common.mapbuffer.MapBuffer
|
||||
import com.facebook.react.uimanager.PixelUtil.toPixelFromDIP
|
||||
import com.facebook.react.uimanager.PixelUtil.toPixelFromSP
|
||||
import com.facebook.react.uimanager.ReactAccessibilityDelegate
|
||||
import com.facebook.react.uimanager.ReactAccessibilityDelegate.AccessibilityRole
|
||||
import com.facebook.react.uimanager.ReactStylesDiffMap
|
||||
import com.facebook.react.uimanager.ViewProps
|
||||
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontStyle
|
||||
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontVariant
|
||||
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight
|
||||
import kotlin.math.ceil
|
||||
|
||||
// TODO: T63643819 refactor naming of TextAttributeProps to make explicit that this represents
|
||||
// TextAttributes and not TextProps. As part of this refactor extract methods that don't belong to
|
||||
// TextAttributeProps (e.g. TextAlign)
|
||||
public class TextAttributeProps private constructor() {
|
||||
public var lineHeight: Float = Float.NaN
|
||||
private set(value) {
|
||||
lineHeightInput = value
|
||||
field =
|
||||
if (value == ReactConstants.UNSET.toFloat()) {
|
||||
Float.NaN
|
||||
} else {
|
||||
if (allowFontScaling) toPixelFromSP(value) else toPixelFromDIP(value)
|
||||
}
|
||||
}
|
||||
|
||||
public var isColorSet: Boolean = false
|
||||
private set
|
||||
|
||||
public var allowFontScaling: Boolean = true
|
||||
private set(value) {
|
||||
if (value != field) {
|
||||
field = value
|
||||
setFontSize(fontSizeInput)
|
||||
lineHeight = lineHeightInput
|
||||
}
|
||||
}
|
||||
|
||||
public var maxFontSizeMultiplier: Float = Float.NaN
|
||||
private set(value) {
|
||||
if (value != field) {
|
||||
field = value
|
||||
setFontSize(fontSizeInput)
|
||||
lineHeight = lineHeightInput
|
||||
}
|
||||
}
|
||||
|
||||
public var isBackgroundColorSet: Boolean = false
|
||||
private set
|
||||
|
||||
public var opacity: Float = Float.NaN
|
||||
private set
|
||||
|
||||
public var numberOfLines: Int = ReactConstants.UNSET
|
||||
private set
|
||||
|
||||
public var fontSize: Int = ReactConstants.UNSET
|
||||
private set
|
||||
|
||||
private var fontSizeInput: Float = ReactConstants.UNSET.toFloat()
|
||||
private var lineHeightInput: Float = ReactConstants.UNSET.toFloat()
|
||||
private var letterSpacingInput: Float = Float.NaN
|
||||
|
||||
// `ReactConstants.UNSET` is -1, same as `LayoutDirection.UNDEFINED` (which is a hidden symbol)
|
||||
public var layoutDirection: Int = ReactConstants.UNSET
|
||||
private set
|
||||
|
||||
internal var textTransform: TextTransform = TextTransform.NONE
|
||||
|
||||
public var isUnderlineTextDecorationSet: Boolean = false
|
||||
private set
|
||||
|
||||
public var isLineThroughTextDecorationSet: Boolean = false
|
||||
private set
|
||||
|
||||
private var includeFontPadding: Boolean = true
|
||||
|
||||
public var accessibilityRole: AccessibilityRole? = null
|
||||
private set
|
||||
|
||||
public var role: ReactAccessibilityDelegate.Role? = null
|
||||
private set
|
||||
|
||||
public var fontStyle: Int = ReactConstants.UNSET
|
||||
private set
|
||||
|
||||
public var fontWeight: Int = ReactConstants.UNSET
|
||||
private set
|
||||
|
||||
/**
|
||||
* NB: If a font family is used that does not have a style in a certain Android version (ie.
|
||||
* monospace bold pre Android 5.0), that style (ie. bold) will not be inherited by nested Text
|
||||
* nodes. To retain that style, you have to add it to those nodes explicitly.
|
||||
*
|
||||
* Example, Android 4.4:
|
||||
* <pre>
|
||||
* <Text style={{fontFamily="serif" fontWeight="bold" }}>Bold Text</Text>
|
||||
* <Text style={{fontFamily="sans-serif"}}>Bold Text</Text>
|
||||
* <Text style={{fontFamily="serif"}}>Bold Text</Text>
|
||||
*
|
||||
* <Text style={{fontFamily="monospace" fontWeight="bold" }}>Not Bold Text</Text>
|
||||
* <Text style={{fontFamily="sans-serif"}}>Not Bold Text</Text>
|
||||
* <Text style={{fontFamily="serif"}}>Not Bold Text</Text>
|
||||
*
|
||||
* <Text style={{fontFamily="monospace" fontWeight="bold" }}>Not Bold Text</Text>
|
||||
* <Text style={{fontFamily="sans-serif" fontWeight="bold" }}>Bold Text</Text>
|
||||
* <Text style={{fontFamily="serif"}}>Bold Text</Text>
|
||||
* </pre> *
|
||||
*/
|
||||
public var fontFamily: String? = null
|
||||
private set
|
||||
|
||||
/** @see android.graphics.Paint.setFontFeatureSettings */
|
||||
public var fontFeatureSettings: String? = null
|
||||
private set
|
||||
|
||||
private var heightOfTallestInlineImage: Float = Float.NaN
|
||||
|
||||
public val effectiveLineHeight: Float
|
||||
// Returns a line height which takes into account the requested line height
|
||||
get() {
|
||||
val useInlineViewHeight =
|
||||
!lineHeight.isNaN() &&
|
||||
!heightOfTallestInlineImage.isNaN() &&
|
||||
heightOfTallestInlineImage > lineHeight
|
||||
return if (useInlineViewHeight) heightOfTallestInlineImage else lineHeight
|
||||
}
|
||||
|
||||
private fun setNumberOfLines(numberOfLines: Int) {
|
||||
this.numberOfLines = if (numberOfLines == 0) ReactConstants.UNSET else numberOfLines
|
||||
}
|
||||
|
||||
public var letterSpacing: Float
|
||||
get() {
|
||||
val letterSpacingPixels =
|
||||
if (allowFontScaling) toPixelFromSP(letterSpacingInput)
|
||||
else toPixelFromDIP(letterSpacingInput)
|
||||
|
||||
require(fontSize > 0) { "FontSize should be a positive value. Current value: $fontSize" }
|
||||
// `letterSpacingPixels` and `fontSize` are both in pixels,
|
||||
// yielding an accurate em value.
|
||||
return letterSpacingPixels / fontSize
|
||||
}
|
||||
private set(letterSpacing) {
|
||||
letterSpacingInput = letterSpacing
|
||||
}
|
||||
|
||||
public val effectiveLetterSpacing: Float
|
||||
get() = letterSpacing
|
||||
|
||||
private fun setFontSize(fontSize: Float) {
|
||||
var fontSizeLocal = fontSize
|
||||
fontSizeInput = fontSizeLocal
|
||||
if (fontSizeLocal != ReactConstants.UNSET.toFloat()) {
|
||||
fontSizeLocal =
|
||||
if (allowFontScaling)
|
||||
ceil(toPixelFromSP(fontSize, maxFontSizeMultiplier).toDouble()).toFloat()
|
||||
else ceil(toPixelFromDIP(fontSize).toDouble()).toFloat()
|
||||
}
|
||||
this.fontSize = fontSizeLocal.toInt()
|
||||
}
|
||||
|
||||
public var color: Int? = null
|
||||
private set(value) {
|
||||
isColorSet = (value != null)
|
||||
if (value != null) {
|
||||
field = value
|
||||
}
|
||||
}
|
||||
|
||||
public var backgroundColor: Int? = 0
|
||||
private set(color) {
|
||||
// TODO: Don't apply background color to anchor TextView since it will be applied on the
|
||||
// View directly
|
||||
// if (!isVirtualAnchor()) {
|
||||
isBackgroundColorSet = (color != null)
|
||||
if (color != null) {
|
||||
field = color
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
private fun setFontVariant(fontVariant: ReadableArray?) {
|
||||
fontFeatureSettings = parseFontVariant(fontVariant)
|
||||
}
|
||||
|
||||
private fun setFontVariant(fontVariant: MapBuffer?) {
|
||||
if (fontVariant == null || fontVariant.count == 0) {
|
||||
fontFeatureSettings = null
|
||||
return
|
||||
}
|
||||
|
||||
val features: MutableList<String?> = ArrayList()
|
||||
val iterator = fontVariant.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val entry = iterator.next()
|
||||
val value = entry.stringValue
|
||||
@Suppress("SENSELESS_COMPARISON")
|
||||
if (value != null) {
|
||||
when (value) {
|
||||
"small-caps" -> features.add("'smcp'")
|
||||
"oldstyle-nums" -> features.add("'onum'")
|
||||
"lining-nums" -> features.add("'lnum'")
|
||||
"tabular-nums" -> features.add("'tnum'")
|
||||
"proportional-nums" -> features.add("'pnum'")
|
||||
"stylistic-one" -> features.add("'ss01'")
|
||||
"stylistic-two" -> features.add("'ss02'")
|
||||
"stylistic-three" -> features.add("'ss03'")
|
||||
"stylistic-four" -> features.add("'ss04'")
|
||||
"stylistic-five" -> features.add("'ss05'")
|
||||
"stylistic-six" -> features.add("'ss06'")
|
||||
"stylistic-seven" -> features.add("'ss07'")
|
||||
"stylistic-eight" -> features.add("'ss08'")
|
||||
"stylistic-nine" -> features.add("'ss09'")
|
||||
"stylistic-ten" -> features.add("'ss10'")
|
||||
"stylistic-eleven" -> features.add("'ss11'")
|
||||
"stylistic-twelve" -> features.add("'ss12'")
|
||||
"stylistic-thirteen" -> features.add("'ss13'")
|
||||
"stylistic-fourteen" -> features.add("'ss14'")
|
||||
"stylistic-fifteen" -> features.add("'ss15'")
|
||||
"stylistic-sixteen" -> features.add("'ss16'")
|
||||
"stylistic-seventeen" -> features.add("'ss17'")
|
||||
"stylistic-eighteen" -> features.add("'ss18'")
|
||||
"stylistic-nineteen" -> features.add("'ss19'")
|
||||
"stylistic-twenty" -> features.add("'ss20'")
|
||||
}
|
||||
}
|
||||
}
|
||||
fontFeatureSettings = TextUtils.join(", ", features)
|
||||
}
|
||||
|
||||
private fun setFontWeight(fontWeightString: String?) {
|
||||
fontWeight = parseFontWeight(fontWeightString)
|
||||
}
|
||||
|
||||
private fun setFontStyle(fontStyleString: String?) {
|
||||
fontStyle = parseFontStyle(fontStyleString)
|
||||
}
|
||||
|
||||
private fun setTextDecorationLine(textDecorationLineString: String?) {
|
||||
isUnderlineTextDecorationSet = false
|
||||
isLineThroughTextDecorationSet = false
|
||||
if (textDecorationLineString != null) {
|
||||
for (textDecorationLineSubString in
|
||||
textDecorationLineString
|
||||
.split("-".toRegex())
|
||||
.dropLastWhile { it.isEmpty() }
|
||||
.toTypedArray()) {
|
||||
if ("underline" == textDecorationLineSubString) {
|
||||
isUnderlineTextDecorationSet = true
|
||||
} else if ("strikethrough" == textDecorationLineSubString) {
|
||||
isLineThroughTextDecorationSet = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setTextShadowOffset(offsetMap: ReadableMap?) {
|
||||
textShadowOffsetDx = 0f
|
||||
textShadowOffsetDy = 0f
|
||||
|
||||
if (offsetMap != null) {
|
||||
if (offsetMap.hasKey(PROP_SHADOW_OFFSET_WIDTH) &&
|
||||
!offsetMap.isNull(PROP_SHADOW_OFFSET_WIDTH)) {
|
||||
textShadowOffsetDx = toPixelFromDIP(offsetMap.getDouble(PROP_SHADOW_OFFSET_WIDTH))
|
||||
}
|
||||
if (offsetMap.hasKey(PROP_SHADOW_OFFSET_HEIGHT) &&
|
||||
!offsetMap.isNull(PROP_SHADOW_OFFSET_HEIGHT)) {
|
||||
textShadowOffsetDy = toPixelFromDIP(offsetMap.getDouble(PROP_SHADOW_OFFSET_HEIGHT))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public var textShadowOffsetDx: Float = 0f
|
||||
private set(value) {
|
||||
field = toPixelFromDIP(value)
|
||||
}
|
||||
|
||||
public var textShadowOffsetDy: Float = 0f
|
||||
private set(value) {
|
||||
field = toPixelFromDIP(value)
|
||||
}
|
||||
|
||||
private fun setLayoutDirection(layoutDirection: String?) {
|
||||
this.layoutDirection = getLayoutDirection(layoutDirection)
|
||||
}
|
||||
|
||||
public var textShadowRadius: Float = 0f
|
||||
private set(value) {
|
||||
if (value != field) {
|
||||
field = value
|
||||
}
|
||||
}
|
||||
|
||||
public var textShadowColor: Int = DEFAULT_TEXT_SHADOW_COLOR
|
||||
private set(value) {
|
||||
if (value != field) {
|
||||
field = value
|
||||
}
|
||||
}
|
||||
|
||||
private fun setTextTransform(textTransform: String?) {
|
||||
this.textTransform =
|
||||
when (textTransform) {
|
||||
null,
|
||||
"none" -> TextTransform.NONE
|
||||
"uppercase" -> TextTransform.UPPERCASE
|
||||
"lowercase" -> TextTransform.LOWERCASE
|
||||
"capitalize" -> TextTransform.CAPITALIZE
|
||||
else -> {
|
||||
FLog.w(ReactConstants.TAG, "Invalid textTransform: $textTransform")
|
||||
TextTransform.NONE
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun setAccessibilityRole(accessibilityRole: String?) {
|
||||
this.accessibilityRole =
|
||||
if (accessibilityRole == null) null else AccessibilityRole.fromValue(accessibilityRole)
|
||||
}
|
||||
|
||||
private fun setRole(role: String?) {
|
||||
if (role == null) {
|
||||
this.role = null
|
||||
} else {
|
||||
this.role = ReactAccessibilityDelegate.Role.fromValue(role)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setRole(role: ReactAccessibilityDelegate.Role) {
|
||||
this.role = role
|
||||
}
|
||||
|
||||
public companion object {
|
||||
// constants for Text Attributes serialization
|
||||
public const val TA_KEY_FOREGROUND_COLOR: Int = 0
|
||||
public const val TA_KEY_BACKGROUND_COLOR: Int = 1
|
||||
public const val TA_KEY_OPACITY: Int = 2
|
||||
public const val TA_KEY_FONT_FAMILY: Int = 3
|
||||
public const val TA_KEY_FONT_SIZE: Int = 4
|
||||
public const val TA_KEY_FONT_SIZE_MULTIPLIER: Int = 5
|
||||
public const val TA_KEY_FONT_WEIGHT: Int = 6
|
||||
public const val TA_KEY_FONT_STYLE: Int = 7
|
||||
public const val TA_KEY_FONT_VARIANT: Int = 8
|
||||
public const val TA_KEY_ALLOW_FONT_SCALING: Int = 9
|
||||
public const val TA_KEY_LETTER_SPACING: Int = 10
|
||||
public const val TA_KEY_LINE_HEIGHT: Int = 11
|
||||
public const val TA_KEY_ALIGNMENT: Int = 12
|
||||
public const val TA_KEY_BEST_WRITING_DIRECTION: Int = 13
|
||||
public const val TA_KEY_TEXT_DECORATION_COLOR: Int = 14
|
||||
public const val TA_KEY_TEXT_DECORATION_LINE: Int = 15
|
||||
public const val TA_KEY_TEXT_DECORATION_STYLE: Int = 16
|
||||
public const val TA_KEY_TEXT_SHADOW_RADIUS: Int = 18
|
||||
public const val TA_KEY_TEXT_SHADOW_COLOR: Int = 19
|
||||
public const val TA_KEY_TEXT_SHADOW_OFFSET_DX: Int = 20
|
||||
public const val TA_KEY_TEXT_SHADOW_OFFSET_DY: Int = 21
|
||||
public const val TA_KEY_IS_HIGHLIGHTED: Int = 22
|
||||
public const val TA_KEY_LAYOUT_DIRECTION: Int = 23
|
||||
public const val TA_KEY_ACCESSIBILITY_ROLE: Int = 24
|
||||
public const val TA_KEY_LINE_BREAK_STRATEGY: Int = 25
|
||||
public const val TA_KEY_ROLE: Int = 26
|
||||
public const val TA_KEY_TEXT_TRANSFORM: Int = 27
|
||||
public const val TA_KEY_MAX_FONT_SIZE_MULTIPLIER: Int = 29
|
||||
|
||||
public const val UNSET: Int = -1
|
||||
|
||||
private const val PROP_SHADOW_OFFSET = "textShadowOffset"
|
||||
private const val PROP_SHADOW_OFFSET_WIDTH = "width"
|
||||
private const val PROP_SHADOW_OFFSET_HEIGHT = "height"
|
||||
private const val PROP_SHADOW_RADIUS = "textShadowRadius"
|
||||
private const val PROP_SHADOW_COLOR = "textShadowColor"
|
||||
|
||||
private const val PROP_TEXT_TRANSFORM = "textTransform"
|
||||
|
||||
private const val DEFAULT_TEXT_SHADOW_COLOR = 0x55000000
|
||||
private val DEFAULT_JUSTIFICATION_MODE =
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) 0 else Layout.JUSTIFICATION_MODE_NONE
|
||||
private const val DEFAULT_BREAK_STRATEGY = Layout.BREAK_STRATEGY_HIGH_QUALITY
|
||||
private const val DEFAULT_HYPHENATION_FREQUENCY = Layout.HYPHENATION_FREQUENCY_NONE
|
||||
|
||||
/** Build a TextAttributeProps using data from the [MapBuffer] received as a parameter. */
|
||||
public fun fromMapBuffer(props: MapBuffer): TextAttributeProps {
|
||||
val result = TextAttributeProps()
|
||||
|
||||
// TODO T83483191: Review constants that are not being set!
|
||||
val iterator = props.iterator()
|
||||
while (iterator.hasNext()) {
|
||||
val entry = iterator.next()
|
||||
when (entry.key) {
|
||||
TA_KEY_FOREGROUND_COLOR -> result.color = entry.intValue
|
||||
TA_KEY_BACKGROUND_COLOR -> result.backgroundColor = entry.intValue
|
||||
TA_KEY_OPACITY -> result.opacity = entry.doubleValue.toFloat()
|
||||
TA_KEY_FONT_FAMILY -> result.fontFamily = entry.stringValue
|
||||
TA_KEY_FONT_SIZE -> result.setFontSize(entry.doubleValue.toFloat())
|
||||
TA_KEY_FONT_SIZE_MULTIPLIER -> {}
|
||||
TA_KEY_FONT_WEIGHT -> result.setFontWeight(entry.stringValue)
|
||||
TA_KEY_FONT_STYLE -> result.setFontStyle(entry.stringValue)
|
||||
TA_KEY_FONT_VARIANT -> result.setFontVariant(entry.mapBufferValue)
|
||||
TA_KEY_ALLOW_FONT_SCALING -> result.allowFontScaling = entry.booleanValue
|
||||
TA_KEY_LETTER_SPACING -> result.letterSpacing = entry.doubleValue.toFloat()
|
||||
TA_KEY_LINE_HEIGHT -> result.lineHeight = entry.doubleValue.toFloat()
|
||||
TA_KEY_ALIGNMENT -> {}
|
||||
TA_KEY_BEST_WRITING_DIRECTION -> {}
|
||||
TA_KEY_TEXT_DECORATION_COLOR -> {}
|
||||
TA_KEY_TEXT_DECORATION_LINE -> result.setTextDecorationLine(entry.stringValue)
|
||||
TA_KEY_TEXT_DECORATION_STYLE -> {}
|
||||
TA_KEY_TEXT_SHADOW_RADIUS -> result.textShadowRadius = entry.doubleValue.toFloat()
|
||||
TA_KEY_TEXT_SHADOW_COLOR -> result.textShadowColor = entry.intValue
|
||||
TA_KEY_TEXT_SHADOW_OFFSET_DX -> result.textShadowOffsetDx = entry.doubleValue.toFloat()
|
||||
TA_KEY_TEXT_SHADOW_OFFSET_DY -> result.textShadowOffsetDy = entry.doubleValue.toFloat()
|
||||
TA_KEY_IS_HIGHLIGHTED -> {}
|
||||
TA_KEY_LAYOUT_DIRECTION -> result.setLayoutDirection(entry.stringValue)
|
||||
TA_KEY_ACCESSIBILITY_ROLE -> result.setAccessibilityRole(entry.stringValue)
|
||||
TA_KEY_ROLE -> result.setRole(ReactAccessibilityDelegate.Role.entries[entry.intValue])
|
||||
TA_KEY_TEXT_TRANSFORM -> result.setTextTransform(entry.stringValue)
|
||||
TA_KEY_MAX_FONT_SIZE_MULTIPLIER ->
|
||||
result.maxFontSizeMultiplier = entry.doubleValue.toFloat()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO T83483191: Review why the following props are not serialized:
|
||||
// setNumberOfLines
|
||||
// setColor
|
||||
// setIncludeFontPadding
|
||||
return result
|
||||
}
|
||||
|
||||
public fun fromReadableMap(props: ReactStylesDiffMap): TextAttributeProps {
|
||||
val result = TextAttributeProps()
|
||||
result.setNumberOfLines(getIntProp(props, ViewProps.NUMBER_OF_LINES, ReactConstants.UNSET))
|
||||
result.lineHeight = getFloatProp(props, ViewProps.LINE_HEIGHT, ReactConstants.UNSET.toFloat())
|
||||
result.letterSpacing = getFloatProp(props, ViewProps.LETTER_SPACING, Float.NaN)
|
||||
result.allowFontScaling = getBooleanProp(props, ViewProps.ALLOW_FONT_SCALING, true)
|
||||
result.maxFontSizeMultiplier =
|
||||
getFloatProp(props, ViewProps.MAX_FONT_SIZE_MULTIPLIER, Float.NaN)
|
||||
result.setFontSize(getFloatProp(props, ViewProps.FONT_SIZE, ReactConstants.UNSET.toFloat()))
|
||||
result.color = if (props.hasKey(ViewProps.COLOR)) props.getInt(ViewProps.COLOR, 0) else null
|
||||
result.color =
|
||||
if (props.hasKey(ViewProps.FOREGROUND_COLOR)) props.getInt(ViewProps.FOREGROUND_COLOR, 0)
|
||||
else null
|
||||
result.backgroundColor =
|
||||
if (props.hasKey(ViewProps.BACKGROUND_COLOR)) props.getInt(ViewProps.BACKGROUND_COLOR, 0)
|
||||
else null
|
||||
result.opacity = getFloatProp(props, ViewProps.OPACITY, Float.NaN)
|
||||
result.fontFamily = getStringProp(props, ViewProps.FONT_FAMILY)
|
||||
result.setFontWeight(getStringProp(props, ViewProps.FONT_WEIGHT))
|
||||
result.setFontStyle(getStringProp(props, ViewProps.FONT_STYLE))
|
||||
result.setFontVariant(getArrayProp(props, ViewProps.FONT_VARIANT))
|
||||
result.includeFontPadding = getBooleanProp(props, ViewProps.INCLUDE_FONT_PADDING, true)
|
||||
result.setTextDecorationLine(getStringProp(props, ViewProps.TEXT_DECORATION_LINE))
|
||||
result.setTextShadowOffset(
|
||||
if (props.hasKey(PROP_SHADOW_OFFSET)) props.getMap(PROP_SHADOW_OFFSET) else null)
|
||||
result.textShadowRadius = getFloatProp(props, PROP_SHADOW_RADIUS, 1f)
|
||||
result.textShadowColor = getIntProp(props, PROP_SHADOW_COLOR, DEFAULT_TEXT_SHADOW_COLOR)
|
||||
result.setTextTransform(getStringProp(props, PROP_TEXT_TRANSFORM))
|
||||
result.setLayoutDirection(getStringProp(props, ViewProps.LAYOUT_DIRECTION))
|
||||
result.setAccessibilityRole(getStringProp(props, ViewProps.ACCESSIBILITY_ROLE))
|
||||
result.setRole(getStringProp(props, ViewProps.ROLE))
|
||||
return result
|
||||
}
|
||||
|
||||
public fun getTextAlignment(props: ReactStylesDiffMap, isRTL: Boolean, defaultValue: Int): Int {
|
||||
if (!props.hasKey(ViewProps.TEXT_ALIGN)) {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
return when (val textAlignPropValue = props.getString(ViewProps.TEXT_ALIGN)) {
|
||||
"justify" -> Gravity.LEFT
|
||||
null,
|
||||
"auto" -> Gravity.NO_GRAVITY
|
||||
"left" -> if (isRTL) Gravity.RIGHT else Gravity.LEFT
|
||||
"right" -> if (isRTL) Gravity.LEFT else Gravity.RIGHT
|
||||
"center" -> Gravity.CENTER_HORIZONTAL
|
||||
else -> {
|
||||
FLog.w(ReactConstants.TAG, "Invalid textAlign: $textAlignPropValue")
|
||||
Gravity.NO_GRAVITY
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun getJustificationMode(props: ReactStylesDiffMap, defaultValue: Int): Int {
|
||||
if (!props.hasKey(ViewProps.TEXT_ALIGN)) {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
val textAlignPropValue = props.getString(ViewProps.TEXT_ALIGN)
|
||||
if ("justify" == textAlignPropValue && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
return Layout.JUSTIFICATION_MODE_INTER_WORD
|
||||
}
|
||||
return DEFAULT_JUSTIFICATION_MODE
|
||||
}
|
||||
|
||||
private fun getBooleanProp(
|
||||
props: ReactStylesDiffMap,
|
||||
name: String,
|
||||
defaultValue: Boolean
|
||||
): Boolean = if (props.hasKey(name)) props.getBoolean(name, defaultValue) else defaultValue
|
||||
|
||||
private fun getStringProp(props: ReactStylesDiffMap, name: String): String? =
|
||||
if (props.hasKey(name)) props.getString(name) else null
|
||||
|
||||
private fun getIntProp(props: ReactStylesDiffMap, name: String, defaultValue: Int): Int =
|
||||
if (props.hasKey(name)) props.getInt(name, defaultValue) else defaultValue
|
||||
|
||||
private fun getFloatProp(props: ReactStylesDiffMap, name: String, defaultValue: Float): Float =
|
||||
if (props.hasKey(name)) props.getFloat(name, defaultValue) else defaultValue
|
||||
|
||||
private fun getArrayProp(props: ReactStylesDiffMap, name: String): ReadableArray? =
|
||||
if (props.hasKey(name)) props.getArray(name) else null
|
||||
|
||||
public fun getLayoutDirection(layoutDirection: String?): Int {
|
||||
return when (layoutDirection) {
|
||||
null,
|
||||
"undefined" -> ReactConstants.UNSET
|
||||
"rtl" -> LayoutDirection.RTL
|
||||
"ltr" -> LayoutDirection.LTR
|
||||
else -> {
|
||||
FLog.w(ReactConstants.TAG, "Invalid layoutDirection: $layoutDirection")
|
||||
ReactConstants.UNSET
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public fun getTextBreakStrategy(textBreakStrategy: String?): Int =
|
||||
when (textBreakStrategy) {
|
||||
null -> DEFAULT_BREAK_STRATEGY
|
||||
"simple" -> Layout.BREAK_STRATEGY_SIMPLE
|
||||
"balanced" -> Layout.BREAK_STRATEGY_BALANCED
|
||||
else -> Layout.BREAK_STRATEGY_HIGH_QUALITY
|
||||
}
|
||||
|
||||
public fun getHyphenationFrequency(hyphenationFrequency: String?): Int =
|
||||
when (hyphenationFrequency) {
|
||||
null -> DEFAULT_HYPHENATION_FREQUENCY
|
||||
"none" -> Layout.HYPHENATION_FREQUENCY_NONE
|
||||
"normal" -> Layout.HYPHENATION_FREQUENCY_NORMAL
|
||||
else -> Layout.HYPHENATION_FREQUENCY_FULL
|
||||
}
|
||||
|
||||
public fun getEllipsizeMode(ellipsizeMode: String?): TruncateAt? =
|
||||
when (ellipsizeMode) {
|
||||
"head" -> TruncateAt.START
|
||||
"middle" -> TruncateAt.MIDDLE
|
||||
"tail" -> TruncateAt.END
|
||||
"clip" -> null
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
+41
-34
@@ -231,7 +231,7 @@ internal object TextLayoutManager {
|
||||
TextAttributeProps.fromMapBuffer(fragment.getMapBuffer(FR_KEY_TEXT_ATTRIBUTES))
|
||||
|
||||
sb.append(
|
||||
TextTransform.apply(fragment.getString(FR_KEY_STRING), textAttributes.mTextTransform))
|
||||
TextTransform.apply(fragment.getString(FR_KEY_STRING), textAttributes.textTransform))
|
||||
|
||||
val end = sb.length
|
||||
val reactTag =
|
||||
@@ -246,10 +246,10 @@ internal object TextLayoutManager {
|
||||
TextInlineViewPlaceholderSpan(reactTag, width.toInt(), height.toInt())))
|
||||
} else if (end >= start) {
|
||||
val roleIsLink =
|
||||
if (textAttributes.mRole != null)
|
||||
(textAttributes.mRole == ReactAccessibilityDelegate.Role.LINK)
|
||||
if (textAttributes.role != null)
|
||||
(textAttributes.role == ReactAccessibilityDelegate.Role.LINK)
|
||||
else
|
||||
(textAttributes.mAccessibilityRole ==
|
||||
(textAttributes.accessibilityRole ==
|
||||
ReactAccessibilityDelegate.AccessibilityRole.LINK)
|
||||
if (roleIsLink) {
|
||||
if (ReactNativeFeatureFlags.enablePreparedTextLayout()) {
|
||||
@@ -258,13 +258,17 @@ internal object TextLayoutManager {
|
||||
ops.add(SetSpanOperation(start, end, ReactClickableSpan(reactTag)))
|
||||
}
|
||||
}
|
||||
if (textAttributes.mIsColorSet) {
|
||||
ops.add(SetSpanOperation(start, end, ReactForegroundColorSpan(textAttributes.mColor)))
|
||||
if (textAttributes.isColorSet) {
|
||||
textAttributes.color
|
||||
?.let { ReactForegroundColorSpan(it) }
|
||||
?.let { SetSpanOperation(start, end, it) }
|
||||
?.let { ops.add(it) }
|
||||
}
|
||||
if (textAttributes.mIsBackgroundColorSet) {
|
||||
ops.add(
|
||||
SetSpanOperation(
|
||||
start, end, ReactBackgroundColorSpan(textAttributes.mBackgroundColor)))
|
||||
if (textAttributes.isBackgroundColorSet) {
|
||||
textAttributes.backgroundColor
|
||||
?.let { ReactBackgroundColorSpan(it) }
|
||||
?.let { SetSpanOperation(start, end, it) }
|
||||
?.let { ops.add(it) }
|
||||
}
|
||||
if (!textAttributes.opacity.isNaN()) {
|
||||
ops.add(SetSpanOperation(start, end, ReactOpacitySpan(textAttributes.opacity)))
|
||||
@@ -273,40 +277,40 @@ internal object TextLayoutManager {
|
||||
ops.add(
|
||||
SetSpanOperation(start, end, CustomLetterSpacingSpan(textAttributes.letterSpacing)))
|
||||
}
|
||||
ops.add(SetSpanOperation(start, end, ReactAbsoluteSizeSpan(textAttributes.mFontSize)))
|
||||
if (textAttributes.mFontStyle != ReactConstants.UNSET ||
|
||||
textAttributes.mFontWeight != ReactConstants.UNSET ||
|
||||
textAttributes.mFontFamily != null) {
|
||||
ops.add(SetSpanOperation(start, end, ReactAbsoluteSizeSpan(textAttributes.fontSize)))
|
||||
if (textAttributes.fontStyle != ReactConstants.UNSET ||
|
||||
textAttributes.fontWeight != ReactConstants.UNSET ||
|
||||
textAttributes.fontFamily != null) {
|
||||
ops.add(
|
||||
SetSpanOperation(
|
||||
start,
|
||||
end,
|
||||
CustomStyleSpan(
|
||||
textAttributes.mFontStyle,
|
||||
textAttributes.mFontWeight,
|
||||
textAttributes.mFontFeatureSettings,
|
||||
textAttributes.mFontFamily,
|
||||
textAttributes.fontStyle,
|
||||
textAttributes.fontWeight,
|
||||
textAttributes.fontFeatureSettings,
|
||||
textAttributes.fontFamily,
|
||||
context.assets)))
|
||||
}
|
||||
if (textAttributes.mIsUnderlineTextDecorationSet) {
|
||||
if (textAttributes.isUnderlineTextDecorationSet) {
|
||||
ops.add(SetSpanOperation(start, end, ReactUnderlineSpan()))
|
||||
}
|
||||
if (textAttributes.mIsLineThroughTextDecorationSet) {
|
||||
if (textAttributes.isLineThroughTextDecorationSet) {
|
||||
ops.add(SetSpanOperation(start, end, ReactStrikethroughSpan()))
|
||||
}
|
||||
if ((textAttributes.mTextShadowOffsetDx != 0f ||
|
||||
textAttributes.mTextShadowOffsetDy != 0f ||
|
||||
textAttributes.mTextShadowRadius != 0f) &&
|
||||
Color.alpha(textAttributes.mTextShadowColor) != 0) {
|
||||
if ((textAttributes.textShadowOffsetDx != 0f ||
|
||||
textAttributes.textShadowOffsetDy != 0f ||
|
||||
textAttributes.textShadowRadius != 0f) &&
|
||||
Color.alpha(textAttributes.textShadowColor) != 0) {
|
||||
ops.add(
|
||||
SetSpanOperation(
|
||||
start,
|
||||
end,
|
||||
ShadowStyleSpan(
|
||||
textAttributes.mTextShadowOffsetDx,
|
||||
textAttributes.mTextShadowOffsetDy,
|
||||
textAttributes.mTextShadowRadius,
|
||||
textAttributes.mTextShadowColor)))
|
||||
textAttributes.textShadowOffsetDx,
|
||||
textAttributes.textShadowOffsetDy,
|
||||
textAttributes.textShadowRadius,
|
||||
textAttributes.textShadowColor)))
|
||||
}
|
||||
if (!textAttributes.effectiveLineHeight.isNaN()) {
|
||||
ops.add(
|
||||
@@ -409,12 +413,16 @@ internal object TextLayoutManager {
|
||||
}
|
||||
|
||||
if (fragment.props.isColorSet) {
|
||||
spannable.setSpan(ReactForegroundColorSpan(fragment.props.color), start, end, spanFlags)
|
||||
spannable.setSpan(
|
||||
fragment.props.color?.let { ReactForegroundColorSpan(it) }, start, end, spanFlags)
|
||||
}
|
||||
|
||||
if (fragment.props.isBackgroundColorSet) {
|
||||
spannable.setSpan(
|
||||
ReactBackgroundColorSpan(fragment.props.backgroundColor), start, end, spanFlags)
|
||||
fragment.props.backgroundColor?.let { ReactBackgroundColorSpan(it) },
|
||||
start,
|
||||
end,
|
||||
spanFlags)
|
||||
}
|
||||
|
||||
if (!fragment.props.opacity.isNaN()) {
|
||||
@@ -426,8 +434,7 @@ internal object TextLayoutManager {
|
||||
CustomLetterSpacingSpan(fragment.props.letterSpacing), start, end, spanFlags)
|
||||
}
|
||||
|
||||
// TODO: Should this be using effectiveFontSize instead of fontSize?
|
||||
spannable.setSpan(ReactAbsoluteSizeSpan(fragment.props.mFontSize), start, end, spanFlags)
|
||||
spannable.setSpan(ReactAbsoluteSizeSpan(fragment.props.fontSize), start, end, spanFlags)
|
||||
|
||||
if (fragment.props.fontStyle != ReactConstants.UNSET ||
|
||||
fragment.props.fontWeight != ReactConstants.UNSET ||
|
||||
@@ -611,8 +618,8 @@ internal object TextLayoutManager {
|
||||
baseTextAttributes: TextAttributeProps,
|
||||
context: Context
|
||||
) {
|
||||
if (baseTextAttributes.effectiveFontSize != ReactConstants.UNSET) {
|
||||
paint.textSize = baseTextAttributes.effectiveFontSize.toFloat()
|
||||
if (baseTextAttributes.fontSize != ReactConstants.UNSET) {
|
||||
paint.textSize = baseTextAttributes.fontSize.toFloat()
|
||||
}
|
||||
|
||||
if (baseTextAttributes.fontStyle != ReactConstants.UNSET ||
|
||||
|
||||
Reference in New Issue
Block a user