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