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