150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich/*
250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * Copyright (C) 2006 The Android Open Source Project
350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich *
49875750593aae7c2a62f33c620809d49162393ebElliott Hughes * Licensed under the Apache License, Version 2.0 (the "License");
59875750593aae7c2a62f33c620809d49162393ebElliott Hughes * you may not use this file except in compliance with the License.
69875750593aae7c2a62f33c620809d49162393ebElliott Hughes * You may obtain a copy of the License at
750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich *
89875750593aae7c2a62f33c620809d49162393ebElliott Hughes *      http://www.apache.org/licenses/LICENSE-2.0
950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich *
109875750593aae7c2a62f33c620809d49162393ebElliott Hughes * Unless required by applicable law or agreed to in writing, software
119875750593aae7c2a62f33c620809d49162393ebElliott Hughes * distributed under the License is distributed on an "AS IS" BASIS,
129875750593aae7c2a62f33c620809d49162393ebElliott Hughes * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139875750593aae7c2a62f33c620809d49162393ebElliott Hughes * See the License for the specific language governing permissions and
1450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich * limitations under the License.
1550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich */
1650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
1750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichpackage android.graphics;
1850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
199875750593aae7c2a62f33c620809d49162393ebElliott Hughesimport android.os.Parcel;
209875750593aae7c2a62f33c620809d49162393ebElliott Hughesimport android.os.Parcelable;
2150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
2250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevichpublic class Region implements Parcelable {
2350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    /**
2450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich     * @hide
2550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich     */
2650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    public final int mNativeRegion;
2750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
2850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    // the native values for these must match up with the enum in SkRegion.h
2950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    public enum Op {
3050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        DIFFERENCE(0),
3150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        INTERSECT(1),
3250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        UNION(2),
3350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        XOR(3),
3450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        REVERSE_DIFFERENCE(4),
3550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        REPLACE(5);
3650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
3750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        Op(int nativeInt) {
3850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich            this.nativeInt = nativeInt;
3950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        }
4050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
4150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        /**
429875750593aae7c2a62f33c620809d49162393ebElliott Hughes         * @hide
4350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich         */
4450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        public final int nativeInt;
4550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    }
4650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
4750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    /** Create an empty region
4850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    */
4950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    public Region() {
5050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        this(nativeConstructor());
5150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    }
5250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
5350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    /** Return a copy of the specified region
5450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    */
5550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    public Region(Region region) {
5650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        this(nativeConstructor());
5750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        nativeSetRegion(mNativeRegion, region.mNativeRegion);
5850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    }
5950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
6050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    /** Return a region set to the specified rectangle
6150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    */
6250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    public Region(Rect r) {
6350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        mNativeRegion = nativeConstructor();
6450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        nativeSetRect(mNativeRegion, r.left, r.top, r.right, r.bottom);
65e58a97b5d77b59fad1572ba3c0572c7434e8e503Thomas Tafertshofer    }
6650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
6750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    /** Return a region set to the specified rectangle
6850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    */
6950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    public Region(int left, int top, int right, int bottom) {
7050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        mNativeRegion = nativeConstructor();
7150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        nativeSetRect(mNativeRegion, left, top, right, bottom);
7250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    }
7350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
7450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    /** Set the region to the empty region
7550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    */
7650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    public void setEmpty() {
7750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        nativeSetRect(mNativeRegion, 0, 0, 0, 0);
7850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    }
7950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
8050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    /** Set the region to the specified region.
8150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    */
829875750593aae7c2a62f33c620809d49162393ebElliott Hughes    public boolean set(Region region) {
8350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        return nativeSetRegion(mNativeRegion, region.mNativeRegion);
8450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    }
85e58a97b5d77b59fad1572ba3c0572c7434e8e503Thomas Tafertshofer
8650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    /** Set the region to the specified rectangle
879875750593aae7c2a62f33c620809d49162393ebElliott Hughes    */
88e58a97b5d77b59fad1572ba3c0572c7434e8e503Thomas Tafertshofer    public boolean set(Rect r) {
8950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        return nativeSetRect(mNativeRegion, r.left, r.top, r.right, r.bottom);
9050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    }
9150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
9250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    /** Set the region to the specified rectangle
9350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    */
9450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    public boolean set(int left, int top, int right, int bottom) {
9550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        return nativeSetRect(mNativeRegion, left, top, right, bottom);
9650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    }
9750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
9850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    /**
9950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich     * Set the region to the area described by the path and clip.
10050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich     * Return true if the resulting region is non-empty. This produces a region
10150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich     * that is identical to the pixels that would be drawn by the path
10250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich     * (with no antialiasing).
10350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich     */
10450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    public boolean setPath(Path path, Region clip) {
10550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich        return nativeSetPath(mNativeRegion, path.ni(), clip.mNativeRegion);
10650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    }
1079875750593aae7c2a62f33c620809d49162393ebElliott Hughes
1089875750593aae7c2a62f33c620809d49162393ebElliott Hughes    /**
10950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich     * Return true if this region is empty
11050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich     */
11150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    public native boolean isEmpty();
11250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
11350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    /**
11450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich     * Return true if the region contains a single rectangle
11550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich     */
11650d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    public native boolean isRect();
11750d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
11850d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    /**
11950d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich     * Return true if the region contains more than one rectangle
12050d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich     */
12150d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    public native boolean isComplex();
12250d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich
12350d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich    /**
12450d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich     * Return a new Rect set to the bounds of the region. If the region is
12550d0b14689b0ae95ea7b66a8c2f7b955115812ddJack Palevich     * 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