Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,7 @@ export type AndroidTextInputNativeProps = Readonly<{
includeFontPadding?: ?boolean,
fontWeight?: ?string,
fontFamily?: ?string,
fontVariationSettings?: ?string,

/**
* I cannot find where these are defined but JS complains without them.
Expand Down Expand Up @@ -714,6 +715,7 @@ export const __INTERNAL_VIEW_CONFIG: PartialViewConfig = {
includeFontPadding: true,
fontWeight: true,
fontFamily: true,
fontVariationSettings: true,
allowFontScaling: true,
onSelectionChange: true,
mostRecentEventCount: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,7 @@ const ReactNativeStyleAttributes: {[string]: AnyAttributeType, ...} = {
fontSize: true,
fontStyle: true,
fontVariant: fontVariantAttribute,
fontVariationSettings: true,
fontWeight: true,
includeFontPadding: true,
letterSpacing: true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,12 @@ export interface TextStyle extends TextStyleIOS, TextStyleAndroid, ViewStyle {
| 'heavy'
| 'black'
| undefined;
/**
* Specifies OpenType font variation axis values using CSS syntax. An empty
* string resets inherited variation settings. On Android, this requires API
* level 26 or later.
*/
fontVariationSettings?: string | undefined;
letterSpacing?: number | undefined;
lineHeight?: number | undefined;
textAlign?:
Expand Down
6 changes: 6 additions & 0 deletions packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -1011,6 +1011,12 @@ type ____TextStyle_InternalBase = Readonly<{
*/
fontWeight?: ____FontWeight_Internal,
fontVariant?: ____FontVariantArray_Internal | string,
/**
* Specifies OpenType font variation axis values using CSS syntax. An empty
* string resets inherited variation settings. On Android, this requires API
* level 26 or later.
*/
fontVariationSettings?: string,
textShadowOffset?: Readonly<{
width: number,
height: number,
Expand Down
4 changes: 4 additions & 0 deletions packages/react-native/ReactAndroid/api/ReactAndroid.api
Original file line number Diff line number Diff line change
Expand Up @@ -4543,6 +4543,7 @@ public final class com/facebook/react/uimanager/ViewProps {
public static final field FONT_SIZE Ljava/lang/String;
public static final field FONT_STYLE Ljava/lang/String;
public static final field FONT_VARIANT Ljava/lang/String;
public static final field FONT_VARIATION_SETTINGS Ljava/lang/String;
public static final field FONT_WEIGHT Ljava/lang/String;
public static final field FOREGROUND_COLOR Ljava/lang/String;
public static final field GAP Ljava/lang/String;
Expand Down Expand Up @@ -6140,6 +6141,7 @@ public final class com/facebook/react/views/text/TextAttributeProps {
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_VARIATION_SETTINGS 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
Expand Down Expand Up @@ -6170,6 +6172,7 @@ public final class com/facebook/react/views/text/TextAttributeProps {
public final fun getFontFeatureSettings ()Ljava/lang/String;
public final fun getFontSize ()I
public final fun getFontStyle ()I
public final fun getFontVariationSettings ()Ljava/lang/String;
public final fun getFontWeight ()I
public final fun getLayoutDirection ()I
public final fun getLetterSpacing ()F
Expand Down Expand Up @@ -6358,6 +6361,7 @@ public class com/facebook/react/views/textinput/ReactTextInputManager : com/face
public final fun setFontSize (Lcom/facebook/react/views/textinput/ReactEditText;F)V
public final fun setFontStyle (Lcom/facebook/react/views/textinput/ReactEditText;Ljava/lang/String;)V
public final fun setFontVariant (Lcom/facebook/react/views/textinput/ReactEditText;Lcom/facebook/react/bridge/ReadableArray;)V
public final fun setFontVariationSettings (Lcom/facebook/react/views/textinput/ReactEditText;Ljava/lang/String;)V
public final fun setFontWeight (Lcom/facebook/react/views/textinput/ReactEditText;Ljava/lang/String;)V
public final fun setImportantForAutofill (Lcom/facebook/react/views/textinput/ReactEditText;Ljava/lang/String;)V
public final fun setIncludeFontPadding (Lcom/facebook/react/views/textinput/ReactEditText;Z)V
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ public object ViewProps {
public const val FONT_WEIGHT: String = "fontWeight"
public const val FONT_STYLE: String = "fontStyle"
public const val FONT_VARIANT: String = "fontVariant"
public const val FONT_VARIATION_SETTINGS: String = "fontVariationSettings"
public const val FONT_FAMILY: String = "fontFamily"
public const val LINE_HEIGHT: String = "lineHeight"
public const val LETTER_SPACING: String = "letterSpacing"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ package com.facebook.react.views.text
import android.content.Context
import android.content.res.AssetManager
import android.content.res.Configuration
import android.graphics.Paint
import android.graphics.Typeface
import android.graphics.fonts.FontVariationAxis
import android.os.Build
import com.facebook.common.logging.FLog
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.common.ReactConstants
import com.facebook.react.common.assets.ReactFontManager
Expand Down Expand Up @@ -151,4 +154,44 @@ public object ReactTypefaceUtils {

return Typeface.create(baseTypeface, adjustedWeight, italic)
}

internal fun parseFontVariationSettings(fontVariationSettings: String?): String? {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
return null
}

if (fontVariationSettings.isNullOrEmpty()) {
return fontVariationSettings
}

if (fontVariationSettings.trim().equals("normal", ignoreCase = true)) {
return ""
}

return try {
FontVariationAxis.fromFontVariationSettings(fontVariationSettings)
fontVariationSettings
} catch (exception: IllegalArgumentException) {
FLog.w(ReactConstants.TAG, "Invalid fontVariationSettings: $fontVariationSettings")
null
}
}

internal fun applyFontVariationSettings(paint: Paint, fontVariationSettings: String?) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
return
}

try {
paint.setFontVariationSettings(fontVariationSettings)
} catch (exception: IllegalArgumentException) {
// Paint instances are reused, so explicitly clear axes from a previous layout.
paint.setFontVariationSettings(null)
FLog.w(
ReactConstants.TAG,
"Invalid fontVariationSettings: $fontVariationSettings",
exception,
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ 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.parseFontVariationSettings
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight
import kotlin.math.ceil

Expand Down Expand Up @@ -153,6 +154,10 @@ public class TextAttributeProps private constructor() {
public var fontFeatureSettings: String? = null
private set

/** @see android.graphics.Paint.setFontVariationSettings */
public var fontVariationSettings: String? = null
private set

@Deprecated("Use lineHeight instead", ReplaceWith("lineHeight"))
public val effectiveLineHeight: Float
get() = lineHeight
Expand Down Expand Up @@ -396,6 +401,7 @@ public class TextAttributeProps private constructor() {
public const val TA_KEY_TEXT_TRANSFORM: Int = 27
public const val TA_KEY_MAX_FONT_SIZE_MULTIPLIER: Int = 29
public const val TA_KEY_TEXT_EFFECTS: Int = 30
public const val TA_KEY_FONT_VARIATION_SETTINGS: Int = 31
private const val TE_KEY_NAME: Int = 0
private const val TE_KEY_PROPS: Int = 1

Expand Down Expand Up @@ -433,6 +439,8 @@ public class TextAttributeProps private constructor() {
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_FONT_VARIATION_SETTINGS ->
result.fontVariationSettings = parseFontVariationSettings(entry.stringValue)
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()
Expand Down Expand Up @@ -500,6 +508,8 @@ public class TextAttributeProps private constructor() {
result.setFontWeight(getStringProp(props, ViewProps.FONT_WEIGHT))
result.setFontStyle(getStringProp(props, ViewProps.FONT_STYLE))
result.setFontVariant(getArrayProp(props, ViewProps.FONT_VARIANT))
result.fontVariationSettings =
parseFontVariationSettings(getStringProp(props, ViewProps.FONT_VARIATION_SETTINGS))
result.includeFontPadding = getBooleanProp(props, ViewProps.INCLUDE_FONT_PADDING, true)
result.setTextDecorationLine(getStringProp(props, ViewProps.TEXT_DECORATION_LINE))
result.textDecorationColor =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,7 @@ internal object TextLayoutManager {
if (
textAttributes.fontStyle != ReactConstants.UNSET ||
textAttributes.fontWeight != ReactConstants.UNSET ||
textAttributes.fontVariationSettings != null ||
textAttributes.fontFamily != null
) {
ops.add(
Expand All @@ -323,6 +324,7 @@ internal object TextLayoutManager {
textAttributes.fontStyle,
textAttributes.fontWeight,
textAttributes.fontFeatureSettings,
textAttributes.fontVariationSettings,
textAttributes.fontFamily,
assets,
fontWeightAdjustment,
Expand Down Expand Up @@ -547,13 +549,15 @@ internal object TextLayoutManager {
if (
fragment.props.fontStyle != ReactConstants.UNSET ||
fragment.props.fontWeight != ReactConstants.UNSET ||
fragment.props.fontVariationSettings != null ||
fragment.props.fontFamily != null
) {
spannable.setSpan(
CustomStyleSpan(
fragment.props.fontStyle,
fragment.props.fontWeight,
fragment.props.fontFeatureSettings,
fragment.props.fontVariationSettings,
fragment.props.fontFamily,
assets,
fontWeightAdjustment,
Expand Down Expand Up @@ -883,6 +887,7 @@ internal object TextLayoutManager {
if (
baseTextAttributes.fontStyle != ReactConstants.UNSET ||
baseTextAttributes.fontWeight != ReactConstants.UNSET ||
baseTextAttributes.fontVariationSettings != null ||
baseTextAttributes.fontFamily != null
) {
val typeface =
Expand Down Expand Up @@ -912,6 +917,8 @@ internal object TextLayoutManager {
paint.setTypeface(typeface)
}
}

ReactTypefaceUtils.applyFontVariationSettings(paint, baseTextAttributes.fontVariationSettings)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ internal class CustomStyleSpan(
private val privateStyle: Int,
private val privateWeight: Int,
val fontFeatureSettings: String?,
val fontVariationSettings: String?,
val fontFamily: String?,
private val assetManager: AssetManager,
private val fontWeightAdjustment: Int = 0,
Expand All @@ -41,6 +42,7 @@ internal class CustomStyleSpan(
privateStyle,
privateWeight,
fontFeatureSettings,
fontVariationSettings,
fontFamily,
assetManager,
fontWeightAdjustment,
Expand All @@ -53,6 +55,7 @@ internal class CustomStyleSpan(
privateStyle,
privateWeight,
fontFeatureSettings,
fontVariationSettings,
fontFamily,
assetManager,
fontWeightAdjustment,
Expand Down Expand Up @@ -81,6 +84,7 @@ internal class CustomStyleSpan(
style: Int,
weight: Int,
fontFeatureSettingsParam: String?,
fontVariationSettingsParam: String?,
family: String?,
assetManager: AssetManager,
fontWeightAdjustment: Int,
Expand All @@ -92,6 +96,7 @@ internal class CustomStyleSpan(
paint.apply {
fontFeatureSettings = fontFeatureSettingsParam
setTypeface(adjustedTypeface)
ReactTypefaceUtils.applyFontVariationSettings(this, fontVariationSettingsParam)
isSubpixelText = true
isLinearText = true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Rect
import android.graphics.Typeface
import android.os.Build
import android.os.Bundle
import android.text.Editable
Expand Down Expand Up @@ -47,6 +48,7 @@ import androidx.core.view.ViewCompat
import com.facebook.common.logging.FLog
import com.facebook.react.bridge.ReactSoftExceptionLogger.logSoftException
import com.facebook.react.common.ReactConstants
import com.facebook.react.common.assets.ReactFontManager
import com.facebook.react.common.build.ReactBuildConfig
import com.facebook.react.internal.featureflags.ReactNativeFeatureFlags
import com.facebook.react.internal.featureflags.ReactNativeNewArchitectureFeatureFlags
Expand All @@ -73,6 +75,7 @@ import com.facebook.react.views.text.ReactTextUpdate
import com.facebook.react.views.text.ReactTypefaceUtils.applyStyles
import com.facebook.react.views.text.ReactTypefaceUtils.getFontWeightAdjustment
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontStyle
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontVariationSettings
import com.facebook.react.views.text.ReactTypefaceUtils.parseFontWeight
import com.facebook.react.views.text.TextAttributes
import com.facebook.react.views.text.TextLayoutManager
Expand Down Expand Up @@ -135,6 +138,9 @@ public open class ReactEditText public constructor(context: Context) : AppCompat
private var fontFamily: String? = null
private var fontWeight = ReactConstants.UNSET
private var fontStyle = ReactConstants.UNSET
internal var parsedFontVariationSettings: String? = null
private set

private var autoFocus = false
private var contextMenuHidden = false
private var didAttachToWindow = false
Expand Down Expand Up @@ -646,6 +652,14 @@ public open class ReactEditText public constructor(context: Context) : AppCompat
}
}

internal fun setReactFontVariationSettings(fontVariationSettings: String?) {
val newParsedFontVariationSettings = parseFontVariationSettings(fontVariationSettings)
if (newParsedFontVariationSettings != parsedFontVariationSettings) {
parsedFontVariationSettings = newParsedFontVariationSettings
typefaceDirty = true
}
}

override fun setFontFeatureSettings(fontFeatureSettings: String?) {
if (fontFeatureSettings != getFontFeatureSettings()) {
super.setFontFeatureSettings(fontFeatureSettings)
Expand All @@ -662,14 +676,18 @@ public open class ReactEditText public constructor(context: Context) : AppCompat

val newTypeface = applyStyles(typeface, fontStyle, fontWeight, fontFamily, context.assets)
typeface = newTypeface
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
super.setFontVariationSettings(parsedFontVariationSettings)
}

// Match behavior of CustomStyleSpan and enable SUBPIXEL_TEXT_FLAG when setting anything
// nonstandard
val enableSubpixelText =
fontStyle != ReactConstants.UNSET ||
fontWeight != ReactConstants.UNSET ||
fontFamily != null ||
fontFeatureSettings != null
fontFeatureSettings != null ||
parsedFontVariationSettings != null
paintFlags =
if (enableSubpixelText) {
paintFlags or Paint.SUBPIXEL_TEXT_FLAG
Expand Down Expand Up @@ -822,11 +840,16 @@ public open class ReactEditText public constructor(context: Context) : AppCompat
span.spacing == textAttributes.effectiveLetterSpacing
}

val effectiveFontStyle = if (fontStyle == ReactConstants.UNSET) Typeface.NORMAL else fontStyle
val effectiveFontWeight =
if (fontWeight == ReactConstants.UNSET) ReactFontManager.TypefaceStyle.NORMAL
else fontWeight
stripSpansOfKind(sb, CustomStyleSpan::class.java) { span: CustomStyleSpan ->
span.style == fontStyle &&
span.style == effectiveFontStyle &&
span.fontFamily == fontFamily &&
span.weight == fontWeight &&
span.fontFeatureSettings == fontFeatureSettings
span.weight == effectiveFontWeight &&
span.fontFeatureSettings == fontFeatureSettings &&
span.fontVariationSettings == parsedFontVariationSettings
}
}

Expand Down Expand Up @@ -901,13 +924,15 @@ public open class ReactEditText public constructor(context: Context) : AppCompat
fontStyle != ReactConstants.UNSET ||
fontWeight != ReactConstants.UNSET ||
fontFamily != null ||
fontFeatureSettings != null
fontFeatureSettings != null ||
parsedFontVariationSettings != null
) {
workingText.setSpan(
CustomStyleSpan(
fontStyle,
fontWeight,
fontFeatureSettings,
parsedFontVariationSettings,
fontFamily,
context.assets,
getFontWeightAdjustment(context),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,11 @@ public open class ReactTextInputManager public constructor() :
view.fontFeatureSettings = parseFontVariant(fontVariant)
}

@ReactProp(name = ViewProps.FONT_VARIATION_SETTINGS)
public fun setFontVariationSettings(view: ReactEditText, fontVariationSettings: String?) {
view.setReactFontVariationSettings(fontVariationSettings)
}

@ReactProp(name = ViewProps.INCLUDE_FONT_PADDING, defaultBoolean = true)
public fun setIncludeFontPadding(view: ReactEditText, includepad: Boolean) {
view.includeFontPadding = includepad
Expand Down
Loading
Loading