#include "precomp.h" // // BA.C // Bounds Accumulation, disply driver side // // Copyright(c) Microsoft 1997- // // // // BA_DDProcessRequest() - see ba.h // // BOOL BA_DDProcessRequest ( DWORD fnEscape, LPOSI_ESCAPE_HEADER pRequest, DWORD cbRequest, LPOSI_ESCAPE_HEADER pResult, DWORD cbResult ) { BOOL rc = TRUE; LPBA_BOUNDS_INFO pBoundsInfo; UINT i; RECT rect; DebugEntry(BA_DDProcessRequest); if ((cbRequest != sizeof(BA_BOUNDS_INFO)) || (cbResult != sizeof(BA_BOUNDS_INFO))) { ERROR_OUT(("BA_DDProcessRequest: Invalid sizes %d, %d for BA_ESC", cbRequest, cbResult)); rc = FALSE; DC_QUIT; } 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 // 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)pRequest; 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; } DC_EXIT_POINT: DebugExitBOOL(BA_DDProcessRequest, rc); return(rc); } // // BA_DDInit - see ba.h for description. // void BA_DDInit(void) { DebugEntry(BA_DDInit); BA_ResetBounds(); DebugExitVOID(BA_DDInit); } // // 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); if (*pNumRects = g_baRectsUsed) { // // Return the bounds that have been accumulated. // TRACE_OUT(( "num rects : %d", g_baRectsUsed)); // // 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) ) { WARNING_OUT(( "Invalid Add Rect (%d,%d,%d,%d)", pRect->left, pRect->top, pRect->right, pRect->bottom )); 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; memcpy(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 ) { int bestMergeIncrease; int 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 ) { TRACE_OUT(( "OL_SAME - %d", iExist)); 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. // TRACE_OUT(( "OL_NONE - %d", iExist)); 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. // TRACE_OUT(( "OL_MERGE_XMIN - %d", iExist)); 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. // TRACE_OUT(( "OL_MERGE_XMAX - %d", iExist)); 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. // TRACE_OUT(( "OL_MERGE_YMIN - %d", iExist)); 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. // TRACE_OUT(( "OL_MERGE_YMAX - %d", iExist)); 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. // TRACE_OUT(( "OL_ENCLOSED - %d", iExist)); 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. // TRACE_OUT(( "OL_PART_ENCLOSED_XMIN - %d", iExist)); 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. // TRACE_OUT(( "OL_PART_ENCLOSED_XMAX - %d", iExist)); 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. // TRACE_OUT(( "OL_PART_ENCLOSED_YMIN - %d", iExist)); 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. // TRACE_OUT(( "OL_PART_ENCLOSED_YMAX - %d", iExist)); 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. // // TRACE_OUT(( "OL_ENCLOSES - %d", iExist)); // // 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. // // TRACE_OUT(( "OL_PART_ENCLOSES_XMIN - %d", iExist)); 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. // // TRACE_OUT(( "OL_PART_ENCLOSES_XMAX - %d", iExist)); 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. // // TRACE_OUT(( "OL_PART_ENCLOSES_YMIN - %d", iExist)); 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. // // TRACE_OUT(( "OL_PART_ENCLOSES_YMAX - %d", iExist)); 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. // // TRACE_OUT(( "OL_SPLIT_X - %d", iExist)); 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. // // TRACE_OUT(( "OL_SPLIT_Y - %d", iExist)); 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. // // TRACE_OUT(( "OL_SPLIT_XMIN_YMIN - %d", iExist)); 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. // // TRACE_OUT(( "OL_SPLIT_XMAX_YMIN - %d", iExist)); 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. // // TRACE_OUT(( "OL_SPLIT_XMIN_YMAX - %d", iExist)); 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. // // TRACE_OUT(( "OL_SPLIT_XMAX_YMAX - %d", iExist)); 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 // g_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); }