merge the formfield patch from ooo-build
[ooovba.git] / svx / source / editeng / txtrange.cxx
blobf79c3530f6551bf0bc9230563cba08ee2438f482
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: txtrange.cxx,v $
10 * $Revision: 1.15 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_svx.hxx"
34 #include "txtrange.hxx"
35 #include <math.h>
36 #include <tools/poly.hxx>
37 #include <tools/debug.hxx>
38 #include <basegfx/polygon/b2dpolygon.hxx>
39 #include <basegfx/polygon/b2dpolygontools.hxx>
41 /*************************************************************************
43 |* TextRanger::TextRanger()
45 |* Beschreibung
46 |* Ersterstellung 20.01.97
47 |* Letzte Aenderung 20.01.97 AMA
49 *************************************************************************/
51 #ifdef WIN
52 #pragma optimize ( "", off )
53 #endif
55 TextRanger::TextRanger( const basegfx::B2DPolyPolygon& rPolyPolygon, const basegfx::B2DPolyPolygon* pLinePolyPolygon,
56 USHORT nCacheSz, USHORT nLft, USHORT nRght, BOOL bSimpl, BOOL bInnr,
57 BOOL bVert ) :
58 pBound( NULL ),
59 nCacheSize( nCacheSz ),
60 nCacheIdx( 0 ),
61 nRight( nRght ),
62 nLeft( nLft ),
63 nUpper( 0 ),
64 nLower( 0 ),
65 nPointCount( 0 ),
66 bSimple( bSimpl ),
67 bInner( bInnr ),
68 bVertical( bVert )
70 #ifndef PRODUCT
71 bFlag3 = bFlag4 = bFlag5 = bFlag6 = bFlag7 = FALSE;
72 #endif
73 pRangeArr = new Range[ nCacheSize ];
74 pCache = new SvLongsPtr[ nCacheSize ];
75 memset( pRangeArr, 0, nCacheSize * sizeof( Range ) );
76 memset( pCache, 0, nCacheSize * sizeof( SvLongsPtr ) );
77 sal_uInt32 nCount(rPolyPolygon.count());
78 mpPolyPolygon = new PolyPolygon( (sal_uInt16)nCount );
80 for(sal_uInt32 i(0L); i < nCount; i++)
82 const basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(i).getDefaultAdaptiveSubdivision());
83 nPointCount += aCandidate.count();
84 mpPolyPolygon->Insert( Polygon(aCandidate), (sal_uInt16)i );
87 if( pLinePolyPolygon )
89 nCount = pLinePolyPolygon->count();
90 mpLinePolyPolygon = new PolyPolygon();
92 for(sal_uInt32 i(0L); i < nCount; i++)
94 const basegfx::B2DPolygon aCandidate(pLinePolyPolygon->getB2DPolygon(i).getDefaultAdaptiveSubdivision());
95 nPointCount += aCandidate.count();
96 mpLinePolyPolygon->Insert( Polygon(aCandidate), (sal_uInt16)i );
99 else
100 mpLinePolyPolygon = NULL;
103 #ifdef WIN
104 #pragma optimize ( "", on )
105 #endif
107 /*************************************************************************
109 |* TextRanger::~TextRanger()
111 |* Beschreibung
112 |* Ersterstellung 20.01.97
113 |* Letzte Aenderung 20.01.97 AMA
115 *************************************************************************/
117 TextRanger::~TextRanger()
119 for( USHORT i = 0; i < nCacheSize; ++i )
120 delete pCache[i];
121 delete[] pCache;
122 delete[] pRangeArr;
123 delete mpPolyPolygon;
124 delete mpLinePolyPolygon;
127 /*-----------------17.11.00 09:49-------------------
128 * TextRanger::SetVertical(..)
129 * If there's is a change in the writing direction,
130 * the cache has to be cleared.
131 * --------------------------------------------------*/
133 void TextRanger::SetVertical( BOOL bNew )
135 if( IsVertical() != bNew )
137 bVertical = bNew;
138 for( USHORT i = 0; i < nCacheSize; ++i )
139 delete pCache[i];
140 memset( pRangeArr, 0, nCacheSize * sizeof( Range ) );
141 memset( pCache, 0, nCacheSize * sizeof( SvLongsPtr ) );
145 /*************************************************************************
147 |* SvxBoundArgs
149 |* Beschreibung
150 |* Ersterstellung 20.01.97
151 |* Letzte Aenderung 20.01.97 AMA
153 *************************************************************************/
155 class SvxBoundArgs
157 SvBools aBoolArr;
158 SvLongs *pLongArr;
159 TextRanger *pTextRanger;
160 long nMin;
161 long nMax;
162 long nTop;
163 long nBottom;
164 long nUpDiff;
165 long nLowDiff;
166 long nUpper;
167 long nLower;
168 long nStart;
169 long nEnd;
170 USHORT nCut;
171 USHORT nLast;
172 USHORT nNext;
173 BYTE nAct;
174 BYTE nFirst;
175 BOOL bClosed : 1;
176 BOOL bInner : 1;
177 BOOL bMultiple : 1;
178 BOOL bConcat : 1;
179 BOOL bRotate : 1;
180 void NoteRange( BOOL bToggle );
181 long Cut( long nY, const Point& rPt1, const Point& rPt2 );
182 void Add();
183 void _NoteFarPoint( long nPx, long nPyDiff, long nDiff );
184 void NoteFarPoint( long nPx, long nPyDiff, long nDiff )
185 { if( nDiff ) _NoteFarPoint( nPx, nPyDiff, nDiff ); }
186 long CalcMax( const Point& rPt1, const Point& rPt2, long nRange, long nFar );
187 void CheckCut( const Point& rLst, const Point& rNxt );
188 inline long A( const Point& rP ) const { return bRotate ? rP.Y() : rP.X(); }
189 inline long B( const Point& rP ) const { return bRotate ? rP.X() : rP.Y(); }
190 public:
191 SvxBoundArgs( TextRanger* pRanger, SvLongs *pLong, const Range& rRange );
192 void NotePoint( const long nA ) { NoteMargin( nA - nStart, nA + nEnd ); }
193 void NoteMargin( const long nL, const long nR )
194 { if( nMin > nL ) nMin = nL; if( nMax < nR ) nMax = nR; }
195 USHORT Area( const Point& rPt );
196 void NoteUpLow( long nA, const BYTE nArea );
197 void Calc( const PolyPolygon& rPoly );
198 void Concat( const PolyPolygon* pPoly );
199 // inlines
200 void NoteLast() { if( bMultiple ) NoteRange( nAct == nFirst ); }
201 void SetClosed( const BOOL bNew ){ bClosed = bNew; }
202 BOOL IsClosed() const { return bClosed; }
203 void SetConcat( const BOOL bNew ){ bConcat = bNew; }
204 BOOL IsConcat() const { return bConcat; }
205 BYTE GetAct() const { return nAct; }
208 SvxBoundArgs::SvxBoundArgs( TextRanger* pRanger, SvLongs *pLong,
209 const Range& rRange )
210 : aBoolArr( 4, 4 ), pLongArr( pLong ), pTextRanger( pRanger ),
211 nTop( rRange.Min() ), nBottom( rRange.Max() ),
212 bInner( pRanger->IsInner() ), bMultiple( bInner || !pRanger->IsSimple() ),
213 bConcat( FALSE ), bRotate( pRanger->IsVertical() )
215 if( bRotate )
217 nStart = pRanger->GetUpper();
218 nEnd = pRanger->GetLower();
219 nLowDiff = pRanger->GetLeft();
220 nUpDiff = pRanger->GetRight();
222 else
224 nStart = pRanger->GetLeft();
225 nEnd = pRanger->GetRight();
226 nLowDiff = pRanger->GetUpper();
227 nUpDiff = pRanger->GetLower();
229 nUpper = nTop - nUpDiff;
230 nLower = nBottom + nLowDiff;
231 pLongArr->Remove( 0, pLongArr->Count() );
234 long SvxBoundArgs::CalcMax( const Point& rPt1, const Point& rPt2,
235 long nRange, long nFarRange )
237 double nDa = Cut( nRange, rPt1, rPt2 ) - Cut( nFarRange, rPt1, rPt2 );
238 double nB;
239 if( nDa < 0 )
241 nDa = -nDa;
242 nB = nEnd;
244 else
245 nB = nStart;
246 nB *= nB;
247 nB += nDa * nDa;
248 nB = nRange + nDa * ( nFarRange - nRange ) / sqrt( nB );
250 BOOL bNote;
251 if( nB < B(rPt2) )
252 bNote = nB > B(rPt1);
253 else
254 bNote = nB < B(rPt1);
255 if( bNote )
256 return( long( nB ) );
257 return 0;
260 void SvxBoundArgs::CheckCut( const Point& rLst, const Point& rNxt )
262 if( nCut & 1 )
263 NotePoint( Cut( nBottom, rLst, rNxt ) );
264 if( nCut & 2 )
265 NotePoint( Cut( nTop, rLst, rNxt ) );
266 if( rLst.X() != rNxt.X() && rLst.Y() != rNxt.Y() )
268 long nYps;
269 if( nLowDiff && ( ( nCut & 1 ) || nLast == 1 || nNext == 1 ) )
271 nYps = CalcMax( rLst, rNxt, nBottom, nLower );
272 if( nYps )
273 _NoteFarPoint( Cut( nYps, rLst, rNxt ), nLower-nYps, nLowDiff );
275 if( nUpDiff && ( ( nCut & 2 ) || nLast == 2 || nNext == 2 ) )
277 nYps = CalcMax( rLst, rNxt, nTop, nUpper );
278 if( nYps )
279 _NoteFarPoint( Cut( nYps, rLst, rNxt ), nYps-nUpper, nUpDiff );
284 void SvxBoundArgs::_NoteFarPoint( long nPa, long nPbDiff, long nDiff )
286 long nTmpA;
287 double nQuot = 2 * nDiff - nPbDiff;
288 nQuot *= nPbDiff;
289 nQuot = sqrt( nQuot );
290 nQuot /= nDiff;
291 nTmpA = nPa - long( nStart * nQuot );
292 nPbDiff = nPa + long( nEnd * nQuot );
293 NoteMargin( nTmpA, nPbDiff );
296 void SvxBoundArgs::NoteRange( BOOL bToggle )
298 DBG_ASSERT( nMax >= nMin || bInner, "NoteRange: Min > Max?");
299 if( nMax < nMin )
300 return;
301 if( !bClosed )
302 bToggle = FALSE;
303 USHORT nIdx = 0;
304 USHORT nCount = pLongArr->Count();
305 DBG_ASSERT( nCount == 2 * aBoolArr.Count(), "NoteRange: Incompatible Sizes" );
306 while( nIdx < nCount && (*pLongArr)[ nIdx ] < nMin )
307 ++nIdx;
308 BOOL bOdd = nIdx % 2 ? TRUE : FALSE;
309 // Kein Ueberlappung mit vorhandenen Intervallen?
310 if( nIdx == nCount || ( !bOdd && nMax < (*pLongArr)[ nIdx ] ) )
311 { // Dann wird ein neues eingefuegt ...
312 pLongArr->Insert( nMin, nIdx );
313 pLongArr->Insert( nMax, nIdx + 1 );
314 aBoolArr.Insert( bToggle, nIdx / 2 );
316 else
317 { // ein vorhandes Intervall erweitern ...
318 USHORT nMaxIdx = nIdx;
319 // Wenn wir auf einer linken Intervallgrenze gelandet sind, muss diese
320 // auf nMin gesenkt werden.
321 if( bOdd )
322 --nIdx;
323 else
324 (*pLongArr)[ nIdx ] = nMin;
325 while( nMaxIdx < nCount && (*pLongArr)[ nMaxIdx ] < nMax )
326 ++nMaxIdx;
327 DBG_ASSERT( nMaxIdx > nIdx || nMin == nMax, "NoteRange: Funny Situation." );
328 if( nMaxIdx )
329 --nMaxIdx;
330 if( nMaxIdx < nIdx )
331 nMaxIdx = nIdx;
332 // Wenn wir auf einer rechten Intervallgrenze landen, muss diese
333 // auf nMax angehoben werden.
334 if( nMaxIdx % 2 )
335 (*pLongArr)[ nMaxIdx-- ] = nMax;
336 // Jetzt werden eventuell noch Intervalle verschmolzen
337 USHORT nDiff = nMaxIdx - nIdx;
338 nMaxIdx = nIdx / 2; // Ab hier ist nMaxIdx der Index im BoolArray.
339 if( nDiff )
341 (*pLongArr).Remove( nIdx + 1, nDiff );
342 nDiff /= 2;
343 USHORT nStop = nMaxIdx + nDiff;
344 for( USHORT i = nMaxIdx; i < nStop; ++i )
345 bToggle ^= aBoolArr[ i ];
346 aBoolArr.Remove( nMaxIdx, nDiff );
348 DBG_ASSERT( nMaxIdx < aBoolArr.Count(), "NoteRange: Too much deleted" );
349 aBoolArr[ nMaxIdx ] ^= bToggle;
353 void SvxBoundArgs::Calc( const PolyPolygon& rPoly )
355 USHORT nCount;
356 nAct = 0;
357 for( USHORT i = 0; i < rPoly.Count(); ++i )
359 const Polygon& rPol = rPoly[ i ];
360 nCount = rPol.GetSize();
361 if( nCount )
363 const Point& rNull = rPol[ 0 ];
364 SetClosed( IsConcat() || ( rNull == rPol[ nCount - 1 ] ) );
365 nLast = Area( rNull );
366 if( nLast & 12 )
368 nFirst = 3;
369 if( bMultiple )
370 nAct = 0;
372 else
374 // Der erste Punkt des Polygons liegt innerhalb der Zeile.
375 if( nLast )
377 if( bMultiple || !nAct )
379 nMin = USHRT_MAX;
380 nMax = 0;
382 if( nLast & 1 )
383 NoteFarPoint( A(rNull), nLower - B(rNull), nLowDiff );
384 else
385 NoteFarPoint( A(rNull), B(rNull) - nUpper, nUpDiff );
387 else
389 if( bMultiple || !nAct )
391 nMin = A(rNull);
392 nMax = nMin + nEnd;
393 nMin -= nStart;
395 else
396 NotePoint( A(rNull) );
398 nFirst = 0; // In welcher Richtung wird die Zeile verlassen?
399 nAct = 3; // Wir sind z.Z. innerhalb der Zeile.
401 if( nCount > 1 )
403 USHORT nIdx = 1;
404 while( TRUE )
406 const Point& rLast = rPol[ nIdx - 1 ];
407 if( nIdx == nCount )
408 nIdx = 0;
409 const Point& rNext = rPol[ nIdx ];
410 nNext = Area( rNext );
411 nCut = nNext ^ nLast;
412 USHORT nOldAct = nAct;
413 if( nAct )
414 CheckCut( rLast, rNext );
415 if( nCut & 4 )
417 NoteUpLow( Cut( nLower, rLast, rNext ), 2 );
418 if( nAct && nAct != nOldAct )
420 nOldAct = nAct;
421 CheckCut( rLast, rNext );
424 if( nCut & 8 )
426 NoteUpLow( Cut( nUpper, rLast, rNext ), 1 );
427 if( nAct && nAct != nOldAct )
428 CheckCut( rLast, rNext );
430 if( !nIdx )
432 if( !( nNext & 12 ) )
433 NoteLast();
434 break;
436 if( !( nNext & 12 ) )
438 if( !nNext )
439 NotePoint( A(rNext) );
440 else if( nNext & 1 )
441 NoteFarPoint( A(rNext), nLower-B(rNext), nLowDiff );
442 else
443 NoteFarPoint( A(rNext), B(rNext)-nUpper, nUpDiff );
445 nLast = nNext;
446 if( ++nIdx == nCount && !IsClosed() )
448 if( !( nNext & 12 ) )
449 NoteLast();
450 break;
454 if( bMultiple && IsConcat() )
456 Add();
457 nAct = 0;
461 if( !bMultiple )
463 DBG_ASSERT( pLongArr->Count() == 0, "I said: Simple!" );
464 if( nAct )
466 if( bInner )
468 long nTmpMin, nTmpMax;
470 nTmpMin = nMin + 2 * nStart;
471 nTmpMax = nMax - 2 * nEnd;
472 if( nTmpMin <= nTmpMax )
474 pLongArr->Insert( nTmpMin, 0 );
475 pLongArr->Insert( nTmpMax, 1 );
479 else
481 pLongArr->Insert( nMin, 0 );
482 pLongArr->Insert( nMax, 1 );
486 else if( !IsConcat() )
487 Add();
490 void SvxBoundArgs::Add()
492 USHORT nLongIdx = 1;
493 USHORT nCount = aBoolArr.Count();
494 if( nCount && ( !bInner || !pTextRanger->IsSimple() ) )
496 BOOL bDelete = aBoolArr[ 0 ];
497 if( bInner )
498 bDelete = !bDelete;
499 for( USHORT nBoolIdx = 1; nBoolIdx < nCount; ++nBoolIdx )
501 if( bDelete )
503 USHORT next = 2;
504 while( nBoolIdx < nCount && !aBoolArr[ nBoolIdx++ ] &&
505 (!bInner || nBoolIdx < nCount ) )
506 next += 2;
507 pLongArr->Remove( nLongIdx, next );
508 next /= 2;
509 nBoolIdx = nBoolIdx - next;
510 nCount = nCount - next;
511 aBoolArr.Remove( nBoolIdx, next );
512 if( nBoolIdx )
513 aBoolArr[ nBoolIdx - 1 ] = FALSE;
514 #if OSL_DEBUG_LEVEL > 1
515 else
516 ++next;
517 #endif
519 bDelete = nBoolIdx < nCount && aBoolArr[ nBoolIdx ];
520 nLongIdx += 2;
521 DBG_ASSERT( nLongIdx == 2*nBoolIdx+1, "BoundArgs: Array-Idx Confusion" );
522 DBG_ASSERT( aBoolArr.Count()*2 == pLongArr->Count(),
523 "BoundArgs: Array-Count: Confusion" );
526 if( 0 != ( nCount = pLongArr->Count() ) )
528 if( bInner )
530 pLongArr->Remove( 0, 1 );
531 pLongArr->Remove( pLongArr->Count() - 1, 1 );
533 // Hier wird die Zeile beim "einfachen" Konturumfluss im Innern
534 // in ein grosses Rechteck zusammengefasst.
535 // Zur Zeit (April 1999) wertet die EditEngine nur das erste Rechteck
536 // aus, falls sie eines Tages in der Lage ist, eine Zeile in mehreren
537 // Teilen auszugeben, kann es sinnvoll sein, die folgenden Zeilen
538 // zu loeschen.
539 if( pTextRanger->IsSimple() && pLongArr->Count() > 2 )
540 pLongArr->Remove( 1, pLongArr->Count() - 2 );
546 void SvxBoundArgs::Concat( const PolyPolygon* pPoly )
548 SetConcat( TRUE );
549 DBG_ASSERT( pPoly, "Nothing to do?" );
550 SvLongs *pOld = pLongArr;
551 pLongArr = new SvLongs( 2, 8 );
552 aBoolArr.Remove( 0, aBoolArr.Count() );
553 bInner = FALSE;
554 Calc( *pPoly );
555 USHORT nCount = pLongArr->Count();
556 USHORT nIdx = 0;
557 USHORT i = 0;
558 BOOL bSubtract = pTextRanger->IsInner();
559 while( i < nCount )
561 USHORT nOldCount = pOld->Count();
562 if( nIdx == nOldCount )
563 { // Am Ende des alten Arrays angelangt...
564 if( !bSubtract )
565 pOld->Insert( pLongArr, nIdx, i, USHRT_MAX );
566 break;
568 long nLeft = (*pLongArr)[ i++ ];
569 long nRight = (*pLongArr)[ i++ ];
570 USHORT nLeftPos = nIdx + 1;
571 while( nLeftPos < nOldCount && nLeft > (*pOld)[ nLeftPos ] )
572 nLeftPos += 2;
573 if( nLeftPos >= nOldCount )
574 { // Das aktuelle Intervall gehoert ans Ende des alten Arrays...
575 if( !bSubtract )
576 pOld->Insert( pLongArr, nOldCount, i - 2, USHRT_MAX );
577 break;
579 USHORT nRightPos = nLeftPos - 1;
580 while( nRightPos < nOldCount && nRight >= (*pOld)[ nRightPos ] )
581 nRightPos += 2;
582 if( nRightPos < nLeftPos )
583 { // Das aktuelle Intervall gehoert zwischen zwei alte Intervalle
584 if( !bSubtract )
585 pOld->Insert( pLongArr, nRightPos, i - 2, i );
586 nIdx = nRightPos + 2;
588 else if( bSubtract ) // Subtrahieren ggf. Trennen
590 long nOld;
591 if( nLeft > ( nOld = (*pOld)[ nLeftPos - 1 ] ) )
592 { // Jetzt spalten wir den linken Teil ab...
593 if( nLeft - 1 > nOld )
595 pOld->Insert( nOld, nLeftPos - 1 );
596 pOld->Insert( nLeft - 1, nLeftPos );
597 nLeftPos += 2;
598 nRightPos += 2;
601 if( nRightPos - nLeftPos > 1 )
602 pOld->Remove( nLeftPos, nRightPos - nLeftPos - 1 );
603 if( ++nRight >= ( nOld = (*pOld)[ nLeftPos ] ) )
604 pOld->Remove( nLeftPos - 1, 2 );
605 else
606 (*pOld)[ nLeftPos - 1 ] = nRight;
608 else // Verschmelzen
610 if( nLeft < (*pOld)[ nLeftPos - 1 ] )
611 (*pOld)[ nLeftPos - 1 ] = nLeft;
612 if( nRight > (*pOld)[ nRightPos - 1 ] )
613 (*pOld)[ nRightPos - 1 ] = nRight;
614 if( nRightPos - nLeftPos > 1 )
615 pOld->Remove( nLeftPos, nRightPos - nLeftPos - 1 );
618 nIdx = nLeftPos - 1;
620 delete pLongArr;
623 /*************************************************************************
624 * SvxBoundArgs::Area ermittelt den Bereich, in dem sich der Punkt befindet
625 * 0 = innerhalb der Zeile
626 * 1 = unterhalb, aber innerhalb der oberen Randes
627 * 2 = oberhalb, aber innerhalb der unteren Randes
628 * 5 = unterhalb des oberen Randes
629 *10 = oberhalb des unteren Randes
630 *************************************************************************/
632 USHORT SvxBoundArgs::Area( const Point& rPt )
634 long nB = B( rPt );
635 if( nB >= nBottom )
637 if( nB >= nLower )
638 return 5;
639 return 1;
641 if( nB <= nTop )
643 if( nB <= nUpper )
644 return 10;
645 return 2;
647 return 0;
650 /*************************************************************************
651 * lcl_Cut berechnet die X-Koordinate der Strecke (Pt1-Pt2) auf der
652 * Y-Koordinate nY.
653 * Vorausgesetzt wird, dass einer der Punkte oberhalb und der andere
654 * unterhalb der Y-Koordinate liegt.
655 *************************************************************************/
657 long SvxBoundArgs::Cut( long nB, const Point& rPt1, const Point& rPt2 )
659 if( pTextRanger->IsVertical() )
661 double nQuot = nB - rPt1.X();
662 nQuot /= ( rPt2.X() - rPt1.X() );
663 nQuot *= ( rPt2.Y() - rPt1.Y() );
664 return long( rPt1.Y() + nQuot );
666 double nQuot = nB - rPt1.Y();
667 nQuot /= ( rPt2.Y() - rPt1.Y() );
668 nQuot *= ( rPt2.X() - rPt1.X() );
669 return long( rPt1.X() + nQuot );
672 void SvxBoundArgs::NoteUpLow( long nA, const BYTE nArea )
674 if( nAct )
676 NoteMargin( nA, nA );
677 if( bMultiple )
679 NoteRange( nArea != nAct );
680 nAct = 0;
682 if( !nFirst )
683 nFirst = nArea;
685 else
687 nAct = nArea;
688 nMin = nA;
689 nMax = nA;
693 SvLongsPtr TextRanger::GetTextRanges( const Range& rRange )
695 DBG_ASSERT( rRange.Min() || rRange.Max(), "Zero-Range not allowed, Bye Bye" );
696 USHORT nIndex = 0;
697 while( nIndex < nCacheSize && rRange != pRangeArr[ nIndex ] )
698 ++nIndex;
699 if( nIndex >= nCacheSize )
701 ++nCacheIdx;
702 nCacheIdx %= nCacheSize;
703 pRangeArr[ nCacheIdx ] = rRange;
704 if( !pCache[ nCacheIdx ] )
705 pCache[ nCacheIdx ] = new SvLongs( 2, 8 );
706 nIndex = nCacheIdx;
707 SvxBoundArgs aArg( this, pCache[ nCacheIdx ], rRange );
708 aArg.Calc( *mpPolyPolygon );
709 if( mpLinePolyPolygon )
710 aArg.Concat( mpLinePolyPolygon );
712 return pCache[ nIndex ];
715 const Rectangle& TextRanger::_GetBoundRect()
717 DBG_ASSERT( 0 == pBound, "Don't call twice." );
718 pBound = new Rectangle( mpPolyPolygon->GetBoundRect() );
719 return *pBound;