• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 
2 /*
3  * Copyright 2006 The Android Open Source Project
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 
10 #ifndef SkRect_DEFINED
11 #define SkRect_DEFINED
12 
13 #include "SkPoint.h"
14 #include "SkSize.h"
15 
16 /** \struct SkIRect
17 
18     SkIRect holds four 32 bit integer coordinates for a rectangle
19 */
20 struct SK_API SkIRect {
21     int32_t fLeft, fTop, fRight, fBottom;
22 
MakeEmptySkIRect23     static SkIRect MakeEmpty() {
24         SkIRect r;
25         r.setEmpty();
26         return r;
27     }
28 
MakeWHSkIRect29     static SkIRect MakeWH(int32_t w, int32_t h) {
30         SkIRect r;
31         r.set(0, 0, w, h);
32         return r;
33     }
34 
MakeSizeSkIRect35     static SkIRect MakeSize(const SkISize& size) {
36         SkIRect r;
37         r.set(0, 0, size.width(), size.height());
38         return r;
39     }
40 
MakeLTRBSkIRect41     static SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b) {
42         SkIRect rect;
43         rect.set(l, t, r, b);
44         return rect;
45     }
46 
MakeXYWHSkIRect47     static SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h) {
48         SkIRect r;
49         r.set(x, y, x + w, y + h);
50         return r;
51     }
52 
leftSkIRect53     int left() const { return fLeft; }
topSkIRect54     int top() const { return fTop; }
rightSkIRect55     int right() const { return fRight; }
bottomSkIRect56     int bottom() const { return fBottom; }
57 
58     /** return the left edge of the rect */
xSkIRect59     int x() const { return fLeft; }
60     /** return the top edge of the rect */
ySkIRect61     int y() const { return fTop; }
62     /**
63      *  Returns the rectangle's width. This does not check for a valid rect
64      *  (i.e. left <= right) so the result may be negative.
65      */
widthSkIRect66     int width() const { return fRight - fLeft; }
67 
68     /**
69      *  Returns the rectangle's height. This does not check for a valid rect
70      *  (i.e. top <= bottom) so the result may be negative.
71      */
heightSkIRect72     int height() const { return fBottom - fTop; }
73 
74     /**
75      *  Return true if the rectangle's width or height are <= 0
76      */
isEmptySkIRect77     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
78 
79     friend bool operator==(const SkIRect& a, const SkIRect& b) {
80         return !memcmp(&a, &b, sizeof(a));
81     }
82 
83     friend bool operator!=(const SkIRect& a, const SkIRect& b) {
84         return !(a == b);
85     }
86 
is16BitSkIRect87     bool is16Bit() const {
88         return  SkIsS16(fLeft) && SkIsS16(fTop) &&
89                 SkIsS16(fRight) && SkIsS16(fBottom);
90     }
91 
92     /** Set the rectangle to (0,0,0,0)
93     */
setEmptySkIRect94     void setEmpty() { memset(this, 0, sizeof(*this)); }
95 
setSkIRect96     void set(int32_t left, int32_t top, int32_t right, int32_t bottom) {
97         fLeft   = left;
98         fTop    = top;
99         fRight  = right;
100         fBottom = bottom;
101     }
102     // alias for set(l, t, r, b)
setLTRBSkIRect103     void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) {
104         this->set(left, top, right, bottom);
105     }
106 
setXYWHSkIRect107     void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) {
108         fLeft = x;
109         fTop = y;
110         fRight = x + width;
111         fBottom = y + height;
112     }
113 
114     /**
115      *  Make the largest representable rectangle
116      */
setLargestSkIRect117     void setLargest() {
118         fLeft = fTop = SK_MinS32;
119         fRight = fBottom = SK_MaxS32;
120     }
121 
122     /**
123      *  Make the largest representable rectangle, but inverted (e.g. fLeft will
124      *  be max 32bit and right will be min 32bit).
125      */
setLargestInvertedSkIRect126     void setLargestInverted() {
127         fLeft = fTop = SK_MaxS32;
128         fRight = fBottom = SK_MinS32;
129     }
130 
131     /** Offset set the rectangle by adding dx to its left and right,
132         and adding dy to its top and bottom.
133     */
offsetSkIRect134     void offset(int32_t dx, int32_t dy) {
135         fLeft   += dx;
136         fTop    += dy;
137         fRight  += dx;
138         fBottom += dy;
139     }
140 
offsetSkIRect141     void offset(const SkIPoint& delta) {
142         this->offset(delta.fX, delta.fY);
143     }
144 
145     /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards,
146         making the rectangle narrower. If dx is negative, then the sides are moved outwards,
147         making the rectangle wider. The same hods true for dy and the top and bottom.
148     */
insetSkIRect149     void inset(int32_t dx, int32_t dy) {
150         fLeft   += dx;
151         fTop    += dy;
152         fRight  -= dx;
153         fBottom -= dy;
154     }
155 
quickRejectSkIRect156     bool quickReject(int l, int t, int r, int b) const {
157         return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b;
158     }
159 
160     /** Returns true if (x,y) is inside the rectangle and the rectangle is not
161         empty. The left and top are considered to be inside, while the right
162         and bottom are not. Thus for the rectangle (0, 0, 5, 10), the
163         points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not.
164     */
containsSkIRect165     bool contains(int32_t x, int32_t y) const {
166         return  (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) &&
167                 (unsigned)(y - fTop) < (unsigned)(fBottom - fTop);
168     }
169 
170     /** Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle.
171         If either rectangle is empty, contains() returns false.
172     */
containsSkIRect173     bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const {
174         return  left < right && top < bottom && !this->isEmpty() && // check for empties
175                 fLeft <= left && fTop <= top &&
176                 fRight >= right && fBottom >= bottom;
177     }
178 
179     /** Returns true if the specified rectangle r is inside or equal to this rectangle.
180     */
containsSkIRect181     bool contains(const SkIRect& r) const {
182         return  !r.isEmpty() && !this->isEmpty() &&     // check for empties
183                 fLeft <= r.fLeft && fTop <= r.fTop &&
184                 fRight >= r.fRight && fBottom >= r.fBottom;
185     }
186 
187     /** Return true if this rectangle contains the specified rectangle.
188 		For speed, this method does not check if either this or the specified
189 		rectangles are empty, and if either is, its return value is undefined.
190 		In the debugging build however, we assert that both this and the
191 		specified rectangles are non-empty.
192     */
containsNoEmptyCheckSkIRect193     bool containsNoEmptyCheck(int32_t left, int32_t top,
194 							  int32_t right, int32_t bottom) const {
195 		SkASSERT(fLeft < fRight && fTop < fBottom);
196         SkASSERT(left < right && top < bottom);
197 
198         return fLeft <= left && fTop <= top &&
199 			   fRight >= right && fBottom >= bottom;
200     }
201 
202     /** If r intersects this rectangle, return true and set this rectangle to that
203         intersection, otherwise return false and do not change this rectangle.
204         If either rectangle is empty, do nothing and return false.
205     */
intersectSkIRect206     bool intersect(const SkIRect& r) {
207         SkASSERT(&r);
208         return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom);
209     }
210 
211     /** If rectangles a and b intersect, return true and set this rectangle to
212         that intersection, otherwise return false and do not change this
213         rectangle. If either rectangle is empty, do nothing and return false.
214     */
intersectSkIRect215     bool intersect(const SkIRect& a, const SkIRect& b) {
216         SkASSERT(&a && &b);
217 
218         if (!a.isEmpty() && !b.isEmpty() &&
219                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
220                 a.fTop < b.fBottom && b.fTop < a.fBottom) {
221             fLeft   = SkMax32(a.fLeft,   b.fLeft);
222             fTop    = SkMax32(a.fTop,    b.fTop);
223             fRight  = SkMin32(a.fRight,  b.fRight);
224             fBottom = SkMin32(a.fBottom, b.fBottom);
225             return true;
226         }
227         return false;
228     }
229 
230     /** If rectangles a and b intersect, return true and set this rectangle to
231         that intersection, otherwise return false and do not change this
232         rectangle. For speed, no check to see if a or b are empty is performed.
233         If either is, then the return result is undefined. In the debug build,
234         we assert that both rectangles are non-empty.
235     */
intersectNoEmptyCheckSkIRect236     bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
237         SkASSERT(&a && &b);
238         SkASSERT(!a.isEmpty() && !b.isEmpty());
239 
240         if (a.fLeft < b.fRight && b.fLeft < a.fRight &&
241                 a.fTop < b.fBottom && b.fTop < a.fBottom) {
242             fLeft   = SkMax32(a.fLeft,   b.fLeft);
243             fTop    = SkMax32(a.fTop,    b.fTop);
244             fRight  = SkMin32(a.fRight,  b.fRight);
245             fBottom = SkMin32(a.fBottom, b.fBottom);
246             return true;
247         }
248         return false;
249     }
250 
251     /** If the rectangle specified by left,top,right,bottom intersects this rectangle,
252         return true and set this rectangle to that intersection,
253         otherwise return false and do not change this rectangle.
254         If either rectangle is empty, do nothing and return false.
255     */
intersectSkIRect256     bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) {
257         if (left < right && top < bottom && !this->isEmpty() &&
258                 fLeft < right && left < fRight && fTop < bottom && top < fBottom) {
259             if (fLeft < left) fLeft = left;
260             if (fTop < top) fTop = top;
261             if (fRight > right) fRight = right;
262             if (fBottom > bottom) fBottom = bottom;
263             return true;
264         }
265         return false;
266     }
267 
268     /** Returns true if a and b are not empty, and they intersect
269     */
IntersectsSkIRect270     static bool Intersects(const SkIRect& a, const SkIRect& b) {
271         return  !a.isEmpty() && !b.isEmpty() &&              // check for empties
272                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
273                 a.fTop < b.fBottom && b.fTop < a.fBottom;
274     }
275 
276     /** Update this rectangle to enclose itself and the specified rectangle.
277         If this rectangle is empty, just set it to the specified rectangle. If the specified
278         rectangle is empty, do nothing.
279     */
280     void join(int32_t left, int32_t top, int32_t right, int32_t bottom);
281 
282     /** Update this rectangle to enclose itself and the specified rectangle.
283         If this rectangle is empty, just set it to the specified rectangle. If the specified
284         rectangle is empty, do nothing.
285     */
joinSkIRect286     void join(const SkIRect& r) {
287         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
288     }
289 
290     /** Swap top/bottom or left/right if there are flipped.
291         This can be called if the edges are computed separately,
292         and may have crossed over each other.
293         When this returns, left <= right && top <= bottom
294     */
295     void sort();
296 
EmptyIRectSkIRect297     static const SkIRect& EmptyIRect() {
298         static const SkIRect gEmpty = { 0, 0, 0, 0 };
299         return gEmpty;
300     }
301 };
302 
303 /** \struct SkRect
304 */
305 struct SK_API SkRect {
306     SkScalar    fLeft, fTop, fRight, fBottom;
307 
MakeEmptySkRect308     static SkRect MakeEmpty() {
309         SkRect r;
310         r.setEmpty();
311         return r;
312     }
313 
MakeWHSkRect314     static SkRect MakeWH(SkScalar w, SkScalar h) {
315         SkRect r;
316         r.set(0, 0, w, h);
317         return r;
318     }
319 
MakeSizeSkRect320     static SkRect MakeSize(const SkSize& size) {
321         SkRect r;
322         r.set(0, 0, size.width(), size.height());
323         return r;
324     }
325 
MakeLTRBSkRect326     static SkRect MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
327         SkRect rect;
328         rect.set(l, t, r, b);
329         return rect;
330     }
331 
MakeXYWHSkRect332     static SkRect MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
333         SkRect r;
334         r.set(x, y, x + w, y + h);
335         return r;
336     }
337 
338     /**
339      *  Return true if the rectangle's width or height are <= 0
340      */
isEmptySkRect341     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
342 
343     /**
344      *  Returns true iff all values in the rect are finite. If any are
345      *  infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this
346      *  returns false.
347      */
isFiniteSkRect348     bool isFinite() const {
349 #ifdef SK_SCALAR_IS_FLOAT
350         // x * 0 will be NaN iff x is infinity or NaN.
351         // a + b will be NaN iff either a or b is NaN.
352         float value = fLeft * 0 + fTop * 0 + fRight * 0 + fBottom * 0;
353 
354         // value is either NaN or it is finite (zero).
355         // value==value will be true iff value is not NaN
356         return value == value;
357 #else
358         // use bit-or for speed, since we don't care about short-circuting the
359         // tests, and we expect the common case will be that we need to check all.
360         int isNaN = (SK_FixedNaN == fLeft)  | (SK_FixedNaN == fTop) |
361                     (SK_FixedNaN == fRight) | (SK_FixedNaN == fBottom);
362         return !isNaN;
363 #endif
364     }
365 
leftSkRect366     SkScalar    left() const { return fLeft; }
topSkRect367     SkScalar    top() const { return fTop; }
rightSkRect368     SkScalar    right() const { return fRight; }
bottomSkRect369     SkScalar    bottom() const { return fBottom; }
widthSkRect370     SkScalar    width() const { return fRight - fLeft; }
heightSkRect371     SkScalar    height() const { return fBottom - fTop; }
centerXSkRect372     SkScalar    centerX() const { return SkScalarHalf(fLeft + fRight); }
centerYSkRect373     SkScalar    centerY() const { return SkScalarHalf(fTop + fBottom); }
374 
375     friend bool operator==(const SkRect& a, const SkRect& b) {
376         return 0 == memcmp(&a, &b, sizeof(a));
377     }
378 
379     friend bool operator!=(const SkRect& a, const SkRect& b) {
380         return 0 != memcmp(&a, &b, sizeof(a));
381     }
382 
383     /** return the 4 points that enclose the rectangle
384     */
385     void toQuad(SkPoint quad[4]) const;
386 
387     /** Set this rectangle to the empty rectangle (0,0,0,0)
388     */
setEmptySkRect389     void setEmpty() { memset(this, 0, sizeof(*this)); }
390 
setSkRect391     void set(const SkIRect& src) {
392         fLeft   = SkIntToScalar(src.fLeft);
393         fTop    = SkIntToScalar(src.fTop);
394         fRight  = SkIntToScalar(src.fRight);
395         fBottom = SkIntToScalar(src.fBottom);
396     }
397 
setSkRect398     void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
399         fLeft   = left;
400         fTop    = top;
401         fRight  = right;
402         fBottom = bottom;
403     }
404     // alias for set(l, t, r, b)
setLTRBSkRect405     void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
406         this->set(left, top, right, bottom);
407     }
408 
409     /** Initialize the rect with the 4 specified integers. The routine handles
410         converting them to scalars (by calling SkIntToScalar)
411      */
isetSkRect412     void iset(int left, int top, int right, int bottom) {
413         fLeft   = SkIntToScalar(left);
414         fTop    = SkIntToScalar(top);
415         fRight  = SkIntToScalar(right);
416         fBottom = SkIntToScalar(bottom);
417     }
418 
419     /** Set this rectangle to be the bounds of the array of points.
420         If the array is empty (count == 0), then set this rectangle
421         to the empty rectangle (0,0,0,0)
422     */
423     void set(const SkPoint pts[], int count);
424 
425     // alias for set(pts, count)
setBoundsSkRect426     void setBounds(const SkPoint pts[], int count) {
427         this->set(pts, count);
428     }
429 
setXYWHSkRect430     void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) {
431         fLeft = x;
432         fTop = y;
433         fRight = x + width;
434         fBottom = y + height;
435     }
436 
437     /**
438      *  Make the largest representable rectangle
439      */
setLargestSkRect440     void setLargest() {
441         fLeft = fTop = SK_ScalarMin;
442         fRight = fBottom = SK_ScalarMax;
443     }
444 
445     /**
446      *  Make the largest representable rectangle, but inverted (e.g. fLeft will
447      *  be max and right will be min).
448      */
setLargestInvertedSkRect449     void setLargestInverted() {
450         fLeft = fTop = SK_ScalarMax;
451         fRight = fBottom = SK_ScalarMin;
452     }
453 
454     /** Offset set the rectangle by adding dx to its left and right,
455         and adding dy to its top and bottom.
456     */
offsetSkRect457     void offset(SkScalar dx, SkScalar dy) {
458         fLeft   += dx;
459         fTop    += dy;
460         fRight  += dx;
461         fBottom += dy;
462     }
463 
offsetSkRect464     void offset(const SkPoint& delta) {
465         this->offset(delta.fX, delta.fY);
466     }
467 
468     /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are
469         moved inwards, making the rectangle narrower. If dx is negative, then
470         the sides are moved outwards, making the rectangle wider. The same holds
471          true for dy and the top and bottom.
472     */
insetSkRect473     void inset(SkScalar dx, SkScalar dy)  {
474         fLeft   += dx;
475         fTop    += dy;
476         fRight  -= dx;
477         fBottom -= dy;
478     }
479 
480    /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are
481        moved outwards, making the rectangle wider. If dx is negative, then the
482        sides are moved inwards, making the rectangle narrower. The same hods
483        true for dy and the top and bottom.
484     */
outsetSkRect485     void outset(SkScalar dx, SkScalar dy)  { this->inset(-dx, -dy); }
486 
487     /** If this rectangle intersects r, return true and set this rectangle to that
488         intersection, otherwise return false and do not change this rectangle.
489         If either rectangle is empty, do nothing and return false.
490     */
491     bool intersect(const SkRect& r);
492 
493     /** If this rectangle intersects the rectangle specified by left, top, right, bottom,
494         return true and set this rectangle to that intersection, otherwise return false
495         and do not change this rectangle.
496         If either rectangle is empty, do nothing and return false.
497     */
498     bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
499 
500     /**
501      *  Return true if this rectangle is not empty, and the specified sides of
502      *  a rectangle are not empty, and they intersect.
503      */
intersectsSkRect504     bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const {
505         return // first check that both are not empty
506                left < right && top < bottom &&
507                fLeft < fRight && fTop < fBottom &&
508                // now check for intersection
509                fLeft < right && left < fRight &&
510                fTop < bottom && top < fBottom;
511     }
512 
513     /** If rectangles a and b intersect, return true and set this rectangle to
514      *  that intersection, otherwise return false and do not change this
515      *  rectangle. If either rectangle is empty, do nothing and return false.
516      */
517     bool intersect(const SkRect& a, const SkRect& b);
518 
519     /**
520      *  Return true if rectangles a and b are not empty and intersect.
521      */
IntersectsSkRect522     static bool Intersects(const SkRect& a, const SkRect& b) {
523         return  !a.isEmpty() && !b.isEmpty() &&
524                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
525                 a.fTop < b.fBottom && b.fTop < a.fBottom;
526     }
527 
528     /**
529      *  Update this rectangle to enclose itself and the specified rectangle.
530      *  If this rectangle is empty, just set it to the specified rectangle.
531      *  If the specified rectangle is empty, do nothing.
532      */
533     void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
534 
535     /** Update this rectangle to enclose itself and the specified rectangle.
536         If this rectangle is empty, just set it to the specified rectangle. If the specified
537         rectangle is empty, do nothing.
538     */
joinSkRect539     void join(const SkRect& r) {
540         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
541     }
542     // alias for join()
growToIncludeSkRect543     void growToInclude(const SkRect& r) { this->join(r); }
544 
545     /**
546      *  Grow the rect to include the specified (x,y). After this call, the
547      *  following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom.
548      *
549      *  This is close, but not quite the same contract as contains(), since
550      *  contains() treats the left and top different from the right and bottom.
551      *  contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note
552      *  that contains(x,y) always returns false if the rect is empty.
553      */
growToIncludeSkRect554     void growToInclude(SkScalar x, SkScalar y) {
555         fLeft  = SkMinScalar(x, fLeft);
556         fRight = SkMaxScalar(x, fRight);
557         fTop    = SkMinScalar(y, fTop);
558         fBottom = SkMaxScalar(y, fBottom);
559     }
560 
561     /**
562      *  Returns true if (p.fX,p.fY) is inside the rectangle, and the rectangle
563      *  is not empty.
564      *
565      *  Contains treats the left and top differently from the right and bottom.
566      *  The left and top coordinates of the rectangle are themselves considered
567      *  to be inside, while the right and bottom are not. Thus for the rectangle
568      *  {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not.
569      */
containsSkRect570     bool contains(const SkPoint& p) const {
571         return !this->isEmpty() &&
572                fLeft <= p.fX && p.fX < fRight && fTop <= p.fY && p.fY < fBottom;
573     }
574 
575     /**
576      *  Returns true if (x,y) is inside the rectangle, and the rectangle
577      *  is not empty.
578      *
579      *  Contains treats the left and top differently from the right and bottom.
580      *  The left and top coordinates of the rectangle are themselves considered
581      *  to be inside, while the right and bottom are not. Thus for the rectangle
582      *  {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not.
583      */
containsSkRect584     bool contains(SkScalar x, SkScalar y) const {
585         return  !this->isEmpty() &&
586                 fLeft <= x && x < fRight && fTop <= y && y < fBottom;
587     }
588 
589     /**
590      *  Return true if this rectangle contains r, and if both rectangles are
591      *  not empty.
592      */
containsSkRect593     bool contains(const SkRect& r) const {
594         return  !r.isEmpty() && !this->isEmpty() &&
595                 fLeft <= r.fLeft && fTop <= r.fTop &&
596                 fRight >= r.fRight && fBottom >= r.fBottom;
597     }
598 
599     /**
600      *  Set the dst rectangle by rounding this rectangle's coordinates to their
601      *  nearest integer values using SkScalarRound.
602      */
roundSkRect603     void round(SkIRect* dst) const {
604         SkASSERT(dst);
605         dst->set(SkScalarRound(fLeft), SkScalarRound(fTop),
606                  SkScalarRound(fRight), SkScalarRound(fBottom));
607     }
608 
609     /**
610      *  Set the dst rectangle by rounding "out" this rectangle, choosing the
611      *  SkScalarFloor of top and left, and the SkScalarCeil of right and bottom.
612      */
roundOutSkRect613     void roundOut(SkIRect* dst) const {
614         SkASSERT(dst);
615         dst->set(SkScalarFloor(fLeft), SkScalarFloor(fTop),
616                  SkScalarCeil(fRight), SkScalarCeil(fBottom));
617     }
618 
619     /**
620      *  Expand this rectangle by rounding its coordinates "out", choosing the
621      *  floor of top and left, and the ceil of right and bottom. If this rect
622      *  is already on integer coordinates, then it will be unchanged.
623      */
roundOutSkRect624     void roundOut() {
625         this->set(SkScalarFloorToScalar(fLeft),
626                   SkScalarFloorToScalar(fTop),
627                   SkScalarCeilToScalar(fRight),
628                   SkScalarCeilToScalar(fBottom));
629     }
630 
631     /**
632      *  Swap top/bottom or left/right if there are flipped (i.e. if width()
633      *  or height() would have returned a negative value.) This should be called
634      *  if the edges are computed separately, and may have crossed over each
635      *  other. When this returns, left <= right && top <= bottom
636      */
637     void sort();
638 };
639 
640 #endif
641 
642