• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef SkRect_DEFINED
18 #define SkRect_DEFINED
19 
20 #include "SkPoint.h"
21 #include "SkSize.h"
22 
23 /** \struct SkIRect
24 
25     SkIRect holds four 32 bit integer coordinates for a rectangle
26 */
27 struct SK_API SkIRect {
28     int32_t fLeft, fTop, fRight, fBottom;
29 
MakeEmptySkIRect30     static SkIRect MakeEmpty() {
31         SkIRect r;
32         r.setEmpty();
33         return r;
34     }
35 
MakeWHSkIRect36     static SkIRect MakeWH(int32_t w, int32_t h) {
37         SkIRect r;
38         r.set(0, 0, w, h);
39         return r;
40     }
41 
MakeSizeSkIRect42     static SkIRect MakeSize(const SkISize& size) {
43         SkIRect r;
44         r.set(0, 0, size.width(), size.height());
45         return r;
46     }
47 
MakeLTRBSkIRect48     static SkIRect MakeLTRB(int32_t l, int32_t t, int32_t r, int32_t b) {
49         SkIRect rect;
50         rect.set(l, t, r, b);
51         return rect;
52     }
53 
MakeXYWHSkIRect54     static SkIRect MakeXYWH(int32_t x, int32_t y, int32_t w, int32_t h) {
55         SkIRect r;
56         r.set(x, y, x + w, y + h);
57         return r;
58     }
59 
60     /** Return true if the rectangle's width or height are <= 0
61     */
isEmptySkIRect62     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
63 
64     /** Returns the rectangle's width. This does not check for a valid rectangle (i.e. left <= right)
65         so the result may be negative.
66     */
widthSkIRect67     int width() const { return fRight - fLeft; }
68 
69     /** Returns the rectangle's height. This does not check for a valid rectangle (i.e. top <= bottom)
70         so the result may be negative.
71     */
heightSkIRect72     int height() const { return fBottom - fTop; }
73 
74     friend int operator==(const SkIRect& a, const SkIRect& b) {
75         return !memcmp(&a, &b, sizeof(a));
76     }
77 
78     friend int operator!=(const SkIRect& a, const SkIRect& b) {
79         return memcmp(&a, &b, sizeof(a));
80     }
81 
is16BitSkIRect82     bool is16Bit() const {
83         return  SkIsS16(fLeft) && SkIsS16(fTop) &&
84                 SkIsS16(fRight) && SkIsS16(fBottom);
85     }
86 
87     /** Set the rectangle to (0,0,0,0)
88     */
setEmptySkIRect89     void setEmpty() { memset(this, 0, sizeof(*this)); }
90 
setSkIRect91     void set(int32_t left, int32_t top, int32_t right, int32_t bottom) {
92         fLeft   = left;
93         fTop    = top;
94         fRight  = right;
95         fBottom = bottom;
96     }
97     // alias for set(l, t, r, b)
setLTRBSkIRect98     void setLTRB(int32_t left, int32_t top, int32_t right, int32_t bottom) {
99         this->set(left, top, right, bottom);
100     }
101 
setXYWHSkIRect102     void setXYWH(int32_t x, int32_t y, int32_t width, int32_t height) {
103         fLeft = x;
104         fTop = y;
105         fRight = x + width;
106         fBottom = y + height;
107     }
108 
109     /**
110      *  Make the largest representable rectangle
111      */
setLargestSkIRect112     void setLargest() {
113         fLeft = fTop = SK_MinS32;
114         fRight = fBottom = SK_MaxS32;
115     }
116 
117     /**
118      *  Make the largest representable rectangle, but inverted (e.g. fLeft will
119      *  be max 32bit and right will be min 32bit).
120      */
setLargestInvertedSkIRect121     void setLargestInverted() {
122         fLeft = fTop = SK_MaxS32;
123         fRight = fBottom = SK_MinS32;
124     }
125 
126     /** Offset set the rectangle by adding dx to its left and right,
127         and adding dy to its top and bottom.
128     */
offsetSkIRect129     void offset(int32_t dx, int32_t dy) {
130         fLeft   += dx;
131         fTop    += dy;
132         fRight  += dx;
133         fBottom += dy;
134     }
135 
offsetSkIRect136     void offset(const SkIPoint& delta) {
137         this->offset(delta.fX, delta.fY);
138     }
139 
140     /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards,
141         making the rectangle narrower. If dx is negative, then the sides are moved outwards,
142         making the rectangle wider. The same hods true for dy and the top and bottom.
143     */
insetSkIRect144     void inset(int32_t dx, int32_t dy) {
145         fLeft   += dx;
146         fTop    += dy;
147         fRight  -= dx;
148         fBottom -= dy;
149     }
150 
quickRejectSkIRect151     bool quickReject(int l, int t, int r, int b) const {
152         return l >= fRight || fLeft >= r || t >= fBottom || fTop >= b;
153     }
154 
155     /** Returns true if (x,y) is inside the rectangle and the rectangle is not
156         empty. The left and top are considered to be inside, while the right
157         and bottom are not. Thus for the rectangle (0, 0, 5, 10), the
158         points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not.
159     */
containsSkIRect160     bool contains(int32_t x, int32_t y) const {
161         return  (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) &&
162                 (unsigned)(y - fTop) < (unsigned)(fBottom - fTop);
163     }
164 
165     /** Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle.
166         If either rectangle is empty, contains() returns false.
167     */
containsSkIRect168     bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const {
169         return  left < right && top < bottom && !this->isEmpty() && // check for empties
170                 fLeft <= left && fTop <= top &&
171                 fRight >= right && fBottom >= bottom;
172     }
173 
174     /** Returns true if the specified rectangle r is inside or equal to this rectangle.
175     */
containsSkIRect176     bool contains(const SkIRect& r) const {
177         return  !r.isEmpty() && !this->isEmpty() &&     // check for empties
178                 fLeft <= r.fLeft && fTop <= r.fTop &&
179                 fRight >= r.fRight && fBottom >= r.fBottom;
180     }
181 
182     /** Return true if this rectangle contains the specified rectangle.
183 		For speed, this method does not check if either this or the specified
184 		rectangles are empty, and if either is, its return value is undefined.
185 		In the debugging build however, we assert that both this and the
186 		specified rectangles are non-empty.
187     */
containsNoEmptyCheckSkIRect188     bool containsNoEmptyCheck(int32_t left, int32_t top,
189 							  int32_t right, int32_t bottom) const {
190 		SkASSERT(fLeft < fRight && fTop < fBottom);
191         SkASSERT(left < right && top < bottom);
192 
193         return fLeft <= left && fTop <= top &&
194 			   fRight >= right && fBottom >= bottom;
195     }
196 
197     /** If r intersects this rectangle, return true and set this rectangle to that
198         intersection, otherwise return false and do not change this rectangle.
199         If either rectangle is empty, do nothing and return false.
200     */
intersectSkIRect201     bool intersect(const SkIRect& r) {
202         SkASSERT(&r);
203         return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom);
204     }
205 
206     /** If rectangles a and b intersect, return true and set this rectangle to
207         that intersection, otherwise return false and do not change this
208         rectangle. If either rectangle is empty, do nothing and return false.
209     */
intersectSkIRect210     bool intersect(const SkIRect& a, const SkIRect& b) {
211         SkASSERT(&a && &b);
212 
213         if (!a.isEmpty() && !b.isEmpty() &&
214                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
215                 a.fTop < b.fBottom && b.fTop < a.fBottom) {
216             fLeft   = SkMax32(a.fLeft,   b.fLeft);
217             fTop    = SkMax32(a.fTop,    b.fTop);
218             fRight  = SkMin32(a.fRight,  b.fRight);
219             fBottom = SkMin32(a.fBottom, b.fBottom);
220             return true;
221         }
222         return false;
223     }
224 
225     /** If rectangles a and b intersect, return true and set this rectangle to
226         that intersection, otherwise return false and do not change this
227         rectangle. For speed, no check to see if a or b are empty is performed.
228         If either is, then the return result is undefined. In the debug build,
229         we assert that both rectangles are non-empty.
230     */
intersectNoEmptyCheckSkIRect231     bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
232         SkASSERT(&a && &b);
233         SkASSERT(!a.isEmpty() && !b.isEmpty());
234 
235         if (a.fLeft < b.fRight && b.fLeft < a.fRight &&
236                 a.fTop < b.fBottom && b.fTop < a.fBottom) {
237             fLeft   = SkMax32(a.fLeft,   b.fLeft);
238             fTop    = SkMax32(a.fTop,    b.fTop);
239             fRight  = SkMin32(a.fRight,  b.fRight);
240             fBottom = SkMin32(a.fBottom, b.fBottom);
241             return true;
242         }
243         return false;
244     }
245 
246     /** If the rectangle specified by left,top,right,bottom intersects this rectangle,
247         return true and set this rectangle to that intersection,
248         otherwise return false and do not change this rectangle.
249         If either rectangle is empty, do nothing and return false.
250     */
intersectSkIRect251     bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) {
252         if (left < right && top < bottom && !this->isEmpty() &&
253                 fLeft < right && left < fRight && fTop < bottom && top < fBottom) {
254             if (fLeft < left) fLeft = left;
255             if (fTop < top) fTop = top;
256             if (fRight > right) fRight = right;
257             if (fBottom > bottom) fBottom = bottom;
258             return true;
259         }
260         return false;
261     }
262 
263     /** Returns true if a and b are not empty, and they intersect
264     */
IntersectsSkIRect265     static bool Intersects(const SkIRect& a, const SkIRect& b) {
266         return  !a.isEmpty() && !b.isEmpty() &&              // check for empties
267                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
268                 a.fTop < b.fBottom && b.fTop < a.fBottom;
269     }
270 
271     /** Update this rectangle to enclose itself and the specified rectangle.
272         If this rectangle is empty, just set it to the specified rectangle. If the specified
273         rectangle is empty, do nothing.
274     */
275     void join(int32_t left, int32_t top, int32_t right, int32_t bottom);
276 
277     /** Update this rectangle to enclose itself and the specified rectangle.
278         If this rectangle is empty, just set it to the specified rectangle. If the specified
279         rectangle is empty, do nothing.
280     */
joinSkIRect281     void join(const SkIRect& r) {
282         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
283     }
284 
285     /** Swap top/bottom or left/right if there are flipped.
286         This can be called if the edges are computed separately,
287         and may have crossed over each other.
288         When this returns, left <= right && top <= bottom
289     */
290     void sort();
291 
EmptyIRectSkIRect292     static const SkIRect& EmptyIRect() {
293         static const SkIRect gEmpty = { 0, 0, 0, 0 };
294         return gEmpty;
295     }
296 };
297 
298 /** \struct SkRect
299 */
300 struct SK_API SkRect {
301     SkScalar    fLeft, fTop, fRight, fBottom;
302 
MakeEmptySkRect303     static SkRect MakeEmpty() {
304         SkRect r;
305         r.setEmpty();
306         return r;
307     }
308 
MakeWHSkRect309     static SkRect MakeWH(SkScalar w, SkScalar h) {
310         SkRect r;
311         r.set(0, 0, w, h);
312         return r;
313     }
314 
MakeSizeSkRect315     static SkRect MakeSize(const SkSize& size) {
316         SkRect r;
317         r.set(0, 0, size.width(), size.height());
318         return r;
319     }
320 
MakeLTRBSkRect321     static SkRect MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
322         SkRect rect;
323         rect.set(l, t, r, b);
324         return rect;
325     }
326 
MakeXYWHSkRect327     static SkRect MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
328         SkRect r;
329         r.set(x, y, x + w, y + h);
330         return r;
331     }
332 
333     /** Return true if the rectangle's width or height are <= 0
334     */
isEmptySkRect335     bool        isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
336     bool        hasValidCoordinates() const;
leftSkRect337     SkScalar    left() const { return fLeft; }
topSkRect338     SkScalar    top() const { return fTop; }
rightSkRect339     SkScalar    right() const { return fRight; }
bottomSkRect340     SkScalar    bottom() const { return fBottom; }
widthSkRect341     SkScalar    width() const { return fRight - fLeft; }
heightSkRect342     SkScalar    height() const { return fBottom - fTop; }
centerXSkRect343     SkScalar    centerX() const { return SkScalarHalf(fLeft + fRight); }
centerYSkRect344     SkScalar    centerY() const { return SkScalarHalf(fTop + fBottom); }
345 
346     friend int operator==(const SkRect& a, const SkRect& b) {
347         return !memcmp(&a, &b, sizeof(a));
348     }
349 
350     friend int operator!=(const SkRect& a, const SkRect& b) {
351         return memcmp(&a, &b, sizeof(a));
352     }
353 
354     /** return the 4 points that enclose the rectangle
355     */
356     void toQuad(SkPoint quad[4]) const;
357 
358     /** Set this rectangle to the empty rectangle (0,0,0,0)
359     */
setEmptySkRect360     void setEmpty() { memset(this, 0, sizeof(*this)); }
361 
setSkRect362     void set(const SkIRect& src) {
363         fLeft   = SkIntToScalar(src.fLeft);
364         fTop    = SkIntToScalar(src.fTop);
365         fRight  = SkIntToScalar(src.fRight);
366         fBottom = SkIntToScalar(src.fBottom);
367     }
368 
setSkRect369     void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
370         fLeft   = left;
371         fTop    = top;
372         fRight  = right;
373         fBottom = bottom;
374     }
375     // alias for set(l, t, r, b)
setLTRBSkRect376     void setLTRB(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
377         this->set(left, top, right, bottom);
378     }
379 
380     /** Initialize the rect with the 4 specified integers. The routine handles
381         converting them to scalars (by calling SkIntToScalar)
382      */
isetSkRect383     void iset(int left, int top, int right, int bottom) {
384         fLeft   = SkIntToScalar(left);
385         fTop    = SkIntToScalar(top);
386         fRight  = SkIntToScalar(right);
387         fBottom = SkIntToScalar(bottom);
388     }
389 
390     /** Set this rectangle to be the bounds of the array of points.
391         If the array is empty (count == 0), then set this rectangle
392         to the empty rectangle (0,0,0,0)
393     */
394     void set(const SkPoint pts[], int count);
395 
396     // alias for set(pts, count)
setBoundsSkRect397     void setBounds(const SkPoint pts[], int count) {
398         this->set(pts, count);
399     }
400 
setXYWHSkRect401     void setXYWH(SkScalar x, SkScalar y, SkScalar width, SkScalar height) {
402         fLeft = x;
403         fTop = y;
404         fRight = x + width;
405         fBottom = y + height;
406     }
407 
408     /**
409      *  Make the largest representable rectangle
410      */
setLargestSkRect411     void setLargest() {
412         fLeft = fTop = SK_ScalarMin;
413         fRight = fBottom = SK_ScalarMax;
414     }
415 
416     /**
417      *  Make the largest representable rectangle, but inverted (e.g. fLeft will
418      *  be max and right will be min).
419      */
setLargestInvertedSkRect420     void setLargestInverted() {
421         fLeft = fTop = SK_ScalarMax;
422         fRight = fBottom = SK_ScalarMin;
423     }
424 
425     /** Offset set the rectangle by adding dx to its left and right,
426         and adding dy to its top and bottom.
427     */
offsetSkRect428     void offset(SkScalar dx, SkScalar dy) {
429         fLeft   += dx;
430         fTop    += dy;
431         fRight  += dx;
432         fBottom += dy;
433     }
434 
offsetSkRect435     void offset(const SkPoint& delta) {
436         this->offset(delta.fX, delta.fY);
437     }
438 
439     /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards,
440         making the rectangle narrower. If dx is negative, then the sides are moved outwards,
441         making the rectangle wider. The same hods true for dy and the top and bottom.
442     */
insetSkRect443     void inset(SkScalar dx, SkScalar dy)  {
444         fLeft   += dx;
445         fTop    += dy;
446         fRight  -= dx;
447         fBottom -= dy;
448     }
449 
450     /** If this rectangle intersects r, return true and set this rectangle to that
451         intersection, otherwise return false and do not change this rectangle.
452         If either rectangle is empty, do nothing and return false.
453     */
454     bool intersect(const SkRect& r);
455 
456     /** If this rectangle intersects the rectangle specified by left, top, right, bottom,
457         return true and set this rectangle to that intersection, otherwise return false
458         and do not change this rectangle.
459         If either rectangle is empty, do nothing and return false.
460     */
461     bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
462 
463     /**
464      *  Return true if this rectangle is not empty, and the specified sides of
465      *  a rectangle are not empty, and they intersect.
466      */
intersectsSkRect467     bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const {
468         return // first check that both are not empty
469                left < right && top < bottom &&
470                fLeft < fRight && fTop < fBottom &&
471                // now check for intersection
472                fLeft < right && left < fRight &&
473                fTop < bottom && top < fBottom;
474     }
475 
476     /**
477      *  Return true if rectangles a and b are not empty and intersect.
478      */
IntersectsSkRect479     static bool Intersects(const SkRect& a, const SkRect& b) {
480         return  !a.isEmpty() && !b.isEmpty() &&
481                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
482                 a.fTop < b.fBottom && b.fTop < a.fBottom;
483     }
484 
485     /**
486      *  Update this rectangle to enclose itself and the specified rectangle.
487      *  If this rectangle is empty, just set it to the specified rectangle.
488      *  If the specified rectangle is empty, do nothing.
489      */
490     void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
491 
492     /** Update this rectangle to enclose itself and the specified rectangle.
493         If this rectangle is empty, just set it to the specified rectangle. If the specified
494         rectangle is empty, do nothing.
495     */
joinSkRect496     void join(const SkRect& r) {
497         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
498     }
499     // alias for join()
growToIncludeSkRect500     void growToInclude(const SkRect& r) { this->join(r); }
501 
502     /**
503      *  Grow the rect to include the specified (x,y). After this call, the
504      *  following will be true: fLeft <= x <= fRight && fTop <= y <= fBottom.
505      *
506      *  This is close, but not quite the same contract as contains(), since
507      *  contains() treats the left and top different from the right and bottom.
508      *  contains(x,y) -> fLeft <= x < fRight && fTop <= y < fBottom. Also note
509      *  that contains(x,y) always returns false if the rect is empty.
510      */
growToIncludeSkRect511     void growToInclude(SkScalar x, SkScalar y) {
512         fLeft  = SkMinScalar(x, fLeft);
513         fRight = SkMaxScalar(x, fRight);
514         fTop    = SkMinScalar(y, fTop);
515         fBottom = SkMaxScalar(y, fBottom);
516     }
517 
518     /**
519      *  Returns true if (p.fX,p.fY) is inside the rectangle, and the rectangle
520      *  is not empty.
521      *
522      *  Contains treats the left and top differently from the right and bottom.
523      *  The left and top coordinates of the rectangle are themselves considered
524      *  to be inside, while the right and bottom are not. Thus for the rectangle
525      *  {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not.
526      */
containsSkRect527     bool contains(const SkPoint& p) const {
528         return !this->isEmpty() &&
529                fLeft <= p.fX && p.fX < fRight && fTop <= p.fY && p.fY < fBottom;
530     }
531 
532     /**
533      *  Returns true if (x,y) is inside the rectangle, and the rectangle
534      *  is not empty.
535      *
536      *  Contains treats the left and top differently from the right and bottom.
537      *  The left and top coordinates of the rectangle are themselves considered
538      *  to be inside, while the right and bottom are not. Thus for the rectangle
539      *  {0, 0, 5, 10}, (0,0) is contained, but (0,10), (5,0) and (5,10) are not.
540      */
containsSkRect541     bool contains(SkScalar x, SkScalar y) const {
542         return  !this->isEmpty() &&
543                 fLeft <= x && x < fRight && fTop <= y && y < fBottom;
544     }
545 
546     /**
547      *  Return true if this rectangle contains r, and if both rectangles are
548      *  not empty.
549      */
containsSkRect550     bool contains(const SkRect& r) const {
551         return  !r.isEmpty() && !this->isEmpty() &&
552                 fLeft <= r.fLeft && fTop <= r.fTop &&
553                 fRight >= r.fRight && fBottom >= r.fBottom;
554     }
555 
556     /**
557      *  Set the dst rectangle by rounding this rectangle's coordinates to their
558      *  nearest integer values using SkScalarRound.
559      */
roundSkRect560     void round(SkIRect* dst) const {
561         SkASSERT(dst);
562         dst->set(SkScalarRound(fLeft), SkScalarRound(fTop),
563                  SkScalarRound(fRight), SkScalarRound(fBottom));
564     }
565 
566     /**
567      *  Set the dst rectangle by rounding "out" this rectangle, choosing the
568      *  SkScalarFloor of top and left, and the SkScalarCeil of right and bottom.
569      */
roundOutSkRect570     void roundOut(SkIRect* dst) const {
571         SkASSERT(dst);
572         dst->set(SkScalarFloor(fLeft), SkScalarFloor(fTop),
573                  SkScalarCeil(fRight), SkScalarCeil(fBottom));
574     }
575 
576     /**
577      *  Swap top/bottom or left/right if there are flipped (i.e. if width()
578      *  or height() would have returned a negative value.) This should be called
579      *  if the edges are computed separately, and may have crossed over each
580      *  other. When this returns, left <= right && top <= bottom
581      */
582     void sort();
583 };
584 
585 #endif
586 
587