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_sw.hxx" 30 31 32 #include <hintids.hxx> 33 #include <editeng/keepitem.hxx> 34 #include <editeng/hyznitem.hxx> 35 #include <pagefrm.hxx> // ChangeFtnRef 36 #include <ndtxt.hxx> // MakeFrm() 37 #include <dcontact.hxx> // SwDrawContact 38 #include <dflyobj.hxx> // SwVirtFlyDrawObj 39 #include <flyfrm.hxx> 40 #include <ftnfrm.hxx> // SwFtnFrm 41 #include <txtftn.hxx> 42 #include <fmtftn.hxx> 43 #include <paratr.hxx> 44 #include <viewopt.hxx> // SwViewOptions 45 #include <viewsh.hxx> // ViewShell 46 #include <frmatr.hxx> 47 #include <pam.hxx> 48 #include <flyfrms.hxx> 49 #include <fmtanchr.hxx> 50 #include <txtcfg.hxx> 51 #include <itrform2.hxx> // SwTxtFormatter 52 #include <widorp.hxx> // Widows and Orphans 53 #include <txtcache.hxx> 54 #include <porrst.hxx> // SwEmptyPortion 55 #include <blink.hxx> // pBlink 56 #include <porfld.hxx> // SwFldPortion 57 #include <sectfrm.hxx> // SwSectionFrm 58 #include <pormulti.hxx> // SwMultiPortion 59 60 #include <rootfrm.hxx> 61 #include <frmfmt.hxx> // SwFrmFmt 62 // OD 2004-05-24 #i28701# 63 #include <sortedobjs.hxx> 64 65 class FormatLevel 66 { 67 static MSHORT nLevel; 68 public: 69 inline FormatLevel() { ++nLevel; } 70 inline ~FormatLevel() { --nLevel; } 71 inline MSHORT GetLevel() const { return nLevel; } 72 static sal_Bool LastLevel() { return 10 < nLevel; } 73 }; 74 MSHORT FormatLevel::nLevel = 0; 75 76 /************************************************************************* 77 * ValidateTxt/Frm() 78 *************************************************************************/ 79 80 void ValidateTxt( SwFrm *pFrm ) // Freund vom Frame 81 { 82 if ( ( ! pFrm->IsVertical() && 83 pFrm->Frm().Width() == pFrm->GetUpper()->Prt().Width() ) || 84 ( pFrm->IsVertical() && 85 pFrm->Frm().Height() == pFrm->GetUpper()->Prt().Height() ) ) 86 pFrm->bValidSize = sal_True; 87 /* 88 pFrm->bValidPrtArea = sal_True; 89 //Die Position validieren um nicht unnoetige (Test-)Moves zu provozieren. 90 //Dabei darf allerdings nicht eine tatsaechlich falsche Coordinate 91 //validiert werden. 92 if ( !pFrm->bValidPos ) 93 { 94 //Leider muessen wir dazu die korrekte Position berechnen. 95 Point aOld( pFrm->Frm().Pos() ); 96 pFrm->MakePos(); 97 if ( aOld != pFrm->Pos() ) 98 { 99 pFrm->Frm().Pos( aOld ); 100 pFrm->bValidPos = sal_False; 101 } 102 } 103 */ 104 } 105 106 void SwTxtFrm::ValidateFrm() 107 { 108 // Umgebung validieren, um Oszillationen zu verhindern. 109 SWAP_IF_SWAPPED( this ) 110 111 if ( !IsInFly() && !IsInTab() ) 112 { //Innerhalb eines Flys nur this validieren, der Rest sollte eigentlich 113 //nur fuer Fussnoten notwendig sein und die gibt es innerhalb von 114 //Flys nicht. Fix fuer 5544 115 SwSectionFrm* pSct = FindSctFrm(); 116 if( pSct ) 117 { 118 if( !pSct->IsColLocked() ) 119 pSct->ColLock(); 120 else 121 pSct = NULL; 122 } 123 124 SwFrm *pUp = GetUpper(); 125 pUp->Calc(); 126 if( pSct ) 127 pSct->ColUnlock(); 128 } 129 ValidateTxt( this ); 130 131 //MA: mindestens das MustFit-Flag muessen wir retten! 132 ASSERT( HasPara(), "ResetPreps(), missing ParaPortion." ); 133 SwParaPortion *pPara = GetPara(); 134 const sal_Bool bMustFit = pPara->IsPrepMustFit(); 135 ResetPreps(); 136 pPara->SetPrepMustFit( bMustFit ); 137 138 UNDO_SWAP( this ) 139 } 140 141 /************************************************************************* 142 * ValidateBodyFrm() 143 *************************************************************************/ 144 145 // nach einem RemoveFtn muss der BodyFrm und alle innenliegenden kalkuliert 146 // werden, damit die DeadLine richtig sitzt. 147 // Erst wird nach aussen hin gesucht, beim Rueckweg werden alle kalkuliert. 148 149 void _ValidateBodyFrm( SwFrm *pFrm ) 150 { 151 if( pFrm && !pFrm->IsCellFrm() ) 152 { 153 if( !pFrm->IsBodyFrm() && pFrm->GetUpper() ) 154 _ValidateBodyFrm( pFrm->GetUpper() ); 155 if( !pFrm->IsSctFrm() ) 156 pFrm->Calc(); 157 else 158 { 159 sal_Bool bOld = ((SwSectionFrm*)pFrm)->IsCntntLocked(); 160 ((SwSectionFrm*)pFrm)->SetCntntLock( sal_True ); 161 pFrm->Calc(); 162 if( !bOld ) 163 ((SwSectionFrm*)pFrm)->SetCntntLock( sal_False ); 164 } 165 } 166 } 167 168 void SwTxtFrm::ValidateBodyFrm() 169 { 170 SWAP_IF_SWAPPED( this ) 171 172 //siehe Kommtar in ValidateFrm() 173 if ( !IsInFly() && !IsInTab() && 174 !( IsInSct() && FindSctFrm()->Lower()->IsColumnFrm() ) ) 175 _ValidateBodyFrm( GetUpper() ); 176 177 UNDO_SWAP( this ) 178 } 179 180 /************************************************************************* 181 * SwTxtFrm::FindBodyFrm() 182 *************************************************************************/ 183 184 sal_Bool SwTxtFrm::_GetDropRect( SwRect &rRect ) const 185 { 186 SWAP_IF_NOT_SWAPPED( this ) 187 188 ASSERT( HasPara(), "SwTxtFrm::_GetDropRect: try again next year." ); 189 SwTxtSizeInfo aInf( (SwTxtFrm*)this ); 190 SwTxtMargin aLine( (SwTxtFrm*)this, &aInf ); 191 if( aLine.GetDropLines() ) 192 { 193 rRect.Top( aLine.Y() ); 194 rRect.Left( aLine.GetLineStart() ); 195 rRect.Height( aLine.GetDropHeight() ); 196 rRect.Width( aLine.GetDropLeft() ); 197 198 if ( IsRightToLeft() ) 199 SwitchLTRtoRTL( rRect ); 200 201 if ( IsVertical() ) 202 SwitchHorizontalToVertical( rRect ); 203 UNDO_SWAP( this ) 204 return sal_True; 205 } 206 207 UNDO_SWAP( this ) 208 209 return sal_False; 210 } 211 212 /************************************************************************* 213 * SwTxtFrm::FindBodyFrm() 214 *************************************************************************/ 215 216 const SwBodyFrm *SwTxtFrm::FindBodyFrm() const 217 { 218 if ( IsInDocBody() ) 219 { 220 const SwFrm *pFrm = GetUpper(); 221 while( pFrm && !pFrm->IsBodyFrm() ) 222 pFrm = pFrm->GetUpper(); 223 return (const SwBodyFrm*)pFrm; 224 } 225 return 0; 226 } 227 228 /************************************************************************* 229 * SwTxtFrm::CalcFollow() 230 *************************************************************************/ 231 232 sal_Bool SwTxtFrm::CalcFollow( const xub_StrLen nTxtOfst ) 233 { 234 SWAP_IF_SWAPPED( this ) 235 236 ASSERT( HasFollow(), "CalcFollow: missing Follow." ); 237 238 SwTxtFrm* pMyFollow = GetFollow(); 239 240 SwParaPortion *pPara = GetPara(); 241 sal_Bool bFollowFld = pPara ? pPara->IsFollowField() : sal_False; 242 243 if( !pMyFollow->GetOfst() || pMyFollow->GetOfst() != nTxtOfst || 244 bFollowFld || pMyFollow->IsFieldFollow() || 245 ( pMyFollow->IsVertical() && !pMyFollow->Prt().Width() ) || 246 ( ! pMyFollow->IsVertical() && !pMyFollow->Prt().Height() ) ) 247 { 248 #ifdef DBG_UTIL 249 const SwFrm *pOldUp = GetUpper(); 250 #endif 251 252 SWRECTFN ( this ) 253 SwTwips nOldBottom = (GetUpper()->Frm().*fnRect->fnGetBottom)(); 254 SwTwips nMyPos = (Frm().*fnRect->fnGetTop)(); 255 256 const SwPageFrm *pPage = 0; 257 sal_Bool bOldInvaCntnt = sal_True; 258 if ( !IsInFly() && GetNext() ) 259 { 260 pPage = FindPageFrm(); 261 //Minimieren - sprich ggf. zuruecksetzen - der Invalidierungen s.u. 262 bOldInvaCntnt = pPage->IsInvalidCntnt(); 263 } 264 265 pMyFollow->_SetOfst( nTxtOfst ); 266 pMyFollow->SetFieldFollow( bFollowFld ); 267 if( HasFtn() || pMyFollow->HasFtn() ) 268 { 269 ValidateFrm(); 270 ValidateBodyFrm(); 271 if( pPara ) 272 { 273 *(pPara->GetReformat()) = SwCharRange(); 274 *(pPara->GetDelta()) = 0; 275 } 276 } 277 278 //Der Fussnotenbereich darf sich keinesfalls vergrossern. 279 SwSaveFtnHeight aSave( FindFtnBossFrm( sal_True ), LONG_MAX ); 280 281 pMyFollow->CalcFtnFlag(); 282 if ( !pMyFollow->GetNext() && !pMyFollow->HasFtn() ) 283 nOldBottom = bVert ? 0 : LONG_MAX; 284 285 while( sal_True ) 286 { 287 if( !FormatLevel::LastLevel() ) 288 { 289 // Weenn der Follow in einem spaltigen Bereich oder einem 290 // spaltigen Rahmen steckt, muss zunaechst dieser kalkuliert 291 // werden, da das FormatWidthCols() nicht funktioniert, wenn 292 // es aus dem MakeAll des _gelockten_ Follows heraus gerufen 293 // wird. 294 SwSectionFrm* pSct = pMyFollow->FindSctFrm(); 295 if( pSct && !pSct->IsAnLower( this ) ) 296 { 297 if( pSct->GetFollow() ) 298 pSct->SimpleFormat(); 299 else if( ( pSct->IsVertical() && !pSct->Frm().Width() ) || 300 ( ! pSct->IsVertical() && !pSct->Frm().Height() ) ) 301 break; 302 } 303 // OD 14.03.2003 #i11760# - intrinsic format of follow is controlled. 304 if ( FollowFormatAllowed() ) 305 { 306 // OD 14.03.2003 #i11760# - no nested format of follows, if 307 // text frame is contained in a column frame. 308 // Thus, forbid intrinsic format of follow. 309 { 310 bool bIsFollowInColumn = false; 311 SwFrm* pFollowUpper = pMyFollow->GetUpper(); 312 while ( pFollowUpper ) 313 { 314 if ( pFollowUpper->IsColumnFrm() ) 315 { 316 bIsFollowInColumn = true; 317 break; 318 } 319 if ( pFollowUpper->IsPageFrm() || 320 pFollowUpper->IsFlyFrm() ) 321 { 322 break; 323 } 324 pFollowUpper = pFollowUpper->GetUpper(); 325 } 326 if ( bIsFollowInColumn ) 327 { 328 pMyFollow->ForbidFollowFormat(); 329 } 330 } 331 332 pMyFollow->Calc(); 333 // Der Follow merkt anhand seiner Frm().Height(), dass was schief 334 // gelaufen ist. 335 ASSERT( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: cheesy follow" ); 336 if( pMyFollow->GetPrev() ) 337 { 338 pMyFollow->Prepare( PREP_CLEAR ); 339 pMyFollow->Calc(); 340 ASSERT( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: very cheesy follow" ); 341 } 342 343 // OD 14.03.2003 #i11760# - reset control flag for follow format. 344 pMyFollow->AllowFollowFormat(); 345 } 346 347 //Sicherstellen, dass der Follow gepaintet wird. 348 pMyFollow->SetCompletePaint(); 349 } 350 351 pPara = GetPara(); 352 //Solange der Follow wg. Orphans Zeilen angefordert, bekommt er 353 //diese und wird erneut formatiert, falls moeglich. 354 if( pPara && pPara->IsPrepWidows() ) 355 CalcPreps(); 356 else 357 break; 358 } 359 360 if( HasFtn() || pMyFollow->HasFtn() ) 361 { 362 ValidateBodyFrm(); 363 ValidateFrm(); 364 if( pPara ) 365 { 366 *(pPara->GetReformat()) = SwCharRange(); 367 *(pPara->GetDelta()) = 0; 368 } 369 } 370 371 if ( pPage ) 372 { 373 if ( !bOldInvaCntnt ) 374 pPage->ValidateCntnt(); 375 } 376 377 #ifdef DBG_UTIL 378 ASSERT( pOldUp == GetUpper(), "SwTxtFrm::CalcFollow: heavy follow" ); 379 #endif 380 381 const long nRemaining = 382 - (GetUpper()->Frm().*fnRect->fnBottomDist)( nOldBottom ); 383 if ( nRemaining > 0 && !GetUpper()->IsSctFrm() && 384 nRemaining != ( bVert ? 385 nMyPos - Frm().Right() : 386 Frm().Top() - nMyPos ) ) 387 { 388 UNDO_SWAP( this ) 389 return sal_True; 390 } 391 } 392 393 UNDO_SWAP( this ) 394 395 return sal_False; 396 } 397 398 /************************************************************************* 399 * SwTxtFrm::AdjustFrm() 400 *************************************************************************/ 401 402 void SwTxtFrm::AdjustFrm( const SwTwips nChgHght, sal_Bool bHasToFit ) 403 { 404 if( IsUndersized() ) 405 { 406 if( GetOfst() && !IsFollow() ) // ein gescrollter Absatz (undersized) 407 return; 408 SetUndersized( nChgHght == 0 || bHasToFit ); 409 } 410 411 // AdjustFrm is called with a swapped frame during 412 // formatting but the frame is not swapped during FormatEmpty 413 SWAP_IF_SWAPPED( this ) 414 SWRECTFN ( this ) 415 416 // Die Size-Variable des Frames wird durch Grow inkrementiert 417 // oder durch Shrink dekrementiert. Wenn die Groesse 418 // unveraendert ist, soll nichts passieren! 419 if( nChgHght >= 0) 420 { 421 SwTwips nChgHeight = nChgHght; 422 if( nChgHght && !bHasToFit ) 423 { 424 if( IsInFtn() && !IsInSct() ) 425 { 426 SwTwips nReal = Grow( nChgHght, sal_True ); 427 if( nReal < nChgHght ) 428 { 429 SwTwips nBot = (*fnRect->fnYInc)( (Frm().*fnRect->fnGetBottom)(), 430 nChgHght - nReal ); 431 SwFrm* pCont = FindFtnFrm()->GetUpper(); 432 433 if( (pCont->Frm().*fnRect->fnBottomDist)( nBot ) > 0 ) 434 { 435 (Frm().*fnRect->fnAddBottom)( nChgHght ); 436 if( bVert ) 437 Prt().SSize().Width() += nChgHght; 438 else 439 Prt().SSize().Height() += nChgHght; 440 UNDO_SWAP( this ) 441 return; 442 } 443 } 444 } 445 446 Grow( nChgHght ); 447 448 if ( IsInFly() ) 449 { 450 //MA 06. May. 93: Wenn einer der Upper ein Fly ist, so ist es 451 //sehr wahrscheinlich, dass dieser Fly durch das Grow seine 452 //Position veraendert - also muss auch meine Position korrigiert 453 //werden (sonst ist die Pruefung s.u. nicht aussagekraeftig). 454 //Die Vorgaenger muessen berechnet werden, damit die Position 455 //korrekt berechnet werden kann. 456 if ( GetPrev() ) 457 { 458 SwFrm *pPre = GetUpper()->Lower(); 459 do 460 { pPre->Calc(); 461 pPre = pPre->GetNext(); 462 } while ( pPre && pPre != this ); 463 } 464 const Point aOldPos( Frm().Pos() ); 465 MakePos(); 466 if ( aOldPos != Frm().Pos() ) 467 { 468 // OD 2004-07-01 #i28701# - use new method <SwFrm::InvalidateObjs(..)> 469 // No format is performed for the floating screen objects. 470 InvalidateObjs( true ); 471 } 472 } 473 nChgHeight = 0; 474 } 475 // Ein Grow() wird von der Layout-Seite immer akzeptiert, 476 // also auch, wenn die FixSize des umgebenden Layoutframes 477 // dies nicht zulassen sollte. Wir ueberpruefen diesen 478 // Fall und korrigieren die Werte. 479 // MA 06. May. 93: Der Frm darf allerdings auch im Notfall nicht 480 // weiter geschrumpft werden als es seine Groesse zulaesst. 481 SwTwips nRstHeight; 482 if ( IsVertical() ) 483 { 484 ASSERT( ! IsSwapped(),"Swapped frame while calculating nRstHeight" ); 485 486 //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin 487 if ( IsVertLR() ) 488 nRstHeight = GetUpper()->Frm().Left() 489 + GetUpper()->Prt().Left() 490 + GetUpper()->Prt().Width() 491 - Frm().Left(); 492 else 493 nRstHeight = Frm().Left() + Frm().Width() - 494 ( GetUpper()->Frm().Left() + GetUpper()->Prt().Left() ); 495 } 496 else 497 nRstHeight = GetUpper()->Frm().Top() 498 + GetUpper()->Prt().Top() 499 + GetUpper()->Prt().Height() 500 - Frm().Top(); 501 502 //In Tabellenzellen kann ich mir evtl. noch ein wenig dazuholen, weil 503 //durch eine vertikale Ausrichtung auch oben noch Raum sein kann. 504 // --> OD 2004-11-25 #115759# - assure, that first lower in upper 505 // is the current one or is valid. 506 if ( IsInTab() && 507 ( GetUpper()->Lower() == this || 508 GetUpper()->Lower()->IsValid() ) ) 509 // <-- 510 { 511 long nAdd = (*fnRect->fnYDiff)( (GetUpper()->Lower()->Frm().*fnRect->fnGetTop)(), 512 (GetUpper()->*fnRect->fnGetPrtTop)() ); 513 ASSERT( nAdd >= 0, "Ey" ); 514 nRstHeight += nAdd; 515 } 516 517 /* ------------------------------------ 518 * #50964#: nRstHeight < 0 bedeutet, dass der TxtFrm komplett ausserhalb seines 519 * Upper liegt. Dies kann passieren, wenn er innerhalb eines FlyAtCntFrm liegt, der 520 * durch das Grow() die Seite gewechselt hat. In so einem Fall ist es falsch, der 521 * folgenden Grow-Versuch durchzufuehren. Im Bugfall fuehrte dies sogar zur 522 * Endlosschleife. 523 * -----------------------------------*/ 524 SwTwips nFrmHeight = (Frm().*fnRect->fnGetHeight)(); 525 SwTwips nPrtHeight = (Prt().*fnRect->fnGetHeight)(); 526 527 if( nRstHeight < nFrmHeight ) 528 { 529 //Kann sein, dass ich die richtige Grosse habe, der Upper aber zu 530 //klein ist und der Upper noch Platz schaffen kann. 531 if( ( nRstHeight >= 0 || ( IsInFtn() && IsInSct() ) ) && !bHasToFit ) 532 nRstHeight += GetUpper()->Grow( nFrmHeight - nRstHeight ); 533 // In spaltigen Bereichen wollen wir moeglichst nicht zu gross werden, damit 534 // nicht ueber GetNextSctLeaf weitere Bereiche angelegt werden. Stattdessen 535 // schrumpfen wir und notieren bUndersized, damit FormatWidthCols die richtige 536 // Spaltengroesse ermitteln kann. 537 if ( nRstHeight < nFrmHeight ) 538 { 539 if( bHasToFit || !IsMoveable() || 540 ( IsInSct() && !FindSctFrm()->MoveAllowed(this) ) ) 541 { 542 SetUndersized( sal_True ); 543 Shrink( Min( ( nFrmHeight - nRstHeight), nPrtHeight ) ); 544 } 545 else 546 SetUndersized( sal_False ); 547 } 548 } 549 else if( nChgHeight ) 550 { 551 if( nRstHeight - nFrmHeight < nChgHeight ) 552 nChgHeight = nRstHeight - nFrmHeight; 553 if( nChgHeight ) 554 Grow( nChgHeight ); 555 } 556 } 557 else 558 Shrink( -nChgHght ); 559 560 UNDO_SWAP( this ) 561 } 562 563 /************************************************************************* 564 * SwTxtFrm::AdjustFollow() 565 *************************************************************************/ 566 567 /* AdjustFollow erwartet folgende Situation: 568 * Der SwTxtIter steht am unteren Ende des Masters, der Offset wird 569 * im Follow eingestellt. 570 * nOffset haelt den Offset im Textstring, ab dem der Master abschliesst 571 * und der Follow beginnt. Wenn er 0 ist, wird der FolgeFrame geloescht. 572 */ 573 574 void SwTxtFrm::_AdjustFollow( SwTxtFormatter &rLine, 575 const xub_StrLen nOffset, const xub_StrLen nEnd, 576 const sal_uInt8 nMode ) 577 { 578 SwFrmSwapper aSwapper( this, sal_False ); 579 580 // Wir haben den Rest der Textmasse: alle Follows loeschen 581 // Sonderfall sind DummyPortions() 582 // - special cases are controlled by parameter <nMode>. 583 if( HasFollow() && !(nMode & 1) && nOffset == nEnd ) 584 { 585 while( GetFollow() ) 586 { 587 if( ((SwTxtFrm*)GetFollow())->IsLocked() ) 588 { 589 ASSERT( sal_False, "+SwTxtFrm::JoinFrm: Follow ist locked." ); 590 return; 591 } 592 JoinFrm(); 593 } 594 595 return; 596 } 597 598 // Tanz auf dem Vulkan: Wir formatieren eben schnell noch einmal 599 // die letzte Zeile fuer das QuoVadis-Geraffel. Selbstverstaendlich 600 // kann sich dadurch auch der Offset verschieben: 601 const xub_StrLen nNewOfst = ( IsInFtn() && ( !GetIndNext() || HasFollow() ) ) ? 602 rLine.FormatQuoVadis(nOffset) : nOffset; 603 604 if( !(nMode & 1) ) 605 { 606 // Wir klauen unseren Follows Textmasse, dabei kann es passieren, 607 // dass wir einige Follows Joinen muessen. 608 while( GetFollow() && GetFollow()->GetFollow() && 609 nNewOfst >= GetFollow()->GetFollow()->GetOfst() ) 610 { 611 DBG_LOOP; 612 JoinFrm(); 613 } 614 } 615 616 // Der Ofst hat sich verschoben. 617 if( GetFollow() ) 618 { 619 #if OSL_DEBUG_LEVEL > 1 620 static sal_Bool bTest = sal_False; 621 if( !bTest || ( nMode & 1 ) ) 622 #endif 623 if ( nMode ) 624 GetFollow()->ManipOfst( 0 ); 625 626 if ( CalcFollow( nNewOfst ) ) // CalcFollow erst zum Schluss, dort erfolgt ein SetOfst 627 rLine.SetOnceMore( sal_True ); 628 } 629 } 630 631 /************************************************************************* 632 * SwTxtFrm::JoinFrm() 633 *************************************************************************/ 634 635 SwCntntFrm *SwTxtFrm::JoinFrm() 636 { 637 ASSERT( GetFollow(), "+SwTxtFrm::JoinFrm: no follow" ); 638 SwTxtFrm *pFoll = GetFollow(); 639 640 SwTxtFrm *pNxt = pFoll->GetFollow(); 641 642 // Alle Fussnoten des zu zerstoerenden Follows werden auf uns 643 // umgehaengt. 644 xub_StrLen nStart = pFoll->GetOfst(); 645 if ( pFoll->HasFtn() ) 646 { 647 const SwpHints *pHints = pFoll->GetTxtNode()->GetpSwpHints(); 648 if( pHints ) 649 { 650 SwFtnBossFrm *pFtnBoss = 0; 651 SwFtnBossFrm *pEndBoss = 0; 652 for ( sal_uInt16 i = 0; i < pHints->Count(); ++i ) 653 { 654 const SwTxtAttr *pHt = (*pHints)[i]; 655 if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nStart ) 656 { 657 if( pHt->GetFtn().IsEndNote() ) 658 { 659 if( !pEndBoss ) 660 pEndBoss = pFoll->FindFtnBossFrm(); 661 pEndBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this ); 662 } 663 else 664 { 665 if( !pFtnBoss ) 666 pFtnBoss = pFoll->FindFtnBossFrm( sal_True ); 667 pFtnBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this ); 668 } 669 SetFtn( sal_True ); 670 } 671 } 672 } 673 } 674 675 #ifdef DBG_UTIL 676 else if ( pFoll->GetValidPrtAreaFlag() || 677 pFoll->GetValidSizeFlag() ) 678 { 679 pFoll->CalcFtnFlag(); 680 ASSERT( !pFoll->HasFtn(), "Missing FtnFlag." ); 681 } 682 #endif 683 684 pFoll->MoveFlyInCnt( this, nStart, STRING_LEN ); 685 pFoll->SetFtn( sal_False ); 686 // --> OD 2005-12-01 #i27138# 687 // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation. 688 // Relation CONTENT_FLOWS_FROM for current next paragraph will change 689 // and relation CONTENT_FLOWS_TO for current previous paragraph, which 690 // is <this>, will change. 691 { 692 ViewShell* pViewShell( pFoll->getRootFrm()->GetCurrShell() ); 693 if ( pViewShell && pViewShell->GetLayout() && 694 pViewShell->GetLayout()->IsAnyShellAccessible() ) 695 { 696 pViewShell->InvalidateAccessibleParaFlowRelation( 697 dynamic_cast<SwTxtFrm*>(pFoll->FindNextCnt( true )), 698 this ); 699 } 700 } 701 // <-- 702 pFoll->Cut(); 703 delete pFoll; 704 pFollow = pNxt; 705 return pNxt; 706 } 707 708 /************************************************************************* 709 * SwTxtFrm::SplitFrm() 710 *************************************************************************/ 711 712 SwCntntFrm *SwTxtFrm::SplitFrm( const xub_StrLen nTxtPos ) 713 { 714 SWAP_IF_SWAPPED( this ) 715 716 // Durch das Paste wird ein Modify() an mich verschickt. 717 // Damit meine Daten nicht verschwinden, locke ich mich. 718 SwTxtFrmLocker aLock( this ); 719 SwTxtFrm *pNew = (SwTxtFrm *)(GetTxtNode()->MakeFrm( this )); 720 pNew->bIsFollow = sal_True; 721 722 pNew->SetFollow( GetFollow() ); 723 SetFollow( pNew ); 724 725 pNew->Paste( GetUpper(), GetNext() ); 726 // --> OD 2005-12-01 #i27138# 727 // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation. 728 // Relation CONTENT_FLOWS_FROM for current next paragraph will change 729 // and relation CONTENT_FLOWS_TO for current previous paragraph, which 730 // is <this>, will change. 731 { 732 ViewShell* pViewShell( pNew->getRootFrm()->GetCurrShell() ); 733 if ( pViewShell && pViewShell->GetLayout() && 734 pViewShell->GetLayout()->IsAnyShellAccessible() ) 735 { 736 pViewShell->InvalidateAccessibleParaFlowRelation( 737 dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )), 738 this ); 739 } 740 } 741 // <-- 742 743 // Wenn durch unsere Aktionen Fussnoten in pNew landen, 744 // so muessen sie umgemeldet werden. 745 if ( HasFtn() ) 746 { 747 const SwpHints *pHints = GetTxtNode()->GetpSwpHints(); 748 if( pHints ) 749 { 750 SwFtnBossFrm *pFtnBoss = 0; 751 SwFtnBossFrm *pEndBoss = 0; 752 for ( sal_uInt16 i = 0; i < pHints->Count(); ++i ) 753 { 754 const SwTxtAttr *pHt = (*pHints)[i]; 755 if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nTxtPos ) 756 { 757 if( pHt->GetFtn().IsEndNote() ) 758 { 759 if( !pEndBoss ) 760 pEndBoss = FindFtnBossFrm(); 761 pEndBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew ); 762 } 763 else 764 { 765 if( !pFtnBoss ) 766 pFtnBoss = FindFtnBossFrm( sal_True ); 767 pFtnBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew ); 768 } 769 pNew->SetFtn( sal_True ); 770 } 771 } 772 } 773 } 774 775 #ifdef DBG_UTIL 776 else 777 { 778 CalcFtnFlag( nTxtPos-1 ); 779 ASSERT( !HasFtn(), "Missing FtnFlag." ); 780 } 781 #endif 782 783 MoveFlyInCnt( pNew, nTxtPos, STRING_LEN ); 784 785 // Kein SetOfst oder CalcFollow, weil gleich ohnehin ein AdjustFollow folgt. 786 787 pNew->ManipOfst( nTxtPos ); 788 789 UNDO_SWAP( this ) 790 return pNew; 791 } 792 793 794 /************************************************************************* 795 * virtual SwTxtFrm::SetOfst() 796 *************************************************************************/ 797 798 void SwTxtFrm::_SetOfst( const xub_StrLen nNewOfst ) 799 { 800 #ifdef DBGTXT 801 // Es gibt tatsaechlich einen Sonderfall, in dem ein SetOfst(0) 802 // zulaessig ist: bug 3496 803 ASSERT( nNewOfst, "!SwTxtFrm::SetOfst: missing JoinFrm()." ); 804 #endif 805 806 // Die Invalidierung unseres Follows ist nicht noetig. 807 // Wir sind ein Follow, werden gleich formatiert und 808 // rufen von dort aus das SetOfst() ! 809 nOfst = nNewOfst; 810 SwParaPortion *pPara = GetPara(); 811 if( pPara ) 812 { 813 SwCharRange &rReformat = *(pPara->GetReformat()); 814 rReformat.Start() = 0; 815 rReformat.Len() = GetTxt().Len(); 816 *(pPara->GetDelta()) = rReformat.Len(); 817 } 818 InvalidateSize(); 819 } 820 821 /************************************************************************* 822 * SwTxtFrm::CalcPreps 823 *************************************************************************/ 824 825 sal_Bool SwTxtFrm::CalcPreps() 826 { 827 ASSERT( ! IsVertical() || ! IsSwapped(), "SwTxtFrm::CalcPreps with swapped frame" ); 828 SWRECTFN( this ); 829 830 SwParaPortion *pPara = GetPara(); 831 if ( !pPara ) 832 return sal_False; 833 sal_Bool bPrep = pPara->IsPrep(); 834 sal_Bool bPrepWidows = pPara->IsPrepWidows(); 835 sal_Bool bPrepAdjust = pPara->IsPrepAdjust(); 836 sal_Bool bPrepMustFit = pPara->IsPrepMustFit(); 837 ResetPreps(); 838 839 sal_Bool bRet = sal_False; 840 if( bPrep && !pPara->GetReformat()->Len() ) 841 { 842 // PREP_WIDOWS bedeutet, dass im Follow die Orphans-Regel 843 // zuschlug. 844 // Es kann in unguenstigen Faellen vorkommen, dass auch ein 845 // PrepAdjust vorliegt (3680)! 846 if( bPrepWidows ) 847 { 848 if( !GetFollow() ) 849 { 850 ASSERT( GetFollow(), "+SwTxtFrm::CalcPreps: no credits" ); 851 return sal_False; 852 } 853 854 // Wir muessen uns auf zwei Faelle einstellen: 855 // Wir konnten dem Follow noch ein paar Zeilen abgeben, 856 // -> dann muessen wir schrumpfen 857 // oder wir muessen auf die naechste Seite 858 // -> dann lassen wir unseren Frame zu gross werden. 859 860 SwTwips nChgHeight = GetParHeight(); 861 if( nChgHeight >= (Prt().*fnRect->fnGetHeight)() ) 862 { 863 if( bPrepMustFit ) 864 { 865 GetFollow()->SetJustWidow( sal_True ); 866 GetFollow()->Prepare( PREP_CLEAR ); 867 } 868 else if ( bVert ) 869 { 870 Frm().Width( Frm().Width() + Frm().Left() ); 871 Prt().Width( Prt().Width() + Frm().Left() ); 872 Frm().Left( 0 ); 873 SetWidow( sal_True ); 874 } 875 else 876 { 877 SwTwips nTmp = LONG_MAX - (Frm().Top()+10000); 878 SwTwips nDiff = nTmp - Frm().Height(); 879 Frm().Height( nTmp ); 880 Prt().Height( Prt().Height() + nDiff ); 881 SetWidow( sal_True ); 882 } 883 } 884 else 885 { 886 ASSERT( nChgHeight < (Prt().*fnRect->fnGetHeight)(), 887 "+SwTxtFrm::CalcPrep: wanna shrink" ); 888 889 nChgHeight = (Prt().*fnRect->fnGetHeight)() - nChgHeight; 890 891 GetFollow()->SetJustWidow( sal_True ); 892 GetFollow()->Prepare( PREP_CLEAR ); 893 Shrink( nChgHeight ); 894 SwRect &rRepaint = *(pPara->GetRepaint()); 895 896 if ( bVert ) 897 { 898 SwRect aRepaint( Frm().Pos() + Prt().Pos(), Prt().SSize() ); 899 SwitchVerticalToHorizontal( aRepaint ); 900 rRepaint.Chg( aRepaint.Pos(), aRepaint.SSize() ); 901 } 902 else 903 rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() ); 904 905 // 6792: Rrand < LRand und Repaint 906 if( 0 >= rRepaint.Width() ) 907 rRepaint.Width(1); 908 } 909 bRet = sal_True; 910 } 911 912 else if ( bPrepAdjust ) 913 { 914 if ( HasFtn() ) 915 { 916 if( !CalcPrepFtnAdjust() ) 917 { 918 if( bPrepMustFit ) 919 { 920 SwTxtLineAccess aAccess( this ); 921 aAccess.GetPara()->SetPrepMustFit( sal_True ); 922 } 923 return sal_False; 924 } 925 } 926 927 SWAP_IF_NOT_SWAPPED( this ) 928 929 SwTxtFormatInfo aInf( this ); 930 SwTxtFormatter aLine( this, &aInf ); 931 932 WidowsAndOrphans aFrmBreak( this ); 933 // Egal was die Attribute meinen, bei MustFit wird 934 // der Absatz im Notfall trotzdem gesplittet... 935 if( bPrepMustFit ) 936 { 937 aFrmBreak.SetKeep( sal_False ); 938 aFrmBreak.ClrOrphLines(); 939 } 940 // Bevor wir FormatAdjust aufrufen muessen wir dafuer 941 // sorgen, dass die Zeilen, die unten raushaengen 942 // auch tatsaechlich abgeschnitten werden. 943 // OD 2004-02-25 #i16128# - method renamed 944 sal_Bool bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine ); 945 bRet = sal_True; 946 while( !bBreak && aLine.Next() ) 947 { 948 // OD 2004-02-25 #i16128# - method renamed 949 bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine ); 950 } 951 if( bBreak ) 952 { 953 // Es gibt Komplikationen: wenn TruncLines gerufen wird, 954 // veraendern sich ploetzlich die Bedingungen in 955 // IsInside, so dass IsBreakNow andere Ergebnisse 956 // liefern kann. Aus diesem Grund wird rFrmBreak bekannt 957 // gegeben, dass da wo rLine steht, das Ende erreicht 958 // ist. Mal sehen, ob's klappt ... 959 aLine.TruncLines(); 960 aFrmBreak.SetRstHeight( aLine ); 961 FormatAdjust( aLine, aFrmBreak, aInf.GetTxt().Len(), aInf.IsStop() ); 962 } 963 else 964 { 965 if( !GetFollow() ) 966 { 967 FormatAdjust( aLine, aFrmBreak, 968 aInf.GetTxt().Len(), aInf.IsStop() ); 969 } 970 else if ( !aFrmBreak.IsKeepAlways() ) 971 { 972 // Siehe Bug: 2320 973 // Vor dem Master wird eine Zeile geloescht, der Follow 974 // koennte eine Zeile abgeben. 975 const SwCharRange aFollowRg( GetFollow()->GetOfst(), 1 ); 976 *(pPara->GetReformat()) += aFollowRg; 977 // Es soll weitergehen! 978 bRet = sal_False; 979 } 980 } 981 982 UNDO_SWAP( this ) 983 // Eine letzte Ueberpruefung, falls das FormatAdjust() nichts 984 // brachte, muessen wir amputieren. 985 if( bPrepMustFit ) 986 { 987 const SwTwips nMust = (GetUpper()->*fnRect->fnGetPrtBottom)(); 988 const SwTwips nIs = (Frm().*fnRect->fnGetBottom)(); 989 990 if( bVert && nIs < nMust ) 991 { 992 Shrink( nMust - nIs ); 993 if( Prt().Width() < 0 ) 994 Prt().Width( 0 ); 995 SetUndersized( sal_True ); 996 } 997 else if ( ! bVert && nIs > nMust ) 998 { 999 Shrink( nIs - nMust ); 1000 if( Prt().Height() < 0 ) 1001 Prt().Height( 0 ); 1002 SetUndersized( sal_True ); 1003 } 1004 } 1005 } 1006 } 1007 pPara->SetPrepMustFit( bPrepMustFit ); 1008 return bRet; 1009 } 1010 1011 1012 /************************************************************************* 1013 * SwTxtFrm::FormatAdjust() 1014 *************************************************************************/ 1015 1016 // Hier werden die Fussnoten und "als Zeichen"-gebundenen Objekte umgehaengt 1017 #define CHG_OFFSET( pFrm, nNew )\ 1018 {\ 1019 if( pFrm->GetOfst() < nNew )\ 1020 pFrm->MoveFlyInCnt( this, 0, nNew );\ 1021 else if( pFrm->GetOfst() > nNew )\ 1022 MoveFlyInCnt( pFrm, nNew, STRING_LEN );\ 1023 } 1024 1025 void SwTxtFrm::FormatAdjust( SwTxtFormatter &rLine, 1026 WidowsAndOrphans &rFrmBreak, 1027 const xub_StrLen nStrLen, 1028 const sal_Bool bDummy ) 1029 { 1030 SWAP_IF_NOT_SWAPPED( this ) 1031 1032 SwParaPortion *pPara = rLine.GetInfo().GetParaPortion(); 1033 1034 xub_StrLen nEnd = rLine.GetStart(); 1035 1036 sal_Bool bHasToFit = pPara->IsPrepMustFit(); 1037 1038 // Das StopFlag wird durch Fussnoten gesetzt, 1039 // die auf die naechste Seite wollen. 1040 // OD, FME 2004-03-03 - call base class method <SwTxtFrmBreak::IsBreakNow(..)> 1041 // instead of method <WidowsAndOrphans::IsBreakNow(..)> to get a break, 1042 // even if due to widow rule no enough lines exists. 1043 sal_uInt8 nNew = ( !GetFollow() && 1044 nEnd < nStrLen && 1045 ( rLine.IsStop() || 1046 ( bHasToFit 1047 ? ( rLine.GetLineNr() > 1 && 1048 !rFrmBreak.IsInside( rLine ) ) 1049 : rFrmBreak.IsBreakNow( rLine ) ) ) ) 1050 ? 1 : 0; 1051 // --> OD #i84870# 1052 // no split of text frame, which only contains a as-character anchored object 1053 const bool bOnlyContainsAsCharAnchoredObj = 1054 !IsFollow() && nStrLen == 1 && 1055 GetDrawObjs() && GetDrawObjs()->Count() == 1 && 1056 (*GetDrawObjs())[0]->GetFrmFmt().GetAnchor().GetAnchorId() == FLY_AS_CHAR; 1057 if ( nNew && bOnlyContainsAsCharAnchoredObj ) 1058 { 1059 nNew = 0; 1060 } 1061 // <-- 1062 if ( nNew ) 1063 { 1064 SplitFrm( nEnd ); 1065 } 1066 1067 const SwFrm *pBodyFrm = (const SwFrm*)(FindBodyFrm()); 1068 1069 const long nBodyHeight = pBodyFrm ? ( IsVertical() ? 1070 pBodyFrm->Frm().Width() : 1071 pBodyFrm->Frm().Height() ) : 0; 1072 1073 // Wenn die aktuellen Werte berechnet wurden, anzeigen, dass 1074 // sie jetzt gueltig sind. 1075 *(pPara->GetReformat()) = SwCharRange(); 1076 sal_Bool bDelta = *pPara->GetDelta() != 0; 1077 *(pPara->GetDelta()) = 0; 1078 1079 if( rLine.IsStop() ) 1080 { 1081 rLine.TruncLines( sal_True ); 1082 nNew = 1; 1083 } 1084 1085 // FindBreak schneidet die letzte Zeile ab. 1086 if( !rFrmBreak.FindBreak( this, rLine, bHasToFit ) ) 1087 { 1088 // Wenn wir bis zum Ende durchformatiert haben, wird nEnd auf das Ende 1089 // gesetzt. In AdjustFollow wird dadurch ggf. JoinFrm() ausgefuehrt. 1090 // Ansonsten ist nEnd das Ende der letzten Zeile im Master. 1091 xub_StrLen nOld = nEnd; 1092 nEnd = rLine.GetEnd(); 1093 if( GetFollow() ) 1094 { 1095 if( nNew && nOld < nEnd ) 1096 RemoveFtn( nOld, nEnd - nOld ); 1097 CHG_OFFSET( GetFollow(), nEnd ) 1098 if( !bDelta ) 1099 GetFollow()->ManipOfst( nEnd ); 1100 } 1101 } 1102 else 1103 { // Wenn wir Zeilen abgeben, darf kein Join auf den Folows gerufen werden, 1104 // im Gegenteil, es muss ggf. sogar ein Follow erzeugt werden. 1105 // Dies muss auch geschehen, wenn die Textmasse komplett im Master 1106 // bleibt, denn es k???nnte ja ein harter Zeilenumbruch noch eine weitere 1107 // Zeile (ohne Textmassse) notwendig machen! 1108 nEnd = rLine.GetEnd(); 1109 if( GetFollow() ) 1110 { 1111 // OD 21.03.2003 #108121# - Another case for not joining the follow: 1112 // Text frame has no content, but a numbering. Then, do *not* join. 1113 // Example of this case: When an empty, but numbered paragraph 1114 // at the end of page is completely displaced by a fly frame. 1115 // Thus, the text frame introduced a follow by a 1116 // <SwTxtFrm::SplitFrm(..)> - see below. The follow then shows 1117 // the numbering and must stay. 1118 if ( GetFollow()->GetOfst() != nEnd || 1119 GetFollow()->IsFieldFollow() || 1120 ( nStrLen == 0 && GetTxtNode()->GetNumRule() ) ) 1121 { 1122 nNew |= 3; 1123 } 1124 CHG_OFFSET( GetFollow(), nEnd ) 1125 GetFollow()->ManipOfst( nEnd ); 1126 } 1127 else 1128 { 1129 // OD 21.03.2003 #108121# - Only split frame, if the frame contains 1130 // content or contains no content, but has a numbering. 1131 // OD #i84870# - no split, if text frame only contains one 1132 // as-character anchored object. 1133 if ( !bOnlyContainsAsCharAnchoredObj && 1134 ( nStrLen > 0 || 1135 ( nStrLen == 0 && GetTxtNode()->GetNumRule() ) ) 1136 ) 1137 { 1138 SplitFrm( nEnd ); 1139 nNew |= 3; 1140 } 1141 } 1142 // Wenn sich die Resthoehe geaendert hat, z.B. durch RemoveFtn() 1143 // dann muessen wir auffuellen, um Oszillationen zu vermeiden! 1144 if( bDummy && pBodyFrm && 1145 nBodyHeight < ( IsVertical() ? 1146 pBodyFrm->Frm().Width() : 1147 pBodyFrm->Frm().Height() ) ) 1148 rLine.MakeDummyLine(); 1149 } 1150 1151 // In AdjustFrm() stellen wir uns selbst per Grow/Shrink ein, 1152 // in AdjustFollow() stellen wir unseren FolgeFrame ein. 1153 1154 const SwTwips nDocPrtTop = Frm().Top() + Prt().Top(); 1155 const SwTwips nOldHeight = Prt().SSize().Height(); 1156 SwTwips nChg = rLine.CalcBottomLine() - nDocPrtTop - nOldHeight; 1157 // --> OD #i84870# - no shrink of text frame, if it only contains one 1158 // as-character anchored object. 1159 if ( nChg < 0 && 1160 bOnlyContainsAsCharAnchoredObj ) 1161 { 1162 nChg = 0; 1163 } 1164 // <-- 1165 1166 // Vertical Formatting: 1167 // The (rotated) repaint rectangle's x coordinate referes to the frame. 1168 // If the frame grows (or shirks) the repaint rectangle cannot simply 1169 // be rotated back after formatting, because we use the upper left point 1170 // of the frame for rotation. This point changes when growing/shrinking. 1171 1172 //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin 1173 if ( IsVertical() && !IsVertLR() && nChg ) 1174 { 1175 SwRect &rRepaint = *(pPara->GetRepaint()); 1176 rRepaint.Left( rRepaint.Left() - nChg ); 1177 rRepaint.Width( rRepaint.Width() - nChg ); 1178 } 1179 1180 AdjustFrm( nChg, bHasToFit ); 1181 1182 /* 1183 // FME 16.07.2003 #i16930# - removed this code because it did not 1184 // work correctly. In SwCntntFrm::MakeAll, the frame did not move to the 1185 // next page, instead the print area was recalculated and 1186 // Prepare( PREP_POS_CHGD, (const void*)&bFormatted, sal_False ) invalidated 1187 // the other flags => loop 1188 1189 // OD 04.04.2003 #108446# - handle special case: 1190 // If text frame contains no content and just has split, because of a 1191 // line stop, it has to move forward. To force this forward move without 1192 // unnecessary formatting of its footnotes and its follow, especially in 1193 // columned sections, adjust frame height to zero (0) and do not perform 1194 // the intrinsic format of the follow. 1195 // The formating method <SwCntntFrm::MakeAll()> will initiate the move forward. 1196 sal_Bool bForcedNoIntrinsicFollowCalc = sal_False; 1197 if ( nEnd == 0 && 1198 rLine.IsStop() && HasFollow() && nNew == 1 1199 ) 1200 { 1201 AdjustFrm( -Frm().SSize().Height(), bHasToFit ); 1202 Prt().Pos().Y() = 0; 1203 Prt().Height( Frm().Height() ); 1204 if ( FollowFormatAllowed() ) 1205 { 1206 bForcedNoIntrinsicFollowCalc = sal_True; 1207 ForbidFollowFormat(); 1208 } 1209 } 1210 else 1211 { 1212 AdjustFrm( nChg, bHasToFit ); 1213 } 1214 */ 1215 1216 if( HasFollow() || IsInFtn() ) 1217 _AdjustFollow( rLine, nEnd, nStrLen, nNew ); 1218 1219 // FME 16.07.2003 #i16930# - removed this code because it did not work 1220 // correctly 1221 // OD 04.04.2003 #108446# - allow intrinsic format of follow, if above 1222 // special case has forbit it. 1223 /* if ( bForcedNoIntrinsicFollowCalc ) 1224 { 1225 AllowFollowFormat(); 1226 } 1227 */ 1228 1229 pPara->SetPrepMustFit( sal_False ); 1230 1231 UNDO_SWAP( this ) 1232 } 1233 1234 /************************************************************************* 1235 * SwTxtFrm::FormatLine() 1236 *************************************************************************/ 1237 1238 // bPrev zeigt an, ob Reformat.Start() wegen Prev() vorgezogen wurde. 1239 // Man weiss sonst nicht, ob man Repaint weiter einschraenken kann oder nicht. 1240 1241 1242 sal_Bool SwTxtFrm::FormatLine( SwTxtFormatter &rLine, const sal_Bool bPrev ) 1243 { 1244 ASSERT( ! IsVertical() || IsSwapped(), 1245 "SwTxtFrm::FormatLine( rLine, bPrev) with unswapped frame" ); 1246 SwParaPortion *pPara = rLine.GetInfo().GetParaPortion(); 1247 // Nach rLine.FormatLine() haelt nStart den neuen Wert, 1248 // waehrend in pOldStart der alte Offset gepflegt wird. 1249 // Ueber diesen Weg soll das nDelta ersetzt werden. 1250 // *pOldStart += rLine.GetCurr()->GetLen(); 1251 const SwLineLayout *pOldCur = rLine.GetCurr(); 1252 const xub_StrLen nOldLen = pOldCur->GetLen(); 1253 const KSHORT nOldAscent = pOldCur->GetAscent(); 1254 const KSHORT nOldHeight = pOldCur->Height(); 1255 const SwTwips nOldWidth = pOldCur->Width() + pOldCur->GetHangingMargin(); 1256 const sal_Bool bOldHyph = pOldCur->IsEndHyph(); 1257 SwTwips nOldTop = 0; 1258 SwTwips nOldBottom = 0; 1259 if( rLine.GetCurr()->IsClipping() ) 1260 rLine.CalcUnclipped( nOldTop, nOldBottom ); 1261 1262 const xub_StrLen nNewStart = rLine.FormatLine( rLine.GetStart() ); 1263 1264 ASSERT( Frm().Pos().Y() + Prt().Pos().Y() == rLine.GetFirstPos(), 1265 "SwTxtFrm::FormatLine: frame leaves orbit." ); 1266 ASSERT( rLine.GetCurr()->Height(), 1267 "SwTxtFrm::FormatLine: line height is zero" ); 1268 1269 // Das aktuelle Zeilenumbruchobjekt. 1270 const SwLineLayout *pNew = rLine.GetCurr(); 1271 1272 sal_Bool bUnChg = nOldLen == pNew->GetLen() && 1273 bOldHyph == pNew->IsEndHyph(); 1274 if ( bUnChg && !bPrev ) 1275 { 1276 // 6672: Toleranz von SLOPPY_TWIPS (5 Twips); vgl. 6922 1277 const long nWidthDiff = nOldWidth > pNew->Width() 1278 ? nOldWidth - pNew->Width() 1279 : pNew->Width() - nOldWidth; 1280 1281 // we only declare a line as unchanged, if its main values have not 1282 // changed and it is not the last line (!paragraph end symbol!) 1283 bUnChg = nOldHeight == pNew->Height() && 1284 nOldAscent == pNew->GetAscent() && 1285 nWidthDiff <= SLOPPY_TWIPS && 1286 pOldCur->GetNext(); 1287 } 1288 1289 // rRepaint wird berechnet: 1290 const SwTwips nBottom = rLine.Y() + rLine.GetLineHeight(); 1291 SwRepaint &rRepaint = *(pPara->GetRepaint()); 1292 if( bUnChg && rRepaint.Top() == rLine.Y() 1293 && (bPrev || nNewStart <= pPara->GetReformat()->Start()) 1294 && ( nNewStart < GetTxtNode()->GetTxt().Len() ) ) 1295 { 1296 rRepaint.Top( nBottom ); 1297 rRepaint.Height( 0 ); 1298 } 1299 else 1300 { 1301 if( nOldTop ) 1302 { 1303 if( nOldTop < rRepaint.Top() ) 1304 rRepaint.Top( nOldTop ); 1305 if( !rLine.IsUnclipped() || nOldBottom > rRepaint.Bottom() ) 1306 { 1307 rRepaint.Bottom( nOldBottom - 1 ); 1308 rLine.SetUnclipped( sal_True ); 1309 } 1310 } 1311 if( rLine.GetCurr()->IsClipping() && rLine.IsFlyInCntBase() ) 1312 { 1313 SwTwips nTmpTop, nTmpBottom; 1314 rLine.CalcUnclipped( nTmpTop, nTmpBottom ); 1315 if( nTmpTop < rRepaint.Top() ) 1316 rRepaint.Top( nTmpTop ); 1317 if( !rLine.IsUnclipped() || nTmpBottom > rRepaint.Bottom() ) 1318 { 1319 rRepaint.Bottom( nTmpBottom - 1 ); 1320 rLine.SetUnclipped( sal_True ); 1321 } 1322 } 1323 else 1324 { 1325 if( !rLine.IsUnclipped() || nBottom > rRepaint.Bottom() ) 1326 { 1327 rRepaint.Bottom( nBottom - 1 ); 1328 rLine.SetUnclipped( sal_False ); 1329 } 1330 } 1331 SwTwips nRght = Max( nOldWidth, pNew->Width() + 1332 pNew->GetHangingMargin() ); 1333 ViewShell *pSh = getRootFrm()->GetCurrShell(); 1334 const SwViewOption *pOpt = pSh ? pSh->GetViewOptions() : 0; 1335 if( pOpt && (pOpt->IsParagraph() || pOpt->IsLineBreak()) ) 1336 nRght += ( Max( nOldAscent, pNew->GetAscent() ) ); 1337 else 1338 nRght += ( Max( nOldAscent, pNew->GetAscent() ) / 4); 1339 nRght += rLine.GetLeftMargin(); 1340 if( rRepaint.GetOfst() || rRepaint.GetRightOfst() < nRght ) 1341 rRepaint.SetRightOfst( nRght ); 1342 1343 // Finally we enlarge the repaint rectangle if we found an underscore 1344 // within our line. 40 Twips should be enough 1345 const sal_Bool bHasUnderscore = 1346 ( rLine.GetInfo().GetUnderScorePos() < nNewStart ); 1347 if ( bHasUnderscore || rLine.GetCurr()->HasUnderscore() ) 1348 rRepaint.Bottom( rRepaint.Bottom() + 40 ); 1349 1350 ((SwLineLayout*)rLine.GetCurr())->SetUnderscore( bHasUnderscore ); 1351 } 1352 if( !bUnChg ) 1353 rLine.SetChanges(); 1354 1355 // Die gute, alte nDelta-Berechnung: 1356 *(pPara->GetDelta()) -= long(pNew->GetLen()) - long(nOldLen); 1357 1358 // Stop! 1359 if( rLine.IsStop() ) 1360 return sal_False; 1361 1362 // Unbedingt noch eine Zeile 1363 if( rLine.IsNewLine() ) 1364 return sal_True; 1365 1366 // bis zum Ende des Strings ? 1367 if( nNewStart >= GetTxtNode()->GetTxt().Len() ) 1368 return sal_False; 1369 1370 if( rLine.GetInfo().IsShift() ) 1371 return sal_True; 1372 1373 // Ende des Reformats erreicht ? 1374 const xub_StrLen nEnd = pPara->GetReformat()->Start() + 1375 pPara->GetReformat()->Len(); 1376 1377 if( nNewStart <= nEnd ) 1378 return sal_True; 1379 1380 return 0 != *(pPara->GetDelta()); 1381 } 1382 1383 /************************************************************************* 1384 * SwTxtFrm::_Format() 1385 *************************************************************************/ 1386 1387 void SwTxtFrm::_Format( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf, 1388 const sal_Bool bAdjust ) 1389 { 1390 ASSERT( ! IsVertical() || IsSwapped(),"SwTxtFrm::_Format with unswapped frame" ); 1391 1392 SwParaPortion *pPara = rLine.GetInfo().GetParaPortion(); 1393 rLine.SetUnclipped( sal_False ); 1394 1395 // Das war dem C30 zu kompliziert: aString( GetTxt() ); 1396 const XubString &rString = GetTxtNode()->GetTxt(); 1397 const xub_StrLen nStrLen = rString.Len(); 1398 1399 SwCharRange &rReformat = *(pPara->GetReformat()); 1400 SwRepaint &rRepaint = *(pPara->GetRepaint()); 1401 SwRepaint *pFreeze = NULL; 1402 1403 // Aus Performancegruenden wird in Init() rReformat auf STRING_LEN gesetzt. 1404 // Fuer diesen Fall wird rReformat angepasst. 1405 if( rReformat.Len() > nStrLen ) 1406 rReformat.Len() = nStrLen; 1407 1408 // Optimiert: 1409 xub_StrLen nEnd = rReformat.Start() + rReformat.Len(); 1410 if( nEnd > nStrLen ) 1411 { 1412 rReformat.Len() = nStrLen - rReformat.Start(); 1413 nEnd = nStrLen; 1414 } 1415 1416 SwTwips nOldBottom; 1417 if( GetOfst() && !IsFollow() ) 1418 { 1419 rLine.Bottom(); 1420 nOldBottom = rLine.Y(); 1421 rLine.Top(); 1422 } 1423 else 1424 nOldBottom = 0; 1425 rLine.CharToLine( rReformat.Start() ); 1426 1427 // Worte koennen durch Fortfall oder Einfuegen eines Space 1428 // auf die Zeile vor der editierten hinausgezogen werden, 1429 // deshalb muss diese ebenfalls formatiert werden. 1430 // Optimierung: Wenn rReformat erst hinter dem ersten Wort der 1431 // Zeile beginnt, so kann diese Zeile die vorige nicht mehr beeinflussen. 1432 // AMA: Leider doch, Textgroessenaenderungen + FlyFrames, die Rueckwirkung 1433 // kann im Extremfall mehrere Zeilen (Frames!!!) betreffen! 1434 1435 // --> FME 2005-04-18 #i46560# 1436 // FME: Yes, consider this case: (word ) has to go to the next line 1437 // because ) is a forbidden character at the beginning of a line although 1438 // (word would still fit on the previous line. Adding text right in front 1439 // of ) would not trigger a reformatting of the previous line. Adding 1 1440 // to the result of FindBrk() does not solve the problem in all cases, 1441 // nevertheless it should be sufficient. 1442 // <-- 1443 sal_Bool bPrev = rLine.GetPrev() && 1444 ( FindBrk( rString, rLine.GetStart(), rReformat.Start() + 1 ) 1445 // --> FME 2005-04-18 #i46560# 1446 + 1 1447 // <-- 1448 >= rReformat.Start() || 1449 rLine.GetCurr()->IsRest() ); 1450 if( bPrev ) 1451 { 1452 while( rLine.Prev() ) 1453 if( rLine.GetCurr()->GetLen() && !rLine.GetCurr()->IsRest() ) 1454 { 1455 if( !rLine.GetStart() ) 1456 rLine.Top(); // damit NumDone nicht durcheinander kommt 1457 break; 1458 } 1459 xub_StrLen nNew = rLine.GetStart() + rLine.GetLength(); 1460 if( nNew ) 1461 { 1462 --nNew; 1463 if( CH_BREAK == rString.GetChar( nNew ) ) 1464 { 1465 ++nNew; 1466 rLine.Next(); 1467 bPrev = sal_False; 1468 } 1469 } 1470 rReformat.Len() += rReformat.Start() - nNew; 1471 rReformat.Start() = nNew; 1472 } 1473 1474 rRepaint.SetOfst( 0 ); 1475 rRepaint.SetRightOfst( 0 ); 1476 rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() ); 1477 if( pPara->IsMargin() ) 1478 rRepaint.Width( rRepaint.Width() + pPara->GetHangingMargin() ); 1479 rRepaint.Top( rLine.Y() ); 1480 // 6792: Rrand < LRand und Repaint 1481 if( 0 >= rRepaint.Width() ) 1482 rRepaint.Width(1); 1483 WidowsAndOrphans aFrmBreak( this, rInf.IsTest() ? 1 : 0 ); 1484 1485 // rLine steht jetzt auf der ersten Zeile, die formatiert werden 1486 // muss. Das Flag bFirst sorgt dafuer, dass nicht Next() gerufen wird. 1487 // Das ganze sieht verdreht aus, aber es muss sichergestellt werden, 1488 // dass bei IsBreakNow rLine auf der Zeile zum stehen kommt, die 1489 // nicht mehr passt. 1490 sal_Bool bFirst = sal_True; 1491 sal_Bool bFormat = sal_True; 1492 1493 // 5383: Das CharToLine() kann uns auch in den roten Bereich fuehren. 1494 // In diesem Fall muessen wir zurueckwandern, bis die Zeile, die 1495 // nicht mehr passt in rLine eingestellt ist. Ansonsten geht Textmasse 1496 // verloren, weil der Ofst im Follow falsch eingestellt wird. 1497 1498 // OD 2004-02-25 #i16128# - method renamed 1499 sal_Bool bBreak = ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 ) 1500 && aFrmBreak.IsBreakNowWidAndOrp( rLine ); 1501 if( bBreak ) 1502 { 1503 sal_Bool bPrevDone = 0 != rLine.Prev(); 1504 // OD 2004-02-25 #i16128# - method renamed 1505 while( bPrevDone && aFrmBreak.IsBreakNowWidAndOrp(rLine) ) 1506 bPrevDone = 0 != rLine.Prev(); 1507 if( bPrevDone ) 1508 { 1509 aFrmBreak.SetKeep( sal_False ); 1510 rLine.Next(); 1511 } 1512 rLine.TruncLines(); 1513 1514 // auf Nummer sicher: 1515 // OD 2004-02-25 #i16128# - method renamed 1516 bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine) && 1517 ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 ); 1518 } 1519 1520 /* Bedeutung der folgenden Flags: 1521 Ist das Watch(End/Mid)Hyph-Flag gesetzt, so muss formatiert werden, wenn 1522 eine Trennung am (Zeilenende/Fly) vorliegt, sofern MaxHyph erreicht ist. 1523 Das Jump(End/Mid)Flag bedeutet, dass die naechste Zeile, bei der keine 1524 Trennung (Zeilenende/Fly) vorliegt, formatiert werden muss, da jetzt 1525 umgebrochen werden koennte, was vorher moeglicherweise durch MaxHyph 1526 verboten war. 1527 Watch(End/Mid)Hyph wird gesetzt, wenn die letzte formatierte Zeile eine 1528 Trennstelle erhalten hat, vorher aber keine hatte, 1529 Jump(End/Mid)Hyph, wenn eine Trennstelle verschwindet. 1530 */ 1531 sal_Bool bJumpEndHyph = sal_False, 1532 bWatchEndHyph = sal_False, 1533 bJumpMidHyph = sal_False, 1534 bWatchMidHyph = sal_False; 1535 1536 const SwAttrSet& rAttrSet = GetTxtNode()->GetSwAttrSet(); 1537 sal_Bool bMaxHyph = ( 0 != 1538 ( rInf.MaxHyph() = rAttrSet.GetHyphenZone().GetMaxHyphens() ) ); 1539 if ( bMaxHyph ) 1540 rLine.InitCntHyph(); 1541 1542 if( IsFollow() && IsFieldFollow() && rLine.GetStart() == GetOfst() ) 1543 { 1544 const SwLineLayout* pLine; 1545 { 1546 SwTxtFrm *pMaster = FindMaster(); 1547 ASSERT( pMaster, "SwTxtFrm::Format: homeless follow" ); 1548 if( !pMaster->HasPara() ) 1549 pMaster->GetFormatted(); 1550 SwTxtSizeInfo aInf( pMaster ); 1551 SwTxtIter aMasterLine( pMaster, &aInf ); 1552 aMasterLine.Bottom(); 1553 pLine = aMasterLine.GetCurr(); 1554 } 1555 SwLinePortion* pRest = 1556 rLine.MakeRestPortion( pLine, GetOfst() ); 1557 if( pRest ) 1558 rInf.SetRest( pRest ); 1559 else 1560 SetFieldFollow( sal_False ); 1561 } 1562 1563 /* Zum Abbruchkriterium: 1564 * Um zu erkennen, dass eine Zeile nicht mehr auf die Seite passt, 1565 * muss sie formatiert werden. Dieser Ueberhang wird z.B. in AdjustFollow 1566 * wieder entfernt. 1567 * Eine weitere Komplikation: wenn wir der Master sind, so muessen 1568 * wir die Zeilen durchgehen, da es ja sein kann, dass eine Zeile 1569 * vom Follow in den Master rutschen kann. 1570 */ 1571 do 1572 { 1573 DBG_LOOP; 1574 if( bFirst ) 1575 bFirst = sal_False; 1576 else 1577 { 1578 if ( bMaxHyph ) 1579 { 1580 if ( rLine.GetCurr()->IsEndHyph() ) 1581 rLine.CntEndHyph()++; 1582 else 1583 rLine.CntEndHyph() = 0; 1584 if ( rLine.GetCurr()->IsMidHyph() ) 1585 rLine.CntMidHyph()++; 1586 else 1587 rLine.CntMidHyph() = 0; 1588 } 1589 if( !rLine.Next() ) 1590 { 1591 if( !bFormat ) 1592 { 1593 SwLinePortion* pRest = 1594 rLine.MakeRestPortion( rLine.GetCurr(), rLine.GetEnd() ); 1595 if( pRest ) 1596 rInf.SetRest( pRest ); 1597 } 1598 rLine.Insert( new SwLineLayout() ); 1599 rLine.Next(); 1600 bFormat = sal_True; 1601 } 1602 } 1603 if ( !bFormat && bMaxHyph && 1604 (bWatchEndHyph || bJumpEndHyph || bWatchMidHyph || bJumpMidHyph) ) 1605 { 1606 if ( rLine.GetCurr()->IsEndHyph() ) 1607 { 1608 if ( bWatchEndHyph ) 1609 bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() ); 1610 } 1611 else 1612 { 1613 bFormat = bJumpEndHyph; 1614 bWatchEndHyph = sal_False; 1615 bJumpEndHyph = sal_False; 1616 } 1617 if ( rLine.GetCurr()->IsMidHyph() ) 1618 { 1619 if ( bWatchMidHyph && !bFormat ) 1620 bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() ); 1621 } 1622 else 1623 { 1624 bFormat = bFormat || bJumpMidHyph; 1625 bWatchMidHyph = sal_False; 1626 bJumpMidHyph = sal_False; 1627 } 1628 } 1629 if( bFormat ) 1630 { 1631 sal_Bool bOldEndHyph = rLine.GetCurr()->IsEndHyph(); 1632 sal_Bool bOldMidHyph = rLine.GetCurr()->IsMidHyph(); 1633 bFormat = FormatLine( rLine, bPrev ); 1634 //9334: Es kann nur ein bPrev geben... (???) 1635 bPrev = sal_False; 1636 if ( bMaxHyph ) 1637 { 1638 if ( rLine.GetCurr()->IsEndHyph() != bOldEndHyph ) 1639 { 1640 bWatchEndHyph = !bOldEndHyph; 1641 bJumpEndHyph = bOldEndHyph; 1642 } 1643 if ( rLine.GetCurr()->IsMidHyph() != bOldMidHyph ) 1644 { 1645 bWatchMidHyph = !bOldMidHyph; 1646 bJumpMidHyph = bOldMidHyph; 1647 } 1648 } 1649 } 1650 1651 if( !rInf.IsNewLine() ) 1652 { 1653 if( !bFormat ) 1654 bFormat = 0 != rInf.GetRest(); 1655 if( rInf.IsStop() || rInf.GetIdx() >= nStrLen ) 1656 break; 1657 if( !bFormat && ( !bMaxHyph || ( !bWatchEndHyph && 1658 !bJumpEndHyph && !bWatchMidHyph && !bJumpMidHyph ) ) ) 1659 { 1660 if( GetFollow() ) 1661 { 1662 while( rLine.Next() ) 1663 ; //Nothing 1664 pFreeze = new SwRepaint( rRepaint ); // to minimize painting 1665 } 1666 else 1667 break; 1668 } 1669 } 1670 // OD 2004-02-25 #i16128# - method renamed 1671 bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine); 1672 }while( !bBreak ); 1673 1674 if( pFreeze ) 1675 { 1676 rRepaint = *pFreeze; 1677 delete pFreeze; 1678 } 1679 1680 if( !rLine.IsStop() ) 1681 { 1682 // Wurde aller Text formatiert und gibt es noch weitere 1683 // Zeilenobjekte, dann sind diese jetzt ueberfluessig, 1684 // weil der Text kuerzer geworden ist. 1685 if( rLine.GetStart() + rLine.GetLength() >= nStrLen && 1686 rLine.GetCurr()->GetNext() ) 1687 { 1688 rLine.TruncLines(); 1689 rLine.SetTruncLines( sal_True ); 1690 } 1691 } 1692 1693 if( !rInf.IsTest() ) 1694 { 1695 // Bei OnceMore lohnt sich kein FormatAdjust 1696 if( bAdjust || !rLine.GetDropFmt() || !rLine.CalcOnceMore() ) 1697 { 1698 FormatAdjust( rLine, aFrmBreak, nStrLen, rInf.IsStop() ); 1699 } 1700 if( rRepaint.HasArea() ) 1701 SetRepaint(); 1702 rLine.SetTruncLines( sal_False ); 1703 if( nOldBottom ) // Bei "gescollten" Absaetzen wird 1704 { // noch ueberprueft, ob durch Schrumpfen 1705 rLine.Bottom(); // das Scrolling ueberfluessig wurde. 1706 SwTwips nNewBottom = rLine.Y(); 1707 if( nNewBottom < nOldBottom ) 1708 _SetOfst( 0 ); 1709 } 1710 } 1711 } 1712 1713 /************************************************************************* 1714 * SwTxtFrm::Format() 1715 *************************************************************************/ 1716 1717 void SwTxtFrm::FormatOnceMore( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf ) 1718 { 1719 ASSERT( ! IsVertical() || IsSwapped(), 1720 "A frame is not swapped in SwTxtFrm::FormatOnceMore" ); 1721 1722 SwParaPortion *pPara = rLine.GetInfo().GetParaPortion(); 1723 if( !pPara ) 1724 return; 1725 1726 // ggf gegen pPara 1727 KSHORT nOld = ((const SwTxtMargin&)rLine).GetDropHeight(); 1728 sal_Bool bShrink = sal_False, 1729 bGrow = sal_False, 1730 bGoOn = rLine.IsOnceMore(); 1731 sal_uInt8 nGo = 0; 1732 while( bGoOn ) 1733 { 1734 #ifdef DBGTXT 1735 aDbstream << "OnceMore!" << endl; 1736 #endif 1737 ++nGo; 1738 rInf.Init(); 1739 rLine.Top(); 1740 if( !rLine.GetDropFmt() ) 1741 rLine.SetOnceMore( sal_False ); 1742 SwCharRange aRange( 0, rInf.GetTxt().Len() ); 1743 *(pPara->GetReformat()) = aRange; 1744 _Format( rLine, rInf ); 1745 1746 bGoOn = rLine.IsOnceMore(); 1747 if( bGoOn ) 1748 { 1749 const KSHORT nNew = ((const SwTxtMargin&)rLine).GetDropHeight(); 1750 if( nOld == nNew ) 1751 bGoOn = sal_False; 1752 else 1753 { 1754 if( nOld > nNew ) 1755 bShrink = sal_True; 1756 else 1757 bGrow = sal_True; 1758 1759 if( bShrink == bGrow || 5 < nGo ) 1760 bGoOn = sal_False; 1761 1762 nOld = nNew; 1763 } 1764 1765 // 6107: Wenn was schief ging, muss noch einmal formatiert werden. 1766 if( !bGoOn ) 1767 { 1768 rInf.CtorInitTxtFormatInfo( this ); 1769 rLine.CtorInitTxtFormatter( this, &rInf ); 1770 rLine.SetDropLines( 1 ); 1771 rLine.CalcDropHeight( 1 ); 1772 SwCharRange aTmpRange( 0, rInf.GetTxt().Len() ); 1773 *(pPara->GetReformat()) = aTmpRange; 1774 _Format( rLine, rInf, sal_True ); 1775 // 8047: Wir painten alles... 1776 SetCompletePaint(); 1777 } 1778 } 1779 } 1780 } 1781 1782 /************************************************************************* 1783 * SwTxtFrm::_Format() 1784 *************************************************************************/ 1785 1786 1787 void SwTxtFrm::_Format( SwParaPortion *pPara ) 1788 { 1789 const xub_StrLen nStrLen = GetTxt().Len(); 1790 1791 // AMA: Wozu soll das gut sein? Scheint mir zuoft zu einem kompletten 1792 // Formatieren und Repainten zu fuehren??? 1793 // if ( !(*pPara->GetDelta()) ) 1794 // *(pPara->GetDelta()) = nStrLen; 1795 // else 1796 if ( !nStrLen ) 1797 { 1798 // Leere Zeilen werden nicht lange gequaelt: 1799 // pPara wird blank geputzt 1800 // entspricht *pPara = SwParaPortion; 1801 sal_Bool bMustFit = pPara->IsPrepMustFit(); 1802 pPara->Truncate(); 1803 pPara->FormatReset(); 1804 if( pBlink && pPara->IsBlinking() ) 1805 pBlink->Delete( pPara ); 1806 1807 // delete pSpaceAdd und pKanaComp 1808 pPara->FinishSpaceAdd(); 1809 pPara->FinishKanaComp(); 1810 pPara->ResetFlags(); 1811 pPara->SetPrepMustFit( bMustFit ); 1812 } 1813 1814 ASSERT( ! IsSwapped(), "A frame is swapped before _Format" ); 1815 1816 if ( IsVertical() ) 1817 SwapWidthAndHeight(); 1818 1819 SwTxtFormatInfo aInf( this ); 1820 SwTxtFormatter aLine( this, &aInf ); 1821 1822 // OD 2004-01-15 #110582# 1823 HideAndShowObjects(); 1824 1825 _Format( aLine, aInf ); 1826 1827 if( aLine.IsOnceMore() ) 1828 FormatOnceMore( aLine, aInf ); 1829 1830 if ( IsVertical() ) 1831 SwapWidthAndHeight(); 1832 1833 ASSERT( ! IsSwapped(), "A frame is swapped after _Format" ); 1834 1835 if( 1 < aLine.GetDropLines() ) 1836 { 1837 if( SVX_ADJUST_LEFT != aLine.GetAdjust() && 1838 SVX_ADJUST_BLOCK != aLine.GetAdjust() ) 1839 { 1840 aLine.CalcDropAdjust(); 1841 aLine.SetPaintDrop( sal_True ); 1842 } 1843 1844 if( aLine.IsPaintDrop() ) 1845 { 1846 aLine.CalcDropRepaint(); 1847 aLine.SetPaintDrop( sal_False ); 1848 } 1849 } 1850 } 1851 1852 /************************************************************************* 1853 * SwTxtFrm::Format() 1854 *************************************************************************/ 1855 1856 /* 1857 * Format berechnet die Groesse des Textframes und ruft, wenn 1858 * diese feststeht, Shrink() oder Grow(), um die Framegroesse dem 1859 * evtl. veraenderten Platzbedarf anzupassen. 1860 */ 1861 1862 void SwTxtFrm::Format( const SwBorderAttrs * ) 1863 { 1864 DBG_LOOP; 1865 #if OSL_DEBUG_LEVEL > 1 1866 const XubString aXXX = GetTxtNode()->GetTxt(); 1867 const SwTwips nDbgY = Frm().Top(); 1868 (void)nDbgY; 1869 const SwPageFrm *pDbgPage = FindPageFrm(); 1870 const MSHORT nDbgPageNr = pDbgPage->GetPhyPageNum(); 1871 (void)nDbgPageNr; 1872 // Um zu gucken, ob es einen Ftn-Bereich gibt. 1873 const SwFrm *pDbgFtnCont = (const SwFrm*)(FindPageFrm()->FindFtnCont()); 1874 (void)pDbgFtnCont; 1875 1876 #ifdef DBG_UTIL 1877 // nStopAt laesst sich vom CV bearbeiten. 1878 static MSHORT nStopAt = 0; 1879 if( nStopAt == GetFrmId() ) 1880 { 1881 int i = GetFrmId(); 1882 (void)i; 1883 } 1884 #endif 1885 #endif 1886 1887 #ifdef DEBUG_FTN 1888 //Fussnote darf nicht auf einer Seite vor ihrer Referenz stehen. 1889 if( IsInFtn() ) 1890 { 1891 const SwFtnFrm *pFtn = (SwFtnFrm*)GetUpper(); 1892 const SwPageFrm *pFtnPage = pFtn->GetRef()->FindPageFrm(); 1893 const MSHORT nFtnPageNr = pFtnPage->GetPhyPageNum(); 1894 if( !IsLocked() ) 1895 { 1896 if( nFtnPageNr > nDbgPageNr ) 1897 { 1898 SwTxtFrmLocker aLock(this); 1899 ASSERT( nFtnPageNr <= nDbgPageNr, "!Ftn steht vor der Referenz." ); 1900 MSHORT i = 0; 1901 } 1902 } 1903 } 1904 #endif 1905 1906 SWRECTFN( this ) 1907 1908 // --> OD 2008-01-31 #newlistlevelattrs# 1909 CalcAdditionalFirstLineOffset(); 1910 // <-- 1911 1912 // Vom Berichtsautopiloten oder ueber die BASIC-Schnittstelle kommen 1913 // gelegentlich TxtFrms mit einer Breite <=0. 1914 if( (Prt().*fnRect->fnGetWidth)() <= 0 ) 1915 { 1916 // Wenn MustFit gesetzt ist, schrumpfen wir ggf. auf die Unterkante 1917 // des Uppers, ansonsten nehmen wir einfach eine Standardgroesse 1918 // von 12 Pt. ein (240 Twip). 1919 SwTxtLineAccess aAccess( this ); 1920 long nFrmHeight = (Frm().*fnRect->fnGetHeight)(); 1921 if( aAccess.GetPara()->IsPrepMustFit() ) 1922 { 1923 const SwTwips nLimit = (GetUpper()->*fnRect->fnGetPrtBottom)(); 1924 const SwTwips nDiff = - (Frm().*fnRect->fnBottomDist)( nLimit ); 1925 if( nDiff > 0 ) 1926 Shrink( nDiff ); 1927 } 1928 else if( 240 < nFrmHeight ) 1929 Shrink( nFrmHeight - 240 ); 1930 else if( 240 > nFrmHeight ) 1931 Grow( 240 - nFrmHeight ); 1932 nFrmHeight = (Frm().*fnRect->fnGetHeight)(); 1933 1934 long nTop = (this->*fnRect->fnGetTopMargin)(); 1935 if( nTop > nFrmHeight ) 1936 (this->*fnRect->fnSetYMargins)( nFrmHeight, 0 ); 1937 else if( (Prt().*fnRect->fnGetHeight)() < 0 ) 1938 (Prt().*fnRect->fnSetHeight)( 0 ); 1939 return; 1940 } 1941 1942 const xub_StrLen nStrLen = GetTxtNode()->GetTxt().Len(); 1943 if ( nStrLen || !FormatEmpty() ) 1944 { 1945 1946 SetEmpty( sal_False ); 1947 // Um nicht durch verschachtelte Formats irritiert zu werden. 1948 FormatLevel aLevel; 1949 if( 12 == aLevel.GetLevel() ) 1950 return; 1951 1952 // Die Formatinformationen duerfen u.U. nicht veraendert werden. 1953 if( IsLocked() ) 1954 return; 1955 1956 // 8708: Vorsicht, das Format() kann auch durch GetFormatted() 1957 // angestossen werden. 1958 if( IsHiddenNow() ) 1959 { 1960 long nPrtHeight = (Prt().*fnRect->fnGetHeight)(); 1961 if( nPrtHeight ) 1962 { 1963 HideHidden(); 1964 Shrink( nPrtHeight ); 1965 } 1966 else 1967 { 1968 // OD 2004-01-20 #110582# - assure that objects anchored 1969 // at paragraph resp. at/as character inside paragraph 1970 // are hidden. 1971 HideAndShowObjects(); 1972 } 1973 ChgThisLines(); 1974 return; 1975 } 1976 1977 // Waehrend wir formatieren, wollen wir nicht gestoert werden. 1978 SwTxtFrmLocker aLock(this); 1979 SwTxtLineAccess aAccess( this ); 1980 const sal_Bool bNew = !aAccess.SwTxtLineAccess::IsAvailable(); 1981 const sal_Bool bSetOfst = ( GetOfst() && GetOfst() > GetTxtNode()->GetTxt().Len() ); 1982 1983 if( CalcPreps() ) 1984 ; // nothing 1985 // Wir returnen, wenn schon formatiert wurde, nicht aber, wenn 1986 // der TxtFrm gerade erzeugt wurde und ueberhaupt keine Format- 1987 // informationen vorliegen. 1988 else if( !bNew && !aAccess.GetPara()->GetReformat()->Len() ) 1989 { 1990 if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() ) 1991 { 1992 aAccess.GetPara()->SetPrepAdjust( sal_True ); 1993 aAccess.GetPara()->SetPrep( sal_True ); 1994 CalcPreps(); 1995 } 1996 SetWidow( sal_False ); 1997 } 1998 else if( bSetOfst && IsFollow() ) 1999 { 2000 SwTxtFrm *pMaster = FindMaster(); 2001 ASSERT( pMaster, "SwTxtFrm::Format: homeless follow" ); 2002 if( pMaster ) 2003 pMaster->Prepare( PREP_FOLLOW_FOLLOWS ); 2004 SwTwips nMaxY = (GetUpper()->*fnRect->fnGetPrtBottom)(); 2005 if( (Frm().*fnRect->fnOverStep)( nMaxY ) ) 2006 (this->*fnRect->fnSetLimit)( nMaxY ); 2007 else if( (Frm().*fnRect->fnBottomDist)( nMaxY ) < 0 ) 2008 (Frm().*fnRect->fnAddBottom)( -(Frm().*fnRect->fnGetHeight)() ); 2009 } 2010 else 2011 { 2012 // bSetOfst here means that we have the "red arrow situation" 2013 if ( bSetOfst ) 2014 _SetOfst( 0 ); 2015 2016 const sal_Bool bOrphan = IsWidow(); 2017 const SwFtnBossFrm* pFtnBoss = HasFtn() ? FindFtnBossFrm() : 0; 2018 SwTwips nFtnHeight = 0; 2019 if( pFtnBoss ) 2020 { 2021 const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont(); 2022 nFtnHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0; 2023 } 2024 do 2025 { 2026 _Format( aAccess.GetPara() ); 2027 if( pFtnBoss && nFtnHeight ) 2028 { 2029 const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont(); 2030 SwTwips nNewHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0; 2031 // If we lost some footnotes, we may have more space 2032 // for our main text, so we have to format again ... 2033 if( nNewHeight < nFtnHeight ) 2034 nFtnHeight = nNewHeight; 2035 else 2036 break; 2037 } 2038 else 2039 break; 2040 } while ( pFtnBoss ); 2041 if( bOrphan ) 2042 { 2043 ValidateFrm(); 2044 SetWidow( sal_False ); 2045 } 2046 } 2047 if( IsEmptyMaster() ) 2048 { 2049 SwFrm* pPre = GetPrev(); 2050 if( pPre && 2051 // --> FME 2004-07-22 #i10826# It's the first, it cannot keep! 2052 pPre->GetIndPrev() && 2053 // <-- 2054 pPre->GetAttrSet()->GetKeep().GetValue() ) 2055 { 2056 pPre->InvalidatePos(); 2057 } 2058 } 2059 } 2060 2061 ChgThisLines(); 2062 2063 // the PrepMustFit should not survive a Format operation 2064 SwParaPortion *pPara = GetPara(); 2065 if ( pPara ) 2066 pPara->SetPrepMustFit( sal_False ); 2067 2068 #if OSL_DEBUG_LEVEL > 1 2069 // Hier ein Instrumentarium, um ungewoehnlichen Master/Follow-Kombinationen, 2070 // insbesondere bei Fussnoten, auf die Schliche zu kommen 2071 if( IsFollow() || GetFollow() ) 2072 { 2073 SwTxtFrm *pTmpFrm = IsFollow() ? FindMaster() : this; 2074 const SwPageFrm *pTmpPage = pTmpFrm->FindPageFrm(); 2075 MSHORT nPgNr = pTmpPage->GetPhyPageNum(); 2076 MSHORT nLast; 2077 MSHORT nDummy = 0; // nur zum Breakpoint setzen 2078 while( pTmpFrm->GetFollow() ) 2079 { 2080 pTmpFrm = pTmpFrm->GetFollow(); 2081 nLast = nPgNr; 2082 pTmpPage = pTmpFrm->FindPageFrm(); 2083 nPgNr = pTmpPage->GetPhyPageNum(); 2084 if( nLast > nPgNr ) 2085 ++nDummy; // schon fast eine Assertion wert 2086 else if( nLast == nPgNr ) 2087 ++nDummy; // bei Spalten voellig normal, aber sonst!? 2088 else if( nLast < nPgNr - 1 ) 2089 ++nDummy; // kann schon mal temporaer vorkommen 2090 } 2091 } 2092 #endif 2093 2094 CalcBaseOfstForFly(); 2095 // OD 2004-03-17 #i11860# 2096 _CalcHeightOfLastLine(); 2097 } 2098 2099 /************************************************************************* 2100 * SwTxtFrm::FormatQuick() 2101 * 2102 * bForceQuickFormat is set if GetFormatted() has been called during the 2103 * painting process. Actually I cannot imagine a situation which requires 2104 * a full formatting of the paragraph during painting, on the other hand 2105 * a full formatting can cause the invalidation of other layout frames, 2106 * e.g., if there are footnotes in this paragraph, and invalid layout 2107 * frames will not calculated during the painting. So I actually want to 2108 * avoid a formatting during painting, but since I'm a coward, I'll only 2109 * force the quick formatting in the situation of issue i29062. 2110 *************************************************************************/ 2111 2112 sal_Bool SwTxtFrm::FormatQuick( bool bForceQuickFormat ) 2113 { 2114 ASSERT( ! IsVertical() || ! IsSwapped(), 2115 "SwTxtFrm::FormatQuick with swapped frame" ); 2116 2117 DBG_LOOP; 2118 #if OSL_DEBUG_LEVEL > 1 2119 const XubString aXXX = GetTxtNode()->GetTxt(); 2120 const SwTwips nDbgY = Frm().Top(); 2121 (void)nDbgY; 2122 #ifdef DBG_UTIL 2123 // nStopAt laesst sich vom CV bearbeiten. 2124 static MSHORT nStopAt = 0; 2125 if( nStopAt == GetFrmId() ) 2126 { 2127 int i = GetFrmId(); 2128 (void)i; 2129 } 2130 #endif 2131 #endif 2132 2133 if( IsEmpty() && FormatEmpty() ) 2134 return sal_True; 2135 2136 // Wir sind sehr waehlerisch: 2137 if( HasPara() || IsWidow() || IsLocked() 2138 || !GetValidSizeFlag() || 2139 ( ( IsVertical() ? Prt().Width() : Prt().Height() ) && IsHiddenNow() ) ) 2140 return sal_False; 2141 2142 SwTxtLineAccess aAccess( this ); 2143 SwParaPortion *pPara = aAccess.GetPara(); 2144 if( !pPara ) 2145 return sal_False; 2146 2147 SwFrmSwapper aSwapper( this, sal_True ); 2148 2149 SwTxtFrmLocker aLock(this); 2150 SwTxtFormatInfo aInf( this, sal_False, sal_True ); 2151 if( 0 != aInf.MaxHyph() ) // 27483: MaxHyphen beachten! 2152 return sal_False; 2153 2154 SwTxtFormatter aLine( this, &aInf ); 2155 2156 // DropCaps sind zu kompliziert... 2157 if( aLine.GetDropFmt() ) 2158 return sal_False; 2159 2160 xub_StrLen nStart = GetOfst(); 2161 const xub_StrLen nEnd = GetFollow() 2162 ? GetFollow()->GetOfst() : aInf.GetTxt().Len(); 2163 do 2164 { 2165 //DBG_LOOP; shadows declaration above. 2166 //resolved into: 2167 #if OSL_DEBUG_LEVEL > 1 2168 #ifdef DBG_UTIL 2169 DbgLoop aDbgLoop2( (const void*) this ); 2170 #endif 2171 #endif 2172 nStart = aLine.FormatLine( nStart ); 2173 if( aInf.IsNewLine() || (!aInf.IsStop() && nStart < nEnd) ) 2174 aLine.Insert( new SwLineLayout() ); 2175 } while( aLine.Next() ); 2176 2177 // Last exit: die Hoehen muessen uebereinstimmen. 2178 Point aTopLeft( Frm().Pos() ); 2179 aTopLeft += Prt().Pos(); 2180 const SwTwips nNewHeight = aLine.Y() + aLine.GetLineHeight(); 2181 const SwTwips nOldHeight = aTopLeft.Y() + Prt().Height(); 2182 2183 if( !bForceQuickFormat && nNewHeight != nOldHeight && !IsUndersized() ) 2184 { 2185 // Achtung: Durch FormatLevel==12 kann diese Situation auftreten, don't panic! 2186 // ASSERT( nNewHeight == nOldHeight, "!FormatQuick: rosebud" ); 2187 const xub_StrLen nStrt = GetOfst(); 2188 _InvalidateRange( SwCharRange( nStrt, nEnd - nStrt) ); 2189 return sal_False; 2190 } 2191 2192 if( pFollow && nStart != ((SwTxtFrm*)pFollow)->GetOfst() ) 2193 return sal_False; // kann z.B. durch Orphans auftreten (35083,35081) 2194 2195 // Geschafft, wir sind durch ... 2196 2197 // Repaint setzen 2198 pPara->GetRepaint()->Pos( aTopLeft ); 2199 pPara->GetRepaint()->SSize( Prt().SSize() ); 2200 2201 // Reformat loeschen 2202 *(pPara->GetReformat()) = SwCharRange(); 2203 *(pPara->GetDelta()) = 0; 2204 2205 return sal_True; 2206 } 2207