| /* |
| * Copyright (C) 2011 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 "SkRegion.h" |
| #include "SkPath.h" |
| #include "GraphicsJNI.h" |
| |
| #ifdef __ANDROID__ // Layoutlib does not support parcel |
| #include <android/binder_parcel.h> |
| #include <android/binder_parcel_jni.h> |
| #include <android/binder_parcel_utils.h> |
| #endif |
| |
| namespace android { |
| |
| static jfieldID gRegion_nativeInstanceFieldID; |
| |
| static inline jboolean boolTojboolean(bool value) { |
| return value ? JNI_TRUE : JNI_FALSE; |
| } |
| |
| static inline SkRegion* GetSkRegion(JNIEnv* env, jobject regionObject) { |
| jlong regionHandle = env->GetLongField(regionObject, gRegion_nativeInstanceFieldID); |
| SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); |
| SkASSERT(region != NULL); |
| return region; |
| } |
| |
| static jlong Region_constructor(JNIEnv* env, jobject) { |
| return reinterpret_cast<jlong>(new SkRegion); |
| } |
| |
| static void Region_destructor(JNIEnv* env, jobject, jlong regionHandle) { |
| SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); |
| SkASSERT(region); |
| delete region; |
| } |
| |
| static void Region_setRegion(JNIEnv* env, jobject, jlong dstHandle, jlong srcHandle) { |
| SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle); |
| const SkRegion* src = reinterpret_cast<SkRegion*>(srcHandle); |
| SkASSERT(dst && src); |
| *dst = *src; |
| } |
| |
| static jboolean Region_setRect(JNIEnv* env, jobject, jlong dstHandle, jint left, jint top, jint right, jint bottom) { |
| SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle); |
| bool result = dst->setRect({left, top, right, bottom}); |
| return boolTojboolean(result); |
| } |
| |
| static jboolean Region_setPath(JNIEnv* env, jobject, jlong dstHandle, |
| jlong pathHandle, jlong clipHandle) { |
| SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle); |
| const SkPath* path = reinterpret_cast<SkPath*>(pathHandle); |
| const SkRegion* clip = reinterpret_cast<SkRegion*>(clipHandle); |
| SkASSERT(dst && path && clip); |
| bool result = dst->setPath(*path, *clip); |
| return boolTojboolean(result); |
| |
| } |
| |
| static jboolean Region_getBounds(JNIEnv* env, jobject, jlong regionHandle, jobject rectBounds) { |
| SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); |
| GraphicsJNI::irect_to_jrect(region->getBounds(), env, rectBounds); |
| bool result = !region->isEmpty(); |
| return boolTojboolean(result); |
| } |
| |
| static jboolean Region_getBoundaryPath(JNIEnv* env, jobject, jlong regionHandle, jlong pathHandle) { |
| const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); |
| SkPath* path = reinterpret_cast<SkPath*>(pathHandle); |
| bool result = region->getBoundaryPath(path); |
| return boolTojboolean(result); |
| } |
| |
| static jboolean Region_op0(JNIEnv* env, jobject, jlong dstHandle, jint left, jint top, jint right, jint bottom, jint op) { |
| SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle); |
| bool result = dst->op({left, top, right, bottom}, (SkRegion::Op)op); |
| return boolTojboolean(result); |
| } |
| |
| static jboolean Region_op1(JNIEnv* env, jobject, jlong dstHandle, jobject rectObject, jlong regionHandle, jint op) { |
| SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle); |
| const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); |
| SkIRect ir; |
| GraphicsJNI::jrect_to_irect(env, rectObject, &ir); |
| bool result = dst->op(ir, *region, (SkRegion::Op)op); |
| return boolTojboolean(result); |
| } |
| |
| static jboolean Region_op2(JNIEnv* env, jobject, jlong dstHandle, jlong region1Handle, jlong region2Handle, jint op) { |
| SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle); |
| const SkRegion* region1 = reinterpret_cast<SkRegion*>(region1Handle); |
| const SkRegion* region2 = reinterpret_cast<SkRegion*>(region2Handle); |
| bool result = dst->op(*region1, *region2, (SkRegion::Op)op); |
| return boolTojboolean(result); |
| } |
| |
| //////////////////////////////////// These are methods, not static |
| |
| static jboolean Region_isEmpty(JNIEnv* env, jobject region) { |
| bool result = GetSkRegion(env, region)->isEmpty(); |
| return boolTojboolean(result); |
| } |
| |
| static jboolean Region_isRect(JNIEnv* env, jobject region) { |
| bool result = GetSkRegion(env, region)->isRect(); |
| return boolTojboolean(result); |
| } |
| |
| static jboolean Region_isComplex(JNIEnv* env, jobject region) { |
| bool result = GetSkRegion(env, region)->isComplex(); |
| return boolTojboolean(result); |
| } |
| |
| static jboolean Region_contains(JNIEnv* env, jobject region, jint x, jint y) { |
| bool result = GetSkRegion(env, region)->contains(x, y); |
| return boolTojboolean(result); |
| } |
| |
| static jboolean Region_quickContains(JNIEnv* env, jobject region, jint left, jint top, jint right, jint bottom) { |
| bool result = GetSkRegion(env, region)->quickContains({left, top, right, bottom}); |
| return boolTojboolean(result); |
| } |
| |
| static jboolean Region_quickRejectIIII(JNIEnv* env, jobject region, jint left, jint top, jint right, jint bottom) { |
| SkIRect ir; |
| ir.setLTRB(left, top, right, bottom); |
| bool result = GetSkRegion(env, region)->quickReject(ir); |
| return boolTojboolean(result); |
| } |
| |
| static jboolean Region_quickRejectRgn(JNIEnv* env, jobject region, jobject other) { |
| bool result = GetSkRegion(env, region)->quickReject(*GetSkRegion(env, other)); |
| return boolTojboolean(result); |
| } |
| |
| static void Region_translate(JNIEnv* env, jobject region, jint x, jint y, jobject dst) { |
| SkRegion* rgn = GetSkRegion(env, region); |
| if (dst) |
| rgn->translate(x, y, GetSkRegion(env, dst)); |
| else |
| rgn->translate(x, y); |
| } |
| |
| // Scale the rectangle by given scale and set the reuslt to the dst. |
| static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) { |
| dst->fLeft = (int)::roundf(src.fLeft * scale); |
| dst->fTop = (int)::roundf(src.fTop * scale); |
| dst->fRight = (int)::roundf(src.fRight * scale); |
| dst->fBottom = (int)::roundf(src.fBottom * scale); |
| } |
| |
| // Scale the region by given scale and set the reuslt to the dst. |
| // dest and src can be the same region instance. |
| static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) { |
| SkRegion tmp; |
| SkRegion::Iterator iter(src); |
| |
| for (; !iter.done(); iter.next()) { |
| SkIRect r; |
| scale_rect(&r, iter.rect(), scale); |
| tmp.op(r, SkRegion::kUnion_Op); |
| } |
| dst->swap(tmp); |
| } |
| |
| static void Region_scale(JNIEnv* env, jobject region, jfloat scale, jobject dst) { |
| SkRegion* rgn = GetSkRegion(env, region); |
| if (dst) |
| scale_rgn(GetSkRegion(env, dst), *rgn, scale); |
| else |
| scale_rgn(rgn, *rgn, scale); |
| } |
| |
| static jstring Region_toString(JNIEnv* env, jobject clazz, jlong regionHandle) { |
| SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); |
| char* str = region->toString(); |
| if (str == NULL) { |
| return NULL; |
| } |
| jstring result = env->NewStringUTF(str); |
| free(str); |
| return result; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| static jlong Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel) |
| { |
| #ifdef __ANDROID__ // Layoutlib does not support parcel |
| if (parcel == nullptr) { |
| return 0; |
| } |
| |
| std::vector<int32_t> rects; |
| |
| AParcel* p = AParcel_fromJavaParcel(env, parcel); |
| ndk::AParcel_readVector(p, &rects); |
| AParcel_delete(p); |
| |
| if ((rects.size() % 4) != 0) { |
| return 0; |
| } |
| |
| SkRegion* region = new SkRegion; |
| for (size_t x = 0; x + 4 <= rects.size(); x += 4) { |
| region->op({rects[x], rects[x+1], rects[x+2], rects[x+3]}, SkRegion::kUnion_Op); |
| } |
| |
| return reinterpret_cast<jlong>(region); |
| #else |
| return 0; |
| #endif |
| } |
| |
| static jboolean Region_writeToParcel(JNIEnv* env, jobject clazz, jlong regionHandle, jobject parcel) |
| { |
| #ifdef __ANDROID__ // Layoutlib does not support parcel |
| const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); |
| if (parcel == nullptr) { |
| return JNI_FALSE; |
| } |
| |
| std::vector<int32_t> rects; |
| SkRegion::Iterator it(*region); |
| while (!it.done()) { |
| const SkIRect& r = it.rect(); |
| rects.push_back(r.fLeft); |
| rects.push_back(r.fTop); |
| rects.push_back(r.fRight); |
| rects.push_back(r.fBottom); |
| it.next(); |
| } |
| |
| AParcel* p = AParcel_fromJavaParcel(env, parcel); |
| ndk::AParcel_writeVector(p, rects); |
| AParcel_delete(p); |
| |
| return JNI_TRUE; |
| #else |
| return JNI_FALSE; |
| #endif |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| static jboolean Region_equals(JNIEnv* env, jobject clazz, jlong r1Handle, jlong r2Handle) |
| { |
| const SkRegion *r1 = reinterpret_cast<SkRegion*>(r1Handle); |
| const SkRegion *r2 = reinterpret_cast<SkRegion*>(r2Handle); |
| return boolTojboolean(*r1 == *r2); |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| struct RgnIterPair { |
| SkRegion fRgn; // a copy of the caller's region |
| SkRegion::Iterator fIter; // an iterator acting upon the copy (fRgn) |
| |
| explicit RgnIterPair(const SkRegion& rgn) : fRgn(rgn) { |
| // have our iterator reference our copy (fRgn), so we know it will be |
| // unchanged for the lifetime of the iterator |
| fIter.reset(fRgn); |
| } |
| }; |
| |
| static jlong RegionIter_constructor(JNIEnv* env, jobject, jlong regionHandle) |
| { |
| const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle); |
| SkASSERT(region); |
| return reinterpret_cast<jlong>(new RgnIterPair(*region)); |
| } |
| |
| static void RegionIter_destructor(JNIEnv* env, jobject, jlong pairHandle) |
| { |
| RgnIterPair* pair = reinterpret_cast<RgnIterPair*>(pairHandle); |
| SkASSERT(pair); |
| delete pair; |
| } |
| |
| static jboolean RegionIter_next(JNIEnv* env, jobject, jlong pairHandle, jobject rectObject) |
| { |
| RgnIterPair* pair = reinterpret_cast<RgnIterPair*>(pairHandle); |
| // the caller has checked that rectObject is not nul |
| SkASSERT(pair); |
| SkASSERT(rectObject); |
| |
| if (!pair->fIter.done()) { |
| GraphicsJNI::irect_to_jrect(pair->fIter.rect(), env, rectObject); |
| pair->fIter.next(); |
| return JNI_TRUE; |
| } |
| return JNI_FALSE; |
| } |
| |
| //////////////////////////////////////////////////////////////////////////////////////////////////////////// |
| |
| static const JNINativeMethod gRegionIterMethods[] = { |
| { "nativeConstructor", "(J)J", (void*)RegionIter_constructor }, |
| { "nativeDestructor", "(J)V", (void*)RegionIter_destructor }, |
| { "nativeNext", "(JLandroid/graphics/Rect;)Z", (void*)RegionIter_next } |
| }; |
| |
| static const JNINativeMethod gRegionMethods[] = { |
| // these are static methods |
| { "nativeConstructor", "()J", (void*)Region_constructor }, |
| { "nativeDestructor", "(J)V", (void*)Region_destructor }, |
| { "nativeSetRegion", "(JJ)V", (void*)Region_setRegion }, |
| { "nativeSetRect", "(JIIII)Z", (void*)Region_setRect }, |
| { "nativeSetPath", "(JJJ)Z", (void*)Region_setPath }, |
| { "nativeGetBounds", "(JLandroid/graphics/Rect;)Z", (void*)Region_getBounds }, |
| { "nativeGetBoundaryPath", "(JJ)Z", (void*)Region_getBoundaryPath }, |
| { "nativeOp", "(JIIIII)Z", (void*)Region_op0 }, |
| { "nativeOp", "(JLandroid/graphics/Rect;JI)Z", (void*)Region_op1 }, |
| { "nativeOp", "(JJJI)Z", (void*)Region_op2 }, |
| // these are methods that take the java region object |
| { "isEmpty", "()Z", (void*)Region_isEmpty }, |
| { "isRect", "()Z", (void*)Region_isRect }, |
| { "isComplex", "()Z", (void*)Region_isComplex }, |
| { "contains", "(II)Z", (void*)Region_contains }, |
| { "quickContains", "(IIII)Z", (void*)Region_quickContains }, |
| { "quickReject", "(IIII)Z", (void*)Region_quickRejectIIII }, |
| { "quickReject", "(Landroid/graphics/Region;)Z", (void*)Region_quickRejectRgn }, |
| { "scale", "(FLandroid/graphics/Region;)V", (void*)Region_scale }, |
| { "translate", "(IILandroid/graphics/Region;)V", (void*)Region_translate }, |
| { "nativeToString", "(J)Ljava/lang/String;", (void*)Region_toString }, |
| // parceling methods |
| { "nativeCreateFromParcel", "(Landroid/os/Parcel;)J", (void*)Region_createFromParcel }, |
| { "nativeWriteToParcel", "(JLandroid/os/Parcel;)Z", (void*)Region_writeToParcel }, |
| { "nativeEquals", "(JJ)Z", (void*)Region_equals }, |
| }; |
| |
| int register_android_graphics_Region(JNIEnv* env) |
| { |
| jclass clazz = FindClassOrDie(env, "android/graphics/Region"); |
| |
| gRegion_nativeInstanceFieldID = GetFieldIDOrDie(env, clazz, "mNativeRegion", "J"); |
| |
| RegisterMethodsOrDie(env, "android/graphics/Region", gRegionMethods, NELEM(gRegionMethods)); |
| return RegisterMethodsOrDie(env, "android/graphics/RegionIterator", gRegionIterMethods, |
| NELEM(gRegionIterMethods)); |
| } |
| |
| } // namespace android |