1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #ifndef SkRect_DEFINED
9 #define SkRect_DEFINED
10 
11 #include "SkPoint.h"
12 #include "SkSize.h"
13 
14 struct SkRect;
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 SK_WARN_UNUSED_RESULT MakeEmpty() {
24         SkIRect r;
25         r.setEmpty();
26         return r;
27     }
28 
MakeLargestSkIRect29     static SkIRect SK_WARN_UNUSED_RESULT MakeLargest() {
30         SkIRect r;
31         r.setLargest();
32         return r;
33     }
34 
MakeWHSkIRect35     static SkIRect SK_WARN_UNUSED_RESULT MakeWH(int32_t w, int32_t h) {
36         SkIRect r;
37         r.set(0, 0, w, h);
38         return r;
39     }
40 
MakeSizeSkIRect41     static SkIRect SK_WARN_UNUSED_RESULT MakeSize(const SkISize& size) {
42         SkIRect r;
43         r.set(0, 0, size.width(), size.height());
44         return r;
45     }
46 
MakeLTRBSkIRect47     static SkIRect SK_WARN_UNUSED_RESULT MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b) {
48         SkIRect rect;
49         rect.set(l, t, r, b);
50         return rect;
51     }
52 
MakeXYWHSkIRect53     static SkIRect SK_WARN_UNUSED_RESULT MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h) {
54         SkIRect r;
55         r.set(x, y, x + w, y + h);
56         return r;
57     }
58 
leftSkIRect59     int left() const { return fLeft; }
topSkIRect60     int top() const { return fTop; }
rightSkIRect61     int right() const { return fRight; }
bottomSkIRect62     int bottom() const { return fBottom; }
63 
64     /** return the left edge of the rect */
xSkIRect65     int x() const { return fLeft; }
66     /** return the top edge of the rect */
ySkIRect67     int y() const { return fTop; }
68     /**
69      *  Returns the rectangle's width. This does not check for a valid rect
70      *  (i.e. left <= right) so the result may be negative.
71      */
widthSkIRect72     int width() const { return fRight - fLeft; }
73 
74     /**
75      *  Returns the rectangle's height. This does not check for a valid rect
76      *  (i.e. top <= bottom) so the result may be negative.
77      */
heightSkIRect78     int height() const { return fBottom - fTop; }
79 
sizeSkIRect80     SkISize size() const { return SkISize::Make(this->width(), this->height()); }
81 
82     /**
83      *  Since the center of an integer rect may fall on a factional value, this
84      *  method is defined to return (right + left) >> 1.
85      *
86      *  This is a specific "truncation" of the average, which is different than
87      *  (right + left) / 2 when the sum is negative.
88      */
centerXSkIRect89     int centerX() const { return (fRight + fLeft) >> 1; }
90 
91     /**
92      *  Since the center of an integer rect may fall on a factional value, this
93      *  method is defined to return (bottom + top) >> 1
94      *
95      *  This is a specific "truncation" of the average, which is different than
96      *  (bottom + top) / 2 when the sum is negative.
97      */
centerYSkIRect98     int centerY() const { return (fBottom + fTop) >> 1; }
99 
100     /**
101      *  Return true if the rectangle's width or height are <= 0
102      */
isEmptySkIRect103     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
104 
isLargestSkIRect105     bool isLargest() const { return SK_MinS32 == fLeft &&
106                                     SK_MinS32 == fTop &&
107                                     SK_MaxS32 == fRight &&
108                                     SK_MaxS32 == fBottom; }
109 
110     friend bool operator==(const SkIRect& a, const SkIRect& b) {
111         return !memcmp(&a, &b, sizeof(a));
112     }
113 
114     friend bool operator!=(const SkIRect& a, const SkIRect& b) {
115         return !(a == b);
116     }
117 
is16BitSkIRect118     bool is16Bit() const {
119         return  SkIsS16(fLeft) && SkIsS16(fTop) &&
120                 SkIsS16(fRight) && SkIsS16(fBottom);
121     }
122 
123     /** Set the rectangle to (0,0,0,0)
124     */
setEmptySkIRect125     void setEmpty() { memset(this, 0, sizeof(*this)); }
126 
setSkIRect127     void set(int32_t left, int32_t top, int32_t right, int32_t bottom) {
128         fLeft   = left;
129         fTop    = top;
130         fRight  = right;
131         fBottom = bottom;
132     }
133     // alias for set(l, t, r, b)
setLTRBSkIRect134     void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) {
135         this->set(left, top, right, bottom);
136     }
137 
setXYWHSkIRect138     void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) {
139         fLeft = x;
140         fTop = y;
141         fRight = x + width;
142         fBottom = y + height;
143     }
144 
145     /**
146      *  Make the largest representable rectangle
147      */
setLargestSkIRect148     void setLargest() {
149         fLeft = fTop = SK_MinS32;
150         fRight = fBottom = SK_MaxS32;
151     }
152 
153     /**
154      *  Make the largest representable rectangle, but inverted (e.g. fLeft will
155      *  be max 32bit and right will be min 32bit).
156      */
setLargestInvertedSkIRect157     void setLargestInverted() {
158         fLeft = fTop = SK_MaxS32;
159         fRight = fBottom = SK_MinS32;
160     }
161 
162     /**
163      *  Return a new IRect, built as an offset of this rect.
164      */
makeOffsetSkIRect165     SkIRect makeOffset(int32_t dx, int32_t dy) const {
166         return MakeLTRB(fLeft + dx, fTop + dy, fRight + dx, fBottom + dy);
167     }
168 
169     /**
170      *  Return a new IRect, built as an inset of this rect.
171      */
makeInsetSkIRect172     SkIRect makeInset(int32_t dx, int32_t dy) const {
173         return MakeLTRB(fLeft + dx, fTop + dy, fRight - dx, fBottom - dy);
174     }
175 
176     /**
177      *  Return a new Rect, built as an outset of this rect.
178      */
makeOutsetSkIRect179     SkIRect makeOutset(int32_t dx, int32_t dy) const {
180         return MakeLTRB(fLeft - dx, fTop - dy, fRight + dx, fBottom + dy);
181     }
182 
183     /** Offset set the rectangle by adding dx to its left and right,
184         and adding dy to its top and bottom.
185     */
offsetSkIRect186     void offset(int32_t dx, int32_t dy) {
187         fLeft   += dx;
188         fTop    += dy;
189         fRight  += dx;
190         fBottom += dy;
191     }
192 
offsetSkIRect193     void offset(const SkIPoint& delta) {
194         this->offset(delta.fX, delta.fY);
195     }
196 
197     /**
198      *  Offset this rect such its new x() and y() will equal newX and newY.
199      */
offsetToSkIRect200     void offsetTo(int32_t newX, int32_t newY) {
201         fRight += newX - fLeft;
202         fBottom += newY - fTop;
203         fLeft = newX;
204         fTop = newY;
205     }
206 
207     /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards,
208         making the rectangle narrower. If dx is negative, then the sides are moved outwards,
209         making the rectangle wider. The same holds true for dy and the top and bottom.
210     */
insetSkIRect211     void inset(int32_t dx, int32_t dy) {
212         fLeft   += dx;
213         fTop    += dy;
214         fRight  -= dx;
215         fBottom -= dy;
216     }
217 
218    /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are
219        moved outwards, making the rectangle wider. If dx is negative, then the
220        sides are moved inwards, making the rectangle narrower. The same holds
221        true for dy and the top and bottom.
222     */
outsetSkIRect223     void outset(int32_t dx, int32_t dy)  { this->inset(-dx, -dy); }
224 
quickRejectSkIRect225     bool quickReject(int l, int t, int r, int b) const {
226         return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b;
227     }
228 
229     /** Returns true if (x,y) is inside the rectangle and the rectangle is not
230         empty. The left and top are considered to be inside, while the right
231         and bottom are not. Thus for the rectangle (0, 0, 5, 10), the
232         points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not.
233     */
containsSkIRect234     bool contains(int32_t x, int32_t y) const {
235         return  (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) &&
236                 (unsigned)(y - fTop) < (unsigned)(fBottom - fTop);
237     }
238 
239     /** Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle.
240         If either rectangle is empty, contains() returns false.
241     */
containsSkIRect242     bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const {
243         return  left < right && top < bottom && !this->isEmpty() && // check for empties
244                 fLeft <= left && fTop <= top &&
245                 fRight >= right && fBottom >= bottom;
246     }
247 
248     /** Returns true if the specified rectangle r is inside or equal to this rectangle.
249     */
containsSkIRect250     bool contains(const SkIRect& r) const {
251         return  !r.isEmpty() && !this->isEmpty() &&     // check for empties
252                 fLeft <= r.fLeft && fTop <= r.fTop &&
253                 fRight >= r.fRight && fBottom >= r.fBottom;
254     }
255 
256     /** Returns true if the specified rectangle r is inside or equal to this rectangle.
257     */
258     bool contains(const SkRect& r) const;
259 
260     /** Return true if this rectangle contains the specified rectangle.
261         For speed, this method does not check if either this or the specified
262         rectangles are empty, and if either is, its return value is undefined.
263         In the debugging build however, we assert that both this and the
264         specified rectangles are non-empty.
265     */
containsNoEmptyCheckSkIRect266     bool containsNoEmptyCheck(int32_t left, int32_t top,
267                               int32_t right, int32_t bottom) const {
268         SkASSERT(fLeft < fRight && fTop < fBottom);
269         SkASSERT(left < right && top < bottom);
270 
271         return fLeft <= left && fTop <= top &&
272                fRight >= right && fBottom >= bottom;
273     }
274 
containsNoEmptyCheckSkIRect275     bool containsNoEmptyCheck(const SkIRect& r) const {
276         return containsNoEmptyCheck(r.fLeft, r.fTop, r.fRight, r.fBottom);
277     }
278 
279     /** If r intersects this rectangle, return true and set this rectangle to that
280         intersection, otherwise return false and do not change this rectangle.
281         If either rectangle is empty, do nothing and return false.
282     */
intersectSkIRect283     bool SK_WARN_UNUSED_RESULT intersect(const SkIRect& r) {
284         return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom);
285     }
286 
287     /** If rectangles a and b intersect, return true and set this rectangle to
288         that intersection, otherwise return false and do not change this
289         rectangle. If either rectangle is empty, do nothing and return false.
290     */
intersectSkIRect291     bool SK_WARN_UNUSED_RESULT intersect(const SkIRect& a, const SkIRect& b) {
292 
293         if (!a.isEmpty() && !b.isEmpty() &&
294                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
295                 a.fTop < b.fBottom && b.fTop < a.fBottom) {
296             fLeft   = SkMax32(a.fLeft,   b.fLeft);
297             fTop    = SkMax32(a.fTop,    b.fTop);
298             fRight  = SkMin32(a.fRight,  b.fRight);
299             fBottom = SkMin32(a.fBottom, b.fBottom);
300             return true;
301         }
302         return false;
303     }
304 
305     /** If rectangles a and b intersect, return true and set this rectangle to
306         that intersection, otherwise return false and do not change this
307         rectangle. For speed, no check to see if a or b are empty is performed.
308         If either is, then the return result is undefined. In the debug build,
309         we assert that both rectangles are non-empty.
310     */
intersectNoEmptyCheckSkIRect311     bool SK_WARN_UNUSED_RESULT intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
312         SkASSERT(!a.isEmpty() && !b.isEmpty());
313 
314         if (a.fLeft < b.fRight && b.fLeft < a.fRight &&
315                 a.fTop < b.fBottom && b.fTop < a.fBottom) {
316             fLeft   = SkMax32(a.fLeft,   b.fLeft);
317             fTop    = SkMax32(a.fTop,    b.fTop);
318             fRight  = SkMin32(a.fRight,  b.fRight);
319             fBottom = SkMin32(a.fBottom, b.fBottom);
320             return true;
321         }
322         return false;
323     }
324 
325     /** If the rectangle specified by left,top,right,bottom intersects this rectangle,
326         return true and set this rectangle to that intersection,
327         otherwise return false and do not change this rectangle.
328         If either rectangle is empty, do nothing and return false.
329     */
intersectSkIRect330     bool SK_WARN_UNUSED_RESULT intersect(int32_t left, int32_t top,
331                                          int32_t right, int32_t bottom) {
332         if (left < right && top < bottom && !this->isEmpty() &&
333                 fLeft < right && left < fRight && fTop < bottom && top < fBottom) {
334             if (fLeft < left) fLeft = left;
335             if (fTop < top) fTop = top;
336             if (fRight > right) fRight = right;
337             if (fBottom > bottom) fBottom = bottom;
338             return true;
339         }
340         return false;
341     }
342 
343     /** Returns true if a and b are not empty, and they intersect
344      */
IntersectsSkIRect345     static bool Intersects(const SkIRect& a, const SkIRect& b) {
346         return  !a.isEmpty() && !b.isEmpty() &&              // check for empties
347                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
348                 a.fTop < b.fBottom && b.fTop < a.fBottom;
349     }
350 
351     /**
352      *  Returns true if a and b intersect. debug-asserts that neither are empty.
353      */
IntersectsNoEmptyCheckSkIRect354     static bool IntersectsNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
355         SkASSERT(!a.isEmpty());
356         SkASSERT(!b.isEmpty());
357         return  a.fLeft < b.fRight && b.fLeft < a.fRight &&
358                 a.fTop < b.fBottom && b.fTop < a.fBottom;
359     }
360 
361     /** Update this rectangle to enclose itself and the specified rectangle.
362         If this rectangle is empty, just set it to the specified rectangle. If the specified
363         rectangle is empty, do nothing.
364     */
365     void join(int32_t left, int32_t top, int32_t right, int32_t bottom);
366 
367     /** Update this rectangle to enclose itself and the specified rectangle.
368         If this rectangle is empty, just set it to the specified rectangle. If the specified
369         rectangle is empty, do nothing.
370     */
joinSkIRect371     void join(const SkIRect& r) {
372         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
373     }
374 
375     /** Swap top/bottom or left/right if there are flipped.
376         This can be called if the edges are computed separately,
377         and may have crossed over each other.
378         When this returns, left <= right && top <= bottom
379     */
380     void sort();
381 
EmptyIRectSkIRect382     static const SkIRect& SK_WARN_UNUSED_RESULT EmptyIRect() {
383         static const SkIRect gEmpty = { 0, 0, 0, 0 };
384         return gEmpty;
385     }
386 };
387 
388 /** \struct SkRect
389 */
390 struct SK_API SkRect {
391     SkScalar    fLeft, fTop, fRight, fBottom;
392 
MakeEmptySkRect393     static SkRect SK_WARN_UNUSED_RESULT MakeEmpty() {
394         SkRect r;
395         r.setEmpty();
396         return r;
397     }
398 
MakeLargestSkRect399     static SkRect SK_WARN_UNUSED_RESULT MakeLargest() {
400         SkRect r;
401         r.setLargest();
402         return r;
403     }
404 
MakeWHSkRect405     static SkRect SK_WARN_UNUSED_RESULT MakeWH(SkScalar w, SkScalar h) {
406         SkRect r;
407         r.set(0, 0, w, h);
408         return r;
409     }
410 
MakeIWHSkRect411     static SkRect SK_WARN_UNUSED_RESULT MakeIWH(int w, int h) {
412         SkRect r;
413         r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
414         return r;
415     }
416 
MakeSizeSkRect417     static SkRect SK_WARN_UNUSED_RESULT MakeSize(const SkSize& size) {
418         SkRect r;
419         r.set(0, 0, size.width(), size.height());
420         return r;
421     }
422 
MakeLTRBSkRect423     static SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
424         SkRect rect;
425         rect.set(l, t, r, b);
426         return rect;
427     }
428 
MakeXYWHSkRect429     static SkRect SK_WARN_UNUSED_RESULT MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
430         SkRect r;
431         r.set(x, y, x + w, y + h);
432         return r;
433     }
434 
435     SK_ATTR_DEPRECATED("use Make()")
MakeFromIRectSkRect436     static SkRect SK_WARN_UNUSED_RESULT MakeFromIRect(const SkIRect& irect) {
437         SkRect r;
438         r.set(SkIntToScalar(irect.fLeft),
439               SkIntToScalar(irect.fTop),
440               SkIntToScalar(irect.fRight),
441               SkIntToScalar(irect.fBottom));
442         return r;
443     }
444 
MakeSkRect445     static SkRect SK_WARN_UNUSED_RESULT Make(const SkIRect& irect) {
446         SkRect r;
447         r.set(SkIntToScalar(irect.fLeft),
448               SkIntToScalar(irect.fTop),
449               SkIntToScalar(irect.fRight),
450               SkIntToScalar(irect.fBottom));
451         return r;
452     }
453 
454     /**
455      *  Return true if the rectangle's width or height are <= 0
456      */
isEmptySkRect457     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
458 
isLargestSkRect459     bool isLargest() const { return SK_ScalarMin == fLeft &&
460                                     SK_ScalarMin == fTop &&
461                                     SK_ScalarMax == fRight &&
462                                     SK_ScalarMax == fBottom; }
463 
464     /**
465      *  Returns true iff all values in the rect are finite. If any are
466      *  infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this
467      *  returns false.
468      */
isFiniteSkRect469     bool isFinite() const {
470         float accum = 0;
471         accum *= fLeft;
472         accum *= fTop;
473         accum *= fRight;
474         accum *= fBottom;
475 
476         // accum is either NaN or it is finite (zero).
477         SkASSERT(0 == accum || SkScalarIsNaN(accum));
478 
479         // value==value will be true iff value is not NaN
480         // TODO: is it faster to say !accum or accum==accum?
481         return !SkScalarIsNaN(accum);
482     }
483 
xSkRect484     SkScalar    x() const { return fLeft; }
ySkRect485     SkScalar    y() const { return fTop; }
leftSkRect486     SkScalar    left() const { return fLeft; }
topSkRect487     SkScalar    top() const { return fTop; }
rightSkRect488     SkScalar    right() const { return fRight; }
bottomSkRect489     SkScalar    bottom() const { return fBottom; }
widthSkRect490     SkScalar    width() const { return fRight - fLeft; }
heightSkRect491     SkScalar    height() const { return fBottom - fTop; }
centerXSkRect492     SkScalar    centerX() const { return SkScalarHalf(fLeft + fRight); }
centerYSkRect493     SkScalar    centerY() const { return SkScalarHalf(fTop + fBottom); }
494 
495     friend bool operator==(const SkRect& a, const SkRect& b) {
496         return SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
497     }
498 
499     friend bool operator!=(const SkRect& a, const SkRect& b) {
500         return !SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
501     }
502 
503     /** return the 4 points that enclose the rectangle (top-left, top-right, bottom-right,
504         bottom-left). TODO: Consider adding param to control whether quad is CW or CCW.
505      */
506     void toQuad(SkPoint quad[4]) const;
507 
508     /** Set this rectangle to the empty rectangle (0,0,0,0)
509     */
setEmptySkRect510     void setEmpty() { memset(this, 0, sizeof(*this)); }
511 
setSkRect512     void set(const SkIRect& src) {
513         fLeft   = SkIntToScalar(src.fLeft);
514         fTop    = SkIntToScalar(src.fTop);
515         fRight  = SkIntToScalar(src.fRight);
516         fBottom = SkIntToScalar(src.fBottom);
517     }
518 
setSkRect519     void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
520         fLeft   = left;
521         fTop    = top;
522         fRight  = right;
523         fBottom = bottom;
524     }
525     // alias for set(l, t, r, b)
setLTRBSkRect526     void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
527         this->set(left, top, right, bottom);
528     }
529 
530     /** Initialize the rect with the 4 specified integers. The routine handles
531         converting them to scalars (by calling SkIntToScalar)
532      */
isetSkRect533     void iset(int left, int top, int right, int bottom) {
534         fLeft   = SkIntToScalar(left);
535         fTop    = SkIntToScalar(top);
536         fRight  = SkIntToScalar(right);
537         fBottom = SkIntToScalar(bottom);
538     }
539 
540     /**
541      *  Set this rectangle to be left/top at 0,0, and have the specified width
542      *  and height (automatically converted to SkScalar).
543      */
isetWHSkRect544     void isetWH(int width, int height) {
545         fLeft = fTop = 0;
546         fRight = SkIntToScalar(width);
547         fBottom = SkIntToScalar(height);
548     }
549 
550     /** Set this rectangle to be the bounds of the array of points.
551         If the array is empty (count == 0), then set this rectangle
552         to the empty rectangle (0,0,0,0)
553     */
setSkRect554     void set(const SkPoint pts[], int count) {
555         // set() had been checking for non-finite values, so keep that behavior
556         // for now. Now that we have setBoundsCheck(), we may decide to make
557         // set() be simpler/faster, and not check for those.
558         (void)this->setBoundsCheck(pts, count);
559     }
560 
561     // alias for set(pts, count)
setBoundsSkRect562     void setBounds(const SkPoint pts[], int count) {
563         (void)this->setBoundsCheck(pts, count);
564     }
565 
566     /**
567      *  Compute the bounds of the array of points, and set this rect to that
568      *  bounds and return true... unless a non-finite value is encountered,
569      *  in which case this rect is set to empty and false is returned.
570      */
571     bool setBoundsCheck(const SkPoint pts[], int count);
572 
setSkRect573     void set(const SkPoint& p0, const SkPoint& p1) {
574         fLeft =   SkMinScalar(p0.fX, p1.fX);
575         fRight =  SkMaxScalar(p0.fX, p1.fX);
576         fTop =    SkMinScalar(p0.fY, p1.fY);
577         fBottom = SkMaxScalar(p0.fY, p1.fY);
578     }
579 
setXYWHSkRect580     void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) {
581         fLeft = x;
582         fTop = y;
583         fRight = x + width;
584         fBottom = y + height;
585     }
586 
setWHSkRect587     void setWH(SkScalar width, SkScalar height) {
588         fLeft = 0;
589         fTop = 0;
590         fRight = width;
591         fBottom = height;
592     }
593 
594     /**
595      *  Make the largest representable rectangle
596      */
setLargestSkRect597     void setLargest() {
598         fLeft = fTop = SK_ScalarMin;
599         fRight = fBottom = SK_ScalarMax;
600     }
601 
602     /**
603      *  Make the largest representable rectangle, but inverted (e.g. fLeft will
604      *  be max and right will be min).
605      */
setLargestInvertedSkRect606     void setLargestInverted() {
607         fLeft = fTop = SK_ScalarMax;
608         fRight = fBottom = SK_ScalarMin;
609     }
610 
611     /**
612      *  Return a new Rect, built as an offset of this rect.
613      */
makeOffsetSkRect614     SkRect makeOffset(SkScalar dx, SkScalar dy) const {
615         return MakeLTRB(fLeft + dx, fTop + dy, fRight + dx, fBottom + dy);
616     }
617 
618     /**
619      *  Return a new Rect, built as an inset of this rect.
620      */
makeInsetSkRect621     SkRect makeInset(SkScalar dx, SkScalar dy) const {
622         return MakeLTRB(fLeft + dx, fTop + dy, fRight - dx, fBottom - dy);
623     }
624 
625     /**
626      *  Return a new Rect, built as an outset of this rect.
627      */
makeOutsetSkRect628     SkRect makeOutset(SkScalar dx, SkScalar dy) const {
629         return MakeLTRB(fLeft - dx, fTop - dy, fRight + dx, fBottom + dy);
630     }
631 
632     /** Offset set the rectangle by adding dx to its left and right,
633         and adding dy to its top and bottom.
634     */
offsetSkRect635     void offset(SkScalar dx, SkScalar dy) {
636         fLeft   += dx;
637         fTop    += dy;
638         fRight  += dx;
639         fBottom += dy;
640     }
641 
offsetSkRect642     void offset(const SkPoint& delta) {
643         this->offset(delta.fX, delta.fY);
644     }
645 
646     /**
647      *  Offset this rect such its new x() and y() will equal newX and newY.
648      */
offsetToSkRect649     void offsetTo(SkScalar newX, SkScalar newY) {
650         fRight += newX - fLeft;
651         fBottom += newY - fTop;
652         fLeft = newX;
653         fTop = newY;
654     }
655 
656     /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are
657         moved inwards, making the rectangle narrower. If dx is negative, then
658         the sides are moved outwards, making the rectangle wider. The same holds
659          true for dy and the top and bottom.
660     */
insetSkRect661     void inset(SkScalar dx, SkScalar dy)  {
662         fLeft   += dx;
663         fTop    += dy;
664         fRight  -= dx;
665         fBottom -= dy;
666     }
667 
668    /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are
669        moved outwards, making the rectangle wider. If dx is negative, then the
670        sides are moved inwards, making the rectangle narrower. The same holds
671        true for dy and the top and bottom.
672     */
outsetSkRect673     void outset(SkScalar dx, SkScalar dy)  { this->inset(-dx, -dy); }
674 
675     /** If this rectangle intersects r, return true and set this rectangle to that
676         intersection, otherwise return false and do not change this rectangle.
677         If either rectangle is empty, do nothing and return false.
678     */
679     bool SK_WARN_UNUSED_RESULT intersect(const SkRect& r);
680 
681     /** If this rectangle intersects the rectangle specified by left, top, right, bottom,
682         return true and set this rectangle to that intersection, otherwise return false
683         and do not change this rectangle.
684         If either rectangle is empty, do nothing and return false.
685     */
686     bool SK_WARN_UNUSED_RESULT intersect(SkScalar left, SkScalar top,
687                                          SkScalar right, SkScalar bottom);
688 
689     /**
690      *  If rectangles a and b intersect, return true and set this rectangle to
691      *  that intersection, otherwise return false and do not change this
692      *  rectangle. If either rectangle is empty, do nothing and return false.
693      */
694     bool SK_WARN_UNUSED_RESULT intersect(const SkRect& a, const SkRect& b);
695 
696 
697 private:
IntersectsSkRect698     static bool Intersects(SkScalar al, SkScalar at, SkScalar ar, SkScalar ab,
699                            SkScalar bl, SkScalar bt, SkScalar br, SkScalar bb) {
700         SkScalar L = SkMaxScalar(al, bl);
701         SkScalar R = SkMinScalar(ar, br);
702         SkScalar T = SkMaxScalar(at, bt);
703         SkScalar B = SkMinScalar(ab, bb);
704         return L < R && T < B;
705     }
706 
707 public:
708     /**
709      *  Return true if this rectangle is not empty, and the specified sides of
710      *  a rectangle are not empty, and they intersect.
711      */
intersectsSkRect712     bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const {
713         return Intersects(fLeft, fTop, fRight, fBottom, left, top, right, bottom);
714     }
715 
intersectsSkRect716     bool intersects(const SkRect& r) const {
717         return Intersects(fLeft, fTop, fRight, fBottom,
718                           r.fLeft, r.fTop, r.fRight, r.fBottom);
719     }
720 
721     /**
722      *  Return true if rectangles a and b are not empty and intersect.
723      */
IntersectsSkRect724     static bool Intersects(const SkRect& a, const SkRect& b) {
725         return Intersects(a.fLeft, a.fTop, a.fRight, a.fBottom,
726                           b.fLeft, b.fTop, b.fRight, b.fBottom);
727     }
728 
729     /**
730      *  Update this rectangle to enclose itself and the specified rectangle.
731      *  If this rectangle is empty, just set it to the specified rectangle.
732      *  If the specified rectangle is empty, do nothing.
733      */
734     void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
735 
736     /** Update this rectangle to enclose itself and the specified rectangle.
737         If this rectangle is empty, just set it to the specified rectangle. If the specified
738         rectangle is empty, do nothing.
739     */
joinSkRect740     void join(const SkRect& r) {
741         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
742     }
743 
joinNonEmptyArgSkRect744     void joinNonEmptyArg(const SkRect& r) {
745         SkASSERT(!r.isEmpty());
746         // if we are empty, just assign
747         if (fLeft >= fRight || fTop >= fBottom) {
748             *this = r;
749         } else {
750             this->joinPossiblyEmptyRect(r);
751         }
752     }
753 
754     /**
755      * Joins the rectangle with another without checking if either are empty (may produce unexpected
756      * results if either rect is inverted).
757      */
joinPossiblyEmptyRectSkRect758     void joinPossiblyEmptyRect(const SkRect& r) {
759         fLeft   = SkMinScalar(fLeft, r.left());
760         fTop    = SkMinScalar(fTop, r.top());
761         fRight  = SkMaxScalar(fRight, r.right());
762         fBottom = SkMaxScalar(fBottom, r.bottom());
763     }
764 
765     /**
766      *  Grow the rect to include the specified (x,y). After this call, the
767      *  following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom.
768      *
769      *  This is close, but not quite the same contract as contains(), since
770      *  contains() treats the left and top different from the right and bottom.
771      *  contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note
772      *  that contains(x,y) always returns false if the rect is empty.
773      */
growToIncludeSkRect774     void growToInclude(SkScalar x, SkScalar y) {
775         fLeft  = SkMinScalar(x, fLeft);
776         fRight = SkMaxScalar(x, fRight);
777         fTop    = SkMinScalar(y, fTop);
778         fBottom = SkMaxScalar(y, fBottom);
779     }
780 
781     /** Bulk version of growToInclude */
growToIncludeSkRect782     void growToInclude(const SkPoint pts[], int count) {
783         this->growToInclude(pts, sizeof(SkPoint), count);
784     }
785 
786     /** Bulk version of growToInclude with stride. */
growToIncludeSkRect787     void growToInclude(const SkPoint pts[], size_t stride, int count) {
788         SkASSERT(count >= 0);
789         SkASSERT(stride >= sizeof(SkPoint));
790         const SkPoint* end = (const SkPoint*)((intptr_t)pts + count * stride);
791         for (; pts < end; pts = (const SkPoint*)((intptr_t)pts + stride)) {
792             this->growToInclude(pts->fX, pts->fY);
793         }
794     }
795 
796     /**
797      *  Return true if this rectangle contains r, and if both rectangles are
798      *  not empty.
799      */
containsSkRect800     bool contains(const SkRect& r) const {
801         // todo: can we eliminate the this->isEmpty check?
802         return  !r.isEmpty() && !this->isEmpty() &&
803                 fLeft <= r.fLeft && fTop <= r.fTop &&
804                 fRight >= r.fRight && fBottom >= r.fBottom;
805     }
806 
807     /**
808      * Returns true if the specified rectangle r is inside or equal to this rectangle.
809      */
containsSkRect810     bool contains(const SkIRect& r) const {
811         // todo: can we eliminate the this->isEmpty check?
812         return  !r.isEmpty() && !this->isEmpty() &&
813                 fLeft <= SkIntToScalar(r.fLeft) && fTop <= SkIntToScalar(r.fTop) &&
814                 fRight >= SkIntToScalar(r.fRight) && fBottom >= SkIntToScalar(r.fBottom);
815     }
816 
817     /**
818      *  Set the dst rectangle by rounding this rectangle's coordinates to their
819      *  nearest integer values using SkScalarRoundToInt.
820      */
roundSkRect821     void round(SkIRect* dst) const {
822         SkASSERT(dst);
823         dst->set(SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop),
824                  SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom));
825     }
826 
827     /**
828      *  Variant of round() that explicitly performs the rounding step (i.e. floor(x + 0.5)) using
829      *  double instead of SkScalar (float). It does this by calling SkDScalarRoundToInt(), which
830      *  may be slower than calling SkScalarRountToInt(), but gives slightly more accurate results.
831      *
832      *  e.g.
833      *      SkScalar x = 0.49999997f;
834      *      int ix = SkScalarRoundToInt(x);
835      *      SkASSERT(0 == ix);  // <--- fails
836      *      ix = SkDScalarRoundToInt(x);
837      *      SkASSERT(0 == ix);  // <--- succeeds
838      */
droundSkRect839     void dround(SkIRect* dst) const {
840         SkASSERT(dst);
841         dst->set(SkDScalarRoundToInt(fLeft), SkDScalarRoundToInt(fTop),
842                  SkDScalarRoundToInt(fRight), SkDScalarRoundToInt(fBottom));
843     }
844 
845     /**
846      *  Set the dst rectangle by rounding "out" this rectangle, choosing the
847      *  SkScalarFloor of top and left, and the SkScalarCeil of right and bottom.
848      */
roundOutSkRect849     void roundOut(SkIRect* dst) const {
850         SkASSERT(dst);
851         dst->set(SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop),
852                  SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom));
853     }
854 
855     /**
856      *  Set the dst rectangle by rounding "out" this rectangle, choosing the
857      *  SkScalarFloorToScalar of top and left, and the SkScalarCeilToScalar of right and bottom.
858      *
859      *  It is safe for this == dst
860      */
roundOutSkRect861     void roundOut(SkRect* dst) const {
862         dst->set(SkScalarFloorToScalar(fLeft),
863                  SkScalarFloorToScalar(fTop),
864                  SkScalarCeilToScalar(fRight),
865                  SkScalarCeilToScalar(fBottom));
866     }
867 
868     /**
869      *  Set the dst rectangle by rounding "in" this rectangle, choosing the
870      *  ceil of top and left, and the floor of right and bottom. This does *not*
871      *  call sort(), so it is possible that the resulting rect is inverted...
872      *  e.g. left >= right or top >= bottom. Call isEmpty() to detect that.
873      */
roundInSkRect874     void roundIn(SkIRect* dst) const {
875         SkASSERT(dst);
876         dst->set(SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop),
877                  SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom));
878     }
879 
880     //! Returns the result of calling round(&dst)
roundSkRect881     SkIRect round() const {
882         SkIRect ir;
883         this->round(&ir);
884         return ir;
885     }
886 
887     //! Returns the result of calling roundOut(&dst)
roundOutSkRect888     SkIRect roundOut() const {
889         SkIRect ir;
890         this->roundOut(&ir);
891         return ir;
892     }
893 
894     /**
895      *  Swap top/bottom or left/right if there are flipped (i.e. if width()
896      *  or height() would have returned a negative value.) This should be called
897      *  if the edges are computed separately, and may have crossed over each
898      *  other. When this returns, left <= right && top <= bottom
899      */
sortSkRect900     void sort() {
901         if (fLeft > fRight) {
902             SkTSwap<SkScalar>(fLeft, fRight);
903         }
904 
905         if (fTop > fBottom) {
906             SkTSwap<SkScalar>(fTop, fBottom);
907         }
908     }
909 
910     /**
911      *  cast-safe way to treat the rect as an array of (4) SkScalars.
912      */
asScalarsSkRect913     const SkScalar* asScalars() const { return &fLeft; }
914 
915     void dump(bool asHex) const;
dumpSkRect916     void dump() const { this->dump(false); }
dumpHexSkRect917     void dumpHex() const { this->dump(true); }
918 };
919 
contains(const SkRect & r)920 inline bool SkIRect::contains(const SkRect& r) const {
921     return  !r.isEmpty() && !this->isEmpty() &&     // check for empties
922             (SkScalar)fLeft <= r.fLeft && (SkScalar)fTop <= r.fTop &&
923             (SkScalar)fRight >= r.fRight && (SkScalar)fBottom >= r.fBottom;
924 }
925 
926 #endif
927