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