Skip to content

Commit

Permalink
Add mul/div by scaler to Dimen
Browse files Browse the repository at this point in the history
Summary:
Support multiplication/division of `Dimen` by non-dimensional scaler:
```Kotlin
1.px * 42.0  // 42.px
val padding = component.gap / 2.0
```

Reviewed By: zielinskimz

Differential Revision: D59061617

fbshipit-source-id: 6c551cfce034cba58a17e8c9612965943b8d3624
  • Loading branch information
aklm11 authored and facebook-github-bot committed Jun 28, 2024
1 parent ac6db37 commit 99b7098
Show file tree
Hide file tree
Showing 2 changed files with 118 additions and 0 deletions.
78 changes: 78 additions & 0 deletions litho-rendercore/src/main/java/com/facebook/rendercore/Dimen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,86 @@ value class Dimen @PublishedApi internal constructor(val encodedValue: Long) {
else -> "NaN"
}
}

operator fun times(other: Double): Dimen {
return Dimen(
when {
// DP case
encodedValue and NAN_MASK != NAN_MASK ->
doubleToRawLongBits(longBitsToDouble(encodedValue) * other)
// PX case
encodedValue and PX_FLAG == PX_FLAG ->
encodePxInt(((encodedValue and PAYLOAD_MASK).toInt() * other).toInt())
// SP case
encodedValue and SP_FLAG == SP_FLAG ->
encodeSpFloat(
(intBitsToFloat((encodedValue and PAYLOAD_MASK).toInt()) * other).toFloat())
else -> doubleToRawLongBits(Double.NaN)
})
}

operator fun times(other: Float): Dimen {
return Dimen(
when {
// DP case
encodedValue and NAN_MASK != NAN_MASK ->
doubleToRawLongBits(longBitsToDouble(encodedValue) * other)
// PX case
encodedValue and PX_FLAG == PX_FLAG ->
encodePxInt(((encodedValue and PAYLOAD_MASK).toInt() * other).toInt())
// SP case
encodedValue and SP_FLAG == SP_FLAG ->
encodeSpFloat(
(intBitsToFloat((encodedValue and PAYLOAD_MASK).toInt()) * other).toFloat())
else -> doubleToRawLongBits(Double.NaN)
})
}

operator fun times(other: Int): Dimen {
return Dimen(
when {
// DP case
encodedValue and NAN_MASK != NAN_MASK ->
doubleToRawLongBits(longBitsToDouble(encodedValue) * other)
// PX case
encodedValue and PX_FLAG == PX_FLAG ->
encodePxInt((encodedValue and PAYLOAD_MASK).toInt() * other)
// SP case
encodedValue and SP_FLAG == SP_FLAG ->
encodeSpFloat(intBitsToFloat(encodedValue.and(PAYLOAD_MASK).toInt()) * other)
else -> doubleToRawLongBits(Double.NaN)
})
}

operator fun div(other: Double): Dimen = this * (1.0 / other)

operator fun div(other: Float): Dimen = this * (1f / other)

operator fun div(other: Int): Dimen {
return Dimen(
when {
// DP case
encodedValue and NAN_MASK != NAN_MASK ->
doubleToRawLongBits(longBitsToDouble(encodedValue) / other)
// PX case
encodedValue and PX_FLAG == PX_FLAG ->
encodePxInt((encodedValue and PAYLOAD_MASK).toInt() / other)
// SP case
encodedValue and SP_FLAG == SP_FLAG ->
encodeSpFloat(intBitsToFloat(encodedValue.and(PAYLOAD_MASK).toInt()) / other)
else -> doubleToRawLongBits(Double.NaN)
})
}

operator fun unaryMinus(): Dimen = this * -1
}

operator fun Double.times(other: Dimen): Dimen = other * this

operator fun Float.times(other: Dimen): Dimen = other * this

operator fun Int.times(other: Dimen): Dimen = other * this

/** Creates a Dimen with a constant dp (density-independent pixels) value. */
inline val Int.dp: Dimen
get() = Dimen(doubleToRawLongBits(this.toDouble()))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,46 @@ class DimenTest {
Dimen(Double.NaN.toRawBits()).toPixels(resourceResolver)
}

@Test
fun `dimen mul div`() {
assertThat(10.sp * 5.0).isEqualTo(50.sp)
assertThat(10.dp * 5.0).isEqualTo(50.dp)
assertThat(10.px * 5.0).isEqualTo(50.px)
assertThat(5.0 * 10.sp).isEqualTo(50.sp)
assertThat(5.0 * 10.dp).isEqualTo(50.dp)
assertThat(5.0 * 10.px).isEqualTo(50.px)

assertThat(10.sp / 2.0).isEqualTo(5.sp)
assertThat(10.dp / 2.0).isEqualTo(5.dp)
assertThat(10.px / 2.0).isEqualTo(5.px)

assertThat(10.sp * 5f).isEqualTo(50.sp)
assertThat(10.dp * 5f).isEqualTo(50.dp)
assertThat(10.px * 5f).isEqualTo(50.px)
assertThat(5f * 10.sp).isEqualTo(50.sp)
assertThat(5f * 10.dp).isEqualTo(50.dp)
assertThat(5f * 10.px).isEqualTo(50.px)

assertThat(10.sp / 2f).isEqualTo(5.sp)
assertThat(10.dp / 2f).isEqualTo(5.dp)
assertThat(10.px / 2f).isEqualTo(5.px)

assertThat(10.sp * 5).isEqualTo(50.sp)
assertThat(10.dp * 5).isEqualTo(50.dp)
assertThat(10.px * 5).isEqualTo(50.px)
assertThat(5 * 10.sp).isEqualTo(50.sp)
assertThat(5 * 10.dp).isEqualTo(50.dp)
assertThat(5 * 10.px).isEqualTo(50.px)

assertThat(10.sp / 2).isEqualTo(5.sp)
assertThat(10.dp / 2).isEqualTo(5.dp)
assertThat(10.px / 2).isEqualTo(5.px)

assertThat(-(10.sp)).isEqualTo((-10).sp)
assertThat(-(10.dp)).isEqualTo((-10).dp)
assertThat(-(10.px)).isEqualTo((-10).px)
}

private class MockResourceResolver(val density: Float, val scaledDensity: Float) :
ResourceResolver(
ApplicationProvider.getApplicationContext<Context>(),
Expand Down

0 comments on commit 99b7098

Please sign in to comment.