diff options
Diffstat (limited to 'sw/source/core/bastyp/swregion.cxx')
-rw-r--r-- | sw/source/core/bastyp/swregion.cxx | 247 |
1 files changed, 247 insertions, 0 deletions
diff --git a/sw/source/core/bastyp/swregion.cxx b/sw/source/core/bastyp/swregion.cxx new file mode 100644 index 000000000000..5b812314da95 --- /dev/null +++ b/sw/source/core/bastyp/swregion.cxx @@ -0,0 +1,247 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * 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_sw.hxx" + + + + +#include <tools/debug.hxx> +#include "swtypes.hxx" +#include "swrect.hxx" +#include "swregion.hxx" + + +SV_IMPL_VARARR( SwRects, SwRect ); + +/************************************************************************* +|* SwRegionRects::SwRegionRects() +|*************************************************************************/ + +SwRegionRects::SwRegionRects( const SwRect &rStartRect, sal_uInt16 nInit, + sal_uInt16 nGrow ) : + SwRects( (sal_uInt8)nInit, (sal_uInt8)nGrow ), + aOrigin( rStartRect ) +{ + Insert( aOrigin, 0 ); +} + +/************************************************************************* + * inline InsertRect() + * + * InsertRect() wird nur von operator-=() gerufen. + * Wenn bDel == sal_True ist, dann wird das Rect an der Position nPos mit + * rRect ueberschrieben, ansonsten wird rRect hinten angehaengt. + *************************************************************************/ + +inline void SwRegionRects::InsertRect( const SwRect &rRect, const sal_uInt16 nPos, + sal_Bool &rDel ) +{ + if( rDel ) + { + pData = (SwRect*)pData; // looks weird but seems to help gcc ->i78417 + *(pData+nPos) = rRect; + rDel = sal_False; + } + else + Insert( rRect, Count() ); +} + +/************************************************************************* +|* +|* SwRegionRects::operator-=() +|* +|* Beschreibung Alle Ueberschneidungen der Rechtecke, die sich +|* gerade im Array befinden, mit dem uebergebenen Rechteck werden +|* entfernt. +|* Dazu muessen die vorhandenen Rechtecke entweder aufgeteilt oder +|* geloescht werden. +|* +|*************************************************************************/ + +void SwRegionRects::operator-=( const SwRect &rRect ) +{ + sal_uInt16 nMax = Count(); + for ( sal_uInt16 i = 0; i < nMax; ++i ) + { + if ( rRect.IsOver( *(pData+i) ) ) + { + SwRect aTmp( *(pData+i) ); + SwRect aInter( aTmp ); + aInter._Intersection( rRect ); + + // Das erste Rect, das wir inserten wollen, nimmt die + // Stelle von i ein. So ersparen wir uns das Delete(). + sal_Bool bDel = sal_True; + + //Jetzt aufteilen das Teil: Es sollen diejenigen Rechtecke + //zurueckbleiben, die im alten aber nicht im neuen liegen. + //Sprich alle Rechtecke die im alten aber nicht in der Intersection + //liegen. + long nTmp; + if ( 0 < (nTmp = aInter.Top() - aTmp.Top()) ) + { + const long nOldVal = aTmp.Height(); + aTmp.Height(nTmp); + InsertRect( aTmp, i, bDel ); + aTmp.Height( nOldVal ); + } + + aTmp.Top( aInter.Top() + aInter.Height() ); + if ( aTmp.Height() > 0 ) + InsertRect( aTmp, i, bDel ); + + aTmp.Top( aInter.Top() ); + aTmp.Bottom( aInter.Bottom() ); + if ( 0 < (nTmp = aInter.Left() - aTmp.Left()) ) + { + const long nOldVal = aTmp.Width(); + aTmp.Width( nTmp ); + InsertRect( aTmp, i, bDel ); + aTmp.Width( nOldVal ); + } + + aTmp.Left( aInter.Left() + aInter.Width() ); //+1? + if ( aTmp.Width() > 0 ) + InsertRect( aTmp, i, bDel ); + + if( bDel ) + { + Remove( i ); + --i; //Damit wir keinen uebergehen. + --nMax; //Damit wir keinen zuviel verarbeiten. + } + } + } + +} + +/************************************************************************* + * SwRegionRects::Invert() + * + * Bezugspunkt ist aOrigin, das Original-SRectangle. + * Aus Loechern werden Flaechen, aus Flaechen werden Loecher. + * Ein Hinweis: Wenn keine Rects abgezogen wurden, so ist das enthaltene + * Rechteck identisch mit aOrigin. Nach Invert() besteht die Region aus + * einem Null-SRectangle. + *************************************************************************/ + +void SwRegionRects::Invert() +{ + // Nicht besonders elegant und schnell, aber wirkungsvoll: + // Wir legen eine weitere Region an und ziehen alle Flaechen ab, + // die in uns noch uebrig geblieben sind. Danach werden alle + // Werte uebertragen. + + // Um unuetze Speicheranforderungen zu vermeiden versuchen wir die + // iniale Groesse moeglichst brauchbar anzulegen: + // Anzahl der Rechtecke in der Region * 2 + 2 + // plus zwei um den Sonderfall eines einzelnen Loches (macht vier + // Rechtecke im inversen Fall) abzudecken. + + SwRegionRects aInvRegion( aOrigin, Count()*2+2 ); + const SwRect *pDat = GetData(); + for( sal_uInt16 i = 0; i < Count(); ++pDat, ++i ) + aInvRegion -= *pDat; + + sal_uInt16 nCpy = Count(), nDel = 0; + if( aInvRegion.Count() < Count() ) + { + nDel = Count() - aInvRegion.Count(); + nCpy = aInvRegion.Count(); + } + // alle vorhandenen ueberschreiben + memcpy( pData, aInvRegion.GetData(), nCpy * sizeof( SwRect )); + + if( nCpy < aInvRegion.Count() ) + Insert( &aInvRegion, nCpy, nCpy ); + else if( nDel ) + Remove( nCpy, nDel ); +} +/************************************************************************* +|* +|* SwRegionRects::Compress() +|* +|* Beschreibung Zusammenfassen von benachbarten Rechtecken. +|* +|*************************************************************************/ +inline SwTwips CalcArea( const SwRect &rRect ) +{ + return rRect.Width() * rRect.Height(); +} + + +void SwRegionRects::Compress( sal_Bool bFuzzy ) +{ + for ( int i = 0; i < Count(); ++i ) + { + for ( int j = i+1; j < Count(); ++j ) + { + //Wenn zwei Rechtecke ineinanderliegen, so ist eins davon + //uberfluessig. + if ( (*(pData + i)).IsInside( *(pData + j) ) ) + { + Remove( static_cast<sal_uInt16>(j), 1 ); + --j; + } + else if ( (*(pData + j)).IsInside( *(pData + i) ) ) + { + *(pData + i) = *(pData + j); + Remove( static_cast<sal_uInt16>(j), 1 ); + i = -1; + break; + } + else + { + //Wenn zwei Rechtecke dieselbe Flaeche haben wie deren + //Union abzueglich deren Intersection, so ist eines + //davon ueberfluessig. + //Um moeglichst viel zusammenzufassen und in der Folge + //moeglichst wenig einzelne Paints zu haben darf die Flaeche + //der Union ruhig ein bischen groesser sein + //( 9622 * 141.5 = 1361513 ~= ein virtel Zentimeter ueber die + // Breite einer DINA4 Seite) + const long nFuzzy = bFuzzy ? 1361513 : 0; + SwRect aUnion( *(pData + i) );aUnion.Union( *(pData + j) ); + SwRect aInter( *(pData + i) );aInter.Intersection( *(pData + j)); + if ( (::CalcArea( *(pData + i) ) + + ::CalcArea( *(pData + j) ) + nFuzzy) >= + (::CalcArea( aUnion ) - CalcArea( aInter )) ) + { + *(pData + i) = aUnion; + Remove( static_cast<sal_uInt16>(j), 1 ); + i = -1; + break; + } + } + } + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |