• 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 SkIRect {
28     int32_t fLeft, fTop, fRight, fBottom;
29 
30     /** Return true if the rectangle's width or height are <= 0
31     */
isEmptySkIRect32     bool isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
33 
34     /** Returns the rectangle's width. This does not check for a valid rectangle (i.e. left <= right)
35         so the result may be negative.
36     */
widthSkIRect37     int width() const { return fRight - fLeft; }
38 
39     /** Returns the rectangle's height. This does not check for a valid rectangle (i.e. top <= bottom)
40         so the result may be negative.
41     */
heightSkIRect42     int height() const { return fBottom - fTop; }
43 
44     friend int operator==(const SkIRect& a, const SkIRect& b) {
45         return !memcmp(&a, &b, sizeof(a));
46     }
47 
48     friend int operator!=(const SkIRect& a, const SkIRect& b) {
49         return memcmp(&a, &b, sizeof(a));
50     }
51 
is16BitSkIRect52     bool is16Bit() const {
53         return  SkIsS16(fLeft) && SkIsS16(fTop) &&
54                 SkIsS16(fRight) && SkIsS16(fBottom);
55     }
56 
57     /** Set the rectangle to (0,0,0,0)
58     */
setEmptySkIRect59     void setEmpty() { memset(this, 0, sizeof(*this)); }
60 
setSkIRect61     void set(int32_t left, int32_t top, int32_t right, int32_t bottom) {
62         fLeft   = left;
63         fTop    = top;
64         fRight  = right;
65         fBottom = bottom;
66     }
67 
68     /** Offset set the rectangle by adding dx to its left and right,
69         and adding dy to its top and bottom.
70     */
offsetSkIRect71     void offset(int32_t dx, int32_t dy) {
72         fLeft   += dx;
73         fTop    += dy;
74         fRight  += dx;
75         fBottom += dy;
76     }
77 
offsetSkIRect78     void offset(const SkIPoint& delta) {
79         this->offset(delta.fX, delta.fY);
80     }
81 
82     /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards,
83         making the rectangle narrower. If dx is negative, then the sides are moved outwards,
84         making the rectangle wider. The same hods true for dy and the top and bottom.
85     */
insetSkIRect86     void inset(int32_t dx, int32_t dy) {
87         fLeft   += dx;
88         fTop    += dy;
89         fRight  -= dx;
90         fBottom -= dy;
91     }
92 
93     /** Returns true if (x,y) is inside the rectangle and the rectangle is not
94         empty. The left and top are considered to be inside, while the right
95         and bottom are not. Thus for the rectangle (0, 0, 5, 10), the
96         points (0,0) and (0,9) are inside, while (-1,0) and (5,9) are not.
97     */
containsSkIRect98     bool contains(int32_t x, int32_t y) const {
99         return  (unsigned)(x - fLeft) < (unsigned)(fRight - fLeft) &&
100                 (unsigned)(y - fTop) < (unsigned)(fBottom - fTop);
101     }
102 
103     /** Returns true if the 4 specified sides of a rectangle are inside or equal to this rectangle.
104         If either rectangle is empty, contains() returns false.
105     */
containsSkIRect106     bool contains(int32_t left, int32_t top, int32_t right, int32_t bottom) const {
107         return  left < right && top < bottom && !this->isEmpty() && // check for empties
108                 fLeft <= left && fTop <= top &&
109                 fRight >= right && fBottom >= bottom;
110     }
111 
112     /** Returns true if the specified rectangle r is inside or equal to this rectangle.
113     */
containsSkIRect114     bool contains(const SkIRect& r) const {
115         return  !r.isEmpty() && !this->isEmpty() &&     // check for empties
116                 fLeft <= r.fLeft && fTop <= r.fTop &&
117                 fRight >= r.fRight && fBottom >= r.fBottom;
118     }
119 
120     /** Return true if this rectangle contains the specified rectangle.
121 		For speed, this method does not check if either this or the specified
122 		rectangles are empty, and if either is, its return value is undefined.
123 		In the debugging build however, we assert that both this and the
124 		specified rectangles are non-empty.
125     */
containsNoEmptyCheckSkIRect126     bool containsNoEmptyCheck(int32_t left, int32_t top,
127 							  int32_t right, int32_t bottom) const {
128 		SkASSERT(fLeft < fRight && fTop < fBottom);
129         SkASSERT(left < right && top < bottom);
130 
131         return fLeft <= left && fTop <= top &&
132 			   fRight >= right && fBottom >= bottom;
133     }
134 
135     /** If r intersects this rectangle, return true and set this rectangle to that
136         intersection, otherwise return false and do not change this rectangle.
137         If either rectangle is empty, do nothing and return false.
138     */
intersectSkIRect139     bool intersect(const SkIRect& r) {
140         SkASSERT(&r);
141         return this->intersect(r.fLeft, r.fTop, r.fRight, r.fBottom);
142     }
143 
144     /** If rectangles a and b intersect, return true and set this rectangle to
145         that intersection, otherwise return false and do not change this
146         rectangle. If either rectangle is empty, do nothing and return false.
147     */
intersectSkIRect148     bool intersect(const SkIRect& a, const SkIRect& b) {
149         SkASSERT(&a && &b);
150 
151         if (!a.isEmpty() && !b.isEmpty() &&
152                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
153                 a.fTop < b.fBottom && b.fTop < a.fBottom) {
154             fLeft   = SkMax32(a.fLeft,   b.fLeft);
155             fTop    = SkMax32(a.fTop,    b.fTop);
156             fRight  = SkMin32(a.fRight,  b.fRight);
157             fBottom = SkMin32(a.fBottom, b.fBottom);
158             return true;
159         }
160         return false;
161     }
162 
163     /** If rectangles a and b intersect, return true and set this rectangle to
164         that intersection, otherwise return false and do not change this
165         rectangle. For speed, no check to see if a or b are empty is performed.
166         If either is, then the return result is undefined. In the debug build,
167         we assert that both rectangles are non-empty.
168     */
intersectNoEmptyCheckSkIRect169     bool intersectNoEmptyCheck(const SkIRect& a, const SkIRect& b) {
170         SkASSERT(&a && &b);
171         SkASSERT(!a.isEmpty() && !b.isEmpty());
172 
173         if (a.fLeft < b.fRight && b.fLeft < a.fRight &&
174                 a.fTop < b.fBottom && b.fTop < a.fBottom) {
175             fLeft   = SkMax32(a.fLeft,   b.fLeft);
176             fTop    = SkMax32(a.fTop,    b.fTop);
177             fRight  = SkMin32(a.fRight,  b.fRight);
178             fBottom = SkMin32(a.fBottom, b.fBottom);
179             return true;
180         }
181         return false;
182     }
183 
184     /** If the rectangle specified by left,top,right,bottom intersects this rectangle,
185         return true and set this rectangle to that intersection,
186         otherwise return false and do not change this rectangle.
187         If either rectangle is empty, do nothing and return false.
188     */
intersectSkIRect189     bool intersect(int32_t left, int32_t top, int32_t right, int32_t bottom) {
190         if (left < right && top < bottom && !this->isEmpty() &&
191                 fLeft < right && left < fRight && fTop < bottom && top < fBottom) {
192             if (fLeft < left) fLeft = left;
193             if (fTop < top) fTop = top;
194             if (fRight > right) fRight = right;
195             if (fBottom > bottom) fBottom = bottom;
196             return true;
197         }
198         return false;
199     }
200 
201     /** Returns true if a and b are not empty, and they intersect
202     */
IntersectsSkIRect203     static bool Intersects(const SkIRect& a, const SkIRect& b) {
204         return  !a.isEmpty() && !b.isEmpty() &&              // check for empties
205                 a.fLeft < b.fRight && b.fLeft < a.fRight &&
206                 a.fTop < b.fBottom && b.fTop < a.fBottom;
207     }
208 
209     /** Update this rectangle to enclose itself and the specified rectangle.
210         If this rectangle is empty, just set it to the specified rectangle. If the specified
211         rectangle is empty, do nothing.
212     */
213     void join(int32_t left, int32_t top, int32_t right, int32_t bottom);
214 
215     /** Update this rectangle to enclose itself and the specified rectangle.
216         If this rectangle is empty, just set it to the specified rectangle. If the specified
217         rectangle is empty, do nothing.
218     */
joinSkIRect219     void join(const SkIRect& r) {
220         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
221     }
222 
223     /** Swap top/bottom or left/right if there are flipped.
224         This can be called if the edges are computed separately,
225         and may have crossed over each other.
226         When this returns, left <= right && top <= bottom
227     */
228     void sort();
229 };
230 
231 /** \struct SkRect
232 */
233 struct SkRect {
234     SkScalar    fLeft, fTop, fRight, fBottom;
235 
MakeSizeSkRect236     static SkRect MakeSize(const SkSize& size) {
237         SkRect r;
238         r.set(0, 0, size.width(), size.height());
239         return r;
240     }
241 
MakeLTRBSkRect242     static SkRect MakeLTRB(SkScalar l, SkScalar t, SkScalar r, SkScalar b) {
243         SkRect rect;
244         rect.set(l, t, r, b);
245         return rect;
246     }
247 
MakeXYWHSkRect248     static SkRect MakeXYWH(SkScalar x, SkScalar y, SkScalar w, SkScalar h) {
249         SkRect r;
250         r.set(x, y, x + w, y + h);
251         return r;
252     }
253 
254     /** Return true if the rectangle's width or height are <= 0
255     */
isEmptySkRect256     bool        isEmpty() const { return fLeft >= fRight || fTop >= fBottom; }
widthSkRect257     SkScalar    width() const { return fRight - fLeft; }
heightSkRect258     SkScalar    height() const { return fBottom - fTop; }
centerXSkRect259     SkScalar    centerX() const { return SkScalarHalf(fLeft + fRight); }
centerYSkRect260     SkScalar    centerY() const { return SkScalarHalf(fTop + fBottom); }
261 
262     friend int operator==(const SkRect& a, const SkRect& b) {
263         return !memcmp(&a, &b, sizeof(a));
264     }
265 
266     friend int operator!=(const SkRect& a, const SkRect& b) {
267         return memcmp(&a, &b, sizeof(a));
268     }
269 
270     /** return the 4 points that enclose the rectangle
271     */
272     void toQuad(SkPoint quad[4]) const;
273 
274     /** Set this rectangle to the empty rectangle (0,0,0,0)
275     */
setEmptySkRect276     void setEmpty() { memset(this, 0, sizeof(*this)); }
277 
setSkRect278     void set(const SkIRect& src) {
279         fLeft   = SkIntToScalar(src.fLeft);
280         fTop    = SkIntToScalar(src.fTop);
281         fRight  = SkIntToScalar(src.fRight);
282         fBottom = SkIntToScalar(src.fBottom);
283     }
284 
setSkRect285     void set(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) {
286         fLeft   = left;
287         fTop    = top;
288         fRight  = right;
289         fBottom = bottom;
290     }
291 
292     /** Initialize the rect with the 4 specified integers. The routine handles
293         converting them to scalars (by calling SkIntToScalar)
294      */
isetSkRect295     void iset(int left, int top, int right, int bottom) {
296         fLeft   = SkIntToScalar(left);
297         fTop    = SkIntToScalar(top);
298         fRight  = SkIntToScalar(right);
299         fBottom = SkIntToScalar(bottom);
300     }
301 
302     /** Set this rectangle to be the bounds of the array of points.
303         If the array is empty (count == 0), then set this rectangle
304         to the empty rectangle (0,0,0,0)
305     */
306     void set(const SkPoint pts[], int count);
307 
308     /** Offset set the rectangle by adding dx to its left and right,
309         and adding dy to its top and bottom.
310     */
offsetSkRect311     void offset(SkScalar dx, SkScalar dy) {
312         fLeft   += dx;
313         fTop    += dy;
314         fRight  += dx;
315         fBottom += dy;
316     }
317 
offsetSkRect318     void offset(const SkPoint& delta) {
319         this->offset(delta.fX, delta.fY);
320     }
321 
322     /** Inset the rectangle by (dx,dy). If dx is positive, then the sides are moved inwards,
323         making the rectangle narrower. If dx is negative, then the sides are moved outwards,
324         making the rectangle wider. The same hods true for dy and the top and bottom.
325     */
insetSkRect326     void inset(SkScalar dx, SkScalar dy)  {
327         fLeft   += dx;
328         fTop    += dy;
329         fRight  -= dx;
330         fBottom -= dy;
331     }
332 
333     /** If this rectangle intersects r, return true and set this rectangle to that
334         intersection, otherwise return false and do not change this rectangle.
335         If either rectangle is empty, do nothing and return false.
336     */
337     bool intersect(const SkRect& r);
338 
339     /** If this rectangle intersects the rectangle specified by left, top, right, bottom,
340         return true and set this rectangle to that intersection, otherwise return false
341         and do not change this rectangle.
342         If either rectangle is empty, do nothing and return false.
343     */
344     bool intersect(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
345 
346     /** Return true if this rectangle is not empty, and the specified sides of
347         a rectangle are not empty, and they intersect.
348     */
intersectsSkRect349     bool intersects(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) const {
350         return // first check that both are not empty
351                left < right && top < bottom &&
352                fLeft < fRight && fTop < fBottom &&
353                // now check for intersection
354                fLeft < right && left < fRight &&
355                fTop < bottom && top < fBottom;
356     }
357 
358     /** Return true if rectangles a and b are not empty and intersect.
359         */
IntersectsSkRect360     static bool Intersects(const SkRect& a, const SkRect& b) {
361         return  !a.isEmpty() && !b.isEmpty() &&             // check for empties
362         a.fLeft < b.fRight && b.fLeft < a.fRight &&
363         a.fTop < b.fBottom && b.fTop < a.fBottom;
364     }
365 
366     /** Update this rectangle to enclose itself and the specified rectangle.
367         If this rectangle is empty, just set it to the specified rectangle. If the specified
368         rectangle is empty, do nothing.
369     */
370     void join(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom);
371 
372     /** Update this rectangle to enclose itself and the specified rectangle.
373         If this rectangle is empty, just set it to the specified rectangle. If the specified
374         rectangle is empty, do nothing.
375     */
joinSkRect376     void join(const SkRect& r) {
377         this->join(r.fLeft, r.fTop, r.fRight, r.fBottom);
378     }
379 
380     /** Returns true if (p.fX,p.fY) is inside the rectangle. The left and top coordinates of
381         the rectangle are considered to be inside, while the right and bottom coordinates
382         are not. Thus for the rectangle (0, 0, 5, 10), the points (0,0) and (0,9) are inside,
383         while (-1,0) and (5,9) are not.
384         If this rectangle is empty, return false.
385     */
containsSkRect386     bool contains(const SkPoint& p) const {
387         return  !this->isEmpty() &&
388                 fLeft <= p.fX && p.fX < fRight &&
389                 fTop <= p.fY && p.fY < fBottom;
390     }
391 
392     /** Returns true if (x,y) is inside the rectangle. The left and top coordinates of
393         the rectangle are considered to be inside, while the right and bottom coordinates
394         are not. Thus for the rectangle (0, 0, 5, 10), the points (0,0) and (0,9) are inside,
395         while (-1,0) and (5,9) are not.
396         If this rectangle is empty, return false.
397     */
containsSkRect398     bool contains(SkScalar x, SkScalar y) const {
399         return  !this->isEmpty() &&
400                 fLeft <= x && x < fRight &&
401                 fTop <= y && y < fBottom;
402     }
403 
404     /** Return true if this rectangle contains r.
405         If either rectangle is empty, return false.
406     */
containsSkRect407     bool contains(const SkRect& r) const {
408         return  !r.isEmpty() && !this->isEmpty() &&     // check for empties
409                 fLeft <= r.fLeft && fTop <= r.fTop &&
410                 fRight >= r.fRight && fBottom >= r.fBottom;
411     }
412 
413     /** Set the dst integer rectangle by rounding this rectangle's coordinates
414         to their nearest integer values.
415     */
roundSkRect416     void round(SkIRect* dst) const {
417         SkASSERT(dst);
418         dst->set(SkScalarRound(fLeft), SkScalarRound(fTop), SkScalarRound(fRight), SkScalarRound(fBottom));
419     }
420 
421     /** Set the dst integer rectangle by rounding "out" this rectangle, choosing the floor of top and left,
422         and the ceiling of right and bototm.
423     */
roundOutSkRect424     void roundOut(SkIRect* dst) const {
425         SkASSERT(dst);
426         dst->set(SkScalarFloor(fLeft), SkScalarFloor(fTop), SkScalarCeil(fRight), SkScalarCeil(fBottom));
427     }
428 
429     /** Swap top/bottom or left/right if there are flipped.
430         This can be called if the edges are computed separately,
431         and may have crossed over each other.
432         When this returns, left <= right && top <= bottom
433     */
434     void sort();
435 };
436 
437 #endif
438 
439