diff options
Diffstat (limited to 'libs/hwui/jni/Region.cpp')
-rw-r--r-- | libs/hwui/jni/Region.cpp | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/libs/hwui/jni/Region.cpp b/libs/hwui/jni/Region.cpp new file mode 100644 index 000000000000..1e064b820591 --- /dev/null +++ b/libs/hwui/jni/Region.cpp @@ -0,0 +1,359 @@ +/* + * 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 |