• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 
20 import com.android.ide.common.rendering.api.LayoutLog;
21 import com.android.layoutlib.bridge.Bridge;
22 import com.android.layoutlib.bridge.impl.DelegateManager;
23 import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
24 
25 import android.graphics.Matrix.ScaleToFit;
26 
27 import java.awt.geom.AffineTransform;
28 import java.awt.geom.NoninvertibleTransformException;
29 
30 /**
31  * Delegate implementing the native methods of android.graphics.Matrix
32  *
33  * Through the layoutlib_create tool, the original native methods of Matrix have been replaced
34  * by calls to methods of the same name in this delegate class.
35  *
36  * This class behaves like the original native implementation, but in Java, keeping previously
37  * native data into its own objects and mapping them to int that are sent back and forth between
38  * it and the original Matrix class.
39  *
40  * @see DelegateManager
41  *
42  */
43 public final class Matrix_Delegate {
44 
45     private final static int MATRIX_SIZE = 9;
46 
47     // ---- delegate manager ----
48     private static final DelegateManager<Matrix_Delegate> sManager =
49             new DelegateManager<Matrix_Delegate>(Matrix_Delegate.class);
50 
51     // ---- delegate data ----
52     private float mValues[] = new float[MATRIX_SIZE];
53 
54     // ---- Public Helper methods ----
55 
getDelegate(int native_instance)56     public static Matrix_Delegate getDelegate(int native_instance) {
57         return sManager.getDelegate(native_instance);
58     }
59 
60     /**
61      * Returns an {@link AffineTransform} matching the given Matrix.
62      */
getAffineTransform(Matrix m)63     public static AffineTransform getAffineTransform(Matrix m) {
64         Matrix_Delegate delegate = sManager.getDelegate(m.native_instance);
65         if (delegate == null) {
66             return null;
67         }
68 
69         return delegate.getAffineTransform();
70     }
71 
hasPerspective(Matrix m)72     public static boolean hasPerspective(Matrix m) {
73         Matrix_Delegate delegate = sManager.getDelegate(m.native_instance);
74         if (delegate == null) {
75             return false;
76         }
77 
78         return delegate.hasPerspective();
79     }
80 
81     /**
82      * Sets the content of the matrix with the content of another matrix.
83      */
set(Matrix_Delegate matrix)84     public void set(Matrix_Delegate matrix) {
85         System.arraycopy(matrix.mValues, 0, mValues, 0, MATRIX_SIZE);
86     }
87 
88     /**
89      * Sets the content of the matrix with the content of another matrix represented as an array
90      * of values.
91      */
set(float[] values)92     public void set(float[] values) {
93         System.arraycopy(values, 0, mValues, 0, MATRIX_SIZE);
94     }
95 
96     /**
97      * Resets the matrix to be the identity matrix.
98      */
reset()99     public void reset() {
100         reset(mValues);
101     }
102 
103     /**
104      * Returns whether or not the matrix is identity.
105      */
isIdentity()106     public boolean isIdentity() {
107         for (int i = 0, k = 0; i < 3; i++) {
108             for (int j = 0; j < 3; j++, k++) {
109                 if (mValues[k] != ((i==j) ? 1 : 0)) {
110                     return false;
111                 }
112             }
113         }
114 
115         return true;
116     }
117 
makeValues(AffineTransform matrix)118     public static float[] makeValues(AffineTransform matrix) {
119         float[] values = new float[MATRIX_SIZE];
120         values[0] = (float) matrix.getScaleX();
121         values[1] = (float) matrix.getShearX();
122         values[2] = (float) matrix.getTranslateX();
123         values[3] = (float) matrix.getShearY();
124         values[4] = (float) matrix.getScaleY();
125         values[5] = (float) matrix.getTranslateY();
126         values[6] = 0.f;
127         values[7] = 0.f;
128         values[8] = 1.f;
129 
130         return values;
131     }
132 
make(AffineTransform matrix)133     public static Matrix_Delegate make(AffineTransform matrix) {
134         return new Matrix_Delegate(makeValues(matrix));
135     }
136 
mapRect(RectF dst, RectF src)137     public boolean mapRect(RectF dst, RectF src) {
138         // array with 4 corners
139         float[] corners = new float[] {
140                 src.left, src.top,
141                 src.right, src.top,
142                 src.right, src.bottom,
143                 src.left, src.bottom,
144         };
145 
146         // apply the transform to them.
147         mapPoints(corners);
148 
149         // now put the result in the rect. We take the min/max of Xs and min/max of Ys
150         dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6]));
151         dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6]));
152 
153         dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7]));
154         dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7]));
155 
156 
157         return (computeTypeMask() & kRectStaysRect_Mask) != 0;
158     }
159 
160 
161     /**
162      * Returns an {@link AffineTransform} matching the matrix.
163      */
getAffineTransform()164     public AffineTransform getAffineTransform() {
165         return getAffineTransform(mValues);
166     }
167 
hasPerspective()168     public boolean hasPerspective() {
169         return (mValues[6] != 0 || mValues[7] != 0 || mValues[8] != 1);
170     }
171 
172 
173 
174     // ---- native methods ----
175 
176     @LayoutlibDelegate
native_create(int native_src_or_zero)177     /*package*/ static int native_create(int native_src_or_zero) {
178         // create the delegate
179         Matrix_Delegate newDelegate = new Matrix_Delegate();
180 
181         // copy from values if needed.
182         if (native_src_or_zero > 0) {
183             Matrix_Delegate oldDelegate = sManager.getDelegate(native_src_or_zero);
184             if (oldDelegate != null) {
185                 System.arraycopy(
186                         oldDelegate.mValues, 0,
187                         newDelegate.mValues, 0,
188                         MATRIX_SIZE);
189             }
190         }
191 
192         return sManager.addNewDelegate(newDelegate);
193     }
194 
195     @LayoutlibDelegate
native_isIdentity(int native_object)196     /*package*/ static boolean native_isIdentity(int native_object) {
197         Matrix_Delegate d = sManager.getDelegate(native_object);
198         if (d == null) {
199             return false;
200         }
201 
202         return d.isIdentity();
203     }
204 
205     @LayoutlibDelegate
native_rectStaysRect(int native_object)206     /*package*/ static boolean native_rectStaysRect(int native_object) {
207         Matrix_Delegate d = sManager.getDelegate(native_object);
208         if (d == null) {
209             return true;
210         }
211 
212         return (d.computeTypeMask() & kRectStaysRect_Mask) != 0;
213     }
214 
215     @LayoutlibDelegate
native_reset(int native_object)216     /*package*/ static void native_reset(int native_object) {
217         Matrix_Delegate d = sManager.getDelegate(native_object);
218         if (d == null) {
219             return;
220         }
221 
222         reset(d.mValues);
223     }
224 
225     @LayoutlibDelegate
native_set(int native_object, int other)226     /*package*/ static void native_set(int native_object, int other) {
227         Matrix_Delegate d = sManager.getDelegate(native_object);
228         if (d == null) {
229             return;
230         }
231 
232         Matrix_Delegate src = sManager.getDelegate(other);
233         if (src == null) {
234             return;
235         }
236 
237         System.arraycopy(src.mValues, 0, d.mValues, 0, MATRIX_SIZE);
238     }
239 
240     @LayoutlibDelegate
native_setTranslate(int native_object, float dx, float dy)241     /*package*/ static void native_setTranslate(int native_object, float dx, float dy) {
242         Matrix_Delegate d = sManager.getDelegate(native_object);
243         if (d == null) {
244             return;
245         }
246 
247         setTranslate(d.mValues, dx, dy);
248     }
249 
250     @LayoutlibDelegate
native_setScale(int native_object, float sx, float sy, float px, float py)251     /*package*/ static void native_setScale(int native_object, float sx, float sy,
252             float px, float py) {
253         Matrix_Delegate d = sManager.getDelegate(native_object);
254         if (d == null) {
255             return;
256         }
257 
258         d.mValues = getScale(sx, sy, px, py);
259     }
260 
261     @LayoutlibDelegate
native_setScale(int native_object, float sx, float sy)262     /*package*/ static void native_setScale(int native_object, float sx, float sy) {
263         Matrix_Delegate d = sManager.getDelegate(native_object);
264         if (d == null) {
265             return;
266         }
267 
268         d.mValues[0] = sx;
269         d.mValues[1] = 0;
270         d.mValues[2] = 0;
271         d.mValues[3] = 0;
272         d.mValues[4] = sy;
273         d.mValues[5] = 0;
274         d.mValues[6] = 0;
275         d.mValues[7] = 0;
276         d.mValues[8] = 1;
277     }
278 
279     @LayoutlibDelegate
native_setRotate(int native_object, float degrees, float px, float py)280     /*package*/ static void native_setRotate(int native_object, float degrees, float px, float py) {
281         Matrix_Delegate d = sManager.getDelegate(native_object);
282         if (d == null) {
283             return;
284         }
285 
286         d.mValues = getRotate(degrees, px, py);
287     }
288 
289     @LayoutlibDelegate
native_setRotate(int native_object, float degrees)290     /*package*/ static void native_setRotate(int native_object, float degrees) {
291         Matrix_Delegate d = sManager.getDelegate(native_object);
292         if (d == null) {
293             return;
294         }
295 
296         setRotate(d.mValues, degrees);
297     }
298 
299     @LayoutlibDelegate
native_setSinCos(int native_object, float sinValue, float cosValue, float px, float py)300     /*package*/ static void native_setSinCos(int native_object, float sinValue, float cosValue,
301             float px, float py) {
302         Matrix_Delegate d = sManager.getDelegate(native_object);
303         if (d == null) {
304             return;
305         }
306 
307         // TODO: do it in one pass
308 
309         // translate so that the pivot is in 0,0
310         setTranslate(d.mValues, -px, -py);
311 
312         // scale
313         d.postTransform(getRotate(sinValue, cosValue));
314         // translate back the pivot
315         d.postTransform(getTranslate(px, py));
316     }
317 
318     @LayoutlibDelegate
native_setSinCos(int native_object, float sinValue, float cosValue)319     /*package*/ static void native_setSinCos(int native_object, float sinValue, float cosValue) {
320         Matrix_Delegate d = sManager.getDelegate(native_object);
321         if (d == null) {
322             return;
323         }
324 
325         setRotate(d.mValues, sinValue, cosValue);
326     }
327 
328     @LayoutlibDelegate
native_setSkew(int native_object, float kx, float ky, float px, float py)329     /*package*/ static void native_setSkew(int native_object, float kx, float ky,
330             float px, float py) {
331         Matrix_Delegate d = sManager.getDelegate(native_object);
332         if (d == null) {
333             return;
334         }
335 
336         d.mValues = getSkew(kx, ky, px, py);
337     }
338 
339     @LayoutlibDelegate
native_setSkew(int native_object, float kx, float ky)340     /*package*/ static void native_setSkew(int native_object, float kx, float ky) {
341         Matrix_Delegate d = sManager.getDelegate(native_object);
342         if (d == null) {
343             return;
344         }
345 
346         d.mValues[0] = 1;
347         d.mValues[1] = kx;
348         d.mValues[2] = -0;
349         d.mValues[3] = ky;
350         d.mValues[4] = 1;
351         d.mValues[5] = 0;
352         d.mValues[6] = 0;
353         d.mValues[7] = 0;
354         d.mValues[8] = 1;
355     }
356 
357     @LayoutlibDelegate
native_setConcat(int native_object, int a, int b)358     /*package*/ static boolean native_setConcat(int native_object, int a, int b) {
359         if (a == native_object) {
360             return native_preConcat(native_object, b);
361         } else if (b == native_object) {
362             return native_postConcat(native_object, a);
363         }
364 
365         Matrix_Delegate d = sManager.getDelegate(native_object);
366         if (d == null) {
367             return false;
368         }
369 
370         Matrix_Delegate a_mtx = sManager.getDelegate(a);
371         if (a_mtx == null) {
372             return false;
373         }
374 
375         Matrix_Delegate b_mtx = sManager.getDelegate(b);
376         if (b_mtx == null) {
377             return false;
378         }
379 
380         multiply(d.mValues, a_mtx.mValues, b_mtx.mValues);
381 
382         return true;
383     }
384 
385     @LayoutlibDelegate
native_preTranslate(int native_object, float dx, float dy)386     /*package*/ static boolean native_preTranslate(int native_object, float dx, float dy) {
387         Matrix_Delegate d = sManager.getDelegate(native_object);
388         if (d == null) {
389             return false;
390         }
391 
392         d.preTransform(getTranslate(dx, dy));
393         return true;
394     }
395 
396     @LayoutlibDelegate
native_preScale(int native_object, float sx, float sy, float px, float py)397     /*package*/ static boolean native_preScale(int native_object, float sx, float sy,
398             float px, float py) {
399         Matrix_Delegate d = sManager.getDelegate(native_object);
400         if (d == null) {
401             return false;
402         }
403 
404         d.preTransform(getScale(sx, sy, px, py));
405         return true;
406     }
407 
408     @LayoutlibDelegate
native_preScale(int native_object, float sx, float sy)409     /*package*/ static boolean native_preScale(int native_object, float sx, float sy) {
410         Matrix_Delegate d = sManager.getDelegate(native_object);
411         if (d == null) {
412             return false;
413         }
414 
415         d.preTransform(getScale(sx, sy));
416         return true;
417     }
418 
419     @LayoutlibDelegate
native_preRotate(int native_object, float degrees, float px, float py)420     /*package*/ static boolean native_preRotate(int native_object, float degrees,
421             float px, float py) {
422         Matrix_Delegate d = sManager.getDelegate(native_object);
423         if (d == null) {
424             return false;
425         }
426 
427         d.preTransform(getRotate(degrees, px, py));
428         return true;
429     }
430 
431     @LayoutlibDelegate
native_preRotate(int native_object, float degrees)432     /*package*/ static boolean native_preRotate(int native_object, float degrees) {
433         Matrix_Delegate d = sManager.getDelegate(native_object);
434         if (d == null) {
435             return false;
436         }
437 
438         double rad = Math.toRadians(degrees);
439         float sin = (float)Math.sin(rad);
440         float cos = (float)Math.cos(rad);
441 
442         d.preTransform(getRotate(sin, cos));
443         return true;
444     }
445 
446     @LayoutlibDelegate
native_preSkew(int native_object, float kx, float ky, float px, float py)447     /*package*/ static boolean native_preSkew(int native_object, float kx, float ky,
448             float px, float py) {
449         Matrix_Delegate d = sManager.getDelegate(native_object);
450         if (d == null) {
451             return false;
452         }
453 
454         d.preTransform(getSkew(kx, ky, px, py));
455         return true;
456     }
457 
458     @LayoutlibDelegate
native_preSkew(int native_object, float kx, float ky)459     /*package*/ static boolean native_preSkew(int native_object, float kx, float ky) {
460         Matrix_Delegate d = sManager.getDelegate(native_object);
461         if (d == null) {
462             return false;
463         }
464 
465         d.preTransform(getSkew(kx, ky));
466         return true;
467     }
468 
469     @LayoutlibDelegate
native_preConcat(int native_object, int other_matrix)470     /*package*/ static boolean native_preConcat(int native_object, int other_matrix) {
471         Matrix_Delegate d = sManager.getDelegate(native_object);
472         if (d == null) {
473             return false;
474         }
475 
476         Matrix_Delegate other = sManager.getDelegate(other_matrix);
477         if (other == null) {
478             return false;
479         }
480 
481         d.preTransform(other.mValues);
482         return true;
483     }
484 
485     @LayoutlibDelegate
native_postTranslate(int native_object, float dx, float dy)486     /*package*/ static boolean native_postTranslate(int native_object, float dx, float dy) {
487         Matrix_Delegate d = sManager.getDelegate(native_object);
488         if (d == null) {
489             return false;
490         }
491 
492         d.postTransform(getTranslate(dx, dy));
493         return true;
494     }
495 
496     @LayoutlibDelegate
native_postScale(int native_object, float sx, float sy, float px, float py)497     /*package*/ static boolean native_postScale(int native_object, float sx, float sy,
498             float px, float py) {
499         Matrix_Delegate d = sManager.getDelegate(native_object);
500         if (d == null) {
501             return false;
502         }
503 
504         d.postTransform(getScale(sx, sy, px, py));
505         return true;
506     }
507 
508     @LayoutlibDelegate
native_postScale(int native_object, float sx, float sy)509     /*package*/ static boolean native_postScale(int native_object, float sx, float sy) {
510         Matrix_Delegate d = sManager.getDelegate(native_object);
511         if (d == null) {
512             return false;
513         }
514 
515         d.postTransform(getScale(sx, sy));
516         return true;
517     }
518 
519     @LayoutlibDelegate
native_postRotate(int native_object, float degrees, float px, float py)520     /*package*/ static boolean native_postRotate(int native_object, float degrees,
521             float px, float py) {
522         Matrix_Delegate d = sManager.getDelegate(native_object);
523         if (d == null) {
524             return false;
525         }
526 
527         d.postTransform(getRotate(degrees, px, py));
528         return true;
529     }
530 
531     @LayoutlibDelegate
native_postRotate(int native_object, float degrees)532     /*package*/ static boolean native_postRotate(int native_object, float degrees) {
533         Matrix_Delegate d = sManager.getDelegate(native_object);
534         if (d == null) {
535             return false;
536         }
537 
538         d.postTransform(getRotate(degrees));
539         return true;
540     }
541 
542     @LayoutlibDelegate
native_postSkew(int native_object, float kx, float ky, float px, float py)543     /*package*/ static boolean native_postSkew(int native_object, float kx, float ky,
544             float px, float py) {
545         Matrix_Delegate d = sManager.getDelegate(native_object);
546         if (d == null) {
547             return false;
548         }
549 
550         d.postTransform(getSkew(kx, ky, px, py));
551         return true;
552     }
553 
554     @LayoutlibDelegate
native_postSkew(int native_object, float kx, float ky)555     /*package*/ static boolean native_postSkew(int native_object, float kx, float ky) {
556         Matrix_Delegate d = sManager.getDelegate(native_object);
557         if (d == null) {
558             return false;
559         }
560 
561         d.postTransform(getSkew(kx, ky));
562         return true;
563     }
564 
565     @LayoutlibDelegate
native_postConcat(int native_object, int other_matrix)566     /*package*/ static boolean native_postConcat(int native_object, int other_matrix) {
567         Matrix_Delegate d = sManager.getDelegate(native_object);
568         if (d == null) {
569             return false;
570         }
571 
572         Matrix_Delegate other = sManager.getDelegate(other_matrix);
573         if (other == null) {
574             return false;
575         }
576 
577         d.postTransform(other.mValues);
578         return true;
579     }
580 
581     @LayoutlibDelegate
native_setRectToRect(int native_object, RectF src, RectF dst, int stf)582     /*package*/ static boolean native_setRectToRect(int native_object, RectF src,
583             RectF dst, int stf) {
584         Matrix_Delegate d = sManager.getDelegate(native_object);
585         if (d == null) {
586             return false;
587         }
588 
589         if (src.isEmpty()) {
590             reset(d.mValues);
591             return false;
592         }
593 
594         if (dst.isEmpty()) {
595             d.mValues[0] = d.mValues[1] = d.mValues[2] = d.mValues[3] = d.mValues[4] = d.mValues[5]
596                = d.mValues[6] = d.mValues[7] = 0;
597             d.mValues[8] = 1;
598         } else {
599             float    tx, sx = dst.width() / src.width();
600             float    ty, sy = dst.height() / src.height();
601             boolean  xLarger = false;
602 
603             if (stf != ScaleToFit.FILL.nativeInt) {
604                 if (sx > sy) {
605                     xLarger = true;
606                     sx = sy;
607                 } else {
608                     sy = sx;
609                 }
610             }
611 
612             tx = dst.left - src.left * sx;
613             ty = dst.top - src.top * sy;
614             if (stf == ScaleToFit.CENTER.nativeInt || stf == ScaleToFit.END.nativeInt) {
615                 float diff;
616 
617                 if (xLarger) {
618                     diff = dst.width() - src.width() * sy;
619                 } else {
620                     diff = dst.height() - src.height() * sy;
621                 }
622 
623                 if (stf == ScaleToFit.CENTER.nativeInt) {
624                     diff = diff / 2;
625                 }
626 
627                 if (xLarger) {
628                     tx += diff;
629                 } else {
630                     ty += diff;
631                 }
632             }
633 
634             d.mValues[0] = sx;
635             d.mValues[4] = sy;
636             d.mValues[2] = tx;
637             d.mValues[5] = ty;
638             d.mValues[1]  = d.mValues[3] = d.mValues[6] = d.mValues[7] = 0;
639 
640         }
641         // shared cleanup
642         d.mValues[8] = 1;
643         return true;
644     }
645 
646     @LayoutlibDelegate
native_setPolyToPoly(int native_object, float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount)647     /*package*/ static boolean native_setPolyToPoly(int native_object, float[] src, int srcIndex,
648             float[] dst, int dstIndex, int pointCount) {
649         // FIXME
650         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
651                 "Matrix.setPolyToPoly is not supported.",
652                 null, null /*data*/);
653         return false;
654     }
655 
656     @LayoutlibDelegate
native_invert(int native_object, int inverse)657     /*package*/ static boolean native_invert(int native_object, int inverse) {
658         Matrix_Delegate d = sManager.getDelegate(native_object);
659         if (d == null) {
660             return false;
661         }
662 
663         Matrix_Delegate inv_mtx = sManager.getDelegate(inverse);
664         if (inv_mtx == null) {
665             return false;
666         }
667 
668         try {
669             AffineTransform affineTransform = d.getAffineTransform();
670             AffineTransform inverseTransform = affineTransform.createInverse();
671             inv_mtx.mValues[0] = (float)inverseTransform.getScaleX();
672             inv_mtx.mValues[1] = (float)inverseTransform.getShearX();
673             inv_mtx.mValues[2] = (float)inverseTransform.getTranslateX();
674             inv_mtx.mValues[3] = (float)inverseTransform.getScaleX();
675             inv_mtx.mValues[4] = (float)inverseTransform.getShearY();
676             inv_mtx.mValues[5] = (float)inverseTransform.getTranslateY();
677 
678             return true;
679         } catch (NoninvertibleTransformException e) {
680             return false;
681         }
682     }
683 
684     @LayoutlibDelegate
native_mapPoints(int native_object, float[] dst, int dstIndex, float[] src, int srcIndex, int ptCount, boolean isPts)685     /*package*/ static void native_mapPoints(int native_object, float[] dst, int dstIndex,
686             float[] src, int srcIndex, int ptCount, boolean isPts) {
687         Matrix_Delegate d = sManager.getDelegate(native_object);
688         if (d == null) {
689             return;
690         }
691 
692         if (isPts) {
693             d.mapPoints(dst, dstIndex, src, srcIndex, ptCount);
694         } else {
695             d.mapVectors(dst, dstIndex, src, srcIndex, ptCount);
696         }
697     }
698 
699     @LayoutlibDelegate
native_mapRect(int native_object, RectF dst, RectF src)700     /*package*/ static boolean native_mapRect(int native_object, RectF dst, RectF src) {
701         Matrix_Delegate d = sManager.getDelegate(native_object);
702         if (d == null) {
703             return false;
704         }
705 
706         return d.mapRect(dst, src);
707     }
708 
709     @LayoutlibDelegate
native_mapRadius(int native_object, float radius)710     /*package*/ static float native_mapRadius(int native_object, float radius) {
711         Matrix_Delegate d = sManager.getDelegate(native_object);
712         if (d == null) {
713             return 0.f;
714         }
715 
716         float[] src = new float[] { radius, 0.f, 0.f, radius };
717         d.mapVectors(src, 0, src, 0, 2);
718 
719         float l1 = getPointLength(src, 0);
720         float l2 = getPointLength(src, 2);
721 
722         return (float) Math.sqrt(l1 * l2);
723     }
724 
725     @LayoutlibDelegate
native_getValues(int native_object, float[] values)726     /*package*/ static void native_getValues(int native_object, float[] values) {
727         Matrix_Delegate d = sManager.getDelegate(native_object);
728         if (d == null) {
729             return;
730         }
731 
732         System.arraycopy(d.mValues, 0, d.mValues, 0, MATRIX_SIZE);
733     }
734 
735     @LayoutlibDelegate
native_setValues(int native_object, float[] values)736     /*package*/ static void native_setValues(int native_object, float[] values) {
737         Matrix_Delegate d = sManager.getDelegate(native_object);
738         if (d == null) {
739             return;
740         }
741 
742         System.arraycopy(values, 0, d.mValues, 0, MATRIX_SIZE);
743     }
744 
745     @LayoutlibDelegate
native_equals(int native_a, int native_b)746     /*package*/ static boolean native_equals(int native_a, int native_b) {
747         Matrix_Delegate a = sManager.getDelegate(native_a);
748         if (a == null) {
749             return false;
750         }
751 
752         Matrix_Delegate b = sManager.getDelegate(native_b);
753         if (b == null) {
754             return false;
755         }
756 
757         for (int i = 0 ; i < MATRIX_SIZE ; i++) {
758             if (a.mValues[i] != b.mValues[i]) {
759                 return false;
760             }
761         }
762 
763         return true;
764     }
765 
766     @LayoutlibDelegate
finalizer(int native_instance)767     /*package*/ static void finalizer(int native_instance) {
768         sManager.removeJavaReferenceFor(native_instance);
769     }
770 
771     // ---- Private helper methods ----
772 
getAffineTransform(float[] matrix)773     /*package*/ static AffineTransform getAffineTransform(float[] matrix) {
774         // the AffineTransform constructor takes the value in a different order
775         // for a matrix [ 0 1 2 ]
776         //              [ 3 4 5 ]
777         // the order is 0, 3, 1, 4, 2, 5...
778         return new AffineTransform(
779                 matrix[0], matrix[3], matrix[1],
780                 matrix[4], matrix[2], matrix[5]);
781     }
782 
783     /**
784      * Reset a matrix to the identity
785      */
reset(float[] mtx)786     private static void reset(float[] mtx) {
787         for (int i = 0, k = 0; i < 3; i++) {
788             for (int j = 0; j < 3; j++, k++) {
789                 mtx[k] = ((i==j) ? 1 : 0);
790             }
791         }
792     }
793 
794     @SuppressWarnings("unused")
795     private final static int kIdentity_Mask      = 0;
796     private final static int kTranslate_Mask     = 0x01;  //!< set if the matrix has translation
797     private final static int kScale_Mask         = 0x02;  //!< set if the matrix has X or Y scale
798     private final static int kAffine_Mask        = 0x04;  //!< set if the matrix skews or rotates
799     private final static int kPerspective_Mask   = 0x08;  //!< set if the matrix is in perspective
800     private final static int kRectStaysRect_Mask = 0x10;
801     @SuppressWarnings("unused")
802     private final static int kUnknown_Mask       = 0x80;
803 
804     @SuppressWarnings("unused")
805     private final static int kAllMasks           = kTranslate_Mask |
806                                                    kScale_Mask |
807                                                    kAffine_Mask |
808                                                    kPerspective_Mask |
809                                                    kRectStaysRect_Mask;
810 
811     // these guys align with the masks, so we can compute a mask from a variable 0/1
812     @SuppressWarnings("unused")
813     private final static int kTranslate_Shift = 0;
814     @SuppressWarnings("unused")
815     private final static int kScale_Shift = 1;
816     @SuppressWarnings("unused")
817     private final static int kAffine_Shift = 2;
818     @SuppressWarnings("unused")
819     private final static int kPerspective_Shift = 3;
820     private final static int kRectStaysRect_Shift = 4;
821 
computeTypeMask()822     private int computeTypeMask() {
823         int mask = 0;
824 
825         if (mValues[6] != 0. || mValues[7] != 0. || mValues[8] != 1.) {
826             mask |= kPerspective_Mask;
827         }
828 
829         if (mValues[2] != 0. || mValues[5] != 0.) {
830             mask |= kTranslate_Mask;
831         }
832 
833         float m00 = mValues[0];
834         float m01 = mValues[1];
835         float m10 = mValues[3];
836         float m11 = mValues[4];
837 
838         if (m01 != 0. || m10 != 0.) {
839             mask |= kAffine_Mask;
840         }
841 
842         if (m00 != 1. || m11 != 1.) {
843             mask |= kScale_Mask;
844         }
845 
846         if ((mask & kPerspective_Mask) == 0) {
847             // map non-zero to 1
848             int im00 = m00 != 0 ? 1 : 0;
849             int im01 = m01 != 0 ? 1 : 0;
850             int im10 = m10 != 0 ? 1 : 0;
851             int im11 = m11 != 0 ? 1 : 0;
852 
853             // record if the (p)rimary and (s)econdary diagonals are all 0 or
854             // all non-zero (answer is 0 or 1)
855             int dp0 = (im00 | im11) ^ 1;  // true if both are 0
856             int dp1 = im00 & im11;        // true if both are 1
857             int ds0 = (im01 | im10) ^ 1;  // true if both are 0
858             int ds1 = im01 & im10;        // true if both are 1
859 
860             // return 1 if primary is 1 and secondary is 0 or
861             // primary is 0 and secondary is 1
862             mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift;
863         }
864 
865         return mask;
866     }
867 
Matrix_Delegate()868     private Matrix_Delegate() {
869         reset();
870     }
871 
Matrix_Delegate(float[] values)872     private Matrix_Delegate(float[] values) {
873         System.arraycopy(values, 0, mValues, 0, MATRIX_SIZE);
874     }
875 
876     /**
877      * Adds the given transformation to the current Matrix
878      * <p/>This in effect does this = this*matrix
879      * @param matrix
880      */
postTransform(float[] matrix)881     private void postTransform(float[] matrix) {
882         float[] tmp = new float[9];
883         multiply(tmp, mValues, matrix);
884         mValues = tmp;
885     }
886 
887     /**
888      * Adds the given transformation to the current Matrix
889      * <p/>This in effect does this = matrix*this
890      * @param matrix
891      */
preTransform(float[] matrix)892     private void preTransform(float[] matrix) {
893         float[] tmp = new float[9];
894         multiply(tmp, matrix, mValues);
895         mValues = tmp;
896     }
897 
898     /**
899      * Apply this matrix to the array of 2D points specified by src, and write
900       * the transformed points into the array of points specified by dst. The
901       * two arrays represent their "points" as pairs of floats [x, y].
902       *
903       * @param dst   The array of dst points (x,y pairs)
904       * @param dstIndex The index of the first [x,y] pair of dst floats
905       * @param src   The array of src points (x,y pairs)
906       * @param srcIndex The index of the first [x,y] pair of src floats
907       * @param pointCount The number of points (x,y pairs) to transform
908       */
909 
mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex, int pointCount)910      private void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,
911                            int pointCount) {
912          final int count = pointCount * 2;
913 
914          float[] tmpDest = dst;
915          boolean inPlace = dst == src;
916          if (inPlace) {
917              tmpDest = new float[dstIndex + count];
918          }
919 
920          for (int i = 0 ; i < count ; i += 2) {
921              // just in case we are doing in place, we better put this in temp vars
922              float x = mValues[0] * src[i + srcIndex] +
923                        mValues[1] * src[i + srcIndex + 1] +
924                        mValues[2];
925              float y = mValues[3] * src[i + srcIndex] +
926                        mValues[4] * src[i + srcIndex + 1] +
927                        mValues[5];
928 
929              tmpDest[i + dstIndex]     = x;
930              tmpDest[i + dstIndex + 1] = y;
931          }
932 
933          if (inPlace) {
934              System.arraycopy(tmpDest, dstIndex, dst, dstIndex, count);
935          }
936      }
937 
938      /**
939       * Apply this matrix to the array of 2D points, and write the transformed
940       * points back into the array
941       *
942       * @param pts The array [x0, y0, x1, y1, ...] of points to transform.
943       */
944 
mapPoints(float[] pts)945      private void mapPoints(float[] pts) {
946          mapPoints(pts, 0, pts, 0, pts.length >> 1);
947      }
948 
mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, int ptCount)949      private void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, int ptCount) {
950          if (hasPerspective()) {
951              // transform the (0,0) point
952              float[] origin = new float[] { 0.f, 0.f};
953              mapPoints(origin);
954 
955              // translate the vector data as points
956              mapPoints(dst, dstIndex, src, srcIndex, ptCount);
957 
958              // then substract the transformed origin.
959              final int count = ptCount * 2;
960              for (int i = 0 ; i < count ; i += 2) {
961                  dst[dstIndex + i] = dst[dstIndex + i] - origin[0];
962                  dst[dstIndex + i + 1] = dst[dstIndex + i + 1] - origin[1];
963              }
964          } else {
965              // make a copy of the matrix
966              Matrix_Delegate copy = new Matrix_Delegate(mValues);
967 
968              // remove the translation
969              setTranslate(copy.mValues, 0, 0);
970 
971              // map the content as points.
972              copy.mapPoints(dst, dstIndex, src, srcIndex, ptCount);
973          }
974      }
975 
getPointLength(float[] src, int index)976      private static float getPointLength(float[] src, int index) {
977          return (float) Math.sqrt(src[index] * src[index] + src[index + 1] * src[index + 1]);
978      }
979 
980     /**
981      * multiply two matrices and store them in a 3rd.
982      * <p/>This in effect does dest = a*b
983      * dest cannot be the same as a or b.
984      */
multiply(float dest[], float[] a, float[] b)985      /*package*/ static void multiply(float dest[], float[] a, float[] b) {
986         // first row
987         dest[0] = b[0] * a[0] + b[1] * a[3] + b[2] * a[6];
988         dest[1] = b[0] * a[1] + b[1] * a[4] + b[2] * a[7];
989         dest[2] = b[0] * a[2] + b[1] * a[5] + b[2] * a[8];
990 
991         // 2nd row
992         dest[3] = b[3] * a[0] + b[4] * a[3] + b[5] * a[6];
993         dest[4] = b[3] * a[1] + b[4] * a[4] + b[5] * a[7];
994         dest[5] = b[3] * a[2] + b[4] * a[5] + b[5] * a[8];
995 
996         // 3rd row
997         dest[6] = b[6] * a[0] + b[7] * a[3] + b[8] * a[6];
998         dest[7] = b[6] * a[1] + b[7] * a[4] + b[8] * a[7];
999         dest[8] = b[6] * a[2] + b[7] * a[5] + b[8] * a[8];
1000     }
1001 
1002     /**
1003      * Returns a matrix that represents a given translate
1004      * @param dx
1005      * @param dy
1006      * @return
1007      */
getTranslate(float dx, float dy)1008     /*package*/ static float[] getTranslate(float dx, float dy) {
1009         return setTranslate(new float[9], dx, dy);
1010     }
1011 
setTranslate(float[] dest, float dx, float dy)1012     /*package*/ static float[] setTranslate(float[] dest, float dx, float dy) {
1013         dest[0] = 1;
1014         dest[1] = 0;
1015         dest[2] = dx;
1016         dest[3] = 0;
1017         dest[4] = 1;
1018         dest[5] = dy;
1019         dest[6] = 0;
1020         dest[7] = 0;
1021         dest[8] = 1;
1022         return dest;
1023     }
1024 
getScale(float sx, float sy)1025     /*package*/ static float[] getScale(float sx, float sy) {
1026         return new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 };
1027     }
1028 
1029     /**
1030      * Returns a matrix that represents the given scale info.
1031      * @param sx
1032      * @param sy
1033      * @param px
1034      * @param py
1035      */
getScale(float sx, float sy, float px, float py)1036     /*package*/ static float[] getScale(float sx, float sy, float px, float py) {
1037         float[] tmp = new float[9];
1038         float[] tmp2 = new float[9];
1039 
1040         // TODO: do it in one pass
1041 
1042         // translate tmp so that the pivot is in 0,0
1043         setTranslate(tmp, -px, -py);
1044 
1045         // scale into tmp2
1046         multiply(tmp2, tmp, getScale(sx, sy));
1047 
1048         // translate back the pivot back into tmp
1049         multiply(tmp, tmp2, getTranslate(px, py));
1050 
1051         return tmp;
1052     }
1053 
1054 
getRotate(float degrees)1055     /*package*/ static float[] getRotate(float degrees) {
1056         double rad = Math.toRadians(degrees);
1057         float sin = (float)Math.sin(rad);
1058         float cos = (float)Math.cos(rad);
1059 
1060         return getRotate(sin, cos);
1061     }
1062 
getRotate(float sin, float cos)1063     /*package*/ static float[] getRotate(float sin, float cos) {
1064         return setRotate(new float[9], sin, cos);
1065     }
1066 
setRotate(float[] dest, float degrees)1067     /*package*/ static float[] setRotate(float[] dest, float degrees) {
1068         double rad = Math.toRadians(degrees);
1069         float sin = (float)Math.sin(rad);
1070         float cos = (float)Math.cos(rad);
1071 
1072         return setRotate(dest, sin, cos);
1073     }
1074 
setRotate(float[] dest, float sin, float cos)1075     /*package*/ static float[] setRotate(float[] dest, float sin, float cos) {
1076         dest[0] = cos;
1077         dest[1] = -sin;
1078         dest[2] = 0;
1079         dest[3] = sin;
1080         dest[4] = cos;
1081         dest[5] = 0;
1082         dest[6] = 0;
1083         dest[7] = 0;
1084         dest[8] = 1;
1085         return dest;
1086     }
1087 
getRotate(float degrees, float px, float py)1088     /*package*/ static float[] getRotate(float degrees, float px, float py) {
1089         float[] tmp = new float[9];
1090         float[] tmp2 = new float[9];
1091 
1092         // TODO: do it in one pass
1093 
1094         // translate so that the pivot is in 0,0
1095         setTranslate(tmp, -px, -py);
1096 
1097         // rotate into tmp2
1098         double rad = Math.toRadians(degrees);
1099         float cos = (float)Math.cos(rad);
1100         float sin = (float)Math.sin(rad);
1101         multiply(tmp2, tmp, getRotate(sin, cos));
1102 
1103         // translate back the pivot back into tmp
1104         multiply(tmp, tmp2, getTranslate(px, py));
1105 
1106         return tmp;
1107     }
1108 
getSkew(float kx, float ky)1109     /*package*/ static float[] getSkew(float kx, float ky) {
1110         return new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 };
1111     }
1112 
getSkew(float kx, float ky, float px, float py)1113     /*package*/ static float[] getSkew(float kx, float ky, float px, float py) {
1114         float[] tmp = new float[9];
1115         float[] tmp2 = new float[9];
1116 
1117         // TODO: do it in one pass
1118 
1119         // translate so that the pivot is in 0,0
1120         setTranslate(tmp, -px, -py);
1121 
1122         // skew into tmp2
1123         multiply(tmp2, tmp, new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 });
1124         // translate back the pivot back into tmp
1125         multiply(tmp, tmp2, getTranslate(px, py));
1126 
1127         return tmp;
1128     }
1129 }
1130