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