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
GetSkRegion(JNIEnv * env,jobject regionObject)32 static inline SkRegion* GetSkRegion(JNIEnv* env, jobject regionObject) {
33 SkRegion* rgn = (SkRegion*)env->GetIntField(regionObject, gRegion_nativeInstanceFieldID);
34 SkASSERT(rgn != NULL);
35 return rgn;
36 }
37
Region_constructor(JNIEnv * env,jobject)38 static SkRegion* Region_constructor(JNIEnv* env, jobject) {
39 return new SkRegion;
40 }
41
Region_destructor(JNIEnv * env,jobject,SkRegion * region)42 static void Region_destructor(JNIEnv* env, jobject, SkRegion* region) {
43 SkASSERT(region);
44 delete region;
45 }
46
Region_setRegion(JNIEnv * env,jobject,SkRegion * dst,const SkRegion * src)47 static void Region_setRegion(JNIEnv* env, jobject, SkRegion* dst, const SkRegion* src) {
48 SkASSERT(dst && src);
49 *dst = *src;
50 }
51
Region_setRect(JNIEnv * env,jobject,SkRegion * dst,int left,int top,int right,int bottom)52 static jboolean Region_setRect(JNIEnv* env, jobject, SkRegion* dst, int left, int top, int right, int bottom) {
53 return dst->setRect(left, top, right, bottom);
54 }
55
Region_setPath(JNIEnv * env,jobject,SkRegion * dst,const SkPath * path,const SkRegion * clip)56 static jboolean Region_setPath(JNIEnv* env, jobject, SkRegion* dst,
57 const SkPath* path, const SkRegion* clip) {
58 SkASSERT(dst && path && clip);
59 return dst->setPath(*path, *clip);
60 }
61
Region_getBounds(JNIEnv * env,jobject,SkRegion * region,jobject rectBounds)62 static jboolean Region_getBounds(JNIEnv* env, jobject, SkRegion* region, jobject rectBounds) {
63 GraphicsJNI::irect_to_jrect(region->getBounds(), env, rectBounds);
64 return !region->isEmpty();
65 }
66
Region_getBoundaryPath(JNIEnv * env,jobject,const SkRegion * region,SkPath * path)67 static jboolean Region_getBoundaryPath(JNIEnv* env, jobject, const SkRegion* region, SkPath* path) {
68 return region->getBoundaryPath(path);
69 }
70
Region_op0(JNIEnv * env,jobject,SkRegion * dst,int left,int top,int right,int bottom,int op)71 static jboolean Region_op0(JNIEnv* env, jobject, SkRegion* dst, int left, int top, int right, int bottom, int op) {
72 SkIRect ir;
73
74 ir.set(left, top, right, bottom);
75 return dst->op(ir, (SkRegion::Op)op);
76 }
77
Region_op1(JNIEnv * env,jobject,SkRegion * dst,jobject rectObject,const SkRegion * region,int op)78 static jboolean Region_op1(JNIEnv* env, jobject, SkRegion* dst, jobject rectObject, const SkRegion* region, int op) {
79 SkIRect ir;
80 GraphicsJNI::jrect_to_irect(env, rectObject, &ir);
81 return dst->op(ir, *region, (SkRegion::Op)op);
82 }
83
Region_op2(JNIEnv * env,jobject,SkRegion * dst,const SkRegion * region1,const SkRegion * region2,int op)84 static jboolean Region_op2(JNIEnv* env, jobject, SkRegion* dst, const SkRegion* region1, const SkRegion* region2, int op) {
85 return dst->op(*region1, *region2, (SkRegion::Op)op);
86 }
87
88 //////////////////////////////////// These are methods, not static
89
Region_isEmpty(JNIEnv * env,jobject region)90 static jboolean Region_isEmpty(JNIEnv* env, jobject region) {
91 return GetSkRegion(env, region)->isEmpty();
92 }
93
Region_isRect(JNIEnv * env,jobject region)94 static jboolean Region_isRect(JNIEnv* env, jobject region) {
95 return GetSkRegion(env, region)->isRect();
96 }
97
Region_isComplex(JNIEnv * env,jobject region)98 static jboolean Region_isComplex(JNIEnv* env, jobject region) {
99 return GetSkRegion(env, region)->isComplex();
100 }
101
Region_contains(JNIEnv * env,jobject region,int x,int y)102 static jboolean Region_contains(JNIEnv* env, jobject region, int x, int y) {
103 return GetSkRegion(env, region)->contains(x, y);
104 }
105
Region_quickContains(JNIEnv * env,jobject region,int left,int top,int right,int bottom)106 static jboolean Region_quickContains(JNIEnv* env, jobject region, int left, int top, int right, int bottom) {
107 return GetSkRegion(env, region)->quickContains(left, top, right, bottom);
108 }
109
Region_quickRejectIIII(JNIEnv * env,jobject region,int left,int top,int right,int bottom)110 static jboolean Region_quickRejectIIII(JNIEnv* env, jobject region, int left, int top, int right, int bottom) {
111 SkIRect ir;
112 ir.set(left, top, right, bottom);
113 return GetSkRegion(env, region)->quickReject(ir);
114 }
115
Region_quickRejectRgn(JNIEnv * env,jobject region,jobject other)116 static jboolean Region_quickRejectRgn(JNIEnv* env, jobject region, jobject other) {
117 return GetSkRegion(env, region)->quickReject(*GetSkRegion(env, other));
118 }
119
Region_translate(JNIEnv * env,jobject region,int x,int y,jobject dst)120 static void Region_translate(JNIEnv* env, jobject region, int x, int y, jobject dst) {
121 SkRegion* rgn = GetSkRegion(env, region);
122 if (dst)
123 rgn->translate(x, y, GetSkRegion(env, dst));
124 else
125 rgn->translate(x, y);
126 }
127
128 // Scale the rectangle by given scale and set the reuslt to the dst.
scale_rect(SkIRect * dst,const SkIRect & src,float scale)129 static void scale_rect(SkIRect* dst, const SkIRect& src, float scale) {
130 dst->fLeft = (int)::roundf(src.fLeft * scale);
131 dst->fTop = (int)::roundf(src.fTop * scale);
132 dst->fRight = (int)::roundf(src.fRight * scale);
133 dst->fBottom = (int)::roundf(src.fBottom * scale);
134 }
135
136 // Scale the region by given scale and set the reuslt to the dst.
137 // dest and src can be the same region instance.
scale_rgn(SkRegion * dst,const SkRegion & src,float scale)138 static void scale_rgn(SkRegion* dst, const SkRegion& src, float scale) {
139 SkRegion tmp;
140 SkRegion::Iterator iter(src);
141
142 for (; !iter.done(); iter.next()) {
143 SkIRect r;
144 scale_rect(&r, iter.rect(), scale);
145 tmp.op(r, SkRegion::kUnion_Op);
146 }
147 dst->swap(tmp);
148 }
149
Region_scale(JNIEnv * env,jobject region,jfloat scale,jobject dst)150 static void Region_scale(JNIEnv* env, jobject region, jfloat scale, jobject dst) {
151 SkRegion* rgn = GetSkRegion(env, region);
152 if (dst)
153 scale_rgn(GetSkRegion(env, dst), *rgn, scale);
154 else
155 scale_rgn(rgn, *rgn, scale);
156 }
157
Region_toString(JNIEnv * env,jobject clazz,SkRegion * region)158 static jstring Region_toString(JNIEnv* env, jobject clazz, SkRegion* region) {
159 char* str = region->toString();
160 if (str == NULL) {
161 return NULL;
162 }
163 jstring result = env->NewStringUTF(str);
164 free(str);
165 return result;
166 }
167
168 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
169
Region_createFromParcel(JNIEnv * env,jobject clazz,jobject parcel)170 static SkRegion* Region_createFromParcel(JNIEnv* env, jobject clazz, jobject parcel)
171 {
172 if (parcel == NULL) {
173 return NULL;
174 }
175
176 android::Parcel* p = android::parcelForJavaObject(env, parcel);
177
178 SkRegion* region = new SkRegion;
179 size_t size = p->readInt32();
180 region->readFromMemory(p->readInplace(size), size);
181
182 return region;
183 }
184
Region_writeToParcel(JNIEnv * env,jobject clazz,const SkRegion * region,jobject parcel)185 static jboolean Region_writeToParcel(JNIEnv* env, jobject clazz, const SkRegion* region, jobject parcel)
186 {
187 if (parcel == NULL) {
188 return false;
189 }
190
191 android::Parcel* p = android::parcelForJavaObject(env, parcel);
192
193 size_t size = region->writeToMemory(NULL);
194 p->writeInt32(size);
195 region->writeToMemory(p->writeInplace(size));
196
197 return true;
198 }
199
200 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
201
Region_equals(JNIEnv * env,jobject clazz,const SkRegion * r1,const SkRegion * r2)202 static jboolean Region_equals(JNIEnv* env, jobject clazz, const SkRegion *r1, const SkRegion* r2)
203 {
204 return (jboolean) (*r1 == *r2);
205 }
206
207 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
208
209 struct RgnIterPair {
210 SkRegion fRgn; // a copy of the caller's region
211 SkRegion::Iterator fIter; // an iterator acting upon the copy (fRgn)
212
RgnIterPairandroid::RgnIterPair213 RgnIterPair(const SkRegion& rgn) : fRgn(rgn) {
214 // have our iterator reference our copy (fRgn), so we know it will be
215 // unchanged for the lifetime of the iterator
216 fIter.reset(fRgn);
217 }
218 };
219
RegionIter_constructor(JNIEnv * env,jobject,const SkRegion * region)220 static RgnIterPair* RegionIter_constructor(JNIEnv* env, jobject, const SkRegion* region)
221 {
222 SkASSERT(region);
223 return new RgnIterPair(*region);
224 }
225
RegionIter_destructor(JNIEnv * env,jobject,RgnIterPair * pair)226 static void RegionIter_destructor(JNIEnv* env, jobject, RgnIterPair* pair)
227 {
228 SkASSERT(pair);
229 delete pair;
230 }
231
RegionIter_next(JNIEnv * env,jobject,RgnIterPair * pair,jobject rectObject)232 static jboolean RegionIter_next(JNIEnv* env, jobject, RgnIterPair* pair, jobject rectObject)
233 {
234 // the caller has checked that rectObject is not nul
235 SkASSERT(pair);
236 SkASSERT(rectObject);
237
238 if (!pair->fIter.done()) {
239 GraphicsJNI::irect_to_jrect(pair->fIter.rect(), env, rectObject);
240 pair->fIter.next();
241 return true;
242 }
243 return false;
244 }
245
246 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
247
248 static JNINativeMethod gRegionIterMethods[] = {
249 { "nativeConstructor", "(I)I", (void*)RegionIter_constructor },
250 { "nativeDestructor", "(I)V", (void*)RegionIter_destructor },
251 { "nativeNext", "(ILandroid/graphics/Rect;)Z", (void*)RegionIter_next }
252 };
253
254 static JNINativeMethod gRegionMethods[] = {
255 // these are static methods
256 { "nativeConstructor", "()I", (void*)Region_constructor },
257 { "nativeDestructor", "(I)V", (void*)Region_destructor },
258 { "nativeSetRegion", "(II)V", (void*)Region_setRegion },
259 { "nativeSetRect", "(IIIII)Z", (void*)Region_setRect },
260 { "nativeSetPath", "(III)Z", (void*)Region_setPath },
261 { "nativeGetBounds", "(ILandroid/graphics/Rect;)Z", (void*)Region_getBounds },
262 { "nativeGetBoundaryPath", "(II)Z", (void*)Region_getBoundaryPath },
263 { "nativeOp", "(IIIIII)Z", (void*)Region_op0 },
264 { "nativeOp", "(ILandroid/graphics/Rect;II)Z", (void*)Region_op1 },
265 { "nativeOp", "(IIII)Z", (void*)Region_op2 },
266 // these are methods that take the java region object
267 { "isEmpty", "()Z", (void*)Region_isEmpty },
268 { "isRect", "()Z", (void*)Region_isRect },
269 { "isComplex", "()Z", (void*)Region_isComplex },
270 { "contains", "(II)Z", (void*)Region_contains },
271 { "quickContains", "(IIII)Z", (void*)Region_quickContains },
272 { "quickReject", "(IIII)Z", (void*)Region_quickRejectIIII },
273 { "quickReject", "(Landroid/graphics/Region;)Z", (void*)Region_quickRejectRgn },
274 { "scale", "(FLandroid/graphics/Region;)V", (void*)Region_scale },
275 { "translate", "(IILandroid/graphics/Region;)V", (void*)Region_translate },
276 { "nativeToString", "(I)Ljava/lang/String;", (void*)Region_toString },
277 // parceling methods
278 { "nativeCreateFromParcel", "(Landroid/os/Parcel;)I", (void*)Region_createFromParcel },
279 { "nativeWriteToParcel", "(ILandroid/os/Parcel;)Z", (void*)Region_writeToParcel },
280 { "nativeEquals", "(II)Z", (void*)Region_equals },
281 };
282
register_android_graphics_Region(JNIEnv * env)283 int register_android_graphics_Region(JNIEnv* env)
284 {
285 jclass clazz = env->FindClass("android/graphics/Region");
286 SkASSERT(clazz);
287
288 gRegion_nativeInstanceFieldID = env->GetFieldID(clazz, "mNativeRegion", "I");
289 SkASSERT(gRegion_nativeInstanceFieldID);
290
291 int result = android::AndroidRuntime::registerNativeMethods(env, "android/graphics/Region",
292 gRegionMethods, SK_ARRAY_COUNT(gRegionMethods));
293 if (result < 0)
294 return result;
295
296 return android::AndroidRuntime::registerNativeMethods(env, "android/graphics/RegionIterator",
297 gRegionIterMethods, SK_ARRAY_COUNT(gRegionIterMethods));
298 }
299
android_graphics_Region_getSkRegion(JNIEnv * env,jobject regionObj)300 SkRegion* android_graphics_Region_getSkRegion(JNIEnv* env, jobject regionObj) {
301 return GetSkRegion(env, regionObj);
302 }
303
304 } // namespace android
305