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
14struct SkRect;
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    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     */
89    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     */
98    int centerY() const { return (fBottom + fTop) >> 1; }
99
100    /**
101     *  Return true if the rectangle's width or height are <= 0
102     */
103    bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
104
105    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
118    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    */
125    void setEmpty() { memset(this, 0, sizeof(*this)); }
126
127    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)
134    void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) {
135        this->set(left, top, right, bottom);
136    }
137
138    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     */
148    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     */
157    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     */
165    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     */
172    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     */
179    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    */
186    void offset(int32_t dx, int32_t dy) {
187        fLeft   += dx;
188        fTop    += dy;
189        fRight  += dx;
190        fBottom += dy;
191    }
192
193    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     */
200    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    */
211    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    */
223    void outset(int32_t dx, int32_t dy)  { this->inset(-dx, -dy); }
224
225    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    */
234    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    */
242    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    */
250    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    */
266    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
275    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    */
283    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    */
291    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    */
311    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    */
330    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     */
345    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     */
354    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    */
371    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
382    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*/
390struct SK_API SkRect {
391    SkScalar    fLeft, fTop, fRight, fBottom;
392
393    static SkRect SK_WARN_UNUSED_RESULT MakeEmpty() {
394        SkRect r;
395        r.setEmpty();
396        return r;
397    }
398
399    static SkRect SK_WARN_UNUSED_RESULT MakeLargest() {
400        SkRect r;
401        r.setLargest();
402        return r;
403    }
404
405    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
411    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
417    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
423    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
429    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()")
436    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
445    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     */
457    bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
458
459    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     */
469    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
484    SkScalar    x() const { return fLeft; }
485    SkScalar    y() const { return fTop; }
486    SkScalar    left() const { return fLeft; }
487    SkScalar    top() const { return fTop; }
488    SkScalar    right() const { return fRight; }
489    SkScalar    bottom() const { return fBottom; }
490    SkScalar    width() const { return fRight - fLeft; }
491    SkScalar    height() const { return fBottom - fTop; }
492    SkScalar    centerX() const { return SkScalarHalf(fLeft + fRight); }
493    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    */
510    void setEmpty() { memset(this, 0, sizeof(*this)); }
511
512    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
519    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)
526    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     */
533    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     */
544    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    */
554    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)
562    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
573    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
580    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
587    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     */
597    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     */
606    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     */
614    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     */
621    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     */
628    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    */
635    void offset(SkScalar dx, SkScalar dy) {
636        fLeft   += dx;
637        fTop    += dy;
638        fRight  += dx;
639        fBottom += dy;
640    }
641
642    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     */
649    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    */
661    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    */
673    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
697private:
698    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
707public:
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     */
712    bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const {
713        return Intersects(fLeft, fTop, fRight, fBottom, left, top, right, bottom);
714    }
715
716    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     */
724    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    */
740    void join(const SkRect& r) {
741        this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
742    }
743
744    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     */
758    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     */
774    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 */
782    void growToInclude(const SkPoint pts[], int count) {
783        this->growToInclude(pts, sizeof(SkPoint), count);
784    }
785
786    /** Bulk version of growToInclude with stride. */
787    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     */
800    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     */
810    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     */
821    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     */
839    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     */
849    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     */
861    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     */
874    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)
881    SkIRect round() const {
882        SkIRect ir;
883        this->round(&ir);
884        return ir;
885    }
886
887    //! Returns the result of calling roundOut(&dst)
888    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     */
900    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     */
913    const SkScalar* asScalars() const { return &fLeft; }
914
915    void dump(bool asHex) const;
916    void dump() const { this->dump(false); }
917    void dumpHex() const { this->dump(true); }
918};
919
920inline 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