1 /* 2 * Copyright (C) 2006 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 import dalvik.annotation.optimization.CriticalNative; 20 import dalvik.annotation.optimization.FastNative; 21 22 import libcore.util.NativeAllocationRegistry; 23 24 import java.io.PrintWriter; 25 26 /** 27 * The Matrix class holds a 3x3 matrix for transforming coordinates. 28 */ 29 public class Matrix { 30 31 public static final int MSCALE_X = 0; //!< use with getValues/setValues 32 public static final int MSKEW_X = 1; //!< use with getValues/setValues 33 public static final int MTRANS_X = 2; //!< use with getValues/setValues 34 public static final int MSKEW_Y = 3; //!< use with getValues/setValues 35 public static final int MSCALE_Y = 4; //!< use with getValues/setValues 36 public static final int MTRANS_Y = 5; //!< use with getValues/setValues 37 public static final int MPERSP_0 = 6; //!< use with getValues/setValues 38 public static final int MPERSP_1 = 7; //!< use with getValues/setValues 39 public static final int MPERSP_2 = 8; //!< use with getValues/setValues 40 41 /** @hide */ 42 public final static Matrix IDENTITY_MATRIX = new Matrix() { 43 void oops() { 44 throw new IllegalStateException("Matrix can not be modified"); 45 } 46 47 @Override 48 public void set(Matrix src) { 49 oops(); 50 } 51 52 @Override 53 public void reset() { 54 oops(); 55 } 56 57 @Override 58 public void setTranslate(float dx, float dy) { 59 oops(); 60 } 61 62 @Override 63 public void setScale(float sx, float sy, float px, float py) { 64 oops(); 65 } 66 67 @Override 68 public void setScale(float sx, float sy) { 69 oops(); 70 } 71 72 @Override 73 public void setRotate(float degrees, float px, float py) { 74 oops(); 75 } 76 77 @Override 78 public void setRotate(float degrees) { 79 oops(); 80 } 81 82 @Override 83 public void setSinCos(float sinValue, float cosValue, float px, float py) { 84 oops(); 85 } 86 87 @Override 88 public void setSinCos(float sinValue, float cosValue) { 89 oops(); 90 } 91 92 @Override 93 public void setSkew(float kx, float ky, float px, float py) { 94 oops(); 95 } 96 97 @Override 98 public void setSkew(float kx, float ky) { 99 oops(); 100 } 101 102 @Override 103 public boolean setConcat(Matrix a, Matrix b) { 104 oops(); 105 return false; 106 } 107 108 @Override 109 public boolean preTranslate(float dx, float dy) { 110 oops(); 111 return false; 112 } 113 114 @Override 115 public boolean preScale(float sx, float sy, float px, float py) { 116 oops(); 117 return false; 118 } 119 120 @Override 121 public boolean preScale(float sx, float sy) { 122 oops(); 123 return false; 124 } 125 126 @Override 127 public boolean preRotate(float degrees, float px, float py) { 128 oops(); 129 return false; 130 } 131 132 @Override 133 public boolean preRotate(float degrees) { 134 oops(); 135 return false; 136 } 137 138 @Override 139 public boolean preSkew(float kx, float ky, float px, float py) { 140 oops(); 141 return false; 142 } 143 144 @Override 145 public boolean preSkew(float kx, float ky) { 146 oops(); 147 return false; 148 } 149 150 @Override 151 public boolean preConcat(Matrix other) { 152 oops(); 153 return false; 154 } 155 156 @Override 157 public boolean postTranslate(float dx, float dy) { 158 oops(); 159 return false; 160 } 161 162 @Override 163 public boolean postScale(float sx, float sy, float px, float py) { 164 oops(); 165 return false; 166 } 167 168 @Override 169 public boolean postScale(float sx, float sy) { 170 oops(); 171 return false; 172 } 173 174 @Override 175 public boolean postRotate(float degrees, float px, float py) { 176 oops(); 177 return false; 178 } 179 180 @Override 181 public boolean postRotate(float degrees) { 182 oops(); 183 return false; 184 } 185 186 @Override 187 public boolean postSkew(float kx, float ky, float px, float py) { 188 oops(); 189 return false; 190 } 191 192 @Override 193 public boolean postSkew(float kx, float ky) { 194 oops(); 195 return false; 196 } 197 198 @Override 199 public boolean postConcat(Matrix other) { 200 oops(); 201 return false; 202 } 203 204 @Override 205 public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf) { 206 oops(); 207 return false; 208 } 209 210 @Override 211 public boolean setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex, 212 int pointCount) { 213 oops(); 214 return false; 215 } 216 217 @Override 218 public void setValues(float[] values) { 219 oops(); 220 } 221 }; 222 223 // sizeof(SkMatrix) is 9 * sizeof(float) + uint32_t 224 private static final long NATIVE_ALLOCATION_SIZE = 40; 225 226 private static class NoImagePreloadHolder { 227 public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( 228 Matrix.class.getClassLoader(), nGetNativeFinalizer(), NATIVE_ALLOCATION_SIZE); 229 } 230 231 /** 232 * @hide 233 */ 234 public final long native_instance; 235 236 /** 237 * Create an identity matrix 238 */ Matrix()239 public Matrix() { 240 native_instance = nCreate(0); 241 NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance); 242 } 243 244 /** 245 * Create a matrix that is a (deep) copy of src 246 * 247 * @param src The matrix to copy into this matrix 248 */ Matrix(Matrix src)249 public Matrix(Matrix src) { 250 native_instance = nCreate(src != null ? src.native_instance : 0); 251 NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance); 252 } 253 254 /** 255 * Returns true if the matrix is identity. This maybe faster than testing if (getType() == 0) 256 */ isIdentity()257 public boolean isIdentity() { 258 return nIsIdentity(native_instance); 259 } 260 261 /** 262 * Gets whether this matrix is affine. An affine matrix preserves straight lines and has no 263 * perspective. 264 * 265 * @return Whether the matrix is affine. 266 */ isAffine()267 public boolean isAffine() { 268 return nIsAffine(native_instance); 269 } 270 271 /** 272 * Returns true if will map a rectangle to another rectangle. This can be true if the matrix is 273 * identity, scale-only, or rotates a multiple of 90 degrees. 274 */ rectStaysRect()275 public boolean rectStaysRect() { 276 return nRectStaysRect(native_instance); 277 } 278 279 /** 280 * (deep) copy the src matrix into this matrix. If src is null, reset this matrix to the 281 * identity matrix. 282 */ set(Matrix src)283 public void set(Matrix src) { 284 if (src == null) { 285 reset(); 286 } else { 287 nSet(native_instance, src.native_instance); 288 } 289 } 290 291 /** 292 * Returns true iff obj is a Matrix and its values equal our values. 293 */ 294 @Override equals(Object obj)295 public boolean equals(Object obj) { 296 // if (obj == this) return true; -- NaN value would mean matrix != itself 297 if (!(obj instanceof Matrix)) { 298 return false; 299 } 300 return nEquals(native_instance, ((Matrix) obj).native_instance); 301 } 302 303 @Override hashCode()304 public int hashCode() { 305 // This should generate the hash code by performing some arithmetic operation on all 306 // the matrix elements -- our equals() does an element-by-element comparison, and we 307 // need to ensure that the hash code for two equal objects is the same. We're not 308 // really using this at the moment, so we take the easy way out. 309 return 44; 310 } 311 312 /** Set the matrix to identity */ reset()313 public void reset() { 314 nReset(native_instance); 315 } 316 317 /** Set the matrix to translate by (dx, dy). */ setTranslate(float dx, float dy)318 public void setTranslate(float dx, float dy) { 319 nSetTranslate(native_instance, dx, dy); 320 } 321 322 /** 323 * Set the matrix to scale by sx and sy, with a pivot point at (px, py). The pivot point is the 324 * coordinate that should remain unchanged by the specified transformation. 325 */ setScale(float sx, float sy, float px, float py)326 public void setScale(float sx, float sy, float px, float py) { 327 nSetScale(native_instance, sx, sy, px, py); 328 } 329 330 /** Set the matrix to scale by sx and sy. */ setScale(float sx, float sy)331 public void setScale(float sx, float sy) { 332 nSetScale(native_instance, sx, sy); 333 } 334 335 /** 336 * Set the matrix to rotate by the specified number of degrees, with a pivot point at (px, py). 337 * The pivot point is the coordinate that should remain unchanged by the specified 338 * transformation. 339 */ setRotate(float degrees, float px, float py)340 public void setRotate(float degrees, float px, float py) { 341 nSetRotate(native_instance, degrees, px, py); 342 } 343 344 /** 345 * Set the matrix to rotate about (0,0) by the specified number of degrees. 346 */ setRotate(float degrees)347 public void setRotate(float degrees) { 348 nSetRotate(native_instance, degrees); 349 } 350 351 /** 352 * Set the matrix to rotate by the specified sine and cosine values, with a pivot point at (px, 353 * py). The pivot point is the coordinate that should remain unchanged by the specified 354 * transformation. 355 */ setSinCos(float sinValue, float cosValue, float px, float py)356 public void setSinCos(float sinValue, float cosValue, float px, float py) { 357 nSetSinCos(native_instance, sinValue, cosValue, px, py); 358 } 359 360 /** Set the matrix to rotate by the specified sine and cosine values. */ setSinCos(float sinValue, float cosValue)361 public void setSinCos(float sinValue, float cosValue) { 362 nSetSinCos(native_instance, sinValue, cosValue); 363 } 364 365 /** 366 * Set the matrix to skew by sx and sy, with a pivot point at (px, py). The pivot point is the 367 * coordinate that should remain unchanged by the specified transformation. 368 */ setSkew(float kx, float ky, float px, float py)369 public void setSkew(float kx, float ky, float px, float py) { 370 nSetSkew(native_instance, kx, ky, px, py); 371 } 372 373 /** Set the matrix to skew by sx and sy. */ setSkew(float kx, float ky)374 public void setSkew(float kx, float ky) { 375 nSetSkew(native_instance, kx, ky); 376 } 377 378 /** 379 * Set the matrix to the concatenation of the two specified matrices and return true. 380 * <p> 381 * Either of the two matrices may also be the target matrix, that is 382 * <code>matrixA.setConcat(matrixA, matrixB);</code> is valid. 383 * </p> 384 * <p class="note"> 385 * In {@link android.os.Build.VERSION_CODES#GINGERBREAD_MR1} and below, this function returns 386 * true only if the result can be represented. In 387 * {@link android.os.Build.VERSION_CODES#HONEYCOMB} and above, it always returns true. 388 * </p> 389 */ setConcat(Matrix a, Matrix b)390 public boolean setConcat(Matrix a, Matrix b) { 391 nSetConcat(native_instance, a.native_instance, b.native_instance); 392 return true; 393 } 394 395 /** 396 * Preconcats the matrix with the specified translation. M' = M * T(dx, dy) 397 */ preTranslate(float dx, float dy)398 public boolean preTranslate(float dx, float dy) { 399 nPreTranslate(native_instance, dx, dy); 400 return true; 401 } 402 403 /** 404 * Preconcats the matrix with the specified scale. M' = M * S(sx, sy, px, py) 405 */ preScale(float sx, float sy, float px, float py)406 public boolean preScale(float sx, float sy, float px, float py) { 407 nPreScale(native_instance, sx, sy, px, py); 408 return true; 409 } 410 411 /** 412 * Preconcats the matrix with the specified scale. M' = M * S(sx, sy) 413 */ preScale(float sx, float sy)414 public boolean preScale(float sx, float sy) { 415 nPreScale(native_instance, sx, sy); 416 return true; 417 } 418 419 /** 420 * Preconcats the matrix with the specified rotation. M' = M * R(degrees, px, py) 421 */ preRotate(float degrees, float px, float py)422 public boolean preRotate(float degrees, float px, float py) { 423 nPreRotate(native_instance, degrees, px, py); 424 return true; 425 } 426 427 /** 428 * Preconcats the matrix with the specified rotation. M' = M * R(degrees) 429 */ preRotate(float degrees)430 public boolean preRotate(float degrees) { 431 nPreRotate(native_instance, degrees); 432 return true; 433 } 434 435 /** 436 * Preconcats the matrix with the specified skew. M' = M * K(kx, ky, px, py) 437 */ preSkew(float kx, float ky, float px, float py)438 public boolean preSkew(float kx, float ky, float px, float py) { 439 nPreSkew(native_instance, kx, ky, px, py); 440 return true; 441 } 442 443 /** 444 * Preconcats the matrix with the specified skew. M' = M * K(kx, ky) 445 */ preSkew(float kx, float ky)446 public boolean preSkew(float kx, float ky) { 447 nPreSkew(native_instance, kx, ky); 448 return true; 449 } 450 451 /** 452 * Preconcats the matrix with the specified matrix. M' = M * other 453 */ preConcat(Matrix other)454 public boolean preConcat(Matrix other) { 455 nPreConcat(native_instance, other.native_instance); 456 return true; 457 } 458 459 /** 460 * Postconcats the matrix with the specified translation. M' = T(dx, dy) * M 461 */ postTranslate(float dx, float dy)462 public boolean postTranslate(float dx, float dy) { 463 nPostTranslate(native_instance, dx, dy); 464 return true; 465 } 466 467 /** 468 * Postconcats the matrix with the specified scale. M' = S(sx, sy, px, py) * M 469 */ postScale(float sx, float sy, float px, float py)470 public boolean postScale(float sx, float sy, float px, float py) { 471 nPostScale(native_instance, sx, sy, px, py); 472 return true; 473 } 474 475 /** 476 * Postconcats the matrix with the specified scale. M' = S(sx, sy) * M 477 */ postScale(float sx, float sy)478 public boolean postScale(float sx, float sy) { 479 nPostScale(native_instance, sx, sy); 480 return true; 481 } 482 483 /** 484 * Postconcats the matrix with the specified rotation. M' = R(degrees, px, py) * M 485 */ postRotate(float degrees, float px, float py)486 public boolean postRotate(float degrees, float px, float py) { 487 nPostRotate(native_instance, degrees, px, py); 488 return true; 489 } 490 491 /** 492 * Postconcats the matrix with the specified rotation. M' = R(degrees) * M 493 */ postRotate(float degrees)494 public boolean postRotate(float degrees) { 495 nPostRotate(native_instance, degrees); 496 return true; 497 } 498 499 /** 500 * Postconcats the matrix with the specified skew. M' = K(kx, ky, px, py) * M 501 */ postSkew(float kx, float ky, float px, float py)502 public boolean postSkew(float kx, float ky, float px, float py) { 503 nPostSkew(native_instance, kx, ky, px, py); 504 return true; 505 } 506 507 /** 508 * Postconcats the matrix with the specified skew. M' = K(kx, ky) * M 509 */ postSkew(float kx, float ky)510 public boolean postSkew(float kx, float ky) { 511 nPostSkew(native_instance, kx, ky); 512 return true; 513 } 514 515 /** 516 * Postconcats the matrix with the specified matrix. M' = other * M 517 */ postConcat(Matrix other)518 public boolean postConcat(Matrix other) { 519 nPostConcat(native_instance, other.native_instance); 520 return true; 521 } 522 523 /** 524 * Controlls how the src rect should align into the dst rect for setRectToRect(). 525 */ 526 public enum ScaleToFit { 527 /** 528 * Scale in X and Y independently, so that src matches dst exactly. This may change the 529 * aspect ratio of the src. 530 */ 531 FILL(0), 532 /** 533 * Compute a scale that will maintain the original src aspect ratio, but will also ensure 534 * that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. START 535 * aligns the result to the left and top edges of dst. 536 */ 537 START(1), 538 /** 539 * Compute a scale that will maintain the original src aspect ratio, but will also ensure 540 * that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. The 541 * result is centered inside dst. 542 */ 543 CENTER(2), 544 /** 545 * Compute a scale that will maintain the original src aspect ratio, but will also ensure 546 * that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. END 547 * aligns the result to the right and bottom edges of dst. 548 */ 549 END(3); 550 551 // the native values must match those in SkMatrix.h ScaleToFit(int nativeInt)552 ScaleToFit(int nativeInt) { 553 this.nativeInt = nativeInt; 554 } 555 556 final int nativeInt; 557 } 558 559 /** 560 * Set the matrix to the scale and translate values that map the source rectangle to the 561 * destination rectangle, returning true if the the result can be represented. 562 * 563 * @param src the source rectangle to map from. 564 * @param dst the destination rectangle to map to. 565 * @param stf the ScaleToFit option 566 * @return true if the matrix can be represented by the rectangle mapping. 567 */ setRectToRect(RectF src, RectF dst, ScaleToFit stf)568 public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf) { 569 if (dst == null || src == null) { 570 throw new NullPointerException(); 571 } 572 return nSetRectToRect(native_instance, src, dst, stf.nativeInt); 573 } 574 575 // private helper to perform range checks on arrays of "points" checkPointArrays(float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount)576 private static void checkPointArrays(float[] src, int srcIndex, 577 float[] dst, int dstIndex, 578 int pointCount) { 579 // check for too-small and too-big indices 580 int srcStop = srcIndex + (pointCount << 1); 581 int dstStop = dstIndex + (pointCount << 1); 582 if ((pointCount | srcIndex | dstIndex | srcStop | dstStop) < 0 || 583 srcStop > src.length || dstStop > dst.length) { 584 throw new ArrayIndexOutOfBoundsException(); 585 } 586 } 587 588 /** 589 * Set the matrix such that the specified src points would map to the specified dst points. The 590 * "points" are represented as an array of floats, order [x0, y0, x1, y1, ...], where each 591 * "point" is 2 float values. 592 * 593 * @param src The array of src [x,y] pairs (points) 594 * @param srcIndex Index of the first pair of src values 595 * @param dst The array of dst [x,y] pairs (points) 596 * @param dstIndex Index of the first pair of dst values 597 * @param pointCount The number of pairs/points to be used. Must be [0..4] 598 * @return true if the matrix was set to the specified transformation 599 */ setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount)600 public boolean setPolyToPoly(float[] src, int srcIndex, 601 float[] dst, int dstIndex, 602 int pointCount) { 603 if (pointCount > 4) { 604 throw new IllegalArgumentException(); 605 } 606 checkPointArrays(src, srcIndex, dst, dstIndex, pointCount); 607 return nSetPolyToPoly(native_instance, src, srcIndex, 608 dst, dstIndex, pointCount); 609 } 610 611 /** 612 * If this matrix can be inverted, return true and if inverse is not null, set inverse to be the 613 * inverse of this matrix. If this matrix cannot be inverted, ignore inverse and return false. 614 */ invert(Matrix inverse)615 public boolean invert(Matrix inverse) { 616 return nInvert(native_instance, inverse.native_instance); 617 } 618 619 /** 620 * Apply this matrix to the array of 2D points specified by src, and write the transformed 621 * points into the array of points specified by dst. The two arrays represent their "points" as 622 * pairs of floats [x, y]. 623 * 624 * @param dst The array of dst points (x,y pairs) 625 * @param dstIndex The index of the first [x,y] pair of dst floats 626 * @param src The array of src points (x,y pairs) 627 * @param srcIndex The index of the first [x,y] pair of src floats 628 * @param pointCount The number of points (x,y pairs) to transform 629 */ mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex, int pointCount)630 public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex, 631 int pointCount) { 632 checkPointArrays(src, srcIndex, dst, dstIndex, pointCount); 633 nMapPoints(native_instance, dst, dstIndex, src, srcIndex, 634 pointCount, true); 635 } 636 637 /** 638 * Apply this matrix to the array of 2D vectors specified by src, and write the transformed 639 * vectors into the array of vectors specified by dst. The two arrays represent their "vectors" 640 * as pairs of floats [x, y]. Note: this method does not apply the translation associated with 641 * the matrix. Use {@link Matrix#mapPoints(float[], int, float[], int, int)} if you want the 642 * translation to be applied. 643 * 644 * @param dst The array of dst vectors (x,y pairs) 645 * @param dstIndex The index of the first [x,y] pair of dst floats 646 * @param src The array of src vectors (x,y pairs) 647 * @param srcIndex The index of the first [x,y] pair of src floats 648 * @param vectorCount The number of vectors (x,y pairs) to transform 649 */ mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, int vectorCount)650 public void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, 651 int vectorCount) { 652 checkPointArrays(src, srcIndex, dst, dstIndex, vectorCount); 653 nMapPoints(native_instance, dst, dstIndex, src, srcIndex, 654 vectorCount, false); 655 } 656 657 /** 658 * Apply this matrix to the array of 2D points specified by src, and write the transformed 659 * points into the array of points specified by dst. The two arrays represent their "points" as 660 * pairs of floats [x, y]. 661 * 662 * @param dst The array of dst points (x,y pairs) 663 * @param src The array of src points (x,y pairs) 664 */ mapPoints(float[] dst, float[] src)665 public void mapPoints(float[] dst, float[] src) { 666 if (dst.length != src.length) { 667 throw new ArrayIndexOutOfBoundsException(); 668 } 669 mapPoints(dst, 0, src, 0, dst.length >> 1); 670 } 671 672 /** 673 * Apply this matrix to the array of 2D vectors specified by src, and write the transformed 674 * vectors into the array of vectors specified by dst. The two arrays represent their "vectors" 675 * as pairs of floats [x, y]. Note: this method does not apply the translation associated with 676 * the matrix. Use {@link Matrix#mapPoints(float[], float[])} if you want the translation to be 677 * applied. 678 * 679 * @param dst The array of dst vectors (x,y pairs) 680 * @param src The array of src vectors (x,y pairs) 681 */ mapVectors(float[] dst, float[] src)682 public void mapVectors(float[] dst, float[] src) { 683 if (dst.length != src.length) { 684 throw new ArrayIndexOutOfBoundsException(); 685 } 686 mapVectors(dst, 0, src, 0, dst.length >> 1); 687 } 688 689 /** 690 * Apply this matrix to the array of 2D points, and write the transformed points back into the 691 * array 692 * 693 * @param pts The array [x0, y0, x1, y1, ...] of points to transform. 694 */ mapPoints(float[] pts)695 public void mapPoints(float[] pts) { 696 mapPoints(pts, 0, pts, 0, pts.length >> 1); 697 } 698 699 /** 700 * Apply this matrix to the array of 2D vectors, and write the transformed vectors back into the 701 * array. Note: this method does not apply the translation associated with the matrix. Use 702 * {@link Matrix#mapPoints(float[])} if you want the translation to be applied. 703 * 704 * @param vecs The array [x0, y0, x1, y1, ...] of vectors to transform. 705 */ mapVectors(float[] vecs)706 public void mapVectors(float[] vecs) { 707 mapVectors(vecs, 0, vecs, 0, vecs.length >> 1); 708 } 709 710 /** 711 * Apply this matrix to the src rectangle, and write the transformed rectangle into dst. This is 712 * accomplished by transforming the 4 corners of src, and then setting dst to the bounds of 713 * those points. 714 * 715 * @param dst Where the transformed rectangle is written. 716 * @param src The original rectangle to be transformed. 717 * @return the result of calling rectStaysRect() 718 */ mapRect(RectF dst, RectF src)719 public boolean mapRect(RectF dst, RectF src) { 720 if (dst == null || src == null) { 721 throw new NullPointerException(); 722 } 723 return nMapRect(native_instance, dst, src); 724 } 725 726 /** 727 * Apply this matrix to the rectangle, and write the transformed rectangle back into it. This is 728 * accomplished by transforming the 4 corners of rect, and then setting it to the bounds of 729 * those points 730 * 731 * @param rect The rectangle to transform. 732 * @return the result of calling rectStaysRect() 733 */ mapRect(RectF rect)734 public boolean mapRect(RectF rect) { 735 return mapRect(rect, rect); 736 } 737 738 /** 739 * Return the mean radius of a circle after it has been mapped by this matrix. NOTE: in 740 * perspective this value assumes the circle has its center at the origin. 741 */ mapRadius(float radius)742 public float mapRadius(float radius) { 743 return nMapRadius(native_instance, radius); 744 } 745 746 /** 747 * Copy 9 values from the matrix into the array. 748 */ getValues(float[] values)749 public void getValues(float[] values) { 750 if (values.length < 9) { 751 throw new ArrayIndexOutOfBoundsException(); 752 } 753 nGetValues(native_instance, values); 754 } 755 756 /** 757 * Copy 9 values from the array into the matrix. Depending on the implementation of Matrix, 758 * these may be transformed into 16.16 integers in the Matrix, such that a subsequent call to 759 * getValues() will not yield exactly the same values. 760 */ setValues(float[] values)761 public void setValues(float[] values) { 762 if (values.length < 9) { 763 throw new ArrayIndexOutOfBoundsException(); 764 } 765 nSetValues(native_instance, values); 766 } 767 768 @Override toString()769 public String toString() { 770 StringBuilder sb = new StringBuilder(64); 771 sb.append("Matrix{"); 772 toShortString(sb); 773 sb.append('}'); 774 return sb.toString(); 775 776 } 777 toShortString()778 public String toShortString() { 779 StringBuilder sb = new StringBuilder(64); 780 toShortString(sb); 781 return sb.toString(); 782 } 783 784 /** 785 * @hide 786 */ toShortString(StringBuilder sb)787 public void toShortString(StringBuilder sb) { 788 float[] values = new float[9]; 789 getValues(values); 790 sb.append('['); 791 sb.append(values[0]); 792 sb.append(", "); 793 sb.append(values[1]); 794 sb.append(", "); 795 sb.append(values[2]); 796 sb.append("]["); 797 sb.append(values[3]); 798 sb.append(", "); 799 sb.append(values[4]); 800 sb.append(", "); 801 sb.append(values[5]); 802 sb.append("]["); 803 sb.append(values[6]); 804 sb.append(", "); 805 sb.append(values[7]); 806 sb.append(", "); 807 sb.append(values[8]); 808 sb.append(']'); 809 } 810 811 /** 812 * Print short string, to optimize dumping. 813 * 814 * @hide 815 */ printShortString(PrintWriter pw)816 public void printShortString(PrintWriter pw) { 817 float[] values = new float[9]; 818 getValues(values); 819 pw.print('['); 820 pw.print(values[0]); 821 pw.print(", "); 822 pw.print(values[1]); 823 pw.print(", "); 824 pw.print(values[2]); 825 pw.print("]["); 826 pw.print(values[3]); 827 pw.print(", "); 828 pw.print(values[4]); 829 pw.print(", "); 830 pw.print(values[5]); 831 pw.print("]["); 832 pw.print(values[6]); 833 pw.print(", "); 834 pw.print(values[7]); 835 pw.print(", "); 836 pw.print(values[8]); 837 pw.print(']'); 838 839 } 840 841 /** @hide */ ni()842 public final long ni() { 843 return native_instance; 844 } 845 846 // ------------------ Regular JNI ------------------------ 847 nCreate(long nSrc_or_zero)848 private static native long nCreate(long nSrc_or_zero); nGetNativeFinalizer()849 private static native long nGetNativeFinalizer(); 850 851 852 // ------------------ Fast JNI ------------------------ 853 854 @FastNative nSetRectToRect(long nObject, RectF src, RectF dst, int stf)855 private static native boolean nSetRectToRect(long nObject, 856 RectF src, RectF dst, int stf); 857 @FastNative nSetPolyToPoly(long nObject, float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount)858 private static native boolean nSetPolyToPoly(long nObject, 859 float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount); 860 @FastNative nMapPoints(long nObject, float[] dst, int dstIndex, float[] src, int srcIndex, int ptCount, boolean isPts)861 private static native void nMapPoints(long nObject, 862 float[] dst, int dstIndex, float[] src, int srcIndex, 863 int ptCount, boolean isPts); 864 @FastNative nMapRect(long nObject, RectF dst, RectF src)865 private static native boolean nMapRect(long nObject, RectF dst, RectF src); 866 @FastNative nGetValues(long nObject, float[] values)867 private static native void nGetValues(long nObject, float[] values); 868 @FastNative nSetValues(long nObject, float[] values)869 private static native void nSetValues(long nObject, float[] values); 870 871 872 // ------------------ Critical JNI ------------------------ 873 874 @CriticalNative nIsIdentity(long nObject)875 private static native boolean nIsIdentity(long nObject); 876 @CriticalNative nIsAffine(long nObject)877 private static native boolean nIsAffine(long nObject); 878 @CriticalNative nRectStaysRect(long nObject)879 private static native boolean nRectStaysRect(long nObject); 880 @CriticalNative nReset(long nObject)881 private static native void nReset(long nObject); 882 @CriticalNative nSet(long nObject, long nOther)883 private static native void nSet(long nObject, long nOther); 884 @CriticalNative nSetTranslate(long nObject, float dx, float dy)885 private static native void nSetTranslate(long nObject, float dx, float dy); 886 @CriticalNative nSetScale(long nObject, float sx, float sy, float px, float py)887 private static native void nSetScale(long nObject, float sx, float sy, float px, float py); 888 @CriticalNative nSetScale(long nObject, float sx, float sy)889 private static native void nSetScale(long nObject, float sx, float sy); 890 @CriticalNative nSetRotate(long nObject, float degrees, float px, float py)891 private static native void nSetRotate(long nObject, float degrees, float px, float py); 892 @CriticalNative nSetRotate(long nObject, float degrees)893 private static native void nSetRotate(long nObject, float degrees); 894 @CriticalNative nSetSinCos(long nObject, float sinValue, float cosValue, float px, float py)895 private static native void nSetSinCos(long nObject, float sinValue, float cosValue, 896 float px, float py); 897 @CriticalNative nSetSinCos(long nObject, float sinValue, float cosValue)898 private static native void nSetSinCos(long nObject, float sinValue, float cosValue); 899 @CriticalNative nSetSkew(long nObject, float kx, float ky, float px, float py)900 private static native void nSetSkew(long nObject, float kx, float ky, float px, float py); 901 @CriticalNative nSetSkew(long nObject, float kx, float ky)902 private static native void nSetSkew(long nObject, float kx, float ky); 903 @CriticalNative nSetConcat(long nObject, long nA, long nB)904 private static native void nSetConcat(long nObject, long nA, long nB); 905 @CriticalNative nPreTranslate(long nObject, float dx, float dy)906 private static native void nPreTranslate(long nObject, float dx, float dy); 907 @CriticalNative nPreScale(long nObject, float sx, float sy, float px, float py)908 private static native void nPreScale(long nObject, float sx, float sy, float px, float py); 909 @CriticalNative nPreScale(long nObject, float sx, float sy)910 private static native void nPreScale(long nObject, float sx, float sy); 911 @CriticalNative nPreRotate(long nObject, float degrees, float px, float py)912 private static native void nPreRotate(long nObject, float degrees, float px, float py); 913 @CriticalNative nPreRotate(long nObject, float degrees)914 private static native void nPreRotate(long nObject, float degrees); 915 @CriticalNative nPreSkew(long nObject, float kx, float ky, float px, float py)916 private static native void nPreSkew(long nObject, float kx, float ky, float px, float py); 917 @CriticalNative nPreSkew(long nObject, float kx, float ky)918 private static native void nPreSkew(long nObject, float kx, float ky); 919 @CriticalNative nPreConcat(long nObject, long nOther_matrix)920 private static native void nPreConcat(long nObject, long nOther_matrix); 921 @CriticalNative nPostTranslate(long nObject, float dx, float dy)922 private static native void nPostTranslate(long nObject, float dx, float dy); 923 @CriticalNative nPostScale(long nObject, float sx, float sy, float px, float py)924 private static native void nPostScale(long nObject, float sx, float sy, float px, float py); 925 @CriticalNative nPostScale(long nObject, float sx, float sy)926 private static native void nPostScale(long nObject, float sx, float sy); 927 @CriticalNative nPostRotate(long nObject, float degrees, float px, float py)928 private static native void nPostRotate(long nObject, float degrees, float px, float py); 929 @CriticalNative nPostRotate(long nObject, float degrees)930 private static native void nPostRotate(long nObject, float degrees); 931 @CriticalNative nPostSkew(long nObject, float kx, float ky, float px, float py)932 private static native void nPostSkew(long nObject, float kx, float ky, float px, float py); 933 @CriticalNative nPostSkew(long nObject, float kx, float ky)934 private static native void nPostSkew(long nObject, float kx, float ky); 935 @CriticalNative nPostConcat(long nObject, long nOther_matrix)936 private static native void nPostConcat(long nObject, long nOther_matrix); 937 @CriticalNative nInvert(long nObject, long nInverse)938 private static native boolean nInvert(long nObject, long nInverse); 939 @CriticalNative nMapRadius(long nObject, float radius)940 private static native float nMapRadius(long nObject, float radius); 941 @CriticalNative nEquals(long nA, long nB)942 private static native boolean nEquals(long nA, long nB); 943 } 944