* complete reimplementation of BRegion and it's backend

I "ported" the region implementation from XOrg to work on BRegion data.

This resulted in pretty much the same code structure as before, with 
RegionSupport.cpp containing the messy details. Only now it _is_ really messy
from a code beauty point of view. I didn't exactly feel like cleaning it
up right now... but I guess I will have to.

So what does this mean - our BRegion implementation was very slow (no offense!),
and on top of that it scaled very badly with more and more rects. The new
implementation seems to be on par with the very fast R5 implementation and
the data looks exactly the same too. BRegion is very performance critical
for the app_server, and I cannot wait to try this on my slow computer...

Some changes are noteworthy: The right and bottom coordinates of
BRegion internal data are now exclusive! I inherited that from the
XOrg implementation and didn't feel like changing the code, seeing it
is probably tested quite well. The conversion is handled transparently.

Secondly, constructing a BRegion with just one rect is not invoking
malloc anymore for the member data, this makes it much more efficient
to use temporary BRegions with just one rect, both externally and internally
in the BRegion implementation.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@21665 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2007-07-19 17:06:28 +00:00
parent 89369ed1ab
commit 582da17386
9 changed files with 1974 additions and 1250 deletions
+59 -52
View File
@@ -1,13 +1,7 @@
/******************************************************************************* /*
/ * Copyright 2007, Haiku. All rights reserved.
/ File: Region.h * Distributed under the terms of the MIT License.
/ */
/ Description: BRegion represents an area that's composed of individual
/ rectangles.
/
/ Copyright 1992-98, Be Incorporated, All Rights Reserved
/
*******************************************************************************/
#ifndef _REGION_H #ifndef _REGION_H
#define _REGION_H #define _REGION_H
@@ -30,57 +24,70 @@ typedef struct {
} clipping_rect; } clipping_rect;
/*----- BRegion class --------------------------------------------*/
class BRegion { class BRegion {
public: public:
BRegion(); BRegion();
BRegion(const BRegion &region); BRegion(const BRegion& region);
BRegion(const BRect rect); BRegion(const BRect rect);
virtual ~BRegion(); virtual ~BRegion();
BRegion &operator=(const BRegion &from); BRegion &operator=(const BRegion &from);
BRect Frame() const; void Set(BRect newBounds);
clipping_rect FrameInt() const; void Set(clipping_rect newBounds);
BRect RectAt(int32 index);
clipping_rect RectAtInt(int32 index);
int32 CountRects();
void Set(BRect newBounds);
void Set(clipping_rect newBounds);
bool Intersects(BRect r) const;
bool Intersects(clipping_rect r) const;
bool Contains(BPoint pt) const;
bool Contains(int32 x, int32 y);
void PrintToStream() const;
void OffsetBy(int32 dh, int32 dv);
void MakeEmpty();
void Include(BRect r);
void Include(clipping_rect r);
void Include(const BRegion*);
void Exclude(BRect r);
void Exclude(clipping_rect r);
void Exclude(const BRegion*);
void IntersectWith(const BRegion*);
/*----- Private or reserved -----------------------------------------*/ BRect Frame() const;
class Support; clipping_rect FrameInt() const;
private: BRect RectAt(int32 index) /*const*/;
friend class BView; clipping_rect RectAtInt(int32 index) /*const*/;
int32 CountRects() /*const*/;
bool Intersects(BRect rect) const;
bool Intersects(clipping_rect rect) const;
bool Contains(BPoint point) const;
bool Contains(int32 x, int32 y) /*const*/;
void PrintToStream() const;
void OffsetBy(int32 x, int32 y);
void MakeEmpty();
void Include(BRect rect);
void Include(clipping_rect rect);
void Include(const BRegion*);
void Exclude(BRect r);
void Exclude(clipping_rect r);
void Exclude(const BRegion* region);
void IntersectWith(const BRegion* region);
private:
friend class BDirectWindow; friend class BDirectWindow;
friend class Support;
friend class BPrivate::ServerLink; friend class BPrivate::ServerLink;
friend class BPrivate::LinkReceiver; friend class BPrivate::LinkReceiver;
void _AddRect(clipping_rect r); class Support;
void set_size(long new_size); friend class Support;
private: private:
long count; BRegion(const clipping_rect& rect);
long data_size;
clipping_rect bound; void _AdoptRegionData(BRegion& region);
clipping_rect *data; bool _SetSize(long newSize);
clipping_rect _Convert(const BRect& rect) const;
clipping_rect _ConvertToInternal(const BRect& rect) const;
private:
long fCount;
long fDataSize;
clipping_rect fBounds;
clipping_rect* fData;
}; };
#endif /* _REGION_H */ #endif // _REGION_H
+8 -4
View File
@@ -402,12 +402,16 @@ err:
status_t status_t
LinkReceiver::ReadRegion(BRegion* region) LinkReceiver::ReadRegion(BRegion* region)
{ {
status_t status = Read(&region->count, sizeof(int32)); status_t status = Read(&region->fCount, sizeof(int32));
if (status >= B_OK) if (status >= B_OK)
status = Read(&region->bound, sizeof(clipping_rect)); status = Read(&region->fBounds, sizeof(clipping_rect));
if (status >= B_OK) { if (status >= B_OK) {
region->set_size(region->count); if (!region->_SetSize(region->fCount))
status = Read(region->data, region->count * sizeof(clipping_rect)); status = B_NO_MEMORY;
else {
status = Read(region->fData,
region->fCount * sizeof(clipping_rect));
}
if (status < B_OK) if (status < B_OK)
region->MakeEmpty(); region->MakeEmpty();
} }
+10 -7
View File
@@ -34,19 +34,22 @@ ServerLink::~ServerLink()
status_t status_t
ServerLink::ReadRegion(BRegion *region) ServerLink::ReadRegion(BRegion *region)
{ {
fReceiver->Read(&region->count, sizeof(long)); fReceiver->Read(&region->fCount, sizeof(long));
fReceiver->Read(&region->bound, sizeof(clipping_rect)); fReceiver->Read(&region->fBounds, sizeof(clipping_rect));
region->set_size(region->count + 1); if (!region->_SetSize(region->fCount))
return fReceiver->Read(region->data, region->count * sizeof(clipping_rect)); return B_NO_MEMORY;
return fReceiver->Read(region->fData,
region->fCount * sizeof(clipping_rect));
} }
status_t status_t
ServerLink::AttachRegion(const BRegion &region) ServerLink::AttachRegion(const BRegion &region)
{ {
fSender->Attach(&region.count, sizeof(long)); fSender->Attach(&region.fCount, sizeof(long));
fSender->Attach(&region.bound, sizeof(clipping_rect)); fSender->Attach(&region.fBounds, sizeof(clipping_rect));
return fSender->Attach(region.data, region.count * sizeof(clipping_rect)); return fSender->Attach(region.fData,
region.fCount * sizeof(clipping_rect));
} }
+7 -4
View File
@@ -303,11 +303,14 @@ BDirectWindow::GetClippingRegion(BRegion *region, BPoint *origin) const
// Otherwise, we would need to call BRegion::Include(clipping_rect) // Otherwise, we would need to call BRegion::Include(clipping_rect)
// for every clipping_rect in our clip_list, and that would be much // for every clipping_rect in our clip_list, and that would be much
// more overkill than this (tested ). // more overkill than this (tested ).
region->set_size(fBufferDesc->clip_list_count); if (!region->_SetSize(fBufferDesc->clip_list_count)) {
region->count = fBufferDesc->clip_list_count; UnlockDirect();
region->bound = fBufferDesc->clip_bounds; return B_NO_MEMORY;
}
region->fCount = fBufferDesc->clip_list_count;
region->fBounds = fBufferDesc->clip_bounds;
for (uint32 c = 0; c < fBufferDesc->clip_list_count; c++) for (uint32 c = 0; c < fBufferDesc->clip_list_count; c++)
region->data[c] = fBufferDesc->clip_list[c]; region->fData[c] = fBufferDesc->clip_list[c];
// adjust bounds by the given origin point // adjust bounds by the given origin point
region->OffsetBy(-originX, -originY); region->OffsetBy(-originX, -originY);
+295 -311
View File
@@ -1,90 +1,50 @@
//------------------------------------------------------------------------------ /*
// Copyright (c) 2003-2005, Haiku, Inc. * Copyright 2003-2007, Haiku. All rights reserved.
// * Distributed under the terms of the MIT License.
// Permission is hereby granted, free of charge, to any person obtaining a *
// copy of this software and associated documentation files (the "Software"), * Authors:
// to deal in the Software without restriction, including without limitation * Stefano Ceccherini ([email protected])
// the rights to use, copy, modify, merge, publish, distribute, sublicense, * Stephan Aßmus <[email protected]>
// and/or sell copies of the Software, and to permit persons to whom the */
// Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// File Name: Region.cpp
// Author: Stefano Ceccherini ([email protected])
// Description: Region class consisting of multiple rectangles
//
//------------------------------------------------------------------------------
// Notes: As now, memory is always allocated and never freed (except on destruction,
// or sometimes when a copy is made).
// This let us be a bit faster since we don't do many reallocations.
// But that means that even an empty region could "waste" much space, if it contained
// many rects before being emptied.
// I.E: a region which contains 24 rects allocates more than 24 * 4 * sizeof(int32)
// = 96 * sizeof(int32) bytes. If we call MakeEmpty(), that region will contain no rects,
// but it will still keep the allocated memory.
// This shouldnt' be an issue, since usually BRegions are just used for calculations,
// and don't last so long.
// Anyway, we can change that behaviour if we want, but BeOS's BRegion seems to behave exactly
// like this.
#include <cstdlib>
#include <cstring>
#include <Debug.h>
#include <Region.h> #include <Region.h>
#include <clipping.h> #include <malloc.h>
#include <RegionSupport.h> #include <string.h>
#include <Debug.h>
#include "clipping.h"
#include "RegionSupport.h"
const static int32 kInitialDataSize = 8; const static int32 kDataBlockSize = 8;
/*! \brief Initializes a region. The region will have no rects, /*! \brief Initializes a region. The region will have no rects,
and its bound will be invalid. and its fBounds will be invalid.
*/ */
BRegion::BRegion() BRegion::BRegion()
: : fCount(0)
data_size(0), , fDataSize(0)
data(NULL) , fBounds((clipping_rect){ 0, 0, 0, 0 })
, fData(NULL)
{ {
data = (clipping_rect *)malloc(kInitialDataSize * sizeof(clipping_rect)); _SetSize(kDataBlockSize);
if (data != NULL)
data_size = kInitialDataSize;
Support::ZeroRegion(*this);
} }
/*! \brief Initializes a region to be a copy of another. /*! \brief Initializes a region to be a copy of another.
\param region The region to copy. \param region The region to copy.
*/ */
BRegion::BRegion(const BRegion &region) BRegion::BRegion(const BRegion& region)
: : fCount(0)
data_size(0), , fDataSize(0)
data(NULL) , fBounds((clipping_rect){ 0, 0, 0, 0 })
, fData(NULL)
{ {
const int32 size = region.data_size > 0 ? region.data_size : 1; *this = region;
data = (clipping_rect *)malloc(size * sizeof(clipping_rect));
if (data != NULL) {
data_size = size;
bound = region.bound;
count = region.count;
memcpy(data, region.data, count * sizeof(clipping_rect));
} else
Support::ZeroRegion(*this);
} }
@@ -92,16 +52,28 @@ BRegion::BRegion(const BRegion &region)
\param rect The BRect to set the region to. \param rect The BRect to set the region to.
*/ */
BRegion::BRegion(const BRect rect) BRegion::BRegion(const BRect rect)
: : fCount(0)
data_size(0), , fDataSize(1)
data(NULL) , fBounds((clipping_rect){ 0, 0, 0, 0 })
, fData(&fBounds)
{
if (!rect.IsValid())
return;
fBounds = _ConvertToInternal(rect);
fCount = 1;
}
// NOTE: private constructor
/*! \brief Initializes a region to contain a clipping_rect.
\param rect The BRect to set the region to.
*/
BRegion::BRegion(const clipping_rect& rect)
: fCount(1)
, fDataSize(1)
, fBounds(rect)
, fData(&fBounds)
{ {
data = (clipping_rect *)malloc(kInitialDataSize * sizeof(clipping_rect));
if (data != NULL) {
data_size = kInitialDataSize;
Set(rect);
} else
Support::ZeroRegion(*this);
} }
@@ -109,68 +81,34 @@ BRegion::BRegion(const BRect rect)
*/ */
BRegion::~BRegion() BRegion::~BRegion()
{ {
free(data); if (fData != &fBounds)
free(fData);
} }
/*! \brief Returns the bounds of the region. // #pragma mark -
\return A BRect which represents the bounds of the region.
/*! \brief Modifies the region to be a copy of the given BRegion.
\param region the BRegion to copy.
\return This function always returns \c *this.
*/ */
BRect BRegion &
BRegion::Frame() const BRegion::operator=(const BRegion &region)
{ {
return to_BRect(bound); if (&region == this)
} return *this;
// handle reallocation if we're too small to contain
// the other region
if (_SetSize(region.fDataSize)) {
memcpy(fData, region.fData, region.fCount * sizeof(clipping_rect));
/*! \brief Returns the bounds of the region as a clipping_rect (which has integer coordinates). fBounds = region.fBounds;
\return A clipping_rect which represents the bounds of the region. fCount = region.fCount;
*/ }
clipping_rect
BRegion::FrameInt() const
{
return bound;
}
/*! \brief Returns the regions's BRect at the given index.
\param index The index (zero based) of the wanted rectangle.
\return If the given index is valid, it returns the BRect at that index,
otherwise, it returns an invalid BRect.
*/
BRect
BRegion::RectAt(int32 index)
{
if (index >= 0 && index < count)
return to_BRect(data[index]);
return BRect(); //An invalid BRect return *this;
}
/*! \brief Returns the regions's clipping_rect at the given index.
\param index The index (zero based) of the wanted rectangle.
\return If the given index is valid, it returns the clipping_rect at that index,
otherwise, it returns an invalid clipping_rect.
*/
clipping_rect
BRegion::RectAtInt(int32 index)
{
if (index >= 0 && index < count)
return data[index];
clipping_rect rect = { 1, 1, 0, 0 };
return rect;
}
/*! \brief Counts the region rects.
\return An int32 which is the total number of rects in the region.
*/
int32
BRegion::CountRects()
{
return count;
} }
@@ -180,7 +118,7 @@ BRegion::CountRects()
void void
BRegion::Set(BRect newBounds) BRegion::Set(BRect newBounds)
{ {
Set(to_clipping_rect(newBounds)); Set(_Convert(newBounds));
} }
@@ -190,17 +128,93 @@ BRegion::Set(BRect newBounds)
void void
BRegion::Set(clipping_rect newBounds) BRegion::Set(clipping_rect newBounds)
{ {
ASSERT(data_size > 0); _SetSize(1);
if (valid_rect(newBounds)) { if (valid_rect(newBounds) && fData) {
count = 1; fCount = 1;
data[0] = newBounds; // cheap convert to internal rect format
bound = newBounds; newBounds.right++;
newBounds.bottom++;
fData[0] = fBounds = newBounds;
} else } else
Support::ZeroRegion(*this); MakeEmpty();
} }
// #pragma mark -
/*! \brief Returns the bounds of the region.
\return A BRect which represents the bounds of the region.
*/
BRect
BRegion::Frame() const
{
return BRect(fBounds.left, fBounds.top,
fBounds.right - 1, fBounds.bottom - 1);
}
/*! \brief Returns the bounds of the region as a clipping_rect (which has integer coordinates).
\return A clipping_rect which represents the bounds of the region.
*/
clipping_rect
BRegion::FrameInt() const
{
return (clipping_rect){ fBounds.left, fBounds.top,
fBounds.right - 1, fBounds.bottom - 1 };
}
/*! \brief Returns the regions's BRect at the given index.
\param index The index (zero based) of the wanted rectangle.
\return If the given index is valid, it returns the BRect at that index,
otherwise, it returns an invalid BRect.
*/
BRect
BRegion::RectAt(int32 index) /*const*/
{
if (index >= 0 && index < fCount) {
const clipping_rect& r = fData[index];
return BRect(r.left, r.top, r.right - 1, r.bottom - 1);
}
return BRect();
// an invalid BRect
}
/*! \brief Returns the regions's clipping_rect at the given index.
\param index The index (zero based) of the wanted rectangle.
\return If the given index is valid, it returns the clipping_rect at that index,
otherwise, it returns an invalid clipping_rect.
*/
clipping_rect
BRegion::RectAtInt(int32 index) /*const*/
{
if (index >= 0 && index < fCount) {
const clipping_rect& r = fData[index];
return (clipping_rect){ r.left, r.top, r.right - 1, r.bottom - 1 };
}
return (clipping_rect){ 1, 1, 0, 0 };
// an invalid clipping_rect
}
/*! \brief Counts the region rects.
\return An int32 which is the total number of rects in the region.
*/
int32
BRegion::CountRects() /*const*/
{
return fCount;
}
// #pragma mark -
/*! \brief Check if the region has any area in common with the given BRect. /*! \brief Check if the region has any area in common with the given BRect.
\param rect The BRect to check the region against to. \param rect The BRect to check the region against to.
\return \ctrue if the region has any area in common with the BRect, \cfalse if not. \return \ctrue if the region has any area in common with the BRect, \cfalse if not.
@@ -208,7 +222,7 @@ BRegion::Set(clipping_rect newBounds)
bool bool
BRegion::Intersects(BRect rect) const BRegion::Intersects(BRect rect) const
{ {
return Intersects(to_clipping_rect(rect)); return Intersects(_Convert(rect));
} }
@@ -219,15 +233,13 @@ BRegion::Intersects(BRect rect) const
bool bool
BRegion::Intersects(clipping_rect rect) const BRegion::Intersects(clipping_rect rect) const
{ {
if (!rects_intersect(rect, bound)) // cheap convert to internal rect format
return false; rect.right ++;
rect.bottom ++;
for (long c = 0; c < count; c++) { int result = Support::XRectInRegion(this, rect);
if (rects_intersect(data[c], rect))
return true; return result > Support::RectangleOut;
}
return false;
} }
@@ -236,18 +248,9 @@ BRegion::Intersects(clipping_rect rect) const
\return \ctrue if the region contains the BPoint, \cfalse if not. \return \ctrue if the region contains the BPoint, \cfalse if not.
*/ */
bool bool
BRegion::Contains(BPoint pt) const BRegion::Contains(BPoint point) const
{ {
// If the point doesn't lie within the region's bounds, return Support::XPointInRegion(this, (int)point.x, (int)point.y);
// don't even try it against the region's rects.
if (!point_in(bound, pt))
return false;
for (long c = 0; c < count; c++) {
if (point_in(data[c], pt))
return true;
}
return false;
} }
@@ -257,17 +260,9 @@ BRegion::Contains(BPoint pt) const
\return \ctrue if the region contains the point, \cfalse if not. \return \ctrue if the region contains the point, \cfalse if not.
*/ */
bool bool
BRegion::Contains(int32 x, int32 y) BRegion::Contains(int32 x, int32 y) /*const*/
{ {
// see above return Support::XPointInRegion(this, x, y);
if (!point_in(bound, x, y))
return false;
for (long c = 0; c < count; c++) {
if (point_in(data[c], x, y))
return true;
}
return false;
} }
@@ -277,30 +272,35 @@ void
BRegion::PrintToStream() const BRegion::PrintToStream() const
{ {
Frame().PrintToStream(); Frame().PrintToStream();
for (long c = 0; c < count; c++) { for (long i = 0; i < fCount; i++) {
clipping_rect *rect = &data[c]; clipping_rect *rect = &fData[i];
printf("data = BRect(l:%ld.0, t:%ld.0, r:%ld.0, b:%ld.0)\n", printf("data[%ld] = BRect(l:%ld.0, t:%ld.0, r:%ld.0, b:%ld.0)\n",
rect->left, rect->top, rect->right, rect->bottom); i, rect->left, rect->top, rect->right - 1, rect->bottom - 1);
} }
} }
// #pragma mark -
/*! \brief Offsets all region's rects, and bounds by the given values. /*! \brief Offsets all region's rects, and bounds by the given values.
\param dh The horizontal offset. \param dh The horizontal offset.
\param dv The vertical offset. \param dv The vertical offset.
*/ */
void void
BRegion::OffsetBy(int32 dh, int32 dv) BRegion::OffsetBy(int32 x, int32 y)
{ {
if (dh == 0 && dv == 0) if (x == 0 && y == 0)
return; return;
if (count > 0) { if (fCount > 0) {
for (long c = 0; c < count; c++) if (fData != &fBounds) {
offset_rect(data[c], dh, dv); for (long i = 0; i < fCount; i++)
offset_rect(fData[i], x, y);
}
offset_rect(bound, dh, dv); offset_rect(fBounds, x, y);
} }
} }
@@ -310,17 +310,21 @@ BRegion::OffsetBy(int32 dh, int32 dv)
void void
BRegion::MakeEmpty() BRegion::MakeEmpty()
{ {
Support::ZeroRegion(*this); fBounds= (clipping_rect){ 0, 0, 0, 0 };
fCount = 0;
} }
// #pragma mark -
/*! \brief Modifies the region, so that it includes the given BRect. /*! \brief Modifies the region, so that it includes the given BRect.
\param rect The BRect to be included by the region. \param rect The BRect to be included by the region.
*/ */
void void
BRegion::Include(BRect rect) BRegion::Include(BRect rect)
{ {
Include(to_clipping_rect(rect)); Include(_Convert(rect));
} }
@@ -330,13 +334,17 @@ BRegion::Include(BRect rect)
void void
BRegion::Include(clipping_rect rect) BRegion::Include(clipping_rect rect)
{ {
BRegion region; // convert to internal rect format
BRegion newRegion; rect.right ++;
rect.bottom ++;
region.Set(rect); // use private clipping_rect constructor which avoids malloc()
BRegion t(rect);
Support::OrRegion(*this, region, newRegion);
Support::CopyRegion(newRegion, *this); BRegion result;
Support::XUnionRegion(this, &t, &result);
_AdoptRegionData(result);
} }
@@ -344,22 +352,25 @@ BRegion::Include(clipping_rect rect)
\param region The region to be included. \param region The region to be included.
*/ */
void void
BRegion::Include(const BRegion *region) BRegion::Include(const BRegion* region)
{ {
BRegion newRegion; BRegion result;
Support::XUnionRegion(this, region, &result);
Support::OrRegion(*this, *region, newRegion);
Support::CopyRegion(newRegion, *this); _AdoptRegionData(result);
} }
// #pragma mark -
/*! \brief Modifies the region, excluding the area represented by the given BRect. /*! \brief Modifies the region, excluding the area represented by the given BRect.
\param rect The BRect to be excluded. \param rect The BRect to be excluded.
*/ */
void void
BRegion::Exclude(BRect rect) BRegion::Exclude(BRect rect)
{ {
Exclude(to_clipping_rect(rect)); Exclude(_Convert(rect));
} }
@@ -369,152 +380,125 @@ BRegion::Exclude(BRect rect)
void void
BRegion::Exclude(clipping_rect rect) BRegion::Exclude(clipping_rect rect)
{ {
BRegion region; // convert to internal rect format
BRegion newRegion; rect.right ++;
rect.bottom ++;
region.Set(rect);
Support::SubRegion(*this, region, newRegion); // use private clipping_rect constructor which avoids malloc()
Support::CopyRegion(newRegion, *this); BRegion t(rect);
BRegion result;
Support::XSubtractRegion(this, &t, &result);
_AdoptRegionData(result);
} }
/*! \brief Modifies the region, excluding the area contained in the given BRegion. /*! \brief Modifies the region, excluding the area contained in the given
BRegion.
\param region The BRegion to be excluded. \param region The BRegion to be excluded.
*/ */
void void
BRegion::Exclude(const BRegion *region) BRegion::Exclude(const BRegion* region)
{ {
BRegion newRegion; BRegion result;
Support::XSubtractRegion(this, region, &result);
Support::SubRegion(*this, *region, newRegion);
Support::CopyRegion(newRegion, *this); _AdoptRegionData(result);
} }
/*! \brief Modifies the region, so that it will contain just the area in common with the given BRegion. // #pragma mark -
/*! \brief Modifies the region, so that it will contain just the area
in common with the given BRegion.
\param region the BRegion to intersect to. \param region the BRegion to intersect to.
*/ */
void void
BRegion::IntersectWith(const BRegion *region) BRegion::IntersectWith(const BRegion* region)
{ {
BRegion newRegion; BRegion result;
Support::XIntersectRegion(this, region, &result);
Support::AndRegion(*this, *region, newRegion);
Support::CopyRegion(newRegion, *this); _AdoptRegionData(result);
} }
/*! \brief Modifies the region to be a copy of the given BRegion. // #pragma mark -
\param region the BRegion to copy.
\return This function always returns \c *this.
*/
BRegion &
BRegion::operator=(const BRegion &region)
{
if (&region != this) {
bound = region.bound;
count = region.count;
// handle reallocation if we're too small to contain
// the other region
set_size(region.data_size);
// TODO: what is this supposed to do??
if (data_size <= 0)
data_size = 1;
if (data)
memcpy(data, region.data, count * sizeof(clipping_rect));
}
return *this;
}
/*! \brief Adds a rect to the region. /*! \brief Takes over the data of a region and marks that region empty.
\param rect The clipping_rect to be added. \param region The region to adopt the data from.
Adds the given rect to the region, merging it with another already contained in the region,
if possible. Recalculate the region's bounds if needed.
*/ */
void void
BRegion::_AddRect(clipping_rect rect) BRegion::_AdoptRegionData(BRegion& region)
{ {
ASSERT(count >= 0); fCount = region.fCount;
ASSERT(data_size >= 0); fDataSize = region.fDataSize;
ASSERT(valid_rect(rect)); fBounds = region.fBounds;
if (fData != &fBounds)
free(fData);
if (region.fData != &region.fBounds)
fData = region.fData;
else
fData = &fBounds;
// Should we just reallocate the memory and // NOTE: MakeEmpty() is not called since _AdoptRegionData is only
// copy the rect ? // called with internally allocated regions, so they don't need to
bool addRect = true; // be left in a valid state.
region.fData = NULL;
if (count > 0) { // region.MakeEmpty();
// Wait! We could merge the rect with one of the
// existing rectangles, if it's adiacent.
// We just check it against the last rectangle, since
// we are keeping them sorted by their "top" coordinates.
long last = count - 1;
if (rect.left == data[last].left && rect.right == data[last].right
&& rect.top == data[last].bottom + 1) {
data[last].bottom = rect.bottom;
addRect = false;
} else if (rect.top == data[last].top && rect.bottom == data[last].bottom) {
if (rect.left == data[last].right + 1) {
data[last].right = rect.right;
addRect = false;
} else if (rect.right == data[last].left - 1) {
data[last].left = rect.left;
addRect = false;
}
}
}
// We weren't lucky.... just add the rect as a new one
if (addRect) {
if (data_size <= count)
set_size(count + 16);
data[count] = rect;
count++;
}
// Recalculate bounds
if (rect.top < bound.top)
bound.top = rect.top;
if (rect.left < bound.left)
bound.left = rect.left;
if (rect.right > bound.right)
bound.right = rect.right;
if (rect.bottom > bound.bottom)
bound.bottom = rect.bottom;
} }
/*! \brief Reallocate the memory in the region. /*! \brief Reallocate the memory in the region.
\param new_size The amount of rectangles that the region could contain. \param newSize The amount of rectangles that the region should be
able to hold.
*/ */
void bool
BRegion::set_size(long new_size) BRegion::_SetSize(long newSize)
{ {
if (new_size <= 0) // we never shrink the size
new_size = data_size + 16; newSize = max_c(fDataSize, newSize);
if (newSize == fDataSize)
return true;
// align newSize to multiple of kDataBlockSize
newSize = ((newSize + kDataBlockSize - 1) / kDataBlockSize) * kDataBlockSize;
if (newSize > 0) {
if (fData == &fBounds) {
fData = (clipping_rect*)malloc(newSize * sizeof(clipping_rect));
fData[0] = fBounds;
} else if (fData)
fData = (clipping_rect*)realloc(fData, newSize * sizeof(clipping_rect));
else
fData = (clipping_rect*)malloc(newSize * sizeof(clipping_rect));
}
data = (clipping_rect *)realloc(data, new_size * sizeof(clipping_rect)); if (!fData || newSize <= 0) {
fDataSize = 0;
if (data == NULL) MakeEmpty();
debugger("BRegion::set_size realloc error\n"); return false;
}
data_size = new_size;
fDataSize = newSize;
ASSERT(count <= data_size); return true;
} }
clipping_rect
BRegion::_Convert(const BRect& rect) const
{
return (clipping_rect){ (int)floorf(rect.left), (int)floorf(rect.top),
(int)ceilf(rect.right), (int)ceilf(rect.bottom) };
}
clipping_rect
BRegion::_ConvertToInternal(const BRect& rect) const
{
return (clipping_rect){ (int)floorf(rect.left), (int)floorf(rect.top),
(int)ceilf(rect.right) + 1, (int)ceilf(rect.bottom) + 1 };
}
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -1671,7 +1671,7 @@ ServerWindow::_DispatchViewMessage(int32 code,
// invalidate view - but only if this is a non-overlay switch // invalidate view - but only if this is a non-overlay switch
if (bitmap == NULL || bitmap->Overlay() == NULL || !wasOverlay) { if (bitmap == NULL || bitmap->Overlay() == NULL || !wasOverlay) {
BRegion dirty(fCurrentLayer->Bounds()); BRegion dirty((BRect)fCurrentLayer->Bounds());
fWindowLayer->InvalidateView(fCurrentLayer, dirty); fWindowLayer->InvalidateView(fCurrentLayer, dirty);
} }
+1 -1
View File
@@ -107,7 +107,7 @@ ViewLayer::ViewLayer(IntRect frame, IntPoint scrollingOffset, const char* name,
fCursor(NULL), fCursor(NULL),
fPicture(NULL), fPicture(NULL),
fLocalClipping(Bounds()), fLocalClipping((BRect)Bounds()),
fScreenClipping(), fScreenClipping(),
fScreenClippingValid(false) fScreenClippingValid(false)
{ {
+1 -1
View File
@@ -288,7 +288,7 @@ WorkspacesLayer::_DarkenColor(RGBColor& color) const
void void
WorkspacesLayer::_Invalidate() const WorkspacesLayer::_Invalidate() const
{ {
BRegion region(Frame()); BRegion region((BRect)Frame());
Window()->MarkContentDirty(region); Window()->MarkContentDirty(region);
} }