Home | History | Annotate | Download | only in graphics
      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 
     17 package android.graphics;
     18 
     19 import android.os.Parcel;
     20 import android.os.Parcelable;
     21 import android.util.Pools.SynchronizedPool;
     22 
     23 public 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 final int 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.ni(), 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.ni());
    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.ni());
    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                 int 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         } finally {
    384             super.finalize();
    385         }
    386     }
    387 
    388     Region(int ni) {
    389         if (ni == 0) {
    390             throw new RuntimeException();
    391         }
    392         mNativeRegion = ni;
    393     }
    394 
    395     /* add dummy parameter so constructor can be called from jni without
    396        triggering 'not cloneable' exception */
    397     private Region(int ni, int dummy) {
    398         this(ni);
    399     }
    400 
    401     final int ni() {
    402         return mNativeRegion;
    403     }
    404 
    405     private static native boolean nativeEquals(int native_r1, int native_r2);
    406 
    407     private static native int nativeConstructor();
    408     private static native void nativeDestructor(int native_region);
    409 
    410     private static native void nativeSetRegion(int native_dst, int native_src);
    411     private static native boolean nativeSetRect(int native_dst, int left,
    412                                                 int top, int right, int bottom);
    413     private static native boolean nativeSetPath(int native_dst, int native_path,
    414                                                 int native_clip);
    415     private static native boolean nativeGetBounds(int native_region, Rect rect);
    416     private static native boolean nativeGetBoundaryPath(int native_region,
    417                                                         int native_path);
    418 
    419     private static native boolean nativeOp(int native_dst, int left, int top,
    420                                            int right, int bottom, int op);
    421     private static native boolean nativeOp(int native_dst, Rect rect,
    422                                            int native_region, int op);
    423     private static native boolean nativeOp(int native_dst, int native_region1,
    424                                            int native_region2, int op);
    425 
    426     private static native int nativeCreateFromParcel(Parcel p);
    427     private static native boolean nativeWriteToParcel(int native_region,
    428                                                       Parcel p);
    429 
    430     private static native String nativeToString(int native_region);
    431 }
    432