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