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