|  | /* libs/android_runtime/android/graphics/PathMeasure.cpp | 
|  | ** | 
|  | ** Copyright 2007, 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. | 
|  | */ | 
|  |  | 
|  | #include "GraphicsJNI.h" | 
|  |  | 
|  | #include "SkMatrix.h" | 
|  | #include "SkPath.h" | 
|  | #include "SkPathMeasure.h" | 
|  | #include "SkPoint.h" | 
|  | #include "SkScalar.h" | 
|  |  | 
|  | /*  We declare an explicit pair, so that we don't have to rely on the java | 
|  | client to be sure not to edit the path while we have an active measure | 
|  | object associated with it. | 
|  |  | 
|  | This costs us the copy of the path, for the sake of not allowing a bad | 
|  | java client to randomly crash (since we can't detect the case where the | 
|  | native path has been modified). | 
|  |  | 
|  | The C side does have this risk, but it chooses for speed over safety. If it | 
|  | later changes this, and is internally safe from changes to the path, then | 
|  | we can remove this explicit copy from our JNI code. | 
|  |  | 
|  | Note that we do not have a reference on the java side to the java path. | 
|  | Were we to not need the native copy here, we would want to add a java | 
|  | reference, so that the java path would not get GD'd while the measure object | 
|  | was still alive. | 
|  | */ | 
|  | struct PathMeasurePair { | 
|  | PathMeasurePair() {} | 
|  | PathMeasurePair(const SkPath& path, bool forceClosed) | 
|  | : fPath(path), fMeasure(fPath, forceClosed) {} | 
|  |  | 
|  | SkPath          fPath;      // copy of the user's path | 
|  | SkPathMeasure   fMeasure;   // this guy points to fPath | 
|  | }; | 
|  |  | 
|  | namespace android { | 
|  |  | 
|  | class SkPathMeasureGlue { | 
|  | public: | 
|  |  | 
|  | static jlong create(JNIEnv* env, jobject clazz, jlong pathHandle, | 
|  | jboolean forceClosedHandle) { | 
|  | const SkPath* path = reinterpret_cast<SkPath*>(pathHandle); | 
|  | bool forceClosed = (forceClosedHandle == JNI_TRUE); | 
|  | PathMeasurePair* pair; | 
|  | if(path) | 
|  | pair = new PathMeasurePair(*path, forceClosed); | 
|  | else | 
|  | pair = new PathMeasurePair; | 
|  | return reinterpret_cast<jlong>(pair); | 
|  | } | 
|  |  | 
|  | static void setPath(JNIEnv* env, jobject clazz, jlong pairHandle, | 
|  | jlong pathHandle, jboolean forceClosedHandle) { | 
|  | PathMeasurePair* pair = reinterpret_cast<PathMeasurePair*>(pairHandle); | 
|  | const SkPath* path = reinterpret_cast<SkPath*>(pathHandle); | 
|  | bool forceClosed = (forceClosedHandle == JNI_TRUE); | 
|  |  | 
|  | if (NULL == path) { | 
|  | pair->fPath.reset(); | 
|  | } else { | 
|  | pair->fPath = *path; | 
|  | } | 
|  | pair->fMeasure.setPath(&pair->fPath, forceClosed); | 
|  | } | 
|  |  | 
|  | static jfloat getLength(JNIEnv* env, jobject clazz, jlong pairHandle) { | 
|  | PathMeasurePair* pair = reinterpret_cast<PathMeasurePair*>(pairHandle); | 
|  | return static_cast<jfloat>(SkScalarToFloat(pair->fMeasure.getLength())); | 
|  | } | 
|  |  | 
|  | static void convertTwoElemFloatArray(JNIEnv* env, jfloatArray array, const SkScalar src[2]) { | 
|  | AutoJavaFloatArray autoArray(env, array, 2); | 
|  | jfloat* ptr = autoArray.ptr(); | 
|  | ptr[0] = SkScalarToFloat(src[0]); | 
|  | ptr[1] = SkScalarToFloat(src[1]); | 
|  | } | 
|  |  | 
|  | static jboolean getPosTan(JNIEnv* env, jobject clazz, jlong pairHandle, jfloat dist, jfloatArray pos, jfloatArray tan) { | 
|  | PathMeasurePair* pair = reinterpret_cast<PathMeasurePair*>(pairHandle); | 
|  | SkScalar    tmpPos[2], tmpTan[2]; | 
|  | SkScalar*   posPtr = pos ? tmpPos : NULL; | 
|  | SkScalar*   tanPtr = tan ? tmpTan : NULL; | 
|  |  | 
|  | if (!pair->fMeasure.getPosTan(dist, (SkPoint*)posPtr, (SkVector*)tanPtr)) { | 
|  | return JNI_FALSE; | 
|  | } | 
|  |  | 
|  | if (pos) { | 
|  | convertTwoElemFloatArray(env, pos, tmpPos); | 
|  | } | 
|  | if (tan) { | 
|  | convertTwoElemFloatArray(env, tan, tmpTan); | 
|  | } | 
|  | return JNI_TRUE; | 
|  | } | 
|  |  | 
|  | static jboolean getMatrix(JNIEnv* env, jobject clazz, jlong pairHandle, jfloat dist, | 
|  | jlong matrixHandle, jint flags) { | 
|  | PathMeasurePair* pair = reinterpret_cast<PathMeasurePair*>(pairHandle); | 
|  | SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle); | 
|  | bool result = pair->fMeasure.getMatrix(dist, matrix, (SkPathMeasure::MatrixFlags)flags); | 
|  | return result ? JNI_TRUE : JNI_FALSE; | 
|  | } | 
|  |  | 
|  | static jboolean getSegment(JNIEnv* env, jobject clazz, jlong pairHandle, jfloat startF, | 
|  | jfloat stopF, jlong dstHandle, jboolean startWithMoveTo) { | 
|  | PathMeasurePair* pair = reinterpret_cast<PathMeasurePair*>(pairHandle); | 
|  | SkPath* dst = reinterpret_cast<SkPath*>(dstHandle); | 
|  | bool result = pair->fMeasure.getSegment(startF, stopF, dst, startWithMoveTo); | 
|  | return result ? JNI_TRUE : JNI_FALSE; | 
|  | } | 
|  |  | 
|  | static jboolean isClosed(JNIEnv* env, jobject clazz, jlong pairHandle) { | 
|  | PathMeasurePair* pair = reinterpret_cast<PathMeasurePair*>(pairHandle); | 
|  | bool result = pair->fMeasure.isClosed(); | 
|  | return result ? JNI_TRUE : JNI_FALSE; | 
|  | } | 
|  |  | 
|  | static jboolean nextContour(JNIEnv* env, jobject clazz, jlong pairHandle) { | 
|  | PathMeasurePair* pair = reinterpret_cast<PathMeasurePair*>(pairHandle); | 
|  | bool result = pair->fMeasure.nextContour(); | 
|  | return result ? JNI_TRUE : JNI_FALSE; | 
|  | } | 
|  |  | 
|  | static void destroy(JNIEnv* env, jobject clazz, jlong pairHandle) { | 
|  | PathMeasurePair* pair = reinterpret_cast<PathMeasurePair*>(pairHandle); | 
|  | delete pair; | 
|  | } | 
|  | }; | 
|  |  | 
|  | static const JNINativeMethod methods[] = { | 
|  | {"native_create",       "(JZ)J",        (void*) SkPathMeasureGlue::create      }, | 
|  | {"native_setPath",      "(JJZ)V",       (void*) SkPathMeasureGlue::setPath     }, | 
|  | {"native_getLength",    "(J)F",         (void*) SkPathMeasureGlue::getLength   }, | 
|  | {"native_getPosTan",    "(JF[F[F)Z",    (void*) SkPathMeasureGlue::getPosTan   }, | 
|  | {"native_getMatrix",    "(JFJI)Z",      (void*) SkPathMeasureGlue::getMatrix   }, | 
|  | {"native_getSegment",   "(JFFJZ)Z",     (void*) SkPathMeasureGlue::getSegment  }, | 
|  | {"native_isClosed",     "(J)Z",         (void*) SkPathMeasureGlue::isClosed    }, | 
|  | {"native_nextContour",  "(J)Z",         (void*) SkPathMeasureGlue::nextContour }, | 
|  | {"native_destroy",      "(J)V",         (void*) SkPathMeasureGlue::destroy     } | 
|  | }; | 
|  |  | 
|  | int register_android_graphics_PathMeasure(JNIEnv* env) { | 
|  | return RegisterMethodsOrDie(env, "android/graphics/PathMeasure", methods, NELEM(methods)); | 
|  | } | 
|  |  | 
|  | } |