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*/
20struct SK_API SkIRect {
21    int32_t fLeft, fTop, fRight, fBottom;
22
23    static SkIRect SK_WARN_UNUSED_RESULT MakeEmpty() {
24        SkIRect r;
25        r.setEmpty();
26        return r;
27    }
28
29    static SkIRect SK_WARN_UNUSED_RESULT MakeLargest() {
30        SkIRect r;
31        r.setLargest();
32        return r;
33    }
34
35    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
41    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
47    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
53    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
59    int left() const { return fLeft; }
60    int top() const { return fTop; }
61    int right() const { return fRight; }
62    int bottom() const { return fBottom; }
63
64    /** return the left edge of the rect */
65    int x() const { return fLeft; }
66    /** return the top edge of the rect */
67    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     */
72    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     */
78    int height() const { return fBottom - fTop; }
79
80    /**
81     *  Since the center of an integer rect may fall on a factional value, this
82     *  method is defined to return (right + left) >> 1.
83     *
84     *  This is a specific "truncation" of the average, which is different than
85     *  (right + left) / 2 when the sum is negative.
86     */
87    int centerX() const { return (fRight + fLeft) >> 1; }
88
89    /**
90     *  Since the center of an integer rect may fall on a factional value, this
91     *  method is defined to return (bottom + top) >> 1
92     *
93     *  This is a specific "truncation" of the average, which is different than
94     *  (bottom + top) / 2 when the sum is negative.
95     */
96    int centerY() const { return (fBottom + fTop) >> 1; }
97
98    /**
99     *  Return true if the rectangle's width or height are <= 0
100     */
101    bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
102
103    bool isLargest() const { return SK_MinS32 == fLeft &&
104                                    SK_MinS32 == fTop &&
105                                    SK_MaxS32 == fRight &&
106                                    SK_MaxS32 == fBottom; }
107
108    friend bool operator==(const SkIRect& a, const SkIRect& b) {
109        return !memcmp(&a, &b, sizeof(a));
110    }
111
112    friend bool operator!=(const SkIRect& a, const SkIRect& b) {
113        return !(a == b);
114    }
115
116    bool is16Bit() const {
117        return  SkIsS16(fLeft) && SkIsS16(fTop) &&
118                SkIsS16(fRight) && SkIsS16(fBottom);
119    }
120
121    /** Set the rectangle to (0,0,0,0)
122    */
123    void setEmpty() { memset(this, 0, sizeof(*this)); }
124
125    void set(int32_t left, int32_t top, int32_t right, int32_t bottom) {
126        fLeft   = left;
127        fTop    = top;
128        fRight  = right;
129        fBottom = bottom;
130    }
131    // alias for set(l, t, r, b)
132    void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) {
133        this->set(left, top, right, bottom);
134    }
135
136    void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) {
137        fLeft = x;
138        fTop = y;
139        fRight = x + width;
140        fBottom = y + height;
141    }
142
143    /**
144     *  Make the largest representable rectangle
145     */
146    void setLargest() {
147        fLeft = fTop = SK_MinS32;
148        fRight = fBottom = SK_MaxS32;
149    }
150
151    /**
152     *  Make the largest representable rectangle, but inverted (e.g. fLeft will
153     *  be max 32bit and right will be min 32bit).
154     */
155    void setLargestInverted() {
156        fLeft = fTop = SK_MaxS32;
157        fRight = fBottom = SK_MinS32;
158    }
159
160    /**
161     *  Return a new IRect, built as an offset of this rect.
162     */
163    SkIRect makeOffset(int dx, int dy) const {
164        return MakeLTRB(fLeft + dx, fTop + dy, fRight + dx, fBottom + dy);
165    }
166
167    /**
168     *  Return a new IRect, built as an inset of this rect.
169     */
170    SkIRect makeInset(int dx, int dy) const {
171        return MakeLTRB(fLeft + dx, fTop + dy, fRight - dx, fBottom - dy);
172    }
173
174    /** Offset set the rectangle by adding dx to its left and right,
175        and adding dy to its top and bottom.
176    */
177    void offset(int32_t dx, int32_t dy) {
178        fLeft   += dx;
179        fTop    += dy;
180        fRight  += dx;
181        fBottom += dy;
182    }
183
184    void offset(const SkIPoint& delta) {
185        this->offset(delta.fX, delta.fY);
186    }
187
188    /**
189     *  Offset this rect such its new x() and y() will equal newX and newY.
190     */
191    void offsetTo(int32_t newX, int32_t newY) {
192        fRight += newX - fLeft;
193        fBottom += newY - fTop;
194        fLeft = newX;
195        fTop = newY;
196    }
197
198    /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards,
199        making the rectangle narrower. If dx is negative, then the sides are moved outwards,
200        making the rectangle wider. The same holds true for dy and the top and bottom.
201    */
202    void inset(int32_t dx, int32_t dy) {
203        fLeft   += dx;
204        fTop    += dy;
205        fRight  -= dx;
206        fBottom -= dy;
207    }
208
209   /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are
210       moved outwards, making the rectangle wider. If dx is negative, then the
211       sides are moved inwards, making the rectangle narrower. The same holds
212       true for dy and the top and bottom.
213    */
214    void outset(int32_t dx, int32_t dy)  { this->inset(-dx, -dy); }
215
216    bool quickReject(int l, int t, int r, int b) const {
217        return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b;
218    }
219
220    /** Returns true if (x,y) is inside the rectangle and the rectangle is not
221        empty. The left and top are considered to be inside, while the right
222        and bottom are not. Thus for the rectangle (0, 0, 5, 10), the
223        points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not.
224    */
225    bool contains(int32_t x, int32_t y) const {
226        return  (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) &&
227                (unsigned)(y - fTop) < (unsigned)(fBottom - fTop);
228    }
229
230    /** Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle.
231        If either rectangle is empty, contains() returns false.
232    */
233    bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const {
234        return  left < right && top < bottom && !this->isEmpty() && // check for empties
235                fLeft <= left && fTop <= top &&
236                fRight >= right && fBottom >= bottom;
237    }
238
239    /** Returns true if the specified rectangle r is inside or equal to this rectangle.
240    */
241    bool contains(const SkIRect& r) const {
242        return  !r.isEmpty() && !this->isEmpty() &&     // check for empties
243                fLeft <= r.fLeft && fTop <= r.fTop &&
244                fRight >= r.fRight && fBottom >= r.fBottom;
245    }
246
247    /** Return true if this rectangle contains the specified rectangle.
248        For speed, this method does not check if either this or the specified
249        rectangles are empty, and if either is, its return value is undefined.
250        In the debugging build however, we assert that both this and the
251        specified rectangles are non-empty.
252    */
253    bool containsNoEmptyCheck(int32_t left, int32_t top,
254                              int32_t right, int32_t bottom) const {
255        SkASSERT(fLeft < fRight && fTop < fBottom);
256        SkASSERT(left < right && top < bottom);
257
258        return fLeft <= left && fTop <= top &&
259               fRight >= right && fBottom >= bottom;
260    }
261
262    bool containsNoEmptyCheck(const SkIRect& r) const {
263        return containsNoEmptyCheck(r.fLeft, r.fTop, r.fRight, r.fBottom);
264    }
265
266    /** If r intersects this rectangle, return true and set this rectangle to that
267        intersection, otherwise return false and do not change this rectangle.
268        If either rectangle is empty, do nothing and return false.
269    */
270    bool intersect(const SkIRect& r) {
271        SkASSERT(&r);
272        return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom);
273    }
274
275    /** If rectangles a and b intersect, return true and set this rectangle to
276        that intersection, otherwise return false and do not change this
277        rectangle. If either rectangle is empty, do nothing and return false.
278    */
279    bool intersect(const SkIRect& a, const SkIRect& b) {
280
281        if (!a.isEmpty() && !b.isEmpty() &&
282                a.fLeft < b.fRight && b.fLeft < a.fRight &&
283                a.fTop < b.fBottom && b.fTop < a.fBottom) {
284            fLeft   = SkMax32(a.fLeft,   b.fLeft);
285            fTop    = SkMax32(a.fTop,    b.fTop);
286            fRight  = SkMin32(a.fRight,  b.fRight);
287            fBottom = SkMin32(a.fBottom, b.fBottom);
288            return true;
289        }
290        return false;
291    }
292
293    /** If rectangles a and b intersect, return true and set this rectangle to
294        that intersection, otherwise return false and do not change this
295        rectangle. For speed, no check to see if a or b are empty is performed.
296        If either is, then the return result is undefined. In the debug build,
297        we assert that both rectangles are non-empty.
298    */
299    bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
300        SkASSERT(!a.isEmpty() && !b.isEmpty());
301
302        if (a.fLeft < b.fRight && b.fLeft < a.fRight &&
303                a.fTop < b.fBottom && b.fTop < a.fBottom) {
304            fLeft   = SkMax32(a.fLeft,   b.fLeft);
305            fTop    = SkMax32(a.fTop,    b.fTop);
306            fRight  = SkMin32(a.fRight,  b.fRight);
307            fBottom = SkMin32(a.fBottom, b.fBottom);
308            return true;
309        }
310        return false;
311    }
312
313    /** If the rectangle specified by left,top,right,bottom intersects this rectangle,
314        return true and set this rectangle to that intersection,
315        otherwise return false and do not change this rectangle.
316        If either rectangle is empty, do nothing and return false.
317    */
318    bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) {
319        if (left < right && top < bottom && !this->isEmpty() &&
320                fLeft < right && left < fRight && fTop < bottom && top < fBottom) {
321            if (fLeft < left) fLeft = left;
322            if (fTop < top) fTop = top;
323            if (fRight > right) fRight = right;
324            if (fBottom > bottom) fBottom = bottom;
325            return true;
326        }
327        return false;
328    }
329
330    /** Returns true if a and b are not empty, and they intersect
331     */
332    static bool Intersects(const SkIRect& a, const SkIRect& b) {
333        return  !a.isEmpty() && !b.isEmpty() &&              // check for empties
334        a.fLeft < b.fRight && b.fLeft < a.fRight &&
335        a.fTop < b.fBottom && b.fTop < a.fBottom;
336    }
337
338    /**
339     *  Returns true if a and b intersect. debug-asserts that neither are empty.
340     */
341    static bool IntersectsNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
342        SkASSERT(!a.isEmpty());
343        SkASSERT(!b.isEmpty());
344        return  a.fLeft < b.fRight && b.fLeft < a.fRight &&
345                a.fTop < b.fBottom && b.fTop < a.fBottom;
346    }
347
348    /** Update this rectangle to enclose itself and the specified rectangle.
349        If this rectangle is empty, just set it to the specified rectangle. If the specified
350        rectangle is empty, do nothing.
351    */
352    void join(int32_t left, int32_t top, int32_t right, int32_t bottom);
353
354    /** Update this rectangle to enclose itself and the specified rectangle.
355        If this rectangle is empty, just set it to the specified rectangle. If the specified
356        rectangle is empty, do nothing.
357    */
358    void join(const SkIRect& r) {
359        this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
360    }
361
362    /** Swap top/bottom or left/right if there are flipped.
363        This can be called if the edges are computed separately,
364        and may have crossed over each other.
365        When this returns, left <= right && top <= bottom
366    */
367    void sort();
368
369    static const SkIRect& SK_WARN_UNUSED_RESULT EmptyIRect() {
370        static const SkIRect gEmpty = { 0, 0, 0, 0 };
371        return gEmpty;
372    }
373};
374
375/** \struct SkRect
376*/
377struct SK_API SkRect {
378    SkScalar    fLeft, fTop, fRight, fBottom;
379
380    static SkRect SK_WARN_UNUSED_RESULT MakeEmpty() {
381        SkRect r;
382        r.setEmpty();
383        return r;
384    }
385
386    static SkRect SK_WARN_UNUSED_RESULT MakeLargest() {
387        SkRect r;
388        r.setLargest();
389        return r;
390    }
391
392    static SkRect SK_WARN_UNUSED_RESULT MakeWH(SkScalar w, SkScalar h) {
393        SkRect r;
394        r.set(0, 0, w, h);
395        return r;
396    }
397
398    static SkRect SK_WARN_UNUSED_RESULT MakeSize(const SkSize& size) {
399        SkRect r;
400        r.set(0, 0, size.width(), size.height());
401        return r;
402    }
403
404    static SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
405        SkRect rect;
406        rect.set(l, t, r, b);
407        return rect;
408    }
409
410    static SkRect SK_WARN_UNUSED_RESULT MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
411        SkRect r;
412        r.set(x, y, x + w, y + h);
413        return r;
414    }
415
416    SK_ATTR_DEPRECATED("use Make()")
417    static SkRect SK_WARN_UNUSED_RESULT MakeFromIRect(const SkIRect& irect) {
418        SkRect r;
419        r.set(SkIntToScalar(irect.fLeft),
420              SkIntToScalar(irect.fTop),
421              SkIntToScalar(irect.fRight),
422              SkIntToScalar(irect.fBottom));
423        return r;
424    }
425
426    static SkRect SK_WARN_UNUSED_RESULT Make(const SkIRect& irect) {
427        SkRect r;
428        r.set(SkIntToScalar(irect.fLeft),
429              SkIntToScalar(irect.fTop),
430              SkIntToScalar(irect.fRight),
431              SkIntToScalar(irect.fBottom));
432        return r;
433    }
434
435    /**
436     *  Return true if the rectangle's width or height are <= 0
437     */
438    bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
439
440    bool isLargest() const { return SK_ScalarMin == fLeft &&
441                                    SK_ScalarMin == fTop &&
442                                    SK_ScalarMax == fRight &&
443                                    SK_ScalarMax == fBottom; }
444
445    /**
446     *  Returns true iff all values in the rect are finite. If any are
447     *  infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this
448     *  returns false.
449     */
450    bool isFinite() const {
451        float accum = 0;
452        accum *= fLeft;
453        accum *= fTop;
454        accum *= fRight;
455        accum *= fBottom;
456
457        // accum is either NaN or it is finite (zero).
458        SkASSERT(0 == accum || !(accum == accum));
459
460        // value==value will be true iff value is not NaN
461        // TODO: is it faster to say !accum or accum==accum?
462        return accum == accum;
463    }
464
465    SkScalar    x() const { return fLeft; }
466    SkScalar    y() const { return fTop; }
467    SkScalar    left() const { return fLeft; }
468    SkScalar    top() const { return fTop; }
469    SkScalar    right() const { return fRight; }
470    SkScalar    bottom() const { return fBottom; }
471    SkScalar    width() const { return fRight - fLeft; }
472    SkScalar    height() const { return fBottom - fTop; }
473    SkScalar    centerX() const { return SkScalarHalf(fLeft + fRight); }
474    SkScalar    centerY() const { return SkScalarHalf(fTop + fBottom); }
475
476    friend bool operator==(const SkRect& a, const SkRect& b) {
477        return SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
478    }
479
480    friend bool operator!=(const SkRect& a, const SkRect& b) {
481        return !SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
482    }
483
484    /** return the 4 points that enclose the rectangle (top-left, top-right, bottom-right,
485        bottom-left). TODO: Consider adding param to control whether quad is CW or CCW.
486     */
487    void toQuad(SkPoint quad[4]) const;
488
489    /** Set this rectangle to the empty rectangle (0,0,0,0)
490    */
491    void setEmpty() { memset(this, 0, sizeof(*this)); }
492
493    void set(const SkIRect& src) {
494        fLeft   = SkIntToScalar(src.fLeft);
495        fTop    = SkIntToScalar(src.fTop);
496        fRight  = SkIntToScalar(src.fRight);
497        fBottom = SkIntToScalar(src.fBottom);
498    }
499
500    void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
501        fLeft   = left;
502        fTop    = top;
503        fRight  = right;
504        fBottom = bottom;
505    }
506    // alias for set(l, t, r, b)
507    void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
508        this->set(left, top, right, bottom);
509    }
510
511    /** Initialize the rect with the 4 specified integers. The routine handles
512        converting them to scalars (by calling SkIntToScalar)
513     */
514    void iset(int left, int top, int right, int bottom) {
515        fLeft   = SkIntToScalar(left);
516        fTop    = SkIntToScalar(top);
517        fRight  = SkIntToScalar(right);
518        fBottom = SkIntToScalar(bottom);
519    }
520
521    /**
522     *  Set this rectangle to be left/top at 0,0, and have the specified width
523     *  and height (automatically converted to SkScalar).
524     */
525    void isetWH(int width, int height) {
526        fLeft = fTop = 0;
527        fRight = SkIntToScalar(width);
528        fBottom = SkIntToScalar(height);
529    }
530
531    /** Set this rectangle to be the bounds of the array of points.
532        If the array is empty (count == 0), then set this rectangle
533        to the empty rectangle (0,0,0,0)
534    */
535    void set(const SkPoint pts[], int count) {
536        // set() had been checking for non-finite values, so keep that behavior
537        // for now. Now that we have setBoundsCheck(), we may decide to make
538        // set() be simpler/faster, and not check for those.
539        (void)this->setBoundsCheck(pts, count);
540    }
541
542    // alias for set(pts, count)
543    void setBounds(const SkPoint pts[], int count) {
544        (void)this->setBoundsCheck(pts, count);
545    }
546
547    /**
548     *  Compute the bounds of the array of points, and set this rect to that
549     *  bounds and return true... unless a non-finite value is encountered,
550     *  in which case this rect is set to empty and false is returned.
551     */
552    bool setBoundsCheck(const SkPoint pts[], int count);
553
554    void set(const SkPoint& p0, const SkPoint& p1) {
555        fLeft =   SkMinScalar(p0.fX, p1.fX);
556        fRight =  SkMaxScalar(p0.fX, p1.fX);
557        fTop =    SkMinScalar(p0.fY, p1.fY);
558        fBottom = SkMaxScalar(p0.fY, p1.fY);
559    }
560
561    void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) {
562        fLeft = x;
563        fTop = y;
564        fRight = x + width;
565        fBottom = y + height;
566    }
567
568    void setWH(SkScalar width, SkScalar height) {
569        fLeft = 0;
570        fTop = 0;
571        fRight = width;
572        fBottom = height;
573    }
574
575    /**
576     *  Make the largest representable rectangle
577     */
578    void setLargest() {
579        fLeft = fTop = SK_ScalarMin;
580        fRight = fBottom = SK_ScalarMax;
581    }
582
583    /**
584     *  Make the largest representable rectangle, but inverted (e.g. fLeft will
585     *  be max and right will be min).
586     */
587    void setLargestInverted() {
588        fLeft = fTop = SK_ScalarMax;
589        fRight = fBottom = SK_ScalarMin;
590    }
591
592    /**
593     *  Return a new Rect, built as an offset of this rect.
594     */
595    SkRect makeOffset(SkScalar dx, SkScalar dy) const {
596        return MakeLTRB(fLeft + dx, fTop + dy, fRight + dx, fBottom + dy);
597    }
598
599    /**
600     *  Return a new Rect, built as an inset of this rect.
601     */
602    SkRect makeInset(SkScalar dx, SkScalar dy) const {
603        return MakeLTRB(fLeft + dx, fTop + dy, fRight - dx, fBottom - dy);
604    }
605
606    /** Offset set the rectangle by adding dx to its left and right,
607        and adding dy to its top and bottom.
608    */
609    void offset(SkScalar dx, SkScalar dy) {
610        fLeft   += dx;
611        fTop    += dy;
612        fRight  += dx;
613        fBottom += dy;
614    }
615
616    void offset(const SkPoint& delta) {
617        this->offset(delta.fX, delta.fY);
618    }
619
620    /**
621     *  Offset this rect such its new x() and y() will equal newX and newY.
622     */
623    void offsetTo(SkScalar newX, SkScalar newY) {
624        fRight += newX - fLeft;
625        fBottom += newY - fTop;
626        fLeft = newX;
627        fTop = newY;
628    }
629
630    /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are
631        moved inwards, making the rectangle narrower. If dx is negative, then
632        the sides are moved outwards, making the rectangle wider. The same holds
633         true for dy and the top and bottom.
634    */
635    void inset(SkScalar dx, SkScalar dy)  {
636        fLeft   += dx;
637        fTop    += dy;
638        fRight  -= dx;
639        fBottom -= dy;
640    }
641
642   /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are
643       moved outwards, making the rectangle wider. If dx is negative, then the
644       sides are moved inwards, making the rectangle narrower. The same holds
645       true for dy and the top and bottom.
646    */
647    void outset(SkScalar dx, SkScalar dy)  { this->inset(-dx, -dy); }
648
649    /** If this rectangle intersects r, return true and set this rectangle to that
650        intersection, otherwise return false and do not change this rectangle.
651        If either rectangle is empty, do nothing and return false.
652    */
653    bool intersect(const SkRect& r);
654    bool intersect2(const SkRect& r);
655
656    /** If this rectangle intersects the rectangle specified by left, top, right, bottom,
657        return true and set this rectangle to that intersection, otherwise return false
658        and do not change this rectangle.
659        If either rectangle is empty, do nothing and return false.
660    */
661    bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
662
663    /**
664     *  Return true if this rectangle is not empty, and the specified sides of
665     *  a rectangle are not empty, and they intersect.
666     */
667    bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const {
668        return // first check that both are not empty
669               left < right && top < bottom &&
670               fLeft < fRight && fTop < fBottom &&
671               // now check for intersection
672               fLeft < right && left < fRight &&
673               fTop < bottom && top < fBottom;
674    }
675
676    /** If rectangles a and b intersect, return true and set this rectangle to
677     *  that intersection, otherwise return false and do not change this
678     *  rectangle. If either rectangle is empty, do nothing and return false.
679     */
680    bool intersect(const SkRect& a, const SkRect& b);
681
682    /**
683     *  Return true if rectangles a and b are not empty and intersect.
684     */
685    static bool Intersects(const SkRect& a, const SkRect& b) {
686        return  !a.isEmpty() && !b.isEmpty() &&
687                a.fLeft < b.fRight && b.fLeft < a.fRight &&
688                a.fTop < b.fBottom && b.fTop < a.fBottom;
689    }
690
691    /**
692     *  Update this rectangle to enclose itself and the specified rectangle.
693     *  If this rectangle is empty, just set it to the specified rectangle.
694     *  If the specified rectangle is empty, do nothing.
695     */
696    void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
697
698    /** Update this rectangle to enclose itself and the specified rectangle.
699        If this rectangle is empty, just set it to the specified rectangle. If the specified
700        rectangle is empty, do nothing.
701    */
702    void join(const SkRect& r) {
703        this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
704    }
705    // alias for join()
706    void growToInclude(const SkRect& r) { this->join(r); }
707
708    /**
709     *  Grow the rect to include the specified (x,y). After this call, the
710     *  following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom.
711     *
712     *  This is close, but not quite the same contract as contains(), since
713     *  contains() treats the left and top different from the right and bottom.
714     *  contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note
715     *  that contains(x,y) always returns false if the rect is empty.
716     */
717    void growToInclude(SkScalar x, SkScalar y) {
718        fLeft  = SkMinScalar(x, fLeft);
719        fRight = SkMaxScalar(x, fRight);
720        fTop    = SkMinScalar(y, fTop);
721        fBottom = SkMaxScalar(y, fBottom);
722    }
723
724    /** Bulk version of growToInclude */
725    void growToInclude(const SkPoint pts[], int count) {
726        this->growToInclude(pts, sizeof(SkPoint), count);
727    }
728
729    /** Bulk version of growToInclude with stride. */
730    void growToInclude(const SkPoint pts[], size_t stride, int count) {
731        SkASSERT(count >= 0);
732        SkASSERT(stride >= sizeof(SkPoint));
733        const SkPoint* end = (const SkPoint*)((intptr_t)pts + count * stride);
734        for (; pts < end; pts = (const SkPoint*)((intptr_t)pts + stride)) {
735            this->growToInclude(pts->fX, pts->fY);
736        }
737    }
738
739    /**
740     *  Return true if this rectangle contains r, and if both rectangles are
741     *  not empty.
742     */
743    bool contains(const SkRect& r) const {
744        // todo: can we eliminate the this->isEmpty check?
745        return  !r.isEmpty() && !this->isEmpty() &&
746                fLeft <= r.fLeft && fTop <= r.fTop &&
747                fRight >= r.fRight && fBottom >= r.fBottom;
748    }
749
750    /**
751     *  Set the dst rectangle by rounding this rectangle's coordinates to their
752     *  nearest integer values using SkScalarRoundToInt.
753     */
754    void round(SkIRect* dst) const {
755        SkASSERT(dst);
756        dst->set(SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop),
757                 SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom));
758    }
759
760    /**
761     *  Variant of round() that explicitly performs the rounding step (i.e. floor(x + 0.5)) using
762     *  double instead of SkScalar (float). It does this by calling SkDScalarRoundToInt(), which
763     *  may be slower than calling SkScalarRountToInt(), but gives slightly more accurate results.
764     *
765     *  e.g.
766     *      SkScalar x = 0.49999997f;
767     *      int ix = SkScalarRoundToInt(x);
768     *      SkASSERT(0 == ix);  // <--- fails
769     *      ix = SkDScalarRoundToInt(x);
770     *      SkASSERT(0 == ix);  // <--- succeeds
771     */
772    void dround(SkIRect* dst) const {
773        SkASSERT(dst);
774        dst->set(SkDScalarRoundToInt(fLeft), SkDScalarRoundToInt(fTop),
775                 SkDScalarRoundToInt(fRight), SkDScalarRoundToInt(fBottom));
776    }
777
778    /**
779     *  Set the dst rectangle by rounding "out" this rectangle, choosing the
780     *  SkScalarFloor of top and left, and the SkScalarCeil of right and bottom.
781     */
782    void roundOut(SkIRect* dst) const {
783        SkASSERT(dst);
784        dst->set(SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop),
785                 SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom));
786    }
787
788    /**
789     *  Expand this rectangle by rounding its coordinates "out", choosing the
790     *  floor of top and left, and the ceil of right and bottom. If this rect
791     *  is already on integer coordinates, then it will be unchanged.
792     */
793    void roundOut() {
794        this->set(SkScalarFloorToScalar(fLeft),
795                  SkScalarFloorToScalar(fTop),
796                  SkScalarCeilToScalar(fRight),
797                  SkScalarCeilToScalar(fBottom));
798    }
799
800    /**
801     *  Set the dst rectangle by rounding "in" this rectangle, choosing the
802     *  ceil of top and left, and the floor of right and bottom. This does *not*
803     *  call sort(), so it is possible that the resulting rect is inverted...
804     *  e.g. left >= right or top >= bottom. Call isEmpty() to detect that.
805     */
806    void roundIn(SkIRect* dst) const {
807        SkASSERT(dst);
808        dst->set(SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop),
809                 SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom));
810    }
811
812    /**
813     *  Return a new SkIRect which is contains the rounded coordinates of this
814     *  rect using SkScalarRoundToInt.
815     */
816    SkIRect round() const {
817        SkIRect ir;
818        this->round(&ir);
819        return ir;
820    }
821
822    /**
823     *  Swap top/bottom or left/right if there are flipped (i.e. if width()
824     *  or height() would have returned a negative value.) This should be called
825     *  if the edges are computed separately, and may have crossed over each
826     *  other. When this returns, left <= right && top <= bottom
827     */
828    void sort();
829
830    /**
831     *  cast-safe way to treat the rect as an array of (4) SkScalars.
832     */
833    const SkScalar* asScalars() const { return &fLeft; }
834
835#ifdef SK_DEVELOPER
836    /**
837     * Dumps the rect using SkDebugf. This is intended for Skia development debugging. Don't
838     * rely on the existence of this function or the formatting of its output.
839     */
840    void dump() const {
841        SkDebugf("{ l: %f, t: %f, r: %f, b: %f }", fLeft, fTop, fRight, fBottom);
842    }
843#endif
844
845};
846
847#endif
848