Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*************************************************************************
3 : : *
4 : : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : : *
6 : : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : : *
8 : : * OpenOffice.org - a multi-platform office productivity suite
9 : : *
10 : : * This file is part of OpenOffice.org.
11 : : *
12 : : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : : * it under the terms of the GNU Lesser General Public License version 3
14 : : * only, as published by the Free Software Foundation.
15 : : *
16 : : * OpenOffice.org is distributed in the hope that it will be useful,
17 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : : * GNU Lesser General Public License version 3 for more details
20 : : * (a copy is included in the LICENSE file that accompanied this code).
21 : : *
22 : : * You should have received a copy of the GNU Lesser General Public License
23 : : * version 3 along with OpenOffice.org. If not, see
24 : : * <http://www.openoffice.org/license.html>
25 : : * for a copy of the LGPLv3 License.
26 : : *
27 : : ************************************************************************/
28 : :
29 : : #include "swrect.hxx"
30 : : #include "swregion.hxx"
31 : : #include "swtypes.hxx"
32 : :
33 : 64755 : SwRegionRects::SwRegionRects( const SwRect &rStartRect, sal_uInt16 nInit ) :
34 : : SwRects(),
35 : 64755 : aOrigin( rStartRect )
36 : : {
37 [ + - ]: 64755 : reserve(nInit);
38 [ + - ]: 64755 : push_back( aOrigin );
39 : 64755 : }
40 : :
41 : : // If <rDel> is sal_True then this Rect will be overwritten by <rRect> at
42 : : // position <nPos>. Otherwise <rRect> is attached at the end.
43 : 112574 : inline void SwRegionRects::InsertRect( const SwRect &rRect,
44 : : const sal_uInt16 nPos, bool &rDel )
45 : : {
46 [ + + ]: 112574 : if( rDel )
47 : : {
48 : 63901 : (*this)[nPos] = rRect;
49 : 63901 : rDel = false;
50 : : }
51 : : else
52 : : {
53 : 48673 : push_back( rRect );
54 : : }
55 : 112574 : }
56 : :
57 : : /** Delete all overlaps of the Rects in array with the given <rRect>
58 : :
59 : : To do so, all existing rectangles have to be either split or deleted.
60 : :
61 : : @param rRect rectangle with the area that should be deleted
62 : : */
63 : 88361 : void SwRegionRects::operator-=( const SwRect &rRect )
64 : : {
65 : 88361 : sal_uInt16 nMax = size();
66 [ + + ]: 330772 : for ( sal_uInt16 i = 0; i < nMax; ++i )
67 : : {
68 [ + + ]: 242411 : if ( rRect.IsOver( (*this)[i] ) )
69 : : {
70 : 73628 : SwRect aTmp( (*this)[i] );
71 : 73628 : SwRect aInter( aTmp );
72 [ + - ]: 73628 : aInter._Intersection( rRect );
73 : :
74 : : // The first Rect that should be inserted takes position of i.
75 : : // This avoids one Delete() call.
76 : 73628 : bool bDel = true;
77 : :
78 : : // now split; only those rectangles should be left over that are in
79 : : // the "old" but not in the "new" area; hence, not in intersection.
80 : : long nTmp;
81 [ + + ]: 73628 : if ( 0 < (nTmp = aInter.Top() - aTmp.Top()) )
82 : : {
83 : 25326 : const long nOldVal = aTmp.Height();
84 : 25326 : aTmp.Height(nTmp);
85 [ + - ]: 25326 : InsertRect( aTmp, i, bDel );
86 : 25326 : aTmp.Height( nOldVal );
87 : : }
88 : :
89 : 73628 : aTmp.Top( aInter.Top() + aInter.Height() );
90 [ + + ]: 73628 : if ( aTmp.Height() > 0 )
91 [ + - ]: 19431 : InsertRect( aTmp, i, bDel );
92 : :
93 : 73628 : aTmp.Top( aInter.Top() );
94 : 73628 : aTmp.Bottom( aInter.Bottom() );
95 [ + + ]: 73628 : if ( 0 < (nTmp = aInter.Left() - aTmp.Left()) )
96 : : {
97 : 36341 : const long nOldVal = aTmp.Width();
98 : 36341 : aTmp.Width( nTmp );
99 [ + - ]: 36341 : InsertRect( aTmp, i, bDel );
100 : 36341 : aTmp.Width( nOldVal );
101 : : }
102 : :
103 : 73628 : aTmp.Left( aInter.Left() + aInter.Width() ); //+1?
104 [ + + ]: 73628 : if ( aTmp.Width() > 0 )
105 [ + - ]: 31476 : InsertRect( aTmp, i, bDel );
106 : :
107 [ + + ]: 73628 : if( bDel )
108 : : {
109 [ + - ][ + - ]: 9727 : erase( begin() + i );
110 : 9727 : --i; // so that we don't forget any
111 : 73628 : --nMax; // so that we don't check too much
112 : : }
113 : : }
114 : : }
115 : 88361 : }
116 : :
117 : : /** invert current rectangle
118 : :
119 : : Change the shape, such that holes with be areas and areas are holes now.
120 : :
121 : : Note: If no rects were removed, then the shape is identical to the original
122 : : shape. As a result, it will be a NULL-SRectangle after inverting.
123 : : */
124 : 7401 : void SwRegionRects::Invert()
125 : : {
126 : : // not very elegant and fast, but efficient:
127 : : // Create a new region and remove all areas that are left over. Afterwards
128 : : // copy all values.
129 : :
130 : : // To avoid unnecessary memory requirements, create a "useful" initial size:
131 : : // Number of rectangles in this area * 2 + 2 for the special case of a
132 : : // single hole (so four Rects in the inverse case).
133 [ + - ]: 7401 : SwRegionRects aInvRegion( aOrigin, size()*2+2 );
134 [ + - ][ + - ]: 40678 : for( const_iterator it = begin(); it != end(); ++it )
[ + + ]
135 [ + - ]: 33277 : aInvRegion -= *it;
136 : :
137 : : // overwrite all existing
138 : 7401 : swap( aInvRegion );
139 : 7401 : }
140 : :
141 : 58404 : inline SwTwips CalcArea( const SwRect &rRect )
142 : : {
143 : 58404 : return rRect.Width() * rRect.Height();
144 : : }
145 : :
146 : : // combine all adjacent rectangles
147 : 6898 : void SwRegionRects::Compress( bool bFuzzy )
148 : : {
149 [ + + ]: 20154 : for ( size_type i = 0; i < size(); ++i )
150 : : {
151 [ + + ]: 24387 : for ( size_type j = i+1; j < size(); ++j )
152 : : {
153 : : // If one rectangle contains a second completely than the latter
154 : : // does not need to be stored and can be deleted
155 [ + + ]: 15582 : if ( (*this)[i].IsInside( (*this)[j] ) )
156 : : {
157 [ + - ][ + - ]: 981 : erase( begin() + j );
158 : 981 : --j;
159 : : }
160 [ - + ]: 14601 : else if ( (*this)[j].IsInside( (*this)[i] ) )
161 : : {
162 : 0 : (*this)[i] = (*this)[j];
163 [ # # ][ # # ]: 0 : erase( begin() + j );
164 : 0 : i = -1;
165 : 0 : break;
166 : : }
167 : : else
168 : : {
169 : : // If two rectangles have the same area of their union minus the
170 : : // intersection then one of them can be deleted.
171 : : // For combining as much as possible (and for having less single
172 : : // paints), the area of the union can be a little bit larger:
173 : : // ( 9622 * 141.5 = 1361513 ~= a quarter (1/4) centimeter wider
174 : : // than the width of a A4 page
175 [ + - ]: 14601 : const long nFuzzy = bFuzzy ? 1361513 : 0;
176 : 14601 : SwRect aUnion( (*this)[i] );
177 [ + - ]: 14601 : aUnion.Union( (*this)[j] );
178 : 14601 : SwRect aInter( (*this)[i] );
179 [ + - ]: 14601 : aInter.Intersection( (*this)[j] );
180 [ + + ]: 29202 : if ( (::CalcArea( (*this)[i] ) +
181 : 14601 : ::CalcArea( (*this)[j] ) + nFuzzy) >=
182 : 14601 : (::CalcArea( aUnion ) - CalcArea( aInter )) )
183 : : {
184 : 4451 : (*this)[i] = aUnion;
185 [ + - ][ + - ]: 4451 : erase( begin() + j );
186 : 14601 : i = -1;
187 : : break;
188 : : }
189 : : }
190 : : }
191 : : }
192 : 6898 : }
193 : :
194 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|