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