1/* libs/android_runtime/android/graphics/Matrix.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9**     http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "GraphicsJNI.h"
19#include "Matrix.h"
20#include "SkMatrix.h"
21#include "core_jni_helpers.h"
22
23#include <Caches.h>
24#include <jni.h>
25
26namespace android {
27
28static_assert(sizeof(SkMatrix) == 40, "Unexpected sizeof(SkMatrix), "
29        "update size in Matrix.java#NATIVE_ALLOCATION_SIZE and here");
30static_assert(SK_SCALAR_IS_FLOAT, "SK_SCALAR_IS_FLOAT is false, "
31        "only float scalar is supported");
32
33class SkMatrixGlue {
34public:
35
36    // ---------------- Regular JNI -----------------------------
37
38    static void finalizer(jlong objHandle) {
39        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
40        delete obj;
41    }
42
43    static jlong getNativeFinalizer(JNIEnv* env, jobject clazz) {
44        return static_cast<jlong>(reinterpret_cast<uintptr_t>(&finalizer));
45    }
46
47    static jlong create(JNIEnv* env, jobject clazz, jlong srcHandle) {
48        const SkMatrix* src = reinterpret_cast<SkMatrix*>(srcHandle);
49        SkMatrix* obj = new SkMatrix();
50        if (src)
51            *obj = *src;
52        else
53            obj->reset();
54        return reinterpret_cast<jlong>(obj);
55    }
56
57    // ---------------- @FastNative -----------------------------
58
59    static void mapPoints(JNIEnv* env, jobject clazz, jlong matrixHandle,
60            jfloatArray dst, jint dstIndex, jfloatArray src, jint srcIndex,
61            jint ptCount, jboolean isPts) {
62        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
63        SkASSERT(ptCount >= 0);
64        AutoJavaFloatArray autoSrc(env, src, srcIndex + (ptCount << 1),
65                kRO_JNIAccess);
66        AutoJavaFloatArray autoDst(env, dst, dstIndex + (ptCount << 1),
67                kRW_JNIAccess);
68        float* srcArray = autoSrc.ptr() + srcIndex;
69        float* dstArray = autoDst.ptr() + dstIndex;
70        if (isPts)
71            matrix->mapPoints((SkPoint*) dstArray, (const SkPoint*) srcArray,
72                    ptCount);
73        else
74            matrix->mapVectors((SkVector*) dstArray, (const SkVector*) srcArray,
75                    ptCount);
76    }
77
78    static jboolean mapRect__RectFRectF(JNIEnv* env, jobject clazz,
79            jlong matrixHandle, jobjectArray dst, jobject src) {
80        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
81        SkRect dst_, src_;
82        GraphicsJNI::jrectf_to_rect(env, src, &src_);
83        jboolean rectStaysRect = matrix->mapRect(&dst_, src_);
84        GraphicsJNI::rect_to_jrectf(dst_, env, dst);
85        return rectStaysRect ? JNI_TRUE : JNI_FALSE;
86    }
87
88    static jboolean setRectToRect(JNIEnv* env, jobject clazz,
89            jlong matrixHandle, jobject src, jobject dst, jint stfHandle) {
90        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
91        SkMatrix::ScaleToFit stf = static_cast<SkMatrix::ScaleToFit>(stfHandle);
92        SkRect src_;
93        GraphicsJNI::jrectf_to_rect(env, src, &src_);
94        SkRect dst_;
95        GraphicsJNI::jrectf_to_rect(env, dst, &dst_);
96        return matrix->setRectToRect(src_, dst_, stf) ? JNI_TRUE : JNI_FALSE;
97    }
98
99    static jboolean setPolyToPoly(JNIEnv* env, jobject clazz,
100            jlong matrixHandle, jfloatArray jsrc, jint srcIndex,
101            jfloatArray jdst, jint dstIndex, jint ptCount) {
102        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
103        SkASSERT(srcIndex >= 0);
104        SkASSERT(dstIndex >= 0);
105        SkASSERT((unsigned )ptCount <= 4);
106
107        AutoJavaFloatArray autoSrc(env, jsrc, srcIndex + (ptCount << 1),
108                kRO_JNIAccess);
109        AutoJavaFloatArray autoDst(env, jdst, dstIndex + (ptCount << 1),
110                kRW_JNIAccess);
111        float* src = autoSrc.ptr() + srcIndex;
112        float* dst = autoDst.ptr() + dstIndex;
113        bool result;
114
115        result = matrix->setPolyToPoly((const SkPoint*) src,
116                (const SkPoint*) dst, ptCount);
117        return result ? JNI_TRUE : JNI_FALSE;
118    }
119
120    static void getValues(JNIEnv* env, jobject clazz, jlong matrixHandle,
121            jfloatArray values) {
122        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
123        AutoJavaFloatArray autoValues(env, values, 9, kRW_JNIAccess);
124        float* dst = autoValues.ptr();
125        for (int i = 0; i < 9; i++) {
126            dst[i] = matrix->get(i);
127        }
128    }
129
130    static void setValues(JNIEnv* env, jobject clazz, jlong matrixHandle,
131            jfloatArray values) {
132        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
133        AutoJavaFloatArray autoValues(env, values, 9, kRO_JNIAccess);
134        const float* src = autoValues.ptr();
135
136        for (int i = 0; i < 9; i++) {
137            matrix->set(i, src[i]);
138        }
139    }
140
141    // ---------------- @CriticalNative -----------------------------
142
143    static jboolean isIdentity(jlong objHandle) {
144        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
145        return obj->isIdentity() ? JNI_TRUE : JNI_FALSE;
146    }
147
148    static jboolean isAffine(jlong objHandle) {
149        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
150        return obj->asAffine(NULL) ? JNI_TRUE : JNI_FALSE;
151    }
152
153    static jboolean rectStaysRect(jlong objHandle) {
154        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
155        return obj->rectStaysRect() ? JNI_TRUE : JNI_FALSE;
156    }
157
158    static void reset(jlong objHandle) {
159        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
160        obj->reset();
161    }
162
163    static void set(jlong objHandle, jlong otherHandle) {
164        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
165        SkMatrix* other = reinterpret_cast<SkMatrix*>(otherHandle);
166        *obj = *other;
167    }
168
169    static void setTranslate(jlong objHandle, jfloat dx, jfloat dy) {
170        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
171        obj->setTranslate(dx, dy);
172    }
173
174    static void setScale__FFFF(jlong objHandle, jfloat sx, jfloat sy, jfloat px,
175            jfloat py) {
176        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
177        obj->setScale(sx, sy, px, py);
178    }
179
180    static void setScale__FF(jlong objHandle, jfloat sx, jfloat sy) {
181        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
182        obj->setScale(sx, sy);
183    }
184
185    static void setRotate__FFF(jlong objHandle, jfloat degrees, jfloat px,
186            jfloat py) {
187        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
188        obj->setRotate(degrees, px, py);
189    }
190
191    static void setRotate__F(jlong objHandle, jfloat degrees) {
192        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
193        obj->setRotate(degrees);
194    }
195
196    static void setSinCos__FFFF(jlong objHandle, jfloat sinValue,
197            jfloat cosValue, jfloat px, jfloat py) {
198        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
199        obj->setSinCos(sinValue, cosValue, px, py);
200    }
201
202    static void setSinCos__FF(jlong objHandle, jfloat sinValue,
203            jfloat cosValue) {
204        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
205        obj->setSinCos(sinValue, cosValue);
206    }
207
208    static void setSkew__FFFF(jlong objHandle, jfloat kx, jfloat ky, jfloat px,
209            jfloat py) {
210        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
211        obj->setSkew(kx, ky, px, py);
212    }
213
214    static void setSkew__FF(jlong objHandle, jfloat kx, jfloat ky) {
215        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
216        obj->setSkew(kx, ky);
217    }
218
219    static void setConcat(jlong objHandle, jlong aHandle, jlong bHandle) {
220        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
221        SkMatrix* a = reinterpret_cast<SkMatrix*>(aHandle);
222        SkMatrix* b = reinterpret_cast<SkMatrix*>(bHandle);
223        obj->setConcat(*a, *b);
224    }
225
226    static void preTranslate(jlong objHandle, jfloat dx, jfloat dy) {
227        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
228        obj->preTranslate(dx, dy);
229    }
230
231    static void preScale__FFFF(jlong objHandle, jfloat sx, jfloat sy, jfloat px,
232            jfloat py) {
233        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
234        obj->preScale(sx, sy, px, py);
235    }
236
237    static void preScale__FF(jlong objHandle, jfloat sx, jfloat sy) {
238        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
239        obj->preScale(sx, sy);
240    }
241
242    static void preRotate__FFF(jlong objHandle, jfloat degrees, jfloat px,
243            jfloat py) {
244        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
245        obj->preRotate(degrees, px, py);
246    }
247
248    static void preRotate__F(jlong objHandle, jfloat degrees) {
249        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
250        obj->preRotate(degrees);
251    }
252
253    static void preSkew__FFFF(jlong objHandle, jfloat kx, jfloat ky, jfloat px,
254            jfloat py) {
255        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
256        obj->preSkew(kx, ky, px, py);
257    }
258
259    static void preSkew__FF(jlong objHandle, jfloat kx, jfloat ky) {
260        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
261        obj->preSkew(kx, ky);
262    }
263
264    static void preConcat(jlong objHandle, jlong otherHandle) {
265        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
266        SkMatrix* other = reinterpret_cast<SkMatrix*>(otherHandle);
267        obj->preConcat(*other);
268    }
269
270    static void postTranslate(jlong objHandle, jfloat dx, jfloat dy) {
271        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
272        obj->postTranslate(dx, dy);
273    }
274
275    static void postScale__FFFF(jlong objHandle, jfloat sx, jfloat sy,
276            jfloat px, jfloat py) {
277        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
278        obj->postScale(sx, sy, px, py);
279    }
280
281    static void postScale__FF(jlong objHandle, jfloat sx, jfloat sy) {
282        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
283        obj->postScale(sx, sy);
284    }
285
286    static void postRotate__FFF(jlong objHandle, jfloat degrees, jfloat px,
287            jfloat py) {
288        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
289        obj->postRotate(degrees, px, py);
290    }
291
292    static void postRotate__F(jlong objHandle, jfloat degrees) {
293        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
294        obj->postRotate(degrees);
295    }
296
297    static void postSkew__FFFF(jlong objHandle, jfloat kx, jfloat ky, jfloat px,
298            jfloat py) {
299        SkMatrix* obj = reinterpret_cast<SkMatrix*>(objHandle);
300        obj->postSkew(kx, ky, px, py);
301    }
302
303    static void postSkew__FF(jlong matrixHandle, jfloat kx, jfloat ky) {
304        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
305        matrix->postSkew(kx, ky);
306    }
307
308    static void postConcat(jlong matrixHandle, jlong otherHandle) {
309        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
310        SkMatrix* other = reinterpret_cast<SkMatrix*>(otherHandle);
311        matrix->postConcat(*other);
312    }
313
314    static jboolean invert(jlong matrixHandle, jlong inverseHandle) {
315        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
316        SkMatrix* inverse = reinterpret_cast<SkMatrix*>(inverseHandle);
317        return matrix->invert(inverse);
318    }
319
320    static jfloat mapRadius(jlong matrixHandle, jfloat radius) {
321        SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
322        float result;
323        result = SkScalarToFloat(matrix->mapRadius(radius));
324        return static_cast<jfloat>(result);
325    }
326
327    static jboolean equals(jlong aHandle, jlong bHandle) {
328        const SkMatrix* a = reinterpret_cast<SkMatrix*>(aHandle);
329        const SkMatrix* b = reinterpret_cast<SkMatrix*>(bHandle);
330        return *a == *b;
331    }
332};
333
334static const JNINativeMethod methods[] = {
335    {"nGetNativeFinalizer", "()J", (void*) SkMatrixGlue::getNativeFinalizer},
336    {"nCreate","(J)J", (void*) SkMatrixGlue::create},
337
338    // ------- @FastNative below here ---------------
339    {"nMapPoints","(J[FI[FIIZ)V", (void*) SkMatrixGlue::mapPoints},
340    {"nMapRect","(JLandroid/graphics/RectF;Landroid/graphics/RectF;)Z",
341            (void*) SkMatrixGlue::mapRect__RectFRectF},
342    {"nSetRectToRect","(JLandroid/graphics/RectF;Landroid/graphics/RectF;I)Z",
343            (void*) SkMatrixGlue::setRectToRect},
344    {"nSetPolyToPoly","(J[FI[FII)Z", (void*) SkMatrixGlue::setPolyToPoly},
345    {"nGetValues","(J[F)V", (void*) SkMatrixGlue::getValues},
346    {"nSetValues","(J[F)V", (void*) SkMatrixGlue::setValues},
347
348    // ------- @CriticalNative below here ---------------
349    {"nIsIdentity","(J)Z", (void*) SkMatrixGlue::isIdentity},
350    {"nIsAffine","(J)Z", (void*) SkMatrixGlue::isAffine},
351    {"nRectStaysRect","(J)Z", (void*) SkMatrixGlue::rectStaysRect},
352    {"nReset","(J)V", (void*) SkMatrixGlue::reset},
353    {"nSet","(JJ)V", (void*) SkMatrixGlue::set},
354    {"nSetTranslate","(JFF)V", (void*) SkMatrixGlue::setTranslate},
355    {"nSetScale","(JFFFF)V", (void*) SkMatrixGlue::setScale__FFFF},
356    {"nSetScale","(JFF)V", (void*) SkMatrixGlue::setScale__FF},
357    {"nSetRotate","(JFFF)V", (void*) SkMatrixGlue::setRotate__FFF},
358    {"nSetRotate","(JF)V", (void*) SkMatrixGlue::setRotate__F},
359    {"nSetSinCos","(JFFFF)V", (void*) SkMatrixGlue::setSinCos__FFFF},
360    {"nSetSinCos","(JFF)V", (void*) SkMatrixGlue::setSinCos__FF},
361    {"nSetSkew","(JFFFF)V", (void*) SkMatrixGlue::setSkew__FFFF},
362    {"nSetSkew","(JFF)V", (void*) SkMatrixGlue::setSkew__FF},
363    {"nSetConcat","(JJJ)V", (void*) SkMatrixGlue::setConcat},
364    {"nPreTranslate","(JFF)V", (void*) SkMatrixGlue::preTranslate},
365    {"nPreScale","(JFFFF)V", (void*) SkMatrixGlue::preScale__FFFF},
366    {"nPreScale","(JFF)V", (void*) SkMatrixGlue::preScale__FF},
367    {"nPreRotate","(JFFF)V", (void*) SkMatrixGlue::preRotate__FFF},
368    {"nPreRotate","(JF)V", (void*) SkMatrixGlue::preRotate__F},
369    {"nPreSkew","(JFFFF)V", (void*) SkMatrixGlue::preSkew__FFFF},
370    {"nPreSkew","(JFF)V", (void*) SkMatrixGlue::preSkew__FF},
371    {"nPreConcat","(JJ)V", (void*) SkMatrixGlue::preConcat},
372    {"nPostTranslate","(JFF)V", (void*) SkMatrixGlue::postTranslate},
373    {"nPostScale","(JFFFF)V", (void*) SkMatrixGlue::postScale__FFFF},
374    {"nPostScale","(JFF)V", (void*) SkMatrixGlue::postScale__FF},
375    {"nPostRotate","(JFFF)V", (void*) SkMatrixGlue::postRotate__FFF},
376    {"nPostRotate","(JF)V", (void*) SkMatrixGlue::postRotate__F},
377    {"nPostSkew","(JFFFF)V", (void*) SkMatrixGlue::postSkew__FFFF},
378    {"nPostSkew","(JFF)V", (void*) SkMatrixGlue::postSkew__FF},
379    {"nPostConcat","(JJ)V", (void*) SkMatrixGlue::postConcat},
380    {"nInvert","(JJ)Z", (void*) SkMatrixGlue::invert},
381    {"nMapRadius","(JF)F", (void*) SkMatrixGlue::mapRadius},
382    {"nEquals", "(JJ)Z", (void*) SkMatrixGlue::equals}
383};
384
385static jfieldID sNativeInstanceField;
386
387int register_android_graphics_Matrix(JNIEnv* env) {
388    int result = RegisterMethodsOrDie(env, "android/graphics/Matrix", methods, NELEM(methods));
389
390    jclass clazz = FindClassOrDie(env, "android/graphics/Matrix");
391    sNativeInstanceField = GetFieldIDOrDie(env, clazz, "native_instance", "J");
392
393    return result;
394}
395
396SkMatrix* android_graphics_Matrix_getSkMatrix(JNIEnv* env, jobject matrixObj) {
397    return reinterpret_cast<SkMatrix*>(env->GetLongField(matrixObj, sNativeInstanceField));
398}
399
400}
401