1/* 2 * Copyright (C) 2024, 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 17import {Point} from './point'; 18import {Point3D} from './point3d'; 19import {Rect} from './rect'; 20import {Region} from './region'; 21 22// These values correspond to the values from the gui::Transform class in the platform, defined in: 23// frameworks/native/libs/ui/include/ui/Transform.h 24// The values are listed in row-major order: 25// [ dsdx, dtdx, tx ] 26// [ dtdy, dsdy, ty ] 27// [ 0, 0, 1 ] 28export class TransformMatrix { 29 constructor( 30 readonly dsdx: number, 31 readonly dtdx: number, 32 readonly tx: number, 33 readonly dtdy: number, 34 readonly dsdy: number, 35 readonly ty: number, 36 ) {} 37 38 static from( 39 m: { 40 dsdx?: number; 41 dtdx?: number; 42 tx?: number; 43 dtdy?: number; 44 dsdy?: number; 45 ty?: number; 46 } = {}, 47 fallback: TransformMatrix = IDENTITY_MATRIX, 48 ): TransformMatrix { 49 return new TransformMatrix( 50 m.dsdx ?? fallback.dsdx, 51 m.dtdx ?? fallback.dtdx, 52 m.tx ?? fallback.tx, 53 m.dtdy ?? fallback.dtdy, 54 m.dsdy ?? fallback.dsdy, 55 m.ty ?? fallback.ty, 56 ); 57 } 58 59 isValid(): boolean { 60 return this.dsdx * this.dsdy !== this.dtdx * this.dtdy; 61 } 62 63 transformPoint(point: Point): Point { 64 return { 65 x: this.dsdx * point.x + this.dtdx * point.y + this.tx, 66 y: this.dtdy * point.x + this.dsdy * point.y + this.ty, 67 }; 68 } 69 70 transformPoint3D(point: Point3D): Point3D { 71 const p = this.transformPoint(point); 72 return new Point3D(p.x, p.y, point.z); 73 } 74 75 transformRect(r: Rect): Rect { 76 const ltPrime = this.transformPoint({x: r.x, y: r.y}); 77 const rbPrime = this.transformPoint({x: r.x + r.w, y: r.y + r.h}); 78 const x = Math.min(ltPrime.x, rbPrime.x); 79 const y = Math.min(ltPrime.y, rbPrime.y); 80 return new Rect( 81 x, 82 y, 83 Math.max(ltPrime.x, rbPrime.x) - x, 84 Math.max(ltPrime.y, rbPrime.y) - y, 85 ); 86 } 87 88 transformRegion(region: Region): Region { 89 return new Region(region.rects.map((rect) => this.transformRect(rect))); 90 } 91 92 inverse(): TransformMatrix { 93 const ident = 1.0 / this.det(); 94 const result = { 95 dsdx: this.dsdy * ident, 96 dtdx: -this.dtdx * ident, 97 tx: 0, 98 dsdy: this.dsdx * ident, 99 dtdy: -this.dtdy * ident, 100 ty: 0, 101 }; 102 const t = TransformMatrix.from(result).transformPoint({ 103 x: -this.tx, 104 y: -this.ty, 105 }); 106 result.tx = t.x; 107 result.ty = t.y; 108 return TransformMatrix.from(result); 109 } 110 111 addTy(ty: number): TransformMatrix { 112 return new TransformMatrix( 113 this.dsdx, 114 this.dtdx, 115 this.tx, 116 this.dtdy, 117 this.dsdy, 118 this.ty + ty, 119 ); 120 } 121 122 isEqual(other: TransformMatrix): boolean { 123 return ( 124 this.dsdx === other.dsdx && 125 this.dtdx === other.dtdx && 126 this.tx === other.tx && 127 this.dtdy === other.dtdy && 128 this.dsdy === other.dsdy && 129 this.ty === other.ty 130 ); 131 } 132 133 private det(): number { 134 return this.dsdx * this.dsdy - this.dtdx * this.dtdy; 135 } 136} 137 138export const IDENTITY_MATRIX = new TransformMatrix(1, 0, 0, 0, 1, 0); 139