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