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        SkASSERT(&a && &b);
281
282        if (!a.isEmpty() && !b.isEmpty() &&
283                a.fLeft < b.fRight && b.fLeft < a.fRight &&
284                a.fTop < b.fBottom && b.fTop < a.fBottom) {
285            fLeft   = SkMax32(a.fLeft,   b.fLeft);
286            fTop    = SkMax32(a.fTop,    b.fTop);
287            fRight  = SkMin32(a.fRight,  b.fRight);
288            fBottom = SkMin32(a.fBottom, b.fBottom);
289            return true;
290        }
291        return false;
292    }
293
294    /** If rectangles a and b intersect, return true and set this rectangle to
295        that intersection, otherwise return false and do not change this
296        rectangle. For speed, no check to see if a or b are empty is performed.
297        If either is, then the return result is undefined. In the debug build,
298        we assert that both rectangles are non-empty.
299    */
300    bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
301        SkASSERT(&a && &b);
302        SkASSERT(!a.isEmpty() && !b.isEmpty());
303
304        if (a.fLeft < b.fRight && b.fLeft < a.fRight &&
305                a.fTop < b.fBottom && b.fTop < a.fBottom) {
306            fLeft   = SkMax32(a.fLeft,   b.fLeft);
307            fTop    = SkMax32(a.fTop,    b.fTop);
308            fRight  = SkMin32(a.fRight,  b.fRight);
309            fBottom = SkMin32(a.fBottom, b.fBottom);
310            return true;
311        }
312        return false;
313    }
314
315    /** If the rectangle specified by left,top,right,bottom intersects this rectangle,
316        return true and set this rectangle to that intersection,
317        otherwise return false and do not change this rectangle.
318        If either rectangle is empty, do nothing and return false.
319    */
320    bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) {
321        if (left < right && top < bottom && !this->isEmpty() &&
322                fLeft < right && left < fRight && fTop < bottom && top < fBottom) {
323            if (fLeft < left) fLeft = left;
324            if (fTop < top) fTop = top;
325            if (fRight > right) fRight = right;
326            if (fBottom > bottom) fBottom = bottom;
327            return true;
328        }
329        return false;
330    }
331
332    /** Returns true if a and b are not empty, and they intersect
333     */
334    static bool Intersects(const SkIRect& a, const SkIRect& b) {
335        return  !a.isEmpty() && !b.isEmpty() &&              // check for empties
336        a.fLeft < b.fRight && b.fLeft < a.fRight &&
337        a.fTop < b.fBottom && b.fTop < a.fBottom;
338    }
339
340    /**
341     *  Returns true if a and b intersect. debug-asserts that neither are empty.
342     */
343    static bool IntersectsNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
344        SkASSERT(!a.isEmpty());
345        SkASSERT(!b.isEmpty());
346        return  a.fLeft < b.fRight && b.fLeft < a.fRight &&
347                a.fTop < b.fBottom && b.fTop < a.fBottom;
348    }
349
350    /** Update this rectangle to enclose itself and the specified rectangle.
351        If this rectangle is empty, just set it to the specified rectangle. If the specified
352        rectangle is empty, do nothing.
353    */
354    void join(int32_t left, int32_t top, int32_t right, int32_t bottom);
355
356    /** Update this rectangle to enclose itself and the specified rectangle.
357        If this rectangle is empty, just set it to the specified rectangle. If the specified
358        rectangle is empty, do nothing.
359    */
360    void join(const SkIRect& r) {
361        this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
362    }
363
364    /** Swap top/bottom or left/right if there are flipped.
365        This can be called if the edges are computed separately,
366        and may have crossed over each other.
367        When this returns, left <= right && top <= bottom
368    */
369    void sort();
370
371    static const SkIRect& SK_WARN_UNUSED_RESULT EmptyIRect() {
372        static const SkIRect gEmpty = { 0, 0, 0, 0 };
373        return gEmpty;
374    }
375};
376
377/** \struct SkRect
378*/
379struct SK_API SkRect {
380    SkScalar    fLeft, fTop, fRight, fBottom;
381
382    static SkRect SK_WARN_UNUSED_RESULT MakeEmpty() {
383        SkRect r;
384        r.setEmpty();
385        return r;
386    }
387
388    static SkRect SK_WARN_UNUSED_RESULT MakeLargest() {
389        SkRect r;
390        r.setLargest();
391        return r;
392    }
393
394    static SkRect SK_WARN_UNUSED_RESULT MakeWH(SkScalar w, SkScalar h) {
395        SkRect r;
396        r.set(0, 0, w, h);
397        return r;
398    }
399
400    static SkRect SK_WARN_UNUSED_RESULT MakeSize(const SkSize& size) {
401        SkRect r;
402        r.set(0, 0, size.width(), size.height());
403        return r;
404    }
405
406    static SkRect SK_WARN_UNUSED_RESULT MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
407        SkRect rect;
408        rect.set(l, t, r, b);
409        return rect;
410    }
411
412    static SkRect SK_WARN_UNUSED_RESULT MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
413        SkRect r;
414        r.set(x, y, x + w, y + h);
415        return r;
416    }
417
418    SK_ATTR_DEPRECATED("use Make()")
419    static SkRect SK_WARN_UNUSED_RESULT MakeFromIRect(const SkIRect& irect) {
420        SkRect r;
421        r.set(SkIntToScalar(irect.fLeft),
422              SkIntToScalar(irect.fTop),
423              SkIntToScalar(irect.fRight),
424              SkIntToScalar(irect.fBottom));
425        return r;
426    }
427
428    static SkRect SK_WARN_UNUSED_RESULT Make(const SkIRect& irect) {
429        SkRect r;
430        r.set(SkIntToScalar(irect.fLeft),
431              SkIntToScalar(irect.fTop),
432              SkIntToScalar(irect.fRight),
433              SkIntToScalar(irect.fBottom));
434        return r;
435    }
436
437    /**
438     *  Return true if the rectangle's width or height are <= 0
439     */
440    bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
441
442    bool isLargest() const { return SK_ScalarMin == fLeft &&
443                                    SK_ScalarMin == fTop &&
444                                    SK_ScalarMax == fRight &&
445                                    SK_ScalarMax == fBottom; }
446
447    /**
448     *  Returns true iff all values in the rect are finite. If any are
449     *  infinite or NaN (or SK_FixedNaN when SkScalar is fixed) then this
450     *  returns false.
451     */
452    bool isFinite() const {
453        float accum = 0;
454        accum *= fLeft;
455        accum *= fTop;
456        accum *= fRight;
457        accum *= fBottom;
458
459        // accum is either NaN or it is finite (zero).
460        SkASSERT(0 == accum || !(accum == accum));
461
462        // value==value will be true iff value is not NaN
463        // TODO: is it faster to say !accum or accum==accum?
464        return accum == accum;
465    }
466
467    SkScalar    x() const { return fLeft; }
468    SkScalar    y() const { return fTop; }
469    SkScalar    left() const { return fLeft; }
470    SkScalar    top() const { return fTop; }
471    SkScalar    right() const { return fRight; }
472    SkScalar    bottom() const { return fBottom; }
473    SkScalar    width() const { return fRight - fLeft; }
474    SkScalar    height() const { return fBottom - fTop; }
475    SkScalar    centerX() const { return SkScalarHalf(fLeft + fRight); }
476    SkScalar    centerY() const { return SkScalarHalf(fTop + fBottom); }
477
478    friend bool operator==(const SkRect& a, const SkRect& b) {
479        return SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
480    }
481
482    friend bool operator!=(const SkRect& a, const SkRect& b) {
483        return !SkScalarsEqual((SkScalar*)&a, (SkScalar*)&b, 4);
484    }
485
486    /** return the 4 points that enclose the rectangle (top-left, top-right, bottom-right,
487        bottom-left). TODO: Consider adding param to control whether quad is CW or CCW.
488     */
489    void toQuad(SkPoint quad[4]) const;
490
491    /** Set this rectangle to the empty rectangle (0,0,0,0)
492    */
493    void setEmpty() { memset(this, 0, sizeof(*this)); }
494
495    void set(const SkIRect& src) {
496        fLeft   = SkIntToScalar(src.fLeft);
497        fTop    = SkIntToScalar(src.fTop);
498        fRight  = SkIntToScalar(src.fRight);
499        fBottom = SkIntToScalar(src.fBottom);
500    }
501
502    void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
503        fLeft   = left;
504        fTop    = top;
505        fRight  = right;
506        fBottom = bottom;
507    }
508    // alias for set(l, t, r, b)
509    void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
510        this->set(left, top, right, bottom);
511    }
512
513    /** Initialize the rect with the 4 specified integers. The routine handles
514        converting them to scalars (by calling SkIntToScalar)
515     */
516    void iset(int left, int top, int right, int bottom) {
517        fLeft   = SkIntToScalar(left);
518        fTop    = SkIntToScalar(top);
519        fRight  = SkIntToScalar(right);
520        fBottom = SkIntToScalar(bottom);
521    }
522
523    /**
524     *  Set this rectangle to be left/top at 0,0, and have the specified width
525     *  and height (automatically converted to SkScalar).
526     */
527    void isetWH(int width, int height) {
528        fLeft = fTop = 0;
529        fRight = SkIntToScalar(width);
530        fBottom = SkIntToScalar(height);
531    }
532
533    /** Set this rectangle to be the bounds of the array of points.
534        If the array is empty (count == 0), then set this rectangle
535        to the empty rectangle (0,0,0,0)
536    */
537    void set(const SkPoint pts[], int count) {
538        // set() had been checking for non-finite values, so keep that behavior
539        // for now. Now that we have setBoundsCheck(), we may decide to make
540        // set() be simpler/faster, and not check for those.
541        (void)this->setBoundsCheck(pts, count);
542    }
543
544    // alias for set(pts, count)
545    void setBounds(const SkPoint pts[], int count) {
546        (void)this->setBoundsCheck(pts, count);
547    }
548
549    /**
550     *  Compute the bounds of the array of points, and set this rect to that
551     *  bounds and return true... unless a non-finite value is encountered,
552     *  in which case this rect is set to empty and false is returned.
553     */
554    bool setBoundsCheck(const SkPoint pts[], int count);
555
556    void set(const SkPoint& p0, const SkPoint& p1) {
557        fLeft =   SkMinScalar(p0.fX, p1.fX);
558        fRight =  SkMaxScalar(p0.fX, p1.fX);
559        fTop =    SkMinScalar(p0.fY, p1.fY);
560        fBottom = SkMaxScalar(p0.fY, p1.fY);
561    }
562
563    void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) {
564        fLeft = x;
565        fTop = y;
566        fRight = x + width;
567        fBottom = y + height;
568    }
569
570    void setWH(SkScalar width, SkScalar height) {
571        fLeft = 0;
572        fTop = 0;
573        fRight = width;
574        fBottom = height;
575    }
576
577    /**
578     *  Make the largest representable rectangle
579     */
580    void setLargest() {
581        fLeft = fTop = SK_ScalarMin;
582        fRight = fBottom = SK_ScalarMax;
583    }
584
585    /**
586     *  Make the largest representable rectangle, but inverted (e.g. fLeft will
587     *  be max and right will be min).
588     */
589    void setLargestInverted() {
590        fLeft = fTop = SK_ScalarMax;
591        fRight = fBottom = SK_ScalarMin;
592    }
593
594    /**
595     *  Return a new Rect, built as an offset of this rect.
596     */
597    SkRect makeOffset(SkScalar dx, SkScalar dy) const {
598        return MakeLTRB(fLeft + dx, fTop + dy, fRight + dx, fBottom + dy);
599    }
600
601    /**
602     *  Return a new Rect, built as an inset of this rect.
603     */
604    SkRect makeInset(SkScalar dx, SkScalar dy) const {
605        return MakeLTRB(fLeft + dx, fTop + dy, fRight - dx, fBottom - dy);
606    }
607
608    /** Offset set the rectangle by adding dx to its left and right,
609        and adding dy to its top and bottom.
610    */
611    void offset(SkScalar dx, SkScalar dy) {
612        fLeft   += dx;
613        fTop    += dy;
614        fRight  += dx;
615        fBottom += dy;
616    }
617
618    void offset(const SkPoint& delta) {
619        this->offset(delta.fX, delta.fY);
620    }
621
622    /**
623     *  Offset this rect such its new x() and y() will equal newX and newY.
624     */
625    void offsetTo(SkScalar newX, SkScalar newY) {
626        fRight += newX - fLeft;
627        fBottom += newY - fTop;
628        fLeft = newX;
629        fTop = newY;
630    }
631
632    /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are
633        moved inwards, making the rectangle narrower. If dx is negative, then
634        the sides are moved outwards, making the rectangle wider. The same holds
635         true for dy and the top and bottom.
636    */
637    void inset(SkScalar dx, SkScalar dy)  {
638        fLeft   += dx;
639        fTop    += dy;
640        fRight  -= dx;
641        fBottom -= dy;
642    }
643
644   /** Outset the rectangle by (dx,dy). If dx is positive, then the sides are
645       moved outwards, making the rectangle wider. If dx is negative, then the
646       sides are moved inwards, making the rectangle narrower. The same holds
647       true for dy and the top and bottom.
648    */
649    void outset(SkScalar dx, SkScalar dy)  { this->inset(-dx, -dy); }
650
651    /** If this rectangle intersects r, return true and set this rectangle to that
652        intersection, otherwise return false and do not change this rectangle.
653        If either rectangle is empty, do nothing and return false.
654    */
655    bool intersect(const SkRect& r);
656    bool intersect2(const SkRect& r);
657
658    /** If this rectangle intersects the rectangle specified by left, top, right, bottom,
659        return true and set this rectangle to that intersection, otherwise return false
660        and do not change this rectangle.
661        If either rectangle is empty, do nothing and return false.
662    */
663    bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
664
665    /**
666     *  Return true if this rectangle is not empty, and the specified sides of
667     *  a rectangle are not empty, and they intersect.
668     */
669    bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const {
670        return // first check that both are not empty
671               left < right && top < bottom &&
672               fLeft < fRight && fTop < fBottom &&
673               // now check for intersection
674               fLeft < right && left < fRight &&
675               fTop < bottom && top < fBottom;
676    }
677
678    /** If rectangles a and b intersect, return true and set this rectangle to
679     *  that intersection, otherwise return false and do not change this
680     *  rectangle. If either rectangle is empty, do nothing and return false.
681     */
682    bool intersect(const SkRect& a, const SkRect& b);
683
684    /**
685     *  Return true if rectangles a and b are not empty and intersect.
686     */
687    static bool Intersects(const SkRect& a, const SkRect& b) {
688        return  !a.isEmpty() && !b.isEmpty() &&
689                a.fLeft < b.fRight && b.fLeft < a.fRight &&
690                a.fTop < b.fBottom && b.fTop < a.fBottom;
691    }
692
693    /**
694     *  Update this rectangle to enclose itself and the specified rectangle.
695     *  If this rectangle is empty, just set it to the specified rectangle.
696     *  If the specified rectangle is empty, do nothing.
697     */
698    void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
699
700    /** Update this rectangle to enclose itself and the specified rectangle.
701        If this rectangle is empty, just set it to the specified rectangle. If the specified
702        rectangle is empty, do nothing.
703    */
704    void join(const SkRect& r) {
705        this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
706    }
707    // alias for join()
708    void growToInclude(const SkRect& r) { this->join(r); }
709
710    /**
711     *  Grow the rect to include the specified (x,y). After this call, the
712     *  following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom.
713     *
714     *  This is close, but not quite the same contract as contains(), since
715     *  contains() treats the left and top different from the right and bottom.
716     *  contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note
717     *  that contains(x,y) always returns false if the rect is empty.
718     */
719    void growToInclude(SkScalar x, SkScalar y) {
720        fLeft  = SkMinScalar(x, fLeft);
721        fRight = SkMaxScalar(x, fRight);
722        fTop    = SkMinScalar(y, fTop);
723        fBottom = SkMaxScalar(y, fBottom);
724    }
725
726    /** Bulk version of growToInclude */
727    void growToInclude(const SkPoint pts[], int count) {
728        this->growToInclude(pts, sizeof(SkPoint), count);
729    }
730
731    /** Bulk version of growToInclude with stride. */
732    void growToInclude(const SkPoint pts[], size_t stride, int count) {
733        SkASSERT(count >= 0);
734        SkASSERT(stride >= sizeof(SkPoint));
735        const SkPoint* end = (const SkPoint*)((intptr_t)pts + count * stride);
736        for (; pts < end; pts = (const SkPoint*)((intptr_t)pts + stride)) {
737            this->growToInclude(pts->fX, pts->fY);
738        }
739    }
740
741    /**
742     *  Return true if this rectangle contains r, and if both rectangles are
743     *  not empty.
744     */
745    bool contains(const SkRect& r) const {
746        // todo: can we eliminate the this->isEmpty check?
747        return  !r.isEmpty() && !this->isEmpty() &&
748                fLeft <= r.fLeft && fTop <= r.fTop &&
749                fRight >= r.fRight && fBottom >= r.fBottom;
750    }
751
752    /**
753     *  Set the dst rectangle by rounding this rectangle's coordinates to their
754     *  nearest integer values using SkScalarRoundToInt.
755     */
756    void round(SkIRect* dst) const {
757        SkASSERT(dst);
758        dst->set(SkScalarRoundToInt(fLeft), SkScalarRoundToInt(fTop),
759                 SkScalarRoundToInt(fRight), SkScalarRoundToInt(fBottom));
760    }
761
762    /**
763     *  Variant of round() that explicitly performs the rounding step (i.e. floor(x + 0.5)) using
764     *  double instead of SkScalar (float). It does this by calling SkDScalarRoundToInt(), which
765     *  may be slower than calling SkScalarRountToInt(), but gives slightly more accurate results.
766     *
767     *  e.g.
768     *      SkScalar x = 0.49999997f;
769     *      int ix = SkScalarRoundToInt(x);
770     *      SkASSERT(0 == ix);  // <--- fails
771     *      ix = SkDScalarRoundToInt(x);
772     *      SkASSERT(0 == ix);  // <--- succeeds
773     */
774    void dround(SkIRect* dst) const {
775        SkASSERT(dst);
776        dst->set(SkDScalarRoundToInt(fLeft), SkDScalarRoundToInt(fTop),
777                 SkDScalarRoundToInt(fRight), SkDScalarRoundToInt(fBottom));
778    }
779
780    /**
781     *  Set the dst rectangle by rounding "out" this rectangle, choosing the
782     *  SkScalarFloor of top and left, and the SkScalarCeil of right and bottom.
783     */
784    void roundOut(SkIRect* dst) const {
785        SkASSERT(dst);
786        dst->set(SkScalarFloorToInt(fLeft), SkScalarFloorToInt(fTop),
787                 SkScalarCeilToInt(fRight), SkScalarCeilToInt(fBottom));
788    }
789
790    /**
791     *  Expand this rectangle by rounding its coordinates "out", choosing the
792     *  floor of top and left, and the ceil of right and bottom. If this rect
793     *  is already on integer coordinates, then it will be unchanged.
794     */
795    void roundOut() {
796        this->set(SkScalarFloorToScalar(fLeft),
797                  SkScalarFloorToScalar(fTop),
798                  SkScalarCeilToScalar(fRight),
799                  SkScalarCeilToScalar(fBottom));
800    }
801
802    /**
803     *  Set the dst rectangle by rounding "in" this rectangle, choosing the
804     *  ceil of top and left, and the floor of right and bottom. This does *not*
805     *  call sort(), so it is possible that the resulting rect is inverted...
806     *  e.g. left >= right or top >= bottom. Call isEmpty() to detect that.
807     */
808    void roundIn(SkIRect* dst) const {
809        SkASSERT(dst);
810        dst->set(SkScalarCeilToInt(fLeft), SkScalarCeilToInt(fTop),
811                 SkScalarFloorToInt(fRight), SkScalarFloorToInt(fBottom));
812    }
813
814    /**
815     *  Return a new SkIRect which is contains the rounded coordinates of this
816     *  rect using SkScalarRoundToInt.
817     */
818    SkIRect round() const {
819        SkIRect ir;
820        this->round(&ir);
821        return ir;
822    }
823
824    /**
825     *  Swap top/bottom or left/right if there are flipped (i.e. if width()
826     *  or height() would have returned a negative value.) This should be called
827     *  if the edges are computed separately, and may have crossed over each
828     *  other. When this returns, left <= right && top <= bottom
829     */
830    void sort();
831
832    /**
833     *  cast-safe way to treat the rect as an array of (4) SkScalars.
834     */
835    const SkScalar* asScalars() const { return &fLeft; }
836
837#ifdef SK_DEVELOPER
838    /**
839     * Dumps the rect using SkDebugf. This is intended for Skia development debugging. Don't
840     * rely on the existence of this function or the formatting of its output.
841     */
842    void dump() const {
843        SkDebugf("{ l: %f, t: %f, r: %f, b: %f }", fLeft, fTop, fRight, fBottom);
844    }
845#endif
846
847};
848
849#endif
850