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