Region.java revision 843ef36f7b96cc19ea7d2996b7c8661b41ec3452
1/*
2 * Copyright (C) 2006 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
17package android.graphics;
18
19import android.os.Parcel;
20import android.os.Parcelable;
21
22public class Region implements Parcelable {
23
24    // the native values for these must match up with the enum in SkRegion.h
25    public enum Op {
26        DIFFERENCE(0),
27        INTERSECT(1),
28        UNION(2),
29        XOR(3),
30        REVERSE_DIFFERENCE(4),
31        REPLACE(5);
32
33        Op(int nativeInt) {
34            this.nativeInt = nativeInt;
35        }
36        final int nativeInt;
37    }
38
39    /** Create an empty region
40    */
41    public Region() {
42        this(nativeConstructor());
43    }
44
45    /** Return a copy of the specified region
46    */
47    public Region(Region region) {
48        this(nativeConstructor());
49        nativeSetRegion(mNativeRegion, region.mNativeRegion);
50    }
51
52    /** Return a region set to the specified rectangle
53    */
54    public Region(Rect r) {
55        mNativeRegion = nativeConstructor();
56        nativeSetRect(mNativeRegion, r.left, r.top, r.right, r.bottom);
57    }
58
59    /** Return a region set to the specified rectangle
60    */
61    public Region(int left, int top, int right, int bottom) {
62        mNativeRegion = nativeConstructor();
63        nativeSetRect(mNativeRegion, left, top, right, bottom);
64    }
65
66    /** Set the region to the empty region
67    */
68    public void setEmpty() {
69        nativeSetRect(mNativeRegion, 0, 0, 0, 0);
70    }
71
72    /** Set the region to the specified region.
73    */
74    public boolean set(Region region) {
75        return nativeSetRegion(mNativeRegion, region.mNativeRegion);
76    }
77
78    /** Set the region to the specified rectangle
79    */
80    public boolean set(Rect r) {
81        return nativeSetRect(mNativeRegion, r.left, r.top, r.right, r.bottom);
82    }
83
84    /** Set the region to the specified rectangle
85    */
86    public boolean set(int left, int top, int right, int bottom) {
87        return nativeSetRect(mNativeRegion, left, top, right, bottom);
88    }
89
90    /**
91     * Set the region to the area described by the path and clip.
92     * Return true if the resulting region is non-empty. This produces a region
93     * that is identical to the pixels that would be drawn by the path
94     * (with no antialiasing).
95     */
96    public boolean setPath(Path path, Region clip) {
97        return nativeSetPath(mNativeRegion, path.ni(), clip.mNativeRegion);
98    }
99
100    /**
101     * Return true if this region is empty
102     */
103    public native boolean isEmpty();
104
105    /**
106     * Return true if the region contains a single rectangle
107     */
108    public native boolean isRect();
109
110    /**
111     * Return true if the region contains more than one rectangle
112     */
113    public native boolean isComplex();
114
115    /**
116     * Return a new Rect set to the bounds of the region. If the region is
117     * empty, the Rect will be set to [0, 0, 0, 0]
118     */
119    public Rect getBounds() {
120        Rect r = new Rect();
121        nativeGetBounds(mNativeRegion, r);
122        return r;
123    }
124
125    /**
126     * Set the Rect to the bounds of the region. If the region is empty, the
127     * Rect will be set to [0, 0, 0, 0]
128     */
129    public boolean getBounds(Rect r) {
130        if (r == null) {
131            throw new NullPointerException();
132        }
133        return nativeGetBounds(mNativeRegion, r);
134    }
135
136    /**
137     * Return the boundary of the region as a new Path. If the region is empty,
138     * the path will also be empty.
139     */
140    public Path getBoundaryPath() {
141        Path path = new Path();
142        nativeGetBoundaryPath(mNativeRegion, path.ni());
143        return path;
144    }
145
146    /**
147     * Set the path to the boundary of the region. If the region is empty, the
148     * path will also be empty.
149     */
150    public boolean getBoundaryPath(Path path) {
151        return nativeGetBoundaryPath(mNativeRegion, path.ni());
152    }
153
154    /**
155     * Return true if the region contains the specified point
156     */
157    public native boolean contains(int x, int y);
158
159    /**
160     * Return true if the region is a single rectangle (not complex) and it
161     * contains the specified rectangle. Returning false is not a guarantee
162     * that the rectangle is not contained by this region, but return true is a
163     * guarantee that the rectangle is contained by this region.
164     */
165    public boolean quickContains(Rect r) {
166        return quickContains(r.left, r.top, r.right, r.bottom);
167    }
168
169    /**
170     * Return true if the region is a single rectangle (not complex) and it
171     * contains the specified rectangle. Returning false is not a guarantee
172     * that the rectangle is not contained by this region, but return true is a
173     * guarantee that the rectangle is contained by this region.
174     */
175    public native boolean quickContains(int left, int top, int right,
176                                        int bottom);
177
178    /**
179     * Return true if the region is empty, or if the specified rectangle does
180     * not intersect the region. Returning false is not a guarantee that they
181     * intersect, but returning true is a guarantee that they do not.
182     */
183    public boolean quickReject(Rect r) {
184        return quickReject(r.left, r.top, r.right, r.bottom);
185    }
186
187    /**
188     * Return true if the region is empty, or if the specified rectangle does
189     * not intersect the region. Returning false is not a guarantee that they
190     * intersect, but returning true is a guarantee that they do not.
191     */
192    public native boolean quickReject(int left, int top, int right, int bottom);
193
194    /**
195     * Return true if the region is empty, or if the specified region does not
196     * intersect the region. Returning false is not a guarantee that they
197     * intersect, but returning true is a guarantee that they do not.
198     */
199    public native boolean quickReject(Region rgn);
200
201    /**
202     * Translate the region by [dx, dy]. If the region is empty, do nothing.
203     */
204    public void translate(int dx, int dy) {
205        translate(dx, dy, null);
206    }
207
208    /**
209     * Set the dst region to the result of translating this region by [dx, dy].
210     * If this region is empty, then dst will be set to empty.
211     */
212    public native void translate(int dx, int dy, Region dst);
213
214    /**
215     * Scale the region by the given scale amount. This re-constructs new region by
216     * scaling the rects that this region consists of. New rectis are computed by scaling
217     * coordinates by float, then rounded by roundf() function to integers. This may results
218     * in less internal rects if 0 < scale < 1. Zero and Negative scale result in
219     * an empty region. If this region is empty, do nothing.
220     *
221     * @hide
222     */
223    public void scale(float scale) {
224        scale(scale, null);
225    }
226
227    /**
228     * Set the dst region to the result of scaling this region by the given scale amount.
229     * If this region is empty, then dst will be set to empty.
230     * @hide
231     */
232    public native void scale(float scale, Region dst);
233
234    public final boolean union(Rect r) {
235        return op(r, Op.UNION);
236    }
237
238    /**
239     * Perform the specified Op on this region and the specified rect. Return
240     * true if the result of the op is not empty.
241     */
242    public boolean op(Rect r, Op op) {
243        return nativeOp(mNativeRegion, r.left, r.top, r.right, r.bottom,
244                        op.nativeInt);
245    }
246
247    /**
248     * Perform the specified Op on this region and the specified rect. Return
249     * true if the result of the op is not empty.
250     */
251    public boolean op(int left, int top, int right, int bottom, Op op) {
252        return nativeOp(mNativeRegion, left, top, right, bottom,
253                        op.nativeInt);
254    }
255
256    /**
257     * Perform the specified Op on this region and the specified region. Return
258     * true if the result of the op is not empty.
259     */
260    public boolean op(Region region, Op op) {
261        return op(this, region, op);
262    }
263
264    /**
265     * Set this region to the result of performing the Op on the specified rect
266     * and region. Return true if the result is not empty.
267     */
268    public boolean op(Rect rect, Region region, Op op) {
269        return nativeOp(mNativeRegion, rect, region.mNativeRegion,
270                        op.nativeInt);
271    }
272
273    /**
274     * Set this region to the result of performing the Op on the specified
275     * regions. Return true if the result is not empty.
276     */
277    public boolean op(Region region1, Region region2, Op op) {
278        return nativeOp(mNativeRegion, region1.mNativeRegion,
279                        region2.mNativeRegion, op.nativeInt);
280    }
281
282    //////////////////////////////////////////////////////////////////////////
283
284    public static final Parcelable.Creator<Region> CREATOR
285        = new Parcelable.Creator<Region>() {
286            /**
287            * Rebuild a Region previously stored with writeToParcel().
288             * @param p    Parcel object to read the region from
289             * @return a new region created from the data in the parcel
290             */
291            public Region createFromParcel(Parcel p) {
292                int ni = nativeCreateFromParcel(p);
293                if (ni == 0) {
294                    throw new RuntimeException();
295                }
296                return new Region(ni);
297            }
298            public Region[] newArray(int size) {
299                return new Region[size];
300            }
301    };
302
303    public int describeContents() {
304        return 0;
305    }
306
307    /**
308     * Write the region and its pixels to the parcel. The region can be
309     * rebuilt from the parcel by calling CREATOR.createFromParcel().
310     * @param p    Parcel object to write the region data into
311     */
312    public void writeToParcel(Parcel p, int flags) {
313        if (!nativeWriteToParcel(mNativeRegion, p)) {
314            throw new RuntimeException();
315        }
316    }
317
318    @Override
319    public boolean equals(Object obj) {
320        if (obj == null || !(obj instanceof Region)) {
321            return false;
322        }
323        Region peer = (Region) obj;
324        return nativeEquals(mNativeRegion, peer.mNativeRegion);
325    }
326
327    protected void finalize() throws Throwable {
328        nativeDestructor(mNativeRegion);
329    }
330
331    /*package*/ Region(int ni) {
332        if (ni == 0) {
333            throw new RuntimeException();
334        }
335        mNativeRegion = ni;
336    }
337
338    /* add dummy parameter so constructor can be called from jni without
339       triggering 'not cloneable' exception */
340    private Region(int ni, int dummy) {
341        this(ni);
342    }
343
344    /*package*/ final int ni() {
345        return mNativeRegion;
346    }
347
348    private static native int nativeConstructor();
349    private static native void nativeDestructor(int native_region);
350
351    private static native boolean nativeSetRegion(int native_dst,
352                                                  int native_src);
353    private static native boolean nativeSetRect(int native_dst, int left,
354                                                int top, int right, int bottom);
355    private static native boolean nativeSetPath(int native_dst, int native_path,
356                                                int native_clip);
357    private static native boolean nativeGetBounds(int native_region, Rect rect);
358    private static native boolean nativeGetBoundaryPath(int native_region,
359                                                        int native_path);
360
361    private static native boolean nativeOp(int native_dst, int left, int top,
362                                           int right, int bottom, int op);
363    private static native boolean nativeOp(int native_dst, Rect rect,
364                                           int native_region, int op);
365    private static native boolean nativeOp(int native_dst, int native_region1,
366                                           int native_region2, int op);
367
368    private static native int nativeCreateFromParcel(Parcel p);
369    private static native boolean nativeWriteToParcel(int native_region,
370                                                      Parcel p);
371
372    private static native boolean nativeEquals(int native_r1, int native_r2);
373
374    private final int mNativeRegion;
375}
376