xref: /trunk/main/sw/source/core/bastyp/swregion.cxx (revision efeef26f)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sw.hxx"
26 
27 
28 
29 
30 #include <tools/debug.hxx>
31 #include "swtypes.hxx"
32 #include "swrect.hxx"
33 #include "swregion.hxx"
34 
35 
36 SV_IMPL_VARARR( SwRects, SwRect );
37 
38 /*************************************************************************
39 |*
40 |*	SwRegionRects::SwRegionRects()
41 |*
42 |*	Ersterstellung		MA 28. Oct. 92
43 |*	Letzte Aenderung	MA 01. Feb. 93
44 |*
45 |*************************************************************************/
46 
SwRegionRects(const SwRect & rStartRect,sal_uInt16 nInit,sal_uInt16 nGrow)47 SwRegionRects::SwRegionRects( const SwRect &rStartRect, sal_uInt16 nInit,
48 														sal_uInt16 nGrow ) :
49 	SwRects( (sal_uInt8)nInit, (sal_uInt8)nGrow ),
50 	aOrigin( rStartRect )
51 {
52 	Insert( aOrigin, 0 );
53 }
54 
55 /*************************************************************************
56  *						inline InsertRect()
57  *
58  * InsertRect() wird nur von operator-=() gerufen.
59  * Wenn bDel == sal_True ist, dann wird das Rect an der Position nPos mit
60  * rRect ueberschrieben, ansonsten wird rRect hinten angehaengt.
61  *************************************************************************/
62 
InsertRect(const SwRect & rRect,const sal_uInt16 nPos,sal_Bool & rDel)63 inline void SwRegionRects::InsertRect( const SwRect &rRect, const sal_uInt16 nPos,
64 									   sal_Bool &rDel )
65 {
66 	if( rDel )
67 	{
68         pData = (SwRect*)pData; // looks weird but seems to help gcc ->i78417
69 		*(pData+nPos) = rRect;
70 		rDel = sal_False;
71 	}
72 	else
73 		Insert( rRect, Count() );
74 }
75 
76 /*************************************************************************
77 |*
78 |*	SwRegionRects::operator-=()
79 |*
80 |*	Beschreibung		Alle Ueberschneidungen der Rechtecke, die sich
81 |*		gerade im Array befinden, mit dem uebergebenen Rechteck werden
82 |*		entfernt.
83 |*		Dazu muessen die vorhandenen Rechtecke entweder aufgeteilt oder
84 |*		geloescht werden.
85 |*	Ersterstellung		MA 28. Oct. 92
86 |*	Letzte Aenderung	MA 09. Sep. 93
87 |*
88 |*************************************************************************/
89 
operator -=(const SwRect & rRect)90 void SwRegionRects::operator-=( const SwRect &rRect )
91 {
92 	sal_uInt16 nMax = Count();
93 	for ( sal_uInt16 i = 0; i < nMax; ++i )
94 	{
95 		if ( rRect.IsOver( *(pData+i) ) )
96 		{
97 			SwRect aTmp( *(pData+i) );
98 			SwRect aInter( aTmp );
99 			aInter._Intersection( rRect );
100 
101 			// Das erste Rect, das wir inserten wollen, nimmt die
102 			// Stelle von i ein. So ersparen wir uns das Delete().
103 			sal_Bool bDel = sal_True;
104 
105 			//Jetzt aufteilen das Teil: Es sollen diejenigen Rechtecke
106 			//zurueckbleiben, die im alten aber nicht im neuen liegen.
107 			//Sprich alle Rechtecke die im alten aber nicht in der Intersection
108 			//liegen.
109 			long nTmp;
110 			if ( 0 < (nTmp = aInter.Top() - aTmp.Top()) )
111 			{
112 				const long nOldVal = aTmp.Height();
113 				aTmp.Height(nTmp);
114 				InsertRect( aTmp, i, bDel );
115 				aTmp.Height( nOldVal );
116 			}
117 
118 			aTmp.Top( aInter.Top() + aInter.Height() );
119 			if ( aTmp.Height() > 0 )
120 				InsertRect( aTmp, i, bDel );
121 
122 			aTmp.Top( aInter.Top() );
123 			aTmp.Bottom( aInter.Bottom() );
124 			if ( 0 < (nTmp = aInter.Left() - aTmp.Left()) )
125 			{
126 				const long nOldVal = aTmp.Width();
127 				aTmp.Width( nTmp );
128 				InsertRect( aTmp, i, bDel );
129 				aTmp.Width( nOldVal );
130 			}
131 
132 			aTmp.Left( aInter.Left() + aInter.Width() ); //+1?
133 			if ( aTmp.Width() > 0 )
134 				InsertRect( aTmp, i, bDel );
135 
136 			if( bDel )
137 			{
138 				Remove( i );
139 				--i;			  //Damit wir keinen uebergehen.
140 				--nMax; 		  //Damit wir keinen zuviel verarbeiten.
141 			}
142 		}
143 	}
144 
145 }
146 
147 /*************************************************************************
148  *						SwRegionRects::Invert()
149  *
150  * Bezugspunkt ist aOrigin, das Original-SRectangle.
151  * Aus Loechern werden Flaechen, aus Flaechen werden Loecher.
152  * Ein Hinweis: Wenn keine Rects abgezogen wurden, so ist das enthaltene
153  * Rechteck identisch mit aOrigin. Nach Invert() besteht die Region aus
154  * einem Null-SRectangle.
155  *************************************************************************/
156 
Invert()157 void SwRegionRects::Invert()
158 {
159 	// Nicht besonders elegant und schnell, aber wirkungsvoll:
160 	// Wir legen eine weitere Region an und ziehen alle Flaechen ab,
161 	// die in uns noch uebrig geblieben sind. Danach werden alle
162 	// Werte uebertragen.
163 
164 	// Um unuetze Speicheranforderungen zu vermeiden versuchen wir die
165 	// iniale Groesse moeglichst brauchbar anzulegen:
166 	// Anzahl der Rechtecke in der Region * 2 + 2
167 	// plus zwei um den Sonderfall eines einzelnen Loches (macht vier
168 	// Rechtecke im inversen Fall) abzudecken.
169 
170 	SwRegionRects aInvRegion( aOrigin, Count()*2+2 );
171 	const SwRect *pDat = GetData();
172 	for( sal_uInt16 i = 0; i < Count(); ++pDat, ++i )
173 		aInvRegion -= *pDat;
174 
175 	sal_uInt16 nCpy = Count(), nDel = 0;
176 	if( aInvRegion.Count() < Count() )
177 	{
178 		nDel = Count() - aInvRegion.Count();
179 		nCpy = aInvRegion.Count();
180 	}
181 	// alle vorhandenen ueberschreiben
182 	memcpy( pData, aInvRegion.GetData(), nCpy * sizeof( SwRect ));
183 
184 	if( nCpy < aInvRegion.Count() )
185 		Insert( &aInvRegion, nCpy, nCpy );
186 	else if( nDel )
187 		Remove( nCpy, nDel );
188 }
189 /*************************************************************************
190 |*
191 |*	SwRegionRects::Compress()
192 |*
193 |*	Beschreibung		Zusammenfassen von benachbarten Rechtecken.
194 |*	Ersterstellung		MA 16. Apr. 93
195 |*	Letzte Aenderung	MA 21. Apr. 93
196 |*
197 |*************************************************************************/
CalcArea(const SwRect & rRect)198 inline SwTwips CalcArea( const SwRect &rRect )
199 {
200 	return rRect.Width() * rRect.Height();
201 }
202 
203 
Compress(sal_Bool bFuzzy)204 void SwRegionRects::Compress( sal_Bool bFuzzy )
205 {
206 	for ( int i = 0; i < Count(); ++i )
207 	{
208 		for ( int j = i+1; j < Count(); ++j )
209 		{
210 			//Wenn zwei Rechtecke ineinanderliegen, so ist eins davon
211 			//uberfluessig.
212 			if ( (*(pData + i)).IsInside( *(pData + j) ) )
213 			{
214 				Remove( static_cast<sal_uInt16>(j), 1 );
215 				--j;
216 			}
217 			else if ( (*(pData + j)).IsInside( *(pData + i) ) )
218 			{
219 				*(pData + i) = *(pData + j);
220 				Remove( static_cast<sal_uInt16>(j), 1 );
221 				i = -1;
222 				break;
223 			}
224 			else
225 			{
226 				//Wenn zwei Rechtecke dieselbe Flaeche haben wie deren
227 				//Union abzueglich deren Intersection, so ist eines
228 				//davon ueberfluessig.
229 				//Um moeglichst viel zusammenzufassen und in der Folge
230 				//moeglichst wenig einzelne Paints zu haben darf die Flaeche
231 				//der Union ruhig ein bischen groesser sein
232 				//( 9622 * 141.5 = 1361513 ~= ein virtel Zentimeter ueber die
233 				//						      Breite einer DINA4 Seite)
234 				const long nFuzzy = bFuzzy ? 1361513 : 0;
235 				SwRect aUnion( *(pData + i) );aUnion.Union( *(pData + j) );
236 				SwRect aInter( *(pData + i) );aInter.Intersection( *(pData + j));
237 				if ( (::CalcArea( *(pData + i) ) +
238 					  ::CalcArea( *(pData + j) ) + nFuzzy) >=
239 					 (::CalcArea( aUnion ) - CalcArea( aInter )) )
240 				{
241 					*(pData + i) = aUnion;
242 					Remove( static_cast<sal_uInt16>(j), 1 );
243 					i = -1;
244 					break;
245 				}
246 			}
247 		}
248 	}
249 }
250 
251