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