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