Revamp InsetBoxShadowDrawable (#46074)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/46074

This brings over the changes made to OutsetBoxShadowDrawable. Namely

1. Removing reliance on CSSBackgroundDrawable for drawing paths
2. Using BlurMaskFilter instead of RenderEffect
3. Removing RenderNode usage

This should make the implementation, more reliable less memory intensive for large boxes, and compatible down to Android API 29. I changed previous gating to allow outset shadows for 28+, and inset for 29+.

Changelog:
[Android][Changed] - Revamp InsetBoxShadowDrawable

Reviewed By: joevilches

Differential Revision: D61348615

fbshipit-source-id: 97b63b5dce65224ca54b76c5318c219973fc09fa
This commit is contained in:
Nick Gerleman
2024-08-17 09:21:06 -07:00
committed by Facebook GitHub Bot
parent f905f90468
commit d9f684b1cf
6 changed files with 298 additions and 142 deletions
@@ -14,14 +14,17 @@ import android.graphics.drawable.Drawable
import android.os.Build
import android.view.View
import androidx.annotation.ColorInt
import androidx.annotation.RequiresApi
import com.facebook.common.logging.FLog
import com.facebook.react.bridge.ReadableArray
import com.facebook.react.common.annotations.UnstableReactNativeAPI
import com.facebook.react.uimanager.common.UIManagerType
import com.facebook.react.uimanager.common.ViewUtil
import com.facebook.react.uimanager.drawable.CSSBackgroundDrawable
import com.facebook.react.uimanager.drawable.CompositeBackgroundDrawable
import com.facebook.react.uimanager.drawable.InsetBoxShadowDrawable
import com.facebook.react.uimanager.drawable.MIN_INSET_BOX_SHADOW_SDK_VERSION
import com.facebook.react.uimanager.drawable.MIN_OUTSET_BOX_SHADOW_SDK_VERSION
import com.facebook.react.uimanager.drawable.OutsetBoxShadowDrawable
import com.facebook.react.uimanager.style.BorderInsets
import com.facebook.react.uimanager.style.BorderRadiusProp
import com.facebook.react.uimanager.style.BorderRadiusStyle
import com.facebook.react.uimanager.style.BorderStyle
@@ -51,9 +54,21 @@ public object BackgroundStyleApplicator {
public fun getBackgroundColor(view: View): Int? = getCSSBackground(view)?.color
@JvmStatic
public fun setBorderWidth(view: View, edge: LogicalEdge, width: Float?): Unit =
ensureCSSBackground(view)
.setBorderWidth(edge.toSpacingType(), PixelUtil.toPixelFromDIP(width ?: Float.NaN))
public fun setBorderWidth(view: View, edge: LogicalEdge, width: Float?): Unit {
ensureCSSBackground(view)
.setBorderWidth(edge.toSpacingType(), PixelUtil.toPixelFromDIP(width ?: Float.NaN))
if (Build.VERSION.SDK_INT >= MIN_INSET_BOX_SHADOW_SDK_VERSION) {
val composite = ensureCompositeBackgroundDrawable(view)
composite.borderInsets = composite.borderInsets ?: BorderInsets()
composite.borderInsets?.setBorderWidth(edge, width)
for (shadow in composite.innerShadows) {
(shadow as InsetBoxShadowDrawable).borderInsets = composite.borderInsets
shadow.invalidateSelf()
}
}
}
@JvmStatic
public fun getBorderWidth(view: View, edge: LogicalEdge): Float? {
@@ -77,12 +92,25 @@ public object BackgroundStyleApplicator {
radius: LengthPercentage?
): Unit {
ensureCSSBackground(view).setBorderRadius(corner, radius)
val compositeBackgroundDrawable = ensureCompositeBackgroundDrawable(view)
if (Build.VERSION.SDK_INT >= 31) {
getCompositeBackgroundDrawable(view)?.outerShadows?.forEach { shadow ->
val outsetShadow = shadow as OutsetBoxShadowDrawable
outsetShadow.borderRadius = outsetShadow.borderRadius ?: BorderRadiusStyle()
outsetShadow.borderRadius?.set(corner, radius)
if (Build.VERSION.SDK_INT >= MIN_OUTSET_BOX_SHADOW_SDK_VERSION) {
for (shadow in compositeBackgroundDrawable.outerShadows) {
if (shadow is OutsetBoxShadowDrawable) {
shadow.borderRadius = shadow.borderRadius ?: BorderRadiusStyle()
shadow.borderRadius?.set(corner, radius)
shadow.invalidateSelf()
}
}
}
if (Build.VERSION.SDK_INT >= MIN_INSET_BOX_SHADOW_SDK_VERSION) {
for (shadow in compositeBackgroundDrawable.innerShadows) {
if (shadow is InsetBoxShadowDrawable) {
shadow.borderRadius = shadow.borderRadius ?: BorderRadiusStyle()
shadow.borderRadius?.set(corner, radius)
shadow.invalidateSelf()
}
}
}
}
@@ -100,11 +128,16 @@ public object BackgroundStyleApplicator {
public fun getBorderStyle(view: View): BorderStyle? = getCSSBackground(view)?.borderStyle
@JvmStatic
@RequiresApi(31)
public fun setBoxShadow(view: View, shadows: List<BoxShadow>): Unit {
if (ViewUtil.getUIManagerType(view) != UIManagerType.FABRIC) {
return
}
val outerShadows = mutableListOf<OutsetBoxShadowDrawable>()
val innerShadows = mutableListOf<InsetBoxShadowDrawable>()
val borderInsets = ensureCompositeBackgroundDrawable(view).borderInsets
for (boxShadow in shadows) {
val offsetX = boxShadow.offsetX
val offsetY = boxShadow.offsetY
@@ -113,17 +146,18 @@ public object BackgroundStyleApplicator {
val spreadDistance = boxShadow.spreadDistance ?: 0f
val inset = boxShadow.inset ?: false
if (inset) {
if (inset && Build.VERSION.SDK_INT >= MIN_INSET_BOX_SHADOW_SDK_VERSION) {
innerShadows.add(
InsetBoxShadowDrawable(
context = view.context,
background = ensureCSSBackground(view),
borderRadius = ensureCSSBackground(view).borderRadius,
borderInsets = borderInsets,
shadowColor = color,
offsetX = offsetX,
offsetY = offsetY,
blurRadius = blurRadius,
spread = spreadDistance))
} else {
} else if (!inset && Build.VERSION.SDK_INT >= MIN_OUTSET_BOX_SHADOW_SDK_VERSION) {
outerShadows.add(
OutsetBoxShadowDrawable(
context = view.context,
@@ -143,11 +177,6 @@ public object BackgroundStyleApplicator {
@JvmStatic
public fun setBoxShadow(view: View, shadows: ReadableArray?): Unit {
if (Build.VERSION.SDK_INT < 31) {
FLog.w("BackgroundStyleApplicator", "\"boxShadow\" requires Android 12 or later")
return
}
if (shadows == null) {
BackgroundStyleApplicator.setBoxShadow(view, emptyList())
return
@@ -25,5 +25,5 @@ internal fun adjustRadiusForSpread(
} else {
1f
}
return (radius + abs(spread) * spreadMultiplier).coerceAtLeast(0f)
return (radius + spread * spreadMultiplier).coerceAtLeast(0f)
}
@@ -10,6 +10,7 @@ package com.facebook.react.uimanager.drawable
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import com.facebook.react.common.annotations.UnstableReactNativeAPI
import com.facebook.react.uimanager.style.BorderInsets
/**
* CompositeBackgroundDrawable can overlay multiple different layers, shadows, and native effects
@@ -52,6 +53,9 @@ internal class CompositeBackgroundDrawable(
*innerShadows.asReversed().toTypedArray())
.toTypedArray()) {
// Holder value for currently set insets
public var borderInsets: BorderInsets? = null
init {
// We want to overlay drawables, instead of placing future drawables within the content area of
// previous ones. E.g. an EditText style may set padding on a TextInput, but we don't want to
@@ -8,171 +8,187 @@
package com.facebook.react.uimanager.drawable
import android.content.Context
import android.graphics.BlurMaskFilter
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.ColorFilter
import android.graphics.Paint
import android.graphics.Rect
import android.graphics.RenderNode
import android.graphics.Path
import android.graphics.RectF
import android.graphics.drawable.Drawable
import androidx.annotation.RequiresApi
import com.facebook.common.logging.FLog
import com.facebook.react.common.annotations.UnstableReactNativeAPI
import com.facebook.react.uimanager.FilterHelper
import com.facebook.react.uimanager.LengthPercentage
import com.facebook.react.uimanager.LengthPercentageType
import com.facebook.react.uimanager.PixelUtil
import com.facebook.react.uimanager.style.BorderInsets
import com.facebook.react.uimanager.style.BorderRadiusStyle
import com.facebook.react.uimanager.style.ComputedBorderRadius
import com.facebook.react.uimanager.style.CornerRadii
import kotlin.math.roundToInt
private const val TAG = "InsetBoxShadowDrawable"
internal const val MIN_INSET_BOX_SHADOW_SDK_VERSION = 29
// "the resulting shadow must approximate {...} a Gaussian blur with a standard deviation equal
// to half the blur radius"
// https://www.w3.org/TR/css-backgrounds-3/#shadow-blur
private const val BLUR_RADIUS_SIGMA_SCALE = 0.5f
private val ZERO_RADII = floatArrayOf(0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f)
/** Draws an inner box-shadow https://www.w3.org/TR/css-backgrounds-3/#shadow-shape */
@RequiresApi(31)
@OptIn(UnstableReactNativeAPI::class)
@RequiresApi(MIN_INSET_BOX_SHADOW_SDK_VERSION)
internal class InsetBoxShadowDrawable(
private val context: Context,
private val background: CSSBackgroundDrawable,
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,
) : Drawable() {
private val renderNode =
RenderNode(TAG).apply {
clipToBounds = false
setRenderEffect(FilterHelper.createBlurEffect(blurRadius * BLUR_RADIUS_SIGMA_SCALE))
public var borderRadius = borderRadius
set(value) {
if (value != field) {
field = value
invalidateSelf()
}
}
private val clearRegionDrawable = CSSBackgroundDrawable(context)
public var borderInsets = borderInsets
set(value) {
if (value != field) {
field = value
invalidateSelf()
}
}
private val shadowPaint = Paint().apply { color = shadowColor }
private val shadowPaint =
Paint().apply {
color = shadowColor
if (blurRadius > 0) {
maskFilter =
BlurMaskFilter(
FilterHelper.sigmaToRadius(blurRadius * BLUR_RADIUS_SIGMA_SCALE),
BlurMaskFilter.Blur.NORMAL)
}
}
override fun setAlpha(alpha: Int) {
renderNode.alpha = alpha / 255f
shadowPaint.alpha = (((alpha / 255f) * (Color.alpha(shadowColor) / 255f)) * 255f).roundToInt()
invalidateSelf()
}
override fun setColorFilter(colorFilter: ColorFilter?): Unit = Unit
override fun setColorFilter(colorFilter: ColorFilter?) {
shadowPaint.colorFilter = colorFilter
invalidateSelf()
}
override fun getOpacity(): Int = (renderNode.alpha * 255).roundToInt()
override fun getOpacity(): Int =
((shadowPaint.alpha / 255f) / (Color.alpha(shadowColor) / 255f) * 255f).roundToInt()
override fun draw(canvas: Canvas) {
if (!canvas.isHardwareAccelerated) {
FLog.w(TAG, "InsetBoxShadowDrawable requires a hardware accelerated canvas")
return
}
// We need the actual size the blur will increase the shadow by so we can
// properly pad. This is not simply the input as Android has it's own
// distinct blur algorithm
val adjustedBlurRadius =
FilterHelper.sigmaToRadius(blurRadius * BLUR_RADIUS_SIGMA_SCALE).roundToInt()
val padding = 2 * adjustedBlurRadius
val computedBorderRadii = computeBorderRadii()
val computedBorderInsets = computeBorderInsets()
val spreadExtent = PixelUtil.toPixelFromDIP(spread).roundToInt().coerceAtLeast(0)
val clearRegionBounds = Rect()
background.getPaddingBoxRect().round(clearRegionBounds)
clearRegionBounds.inset(spreadExtent, spreadExtent)
clearRegionBounds.offset(
PixelUtil.toPixelFromDIP(offsetX).roundToInt() + padding / 2,
PixelUtil.toPixelFromDIP(offsetY).roundToInt() + padding / 2,
)
val clearRegionBorderRadii = getClearRegionBorderRadii(spreadExtent, background)
val paddingBoxRect =
RectF(
bounds.left + (computedBorderInsets?.left ?: 0f),
bounds.top + (computedBorderInsets?.top ?: 0f),
bounds.right - (computedBorderInsets?.right ?: 0f),
bounds.bottom - (computedBorderInsets?.bottom ?: 0f))
val paddingBoxRadii =
computedBorderRadii?.let {
floatArrayOf(
innerRadius(it.topLeft.horizontal, computedBorderInsets?.left),
innerRadius(it.topLeft.vertical, computedBorderInsets?.top),
innerRadius(it.topRight.horizontal, computedBorderInsets?.right),
innerRadius(it.topRight.vertical, computedBorderInsets?.top),
innerRadius(it.bottomRight.horizontal, computedBorderInsets?.right),
innerRadius(it.bottomRight.vertical, computedBorderInsets?.bottom),
innerRadius(it.bottomLeft.horizontal, computedBorderInsets?.left),
innerRadius(it.bottomLeft.vertical, computedBorderInsets?.bottom))
}
if (!renderNode.hasDisplayList() ||
shadowPaint.colorFilter != colorFilter ||
clearRegionDrawable.layoutDirection != layoutDirection ||
clearRegionDrawable.borderRadius != clearRegionBorderRadii ||
clearRegionDrawable.bounds != clearRegionBounds) {
val x = PixelUtil.toPixelFromDIP(offsetX)
val y = PixelUtil.toPixelFromDIP(offsetY)
val spreadExtent = PixelUtil.toPixelFromDIP(spread)
val innerRect =
RectF(paddingBoxRect).apply {
inset(spreadExtent, spreadExtent)
offset(x, y)
}
shadowPaint.colorFilter = colorFilter
clearRegionDrawable.bounds = clearRegionBounds
clearRegionDrawable.layoutDirection = layoutDirection
clearRegionDrawable.borderRadius = clearRegionBorderRadii
with(renderNode) {
// We pad by the blur radius so that the edges of the blur look good and
// the blur artifacts can bleed into the view if needed
setPosition(Rect(bounds).apply { inset(-padding, -padding) })
beginRecording().let { renderNodeCanvas ->
val borderBoxPath = clearRegionDrawable.getBorderBoxPath()
if (borderBoxPath != null) {
renderNodeCanvas.clipOutPath(borderBoxPath)
} else {
renderNodeCanvas.clipOutRect(clearRegionDrawable.borderBoxRect)
// Graciously stolen from Blink
// https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/paint/box_painter_base.cc;l=338;drc=0a301506035e13015ea5c8dd39164d0d5954fa60
val blurExtent = FilterHelper.sigmaToRadius(blurRadius)
val outerRect =
RectF(innerRect).apply {
inset(-blurExtent, -blurExtent)
if (spreadExtent < 0) {
inset(spreadExtent, spreadExtent)
}
renderNodeCanvas.drawPaint(shadowPaint)
endRecording()
union(RectF(this).apply { offset(-x, -y) })
}
canvas.save().let { saveCount ->
if (paddingBoxRadii != null) {
canvas.clipPath(
Path().apply { addRoundRect(paddingBoxRect, paddingBoxRadii, Path.Direction.CW) })
val innerRadii =
paddingBoxRadii.map { adjustRadiusForSpread(it, -spreadExtent) }.toFloatArray()
canvas.drawDoubleRoundRect(outerRect, ZERO_RADII, innerRect, innerRadii, shadowPaint)
} else {
canvas.clipRect(paddingBoxRect)
canvas.drawDoubleRoundRect(outerRect, ZERO_RADII, innerRect, ZERO_RADII, shadowPaint)
}
// We actually draw the render node into our canvas and clip out the
// padding
with(canvas) {
save()
val paddingBoxPath = background.getPaddingBoxPath()
if (paddingBoxPath != null) {
canvas.clipPath(paddingBoxPath)
} else {
canvas.clipRect(background.getPaddingBoxRect())
}
// This positions the render node properly since we padded it
canvas.translate(padding / 2f, padding / 2f)
drawRenderNode(renderNode)
restore()
}
canvas.restoreToCount(saveCount)
}
}
// TODO: Remove usage of unsafe `CSSBackgroundDrawable.getComputedBorderRadius`
@Suppress("DEPRECATION")
private fun getClearRegionBorderRadii(
spread: Int,
background: CSSBackgroundDrawable,
): BorderRadiusStyle {
// Accessing this is super duper unsafe and only works because the CSSBackgroundDrawable renders
// first
val computedBorderRadii = background.computedBorderRadius
val borderWidth = background.getDirectionAwareBorderInsets()
private fun computeBorderRadii(): ComputedBorderRadius? {
val resolvedBorderRadii =
borderRadius?.resolve(
layoutDirection,
context,
PixelUtil.toDIPFromPixel(bounds.width().toFloat()),
PixelUtil.toDIPFromPixel(bounds.height().toFloat()))
val topLeftRadius = computedBorderRadii.topLeft.toPixelFromDIP()
val topRightRadius = computedBorderRadii.topRight.toPixelFromDIP()
val bottomLeftRadius = computedBorderRadii.bottomLeft.toPixelFromDIP()
val bottomRightRadius = computedBorderRadii.bottomRight.toPixelFromDIP()
val innerTopLeftRadius =
background.getInnerBorderRadius(topLeftRadius.horizontal, borderWidth.left)
val innerTopRightRadius =
background.getInnerBorderRadius(topRightRadius.horizontal, borderWidth.right)
val innerBottomRightRadius =
background.getInnerBorderRadius(bottomRightRadius.horizontal, borderWidth.right)
val innerBottomLeftRadius =
background.getInnerBorderRadius(bottomLeftRadius.horizontal, borderWidth.left)
val spreadWithDirection = -spread.toFloat()
return BorderRadiusStyle(
topLeft =
LengthPercentage(
adjustRadiusForSpread(innerTopLeftRadius, spreadWithDirection),
LengthPercentageType.POINT),
topRight =
LengthPercentage(
adjustRadiusForSpread(innerTopRightRadius, spreadWithDirection),
LengthPercentageType.POINT),
bottomLeft =
LengthPercentage(
adjustRadiusForSpread(innerBottomLeftRadius, spreadWithDirection),
LengthPercentageType.POINT),
bottomRight =
LengthPercentage(
adjustRadiusForSpread(innerBottomRightRadius, spreadWithDirection),
LengthPercentageType.POINT),
)
return if (resolvedBorderRadii?.hasRoundedBorders() == true) {
ComputedBorderRadius(
topLeft =
CornerRadii(
PixelUtil.toPixelFromDIP(resolvedBorderRadii.topLeft.horizontal),
PixelUtil.toPixelFromDIP(resolvedBorderRadii.topLeft.vertical)),
topRight =
CornerRadii(
PixelUtil.toPixelFromDIP(resolvedBorderRadii.topRight.horizontal),
PixelUtil.toPixelFromDIP(resolvedBorderRadii.topRight.vertical)),
bottomLeft =
CornerRadii(
PixelUtil.toPixelFromDIP(resolvedBorderRadii.bottomLeft.horizontal),
PixelUtil.toPixelFromDIP(resolvedBorderRadii.bottomLeft.vertical)),
bottomRight =
CornerRadii(
PixelUtil.toPixelFromDIP(resolvedBorderRadii.bottomRight.horizontal),
PixelUtil.toPixelFromDIP(resolvedBorderRadii.bottomRight.vertical)),
)
} else {
null
}
}
private fun computeBorderInsets(): RectF? =
borderInsets?.resolve(layoutDirection, context)?.let {
RectF(
PixelUtil.toPixelFromDIP(it.left),
PixelUtil.toPixelFromDIP(it.top),
PixelUtil.toPixelFromDIP(it.right),
PixelUtil.toPixelFromDIP(it.bottom))
}
private fun innerRadius(radius: Float, borderInset: Float?): Float =
(radius - (borderInset ?: 0f)).coerceAtLeast(0f)
}
@@ -24,13 +24,15 @@ import com.facebook.react.uimanager.style.ComputedBorderRadius
import com.facebook.react.uimanager.style.CornerRadii
import kotlin.math.roundToInt
internal const val MIN_OUTSET_BOX_SHADOW_SDK_VERSION = 28
// "the resulting shadow must approximate {...} a Gaussian blur with a standard deviation equal
// to half the blur radius"
// https://www.w3.org/TR/css-backgrounds-3/#shadow-blur
private const val BLUR_RADIUS_SIGMA_SCALE = 0.5f
/** Draws an outer box-shadow https://www.w3.org/TR/css-backgrounds-3/#shadow-shape */
@RequiresApi(28)
@RequiresApi(MIN_OUTSET_BOX_SHADOW_SDK_VERSION)
internal class OutsetBoxShadowDrawable(
private val context: Context,
borderRadius: BorderRadiusStyle? = null,
@@ -97,7 +99,7 @@ internal class OutsetBoxShadowDrawable(
)
}
val spreadExtent = PixelUtil.toPixelFromDIP(spread).coerceAtLeast(0f)
val spreadExtent = PixelUtil.toPixelFromDIP(spread)
val shadowRect =
RectF(bounds).apply {
inset(-spreadExtent, -spreadExtent)
@@ -0,0 +1,105 @@
/*
* 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.uimanager.style
import android.content.Context
import android.graphics.RectF
import android.util.LayoutDirection
import com.facebook.react.modules.i18nmanager.I18nUtil
/** Represents the insets from border pox to padding box (i.e. border widths) */
internal class BorderInsets {
private val edgeInsets = arrayOfNulls<Float?>(LogicalEdge.values().size)
public fun setBorderWidth(edge: LogicalEdge, width: Float?) {
edgeInsets[edge.ordinal] = width
}
public fun resolve(
layoutDirection: Int,
context: Context,
): RectF {
return when (layoutDirection) {
LayoutDirection.LTR ->
RectF(
edgeInsets[LogicalEdge.START.ordinal]
?: edgeInsets[LogicalEdge.LEFT.ordinal]
?: edgeInsets[LogicalEdge.HORIZONTAL.ordinal]
?: edgeInsets[LogicalEdge.ALL.ordinal]
?: 0f,
edgeInsets[LogicalEdge.BLOCK_START.ordinal]
?: edgeInsets[LogicalEdge.TOP.ordinal]
?: edgeInsets[LogicalEdge.BLOCK.ordinal]
?: edgeInsets[LogicalEdge.VERTICAL.ordinal]
?: edgeInsets[LogicalEdge.ALL.ordinal]
?: 0f,
edgeInsets[LogicalEdge.END.ordinal]
?: edgeInsets[LogicalEdge.RIGHT.ordinal]
?: edgeInsets[LogicalEdge.HORIZONTAL.ordinal]
?: edgeInsets[LogicalEdge.ALL.ordinal]
?: 0f,
edgeInsets[LogicalEdge.BLOCK_END.ordinal]
?: edgeInsets[LogicalEdge.BOTTOM.ordinal]
?: edgeInsets[LogicalEdge.BLOCK.ordinal]
?: edgeInsets[LogicalEdge.VERTICAL.ordinal]
?: edgeInsets[LogicalEdge.ALL.ordinal]
?: 0f)
LayoutDirection.RTL ->
if (I18nUtil.instance.doLeftAndRightSwapInRTL(context)) {
RectF(
edgeInsets[LogicalEdge.END.ordinal]
?: edgeInsets[LogicalEdge.RIGHT.ordinal]
?: edgeInsets[LogicalEdge.HORIZONTAL.ordinal]
?: edgeInsets[LogicalEdge.ALL.ordinal]
?: 0f,
edgeInsets[LogicalEdge.BLOCK_START.ordinal]
?: edgeInsets[LogicalEdge.TOP.ordinal]
?: edgeInsets[LogicalEdge.BLOCK.ordinal]
?: edgeInsets[LogicalEdge.VERTICAL.ordinal]
?: edgeInsets[LogicalEdge.ALL.ordinal]
?: 0f,
edgeInsets[LogicalEdge.START.ordinal]
?: edgeInsets[LogicalEdge.LEFT.ordinal]
?: edgeInsets[LogicalEdge.HORIZONTAL.ordinal]
?: edgeInsets[LogicalEdge.ALL.ordinal]
?: 0f,
edgeInsets[LogicalEdge.BLOCK_END.ordinal]
?: edgeInsets[LogicalEdge.BOTTOM.ordinal]
?: edgeInsets[LogicalEdge.BLOCK.ordinal]
?: edgeInsets[LogicalEdge.VERTICAL.ordinal]
?: edgeInsets[LogicalEdge.ALL.ordinal]
?: 0f)
} else {
RectF(
edgeInsets[LogicalEdge.END.ordinal]
?: edgeInsets[LogicalEdge.LEFT.ordinal]
?: edgeInsets[LogicalEdge.HORIZONTAL.ordinal]
?: edgeInsets[LogicalEdge.ALL.ordinal]
?: 0f,
edgeInsets[LogicalEdge.BLOCK_START.ordinal]
?: edgeInsets[LogicalEdge.TOP.ordinal]
?: edgeInsets[LogicalEdge.BLOCK.ordinal]
?: edgeInsets[LogicalEdge.VERTICAL.ordinal]
?: edgeInsets[LogicalEdge.ALL.ordinal]
?: 0f,
edgeInsets[LogicalEdge.START.ordinal]
?: edgeInsets[LogicalEdge.RIGHT.ordinal]
?: edgeInsets[LogicalEdge.HORIZONTAL.ordinal]
?: edgeInsets[LogicalEdge.ALL.ordinal]
?: 0f,
edgeInsets[LogicalEdge.BLOCK_END.ordinal]
?: edgeInsets[LogicalEdge.BOTTOM.ordinal]
?: edgeInsets[LogicalEdge.BLOCK.ordinal]
?: edgeInsets[LogicalEdge.VERTICAL.ordinal]
?: edgeInsets[LogicalEdge.ALL.ordinal]
?: 0f)
}
else -> throw IllegalArgumentException("Expected resolved layout direction")
}
}
}