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 : :
30 : : #include <editeng/txtrange.hxx>
31 : : #include <math.h>
32 : : #include <tools/poly.hxx>
33 : : #include <tools/debug.hxx>
34 : : #include <basegfx/polygon/b2dpolygon.hxx>
35 : : #include <basegfx/polygon/b2dpolygontools.hxx>
36 : :
37 : : #include <vector>
38 : :
39 : 16 : TextRanger::TextRanger( const basegfx::B2DPolyPolygon& rPolyPolygon,
40 : : const basegfx::B2DPolyPolygon* pLinePolyPolygon,
41 : : sal_uInt16 nCacheSz, sal_uInt16 nLft, sal_uInt16 nRght,
42 : : sal_Bool bSimpl, sal_Bool bInnr, sal_Bool bVert ) :
43 : : pBound( NULL ),
44 : : nCacheSize( nCacheSz ),
45 : : nRight( nRght ),
46 : : nLeft( nLft ),
47 : : nUpper( 0 ),
48 : : nLower( 0 ),
49 : : nPointCount( 0 ),
50 : : bSimple( bSimpl ),
51 : : bInner( bInnr ),
52 : 16 : bVertical( bVert )
53 : : {
54 : : #ifdef DBG_UTIL
55 : : bFlag3 = bFlag4 = bFlag5 = bFlag6 = bFlag7 = sal_False;
56 : : #endif
57 [ + - ]: 16 : sal_uInt32 nCount(rPolyPolygon.count());
58 [ + - ][ + - ]: 16 : mpPolyPolygon = new PolyPolygon( (sal_uInt16)nCount );
59 : :
60 [ + + ]: 32 : for(sal_uInt32 i(0L); i < nCount; i++)
61 : : {
62 [ + - ][ + - ]: 16 : const basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(i).getDefaultAdaptiveSubdivision());
[ + - ]
63 [ + - ]: 16 : nPointCount += aCandidate.count();
64 [ + - ][ + - ]: 16 : mpPolyPolygon->Insert( Polygon(aCandidate), (sal_uInt16)i );
[ + - ]
65 [ + - ]: 16 : }
66 : :
67 [ - + ]: 16 : if( pLinePolyPolygon )
68 : : {
69 [ # # ]: 0 : nCount = pLinePolyPolygon->count();
70 [ # # ][ # # ]: 0 : mpLinePolyPolygon = new PolyPolygon();
71 : :
72 [ # # ]: 0 : for(sal_uInt32 i(0L); i < nCount; i++)
73 : : {
74 [ # # ][ # # ]: 0 : const basegfx::B2DPolygon aCandidate(pLinePolyPolygon->getB2DPolygon(i).getDefaultAdaptiveSubdivision());
[ # # ]
75 [ # # ]: 0 : nPointCount += aCandidate.count();
76 [ # # ][ # # ]: 0 : mpLinePolyPolygon->Insert( Polygon(aCandidate), (sal_uInt16)i );
[ # # ]
77 [ # # ]: 0 : }
78 : : }
79 : : else
80 : 16 : mpLinePolyPolygon = NULL;
81 : 16 : }
82 : :
83 : :
84 : 16 : TextRanger::~TextRanger()
85 : : {
86 : 16 : mRangeCache.clear();
87 [ + - ][ + - ]: 16 : delete mpPolyPolygon;
88 [ - + ][ # # ]: 16 : delete mpLinePolyPolygon;
89 : 16 : }
90 : :
91 : : /* TextRanger::SetVertical(..)
92 : : If there's is a change in the writing direction,
93 : : the cache has to be cleared.
94 : : */
95 : 0 : void TextRanger::SetVertical( sal_Bool bNew )
96 : : {
97 [ # # ]: 0 : if( IsVertical() != bNew )
98 : : {
99 : 0 : bVertical = bNew;
100 : 0 : mRangeCache.clear();
101 : : }
102 : 0 : }
103 : :
104 : : //! SvxBoundArgs is used to perform temporary calculations on a range array.
105 : : //! Temporary instances are created in TextRanger::GetTextRanges()
106 : 16 : class SvxBoundArgs
107 : : {
108 : : std::vector<bool> aBoolArr;
109 : : LongDqPtr pLongArr;
110 : : TextRanger *pTextRanger;
111 : : long nMin;
112 : : long nMax;
113 : : long nTop;
114 : : long nBottom;
115 : : long nUpDiff;
116 : : long nLowDiff;
117 : : long nUpper;
118 : : long nLower;
119 : : long nStart;
120 : : long nEnd;
121 : : sal_uInt16 nCut;
122 : : sal_uInt16 nLast;
123 : : sal_uInt16 nNext;
124 : : sal_uInt8 nAct;
125 : : sal_uInt8 nFirst;
126 : : sal_Bool bClosed : 1;
127 : : sal_Bool bInner : 1;
128 : : sal_Bool bMultiple : 1;
129 : : sal_Bool bConcat : 1;
130 : : sal_Bool bRotate : 1;
131 : : void NoteRange( bool bToggle );
132 : : long Cut( long nY, const Point& rPt1, const Point& rPt2 );
133 : : void Add();
134 : : void _NoteFarPoint( long nPx, long nPyDiff, long nDiff );
135 : 0 : void NoteFarPoint( long nPx, long nPyDiff, long nDiff )
136 [ # # ]: 0 : { if( nDiff ) _NoteFarPoint( nPx, nPyDiff, nDiff ); }
137 : : long CalcMax( const Point& rPt1, const Point& rPt2, long nRange, long nFar );
138 : : void CheckCut( const Point& rLst, const Point& rNxt );
139 [ # # ]: 0 : inline long A( const Point& rP ) const { return bRotate ? rP.Y() : rP.X(); }
140 [ - + ]: 96 : inline long B( const Point& rP ) const { return bRotate ? rP.X() : rP.Y(); }
141 : : public:
142 : : SvxBoundArgs( TextRanger* pRanger, LongDqPtr pLong, const Range& rRange );
143 : 64 : void NotePoint( const long nA ) { NoteMargin( nA - nStart, nA + nEnd ); }
144 : 111 : void NoteMargin( const long nL, const long nR )
145 [ + + ][ - + ]: 111 : { if( nMin > nL ) nMin = nL; if( nMax < nR ) nMax = nR; }
146 : : sal_uInt16 Area( const Point& rPt );
147 : : void NoteUpLow( long nA, const sal_uInt8 nArea );
148 : : void Calc( const PolyPolygon& rPoly );
149 : : void Concat( const PolyPolygon* pPoly );
150 : : // inlines
151 [ # # ]: 0 : void NoteLast() { if( bMultiple ) NoteRange( nAct == nFirst ); }
152 : 16 : void SetClosed( const sal_Bool bNew ){ bClosed = bNew; }
153 : 16 : sal_Bool IsClosed() const { return bClosed; }
154 : 0 : void SetConcat( const sal_Bool bNew ){ bConcat = bNew; }
155 : 18 : sal_Bool IsConcat() const { return bConcat; }
156 : : sal_uInt8 GetAct() const { return nAct; }
157 : : };
158 : :
159 : 16 : SvxBoundArgs::SvxBoundArgs( TextRanger* pRanger, LongDqPtr pLong,
160 : : const Range& rRange )
161 : : : pLongArr( pLong ), pTextRanger( pRanger ),
162 : 16 : nTop( rRange.Min() ), nBottom( rRange.Max() ),
163 : 32 : bInner( pRanger->IsInner() ), bMultiple( bInner || !pRanger->IsSimple() ),
164 [ + - + + ]: 48 : bConcat( sal_False ), bRotate( pRanger->IsVertical() )
165 : : {
166 [ - + ]: 16 : if( bRotate )
167 : : {
168 : 0 : nStart = pRanger->GetUpper();
169 : 0 : nEnd = pRanger->GetLower();
170 : 0 : nLowDiff = pRanger->GetLeft();
171 : 0 : nUpDiff = pRanger->GetRight();
172 : : }
173 : : else
174 : : {
175 : 16 : nStart = pRanger->GetLeft();
176 : 16 : nEnd = pRanger->GetRight();
177 : 16 : nLowDiff = pRanger->GetUpper();
178 : 16 : nUpDiff = pRanger->GetLower();
179 : : }
180 : 16 : nUpper = nTop - nUpDiff;
181 : 16 : nLower = nBottom + nLowDiff;
182 : 16 : pLongArr->clear();
183 : 16 : }
184 : :
185 : 0 : long SvxBoundArgs::CalcMax( const Point& rPt1, const Point& rPt2,
186 : : long nRange, long nFarRange )
187 : : {
188 : 0 : double nDa = Cut( nRange, rPt1, rPt2 ) - Cut( nFarRange, rPt1, rPt2 );
189 : : double nB;
190 [ # # ]: 0 : if( nDa < 0 )
191 : : {
192 : 0 : nDa = -nDa;
193 : 0 : nB = nEnd;
194 : : }
195 : : else
196 : 0 : nB = nStart;
197 : 0 : nB *= nB;
198 : 0 : nB += nDa * nDa;
199 : 0 : nB = nRange + nDa * ( nFarRange - nRange ) / sqrt( nB );
200 : :
201 : : sal_Bool bNote;
202 [ # # ]: 0 : if( nB < B(rPt2) )
203 : 0 : bNote = nB > B(rPt1);
204 : : else
205 : 0 : bNote = nB < B(rPt1);
206 [ # # ]: 0 : if( bNote )
207 : 0 : return( long( nB ) );
208 : 0 : return 0;
209 : : }
210 : :
211 : 62 : void SvxBoundArgs::CheckCut( const Point& rLst, const Point& rNxt )
212 : : {
213 [ + + ]: 62 : if( nCut & 1 )
214 : 32 : NotePoint( Cut( nBottom, rLst, rNxt ) );
215 [ + + ]: 62 : if( nCut & 2 )
216 : 32 : NotePoint( Cut( nTop, rLst, rNxt ) );
217 [ + + ][ - + ]: 62 : if( rLst.X() != rNxt.X() && rLst.Y() != rNxt.Y() )
[ - + ]
218 : : {
219 : : long nYps;
220 [ # # ][ # # ]: 0 : if( nLowDiff && ( ( nCut & 1 ) || nLast == 1 || nNext == 1 ) )
[ # # ][ # # ]
221 : : {
222 : 0 : nYps = CalcMax( rLst, rNxt, nBottom, nLower );
223 [ # # ]: 0 : if( nYps )
224 : 0 : _NoteFarPoint( Cut( nYps, rLst, rNxt ), nLower-nYps, nLowDiff );
225 : : }
226 [ # # ][ # # ]: 0 : if( nUpDiff && ( ( nCut & 2 ) || nLast == 2 || nNext == 2 ) )
[ # # ][ # # ]
227 : : {
228 : 0 : nYps = CalcMax( rLst, rNxt, nTop, nUpper );
229 [ # # ]: 0 : if( nYps )
230 : 0 : _NoteFarPoint( Cut( nYps, rLst, rNxt ), nYps-nUpper, nUpDiff );
231 : : }
232 : : }
233 : 62 : }
234 : :
235 : 0 : void SvxBoundArgs::_NoteFarPoint( long nPa, long nPbDiff, long nDiff )
236 : : {
237 : : long nTmpA;
238 : 0 : double nQuot = 2 * nDiff - nPbDiff;
239 : 0 : nQuot *= nPbDiff;
240 : 0 : nQuot = sqrt( nQuot );
241 : 0 : nQuot /= nDiff;
242 : 0 : nTmpA = nPa - long( nStart * nQuot );
243 : 0 : nPbDiff = nPa + long( nEnd * nQuot );
244 : 0 : NoteMargin( nTmpA, nPbDiff );
245 : 0 : }
246 : :
247 : 2 : void SvxBoundArgs::NoteRange( bool bToggle )
248 : : {
249 : : DBG_ASSERT( nMax >= nMin || bInner, "NoteRange: Min > Max?");
250 [ - + ]: 2 : if( nMax < nMin )
251 : 2 : return;
252 [ - + ]: 2 : if( !bClosed )
253 : 0 : bToggle = sal_False;
254 : 2 : sal_uInt16 nIdx = 0;
255 : 2 : sal_uInt16 nCount = pLongArr->size();
256 : : DBG_ASSERT( nCount == 2 * aBoolArr.size(), "NoteRange: Incompatible Sizes" );
257 [ + + ][ - + ]: 2 : while( nIdx < nCount && (*pLongArr)[ nIdx ] < nMin )
[ - + ]
258 : 0 : ++nIdx;
259 : 2 : sal_Bool bOdd = (nIdx % 2) ? sal_True : sal_False;
260 : : // No overlap with existing intervals?
261 [ + + ][ + - ]: 2 : if( nIdx == nCount || ( !bOdd && nMax < (*pLongArr)[ nIdx ] ) )
[ + - ][ + - ]
262 : : { // Then a new one is inserted ...
263 [ + - ][ + - ]: 2 : pLongArr->insert( pLongArr->begin() + nIdx, nMin );
264 [ + - ][ + - ]: 2 : pLongArr->insert( pLongArr->begin() + nIdx + 1, nMax );
[ + - ]
265 [ + - ]: 2 : aBoolArr.insert( aBoolArr.begin() + (nIdx/2), bToggle );
266 : : }
267 : : else
268 : : { // expand an existing interval ...
269 : 0 : sal_uInt16 nMaxIdx = nIdx;
270 : : // If we end up on a left interval boundary, it must be reduced to nMin.
271 [ # # ]: 0 : if( bOdd )
272 : 0 : --nIdx;
273 : : else
274 : 0 : (*pLongArr)[ nIdx ] = nMin;
275 [ # # ][ # # ]: 0 : while( nMaxIdx < nCount && (*pLongArr)[ nMaxIdx ] < nMax )
[ # # ]
276 : 0 : ++nMaxIdx;
277 : : DBG_ASSERT( nMaxIdx > nIdx || nMin == nMax, "NoteRange: Funny Situation." );
278 [ # # ]: 0 : if( nMaxIdx )
279 : 0 : --nMaxIdx;
280 [ # # ]: 0 : if( nMaxIdx < nIdx )
281 : 0 : nMaxIdx = nIdx;
282 : : // If we end up on a right interval boundary, it must be raised to nMax.
283 [ # # ]: 0 : if( nMaxIdx % 2 )
284 : 0 : (*pLongArr)[ nMaxIdx-- ] = nMax;
285 : : // Possible merge of intervals.
286 : 0 : sal_uInt16 nDiff = nMaxIdx - nIdx;
287 : 0 : nMaxIdx = nIdx / 2; // From here on is nMaxIdx the Index in BoolArray.
288 [ # # ]: 0 : if( nDiff )
289 : : {
290 [ # # ][ # # ]: 0 : pLongArr->erase( pLongArr->begin() + nIdx + 1, pLongArr->begin() + nIdx + 1 + nDiff );
[ # # ][ # # ]
[ # # ][ # # ]
291 : 0 : nDiff /= 2;
292 : 0 : sal_uInt16 nStop = nMaxIdx + nDiff;
293 [ # # ]: 0 : for( sal_uInt16 i = nMaxIdx; i < nStop; ++i )
294 : 0 : bToggle ^= aBoolArr[ i ];
295 [ # # ]: 0 : aBoolArr.erase( aBoolArr.begin() + nMaxIdx, aBoolArr.begin() + (nMaxIdx + nDiff) );
296 : : }
297 : : DBG_ASSERT( nMaxIdx < aBoolArr.size(), "NoteRange: Too much deleted" );
298 [ # # ]: 0 : aBoolArr[ nMaxIdx ] = aBoolArr[ nMaxIdx ] ^ bToggle;
299 : : }
300 : : }
301 : :
302 : 16 : void SvxBoundArgs::Calc( const PolyPolygon& rPoly )
303 : : {
304 : : sal_uInt16 nCount;
305 : 16 : nAct = 0;
306 [ + + ]: 32 : for( sal_uInt16 i = 0; i < rPoly.Count(); ++i )
307 : : {
308 : 16 : const Polygon& rPol = rPoly[ i ];
309 : 16 : nCount = rPol.GetSize();
310 [ + - ]: 16 : if( nCount )
311 : : {
312 : 16 : const Point& rNull = rPol[ 0 ];
313 [ + - ][ + - ]: 16 : SetClosed( IsConcat() || ( rNull == rPol[ nCount - 1 ] ) );
314 : 16 : nLast = Area( rNull );
315 [ + - ]: 16 : if( nLast & 12 )
316 : : {
317 : 16 : nFirst = 3;
318 [ + + ]: 16 : if( bMultiple )
319 : 1 : nAct = 0;
320 : : }
321 : : else
322 : : {
323 : : // The first point of the polygon is within the line.
324 [ # # ]: 0 : if( nLast )
325 : : {
326 [ # # ][ # # ]: 0 : if( bMultiple || !nAct )
327 : : {
328 : 0 : nMin = USHRT_MAX;
329 : 0 : nMax = 0;
330 : : }
331 [ # # ]: 0 : if( nLast & 1 )
332 : 0 : NoteFarPoint( A(rNull), nLower - B(rNull), nLowDiff );
333 : : else
334 : 0 : NoteFarPoint( A(rNull), B(rNull) - nUpper, nUpDiff );
335 : : }
336 : : else
337 : : {
338 [ # # ][ # # ]: 0 : if( bMultiple || !nAct )
339 : : {
340 : 0 : nMin = A(rNull);
341 : 0 : nMax = nMin + nEnd;
342 : 0 : nMin -= nStart;
343 : : }
344 : : else
345 : 0 : NotePoint( A(rNull) );
346 : : }
347 : 0 : nFirst = 0; // leaving the line in which direction?
348 : 0 : nAct = 3; // we are within the line at the moment.
349 : : }
350 [ + - ]: 16 : if( nCount > 1 )
351 : : {
352 : 16 : sal_uInt16 nIdx = 1;
353 : 80 : while( sal_True )
354 : : {
355 : 80 : const Point& rLast = rPol[ nIdx - 1 ];
356 [ + + ]: 80 : if( nIdx == nCount )
357 : 16 : nIdx = 0;
358 : 80 : const Point& rNext = rPol[ nIdx ];
359 : 80 : nNext = Area( rNext );
360 : 80 : nCut = nNext ^ nLast;
361 : 80 : sal_uInt16 nOldAct = nAct;
362 [ + + ]: 80 : if( nAct )
363 : 45 : CheckCut( rLast, rNext );
364 [ + + ]: 80 : if( nCut & 4 )
365 : : {
366 : 32 : NoteUpLow( Cut( nLower, rLast, rNext ), 2 );
367 [ + + ][ + - ]: 32 : if( nAct && nAct != nOldAct )
368 : : {
369 : 17 : nOldAct = nAct;
370 : 17 : CheckCut( rLast, rNext );
371 : : }
372 : : }
373 [ + + ]: 80 : if( nCut & 8 )
374 : : {
375 : 32 : NoteUpLow( Cut( nUpper, rLast, rNext ), 1 );
376 [ - + ][ + + ]: 32 : if( nAct && nAct != nOldAct )
377 : 0 : CheckCut( rLast, rNext );
378 : : }
379 [ + + ]: 80 : if( !nIdx )
380 : : {
381 [ - + ]: 16 : if( !( nNext & 12 ) )
382 : 0 : NoteLast();
383 : 16 : break;
384 : : }
385 [ - + ]: 64 : if( !( nNext & 12 ) )
386 : : {
387 [ # # ]: 0 : if( !nNext )
388 : 0 : NotePoint( A(rNext) );
389 [ # # ]: 0 : else if( nNext & 1 )
390 : 0 : NoteFarPoint( A(rNext), nLower-B(rNext), nLowDiff );
391 : : else
392 : 0 : NoteFarPoint( A(rNext), B(rNext)-nUpper, nUpDiff );
393 : : }
394 : 64 : nLast = nNext;
395 [ + + ][ - + ]: 64 : if( ++nIdx == nCount && !IsClosed() )
[ - + ]
396 : : {
397 [ # # ]: 0 : if( !( nNext & 12 ) )
398 : 0 : NoteLast();
399 : 0 : break;
400 : : }
401 : : }
402 : : }
403 [ + + ][ - + ]: 16 : if( bMultiple && IsConcat() )
[ - + ]
404 : : {
405 : 0 : Add();
406 : 0 : nAct = 0;
407 : : }
408 : : }
409 : : }
410 [ + + ]: 16 : if( !bMultiple )
411 : : {
412 : : DBG_ASSERT( pLongArr->empty(), "I said: Simple!" );
413 [ + - ]: 15 : if( nAct )
414 : : {
415 [ - + ]: 15 : if( bInner )
416 : : {
417 : 0 : long nTmpMin = nMin + 2 * nStart;
418 : 0 : long nTmpMax = nMax - 2 * nEnd;
419 [ # # ]: 0 : if( nTmpMin <= nTmpMax )
420 : : {
421 [ # # ]: 0 : pLongArr->push_front(nTmpMax);
422 [ # # ]: 0 : pLongArr->push_front(nTmpMin);
423 : : }
424 : : }
425 : : else
426 : : {
427 : 15 : pLongArr->push_front(nMax);
428 : 15 : pLongArr->push_front(nMin);
429 : : }
430 : : }
431 : : }
432 [ + - ]: 1 : else if( !IsConcat() )
433 : 1 : Add();
434 : 16 : }
435 : :
436 : 1 : void SvxBoundArgs::Add()
437 : : {
438 : 1 : size_t nCount = aBoolArr.size();
439 [ - + ][ # # ]: 1 : if( nCount && ( !bInner || !pTextRanger->IsSimple() ) )
[ + - ][ + - ]
440 : : {
441 : 1 : sal_Bool bDelete = aBoolArr.front();
442 [ - + ]: 1 : if( bInner )
443 : 0 : bDelete = !bDelete;
444 : 1 : sal_uInt16 nLongIdx = 1;
445 [ + + ]: 2 : for( size_t nBoolIdx = 1; nBoolIdx < nCount; ++nBoolIdx )
446 : : {
447 [ + - ]: 1 : if( bDelete )
448 : : {
449 : 1 : sal_uInt16 next = 2;
450 [ + - ][ + - ]: 1 : while( nBoolIdx < nCount && !aBoolArr[ nBoolIdx++ ] &&
[ - + ][ # # ]
[ # # ][ + - ]
[ - + # # ]
451 : 0 : (!bInner || nBoolIdx < nCount ) )
452 : 0 : next += 2;
453 [ + - ][ + - ]: 1 : pLongArr->erase( pLongArr->begin() + nLongIdx, pLongArr->begin() + nLongIdx + next );
[ + - ][ + - ]
454 : 1 : next /= 2;
455 : 1 : nBoolIdx = nBoolIdx - next;
456 : 1 : nCount = nCount - next;
457 [ + - ]: 1 : aBoolArr.erase( aBoolArr.begin() + nBoolIdx, aBoolArr.begin() + (nBoolIdx + next) );
458 [ + - ]: 1 : if( nBoolIdx )
459 : 1 : aBoolArr[ nBoolIdx - 1 ] = sal_False;
460 : : #if OSL_DEBUG_LEVEL > 1
461 : : else
462 : : ++next;
463 : : #endif
464 : : }
465 [ - + ][ # # ]: 1 : bDelete = nBoolIdx < nCount && aBoolArr[ nBoolIdx ];
[ # # ][ - + ]
[ # # ]
466 : 1 : nLongIdx += 2;
467 : : DBG_ASSERT( nLongIdx == 2*nBoolIdx+1, "BoundArgs: Array-Idx Confusion" );
468 : : DBG_ASSERT( aBoolArr.size()*2 == pLongArr->size(),
469 : : "BoundArgs: Array-Count: Confusion" );
470 : : }
471 : : }
472 [ + - ]: 1 : if( 0 != ( nCount = pLongArr->size() ) )
473 : : {
474 [ - + ]: 1 : if( bInner )
475 : : {
476 : 0 : pLongArr->pop_front();
477 : 0 : pLongArr->pop_back();
478 : :
479 : : // Here the line is held inside a large rectangle for "simple"
480 : : // contour wrap. Currently (April 1999) the EditEngine evaluates
481 : : // only the first rectangle. If it one day is able to output a line
482 : : // in several parts, it may be advisable to delete the following lines.
483 [ # # ][ # # ]: 0 : if( pTextRanger->IsSimple() && pLongArr->size() > 2 )
[ # # ]
484 [ # # ][ # # ]: 0 : pLongArr->erase( pLongArr->begin() + 1, pLongArr->end() - 1 );
[ # # ]
485 : :
486 : : }
487 : : }
488 : 1 : }
489 : :
490 : 0 : void SvxBoundArgs::Concat( const PolyPolygon* pPoly )
491 : : {
492 : 0 : SetConcat( sal_True );
493 : : DBG_ASSERT( pPoly, "Nothing to do?" );
494 : 0 : LongDqPtr pOld = pLongArr;
495 [ # # ]: 0 : pLongArr = new std::deque<long>();
496 : 0 : aBoolArr.clear();
497 : 0 : bInner = sal_False;
498 : 0 : Calc( *pPoly ); // Note that this updates pLongArr, which is why we swapped it out earlier.
499 : 0 : sal_uInt16 nCount = pLongArr->size();
500 : 0 : sal_uInt16 nIdx = 0;
501 : 0 : sal_uInt16 i = 0;
502 : 0 : sal_Bool bSubtract = pTextRanger->IsInner();
503 [ # # ]: 0 : while( i < nCount )
504 : : {
505 : 0 : sal_uLong nOldCount = pOld->size();
506 [ # # ]: 0 : if( nIdx == nOldCount )
507 : : { // Reached the end of the old Array...
508 [ # # ]: 0 : if( !bSubtract )
509 [ # # ][ # # ]: 0 : pOld->insert( pOld->begin() + nIdx, pLongArr->begin() + i, pLongArr->end() );
[ # # ]
510 : 0 : break;
511 : : }
512 : 0 : long nLeft = (*pLongArr)[ i++ ];
513 : 0 : long nRight = (*pLongArr)[ i++ ];
514 : 0 : sal_uInt16 nLeftPos = nIdx + 1;
515 [ # # ][ # # ]: 0 : while( nLeftPos < nOldCount && nLeft > (*pOld)[ nLeftPos ] )
[ # # ]
516 : 0 : nLeftPos += 2;
517 [ # # ]: 0 : if( nLeftPos >= nOldCount )
518 : : { // The current interval belongs to the end of the old array ...
519 [ # # ]: 0 : if( !bSubtract )
520 [ # # ][ # # ]: 0 : pOld->insert( pOld->begin() + nOldCount, pLongArr->begin() + i - 2, pLongArr->end() );
[ # # ][ # # ]
521 : 0 : break;
522 : : }
523 : 0 : sal_uInt16 nRightPos = nLeftPos - 1;
524 [ # # ][ # # ]: 0 : while( nRightPos < nOldCount && nRight >= (*pOld)[ nRightPos ] )
[ # # ]
525 : 0 : nRightPos += 2;
526 [ # # ]: 0 : if( nRightPos < nLeftPos )
527 : : { // The current interval belongs between two old intervals
528 [ # # ]: 0 : if( !bSubtract )
529 [ # # ][ # # ]: 0 : pOld->insert( pOld->begin() + nRightPos, pLongArr->begin() + i - 2, pLongArr->begin() + i );
[ # # ][ # # ]
[ # # ]
530 : 0 : nIdx = nRightPos + 2;
531 : : }
532 [ # # ]: 0 : else if( bSubtract ) // Subtract, if necessary separate
533 : : {
534 : : long nOld;
535 [ # # ][ # # ]: 0 : if( nLeft > ( nOld = (*pOld)[ nLeftPos - 1 ] ) )
536 : : { // Now we split the left part...
537 [ # # ]: 0 : if( nLeft - 1 > nOld )
538 : : {
539 [ # # ][ # # ]: 0 : pOld->insert( pOld->begin() + nLeftPos - 1, nOld );
[ # # ]
540 [ # # ][ # # ]: 0 : pOld->insert( pOld->begin() + nLeftPos, nLeft - 1 );
541 : 0 : nLeftPos += 2;
542 : 0 : nRightPos += 2;
543 : : }
544 : : }
545 [ # # ]: 0 : if( nRightPos - nLeftPos > 1 )
546 [ # # ][ # # ]: 0 : pOld->erase( pOld->begin() + nLeftPos, pOld->begin() + nRightPos - 1 );
[ # # ][ # # ]
547 [ # # ][ # # ]: 0 : if( ++nRight >= ( nOld = (*pOld)[ nLeftPos ] ) )
548 [ # # ][ # # ]: 0 : pOld->erase( pOld->begin() + nLeftPos - 1, pOld->begin() + nLeftPos + 1 );
[ # # ][ # # ]
[ # # ]
549 : : else
550 [ # # ]: 0 : (*pOld)[ nLeftPos - 1 ] = nRight;
551 : : }
552 : : else // Merge
553 : : {
554 [ # # ]: 0 : if( nLeft < (*pOld)[ nLeftPos - 1 ] )
555 : 0 : (*pOld)[ nLeftPos - 1 ] = nLeft;
556 [ # # ]: 0 : if( nRight > (*pOld)[ nRightPos - 1 ] )
557 : 0 : (*pOld)[ nRightPos - 1 ] = nRight;
558 [ # # ]: 0 : if( nRightPos - nLeftPos > 1 )
559 [ # # ][ # # ]: 0 : pOld->erase( pOld->begin() + nLeftPos, pOld->begin() + nRightPos - 1 );
[ # # ][ # # ]
560 : :
561 : : }
562 : 0 : nIdx = nLeftPos - 1;
563 : : }
564 [ # # ]: 0 : delete pLongArr;
565 : 0 : }
566 : :
567 : : /*************************************************************************
568 : : * SvxBoundArgs::Area returns the area in which the point is located.
569 : : * 0 = within the line
570 : : * 1 = below, but within the upper edge
571 : : * 2 = above, but within the lower edge
572 : : * 5 = below the upper edge
573 : : *10 = above the lower edge
574 : : *************************************************************************/
575 : :
576 : 96 : sal_uInt16 SvxBoundArgs::Area( const Point& rPt )
577 : : {
578 : 96 : long nB = B( rPt );
579 [ + + ]: 96 : if( nB >= nBottom )
580 : : {
581 [ + - ]: 32 : if( nB >= nLower )
582 : 32 : return 5;
583 : 0 : return 1;
584 : : }
585 [ + - ]: 64 : if( nB <= nTop )
586 : : {
587 [ + - ]: 64 : if( nB <= nUpper )
588 : 64 : return 10;
589 : 0 : return 2;
590 : : }
591 : 96 : return 0;
592 : : }
593 : :
594 : : /*************************************************************************
595 : : * lcl_Cut calculates the X-Coordinate of the distance (Pt1-Pt2) at the
596 : : * Y-Coordinate nY.
597 : : * It is assumed that the one of the points are located above and the other
598 : : * one below the Y-Coordinate.
599 : : *************************************************************************/
600 : :
601 : 128 : long SvxBoundArgs::Cut( long nB, const Point& rPt1, const Point& rPt2 )
602 : : {
603 [ - + ]: 128 : if( pTextRanger->IsVertical() )
604 : : {
605 : 0 : double nQuot = nB - rPt1.X();
606 : 0 : nQuot /= ( rPt2.X() - rPt1.X() );
607 : 0 : nQuot *= ( rPt2.Y() - rPt1.Y() );
608 : 0 : return long( rPt1.Y() + nQuot );
609 : : }
610 : 128 : double nQuot = nB - rPt1.Y();
611 : 128 : nQuot /= ( rPt2.Y() - rPt1.Y() );
612 : 128 : nQuot *= ( rPt2.X() - rPt1.X() );
613 : 128 : return long( rPt1.X() + nQuot );
614 : : }
615 : :
616 : 64 : void SvxBoundArgs::NoteUpLow( long nA, const sal_uInt8 nArea )
617 : : {
618 [ + + ]: 64 : if( nAct )
619 : : {
620 : 47 : NoteMargin( nA, nA );
621 [ + + ]: 47 : if( bMultiple )
622 : : {
623 : 2 : NoteRange( nArea != nAct );
624 : 2 : nAct = 0;
625 : : }
626 [ - + ]: 47 : if( !nFirst )
627 : 0 : nFirst = nArea;
628 : : }
629 : : else
630 : : {
631 : 17 : nAct = nArea;
632 : 17 : nMin = nA;
633 : 17 : nMax = nA;
634 : : }
635 : 64 : }
636 : :
637 : 48 : LongDqPtr TextRanger::GetTextRanges( const Range& rRange )
638 : : {
639 : : DBG_ASSERT( rRange.Min() || rRange.Max(), "Zero-Range not allowed, Bye Bye" );
640 : : //Can we find the result we need in the cache?
641 [ # # ][ + - ]: 48 : for (std::deque<RangeCache>::iterator it = mRangeCache.begin(); it != mRangeCache.end(); ++it)
[ + + ]
642 : : {
643 [ + - ][ + - ]: 32 : if (it->range == rRange)
644 [ + - ]: 32 : return &(it->results);
645 : : }
646 : : //Calculate a new result
647 [ + - ]: 16 : RangeCache rngCache(rRange);
648 [ + - ]: 16 : SvxBoundArgs aArg( this, &(rngCache.results), rRange );
649 [ + - ]: 16 : aArg.Calc( *mpPolyPolygon );
650 [ - + ]: 16 : if( mpLinePolyPolygon )
651 [ # # ]: 0 : aArg.Concat( mpLinePolyPolygon );
652 : : //Add new result to the cache
653 [ + - ]: 16 : mRangeCache.push_back(rngCache);
654 [ - + ]: 16 : if (mRangeCache.size() > nCacheSize)
655 [ # # ]: 0 : mRangeCache.pop_front();
656 [ + - ]: 48 : return &(mRangeCache.back().results);
657 : : }
658 : :
659 : 0 : const Rectangle& TextRanger::_GetBoundRect()
660 : : {
661 : : DBG_ASSERT( 0 == pBound, "Don't call twice." );
662 [ # # ]: 0 : pBound = new Rectangle( mpPolyPolygon->GetBoundRect() );
663 : 0 : return *pBound;
664 : : }
665 : :
666 : :
667 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|