tcp: Fix 64 bit build with debugging features enabled.
[haiku.git] / src / kits / interface / Region.cpp
blobe5b77d40250551bae41b26859569fdf5f19db2c3
1 /*
2 * Copyright 2003-2014 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Stephan Aßmus, superstippi@gmx.de
7 * Stefano Ceccherini, burton666@libero.it
8 */
11 #include <Region.h>
13 #include <stdlib.h>
14 #include <string.h>
16 #include <Debug.h>
18 #include "clipping.h"
19 #include "RegionSupport.h"
22 const static int32 kDataBlockSize = 8;
25 // Initializes an empty region.
26 BRegion::BRegion()
28 fCount(0),
29 fDataSize(0),
30 fBounds((clipping_rect){ 0, 0, 0, 0 }),
31 fData(NULL)
33 _SetSize(kDataBlockSize);
37 // Initializes a region to be a copy of another.
38 BRegion::BRegion(const BRegion& other)
40 fCount(0),
41 fDataSize(0),
42 fBounds((clipping_rect){ 0, 0, 0, 0 }),
43 fData(NULL)
45 *this = other;
49 // Initializes a region to contain a BRect.
50 BRegion::BRegion(const BRect rect)
52 fCount(0),
53 fDataSize(1),
54 fBounds((clipping_rect){ 0, 0, 0, 0 }),
55 fData(&fBounds)
57 if (!rect.IsValid())
58 return;
60 fBounds = _ConvertToInternal(rect);
61 fCount = 1;
65 // Initializes a region to contain a clipping_rect.
66 // NOTE: private constructor
67 BRegion::BRegion(const clipping_rect& clipping)
69 fCount(1),
70 fDataSize(1),
71 fBounds(clipping),
72 fData(&fBounds)
77 BRegion::~BRegion()
79 if (fData != &fBounds)
80 free(fData);
84 // Modifies the region to be a copy of the given BRegion.
85 BRegion&
86 BRegion::operator=(const BRegion& other)
88 if (&other == this)
89 return *this;
91 // handle reallocation if we're too small to contain
92 // the other other
93 if (_SetSize(other.fDataSize)) {
94 memcpy(fData, other.fData, other.fCount * sizeof(clipping_rect));
96 fBounds = other.fBounds;
97 fCount = other.fCount;
100 return *this;
104 // Compares this region to another (by value).
105 bool
106 BRegion::operator==(const BRegion& other) const
108 if (&other == this)
109 return true;
111 if (fCount != other.fCount)
112 return false;
114 return memcmp(fData, other.fData, fCount * sizeof(clipping_rect)) == 0;
118 // Set the region to contain just the given BRect.
119 void
120 BRegion::Set(BRect rect)
122 Set(_Convert(rect));
126 //Set the region to contain just the given clipping_rect.
127 void
128 BRegion::Set(clipping_rect clipping)
130 _SetSize(1);
132 if (valid_rect(clipping) && fData != NULL) {
133 fCount = 1;
134 // cheap convert to internal rect format
135 clipping.right++;
136 clipping.bottom++;
137 fData[0] = fBounds = clipping;
138 } else
139 MakeEmpty();
143 // Returns the bounds of the region.
144 BRect
145 BRegion::Frame() const
147 return BRect(fBounds.left, fBounds.top,
148 fBounds.right - 1, fBounds.bottom - 1);
152 // Returns the bounds of the region as a clipping_rect
153 // (which has integer coordinates).
154 clipping_rect
155 BRegion::FrameInt() const
157 return (clipping_rect){ fBounds.left, fBounds.top,
158 fBounds.right - 1, fBounds.bottom - 1 };
162 // Returns the rect contained in the region at the given index.
163 BRect
164 BRegion::RectAt(int32 index)
166 return const_cast<const BRegion*>(this)->RectAt(index);
170 // Returns the rect contained in the region at the given index. (const)
171 BRect
172 BRegion::RectAt(int32 index) const
174 if (index >= 0 && index < fCount) {
175 const clipping_rect& r = fData[index];
176 return BRect(r.left, r.top, r.right - 1, r.bottom - 1);
179 return BRect();
180 // an invalid BRect
184 // Returns the clipping_rect contained in the region at the given index.
185 clipping_rect
186 BRegion::RectAtInt(int32 index)
188 return const_cast<const BRegion*>(this)->RectAtInt(index);
192 // Returns the clipping_rect contained in the region at the given index.
193 clipping_rect
194 BRegion::RectAtInt(int32 index) const
196 if (index >= 0 && index < fCount) {
197 const clipping_rect& r = fData[index];
198 return (clipping_rect){ r.left, r.top, r.right - 1, r.bottom - 1 };
201 return (clipping_rect){ 1, 1, 0, 0 };
202 // an invalid clipping_rect
206 // Returns the number of rects contained in the region.
207 int32
208 BRegion::CountRects()
210 return fCount;
214 // Returns the number of rects contained in the region.
215 int32
216 BRegion::CountRects() const
218 return fCount;
222 // Check if the region has any area in common with the given BRect.
223 bool
224 BRegion::Intersects(BRect rect) const
226 return Intersects(_Convert(rect));
230 // Check if the region has any area in common with the given clipping_rect.
231 bool
232 BRegion::Intersects(clipping_rect clipping) const
234 // cheap convert to internal rect format
235 clipping.right++;
236 clipping.bottom++;
238 int result = Support::XRectInRegion(this, clipping);
240 return result > Support::RectangleOut;
244 // Check if the region contains the given BPoint.
245 bool
246 BRegion::Contains(BPoint point) const
248 return Support::XPointInRegion(this, (int)point.x, (int)point.y);
252 // Check if the region contains the given coordinates.
253 bool
254 BRegion::Contains(int32 x, int32 y)
256 return Support::XPointInRegion(this, x, y);
260 // Check if the region contains the given coordinates.
261 bool
262 BRegion::Contains(int32 x, int32 y) const
264 return Support::XPointInRegion(this, x, y);
268 // Prints the BRegion to stdout.
269 void
270 BRegion::PrintToStream() const
272 Frame().PrintToStream();
274 for (int32 i = 0; i < fCount; i++) {
275 clipping_rect *rect = &fData[i];
276 printf("data[%" B_PRId32 "] = BRect(l:%" B_PRId32 ".0, t:%" B_PRId32
277 ".0, r:%" B_PRId32 ".0, b:%" B_PRId32 ".0)\n",
278 i, rect->left, rect->top, rect->right - 1, rect->bottom - 1);
283 void
284 BRegion::OffsetBy(const BPoint& point)
286 OffsetBy(point.x, point.y);
290 // Applies the given x and y offsets to each rect contained by
291 // the region and recalculates the region's bounds.
292 void
293 BRegion::OffsetBy(int32 x, int32 y)
295 if (x == 0 && y == 0)
296 return;
298 if (fCount > 0) {
299 if (fData != &fBounds) {
300 for (int32 i = 0; i < fCount; i++)
301 offset_rect(fData[i], x, y);
304 offset_rect(fBounds, x, y);
309 void
310 BRegion::ScaleBy(BSize scale)
312 ScaleBy(scale.Width(), scale.Height());
316 void
317 BRegion::ScaleBy(float x, float y)
319 if (x == 1.0 && y == 1.0)
320 return;
322 if (fCount > 0) {
323 if (fData != &fBounds) {
324 for (int32 i = 0; i < fCount; i++)
325 scale_rect(fData[i], x, y);
328 scale_rect(fBounds, x, y);
333 // Empties the region, so that it doesn't include any rect, and invalidates
334 // its bounds.
335 void
336 BRegion::MakeEmpty()
338 fBounds = (clipping_rect){ 0, 0, 0, 0 };
339 fCount = 0;
343 // Modifies the region, so that it includes the given BRect.
344 void
345 BRegion::Include(BRect rect)
347 Include(_Convert(rect));
351 // Modifies the region, so that it includes the given clipping_rect.
352 void
353 BRegion::Include(clipping_rect clipping)
355 if (!valid_rect(clipping))
356 return;
358 // convert to internal clipping format
359 clipping.right++;
360 clipping.bottom++;
362 // use private clipping_rect constructor which avoids malloc()
363 BRegion temp(clipping);
365 BRegion result;
366 Support::XUnionRegion(this, &temp, &result);
368 _AdoptRegionData(result);
372 // Modifies the region, so that it includes the area of the given region.
373 void
374 BRegion::Include(const BRegion* region)
376 BRegion result;
377 Support::XUnionRegion(this, region, &result);
379 _AdoptRegionData(result);
383 /*! \brief Modifies the region, excluding the area represented by the given BRect.
384 \param rect The BRect to be excluded.
386 void
387 BRegion::Exclude(BRect rect)
389 Exclude(_Convert(rect));
393 // Modifies the region, excluding the area represented by the given clipping_rect.
394 void
395 BRegion::Exclude(clipping_rect clipping)
397 if (!valid_rect(clipping))
398 return;
400 // convert to internal clipping format
401 clipping.right++;
402 clipping.bottom++;
404 // use private clipping_rect constructor which avoids malloc()
405 BRegion temp(clipping);
407 BRegion result;
408 Support::XSubtractRegion(this, &temp, &result);
410 _AdoptRegionData(result);
414 // Modifies the region, excluding the area contained in the given BRegion.
415 void
416 BRegion::Exclude(const BRegion* region)
418 BRegion result;
419 Support::XSubtractRegion(this, region, &result);
421 _AdoptRegionData(result);
425 // Modifies the region, so that it will contain only the area in common
426 // with the given BRegion.
427 void
428 BRegion::IntersectWith(const BRegion* region)
430 BRegion result;
431 Support::XIntersectRegion(this, region, &result);
433 _AdoptRegionData(result);
437 // Modifies the region, so that it will contain just the area which both
438 // regions do not have in common.
439 void
440 BRegion::ExclusiveInclude(const BRegion* region)
442 BRegion result;
443 Support::XXorRegion(this, region, &result);
445 _AdoptRegionData(result);
449 // #pragma mark - BRegion private methods
453 \fn void BRegion::_AdoptRegionData(BRegion& region)
454 \brief Takes over the data of \a region and empties it.
456 \param region The \a region to adopt data from.
458 void
459 BRegion::_AdoptRegionData(BRegion& region)
461 fCount = region.fCount;
462 fDataSize = region.fDataSize;
463 fBounds = region.fBounds;
464 if (fData != &fBounds)
465 free(fData);
466 if (region.fData != &region.fBounds)
467 fData = region.fData;
468 else
469 fData = &fBounds;
471 // NOTE: MakeEmpty() is not called since _AdoptRegionData is only
472 // called with internally allocated regions, so they don't need to
473 // be left in a valid state.
474 region.fData = NULL;
475 // region.MakeEmpty();
480 \fn bool BRegion::_SetSize(int32 newSize)
481 \brief Reallocate the memory in the region.
483 \param newSize The amount of rectangles that the region should be
484 able to hold.
486 bool
487 BRegion::_SetSize(int32 newSize)
489 // we never shrink the size
490 newSize = max_c(fDataSize, newSize);
491 // The amount of rectangles that the region should be able to hold.
492 if (newSize == fDataSize)
493 return true;
495 // align newSize to multiple of kDataBlockSize
496 newSize = ((newSize + kDataBlockSize - 1) / kDataBlockSize) * kDataBlockSize;
498 if (newSize > 0) {
499 if (fData == &fBounds) {
500 fData = (clipping_rect*)malloc(newSize * sizeof(clipping_rect));
501 fData[0] = fBounds;
502 } else if (fData) {
503 clipping_rect* resizedData = (clipping_rect*)realloc(fData,
504 newSize * sizeof(clipping_rect));
505 if (!resizedData) {
506 // failed to resize, but we cannot keep the
507 // previous state of the object
508 free(fData);
509 fData = NULL;
510 } else
511 fData = resizedData;
512 } else
513 fData = (clipping_rect*)malloc(newSize * sizeof(clipping_rect));
514 } else {
515 // just an empty region, but no error
516 MakeEmpty();
517 return true;
520 if (!fData) {
521 // allocation actually failed
522 fDataSize = 0;
523 MakeEmpty();
524 return false;
527 fDataSize = newSize;
528 return true;
532 clipping_rect
533 BRegion::_Convert(const BRect& rect) const
535 return (clipping_rect){ (int)floorf(rect.left), (int)floorf(rect.top),
536 (int)ceilf(rect.right), (int)ceilf(rect.bottom) };
540 clipping_rect
541 BRegion::_ConvertToInternal(const BRect& rect) const
543 return (clipping_rect){ (int)floorf(rect.left), (int)floorf(rect.top),
544 (int)ceilf(rect.right) + 1, (int)ceilf(rect.bottom) + 1 };
548 clipping_rect
549 BRegion::_ConvertToInternal(const clipping_rect& rect) const
551 return (clipping_rect){ rect.left, rect.top,
552 rect.right + 1, rect.bottom + 1 };