xref: /AOO41X/main/sw/source/core/bastyp/swregion.cxx (revision efeef26f81c84063fb0a91bde3856d4a51172d90)
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