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