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 <core_jni_helpers.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 == nullptr) {
210 return 0;
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 == nullptr) {
218 return 0;
219 }
220
221 SkRegion* region = new SkRegion;
222 size_t actualSize = region->readFromMemory(regionData, size);
223 if (size != actualSize) {
224 delete region;
225 return 0;
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 == nullptr) {
235 return JNI_FALSE;
236 }
237
238 android::Parcel* p = android::parcelForJavaObject(env, parcel);
239
240 const size_t size = region->writeToMemory(nullptr);
241 p->writeInt32(size);
242 void* dst = p->writeInplace(size);
243 if (dst == nullptr) {
244 ALOGE("Region.writeToParcel could not write %zi bytes", size);
245 return JNI_FALSE;
246 }
247 const size_t sizeWritten = region->writeToMemory(dst);
248 if (sizeWritten != size) {
249 ALOGE("SkRegion::writeToMemory should have written %zi bytes but wrote %zi",
250 size, sizeWritten);
251 }
252
253 return JNI_TRUE;
254 }
255
256 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
257
Region_equals(JNIEnv * env,jobject clazz,jlong r1Handle,jlong r2Handle)258 static jboolean Region_equals(JNIEnv* env, jobject clazz, jlong r1Handle, jlong r2Handle)
259 {
260 const SkRegion *r1 = reinterpret_cast<SkRegion*>(r1Handle);
261 const SkRegion *r2 = reinterpret_cast<SkRegion*>(r2Handle);
262 return boolTojboolean(*r1 == *r2);
263 }
264
265 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
266
267 struct RgnIterPair {
268 SkRegion fRgn; // a copy of the caller's region
269 SkRegion::Iterator fIter; // an iterator acting upon the copy (fRgn)
270
RgnIterPairandroid::RgnIterPair271 RgnIterPair(const SkRegion& rgn) : fRgn(rgn) {
272 // have our iterator reference our copy (fRgn), so we know it will be
273 // unchanged for the lifetime of the iterator
274 fIter.reset(fRgn);
275 }
276 };
277
RegionIter_constructor(JNIEnv * env,jobject,jlong regionHandle)278 static jlong RegionIter_constructor(JNIEnv* env, jobject, jlong regionHandle)
279 {
280 const SkRegion* region = reinterpret_cast<SkRegion*>(regionHandle);
281 SkASSERT(region);
282 return reinterpret_cast<jlong>(new RgnIterPair(*region));
283 }
284
RegionIter_destructor(JNIEnv * env,jobject,jlong pairHandle)285 static void RegionIter_destructor(JNIEnv* env, jobject, jlong pairHandle)
286 {
287 RgnIterPair* pair = reinterpret_cast<RgnIterPair*>(pairHandle);
288 SkASSERT(pair);
289 delete pair;
290 }
291
RegionIter_next(JNIEnv * env,jobject,jlong pairHandle,jobject rectObject)292 static jboolean RegionIter_next(JNIEnv* env, jobject, jlong pairHandle, jobject rectObject)
293 {
294 RgnIterPair* pair = reinterpret_cast<RgnIterPair*>(pairHandle);
295 // the caller has checked that rectObject is not nul
296 SkASSERT(pair);
297 SkASSERT(rectObject);
298
299 if (!pair->fIter.done()) {
300 GraphicsJNI::irect_to_jrect(pair->fIter.rect(), env, rectObject);
301 pair->fIter.next();
302 return JNI_TRUE;
303 }
304 return JNI_FALSE;
305 }
306
307 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
308
309 static JNINativeMethod gRegionIterMethods[] = {
310 { "nativeConstructor", "(J)J", (void*)RegionIter_constructor },
311 { "nativeDestructor", "(J)V", (void*)RegionIter_destructor },
312 { "nativeNext", "(JLandroid/graphics/Rect;)Z", (void*)RegionIter_next }
313 };
314
315 static JNINativeMethod gRegionMethods[] = {
316 // these are static methods
317 { "nativeConstructor", "()J", (void*)Region_constructor },
318 { "nativeDestructor", "(J)V", (void*)Region_destructor },
319 { "nativeSetRegion", "(JJ)V", (void*)Region_setRegion },
320 { "nativeSetRect", "(JIIII)Z", (void*)Region_setRect },
321 { "nativeSetPath", "(JJJ)Z", (void*)Region_setPath },
322 { "nativeGetBounds", "(JLandroid/graphics/Rect;)Z", (void*)Region_getBounds },
323 { "nativeGetBoundaryPath", "(JJ)Z", (void*)Region_getBoundaryPath },
324 { "nativeOp", "(JIIIII)Z", (void*)Region_op0 },
325 { "nativeOp", "(JLandroid/graphics/Rect;JI)Z", (void*)Region_op1 },
326 { "nativeOp", "(JJJI)Z", (void*)Region_op2 },
327 // these are methods that take the java region object
328 { "isEmpty", "()Z", (void*)Region_isEmpty },
329 { "isRect", "()Z", (void*)Region_isRect },
330 { "isComplex", "()Z", (void*)Region_isComplex },
331 { "contains", "(II)Z", (void*)Region_contains },
332 { "quickContains", "(IIII)Z", (void*)Region_quickContains },
333 { "quickReject", "(IIII)Z", (void*)Region_quickRejectIIII },
334 { "quickReject", "(Landroid/graphics/Region;)Z", (void*)Region_quickRejectRgn },
335 { "scale", "(FLandroid/graphics/Region;)V", (void*)Region_scale },
336 { "translate", "(IILandroid/graphics/Region;)V", (void*)Region_translate },
337 { "nativeToString", "(J)Ljava/lang/String;", (void*)Region_toString },
338 // parceling methods
339 { "nativeCreateFromParcel", "(Landroid/os/Parcel;)J", (void*)Region_createFromParcel },
340 { "nativeWriteToParcel", "(JLandroid/os/Parcel;)Z", (void*)Region_writeToParcel },
341 { "nativeEquals", "(JJ)Z", (void*)Region_equals },
342 };
343
register_android_graphics_Region(JNIEnv * env)344 int register_android_graphics_Region(JNIEnv* env)
345 {
346 jclass clazz = FindClassOrDie(env, "android/graphics/Region");
347
348 gRegion_nativeInstanceFieldID = GetFieldIDOrDie(env, clazz, "mNativeRegion", "J");
349
350 RegisterMethodsOrDie(env, "android/graphics/Region", gRegionMethods, NELEM(gRegionMethods));
351 return RegisterMethodsOrDie(env, "android/graphics/RegionIterator", gRegionIterMethods,
352 NELEM(gRegionIterMethods));
353 }
354
android_graphics_Region_getSkRegion(JNIEnv * env,jobject regionObj)355 SkRegion* android_graphics_Region_getSkRegion(JNIEnv* env, jobject regionObj) {
356 return GetSkRegion(env, regionObj);
357 }
358
359 } // namespace android
360