1 /* 2 * Copyright (C) 2007 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 #include <math.h> 18 19 #include <cutils/compiler.h> 20 #include <utils/String8.h> 21 #include <ui/Region.h> 22 23 #include "Transform.h" 24 25 // --------------------------------------------------------------------------- 26 27 namespace android { 28 29 // --------------------------------------------------------------------------- 30 31 template <typename T> inline T min(T a, T b) { 32 return a<b ? a : b; 33 } 34 template <typename T> inline T min(T a, T b, T c) { 35 return min(a, min(b, c)); 36 } 37 template <typename T> inline T min(T a, T b, T c, T d) { 38 return min(a, b, min(c, d)); 39 } 40 41 template <typename T> inline T max(T a, T b) { 42 return a>b ? a : b; 43 } 44 template <typename T> inline T max(T a, T b, T c) { 45 return max(a, max(b, c)); 46 } 47 template <typename T> inline T max(T a, T b, T c, T d) { 48 return max(a, b, max(c, d)); 49 } 50 51 // --------------------------------------------------------------------------- 52 53 Transform::Transform() { 54 reset(); 55 } 56 57 Transform::Transform(const Transform& other) 58 : mMatrix(other.mMatrix), mType(other.mType) { 59 } 60 61 Transform::Transform(uint32_t orientation) { 62 set(orientation, 0, 0); 63 } 64 65 Transform::~Transform() { 66 } 67 68 static const float EPSILON = 0.0f; 69 70 bool Transform::isZero(float f) { 71 return fabs(f) <= EPSILON; 72 } 73 74 bool Transform::absIsOne(float f) { 75 return isZero(fabs(f) - 1.0f); 76 } 77 78 Transform Transform::operator * (const Transform& rhs) const 79 { 80 if (CC_LIKELY(mType == IDENTITY)) 81 return rhs; 82 83 Transform r(*this); 84 if (rhs.mType == IDENTITY) 85 return r; 86 87 // TODO: we could use mType to optimize the matrix multiply 88 const mat33& A(mMatrix); 89 const mat33& B(rhs.mMatrix); 90 mat33& D(r.mMatrix); 91 for (int i=0 ; i<3 ; i++) { 92 const float v0 = A[0][i]; 93 const float v1 = A[1][i]; 94 const float v2 = A[2][i]; 95 D[0][i] = v0*B[0][0] + v1*B[0][1] + v2*B[0][2]; 96 D[1][i] = v0*B[1][0] + v1*B[1][1] + v2*B[1][2]; 97 D[2][i] = v0*B[2][0] + v1*B[2][1] + v2*B[2][2]; 98 } 99 r.mType |= rhs.mType; 100 101 // TODO: we could recompute this value from r and rhs 102 r.mType &= 0xFF; 103 r.mType |= UNKNOWN_TYPE; 104 return r; 105 } 106 107 float const* Transform::operator [] (int i) const { 108 return mMatrix[i].v; 109 } 110 111 bool Transform::transformed() const { 112 return type() > TRANSLATE; 113 } 114 115 int Transform::tx() const { 116 return floorf(mMatrix[2][0] + 0.5f); 117 } 118 119 int Transform::ty() const { 120 return floorf(mMatrix[2][1] + 0.5f); 121 } 122 123 void Transform::reset() { 124 mType = IDENTITY; 125 for(int i=0 ; i<3 ; i++) { 126 vec3& v(mMatrix[i]); 127 for (int j=0 ; j<3 ; j++) 128 v[j] = ((i==j) ? 1.0f : 0.0f); 129 } 130 } 131 132 void Transform::set(float tx, float ty) 133 { 134 mMatrix[2][0] = tx; 135 mMatrix[2][1] = ty; 136 mMatrix[2][2] = 1.0f; 137 138 if (isZero(tx) && isZero(ty)) { 139 mType &= ~TRANSLATE; 140 } else { 141 mType |= TRANSLATE; 142 } 143 } 144 145 void Transform::set(float a, float b, float c, float d) 146 { 147 mat33& M(mMatrix); 148 M[0][0] = a; M[1][0] = b; 149 M[0][1] = c; M[1][1] = d; 150 M[0][2] = 0; M[1][2] = 0; 151 mType = UNKNOWN_TYPE; 152 } 153 154 status_t Transform::set(uint32_t flags, float w, float h) 155 { 156 if (flags & ROT_INVALID) { 157 // that's not allowed! 158 reset(); 159 return BAD_VALUE; 160 } 161 162 mType = flags << 8; 163 float sx = (flags & FLIP_H) ? -1 : 1; 164 float sy = (flags & FLIP_V) ? -1 : 1; 165 float a=0, b=0, c=0, d=0, x=0, y=0; 166 int xmask = 0; 167 168 // computation of x,y 169 // x y 170 // 0 0 0 171 // w 0 ROT90 172 // w h FLIPH|FLIPV 173 // 0 h FLIPH|FLIPV|ROT90 174 175 if (flags & ROT_90) { 176 mType |= ROTATE; 177 b = -sy; 178 c = sx; 179 xmask = 1; 180 } else { 181 a = sx; 182 d = sy; 183 } 184 185 if (flags & FLIP_H) { 186 mType ^= SCALE; 187 xmask ^= 1; 188 } 189 190 if (flags & FLIP_V) { 191 mType ^= SCALE; 192 y = h; 193 } 194 195 if ((flags & ROT_180) == ROT_180) { 196 mType |= ROTATE; 197 } 198 199 if (xmask) { 200 x = w; 201 } 202 203 if (!isZero(x) || !isZero(y)) { 204 mType |= TRANSLATE; 205 } 206 207 mat33& M(mMatrix); 208 M[0][0] = a; M[1][0] = b; M[2][0] = x; 209 M[0][1] = c; M[1][1] = d; M[2][1] = y; 210 M[0][2] = 0; M[1][2] = 0; M[2][2] = 1; 211 212 return NO_ERROR; 213 } 214 215 Transform::vec2 Transform::transform(const vec2& v) const { 216 vec2 r; 217 const mat33& M(mMatrix); 218 r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0]; 219 r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1]; 220 return r; 221 } 222 223 Transform::vec3 Transform::transform(const vec3& v) const { 224 vec3 r; 225 const mat33& M(mMatrix); 226 r[0] = M[0][0]*v[0] + M[1][0]*v[1] + M[2][0]*v[2]; 227 r[1] = M[0][1]*v[0] + M[1][1]*v[1] + M[2][1]*v[2]; 228 r[2] = M[0][2]*v[0] + M[1][2]*v[1] + M[2][2]*v[2]; 229 return r; 230 } 231 232 void Transform::transform(fixed1616* point, int x, int y) const 233 { 234 const float toFixed = 65536.0f; 235 const mat33& M(mMatrix); 236 vec2 v(x, y); 237 v = transform(v); 238 point[0] = v[0] * toFixed; 239 point[1] = v[1] * toFixed; 240 } 241 242 Rect Transform::makeBounds(int w, int h) const 243 { 244 return transform( Rect(w, h) ); 245 } 246 247 Rect Transform::transform(const Rect& bounds) const 248 { 249 Rect r; 250 vec2 lt( bounds.left, bounds.top ); 251 vec2 rt( bounds.right, bounds.top ); 252 vec2 lb( bounds.left, bounds.bottom ); 253 vec2 rb( bounds.right, bounds.bottom ); 254 255 lt = transform(lt); 256 rt = transform(rt); 257 lb = transform(lb); 258 rb = transform(rb); 259 260 r.left = floorf(min(lt[0], rt[0], lb[0], rb[0]) + 0.5f); 261 r.top = floorf(min(lt[1], rt[1], lb[1], rb[1]) + 0.5f); 262 r.right = floorf(max(lt[0], rt[0], lb[0], rb[0]) + 0.5f); 263 r.bottom = floorf(max(lt[1], rt[1], lb[1], rb[1]) + 0.5f); 264 265 return r; 266 } 267 268 Region Transform::transform(const Region& reg) const 269 { 270 Region out; 271 if (CC_UNLIKELY(transformed())) { 272 if (CC_LIKELY(preserveRects())) { 273 Region::const_iterator it = reg.begin(); 274 Region::const_iterator const end = reg.end(); 275 while (it != end) { 276 out.orSelf(transform(*it++)); 277 } 278 } else { 279 out.set(transform(reg.bounds())); 280 } 281 } else { 282 out = reg.translate(tx(), ty()); 283 } 284 return out; 285 } 286 287 uint32_t Transform::type() const 288 { 289 if (mType & UNKNOWN_TYPE) { 290 // recompute what this transform is 291 292 const mat33& M(mMatrix); 293 const float a = M[0][0]; 294 const float b = M[1][0]; 295 const float c = M[0][1]; 296 const float d = M[1][1]; 297 const float x = M[2][0]; 298 const float y = M[2][1]; 299 300 bool scale = false; 301 uint32_t flags = ROT_0; 302 if (isZero(b) && isZero(c)) { 303 if (a<0) flags |= FLIP_H; 304 if (d<0) flags |= FLIP_V; 305 if (!absIsOne(a) || !absIsOne(d)) { 306 scale = true; 307 } 308 } else if (isZero(a) && isZero(d)) { 309 flags |= ROT_90; 310 if (b>0) flags |= FLIP_H; 311 if (c<0) flags |= FLIP_V; 312 if (!absIsOne(b) || !absIsOne(c)) { 313 scale = true; 314 } 315 } else { 316 flags = ROT_INVALID; 317 } 318 319 mType = flags << 8; 320 if (flags & ROT_INVALID) { 321 mType |= UNKNOWN; 322 } else { 323 if ((flags & ROT_90) || ((flags & ROT_180) == ROT_180)) 324 mType |= ROTATE; 325 if (flags & FLIP_H) 326 mType ^= SCALE; 327 if (flags & FLIP_V) 328 mType ^= SCALE; 329 if (scale) 330 mType |= SCALE; 331 } 332 333 if (!isZero(x) || !isZero(y)) 334 mType |= TRANSLATE; 335 } 336 return mType; 337 } 338 339 uint32_t Transform::getType() const { 340 return type() & 0xFF; 341 } 342 343 uint32_t Transform::getOrientation() const 344 { 345 return (type() >> 8) & 0xFF; 346 } 347 348 bool Transform::preserveRects() const 349 { 350 return (type() & ROT_INVALID) ? false : true; 351 } 352 353 void Transform::dump(const char* name) const 354 { 355 type(); // updates the type 356 357 String8 flags, type; 358 const mat33& m(mMatrix); 359 uint32_t orient = mType >> 8; 360 361 if (orient&ROT_INVALID) { 362 flags.append("ROT_INVALID "); 363 } else { 364 if (orient&ROT_90) { 365 flags.append("ROT_90 "); 366 } else { 367 flags.append("ROT_0 "); 368 } 369 if (orient&FLIP_V) 370 flags.append("FLIP_V "); 371 if (orient&FLIP_H) 372 flags.append("FLIP_H "); 373 } 374 375 if (!(mType&(SCALE|ROTATE|TRANSLATE))) 376 type.append("IDENTITY "); 377 if (mType&SCALE) 378 type.append("SCALE "); 379 if (mType&ROTATE) 380 type.append("ROTATE "); 381 if (mType&TRANSLATE) 382 type.append("TRANSLATE "); 383 384 LOGD("%s 0x%08x (%s, %s)", name, mType, flags.string(), type.string()); 385 LOGD("%.4f %.4f %.4f", m[0][0], m[1][0], m[2][0]); 386 LOGD("%.4f %.4f %.4f", m[0][1], m[1][1], m[2][1]); 387 LOGD("%.4f %.4f %.4f", m[0][2], m[1][2], m[2][2]); 388 } 389 390 // --------------------------------------------------------------------------- 391 392 }; // namespace android 393