1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 @file:Suppress("NOTHING_TO_INLINE", "KotlinRedundantDiagnosticSuppress")
18 
19 package androidx.compose.ui.unit
20 
21 import androidx.compose.runtime.Immutable
22 import androidx.compose.runtime.Stable
23 import androidx.compose.ui.geometry.Size
24 import androidx.compose.ui.util.fastRoundToInt
25 import androidx.compose.ui.util.packInts
26 import androidx.compose.ui.util.unpackInt1
27 import androidx.compose.ui.util.unpackInt2
28 
29 /** Constructs an [IntSize] from width and height [Int] values. */
IntSizenull30 @Stable inline fun IntSize(width: Int, height: Int): IntSize = IntSize(packInts(width, height))
31 
32 /**
33  * A two-dimensional size class used for measuring in [Int] pixels.
34  *
35  * To create an [IntSize], call the top-level function that accepts a width/height pair of
36  * dimensions:
37  * ```
38  * val size = IntSize(width, height)
39  * ```
40  *
41  * The primary constructor of [IntSize] is intended to be used with the [packedValue] property to
42  * allow storing sizes in arrays or collections of primitives without boxing.
43  *
44  * @param packedValue [Long] value encoding the [width] and [height] components of the [IntSize].
45  *   Encoded values can be obtained by using the [packedValue] property of existing [IntSize]
46  *   instances.
47  */
48 @Immutable
49 @kotlin.jvm.JvmInline
50 value class IntSize @PublishedApi internal constructor(val packedValue: Long) {
51     /** The horizontal aspect of the size in [Int] pixels. */
52     @Stable
53     inline val width: Int
54         get() = unpackInt1(packedValue)
55 
56     /** The vertical aspect of the size in [Int] pixels. */
57     @Stable
58     inline val height: Int
59         get() = unpackInt2(packedValue)
60 
61     @Stable inline operator fun component1(): Int = width
62 
63     @Stable inline operator fun component2(): Int = height
64 
65     /** Returns an IntSize scaled by multiplying [width] and [height] by [other] */
66     @Stable
67     operator fun times(other: Int): IntSize =
68         IntSize(packInts(unpackInt1(packedValue) * other, unpackInt2(packedValue) * other))
69 
70     /** Returns an IntSize scaled by dividing [width] and [height] by [other] */
71     @Stable
72     operator fun div(other: Int): IntSize =
73         IntSize(packInts(unpackInt1(packedValue) / other, unpackInt2(packedValue) / other))
74 
75     @Stable override fun toString(): String = "$width x $height"
76 
77     companion object {
78         /** IntSize with a zero (0) width and height. */
79         val Zero = IntSize(0L)
80     }
81 }
82 
83 /** Returns an [IntSize] with [size]'s [IntSize.width] and [IntSize.height] multiplied by [this]. */
timesnull84 @Stable inline operator fun Int.times(size: IntSize) = size * this
85 
86 /** Convert a [IntSize] to a [IntRect]. */
87 @Stable
88 fun IntSize.toIntRect(): IntRect {
89     return IntRect(IntOffset.Zero, this)
90 }
91 
92 /**
93  * Returns the [IntOffset] of the center of the rect from the point of [0, 0] with this [IntSize].
94  */
95 @Stable
96 val IntSize.center: IntOffset
97     get() =
98         IntOffset(
99             // Divide X by 2 by moving it to the low bits, then place it back in the high bits
100             (packedValue shr 33 shl 32) or
101                 // Move Y to the high bits so we can preserve the sign when dividing by 2, then
102                 // move Y back to the low bits and mask out the top 32 bits for X
103                 ((packedValue shl 32 shr 33) and 0xffffffffL)
104         )
105 
106 // temporary while PxSize is transitioned to Size
toSizenull107 @Stable fun IntSize.toSize() = Size(width.toFloat(), height.toFloat())
108 
109 /**
110  * Convert a [Size] to an [IntSize]. This rounds the width and height values down to the nearest
111  * integer.
112  */
113 @Stable fun Size.toIntSize(): IntSize = IntSize(packInts(this.width.toInt(), this.height.toInt()))
114 
115 /**
116  * Convert a [Size] to an [IntSize]. This rounds [Size.width] and [Size.height] to the nearest
117  * integer.
118  */
119 @Stable
120 fun Size.roundToIntSize(): IntSize =
121     IntSize(packInts(this.width.fastRoundToInt(), this.height.fastRoundToInt()))
122