Region.cpp revision 5e49b497ae2019586937aae0e8159292363728b5
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
28namespace android {
29
30static jfieldID gRegion_nativeInstanceFieldID;
31
32static 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
38static SkRegion* Region_constructor(JNIEnv* env, jobject) {
39    return new SkRegion;
40}
41
42static void Region_destructor(JNIEnv* env, jobject, SkRegion* region) {
43    SkASSERT(region);
44    delete region;
45}
46
47static void Region_setRegion(JNIEnv* env, jobject, SkRegion* dst, const SkRegion* src) {
48    SkASSERT(dst && src);
49    *dst = *src;
50}
51
52static 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
56static 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
62static 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
67static jboolean Region_getBoundaryPath(JNIEnv* env, jobject, const SkRegion* region, SkPath* path) {
68    return region->getBoundaryPath(path);
69}
70
71static 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
78static 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
84static 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
90static jboolean Region_isEmpty(JNIEnv* env, jobject region) {
91    return GetSkRegion(env, region)->isEmpty();
92}
93
94static jboolean Region_isRect(JNIEnv* env, jobject region) {
95    return GetSkRegion(env, region)->isRect();
96}
97
98static jboolean Region_isComplex(JNIEnv* env, jobject region) {
99    return GetSkRegion(env, region)->isComplex();
100}
101
102static jboolean Region_contains(JNIEnv* env, jobject region, int x, int y) {
103    return GetSkRegion(env, region)->contains(x, y);
104}
105
106static 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
110static 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
116static jboolean Region_quickRejectRgn(JNIEnv* env, jobject region, jobject other) {
117    return GetSkRegion(env, region)->quickReject(*GetSkRegion(env, other));
118}
119
120static 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.
129static 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.
138static 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
150static 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
158static 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
170static 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
185static 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
202static jboolean Region_equals(JNIEnv* env, jobject clazz, const SkRegion *r1, const SkRegion* r2)
203{
204  return (jboolean) (*r1 == *r2);
205}
206
207////////////////////////////////////////////////////////////////////////////////////////////////////////////
208
209struct RgnIterPair {
210    SkRegion            fRgn;   // a copy of the caller's region
211    SkRegion::Iterator  fIter;  // an iterator acting upon the copy (fRgn)
212
213    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
220static RgnIterPair* RegionIter_constructor(JNIEnv* env, jobject, const SkRegion* region)
221{
222    SkASSERT(region);
223    return new RgnIterPair(*region);
224}
225
226static void RegionIter_destructor(JNIEnv* env, jobject, RgnIterPair* pair)
227{
228    SkASSERT(pair);
229    delete pair;
230}
231
232static 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
248static 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
254static 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
283int 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
300SkRegion* android_graphics_Region_getSkRegion(JNIEnv* env, jobject regionObj) {
301    return GetSkRegion(env, regionObj);
302}
303
304} // namespace android
305