content: /*
   * Copyright (C) 2006 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  package android.graphics;
  
  import android.annotation.UnsupportedAppUsage;
  
  import dalvik.annotation.optimization.CriticalNative;
  import dalvik.annotation.optimization.FastNative;
  
  import libcore.util.NativeAllocationRegistry;
  
  import java.io.PrintWriter;
  
  /**
   * The Matrix class holds a 3x3 matrix for transforming coordinates.
   */
  public class Matrix {
  
      public static final int MSCALE_X = 0;   //!< use with getValues/setValues
      public static final int MSKEW_X  = 1;   //!< use with getValues/setValues
      public static final int MTRANS_X = 2;   //!< use with getValues/setValues
      public static final int MSKEW_Y  = 3;   //!< use with getValues/setValues
      public static final int MSCALE_Y = 4;   //!< use with getValues/setValues
      public static final int MTRANS_Y = 5;   //!< use with getValues/setValues
      public static final int MPERSP_0 = 6;   //!< use with getValues/setValues
      public static final int MPERSP_1 = 7;   //!< use with getValues/setValues
      public static final int MPERSP_2 = 8;   //!< use with getValues/setValues
  
      /** @hide */
      @UnsupportedAppUsage
      public final static Matrix IDENTITY_MATRIX = new Matrix() {
          void oops() {
              throw new IllegalStateException("Matrix can not be modified");
          }
  
          @Override
          public void set(Matrix src) {
              oops();
          }
  
          @Override
          public void reset() {
              oops();
          }
  
          @Override
          public void setTranslate(float dx, float dy) {
              oops();
          }
  
          @Override
          public void setScale(float sx, float sy, float px, float py) {
              oops();
          }
  
          @Override
          public void setScale(float sx, float sy) {
              oops();
          }
  
          @Override
          public void setRotate(float degrees, float px, float py) {
              oops();
          }
  
          @Override
          public void setRotate(float degrees) {
              oops();
          }
  
          @Override
          public void setSinCos(float sinValue, float cosValue, float px, float py) {
              oops();
          }
  
          @Override
          public void setSinCos(float sinValue, float cosValue) {
              oops();
          }
  
          @Override
          public void setSkew(float kx, float ky, float px, float py) {
              oops();
          }
  
          @Override
          public void setSkew(float kx, float ky) {
              oops();
          }
  
          @Override
          public boolean setConcat(Matrix a, Matrix b) {
              oops();
              return false;
          }
  
          @Override
          public boolean preTranslate(float dx, float dy) {
              oops();
              return false;
          }
  
          @Override
          public boolean preScale(float sx, float sy, float px, float py) {
              oops();
              return false;
          }
  
          @Override
          public boolean preScale(float sx, float sy) {
              oops();
              return false;
          }
  
          @Override
          public boolean preRotate(float degrees, float px, float py) {
              oops();
              return false;
          }
  
          @Override
          public boolean preRotate(float degrees) {
              oops();
              return false;
          }
  
          @Override
          public boolean preSkew(float kx, float ky, float px, float py) {
              oops();
              return false;
          }
  
          @Override
          public boolean preSkew(float kx, float ky) {
              oops();
              return false;
          }
  
          @Override
          public boolean preConcat(Matrix other) {
              oops();
              return false;
          }
  
          @Override
          public boolean postTranslate(float dx, float dy) {
              oops();
              return false;
          }
  
          @Override
          public boolean postScale(float sx, float sy, float px, float py) {
              oops();
              return false;
          }
  
          @Override
          public boolean postScale(float sx, float sy) {
              oops();
              return false;
          }
  
          @Override
          public boolean postRotate(float degrees, float px, float py) {
              oops();
              return false;
          }
  
          @Override
          public boolean postRotate(float degrees) {
              oops();
              return false;
          }
  
          @Override
          public boolean postSkew(float kx, float ky, float px, float py) {
              oops();
              return false;
          }
  
          @Override
          public boolean postSkew(float kx, float ky) {
              oops();
              return false;
          }
  
          @Override
          public boolean postConcat(Matrix other) {
              oops();
              return false;
          }
  
          @Override
          public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf) {
              oops();
              return false;
          }
  
          @Override
          public boolean setPolyToPoly(float[] src, int srcIndex, float[] dst, int dstIndex,
                  int pointCount) {
              oops();
              return false;
          }
  
          @Override
          public void setValues(float[] values) {
              oops();
          }
      };
  
      private static class NoImagePreloadHolder {
          public static final NativeAllocationRegistry sRegistry =
                  NativeAllocationRegistry.createMalloced(
                  Matrix.class.getClassLoader(), nGetNativeFinalizer());
      }
  
      /**
       * @hide
       */
      @UnsupportedAppUsage
      public final long native_instance;
  
      /**
       * Create an identity matrix
       */
      public Matrix() {
          native_instance = nCreate(0);
          NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance);
      }
  
      /**
       * Create a matrix that is a (deep) copy of src
       *
       * @param src The matrix to copy into this matrix
       */
      public Matrix(Matrix src) {
          native_instance = nCreate(src != null ? src.native_instance : 0);
          NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, native_instance);
      }
  
      /**
       * Returns true if the matrix is identity. This maybe faster than testing if (getType() == 0)
       */
      public boolean isIdentity() {
          return nIsIdentity(native_instance);
      }
  
      /**
       * Gets whether this matrix is affine. An affine matrix preserves straight lines and has no
       * perspective.
       *
       * @return Whether the matrix is affine.
       */
      public boolean isAffine() {
          return nIsAffine(native_instance);
      }
  
      /**
       * Returns true if will map a rectangle to another rectangle. This can be true if the matrix is
       * identity, scale-only, or rotates a multiple of 90 degrees.
       */
      public boolean rectStaysRect() {
          return nRectStaysRect(native_instance);
      }
  
      /**
       * (deep) copy the src matrix into this matrix. If src is null, reset this matrix to the
       * identity matrix.
       */
      public void set(Matrix src) {
          if (src == null) {
              reset();
          } else {
              nSet(native_instance, src.native_instance);
          }
      }
  
      /**
       * Returns true iff obj is a Matrix and its values equal our values.
       */
      @Override
      public boolean equals(Object obj) {
          // if (obj == this) return true; -- NaN value would mean matrix != itself
          if (!(obj instanceof Matrix)) {
              return false;
          }
          return nEquals(native_instance, ((Matrix) obj).native_instance);
      }
  
      @Override
      public int hashCode() {
          // This should generate the hash code by performing some arithmetic operation on all
          // the matrix elements -- our equals() does an element-by-element comparison, and we
          // need to ensure that the hash code for two equal objects is the same. We're not
          // really using this at the moment, so we take the easy way out.
          return 44;
      }
  
      /** Set the matrix to identity */
      public void reset() {
          nReset(native_instance);
      }
  
      /** Set the matrix to translate by (dx, dy). */
      public void setTranslate(float dx, float dy) {
          nSetTranslate(native_instance, dx, dy);
      }
  
      /**
       * Set the matrix to scale by sx and sy, with a pivot point at (px, py). The pivot point is the
       * coordinate that should remain unchanged by the specified transformation.
       */
      public void setScale(float sx, float sy, float px, float py) {
          nSetScale(native_instance, sx, sy, px, py);
      }
  
      /** Set the matrix to scale by sx and sy. */
      public void setScale(float sx, float sy) {
          nSetScale(native_instance, sx, sy);
      }
  
      /**
       * Set the matrix to rotate by the specified number of degrees, with a pivot point at (px, py).
       * The pivot point is the coordinate that should remain unchanged by the specified
       * transformation.
       */
      public void setRotate(float degrees, float px, float py) {
          nSetRotate(native_instance, degrees, px, py);
      }
  
      /**
       * Set the matrix to rotate about (0,0) by the specified number of degrees.
       */
      public void setRotate(float degrees) {
          nSetRotate(native_instance, degrees);
      }
  
      /**
       * Set the matrix to rotate by the specified sine and cosine values, with a pivot point at (px,
       * py). The pivot point is the coordinate that should remain unchanged by the specified
       * transformation.
       */
      public void setSinCos(float sinValue, float cosValue, float px, float py) {
          nSetSinCos(native_instance, sinValue, cosValue, px, py);
      }
  
      /** Set the matrix to rotate by the specified sine and cosine values. */
      public void setSinCos(float sinValue, float cosValue) {
          nSetSinCos(native_instance, sinValue, cosValue);
      }
  
      /**
       * Set the matrix to skew by sx and sy, with a pivot point at (px, py). The pivot point is the
       * coordinate that should remain unchanged by the specified transformation.
       */
      public void setSkew(float kx, float ky, float px, float py) {
          nSetSkew(native_instance, kx, ky, px, py);
      }
  
      /** Set the matrix to skew by sx and sy. */
      public void setSkew(float kx, float ky) {
          nSetSkew(native_instance, kx, ky);
      }
  
      /**
       * Set the matrix to the concatenation of the two specified matrices and return true.
       * <p>
       * Either of the two matrices may also be the target matrix, that is
       * <code>matrixA.setConcat(matrixA, matrixB);</code> is valid.
       * </p>
       * <p class="note">
       * In {@link android.os.Build.VERSION_CODES#GINGERBREAD_MR1} and below, this function returns
       * true only if the result can be represented. In
       * {@link android.os.Build.VERSION_CODES#HONEYCOMB} and above, it always returns true.
       * </p>
       */
      public boolean setConcat(Matrix a, Matrix b) {
          nSetConcat(native_instance, a.native_instance, b.native_instance);
          return true;
      }
  
      /**
       * Preconcats the matrix with the specified translation. M' = M * T(dx, dy)
       */
      public boolean preTranslate(float dx, float dy) {
          nPreTranslate(native_instance, dx, dy);
          return true;
      }
  
      /**
       * Preconcats the matrix with the specified scale. M' = M * S(sx, sy, px, py)
       */
      public boolean preScale(float sx, float sy, float px, float py) {
          nPreScale(native_instance, sx, sy, px, py);
          return true;
      }
  
      /**
       * Preconcats the matrix with the specified scale. M' = M * S(sx, sy)
       */
      public boolean preScale(float sx, float sy) {
          nPreScale(native_instance, sx, sy);
          return true;
      }
  
      /**
       * Preconcats the matrix with the specified rotation. M' = M * R(degrees, px, py)
       */
      public boolean preRotate(float degrees, float px, float py) {
          nPreRotate(native_instance, degrees, px, py);
          return true;
      }
  
      /**
       * Preconcats the matrix with the specified rotation. M' = M * R(degrees)
       */
      public boolean preRotate(float degrees) {
          nPreRotate(native_instance, degrees);
          return true;
      }
  
      /**
       * Preconcats the matrix with the specified skew. M' = M * K(kx, ky, px, py)
       */
      public boolean preSkew(float kx, float ky, float px, float py) {
          nPreSkew(native_instance, kx, ky, px, py);
          return true;
      }
  
      /**
       * Preconcats the matrix with the specified skew. M' = M * K(kx, ky)
       */
      public boolean preSkew(float kx, float ky) {
          nPreSkew(native_instance, kx, ky);
          return true;
      }
  
      /**
       * Preconcats the matrix with the specified matrix. M' = M * other
       */
      public boolean preConcat(Matrix other) {
          nPreConcat(native_instance, other.native_instance);
          return true;
      }
  
      /**
       * Postconcats the matrix with the specified translation. M' = T(dx, dy) * M
       */
      public boolean postTranslate(float dx, float dy) {
          nPostTranslate(native_instance, dx, dy);
          return true;
      }
  
      /**
       * Postconcats the matrix with the specified scale. M' = S(sx, sy, px, py) * M
       */
      public boolean postScale(float sx, float sy, float px, float py) {
          nPostScale(native_instance, sx, sy, px, py);
          return true;
      }
  
      /**
       * Postconcats the matrix with the specified scale. M' = S(sx, sy) * M
       */
      public boolean postScale(float sx, float sy) {
          nPostScale(native_instance, sx, sy);
          return true;
      }
  
      /**
       * Postconcats the matrix with the specified rotation. M' = R(degrees, px, py) * M
       */
      public boolean postRotate(float degrees, float px, float py) {
          nPostRotate(native_instance, degrees, px, py);
          return true;
      }
  
      /**
       * Postconcats the matrix with the specified rotation. M' = R(degrees) * M
       */
      public boolean postRotate(float degrees) {
          nPostRotate(native_instance, degrees);
          return true;
      }
  
      /**
       * Postconcats the matrix with the specified skew. M' = K(kx, ky, px, py) * M
       */
      public boolean postSkew(float kx, float ky, float px, float py) {
          nPostSkew(native_instance, kx, ky, px, py);
          return true;
      }
  
      /**
       * Postconcats the matrix with the specified skew. M' = K(kx, ky) * M
       */
      public boolean postSkew(float kx, float ky) {
          nPostSkew(native_instance, kx, ky);
          return true;
      }
  
      /**
       * Postconcats the matrix with the specified matrix. M' = other * M
       */
      public boolean postConcat(Matrix other) {
          nPostConcat(native_instance, other.native_instance);
          return true;
      }
  
      /**
       * Controlls how the src rect should align into the dst rect for setRectToRect().
       */
      public enum ScaleToFit {
          /**
           * Scale in X and Y independently, so that src matches dst exactly. This may change the
           * aspect ratio of the src.
           */
          FILL(0),
          /**
           * Compute a scale that will maintain the original src aspect ratio, but will also ensure
           * that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. START
           * aligns the result to the left and top edges of dst.
           */
          START(1),
          /**
           * Compute a scale that will maintain the original src aspect ratio, but will also ensure
           * that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. The
           * result is centered inside dst.
           */
          CENTER(2),
          /**
           * Compute a scale that will maintain the original src aspect ratio, but will also ensure
           * that src fits entirely inside dst. At least one axis (X or Y) will fit exactly. END
           * aligns the result to the right and bottom edges of dst.
           */
          END(3);
  
          // the native values must match those in SkMatrix.h
          ScaleToFit(int nativeInt) {
              this.nativeInt = nativeInt;
          }
  
          final int nativeInt;
      }
  
      /**
       * Set the matrix to the scale and translate values that map the source rectangle to the
       * destination rectangle, returning true if the the result can be represented.
       *
       * @param src the source rectangle to map from.
       * @param dst the destination rectangle to map to.
       * @param stf the ScaleToFit option
       * @return true if the matrix can be represented by the rectangle mapping.
       */
      public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf) {
          if (dst == null || src == null) {
              throw new NullPointerException();
          }
          return nSetRectToRect(native_instance, src, dst, stf.nativeInt);
      }
  
      // private helper to perform range checks on arrays of "points"
      private static void checkPointArrays(float[] src, int srcIndex,
              float[] dst, int dstIndex,
              int pointCount) {
          // check for too-small and too-big indices
          int srcStop = srcIndex + (pointCount << 1);
          int dstStop = dstIndex + (pointCount << 1);
          if ((pointCount | srcIndex | dstIndex | srcStop | dstStop) < 0 ||
                  srcStop > src.length || dstStop > dst.length) {
              throw new ArrayIndexOutOfBoundsException();
          }
      }
  
      /**
       * Set the matrix such that the specified src points would map to the specified dst points. The
       * "points" are represented as an array of floats, order [x0, y0, x1, y1, ...], where each
       * "point" is 2 float values.
       *
       * @param src The array of src [x,y] pairs (points)
       * @param srcIndex Index of the first pair of src values
       * @param dst The array of dst [x,y] pairs (points)
       * @param dstIndex Index of the first pair of dst values
       * @param pointCount The number of pairs/points to be used. Must be [0..4]
       * @return true if the matrix was set to the specified transformation
       */
      public boolean setPolyToPoly(float[] src, int srcIndex,
              float[] dst, int dstIndex,
              int pointCount) {
          if (pointCount > 4) {
              throw new IllegalArgumentException();
          }
          checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
          return nSetPolyToPoly(native_instance, src, srcIndex,
                  dst, dstIndex, pointCount);
      }
  
      /**
       * If this matrix can be inverted, return true and if inverse is not null, set inverse to be the
       * inverse of this matrix. If this matrix cannot be inverted, ignore inverse and return false.
       */
      public boolean invert(Matrix inverse) {
          return nInvert(native_instance, inverse.native_instance);
      }
  
      /**
       * Apply this matrix to the array of 2D points specified by src, and write the transformed
       * points into the array of points specified by dst. The two arrays represent their "points" as
       * pairs of floats [x, y].
       *
       * @param dst The array of dst points (x,y pairs)
       * @param dstIndex The index of the first [x,y] pair of dst floats
       * @param src The array of src points (x,y pairs)
       * @param srcIndex The index of the first [x,y] pair of src floats
       * @param pointCount The number of points (x,y pairs) to transform
       */
      public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,
              int pointCount) {
          checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
          nMapPoints(native_instance, dst, dstIndex, src, srcIndex,
                  pointCount, true);
      }
  
      /**
       * Apply this matrix to the array of 2D vectors specified by src, and write the transformed
       * vectors into the array of vectors specified by dst. The two arrays represent their "vectors"
       * as pairs of floats [x, y]. Note: this method does not apply the translation associated with
       * the matrix. Use {@link Matrix#mapPoints(float[], int, float[], int, int)} if you want the
       * translation to be applied.
       *
       * @param dst The array of dst vectors (x,y pairs)
       * @param dstIndex The index of the first [x,y] pair of dst floats
       * @param src The array of src vectors (x,y pairs)
       * @param srcIndex The index of the first [x,y] pair of src floats
       * @param vectorCount The number of vectors (x,y pairs) to transform
       */
      public void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex,
              int vectorCount) {
          checkPointArrays(src, srcIndex, dst, dstIndex, vectorCount);
          nMapPoints(native_instance, dst, dstIndex, src, srcIndex,
                  vectorCount, false);
      }
  
      /**
       * Apply this matrix to the array of 2D points specified by src, and write the transformed
       * points into the array of points specified by dst. The two arrays represent their "points" as
       * pairs of floats [x, y].
       *
       * @param dst The array of dst points (x,y pairs)
       * @param src The array of src points (x,y pairs)
       */
      public void mapPoints(float[] dst, float[] src) {
          if (dst.length != src.length) {
              throw new ArrayIndexOutOfBoundsException();
          }
          mapPoints(dst, 0, src, 0, dst.length >> 1);
      }
  
      /**
       * Apply this matrix to the array of 2D vectors specified by src, and write the transformed
       * vectors into the array of vectors specified by dst. The two arrays represent their "vectors"
       * as pairs of floats [x, y]. Note: this method does not apply the translation associated with
       * the matrix. Use {@link Matrix#mapPoints(float[], float[])} if you want the translation to be
       * applied.
       *
       * @param dst The array of dst vectors (x,y pairs)
       * @param src The array of src vectors (x,y pairs)
       */
      public void mapVectors(float[] dst, float[] src) {
          if (dst.length != src.length) {
              throw new ArrayIndexOutOfBoundsException();
          }
          mapVectors(dst, 0, src, 0, dst.length >> 1);
      }
  
      /**
       * Apply this matrix to the array of 2D points, and write the transformed points back into the
       * array
       *
       * @param pts The array [x0, y0, x1, y1, ...] of points to transform.
       */
      public void mapPoints(float[] pts) {
          mapPoints(pts, 0, pts, 0, pts.length >> 1);
      }
  
      /**
       * Apply this matrix to the array of 2D vectors, and write the transformed vectors back into the
       * array. Note: this method does not apply the translation associated with the matrix. Use
       * {@link Matrix#mapPoints(float[])} if you want the translation to be applied.
       *
       * @param vecs The array [x0, y0, x1, y1, ...] of vectors to transform.
       */
      public void mapVectors(float[] vecs) {
          mapVectors(vecs, 0, vecs, 0, vecs.length >> 1);
      }
  
      /**
       * Apply this matrix to the src rectangle, and write the transformed rectangle into dst. This is
       * accomplished by transforming the 4 corners of src, and then setting dst to the bounds of
       * those points.
       *
       * @param dst Where the transformed rectangle is written.
       * @param src The original rectangle to be transformed.
       * @return the result of calling rectStaysRect()
       */
      public boolean mapRect(RectF dst, RectF src) {
          if (dst == null || src == null) {
              throw new NullPointerException();
          }
          return nMapRect(native_instance, dst, src);
      }
  
      /**
       * Apply this matrix to the rectangle, and write the transformed rectangle back into it. This is
       * accomplished by transforming the 4 corners of rect, and then setting it to the bounds of
       * those points
       *
       * @param rect The rectangle to transform.
       * @return the result of calling rectStaysRect()
       */
      public boolean mapRect(RectF rect) {
          return mapRect(rect, rect);
      }
  
      /**
       * Return the mean radius of a circle after it has been mapped by this matrix. NOTE: in
       * perspective this value assumes the circle has its center at the origin.
       */
      public float mapRadius(float radius) {
          return nMapRadius(native_instance, radius);
      }
  
      /**
       * Copy 9 values from the matrix into the array.
       */
      public void getValues(float[] values) {
          if (values.length < 9) {
              throw new ArrayIndexOutOfBoundsException();
          }
          nGetValues(native_instance, values);
      }
  
      /**
       * Copy 9 values from the array into the matrix. Depending on the implementation of Matrix,
       * these may be transformed into 16.16 integers in the Matrix, such that a subsequent call to
       * getValues() will not yield exactly the same values.
       */
      public void setValues(float[] values) {
          if (values.length < 9) {
              throw new ArrayIndexOutOfBoundsException();
          }
          nSetValues(native_instance, values);
      }
  
      @Override
      public String toString() {
          StringBuilder sb = new StringBuilder(64);
          sb.append("Matrix{");
          toShortString(sb);
          sb.append('}');
          return sb.toString();
  
      }
  
      public String toShortString() {
          StringBuilder sb = new StringBuilder(64);
          toShortString(sb);
          return sb.toString();
      }
  
      /**
       * @hide
       */
      public void toShortString(StringBuilder sb) {
          float[] values = new float[9];
          getValues(values);
          sb.append('[');
          sb.append(values[0]);
          sb.append(", ");
          sb.append(values[1]);
          sb.append(", ");
          sb.append(values[2]);
          sb.append("][");
          sb.append(values[3]);
          sb.append(", ");
          sb.append(values[4]);
          sb.append(", ");
          sb.append(values[5]);
          sb.append("][");
          sb.append(values[6]);
          sb.append(", ");
          sb.append(values[7]);
          sb.append(", ");
          sb.append(values[8]);
          sb.append(']');
      }
  
      /**
       * Print short string, to optimize dumping.
       *
       * @hide
       */
      public void printShortString(PrintWriter pw) {
          float[] values = new float[9];
          getValues(values);
          pw.print('[');
          pw.print(values[0]);
          pw.print(", ");
          pw.print(values[1]);
          pw.print(", ");
          pw.print(values[2]);
          pw.print("][");
          pw.print(values[3]);
          pw.print(", ");
          pw.print(values[4]);
          pw.print(", ");
          pw.print(values[5]);
          pw.print("][");
          pw.print(values[6]);
          pw.print(", ");
          pw.print(values[7]);
          pw.print(", ");
          pw.print(values[8]);
          pw.print(']');
  
      }
  
      /** @hide */
      public final long ni() {
          return native_instance;
      }
  
      // ------------------ Regular JNI ------------------------
  
      private static native long nCreate(long nSrc_or_zero);
      private static native long nGetNativeFinalizer();
  
  
      // ------------------ Fast JNI ------------------------
  
      @FastNative
      private static native boolean nSetRectToRect(long nObject,
              RectF src, RectF dst, int stf);
      @FastNative
      private static native boolean nSetPolyToPoly(long nObject,
              float[] src, int srcIndex, float[] dst, int dstIndex, int pointCount);
      @FastNative
      private static native void nMapPoints(long nObject,
              float[] dst, int dstIndex, float[] src, int srcIndex,
              int ptCount, boolean isPts);
      @FastNative
      private static native boolean nMapRect(long nObject, RectF dst, RectF src);
      @FastNative
      private static native void nGetValues(long nObject, float[] values);
      @FastNative
      private static native void nSetValues(long nObject, float[] values);
  
  
      // ------------------ Critical JNI ------------------------
  
      @CriticalNative
      private static native boolean nIsIdentity(long nObject);
      @CriticalNative
      private static native boolean nIsAffine(long nObject);
      @CriticalNative
      private static native boolean nRectStaysRect(long nObject);
      @CriticalNative
      private static native void nReset(long nObject);
      @CriticalNative
      private static native void nSet(long nObject, long nOther);
      @CriticalNative
      private static native void nSetTranslate(long nObject, float dx, float dy);
      @CriticalNative
      private static native void nSetScale(long nObject, float sx, float sy, float px, float py);
      @CriticalNative
      private static native void nSetScale(long nObject, float sx, float sy);
      @CriticalNative
      private static native void nSetRotate(long nObject, float degrees, float px, float py);
      @CriticalNative
      private static native void nSetRotate(long nObject, float degrees);
      @CriticalNative
      private static native void nSetSinCos(long nObject, float sinValue, float cosValue,
              float px, float py);
      @CriticalNative
      private static native void nSetSinCos(long nObject, float sinValue, float cosValue);
      @CriticalNative
      private static native void nSetSkew(long nObject, float kx, float ky, float px, float py);
      @CriticalNative
      private static native void nSetSkew(long nObject, float kx, float ky);
      @CriticalNative
      private static native void nSetConcat(long nObject, long nA, long nB);
      @CriticalNative
      private static native void nPreTranslate(long nObject, float dx, float dy);
      @CriticalNative
      private static native void nPreScale(long nObject, float sx, float sy, float px, float py);
      @CriticalNative
      private static native void nPreScale(long nObject, float sx, float sy);
      @CriticalNative
      private static native void nPreRotate(long nObject, float degrees, float px, float py);
      @CriticalNative
      private static native void nPreRotate(long nObject, float degrees);
      @CriticalNative
      private static native void nPreSkew(long nObject, float kx, float ky, float px, float py);
      @CriticalNative
      private static native void nPreSkew(long nObject, float kx, float ky);
      @CriticalNative
      private static native void nPreConcat(long nObject, long nOther_matrix);
      @CriticalNative
      private static native void nPostTranslate(long nObject, float dx, float dy);
      @CriticalNative
      private static native void nPostScale(long nObject, float sx, float sy, float px, float py);
      @CriticalNative
      private static native void nPostScale(long nObject, float sx, float sy);
      @CriticalNative
      private static native void nPostRotate(long nObject, float degrees, float px, float py);
      @CriticalNative
      private static native void nPostRotate(long nObject, float degrees);
      @CriticalNative
      private static native void nPostSkew(long nObject, float kx, float ky, float px, float py);
      @CriticalNative
      private static native void nPostSkew(long nObject, float kx, float ky);
      @CriticalNative
      private static native void nPostConcat(long nObject, long nOther_matrix);
      @CriticalNative
      private static native boolean nInvert(long nObject, long nInverse);
      @CriticalNative
      private static native float nMapRadius(long nObject, float radius);
      @CriticalNative
      private static native boolean nEquals(long nA, long nB);
  }
  