• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "SkRegion.h"
18 #include "SkPath.h"
19 #include "GraphicsJNI.h"
20 
21 #include <binder/Parcel.h>
22 #include "android_os_Parcel.h"
23 #include "android_util_Binder.h"
24 
25 #include <jni.h>
26 #include <android_runtime/AndroidRuntime.h>
27 
28 namespace android {
29 
30 static jfieldID gRegion_nativeInstanceFieldID;
31 
boolTojboolean(bool value)32 static inline jboolean boolTojboolean(bool value) {
33     return value ? JNI_TRUE : JNI_FALSE;
34 }
35 
GetSkRegion(JNIEnv * env,jobject regionObject)36 static inline SkRegion* GetSkRegion(JNIEnv* env, jobject regionObject) {
37     jlong regionHandle = env->GetLongField(regionObject, gRegion_nativeInstanceFieldID);
38     SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
39     SkASSERT(region != NULL);
40     return region;
41 }
42 
Region_constructor(JNIEnv * env,jobject)43 static jlong Region_constructor(JNIEnv* env, jobject) {
44     return reinterpret_cast<jlong>(new SkRegion);
45 }
46 
Region_destructor(JNIEnv * env,jobject,jlong regionHandle)47 static void Region_destructor(JNIEnv* env, jobject, jlong regionHandle) {
48     SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
49     SkASSERT(region);
50     delete region;
51 }
52 
Region_setRegion(JNIEnv * env,jobject,jlong dstHandle,jlong srcHandle)53 static void Region_setRegion(JNIEnv* env, jobject, jlong dstHandle, jlong srcHandle) {
54     SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle);
55     const SkRegion* src = reinterpret_cast<SkRegion*>(srcHandle);
56     SkASSERT(dst && src);
57     *dst = *src;
58 }
59 
Region_setRect(JNIEnv * env,jobject,jlong dstHandle,jint left,jint top,jint right,jint bottom)60 static jboolean Region_setRect(JNIEnv* env, jobject, jlong dstHandle, jint left, jint top, jint right, jint bottom) {
61     SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle);
62     bool result = dst->setRect(left, top, right, bottom);
63     return boolTojboolean(result);
64 }
65 
Region_setPath(JNIEnv * env,jobject,jlong dstHandle,jlong pathHandle,jlong clipHandle)66 static jboolean Region_setPath(JNIEnv* env, jobject, jlong dstHandle,
67                                jlong pathHandle, jlong clipHandle) {
68     SkRegion*       dst  = reinterpret_cast<SkRegion*>(dstHandle);
69     const SkPath*   path = reinterpret_cast<SkPath*>(pathHandle);
70     const SkRegion* clip = reinterpret_cast<SkRegion*>(clipHandle);
71     SkASSERT(dst && path && clip);
72     bool result = dst->setPath(*path, *clip);
73     return boolTojboolean(result);
74 
75 }
76 
Region_getBounds(JNIEnv * env,jobject,jlong regionHandle,jobject rectBounds)77 static jboolean Region_getBounds(JNIEnv* env, jobject, jlong regionHandle, jobject rectBounds) {
78     SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
79     GraphicsJNI::irect_to_jrect(region->getBounds(), env, rectBounds);
80     bool result = !region->isEmpty();
81     return boolTojboolean(result);
82 }
83 
Region_getBoundaryPath(JNIEnv * env,jobject,jlong regionHandle,jlong pathHandle)84 static jboolean Region_getBoundaryPath(JNIEnv* env, jobject, jlong regionHandle, jlong pathHandle) {
85     const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
86     SkPath*   path = reinterpret_cast<SkPath*>(pathHandle);
87     bool result = region->getBoundaryPath(path);
88     return boolTojboolean(result);
89 }
90 
Region_op0(JNIEnv * env,jobject,jlong dstHandle,jint left,jint top,jint right,jint bottom,jint op)91 static jboolean Region_op0(JNIEnv* env, jobject, jlong dstHandle, jint left, jint top, jint right, jint bottom, jint op) {
92     SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle);
93     SkIRect ir;
94 
95     ir.set(left, top, right, bottom);
96     bool result = dst->op(ir, (SkRegion::Op)op);
97     return boolTojboolean(result);
98 }
99 
Region_op1(JNIEnv * env,jobject,jlong dstHandle,jobject rectObject,jlong regionHandle,jint op)100 static jboolean Region_op1(JNIEnv* env, jobject, jlong dstHandle, jobject rectObject, jlong regionHandle, jint op) {
101     SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle);
102     const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
103     SkIRect    ir;
104     GraphicsJNI::jrect_to_irect(env, rectObject, &ir);
105     bool result = dst->op(ir, *region, (SkRegion::Op)op);
106     return boolTojboolean(result);
107 }
108 
Region_op2(JNIEnv * env,jobject,jlong dstHandle,jlong region1Handle,jlong region2Handle,jint op)109 static jboolean Region_op2(JNIEnv* env, jobject, jlong dstHandle, jlong region1Handle, jlong region2Handle, jint op) {
110     SkRegion* dst = reinterpret_cast<SkRegion*>(dstHandle);
111     const SkRegion* region1 = reinterpret_cast<SkRegion*>(region1Handle);
112     const SkRegion* region2 = reinterpret_cast<SkRegion*>(region2Handle);
113     bool result = dst->op(*region1, *region2, (SkRegion::Op)op);
114     return boolTojboolean(result);
115 }
116 
117 ////////////////////////////////////  These are methods, not static
118 
Region_isEmpty(JNIEnv * env,jobject region)119 static jboolean Region_isEmpty(JNIEnv* env, jobject region) {
120     bool result = GetSkRegion(env, region)->isEmpty();
121     return boolTojboolean(result);
122 }
123 
Region_isRect(JNIEnv * env,jobject region)124 static jboolean Region_isRect(JNIEnv* env, jobject region) {
125     bool result = GetSkRegion(env, region)->isRect();
126     return boolTojboolean(result);
127 }
128 
Region_isComplex(JNIEnv * env,jobject region)129 static jboolean Region_isComplex(JNIEnv* env, jobject region) {
130     bool result = GetSkRegion(env, region)->isComplex();
131     return boolTojboolean(result);
132 }
133 
Region_contains(JNIEnv * env,jobject region,jint x,jint y)134 static jboolean Region_contains(JNIEnv* env, jobject region, jint x, jint y) {
135     bool result = GetSkRegion(env, region)->contains(x, y);
136     return boolTojboolean(result);
137 }
138 
Region_quickContains(JNIEnv * env,jobject region,jint left,jint top,jint right,jint bottom)139 static jboolean Region_quickContains(JNIEnv* env, jobject region, jint left, jint top, jint right, jint bottom) {
140     bool result = GetSkRegion(env, region)->quickContains(left, top, right, bottom);
141     return boolTojboolean(result);
142 }
143 
Region_quickRejectIIII(JNIEnv * env,jobject region,jint left,jint top,jint right,jint bottom)144 static jboolean Region_quickRejectIIII(JNIEnv* env, jobject region, jint left, jint top, jint right, jint bottom) {
145     SkIRect ir;
146     ir.set(left, top, right, bottom);
147     bool result = GetSkRegion(env, region)->quickReject(ir);
148     return boolTojboolean(result);
149 }
150 
Region_quickRejectRgn(JNIEnv * env,jobject region,jobject other)151 static jboolean Region_quickRejectRgn(JNIEnv* env, jobject region, jobject other) {
152     bool result = GetSkRegion(env, region)->quickReject(*GetSkRegion(env, other));
153     return boolTojboolean(result);
154 }
155 
Region_translate(JNIEnv * env,jobject region,jint x,jint y,jobject dst)156 static void Region_translate(JNIEnv* env, jobject region, jint x, jint y, jobject dst) {
157     SkRegion* rgn = GetSkRegion(env, region);
158     if (dst)
159         rgn->translate(x, y, GetSkRegion(env, dst));
160     else
161         rgn->translate(x, y);
162 }
163 
164 // Scale the rectangle by given scale and set the reuslt to the dst.
scale_rect(SkIRect * dst,const SkIRect & src,float scale)165 static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
166    dst->fLeft = (int)::roundf(src.fLeft * scale);
167    dst->fTop = (int)::roundf(src.fTop * scale);
168    dst->fRight = (int)::roundf(src.fRight * scale);
169    dst->fBottom = (int)::roundf(src.fBottom * scale);
170 }
171 
172 // Scale the region by given scale and set the reuslt to the dst.
173 // dest and src can be the same region instance.
scale_rgn(SkRegion * dst,const SkRegion & src,float scale)174 static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
175    SkRegion tmp;
176    SkRegion::Iterator iter(src);
177 
178    for (; !iter.done(); iter.next()) {
179        SkIRect r;
180        scale_rect(&r, iter.rect(), scale);
181        tmp.op(r, SkRegion::kUnion_Op);
182    }
183    dst->swap(tmp);
184 }
185 
Region_scale(JNIEnv * env,jobject region,jfloat scale,jobject dst)186 static void Region_scale(JNIEnv* env, jobject region, jfloat scale, jobject dst) {
187     SkRegion* rgn = GetSkRegion(env, region);
188     if (dst)
189         scale_rgn(GetSkRegion(env, dst), *rgn, scale);
190     else
191         scale_rgn(rgn, *rgn, scale);
192 }
193 
Region_toString(JNIEnv * env,jobject clazz,jlong regionHandle)194 static jstring Region_toString(JNIEnv* env, jobject clazz, jlong regionHandle) {
195     SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
196     char* str = region->toString();
197     if (str == NULL) {
198         return NULL;
199     }
200     jstring result = env->NewStringUTF(str);
201     free(str);
202     return result;
203 }
204 
205 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
206 
Region_createFromParcel(JNIEnv * env,jobject clazz,jobject parcel)207 static jlong Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel)
208 {
209     if (parcel == NULL) {
210         return NULL;
211     }
212 
213     android::Parcel* p = android::parcelForJavaObject(env, parcel);
214 
215     const size_t size = p->readInt32();
216     const void* regionData = p->readInplace(size);
217     if (regionData == NULL) {
218         return NULL;
219     }
220     SkRegion* region = new SkRegion;
221     size_t actualSize = region->readFromMemory(regionData, size);
222 
223     if (size != actualSize) {
224         delete region;
225         return NULL;
226     }
227 
228     return reinterpret_cast<jlong>(region);
229 }
230 
Region_writeToParcel(JNIEnv * env,jobject clazz,jlong regionHandle,jobject parcel)231 static jboolean Region_writeToParcel(JNIEnv* env, jobject clazz, jlong regionHandle, jobject parcel)
232 {
233     const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
234     if (parcel == NULL) {
235         return JNI_FALSE;
236     }
237 
238     android::Parcel* p = android::parcelForJavaObject(env, parcel);
239 
240     size_t size = region->writeToMemory(NULL);
241     p->writeInt32(size);
242     region->writeToMemory(p->writeInplace(size));
243 
244     return JNI_TRUE;
245 }
246 
247 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
248 
Region_equals(JNIEnv * env,jobject clazz,jlong r1Handle,jlong r2Handle)249 static jboolean Region_equals(JNIEnv* env, jobject clazz, jlong r1Handle, jlong r2Handle)
250 {
251     const SkRegion *r1 = reinterpret_cast<SkRegion*>(r1Handle);
252     const SkRegion *r2 = reinterpret_cast<SkRegion*>(r2Handle);
253     return boolTojboolean(*r1 == *r2);
254 }
255 
256 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
257 
258 struct RgnIterPair {
259     SkRegion            fRgn;   // a copy of the caller's region
260     SkRegion::Iterator  fIter;  // an iterator acting upon the copy (fRgn)
261 
RgnIterPairandroid::RgnIterPair262     RgnIterPair(const SkRegion& rgn) : fRgn(rgn) {
263         // have our iterator reference our copy (fRgn), so we know it will be
264         // unchanged for the lifetime of the iterator
265         fIter.reset(fRgn);
266     }
267 };
268 
RegionIter_constructor(JNIEnv * env,jobject,jlong regionHandle)269 static jlong RegionIter_constructor(JNIEnv* env, jobject, jlong regionHandle)
270 {
271     const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
272     SkASSERT(region);
273     return reinterpret_cast<jlong>(new RgnIterPair(*region));
274 }
275 
RegionIter_destructor(JNIEnv * env,jobject,jlong pairHandle)276 static void RegionIter_destructor(JNIEnv* env, jobject, jlong pairHandle)
277 {
278     RgnIterPair* pair = reinterpret_cast<RgnIterPair*>(pairHandle);
279     SkASSERT(pair);
280     delete pair;
281 }
282 
RegionIter_next(JNIEnv * env,jobject,jlong pairHandle,jobject rectObject)283 static jboolean RegionIter_next(JNIEnv* env, jobject, jlong pairHandle, jobject rectObject)
284 {
285     RgnIterPair* pair = reinterpret_cast<RgnIterPair*>(pairHandle);
286     // the caller has checked that rectObject is not nul
287     SkASSERT(pair);
288     SkASSERT(rectObject);
289 
290     if (!pair->fIter.done()) {
291         GraphicsJNI::irect_to_jrect(pair->fIter.rect(), env, rectObject);
292         pair->fIter.next();
293         return JNI_TRUE;
294     }
295     return JNI_FALSE;
296 }
297 
298 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
299 
300 static JNINativeMethod gRegionIterMethods[] = {
301     { "nativeConstructor",  "(J)J",                         (void*)RegionIter_constructor   },
302     { "nativeDestructor",   "(J)V",                         (void*)RegionIter_destructor    },
303     { "nativeNext",         "(JLandroid/graphics/Rect;)Z",  (void*)RegionIter_next          }
304 };
305 
306 static JNINativeMethod gRegionMethods[] = {
307     // these are static methods
308     { "nativeConstructor",      "()J",                              (void*)Region_constructor       },
309     { "nativeDestructor",       "(J)V",                             (void*)Region_destructor        },
310     { "nativeSetRegion",        "(JJ)V",                            (void*)Region_setRegion         },
311     { "nativeSetRect",          "(JIIII)Z",                         (void*)Region_setRect           },
312     { "nativeSetPath",          "(JJJ)Z",                           (void*)Region_setPath           },
313     { "nativeGetBounds",        "(JLandroid/graphics/Rect;)Z",      (void*)Region_getBounds         },
314     { "nativeGetBoundaryPath",  "(JJ)Z",                            (void*)Region_getBoundaryPath   },
315     { "nativeOp",               "(JIIIII)Z",                        (void*)Region_op0               },
316     { "nativeOp",               "(JLandroid/graphics/Rect;JI)Z",    (void*)Region_op1               },
317     { "nativeOp",               "(JJJI)Z",                          (void*)Region_op2               },
318     // these are methods that take the java region object
319     { "isEmpty",                "()Z",                              (void*)Region_isEmpty           },
320     { "isRect",                 "()Z",                              (void*)Region_isRect            },
321     { "isComplex",              "()Z",                              (void*)Region_isComplex         },
322     { "contains",               "(II)Z",                            (void*)Region_contains          },
323     { "quickContains",          "(IIII)Z",                          (void*)Region_quickContains     },
324     { "quickReject",            "(IIII)Z",                          (void*)Region_quickRejectIIII   },
325     { "quickReject",            "(Landroid/graphics/Region;)Z",     (void*)Region_quickRejectRgn    },
326     { "scale",                  "(FLandroid/graphics/Region;)V",    (void*)Region_scale             },
327     { "translate",              "(IILandroid/graphics/Region;)V",   (void*)Region_translate         },
328     { "nativeToString",         "(J)Ljava/lang/String;",            (void*)Region_toString          },
329     // parceling methods
330     { "nativeCreateFromParcel", "(Landroid/os/Parcel;)J",           (void*)Region_createFromParcel  },
331     { "nativeWriteToParcel",    "(JLandroid/os/Parcel;)Z",          (void*)Region_writeToParcel     },
332     { "nativeEquals",           "(JJ)Z",                            (void*)Region_equals            },
333 };
334 
register_android_graphics_Region(JNIEnv * env)335 int register_android_graphics_Region(JNIEnv* env)
336 {
337     jclass clazz = env->FindClass("android/graphics/Region");
338     SkASSERT(clazz);
339 
340     gRegion_nativeInstanceFieldID = env->GetFieldID(clazz, "mNativeRegion", "J");
341     SkASSERT(gRegion_nativeInstanceFieldID);
342 
343     int result = android::AndroidRuntime::registerNativeMethods(env, "android/graphics/Region",
344                                                              gRegionMethods, SK_ARRAY_COUNT(gRegionMethods));
345     if (result < 0)
346         return result;
347 
348     return android::AndroidRuntime::registerNativeMethods(env, "android/graphics/RegionIterator",
349                                                        gRegionIterMethods, SK_ARRAY_COUNT(gRegionIterMethods));
350 }
351 
android_graphics_Region_getSkRegion(JNIEnv * env,jobject regionObj)352 SkRegion* android_graphics_Region_getSkRegion(JNIEnv* env, jobject regionObj) {
353     return GetSkRegion(env, regionObj);
354 }
355 
356 } // namespace android
357