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