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