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