Fixed a possible buffer overflow in r_or() and r_sub() (thanks to Ingo Weinhold for his advices), stripped BRegion of all his friends, and moved them into a single class (BRegion::Support()). Removed "find_small_bottom()", as we didn't use it at all. Added some debugging output to BRegion::Support (that will help fixing bugs)
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5131 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
9da902c635
commit
4be90e7fc1
@ -61,37 +61,16 @@ clipping_rect RectAtInt(int32 index);
|
||||
void IntersectWith(const BRegion*);
|
||||
|
||||
/*----- Private or reserved -----------------------------------------*/
|
||||
class Support;
|
||||
|
||||
private:
|
||||
|
||||
friend class BView;
|
||||
friend class BDirectWindow;
|
||||
friend void zero_region(BRegion *a_region);
|
||||
friend void clear_region(BRegion *a_region);
|
||||
friend void cleanup_region_1(BRegion *region_in);
|
||||
friend void cleanup_region(BRegion *region_in);
|
||||
friend void sort_rects(clipping_rect *rects, long count);
|
||||
friend void sort_trans(long *lptr1, long *lptr2, long count);
|
||||
friend void cleanup_region_horizontal(BRegion *region_in);
|
||||
friend void copy_region(BRegion *src_region, BRegion *dst_region);
|
||||
friend void copy_region_n(BRegion*, BRegion*, long);
|
||||
friend void and_region_complex(BRegion*, BRegion*, BRegion*);
|
||||
friend void and_region_1_to_n(BRegion*, BRegion*, BRegion*);
|
||||
friend void and_region(BRegion*, BRegion*, BRegion*);
|
||||
friend void append_region(BRegion*, BRegion*, BRegion*);
|
||||
friend void r_or(long, long, BRegion*, BRegion*, BRegion*, long*, long *);
|
||||
friend void or_region_complex(BRegion*, BRegion*, BRegion*);
|
||||
friend void or_region_1_to_n(BRegion*, BRegion*, BRegion*);
|
||||
friend void or_region_no_x(BRegion*, BRegion*, BRegion*);
|
||||
friend void or_region(BRegion*, BRegion*, BRegion*);
|
||||
friend void sub(long, long, BRegion*, BRegion*, BRegion*, long*, long*);
|
||||
friend void sub_region_complex(BRegion*, BRegion*, BRegion*);
|
||||
friend void r_sub(long , long, BRegion*, BRegion*, BRegion*, long*, long*);
|
||||
friend void sub_region(BRegion*, BRegion*, BRegion*);
|
||||
friend class Support;
|
||||
|
||||
void _AddRect(clipping_rect r);
|
||||
void set_size(long new_size);
|
||||
long find_small_bottom(long y1, long y2, long *hint, long *where);
|
||||
|
||||
private:
|
||||
long count;
|
||||
|
42
headers/private/interface/RegionSupport.h
Normal file
42
headers/private/interface/RegionSupport.h
Normal file
@ -0,0 +1,42 @@
|
||||
// This file is distributed under the OpenBeOS license
|
||||
|
||||
#ifndef __REGION_SUPPORT_H
|
||||
#define __REGION_SUPPORT_H
|
||||
|
||||
#include <Region.h>
|
||||
|
||||
class BRegion::Support
|
||||
{
|
||||
public:
|
||||
static void ZeroRegion(BRegion *a_region);
|
||||
static void ClearRegion(BRegion *a_region);
|
||||
static void CopyRegion(BRegion *src_region, BRegion *dst_region);
|
||||
static void AndRegion(BRegion *first, BRegion *second, BRegion *dest);
|
||||
static void OrRegion(BRegion *first, BRegion *second, BRegion *dest);
|
||||
static void SubRegion(BRegion *first, BRegion *second, BRegion *dest);
|
||||
|
||||
private:
|
||||
static void CleanupRegion(BRegion *region_in);
|
||||
static void CleanupRegionVertical(BRegion *region_in);
|
||||
static void CleanupRegionHorizontal(BRegion *region_in);
|
||||
|
||||
static void SortRects(clipping_rect *rects, long count);
|
||||
static void SortTrans(long *lptr1, long *lptr2, long count);
|
||||
|
||||
static void CopyRegionMore(BRegion*, BRegion*, long);
|
||||
|
||||
static void AndRegionComplex(BRegion*, BRegion*, BRegion*);
|
||||
static void AndRegion1ToN(BRegion*, BRegion*, BRegion*);
|
||||
|
||||
static void AppendRegion(BRegion*, BRegion*, BRegion*);
|
||||
|
||||
static void OrRegionComplex(BRegion*, BRegion*, BRegion*);
|
||||
static void OrRegion1ToN(BRegion*, BRegion*, BRegion*);
|
||||
static void OrRegionNoX(BRegion*, BRegion*, BRegion*);
|
||||
static void ROr(long, long, BRegion*, BRegion*, BRegion*, long*, long *);
|
||||
|
||||
static void SubRegionComplex(BRegion*, BRegion*, BRegion*);
|
||||
static void RSub(long , long, BRegion*, BRegion*, BRegion*, long*, long*);
|
||||
};
|
||||
|
||||
#endif // __REGION_SUPPORT_H
|
@ -25,7 +25,8 @@
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// Notes: As now, memory is always allocated and never freed (except on destruction).
|
||||
// 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.
|
||||
@ -46,9 +47,9 @@
|
||||
#include <Debug.h>
|
||||
#include <Region.h>
|
||||
|
||||
// Private Includes -------------------------------------------------------------
|
||||
#include <clipping.h>
|
||||
|
||||
#include "region_helpers.h"
|
||||
#include <RegionSupport.h>
|
||||
|
||||
|
||||
/*! \brief Initializes a region. The region will have no rects,
|
||||
@ -61,7 +62,7 @@ BRegion::BRegion()
|
||||
{
|
||||
data = (clipping_rect *)malloc(data_size * sizeof(clipping_rect));
|
||||
|
||||
zero_region(this);
|
||||
Support::ZeroRegion(this);
|
||||
}
|
||||
|
||||
|
||||
@ -70,25 +71,18 @@ BRegion::BRegion()
|
||||
*/
|
||||
BRegion::BRegion(const BRegion ®ion)
|
||||
:
|
||||
data_size(8),
|
||||
data(NULL)
|
||||
{
|
||||
if (®ion != this) {
|
||||
bound = region.bound;
|
||||
count = region.count;
|
||||
data_size = region.data_size;
|
||||
bound = region.bound;
|
||||
count = region.count;
|
||||
data_size = region.data_size;
|
||||
|
||||
if (data_size <= 0)
|
||||
data_size = 1;
|
||||
|
||||
if (data_size <= 0)
|
||||
data_size = 1;
|
||||
|
||||
data = (clipping_rect *)malloc(data_size * sizeof(clipping_rect));
|
||||
|
||||
memcpy(data, region.data, count * sizeof(clipping_rect));
|
||||
} else {
|
||||
|
||||
data = (clipping_rect *)malloc(data_size * sizeof(clipping_rect));
|
||||
zero_region(this);
|
||||
}
|
||||
data = (clipping_rect *)malloc(data_size * sizeof(clipping_rect));
|
||||
|
||||
memcpy(data, region.data, count * sizeof(clipping_rect));
|
||||
}
|
||||
|
||||
|
||||
@ -200,7 +194,7 @@ BRegion::Set(clipping_rect newBounds)
|
||||
bound = newBounds;
|
||||
}
|
||||
else
|
||||
zero_region(this);
|
||||
Support::ZeroRegion(this);
|
||||
}
|
||||
|
||||
|
||||
@ -310,7 +304,7 @@ BRegion::OffsetBy(int32 dh, int32 dv)
|
||||
void
|
||||
BRegion::MakeEmpty()
|
||||
{
|
||||
zero_region(this);
|
||||
Support::ZeroRegion(this);
|
||||
}
|
||||
|
||||
|
||||
@ -335,8 +329,8 @@ BRegion::Include(clipping_rect rect)
|
||||
|
||||
region.Set(rect);
|
||||
|
||||
or_region(this, ®ion, &newRegion);
|
||||
copy_region(&newRegion, this);
|
||||
Support::OrRegion(this, ®ion, &newRegion);
|
||||
Support::CopyRegion(&newRegion, this);
|
||||
}
|
||||
|
||||
|
||||
@ -348,8 +342,8 @@ BRegion::Include(const BRegion *region)
|
||||
{
|
||||
BRegion newRegion;
|
||||
|
||||
or_region(this, const_cast<BRegion *>(region), &newRegion);
|
||||
copy_region(&newRegion, this);
|
||||
Support::OrRegion(this, const_cast<BRegion *>(region), &newRegion);
|
||||
Support::CopyRegion(&newRegion, this);
|
||||
}
|
||||
|
||||
|
||||
@ -374,8 +368,8 @@ BRegion::Exclude(clipping_rect rect)
|
||||
|
||||
region.Set(rect);
|
||||
|
||||
sub_region(this, ®ion, &newRegion);
|
||||
copy_region(&newRegion, this);
|
||||
Support::SubRegion(this, ®ion, &newRegion);
|
||||
Support::CopyRegion(&newRegion, this);
|
||||
}
|
||||
|
||||
|
||||
@ -387,8 +381,8 @@ BRegion::Exclude(const BRegion *region)
|
||||
{
|
||||
BRegion newRegion;
|
||||
|
||||
sub_region(this, const_cast<BRegion *>(region), &newRegion);
|
||||
copy_region(&newRegion, this);
|
||||
Support::SubRegion(this, const_cast<BRegion *>(region), &newRegion);
|
||||
Support::CopyRegion(&newRegion, this);
|
||||
}
|
||||
|
||||
|
||||
@ -400,8 +394,8 @@ BRegion::IntersectWith(const BRegion *region)
|
||||
{
|
||||
BRegion newRegion;
|
||||
|
||||
and_region(this, const_cast<BRegion *>(region), &newRegion);
|
||||
copy_region(&newRegion, this);
|
||||
Support::AndRegion(this, const_cast<BRegion *>(region), &newRegion);
|
||||
Support::CopyRegion(&newRegion, this);
|
||||
}
|
||||
|
||||
|
||||
@ -515,12 +509,3 @@ BRegion::set_size(long new_size)
|
||||
|
||||
ASSERT(count <= data_size);
|
||||
}
|
||||
|
||||
|
||||
long
|
||||
BRegion::find_small_bottom(long y1, long y2, long *hint, long *where)
|
||||
{
|
||||
//XXX: What does this do?
|
||||
PRINT(("%s\n", __PRETTY_FUNCTION__));
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,24 +1,69 @@
|
||||
#include <cstring>
|
||||
//------------------------------------------------------------------------------
|
||||
// Copyright (c) 2003, OpenBeOS
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||
// copy of this software and associated documentation files (the "Software"),
|
||||
// to deal in the Software without restriction, including without limitation
|
||||
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
// 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: RegionSupport.cpp
|
||||
// Author: Stefano Ceccherini (burton666@libero.it)
|
||||
// Description: Class that does the dirty work for BRegion.
|
||||
//
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
// TODO: check for possible performance issue in ROr() and RSub().
|
||||
// Check if inlining some methods can make us be faster.
|
||||
|
||||
// Standard Includes -----------------------------------------------------------
|
||||
#include <cstring>
|
||||
#include <new>
|
||||
|
||||
// System Includes -------------------------------------------------------------
|
||||
#include <Debug.h>
|
||||
#include <Region.h>
|
||||
|
||||
// Private Includes -------------------------------------------------------------
|
||||
#include <clipping.h>
|
||||
#include <RegionSupport.h>
|
||||
|
||||
#include "region_helpers.h"
|
||||
// Constants --------------------------------------------------------------------
|
||||
const int32 kMaxPoints = 1024;
|
||||
const int32 kMaxVerticalExtent = 0x10000000;
|
||||
|
||||
static const int32 kMaxPoints = 1024;
|
||||
static const int32 kMaxVerticalExtent = 0x10000000;
|
||||
|
||||
/* friend functions */
|
||||
#define TRACE_REGION 0
|
||||
#if TRACE_REGION
|
||||
#define RTRACE printf
|
||||
#define CALLED() RTRACE("%s\n", __PRETTY_FUNCTION__)
|
||||
#else
|
||||
#define RTRACE (void)
|
||||
#define CALLED()
|
||||
#endif
|
||||
|
||||
|
||||
/*! \brief zeroes the given region, setting its rect count to 0,
|
||||
and invalidating its bound rectangle.
|
||||
\param region The region to be zeroed.
|
||||
*/
|
||||
void
|
||||
zero_region(BRegion *region)
|
||||
BRegion::Support::ZeroRegion(BRegion *region)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
region->count = 0;
|
||||
region->bound.left = 0x7ffffffd;
|
||||
region->bound.top = 0x7ffffffd;
|
||||
@ -27,9 +72,18 @@ zero_region(BRegion *region)
|
||||
}
|
||||
|
||||
|
||||
/*! \brief clear the given region, setting its rect count to 0,
|
||||
and setting its bound rectangle to 0xFFFFFFF, 0xFFFFFFF, 0xF0000001, 0xF0000001.
|
||||
\param region The region to be cleared.
|
||||
*/
|
||||
void
|
||||
clear_region(BRegion *region)
|
||||
BRegion::Support::ClearRegion(BRegion *region)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
// XXX: What is it used for ?
|
||||
// Can be that a cleared region represents an infinite one ?
|
||||
|
||||
region->count = 0;
|
||||
region->bound.left = 0xfffffff;
|
||||
region->bound.top = 0xfffffff;
|
||||
@ -38,41 +92,148 @@ clear_region(BRegion *region)
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Cleanup the region vertically.
|
||||
\param region The region to be cleaned.
|
||||
/*! \brief Copy a region to another.
|
||||
\param source The region to be copied.
|
||||
\param dest The destination region.
|
||||
*/
|
||||
void
|
||||
cleanup_region_1(BRegion *region)
|
||||
BRegion::Support::CopyRegion(BRegion *source, BRegion *dest)
|
||||
{
|
||||
clipping_rect testRect =
|
||||
{
|
||||
1, 1,
|
||||
-1, -2
|
||||
};
|
||||
|
||||
long newCount = -1;
|
||||
CALLED();
|
||||
ASSERT(source);
|
||||
ASSERT(dest);
|
||||
ASSERT(source != dest);
|
||||
|
||||
if (region->count > 0) {
|
||||
for (long x = 0; x < region->count; x++) {
|
||||
clipping_rect rect = region->data[x];
|
||||
|
||||
if (rect.left == testRect.left && rect.right == testRect.right
|
||||
&& rect.top == testRect.bottom + 1) {
|
||||
|
||||
ASSERT(newCount >= 0);
|
||||
region->data[newCount].bottom = rect.bottom;
|
||||
|
||||
} else {
|
||||
newCount++;
|
||||
region->data[newCount] = region->data[x];
|
||||
testRect = region->data[x];
|
||||
}
|
||||
}
|
||||
region->count = newCount + 1;
|
||||
|
||||
cleanup_region_horizontal(region);
|
||||
// If there is not enough memory, allocate
|
||||
if (dest->data_size < source->count) {
|
||||
free(dest->data);
|
||||
dest->data_size = source->count + 8;
|
||||
dest->data = (clipping_rect *)malloc(dest->data_size * sizeof(clipping_rect));
|
||||
}
|
||||
|
||||
dest->count = source->count;
|
||||
|
||||
// Copy rectangles and bounds.
|
||||
memcpy(dest->data, source->data, source->count * sizeof(clipping_rect));
|
||||
dest->bound = source->bound;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Modify the destination region to be the intersection of the two given regions.
|
||||
\param first The first region to be intersected.
|
||||
\param second The second region to be intersected.
|
||||
\param dest The destination region.
|
||||
|
||||
This function is a sort of method selector. It checks for some special
|
||||
cases, then it calls the appropriate specialized function.
|
||||
*/
|
||||
void
|
||||
BRegion::Support::AndRegion(BRegion *first, BRegion *second, BRegion *dest)
|
||||
{
|
||||
CALLED();
|
||||
ASSERT(first);
|
||||
ASSERT(second);
|
||||
ASSERT(dest);
|
||||
|
||||
clipping_rect intersection = sect_rect(first->bound, second->bound);
|
||||
|
||||
if (first->count == 0 || second->count == 0 || !valid_rect(intersection))
|
||||
ZeroRegion(dest);
|
||||
|
||||
else if (first->count == 1 && second->count == 1) {
|
||||
dest->data[0] = intersection;
|
||||
dest->bound = intersection;
|
||||
dest->count = 1;
|
||||
}
|
||||
else if (first->count > 1 && second->count == 1)
|
||||
AndRegion1ToN(second, first, dest);
|
||||
|
||||
else if (first->count == 1 && second->count > 1)
|
||||
AndRegion1ToN(first, second, dest);
|
||||
|
||||
else
|
||||
AndRegionComplex(first, second, dest);
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Modify the destination region to be the union of the two given regions.
|
||||
\param first The first region to be merged.
|
||||
\param second The second region to be merged.
|
||||
\param dest The destination region.
|
||||
|
||||
This function is a sort of method selector. It checks for some special
|
||||
cases, then it calls the appropriate specialized function.
|
||||
*/
|
||||
void
|
||||
BRegion::Support::OrRegion(BRegion *first, BRegion *second, BRegion *dest)
|
||||
{
|
||||
CALLED();
|
||||
ASSERT(first);
|
||||
ASSERT(second);
|
||||
ASSERT(dest);
|
||||
|
||||
BRegion *regionA, *regionB;
|
||||
|
||||
// A little trick, to save some work...
|
||||
if (first->count != 0) {
|
||||
regionA = first;
|
||||
regionB = second;
|
||||
} else {
|
||||
regionA = second;
|
||||
regionB = first;
|
||||
}
|
||||
|
||||
if (regionB->count == 0)
|
||||
CopyRegion(regionA, dest);
|
||||
else {
|
||||
if (regionB->bound.top > regionA->bound.bottom)
|
||||
AppendRegion(regionA, regionB, dest);
|
||||
|
||||
else if (regionA->bound.top > regionB->bound.bottom)
|
||||
AppendRegion(regionB, regionA, dest);
|
||||
|
||||
else if (regionA->bound.left > regionB->bound.right)
|
||||
OrRegionNoX(regionB, regionA, dest);
|
||||
|
||||
else if (regionB->bound.left > regionA->bound.right)
|
||||
OrRegionNoX(regionA, regionB, dest);
|
||||
|
||||
else if (regionA->count == 1)
|
||||
OrRegion1ToN(regionA, regionB, dest);
|
||||
|
||||
else if (regionB->count == 1)
|
||||
OrRegion1ToN(regionB, regionA, dest);
|
||||
|
||||
else
|
||||
OrRegionComplex(regionA, regionB, dest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Modify the destination region to be the difference of the two given regions.
|
||||
\param first The subtraend region.
|
||||
\param second The minuend region.
|
||||
\param dest The destination region.
|
||||
|
||||
This function is a sort of method selector. It checks for some special
|
||||
cases, then it calls the appropriate specialized function.
|
||||
*/
|
||||
void
|
||||
BRegion::Support::SubRegion(BRegion *first, BRegion *second, BRegion *dest)
|
||||
{
|
||||
CALLED();
|
||||
ASSERT(first);
|
||||
ASSERT(second);
|
||||
ASSERT(dest);
|
||||
|
||||
if (first->count == 0)
|
||||
ZeroRegion(dest);
|
||||
|
||||
else if (second->count == 0 || !rects_intersect(first->bound, second->bound))
|
||||
CopyRegion(first, dest);
|
||||
|
||||
else
|
||||
SubRegionComplex(second, first, dest);
|
||||
}
|
||||
|
||||
|
||||
@ -80,24 +241,88 @@ cleanup_region_1(BRegion *region)
|
||||
\param region The region to be cleaned.
|
||||
*/
|
||||
void
|
||||
cleanup_region(BRegion *region)
|
||||
BRegion::Support::CleanupRegion(BRegion *region)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
long oldCount;
|
||||
|
||||
do {
|
||||
oldCount = region->count;
|
||||
cleanup_region_1(region);
|
||||
CleanupRegionVertical(region);
|
||||
CleanupRegionHorizontal(region);
|
||||
} while (region->count < oldCount);
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Cleanup the region vertically.
|
||||
\param region The region to be cleaned.
|
||||
*/
|
||||
void
|
||||
BRegion::Support::CleanupRegionVertical(BRegion *region)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
clipping_rect testRect = { 1, 1, -1, -2 };
|
||||
long newCount = -1;
|
||||
|
||||
for (long x = 0; x < region->count; x++) {
|
||||
clipping_rect rect = region->data[x];
|
||||
|
||||
if (rect.left == testRect.left && rect.right == testRect.right
|
||||
&& rect.top == testRect.bottom + 1) {
|
||||
|
||||
ASSERT(newCount >= 0);
|
||||
region->data[newCount].bottom = rect.bottom;
|
||||
|
||||
} else {
|
||||
newCount++;
|
||||
region->data[newCount] = region->data[x];
|
||||
testRect = region->data[x];
|
||||
}
|
||||
}
|
||||
region->count = newCount + 1;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Cleanup the region horizontally.
|
||||
\param region The region to be cleaned.
|
||||
*/
|
||||
void
|
||||
BRegion::Support::CleanupRegionHorizontal(BRegion *region)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
clipping_rect testRect = { 1, 1, -2, -1 };
|
||||
long newCount = -1;
|
||||
|
||||
for (long x = 0; x < region->count; x++) {
|
||||
clipping_rect rect = region->data[x];
|
||||
if (rect.top == testRect.top && rect.bottom == testRect.bottom
|
||||
&& rect.left == testRect.right + 1) {
|
||||
|
||||
ASSERT(newCount >= 0);
|
||||
region->data[newCount].right = rect.right;
|
||||
|
||||
} else {
|
||||
newCount++;
|
||||
region->data[newCount] = rect;
|
||||
}
|
||||
testRect = region->data[newCount];
|
||||
}
|
||||
region->count = newCount + 1;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Sorts the given rects by their top value.
|
||||
\param rects A pointer to an array of clipping_rects.
|
||||
\param count The number of rectangles in the array.
|
||||
*/
|
||||
void
|
||||
sort_rects(clipping_rect *rects, long count)
|
||||
BRegion::Support::SortRects(clipping_rect *rects, long count)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
bool again; //flag that tells we changed rects positions
|
||||
|
||||
if (count == 2) {
|
||||
@ -123,8 +348,10 @@ sort_rects(clipping_rect *rects, long count)
|
||||
|
||||
|
||||
void
|
||||
sort_trans(long *lptr1, long *lptr2, long count)
|
||||
BRegion::Support::SortTrans(long *lptr1, long *lptr2, long count)
|
||||
{
|
||||
CALLED();
|
||||
|
||||
bool again; //flag that tells we changed trans positions
|
||||
|
||||
if (count == 2) {
|
||||
@ -157,72 +384,15 @@ sort_trans(long *lptr1, long *lptr2, long count)
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Cleanup the region horizontally.
|
||||
\param region The region to be cleaned.
|
||||
*/
|
||||
void
|
||||
cleanup_region_horizontal(BRegion *region)
|
||||
{
|
||||
clipping_rect testRect =
|
||||
{
|
||||
1, 1,
|
||||
-2, -1
|
||||
};
|
||||
|
||||
long newCount = -1;
|
||||
|
||||
for (long x = 0; x < region->count; x++) {
|
||||
clipping_rect rect = region->data[x];
|
||||
if (rect.top == testRect.top && rect.bottom == testRect.bottom
|
||||
&& rect.left == testRect.right + 1) {
|
||||
|
||||
ASSERT(newCount >= 0);
|
||||
region->data[newCount].right = rect.right;
|
||||
|
||||
} else {
|
||||
newCount++;
|
||||
region->data[newCount] = rect;
|
||||
}
|
||||
testRect = region->data[newCount];
|
||||
}
|
||||
region->count = newCount + 1;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Copy a region to another.
|
||||
\param source The region to be copied.
|
||||
\param dest The destination region.
|
||||
*/
|
||||
void
|
||||
copy_region(BRegion *source, BRegion *dest)
|
||||
{
|
||||
ASSERT(source);
|
||||
ASSERT(dest);
|
||||
ASSERT(source != dest);
|
||||
|
||||
// If there is not enough memory, allocate
|
||||
if (dest->data_size < source->count) {
|
||||
free(dest->data);
|
||||
dest->data_size = source->count + 8;
|
||||
dest->data = (clipping_rect *)malloc(dest->data_size * sizeof(clipping_rect));
|
||||
}
|
||||
|
||||
dest->count = source->count;
|
||||
|
||||
// Copy rectangles and bounds.
|
||||
memcpy(dest->data, source->data, source->count * sizeof(clipping_rect));
|
||||
dest->bound = source->bound;
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Copy a region to another, allocating some additional memory in the destination region.
|
||||
\param source The region to be copied.
|
||||
\param dest The destination region.
|
||||
\param count Amount of additional memory to be allocated in the destination region.
|
||||
*/
|
||||
void
|
||||
copy_region_n(BRegion *source, BRegion *dest, long count)
|
||||
BRegion::Support::CopyRegionMore(BRegion *source, BRegion *dest, long count)
|
||||
{
|
||||
CALLED();
|
||||
ASSERT(source);
|
||||
ASSERT(dest);
|
||||
ASSERT(source != dest);
|
||||
@ -250,13 +420,14 @@ copy_region_n(BRegion *source, BRegion *dest, long count)
|
||||
Called by and_region() when the intersection is complex.
|
||||
*/
|
||||
void
|
||||
and_region_complex(BRegion *first, BRegion *second, BRegion *dest)
|
||||
BRegion::Support::AndRegionComplex(BRegion *first, BRegion *second, BRegion *dest)
|
||||
{
|
||||
CALLED();
|
||||
ASSERT(first);
|
||||
ASSERT(second);
|
||||
ASSERT(dest);
|
||||
|
||||
zero_region(dest);
|
||||
ZeroRegion(dest);
|
||||
|
||||
for (long f = 0; f < first->count; f++) {
|
||||
for (long s = 0; s < second->count; s++) {
|
||||
@ -267,7 +438,7 @@ and_region_complex(BRegion *first, BRegion *second, BRegion *dest)
|
||||
}
|
||||
|
||||
if (dest->count > 1)
|
||||
sort_rects(dest->data, dest->count);
|
||||
SortRects(dest->data, dest->count);
|
||||
}
|
||||
|
||||
|
||||
@ -279,8 +450,9 @@ and_region_complex(BRegion *first, BRegion *second, BRegion *dest)
|
||||
Called by and_region() when one of the two region contains just one rect.
|
||||
*/
|
||||
void
|
||||
and_region_1_to_n(BRegion *first, BRegion *second, BRegion *dest)
|
||||
BRegion::Support::AndRegion1ToN(BRegion *first, BRegion *second, BRegion *dest)
|
||||
{
|
||||
CALLED();
|
||||
ASSERT(first);
|
||||
ASSERT(second);
|
||||
ASSERT(dest);
|
||||
@ -292,11 +464,11 @@ and_region_1_to_n(BRegion *first, BRegion *second, BRegion *dest)
|
||||
&& first->bound.bottom >= second->bound.bottom
|
||||
&& first->bound.left <= second->bound.left
|
||||
&& first->bound.right >= second->bound.right)
|
||||
copy_region(second, dest);
|
||||
CopyRegion(second, dest);
|
||||
else {
|
||||
// Otherwise, we check the rect of the first region against the rects
|
||||
// of the second, and we add their intersections to the destination region
|
||||
zero_region(dest);
|
||||
ZeroRegion(dest);
|
||||
for (long x = 0; x < second->count; x++) {
|
||||
clipping_rect testRect = sect_rect(first->data[0], second->data[x]);
|
||||
if (valid_rect(testRect))
|
||||
@ -306,42 +478,6 @@ and_region_1_to_n(BRegion *first, BRegion *second, BRegion *dest)
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Modify the destination region to be the intersection of the two given regions.
|
||||
\param first The first region to be intersected.
|
||||
\param second The second region to be intersected.
|
||||
\param dest The destination region.
|
||||
|
||||
This function is a sort of method selector. It checks for some special
|
||||
cases, then it calls the appropriate specialized function.
|
||||
*/
|
||||
void
|
||||
and_region(BRegion *first, BRegion *second, BRegion *dest)
|
||||
{
|
||||
ASSERT(first);
|
||||
ASSERT(second);
|
||||
ASSERT(dest);
|
||||
|
||||
clipping_rect intersection = sect_rect(first->bound, second->bound);
|
||||
|
||||
if (first->count == 0 || second->count == 0 || !valid_rect(intersection))
|
||||
zero_region(dest);
|
||||
|
||||
else if (first->count == 1 && second->count == 1) {
|
||||
dest->data[0] = intersection;
|
||||
dest->bound = intersection;
|
||||
dest->count = 1;
|
||||
}
|
||||
else if (first->count > 1 && second->count == 1)
|
||||
and_region_1_to_n(second, first, dest);
|
||||
|
||||
else if (first->count == 1 && second->count > 1)
|
||||
and_region_1_to_n(first, second, dest);
|
||||
|
||||
else
|
||||
and_region_complex(first, second, dest);
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Modify the destination region to be the union of the two given regions.
|
||||
\param first The first region to be or-ed.
|
||||
\param second The second region to be or-ed.
|
||||
@ -352,13 +488,14 @@ and_region(BRegion *first, BRegion *second, BRegion *dest)
|
||||
coordinate.
|
||||
*/
|
||||
void
|
||||
append_region(BRegion *first, BRegion *second, BRegion *dest)
|
||||
BRegion::Support::AppendRegion(BRegion *first, BRegion *second, BRegion *dest)
|
||||
{
|
||||
CALLED();
|
||||
ASSERT(first);
|
||||
ASSERT(second);
|
||||
ASSERT(dest);
|
||||
|
||||
copy_region(first, dest);
|
||||
CopyRegion(first, dest);
|
||||
|
||||
for (long c = 0; c < second->count; c++)
|
||||
dest->_AddRect(second->data[c]);
|
||||
@ -366,10 +503,15 @@ append_region(BRegion *first, BRegion *second, BRegion *dest)
|
||||
|
||||
|
||||
void
|
||||
r_or(long top, long bottom, BRegion *first, BRegion *second, BRegion *dest, long *indexA, long *indexB)
|
||||
BRegion::Support::ROr(long top, long bottom, BRegion *first, BRegion *second, BRegion *dest, long *indexA, long *indexB)
|
||||
{
|
||||
int32 lefts[kMaxPoints];
|
||||
int32 rights[kMaxPoints];
|
||||
CALLED();
|
||||
|
||||
int32 stackLefts[kMaxPoints];
|
||||
int32 stackRights[kMaxPoints];
|
||||
|
||||
int32 *lefts = stackLefts;
|
||||
int32 *rights = stackRights;
|
||||
|
||||
long i1 = *indexA;
|
||||
long i2 = *indexB;
|
||||
@ -380,6 +522,19 @@ r_or(long top, long bottom, BRegion *first, BRegion *second, BRegion *dest, long
|
||||
long foundCount = 0;
|
||||
long x = 0;
|
||||
|
||||
// allocate arrays on the heap, if the ones one the stack are too small
|
||||
int32 *allocatedBuffer = NULL;
|
||||
int32 maxCount = first->count - i1 + second->count - i2;
|
||||
|
||||
if (maxCount > kMaxPoints) {
|
||||
RTRACE("Stack space isn't sufficient. Allocating %d bytes on the heap...\n",
|
||||
2 * maxCount);
|
||||
lefts = allocatedBuffer = new(nothrow) int32[2 * maxCount];
|
||||
if (!allocatedBuffer)
|
||||
return;
|
||||
rights = allocatedBuffer + maxCount;
|
||||
}
|
||||
|
||||
// Store left and right points to the appropriate array
|
||||
for (x = i1; x < first->count; x++) {
|
||||
|
||||
@ -415,7 +570,7 @@ r_or(long top, long bottom, BRegion *first, BRegion *second, BRegion *dest, long
|
||||
*indexB = i2;
|
||||
|
||||
if (foundCount > 1)
|
||||
sort_trans(lefts, rights, foundCount);
|
||||
SortTrans(lefts, rights, foundCount);
|
||||
|
||||
ASSERT(foundCount > 0);
|
||||
|
||||
@ -440,7 +595,12 @@ r_or(long top, long bottom, BRegion *first, BRegion *second, BRegion *dest, long
|
||||
|
||||
dest->_AddRect(rect);
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
if (allocatedBuffer) {
|
||||
RTRACE("Freeing heap...\n");
|
||||
delete[] allocatedBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -451,8 +611,9 @@ r_or(long top, long bottom, BRegion *first, BRegion *second, BRegion *dest, long
|
||||
\param dest The destination region.
|
||||
*/
|
||||
void
|
||||
or_region_complex(BRegion *first, BRegion *second, BRegion *dest)
|
||||
BRegion::Support::OrRegionComplex(BRegion *first, BRegion *second, BRegion *dest)
|
||||
{
|
||||
CALLED();
|
||||
long a = 0, b = 0;
|
||||
|
||||
int32 top;
|
||||
@ -482,11 +643,11 @@ or_region_complex(BRegion *first, BRegion *second, BRegion *dest)
|
||||
if (bottom >= kMaxVerticalExtent)
|
||||
break;
|
||||
|
||||
r_or(top, bottom, first, second, dest, &a, &b);
|
||||
ROr(top, bottom, first, second, dest, &a, &b);
|
||||
|
||||
} while (true);
|
||||
|
||||
cleanup_region(dest);
|
||||
CleanupRegion(dest);
|
||||
}
|
||||
|
||||
|
||||
@ -499,8 +660,9 @@ or_region_complex(BRegion *first, BRegion *second, BRegion *dest)
|
||||
one rect.
|
||||
*/
|
||||
void
|
||||
or_region_1_to_n(BRegion *first, BRegion *second, BRegion *dest)
|
||||
BRegion::Support::OrRegion1ToN(BRegion *first, BRegion *second, BRegion *dest)
|
||||
{
|
||||
CALLED();
|
||||
ASSERT(first);
|
||||
ASSERT(second);
|
||||
ASSERT(dest);
|
||||
@ -512,9 +674,9 @@ or_region_1_to_n(BRegion *first, BRegion *second, BRegion *dest)
|
||||
&& first->bound.bottom >= second->bound.bottom
|
||||
&& first->bound.left <= second->bound.left
|
||||
&& first->bound.right >= second->bound.right)
|
||||
copy_region(first, dest);
|
||||
CopyRegion(first, dest);
|
||||
else
|
||||
or_region_complex(first, second, dest);
|
||||
OrRegionComplex(first, second, dest);
|
||||
}
|
||||
|
||||
|
||||
@ -526,13 +688,14 @@ or_region_1_to_n(BRegion *first, BRegion *second, BRegion *dest)
|
||||
This function is called by or_region when the two regions don't intersect.
|
||||
*/
|
||||
void
|
||||
or_region_no_x(BRegion *first, BRegion *second, BRegion *dest)
|
||||
BRegion::Support::OrRegionNoX(BRegion *first, BRegion *second, BRegion *dest)
|
||||
{
|
||||
CALLED();
|
||||
ASSERT(first);
|
||||
ASSERT(second);
|
||||
ASSERT(dest);
|
||||
|
||||
zero_region(dest);
|
||||
ZeroRegion(dest);
|
||||
|
||||
long x;
|
||||
|
||||
@ -570,59 +733,6 @@ or_region_no_x(BRegion *first, BRegion *second, BRegion *dest)
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Modify the destination region to be the union of the two given regions.
|
||||
\param first The first region to be merged.
|
||||
\param second The second region to be merged.
|
||||
\param dest The destination region.
|
||||
|
||||
This function is a sort of method selector. It checks for some special
|
||||
cases, then it calls the appropriate specialized function.
|
||||
*/
|
||||
void
|
||||
or_region(BRegion *first, BRegion *second, BRegion *dest)
|
||||
{
|
||||
ASSERT(first);
|
||||
ASSERT(second);
|
||||
ASSERT(dest);
|
||||
|
||||
BRegion *regionA, *regionB;
|
||||
|
||||
// A little trick, to save some work...
|
||||
if (first->count != 0) {
|
||||
regionA = first;
|
||||
regionB = second;
|
||||
} else {
|
||||
regionA = second;
|
||||
regionB = first;
|
||||
}
|
||||
|
||||
if (regionB->count == 0)
|
||||
copy_region(regionA, dest);
|
||||
else {
|
||||
if (regionB->bound.top > regionA->bound.bottom)
|
||||
append_region(regionA, regionB, dest);
|
||||
|
||||
else if (regionA->bound.top > regionB->bound.bottom)
|
||||
append_region(regionB, regionA, dest);
|
||||
|
||||
else if (regionA->bound.left > regionB->bound.right)
|
||||
or_region_no_x(regionB, regionA, dest);
|
||||
|
||||
else if (regionB->bound.left > regionA->bound.right)
|
||||
or_region_no_x(regionA, regionB, dest);
|
||||
|
||||
else if (regionA->count == 1)
|
||||
or_region_1_to_n(regionA, regionB, dest);
|
||||
|
||||
else if (regionB->count == 1)
|
||||
or_region_1_to_n(regionB, regionA, dest);
|
||||
|
||||
else
|
||||
or_region_complex(regionA, regionB, dest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Divides the plane into horizontal bands, then passes those bands to r_sub
|
||||
which does the real work.
|
||||
\param first The subtraend region.
|
||||
@ -630,8 +740,9 @@ or_region(BRegion *first, BRegion *second, BRegion *dest)
|
||||
\param dest The destination region.
|
||||
*/
|
||||
void
|
||||
sub_region_complex(BRegion *first, BRegion *second, BRegion *dest)
|
||||
BRegion::Support::SubRegionComplex(BRegion *first, BRegion *second, BRegion *dest)
|
||||
{
|
||||
CALLED();
|
||||
long a = 0, b = 0;
|
||||
|
||||
int32 top;
|
||||
@ -661,22 +772,29 @@ sub_region_complex(BRegion *first, BRegion *second, BRegion *dest)
|
||||
if (bottom >= kMaxVerticalExtent)
|
||||
break;
|
||||
|
||||
r_sub(top, bottom, first, second, dest, &a, &b);
|
||||
RSub(top, bottom, first, second, dest, &a, &b);
|
||||
|
||||
} while (true);
|
||||
|
||||
cleanup_region(dest);
|
||||
CleanupRegion(dest);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
r_sub(long top, long bottom, BRegion *first, BRegion *second, BRegion *dest, long *indexA, long *indexB)
|
||||
BRegion::Support::RSub(long top, long bottom, BRegion *first, BRegion *second, BRegion *dest, long *indexA, long *indexB)
|
||||
{
|
||||
int32 leftsA[kMaxPoints / 2];
|
||||
int32 rightsA[kMaxPoints / 2];
|
||||
int32 leftsB[kMaxPoints / 2];
|
||||
int32 rightsB[kMaxPoints / 2];
|
||||
CALLED();
|
||||
|
||||
int32 stackLeftsA[kMaxPoints / 2];
|
||||
int32 stackLeftsB[kMaxPoints / 2];
|
||||
int32 stackRightsA[kMaxPoints / 2];
|
||||
int32 stackRightsB[kMaxPoints / 2];
|
||||
|
||||
int32 *leftsA = stackLeftsA;
|
||||
int32 *leftsB = stackLeftsB;
|
||||
int32 *rightsA = stackRightsA;
|
||||
int32 *rightsB = stackRightsB;
|
||||
|
||||
long i1 = *indexA;
|
||||
long i2 = *indexB;
|
||||
|
||||
@ -687,6 +805,22 @@ r_sub(long top, long bottom, BRegion *first, BRegion *second, BRegion *dest, lon
|
||||
long foundB = 0;
|
||||
long x = 0;
|
||||
|
||||
// allocate arrays on the heap, if the ones one the stack are too small
|
||||
int32 *allocatedBuffer = NULL;
|
||||
int32 maxCountA = first->count - i1;
|
||||
int32 maxCountB = second->count - i2;
|
||||
|
||||
if (maxCountA + maxCountB > kMaxPoints) {
|
||||
RTRACE("Stack space isn't sufficient. Allocating %d bytes on the heap...\n",
|
||||
2 * (maxCountA + maxCountB));
|
||||
leftsA = allocatedBuffer = new(nothrow) int32[2 * (maxCountA + maxCountB)];
|
||||
if (!allocatedBuffer)
|
||||
return;
|
||||
rightsA = allocatedBuffer + maxCountA;
|
||||
leftsB = rightsA + maxCountA;
|
||||
rightsB = leftsB + maxCountB;
|
||||
}
|
||||
|
||||
// Store left and right points to the appropriate array
|
||||
for (x = i1; x < first->count; x++) {
|
||||
|
||||
@ -707,7 +841,7 @@ r_sub(long top, long bottom, BRegion *first, BRegion *second, BRegion *dest, lon
|
||||
*indexA = i1;
|
||||
|
||||
if (foundA > 1)
|
||||
sort_trans(leftsA, rightsA, foundA);
|
||||
SortTrans(leftsA, rightsA, foundA);
|
||||
|
||||
for (x = i2; x < second->count; x++) {
|
||||
if (second->data[x].bottom >= top && *indexB == -1)
|
||||
@ -725,7 +859,7 @@ r_sub(long top, long bottom, BRegion *first, BRegion *second, BRegion *dest, lon
|
||||
*indexB = i2;
|
||||
|
||||
if (foundB > 1)
|
||||
sort_trans(leftsB, rightsB, foundB);
|
||||
SortTrans(leftsB, rightsB, foundB);
|
||||
|
||||
// No minuend's rect, just add all the subtraend's rects.
|
||||
if (foundA == 0)
|
||||
@ -800,31 +934,11 @@ r_sub(long top, long bottom, BRegion *first, BRegion *second, BRegion *dest, lon
|
||||
}
|
||||
}
|
||||
|
||||
if (allocatedBuffer) {
|
||||
RTRACE("Freeing heap...\n");
|
||||
delete[] allocatedBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*! \brief Modify the destination region to be the difference of the two given regions.
|
||||
\param first The subtraend region.
|
||||
\param second The minuend region.
|
||||
\param dest The destination region.
|
||||
|
||||
This function is a sort of method selector. It checks for some special
|
||||
cases, then it calls the appropriate specialized function.
|
||||
*/
|
||||
void
|
||||
sub_region(BRegion *first, BRegion *second, BRegion *dest)
|
||||
{
|
||||
ASSERT(first);
|
||||
ASSERT(second);
|
||||
ASSERT(dest);
|
||||
|
||||
if (first->count == 0)
|
||||
zero_region(dest);
|
||||
|
||||
else if (second->count == 0 || !rects_intersect(first->bound, second->bound))
|
||||
copy_region(first, dest);
|
||||
|
||||
else
|
||||
sub_region_complex(second, first, dest);
|
||||
}
|
||||
|
||||
#undef TRACE_REGION
|
@ -18,7 +18,7 @@ INTERFACE_KIT_SOURCE =
|
||||
RadioButton.cpp
|
||||
Rect.cpp
|
||||
Region.cpp
|
||||
region_helpers.cpp
|
||||
RegionSupport.cpp
|
||||
ScrollBar.cpp
|
||||
StatusBar.cpp
|
||||
StringView.cpp
|
||||
|
@ -1,26 +0,0 @@
|
||||
#ifndef __REGION_HELPERS_H
|
||||
#define __REGION_HELPERS_H
|
||||
|
||||
void zero_region(BRegion *a_region);
|
||||
void clear_region(BRegion *a_region);
|
||||
void cleanup_region_1(BRegion *region_in);
|
||||
void cleanup_region(BRegion *region_in);
|
||||
void sort_rects(clipping_rect *rects, long count);
|
||||
void sort_trans(long *lptr1, long *lptr2, long count);
|
||||
void cleanup_region_horizontal(BRegion *region_in);
|
||||
void copy_region(BRegion *src_region, BRegion *dst_region);
|
||||
void copy_region_n(BRegion*, BRegion*, long);
|
||||
void and_region_complex(BRegion*, BRegion*, BRegion*);
|
||||
void and_region_1_to_n(BRegion*, BRegion*, BRegion*);
|
||||
void and_region(BRegion*, BRegion*, BRegion*);
|
||||
void append_region(BRegion*, BRegion*, BRegion*);
|
||||
void r_or(long, long, BRegion*, BRegion*, BRegion*, long*, long *);
|
||||
void or_region_complex(BRegion*, BRegion*, BRegion*);
|
||||
void or_region_1_to_n(BRegion*, BRegion*, BRegion*);
|
||||
void or_region_no_x(BRegion*, BRegion*, BRegion*);
|
||||
void or_region(BRegion*, BRegion*, BRegion*);
|
||||
void sub_region_complex(BRegion*, BRegion*, BRegion*);
|
||||
void r_sub(long , long, BRegion*, BRegion*, BRegion*, long*, long*);
|
||||
void sub_region(BRegion*, BRegion*, BRegion*);
|
||||
|
||||
#endif // __REGION_HELPERS_H
|
Loading…
Reference in New Issue
Block a user