blob: 2dedaf980a7ce52d5f18d3642aa3262d2c178296 [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the 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()
|*
|* Ersterstellung MA 28. Oct. 92
|* Letzte Aenderung MA 01. Feb. 93
|*
|*************************************************************************/
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.
|* Ersterstellung MA 28. Oct. 92
|* Letzte Aenderung MA 09. Sep. 93
|*
|*************************************************************************/
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.
|* Ersterstellung MA 16. Apr. 93
|* Letzte Aenderung MA 21. Apr. 93
|*
|*************************************************************************/
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;
}
}
}
}
}