1/* 2 * Copyright 2019, 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/* transform type flags */ 18const TRANSLATE_VAL = 0x0001; 19const ROTATE_VAL = 0x0002; 20const SCALE_VAL = 0x0004; 21 22/* orientation flags */ 23const FLIP_H_VAL = 0x0100; // (1 << 0 << 8) 24const FLIP_V_VAL = 0x0200; // (1 << 1 << 8) 25const ROT_90_VAL = 0x0400; // (1 << 2 << 8) 26const ROT_INVALID_VAL = 0x8000; // (0x80 << 8) 27 28function is_proto_2(transform) { 29 /* 30 * Checks if the loaded file was a stored with ProtoBuf2 or Protobuf3 31 * 32 * Proto2 files don't have a Type for the transform object but all other 33 * fields of the transform are set. 34 * 35 * Proto3 has a type field for the transform but doesn't store default 36 * values (0 for transform type), also, the framework/native implementation 37 * doesn't write a transform in case it is an identity matrix. 38 */ 39 var propertyNames = Object.getOwnPropertyNames(transform); 40 return (!propertyNames.includes("type") && propertyNames.includes("dsdx")); 41} 42 43function is_simple_transform(transform) { 44 transform = transform || {}; 45 if (is_proto_2(transform)) { 46 return false; 47 } 48 return is_type_flag_clear(transform, ROT_INVALID_VAL|SCALE_VAL); 49} 50 51/** 52 * Converts a transform type into readable format. 53 * Adapted from the dump function from framework/native 54 * 55 * @param {*} transform Transform object ot be converter 56 */ 57function format_transform_type(transform) { 58 if (is_proto_2(transform)) { 59 return ""; 60 } 61 62 if (is_type_flag_clear(transform, SCALE_VAL | ROTATE_VAL | TRANSLATE_VAL)) { 63 return "IDENTITY"; 64 } 65 66 var type_flags = []; 67 if (is_type_flag_set(transform, SCALE_VAL)) { 68 type_flags.push("SCALE"); 69 } 70 if (is_type_flag_set(transform, TRANSLATE_VAL)) { 71 type_flags.push("TRANSLATE"); 72 } 73 74 if (is_type_flag_set(transform, ROT_INVALID_VAL)) { 75 type_flags.push("ROT_INVALID"); 76 } else if (is_type_flag_set(transform, ROT_90_VAL|FLIP_V_VAL|FLIP_H_VAL)) { 77 type_flags.push("ROT_270"); 78 } else if (is_type_flag_set(transform, FLIP_V_VAL|FLIP_H_VAL)) { 79 type_flags.push("ROT_180"); 80 } else { 81 if (is_type_flag_set(transform, ROT_90_VAL)) { 82 type_flags.push("ROT_90"); 83 } 84 if (is_type_flag_set(transform, FLIP_V_VAL)) { 85 type_flags.push("FLIP_V"); 86 } 87 if (is_type_flag_set(transform, FLIP_H_VAL)) { 88 type_flags.push("FLIP_H"); 89 } 90 } 91 92 if (type_flags.length == 0) { 93 throw "Unknown transform type " + transform ; 94 } 95 96 return type_flags.join(', '); 97} 98 99 100/** 101 * Ensures all values of the transform object are set. 102 */ 103function fill_transform_data(transform) { 104 function fill_simple_transform(transform) { 105 // ROT_270 = ROT_90|FLIP_H|FLIP_V; 106 if (is_type_flag_set(transform, ROT_90_VAL|FLIP_V_VAL|FLIP_H_VAL)) { 107 transform.dsdx = 0.0; 108 transform.dtdx = -1.0; 109 transform.dsdy = 1.0; 110 transform.dtdy = 0.0; 111 return; 112 } 113 114 // ROT_180 = FLIP_H|FLIP_V; 115 if (is_type_flag_set(transform, FLIP_V_VAL|FLIP_H_VAL)) { 116 transform.dsdx = -1.0; 117 transform.dtdx = 0.0; 118 transform.dsdy = 0.0; 119 transform.dtdy = -1.0; 120 return; 121 } 122 123 // ROT_90 124 if (is_type_flag_set(transform, ROT_90_VAL)) { 125 transform.dsdx = 0.0; 126 transform.dtdx = 1.0; 127 transform.dsdy = -1.0; 128 transform.dtdy = 0.0; 129 return; 130 } 131 132 // IDENTITY 133 if (is_type_flag_clear(transform, SCALE_VAL | ROTATE_VAL)) { 134 transform.dsdx = 1.0; 135 transform.dtdx = 0.0; 136 transform.dsdy = 0.0; 137 transform.dtdy = 1.0; 138 transform.type = 0; 139 return; 140 } 141 142 throw "Unknown transform type " + transform; 143 } 144 145 if (!transform) { 146 return; 147 } 148 149 if (is_proto_2(transform)) { 150 return; 151 } 152 153 if (is_simple_transform(transform)){ 154 fill_simple_transform(transform); 155 } 156 157 transform.dsdx = transform.dsdx || 0.0; 158 transform.dtdx = transform.dtdx || 0.0; 159 transform.dsdy = transform.dsdy || 0.0; 160 transform.dtdy = transform.dtdy || 0.0; 161} 162 163function is_type_flag_set(transform, bits) { 164 transform = transform || {}; 165 var type = transform.type || 0; 166 return (type & bits) === bits; 167} 168 169function is_type_flag_clear(transform, bits) { 170 transform = transform || {}; 171 var type = transform.type || 0; 172 return (type & bits) === 0; 173} 174 175function multiply_vec2(matrix, x, y) { 176 if (!matrix) return {x, y}; 177 // |dsdx dsdy tx| | x | 178 // |dtdx dtdy ty| x | y | 179 // |0 0 1 | | 1 | 180 return { 181 x: matrix.dsdx * x + matrix.dsdy * y + matrix.tx, 182 y: matrix.dtdx * x + matrix.dtdy * y + matrix.ty 183 }; 184} 185 186function multiply_rect(matrix, rect) { 187 // |dsdx dsdy tx| | left, top | 188 // matrix = |dtdx dtdy ty| rect = | | 189 // |0 0 1 | | right, bottom | 190 191 var left_top = multiply_vec2(matrix, rect.left, rect.top); 192 var right_top = multiply_vec2(matrix, rect.right, rect.top); 193 var left_bottom = multiply_vec2(matrix, rect.left, rect.bottom); 194 var right_bottom = multiply_vec2(matrix, rect.right, rect.bottom); 195 196 var outrect = {}; 197 outrect.left = Math.min(left_top.x, right_top.x, left_bottom.x, right_bottom.x); 198 outrect.top = Math.min(left_top.y, right_top.y, left_bottom.y, right_bottom.y); 199 outrect.right = Math.max(left_top.x, right_top.x, left_bottom.x, right_bottom.x); 200 outrect.bottom = Math.max(left_top.y, right_top.y, left_bottom.y, right_bottom.y); 201 return outrect; 202} 203 204// Returns true if the applying the transform on an an axis aligned rectangle 205// results in another axis aligned rectangle. 206function is_simple_rotation(transform) { 207 return !is_type_flag_set(transform, ROT_INVALID_VAL); 208} 209 210export {format_transform_type, fill_transform_data, is_simple_transform, 211 multiply_rect, is_simple_rotation};