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