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