text: /**************************************************************
   * 
   * 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;
  				}
  			}
  		}
  	}
  }
  
  