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:
@@ -61,37 +61,16 @@ clipping_rect RectAtInt(int32 index);
|
|||||||
void IntersectWith(const BRegion*);
|
void IntersectWith(const BRegion*);
|
||||||
|
|
||||||
/*----- Private or reserved -----------------------------------------*/
|
/*----- Private or reserved -----------------------------------------*/
|
||||||
|
class Support;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
friend class BView;
|
friend class BView;
|
||||||
friend class BDirectWindow;
|
friend class BDirectWindow;
|
||||||
friend void zero_region(BRegion *a_region);
|
friend class Support;
|
||||||
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*);
|
|
||||||
|
|
||||||
void _AddRect(clipping_rect r);
|
void _AddRect(clipping_rect r);
|
||||||
void set_size(long new_size);
|
void set_size(long new_size);
|
||||||
long find_small_bottom(long y1, long y2, long *hint, long *where);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
long count;
|
long count;
|
||||||
|
|||||||
@@ -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.
|
// 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
|
// But that means that even an empty region could "waste" much space, if it contained
|
||||||
// many rects before being emptied.
|
// many rects before being emptied.
|
||||||
@@ -46,9 +47,9 @@
|
|||||||
#include <Debug.h>
|
#include <Debug.h>
|
||||||
#include <Region.h>
|
#include <Region.h>
|
||||||
|
|
||||||
|
// Private Includes -------------------------------------------------------------
|
||||||
#include <clipping.h>
|
#include <clipping.h>
|
||||||
|
#include <RegionSupport.h>
|
||||||
#include "region_helpers.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*! \brief Initializes a region. The region will have no rects,
|
/*! \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));
|
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)
|
BRegion::BRegion(const BRegion ®ion)
|
||||||
:
|
:
|
||||||
data_size(8),
|
|
||||||
data(NULL)
|
data(NULL)
|
||||||
{
|
{
|
||||||
if (®ion != this) {
|
bound = region.bound;
|
||||||
bound = region.bound;
|
count = region.count;
|
||||||
count = region.count;
|
data_size = region.data_size;
|
||||||
data_size = region.data_size;
|
|
||||||
|
if (data_size <= 0)
|
||||||
|
data_size = 1;
|
||||||
|
|
||||||
if (data_size <= 0)
|
data = (clipping_rect *)malloc(data_size * sizeof(clipping_rect));
|
||||||
data_size = 1;
|
|
||||||
|
memcpy(data, region.data, count * sizeof(clipping_rect));
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -200,7 +194,7 @@ BRegion::Set(clipping_rect newBounds)
|
|||||||
bound = newBounds;
|
bound = newBounds;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
zero_region(this);
|
Support::ZeroRegion(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -310,7 +304,7 @@ BRegion::OffsetBy(int32 dh, int32 dv)
|
|||||||
void
|
void
|
||||||
BRegion::MakeEmpty()
|
BRegion::MakeEmpty()
|
||||||
{
|
{
|
||||||
zero_region(this);
|
Support::ZeroRegion(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -335,8 +329,8 @@ BRegion::Include(clipping_rect rect)
|
|||||||
|
|
||||||
region.Set(rect);
|
region.Set(rect);
|
||||||
|
|
||||||
or_region(this, ®ion, &newRegion);
|
Support::OrRegion(this, ®ion, &newRegion);
|
||||||
copy_region(&newRegion, this);
|
Support::CopyRegion(&newRegion, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -348,8 +342,8 @@ BRegion::Include(const BRegion *region)
|
|||||||
{
|
{
|
||||||
BRegion newRegion;
|
BRegion newRegion;
|
||||||
|
|
||||||
or_region(this, const_cast<BRegion *>(region), &newRegion);
|
Support::OrRegion(this, const_cast<BRegion *>(region), &newRegion);
|
||||||
copy_region(&newRegion, this);
|
Support::CopyRegion(&newRegion, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -374,8 +368,8 @@ BRegion::Exclude(clipping_rect rect)
|
|||||||
|
|
||||||
region.Set(rect);
|
region.Set(rect);
|
||||||
|
|
||||||
sub_region(this, ®ion, &newRegion);
|
Support::SubRegion(this, ®ion, &newRegion);
|
||||||
copy_region(&newRegion, this);
|
Support::CopyRegion(&newRegion, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -387,8 +381,8 @@ BRegion::Exclude(const BRegion *region)
|
|||||||
{
|
{
|
||||||
BRegion newRegion;
|
BRegion newRegion;
|
||||||
|
|
||||||
sub_region(this, const_cast<BRegion *>(region), &newRegion);
|
Support::SubRegion(this, const_cast<BRegion *>(region), &newRegion);
|
||||||
copy_region(&newRegion, this);
|
Support::CopyRegion(&newRegion, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -400,8 +394,8 @@ BRegion::IntersectWith(const BRegion *region)
|
|||||||
{
|
{
|
||||||
BRegion newRegion;
|
BRegion newRegion;
|
||||||
|
|
||||||
and_region(this, const_cast<BRegion *>(region), &newRegion);
|
Support::AndRegion(this, const_cast<BRegion *>(region), &newRegion);
|
||||||
copy_region(&newRegion, this);
|
Support::CopyRegion(&newRegion, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -515,12 +509,3 @@ BRegion::set_size(long new_size)
|
|||||||
|
|
||||||
ASSERT(count <= data_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 ([email protected])
|
||||||
|
// 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 <Debug.h>
|
||||||
#include <Region.h>
|
#include <Region.h>
|
||||||
|
|
||||||
|
// Private Includes -------------------------------------------------------------
|
||||||
#include <clipping.h>
|
#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,
|
/*! \brief zeroes the given region, setting its rect count to 0,
|
||||||
and invalidating its bound rectangle.
|
and invalidating its bound rectangle.
|
||||||
\param region The region to be zeroed.
|
\param region The region to be zeroed.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
zero_region(BRegion *region)
|
BRegion::Support::ZeroRegion(BRegion *region)
|
||||||
{
|
{
|
||||||
|
CALLED();
|
||||||
|
|
||||||
region->count = 0;
|
region->count = 0;
|
||||||
region->bound.left = 0x7ffffffd;
|
region->bound.left = 0x7ffffffd;
|
||||||
region->bound.top = 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
|
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->count = 0;
|
||||||
region->bound.left = 0xfffffff;
|
region->bound.left = 0xfffffff;
|
||||||
region->bound.top = 0xfffffff;
|
region->bound.top = 0xfffffff;
|
||||||
@@ -38,41 +92,148 @@ clear_region(BRegion *region)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*! \brief Cleanup the region vertically.
|
/*! \brief Copy a region to another.
|
||||||
\param region The region to be cleaned.
|
\param source The region to be copied.
|
||||||
|
\param dest The destination region.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
cleanup_region_1(BRegion *region)
|
BRegion::Support::CopyRegion(BRegion *source, BRegion *dest)
|
||||||
{
|
{
|
||||||
clipping_rect testRect =
|
CALLED();
|
||||||
{
|
ASSERT(source);
|
||||||
1, 1,
|
ASSERT(dest);
|
||||||
-1, -2
|
ASSERT(source != dest);
|
||||||
};
|
|
||||||
|
|
||||||
long newCount = -1;
|
|
||||||
|
|
||||||
if (region->count > 0) {
|
// If there is not enough memory, allocate
|
||||||
for (long x = 0; x < region->count; x++) {
|
if (dest->data_size < source->count) {
|
||||||
clipping_rect rect = region->data[x];
|
free(dest->data);
|
||||||
|
dest->data_size = source->count + 8;
|
||||||
if (rect.left == testRect.left && rect.right == testRect.right
|
dest->data = (clipping_rect *)malloc(dest->data_size * sizeof(clipping_rect));
|
||||||
&& 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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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.
|
\param region The region to be cleaned.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
cleanup_region(BRegion *region)
|
BRegion::Support::CleanupRegion(BRegion *region)
|
||||||
{
|
{
|
||||||
|
CALLED();
|
||||||
|
|
||||||
long oldCount;
|
long oldCount;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
oldCount = region->count;
|
oldCount = region->count;
|
||||||
cleanup_region_1(region);
|
CleanupRegionVertical(region);
|
||||||
|
CleanupRegionHorizontal(region);
|
||||||
} while (region->count < oldCount);
|
} 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.
|
/*! \brief Sorts the given rects by their top value.
|
||||||
\param rects A pointer to an array of clipping_rects.
|
\param rects A pointer to an array of clipping_rects.
|
||||||
\param count The number of rectangles in the array.
|
\param count The number of rectangles in the array.
|
||||||
*/
|
*/
|
||||||
void
|
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
|
bool again; //flag that tells we changed rects positions
|
||||||
|
|
||||||
if (count == 2) {
|
if (count == 2) {
|
||||||
@@ -123,8 +348,10 @@ sort_rects(clipping_rect *rects, long count)
|
|||||||
|
|
||||||
|
|
||||||
void
|
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
|
bool again; //flag that tells we changed trans positions
|
||||||
|
|
||||||
if (count == 2) {
|
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.
|
/*! \brief Copy a region to another, allocating some additional memory in the destination region.
|
||||||
\param source The region to be copied.
|
\param source The region to be copied.
|
||||||
\param dest The destination region.
|
\param dest The destination region.
|
||||||
\param count Amount of additional memory to be allocated in the destination region.
|
\param count Amount of additional memory to be allocated in the destination region.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
copy_region_n(BRegion *source, BRegion *dest, long count)
|
BRegion::Support::CopyRegionMore(BRegion *source, BRegion *dest, long count)
|
||||||
{
|
{
|
||||||
|
CALLED();
|
||||||
ASSERT(source);
|
ASSERT(source);
|
||||||
ASSERT(dest);
|
ASSERT(dest);
|
||||||
ASSERT(source != 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.
|
Called by and_region() when the intersection is complex.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
and_region_complex(BRegion *first, BRegion *second, BRegion *dest)
|
BRegion::Support::AndRegionComplex(BRegion *first, BRegion *second, BRegion *dest)
|
||||||
{
|
{
|
||||||
|
CALLED();
|
||||||
ASSERT(first);
|
ASSERT(first);
|
||||||
ASSERT(second);
|
ASSERT(second);
|
||||||
ASSERT(dest);
|
ASSERT(dest);
|
||||||
|
|
||||||
zero_region(dest);
|
ZeroRegion(dest);
|
||||||
|
|
||||||
for (long f = 0; f < first->count; f++) {
|
for (long f = 0; f < first->count; f++) {
|
||||||
for (long s = 0; s < second->count; s++) {
|
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)
|
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.
|
Called by and_region() when one of the two region contains just one rect.
|
||||||
*/
|
*/
|
||||||
void
|
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(first);
|
||||||
ASSERT(second);
|
ASSERT(second);
|
||||||
ASSERT(dest);
|
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.bottom >= second->bound.bottom
|
||||||
&& first->bound.left <= second->bound.left
|
&& first->bound.left <= second->bound.left
|
||||||
&& first->bound.right >= second->bound.right)
|
&& first->bound.right >= second->bound.right)
|
||||||
copy_region(second, dest);
|
CopyRegion(second, dest);
|
||||||
else {
|
else {
|
||||||
// Otherwise, we check the rect of the first region against the rects
|
// Otherwise, we check the rect of the first region against the rects
|
||||||
// of the second, and we add their intersections to the destination region
|
// 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++) {
|
for (long x = 0; x < second->count; x++) {
|
||||||
clipping_rect testRect = sect_rect(first->data[0], second->data[x]);
|
clipping_rect testRect = sect_rect(first->data[0], second->data[x]);
|
||||||
if (valid_rect(testRect))
|
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.
|
/*! \brief Modify the destination region to be the union of the two given regions.
|
||||||
\param first The first region to be or-ed.
|
\param first The first region to be or-ed.
|
||||||
\param second The second 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.
|
coordinate.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
append_region(BRegion *first, BRegion *second, BRegion *dest)
|
BRegion::Support::AppendRegion(BRegion *first, BRegion *second, BRegion *dest)
|
||||||
{
|
{
|
||||||
|
CALLED();
|
||||||
ASSERT(first);
|
ASSERT(first);
|
||||||
ASSERT(second);
|
ASSERT(second);
|
||||||
ASSERT(dest);
|
ASSERT(dest);
|
||||||
|
|
||||||
copy_region(first, dest);
|
CopyRegion(first, dest);
|
||||||
|
|
||||||
for (long c = 0; c < second->count; c++)
|
for (long c = 0; c < second->count; c++)
|
||||||
dest->_AddRect(second->data[c]);
|
dest->_AddRect(second->data[c]);
|
||||||
@@ -366,10 +503,15 @@ append_region(BRegion *first, BRegion *second, BRegion *dest)
|
|||||||
|
|
||||||
|
|
||||||
void
|
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];
|
CALLED();
|
||||||
int32 rights[kMaxPoints];
|
|
||||||
|
int32 stackLefts[kMaxPoints];
|
||||||
|
int32 stackRights[kMaxPoints];
|
||||||
|
|
||||||
|
int32 *lefts = stackLefts;
|
||||||
|
int32 *rights = stackRights;
|
||||||
|
|
||||||
long i1 = *indexA;
|
long i1 = *indexA;
|
||||||
long i2 = *indexB;
|
long i2 = *indexB;
|
||||||
@@ -380,6 +522,19 @@ r_or(long top, long bottom, BRegion *first, BRegion *second, BRegion *dest, long
|
|||||||
long foundCount = 0;
|
long foundCount = 0;
|
||||||
long x = 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
|
// Store left and right points to the appropriate array
|
||||||
for (x = i1; x < first->count; x++) {
|
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;
|
*indexB = i2;
|
||||||
|
|
||||||
if (foundCount > 1)
|
if (foundCount > 1)
|
||||||
sort_trans(lefts, rights, foundCount);
|
SortTrans(lefts, rights, foundCount);
|
||||||
|
|
||||||
ASSERT(foundCount > 0);
|
ASSERT(foundCount > 0);
|
||||||
|
|
||||||
@@ -440,7 +595,12 @@ r_or(long top, long bottom, BRegion *first, BRegion *second, BRegion *dest, long
|
|||||||
|
|
||||||
dest->_AddRect(rect);
|
dest->_AddRect(rect);
|
||||||
current = next;
|
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.
|
\param dest The destination region.
|
||||||
*/
|
*/
|
||||||
void
|
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;
|
long a = 0, b = 0;
|
||||||
|
|
||||||
int32 top;
|
int32 top;
|
||||||
@@ -482,11 +643,11 @@ or_region_complex(BRegion *first, BRegion *second, BRegion *dest)
|
|||||||
if (bottom >= kMaxVerticalExtent)
|
if (bottom >= kMaxVerticalExtent)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
r_or(top, bottom, first, second, dest, &a, &b);
|
ROr(top, bottom, first, second, dest, &a, &b);
|
||||||
|
|
||||||
} while (true);
|
} while (true);
|
||||||
|
|
||||||
cleanup_region(dest);
|
CleanupRegion(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -499,8 +660,9 @@ or_region_complex(BRegion *first, BRegion *second, BRegion *dest)
|
|||||||
one rect.
|
one rect.
|
||||||
*/
|
*/
|
||||||
void
|
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(first);
|
||||||
ASSERT(second);
|
ASSERT(second);
|
||||||
ASSERT(dest);
|
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.bottom >= second->bound.bottom
|
||||||
&& first->bound.left <= second->bound.left
|
&& first->bound.left <= second->bound.left
|
||||||
&& first->bound.right >= second->bound.right)
|
&& first->bound.right >= second->bound.right)
|
||||||
copy_region(first, dest);
|
CopyRegion(first, dest);
|
||||||
else
|
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.
|
This function is called by or_region when the two regions don't intersect.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
or_region_no_x(BRegion *first, BRegion *second, BRegion *dest)
|
BRegion::Support::OrRegionNoX(BRegion *first, BRegion *second, BRegion *dest)
|
||||||
{
|
{
|
||||||
|
CALLED();
|
||||||
ASSERT(first);
|
ASSERT(first);
|
||||||
ASSERT(second);
|
ASSERT(second);
|
||||||
ASSERT(dest);
|
ASSERT(dest);
|
||||||
|
|
||||||
zero_region(dest);
|
ZeroRegion(dest);
|
||||||
|
|
||||||
long x;
|
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
|
/*! \brief Divides the plane into horizontal bands, then passes those bands to r_sub
|
||||||
which does the real work.
|
which does the real work.
|
||||||
\param first The subtraend region.
|
\param first The subtraend region.
|
||||||
@@ -630,8 +740,9 @@ or_region(BRegion *first, BRegion *second, BRegion *dest)
|
|||||||
\param dest The destination region.
|
\param dest The destination region.
|
||||||
*/
|
*/
|
||||||
void
|
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;
|
long a = 0, b = 0;
|
||||||
|
|
||||||
int32 top;
|
int32 top;
|
||||||
@@ -661,22 +772,29 @@ sub_region_complex(BRegion *first, BRegion *second, BRegion *dest)
|
|||||||
if (bottom >= kMaxVerticalExtent)
|
if (bottom >= kMaxVerticalExtent)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
r_sub(top, bottom, first, second, dest, &a, &b);
|
RSub(top, bottom, first, second, dest, &a, &b);
|
||||||
|
|
||||||
} while (true);
|
} while (true);
|
||||||
|
|
||||||
cleanup_region(dest);
|
CleanupRegion(dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
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];
|
CALLED();
|
||||||
int32 rightsA[kMaxPoints / 2];
|
|
||||||
int32 leftsB[kMaxPoints / 2];
|
|
||||||
int32 rightsB[kMaxPoints / 2];
|
|
||||||
|
|
||||||
|
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 i1 = *indexA;
|
||||||
long i2 = *indexB;
|
long i2 = *indexB;
|
||||||
|
|
||||||
@@ -687,6 +805,22 @@ r_sub(long top, long bottom, BRegion *first, BRegion *second, BRegion *dest, lon
|
|||||||
long foundB = 0;
|
long foundB = 0;
|
||||||
long x = 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
|
// Store left and right points to the appropriate array
|
||||||
for (x = i1; x < first->count; x++) {
|
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;
|
*indexA = i1;
|
||||||
|
|
||||||
if (foundA > 1)
|
if (foundA > 1)
|
||||||
sort_trans(leftsA, rightsA, foundA);
|
SortTrans(leftsA, rightsA, foundA);
|
||||||
|
|
||||||
for (x = i2; x < second->count; x++) {
|
for (x = i2; x < second->count; x++) {
|
||||||
if (second->data[x].bottom >= top && *indexB == -1)
|
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;
|
*indexB = i2;
|
||||||
|
|
||||||
if (foundB > 1)
|
if (foundB > 1)
|
||||||
sort_trans(leftsB, rightsB, foundB);
|
SortTrans(leftsB, rightsB, foundB);
|
||||||
|
|
||||||
// No minuend's rect, just add all the subtraend's rects.
|
// No minuend's rect, just add all the subtraend's rects.
|
||||||
if (foundA == 0)
|
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.
|
#undef TRACE_REGION
|
||||||
\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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ INTERFACE_KIT_SOURCE =
|
|||||||
RadioButton.cpp
|
RadioButton.cpp
|
||||||
Rect.cpp
|
Rect.cpp
|
||||||
Region.cpp
|
Region.cpp
|
||||||
region_helpers.cpp
|
RegionSupport.cpp
|
||||||
ScrollBar.cpp
|
ScrollBar.cpp
|
||||||
StatusBar.cpp
|
StatusBar.cpp
|
||||||
StringView.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
|
|
||||||
Reference in New Issue
Block a user