From 85e8e1793e4834c4f692b933e9aac055ab455a4f Mon Sep 17 00:00:00 2001 From: Jorge Cabiedes Acosta Date: Thu, 3 Oct 2024 16:08:45 -0700 Subject: [PATCH] Nullable borderRadius optimization on shadows and outline Differential Revision: D63798853 --- .../uimanager/BackgroundStyleApplicator.kt | 27 ++++++------ .../drawable/CompositeBackgroundDrawable.kt | 42 +++++++++++++++++-- .../drawable/InsetBoxShadowDrawable.kt | 20 +-------- .../uimanager/drawable/OutlineDrawable.kt | 20 ++++----- .../drawable/OutsetBoxShadowDrawable.kt | 10 +---- 5 files changed, 61 insertions(+), 58 deletions(-) diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BackgroundStyleApplicator.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BackgroundStyleApplicator.kt index 68c3f807931008..27d3abadee5a4e 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BackgroundStyleApplicator.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/BackgroundStyleApplicator.kt @@ -109,6 +109,9 @@ public object BackgroundStyleApplicator { ): Unit { ensureCSSBackground(view).setBorderRadius(corner, radius) val compositeBackgroundDrawable = ensureCompositeBackgroundDrawable(view) + compositeBackgroundDrawable.borderRadius = + compositeBackgroundDrawable.borderRadius ?: BorderRadiusStyle() + compositeBackgroundDrawable.borderRadius?.set(corner, radius) if (Build.VERSION.SDK_INT >= MIN_OUTSET_BOX_SHADOW_SDK_VERSION) { val outerShadows = compositeBackgroundDrawable.outerShadows @@ -116,8 +119,7 @@ public object BackgroundStyleApplicator { for (i in 0 until outerShadows.numberOfLayers) { val shadow = outerShadows.getDrawable(i) if (shadow is OutsetBoxShadowDrawable) { - shadow.borderRadius = shadow.borderRadius ?: BorderRadiusStyle() - shadow.borderRadius?.set(corner, radius) + shadow.borderRadius = compositeBackgroundDrawable.borderRadius shadow.invalidateSelf() } } @@ -130,20 +132,15 @@ public object BackgroundStyleApplicator { for (i in 0 until innerShadows.numberOfLayers) { val shadow = innerShadows.getDrawable(i) if (shadow is InsetBoxShadowDrawable) { - shadow.borderRadius = shadow.borderRadius ?: BorderRadiusStyle() - shadow.borderRadius?.set(corner, radius) + shadow.borderRadius = compositeBackgroundDrawable.borderRadius shadow.invalidateSelf() } } } } - val outline = compositeBackgroundDrawable.outline - if (outline != null) { - outline.borderRadius = outline.borderRadius ?: BorderRadiusStyle() - outline.borderRadius?.set(corner, radius) - outline.invalidateSelf() - } + compositeBackgroundDrawable.outline?.borderRadius = compositeBackgroundDrawable.borderRadius + compositeBackgroundDrawable.outline?.invalidateSelf() } @JvmStatic @@ -219,7 +216,9 @@ public object BackgroundStyleApplicator { var innerShadows: LayerDrawable? = null var outerShadows: LayerDrawable? = null - val borderInsets = ensureCompositeBackgroundDrawable(view).borderInsets + val compositeBackgroundDrawable = ensureCompositeBackgroundDrawable(view) + val borderInsets = compositeBackgroundDrawable.borderInsets + val borderRadius = compositeBackgroundDrawable.borderRadius for (boxShadow in shadows.asReversed()) { val offsetX = boxShadow.offsetX @@ -236,7 +235,7 @@ public object BackgroundStyleApplicator { innerShadows.addLayer( InsetBoxShadowDrawable( context = view.context, - borderRadius = ensureCSSBackground(view).borderRadius, + borderRadius = borderRadius, borderInsets = borderInsets, shadowColor = color, offsetX = offsetX, @@ -250,7 +249,7 @@ public object BackgroundStyleApplicator { outerShadows.addLayer( OutsetBoxShadowDrawable( context = view.context, - borderRadius = ensureCSSBackground(view).borderRadius, + borderRadius = borderRadius, shadowColor = color, offsetX = offsetX, offsetY = offsetY, @@ -347,7 +346,7 @@ public object BackgroundStyleApplicator { outline = OutlineDrawable( context = view.context, - borderRadius = ensureCSSBackground(view).borderRadius.copy(), + borderRadius = compositeBackgroundDrawable.borderRadius, outlineColor = Color.BLACK, outlineOffset = 0f, outlineStyle = OutlineStyle.SOLID, diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CompositeBackgroundDrawable.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CompositeBackgroundDrawable.kt index 8ebb833e45fe39..5cb2d04730d549 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CompositeBackgroundDrawable.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/CompositeBackgroundDrawable.kt @@ -11,6 +11,7 @@ import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable import com.facebook.react.common.annotations.UnstableReactNativeAPI import com.facebook.react.uimanager.style.BorderInsets +import com.facebook.react.uimanager.style.BorderRadiusStyle /** * CompositeBackgroundDrawable can overlay multiple different layers, shadows, and native effects @@ -58,6 +59,8 @@ internal class CompositeBackgroundDrawable( .toTypedArray()) { // Holder value for currently set insets public var borderInsets: BorderInsets? = null + // Holder value for currently set border radius + public var borderRadius: BorderRadiusStyle? = null init { // We want to overlay drawables, instead of placing future drawables within the content area of @@ -70,7 +73,16 @@ internal class CompositeBackgroundDrawable( cssBackground: CSSBackgroundDrawable? ): CompositeBackgroundDrawable { return CompositeBackgroundDrawable( - originalBackground, outerShadows, cssBackground, feedbackUnderlay, innerShadows, outline) + originalBackground, + outerShadows, + cssBackground, + feedbackUnderlay, + innerShadows, + outline) + .apply { + borderInsets = this@CompositeBackgroundDrawable.borderInsets + borderRadius = this@CompositeBackgroundDrawable.borderRadius + } } public fun withNewShadows( @@ -78,16 +90,38 @@ internal class CompositeBackgroundDrawable( innerShadows: LayerDrawable? ): CompositeBackgroundDrawable { return CompositeBackgroundDrawable( - originalBackground, outerShadows, cssBackground, feedbackUnderlay, innerShadows, outline) + originalBackground, + outerShadows, + cssBackground, + feedbackUnderlay, + innerShadows, + outline) + .apply { + borderInsets = this@CompositeBackgroundDrawable.borderInsets + borderRadius = this@CompositeBackgroundDrawable.borderRadius + } } public fun withNewOutline(outline: OutlineDrawable): CompositeBackgroundDrawable { return CompositeBackgroundDrawable( - originalBackground, outerShadows, cssBackground, feedbackUnderlay, innerShadows, outline) + originalBackground, + outerShadows, + cssBackground, + feedbackUnderlay, + innerShadows, + outline) + .apply { + borderInsets = this@CompositeBackgroundDrawable.borderInsets + borderRadius = this@CompositeBackgroundDrawable.borderRadius + } } public fun withNewFeedbackUnderlay(newUnderlay: Drawable?): CompositeBackgroundDrawable { return CompositeBackgroundDrawable( - originalBackground, outerShadows, cssBackground, newUnderlay, innerShadows, outline) + originalBackground, outerShadows, cssBackground, newUnderlay, innerShadows, outline) + .apply { + borderInsets = this@CompositeBackgroundDrawable.borderInsets + borderRadius = this@CompositeBackgroundDrawable.borderRadius + } } } diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/InsetBoxShadowDrawable.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/InsetBoxShadowDrawable.kt index f29f148efdb2c0..09632363e0a694 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/InsetBoxShadowDrawable.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/InsetBoxShadowDrawable.kt @@ -40,30 +40,14 @@ private val ZERO_RADII = floatArrayOf(0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f) @RequiresApi(MIN_INSET_BOX_SHADOW_SDK_VERSION) internal class InsetBoxShadowDrawable( private val context: Context, - borderRadius: BorderRadiusStyle? = null, - borderInsets: BorderInsets? = null, private val shadowColor: Int, private val offsetX: Float, private val offsetY: Float, private val blurRadius: Float, private val spread: Float, + var borderRadius: BorderRadiusStyle? = null, + var borderInsets: BorderInsets? = null, ) : Drawable() { - public var borderRadius = borderRadius - set(value) { - if (value != field) { - field = value - invalidateSelf() - } - } - - public var borderInsets = borderInsets - set(value) { - if (value != field) { - field = value - invalidateSelf() - } - } - private val shadowPaint = Paint().apply { color = shadowColor diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutlineDrawable.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutlineDrawable.kt index cb7e2f10494b00..b511dd8fdf4868 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutlineDrawable.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutlineDrawable.kt @@ -23,14 +23,11 @@ import com.facebook.react.uimanager.style.ComputedBorderRadius import com.facebook.react.uimanager.style.CornerRadii import com.facebook.react.uimanager.style.OutlineStyle import kotlin.math.roundToInt -import kotlin.properties.ObservableProperty -import kotlin.properties.ReadWriteProperty -import kotlin.reflect.KProperty /** Draws outline https://drafts.csswg.org/css-ui/#outline */ internal class OutlineDrawable( private val context: Context, - borderRadius: BorderRadiusStyle? = null, + var borderRadius: BorderRadiusStyle? = null, outlineColor: Int, outlineOffset: Float, outlineStyle: OutlineStyle, @@ -43,17 +40,14 @@ internal class OutlineDrawable( */ private val gapBetweenPaths = 0.8f - private fun invalidatingChange(initialValue: T): ReadWriteProperty = - object : ObservableProperty(initialValue) { - override fun afterChange(property: KProperty<*>, oldValue: T, newValue: T) { - if (oldValue != newValue) { - invalidateSelf() - } - } + public var outlineOffset: Float = outlineOffset + set(value) { + if (value != field) { + field = value + invalidateSelf() } + } - public var borderRadius: BorderRadiusStyle? by invalidatingChange(borderRadius) - public var outlineOffset: Float by invalidatingChange(outlineOffset) public var outlineStyle: OutlineStyle = outlineStyle set(value) { if (value != field) { diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutsetBoxShadowDrawable.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutsetBoxShadowDrawable.kt index 9df839902af88e..572b1e2be08173 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutsetBoxShadowDrawable.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/drawable/OutsetBoxShadowDrawable.kt @@ -37,21 +37,13 @@ private const val BLUR_RADIUS_SIGMA_SCALE = 0.5f @RequiresApi(MIN_OUTSET_BOX_SHADOW_SDK_VERSION) internal class OutsetBoxShadowDrawable( private val context: Context, - borderRadius: BorderRadiusStyle? = null, + var borderRadius: BorderRadiusStyle? = null, private val shadowColor: Int, private val offsetX: Float, private val offsetY: Float, private val blurRadius: Float, private val spread: Float, ) : Drawable() { - public var borderRadius = borderRadius - set(value) { - if (value != field) { - field = value - invalidateSelf() - } - } - private val shadowPaint = Paint().apply { color = shadowColor