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