1 /* 2 * Copyright (C) 2023 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 package android.tools.common.datatypes 18 19 import android.tools.common.withCache 20 import kotlin.js.JsExport 21 import kotlin.js.JsName 22 23 /** 24 * Wrapper for RectProto 25 * 26 * ``` 27 * - frameworks/native/services/surfaceflinger/layerproto/common.proto and 28 * - frameworks/base/core/proto/android/graphics/rect.proto 29 * ``` 30 * 31 * This class is used by flicker and Winscope 32 */ 33 @JsExport 34 open class Rect( 35 @JsName("left") val left: Int = 0, 36 @JsName("top") val top: Int = 0, 37 @JsName("right") val right: Int = 0, 38 @JsName("bottom") val bottom: Int = 0 39 ) : DataType() { 40 @JsName("height") val height: Int = bottom - top 41 @JsName("width") val width: Int = right - left centerXnull42 @JsName("centerX") fun centerX(): Int = (left + right) / 2 43 @JsName("centerY") fun centerY(): Int = (top + bottom) / 2 44 /** Returns true if the rectangle is empty (left >= right or top >= bottom) */ 45 override val isEmpty: Boolean = width <= 0 || height <= 0 46 47 /** Returns a [RectF] version fo this rectangle. */ 48 @JsName("toRectF") 49 fun toRectF(): RectF { 50 return RectF.from(left.toFloat(), top.toFloat(), right.toFloat(), bottom.toFloat()) 51 } 52 doPrintValuenull53 override fun doPrintValue() = "($left, $top) - ($right, $bottom)" 54 55 /** 56 * Returns true iff the specified rectangle r is inside or equal to this rectangle. An empty 57 * rectangle never contains another rectangle. 58 * 59 * @param rect The rectangle being tested for containment. 60 * @return true iff the specified rectangle r is inside or equal to this 61 * 62 * ``` 63 * rectangle 64 * ``` 65 */ 66 operator fun contains(rect: Rect): Boolean { 67 val thisRect = toRectF() 68 val otherRect = rect.toRectF() 69 return thisRect.contains(otherRect) 70 } 71 72 /** 73 * Returns a [Rect] where the dimensions don't exceed those of [crop] 74 * 75 * @param crop The crop that should be applied to this layer 76 */ 77 @JsName("crop") cropnull78 fun crop(crop: Rect): Rect { 79 val newLeft = maxOf(left, crop.left) 80 val newTop = maxOf(top, crop.top) 81 val newRight = minOf(right, crop.right) 82 val newBottom = minOf(bottom, crop.bottom) 83 return from(newLeft, newTop, newRight, newBottom) 84 } 85 86 /** 87 * Returns true if: fLeft <= x < fRight && fTop <= y < fBottom. Returns false if SkIRect is 88 * empty. 89 * 90 * Considers input to describe constructed SkIRect: (x, y, x + 1, y + 1) and returns true if 91 * constructed area is completely enclosed by SkIRect area. 92 * 93 * @param x test SkIPoint x-coordinate @param y test SkIPoint y-coordinate @return true if (x, 94 * y) is inside SkIRect 95 */ 96 @JsName("containsPoint") containsnull97 fun contains(x: Int, y: Int): Boolean { 98 return x in left until right && y in top until bottom 99 } 100 101 /** 102 * If the specified rectangle intersects this rectangle, return true and set this rectangle to 103 * that intersection, otherwise return false and do not change this rectangle. No check is 104 * performed to see if either rectangle is empty. To just test for intersection, use 105 * intersects() 106 * 107 * @param rect The rectangle being intersected with this rectangle. 108 * @return A rectangle with the intersection coordinates 109 */ 110 @JsName("intersection") intersectionnull111 fun intersection(rect: Rect): Rect { 112 val thisRect = toRectF() 113 val otherRect = rect.toRectF() 114 return thisRect.intersection(otherRect).toRect() 115 } 116 117 @JsName("clone") clonenull118 fun clone(): Rect { 119 return from(left, top, right, bottom) 120 } 121 122 companion object { 123 @JsName("EMPTY") 124 val EMPTY: Rect <lambda>null125 get() = withCache { Rect() } 126 127 @JsName("from") <lambda>null128 fun from(left: Int, top: Int, right: Int, bottom: Int): Rect = withCache { 129 Rect(left, top, right, bottom) 130 } 131 withoutCachenull132 internal fun withoutCache(left: Int, top: Int, right: Int, bottom: Int): Rect = 133 Rect(left, top, right, bottom) 134 } 135 } 136