1 /* 2 * Copyright (C) 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 package com.android.server.wm.traces.common.layers 18 19 import com.android.server.wm.traces.common.Matrix33 20 import com.android.server.wm.traces.common.RectF 21 import com.android.server.wm.traces.common.service.PlatformConsts 22 23 /** 24 * Wrapper for TransformProto (frameworks/native/services/surfaceflinger/layerproto/common.proto) 25 * 26 * This class is used by flicker and Winscope 27 */ 28 open class Transform(val type: Int?, val matrix: Matrix33) { 29 30 /** 31 * Returns true if the applying the transform on an an axis aligned rectangle 32 * results in another axis aligned rectangle. 33 */ 34 val isSimpleRotation: Boolean = !(type?.isFlagSet(ROT_INVALID_VAL) ?: true) 35 36 /** 37 * The transformation matrix is defined as the product of: 38 * | cos(a) -sin(a) | \/ | X 0 | 39 * | sin(a) cos(a) | /\ | 0 Y | 40 * 41 * where a is a rotation angle, and X and Y are scaling factors. 42 * A transformation matrix is invalid when either X or Y is zero, 43 * as a rotation matrix is valid for any angle. When either X or Y 44 * is 0, then the scaling matrix is not invertible, which makes the 45 * transformation matrix not invertible as well. A 2D matrix with 46 * components | A B | is not invertible if and only if AD - BC = 0. 47 * | C D | 48 * This check is included above. 49 */ 50 val isValid: Boolean 51 get() { 52 // determinant of transform 53 return matrix.dsdx * matrix.dtdy != matrix.dtdx * matrix.dsdy 54 } 55 getRotationnull56 fun getRotation(): Int { 57 if (type == null) { 58 return PlatformConsts.ROTATION_0 59 } 60 61 return when { 62 type.isFlagClear(SCALE_VAL or ROTATE_VAL or TRANSLATE_VAL) -> PlatformConsts.ROTATION_0 63 type.isFlagSet(ROT_90_VAL) -> PlatformConsts.ROTATION_90 64 type.isFlagSet(FLIP_V_VAL or FLIP_H_VAL) -> PlatformConsts.ROTATION_180 65 type.isFlagSet(ROT_90_VAL or FLIP_V_VAL or FLIP_H_VAL) -> PlatformConsts.ROTATION_270 66 else -> PlatformConsts.ROTATION_0 67 } 68 } 69 70 private val typeFlags: Array<String> 71 get() { 72 if (type == null) { 73 return arrayOf("IDENTITY") 74 } 75 76 val result = mutableListOf<String>() 77 78 if (type.isFlagClear(SCALE_VAL or ROTATE_VAL or TRANSLATE_VAL)) { 79 result.add("IDENTITY") 80 } 81 82 if (type.isFlagSet(SCALE_VAL)) { 83 result.add("SCALE") 84 } 85 86 if (type.isFlagSet(TRANSLATE_VAL)) { 87 result.add("TRANSLATE") 88 } 89 90 when { 91 type.isFlagSet(ROT_INVALID_VAL) -> result.add("ROT_INVALID") 92 type.isFlagSet(ROT_90_VAL or FLIP_V_VAL or FLIP_H_VAL) -> result.add("ROT_270") 93 type.isFlagSet(FLIP_V_VAL or FLIP_H_VAL) -> result.add("ROT_180") 94 else -> { 95 if (type.isFlagSet(ROT_90_VAL)) { 96 result.add("ROT_90") 97 } 98 if (type.isFlagSet(FLIP_V_VAL)) { 99 result.add("FLIP_V") 100 } 101 if (type.isFlagSet(FLIP_H_VAL)) { 102 result.add("FLIP_H") 103 } 104 } 105 } 106 107 if (result.isEmpty()) { 108 throw RuntimeException("Unknown transform type $type") 109 } 110 111 return result.toTypedArray() 112 } 113 prettyPrintnull114 fun prettyPrint(): String { 115 val transformType = typeFlags.joinToString("|") 116 117 if (isSimpleTransform(type)) { 118 return transformType 119 } 120 121 return "$transformType ${matrix.prettyPrint()}" 122 } 123 toStringnull124 override fun toString(): String = prettyPrint() 125 126 fun apply(bounds: RectF?): RectF { 127 return multiplyRect(matrix, bounds ?: RectF.EMPTY) 128 } 129 130 private data class Vec2(val x: Float, val y: Float) 131 multiplyRectnull132 private fun multiplyRect(matrix: Matrix33, rect: RectF): RectF { 133 // |dsdx dsdy tx| | left, top | 134 // matrix = |dtdx dtdy ty| rect = | | 135 // |0 0 1 | | right, bottom | 136 137 val leftTop = multiplyVec2(matrix, rect.left, rect.top) 138 val rightTop = multiplyVec2(matrix, rect.right, rect.top) 139 val leftBottom = multiplyVec2(matrix, rect.left, rect.bottom) 140 val rightBottom = multiplyVec2(matrix, rect.right, rect.bottom) 141 142 return RectF( 143 left = arrayOf(leftTop.x, rightTop.x, leftBottom.x, rightBottom.x).minOrNull() ?: 0f, 144 top = arrayOf(leftTop.y, rightTop.y, leftBottom.y, rightBottom.y).minOrNull() ?: 0f, 145 right = arrayOf(leftTop.x, rightTop.x, leftBottom.x, rightBottom.x).minOrNull() ?: 0f, 146 bottom = arrayOf(leftTop.y, rightTop.y, leftBottom.y, rightBottom.y).minOrNull() ?: 0f 147 ) 148 } 149 multiplyVec2null150 private fun multiplyVec2(matrix: Matrix33, x: Float, y: Float): Vec2 { 151 // |dsdx dsdy tx| | x | 152 // |dtdx dtdy ty| x | y | 153 // |0 0 1 | | 1 | 154 return Vec2( 155 matrix.dsdx * x + matrix.dsdy * y + matrix.tx, 156 matrix.dtdx * x + matrix.dtdy * y + matrix.ty 157 ) 158 } 159 160 companion object { 161 val EMPTY: Transform = Transform(type = null, matrix = Matrix33.EMPTY) 162 163 /* transform type flags */ 164 const val TRANSLATE_VAL = 0x0001 165 const val ROTATE_VAL = 0x0002 166 const val SCALE_VAL = 0x0004 167 168 /* orientation flags */ 169 const val FLIP_H_VAL = 0x0100 // (1 << 0 << 8) 170 const val FLIP_V_VAL = 0x0200 // (1 << 1 << 8) 171 const val ROT_90_VAL = 0x0400 // (1 << 2 << 8) 172 const val ROT_INVALID_VAL = 0x8000 // (0x80 << 8) 173 isSimpleTransformnull174 fun isSimpleTransform(type: Int?): Boolean { 175 return type?.isFlagClear(ROT_INVALID_VAL or SCALE_VAL) ?: false 176 } 177 isFlagClearnull178 fun Int.isFlagClear(bits: Int): Boolean { 179 return this and bits == 0 180 } 181 isFlagSetnull182 fun Int.isFlagSet(bits: Int): Boolean { 183 return this and bits == bits 184 } 185 } 186 equalsnull187 override fun equals(other: Any?): Boolean { 188 if (this === other) return true 189 if (other !is Transform) return false 190 191 if (type != other.type) return false 192 if (matrix != other.matrix) return false 193 if (isSimpleRotation != other.isSimpleRotation) return false 194 195 return true 196 } 197 hashCodenull198 override fun hashCode(): Int { 199 var result = type ?: 0 200 result = 31 * result + matrix.hashCode() 201 result = 31 * result + isSimpleRotation.hashCode() 202 return result 203 } 204 }