summaryrefslogtreecommitdiff
path: root/libs/hwui/jni/Region.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/jni/Region.cpp')
-rw-r--r--libs/hwui/jni/Region.cpp359
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