summaryrefslogtreecommitdiff
path: root/vcl/source/gdi/regband.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'vcl/source/gdi/regband.cxx')
-rw-r--r--vcl/source/gdi/regband.cxx969
1 files changed, 969 insertions, 0 deletions
diff --git a/vcl/source/gdi/regband.cxx b/vcl/source/gdi/regband.cxx
new file mode 100644
index 000000000000..14f45b4beafd
--- /dev/null
+++ b/vcl/source/gdi/regband.cxx
@@ -0,0 +1,969 @@
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_vcl.hxx"
+#include <tools/debug.hxx>
+#include <vcl/salbtype.hxx>
+#include <vcl/regband.hxx>
+
+#include <algorithm>
+
+
+// =======================================================================
+//
+// ImplRegionBand
+//
+// Jedes Band enthaelt die zwischen der enthaltenen Ober- und Untergrenze
+// enthaltenen Rechtecke. Bei den Operationen Union, Intersect, XOr und
+// Exclude werden immer Rechtecke der gleichen Hoehe ausgewerte; die
+// Grenzen der Baender sind immer so zu waehlen, dasz dies moeglich ist.
+//
+// Die Rechtecke in den Baendern werden nach Moeglichkeit zusammengefaszt.
+//
+// Bei der Umwandlung von Polygonen werden alle Punkte des Polygons
+// in die einzelnen Baender eingetragen (sie stehen fuer jedes Band als
+// Punkte in einer Liste). Nach dem Eintragen der Punkte werden diese
+// in Rechtecke umgewandelt und die Liste der Punkte geloescht.
+//
+// -----------------------------------------------------------------------
+
+ImplRegionBand::ImplRegionBand( long nTop, long nBottom )
+{
+ // save boundaries
+ mnYTop = nTop;
+ mnYBottom = nBottom;
+
+ // initialize lists
+ mpNextBand = NULL;
+ mpPrevBand = NULL;
+ mpFirstSep = NULL;
+ mpFirstBandPoint = NULL;
+ mbTouched = FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+ImplRegionBand::ImplRegionBand(
+ const ImplRegionBand& rRegionBand,
+ const bool bIgnorePoints)
+{
+ // copy boundaries
+ mnYTop = rRegionBand.mnYTop;
+ mnYBottom = rRegionBand.mnYBottom;
+ mbTouched = rRegionBand.mbTouched;
+
+ // initialisation
+ mpNextBand = NULL;
+ mpPrevBand = NULL;
+ mpFirstSep = NULL;
+ mpFirstBandPoint = NULL;
+
+ // copy all elements of the list with separations
+ ImplRegionBandSep* pNewSep;
+ ImplRegionBandSep* pPrevSep = 0;
+ ImplRegionBandSep* pSep = rRegionBand.mpFirstSep;
+ while ( pSep )
+ {
+ // create new and copy data
+ pNewSep = new ImplRegionBandSep;
+ pNewSep->mnXLeft = pSep->mnXLeft;
+ pNewSep->mnXRight = pSep->mnXRight;
+ pNewSep->mbRemoved = pSep->mbRemoved;
+ pNewSep->mpNextSep = NULL;
+ if ( pSep == rRegionBand.mpFirstSep )
+ mpFirstSep = pNewSep;
+ else
+ pPrevSep->mpNextSep = pNewSep;
+
+ pPrevSep = pNewSep;
+ pSep = pSep->mpNextSep;
+ }
+
+ if ( ! bIgnorePoints)
+ {
+ // Copy points.
+ ImplRegionBandPoint* pPoint = rRegionBand.mpFirstBandPoint;
+ ImplRegionBandPoint* pPrevPointCopy = NULL;
+ while (pPoint != NULL)
+ {
+ ImplRegionBandPoint* pPointCopy = new ImplRegionBandPoint();
+ pPointCopy->mnX = pPoint->mnX;
+ pPointCopy->mnLineId = pPoint->mnLineId;
+ pPointCopy->mbEndPoint = pPoint->mbEndPoint;
+ pPointCopy->meLineType = pPoint->meLineType;
+
+ if (pPrevPointCopy != NULL)
+ pPrevPointCopy->mpNextBandPoint = pPointCopy;
+ else
+ mpFirstBandPoint = pPointCopy;
+
+ pPrevPointCopy = pPointCopy;
+ pPoint = pPoint->mpNextBandPoint;
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+ImplRegionBand::~ImplRegionBand()
+{
+ DBG_ASSERT( mpFirstBandPoint == NULL, "ImplRegionBand::~ImplRegionBand -> pointlist not empty" );
+
+ // delete elements of the list
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ ImplRegionBandSep* pTempSep = pSep->mpNextSep;
+ delete pSep;
+ pSep = pTempSep;
+ }
+
+ // delete elements of the list
+ ImplRegionBandPoint* pPoint = mpFirstBandPoint;
+ while ( pPoint )
+ {
+ ImplRegionBandPoint* pTempPoint = pPoint->mpNextBandPoint;
+ delete pPoint;
+ pPoint = pTempPoint;
+ }
+}
+
+// -----------------------------------------------------------------------
+//
+// generate separations from lines and process union with existing
+// separations
+
+void ImplRegionBand::ProcessPoints()
+{
+ // check Pointlist
+ ImplRegionBandPoint* pRegionBandPoint = mpFirstBandPoint;
+ while ( pRegionBandPoint )
+ {
+ // within list?
+ if ( pRegionBandPoint && pRegionBandPoint->mpNextBandPoint )
+ {
+ // start/stop?
+ if ( pRegionBandPoint->mbEndPoint && pRegionBandPoint->mpNextBandPoint->mbEndPoint )
+ {
+ // same direction? -> remove next point!
+ if ( pRegionBandPoint->meLineType == pRegionBandPoint->mpNextBandPoint->meLineType )
+ {
+ ImplRegionBandPoint* pSaveRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
+ pRegionBandPoint->mpNextBandPoint = pRegionBandPoint->mpNextBandPoint->mpNextBandPoint;
+ delete pSaveRegionBandPoint;
+ }
+ }
+ }
+
+ // continue with next element in the list
+ pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
+ }
+
+ pRegionBandPoint = mpFirstBandPoint;
+ while ( pRegionBandPoint && pRegionBandPoint->mpNextBandPoint )
+ {
+ Union( pRegionBandPoint->mnX, pRegionBandPoint->mpNextBandPoint->mnX );
+
+ ImplRegionBandPoint* pNextBandPoint = pRegionBandPoint->mpNextBandPoint->mpNextBandPoint;
+
+ // remove allready processed points
+ delete pRegionBandPoint->mpNextBandPoint;
+ delete pRegionBandPoint;
+
+ // continue with next element in the list
+ pRegionBandPoint = pNextBandPoint;
+ }
+
+ // remove last element if necessary
+ if ( pRegionBandPoint )
+ delete pRegionBandPoint;
+
+ // list is now empty
+ mpFirstBandPoint = NULL;
+}
+
+// -----------------------------------------------------------------------
+//
+// generate separations from lines and process union with existing
+// separations
+
+BOOL ImplRegionBand::InsertPoint( long nX, long nLineId,
+ BOOL bEndPoint, LineType eLineType )
+{
+ if ( !mpFirstBandPoint )
+ {
+ mpFirstBandPoint = new ImplRegionBandPoint;
+ mpFirstBandPoint->mnX = nX;
+ mpFirstBandPoint->mnLineId = nLineId;
+ mpFirstBandPoint->mbEndPoint = bEndPoint;
+ mpFirstBandPoint->meLineType = eLineType;
+ mpFirstBandPoint->mpNextBandPoint = NULL;
+ return TRUE;
+ }
+
+ // look if line allready touched the band
+ ImplRegionBandPoint* pRegionBandPoint = mpFirstBandPoint;
+ ImplRegionBandPoint* pLastTestedRegionBandPoint = NULL;
+ while( pRegionBandPoint )
+ {
+ if ( pRegionBandPoint->mnLineId == nLineId )
+ {
+ if ( bEndPoint )
+ {
+ if( !pRegionBandPoint->mbEndPoint )
+ {
+ // remove old band point
+ if( !mpFirstBandPoint->mpNextBandPoint )
+ {
+ // if we've only got one point => replace first point
+ pRegionBandPoint->mnX = nX;
+ pRegionBandPoint->mbEndPoint = TRUE;
+ return TRUE;
+ }
+ else
+ {
+ // remove current point
+ if( !pLastTestedRegionBandPoint )
+ {
+ // remove and delete old first point
+ ImplRegionBandPoint* pSaveBandPoint = mpFirstBandPoint;
+ mpFirstBandPoint = mpFirstBandPoint->mpNextBandPoint;
+ delete pSaveBandPoint;
+ }
+ else
+ {
+ // remove and delete current band point
+ pLastTestedRegionBandPoint->mpNextBandPoint = pRegionBandPoint->mpNextBandPoint;
+ delete pRegionBandPoint;
+ }
+
+ break;
+ }
+ }
+ }
+ else
+ return FALSE;
+ }
+
+ // use next element
+ pLastTestedRegionBandPoint = pRegionBandPoint;
+ pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
+ }
+
+ // search appropriate position and insert point into the list
+ ImplRegionBandPoint* pNewRegionBandPoint;
+
+ pRegionBandPoint = mpFirstBandPoint;
+ pLastTestedRegionBandPoint = NULL;
+ while ( pRegionBandPoint )
+ {
+ // new point completly left? -> insert as first point
+ if ( nX <= pRegionBandPoint->mnX )
+ {
+ pNewRegionBandPoint = new ImplRegionBandPoint;
+ pNewRegionBandPoint->mnX = nX;
+ pNewRegionBandPoint->mnLineId = nLineId;
+ pNewRegionBandPoint->mbEndPoint = bEndPoint;
+ pNewRegionBandPoint->meLineType = eLineType;
+ pNewRegionBandPoint->mpNextBandPoint = pRegionBandPoint;
+
+ // connections to the new point
+ if ( !pLastTestedRegionBandPoint )
+ mpFirstBandPoint = pNewRegionBandPoint;
+ else
+ pLastTestedRegionBandPoint->mpNextBandPoint = pNewRegionBandPoint;
+
+ return TRUE;
+ }
+
+ // use next element
+ pLastTestedRegionBandPoint = pRegionBandPoint;
+ pRegionBandPoint = pRegionBandPoint->mpNextBandPoint;
+ }
+
+ // not inserted -> add to the end of the list
+ pNewRegionBandPoint = new ImplRegionBandPoint;
+ pNewRegionBandPoint->mnX = nX;
+ pNewRegionBandPoint->mnLineId = nLineId;
+ pNewRegionBandPoint->mbEndPoint = bEndPoint;
+ pNewRegionBandPoint->meLineType = eLineType;
+ pNewRegionBandPoint->mpNextBandPoint = NULL;
+
+ // connections to the new point
+ pLastTestedRegionBandPoint->mpNextBandPoint = pNewRegionBandPoint;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplRegionBand::MoveX( long nHorzMove )
+{
+ // move all x-separations
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ pSep->mnXLeft += nHorzMove;
+ pSep->mnXRight += nHorzMove;
+ pSep = pSep->mpNextSep;
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void ImplRegionBand::ScaleX( double fHorzScale )
+{
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ pSep->mnXLeft = FRound( pSep->mnXLeft * fHorzScale );
+ pSep->mnXRight = FRound( pSep->mnXRight * fHorzScale );
+ pSep = pSep->mpNextSep;
+ }
+}
+
+// -----------------------------------------------------------------------
+//
+// combine overlaping sparations
+
+BOOL ImplRegionBand::OptimizeBand()
+{
+ ImplRegionBandSep* pPrevSep = 0;
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ // remove?
+ if ( pSep->mbRemoved || (pSep->mnXRight < pSep->mnXLeft) )
+ {
+ ImplRegionBandSep* pOldSep = pSep;
+ if ( pSep == mpFirstSep )
+ mpFirstSep = pSep->mpNextSep;
+ else
+ pPrevSep->mpNextSep = pSep->mpNextSep;
+ pSep = pSep->mpNextSep;
+ delete pOldSep;
+ continue;
+ }
+
+ // overlaping separations? -> combine!
+ if ( pSep->mpNextSep )
+ {
+ if ( (pSep->mnXRight+1) >= pSep->mpNextSep->mnXLeft )
+ {
+ if ( pSep->mpNextSep->mnXRight > pSep->mnXRight )
+ pSep->mnXRight = pSep->mpNextSep->mnXRight;
+
+ ImplRegionBandSep* pOldSep = pSep->mpNextSep;
+ pSep->mpNextSep = pOldSep->mpNextSep;
+ delete pOldSep;
+ continue;
+ }
+ }
+
+ pPrevSep = pSep;
+ pSep = pSep->mpNextSep;
+ }
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+void ImplRegionBand::Union( long nXLeft, long nXRight )
+{
+ DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Union(): nxLeft > nXRight" );
+
+ // band empty? -> add element
+ if ( !mpFirstSep )
+ {
+ mpFirstSep = new ImplRegionBandSep;
+ mpFirstSep->mnXLeft = nXLeft;
+ mpFirstSep->mnXRight = nXRight;
+ mpFirstSep->mbRemoved = FALSE;
+ mpFirstSep->mpNextSep = NULL;
+ return;
+ }
+
+ // process real union
+ ImplRegionBandSep* pNewSep;
+ ImplRegionBandSep* pPrevSep = 0;
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ // new separation completely inside? nothing to do!
+ if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
+ return;
+
+ // new separation completly left? -> new separation!
+ if ( nXRight < pSep->mnXLeft )
+ {
+ pNewSep = new ImplRegionBandSep;
+ pNewSep->mnXLeft = nXLeft;
+ pNewSep->mnXRight = nXRight;
+ pNewSep->mbRemoved = FALSE;
+
+ pNewSep->mpNextSep = pSep;
+ if ( pSep == mpFirstSep )
+ mpFirstSep = pNewSep;
+ else
+ pPrevSep->mpNextSep = pNewSep;
+ break;
+ }
+
+ // new separation overlaping from left? -> extend boundary
+ if ( (nXRight >= pSep->mnXLeft) && (nXLeft <= pSep->mnXLeft) )
+ pSep->mnXLeft = nXLeft;
+
+ // new separation overlaping from right? -> extend boundary
+ if ( (nXLeft <= pSep->mnXRight) && (nXRight > pSep->mnXRight) )
+ {
+ pSep->mnXRight = nXRight;
+ break;
+ }
+
+ // not inserted, but last element? -> add to the end of the list
+ if ( !pSep->mpNextSep && (nXLeft > pSep->mnXRight) )
+ {
+ pNewSep = new ImplRegionBandSep;
+ pNewSep->mnXLeft = nXLeft;
+ pNewSep->mnXRight = nXRight;
+ pNewSep->mbRemoved = FALSE;
+
+ pSep->mpNextSep = pNewSep;
+ pNewSep->mpNextSep = NULL;
+ break;
+ }
+
+ pPrevSep = pSep;
+ pSep = pSep->mpNextSep;
+ }
+
+ OptimizeBand();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplRegionBand::Intersect( long nXLeft, long nXRight )
+{
+ DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Intersect(): nxLeft > nXRight" );
+
+ // band has been touched
+ mbTouched = TRUE;
+
+ // band empty? -> nothing to do
+ if ( !mpFirstSep )
+ return;
+
+ // process real intersection
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ // new separation completly outside? -> remove separation
+ if ( (nXRight < pSep->mnXLeft) || (nXLeft > pSep->mnXRight) )
+ // will be removed from the optimizer
+ pSep->mbRemoved = TRUE;
+
+ // new separation overlaping from left? -> reduce right boundary
+ if ( (nXLeft <= pSep->mnXLeft) &&
+ (nXRight <= pSep->mnXRight) &&
+ (nXRight >= pSep->mnXLeft) )
+ pSep->mnXRight = nXRight;
+
+ // new separation overlaping from right? -> reduce right boundary
+ if ( (nXLeft >= pSep->mnXLeft) &&
+ (nXLeft <= pSep->mnXRight) &&
+ (nXRight >= pSep->mnXRight) )
+ pSep->mnXLeft = nXLeft;
+
+ // new separation within the actual one? -> reduce both boundaries
+ if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
+ {
+ pSep->mnXRight = nXRight;
+ pSep->mnXLeft = nXLeft;
+ }
+
+ pSep = pSep->mpNextSep;
+ }
+
+ OptimizeBand();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplRegionBand::Exclude( long nXLeft, long nXRight )
+{
+ DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::Exclude(): nxLeft > nXRight" );
+
+ // band has been touched
+ mbTouched = TRUE;
+
+ // band empty? -> nothing to do
+ if ( !mpFirstSep )
+ return;
+
+ // process real exclusion
+ ImplRegionBandSep* pNewSep;
+ ImplRegionBandSep* pPrevSep = 0;
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ BOOL bSepProcessed = FALSE;
+
+ // new separation completely overlapping? -> remove separation
+ if ( (nXLeft <= pSep->mnXLeft) && (nXRight >= pSep->mnXRight) )
+ {
+ // will be removed from the optimizer
+ pSep->mbRemoved = TRUE;
+ bSepProcessed = TRUE;
+ }
+
+ // new separation overlaping from left? -> reduce boundary
+ if ( !bSepProcessed )
+ {
+ if ( (nXRight >= pSep->mnXLeft) && (nXLeft <= pSep->mnXLeft) )
+ {
+ pSep->mnXLeft = nXRight+1;
+ bSepProcessed = TRUE;
+ }
+ }
+
+ // new separation overlaping from right? -> reduce boundary
+ if ( !bSepProcessed )
+ {
+ if ( (nXLeft <= pSep->mnXRight) && (nXRight > pSep->mnXRight) )
+ {
+ pSep->mnXRight = nXLeft-1;
+ bSepProcessed = TRUE;
+ }
+ }
+
+ // new separation within the actual one? -> reduce boundary
+ // and add new entry for reminder
+ if ( !bSepProcessed )
+ {
+ if ( (nXLeft >= pSep->mnXLeft) && (nXRight <= pSep->mnXRight) )
+ {
+ pNewSep = new ImplRegionBandSep;
+ pNewSep->mnXLeft = pSep->mnXLeft;
+ pNewSep->mnXRight = nXLeft-1;
+ pNewSep->mbRemoved = FALSE;
+
+ pSep->mnXLeft = nXRight+1;
+
+ // connections from the new separation
+ pNewSep->mpNextSep = pSep;
+
+ // connections to the new separation
+ if ( pSep == mpFirstSep )
+ mpFirstSep = pNewSep;
+ else
+ pPrevSep->mpNextSep = pNewSep;
+ }
+ }
+
+ pPrevSep = pSep;
+ pSep = pSep->mpNextSep;
+ }
+
+ OptimizeBand();
+}
+
+// -----------------------------------------------------------------------
+
+void ImplRegionBand::XOr( long nXLeft, long nXRight )
+{
+ DBG_ASSERT( nXLeft <= nXRight, "ImplRegionBand::XOr(): nxLeft > nXRight" );
+
+ // #i46602# Reworked rectangle Xor
+ //
+ // In general, we can distinguish 11 cases of intersection
+ // (details below). The old implementation explicitely handled 7
+ // cases (numbered in the order of appearance, use CVS to get your
+ // hands on the old version), therefore, I've sticked to that
+ // order, and added four more cases. The code below references
+ // those numbers via #1, #2, etc.
+ //
+ // Num Mnem newX:oldX newY:oldY Description Result Can quit?
+ //
+ // #1 Empty band - - The band is empty, thus, simply add new bandSep just add Yes
+ //
+ // #2 apart - - The rectangles are disjunct, add new one as is just add Yes
+ //
+ // #3 atop == == The rectangles are _exactly_ the same, remove existing just remove Yes
+ //
+ // #4 around < > The new rectangle extends the old to both sides intersect No
+ //
+ // #5 left < < The new rectangle is left of the old (but intersects) intersect Yes
+ //
+ // #5b left-atop < == The new is left of the old, and coincides on the right intersect Yes
+ //
+ // #6 right > > The new is right of the old (but intersects) intersect No
+ //
+ // #6b right-atop == > The new is right of the old, and coincides on the left intersect No
+ //
+ // #7 inside > < The new is fully inside the old intersect Yes
+ //
+ // #8 inside-right > == The new is fully inside the old, coincides on the right intersect Yes
+ //
+ // #9 inside-left == < The new is fully inside the old, coincides on the left intersect Yes
+ //
+ //
+ // Then, to correctly perform XOr, the segment that's switched off
+ // (i.e. the overlapping part of the old and the new segment) must
+ // be extended by one pixel value at each border:
+ // 1 1
+ // 0 4 0 4
+ // 111100000001111
+ //
+ // Clearly, the leading band sep now goes from 0 to 3, and the
+ // trailing band sep from 11 to 14. This mimicks the xor look of a
+ // bitmap operation.
+ //
+
+ // band empty? -> add element
+ if ( !mpFirstSep )
+ {
+ mpFirstSep = new ImplRegionBandSep;
+ mpFirstSep->mnXLeft = nXLeft;
+ mpFirstSep->mnXRight = nXRight;
+ mpFirstSep->mbRemoved = FALSE;
+ mpFirstSep->mpNextSep = NULL;
+ return;
+ }
+
+ // process real xor
+ ImplRegionBandSep* pNewSep;
+ ImplRegionBandSep* pPrevSep = 0;
+ ImplRegionBandSep* pSep = mpFirstSep;
+
+ while ( pSep )
+ {
+ long nOldLeft( pSep->mnXLeft );
+ long nOldRight( pSep->mnXRight );
+
+ // did the current segment actually touch the new rect? If
+ // not, skip all comparisons, go on, loop and try to find
+ // intersecting bandSep
+ if( nXLeft <= nOldRight )
+ {
+ if( nXRight < nOldLeft )
+ {
+ // #2
+
+ // add _before_ current bandSep
+ pNewSep = new ImplRegionBandSep;
+ pNewSep->mnXLeft = nXLeft;
+ pNewSep->mnXRight = nXRight;
+ pNewSep->mpNextSep = pSep;
+ pNewSep->mbRemoved = FALSE;
+
+ // connections from the new separation
+ pNewSep->mpNextSep = pSep;
+
+ // connections to the new separation
+ if ( pSep == mpFirstSep )
+ mpFirstSep = pNewSep;
+ else
+ pPrevSep->mpNextSep = pNewSep;
+ pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
+ break;
+ }
+ else if( nXLeft == nOldLeft && nXRight == nOldRight )
+ {
+ // #3
+ pSep->mbRemoved = TRUE;
+ pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
+ break;
+ }
+ else if( nXLeft != nOldLeft && nXRight == nOldRight )
+ {
+ // # 5b, 8
+ if( nXLeft < nOldLeft )
+ {
+ nXRight = nOldLeft; // 5b
+ }
+ else
+ {
+ nXRight = nXLeft; // 8
+ nXLeft = nOldLeft;
+ }
+
+ pSep->mnXLeft = nXLeft;
+ pSep->mnXRight = nXRight-1;
+
+ pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
+ break;
+ }
+ else if( nXLeft == nOldLeft && nXRight != nOldRight )
+ {
+ // # 6b, 9
+
+ if( nXRight > nOldRight )
+ {
+ nXLeft = nOldRight+1; // 6b
+
+ // cannot break here, simply mark segment as removed,
+ // and go on with adapted nXLeft/nXRight
+ pSep->mbRemoved = TRUE;
+ }
+ else
+ {
+ pSep->mnXLeft = nXRight+1; // 9
+
+ pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
+ break;
+ }
+ }
+ else // if( nXLeft != nOldLeft && nXRight != nOldRight ) follows automatically
+ {
+ // #4,5,6,7
+ DBG_ASSERT( nXLeft != nOldLeft && nXRight != nOldRight,
+ "ImplRegionBand::XOr(): Case 4,5,6,7 expected all coordinates to be not equal!" );
+
+ // The plain-jane check would look like this:
+ //
+ // if( nXLeft < nOldLeft )
+ // {
+ // // #4,5
+ // if( nXRight > nOldRight )
+ // {
+ // // #4
+ // }
+ // else
+ // {
+ // // #5 done!
+ // }
+ // }
+ // else
+ // {
+ // // #6,7
+ // if( nXRight > nOldRight )
+ // {
+ // // #6
+ // }
+ // else
+ // {
+ // // #7 done!
+ // }
+ // }
+ //
+ // but since we generally don't have to care whether
+ // it's 4 or 6 (only that we must not stop processing
+ // here), condensed that in such a way that only the
+ // coordinates get shuffled into correct ordering.
+
+ if( nXLeft < nOldLeft )
+ ::std::swap( nOldLeft, nXLeft );
+
+ bool bDone( false );
+
+ if( nXRight < nOldRight )
+ {
+ ::std::swap( nOldRight, nXRight );
+ bDone = true;
+ }
+
+ // now, nOldLeft<nXLeft<=nOldRight<nXRight always
+ // holds. Note that we need the nXLeft<=nOldRight here, as
+ // the intersection part might be only one pixel (original
+ // nXLeft==nXRight)
+ DBG_ASSERT( nOldLeft<nXLeft && nXLeft<=nOldRight && nOldRight<nXRight,
+ "ImplRegionBand::XOr(): Case 4,5,6,7 expected coordinates to be ordered now!" );
+
+ pSep->mnXLeft = nOldLeft;
+ pSep->mnXRight = nXLeft-1;
+
+ nXLeft = nOldRight+1;
+ // nxRight is already setup correctly
+
+ if( bDone )
+ {
+ // add behind current bandSep
+ pNewSep = new ImplRegionBandSep;
+
+ pNewSep->mnXLeft = nXLeft;
+ pNewSep->mnXRight = nXRight;
+ pNewSep->mpNextSep = pSep->mpNextSep;
+ pNewSep->mbRemoved = FALSE;
+
+ // connections from the new separation
+ pSep->mpNextSep = pNewSep;
+
+ pPrevSep = NULL; // do not run accidentally into the "right" case when breaking the loop
+ break;
+ }
+ }
+ }
+
+ pPrevSep = pSep;
+ pSep = pSep->mpNextSep;
+ }
+
+ // new separation completely right of existing bandSeps ?
+ if( pPrevSep && nXLeft >= pPrevSep->mnXRight )
+ {
+ pNewSep = new ImplRegionBandSep;
+ pNewSep->mnXLeft = nXLeft;
+ pNewSep->mnXRight = nXRight;
+ pNewSep->mpNextSep = NULL;
+ pNewSep->mbRemoved = FALSE;
+
+ // connections from the new separation
+ pPrevSep->mpNextSep = pNewSep;
+ }
+
+ OptimizeBand();
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplRegionBand::IsInside( long nX )
+{
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ if ( (pSep->mnXLeft <= nX) && (pSep->mnXRight >= nX) )
+ return TRUE;
+
+ pSep = pSep->mpNextSep;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplRegionBand::IsOver( long nLeft, long nRight )
+{
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ if ( (pSep->mnXLeft < nRight) && (pSep->mnXRight > nLeft) )
+ return TRUE;
+
+ pSep = pSep->mpNextSep;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplRegionBand::IsInside( long nLeft, long nRight )
+{
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep )
+ {
+ if ( (pSep->mnXLeft >= nLeft) && (nRight <= pSep->mnXRight) )
+ return TRUE;
+
+ pSep = pSep->mpNextSep;
+ }
+
+ return FALSE;
+}
+
+// -----------------------------------------------------------------------
+
+long ImplRegionBand::GetXLeftBoundary() const
+{
+ DBG_ASSERT( mpFirstSep != NULL, "ImplRegionBand::XLeftBoundary -> no separation in band!" );
+
+ return mpFirstSep->mnXLeft;
+}
+
+// -----------------------------------------------------------------------
+
+long ImplRegionBand::GetXRightBoundary() const
+{
+ DBG_ASSERT( mpFirstSep != NULL, "ImplRegionBand::XRightBoundary -> no separation in band!" );
+
+ // search last separation
+ ImplRegionBandSep* pSep = mpFirstSep;
+ while ( pSep->mpNextSep )
+ pSep = pSep->mpNextSep;
+ return pSep->mnXRight;
+}
+
+// -----------------------------------------------------------------------
+
+BOOL ImplRegionBand::operator==( const ImplRegionBand& rRegionBand ) const
+{
+ ImplRegionBandSep* pOwnRectBandSep = mpFirstSep;
+ ImplRegionBandSep* pSecondRectBandSep = rRegionBand.mpFirstSep;
+ while ( pOwnRectBandSep && pSecondRectBandSep )
+ {
+ // get boundaries of current rectangle
+ long nOwnXLeft = pOwnRectBandSep->mnXLeft;
+ long nSecondXLeft = pSecondRectBandSep->mnXLeft;
+ if ( nOwnXLeft != nSecondXLeft )
+ return FALSE;
+
+ long nOwnXRight = pOwnRectBandSep->mnXRight;
+ long nSecondXRight = pSecondRectBandSep->mnXRight;
+ if ( nOwnXRight != nSecondXRight )
+ return FALSE;
+
+ // get next separation from current band
+ pOwnRectBandSep = pOwnRectBandSep->mpNextSep;
+
+ // get next separation from current band
+ pSecondRectBandSep = pSecondRectBandSep->mpNextSep;
+ }
+
+ // differnt number of separations?
+ if ( pOwnRectBandSep || pSecondRectBandSep )
+ return FALSE;
+
+ return TRUE;
+}
+
+// -----------------------------------------------------------------------
+
+ImplRegionBand* ImplRegionBand::SplitBand (const sal_Int32 nY)
+{
+ OSL_ASSERT(nY>mnYTop);
+ OSL_ASSERT(nY<=mnYBottom);
+
+ // Create a copy of the given band (we tell the constructor to copy the points together
+ // with the seps.)
+ ImplRegionBand* pLowerBand = new ImplRegionBand(*this, false);
+
+ // Adapt vertical coordinates.
+ mnYBottom = nY-1;
+ pLowerBand->mnYTop = nY;
+
+ // Insert new band into list of bands.
+ pLowerBand->mpNextBand = mpNextBand;
+ mpNextBand = pLowerBand;
+ pLowerBand->mpPrevBand = this;
+ if (pLowerBand->mpNextBand != NULL)
+ pLowerBand->mpNextBand->mpPrevBand = pLowerBand;
+
+ return pLowerBand;
+}