• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
18 const TRANSLATE_VAL   = 0x0001;
19 const ROTATE_VAL      = 0x0002;
20 const SCALE_VAL       = 0x0004;
21 
22 /* orientation flags */
23 const FLIP_H_VAL      = 0x0100; // (1 << 0 << 8)
24 const FLIP_V_VAL      = 0x0200; // (1 << 1 << 8)
25 const ROT_90_VAL      = 0x0400; // (1 << 2 << 8)
26 const ROT_INVALID_VAL = 0x8000; // (0x80 << 8)
27 
28 function 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 
43 function 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  */
57 function 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  */
103 function 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 
163 function is_type_flag_set(transform, bits) {
164     transform = transform || {};
165     var type = transform.type || 0;
166     return (type & bits) === bits;
167 }
168 
169 function is_type_flag_clear(transform, bits) {
170   transform = transform || {};
171   var type = transform.type || 0;
172   return (type & bits) === 0;
173 }
174 
175 function 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 
186 function 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.
206 function is_simple_rotation(transform) {
207   return !is_type_flag_set(transform, ROT_INVALID_VAL);
208 }
209 
210 export {format_transform_type, fill_transform_data, is_simple_transform,
211         multiply_rect, is_simple_rotation};