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