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