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