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.CheckResult; 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.annotation.UnsupportedAppUsage; 23 import android.os.Parcel; 24 import android.os.Parcelable; 25 import android.text.TextUtils; 26 import android.util.proto.ProtoInputStream; 27 import android.util.proto.ProtoOutputStream; 28 import android.util.proto.WireTypeMismatchException; 29 30 import java.io.IOException; 31 import java.io.PrintWriter; 32 import java.util.regex.Matcher; 33 import java.util.regex.Pattern; 34 35 /** 36 * Rect holds four integer coordinates for a rectangle. The rectangle is 37 * represented by the coordinates of its 4 edges (left, top, right bottom). 38 * These fields can be accessed directly. Use width() and height() to retrieve 39 * the rectangle's width and height. Note: most methods do not check to see that 40 * the coordinates are sorted correctly (i.e. left <= right and top <= bottom). 41 * <p> 42 * Note that the right and bottom coordinates are exclusive. This means a Rect 43 * being drawn untransformed onto a {@link android.graphics.Canvas} will draw 44 * into the column and row described by its left and top coordinates, but not 45 * those of its bottom and right. 46 */ 47 public final class Rect implements Parcelable { 48 public int left; 49 public int top; 50 public int right; 51 public int bottom; 52 53 /** 54 * A helper class for flattened rectange pattern recognition. A separate 55 * class to avoid an initialization dependency on a regular expression 56 * causing Rect to not be initializable with an ahead-of-time compilation 57 * scheme. 58 */ 59 private static final class UnflattenHelper { 60 private static final Pattern FLATTENED_PATTERN = Pattern.compile( 61 "(-?\\d+) (-?\\d+) (-?\\d+) (-?\\d+)"); 62 getMatcher(String str)63 static Matcher getMatcher(String str) { 64 return FLATTENED_PATTERN.matcher(str); 65 } 66 } 67 68 /** 69 * Create a new empty Rect. All coordinates are initialized to 0. 70 */ Rect()71 public Rect() {} 72 73 /** 74 * Create a new rectangle with the specified coordinates. Note: no range 75 * checking is performed, so the caller must ensure that left <= right and 76 * top <= bottom. 77 * 78 * @param left The X coordinate of the left side of the rectangle 79 * @param top The Y coordinate of the top of the rectangle 80 * @param right The X coordinate of the right side of the rectangle 81 * @param bottom The Y coordinate of the bottom of the rectangle 82 */ Rect(int left, int top, int right, int bottom)83 public Rect(int left, int top, int right, int bottom) { 84 this.left = left; 85 this.top = top; 86 this.right = right; 87 this.bottom = bottom; 88 } 89 90 /** 91 * Create a new rectangle, initialized with the values in the specified 92 * rectangle (which is left unmodified). 93 * 94 * @param r The rectangle whose coordinates are copied into the new 95 * rectangle. 96 */ Rect(@ullable Rect r)97 public Rect(@Nullable Rect r) { 98 if (r == null) { 99 left = top = right = bottom = 0; 100 } else { 101 left = r.left; 102 top = r.top; 103 right = r.right; 104 bottom = r.bottom; 105 } 106 } 107 108 /** 109 * @hide 110 */ Rect(@ullable Insets r)111 public Rect(@Nullable Insets r) { 112 if (r == null) { 113 left = top = right = bottom = 0; 114 } else { 115 left = r.left; 116 top = r.top; 117 right = r.right; 118 bottom = r.bottom; 119 } 120 } 121 122 /** 123 * Returns a copy of {@code r} if {@code r} is not {@code null}, or {@code null} otherwise. 124 * 125 * @hide 126 */ 127 @Nullable copyOrNull(@ullable Rect r)128 public static Rect copyOrNull(@Nullable Rect r) { 129 return r == null ? null : new Rect(r); 130 } 131 132 @Override equals(Object o)133 public boolean equals(Object o) { 134 if (this == o) return true; 135 if (o == null || getClass() != o.getClass()) return false; 136 137 Rect r = (Rect) o; 138 return left == r.left && top == r.top && right == r.right && bottom == r.bottom; 139 } 140 141 @Override hashCode()142 public int hashCode() { 143 int result = left; 144 result = 31 * result + top; 145 result = 31 * result + right; 146 result = 31 * result + bottom; 147 return result; 148 } 149 150 @Override toString()151 public String toString() { 152 StringBuilder sb = new StringBuilder(32); 153 sb.append("Rect("); sb.append(left); sb.append(", "); 154 sb.append(top); sb.append(" - "); sb.append(right); 155 sb.append(", "); sb.append(bottom); sb.append(")"); 156 return sb.toString(); 157 } 158 159 /** 160 * Return a string representation of the rectangle in a compact form. 161 */ 162 @NonNull toShortString()163 public String toShortString() { 164 return toShortString(new StringBuilder(32)); 165 } 166 167 /** 168 * Return a string representation of the rectangle in a compact form. 169 * @hide 170 */ 171 @NonNull toShortString(@onNull StringBuilder sb)172 public String toShortString(@NonNull StringBuilder sb) { 173 sb.setLength(0); 174 sb.append('['); sb.append(left); sb.append(','); 175 sb.append(top); sb.append("]["); sb.append(right); 176 sb.append(','); sb.append(bottom); sb.append(']'); 177 return sb.toString(); 178 } 179 180 /** 181 * Return a string representation of the rectangle in a well-defined format. 182 * 183 * <p>You can later recover the Rect from this string through 184 * {@link #unflattenFromString(String)}. 185 * 186 * @return Returns a new String of the form "left top right bottom" 187 */ 188 @NonNull flattenToString()189 public String flattenToString() { 190 StringBuilder sb = new StringBuilder(32); 191 // WARNING: Do not change the format of this string, it must be 192 // preserved because Rects are saved in this flattened format. 193 sb.append(left); 194 sb.append(' '); 195 sb.append(top); 196 sb.append(' '); 197 sb.append(right); 198 sb.append(' '); 199 sb.append(bottom); 200 return sb.toString(); 201 } 202 203 /** 204 * Returns a Rect from a string of the form returned by {@link #flattenToString}, 205 * or null if the string is not of that form. 206 */ 207 @Nullable unflattenFromString(@ullable String str)208 public static Rect unflattenFromString(@Nullable String str) { 209 if (TextUtils.isEmpty(str)) { 210 return null; 211 } 212 213 Matcher matcher = UnflattenHelper.getMatcher(str); 214 if (!matcher.matches()) { 215 return null; 216 } 217 return new Rect(Integer.parseInt(matcher.group(1)), 218 Integer.parseInt(matcher.group(2)), 219 Integer.parseInt(matcher.group(3)), 220 Integer.parseInt(matcher.group(4))); 221 } 222 223 /** 224 * Print short representation to given writer. 225 * @hide 226 */ 227 @UnsupportedAppUsage printShortString(@onNull PrintWriter pw)228 public void printShortString(@NonNull PrintWriter pw) { 229 pw.print('['); pw.print(left); pw.print(','); 230 pw.print(top); pw.print("]["); pw.print(right); 231 pw.print(','); pw.print(bottom); pw.print(']'); 232 } 233 234 /** 235 * Write to a protocol buffer output stream. 236 * Protocol buffer message definition at {@link android.graphics.RectProto} 237 * 238 * @param protoOutputStream Stream to write the Rect object to. 239 * @param fieldId Field Id of the Rect as defined in the parent message 240 * @hide 241 */ writeToProto(@onNull ProtoOutputStream protoOutputStream, long fieldId)242 public void writeToProto(@NonNull ProtoOutputStream protoOutputStream, long fieldId) { 243 final long token = protoOutputStream.start(fieldId); 244 protoOutputStream.write(RectProto.LEFT, left); 245 protoOutputStream.write(RectProto.TOP, top); 246 protoOutputStream.write(RectProto.RIGHT, right); 247 protoOutputStream.write(RectProto.BOTTOM, bottom); 248 protoOutputStream.end(token); 249 } 250 251 /** 252 * Read from a protocol buffer input stream. 253 * Protocol buffer message definition at {@link android.graphics.RectProto} 254 * 255 * @param proto Stream to read the Rect object from. 256 * @param fieldId Field Id of the Rect as defined in the parent message 257 * @hide 258 */ readFromProto(@onNull ProtoInputStream proto, long fieldId)259 public void readFromProto(@NonNull ProtoInputStream proto, long fieldId) throws IOException, 260 WireTypeMismatchException { 261 final long token = proto.start(fieldId); 262 try { 263 while (proto.nextField() != ProtoInputStream.NO_MORE_FIELDS) { 264 switch (proto.getFieldNumber()) { 265 case (int) RectProto.LEFT: 266 left = proto.readInt(RectProto.LEFT); 267 break; 268 case (int) RectProto.TOP: 269 top = proto.readInt(RectProto.TOP); 270 break; 271 case (int) RectProto.RIGHT: 272 right = proto.readInt(RectProto.RIGHT); 273 break; 274 case (int) RectProto.BOTTOM: 275 bottom = proto.readInt(RectProto.BOTTOM); 276 break; 277 } 278 } 279 } finally { 280 // Let caller handle any exceptions 281 proto.end(token); 282 } 283 } 284 285 /** 286 * Returns true if the rectangle is empty (left >= right or top >= bottom) 287 */ isEmpty()288 public final boolean isEmpty() { 289 return left >= right || top >= bottom; 290 } 291 292 /** 293 * @return the rectangle's width. This does not check for a valid rectangle 294 * (i.e. left <= right) so the result may be negative. 295 */ width()296 public final int width() { 297 return right - left; 298 } 299 300 /** 301 * @return the rectangle's height. This does not check for a valid rectangle 302 * (i.e. top <= bottom) so the result may be negative. 303 */ height()304 public final int height() { 305 return bottom - top; 306 } 307 308 /** 309 * @return the horizontal center of the rectangle. If the computed value 310 * is fractional, this method returns the largest integer that is 311 * less than the computed value. 312 */ centerX()313 public final int centerX() { 314 return (left + right) >> 1; 315 } 316 317 /** 318 * @return the vertical center of the rectangle. If the computed value 319 * is fractional, this method returns the largest integer that is 320 * less than the computed value. 321 */ centerY()322 public final int centerY() { 323 return (top + bottom) >> 1; 324 } 325 326 /** 327 * @return the exact horizontal center of the rectangle as a float. 328 */ exactCenterX()329 public final float exactCenterX() { 330 return (left + right) * 0.5f; 331 } 332 333 /** 334 * @return the exact vertical center of the rectangle as a float. 335 */ exactCenterY()336 public final float exactCenterY() { 337 return (top + bottom) * 0.5f; 338 } 339 340 /** 341 * Set the rectangle to (0,0,0,0) 342 */ setEmpty()343 public void setEmpty() { 344 left = right = top = bottom = 0; 345 } 346 347 /** 348 * Set the rectangle's coordinates to the specified values. Note: no range 349 * checking is performed, so it is up to the caller to ensure that 350 * left <= right and top <= bottom. 351 * 352 * @param left The X coordinate of the left side of the rectangle 353 * @param top The Y coordinate of the top of the rectangle 354 * @param right The X coordinate of the right side of the rectangle 355 * @param bottom The Y coordinate of the bottom of the rectangle 356 */ set(int left, int top, int right, int bottom)357 public void set(int left, int top, int right, int bottom) { 358 this.left = left; 359 this.top = top; 360 this.right = right; 361 this.bottom = bottom; 362 } 363 364 /** 365 * Copy the coordinates from src into this rectangle. 366 * 367 * @param src The rectangle whose coordinates are copied into this 368 * rectangle. 369 */ set(@onNull Rect src)370 public void set(@NonNull Rect src) { 371 this.left = src.left; 372 this.top = src.top; 373 this.right = src.right; 374 this.bottom = src.bottom; 375 } 376 377 /** 378 * Offset the rectangle by adding dx to its left and right coordinates, and 379 * adding dy to its top and bottom coordinates. 380 * 381 * @param dx The amount to add to the rectangle's left and right coordinates 382 * @param dy The amount to add to the rectangle's top and bottom coordinates 383 */ offset(int dx, int dy)384 public void offset(int dx, int dy) { 385 left += dx; 386 top += dy; 387 right += dx; 388 bottom += dy; 389 } 390 391 /** 392 * Offset the rectangle to a specific (left, top) position, 393 * keeping its width and height the same. 394 * 395 * @param newLeft The new "left" coordinate for the rectangle 396 * @param newTop The new "top" coordinate for the rectangle 397 */ offsetTo(int newLeft, int newTop)398 public void offsetTo(int newLeft, int newTop) { 399 right += newLeft - left; 400 bottom += newTop - top; 401 left = newLeft; 402 top = newTop; 403 } 404 405 /** 406 * Inset the rectangle by (dx,dy). If dx is positive, then the sides are 407 * moved inwards, making the rectangle narrower. If dx is negative, then the 408 * sides are moved outwards, making the rectangle wider. The same holds true 409 * for dy and the top and bottom. 410 * 411 * @param dx The amount to add(subtract) from the rectangle's left(right) 412 * @param dy The amount to add(subtract) from the rectangle's top(bottom) 413 */ inset(int dx, int dy)414 public void inset(int dx, int dy) { 415 left += dx; 416 top += dy; 417 right -= dx; 418 bottom -= dy; 419 } 420 421 /** 422 * Insets the rectangle on all sides specified by the dimensions of the {@code insets} 423 * rectangle. 424 * @hide 425 * @param insets The rectangle specifying the insets on all side. 426 */ inset(@onNull Rect insets)427 public void inset(@NonNull Rect insets) { 428 left += insets.left; 429 top += insets.top; 430 right -= insets.right; 431 bottom -= insets.bottom; 432 } 433 434 /** 435 * Insets the rectangle on all sides specified by the dimensions of {@code insets}. 436 * @hide 437 * @param insets The insets to inset the rect by. 438 */ inset(Insets insets)439 public void inset(Insets insets) { 440 left += insets.left; 441 top += insets.top; 442 right -= insets.right; 443 bottom -= insets.bottom; 444 } 445 446 /** 447 * Insets the rectangle on all sides specified by the insets. 448 * @hide 449 * @param left The amount to add from the rectangle's left 450 * @param top The amount to add from the rectangle's top 451 * @param right The amount to subtract from the rectangle's right 452 * @param bottom The amount to subtract from the rectangle's bottom 453 */ inset(int left, int top, int right, int bottom)454 public void inset(int left, int top, int right, int bottom) { 455 this.left += left; 456 this.top += top; 457 this.right -= right; 458 this.bottom -= bottom; 459 } 460 461 /** 462 * Returns true if (x,y) is inside the rectangle. The left and top are 463 * considered to be inside, while the right and bottom are not. This means 464 * that for a x,y to be contained: left <= x < right and top <= y < bottom. 465 * An empty rectangle never contains any point. 466 * 467 * @param x The X coordinate of the point being tested for containment 468 * @param y The Y coordinate of the point being tested for containment 469 * @return true iff (x,y) are contained by the rectangle, where containment 470 * means left <= x < right and top <= y < bottom 471 */ contains(int x, int y)472 public boolean contains(int x, int y) { 473 return left < right && top < bottom // check for empty first 474 && x >= left && x < right && y >= top && y < bottom; 475 } 476 477 /** 478 * Returns true iff the 4 specified sides of a rectangle are inside or equal 479 * to this rectangle. i.e. is this rectangle a superset of the specified 480 * rectangle. An empty rectangle never contains another rectangle. 481 * 482 * @param left The left side of the rectangle being tested for containment 483 * @param top The top of the rectangle being tested for containment 484 * @param right The right side of the rectangle being tested for containment 485 * @param bottom The bottom of the rectangle being tested for containment 486 * @return true iff the the 4 specified sides of a rectangle are inside or 487 * equal to this rectangle 488 */ contains(int left, int top, int right, int bottom)489 public boolean contains(int left, int top, int right, int bottom) { 490 // check for empty first 491 return this.left < this.right && this.top < this.bottom 492 // now check for containment 493 && this.left <= left && this.top <= top 494 && this.right >= right && this.bottom >= bottom; 495 } 496 497 /** 498 * Returns true iff the specified rectangle r is inside or equal to this 499 * rectangle. An empty rectangle never contains another rectangle. 500 * 501 * @param r The rectangle being tested for containment. 502 * @return true iff the specified rectangle r is inside or equal to this 503 * rectangle 504 */ contains(@onNull Rect r)505 public boolean contains(@NonNull Rect r) { 506 // check for empty first 507 return this.left < this.right && this.top < this.bottom 508 // now check for containment 509 && left <= r.left && top <= r.top && right >= r.right && bottom >= r.bottom; 510 } 511 512 /** 513 * If the rectangle specified by left,top,right,bottom intersects this 514 * rectangle, return true and set this rectangle to that intersection, 515 * otherwise return false and do not change this rectangle. No check is 516 * performed to see if either rectangle is empty. Note: To just test for 517 * intersection, use {@link #intersects(Rect, Rect)}. 518 * 519 * @param left The left side of the rectangle being intersected with this 520 * rectangle 521 * @param top The top of the rectangle being intersected with this rectangle 522 * @param right The right side of the rectangle being intersected with this 523 * rectangle. 524 * @param bottom The bottom of the rectangle being intersected with this 525 * rectangle. 526 * @return true if the specified rectangle and this rectangle intersect 527 * (and this rectangle is then set to that intersection) else 528 * return false and do not change this rectangle. 529 */ 530 @CheckResult intersect(int left, int top, int right, int bottom)531 public boolean intersect(int left, int top, int right, int bottom) { 532 if (this.left < right && left < this.right && this.top < bottom && top < this.bottom) { 533 if (this.left < left) this.left = left; 534 if (this.top < top) this.top = top; 535 if (this.right > right) this.right = right; 536 if (this.bottom > bottom) this.bottom = bottom; 537 return true; 538 } 539 return false; 540 } 541 542 /** 543 * If the specified rectangle intersects this rectangle, return true and set 544 * this rectangle to that intersection, otherwise return false and do not 545 * change this rectangle. No check is performed to see if either rectangle 546 * is empty. To just test for intersection, use intersects() 547 * 548 * @param r The rectangle being intersected with this rectangle. 549 * @return true if the specified rectangle and this rectangle intersect 550 * (and this rectangle is then set to that intersection) else 551 * return false and do not change this rectangle. 552 */ 553 @CheckResult intersect(@onNull Rect r)554 public boolean intersect(@NonNull Rect r) { 555 return intersect(r.left, r.top, r.right, r.bottom); 556 } 557 558 /** 559 * If the specified rectangle intersects this rectangle, set this rectangle to that 560 * intersection, otherwise set this rectangle to the empty rectangle. 561 * @see #inset(int, int, int, int) but without checking if the rects overlap. 562 * @hide 563 */ intersectUnchecked(@onNull Rect other)564 public void intersectUnchecked(@NonNull Rect other) { 565 left = Math.max(left, other.left); 566 top = Math.max(top, other.top); 567 right = Math.min(right, other.right); 568 bottom = Math.min(bottom, other.bottom); 569 } 570 571 /** 572 * If rectangles a and b intersect, return true and set this rectangle to 573 * that intersection, otherwise return false and do not change this 574 * rectangle. No check is performed to see if either rectangle is empty. 575 * To just test for intersection, use intersects() 576 * 577 * @param a The first rectangle being intersected with 578 * @param b The second rectangle being intersected with 579 * @return true iff the two specified rectangles intersect. If they do, set 580 * this rectangle to that intersection. If they do not, return 581 * false and do not change this rectangle. 582 */ 583 @CheckResult setIntersect(@onNull Rect a, @NonNull Rect b)584 public boolean setIntersect(@NonNull Rect a, @NonNull Rect b) { 585 if (a.left < b.right && b.left < a.right && a.top < b.bottom && b.top < a.bottom) { 586 left = Math.max(a.left, b.left); 587 top = Math.max(a.top, b.top); 588 right = Math.min(a.right, b.right); 589 bottom = Math.min(a.bottom, b.bottom); 590 return true; 591 } 592 return false; 593 } 594 595 /** 596 * Returns true if this rectangle intersects the specified rectangle. 597 * In no event is this rectangle modified. No check is performed to see 598 * if either rectangle is empty. To record the intersection, use intersect() 599 * or setIntersect(). 600 * 601 * @param left The left side of the rectangle being tested for intersection 602 * @param top The top of the rectangle being tested for intersection 603 * @param right The right side of the rectangle being tested for 604 * intersection 605 * @param bottom The bottom of the rectangle being tested for intersection 606 * @return true iff the specified rectangle intersects this rectangle. In 607 * no event is this rectangle modified. 608 */ intersects(int left, int top, int right, int bottom)609 public boolean intersects(int left, int top, int right, int bottom) { 610 return this.left < right && left < this.right && this.top < bottom && top < this.bottom; 611 } 612 613 /** 614 * Returns true iff the two specified rectangles intersect. In no event are 615 * either of the rectangles modified. To record the intersection, 616 * use {@link #intersect(Rect)} or {@link #setIntersect(Rect, Rect)}. 617 * 618 * @param a The first rectangle being tested for intersection 619 * @param b The second rectangle being tested for intersection 620 * @return true iff the two specified rectangles intersect. In no event are 621 * either of the rectangles modified. 622 */ intersects(@onNull Rect a, @NonNull Rect b)623 public static boolean intersects(@NonNull Rect a, @NonNull Rect b) { 624 return a.left < b.right && b.left < a.right && a.top < b.bottom && b.top < a.bottom; 625 } 626 627 /** 628 * Update this Rect to enclose itself and the specified rectangle. If the 629 * specified rectangle is empty, nothing is done. If this rectangle is empty 630 * it is set to the specified rectangle. 631 * 632 * @param left The left edge being unioned with this rectangle 633 * @param top The top edge being unioned with this rectangle 634 * @param right The right edge being unioned with this rectangle 635 * @param bottom The bottom edge being unioned with this rectangle 636 */ union(int left, int top, int right, int bottom)637 public void union(int left, int top, int right, int bottom) { 638 if ((left < right) && (top < bottom)) { 639 if ((this.left < this.right) && (this.top < this.bottom)) { 640 if (this.left > left) this.left = left; 641 if (this.top > top) this.top = top; 642 if (this.right < right) this.right = right; 643 if (this.bottom < bottom) this.bottom = bottom; 644 } else { 645 this.left = left; 646 this.top = top; 647 this.right = right; 648 this.bottom = bottom; 649 } 650 } 651 } 652 653 /** 654 * Update this Rect to enclose itself and the specified rectangle. If the 655 * specified rectangle is empty, nothing is done. If this rectangle is empty 656 * it is set to the specified rectangle. 657 * 658 * @param r The rectangle being unioned with this rectangle 659 */ union(@onNull Rect r)660 public void union(@NonNull Rect r) { 661 union(r.left, r.top, r.right, r.bottom); 662 } 663 664 /** 665 * Update this Rect to enclose itself and the [x,y] coordinate. There is no 666 * check to see that this rectangle is non-empty. 667 * 668 * @param x The x coordinate of the point to add to the rectangle 669 * @param y The y coordinate of the point to add to the rectangle 670 */ union(int x, int y)671 public void union(int x, int y) { 672 if (x < left) { 673 left = x; 674 } else if (x > right) { 675 right = x; 676 } 677 if (y < top) { 678 top = y; 679 } else if (y > bottom) { 680 bottom = y; 681 } 682 } 683 684 /** 685 * Swap top/bottom or left/right if there are flipped (i.e. left > right 686 * and/or top > bottom). This can be called if 687 * the edges are computed separately, and may have crossed over each other. 688 * If the edges are already correct (i.e. left <= right and top <= bottom) 689 * then nothing is done. 690 */ sort()691 public void sort() { 692 if (left > right) { 693 int temp = left; 694 left = right; 695 right = temp; 696 } 697 if (top > bottom) { 698 int temp = top; 699 top = bottom; 700 bottom = temp; 701 } 702 } 703 704 /** 705 * Parcelable interface methods 706 */ 707 @Override describeContents()708 public int describeContents() { 709 return 0; 710 } 711 712 /** 713 * Write this rectangle to the specified parcel. To restore a rectangle from 714 * a parcel, use readFromParcel() 715 * @param out The parcel to write the rectangle's coordinates into 716 */ 717 @Override writeToParcel(Parcel out, int flags)718 public void writeToParcel(Parcel out, int flags) { 719 out.writeInt(left); 720 out.writeInt(top); 721 out.writeInt(right); 722 out.writeInt(bottom); 723 } 724 725 public static final @android.annotation.NonNull Parcelable.Creator<Rect> CREATOR = new Parcelable.Creator<Rect>() { 726 /** 727 * Return a new rectangle from the data in the specified parcel. 728 */ 729 @Override 730 public Rect createFromParcel(Parcel in) { 731 Rect r = new Rect(); 732 r.readFromParcel(in); 733 return r; 734 } 735 736 /** 737 * Return an array of rectangles of the specified size. 738 */ 739 @Override 740 public Rect[] newArray(int size) { 741 return new Rect[size]; 742 } 743 }; 744 745 /** 746 * Set the rectangle's coordinates from the data stored in the specified 747 * parcel. To write a rectangle to a parcel, call writeToParcel(). 748 * 749 * @param in The parcel to read the rectangle's coordinates from 750 */ readFromParcel(@onNull Parcel in)751 public void readFromParcel(@NonNull Parcel in) { 752 left = in.readInt(); 753 top = in.readInt(); 754 right = in.readInt(); 755 bottom = in.readInt(); 756 } 757 758 /** 759 * Scales up the rect by the given scale. 760 * @hide 761 */ 762 @UnsupportedAppUsage scale(float scale)763 public void scale(float scale) { 764 if (scale != 1.0f) { 765 left = (int) (left * scale + 0.5f); 766 top = (int) (top * scale + 0.5f); 767 right = (int) (right * scale + 0.5f); 768 bottom = (int) (bottom * scale + 0.5f); 769 } 770 } 771 772 } 773