• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 */
20 struct SK_API SkIRect {
21     int32_t fLeft, fTop, fRight, fBottom;
22 
MakeEmptySkIRect23     static SkIRect SK_WARN_UNUSED_RESULT MakeEmpty() {
24         SkIRect r;
25         r.setEmpty();
26         return r;
27     }
28 
MakeLargestSkIRect29     static SkIRect SK_WARN_UNUSED_RESULT MakeLargest() {
30         SkIRect r;
31         r.setLargest();
32         return r;
33     }
34 
MakeWHSkIRect35     static SkIRect SK_WARN_UNUSED_RESULT MakeWH(int32_t w, int32_t h) {
36         SkIRect r;
37         r.set(0, 0, w, h);
38         return r;
39     }
40 
MakeSizeSkIRect41     static SkIRect SK_WARN_UNUSED_RESULT MakeSize(const SkISize& size) {
42         SkIRect r;
43         r.set(0, 0, size.width(), size.height());
44         return r;
45     }
46 
MakeLTRBSkIRect47     static SkIRect SK_WARN_UNUSED_RESULT MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b) {
48         SkIRect rect;
49         rect.set(l, t, r, b);
50         return rect;
51     }
52 
MakeXYWHSkIRect53     static SkIRect SK_WARN_UNUSED_RESULT MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h) {
54         SkIRect r;
55         r.set(x, y, x + w, y + h);
56         return r;
57     }
58 
leftSkIRect59     int left() const { return fLeft; }
topSkIRect60     int top() const { return fTop; }
rightSkIRect61     int right() const { return fRight; }
bottomSkIRect62     int bottom() const { return fBottom; }
63 
64     /** return the left edge of the rect */
xSkIRect65     int x() const { return fLeft; }
66     /** return the top edge of the rect */
ySkIRect67     int y() const { return fTop; }
68     /**
69      *  Returns the rectangle's width. This does not check for a valid rect
70      *  (i.e. left <= right) so the result may be negative.
71      */
widthSkIRect72     int width() const { return fRight - fLeft; }
73 
74     /**
75      *  Returns the rectangle's height. This does not check for a valid rect
76      *  (i.e. top <= bottom) so the result may be negative.
77      */
heightSkIRect78     int height() const { return fBottom - fTop; }
79 
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      */
centerXSkIRect87     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      */
centerYSkIRect96     int centerY() const { return (fBottom + fTop) >> 1; }
97 
98     /**
99      *  Return true if the rectangle's width or height are <= 0
100      */
isEmptySkIRect101     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
102 
isLargestSkIRect103     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 
is16BitSkIRect116     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     */
setEmptySkIRect123     void setEmpty() { memset(this, 0, sizeof(*this)); }
124 
setSkIRect125     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)
setLTRBSkIRect132     void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) {
133         this->set(left, top, right, bottom);
134     }
135 
setXYWHSkIRect136     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      */
setLargestSkIRect146     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      */
setLargestInvertedSkIRect155     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      */
makeOffsetSkIRect163     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      */
makeInsetSkIRect170     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     */
offsetSkIRect177     void offset(int32_t dx, int32_t dy) {
178         fLeft   += dx;
179         fTop    += dy;
180         fRight  += dx;
181         fBottom += dy;
182     }
183 
offsetSkIRect184     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      */
offsetToSkIRect191     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     */
insetSkIRect202     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     */
outsetSkIRect214     void outset(int32_t dx, int32_t dy)  { this->inset(-dx, -dy); }
215 
quickRejectSkIRect216     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     */
containsSkIRect225     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     */
containsSkIRect233     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     */
containsSkIRect241     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     */
containsNoEmptyCheckSkIRect253     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 
containsNoEmptyCheckSkIRect262     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     */
intersectSkIRect270     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     */
intersectSkIRect279     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     */
intersectNoEmptyCheckSkIRect300     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     */
intersectSkIRect320     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      */
IntersectsSkIRect334     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      */
IntersectsNoEmptyCheckSkIRect343     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     */
joinSkIRect360     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 
EmptyIRectSkIRect371     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 */
379 struct SK_API SkRect {
380     SkScalar    fLeft, fTop, fRight, fBottom;
381 
MakeEmptySkRect382     static SkRect SK_WARN_UNUSED_RESULT MakeEmpty() {
383         SkRect r;
384         r.setEmpty();
385         return r;
386     }
387 
MakeLargestSkRect388     static SkRect SK_WARN_UNUSED_RESULT MakeLargest() {
389         SkRect r;
390         r.setLargest();
391         return r;
392     }
393 
MakeWHSkRect394     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 
MakeSizeSkRect400     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 
MakeLTRBSkRect406     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 
MakeXYWHSkRect412     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()")
MakeFromIRectSkRect419     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 
MakeSkRect428     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      */
isEmptySkRect440     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
441 
isLargestSkRect442     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      */
isFiniteSkRect452     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 
xSkRect467     SkScalar    x() const { return fLeft; }
ySkRect468     SkScalar    y() const { return fTop; }
leftSkRect469     SkScalar    left() const { return fLeft; }
topSkRect470     SkScalar    top() const { return fTop; }
rightSkRect471     SkScalar    right() const { return fRight; }
bottomSkRect472     SkScalar    bottom() const { return fBottom; }
widthSkRect473     SkScalar    width() const { return fRight - fLeft; }
heightSkRect474     SkScalar    height() const { return fBottom - fTop; }
centerXSkRect475     SkScalar    centerX() const { return SkScalarHalf(fLeft + fRight); }
centerYSkRect476     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     */
setEmptySkRect493     void setEmpty() { memset(this, 0, sizeof(*this)); }
494 
setSkRect495     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 
setSkRect502     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)
setLTRBSkRect509     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      */
isetSkRect516     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      */
isetWHSkRect527     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     */
setSkRect537     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)
setBoundsSkRect545     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 
setSkRect556     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 
setXYWHSkRect563     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 
setWHSkRect570     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      */
setLargestSkRect580     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      */
setLargestInvertedSkRect589     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      */
makeOffsetSkRect597     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      */
makeInsetSkRect604     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     */
offsetSkRect611     void offset(SkScalar dx, SkScalar dy) {
612         fLeft   += dx;
613         fTop    += dy;
614         fRight  += dx;
615         fBottom += dy;
616     }
617 
offsetSkRect618     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      */
offsetToSkRect625     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     */
insetSkRect637     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     */
outsetSkRect649     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      */
intersectsSkRect669     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      */
IntersectsSkRect687     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     */
joinSkRect704     void join(const SkRect& r) {
705         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
706     }
707     // alias for join()
growToIncludeSkRect708     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      */
growToIncludeSkRect719     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 */
growToIncludeSkRect727     void growToInclude(const SkPoint pts[], int count) {
728         this->growToInclude(pts, sizeof(SkPoint), count);
729     }
730 
731     /** Bulk version of growToInclude with stride. */
growToIncludeSkRect732     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      */
containsSkRect745     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      */
roundSkRect756     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      */
droundSkRect774     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      */
roundOutSkRect784     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      */
roundOutSkRect795     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      */
roundInSkRect808     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      */
roundSkRect818     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      */
asScalarsSkRect835     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      */
dumpSkRect842     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