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