2476 lines
98 KiB
C
2476 lines
98 KiB
C
|
//
|
||
|
// BA.C
|
||
|
// Bounds Accumulator
|
||
|
//
|
||
|
// Copyright(c) Microsoft 1997-
|
||
|
//
|
||
|
|
||
|
#include <as16.h>
|
||
|
|
||
|
|
||
|
//
|
||
|
// BA_DDProcessRequest()
|
||
|
// Handles BA escapes
|
||
|
//
|
||
|
|
||
|
|
||
|
BOOL BA_DDProcessRequest
|
||
|
(
|
||
|
UINT fnEscape,
|
||
|
LPOSI_ESCAPE_HEADER pResult,
|
||
|
DWORD cbResult
|
||
|
)
|
||
|
{
|
||
|
BOOL rc = TRUE;
|
||
|
LPBA_BOUNDS_INFO pBoundsInfo;
|
||
|
UINT i;
|
||
|
RECT rect;
|
||
|
|
||
|
DebugEntry(BA_DDProcessRequest);
|
||
|
|
||
|
switch (fnEscape)
|
||
|
{
|
||
|
case BA_ESC_GET_BOUNDS:
|
||
|
{
|
||
|
//
|
||
|
// The share core is calling us to get the current bounds
|
||
|
// (presumably to try to send them). While the share core is
|
||
|
// processing the bounds, we reset the bounds, but take a copy
|
||
|
// first to use for spoiling orders by SDA. When the share
|
||
|
// core has completed processing the bounds, it will call us
|
||
|
// again with a BA_ESC_RETURN_BOUNDS escape (even if it has
|
||
|
// sent all the bounds).
|
||
|
//
|
||
|
// So, we have to:
|
||
|
// - return the bounds to the share core
|
||
|
// - set up the spoiling rects to be these bounds
|
||
|
// - clear our main bounds.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// This will copy the current bounds to the caller's buffer and
|
||
|
// clear our current bounds.
|
||
|
// NOTE: We keep these in globals because the caller will shortly
|
||
|
// call us to return any unsent bounds rects.
|
||
|
//
|
||
|
BA_CopyBounds(g_baSpoilingRects, &g_baNumSpoilingRects, TRUE);
|
||
|
|
||
|
//
|
||
|
// Return the bounds info to the share core
|
||
|
//
|
||
|
if (g_baNumSpoilingRects)
|
||
|
{
|
||
|
TRACE_OUT(( "Returning %d rects to share core", g_baNumSpoilingRects));
|
||
|
}
|
||
|
|
||
|
pBoundsInfo = (LPBA_BOUNDS_INFO)pResult;
|
||
|
pBoundsInfo->numRects = g_baNumSpoilingRects;
|
||
|
|
||
|
for (i = 0; i < g_baNumSpoilingRects; i++)
|
||
|
{
|
||
|
RECT_TO_RECTL(&g_baSpoilingRects[i], &pBoundsInfo->rects[i]);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case BA_ESC_RETURN_BOUNDS:
|
||
|
{
|
||
|
//
|
||
|
// The share core has completed its processing of the bounds
|
||
|
// which we passed on the BA_ESC_GET_BOUNDS escape. We have to
|
||
|
// reset the spoiling rectangles and add any bounds which the
|
||
|
// share core failed to process into our current bounds.
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// To reset the spoiling bounds we just have to reset the
|
||
|
// number of bounds.
|
||
|
//
|
||
|
g_baNumSpoilingRects = 0;
|
||
|
|
||
|
//
|
||
|
// Now add the share core's bounds into our current bounds
|
||
|
//
|
||
|
pBoundsInfo = (LPBA_BOUNDS_INFO)pResult;
|
||
|
|
||
|
if (pBoundsInfo->numRects)
|
||
|
{
|
||
|
TRACE_OUT(( "Received %d rects from share core",
|
||
|
pBoundsInfo->numRects));
|
||
|
}
|
||
|
|
||
|
for (i = 0 ; i < pBoundsInfo->numRects ; i++)
|
||
|
{
|
||
|
RECTL_TO_RECT(&pBoundsInfo->rects[i], &rect);
|
||
|
|
||
|
TRACE_OUT(( "Rect %d, {%d, %d, %d, %d}",
|
||
|
i, rect.left, rect.top, rect.right, rect.bottom));
|
||
|
|
||
|
BA_AddScreenData(&rect);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
{
|
||
|
ERROR_OUT(( "Unrecognised BA escape"));
|
||
|
rc = FALSE;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
DebugExitBOOL(BA_DDProcessRequest, rc);
|
||
|
return(rc);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// BA_DDInit - see ba.h for description.
|
||
|
//
|
||
|
void BA_DDInit(void)
|
||
|
{
|
||
|
DebugEntry(BA_Init);
|
||
|
|
||
|
BA_ResetBounds();
|
||
|
|
||
|
DebugExitVOID(BA_Init);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// This gets a current version of our bound rect list, and clears it
|
||
|
// afterwards if requested.
|
||
|
//
|
||
|
void BA_CopyBounds
|
||
|
(
|
||
|
LPRECT pRects,
|
||
|
LPUINT pNumRects,
|
||
|
BOOL fReset
|
||
|
)
|
||
|
{
|
||
|
UINT i;
|
||
|
#ifdef DEBUG
|
||
|
UINT cRects = 0;
|
||
|
#endif
|
||
|
|
||
|
DebugEntry(BA_CopyBounds);
|
||
|
|
||
|
*pNumRects = g_baRectsUsed;
|
||
|
|
||
|
//
|
||
|
// A return with *pNumRects as zero is an OK return - it just says
|
||
|
// no bounds have been accumulated since the last call.
|
||
|
//
|
||
|
if ( *pNumRects != 0)
|
||
|
{
|
||
|
//
|
||
|
// We can return the bounds in any order - we don't care how we
|
||
|
// order the SDA rectangles.
|
||
|
//
|
||
|
// Also note that we must compare BA_NUM_RECTS + 1 sets of
|
||
|
// rectangles because that's the number actually used by the add
|
||
|
// rectangle code and while it guarantees that it will only use
|
||
|
// BA_NUM_RECTS rectangles, it does not guarantee that the last
|
||
|
// element in the array is the merge rectangle.
|
||
|
//
|
||
|
for (i = 0; i <= BA_NUM_RECTS; i++)
|
||
|
{
|
||
|
if (g_baBounds[i].InUse)
|
||
|
{
|
||
|
TRACE_OUT(("Found rect: {%04d,%04d,%04d,%04d}",
|
||
|
g_baBounds[i].Coord.left, g_baBounds[i].Coord.top,
|
||
|
g_baBounds[i].Coord.right, g_baBounds[i].Coord.bottom));
|
||
|
|
||
|
*pRects = g_baBounds[i].Coord;
|
||
|
pRects++;
|
||
|
#ifdef DEBUG
|
||
|
cRects++;
|
||
|
#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check for self-consistency
|
||
|
//
|
||
|
ASSERT(cRects == *pNumRects);
|
||
|
|
||
|
if (fReset)
|
||
|
BA_ResetBounds();
|
||
|
}
|
||
|
|
||
|
DebugExitVOID(BACopyBounds);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
//
|
||
|
// BA_AddScreenData(..)
|
||
|
//
|
||
|
// Adds the specified rectangle to the current Screen Data Area.
|
||
|
//
|
||
|
// Called by the GDI interception code for orders that it cannot send as
|
||
|
// orders.
|
||
|
//
|
||
|
// NOTE that the rectangle is inclusive coords
|
||
|
//
|
||
|
//
|
||
|
void BA_AddScreenData(LPRECT pRect)
|
||
|
{
|
||
|
RECT preRects[BA_NUM_RECTS];
|
||
|
RECT postRects[BA_NUM_RECTS];
|
||
|
UINT numPreRects;
|
||
|
UINT numPostRects;
|
||
|
UINT i;
|
||
|
|
||
|
DebugEntry(BA_AddScreenData);
|
||
|
|
||
|
//
|
||
|
// Check that the caller has passed a valid rectangle. If not, do a
|
||
|
// trace alert, and then return immediately (as an invalid rectangle
|
||
|
// shouldn't contribute to the accumulated bounds) - but report an OK
|
||
|
// return code, so we keep running.
|
||
|
//
|
||
|
if ((pRect->right < pRect->left) ||
|
||
|
(pRect->bottom < pRect->top) )
|
||
|
{
|
||
|
//
|
||
|
// NOTE: This will happen when the visrgn of a DC clips out the
|
||
|
// output, so the drawing bounds are empty, but the output
|
||
|
// 'succeeded'. BUT WE SHOULD NEVER GET A RECT THAT IS LESS THAN
|
||
|
// EMPTY--if so, it means the right/left or bottom/top coords got
|
||
|
// mistakenly flipped.
|
||
|
//
|
||
|
ASSERT(pRect->right >= pRect->left-1);
|
||
|
ASSERT(pRect->bottom >= pRect->top-1);
|
||
|
DC_QUIT;
|
||
|
}
|
||
|
|
||
|
if ((g_oaFlow == OAFLOW_SLOW) && g_baSpoilByNewSDAEnabled)
|
||
|
{
|
||
|
//
|
||
|
// We are spoiling existing orders by new SDA, so query the current
|
||
|
// bounds.
|
||
|
//
|
||
|
BA_CopyBounds(preRects, &numPreRects, FALSE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Add the rect to the bounds.
|
||
|
//
|
||
|
if (BAAddRect(pRect, 0))
|
||
|
{
|
||
|
if ((pRect->right > pRect->left) && (pRect->bottom > pRect->top))
|
||
|
{
|
||
|
LPBA_FAST_DATA lpbaFast;
|
||
|
|
||
|
lpbaFast = BA_FST_START_WRITING;
|
||
|
|
||
|
SHM_CheckPointer(lpbaFast);
|
||
|
lpbaFast->totalSDA += COM_SizeOfRectInclusive(pRect);
|
||
|
|
||
|
TRACE_OUT(("Added rect to bounds, giving %ld of SD", lpbaFast->totalSDA));
|
||
|
|
||
|
//
|
||
|
// This is where the Win95 product would make a call to
|
||
|
// DCS_TriggerEarlyTimer
|
||
|
//
|
||
|
|
||
|
BA_FST_STOP_WRITING;
|
||
|
}
|
||
|
|
||
|
if ((g_oaFlow == OAFLOW_SLOW) && g_baSpoilByNewSDAEnabled)
|
||
|
{
|
||
|
//
|
||
|
// Adding the new rectangle changed the existing bounds so
|
||
|
// query the new bounds
|
||
|
//
|
||
|
BA_CopyBounds(postRects, &numPostRects, FALSE);
|
||
|
|
||
|
//
|
||
|
// Try to spoil existing orders using each of the rectangles
|
||
|
// which have changed.
|
||
|
//
|
||
|
for (i = 0; i < numPostRects; i++)
|
||
|
{
|
||
|
if ( (i > numPreRects) ||
|
||
|
(postRects[i].left != preRects[i].left) ||
|
||
|
(postRects[i].right != preRects[i].right) ||
|
||
|
(postRects[i].top != preRects[i].top) ||
|
||
|
(postRects[i].bottom != preRects[i].bottom) )
|
||
|
{
|
||
|
OA_DDSpoilOrdersByRect(&postRects[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
DC_EXIT_POINT:
|
||
|
DebugExitVOID(BA_AddScreenData);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
//
|
||
|
// BA_QuerySpoilingBounds() - see ba.h
|
||
|
//
|
||
|
//
|
||
|
void BA_QuerySpoilingBounds(LPRECT pRects, LPUINT pNumRects)
|
||
|
{
|
||
|
DebugEntry(BA_QuerySpoilingBounds);
|
||
|
|
||
|
//
|
||
|
// Just have to return the number of spoiling rectangles, and the
|
||
|
// rectangles themselves. No rectangles is perfectly valid.
|
||
|
//
|
||
|
TRACE_OUT(( "Num rects %d", g_baNumSpoilingRects));
|
||
|
|
||
|
*pNumRects = g_baNumSpoilingRects;
|
||
|
hmemcpy(pRects, g_baSpoilingRects, g_baNumSpoilingRects*sizeof(RECT));
|
||
|
|
||
|
DebugExitVOID(BA_QuerySpoilingBounds);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void BA_ResetBounds(void)
|
||
|
{
|
||
|
UINT i;
|
||
|
|
||
|
DebugEntry(BA_ResetBounds);
|
||
|
|
||
|
//
|
||
|
// Clear the bounds - reset the number we are using, mark all slots as
|
||
|
// free, and clean the list.
|
||
|
//
|
||
|
for ( i = 0; i <= BA_NUM_RECTS; i++ )
|
||
|
{
|
||
|
g_baBounds[i].InUse = FALSE;
|
||
|
g_baBounds[i].iNext = BA_INVALID_RECT_INDEX;
|
||
|
}
|
||
|
|
||
|
g_baFirstRect = BA_INVALID_RECT_INDEX;
|
||
|
g_baLastRect = BA_INVALID_RECT_INDEX;
|
||
|
g_baRectsUsed = 0;
|
||
|
|
||
|
DebugExitVOID(BA_ResetBounds);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Name: BAOverlap
|
||
|
//
|
||
|
// Description: Detects overlap between two rectangles.
|
||
|
//
|
||
|
// - check for no overlap using loose test that lets through
|
||
|
// adjacent/overlapping merges
|
||
|
// - check for adjacent/overlapping merges
|
||
|
// - check for no overlap (using strict test)
|
||
|
// - use outcodes to check internal edge cases
|
||
|
// - use outcodes to check external edge cases
|
||
|
//
|
||
|
// If at each stage the check detects that the two rectangles
|
||
|
// meet the criteria, the function returns the appropriate
|
||
|
// return or outcode combination.
|
||
|
//
|
||
|
// Note that all rectangle coordinates are inclusive, ie
|
||
|
// a rectangle of 0,0,0,0 has an area of 1 pel.
|
||
|
//
|
||
|
// This function does not alter either of the rectangles.
|
||
|
//
|
||
|
// Params (IN): pRect1 - first rectangle
|
||
|
// pRect2 - second rectangle
|
||
|
//
|
||
|
// Returns: One of the overlap return codes or outcode combinations
|
||
|
// defined above.
|
||
|
//
|
||
|
//
|
||
|
int BAOverlap(LPRECT pRect1, LPRECT pRect2 )
|
||
|
{
|
||
|
int ExternalEdges;
|
||
|
int ExternalCount;
|
||
|
int InternalEdges;
|
||
|
int InternalCount;
|
||
|
|
||
|
//
|
||
|
// Check for no overlap.
|
||
|
//
|
||
|
// Note that this test is looser than strict no overlap, and will let
|
||
|
// through rectangles that do not overlap, but just abutt by one pel -
|
||
|
// so that we get a chance to detect adjacent merges.
|
||
|
//
|
||
|
// So (for example) for the following:
|
||
|
//
|
||
|
// - it detects no overlap when there is at least 1 pel between rects
|
||
|
//
|
||
|
// 10,10 52,10
|
||
|
// +----------++----------+
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | Rect 1 || Rect 2 |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// +----------++----------+
|
||
|
// 50,50 100,50
|
||
|
//
|
||
|
// - it allows rectangles through when they abutt and are mergable
|
||
|
//
|
||
|
// 10,10 51,10
|
||
|
// +----------++----------+
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | Rect 1 || Rect 2 |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// +----------++----------+
|
||
|
// 50,50 100,50
|
||
|
//
|
||
|
// - it allows rectangles through when they abutt, even where they are
|
||
|
// not mergable
|
||
|
//
|
||
|
// 10,10
|
||
|
// +----------+51,15
|
||
|
// | |+----------+
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | Rect 1 || |
|
||
|
// | || Rect 2 |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// +----------+| |
|
||
|
// 50,50+----------+
|
||
|
// 100,55
|
||
|
//
|
||
|
// - it allows rectangles through when they overlap in some way
|
||
|
//
|
||
|
// 40,0
|
||
|
// +------------+
|
||
|
// 10,10 | |
|
||
|
// +-------+--+ |
|
||
|
// | | | |
|
||
|
// | | | Rect 2 |
|
||
|
// | | | |
|
||
|
// |Rect 1 | | |
|
||
|
// | | | |
|
||
|
// | +--+---------+
|
||
|
// | | 90,40
|
||
|
// +----------+
|
||
|
// 50,50
|
||
|
//
|
||
|
//
|
||
|
if (!((pRect1->left <= pRect2->right + 1) &&
|
||
|
(pRect1->top <= pRect2->bottom + 1) &&
|
||
|
(pRect1->right >= pRect2->left - 1) &&
|
||
|
(pRect1->bottom >= pRect2->top - 1) ))
|
||
|
{
|
||
|
return(OL_NONE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check for adjoining/overlapping rectangles which can be merged.
|
||
|
//
|
||
|
// These tests detect (for example for the XMAX variant), where:
|
||
|
//
|
||
|
// - the rectangles abutt and can be merged
|
||
|
//
|
||
|
// 10,10 51,10
|
||
|
// +----------++----------+
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | Rect 1 || Rect 2 |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// +----------++----------+
|
||
|
// 50,50 100,50
|
||
|
//
|
||
|
// - the rectangles overlap and can be merged
|
||
|
//
|
||
|
// 10,10 40,10
|
||
|
// +-------+--+------+
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// |Rect 1 | |Rect 2|
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// +-------+--+------+
|
||
|
// 50,50 90,50
|
||
|
//
|
||
|
// - the rectangles abutt and cannot be merged - this case is detected
|
||
|
// by the strict overlap case below
|
||
|
//
|
||
|
// 10,10
|
||
|
// +----------+51,15
|
||
|
// | |+----------+
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | Rect 1 || |
|
||
|
// | || Rect 2 |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// +----------+| |
|
||
|
// 50,50+----------+
|
||
|
// 100,55
|
||
|
//
|
||
|
// - the rectangles overlap and cannot be merged - this case is
|
||
|
// detected by the outcode tests below
|
||
|
//
|
||
|
// 40,0
|
||
|
// +------------+
|
||
|
// 10,10 | |
|
||
|
// +-------+--+ |
|
||
|
// | | | |
|
||
|
// | | | Rect 2 |
|
||
|
// | | | |
|
||
|
// |Rect 1 | | |
|
||
|
// | | | |
|
||
|
// | +--+---------+
|
||
|
// | | 90,40
|
||
|
// +----------+
|
||
|
// 50,50
|
||
|
//
|
||
|
// - rectangle 2 is enclosed in rectangle 1 and should not be merged -
|
||
|
// this case is detected by the outcode tests below.
|
||
|
//
|
||
|
// 10,10 40,10
|
||
|
// +-------+------+-----+
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// |Rect 1 |Rect 2| |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// +-------+------+-----+
|
||
|
// 60,50 90,50
|
||
|
// Rect2 Rect1
|
||
|
//
|
||
|
//
|
||
|
if ( (pRect1->left <= pRect2->right + 1) &&
|
||
|
(pRect1->left > pRect2->left ) &&
|
||
|
(pRect1->right > pRect2->right ) &&
|
||
|
(pRect1->top == pRect2->top ) &&
|
||
|
(pRect1->bottom == pRect2->bottom ) )
|
||
|
{
|
||
|
return(OL_MERGE_XMIN);
|
||
|
}
|
||
|
|
||
|
if ( (pRect1->top <= pRect2->bottom + 1) &&
|
||
|
(pRect1->top > pRect2->top ) &&
|
||
|
(pRect1->bottom > pRect2->bottom ) &&
|
||
|
(pRect1->left == pRect2->left ) &&
|
||
|
(pRect1->right == pRect2->right ) )
|
||
|
{
|
||
|
return(OL_MERGE_YMIN);
|
||
|
}
|
||
|
|
||
|
if ( (pRect1->right >= pRect2->left - 1) &&
|
||
|
(pRect1->right < pRect2->right ) &&
|
||
|
(pRect1->left < pRect2->left ) &&
|
||
|
(pRect1->top == pRect2->top ) &&
|
||
|
(pRect1->bottom == pRect2->bottom ) )
|
||
|
{
|
||
|
return(OL_MERGE_XMAX);
|
||
|
}
|
||
|
|
||
|
if ( (pRect1->bottom >= pRect2->top - 1) &&
|
||
|
(pRect1->bottom < pRect2->bottom ) &&
|
||
|
(pRect1->top < pRect2->top ) &&
|
||
|
(pRect1->left == pRect2->left ) &&
|
||
|
(pRect1->right == pRect2->right ) )
|
||
|
{
|
||
|
return(OL_MERGE_YMAX);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check for no overlap.
|
||
|
// Note that this test is a stricter version than the earlier one, so
|
||
|
// that we now only continue testing rectangles that do genuinely
|
||
|
// overlap.
|
||
|
//
|
||
|
if (!((pRect1->left <= pRect2->right) &&
|
||
|
(pRect1->top <= pRect2->bottom) &&
|
||
|
(pRect1->right >= pRect2->left) &&
|
||
|
(pRect1->bottom >= pRect2->top) ))
|
||
|
{
|
||
|
return(OL_NONE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Use outcodes for Internal edge cases, as follows:
|
||
|
//
|
||
|
// EE_XMIN - rect1 xmin is enclosed within rect2
|
||
|
// EE_YMIN - rect1 ymin is enclosed within rect2
|
||
|
// EE_XMAX - rect1 xmax is enclosed within rect2
|
||
|
// EE_YMAX - rect1 ymax is enclosed within rect2
|
||
|
//
|
||
|
// If 3 or more bits are set then rect1 is enclosed either partially or
|
||
|
// completely within rect2 as follows (see individual switch cases for
|
||
|
// diagrams).
|
||
|
//
|
||
|
// OL_ENCLOSED = EE_XMIN | EE_YMIN | EE_XMAX | EE_YMAX
|
||
|
// OL_PART_ENCLOSED_XMIN = EE_XMIN | EE_YMIN | EE_YMAX
|
||
|
// OL_PART_ENCLOSED_YMIN = EE_XMIN | EE_YMIN | EE_XMAX
|
||
|
// OL_PART_ENCLOSED_XMAX = EE_YMIN | EE_XMAX | EE_YMAX
|
||
|
// OL_PART_ENCLOSED_YMAX = EE_XMIN | EE_XMAX | EE_YMAX
|
||
|
//
|
||
|
// In practice, if 3 or more bits are set, the negative of the outcode
|
||
|
// value is retruned to ensure that it is distinct from the external
|
||
|
// edge outcode returns (see below).
|
||
|
//
|
||
|
//
|
||
|
InternalCount = 0;
|
||
|
InternalEdges = 0;
|
||
|
if ( pRect1->left >= pRect2->left && pRect1->left <= pRect2->right)
|
||
|
{
|
||
|
InternalEdges |= EE_XMIN;
|
||
|
InternalCount ++;
|
||
|
}
|
||
|
if ( pRect1->top >= pRect2->top && pRect1->top <= pRect2->bottom)
|
||
|
{
|
||
|
InternalEdges |= EE_YMIN;
|
||
|
InternalCount ++;
|
||
|
}
|
||
|
if ( pRect1->right >= pRect2->left && pRect1->right <= pRect2->right)
|
||
|
{
|
||
|
InternalEdges |= EE_XMAX;
|
||
|
InternalCount ++;
|
||
|
}
|
||
|
if ( pRect1->bottom >= pRect2->top && pRect1->bottom <= pRect2->bottom)
|
||
|
{
|
||
|
InternalEdges |= EE_YMAX;
|
||
|
InternalCount ++;
|
||
|
}
|
||
|
|
||
|
if ( InternalCount >= 3)
|
||
|
{
|
||
|
return(-InternalEdges);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Use outcodes for External edge cases as follows.
|
||
|
//
|
||
|
// EE_XMIN - rect1 xmin is left of rect2 xmin
|
||
|
// EE_YMIN - rect1 ymin is above rect2 ymin
|
||
|
// EE_XMAX - rect1 xmax is right of rect2 xmax
|
||
|
// EE_YMAX - rect1 ymax is below rect2 ymax
|
||
|
//
|
||
|
// These are the classic "line" outcodes.
|
||
|
//
|
||
|
// If 2 or more bits are set then rect1 overlaps rect2 as follows (see
|
||
|
// individual switch cases for diagrams).
|
||
|
//
|
||
|
// OL_ENCLOSES = EE_XMIN | EE_YMIN | EE_XMAX | EE_YMAX
|
||
|
// OL_PART_ENCLOSES_XMIN = EE_YMIN | EE_XMAX | EE_YMAX
|
||
|
// OL_PART_ENCLOSES_XMAX = EE_XMIN | EE_YMIN | EE_YMAX
|
||
|
// OL_PART_ENCLOSES_YMIN = EE_XMIN | EE_XMAX | EE_YMAX
|
||
|
// OL_PART_ENCLOSES_YMAX = EE_XMIN | EE_YMIN | EE_XMAX
|
||
|
// OL_SPLIT_X = EE_YMIN | EE_YMAX
|
||
|
// OL_SPLIT_Y = EE_XMIN | EE_XMAX
|
||
|
// OL_SPLIT_XMIN_YMIN = EE_XMAX | EE_YMAX
|
||
|
// OL_SPLIT_XMAX_YMIN = EE_XMIN | EE_YMAX
|
||
|
// OL_SPLIT_XMIN_YMAX = EE_YMIN | EE_XMAX
|
||
|
// OL_SPLIT_XMAX_YMAX = EE_XMIN | EE_YMIN
|
||
|
//
|
||
|
// The accumulated outcode value is returned.
|
||
|
//
|
||
|
//
|
||
|
ExternalEdges = 0;
|
||
|
ExternalCount = 0;
|
||
|
if ( pRect1->left <= pRect2->left )
|
||
|
{
|
||
|
ExternalEdges |= EE_XMIN;
|
||
|
ExternalCount ++;
|
||
|
}
|
||
|
if ( pRect1->top <= pRect2->top )
|
||
|
{
|
||
|
ExternalEdges |= EE_YMIN;
|
||
|
ExternalCount ++;
|
||
|
}
|
||
|
if ( pRect1->right >= pRect2->right )
|
||
|
{
|
||
|
ExternalEdges |= EE_XMAX;
|
||
|
ExternalCount ++;
|
||
|
}
|
||
|
if ( pRect1->bottom >= pRect2->bottom )
|
||
|
{
|
||
|
ExternalEdges |= EE_YMAX;
|
||
|
ExternalCount ++;
|
||
|
}
|
||
|
if (ExternalCount >= 2)
|
||
|
{
|
||
|
return(ExternalEdges);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If get here then we failed to detect a valid case.
|
||
|
//
|
||
|
WARNING_OUT(( "Unrecognised Overlap: (%d,%d,%d,%d),(%d,%d,%d,%d)",
|
||
|
pRect1->left, pRect1->top, pRect1->right, pRect1->bottom,
|
||
|
pRect2->left, pRect2->top, pRect2->right, pRect2->bottom ));
|
||
|
return(OL_NONE);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Name: BAAddRectList
|
||
|
//
|
||
|
// Description: Adds a rectangle to the list of accumulated rectangles.
|
||
|
//
|
||
|
// - find a free slot in the array
|
||
|
// - add slot record to list
|
||
|
// - fill slot record with rect and mark as in use.
|
||
|
//
|
||
|
// Params (IN): pRect - rectangle to add
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
//
|
||
|
void BAAddRectList(LPRECT pRect)
|
||
|
{
|
||
|
UINT i;
|
||
|
BOOL fFoundFreeSlot;
|
||
|
|
||
|
DebugEntry(BAAddRectList);
|
||
|
|
||
|
//
|
||
|
// Find a free slot in the array. Note that the loop searches to
|
||
|
// BA_NUM_RECTS+1, because:
|
||
|
//
|
||
|
// - the array is defined as having one more slot than BA_NUM_RECTS
|
||
|
//
|
||
|
// - we may need to add a rect in that slot when BA_NUM_RECTS are
|
||
|
// in use prior to a forced merge.
|
||
|
//
|
||
|
fFoundFreeSlot = FALSE;
|
||
|
for ( i = 0; i <= BA_NUM_RECTS; i++ )
|
||
|
{
|
||
|
if (!g_baBounds[i].InUse)
|
||
|
{
|
||
|
fFoundFreeSlot = TRUE;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!fFoundFreeSlot)
|
||
|
{
|
||
|
WARNING_OUT(( "No space in array for rect (%d,%d,%d,%d)",
|
||
|
pRect->left,
|
||
|
pRect->top,
|
||
|
pRect->right,
|
||
|
pRect->bottom));
|
||
|
|
||
|
for ( i = 0; i <= BA_NUM_RECTS; i++ )
|
||
|
{
|
||
|
WARNING_OUT((
|
||
|
"Entry %i:Next(%lx),(%d,%d,%d,%d),Index(%d),InUse(%d)",
|
||
|
g_baBounds[i].iNext,
|
||
|
g_baBounds[i].Coord.left,
|
||
|
g_baBounds[i].Coord.top,
|
||
|
g_baBounds[i].Coord.right,
|
||
|
g_baBounds[i].Coord.bottom,
|
||
|
i,
|
||
|
g_baBounds[i].InUse));
|
||
|
}
|
||
|
|
||
|
DC_QUIT;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If first rect, then set up list.
|
||
|
// If not, add to tail of list.
|
||
|
//
|
||
|
if (g_baRectsUsed == 0)
|
||
|
{
|
||
|
g_baFirstRect = i;
|
||
|
g_baLastRect = i;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_baBounds[g_baLastRect].iNext = i;
|
||
|
g_baLastRect = i;
|
||
|
}
|
||
|
g_baBounds[i].iNext = BA_INVALID_RECT_INDEX;
|
||
|
|
||
|
//
|
||
|
// Fill in slot and mark as in use.
|
||
|
//
|
||
|
g_baBounds[i].InUse = TRUE;
|
||
|
g_baBounds[i].Coord = *pRect;
|
||
|
|
||
|
//
|
||
|
// Increment number of rectangles.
|
||
|
//
|
||
|
TRACE_OUT(( "Add Rect : ix - %d, (%d,%d,%d,%d)", i,
|
||
|
pRect->left,pRect->top,pRect->right,pRect->bottom));
|
||
|
g_baRectsUsed++;
|
||
|
|
||
|
DC_EXIT_POINT:
|
||
|
DebugExitVOID(BAAddRectList);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Name: BA_RemoveRectList
|
||
|
//
|
||
|
// Description: Removes a rectangle from the list of accumulated
|
||
|
// rectangles.
|
||
|
//
|
||
|
// - find the rectangle in the list
|
||
|
// - unlink it from the list and mark the slot as free
|
||
|
//
|
||
|
// Params (IN): pRect - rectangle to remove
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
//
|
||
|
void BA_RemoveRectList(LPRECT pRect)
|
||
|
{
|
||
|
UINT i;
|
||
|
UINT j;
|
||
|
|
||
|
DebugEntry(BA_RemoveRectList);
|
||
|
|
||
|
//
|
||
|
// If rectangle to remove is first...
|
||
|
// Remove it by adjusting first pointer and mark as free.
|
||
|
// Note that the check for tail adjustment has to be done before we
|
||
|
// change first.
|
||
|
//
|
||
|
if ( g_baBounds[g_baFirstRect].Coord.left == pRect->left &&
|
||
|
g_baBounds[g_baFirstRect].Coord.top == pRect->top &&
|
||
|
g_baBounds[g_baFirstRect].Coord.right == pRect->right &&
|
||
|
g_baBounds[g_baFirstRect].Coord.bottom == pRect->bottom )
|
||
|
{
|
||
|
TRACE_OUT(( "Remove first"));
|
||
|
if (g_baFirstRect == g_baLastRect)
|
||
|
{
|
||
|
g_baLastRect = BA_INVALID_RECT_INDEX;
|
||
|
}
|
||
|
g_baBounds[g_baFirstRect].InUse = FALSE;
|
||
|
g_baFirstRect = g_baBounds[g_baFirstRect].iNext;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If rectangle to remove is not first...
|
||
|
// Find it in list, remove it by adjusting previous pointer and mark it
|
||
|
// as free.
|
||
|
// Note that the check for tail adjustment has to be done before we
|
||
|
// change the previous pointer.
|
||
|
//
|
||
|
else
|
||
|
{
|
||
|
TRACE_OUT(( "Remove not first"));
|
||
|
for ( j = g_baFirstRect;
|
||
|
g_baBounds[j].iNext != BA_INVALID_RECT_INDEX;
|
||
|
j = g_baBounds[j].iNext )
|
||
|
{
|
||
|
if ( (g_baBounds[g_baBounds[j].iNext].Coord.left == pRect->left) &&
|
||
|
(g_baBounds[g_baBounds[j].iNext].Coord.top == pRect->top) &&
|
||
|
(g_baBounds[g_baBounds[j].iNext].Coord.right == pRect->right) &&
|
||
|
(g_baBounds[g_baBounds[j].iNext].Coord.bottom == pRect->bottom) )
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (j == BA_INVALID_RECT_INDEX)
|
||
|
{
|
||
|
WARNING_OUT(( "Couldn't remove rect (%d,%d,%d,%d)",
|
||
|
pRect->left,
|
||
|
pRect->top,
|
||
|
pRect->right,
|
||
|
pRect->bottom ));
|
||
|
|
||
|
for ( i = 0; i <= BA_NUM_RECTS; i++ )
|
||
|
{
|
||
|
WARNING_OUT((
|
||
|
"Entry %i:Next(%lx),(%d,%d,%d,%d),Index(%d),InUse(%d)",
|
||
|
g_baBounds[i].iNext,
|
||
|
g_baBounds[i].Coord.left,
|
||
|
g_baBounds[i].Coord.top,
|
||
|
g_baBounds[i].Coord.right,
|
||
|
g_baBounds[i].Coord.bottom,
|
||
|
i,
|
||
|
g_baBounds[i].InUse));
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (g_baBounds[j].iNext == g_baLastRect )
|
||
|
{
|
||
|
g_baLastRect = j;
|
||
|
}
|
||
|
g_baBounds[g_baBounds[j].iNext].InUse = FALSE;
|
||
|
g_baBounds[j].iNext = g_baBounds[g_baBounds[j].iNext].iNext;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// One less rect...
|
||
|
//
|
||
|
g_baRectsUsed--;
|
||
|
DebugExitVOID(BA_RemoveRectList);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Name: BAAddRect
|
||
|
//
|
||
|
// Description: Accumulates rectangles.
|
||
|
//
|
||
|
// This is a complex routine, with the essential algorithm
|
||
|
// as follows.
|
||
|
//
|
||
|
// - Start with the supplied rectangle as the candidate
|
||
|
// rectangle.
|
||
|
//
|
||
|
// - Compare the candidate against each of the existing
|
||
|
// accumulated rectangles.
|
||
|
//
|
||
|
// - If some form of overlap is detected between the
|
||
|
// candidate and an existing rectangle, this may result in
|
||
|
// one of the following (see the cases of the switch for
|
||
|
// details):
|
||
|
//
|
||
|
// - adjust the candidate or the existing rectangle or both
|
||
|
// - merge the candidate into the existing rectangle
|
||
|
// - discard the candidate as it is enclosed by an existing
|
||
|
// rectangle.
|
||
|
//
|
||
|
// - If the merge or adjustment results in a changed
|
||
|
// candidate, restart the comparisons from the beginning of
|
||
|
// the list with the changed candidate.
|
||
|
//
|
||
|
// - If the adjustment results in a split (giving two
|
||
|
// candidate rectangles), invoke this routine recursively
|
||
|
// with one of the two candidates as its candidate.
|
||
|
//
|
||
|
// - If no overlap is detected against the existing rectangles,
|
||
|
// add the candidate to the list of accumulated rectangles.
|
||
|
//
|
||
|
// - If the add results in more than BA_NUM_RECTS
|
||
|
// accumulated rectangles, do a forced merge of two of the
|
||
|
// accumulate rectangles (which include the newly added
|
||
|
// candidate) - choosing the two rectangles where the merged
|
||
|
// rectangle results in the smallest increase in area over
|
||
|
// the two non-merged rectangles.
|
||
|
//
|
||
|
// - After a forced merge, restart the comparisons from the
|
||
|
// beginning of the list with the newly merged rectangle as
|
||
|
// the candidate.
|
||
|
//
|
||
|
// For a particular call, this process will continue until
|
||
|
// the candidate (whether the supplied rectangle, an adjusted
|
||
|
// version of that rectangle, or a merged rectangle):
|
||
|
//
|
||
|
// - does not find an overlap among the rectangles in the list
|
||
|
// and does not cause a forced merge
|
||
|
// - is discarded becuase it is enclosed within one of the
|
||
|
// rectangles in the list.
|
||
|
//
|
||
|
// Note that all rectangle coordinates are inclusive, ie
|
||
|
// a rectangle of 0,0,0,0 has an area of 1 pel.
|
||
|
//
|
||
|
// Params (IN): pCand - new candidate rectangle
|
||
|
// level - recursion level
|
||
|
//
|
||
|
// Returns: TRUE if rectandle was spoilt due to a complete overlap.
|
||
|
//
|
||
|
//
|
||
|
BOOL BAAddRect
|
||
|
(
|
||
|
LPRECT pCand,
|
||
|
int level
|
||
|
)
|
||
|
{
|
||
|
LONG bestMergeIncrease;
|
||
|
LONG mergeIncrease;
|
||
|
UINT iBestMerge1;
|
||
|
UINT iBestMerge2;
|
||
|
UINT iExist;
|
||
|
UINT iTmp;
|
||
|
BOOL fRectToAdd;
|
||
|
BOOL fRectMerged;
|
||
|
BOOL fResetRects;
|
||
|
RECT rectNew;
|
||
|
UINT iLastMerge;
|
||
|
int OverlapType;
|
||
|
BOOL rc = TRUE;
|
||
|
|
||
|
DebugEntry(BAAddRect);
|
||
|
|
||
|
//
|
||
|
// Increase the level count in case we recurse.
|
||
|
//
|
||
|
level++;
|
||
|
|
||
|
//
|
||
|
// Start off by assuming the candidate rectangle will be added to the
|
||
|
// accumulated list of rectangles, and that no merges will occur.
|
||
|
//
|
||
|
fRectToAdd = TRUE;
|
||
|
fRectMerged = FALSE;
|
||
|
|
||
|
//
|
||
|
// Loop until no merges occur.
|
||
|
//
|
||
|
do
|
||
|
{
|
||
|
TRACE_OUT(( "Candidate rect: (%d,%d,%d,%d)",
|
||
|
pCand->left,pCand->top,pCand->right,pCand->bottom));
|
||
|
|
||
|
//
|
||
|
// Compare the current candidate rectangle against the rectangles
|
||
|
// in the current accumulated list.
|
||
|
//
|
||
|
iExist = g_baFirstRect;
|
||
|
|
||
|
while (iExist != BA_INVALID_RECT_INDEX)
|
||
|
{
|
||
|
//
|
||
|
// Assume that the comparisons will run through the whole list.
|
||
|
//
|
||
|
fResetRects = FALSE;
|
||
|
|
||
|
//
|
||
|
// If the candidate and the existing rectangle are the same
|
||
|
// then ignore. This occurs when an existing rectangle is
|
||
|
// replaced by a candidate and the comparisons are restarted
|
||
|
// from the front of the list - whereupon at some point the
|
||
|
// candidate will be compared with itself.
|
||
|
//
|
||
|
if ( &g_baBounds[iExist].Coord == pCand )
|
||
|
{
|
||
|
iExist = g_baBounds[iExist].iNext;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Switch on the overlap type (see Overlap routine).
|
||
|
//
|
||
|
OverlapType = BAOverlap(&(g_baBounds[iExist].Coord), pCand);
|
||
|
switch (OverlapType)
|
||
|
{
|
||
|
|
||
|
case OL_NONE:
|
||
|
//
|
||
|
// No overlap.
|
||
|
//
|
||
|
break;
|
||
|
|
||
|
case OL_MERGE_XMIN:
|
||
|
//
|
||
|
// - either the candidate abutts the existing rectangle
|
||
|
// on the left
|
||
|
//
|
||
|
// 10,10 51,10
|
||
|
// +----------++----------+
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | Cand || Exist |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// +----------++----------+
|
||
|
// 50,50 100,50
|
||
|
//
|
||
|
// - or the candidate overlaps the existing on the left
|
||
|
// and can be merged
|
||
|
//
|
||
|
// 10,10 40,10
|
||
|
// +-------+--+------+
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | Cand | |Exist |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// +-------+--+------+
|
||
|
// 50,50 90,50
|
||
|
//
|
||
|
// If the candidate is the original, merge the
|
||
|
// candidate into the existing, and make the existing
|
||
|
// the new candidate.
|
||
|
//
|
||
|
// If this is a merge of two existing rectangles (ie
|
||
|
// the candidate is the result of a merge), merge the
|
||
|
// overlapping existing into the candidate (the last
|
||
|
// merged) and remove the existing.
|
||
|
//
|
||
|
// For both, start the comparisons again with the new
|
||
|
// candidate.
|
||
|
//
|
||
|
if ( fRectToAdd )
|
||
|
{
|
||
|
g_baBounds[iExist].Coord.left = pCand->left;
|
||
|
pCand = &(g_baBounds[iExist].Coord);
|
||
|
fRectToAdd = FALSE;
|
||
|
iLastMerge = iExist;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pCand->right = g_baBounds[iExist].Coord.right;
|
||
|
BA_RemoveRectList(&(g_baBounds[iExist].Coord));
|
||
|
}
|
||
|
|
||
|
fResetRects = TRUE;
|
||
|
break;
|
||
|
|
||
|
|
||
|
case OL_MERGE_XMAX:
|
||
|
//
|
||
|
// - either the candidate abutts the existing rectangle
|
||
|
// on the right
|
||
|
//
|
||
|
// 10,10 51,10
|
||
|
// +----------++----------+
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | Exist || Cand |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// | || |
|
||
|
// +----------++----------+
|
||
|
// 50,50 100,50
|
||
|
//
|
||
|
// - or the candidate overlaps the existing on the right
|
||
|
// and can be merged
|
||
|
//
|
||
|
// 10,10 40,10
|
||
|
// +-------+--+------+
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | Exist | | Cand |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// +-------+--+------+
|
||
|
// 50,50 90,50
|
||
|
//
|
||
|
// If the candidate is the original, merge the
|
||
|
// candidate into the existing, and make the existing
|
||
|
// the new candidate.
|
||
|
//
|
||
|
// If this is a merge of two existing rectangles (ie
|
||
|
// the candidate is the result of a merge), merge the
|
||
|
// overlapping existing into the candidate (the last
|
||
|
// merged) and remove the existing.
|
||
|
//
|
||
|
// For both, start the comparisons again with the new
|
||
|
// candidate.
|
||
|
//
|
||
|
if ( fRectToAdd )
|
||
|
{
|
||
|
g_baBounds[iExist].Coord.right = pCand->right;
|
||
|
pCand = &(g_baBounds[iExist].Coord);
|
||
|
fRectToAdd = FALSE;
|
||
|
iLastMerge = iExist;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pCand->left = g_baBounds[iExist].Coord.left;
|
||
|
BA_RemoveRectList(&(g_baBounds[iExist].Coord));
|
||
|
}
|
||
|
|
||
|
fResetRects = TRUE;
|
||
|
break;
|
||
|
|
||
|
case OL_MERGE_YMIN:
|
||
|
//
|
||
|
// - either the candidate abutts the existing rectangle
|
||
|
// on the top
|
||
|
//
|
||
|
// 10,10
|
||
|
// +---------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | Cand |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// +---------+50,50
|
||
|
// 10,51+---------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | Exist |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// +---------+50,100
|
||
|
//
|
||
|
// - or the candidate overlaps the existing on the top
|
||
|
// and can be merged
|
||
|
//
|
||
|
// 10,10
|
||
|
// +---------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | Cand |
|
||
|
// | |
|
||
|
// | |
|
||
|
// Exist 10,40+---------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// +---------+50,60 Cand
|
||
|
// | |
|
||
|
// | Exist |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// +---------+50,100
|
||
|
//
|
||
|
// If the candidate is the original, merge the
|
||
|
// candidate into the existing, and make the existing
|
||
|
// the new candidate.
|
||
|
//
|
||
|
// If this is a merge of two existing rectangles (ie
|
||
|
// the candidate is the result of a merge), merge the
|
||
|
// overlapping existing into the candidate (the last
|
||
|
// merged) and remove the existing.
|
||
|
//
|
||
|
// For both, start the comparisons again with the new
|
||
|
// candidate.
|
||
|
//
|
||
|
if ( fRectToAdd )
|
||
|
{
|
||
|
g_baBounds[iExist].Coord.top = pCand->top;
|
||
|
pCand = &(g_baBounds[iExist].Coord);
|
||
|
fRectToAdd = FALSE;
|
||
|
iLastMerge = iExist;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pCand->bottom = g_baBounds[iExist].Coord.bottom;
|
||
|
BA_RemoveRectList(&(g_baBounds[iExist].Coord));
|
||
|
}
|
||
|
|
||
|
fResetRects = TRUE;
|
||
|
break;
|
||
|
|
||
|
case OL_MERGE_YMAX:
|
||
|
//
|
||
|
// - either the candidate abutts the existing rectangle
|
||
|
// from below
|
||
|
//
|
||
|
// 10,10
|
||
|
// +---------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | Exist |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// +---------+50,50
|
||
|
// 10,51+---------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | Cand |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// +---------+50,100
|
||
|
//
|
||
|
// - or the candidate overlaps the existing from below
|
||
|
// and can be merged
|
||
|
//
|
||
|
// 10,10
|
||
|
// +---------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | Exist |
|
||
|
// | |
|
||
|
// | |
|
||
|
// Cand 10,40+---------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// +---------+50,60 Exist
|
||
|
// | |
|
||
|
// | Cand |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// +---------+50,100
|
||
|
//
|
||
|
// If the candidate is the original, merge the
|
||
|
// candidate into the existing, and make the existing
|
||
|
// the new candidate.
|
||
|
//
|
||
|
// If this is a merge of two existing rectangles (ie
|
||
|
// the candidate is the result of a merge), merge the
|
||
|
// overlapping existing into the candidate (the last
|
||
|
// merged) and remove the existing.
|
||
|
//
|
||
|
// For both, start the comparisons again with the new
|
||
|
// candidate.
|
||
|
//
|
||
|
if ( fRectToAdd )
|
||
|
{
|
||
|
g_baBounds[iExist].Coord.bottom = pCand->bottom;
|
||
|
pCand = &(g_baBounds[iExist].Coord);
|
||
|
fRectToAdd = FALSE;
|
||
|
iLastMerge = iExist;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pCand->top = g_baBounds[iExist].Coord.top;
|
||
|
BA_RemoveRectList(&(g_baBounds[iExist].Coord));
|
||
|
}
|
||
|
|
||
|
fResetRects = TRUE;
|
||
|
break;
|
||
|
|
||
|
case OL_ENCLOSED:
|
||
|
//
|
||
|
// The existing is enclosed by the candidate.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +----------------------+
|
||
|
// | Cand |
|
||
|
// | |
|
||
|
// | 130,130 |
|
||
|
// | +------------+ |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | Exist | |
|
||
|
// | | | |
|
||
|
// | +------------+ |
|
||
|
// | 170,170 |
|
||
|
// | |
|
||
|
// +----------------------+
|
||
|
// 200,200
|
||
|
//
|
||
|
// If the candidate is the original, replace the
|
||
|
// existing by the candidate, and make the new existing
|
||
|
// the new candidate.
|
||
|
//
|
||
|
// If the candidate is an existing rectangle, remove
|
||
|
// the other existing rectangle.
|
||
|
//
|
||
|
// For both, start the comparisons again with the new
|
||
|
// candidate.
|
||
|
//
|
||
|
if ( fRectToAdd )
|
||
|
{
|
||
|
g_baBounds[iExist].Coord = *pCand;
|
||
|
pCand = &(g_baBounds[iExist].Coord);
|
||
|
fRectToAdd = FALSE;
|
||
|
iLastMerge = iExist;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
BA_RemoveRectList(&(g_baBounds[iExist].Coord));
|
||
|
}
|
||
|
|
||
|
fResetRects = TRUE;
|
||
|
break;
|
||
|
|
||
|
case OL_PART_ENCLOSED_XMIN:
|
||
|
//
|
||
|
// The existing is partially enclosed by the candidate
|
||
|
// - but not on the right.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +----------------------+
|
||
|
// | Cand |
|
||
|
// | |
|
||
|
// | 130,130 |
|
||
|
// | +-----------------+---+
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | Exist | |
|
||
|
// | | | |
|
||
|
// | +-----------------+---+
|
||
|
// | | 220,170
|
||
|
// | |
|
||
|
// +----------------------+
|
||
|
// 200,200
|
||
|
//
|
||
|
// Adjust the existing rectangle to be the non-
|
||
|
// overlapped portion.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +----------------------+
|
||
|
// | |
|
||
|
// | |201,130
|
||
|
// | |+--+
|
||
|
// | ||E |
|
||
|
// | ||x |
|
||
|
// | Cand ||i |
|
||
|
// | ||s |
|
||
|
// | ||t |
|
||
|
// | || |
|
||
|
// | |+--+
|
||
|
// | | 220,170
|
||
|
// +----------------------+
|
||
|
// 200,200
|
||
|
//
|
||
|
// Note that this does not restart the comparisons.
|
||
|
//
|
||
|
g_baBounds[iExist].Coord.left = pCand->right + 1;
|
||
|
break;
|
||
|
|
||
|
case OL_PART_ENCLOSED_XMAX:
|
||
|
//
|
||
|
// The existing is partially enclosed by the candidate
|
||
|
// - but not on the left.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +----------------------+
|
||
|
// | Cand |
|
||
|
// 70,130 | |
|
||
|
// +-----+---------------+ |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | Exist | |
|
||
|
// | | | |
|
||
|
// +-----+---------------+ |
|
||
|
// | 170,170 |
|
||
|
// | |
|
||
|
// +----------------------+
|
||
|
// 200,200
|
||
|
//
|
||
|
// Adjust the existing rectangle to be the non-
|
||
|
// overlapped portion.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +----------------------+
|
||
|
// 70,130 | |
|
||
|
// +----+| |
|
||
|
// | E || |
|
||
|
// | x || |
|
||
|
// | i || Cand |
|
||
|
// | s || |
|
||
|
// | t || |
|
||
|
// | || |
|
||
|
// +----+| |
|
||
|
// 99,170| |
|
||
|
// | |
|
||
|
// +----------------------+
|
||
|
// 200,200
|
||
|
//
|
||
|
// Note that this does not restart the comparisons.
|
||
|
//
|
||
|
g_baBounds[iExist].Coord.right = pCand->left - 1;
|
||
|
break;
|
||
|
|
||
|
case OL_PART_ENCLOSED_YMIN:
|
||
|
//
|
||
|
// The existing is partially enclosed by the candidate
|
||
|
// - but not on the bottom.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +----------------------+
|
||
|
// | Cand |
|
||
|
// | 130,130 |
|
||
|
// | +--------+ |
|
||
|
// | | | |
|
||
|
// | | Exist | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// +-----+--------+-------+
|
||
|
// | | 200,200
|
||
|
// | |
|
||
|
// | |
|
||
|
// +--------+170,230
|
||
|
//
|
||
|
// Adjust the existing rectangle to be the non-
|
||
|
// overlapped portion.
|
||
|
//
|
||
|
//
|
||
|
// 100,100
|
||
|
// +----------------------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | Cand |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// +----------------------+
|
||
|
// 130,201+---------+ 200,200
|
||
|
// | |
|
||
|
// | Exist |
|
||
|
// | |
|
||
|
// +---------+170,230
|
||
|
//
|
||
|
// Note that this does not restart the comparisons.
|
||
|
//
|
||
|
g_baBounds[iExist].Coord.top = pCand->bottom + 1;
|
||
|
break;
|
||
|
|
||
|
case OL_PART_ENCLOSED_YMAX:
|
||
|
//
|
||
|
// The existing is partially enclosed by the candidate
|
||
|
// - but not on the top.
|
||
|
//
|
||
|
// 70,130
|
||
|
// +---------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// 100,100 | |
|
||
|
// +-----+---------+------+
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | Exist | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | +---------+ |
|
||
|
// | 170,170 |
|
||
|
// | |
|
||
|
// | Cand |
|
||
|
// +----------------------+
|
||
|
// 200,200
|
||
|
//
|
||
|
// Adjust the existing rectangle to be the non-
|
||
|
// overlapped portion.
|
||
|
//
|
||
|
// 70,130
|
||
|
// +---------+
|
||
|
// | |
|
||
|
// | Exist |
|
||
|
// | |
|
||
|
// 100,100 +---------+170,99
|
||
|
// +----------------------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | Cand |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// +----------------------+
|
||
|
// 200,200
|
||
|
//
|
||
|
// Note that this does not restart the comparisons.
|
||
|
//
|
||
|
g_baBounds[iExist].Coord.bottom = pCand->top - 1;
|
||
|
break;
|
||
|
|
||
|
case OL_ENCLOSES:
|
||
|
//
|
||
|
// The existing encloses the candidate.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +----------------------+
|
||
|
// | Exist |
|
||
|
// | |
|
||
|
// | 130,130 |
|
||
|
// | +------------+ |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | Cand | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | +------------+ |
|
||
|
// | 170,170 |
|
||
|
// | |
|
||
|
// +----------------------+
|
||
|
// 200,200
|
||
|
//
|
||
|
// Just discard the candidate by exiting.
|
||
|
//
|
||
|
//
|
||
|
//
|
||
|
// Return FALSE indicating that the rectangle is
|
||
|
// already catered for by the existing bounds
|
||
|
//
|
||
|
rc= FALSE;
|
||
|
DC_QUIT;
|
||
|
break;
|
||
|
|
||
|
case OL_PART_ENCLOSES_XMIN:
|
||
|
//
|
||
|
// The existing partially encloses the candidate - but
|
||
|
// not on the left.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +----------------------+
|
||
|
// | Exist |
|
||
|
// 70,130 | |
|
||
|
// +-----+---------------+ |
|
||
|
// | | | |
|
||
|
// | | Cand | |
|
||
|
// | | | |
|
||
|
// +-----+---------------+ |
|
||
|
// | 170,170 |
|
||
|
// | |
|
||
|
// +----------------------+
|
||
|
// 200,200
|
||
|
//
|
||
|
// Adjust the candidate rectangle to be the non-
|
||
|
// overlapped portion.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +----------------------+
|
||
|
// 70,130 | |
|
||
|
// +----+| |
|
||
|
// | || |
|
||
|
// | C || |
|
||
|
// | a || |
|
||
|
// | n || Exist |
|
||
|
// | d || |
|
||
|
// | || |
|
||
|
// +----+| |
|
||
|
// 99,170| |
|
||
|
// | |
|
||
|
// +----------------------+
|
||
|
// 200,200
|
||
|
//
|
||
|
// Because this affects the candidate, restart the
|
||
|
// comparisons to check for overlaps between the
|
||
|
// adjusted candidate and other existing rectangles.
|
||
|
//
|
||
|
//
|
||
|
pCand->right = g_baBounds[iExist].Coord.left - 1;
|
||
|
|
||
|
fResetRects = TRUE;
|
||
|
break;
|
||
|
|
||
|
case OL_PART_ENCLOSES_XMAX:
|
||
|
//
|
||
|
// The existing partially encloses the candidate - but
|
||
|
// not on the right.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +----------------------+
|
||
|
// | Exist |
|
||
|
// | |
|
||
|
// | 130,130 |
|
||
|
// | +-----------------+---+
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | Cand | |
|
||
|
// | | | |
|
||
|
// | +-----------------+---+
|
||
|
// | | 220,170
|
||
|
// | |
|
||
|
// +----------------------+
|
||
|
// 200,200
|
||
|
//
|
||
|
// Adjust the candidate rectangle to be the non-
|
||
|
// overlapped portion.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +----------------------+
|
||
|
// | |201,130
|
||
|
// | |+--+
|
||
|
// | || |
|
||
|
// | ||C |
|
||
|
// | Exist ||a |
|
||
|
// | ||n |
|
||
|
// | ||d |
|
||
|
// | || |
|
||
|
// | |+--+
|
||
|
// | | 220,170
|
||
|
// +----------------------+
|
||
|
// 200,200
|
||
|
//
|
||
|
// Because this affects the candidate, restart the
|
||
|
// comparisons to check for overlaps between the
|
||
|
// adjusted candidate and other existing rectangles.
|
||
|
//
|
||
|
//
|
||
|
pCand->left = g_baBounds[iExist].Coord.right + 1;
|
||
|
|
||
|
fResetRects = TRUE;
|
||
|
break;
|
||
|
|
||
|
case OL_PART_ENCLOSES_YMIN:
|
||
|
//
|
||
|
// The existing partially encloses the candidate - but
|
||
|
// not on the top.
|
||
|
//
|
||
|
// 70,130
|
||
|
// +---------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// 100,100 | |
|
||
|
// +-----+---------+------+
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | Cand | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | +---------+ |
|
||
|
// | 170,170 |
|
||
|
// | |
|
||
|
// | Exist |
|
||
|
// +----------------------+
|
||
|
// 200,200
|
||
|
//
|
||
|
// Adjust the candidate rectangle to be the non-
|
||
|
// overlapped portion.
|
||
|
//
|
||
|
//
|
||
|
// 70,130
|
||
|
// +---------+
|
||
|
// | |
|
||
|
// | Cand |
|
||
|
// | |
|
||
|
// 100,100 +---------+170,99
|
||
|
// +----------------------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | Exist |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// +----------------------+
|
||
|
// 200,200
|
||
|
//
|
||
|
// Because this affects the candidate, restart the
|
||
|
// comparisons to check for overlaps between the
|
||
|
// adjusted candidate and other existing rectangles.
|
||
|
//
|
||
|
//
|
||
|
pCand->bottom = g_baBounds[iExist].Coord.top - 1;
|
||
|
|
||
|
fResetRects = TRUE;
|
||
|
break;
|
||
|
|
||
|
case OL_PART_ENCLOSES_YMAX:
|
||
|
//
|
||
|
// The existing partially encloses the candidate - but
|
||
|
// not on the bottom.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +----------------------+
|
||
|
// | Exist |
|
||
|
// | |
|
||
|
// | 130,130 |
|
||
|
// | +--------+ |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | Cand | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// +-----+--------+-------+
|
||
|
// | | 200,200
|
||
|
// | |
|
||
|
// | |
|
||
|
// +--------+170,230
|
||
|
//
|
||
|
// Adjust the candidate rectangle to be the non-
|
||
|
// overlapped portion.
|
||
|
//
|
||
|
//
|
||
|
// 100,100
|
||
|
// +----------------------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | Exist |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// +----------------------+
|
||
|
// 130,201+---------+ 200,200
|
||
|
// | |
|
||
|
// | Cand |
|
||
|
// | |
|
||
|
// +---------+170,230
|
||
|
//
|
||
|
// Because this affects the candidate, restart the
|
||
|
// comparisons to check for overlaps between the
|
||
|
// adjusted candidate and other existing rectangles.
|
||
|
//
|
||
|
//
|
||
|
pCand->top = g_baBounds[iExist].Coord.bottom + 1;
|
||
|
|
||
|
fResetRects = TRUE;
|
||
|
break;
|
||
|
|
||
|
case OL_SPLIT_X:
|
||
|
//
|
||
|
// The existing overlaps the candicate, but neither can
|
||
|
// be merged or adjusted.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +--------+
|
||
|
// | |
|
||
|
// 70,130 | Exist |
|
||
|
// +-----+--------+------+
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | Cand| | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// +-----+--------+------+180,160
|
||
|
// | |
|
||
|
// | |
|
||
|
// +--------+150,200
|
||
|
//
|
||
|
// Need to split candidate into left and right halves.
|
||
|
//
|
||
|
// Only do a split if there is spare room in the list -
|
||
|
// because both the split rectangles may need to be
|
||
|
// added to the list.
|
||
|
//
|
||
|
// If there is spare room, split the candidate into a
|
||
|
// smaller candidate on the left and a new rectangle on
|
||
|
// the right. Call this routine recursively to handle
|
||
|
// the new rectangle.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +--------+
|
||
|
// | |
|
||
|
// 70,130 | |151,130
|
||
|
// +----+| |+-----+
|
||
|
// | || || |
|
||
|
// | || || |
|
||
|
// |Cand|| Exist || New |
|
||
|
// | || || |
|
||
|
// | || || |
|
||
|
// +----+| |+-----+
|
||
|
// 99,160| | 180,160
|
||
|
// | |
|
||
|
// +--------+150,200
|
||
|
//
|
||
|
// After the recursion, because the candidate has
|
||
|
// changed, restart the comparisons to check for
|
||
|
// overlaps between the adjusted candidate and other
|
||
|
// existing rectangles.
|
||
|
//
|
||
|
//
|
||
|
if ((g_baRectsUsed < BA_NUM_RECTS) &&
|
||
|
(level < ADDR_RECURSE_LIMIT))
|
||
|
{
|
||
|
rectNew.left = g_baBounds[iExist].Coord.right + 1;
|
||
|
rectNew.right = pCand->right;
|
||
|
rectNew.top = pCand->top;
|
||
|
rectNew.bottom = pCand->bottom;
|
||
|
pCand->right = g_baBounds[iExist].Coord.left - 1;
|
||
|
|
||
|
TRACE_OUT(( "*** RECURSION ***"));
|
||
|
BAAddRect(&rectNew, level);
|
||
|
TRACE_OUT(( "*** RETURN ***"));
|
||
|
|
||
|
if (!fRectToAdd && !g_baBounds[iLastMerge].InUse)
|
||
|
{
|
||
|
TRACE_OUT(( "FINISHED - %d", iLastMerge));
|
||
|
DC_QUIT;
|
||
|
}
|
||
|
|
||
|
fResetRects = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case OL_SPLIT_Y:
|
||
|
//
|
||
|
// The existing overlaps the candicate, but neither can
|
||
|
// be merged or adjusted.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +--------+
|
||
|
// | |
|
||
|
// 70,130 | Cand |
|
||
|
// +-----+--------+------+
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// |Exist| | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// +-----+--------+------+180,160
|
||
|
// | |
|
||
|
// | |
|
||
|
// +--------+150,200
|
||
|
//
|
||
|
// Need to split candidate into top and bottom halves.
|
||
|
//
|
||
|
// Only do a split if there is spare room in the list -
|
||
|
// because both the split rectangles may need to be
|
||
|
// added to the list.
|
||
|
//
|
||
|
// If there is spare room, split the candidate into a
|
||
|
// smaller candidate on the top and a new rectangle on
|
||
|
// the bottom. Call this routine recursively to handle
|
||
|
// the new rectangle.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +--------+
|
||
|
// | Cand |
|
||
|
// 70,130 +--------+150,129
|
||
|
// +---------------------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// +---------------------+180,160
|
||
|
// 100,161+--------+
|
||
|
// | New |
|
||
|
// +--------+150,200
|
||
|
//
|
||
|
// After the recursion, because the candidate has
|
||
|
// changed, restart the comparisons to check for
|
||
|
// overlaps between the adjusted candidate and other
|
||
|
// existing rectangles.
|
||
|
//
|
||
|
//
|
||
|
|
||
|
if ((g_baRectsUsed < BA_NUM_RECTS) &&
|
||
|
(level < ADDR_RECURSE_LIMIT))
|
||
|
{
|
||
|
rectNew.left = pCand->left;
|
||
|
rectNew.right = pCand->right;
|
||
|
rectNew.top = g_baBounds[iExist].Coord.bottom + 1;
|
||
|
rectNew.bottom = pCand->bottom;
|
||
|
pCand->bottom = g_baBounds[iExist].Coord.top - 1;
|
||
|
|
||
|
TRACE_OUT(( "*** RECURSION ***"));
|
||
|
BAAddRect(&rectNew, level);
|
||
|
TRACE_OUT(( "*** RETURN ***"));
|
||
|
|
||
|
if (!fRectToAdd && !g_baBounds[iLastMerge].InUse)
|
||
|
{
|
||
|
TRACE_OUT(( "FINISHED - %d", iLastMerge));
|
||
|
DC_QUIT;
|
||
|
}
|
||
|
|
||
|
fResetRects = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case OL_SPLIT_XMIN_YMIN:
|
||
|
//
|
||
|
// The existing overlaps the candicate, but neither can
|
||
|
// be merged or adjusted.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +---------------+
|
||
|
// | Cand |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | 150,150 |
|
||
|
// | +-------+-----+
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// +-------+-------+ |
|
||
|
// | 200,200 |
|
||
|
// | |
|
||
|
// | Exist |
|
||
|
// | |
|
||
|
// +-------------+
|
||
|
// 250,250
|
||
|
//
|
||
|
// Need to split candidate into top and left pieces.
|
||
|
//
|
||
|
// Only do a split if there is spare room in the list -
|
||
|
// because both the split rectangles may need to be
|
||
|
// added to the list.
|
||
|
//
|
||
|
// If there is spare room, split the candidate into a
|
||
|
// smaller candidate on the left and a new rectangle on
|
||
|
// the top. Call this routine recursively to handle
|
||
|
// the new rectangle.
|
||
|
//
|
||
|
// 100,100 151,100
|
||
|
// +-------+-------+
|
||
|
// | | |
|
||
|
// | | New |
|
||
|
// | | |
|
||
|
// | | |200,149
|
||
|
// | +-------+-----+
|
||
|
// | Cand |150,150 |
|
||
|
// | | |
|
||
|
// | | |
|
||
|
// | | |
|
||
|
// | | Exist |
|
||
|
// +-------+ |
|
||
|
// 150,200| |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// +-------------+
|
||
|
// 250,250
|
||
|
//
|
||
|
// After the recursion, because the candidate has
|
||
|
// changed, restart the comparisons to check for
|
||
|
// overlaps between the adjusted candidate and other
|
||
|
// existing rectangles.
|
||
|
//
|
||
|
//
|
||
|
|
||
|
if ( g_baRectsUsed < BA_NUM_RECTS )
|
||
|
{
|
||
|
rectNew.left = g_baBounds[iExist].Coord.left;
|
||
|
rectNew.right = pCand->right;
|
||
|
rectNew.top = pCand->top;
|
||
|
rectNew.bottom = g_baBounds[iExist].Coord.top - 1;
|
||
|
pCand->right = g_baBounds[iExist].Coord.left - 1;
|
||
|
|
||
|
TRACE_OUT(( "*** RECURSION ***"));
|
||
|
BAAddRect(&rectNew, level);
|
||
|
TRACE_OUT(( "*** RETURN ***"));
|
||
|
|
||
|
if (!fRectToAdd && !g_baBounds[iLastMerge].InUse)
|
||
|
{
|
||
|
TRACE_OUT(( "FINISHED - %d", iLastMerge));
|
||
|
DC_QUIT;
|
||
|
}
|
||
|
|
||
|
fResetRects = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case OL_SPLIT_XMAX_YMIN:
|
||
|
//
|
||
|
// The existing overlaps the candicate, but neither can
|
||
|
// be merged or adjusted.
|
||
|
//
|
||
|
// 150,100
|
||
|
// +---------------+
|
||
|
// | |
|
||
|
// | Cand |
|
||
|
// 100,150 | |
|
||
|
// +------+--------+ |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | +--------+------+
|
||
|
// | | 250,200
|
||
|
// | Exist |
|
||
|
// | |
|
||
|
// +---------------+
|
||
|
// 200,250
|
||
|
//
|
||
|
// Need to split candidate into top and right pieces.
|
||
|
//
|
||
|
// Only do a split if there is spare room in the list -
|
||
|
// because both the split rectangles may need to be
|
||
|
// added to the list.
|
||
|
//
|
||
|
// If there is spare room, split the candidate into a
|
||
|
// smaller candidate on the right and a new rectangle
|
||
|
// on the top. Call this routine recursively to handle
|
||
|
// the new rectangle.
|
||
|
//
|
||
|
// 150,100 201,100
|
||
|
// +--------+------+
|
||
|
// | New | |
|
||
|
// | | |
|
||
|
// 100,150 | 200,149| |
|
||
|
// +------+--------+ |
|
||
|
// | | Cand |
|
||
|
// | | |
|
||
|
// | | |
|
||
|
// | | |
|
||
|
// | Exist | |
|
||
|
// | | |
|
||
|
// | +------+
|
||
|
// | | 250,200
|
||
|
// | |
|
||
|
// | |
|
||
|
// +---------------+
|
||
|
// 200,250
|
||
|
//
|
||
|
// After the recursion, because the candidate has
|
||
|
// changed, restart the comparisons to check for
|
||
|
// overlaps between the adjusted candidate and other
|
||
|
// existing rectangles.
|
||
|
//
|
||
|
//
|
||
|
|
||
|
if ((g_baRectsUsed < BA_NUM_RECTS) &&
|
||
|
(level < ADDR_RECURSE_LIMIT))
|
||
|
{
|
||
|
rectNew.left = pCand->left;
|
||
|
rectNew.right = g_baBounds[iExist].Coord.right;
|
||
|
rectNew.top = pCand->top;
|
||
|
rectNew.bottom = g_baBounds[iExist].Coord.top - 1;
|
||
|
pCand->left = g_baBounds[iExist].Coord.right + 1;
|
||
|
|
||
|
TRACE_OUT(( "*** RECURSION ***"));
|
||
|
BAAddRect(&rectNew, level);
|
||
|
TRACE_OUT(( "*** RETURN ***"));
|
||
|
|
||
|
if (!fRectToAdd && !g_baBounds[iLastMerge].InUse)
|
||
|
{
|
||
|
TRACE_OUT(( "FINISHED - %d", iLastMerge));
|
||
|
DC_QUIT;
|
||
|
}
|
||
|
|
||
|
fResetRects = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case OL_SPLIT_XMIN_YMAX:
|
||
|
//
|
||
|
// The existing overlaps the candicate, but neither can
|
||
|
// be merged or adjusted.
|
||
|
//
|
||
|
// 150,100
|
||
|
// +---------------+
|
||
|
// | |
|
||
|
// | Exist |
|
||
|
// 100,150 | |
|
||
|
// +------+--------+ |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | +--------+------+
|
||
|
// | | 250,200
|
||
|
// | Cand |
|
||
|
// | |
|
||
|
// +---------------+
|
||
|
// 200,250
|
||
|
//
|
||
|
// Need to split candidate into left and bottom pieces.
|
||
|
//
|
||
|
// Only do a split if there is spare room in the list -
|
||
|
// because both the split rectangles may need to be
|
||
|
// added to the list.
|
||
|
//
|
||
|
// If there is spare room, split the candidate into a
|
||
|
// smaller candidate on the left and a new rectangle on
|
||
|
// the bottom. Call this routine recursively to handle
|
||
|
// the new rectangle.
|
||
|
//
|
||
|
// 150,100
|
||
|
// +---------------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// 100,150 | |
|
||
|
// +------+ |
|
||
|
// | | |
|
||
|
// | | |
|
||
|
// | | |
|
||
|
// | | |
|
||
|
// | Cand | |
|
||
|
// | | |
|
||
|
// | +--------+------+
|
||
|
// | |151,200 | 250,200
|
||
|
// | | |
|
||
|
// | | New |
|
||
|
// +------+--------+
|
||
|
// 149,250 200,250
|
||
|
//
|
||
|
// After the recursion, because the candidate has
|
||
|
// changed, restart the comparisons to check for
|
||
|
// overlaps between the adjusted candidate and other
|
||
|
// existing rectangles.
|
||
|
//
|
||
|
//
|
||
|
|
||
|
if ((g_baRectsUsed < BA_NUM_RECTS) &&
|
||
|
(level < ADDR_RECURSE_LIMIT))
|
||
|
{
|
||
|
rectNew.left = g_baBounds[iExist].Coord.left;
|
||
|
rectNew.right = pCand->right;
|
||
|
rectNew.top = g_baBounds[iExist].Coord.bottom + 1;
|
||
|
rectNew.bottom = pCand->bottom;
|
||
|
pCand->right = g_baBounds[iExist].Coord.left - 1;
|
||
|
|
||
|
TRACE_OUT(( "*** RECURSION ***"));
|
||
|
BAAddRect(&rectNew, level);
|
||
|
TRACE_OUT(( "*** RETURN ***"));
|
||
|
|
||
|
if (!fRectToAdd && !g_baBounds[iLastMerge].InUse)
|
||
|
{
|
||
|
TRACE_OUT(( "FINISHED - %d", iLastMerge));
|
||
|
DC_QUIT;
|
||
|
}
|
||
|
|
||
|
fResetRects = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case OL_SPLIT_XMAX_YMAX:
|
||
|
//
|
||
|
// The existing overlaps the candicate, but neither can
|
||
|
// be merged or adjusted.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +---------------+
|
||
|
// | Exist |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | 150,150 |
|
||
|
// | +-------+-----+
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// | | | |
|
||
|
// +-------+-------+ |
|
||
|
// | 200,200 |
|
||
|
// | |
|
||
|
// | Cand |
|
||
|
// | |
|
||
|
// +-------------+
|
||
|
// 250,250
|
||
|
//
|
||
|
// Need to split candidate into bottom and right pieces.
|
||
|
//
|
||
|
// Only do a split if there is spare room in the list -
|
||
|
// because both the split rectangles may need to be
|
||
|
// added to the list.
|
||
|
//
|
||
|
// If there is spare room, split the candidate into a
|
||
|
// smaller candidate on the right and a new rectangle
|
||
|
// on the bottom. Call this routine recursively to
|
||
|
// handle the new rectangle.
|
||
|
//
|
||
|
// 100,100
|
||
|
// +---------------+
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |
|
||
|
// | |201,150
|
||
|
// | Exist +-----+
|
||
|
// | | |
|
||
|
// | | |
|
||
|
// | | |
|
||
|
// | |Cand |
|
||
|
// | 200,200| |
|
||
|
// +-------+-------+ |
|
||
|
// 150,201| | |
|
||
|
// | | |
|
||
|
// | New | |
|
||
|
// | | |
|
||
|
// +-------+-----+
|
||
|
// 200,250 250,250
|
||
|
//
|
||
|
// After the recursion, because the candidate has
|
||
|
// changed, restart the comparisons to check for
|
||
|
// overlaps between the adjusted candidate and other
|
||
|
// existing rectangles.
|
||
|
//
|
||
|
//
|
||
|
|
||
|
if ((g_baRectsUsed < BA_NUM_RECTS) &&
|
||
|
(level < ADDR_RECURSE_LIMIT))
|
||
|
{
|
||
|
rectNew.left = pCand->left;
|
||
|
rectNew.right = g_baBounds[iExist].Coord.right;
|
||
|
rectNew.top = g_baBounds[iExist].Coord.bottom + 1;
|
||
|
rectNew.bottom = pCand->bottom;
|
||
|
pCand->left = g_baBounds[iExist].Coord.right + 1;
|
||
|
|
||
|
TRACE_OUT(( "*** RECURSION ***"));
|
||
|
BAAddRect(&rectNew, level);
|
||
|
TRACE_OUT(( "*** RETURN ***"));
|
||
|
|
||
|
if (!fRectToAdd && !g_baBounds[iLastMerge].InUse)
|
||
|
{
|
||
|
TRACE_OUT(( "FINISHED - %d", iLastMerge));
|
||
|
DC_QUIT;
|
||
|
}
|
||
|
|
||
|
fResetRects = TRUE;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
//
|
||
|
// This should not happen.
|
||
|
//
|
||
|
ERROR_OUT(( "Unrecognised overlap case-%d",OverlapType));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
iExist = (fResetRects) ? g_baFirstRect :
|
||
|
g_baBounds[iExist].iNext;
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Arriving here means that no overlap was found between the
|
||
|
// candidate and the existing rectangles.
|
||
|
//
|
||
|
// - If the candidate is the original rectangle, add it to the
|
||
|
// list.
|
||
|
// - If the candidate is an existing rectangle, it is already in
|
||
|
// the list.
|
||
|
//
|
||
|
if ( fRectToAdd )
|
||
|
{
|
||
|
BAAddRectList(pCand);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// The compare and add processing above is allowed to add a
|
||
|
// rectangle to the list when there are already BA_NUM_RECTS
|
||
|
// (eg. when doing a split or when there is no overlap at all with
|
||
|
// the existing rectangles) - and there is an extra slot for that
|
||
|
// purpose.
|
||
|
//
|
||
|
// If we now have more than BA_NUM_RECTS rectangles, do a
|
||
|
// forced merge, so that the next call to this routine has a spare
|
||
|
// slot.
|
||
|
//
|
||
|
//
|
||
|
fRectMerged = ( g_baRectsUsed > BA_NUM_RECTS );
|
||
|
if ( fRectMerged )
|
||
|
{
|
||
|
//
|
||
|
// Start looking for merged rectangles.
|
||
|
//
|
||
|
// For each rectangle in the list, compare it with the others,
|
||
|
// and Determine cost of merging.
|
||
|
//
|
||
|
// We want to merge the two rectangles with the minimum
|
||
|
// area difference, ie that will produce a merged
|
||
|
// rectangle that covers the least superfluous screen
|
||
|
// area.
|
||
|
//
|
||
|
// Note that we calculate the areas of the rectangles here
|
||
|
// (rather than on the fly as they are created/ manipulated in
|
||
|
// the loop), as the statistics show that forced merges occur
|
||
|
// very much less frequently than non-forced manipulations (ie
|
||
|
// splits, adds etc.
|
||
|
//
|
||
|
//
|
||
|
bestMergeIncrease = 0x7FFFFFFF;
|
||
|
|
||
|
for ( iExist = g_baFirstRect;
|
||
|
iExist != BA_INVALID_RECT_INDEX;
|
||
|
iExist = g_baBounds[iExist].iNext )
|
||
|
{
|
||
|
g_baBounds[iExist].Area =
|
||
|
COM_SizeOfRectInclusive(&g_baBounds[iExist].Coord);
|
||
|
}
|
||
|
|
||
|
#ifdef _DEBUG
|
||
|
iBestMerge1 = BA_INVALID_RECT_INDEX;
|
||
|
iBestMerge2 = BA_INVALID_RECT_INDEX;
|
||
|
#endif
|
||
|
for ( iExist = g_baFirstRect;
|
||
|
iExist != BA_INVALID_RECT_INDEX;
|
||
|
iExist = g_baBounds[iExist].iNext )
|
||
|
{
|
||
|
for ( iTmp = g_baBounds[iExist].iNext;
|
||
|
iTmp != BA_INVALID_RECT_INDEX;
|
||
|
iTmp = g_baBounds[iTmp].iNext )
|
||
|
{
|
||
|
rectNew.left = min( g_baBounds[iExist].Coord.left,
|
||
|
g_baBounds[iTmp].Coord.left );
|
||
|
rectNew.top = min( g_baBounds[iExist].Coord.top,
|
||
|
g_baBounds[iTmp].Coord.top );
|
||
|
rectNew.right = max( g_baBounds[iExist].Coord.right,
|
||
|
g_baBounds[iTmp].Coord.right );
|
||
|
rectNew.bottom = max( g_baBounds[iExist].Coord.bottom,
|
||
|
g_baBounds[iTmp].Coord.bottom );
|
||
|
|
||
|
mergeIncrease = COM_SizeOfRectInclusive(&rectNew) -
|
||
|
g_baBounds[iExist].Area - g_baBounds[iTmp].Area;
|
||
|
|
||
|
if (bestMergeIncrease > mergeIncrease)
|
||
|
{
|
||
|
iBestMerge1 = iExist;
|
||
|
iBestMerge2 = iTmp;
|
||
|
bestMergeIncrease = mergeIncrease;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ASSERT(iBestMerge1 != BA_INVALID_RECT_INDEX);
|
||
|
ASSERT(iBestMerge2 != BA_INVALID_RECT_INDEX);
|
||
|
|
||
|
//
|
||
|
// Now do the merge.
|
||
|
//
|
||
|
// We recalculate the size of the merged rectangle here -
|
||
|
// alternatively we could remember the size of the best so far
|
||
|
// in the loop above. The trade off is between calculating
|
||
|
// twice or copying at least once but probably more than once
|
||
|
// as we find successively better merges.
|
||
|
//
|
||
|
TRACE_OUT(("BestMerge1 %d, {%d,%d,%d,%d}", iBestMerge1,
|
||
|
g_baBounds[iBestMerge1].Coord.left,
|
||
|
g_baBounds[iBestMerge1].Coord.top,
|
||
|
g_baBounds[iBestMerge1].Coord.right,
|
||
|
g_baBounds[iBestMerge1].Coord.bottom ));
|
||
|
|
||
|
TRACE_OUT(("BestMerge2 %d, {%d,%d,%d,%d}", iBestMerge2,
|
||
|
g_baBounds[iBestMerge2].Coord.left,
|
||
|
g_baBounds[iBestMerge2].Coord.top,
|
||
|
g_baBounds[iBestMerge2].Coord.right,
|
||
|
g_baBounds[iBestMerge2].Coord.bottom ));
|
||
|
|
||
|
g_baBounds[iBestMerge1].Coord.left =
|
||
|
min( g_baBounds[iBestMerge1].Coord.left,
|
||
|
g_baBounds[iBestMerge2].Coord.left );
|
||
|
g_baBounds[iBestMerge1].Coord.top =
|
||
|
min( g_baBounds[iBestMerge1].Coord.top,
|
||
|
g_baBounds[iBestMerge2].Coord.top );
|
||
|
g_baBounds[iBestMerge1].Coord.right =
|
||
|
max( g_baBounds[iBestMerge1].Coord.right,
|
||
|
g_baBounds[iBestMerge2].Coord.right );
|
||
|
g_baBounds[iBestMerge1].Coord.bottom =
|
||
|
max( g_baBounds[iBestMerge1].Coord.bottom,
|
||
|
g_baBounds[iBestMerge2].Coord.bottom );
|
||
|
|
||
|
//
|
||
|
// Remove the second best merge.
|
||
|
//
|
||
|
BA_RemoveRectList(&(g_baBounds[iBestMerge2].Coord));
|
||
|
|
||
|
//
|
||
|
// The best merged rectangle becomes the candidate, and we fall
|
||
|
// back to the head of the comparison loop to start again.
|
||
|
//
|
||
|
pCand = &(g_baBounds[iBestMerge1].Coord);
|
||
|
iLastMerge = iBestMerge1;
|
||
|
fRectToAdd = FALSE;
|
||
|
}
|
||
|
|
||
|
} while ( fRectMerged );
|
||
|
|
||
|
DC_EXIT_POINT:
|
||
|
DebugExitBOOL(BAAddRect, rc);
|
||
|
return(rc);
|
||
|
}
|