1 /* libs/android_runtime/android/graphics/PathMeasure.cpp
2 **
3 ** Copyright 2007, 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
20 #include "SkPathMeasure.h"
21
22 /* We declare an explicit pair, so that we don't have to rely on the java
23 client to be sure not to edit the path while we have an active measure
24 object associated with it.
25
26 This costs us the copy of the path, for the sake of not allowing a bad
27 java client to randomly crash (since we can't detect the case where the
28 native path has been modified).
29
30 The C side does have this risk, but it chooses for speed over safety. If it
31 later changes this, and is internally safe from changes to the path, then
32 we can remove this explicit copy from our JNI code.
33
34 Note that we do not have a reference on the java side to the java path.
35 Were we to not need the native copy here, we would want to add a java
36 reference, so that the java path would not get GD'd while the measure object
37 was still alive.
38 */
39 struct PathMeasurePair {
PathMeasurePairPathMeasurePair40 PathMeasurePair() {}
PathMeasurePairPathMeasurePair41 PathMeasurePair(const SkPath& path, bool forceClosed)
42 : fPath(path), fMeasure(fPath, forceClosed) {}
43
44 SkPath fPath; // copy of the user's path
45 SkPathMeasure fMeasure; // this guy points to fPath
46 };
47
48 namespace android {
49
50 class SkPathMeasureGlue {
51 public:
52
create(JNIEnv * env,jobject clazz,jlong pathHandle,jboolean forceClosedHandle)53 static jlong create(JNIEnv* env, jobject clazz, jlong pathHandle,
54 jboolean forceClosedHandle) {
55 const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
56 bool forceClosed = (forceClosedHandle == JNI_TRUE);
57 PathMeasurePair* pair;
58 if(path)
59 pair = new PathMeasurePair(*path, forceClosed);
60 else
61 pair = new PathMeasurePair;
62 return reinterpret_cast<jlong>(pair);
63 }
64
setPath(JNIEnv * env,jobject clazz,jlong pairHandle,jlong pathHandle,jboolean forceClosedHandle)65 static void setPath(JNIEnv* env, jobject clazz, jlong pairHandle,
66 jlong pathHandle, jboolean forceClosedHandle) {
67 PathMeasurePair* pair = reinterpret_cast<PathMeasurePair*>(pairHandle);
68 const SkPath* path = reinterpret_cast<SkPath*>(pathHandle);
69 bool forceClosed = (forceClosedHandle == JNI_TRUE);
70
71 if (NULL == path) {
72 pair->fPath.reset();
73 } else {
74 pair->fPath = *path;
75 }
76 pair->fMeasure.setPath(&pair->fPath, forceClosed);
77 }
78
getLength(JNIEnv * env,jobject clazz,jlong pairHandle)79 static jfloat getLength(JNIEnv* env, jobject clazz, jlong pairHandle) {
80 PathMeasurePair* pair = reinterpret_cast<PathMeasurePair*>(pairHandle);
81 return static_cast<jfloat>(SkScalarToFloat(pair->fMeasure.getLength()));
82 }
83
convertTwoElemFloatArray(JNIEnv * env,jfloatArray array,const SkScalar src[2])84 static void convertTwoElemFloatArray(JNIEnv* env, jfloatArray array, const SkScalar src[2]) {
85 AutoJavaFloatArray autoArray(env, array, 2);
86 jfloat* ptr = autoArray.ptr();
87 ptr[0] = SkScalarToFloat(src[0]);
88 ptr[1] = SkScalarToFloat(src[1]);
89 }
90
getPosTan(JNIEnv * env,jobject clazz,jlong pairHandle,jfloat dist,jfloatArray pos,jfloatArray tan)91 static jboolean getPosTan(JNIEnv* env, jobject clazz, jlong pairHandle, jfloat dist, jfloatArray pos, jfloatArray tan) {
92 PathMeasurePair* pair = reinterpret_cast<PathMeasurePair*>(pairHandle);
93 SkScalar tmpPos[2], tmpTan[2];
94 SkScalar* posPtr = pos ? tmpPos : NULL;
95 SkScalar* tanPtr = tan ? tmpTan : NULL;
96
97 if (!pair->fMeasure.getPosTan(dist, (SkPoint*)posPtr, (SkVector*)tanPtr)) {
98 return JNI_FALSE;
99 }
100
101 if (pos) {
102 convertTwoElemFloatArray(env, pos, tmpPos);
103 }
104 if (tan) {
105 convertTwoElemFloatArray(env, tan, tmpTan);
106 }
107 return JNI_TRUE;
108 }
109
getMatrix(JNIEnv * env,jobject clazz,jlong pairHandle,jfloat dist,jlong matrixHandle,jint flags)110 static jboolean getMatrix(JNIEnv* env, jobject clazz, jlong pairHandle, jfloat dist,
111 jlong matrixHandle, jint flags) {
112 PathMeasurePair* pair = reinterpret_cast<PathMeasurePair*>(pairHandle);
113 SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
114 bool result = pair->fMeasure.getMatrix(dist, matrix, (SkPathMeasure::MatrixFlags)flags);
115 return result ? JNI_TRUE : JNI_FALSE;
116 }
117
getSegment(JNIEnv * env,jobject clazz,jlong pairHandle,jfloat startF,jfloat stopF,jlong dstHandle,jboolean startWithMoveTo)118 static jboolean getSegment(JNIEnv* env, jobject clazz, jlong pairHandle, jfloat startF,
119 jfloat stopF, jlong dstHandle, jboolean startWithMoveTo) {
120 PathMeasurePair* pair = reinterpret_cast<PathMeasurePair*>(pairHandle);
121 SkPath* dst = reinterpret_cast<SkPath*>(dstHandle);
122 bool result = pair->fMeasure.getSegment(startF, stopF, dst, startWithMoveTo);
123 return result ? JNI_TRUE : JNI_FALSE;
124 }
125
isClosed(JNIEnv * env,jobject clazz,jlong pairHandle)126 static jboolean isClosed(JNIEnv* env, jobject clazz, jlong pairHandle) {
127 PathMeasurePair* pair = reinterpret_cast<PathMeasurePair*>(pairHandle);
128 bool result = pair->fMeasure.isClosed();
129 return result ? JNI_TRUE : JNI_FALSE;
130 }
131
nextContour(JNIEnv * env,jobject clazz,jlong pairHandle)132 static jboolean nextContour(JNIEnv* env, jobject clazz, jlong pairHandle) {
133 PathMeasurePair* pair = reinterpret_cast<PathMeasurePair*>(pairHandle);
134 bool result = pair->fMeasure.nextContour();
135 return result ? JNI_TRUE : JNI_FALSE;
136 }
137
destroy(JNIEnv * env,jobject clazz,jlong pairHandle)138 static void destroy(JNIEnv* env, jobject clazz, jlong pairHandle) {
139 PathMeasurePair* pair = reinterpret_cast<PathMeasurePair*>(pairHandle);
140 delete pair;
141 }
142 };
143
144 static const JNINativeMethod methods[] = {
145 {"native_create", "(JZ)J", (void*) SkPathMeasureGlue::create },
146 {"native_setPath", "(JJZ)V", (void*) SkPathMeasureGlue::setPath },
147 {"native_getLength", "(J)F", (void*) SkPathMeasureGlue::getLength },
148 {"native_getPosTan", "(JF[F[F)Z", (void*) SkPathMeasureGlue::getPosTan },
149 {"native_getMatrix", "(JFJI)Z", (void*) SkPathMeasureGlue::getMatrix },
150 {"native_getSegment", "(JFFJZ)Z", (void*) SkPathMeasureGlue::getSegment },
151 {"native_isClosed", "(J)Z", (void*) SkPathMeasureGlue::isClosed },
152 {"native_nextContour", "(J)Z", (void*) SkPathMeasureGlue::nextContour },
153 {"native_destroy", "(J)V", (void*) SkPathMeasureGlue::destroy }
154 };
155
register_android_graphics_PathMeasure(JNIEnv * env)156 int register_android_graphics_PathMeasure(JNIEnv* env) {
157 return RegisterMethodsOrDie(env, "android/graphics/PathMeasure", methods, NELEM(methods));
158 }
159
160 }
161