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