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