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