blob: ec7f7a05b685d9e56c27fa6e377aa980bc9dece7 [file] [log] [blame]
The Android Open Source Project9066cfe2009-03-03 19:31:44 -08001/*
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
Jake Wharton22c3c8d2018-06-05 12:50:58 -040019import android.annotation.NonNull;
Mathew Inwood0d649f22018-07-31 14:29:22 +010020import android.annotation.UnsupportedAppUsage;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080021import android.os.Parcel;
22import android.os.Parcelable;
Svetoslav Ganov545252f2012-12-10 18:29:24 -080023import android.util.Pools.SynchronizedPool;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080024
25public class Region implements Parcelable {
Svetoslav Ganov545252f2012-12-10 18:29:24 -080026
27 private static final int MAX_POOL_SIZE = 10;
28
29 private static final SynchronizedPool<Region> sPool =
30 new SynchronizedPool<Region>(MAX_POOL_SIZE);
31
Romain Guy61c8c9c2010-08-09 20:48:09 -070032 /**
33 * @hide
34 */
Mathew Inwood0d649f22018-07-31 14:29:22 +010035 @UnsupportedAppUsage
Hans Boehmffa84e02014-11-11 17:01:37 -080036 public long mNativeRegion;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080037
38 // the native values for these must match up with the enum in SkRegion.h
39 public enum Op {
40 DIFFERENCE(0),
41 INTERSECT(1),
42 UNION(2),
43 XOR(3),
44 REVERSE_DIFFERENCE(4),
45 REPLACE(5);
46
47 Op(int nativeInt) {
48 this.nativeInt = nativeInt;
49 }
Romain Guy079ba2c2010-07-16 14:12:24 -070050
51 /**
52 * @hide
53 */
Mathew Inwood0d649f22018-07-31 14:29:22 +010054 @UnsupportedAppUsage
Romain Guy079ba2c2010-07-16 14:12:24 -070055 public final int nativeInt;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080056 }
57
58 /** Create an empty region
59 */
60 public Region() {
61 this(nativeConstructor());
62 }
63
64 /** Return a copy of the specified region
65 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -040066 public Region(@NonNull Region region) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080067 this(nativeConstructor());
68 nativeSetRegion(mNativeRegion, region.mNativeRegion);
69 }
70
71 /** Return a region set to the specified rectangle
72 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -040073 public Region(@NonNull Rect r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080074 mNativeRegion = nativeConstructor();
75 nativeSetRect(mNativeRegion, r.left, r.top, r.right, r.bottom);
76 }
77
78 /** Return a region set to the specified rectangle
79 */
80 public Region(int left, int top, int right, int bottom) {
81 mNativeRegion = nativeConstructor();
82 nativeSetRect(mNativeRegion, left, top, right, bottom);
83 }
84
85 /** Set the region to the empty region
86 */
87 public void setEmpty() {
88 nativeSetRect(mNativeRegion, 0, 0, 0, 0);
89 }
90
91 /** Set the region to the specified region.
92 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -040093 public boolean set(@NonNull Region region) {
Derek Sollenberger250f8ef2013-02-01 11:56:14 -050094 nativeSetRegion(mNativeRegion, region.mNativeRegion);
95 return true;
The Android Open Source Project9066cfe2009-03-03 19:31:44 -080096 }
97
98 /** Set the region to the specified rectangle
99 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400100 public boolean set(@NonNull Rect r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800101 return nativeSetRect(mNativeRegion, r.left, r.top, r.right, r.bottom);
102 }
103
104 /** Set the region to the specified rectangle
105 */
106 public boolean set(int left, int top, int right, int bottom) {
107 return nativeSetRect(mNativeRegion, left, top, right, bottom);
108 }
109
110 /**
111 * Set the region to the area described by the path and clip.
112 * Return true if the resulting region is non-empty. This produces a region
113 * that is identical to the pixels that would be drawn by the path
114 * (with no antialiasing).
115 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400116 public boolean setPath(@NonNull Path path, @NonNull Region clip) {
sergeyva6a85572016-07-27 14:13:34 -0700117 return nativeSetPath(mNativeRegion, path.readOnlyNI(), clip.mNativeRegion);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800118 }
119
120 /**
121 * Return true if this region is empty
122 */
123 public native boolean isEmpty();
124
125 /**
126 * Return true if the region contains a single rectangle
127 */
128 public native boolean isRect();
129
130 /**
131 * Return true if the region contains more than one rectangle
132 */
133 public native boolean isComplex();
134
135 /**
136 * Return a new Rect set to the bounds of the region. If the region is
137 * empty, the Rect will be set to [0, 0, 0, 0]
138 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400139 @NonNull
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800140 public Rect getBounds() {
141 Rect r = new Rect();
142 nativeGetBounds(mNativeRegion, r);
143 return r;
144 }
145
146 /**
147 * Set the Rect to the bounds of the region. If the region is empty, the
148 * Rect will be set to [0, 0, 0, 0]
149 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400150 public boolean getBounds(@NonNull Rect r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800151 if (r == null) {
152 throw new NullPointerException();
153 }
154 return nativeGetBounds(mNativeRegion, r);
155 }
156
157 /**
158 * Return the boundary of the region as a new Path. If the region is empty,
159 * the path will also be empty.
160 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400161 @NonNull
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800162 public Path getBoundaryPath() {
163 Path path = new Path();
sergeyva6a85572016-07-27 14:13:34 -0700164 nativeGetBoundaryPath(mNativeRegion, path.mutateNI());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800165 return path;
166 }
167
168 /**
169 * Set the path to the boundary of the region. If the region is empty, the
170 * path will also be empty.
171 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400172 public boolean getBoundaryPath(@NonNull Path path) {
sergeyva6a85572016-07-27 14:13:34 -0700173 return nativeGetBoundaryPath(mNativeRegion, path.mutateNI());
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800174 }
175
176 /**
177 * Return true if the region contains the specified point
178 */
179 public native boolean contains(int x, int y);
180
181 /**
182 * Return true if the region is a single rectangle (not complex) and it
183 * contains the specified rectangle. Returning false is not a guarantee
184 * that the rectangle is not contained by this region, but return true is a
185 * guarantee that the rectangle is contained by this region.
186 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400187 public boolean quickContains(@NonNull Rect r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800188 return quickContains(r.left, r.top, r.right, r.bottom);
189 }
190
191 /**
192 * Return true if the region is a single rectangle (not complex) and it
193 * contains the specified rectangle. Returning false is not a guarantee
194 * that the rectangle is not contained by this region, but return true is a
195 * guarantee that the rectangle is contained by this region.
196 */
197 public native boolean quickContains(int left, int top, int right,
198 int bottom);
199
200 /**
201 * Return true if the region is empty, or if the specified rectangle does
202 * not intersect the region. Returning false is not a guarantee that they
203 * intersect, but returning true is a guarantee that they do not.
204 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400205 public boolean quickReject(@NonNull Rect r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800206 return quickReject(r.left, r.top, r.right, r.bottom);
207 }
208
209 /**
210 * Return true if the region is empty, or if the specified rectangle does
211 * not intersect the region. Returning false is not a guarantee that they
212 * intersect, but returning true is a guarantee that they do not.
213 */
214 public native boolean quickReject(int left, int top, int right, int bottom);
215
216 /**
217 * Return true if the region is empty, or if the specified region does not
218 * intersect the region. Returning false is not a guarantee that they
219 * intersect, but returning true is a guarantee that they do not.
220 */
221 public native boolean quickReject(Region rgn);
222
223 /**
224 * Translate the region by [dx, dy]. If the region is empty, do nothing.
225 */
226 public void translate(int dx, int dy) {
227 translate(dx, dy, null);
228 }
229
230 /**
231 * Set the dst region to the result of translating this region by [dx, dy].
232 * If this region is empty, then dst will be set to empty.
233 */
234 public native void translate(int dx, int dy, Region dst);
235
Mitsuru Oshimab10f1382009-05-11 17:11:37 -0700236 /**
237 * Scale the region by the given scale amount. This re-constructs new region by
238 * scaling the rects that this region consists of. New rectis are computed by scaling
239 * coordinates by float, then rounded by roundf() function to integers. This may results
240 * in less internal rects if 0 < scale < 1. Zero and Negative scale result in
241 * an empty region. If this region is empty, do nothing.
242 *
243 * @hide
244 */
Mathew Inwood0d649f22018-07-31 14:29:22 +0100245 @UnsupportedAppUsage
Mitsuru Oshimab10f1382009-05-11 17:11:37 -0700246 public void scale(float scale) {
247 scale(scale, null);
248 }
249
250 /**
251 * Set the dst region to the result of scaling this region by the given scale amount.
252 * If this region is empty, then dst will be set to empty.
253 * @hide
254 */
255 public native void scale(float scale, Region dst);
256
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400257 public final boolean union(@NonNull Rect r) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800258 return op(r, Op.UNION);
259 }
260
261 /**
262 * Perform the specified Op on this region and the specified rect. Return
263 * true if the result of the op is not empty.
264 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400265 public boolean op(@NonNull Rect r, @NonNull Op op) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800266 return nativeOp(mNativeRegion, r.left, r.top, r.right, r.bottom,
267 op.nativeInt);
268 }
269
270 /**
271 * Perform the specified Op on this region and the specified rect. Return
272 * true if the result of the op is not empty.
273 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400274 public boolean op(int left, int top, int right, int bottom, @NonNull Op op) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800275 return nativeOp(mNativeRegion, left, top, right, bottom,
276 op.nativeInt);
277 }
278
279 /**
280 * Perform the specified Op on this region and the specified region. Return
281 * true if the result of the op is not empty.
282 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400283 public boolean op(@NonNull Region region, @NonNull Op op) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800284 return op(this, region, op);
285 }
286
287 /**
288 * Set this region to the result of performing the Op on the specified rect
289 * and region. Return true if the result is not empty.
290 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400291 public boolean op(@NonNull Rect rect, @NonNull Region region, @NonNull Op op) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800292 return nativeOp(mNativeRegion, rect, region.mNativeRegion,
293 op.nativeInt);
294 }
295
296 /**
297 * Set this region to the result of performing the Op on the specified
298 * regions. Return true if the result is not empty.
299 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400300 public boolean op(@NonNull Region region1, @NonNull Region region2, @NonNull Op op) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800301 return nativeOp(mNativeRegion, region1.mNativeRegion,
302 region2.mNativeRegion, op.nativeInt);
303 }
304
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400305 @Override
Joe Onorato120856c2011-01-19 14:52:08 -0800306 public String toString() {
307 return nativeToString(mNativeRegion);
308 }
309
Svetoslav Ganov545252f2012-12-10 18:29:24 -0800310 /**
311 * @return An instance from a pool if such or a new one.
312 *
313 * @hide
314 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400315 @NonNull
Svetoslav Ganov545252f2012-12-10 18:29:24 -0800316 public static Region obtain() {
317 Region region = sPool.acquire();
318 return (region != null) ? region : new Region();
319 }
320
321 /**
322 * @return An instance from a pool if such or a new one.
323 *
324 * @param other Region to copy values from for initialization.
325 *
326 * @hide
327 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400328 @NonNull
329 public static Region obtain(@NonNull Region other) {
Svetoslav Ganov545252f2012-12-10 18:29:24 -0800330 Region region = obtain();
331 region.set(other);
332 return region;
333 }
334
335 /**
336 * Recycles an instance.
337 *
338 * @hide
339 */
Mathew Inwood0d649f22018-07-31 14:29:22 +0100340 @UnsupportedAppUsage
Svetoslav Ganov545252f2012-12-10 18:29:24 -0800341 public void recycle() {
342 setEmpty();
343 sPool.release(this);
344 }
345
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800346 //////////////////////////////////////////////////////////////////////////
347
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700348 public static final @android.annotation.NonNull Parcelable.Creator<Region> CREATOR
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800349 = new Parcelable.Creator<Region>() {
350 /**
351 * Rebuild a Region previously stored with writeToParcel().
352 * @param p Parcel object to read the region from
353 * @return a new region created from the data in the parcel
354 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400355 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800356 public Region createFromParcel(Parcel p) {
Ashok Bhata0398432014-01-20 20:08:01 +0000357 long ni = nativeCreateFromParcel(p);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800358 if (ni == 0) {
359 throw new RuntimeException();
360 }
361 return new Region(ni);
362 }
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400363 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800364 public Region[] newArray(int size) {
365 return new Region[size];
366 }
367 };
368
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400369 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800370 public int describeContents() {
371 return 0;
372 }
373
374 /**
375 * Write the region and its pixels to the parcel. The region can be
376 * rebuilt from the parcel by calling CREATOR.createFromParcel().
377 * @param p Parcel object to write the region data into
378 */
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400379 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800380 public void writeToParcel(Parcel p, int flags) {
381 if (!nativeWriteToParcel(mNativeRegion, p)) {
382 throw new RuntimeException();
383 }
384 }
Mitsuru Oshimab10f1382009-05-11 17:11:37 -0700385
386 @Override
387 public boolean equals(Object obj) {
388 if (obj == null || !(obj instanceof Region)) {
389 return false;
390 }
391 Region peer = (Region) obj;
392 return nativeEquals(mNativeRegion, peer.mNativeRegion);
393 }
394
Jake Wharton22c3c8d2018-06-05 12:50:58 -0400395 @Override
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800396 protected void finalize() throws Throwable {
Romain Guy61c8c9c2010-08-09 20:48:09 -0700397 try {
398 nativeDestructor(mNativeRegion);
Hans Boehmffa84e02014-11-11 17:01:37 -0800399 mNativeRegion = 0;
Romain Guy61c8c9c2010-08-09 20:48:09 -0700400 } finally {
401 super.finalize();
402 }
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800403 }
404
Ashok Bhata0398432014-01-20 20:08:01 +0000405 Region(long ni) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800406 if (ni == 0) {
407 throw new RuntimeException();
408 }
409 mNativeRegion = ni;
410 }
411
412 /* add dummy parameter so constructor can be called from jni without
413 triggering 'not cloneable' exception */
Mathew Inwood0d649f22018-07-31 14:29:22 +0100414 @UnsupportedAppUsage
Ashok Bhata0398432014-01-20 20:08:01 +0000415 private Region(long ni, int dummy) {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800416 this(ni);
417 }
418
Ashok Bhata0398432014-01-20 20:08:01 +0000419 final long ni() {
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800420 return mNativeRegion;
421 }
422
Ashok Bhata0398432014-01-20 20:08:01 +0000423 private static native boolean nativeEquals(long native_r1, long native_r2);
Joe Onorato120856c2011-01-19 14:52:08 -0800424
Ashok Bhata0398432014-01-20 20:08:01 +0000425 private static native long nativeConstructor();
426 private static native void nativeDestructor(long native_region);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800427
Ashok Bhata0398432014-01-20 20:08:01 +0000428 private static native void nativeSetRegion(long native_dst, long native_src);
429 private static native boolean nativeSetRect(long native_dst, int left,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800430 int top, int right, int bottom);
Ashok Bhata0398432014-01-20 20:08:01 +0000431 private static native boolean nativeSetPath(long native_dst, long native_path,
432 long native_clip);
433 private static native boolean nativeGetBounds(long native_region, Rect rect);
434 private static native boolean nativeGetBoundaryPath(long native_region,
435 long native_path);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800436
Ashok Bhata0398432014-01-20 20:08:01 +0000437 private static native boolean nativeOp(long native_dst, int left, int top,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800438 int right, int bottom, int op);
Ashok Bhata0398432014-01-20 20:08:01 +0000439 private static native boolean nativeOp(long native_dst, Rect rect,
440 long native_region, int op);
441 private static native boolean nativeOp(long native_dst, long native_region1,
442 long native_region2, int op);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800443
Ashok Bhata0398432014-01-20 20:08:01 +0000444 private static native long nativeCreateFromParcel(Parcel p);
445 private static native boolean nativeWriteToParcel(long native_region,
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800446 Parcel p);
447
Ashok Bhata0398432014-01-20 20:08:01 +0000448 private static native String nativeToString(long native_region);
The Android Open Source Project9066cfe2009-03-03 19:31:44 -0800449}