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_editeng.hxx"
26
27 #include <editeng/txtrange.hxx>
28 #include <math.h>
29 #include <tools/poly.hxx>
30 #include <tools/debug.hxx>
31 #include <basegfx/polygon/b2dpolygon.hxx>
32 #include <basegfx/polygon/b2dpolygontools.hxx>
33
34 /*************************************************************************
35 |*
36 |* TextRanger::TextRanger()
37 |*
38 |* Beschreibung
39 |* Ersterstellung 20.01.97
40 |* Letzte Aenderung 20.01.97 AMA
41 |*
42 *************************************************************************/
43
TextRanger(const basegfx::B2DPolyPolygon & rPolyPolygon,const basegfx::B2DPolyPolygon * pLinePolyPolygon,sal_uInt16 nCacheSz,sal_uInt16 nLft,sal_uInt16 nRght,sal_Bool bSimpl,sal_Bool bInnr,sal_Bool bVert)44 TextRanger::TextRanger( const basegfx::B2DPolyPolygon& rPolyPolygon, const basegfx::B2DPolyPolygon* pLinePolyPolygon,
45 sal_uInt16 nCacheSz, sal_uInt16 nLft, sal_uInt16 nRght, sal_Bool bSimpl, sal_Bool bInnr,
46 sal_Bool bVert ) :
47 pBound( NULL ),
48 nCacheSize( nCacheSz ),
49 nCacheIdx( 0 ),
50 nRight( nRght ),
51 nLeft( nLft ),
52 nUpper( 0 ),
53 nLower( 0 ),
54 nPointCount( 0 ),
55 bSimple( bSimpl ),
56 bInner( bInnr ),
57 bVertical( bVert )
58 {
59 #ifdef DBG_UTIL
60 bFlag3 = bFlag4 = bFlag5 = bFlag6 = bFlag7 = sal_False;
61 #endif
62 pRangeArr = new Range[ nCacheSize ];
63 pCache = new SvLongsPtr[ nCacheSize ];
64 memset( pRangeArr, 0, nCacheSize * sizeof( Range ) );
65 memset( pCache, 0, nCacheSize * sizeof( SvLongsPtr ) );
66 sal_uInt32 nCount(rPolyPolygon.count());
67 mpPolyPolygon = new PolyPolygon( (sal_uInt16)nCount );
68
69 for(sal_uInt32 i(0L); i < nCount; i++)
70 {
71 const basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(i).getDefaultAdaptiveSubdivision());
72 nPointCount += aCandidate.count();
73 mpPolyPolygon->Insert( Polygon(aCandidate), (sal_uInt16)i );
74 }
75
76 if( pLinePolyPolygon )
77 {
78 nCount = pLinePolyPolygon->count();
79 mpLinePolyPolygon = new PolyPolygon();
80
81 for(sal_uInt32 i(0L); i < nCount; i++)
82 {
83 const basegfx::B2DPolygon aCandidate(pLinePolyPolygon->getB2DPolygon(i).getDefaultAdaptiveSubdivision());
84 nPointCount += aCandidate.count();
85 mpLinePolyPolygon->Insert( Polygon(aCandidate), (sal_uInt16)i );
86 }
87 }
88 else
89 mpLinePolyPolygon = NULL;
90 }
91
92 /*************************************************************************
93 |*
94 |* TextRanger::~TextRanger()
95 |*
96 |* Beschreibung
97 |* Ersterstellung 20.01.97
98 |* Letzte Aenderung 20.01.97 AMA
99 |*
100 *************************************************************************/
101
~TextRanger()102 TextRanger::~TextRanger()
103 {
104 for( sal_uInt16 i = 0; i < nCacheSize; ++i )
105 delete pCache[i];
106 delete[] pCache;
107 delete[] pRangeArr;
108 delete mpPolyPolygon;
109 delete mpLinePolyPolygon;
110 delete pBound;
111 }
112
113 /*-----------------17.11.00 09:49-------------------
114 * TextRanger::SetVertical(..)
115 * If there's is a change in the writing direction,
116 * the cache has to be cleared.
117 * --------------------------------------------------*/
118
SetVertical(sal_Bool bNew)119 void TextRanger::SetVertical( sal_Bool bNew )
120 {
121 if( IsVertical() != bNew )
122 {
123 bVertical = bNew;
124 for( sal_uInt16 i = 0; i < nCacheSize; ++i )
125 delete pCache[i];
126 memset( pRangeArr, 0, nCacheSize * sizeof( Range ) );
127 memset( pCache, 0, nCacheSize * sizeof( SvLongsPtr ) );
128 }
129 }
130
131 /*************************************************************************
132 |*
133 |* SvxBoundArgs
134 |*
135 |* Beschreibung
136 |* Ersterstellung 20.01.97
137 |* Letzte Aenderung 20.01.97 AMA
138 |*
139 *************************************************************************/
140
141 class SvxBoundArgs
142 {
143 SvBools aBoolArr;
144 SvLongs *pLongArr;
145 TextRanger *pTextRanger;
146 long nMin;
147 long nMax;
148 long nTop;
149 long nBottom;
150 long nUpDiff;
151 long nLowDiff;
152 long nUpper;
153 long nLower;
154 long nStart;
155 long nEnd;
156 sal_uInt16 nCut;
157 sal_uInt16 nLast;
158 sal_uInt16 nNext;
159 sal_uInt8 nAct;
160 sal_uInt8 nFirst;
161 sal_Bool bClosed : 1;
162 sal_Bool bInner : 1;
163 sal_Bool bMultiple : 1;
164 sal_Bool bConcat : 1;
165 sal_Bool bRotate : 1;
166 void NoteRange( sal_Bool bToggle );
167 long Cut( long nY, const Point& rPt1, const Point& rPt2 );
168 void Add();
169 void _NoteFarPoint( long nPx, long nPyDiff, long nDiff );
NoteFarPoint(long nPx,long nPyDiff,long nDiff)170 void NoteFarPoint( long nPx, long nPyDiff, long nDiff )
171 { if( nDiff ) _NoteFarPoint( nPx, nPyDiff, nDiff ); }
172 long CalcMax( const Point& rPt1, const Point& rPt2, long nRange, long nFar );
173 void CheckCut( const Point& rLst, const Point& rNxt );
A(const Point & rP) const174 inline long A( const Point& rP ) const { return bRotate ? rP.Y() : rP.X(); }
B(const Point & rP) const175 inline long B( const Point& rP ) const { return bRotate ? rP.X() : rP.Y(); }
176 public:
177 SvxBoundArgs( TextRanger* pRanger, SvLongs *pLong, const Range& rRange );
NotePoint(const long nA)178 void NotePoint( const long nA ) { NoteMargin( nA - nStart, nA + nEnd ); }
NoteMargin(const long nL,const long nR)179 void NoteMargin( const long nL, const long nR )
180 { if( nMin > nL ) nMin = nL; if( nMax < nR ) nMax = nR; }
181 sal_uInt16 Area( const Point& rPt );
182 void NoteUpLow( long nA, const sal_uInt8 nArea );
183 void Calc( const PolyPolygon& rPoly );
184 void Concat( const PolyPolygon* pPoly );
185 // inlines
NoteLast()186 void NoteLast() { if( bMultiple ) NoteRange( nAct == nFirst ); }
SetClosed(const sal_Bool bNew)187 void SetClosed( const sal_Bool bNew ){ bClosed = bNew; }
IsClosed() const188 sal_Bool IsClosed() const { return bClosed; }
SetConcat(const sal_Bool bNew)189 void SetConcat( const sal_Bool bNew ){ bConcat = bNew; }
IsConcat() const190 sal_Bool IsConcat() const { return bConcat; }
GetAct() const191 sal_uInt8 GetAct() const { return nAct; }
192 };
193
SvxBoundArgs(TextRanger * pRanger,SvLongs * pLong,const Range & rRange)194 SvxBoundArgs::SvxBoundArgs( TextRanger* pRanger, SvLongs *pLong,
195 const Range& rRange )
196 : pLongArr( pLong ), pTextRanger( pRanger ),
197 nTop( rRange.Min() ), nBottom( rRange.Max() ),
198 bInner( pRanger->IsInner() ), bMultiple( bInner || !pRanger->IsSimple() ),
199 bConcat( sal_False ), bRotate( pRanger->IsVertical() )
200 {
201 if( bRotate )
202 {
203 nStart = pRanger->GetUpper();
204 nEnd = pRanger->GetLower();
205 nLowDiff = pRanger->GetLeft();
206 nUpDiff = pRanger->GetRight();
207 }
208 else
209 {
210 nStart = pRanger->GetLeft();
211 nEnd = pRanger->GetRight();
212 nLowDiff = pRanger->GetUpper();
213 nUpDiff = pRanger->GetLower();
214 }
215 nUpper = nTop - nUpDiff;
216 nLower = nBottom + nLowDiff;
217 pLongArr->Remove( 0, pLongArr->Count() );
218 }
219
CalcMax(const Point & rPt1,const Point & rPt2,long nRange,long nFarRange)220 long SvxBoundArgs::CalcMax( const Point& rPt1, const Point& rPt2,
221 long nRange, long nFarRange )
222 {
223 double nDa = Cut( nRange, rPt1, rPt2 ) - Cut( nFarRange, rPt1, rPt2 );
224 double nB;
225 if( nDa < 0 )
226 {
227 nDa = -nDa;
228 nB = nEnd;
229 }
230 else
231 nB = nStart;
232 nB *= nB;
233 nB += nDa * nDa;
234 nB = nRange + nDa * ( nFarRange - nRange ) / sqrt( nB );
235
236 sal_Bool bNote;
237 if( nB < B(rPt2) )
238 bNote = nB > B(rPt1);
239 else
240 bNote = nB < B(rPt1);
241 if( bNote )
242 return( long( nB ) );
243 return 0;
244 }
245
CheckCut(const Point & rLst,const Point & rNxt)246 void SvxBoundArgs::CheckCut( const Point& rLst, const Point& rNxt )
247 {
248 if( nCut & 1 )
249 NotePoint( Cut( nBottom, rLst, rNxt ) );
250 if( nCut & 2 )
251 NotePoint( Cut( nTop, rLst, rNxt ) );
252 if( rLst.X() != rNxt.X() && rLst.Y() != rNxt.Y() )
253 {
254 long nYps;
255 if( nLowDiff && ( ( nCut & 1 ) || nLast == 1 || nNext == 1 ) )
256 {
257 nYps = CalcMax( rLst, rNxt, nBottom, nLower );
258 if( nYps )
259 _NoteFarPoint( Cut( nYps, rLst, rNxt ), nLower-nYps, nLowDiff );
260 }
261 if( nUpDiff && ( ( nCut & 2 ) || nLast == 2 || nNext == 2 ) )
262 {
263 nYps = CalcMax( rLst, rNxt, nTop, nUpper );
264 if( nYps )
265 _NoteFarPoint( Cut( nYps, rLst, rNxt ), nYps-nUpper, nUpDiff );
266 }
267 }
268 }
269
_NoteFarPoint(long nPa,long nPbDiff,long nDiff)270 void SvxBoundArgs::_NoteFarPoint( long nPa, long nPbDiff, long nDiff )
271 {
272 long nTmpA;
273 double nQuot = 2 * nDiff - nPbDiff;
274 nQuot *= nPbDiff;
275 nQuot = sqrt( nQuot );
276 nQuot /= nDiff;
277 nTmpA = nPa - long( nStart * nQuot );
278 nPbDiff = nPa + long( nEnd * nQuot );
279 NoteMargin( nTmpA, nPbDiff );
280 }
281
NoteRange(sal_Bool bToggle)282 void SvxBoundArgs::NoteRange( sal_Bool bToggle )
283 {
284 DBG_ASSERT( nMax >= nMin || bInner, "NoteRange: Min > Max?");
285 if( nMax < nMin )
286 return;
287 if( !bClosed )
288 bToggle = sal_False;
289 sal_uInt16 nIdx = 0;
290 sal_uInt16 nCount = pLongArr->Count();
291 DBG_ASSERT( nCount == 2 * aBoolArr.size(), "NoteRange: Incompatible Sizes" );
292 while( nIdx < nCount && (*pLongArr)[ nIdx ] < nMin )
293 ++nIdx;
294 sal_Bool bOdd = nIdx % 2 ? sal_True : sal_False;
295 // Kein Ueberlappung mit vorhandenen Intervallen?
296 if( nIdx == nCount || ( !bOdd && nMax < (*pLongArr)[ nIdx ] ) )
297 { // Dann wird ein neues eingefuegt ...
298 pLongArr->Insert( nMin, nIdx );
299 pLongArr->Insert( nMax, nIdx + 1 );
300 aBoolArr.insert( aBoolArr.begin() + nIdx / 2, bToggle );
301 }
302 else
303 { // ein vorhandes Intervall erweitern ...
304 sal_uInt16 nMaxIdx = nIdx;
305 // Wenn wir auf einer linken Intervallgrenze gelandet sind, muss diese
306 // auf nMin gesenkt werden.
307 if( bOdd )
308 --nIdx;
309 else
310 (*pLongArr)[ nIdx ] = nMin;
311 while( nMaxIdx < nCount && (*pLongArr)[ nMaxIdx ] < nMax )
312 ++nMaxIdx;
313 DBG_ASSERT( nMaxIdx > nIdx || nMin == nMax, "NoteRange: Funny Situation." );
314 if( nMaxIdx )
315 --nMaxIdx;
316 if( nMaxIdx < nIdx )
317 nMaxIdx = nIdx;
318 // Wenn wir auf einer rechten Intervallgrenze landen, muss diese
319 // auf nMax angehoben werden.
320 if( nMaxIdx % 2 )
321 (*pLongArr)[ nMaxIdx-- ] = nMax;
322 // Jetzt werden eventuell noch Intervalle verschmolzen
323 sal_uInt16 nDiff = nMaxIdx - nIdx;
324 nMaxIdx = nIdx / 2; // Ab hier ist nMaxIdx der Index im BoolArray.
325 if( nDiff )
326 {
327 (*pLongArr).Remove( nIdx + 1, nDiff );
328 nDiff /= 2;
329 sal_uInt16 nStop = nMaxIdx + nDiff;
330 for( sal_uInt16 i = nMaxIdx; i < nStop; ++i )
331 bToggle ^= aBoolArr[ i ];
332 aBoolArr.erase( aBoolArr.begin() + nMaxIdx, aBoolArr.begin() + (nMaxIdx + nDiff) );
333 }
334 DBG_ASSERT( nMaxIdx < aBoolArr.size(), "NoteRange: Too much deleted" );
335 aBoolArr[ nMaxIdx ] ^= bToggle;
336 }
337 }
338
Calc(const PolyPolygon & rPoly)339 void SvxBoundArgs::Calc( const PolyPolygon& rPoly )
340 {
341 sal_uInt16 nCount;
342 nAct = 0;
343 for( sal_uInt16 i = 0; i < rPoly.Count(); ++i )
344 {
345 const Polygon& rPol = rPoly[ i ];
346 nCount = rPol.GetSize();
347 if( nCount )
348 {
349 const Point& rNull = rPol[ 0 ];
350 SetClosed( IsConcat() || ( rNull == rPol[ nCount - 1 ] ) );
351 nLast = Area( rNull );
352 if( nLast & 12 )
353 {
354 nFirst = 3;
355 if( bMultiple )
356 nAct = 0;
357 }
358 else
359 {
360 // Der erste Punkt des Polygons liegt innerhalb der Zeile.
361 if( nLast )
362 {
363 if( bMultiple || !nAct )
364 {
365 nMin = USHRT_MAX;
366 nMax = 0;
367 }
368 if( nLast & 1 )
369 NoteFarPoint( A(rNull), nLower - B(rNull), nLowDiff );
370 else
371 NoteFarPoint( A(rNull), B(rNull) - nUpper, nUpDiff );
372 }
373 else
374 {
375 if( bMultiple || !nAct )
376 {
377 nMin = A(rNull);
378 nMax = nMin + nEnd;
379 nMin -= nStart;
380 }
381 else
382 NotePoint( A(rNull) );
383 }
384 nFirst = 0; // In welcher Richtung wird die Zeile verlassen?
385 nAct = 3; // Wir sind z.Z. innerhalb der Zeile.
386 }
387 if( nCount > 1 )
388 {
389 sal_uInt16 nIdx = 1;
390 while( sal_True )
391 {
392 const Point& rLast = rPol[ nIdx - 1 ];
393 if( nIdx == nCount )
394 nIdx = 0;
395 const Point& rNext = rPol[ nIdx ];
396 nNext = Area( rNext );
397 nCut = nNext ^ nLast;
398 sal_uInt16 nOldAct = nAct;
399 if( nAct )
400 CheckCut( rLast, rNext );
401 if( nCut & 4 )
402 {
403 NoteUpLow( Cut( nLower, rLast, rNext ), 2 );
404 if( nAct && nAct != nOldAct )
405 {
406 nOldAct = nAct;
407 CheckCut( rLast, rNext );
408 }
409 }
410 if( nCut & 8 )
411 {
412 NoteUpLow( Cut( nUpper, rLast, rNext ), 1 );
413 if( nAct && nAct != nOldAct )
414 CheckCut( rLast, rNext );
415 }
416 if( !nIdx )
417 {
418 if( !( nNext & 12 ) )
419 NoteLast();
420 break;
421 }
422 if( !( nNext & 12 ) )
423 {
424 if( !nNext )
425 NotePoint( A(rNext) );
426 else if( nNext & 1 )
427 NoteFarPoint( A(rNext), nLower-B(rNext), nLowDiff );
428 else
429 NoteFarPoint( A(rNext), B(rNext)-nUpper, nUpDiff );
430 }
431 nLast = nNext;
432 if( ++nIdx == nCount && !IsClosed() )
433 {
434 if( !( nNext & 12 ) )
435 NoteLast();
436 break;
437 }
438 }
439 }
440 if( bMultiple && IsConcat() )
441 {
442 Add();
443 nAct = 0;
444 }
445 }
446 }
447 if( !bMultiple )
448 {
449 DBG_ASSERT( pLongArr->Count() == 0, "I said: Simple!" );
450 if( nAct )
451 {
452 if( bInner )
453 {
454 long nTmpMin, nTmpMax;
455 {
456 nTmpMin = nMin + 2 * nStart;
457 nTmpMax = nMax - 2 * nEnd;
458 if( nTmpMin <= nTmpMax )
459 {
460 pLongArr->Insert( nTmpMin, 0 );
461 pLongArr->Insert( nTmpMax, 1 );
462 }
463 }
464 }
465 else
466 {
467 pLongArr->Insert( nMin, 0 );
468 pLongArr->Insert( nMax, 1 );
469 }
470 }
471 }
472 else if( !IsConcat() )
473 Add();
474 }
475
Add()476 void SvxBoundArgs::Add()
477 {
478 sal_uInt16 nLongIdx = 1;
479 size_t nCount = aBoolArr.size();
480 if( nCount && ( !bInner || !pTextRanger->IsSimple() ) )
481 {
482 sal_Bool bDelete = aBoolArr.front();
483 if( bInner )
484 bDelete = !bDelete;
485 for( size_t nBoolIdx = 1; nBoolIdx < nCount; ++nBoolIdx )
486 {
487 if( bDelete )
488 {
489 sal_uInt16 next = 2;
490 while( nBoolIdx < nCount && !aBoolArr[ nBoolIdx++ ] &&
491 (!bInner || nBoolIdx < nCount ) )
492 next += 2;
493 pLongArr->Remove( nLongIdx, next );
494 next /= 2;
495 nBoolIdx = nBoolIdx - next;
496 nCount = nCount - next;
497 aBoolArr.erase( aBoolArr.begin() + nBoolIdx, aBoolArr.begin() + (nBoolIdx + next) );
498 if( nBoolIdx )
499 aBoolArr[ nBoolIdx - 1 ] = sal_False;
500 #if OSL_DEBUG_LEVEL > 1
501 else
502 ++next;
503 #endif
504 }
505 bDelete = nBoolIdx < nCount && aBoolArr[ nBoolIdx ];
506 nLongIdx += 2;
507 DBG_ASSERT( nLongIdx == 2*nBoolIdx+1, "BoundArgs: Array-Idx Confusion" );
508 DBG_ASSERT( aBoolArr.size()*2 == pLongArr->Count(),
509 "BoundArgs: Array-Count: Confusion" );
510 }
511 }
512 if( 0 != ( nCount = pLongArr->Count() ) )
513 {
514 if( bInner )
515 {
516 pLongArr->Remove( 0, 1 );
517 pLongArr->Remove( pLongArr->Count() - 1, 1 );
518
519 // Hier wird die Zeile beim "einfachen" Konturumfluss im Innern
520 // in ein grosses Rechteck zusammengefasst.
521 // Zur Zeit (April 1999) wertet die EditEngine nur das erste Rechteck
522 // aus, falls sie eines Tages in der Lage ist, eine Zeile in mehreren
523 // Teilen auszugeben, kann es sinnvoll sein, die folgenden Zeilen
524 // zu loeschen.
525 if( pTextRanger->IsSimple() && pLongArr->Count() > 2 )
526 pLongArr->Remove( 1, pLongArr->Count() - 2 );
527
528 }
529 }
530 }
531
Concat(const PolyPolygon * pPoly)532 void SvxBoundArgs::Concat( const PolyPolygon* pPoly )
533 {
534 SetConcat( sal_True );
535 DBG_ASSERT( pPoly, "Nothing to do?" );
536 SvLongs *pOld = pLongArr;
537 pLongArr = new SvLongs( 2, 8 );
538 aBoolArr.clear();
539 bInner = sal_False;
540 Calc( *pPoly );
541 sal_uInt16 nCount = pLongArr->Count();
542 sal_uInt16 nIdx = 0;
543 sal_uInt16 i = 0;
544 sal_Bool bSubtract = pTextRanger->IsInner();
545 while( i < nCount )
546 {
547 sal_uInt16 nOldCount = pOld->Count();
548 if( nIdx == nOldCount )
549 { // Am Ende des alten Arrays angelangt...
550 if( !bSubtract )
551 pOld->Insert( pLongArr, nIdx, i, USHRT_MAX );
552 break;
553 }
554 long nLeft = (*pLongArr)[ i++ ];
555 long nRight = (*pLongArr)[ i++ ];
556 sal_uInt16 nLeftPos = nIdx + 1;
557 while( nLeftPos < nOldCount && nLeft > (*pOld)[ nLeftPos ] )
558 nLeftPos += 2;
559 if( nLeftPos >= nOldCount )
560 { // Das aktuelle Intervall gehoert ans Ende des alten Arrays...
561 if( !bSubtract )
562 pOld->Insert( pLongArr, nOldCount, i - 2, USHRT_MAX );
563 break;
564 }
565 sal_uInt16 nRightPos = nLeftPos - 1;
566 while( nRightPos < nOldCount && nRight >= (*pOld)[ nRightPos ] )
567 nRightPos += 2;
568 if( nRightPos < nLeftPos )
569 { // Das aktuelle Intervall gehoert zwischen zwei alte Intervalle
570 if( !bSubtract )
571 pOld->Insert( pLongArr, nRightPos, i - 2, i );
572 nIdx = nRightPos + 2;
573 }
574 else if( bSubtract ) // Subtrahieren ggf. Trennen
575 {
576 long nOld;
577 if( nLeft > ( nOld = (*pOld)[ nLeftPos - 1 ] ) )
578 { // Jetzt spalten wir den linken Teil ab...
579 if( nLeft - 1 > nOld )
580 {
581 pOld->Insert( nOld, nLeftPos - 1 );
582 pOld->Insert( nLeft - 1, nLeftPos );
583 nLeftPos += 2;
584 nRightPos += 2;
585 }
586 }
587 if( nRightPos - nLeftPos > 1 )
588 pOld->Remove( nLeftPos, nRightPos - nLeftPos - 1 );
589 if( ++nRight >= ( nOld = (*pOld)[ nLeftPos ] ) )
590 pOld->Remove( nLeftPos - 1, 2 );
591 else
592 (*pOld)[ nLeftPos - 1 ] = nRight;
593 }
594 else // Verschmelzen
595 {
596 if( nLeft < (*pOld)[ nLeftPos - 1 ] )
597 (*pOld)[ nLeftPos - 1 ] = nLeft;
598 if( nRight > (*pOld)[ nRightPos - 1 ] )
599 (*pOld)[ nRightPos - 1 ] = nRight;
600 if( nRightPos - nLeftPos > 1 )
601 pOld->Remove( nLeftPos, nRightPos - nLeftPos - 1 );
602
603 }
604 nIdx = nLeftPos - 1;
605 }
606 delete pLongArr;
607 }
608
609 /*************************************************************************
610 * SvxBoundArgs::Area ermittelt den Bereich, in dem sich der Punkt befindet
611 * 0 = innerhalb der Zeile
612 * 1 = unterhalb, aber innerhalb der oberen Randes
613 * 2 = oberhalb, aber innerhalb der unteren Randes
614 * 5 = unterhalb des oberen Randes
615 *10 = oberhalb des unteren Randes
616 *************************************************************************/
617
Area(const Point & rPt)618 sal_uInt16 SvxBoundArgs::Area( const Point& rPt )
619 {
620 long nB = B( rPt );
621 if( nB >= nBottom )
622 {
623 if( nB >= nLower )
624 return 5;
625 return 1;
626 }
627 if( nB <= nTop )
628 {
629 if( nB <= nUpper )
630 return 10;
631 return 2;
632 }
633 return 0;
634 }
635
636 /*************************************************************************
637 * lcl_Cut berechnet die X-Koordinate der Strecke (Pt1-Pt2) auf der
638 * Y-Koordinate nY.
639 * Vorausgesetzt wird, dass einer der Punkte oberhalb und der andere
640 * unterhalb der Y-Koordinate liegt.
641 *************************************************************************/
642
Cut(long nB,const Point & rPt1,const Point & rPt2)643 long SvxBoundArgs::Cut( long nB, const Point& rPt1, const Point& rPt2 )
644 {
645 if( pTextRanger->IsVertical() )
646 {
647 double nQuot = nB - rPt1.X();
648 nQuot /= ( rPt2.X() - rPt1.X() );
649 nQuot *= ( rPt2.Y() - rPt1.Y() );
650 return long( rPt1.Y() + nQuot );
651 }
652 double nQuot = nB - rPt1.Y();
653 nQuot /= ( rPt2.Y() - rPt1.Y() );
654 nQuot *= ( rPt2.X() - rPt1.X() );
655 return long( rPt1.X() + nQuot );
656 }
657
NoteUpLow(long nA,const sal_uInt8 nArea)658 void SvxBoundArgs::NoteUpLow( long nA, const sal_uInt8 nArea )
659 {
660 if( nAct )
661 {
662 NoteMargin( nA, nA );
663 if( bMultiple )
664 {
665 NoteRange( nArea != nAct );
666 nAct = 0;
667 }
668 if( !nFirst )
669 nFirst = nArea;
670 }
671 else
672 {
673 nAct = nArea;
674 nMin = nA;
675 nMax = nA;
676 }
677 }
678
GetTextRanges(const Range & rRange)679 SvLongsPtr TextRanger::GetTextRanges( const Range& rRange )
680 {
681 DBG_ASSERT( rRange.Min() || rRange.Max(), "Zero-Range not allowed, Bye Bye" );
682 sal_uInt16 nIndex = 0;
683 while( nIndex < nCacheSize && rRange != pRangeArr[ nIndex ] )
684 ++nIndex;
685 if( nIndex >= nCacheSize )
686 {
687 ++nCacheIdx;
688 nCacheIdx %= nCacheSize;
689 pRangeArr[ nCacheIdx ] = rRange;
690 if( !pCache[ nCacheIdx ] )
691 pCache[ nCacheIdx ] = new SvLongs( 2, 8 );
692 nIndex = nCacheIdx;
693 SvxBoundArgs aArg( this, pCache[ nCacheIdx ], rRange );
694 aArg.Calc( *mpPolyPolygon );
695 if( mpLinePolyPolygon )
696 aArg.Concat( mpLinePolyPolygon );
697 }
698 return pCache[ nIndex ];
699 }
700
_GetBoundRect()701 const Rectangle& TextRanger::_GetBoundRect()
702 {
703 DBG_ASSERT( 0 == pBound, "Don't call twice." );
704 pBound = new Rectangle( mpPolyPolygon->GetBoundRect() );
705 return *pBound;
706 }
707
708
709