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 long 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 Op(int nativeInt)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 */ Region()56 public Region() { 57 this(nativeConstructor()); 58 } 59 60 /** Return a copy of the specified region 61 */ Region(Region region)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 */ Region(Rect r)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 */ Region(int left, int top, int right, int bottom)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 */ setEmpty()83 public void setEmpty() { 84 nativeSetRect(mNativeRegion, 0, 0, 0, 0); 85 } 86 87 /** Set the region to the specified region. 88 */ set(Region region)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 */ set(Rect r)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 */ set(int left, int top, int right, int bottom)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 */ setPath(Path path, Region clip)112 public boolean setPath(Path path, Region clip) { 113 return nativeSetPath(mNativeRegion, path.readOnlyNI(), clip.mNativeRegion); 114 } 115 116 /** 117 * Return true if this region is empty 118 */ isEmpty()119 public native boolean isEmpty(); 120 121 /** 122 * Return true if the region contains a single rectangle 123 */ isRect()124 public native boolean isRect(); 125 126 /** 127 * Return true if the region contains more than one rectangle 128 */ isComplex()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 */ getBounds()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 */ getBounds(Rect r)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 */ getBoundaryPath()156 public Path getBoundaryPath() { 157 Path path = new Path(); 158 nativeGetBoundaryPath(mNativeRegion, path.mutateNI()); 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 */ getBoundaryPath(Path path)166 public boolean getBoundaryPath(Path path) { 167 return nativeGetBoundaryPath(mNativeRegion, path.mutateNI()); 168 } 169 170 /** 171 * Return true if the region contains the specified point 172 */ contains(int x, int y)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 */ quickContains(Rect r)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 */ quickContains(int left, int top, int right, int bottom)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 */ quickReject(Rect r)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 */ quickReject(int left, int top, int right, int bottom)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 */ quickReject(Region rgn)215 public native boolean quickReject(Region rgn); 216 217 /** 218 * Translate the region by [dx, dy]. If the region is empty, do nothing. 219 */ translate(int dx, int dy)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 */ translate(int dx, int dy, Region dst)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 */ scale(float scale)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 */ scale(float scale, Region dst)248 public native void scale(float scale, Region dst); 249 union(Rect r)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 */ op(Rect r, Op op)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 */ op(int left, int top, int right, int bottom, Op op)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 */ op(Region region, Op op)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 */ op(Rect rect, Region region, Op op)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 */ op(Region region1, Region region2, Op op)293 public boolean op(Region region1, Region region2, Op op) { 294 return nativeOp(mNativeRegion, region1.mNativeRegion, 295 region2.mNativeRegion, op.nativeInt); 296 } 297 toString()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 */ obtain()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 */ obtain(Region other)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 */ recycle()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 long 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 describeContents()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 */ writeToParcel(Parcel p, int flags)365 public void writeToParcel(Parcel p, int flags) { 366 if (!nativeWriteToParcel(mNativeRegion, p)) { 367 throw new RuntimeException(); 368 } 369 } 370 371 @Override equals(Object obj)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 finalize()380 protected void finalize() throws Throwable { 381 try { 382 nativeDestructor(mNativeRegion); 383 mNativeRegion = 0; 384 } finally { 385 super.finalize(); 386 } 387 } 388 Region(long ni)389 Region(long ni) { 390 if (ni == 0) { 391 throw new RuntimeException(); 392 } 393 mNativeRegion = ni; 394 } 395 396 /* add dummy parameter so constructor can be called from jni without 397 triggering 'not cloneable' exception */ Region(long ni, int dummy)398 private Region(long ni, int dummy) { 399 this(ni); 400 } 401 ni()402 final long ni() { 403 return mNativeRegion; 404 } 405 nativeEquals(long native_r1, long native_r2)406 private static native boolean nativeEquals(long native_r1, long native_r2); 407 nativeConstructor()408 private static native long nativeConstructor(); nativeDestructor(long native_region)409 private static native void nativeDestructor(long native_region); 410 nativeSetRegion(long native_dst, long native_src)411 private static native void nativeSetRegion(long native_dst, long native_src); nativeSetRect(long native_dst, int left, int top, int right, int bottom)412 private static native boolean nativeSetRect(long native_dst, int left, 413 int top, int right, int bottom); nativeSetPath(long native_dst, long native_path, long native_clip)414 private static native boolean nativeSetPath(long native_dst, long native_path, 415 long native_clip); nativeGetBounds(long native_region, Rect rect)416 private static native boolean nativeGetBounds(long native_region, Rect rect); nativeGetBoundaryPath(long native_region, long native_path)417 private static native boolean nativeGetBoundaryPath(long native_region, 418 long native_path); 419 nativeOp(long native_dst, int left, int top, int right, int bottom, int op)420 private static native boolean nativeOp(long native_dst, int left, int top, 421 int right, int bottom, int op); nativeOp(long native_dst, Rect rect, long native_region, int op)422 private static native boolean nativeOp(long native_dst, Rect rect, 423 long native_region, int op); nativeOp(long native_dst, long native_region1, long native_region2, int op)424 private static native boolean nativeOp(long native_dst, long native_region1, 425 long native_region2, int op); 426 nativeCreateFromParcel(Parcel p)427 private static native long nativeCreateFromParcel(Parcel p); nativeWriteToParcel(long native_region, Parcel p)428 private static native boolean nativeWriteToParcel(long native_region, 429 Parcel p); 430 nativeToString(long native_region)431 private static native String nativeToString(long native_region); 432 } 433