1 /* 2 * Copyright (C) 2010 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 android.graphics; 18 19 20 import com.android.ide.common.rendering.api.LayoutLog; 21 import com.android.layoutlib.bridge.Bridge; 22 import com.android.layoutlib.bridge.impl.DelegateManager; 23 import com.android.tools.layoutlib.annotations.LayoutlibDelegate; 24 25 import android.graphics.Matrix.ScaleToFit; 26 27 import java.awt.geom.AffineTransform; 28 import java.awt.geom.NoninvertibleTransformException; 29 30 /** 31 * Delegate implementing the native methods of android.graphics.Matrix 32 * 33 * Through the layoutlib_create tool, the original native methods of Matrix have been replaced 34 * by calls to methods of the same name in this delegate class. 35 * 36 * This class behaves like the original native implementation, but in Java, keeping previously 37 * native data into its own objects and mapping them to int that are sent back and forth between 38 * it and the original Matrix class. 39 * 40 * @see DelegateManager 41 * 42 */ 43 public final class Matrix_Delegate { 44 45 private final static int MATRIX_SIZE = 9; 46 47 // ---- delegate manager ---- 48 private static final DelegateManager<Matrix_Delegate> sManager = 49 new DelegateManager<Matrix_Delegate>(Matrix_Delegate.class); 50 51 // ---- delegate data ---- 52 private float mValues[] = new float[MATRIX_SIZE]; 53 54 // ---- Public Helper methods ---- 55 getDelegate(long native_instance)56 public static Matrix_Delegate getDelegate(long native_instance) { 57 return sManager.getDelegate(native_instance); 58 } 59 60 /** 61 * Returns an {@link AffineTransform} matching the given Matrix. 62 */ getAffineTransform(Matrix m)63 public static AffineTransform getAffineTransform(Matrix m) { 64 Matrix_Delegate delegate = sManager.getDelegate(m.native_instance); 65 if (delegate == null) { 66 return null; 67 } 68 69 return delegate.getAffineTransform(); 70 } 71 hasPerspective(Matrix m)72 public static boolean hasPerspective(Matrix m) { 73 Matrix_Delegate delegate = sManager.getDelegate(m.native_instance); 74 if (delegate == null) { 75 return false; 76 } 77 78 return delegate.hasPerspective(); 79 } 80 81 /** 82 * Sets the content of the matrix with the content of another matrix. 83 */ set(Matrix_Delegate matrix)84 public void set(Matrix_Delegate matrix) { 85 System.arraycopy(matrix.mValues, 0, mValues, 0, MATRIX_SIZE); 86 } 87 88 /** 89 * Sets the content of the matrix with the content of another matrix represented as an array 90 * of values. 91 */ set(float[] values)92 public void set(float[] values) { 93 System.arraycopy(values, 0, mValues, 0, MATRIX_SIZE); 94 } 95 96 /** 97 * Resets the matrix to be the identity matrix. 98 */ reset()99 public void reset() { 100 reset(mValues); 101 } 102 103 /** 104 * Returns whether or not the matrix is identity. 105 */ isIdentity()106 public boolean isIdentity() { 107 for (int i = 0, k = 0; i < 3; i++) { 108 for (int j = 0; j < 3; j++, k++) { 109 if (mValues[k] != ((i==j) ? 1 : 0)) { 110 return false; 111 } 112 } 113 } 114 115 return true; 116 } 117 makeValues(AffineTransform matrix)118 public static float[] makeValues(AffineTransform matrix) { 119 float[] values = new float[MATRIX_SIZE]; 120 values[0] = (float) matrix.getScaleX(); 121 values[1] = (float) matrix.getShearX(); 122 values[2] = (float) matrix.getTranslateX(); 123 values[3] = (float) matrix.getShearY(); 124 values[4] = (float) matrix.getScaleY(); 125 values[5] = (float) matrix.getTranslateY(); 126 values[6] = 0.f; 127 values[7] = 0.f; 128 values[8] = 1.f; 129 130 return values; 131 } 132 make(AffineTransform matrix)133 public static Matrix_Delegate make(AffineTransform matrix) { 134 return new Matrix_Delegate(makeValues(matrix)); 135 } 136 mapRect(RectF dst, RectF src)137 public boolean mapRect(RectF dst, RectF src) { 138 // array with 4 corners 139 float[] corners = new float[] { 140 src.left, src.top, 141 src.right, src.top, 142 src.right, src.bottom, 143 src.left, src.bottom, 144 }; 145 146 // apply the transform to them. 147 mapPoints(corners); 148 149 // now put the result in the rect. We take the min/max of Xs and min/max of Ys 150 dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6])); 151 dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6])); 152 153 dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7])); 154 dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7])); 155 156 157 return (computeTypeMask() & kRectStaysRect_Mask) != 0; 158 } 159 160 161 /** 162 * Returns an {@link AffineTransform} matching the matrix. 163 */ getAffineTransform()164 public AffineTransform getAffineTransform() { 165 return getAffineTransform(mValues); 166 } 167 hasPerspective()168 public boolean hasPerspective() { 169 return (mValues[6] != 0 || mValues[7] != 0 || mValues[8] != 1); 170 } 171 172 173 174 // ---- native methods ---- 175 176 @LayoutlibDelegate native_create(long native_src_or_zero)177 /*package*/ static long native_create(long native_src_or_zero) { 178 // create the delegate 179 Matrix_Delegate newDelegate = new Matrix_Delegate(); 180 181 // copy from values if needed. 182 if (native_src_or_zero > 0) { 183 Matrix_Delegate oldDelegate = sManager.getDelegate(native_src_or_zero); 184 if (oldDelegate != null) { 185 System.arraycopy( 186 oldDelegate.mValues, 0, 187 newDelegate.mValues, 0, 188 MATRIX_SIZE); 189 } 190 } 191 192 return sManager.addNewDelegate(newDelegate); 193 } 194 195 @LayoutlibDelegate native_isIdentity(long native_object)196 /*package*/ static boolean native_isIdentity(long native_object) { 197 Matrix_Delegate d = sManager.getDelegate(native_object); 198 if (d == null) { 199 return false; 200 } 201 202 return d.isIdentity(); 203 } 204 205 @LayoutlibDelegate native_isAffine(long native_object)206 /*package*/ static boolean native_isAffine(long native_object) { 207 Matrix_Delegate d = sManager.getDelegate(native_object); 208 if (d == null) { 209 return true; 210 } 211 212 return (d.computeTypeMask() & kPerspective_Mask) == 0; 213 } 214 215 @LayoutlibDelegate native_rectStaysRect(long native_object)216 /*package*/ static boolean native_rectStaysRect(long native_object) { 217 Matrix_Delegate d = sManager.getDelegate(native_object); 218 if (d == null) { 219 return true; 220 } 221 222 return (d.computeTypeMask() & kRectStaysRect_Mask) != 0; 223 } 224 225 @LayoutlibDelegate native_reset(long native_object)226 /*package*/ static void native_reset(long native_object) { 227 Matrix_Delegate d = sManager.getDelegate(native_object); 228 if (d == null) { 229 return; 230 } 231 232 reset(d.mValues); 233 } 234 235 @LayoutlibDelegate native_set(long native_object, long other)236 /*package*/ static void native_set(long native_object, long other) { 237 Matrix_Delegate d = sManager.getDelegate(native_object); 238 if (d == null) { 239 return; 240 } 241 242 Matrix_Delegate src = sManager.getDelegate(other); 243 if (src == null) { 244 return; 245 } 246 247 System.arraycopy(src.mValues, 0, d.mValues, 0, MATRIX_SIZE); 248 } 249 250 @LayoutlibDelegate native_setTranslate(long native_object, float dx, float dy)251 /*package*/ static void native_setTranslate(long native_object, float dx, float dy) { 252 Matrix_Delegate d = sManager.getDelegate(native_object); 253 if (d == null) { 254 return; 255 } 256 257 setTranslate(d.mValues, dx, dy); 258 } 259 260 @LayoutlibDelegate native_setScale(long native_object, float sx, float sy, float px, float py)261 /*package*/ static void native_setScale(long native_object, float sx, float sy, 262 float px, float py) { 263 Matrix_Delegate d = sManager.getDelegate(native_object); 264 if (d == null) { 265 return; 266 } 267 268 d.mValues = getScale(sx, sy, px, py); 269 } 270 271 @LayoutlibDelegate native_setScale(long native_object, float sx, float sy)272 /*package*/ static void native_setScale(long native_object, float sx, float sy) { 273 Matrix_Delegate d = sManager.getDelegate(native_object); 274 if (d == null) { 275 return; 276 } 277 278 d.mValues[0] = sx; 279 d.mValues[1] = 0; 280 d.mValues[2] = 0; 281 d.mValues[3] = 0; 282 d.mValues[4] = sy; 283 d.mValues[5] = 0; 284 d.mValues[6] = 0; 285 d.mValues[7] = 0; 286 d.mValues[8] = 1; 287 } 288 289 @LayoutlibDelegate native_setRotate(long native_object, float degrees, float px, float py)290 /*package*/ static void native_setRotate(long native_object, float degrees, float px, float py) { 291 Matrix_Delegate d = sManager.getDelegate(native_object); 292 if (d == null) { 293 return; 294 } 295 296 d.mValues = getRotate(degrees, px, py); 297 } 298 299 @LayoutlibDelegate native_setRotate(long native_object, float degrees)300 /*package*/ static void native_setRotate(long native_object, float degrees) { 301 Matrix_Delegate d = sManager.getDelegate(native_object); 302 if (d == null) { 303 return; 304 } 305 306 setRotate(d.mValues, degrees); 307 } 308 309 @LayoutlibDelegate native_setSinCos(long native_object, float sinValue, float cosValue, float px, float py)310 /*package*/ static void native_setSinCos(long native_object, float sinValue, float cosValue, 311 float px, float py) { 312 Matrix_Delegate d = sManager.getDelegate(native_object); 313 if (d == null) { 314 return; 315 } 316 317 // TODO: do it in one pass 318 319 // translate so that the pivot is in 0,0 320 setTranslate(d.mValues, -px, -py); 321 322 // scale 323 d.postTransform(getRotate(sinValue, cosValue)); 324 // translate back the pivot 325 d.postTransform(getTranslate(px, py)); 326 } 327 328 @LayoutlibDelegate native_setSinCos(long native_object, float sinValue, float cosValue)329 /*package*/ static void native_setSinCos(long native_object, float sinValue, float cosValue) { 330 Matrix_Delegate d = sManager.getDelegate(native_object); 331 if (d == null) { 332 return; 333 } 334 335 setRotate(d.mValues, sinValue, cosValue); 336 } 337 338 @LayoutlibDelegate native_setSkew(long native_object, float kx, float ky, float px, float py)339 /*package*/ static void native_setSkew(long native_object, float kx, float ky, 340 float px, float py) { 341 Matrix_Delegate d = sManager.getDelegate(native_object); 342 if (d == null) { 343 return; 344 } 345 346 d.mValues = getSkew(kx, ky, px, py); 347 } 348 349 @LayoutlibDelegate native_setSkew(long native_object, float kx, float ky)350 /*package*/ static void native_setSkew(long native_object, float kx, float ky) { 351 Matrix_Delegate d = sManager.getDelegate(native_object); 352 if (d == null) { 353 return; 354 } 355 356 d.mValues[0] = 1; 357 d.mValues[1] = kx; 358 d.mValues[2] = -0; 359 d.mValues[3] = ky; 360 d.mValues[4] = 1; 361 d.mValues[5] = 0; 362 d.mValues[6] = 0; 363 d.mValues[7] = 0; 364 d.mValues[8] = 1; 365 } 366 367 @LayoutlibDelegate native_setConcat(long native_object, long a, long b)368 /*package*/ static void native_setConcat(long native_object, long a, long b) { 369 if (a == native_object) { 370 native_preConcat(native_object, b); 371 return; 372 } else if (b == native_object) { 373 native_postConcat(native_object, a); 374 return; 375 } 376 377 Matrix_Delegate d = sManager.getDelegate(native_object); 378 Matrix_Delegate a_mtx = sManager.getDelegate(a); 379 Matrix_Delegate b_mtx = sManager.getDelegate(b); 380 if (d != null && a_mtx != null && b_mtx != null) { 381 multiply(d.mValues, a_mtx.mValues, b_mtx.mValues); 382 } 383 } 384 385 @LayoutlibDelegate native_preTranslate(long native_object, float dx, float dy)386 /*package*/ static void native_preTranslate(long native_object, float dx, float dy) { 387 Matrix_Delegate d = sManager.getDelegate(native_object); 388 if (d != null) { 389 d.preTransform(getTranslate(dx, dy)); 390 } 391 } 392 393 @LayoutlibDelegate native_preScale(long native_object, float sx, float sy, float px, float py)394 /*package*/ static void native_preScale(long native_object, float sx, float sy, 395 float px, float py) { 396 Matrix_Delegate d = sManager.getDelegate(native_object); 397 if (d != null) { 398 d.preTransform(getScale(sx, sy, px, py)); 399 } 400 } 401 402 @LayoutlibDelegate native_preScale(long native_object, float sx, float sy)403 /*package*/ static void native_preScale(long native_object, float sx, float sy) { 404 Matrix_Delegate d = sManager.getDelegate(native_object); 405 if (d != null) { 406 d.preTransform(getScale(sx, sy)); 407 } 408 } 409 410 @LayoutlibDelegate native_preRotate(long native_object, float degrees, float px, float py)411 /*package*/ static void native_preRotate(long native_object, float degrees, 412 float px, float py) { 413 Matrix_Delegate d = sManager.getDelegate(native_object); 414 if (d != null) { 415 d.preTransform(getRotate(degrees, px, py)); 416 } 417 } 418 419 @LayoutlibDelegate native_preRotate(long native_object, float degrees)420 /*package*/ static void native_preRotate(long native_object, float degrees) { 421 Matrix_Delegate d = sManager.getDelegate(native_object); 422 if (d != null) { 423 424 double rad = Math.toRadians(degrees); 425 float sin = (float) Math.sin(rad); 426 float cos = (float) Math.cos(rad); 427 428 d.preTransform(getRotate(sin, cos)); 429 } 430 } 431 432 @LayoutlibDelegate native_preSkew(long native_object, float kx, float ky, float px, float py)433 /*package*/ static void native_preSkew(long native_object, float kx, float ky, 434 float px, float py) { 435 Matrix_Delegate d = sManager.getDelegate(native_object); 436 if (d != null) { 437 d.preTransform(getSkew(kx, ky, px, py)); 438 } 439 } 440 441 @LayoutlibDelegate native_preSkew(long native_object, float kx, float ky)442 /*package*/ static void native_preSkew(long native_object, float kx, float ky) { 443 Matrix_Delegate d = sManager.getDelegate(native_object); 444 if (d != null) { 445 d.preTransform(getSkew(kx, ky)); 446 } 447 } 448 449 @LayoutlibDelegate native_preConcat(long native_object, long other_matrix)450 /*package*/ static void native_preConcat(long native_object, long other_matrix) { 451 Matrix_Delegate d = sManager.getDelegate(native_object); 452 Matrix_Delegate other = sManager.getDelegate(other_matrix); 453 if (d != null && other != null) { 454 d.preTransform(other.mValues); 455 } 456 } 457 458 @LayoutlibDelegate native_postTranslate(long native_object, float dx, float dy)459 /*package*/ static void native_postTranslate(long native_object, float dx, float dy) { 460 Matrix_Delegate d = sManager.getDelegate(native_object); 461 if (d != null) { 462 d.postTransform(getTranslate(dx, dy)); 463 } 464 } 465 466 @LayoutlibDelegate native_postScale(long native_object, float sx, float sy, float px, float py)467 /*package*/ static void native_postScale(long native_object, float sx, float sy, 468 float px, float py) { 469 Matrix_Delegate d = sManager.getDelegate(native_object); 470 if (d != null) { 471 d.postTransform(getScale(sx, sy, px, py)); 472 } 473 } 474 475 @LayoutlibDelegate native_postScale(long native_object, float sx, float sy)476 /*package*/ static void native_postScale(long native_object, float sx, float sy) { 477 Matrix_Delegate d = sManager.getDelegate(native_object); 478 if (d != null) { 479 d.postTransform(getScale(sx, sy)); 480 } 481 } 482 483 @LayoutlibDelegate native_postRotate(long native_object, float degrees, float px, float py)484 /*package*/ static void native_postRotate(long native_object, float degrees, 485 float px, float py) { 486 Matrix_Delegate d = sManager.getDelegate(native_object); 487 if (d != null) { 488 d.postTransform(getRotate(degrees, px, py)); 489 } 490 } 491 492 @LayoutlibDelegate native_postRotate(long native_object, float degrees)493 /*package*/ static void native_postRotate(long native_object, float degrees) { 494 Matrix_Delegate d = sManager.getDelegate(native_object); 495 if (d != null) { 496 d.postTransform(getRotate(degrees)); 497 } 498 } 499 500 @LayoutlibDelegate native_postSkew(long native_object, float kx, float ky, float px, float py)501 /*package*/ static void native_postSkew(long native_object, float kx, float ky, 502 float px, float py) { 503 Matrix_Delegate d = sManager.getDelegate(native_object); 504 if (d != null) { 505 d.postTransform(getSkew(kx, ky, px, py)); 506 } 507 } 508 509 @LayoutlibDelegate native_postSkew(long native_object, float kx, float ky)510 /*package*/ static void native_postSkew(long native_object, float kx, float ky) { 511 Matrix_Delegate d = sManager.getDelegate(native_object); 512 if (d != null) { 513 d.postTransform(getSkew(kx, ky)); 514 } 515 } 516 517 @LayoutlibDelegate native_postConcat(long native_object, long other_matrix)518 /*package*/ static void native_postConcat(long native_object, long other_matrix) { 519 Matrix_Delegate d = sManager.getDelegate(native_object); 520 Matrix_Delegate other = sManager.getDelegate(other_matrix); 521 if (d != null && other != null) { 522 d.postTransform(other.mValues); 523 } 524 } 525 526 @LayoutlibDelegate native_setRectToRect(long native_object, RectF src, RectF dst, int stf)527 /*package*/ static boolean native_setRectToRect(long native_object, RectF src, 528 RectF dst, int stf) { 529 Matrix_Delegate d = sManager.getDelegate(native_object); 530 if (d == null) { 531 return false; 532 } 533 534 if (src.isEmpty()) { 535 reset(d.mValues); 536 return false; 537 } 538 539 if (dst.isEmpty()) { 540 d.mValues[0] = d.mValues[1] = d.mValues[2] = d.mValues[3] = d.mValues[4] = d.mValues[5] 541 = d.mValues[6] = d.mValues[7] = 0; 542 d.mValues[8] = 1; 543 } else { 544 float tx, sx = dst.width() / src.width(); 545 float ty, sy = dst.height() / src.height(); 546 boolean xLarger = false; 547 548 if (stf != ScaleToFit.FILL.nativeInt) { 549 if (sx > sy) { 550 xLarger = true; 551 sx = sy; 552 } else { 553 sy = sx; 554 } 555 } 556 557 tx = dst.left - src.left * sx; 558 ty = dst.top - src.top * sy; 559 if (stf == ScaleToFit.CENTER.nativeInt || stf == ScaleToFit.END.nativeInt) { 560 float diff; 561 562 if (xLarger) { 563 diff = dst.width() - src.width() * sy; 564 } else { 565 diff = dst.height() - src.height() * sy; 566 } 567 568 if (stf == ScaleToFit.CENTER.nativeInt) { 569 diff = diff / 2; 570 } 571 572 if (xLarger) { 573 tx += diff; 574 } else { 575 ty += diff; 576 } 577 } 578 579 d.mValues[0] = sx; 580 d.mValues[4] = sy; 581 d.mValues[2] = tx; 582 d.mValues[5] = ty; 583 d.mValues[1] = d.mValues[3] = d.mValues[6] = d.mValues[7] = 0; 584 585 } 586 // shared cleanup 587 d.mValues[8] = 1; 588 return true; 589 } 590 591 @LayoutlibDelegate native_setPolyToPoly(long native_object, float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount)592 /*package*/ static boolean native_setPolyToPoly(long native_object, float[] src, int srcIndex, 593 float[] dst, int dstIndex, int pointCount) { 594 // FIXME 595 Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, 596 "Matrix.setPolyToPoly is not supported.", 597 null, null /*data*/); 598 return false; 599 } 600 601 @LayoutlibDelegate native_invert(long native_object, long inverse)602 /*package*/ static boolean native_invert(long native_object, long inverse) { 603 Matrix_Delegate d = sManager.getDelegate(native_object); 604 if (d == null) { 605 return false; 606 } 607 608 Matrix_Delegate inv_mtx = sManager.getDelegate(inverse); 609 if (inv_mtx == null) { 610 return false; 611 } 612 613 try { 614 AffineTransform affineTransform = d.getAffineTransform(); 615 AffineTransform inverseTransform = affineTransform.createInverse(); 616 inv_mtx.mValues[0] = (float)inverseTransform.getScaleX(); 617 inv_mtx.mValues[1] = (float)inverseTransform.getShearX(); 618 inv_mtx.mValues[2] = (float)inverseTransform.getTranslateX(); 619 inv_mtx.mValues[3] = (float)inverseTransform.getScaleX(); 620 inv_mtx.mValues[4] = (float)inverseTransform.getShearY(); 621 inv_mtx.mValues[5] = (float)inverseTransform.getTranslateY(); 622 623 return true; 624 } catch (NoninvertibleTransformException e) { 625 return false; 626 } 627 } 628 629 @LayoutlibDelegate native_mapPoints(long native_object, float[] dst, int dstIndex, float[] src, int srcIndex, int ptCount, boolean isPts)630 /*package*/ static void native_mapPoints(long native_object, float[] dst, int dstIndex, 631 float[] src, int srcIndex, int ptCount, boolean isPts) { 632 Matrix_Delegate d = sManager.getDelegate(native_object); 633 if (d == null) { 634 return; 635 } 636 637 if (isPts) { 638 d.mapPoints(dst, dstIndex, src, srcIndex, ptCount); 639 } else { 640 d.mapVectors(dst, dstIndex, src, srcIndex, ptCount); 641 } 642 } 643 644 @LayoutlibDelegate native_mapRect(long native_object, RectF dst, RectF src)645 /*package*/ static boolean native_mapRect(long native_object, RectF dst, RectF src) { 646 Matrix_Delegate d = sManager.getDelegate(native_object); 647 if (d == null) { 648 return false; 649 } 650 651 return d.mapRect(dst, src); 652 } 653 654 @LayoutlibDelegate native_mapRadius(long native_object, float radius)655 /*package*/ static float native_mapRadius(long native_object, float radius) { 656 Matrix_Delegate d = sManager.getDelegate(native_object); 657 if (d == null) { 658 return 0.f; 659 } 660 661 float[] src = new float[] { radius, 0.f, 0.f, radius }; 662 d.mapVectors(src, 0, src, 0, 2); 663 664 float l1 = (float) Math.hypot(src[0], src[1]); 665 float l2 = (float) Math.hypot(src[2], src[3]); 666 return (float) Math.sqrt(l1 * l2); 667 } 668 669 @LayoutlibDelegate native_getValues(long native_object, float[] values)670 /*package*/ static void native_getValues(long native_object, float[] values) { 671 Matrix_Delegate d = sManager.getDelegate(native_object); 672 if (d == null) { 673 return; 674 } 675 676 System.arraycopy(d.mValues, 0, values, 0, MATRIX_SIZE); 677 } 678 679 @LayoutlibDelegate native_setValues(long native_object, float[] values)680 /*package*/ static void native_setValues(long native_object, float[] values) { 681 Matrix_Delegate d = sManager.getDelegate(native_object); 682 if (d == null) { 683 return; 684 } 685 686 System.arraycopy(values, 0, d.mValues, 0, MATRIX_SIZE); 687 } 688 689 @LayoutlibDelegate native_equals(long native_a, long native_b)690 /*package*/ static boolean native_equals(long native_a, long native_b) { 691 Matrix_Delegate a = sManager.getDelegate(native_a); 692 if (a == null) { 693 return false; 694 } 695 696 Matrix_Delegate b = sManager.getDelegate(native_b); 697 if (b == null) { 698 return false; 699 } 700 701 for (int i = 0 ; i < MATRIX_SIZE ; i++) { 702 if (a.mValues[i] != b.mValues[i]) { 703 return false; 704 } 705 } 706 707 return true; 708 } 709 710 @LayoutlibDelegate finalizer(long native_instance)711 /*package*/ static void finalizer(long native_instance) { 712 sManager.removeJavaReferenceFor(native_instance); 713 } 714 715 // ---- Private helper methods ---- 716 getAffineTransform(float[] matrix)717 /*package*/ static AffineTransform getAffineTransform(float[] matrix) { 718 // the AffineTransform constructor takes the value in a different order 719 // for a matrix [ 0 1 2 ] 720 // [ 3 4 5 ] 721 // the order is 0, 3, 1, 4, 2, 5... 722 return new AffineTransform( 723 matrix[0], matrix[3], matrix[1], 724 matrix[4], matrix[2], matrix[5]); 725 } 726 727 /** 728 * Reset a matrix to the identity 729 */ reset(float[] mtx)730 private static void reset(float[] mtx) { 731 for (int i = 0, k = 0; i < 3; i++) { 732 for (int j = 0; j < 3; j++, k++) { 733 mtx[k] = ((i==j) ? 1 : 0); 734 } 735 } 736 } 737 738 @SuppressWarnings("unused") 739 private final static int kIdentity_Mask = 0; 740 private final static int kTranslate_Mask = 0x01; //!< set if the matrix has translation 741 private final static int kScale_Mask = 0x02; //!< set if the matrix has X or Y scale 742 private final static int kAffine_Mask = 0x04; //!< set if the matrix skews or rotates 743 private final static int kPerspective_Mask = 0x08; //!< set if the matrix is in perspective 744 private final static int kRectStaysRect_Mask = 0x10; 745 @SuppressWarnings("unused") 746 private final static int kUnknown_Mask = 0x80; 747 748 @SuppressWarnings("unused") 749 private final static int kAllMasks = kTranslate_Mask | 750 kScale_Mask | 751 kAffine_Mask | 752 kPerspective_Mask | 753 kRectStaysRect_Mask; 754 755 // these guys align with the masks, so we can compute a mask from a variable 0/1 756 @SuppressWarnings("unused") 757 private final static int kTranslate_Shift = 0; 758 @SuppressWarnings("unused") 759 private final static int kScale_Shift = 1; 760 @SuppressWarnings("unused") 761 private final static int kAffine_Shift = 2; 762 @SuppressWarnings("unused") 763 private final static int kPerspective_Shift = 3; 764 private final static int kRectStaysRect_Shift = 4; 765 computeTypeMask()766 private int computeTypeMask() { 767 int mask = 0; 768 769 if (mValues[6] != 0. || mValues[7] != 0. || mValues[8] != 1.) { 770 mask |= kPerspective_Mask; 771 } 772 773 if (mValues[2] != 0. || mValues[5] != 0.) { 774 mask |= kTranslate_Mask; 775 } 776 777 float m00 = mValues[0]; 778 float m01 = mValues[1]; 779 float m10 = mValues[3]; 780 float m11 = mValues[4]; 781 782 if (m01 != 0. || m10 != 0.) { 783 mask |= kAffine_Mask; 784 } 785 786 if (m00 != 1. || m11 != 1.) { 787 mask |= kScale_Mask; 788 } 789 790 if ((mask & kPerspective_Mask) == 0) { 791 // map non-zero to 1 792 int im00 = m00 != 0 ? 1 : 0; 793 int im01 = m01 != 0 ? 1 : 0; 794 int im10 = m10 != 0 ? 1 : 0; 795 int im11 = m11 != 0 ? 1 : 0; 796 797 // record if the (p)rimary and (s)econdary diagonals are all 0 or 798 // all non-zero (answer is 0 or 1) 799 int dp0 = (im00 | im11) ^ 1; // true if both are 0 800 int dp1 = im00 & im11; // true if both are 1 801 int ds0 = (im01 | im10) ^ 1; // true if both are 0 802 int ds1 = im01 & im10; // true if both are 1 803 804 // return 1 if primary is 1 and secondary is 0 or 805 // primary is 0 and secondary is 1 806 mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift; 807 } 808 809 return mask; 810 } 811 Matrix_Delegate()812 private Matrix_Delegate() { 813 reset(); 814 } 815 Matrix_Delegate(float[] values)816 private Matrix_Delegate(float[] values) { 817 System.arraycopy(values, 0, mValues, 0, MATRIX_SIZE); 818 } 819 820 /** 821 * Adds the given transformation to the current Matrix 822 * <p/>This in effect does this = this*matrix 823 * @param matrix 824 */ postTransform(float[] matrix)825 private void postTransform(float[] matrix) { 826 float[] tmp = new float[9]; 827 multiply(tmp, mValues, matrix); 828 mValues = tmp; 829 } 830 831 /** 832 * Adds the given transformation to the current Matrix 833 * <p/>This in effect does this = matrix*this 834 * @param matrix 835 */ preTransform(float[] matrix)836 private void preTransform(float[] matrix) { 837 float[] tmp = new float[9]; 838 multiply(tmp, matrix, mValues); 839 mValues = tmp; 840 } 841 842 /** 843 * Apply this matrix to the array of 2D points specified by src, and write 844 * the transformed points into the array of points specified by dst. The 845 * two arrays represent their "points" as pairs of floats [x, y]. 846 * 847 * @param dst The array of dst points (x,y pairs) 848 * @param dstIndex The index of the first [x,y] pair of dst floats 849 * @param src The array of src points (x,y pairs) 850 * @param srcIndex The index of the first [x,y] pair of src floats 851 * @param pointCount The number of points (x,y pairs) to transform 852 */ 853 mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex, int pointCount)854 private void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex, 855 int pointCount) { 856 final int count = pointCount * 2; 857 858 float[] tmpDest = dst; 859 boolean inPlace = dst == src; 860 if (inPlace) { 861 tmpDest = new float[dstIndex + count]; 862 } 863 864 for (int i = 0 ; i < count ; i += 2) { 865 // just in case we are doing in place, we better put this in temp vars 866 float x = mValues[0] * src[i + srcIndex] + 867 mValues[1] * src[i + srcIndex + 1] + 868 mValues[2]; 869 float y = mValues[3] * src[i + srcIndex] + 870 mValues[4] * src[i + srcIndex + 1] + 871 mValues[5]; 872 873 tmpDest[i + dstIndex] = x; 874 tmpDest[i + dstIndex + 1] = y; 875 } 876 877 if (inPlace) { 878 System.arraycopy(tmpDest, dstIndex, dst, dstIndex, count); 879 } 880 } 881 882 /** 883 * Apply this matrix to the array of 2D points, and write the transformed 884 * points back into the array 885 * 886 * @param pts The array [x0, y0, x1, y1, ...] of points to transform. 887 */ 888 mapPoints(float[] pts)889 private void mapPoints(float[] pts) { 890 mapPoints(pts, 0, pts, 0, pts.length >> 1); 891 } 892 mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, int ptCount)893 private void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, int ptCount) { 894 if (hasPerspective()) { 895 // transform the (0,0) point 896 float[] origin = new float[] { 0.f, 0.f}; 897 mapPoints(origin); 898 899 // translate the vector data as points 900 mapPoints(dst, dstIndex, src, srcIndex, ptCount); 901 902 // then substract the transformed origin. 903 final int count = ptCount * 2; 904 for (int i = 0 ; i < count ; i += 2) { 905 dst[dstIndex + i] = dst[dstIndex + i] - origin[0]; 906 dst[dstIndex + i + 1] = dst[dstIndex + i + 1] - origin[1]; 907 } 908 } else { 909 // make a copy of the matrix 910 Matrix_Delegate copy = new Matrix_Delegate(mValues); 911 912 // remove the translation 913 setTranslate(copy.mValues, 0, 0); 914 915 // map the content as points. 916 copy.mapPoints(dst, dstIndex, src, srcIndex, ptCount); 917 } 918 } 919 920 /** 921 * multiply two matrices and store them in a 3rd. 922 * <p/>This in effect does dest = a*b 923 * dest cannot be the same as a or b. 924 */ multiply(float dest[], float[] a, float[] b)925 /*package*/ static void multiply(float dest[], float[] a, float[] b) { 926 // first row 927 dest[0] = b[0] * a[0] + b[1] * a[3] + b[2] * a[6]; 928 dest[1] = b[0] * a[1] + b[1] * a[4] + b[2] * a[7]; 929 dest[2] = b[0] * a[2] + b[1] * a[5] + b[2] * a[8]; 930 931 // 2nd row 932 dest[3] = b[3] * a[0] + b[4] * a[3] + b[5] * a[6]; 933 dest[4] = b[3] * a[1] + b[4] * a[4] + b[5] * a[7]; 934 dest[5] = b[3] * a[2] + b[4] * a[5] + b[5] * a[8]; 935 936 // 3rd row 937 dest[6] = b[6] * a[0] + b[7] * a[3] + b[8] * a[6]; 938 dest[7] = b[6] * a[1] + b[7] * a[4] + b[8] * a[7]; 939 dest[8] = b[6] * a[2] + b[7] * a[5] + b[8] * a[8]; 940 } 941 942 /** 943 * Returns a matrix that represents a given translate 944 * @param dx 945 * @param dy 946 * @return 947 */ getTranslate(float dx, float dy)948 /*package*/ static float[] getTranslate(float dx, float dy) { 949 return setTranslate(new float[9], dx, dy); 950 } 951 setTranslate(float[] dest, float dx, float dy)952 /*package*/ static float[] setTranslate(float[] dest, float dx, float dy) { 953 dest[0] = 1; 954 dest[1] = 0; 955 dest[2] = dx; 956 dest[3] = 0; 957 dest[4] = 1; 958 dest[5] = dy; 959 dest[6] = 0; 960 dest[7] = 0; 961 dest[8] = 1; 962 return dest; 963 } 964 getScale(float sx, float sy)965 /*package*/ static float[] getScale(float sx, float sy) { 966 return new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 }; 967 } 968 969 /** 970 * Returns a matrix that represents the given scale info. 971 * @param sx 972 * @param sy 973 * @param px 974 * @param py 975 */ getScale(float sx, float sy, float px, float py)976 /*package*/ static float[] getScale(float sx, float sy, float px, float py) { 977 float[] tmp = new float[9]; 978 float[] tmp2 = new float[9]; 979 980 // TODO: do it in one pass 981 982 // translate tmp so that the pivot is in 0,0 983 setTranslate(tmp, -px, -py); 984 985 // scale into tmp2 986 multiply(tmp2, tmp, getScale(sx, sy)); 987 988 // translate back the pivot back into tmp 989 multiply(tmp, tmp2, getTranslate(px, py)); 990 991 return tmp; 992 } 993 994 getRotate(float degrees)995 /*package*/ static float[] getRotate(float degrees) { 996 double rad = Math.toRadians(degrees); 997 float sin = (float)Math.sin(rad); 998 float cos = (float)Math.cos(rad); 999 1000 return getRotate(sin, cos); 1001 } 1002 getRotate(float sin, float cos)1003 /*package*/ static float[] getRotate(float sin, float cos) { 1004 return setRotate(new float[9], sin, cos); 1005 } 1006 setRotate(float[] dest, float degrees)1007 /*package*/ static float[] setRotate(float[] dest, float degrees) { 1008 double rad = Math.toRadians(degrees); 1009 float sin = (float)Math.sin(rad); 1010 float cos = (float)Math.cos(rad); 1011 1012 return setRotate(dest, sin, cos); 1013 } 1014 setRotate(float[] dest, float sin, float cos)1015 /*package*/ static float[] setRotate(float[] dest, float sin, float cos) { 1016 dest[0] = cos; 1017 dest[1] = -sin; 1018 dest[2] = 0; 1019 dest[3] = sin; 1020 dest[4] = cos; 1021 dest[5] = 0; 1022 dest[6] = 0; 1023 dest[7] = 0; 1024 dest[8] = 1; 1025 return dest; 1026 } 1027 getRotate(float degrees, float px, float py)1028 /*package*/ static float[] getRotate(float degrees, float px, float py) { 1029 float[] tmp = new float[9]; 1030 float[] tmp2 = new float[9]; 1031 1032 // TODO: do it in one pass 1033 1034 // translate so that the pivot is in 0,0 1035 setTranslate(tmp, -px, -py); 1036 1037 // rotate into tmp2 1038 double rad = Math.toRadians(degrees); 1039 float cos = (float)Math.cos(rad); 1040 float sin = (float)Math.sin(rad); 1041 multiply(tmp2, tmp, getRotate(sin, cos)); 1042 1043 // translate back the pivot back into tmp 1044 multiply(tmp, tmp2, getTranslate(px, py)); 1045 1046 return tmp; 1047 } 1048 getSkew(float kx, float ky)1049 /*package*/ static float[] getSkew(float kx, float ky) { 1050 return new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 }; 1051 } 1052 getSkew(float kx, float ky, float px, float py)1053 /*package*/ static float[] getSkew(float kx, float ky, float px, float py) { 1054 float[] tmp = new float[9]; 1055 float[] tmp2 = new float[9]; 1056 1057 // TODO: do it in one pass 1058 1059 // translate so that the pivot is in 0,0 1060 setTranslate(tmp, -px, -py); 1061 1062 // skew into tmp2 1063 multiply(tmp2, tmp, new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 }); 1064 // translate back the pivot back into tmp 1065 multiply(tmp, tmp2, getTranslate(px, py)); 1066 1067 return tmp; 1068 } 1069 } 1070