2 * Copyright 2003-2014 Haiku, Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Stephan Aßmus, superstippi@gmx.de
7 * Stefano Ceccherini, burton666@libero.it
19 #include "RegionSupport.h"
22 const static int32 kDataBlockSize
= 8;
25 // Initializes an empty region.
30 fBounds((clipping_rect
){ 0, 0, 0, 0 }),
33 _SetSize(kDataBlockSize
);
37 // Initializes a region to be a copy of another.
38 BRegion::BRegion(const BRegion
& other
)
42 fBounds((clipping_rect
){ 0, 0, 0, 0 }),
49 // Initializes a region to contain a BRect.
50 BRegion::BRegion(const BRect rect
)
54 fBounds((clipping_rect
){ 0, 0, 0, 0 }),
60 fBounds
= _ConvertToInternal(rect
);
65 // Initializes a region to contain a clipping_rect.
66 // NOTE: private constructor
67 BRegion::BRegion(const clipping_rect
& clipping
)
79 if (fData
!= &fBounds
)
84 // Modifies the region to be a copy of the given BRegion.
86 BRegion::operator=(const BRegion
& other
)
91 // handle reallocation if we're too small to contain
93 if (_SetSize(other
.fDataSize
)) {
94 memcpy(fData
, other
.fData
, other
.fCount
* sizeof(clipping_rect
));
96 fBounds
= other
.fBounds
;
97 fCount
= other
.fCount
;
104 // Compares this region to another (by value).
106 BRegion::operator==(const BRegion
& other
) const
111 if (fCount
!= other
.fCount
)
114 return memcmp(fData
, other
.fData
, fCount
* sizeof(clipping_rect
)) == 0;
118 // Set the region to contain just the given BRect.
120 BRegion::Set(BRect rect
)
126 //Set the region to contain just the given clipping_rect.
128 BRegion::Set(clipping_rect clipping
)
132 if (valid_rect(clipping
) && fData
!= NULL
) {
134 // cheap convert to internal rect format
137 fData
[0] = fBounds
= clipping
;
143 // Returns the bounds of the region.
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).
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.
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)
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);
184 // Returns the clipping_rect contained in the region at the given index.
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.
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.
208 BRegion::CountRects()
214 // Returns the number of rects contained in the region.
216 BRegion::CountRects() const
222 // Check if the region has any area in common with the given BRect.
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.
232 BRegion::Intersects(clipping_rect clipping
) const
234 // cheap convert to internal rect format
238 int result
= Support::XRectInRegion(this, clipping
);
240 return result
> Support::RectangleOut
;
244 // Check if the region contains the given BPoint.
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.
254 BRegion::Contains(int32 x
, int32 y
)
256 return Support::XPointInRegion(this, x
, y
);
260 // Check if the region contains the given coordinates.
262 BRegion::Contains(int32 x
, int32 y
) const
264 return Support::XPointInRegion(this, x
, y
);
268 // Prints the BRegion to stdout.
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);
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.
293 BRegion::OffsetBy(int32 x
, int32 y
)
295 if (x
== 0 && y
== 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
);
310 BRegion::ScaleBy(BSize scale
)
312 ScaleBy(scale
.Width(), scale
.Height());
317 BRegion::ScaleBy(float x
, float y
)
319 if (x
== 1.0 && y
== 1.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
338 fBounds
= (clipping_rect
){ 0, 0, 0, 0 };
343 // Modifies the region, so that it includes the given BRect.
345 BRegion::Include(BRect rect
)
347 Include(_Convert(rect
));
351 // Modifies the region, so that it includes the given clipping_rect.
353 BRegion::Include(clipping_rect clipping
)
355 if (!valid_rect(clipping
))
358 // convert to internal clipping format
362 // use private clipping_rect constructor which avoids malloc()
363 BRegion
temp(clipping
);
366 Support::XUnionRegion(this, &temp
, &result
);
368 _AdoptRegionData(result
);
372 // Modifies the region, so that it includes the area of the given region.
374 BRegion::Include(const BRegion
* region
)
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.
387 BRegion::Exclude(BRect rect
)
389 Exclude(_Convert(rect
));
393 // Modifies the region, excluding the area represented by the given clipping_rect.
395 BRegion::Exclude(clipping_rect clipping
)
397 if (!valid_rect(clipping
))
400 // convert to internal clipping format
404 // use private clipping_rect constructor which avoids malloc()
405 BRegion
temp(clipping
);
408 Support::XSubtractRegion(this, &temp
, &result
);
410 _AdoptRegionData(result
);
414 // Modifies the region, excluding the area contained in the given BRegion.
416 BRegion::Exclude(const BRegion
* region
)
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.
428 BRegion::IntersectWith(const BRegion
* region
)
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.
440 BRegion::ExclusiveInclude(const BRegion
* region
)
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.
459 BRegion::_AdoptRegionData(BRegion
& region
)
461 fCount
= region
.fCount
;
462 fDataSize
= region
.fDataSize
;
463 fBounds
= region
.fBounds
;
464 if (fData
!= &fBounds
)
466 if (region
.fData
!= ®ion
.fBounds
)
467 fData
= region
.fData
;
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.
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
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
)
495 // align newSize to multiple of kDataBlockSize
496 newSize
= ((newSize
+ kDataBlockSize
- 1) / kDataBlockSize
) * kDataBlockSize
;
499 if (fData
== &fBounds
) {
500 fData
= (clipping_rect
*)malloc(newSize
* sizeof(clipping_rect
));
503 clipping_rect
* resizedData
= (clipping_rect
*)realloc(fData
,
504 newSize
* sizeof(clipping_rect
));
506 // failed to resize, but we cannot keep the
507 // previous state of the object
513 fData
= (clipping_rect
*)malloc(newSize
* sizeof(clipping_rect
));
515 // just an empty region, but no error
521 // allocation actually failed
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
) };
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 };
549 BRegion::_ConvertToInternal(const clipping_rect
& rect
) const
551 return (clipping_rect
){ rect
.left
, rect
.top
,
552 rect
.right
+ 1, rect
.bottom
+ 1 };