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