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