xref: /aoo41x/main/editeng/source/misc/txtrange.cxx (revision 190118d0)
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