summaryrefslogtreecommitdiff
path: root/sw/source/core/text/frmform.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sw/source/core/text/frmform.cxx')
-rw-r--r--sw/source/core/text/frmform.cxx2068
1 files changed, 2068 insertions, 0 deletions
diff --git a/sw/source/core/text/frmform.cxx b/sw/source/core/text/frmform.cxx
new file mode 100644
index 000000000000..e28b1694d8a6
--- /dev/null
+++ b/sw/source/core/text/frmform.cxx
@@ -0,0 +1,2068 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*************************************************************************
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * Copyright 2000, 2010 Oracle and/or its affiliates.
+ *
+ * OpenOffice.org - a multi-platform office productivity suite
+ *
+ * This file is part of OpenOffice.org.
+ *
+ * OpenOffice.org is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License version 3
+ * only, as published by the Free Software Foundation.
+ *
+ * OpenOffice.org is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License version 3 for more details
+ * (a copy is included in the LICENSE file that accompanied this code).
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * version 3 along with OpenOffice.org. If not, see
+ * <http://www.openoffice.org/license.html>
+ * for a copy of the LGPLv3 License.
+ *
+ ************************************************************************/
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_sw.hxx"
+
+#include <hintids.hxx>
+#include <editeng/keepitem.hxx>
+#include <editeng/hyznitem.hxx>
+#include <pagefrm.hxx> // ChangeFtnRef
+#include <ndtxt.hxx> // MakeFrm()
+#include <dcontact.hxx> // SwDrawContact
+#include <dflyobj.hxx> // SwVirtFlyDrawObj
+#include <flyfrm.hxx>
+#include <ftnfrm.hxx> // SwFtnFrm
+#include <txtftn.hxx>
+#include <fmtftn.hxx>
+#include <paratr.hxx>
+#include <viewopt.hxx> // SwViewOptions
+#include <viewsh.hxx> // ViewShell
+#include <frmatr.hxx>
+#include <pam.hxx>
+#include <flyfrms.hxx>
+#include <fmtanchr.hxx>
+#include <itrform2.hxx> // SwTxtFormatter
+#include <widorp.hxx> // Widows and Orphans
+#include <txtcache.hxx>
+#include <porrst.hxx> // SwEmptyPortion
+#include <blink.hxx> // pBlink
+#include <porfld.hxx> // SwFldPortion
+#include <sectfrm.hxx> // SwSectionFrm
+#include <pormulti.hxx> // SwMultiPortion
+
+#include <rootfrm.hxx>
+#include <frmfmt.hxx> // SwFrmFmt
+// OD 2004-05-24 #i28701#
+#include <sortedobjs.hxx>
+
+// Toleranzwert in der Formatierung und Textausgabe.
+#define SLOPPY_TWIPS 5
+
+class FormatLevel
+{
+ static MSHORT nLevel;
+public:
+ inline FormatLevel() { ++nLevel; }
+ inline ~FormatLevel() { --nLevel; }
+ inline MSHORT GetLevel() const { return nLevel; }
+ static sal_Bool LastLevel() { return 10 < nLevel; }
+};
+MSHORT FormatLevel::nLevel = 0;
+
+/*************************************************************************
+ * ValidateTxt/Frm()
+ *************************************************************************/
+
+void ValidateTxt( SwFrm *pFrm ) // Freund vom Frame
+{
+ if ( ( ! pFrm->IsVertical() &&
+ pFrm->Frm().Width() == pFrm->GetUpper()->Prt().Width() ) ||
+ ( pFrm->IsVertical() &&
+ pFrm->Frm().Height() == pFrm->GetUpper()->Prt().Height() ) )
+ pFrm->bValidSize = sal_True;
+}
+
+void SwTxtFrm::ValidateFrm()
+{
+ // Umgebung validieren, um Oszillationen zu verhindern.
+ SWAP_IF_SWAPPED( this )
+
+ if ( !IsInFly() && !IsInTab() )
+ { //Innerhalb eines Flys nur this validieren, der Rest sollte eigentlich
+ //nur fuer Fussnoten notwendig sein und die gibt es innerhalb von
+ //Flys nicht. Fix fuer 5544
+ SwSectionFrm* pSct = FindSctFrm();
+ if( pSct )
+ {
+ if( !pSct->IsColLocked() )
+ pSct->ColLock();
+ else
+ pSct = NULL;
+ }
+
+ SwFrm *pUp = GetUpper();
+ pUp->Calc();
+ if( pSct )
+ pSct->ColUnlock();
+ }
+ ValidateTxt( this );
+
+ //MA: mindestens das MustFit-Flag muessen wir retten!
+ OSL_ENSURE( HasPara(), "ResetPreps(), missing ParaPortion." );
+ SwParaPortion *pPara = GetPara();
+ const sal_Bool bMustFit = pPara->IsPrepMustFit();
+ ResetPreps();
+ pPara->SetPrepMustFit( bMustFit );
+
+ UNDO_SWAP( this )
+}
+
+/*************************************************************************
+ * ValidateBodyFrm()
+ *************************************************************************/
+
+// nach einem RemoveFtn muss der BodyFrm und alle innenliegenden kalkuliert
+// werden, damit die DeadLine richtig sitzt.
+// Erst wird nach aussen hin gesucht, beim Rueckweg werden alle kalkuliert.
+
+void _ValidateBodyFrm( SwFrm *pFrm )
+{
+ if( pFrm && !pFrm->IsCellFrm() )
+ {
+ if( !pFrm->IsBodyFrm() && pFrm->GetUpper() )
+ _ValidateBodyFrm( pFrm->GetUpper() );
+ if( !pFrm->IsSctFrm() )
+ pFrm->Calc();
+ else
+ {
+ sal_Bool bOld = ((SwSectionFrm*)pFrm)->IsCntntLocked();
+ ((SwSectionFrm*)pFrm)->SetCntntLock( sal_True );
+ pFrm->Calc();
+ if( !bOld )
+ ((SwSectionFrm*)pFrm)->SetCntntLock( sal_False );
+ }
+ }
+}
+
+void SwTxtFrm::ValidateBodyFrm()
+{
+ SWAP_IF_SWAPPED( this )
+
+ //siehe Kommtar in ValidateFrm()
+ if ( !IsInFly() && !IsInTab() &&
+ !( IsInSct() && FindSctFrm()->Lower()->IsColumnFrm() ) )
+ _ValidateBodyFrm( GetUpper() );
+
+ UNDO_SWAP( this )
+}
+
+/*************************************************************************
+ * SwTxtFrm::FindBodyFrm()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::_GetDropRect( SwRect &rRect ) const
+{
+ SWAP_IF_NOT_SWAPPED( this )
+
+ OSL_ENSURE( HasPara(), "SwTxtFrm::_GetDropRect: try again next year." );
+ SwTxtSizeInfo aInf( (SwTxtFrm*)this );
+ SwTxtMargin aLine( (SwTxtFrm*)this, &aInf );
+ if( aLine.GetDropLines() )
+ {
+ rRect.Top( aLine.Y() );
+ rRect.Left( aLine.GetLineStart() );
+ rRect.Height( aLine.GetDropHeight() );
+ rRect.Width( aLine.GetDropLeft() );
+
+ if ( IsRightToLeft() )
+ SwitchLTRtoRTL( rRect );
+
+ if ( IsVertical() )
+ SwitchHorizontalToVertical( rRect );
+ UNDO_SWAP( this )
+ return sal_True;
+ }
+
+ UNDO_SWAP( this )
+
+ return sal_False;
+}
+
+/*************************************************************************
+ * SwTxtFrm::FindBodyFrm()
+ *************************************************************************/
+
+const SwBodyFrm *SwTxtFrm::FindBodyFrm() const
+{
+ if ( IsInDocBody() )
+ {
+ const SwFrm *pFrm = GetUpper();
+ while( pFrm && !pFrm->IsBodyFrm() )
+ pFrm = pFrm->GetUpper();
+ return (const SwBodyFrm*)pFrm;
+ }
+ return 0;
+}
+
+/*************************************************************************
+ * SwTxtFrm::CalcFollow()
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::CalcFollow( const xub_StrLen nTxtOfst )
+{
+ SWAP_IF_SWAPPED( this )
+
+ OSL_ENSURE( HasFollow(), "CalcFollow: missing Follow." );
+
+ SwTxtFrm* pMyFollow = GetFollow();
+
+ SwParaPortion *pPara = GetPara();
+ sal_Bool bFollowFld = pPara ? pPara->IsFollowField() : sal_False;
+
+ if( !pMyFollow->GetOfst() || pMyFollow->GetOfst() != nTxtOfst ||
+ bFollowFld || pMyFollow->IsFieldFollow() ||
+ ( pMyFollow->IsVertical() && !pMyFollow->Prt().Width() ) ||
+ ( ! pMyFollow->IsVertical() && !pMyFollow->Prt().Height() ) )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ const SwFrm *pOldUp = GetUpper();
+#endif
+
+ SWRECTFN ( this )
+ SwTwips nOldBottom = (GetUpper()->Frm().*fnRect->fnGetBottom)();
+ SwTwips nMyPos = (Frm().*fnRect->fnGetTop)();
+
+ const SwPageFrm *pPage = 0;
+ sal_Bool bOldInvaCntnt = sal_True;
+ if ( !IsInFly() && GetNext() )
+ {
+ pPage = FindPageFrm();
+ //Minimieren - sprich ggf. zuruecksetzen - der Invalidierungen s.u.
+ bOldInvaCntnt = pPage->IsInvalidCntnt();
+ }
+
+ pMyFollow->_SetOfst( nTxtOfst );
+ pMyFollow->SetFieldFollow( bFollowFld );
+ if( HasFtn() || pMyFollow->HasFtn() )
+ {
+ ValidateFrm();
+ ValidateBodyFrm();
+ if( pPara )
+ {
+ *(pPara->GetReformat()) = SwCharRange();
+ *(pPara->GetDelta()) = 0;
+ }
+ }
+
+ //Der Fussnotenbereich darf sich keinesfalls vergrossern.
+ SwSaveFtnHeight aSave( FindFtnBossFrm( sal_True ), LONG_MAX );
+
+ pMyFollow->CalcFtnFlag();
+ if ( !pMyFollow->GetNext() && !pMyFollow->HasFtn() )
+ nOldBottom = bVert ? 0 : LONG_MAX;
+
+ while( sal_True )
+ {
+ if( !FormatLevel::LastLevel() )
+ {
+ // Weenn der Follow in einem spaltigen Bereich oder einem
+ // spaltigen Rahmen steckt, muss zunaechst dieser kalkuliert
+ // werden, da das FormatWidthCols() nicht funktioniert, wenn
+ // es aus dem MakeAll des _gelockten_ Follows heraus gerufen
+ // wird.
+ SwSectionFrm* pSct = pMyFollow->FindSctFrm();
+ if( pSct && !pSct->IsAnLower( this ) )
+ {
+ if( pSct->GetFollow() )
+ pSct->SimpleFormat();
+ else if( ( pSct->IsVertical() && !pSct->Frm().Width() ) ||
+ ( ! pSct->IsVertical() && !pSct->Frm().Height() ) )
+ break;
+ }
+ // OD 14.03.2003 #i11760# - intrinsic format of follow is controlled.
+ if ( FollowFormatAllowed() )
+ {
+ // OD 14.03.2003 #i11760# - no nested format of follows, if
+ // text frame is contained in a column frame.
+ // Thus, forbid intrinsic format of follow.
+ {
+ bool bIsFollowInColumn = false;
+ SwFrm* pFollowUpper = pMyFollow->GetUpper();
+ while ( pFollowUpper )
+ {
+ if ( pFollowUpper->IsColumnFrm() )
+ {
+ bIsFollowInColumn = true;
+ break;
+ }
+ if ( pFollowUpper->IsPageFrm() ||
+ pFollowUpper->IsFlyFrm() )
+ {
+ break;
+ }
+ pFollowUpper = pFollowUpper->GetUpper();
+ }
+ if ( bIsFollowInColumn )
+ {
+ pMyFollow->ForbidFollowFormat();
+ }
+ }
+
+ pMyFollow->Calc();
+ // Der Follow merkt anhand seiner Frm().Height(), dass was schief
+ // gelaufen ist.
+ OSL_ENSURE( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: cheesy follow" );
+ if( pMyFollow->GetPrev() )
+ {
+ pMyFollow->Prepare( PREP_CLEAR );
+ pMyFollow->Calc();
+ OSL_ENSURE( !pMyFollow->GetPrev(), "SwTxtFrm::CalcFollow: very cheesy follow" );
+ }
+
+ // OD 14.03.2003 #i11760# - reset control flag for follow format.
+ pMyFollow->AllowFollowFormat();
+ }
+
+ //Sicherstellen, dass der Follow gepaintet wird.
+ pMyFollow->SetCompletePaint();
+ }
+
+ pPara = GetPara();
+ //Solange der Follow wg. Orphans Zeilen angefordert, bekommt er
+ //diese und wird erneut formatiert, falls moeglich.
+ if( pPara && pPara->IsPrepWidows() )
+ CalcPreps();
+ else
+ break;
+ }
+
+ if( HasFtn() || pMyFollow->HasFtn() )
+ {
+ ValidateBodyFrm();
+ ValidateFrm();
+ if( pPara )
+ {
+ *(pPara->GetReformat()) = SwCharRange();
+ *(pPara->GetDelta()) = 0;
+ }
+ }
+
+ if ( pPage )
+ {
+ if ( !bOldInvaCntnt )
+ pPage->ValidateCntnt();
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ OSL_ENSURE( pOldUp == GetUpper(), "SwTxtFrm::CalcFollow: heavy follow" );
+#endif
+
+ const long nRemaining =
+ - (GetUpper()->Frm().*fnRect->fnBottomDist)( nOldBottom );
+ if ( nRemaining > 0 && !GetUpper()->IsSctFrm() &&
+ nRemaining != ( bVert ?
+ nMyPos - Frm().Right() :
+ Frm().Top() - nMyPos ) )
+ {
+ UNDO_SWAP( this )
+ return sal_True;
+ }
+ }
+
+ UNDO_SWAP( this )
+
+ return sal_False;
+}
+
+/*************************************************************************
+ * SwTxtFrm::AdjustFrm()
+ *************************************************************************/
+
+void SwTxtFrm::AdjustFrm( const SwTwips nChgHght, sal_Bool bHasToFit )
+{
+ if( IsUndersized() )
+ {
+ if( GetOfst() && !IsFollow() ) // ein gescrollter Absatz (undersized)
+ return;
+ SetUndersized( nChgHght == 0 || bHasToFit );
+ }
+
+ // AdjustFrm is called with a swapped frame during
+ // formatting but the frame is not swapped during FormatEmpty
+ SWAP_IF_SWAPPED( this )
+ SWRECTFN ( this )
+
+ // Die Size-Variable des Frames wird durch Grow inkrementiert
+ // oder durch Shrink dekrementiert. Wenn die Groesse
+ // unveraendert ist, soll nichts passieren!
+ if( nChgHght >= 0)
+ {
+ SwTwips nChgHeight = nChgHght;
+ if( nChgHght && !bHasToFit )
+ {
+ if( IsInFtn() && !IsInSct() )
+ {
+ SwTwips nReal = Grow( nChgHght, sal_True );
+ if( nReal < nChgHght )
+ {
+ SwTwips nBot = (*fnRect->fnYInc)( (Frm().*fnRect->fnGetBottom)(),
+ nChgHght - nReal );
+ SwFrm* pCont = FindFtnFrm()->GetUpper();
+
+ if( (pCont->Frm().*fnRect->fnBottomDist)( nBot ) > 0 )
+ {
+ (Frm().*fnRect->fnAddBottom)( nChgHght );
+ if( bVert )
+ Prt().SSize().Width() += nChgHght;
+ else
+ Prt().SSize().Height() += nChgHght;
+ UNDO_SWAP( this )
+ return;
+ }
+ }
+ }
+
+ Grow( nChgHght );
+
+ if ( IsInFly() )
+ {
+ //MA 06. May. 93: Wenn einer der Upper ein Fly ist, so ist es
+ //sehr wahrscheinlich, dass dieser Fly durch das Grow seine
+ //Position veraendert - also muss auch meine Position korrigiert
+ //werden (sonst ist die Pruefung s.u. nicht aussagekraeftig).
+ //Die Vorgaenger muessen berechnet werden, damit die Position
+ //korrekt berechnet werden kann.
+ if ( GetPrev() )
+ {
+ SwFrm *pPre = GetUpper()->Lower();
+ do
+ { pPre->Calc();
+ pPre = pPre->GetNext();
+ } while ( pPre && pPre != this );
+ }
+ const Point aOldPos( Frm().Pos() );
+ MakePos();
+ if ( aOldPos != Frm().Pos() )
+ {
+ // OD 2004-07-01 #i28701# - use new method <SwFrm::InvalidateObjs(..)>
+ // No format is performed for the floating screen objects.
+ InvalidateObjs( true );
+ }
+ }
+ nChgHeight = 0;
+ }
+ // Ein Grow() wird von der Layout-Seite immer akzeptiert,
+ // also auch, wenn die FixSize des umgebenden Layoutframes
+ // dies nicht zulassen sollte. Wir ueberpruefen diesen
+ // Fall und korrigieren die Werte.
+ // MA 06. May. 93: Der Frm darf allerdings auch im Notfall nicht
+ // weiter geschrumpft werden als es seine Groesse zulaesst.
+ SwTwips nRstHeight;
+ if ( IsVertical() )
+ {
+ OSL_ENSURE( ! IsSwapped(),"Swapped frame while calculating nRstHeight" );
+
+ //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
+ if ( IsVertLR() )
+ nRstHeight = GetUpper()->Frm().Left()
+ + GetUpper()->Prt().Left()
+ + GetUpper()->Prt().Width()
+ - Frm().Left();
+ else
+ nRstHeight = Frm().Left() + Frm().Width() -
+ ( GetUpper()->Frm().Left() + GetUpper()->Prt().Left() );
+ }
+ else
+ nRstHeight = GetUpper()->Frm().Top()
+ + GetUpper()->Prt().Top()
+ + GetUpper()->Prt().Height()
+ - Frm().Top();
+
+ //In Tabellenzellen kann ich mir evtl. noch ein wenig dazuholen, weil
+ //durch eine vertikale Ausrichtung auch oben noch Raum sein kann.
+ // --> OD 2004-11-25 #115759# - assure, that first lower in upper
+ // is the current one or is valid.
+ if ( IsInTab() &&
+ ( GetUpper()->Lower() == this ||
+ GetUpper()->Lower()->IsValid() ) )
+ // <--
+ {
+ long nAdd = (*fnRect->fnYDiff)( (GetUpper()->Lower()->Frm().*fnRect->fnGetTop)(),
+ (GetUpper()->*fnRect->fnGetPrtTop)() );
+ OSL_ENSURE( nAdd >= 0, "Ey" );
+ nRstHeight += nAdd;
+ }
+
+/* ------------------------------------
+ * #50964#: nRstHeight < 0 bedeutet, dass der TxtFrm komplett ausserhalb seines
+ * Upper liegt. Dies kann passieren, wenn er innerhalb eines FlyAtCntFrm liegt, der
+ * durch das Grow() die Seite gewechselt hat. In so einem Fall ist es falsch, der
+ * folgenden Grow-Versuch durchzufuehren. Im Bugfall fuehrte dies sogar zur
+ * Endlosschleife.
+ * -----------------------------------*/
+ SwTwips nFrmHeight = (Frm().*fnRect->fnGetHeight)();
+ SwTwips nPrtHeight = (Prt().*fnRect->fnGetHeight)();
+
+ if( nRstHeight < nFrmHeight )
+ {
+ //Kann sein, dass ich die richtige Grosse habe, der Upper aber zu
+ //klein ist und der Upper noch Platz schaffen kann.
+ if( ( nRstHeight >= 0 || ( IsInFtn() && IsInSct() ) ) && !bHasToFit )
+ nRstHeight += GetUpper()->Grow( nFrmHeight - nRstHeight );
+ // In spaltigen Bereichen wollen wir moeglichst nicht zu gross werden, damit
+ // nicht ueber GetNextSctLeaf weitere Bereiche angelegt werden. Stattdessen
+ // schrumpfen wir und notieren bUndersized, damit FormatWidthCols die richtige
+ // Spaltengroesse ermitteln kann.
+ if ( nRstHeight < nFrmHeight )
+ {
+ if( bHasToFit || !IsMoveable() ||
+ ( IsInSct() && !FindSctFrm()->MoveAllowed(this) ) )
+ {
+ SetUndersized( sal_True );
+ Shrink( Min( ( nFrmHeight - nRstHeight), nPrtHeight ) );
+ }
+ else
+ SetUndersized( sal_False );
+ }
+ }
+ else if( nChgHeight )
+ {
+ if( nRstHeight - nFrmHeight < nChgHeight )
+ nChgHeight = nRstHeight - nFrmHeight;
+ if( nChgHeight )
+ Grow( nChgHeight );
+ }
+ }
+ else
+ Shrink( -nChgHght );
+
+ UNDO_SWAP( this )
+}
+
+/*************************************************************************
+ * SwTxtFrm::AdjustFollow()
+ *************************************************************************/
+
+/* AdjustFollow erwartet folgende Situation:
+ * Der SwTxtIter steht am unteren Ende des Masters, der Offset wird
+ * im Follow eingestellt.
+ * nOffset haelt den Offset im Textstring, ab dem der Master abschliesst
+ * und der Follow beginnt. Wenn er 0 ist, wird der FolgeFrame geloescht.
+ */
+
+void SwTxtFrm::_AdjustFollow( SwTxtFormatter &rLine,
+ const xub_StrLen nOffset, const xub_StrLen nEnd,
+ const sal_uInt8 nMode )
+{
+ SwFrmSwapper aSwapper( this, sal_False );
+
+ // Wir haben den Rest der Textmasse: alle Follows loeschen
+ // Sonderfall sind DummyPortions()
+ // - special cases are controlled by parameter <nMode>.
+ if( HasFollow() && !(nMode & 1) && nOffset == nEnd )
+ {
+ while( GetFollow() )
+ {
+ if( ((SwTxtFrm*)GetFollow())->IsLocked() )
+ {
+ OSL_FAIL( "+SwTxtFrm::JoinFrm: Follow ist locked." );
+ return;
+ }
+ JoinFrm();
+ }
+
+ return;
+ }
+
+ // Tanz auf dem Vulkan: Wir formatieren eben schnell noch einmal
+ // die letzte Zeile fuer das QuoVadis-Geraffel. Selbstverstaendlich
+ // kann sich dadurch auch der Offset verschieben:
+ const xub_StrLen nNewOfst = ( IsInFtn() && ( !GetIndNext() || HasFollow() ) ) ?
+ rLine.FormatQuoVadis(nOffset) : nOffset;
+
+ if( !(nMode & 1) )
+ {
+ // Wir klauen unseren Follows Textmasse, dabei kann es passieren,
+ // dass wir einige Follows Joinen muessen.
+ while( GetFollow() && GetFollow()->GetFollow() &&
+ nNewOfst >= GetFollow()->GetFollow()->GetOfst() )
+ {
+ JoinFrm();
+ }
+ }
+
+ // Der Ofst hat sich verschoben.
+ if( GetFollow() )
+ {
+#if OSL_DEBUG_LEVEL > 1
+ static sal_Bool bTest = sal_False;
+ if( !bTest || ( nMode & 1 ) )
+#endif
+ if ( nMode )
+ GetFollow()->ManipOfst( 0 );
+
+ if ( CalcFollow( nNewOfst ) ) // CalcFollow erst zum Schluss, dort erfolgt ein SetOfst
+ rLine.SetOnceMore( sal_True );
+ }
+}
+
+/*************************************************************************
+ * SwTxtFrm::JoinFrm()
+ *************************************************************************/
+
+SwCntntFrm *SwTxtFrm::JoinFrm()
+{
+ OSL_ENSURE( GetFollow(), "+SwTxtFrm::JoinFrm: no follow" );
+ SwTxtFrm *pFoll = GetFollow();
+
+ SwTxtFrm *pNxt = pFoll->GetFollow();
+
+ // Alle Fussnoten des zu zerstoerenden Follows werden auf uns
+ // umgehaengt.
+ xub_StrLen nStart = pFoll->GetOfst();
+ if ( pFoll->HasFtn() )
+ {
+ const SwpHints *pHints = pFoll->GetTxtNode()->GetpSwpHints();
+ if( pHints )
+ {
+ SwFtnBossFrm *pFtnBoss = 0;
+ SwFtnBossFrm *pEndBoss = 0;
+ for ( sal_uInt16 i = 0; i < pHints->Count(); ++i )
+ {
+ const SwTxtAttr *pHt = (*pHints)[i];
+ if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nStart )
+ {
+ if( pHt->GetFtn().IsEndNote() )
+ {
+ if( !pEndBoss )
+ pEndBoss = pFoll->FindFtnBossFrm();
+ pEndBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this );
+ }
+ else
+ {
+ if( !pFtnBoss )
+ pFtnBoss = pFoll->FindFtnBossFrm( sal_True );
+ pFtnBoss->ChangeFtnRef( pFoll, (SwTxtFtn*)pHt, this );
+ }
+ SetFtn( sal_True );
+ }
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ else if ( pFoll->GetValidPrtAreaFlag() ||
+ pFoll->GetValidSizeFlag() )
+ {
+ pFoll->CalcFtnFlag();
+ OSL_ENSURE( !pFoll->HasFtn(), "Missing FtnFlag." );
+ }
+#endif
+
+ pFoll->MoveFlyInCnt( this, nStart, STRING_LEN );
+ pFoll->SetFtn( sal_False );
+ // --> OD 2005-12-01 #i27138#
+ // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation.
+ // Relation CONTENT_FLOWS_FROM for current next paragraph will change
+ // and relation CONTENT_FLOWS_TO for current previous paragraph, which
+ // is <this>, will change.
+ {
+ ViewShell* pViewShell( pFoll->getRootFrm()->GetCurrShell() );
+ if ( pViewShell && pViewShell->GetLayout() &&
+ pViewShell->GetLayout()->IsAnyShellAccessible() )
+ {
+ pViewShell->InvalidateAccessibleParaFlowRelation(
+ dynamic_cast<SwTxtFrm*>(pFoll->FindNextCnt( true )),
+ this );
+ }
+ }
+ // <--
+ pFoll->Cut();
+ delete pFoll;
+ pFollow = pNxt;
+ return pNxt;
+}
+
+/*************************************************************************
+ * SwTxtFrm::SplitFrm()
+ *************************************************************************/
+
+SwCntntFrm *SwTxtFrm::SplitFrm( const xub_StrLen nTxtPos )
+{
+ SWAP_IF_SWAPPED( this )
+
+ // Durch das Paste wird ein Modify() an mich verschickt.
+ // Damit meine Daten nicht verschwinden, locke ich mich.
+ SwTxtFrmLocker aLock( this );
+ SwTxtFrm *pNew = (SwTxtFrm *)(GetTxtNode()->MakeFrm( this ));
+ pNew->bIsFollow = sal_True;
+
+ pNew->SetFollow( GetFollow() );
+ SetFollow( pNew );
+
+ pNew->Paste( GetUpper(), GetNext() );
+ // --> OD 2005-12-01 #i27138#
+ // notify accessibility paragraphs objects about changed CONTENT_FLOWS_FROM/_TO relation.
+ // Relation CONTENT_FLOWS_FROM for current next paragraph will change
+ // and relation CONTENT_FLOWS_TO for current previous paragraph, which
+ // is <this>, will change.
+ {
+ ViewShell* pViewShell( pNew->getRootFrm()->GetCurrShell() );
+ if ( pViewShell && pViewShell->GetLayout() &&
+ pViewShell->GetLayout()->IsAnyShellAccessible() )
+ {
+ pViewShell->InvalidateAccessibleParaFlowRelation(
+ dynamic_cast<SwTxtFrm*>(pNew->FindNextCnt( true )),
+ this );
+ }
+ }
+ // <--
+
+ // Wenn durch unsere Aktionen Fussnoten in pNew landen,
+ // so muessen sie umgemeldet werden.
+ if ( HasFtn() )
+ {
+ const SwpHints *pHints = GetTxtNode()->GetpSwpHints();
+ if( pHints )
+ {
+ SwFtnBossFrm *pFtnBoss = 0;
+ SwFtnBossFrm *pEndBoss = 0;
+ for ( sal_uInt16 i = 0; i < pHints->Count(); ++i )
+ {
+ const SwTxtAttr *pHt = (*pHints)[i];
+ if( RES_TXTATR_FTN==pHt->Which() && *pHt->GetStart()>=nTxtPos )
+ {
+ if( pHt->GetFtn().IsEndNote() )
+ {
+ if( !pEndBoss )
+ pEndBoss = FindFtnBossFrm();
+ pEndBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew );
+ }
+ else
+ {
+ if( !pFtnBoss )
+ pFtnBoss = FindFtnBossFrm( sal_True );
+ pFtnBoss->ChangeFtnRef( this, (SwTxtFtn*)pHt, pNew );
+ }
+ pNew->SetFtn( sal_True );
+ }
+ }
+ }
+ }
+
+#if OSL_DEBUG_LEVEL > 1
+ else
+ {
+ CalcFtnFlag( nTxtPos-1 );
+ OSL_ENSURE( !HasFtn(), "Missing FtnFlag." );
+ }
+#endif
+
+ MoveFlyInCnt( pNew, nTxtPos, STRING_LEN );
+
+ // Kein SetOfst oder CalcFollow, weil gleich ohnehin ein AdjustFollow folgt.
+
+ pNew->ManipOfst( nTxtPos );
+
+ UNDO_SWAP( this )
+ return pNew;
+}
+
+
+/*************************************************************************
+ * virtual SwTxtFrm::SetOfst()
+ *************************************************************************/
+
+void SwTxtFrm::_SetOfst( const xub_StrLen nNewOfst )
+{
+ // Die Invalidierung unseres Follows ist nicht noetig.
+ // Wir sind ein Follow, werden gleich formatiert und
+ // rufen von dort aus das SetOfst() !
+ nOfst = nNewOfst;
+ SwParaPortion *pPara = GetPara();
+ if( pPara )
+ {
+ SwCharRange &rReformat = *(pPara->GetReformat());
+ rReformat.Start() = 0;
+ rReformat.Len() = GetTxt().Len();
+ *(pPara->GetDelta()) = rReformat.Len();
+ }
+ InvalidateSize();
+}
+
+/*************************************************************************
+ * SwTxtFrm::CalcPreps
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::CalcPreps()
+{
+ OSL_ENSURE( ! IsVertical() || ! IsSwapped(), "SwTxtFrm::CalcPreps with swapped frame" );
+ SWRECTFN( this );
+
+ SwParaPortion *pPara = GetPara();
+ if ( !pPara )
+ return sal_False;
+ sal_Bool bPrep = pPara->IsPrep();
+ sal_Bool bPrepWidows = pPara->IsPrepWidows();
+ sal_Bool bPrepAdjust = pPara->IsPrepAdjust();
+ sal_Bool bPrepMustFit = pPara->IsPrepMustFit();
+ ResetPreps();
+
+ sal_Bool bRet = sal_False;
+ if( bPrep && !pPara->GetReformat()->Len() )
+ {
+ // PREP_WIDOWS bedeutet, dass im Follow die Orphans-Regel
+ // zuschlug.
+ // Es kann in unguenstigen Faellen vorkommen, dass auch ein
+ // PrepAdjust vorliegt (3680)!
+ if( bPrepWidows )
+ {
+ if( !GetFollow() )
+ {
+ OSL_ENSURE( GetFollow(), "+SwTxtFrm::CalcPreps: no credits" );
+ return sal_False;
+ }
+
+ // Wir muessen uns auf zwei Faelle einstellen:
+ // Wir konnten dem Follow noch ein paar Zeilen abgeben,
+ // -> dann muessen wir schrumpfen
+ // oder wir muessen auf die naechste Seite
+ // -> dann lassen wir unseren Frame zu gross werden.
+
+ SwTwips nChgHeight = GetParHeight();
+ if( nChgHeight >= (Prt().*fnRect->fnGetHeight)() )
+ {
+ if( bPrepMustFit )
+ {
+ GetFollow()->SetJustWidow( sal_True );
+ GetFollow()->Prepare( PREP_CLEAR );
+ }
+ else if ( bVert )
+ {
+ Frm().Width( Frm().Width() + Frm().Left() );
+ Prt().Width( Prt().Width() + Frm().Left() );
+ Frm().Left( 0 );
+ SetWidow( sal_True );
+ }
+ else
+ {
+ SwTwips nTmp = LONG_MAX - (Frm().Top()+10000);
+ SwTwips nDiff = nTmp - Frm().Height();
+ Frm().Height( nTmp );
+ Prt().Height( Prt().Height() + nDiff );
+ SetWidow( sal_True );
+ }
+ }
+ else
+ {
+ OSL_ENSURE( nChgHeight < (Prt().*fnRect->fnGetHeight)(),
+ "+SwTxtFrm::CalcPrep: wanna shrink" );
+
+ nChgHeight = (Prt().*fnRect->fnGetHeight)() - nChgHeight;
+
+ GetFollow()->SetJustWidow( sal_True );
+ GetFollow()->Prepare( PREP_CLEAR );
+ Shrink( nChgHeight );
+ SwRect &rRepaint = *(pPara->GetRepaint());
+
+ if ( bVert )
+ {
+ SwRect aRepaint( Frm().Pos() + Prt().Pos(), Prt().SSize() );
+ SwitchVerticalToHorizontal( aRepaint );
+ rRepaint.Chg( aRepaint.Pos(), aRepaint.SSize() );
+ }
+ else
+ rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() );
+
+ if( 0 >= rRepaint.Width() )
+ rRepaint.Width(1);
+ }
+ bRet = sal_True;
+ }
+
+ else if ( bPrepAdjust )
+ {
+ if ( HasFtn() )
+ {
+ if( !CalcPrepFtnAdjust() )
+ {
+ if( bPrepMustFit )
+ {
+ SwTxtLineAccess aAccess( this );
+ aAccess.GetPara()->SetPrepMustFit( sal_True );
+ }
+ return sal_False;
+ }
+ }
+
+ SWAP_IF_NOT_SWAPPED( this )
+
+ SwTxtFormatInfo aInf( this );
+ SwTxtFormatter aLine( this, &aInf );
+
+ WidowsAndOrphans aFrmBreak( this );
+ // Egal was die Attribute meinen, bei MustFit wird
+ // der Absatz im Notfall trotzdem gesplittet...
+ if( bPrepMustFit )
+ {
+ aFrmBreak.SetKeep( sal_False );
+ aFrmBreak.ClrOrphLines();
+ }
+ // Bevor wir FormatAdjust aufrufen muessen wir dafuer
+ // sorgen, dass die Zeilen, die unten raushaengen
+ // auch tatsaechlich abgeschnitten werden.
+ // OD 2004-02-25 #i16128# - method renamed
+ sal_Bool bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine );
+ bRet = sal_True;
+ while( !bBreak && aLine.Next() )
+ {
+ // OD 2004-02-25 #i16128# - method renamed
+ bBreak = aFrmBreak.IsBreakNowWidAndOrp( aLine );
+ }
+ if( bBreak )
+ {
+ // Es gibt Komplikationen: wenn TruncLines gerufen wird,
+ // veraendern sich ploetzlich die Bedingungen in
+ // IsInside, so dass IsBreakNow andere Ergebnisse
+ // liefern kann. Aus diesem Grund wird rFrmBreak bekannt
+ // gegeben, dass da wo rLine steht, das Ende erreicht
+ // ist. Mal sehen, ob's klappt ...
+ aLine.TruncLines();
+ aFrmBreak.SetRstHeight( aLine );
+ FormatAdjust( aLine, aFrmBreak, aInf.GetTxt().Len(), aInf.IsStop() );
+ }
+ else
+ {
+ if( !GetFollow() )
+ {
+ FormatAdjust( aLine, aFrmBreak,
+ aInf.GetTxt().Len(), aInf.IsStop() );
+ }
+ else if ( !aFrmBreak.IsKeepAlways() )
+ {
+ // Siehe Bug: 2320
+ // Vor dem Master wird eine Zeile geloescht, der Follow
+ // koennte eine Zeile abgeben.
+ const SwCharRange aFollowRg( GetFollow()->GetOfst(), 1 );
+ *(pPara->GetReformat()) += aFollowRg;
+ // Es soll weitergehen!
+ bRet = sal_False;
+ }
+ }
+
+ UNDO_SWAP( this )
+ // Eine letzte Ueberpruefung, falls das FormatAdjust() nichts
+ // brachte, muessen wir amputieren.
+ if( bPrepMustFit )
+ {
+ const SwTwips nMust = (GetUpper()->*fnRect->fnGetPrtBottom)();
+ const SwTwips nIs = (Frm().*fnRect->fnGetBottom)();
+
+ if( bVert && nIs < nMust )
+ {
+ Shrink( nMust - nIs );
+ if( Prt().Width() < 0 )
+ Prt().Width( 0 );
+ SetUndersized( sal_True );
+ }
+ else if ( ! bVert && nIs > nMust )
+ {
+ Shrink( nIs - nMust );
+ if( Prt().Height() < 0 )
+ Prt().Height( 0 );
+ SetUndersized( sal_True );
+ }
+ }
+ }
+ }
+ pPara->SetPrepMustFit( bPrepMustFit );
+ return bRet;
+}
+
+
+/*************************************************************************
+ * SwTxtFrm::FormatAdjust()
+ *************************************************************************/
+
+// Hier werden die Fussnoten und "als Zeichen"-gebundenen Objekte umgehaengt
+#define CHG_OFFSET( pFrm, nNew )\
+ {\
+ if( pFrm->GetOfst() < nNew )\
+ pFrm->MoveFlyInCnt( this, 0, nNew );\
+ else if( pFrm->GetOfst() > nNew )\
+ MoveFlyInCnt( pFrm, nNew, STRING_LEN );\
+ }
+
+void SwTxtFrm::FormatAdjust( SwTxtFormatter &rLine,
+ WidowsAndOrphans &rFrmBreak,
+ const xub_StrLen nStrLen,
+ const sal_Bool bDummy )
+{
+ SWAP_IF_NOT_SWAPPED( this )
+
+ SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
+
+ xub_StrLen nEnd = rLine.GetStart();
+
+ sal_Bool bHasToFit = pPara->IsPrepMustFit();
+
+ // Das StopFlag wird durch Fussnoten gesetzt,
+ // die auf die naechste Seite wollen.
+ // OD, FME 2004-03-03 - call base class method <SwTxtFrmBreak::IsBreakNow(..)>
+ // instead of method <WidowsAndOrphans::IsBreakNow(..)> to get a break,
+ // even if due to widow rule no enough lines exists.
+ sal_uInt8 nNew = ( !GetFollow() &&
+ nEnd < nStrLen &&
+ ( rLine.IsStop() ||
+ ( bHasToFit
+ ? ( rLine.GetLineNr() > 1 &&
+ !rFrmBreak.IsInside( rLine ) )
+ : rFrmBreak.IsBreakNow( rLine ) ) ) )
+ ? 1 : 0;
+ if ( nNew )
+ SplitFrm( nEnd );
+
+ const SwFrm *pBodyFrm = (const SwFrm*)(FindBodyFrm());
+
+ const long nBodyHeight = pBodyFrm ? ( IsVertical() ?
+ pBodyFrm->Frm().Width() :
+ pBodyFrm->Frm().Height() ) : 0;
+
+ // Wenn die aktuellen Werte berechnet wurden, anzeigen, dass
+ // sie jetzt gueltig sind.
+ *(pPara->GetReformat()) = SwCharRange();
+ sal_Bool bDelta = *pPara->GetDelta() != 0;
+ *(pPara->GetDelta()) = 0;
+
+ if( rLine.IsStop() )
+ {
+ rLine.TruncLines( sal_True );
+ nNew = 1;
+ }
+
+ // FindBreak schneidet die letzte Zeile ab.
+ if( !rFrmBreak.FindBreak( this, rLine, bHasToFit ) )
+ {
+ // Wenn wir bis zum Ende durchformatiert haben, wird nEnd auf das Ende
+ // gesetzt. In AdjustFollow wird dadurch ggf. JoinFrm() ausgefuehrt.
+ // Ansonsten ist nEnd das Ende der letzten Zeile im Master.
+ xub_StrLen nOld = nEnd;
+ nEnd = rLine.GetEnd();
+ if( GetFollow() )
+ {
+ if( nNew && nOld < nEnd )
+ RemoveFtn( nOld, nEnd - nOld );
+ CHG_OFFSET( GetFollow(), nEnd )
+ if( !bDelta )
+ GetFollow()->ManipOfst( nEnd );
+ }
+ }
+ else
+ { // Wenn wir Zeilen abgeben, darf kein Join auf den Folows gerufen werden,
+ // im Gegenteil, es muss ggf. sogar ein Follow erzeugt werden.
+ // Dies muss auch geschehen, wenn die Textmasse komplett im Master
+ // bleibt, denn es k???nnte ja ein harter Zeilenumbruch noch eine weitere
+ // Zeile (ohne Textmassse) notwendig machen!
+ nEnd = rLine.GetEnd();
+ if( GetFollow() )
+ {
+ // OD 21.03.2003 #108121# - Another case for not joining the follow:
+ // Text frame has no content, but a numbering. Then, do *not* join.
+ // Example of this case: When an empty, but numbered paragraph
+ // at the end of page is completely displaced by a fly frame.
+ // Thus, the text frame introduced a follow by a
+ // <SwTxtFrm::SplitFrm(..)> - see below. The follow then shows
+ // the numbering and must stay.
+ if ( GetFollow()->GetOfst() != nEnd ||
+ GetFollow()->IsFieldFollow() ||
+ ( nStrLen == 0 && GetTxtNode()->GetNumRule())
+ )
+ {
+ nNew |= 3;
+ }
+ CHG_OFFSET( GetFollow(), nEnd )
+ GetFollow()->ManipOfst( nEnd );
+ }
+ else
+ {
+ // OD 21.03.2003 #108121# - Only split frame, if the frame contains
+ // content or contains no content, but has a numbering.
+ if ( nStrLen > 0 ||
+ ( nStrLen == 0 && GetTxtNode()->GetNumRule())
+ )
+ {
+ SplitFrm( nEnd );
+ nNew |= 3;
+ }
+ }
+ // Wenn sich die Resthoehe geaendert hat, z.B. durch RemoveFtn()
+ // dann muessen wir auffuellen, um Oszillationen zu vermeiden!
+ if( bDummy && pBodyFrm &&
+ nBodyHeight < ( IsVertical() ?
+ pBodyFrm->Frm().Width() :
+ pBodyFrm->Frm().Height() ) )
+ rLine.MakeDummyLine();
+ }
+
+ // In AdjustFrm() stellen wir uns selbst per Grow/Shrink ein,
+ // in AdjustFollow() stellen wir unseren FolgeFrame ein.
+
+ const SwTwips nDocPrtTop = Frm().Top() + Prt().Top();
+ const SwTwips nOldHeight = Prt().SSize().Height();
+ const SwTwips nChg = rLine.CalcBottomLine() - nDocPrtTop - nOldHeight;
+
+ // Vertical Formatting:
+ // The (rotated) repaint rectangle's x coordinate referes to the frame.
+ // If the frame grows (or shirks) the repaint rectangle cannot simply
+ // be rotated back after formatting, because we use the upper left point
+ // of the frame for rotation. This point changes when growing/shrinking.
+
+ //Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
+ if ( IsVertical() && !IsVertLR() && nChg )
+ {
+ SwRect &rRepaint = *(pPara->GetRepaint());
+ rRepaint.Left( rRepaint.Left() - nChg );
+ rRepaint.Width( rRepaint.Width() - nChg );
+ }
+
+ AdjustFrm( nChg, bHasToFit );
+
+ if( HasFollow() || IsInFtn() )
+ _AdjustFollow( rLine, nEnd, nStrLen, nNew );
+
+ pPara->SetPrepMustFit( sal_False );
+
+ UNDO_SWAP( this )
+}
+
+/*************************************************************************
+ * SwTxtFrm::FormatLine()
+ *************************************************************************/
+
+// bPrev zeigt an, ob Reformat.Start() wegen Prev() vorgezogen wurde.
+// Man weiss sonst nicht, ob man Repaint weiter einschraenken kann oder nicht.
+
+
+sal_Bool SwTxtFrm::FormatLine( SwTxtFormatter &rLine, const sal_Bool bPrev )
+{
+ OSL_ENSURE( ! IsVertical() || IsSwapped(),
+ "SwTxtFrm::FormatLine( rLine, bPrev) with unswapped frame" );
+ SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
+ const SwLineLayout *pOldCur = rLine.GetCurr();
+ const xub_StrLen nOldLen = pOldCur->GetLen();
+ const KSHORT nOldAscent = pOldCur->GetAscent();
+ const KSHORT nOldHeight = pOldCur->Height();
+ const SwTwips nOldWidth = pOldCur->Width() + pOldCur->GetHangingMargin();
+ const sal_Bool bOldHyph = pOldCur->IsEndHyph();
+ SwTwips nOldTop = 0;
+ SwTwips nOldBottom = 0;
+ if( rLine.GetCurr()->IsClipping() )
+ rLine.CalcUnclipped( nOldTop, nOldBottom );
+
+ const xub_StrLen nNewStart = rLine.FormatLine( rLine.GetStart() );
+
+ OSL_ENSURE( Frm().Pos().Y() + Prt().Pos().Y() == rLine.GetFirstPos(),
+ "SwTxtFrm::FormatLine: frame leaves orbit." );
+ OSL_ENSURE( rLine.GetCurr()->Height(),
+ "SwTxtFrm::FormatLine: line height is zero" );
+
+ // Das aktuelle Zeilenumbruchobjekt.
+ const SwLineLayout *pNew = rLine.GetCurr();
+
+ sal_Bool bUnChg = nOldLen == pNew->GetLen() &&
+ bOldHyph == pNew->IsEndHyph();
+ if ( bUnChg && !bPrev )
+ {
+ const long nWidthDiff = nOldWidth > pNew->Width()
+ ? nOldWidth - pNew->Width()
+ : pNew->Width() - nOldWidth;
+
+ // we only declare a line as unchanged, if its main values have not
+ // changed and it is not the last line (!paragraph end symbol!)
+ bUnChg = nOldHeight == pNew->Height() &&
+ nOldAscent == pNew->GetAscent() &&
+ nWidthDiff <= SLOPPY_TWIPS &&
+ pOldCur->GetNext();
+ }
+
+ // rRepaint wird berechnet:
+ const SwTwips nBottom = rLine.Y() + rLine.GetLineHeight();
+ SwRepaint &rRepaint = *(pPara->GetRepaint());
+ if( bUnChg && rRepaint.Top() == rLine.Y()
+ && (bPrev || nNewStart <= pPara->GetReformat()->Start())
+ && ( nNewStart < GetTxtNode()->GetTxt().Len() ) )
+ {
+ rRepaint.Top( nBottom );
+ rRepaint.Height( 0 );
+ }
+ else
+ {
+ if( nOldTop )
+ {
+ if( nOldTop < rRepaint.Top() )
+ rRepaint.Top( nOldTop );
+ if( !rLine.IsUnclipped() || nOldBottom > rRepaint.Bottom() )
+ {
+ rRepaint.Bottom( nOldBottom - 1 );
+ rLine.SetUnclipped( sal_True );
+ }
+ }
+ if( rLine.GetCurr()->IsClipping() && rLine.IsFlyInCntBase() )
+ {
+ SwTwips nTmpTop, nTmpBottom;
+ rLine.CalcUnclipped( nTmpTop, nTmpBottom );
+ if( nTmpTop < rRepaint.Top() )
+ rRepaint.Top( nTmpTop );
+ if( !rLine.IsUnclipped() || nTmpBottom > rRepaint.Bottom() )
+ {
+ rRepaint.Bottom( nTmpBottom - 1 );
+ rLine.SetUnclipped( sal_True );
+ }
+ }
+ else
+ {
+ if( !rLine.IsUnclipped() || nBottom > rRepaint.Bottom() )
+ {
+ rRepaint.Bottom( nBottom - 1 );
+ rLine.SetUnclipped( sal_False );
+ }
+ }
+ SwTwips nRght = Max( nOldWidth, pNew->Width() +
+ pNew->GetHangingMargin() );
+ ViewShell *pSh = getRootFrm()->GetCurrShell();
+ const SwViewOption *pOpt = pSh ? pSh->GetViewOptions() : 0;
+ if( pOpt && (pOpt->IsParagraph() || pOpt->IsLineBreak()) )
+ nRght += ( Max( nOldAscent, pNew->GetAscent() ) );
+ else
+ nRght += ( Max( nOldAscent, pNew->GetAscent() ) / 4);
+ nRght += rLine.GetLeftMargin();
+ if( rRepaint.GetOfst() || rRepaint.GetRightOfst() < nRght )
+ rRepaint.SetRightOfst( nRght );
+
+ // Finally we enlarge the repaint rectangle if we found an underscore
+ // within our line. 40 Twips should be enough
+ const sal_Bool bHasUnderscore =
+ ( rLine.GetInfo().GetUnderScorePos() < nNewStart );
+ if ( bHasUnderscore || rLine.GetCurr()->HasUnderscore() )
+ rRepaint.Bottom( rRepaint.Bottom() + 40 );
+
+ ((SwLineLayout*)rLine.GetCurr())->SetUnderscore( bHasUnderscore );
+ }
+ if( !bUnChg )
+ rLine.SetChanges();
+
+ // Die gute, alte nDelta-Berechnung:
+ *(pPara->GetDelta()) -= long(pNew->GetLen()) - long(nOldLen);
+
+ // Stop!
+ if( rLine.IsStop() )
+ return sal_False;
+
+ // Unbedingt noch eine Zeile
+ if( rLine.IsNewLine() )
+ return sal_True;
+
+ // bis zum Ende des Strings ?
+ if( nNewStart >= GetTxtNode()->GetTxt().Len() )
+ return sal_False;
+
+ if( rLine.GetInfo().IsShift() )
+ return sal_True;
+
+ // Ende des Reformats erreicht ?
+ const xub_StrLen nEnd = pPara->GetReformat()->Start() +
+ pPara->GetReformat()->Len();
+
+ if( nNewStart <= nEnd )
+ return sal_True;
+
+ return 0 != *(pPara->GetDelta());
+}
+
+/*************************************************************************
+ * SwTxtFrm::_Format()
+ *************************************************************************/
+
+void SwTxtFrm::_Format( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf,
+ const sal_Bool bAdjust )
+{
+ OSL_ENSURE( ! IsVertical() || IsSwapped(),"SwTxtFrm::_Format with unswapped frame" );
+
+ SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
+ rLine.SetUnclipped( sal_False );
+
+ // Das war dem C30 zu kompliziert: aString( GetTxt() );
+ const XubString &rString = GetTxtNode()->GetTxt();
+ const xub_StrLen nStrLen = rString.Len();
+
+ SwCharRange &rReformat = *(pPara->GetReformat());
+ SwRepaint &rRepaint = *(pPara->GetRepaint());
+ SwRepaint *pFreeze = NULL;
+
+ // Aus Performancegruenden wird in Init() rReformat auf STRING_LEN gesetzt.
+ // Fuer diesen Fall wird rReformat angepasst.
+ if( rReformat.Len() > nStrLen )
+ rReformat.Len() = nStrLen;
+
+ // Optimiert:
+ xub_StrLen nEnd = rReformat.Start() + rReformat.Len();
+ if( nEnd > nStrLen )
+ {
+ rReformat.Len() = nStrLen - rReformat.Start();
+ nEnd = nStrLen;
+ }
+
+ SwTwips nOldBottom;
+ if( GetOfst() && !IsFollow() )
+ {
+ rLine.Bottom();
+ nOldBottom = rLine.Y();
+ rLine.Top();
+ }
+ else
+ nOldBottom = 0;
+ rLine.CharToLine( rReformat.Start() );
+
+ // Worte koennen durch Fortfall oder Einfuegen eines Space
+ // auf die Zeile vor der editierten hinausgezogen werden,
+ // deshalb muss diese ebenfalls formatiert werden.
+ // Optimierung: Wenn rReformat erst hinter dem ersten Wort der
+ // Zeile beginnt, so kann diese Zeile die vorige nicht mehr beeinflussen.
+ // AMA: Leider doch, Textgroessenaenderungen + FlyFrames, die Rueckwirkung
+ // kann im Extremfall mehrere Zeilen (Frames!!!) betreffen!
+
+ // --> FME 2005-04-18 #i46560#
+ // FME: Yes, consider this case: (word ) has to go to the next line
+ // because ) is a forbidden character at the beginning of a line although
+ // (word would still fit on the previous line. Adding text right in front
+ // of ) would not trigger a reformatting of the previous line. Adding 1
+ // to the result of FindBrk() does not solve the problem in all cases,
+ // nevertheless it should be sufficient.
+ // <--
+ sal_Bool bPrev = rLine.GetPrev() &&
+ ( FindBrk( rString, rLine.GetStart(), rReformat.Start() + 1 )
+ // --> FME 2005-04-18 #i46560#
+ + 1
+ // <--
+ >= rReformat.Start() ||
+ rLine.GetCurr()->IsRest() );
+ if( bPrev )
+ {
+ while( rLine.Prev() )
+ if( rLine.GetCurr()->GetLen() && !rLine.GetCurr()->IsRest() )
+ {
+ if( !rLine.GetStart() )
+ rLine.Top(); // damit NumDone nicht durcheinander kommt
+ break;
+ }
+ xub_StrLen nNew = rLine.GetStart() + rLine.GetLength();
+ if( nNew )
+ {
+ --nNew;
+ if( CH_BREAK == rString.GetChar( nNew ) )
+ {
+ ++nNew;
+ rLine.Next();
+ bPrev = sal_False;
+ }
+ }
+ rReformat.Len() += rReformat.Start() - nNew;
+ rReformat.Start() = nNew;
+ }
+
+ rRepaint.SetOfst( 0 );
+ rRepaint.SetRightOfst( 0 );
+ rRepaint.Chg( Frm().Pos() + Prt().Pos(), Prt().SSize() );
+ if( pPara->IsMargin() )
+ rRepaint.Width( rRepaint.Width() + pPara->GetHangingMargin() );
+ rRepaint.Top( rLine.Y() );
+ if( 0 >= rRepaint.Width() )
+ rRepaint.Width(1);
+ WidowsAndOrphans aFrmBreak( this, rInf.IsTest() ? 1 : 0 );
+
+ // rLine steht jetzt auf der ersten Zeile, die formatiert werden
+ // muss. Das Flag bFirst sorgt dafuer, dass nicht Next() gerufen wird.
+ // Das ganze sieht verdreht aus, aber es muss sichergestellt werden,
+ // dass bei IsBreakNow rLine auf der Zeile zum stehen kommt, die
+ // nicht mehr passt.
+ sal_Bool bFirst = sal_True;
+ sal_Bool bFormat = sal_True;
+
+ // 5383: Das CharToLine() kann uns auch in den roten Bereich fuehren.
+ // In diesem Fall muessen wir zurueckwandern, bis die Zeile, die
+ // nicht mehr passt in rLine eingestellt ist. Ansonsten geht Textmasse
+ // verloren, weil der Ofst im Follow falsch eingestellt wird.
+
+ // OD 2004-02-25 #i16128# - method renamed
+ sal_Bool bBreak = ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 )
+ && aFrmBreak.IsBreakNowWidAndOrp( rLine );
+ if( bBreak )
+ {
+ sal_Bool bPrevDone = 0 != rLine.Prev();
+ // OD 2004-02-25 #i16128# - method renamed
+ while( bPrevDone && aFrmBreak.IsBreakNowWidAndOrp(rLine) )
+ bPrevDone = 0 != rLine.Prev();
+ if( bPrevDone )
+ {
+ aFrmBreak.SetKeep( sal_False );
+ rLine.Next();
+ }
+ rLine.TruncLines();
+
+ // auf Nummer sicher:
+ // OD 2004-02-25 #i16128# - method renamed
+ bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine) &&
+ ( !pPara->IsPrepMustFit() || rLine.GetLineNr() > 1 );
+ }
+
+ /* Bedeutung der folgenden Flags:
+ Ist das Watch(End/Mid)Hyph-Flag gesetzt, so muss formatiert werden, wenn
+ eine Trennung am (Zeilenende/Fly) vorliegt, sofern MaxHyph erreicht ist.
+ Das Jump(End/Mid)Flag bedeutet, dass die naechste Zeile, bei der keine
+ Trennung (Zeilenende/Fly) vorliegt, formatiert werden muss, da jetzt
+ umgebrochen werden koennte, was vorher moeglicherweise durch MaxHyph
+ verboten war.
+ Watch(End/Mid)Hyph wird gesetzt, wenn die letzte formatierte Zeile eine
+ Trennstelle erhalten hat, vorher aber keine hatte,
+ Jump(End/Mid)Hyph, wenn eine Trennstelle verschwindet.
+ */
+ sal_Bool bJumpEndHyph = sal_False,
+ bWatchEndHyph = sal_False,
+ bJumpMidHyph = sal_False,
+ bWatchMidHyph = sal_False;
+
+ const SwAttrSet& rAttrSet = GetTxtNode()->GetSwAttrSet();
+ sal_Bool bMaxHyph = ( 0 !=
+ ( rInf.MaxHyph() = rAttrSet.GetHyphenZone().GetMaxHyphens() ) );
+ if ( bMaxHyph )
+ rLine.InitCntHyph();
+
+ if( IsFollow() && IsFieldFollow() && rLine.GetStart() == GetOfst() )
+ {
+ const SwLineLayout* pLine;
+ {
+ SwTxtFrm *pMaster = FindMaster();
+ OSL_ENSURE( pMaster, "SwTxtFrm::Format: homeless follow" );
+ if( !pMaster->HasPara() )
+ pMaster->GetFormatted();
+ SwTxtSizeInfo aInf( pMaster );
+ SwTxtIter aMasterLine( pMaster, &aInf );
+ aMasterLine.Bottom();
+ pLine = aMasterLine.GetCurr();
+ }
+ SwLinePortion* pRest =
+ rLine.MakeRestPortion( pLine, GetOfst() );
+ if( pRest )
+ rInf.SetRest( pRest );
+ else
+ SetFieldFollow( sal_False );
+ }
+
+ /* Zum Abbruchkriterium:
+ * Um zu erkennen, dass eine Zeile nicht mehr auf die Seite passt,
+ * muss sie formatiert werden. Dieser Ueberhang wird z.B. in AdjustFollow
+ * wieder entfernt.
+ * Eine weitere Komplikation: wenn wir der Master sind, so muessen
+ * wir die Zeilen durchgehen, da es ja sein kann, dass eine Zeile
+ * vom Follow in den Master rutschen kann.
+ */
+ do
+ {
+ if( bFirst )
+ bFirst = sal_False;
+ else
+ {
+ if ( bMaxHyph )
+ {
+ if ( rLine.GetCurr()->IsEndHyph() )
+ rLine.CntEndHyph()++;
+ else
+ rLine.CntEndHyph() = 0;
+ if ( rLine.GetCurr()->IsMidHyph() )
+ rLine.CntMidHyph()++;
+ else
+ rLine.CntMidHyph() = 0;
+ }
+ if( !rLine.Next() )
+ {
+ if( !bFormat )
+ {
+ SwLinePortion* pRest =
+ rLine.MakeRestPortion( rLine.GetCurr(), rLine.GetEnd() );
+ if( pRest )
+ rInf.SetRest( pRest );
+ }
+ rLine.Insert( new SwLineLayout() );
+ rLine.Next();
+ bFormat = sal_True;
+ }
+ }
+ if ( !bFormat && bMaxHyph &&
+ (bWatchEndHyph || bJumpEndHyph || bWatchMidHyph || bJumpMidHyph) )
+ {
+ if ( rLine.GetCurr()->IsEndHyph() )
+ {
+ if ( bWatchEndHyph )
+ bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() );
+ }
+ else
+ {
+ bFormat = bJumpEndHyph;
+ bWatchEndHyph = sal_False;
+ bJumpEndHyph = sal_False;
+ }
+ if ( rLine.GetCurr()->IsMidHyph() )
+ {
+ if ( bWatchMidHyph && !bFormat )
+ bFormat = ( rLine.CntEndHyph() == rInf.MaxHyph() );
+ }
+ else
+ {
+ bFormat = bFormat || bJumpMidHyph;
+ bWatchMidHyph = sal_False;
+ bJumpMidHyph = sal_False;
+ }
+ }
+ if( bFormat )
+ {
+ sal_Bool bOldEndHyph = rLine.GetCurr()->IsEndHyph();
+ sal_Bool bOldMidHyph = rLine.GetCurr()->IsMidHyph();
+ bFormat = FormatLine( rLine, bPrev );
+ //9334: Es kann nur ein bPrev geben... (???)
+ bPrev = sal_False;
+ if ( bMaxHyph )
+ {
+ if ( rLine.GetCurr()->IsEndHyph() != bOldEndHyph )
+ {
+ bWatchEndHyph = !bOldEndHyph;
+ bJumpEndHyph = bOldEndHyph;
+ }
+ if ( rLine.GetCurr()->IsMidHyph() != bOldMidHyph )
+ {
+ bWatchMidHyph = !bOldMidHyph;
+ bJumpMidHyph = bOldMidHyph;
+ }
+ }
+ }
+
+ if( !rInf.IsNewLine() )
+ {
+ if( !bFormat )
+ bFormat = 0 != rInf.GetRest();
+ if( rInf.IsStop() || rInf.GetIdx() >= nStrLen )
+ break;
+ if( !bFormat && ( !bMaxHyph || ( !bWatchEndHyph &&
+ !bJumpEndHyph && !bWatchMidHyph && !bJumpMidHyph ) ) )
+ {
+ if( GetFollow() )
+ {
+ while( rLine.Next() )
+ ; //Nothing
+ pFreeze = new SwRepaint( rRepaint ); // to minimize painting
+ }
+ else
+ break;
+ }
+ }
+ // OD 2004-02-25 #i16128# - method renamed
+ bBreak = aFrmBreak.IsBreakNowWidAndOrp(rLine);
+ }while( !bBreak );
+
+ if( pFreeze )
+ {
+ rRepaint = *pFreeze;
+ delete pFreeze;
+ }
+
+ if( !rLine.IsStop() )
+ {
+ // Wurde aller Text formatiert und gibt es noch weitere
+ // Zeilenobjekte, dann sind diese jetzt ueberfluessig,
+ // weil der Text kuerzer geworden ist.
+ if( rLine.GetStart() + rLine.GetLength() >= nStrLen &&
+ rLine.GetCurr()->GetNext() )
+ {
+ rLine.TruncLines();
+ rLine.SetTruncLines( sal_True );
+ }
+ }
+
+ if( !rInf.IsTest() )
+ {
+ // Bei OnceMore lohnt sich kein FormatAdjust
+ if( bAdjust || !rLine.GetDropFmt() || !rLine.CalcOnceMore() )
+ {
+ FormatAdjust( rLine, aFrmBreak, nStrLen, rInf.IsStop() );
+ }
+ if( rRepaint.HasArea() )
+ SetRepaint();
+ rLine.SetTruncLines( sal_False );
+ if( nOldBottom ) // Bei "gescollten" Absaetzen wird
+ { // noch ueberprueft, ob durch Schrumpfen
+ rLine.Bottom(); // das Scrolling ueberfluessig wurde.
+ SwTwips nNewBottom = rLine.Y();
+ if( nNewBottom < nOldBottom )
+ _SetOfst( 0 );
+ }
+ }
+}
+
+/*************************************************************************
+ * SwTxtFrm::Format()
+ *************************************************************************/
+
+void SwTxtFrm::FormatOnceMore( SwTxtFormatter &rLine, SwTxtFormatInfo &rInf )
+{
+ OSL_ENSURE( ! IsVertical() || IsSwapped(),
+ "A frame is not swapped in SwTxtFrm::FormatOnceMore" );
+
+ SwParaPortion *pPara = rLine.GetInfo().GetParaPortion();
+ if( !pPara )
+ return;
+
+ // ggf gegen pPara
+ KSHORT nOld = ((const SwTxtMargin&)rLine).GetDropHeight();
+ sal_Bool bShrink = sal_False,
+ bGrow = sal_False,
+ bGoOn = rLine.IsOnceMore();
+ sal_uInt8 nGo = 0;
+ while( bGoOn )
+ {
+ ++nGo;
+ rInf.Init();
+ rLine.Top();
+ if( !rLine.GetDropFmt() )
+ rLine.SetOnceMore( sal_False );
+ SwCharRange aRange( 0, rInf.GetTxt().Len() );
+ *(pPara->GetReformat()) = aRange;
+ _Format( rLine, rInf );
+
+ bGoOn = rLine.IsOnceMore();
+ if( bGoOn )
+ {
+ const KSHORT nNew = ((const SwTxtMargin&)rLine).GetDropHeight();
+ if( nOld == nNew )
+ bGoOn = sal_False;
+ else
+ {
+ if( nOld > nNew )
+ bShrink = sal_True;
+ else
+ bGrow = sal_True;
+
+ if( bShrink == bGrow || 5 < nGo )
+ bGoOn = sal_False;
+
+ nOld = nNew;
+ }
+
+ // 6107: Wenn was schief ging, muss noch einmal formatiert werden.
+ if( !bGoOn )
+ {
+ rInf.CtorInitTxtFormatInfo( this );
+ rLine.CtorInitTxtFormatter( this, &rInf );
+ rLine.SetDropLines( 1 );
+ rLine.CalcDropHeight( 1 );
+ SwCharRange aTmpRange( 0, rInf.GetTxt().Len() );
+ *(pPara->GetReformat()) = aTmpRange;
+ _Format( rLine, rInf, sal_True );
+ // 8047: Wir painten alles...
+ SetCompletePaint();
+ }
+ }
+ }
+}
+
+/*************************************************************************
+ * SwTxtFrm::_Format()
+ *************************************************************************/
+
+
+void SwTxtFrm::_Format( SwParaPortion *pPara )
+{
+ const xub_StrLen nStrLen = GetTxt().Len();
+
+ if ( !nStrLen )
+ {
+ // Leere Zeilen werden nicht lange gequaelt:
+ // pPara wird blank geputzt
+ // entspricht *pPara = SwParaPortion;
+ sal_Bool bMustFit = pPara->IsPrepMustFit();
+ pPara->Truncate();
+ pPara->FormatReset();
+ if( pBlink && pPara->IsBlinking() )
+ pBlink->Delete( pPara );
+
+ // delete pSpaceAdd und pKanaComp
+ pPara->FinishSpaceAdd();
+ pPara->FinishKanaComp();
+ pPara->ResetFlags();
+ pPara->SetPrepMustFit( bMustFit );
+ }
+
+ OSL_ENSURE( ! IsSwapped(), "A frame is swapped before _Format" );
+
+ if ( IsVertical() )
+ SwapWidthAndHeight();
+
+ SwTxtFormatInfo aInf( this );
+ SwTxtFormatter aLine( this, &aInf );
+
+ // OD 2004-01-15 #110582#
+ HideAndShowObjects();
+
+ _Format( aLine, aInf );
+
+ if( aLine.IsOnceMore() )
+ FormatOnceMore( aLine, aInf );
+
+ if ( IsVertical() )
+ SwapWidthAndHeight();
+
+ OSL_ENSURE( ! IsSwapped(), "A frame is swapped after _Format" );
+
+ if( 1 < aLine.GetDropLines() )
+ {
+ if( SVX_ADJUST_LEFT != aLine.GetAdjust() &&
+ SVX_ADJUST_BLOCK != aLine.GetAdjust() )
+ {
+ aLine.CalcDropAdjust();
+ aLine.SetPaintDrop( sal_True );
+ }
+
+ if( aLine.IsPaintDrop() )
+ {
+ aLine.CalcDropRepaint();
+ aLine.SetPaintDrop( sal_False );
+ }
+ }
+}
+
+/*************************************************************************
+ * SwTxtFrm::Format()
+ *************************************************************************/
+
+/*
+ * Format berechnet die Groesse des Textframes und ruft, wenn
+ * diese feststeht, Shrink() oder Grow(), um die Framegroesse dem
+ * evtl. veraenderten Platzbedarf anzupassen.
+ */
+
+void SwTxtFrm::Format( const SwBorderAttrs * )
+{
+#if OSL_DEBUG_LEVEL > 1
+ const XubString aXXX = GetTxtNode()->GetTxt();
+ const SwTwips nDbgY = Frm().Top();
+ (void)nDbgY;
+ const SwPageFrm *pDbgPage = FindPageFrm();
+ const MSHORT nDbgPageNr = pDbgPage->GetPhyPageNum();
+ (void)nDbgPageNr;
+ // Um zu gucken, ob es einen Ftn-Bereich gibt.
+ const SwFrm *pDbgFtnCont = (const SwFrm*)(FindPageFrm()->FindFtnCont());
+ (void)pDbgFtnCont;
+
+ // nStopAt laesst sich vom CV bearbeiten.
+ static MSHORT nStopAt = 0;
+ if( nStopAt == GetFrmId() )
+ {
+ int i = GetFrmId();
+ (void)i;
+ }
+#endif
+
+ SWRECTFN( this )
+
+ CalcAdditionalFirstLineOffset();
+
+ // Vom Berichtsautopiloten oder ueber die BASIC-Schnittstelle kommen
+ // gelegentlich TxtFrms mit einer Breite <=0.
+ if( (Prt().*fnRect->fnGetWidth)() <= 0 )
+ {
+ // Wenn MustFit gesetzt ist, schrumpfen wir ggf. auf die Unterkante
+ // des Uppers, ansonsten nehmen wir einfach eine Standardgroesse
+ // von 12 Pt. ein (240 Twip).
+ SwTxtLineAccess aAccess( this );
+ long nFrmHeight = (Frm().*fnRect->fnGetHeight)();
+ if( aAccess.GetPara()->IsPrepMustFit() )
+ {
+ const SwTwips nLimit = (GetUpper()->*fnRect->fnGetPrtBottom)();
+ const SwTwips nDiff = - (Frm().*fnRect->fnBottomDist)( nLimit );
+ if( nDiff > 0 )
+ Shrink( nDiff );
+ }
+ else if( 240 < nFrmHeight )
+ Shrink( nFrmHeight - 240 );
+ else if( 240 > nFrmHeight )
+ Grow( 240 - nFrmHeight );
+ nFrmHeight = (Frm().*fnRect->fnGetHeight)();
+
+ long nTop = (this->*fnRect->fnGetTopMargin)();
+ if( nTop > nFrmHeight )
+ (this->*fnRect->fnSetYMargins)( nFrmHeight, 0 );
+ else if( (Prt().*fnRect->fnGetHeight)() < 0 )
+ (Prt().*fnRect->fnSetHeight)( 0 );
+ return;
+ }
+
+ const xub_StrLen nStrLen = GetTxtNode()->GetTxt().Len();
+ if ( nStrLen || !FormatEmpty() )
+ {
+
+ SetEmpty( sal_False );
+ // Um nicht durch verschachtelte Formats irritiert zu werden.
+ FormatLevel aLevel;
+ if( 12 == aLevel.GetLevel() )
+ return;
+
+ // Die Formatinformationen duerfen u.U. nicht veraendert werden.
+ if( IsLocked() )
+ return;
+
+ // 8708: Vorsicht, das Format() kann auch durch GetFormatted()
+ // angestossen werden.
+ if( IsHiddenNow() )
+ {
+ long nPrtHeight = (Prt().*fnRect->fnGetHeight)();
+ if( nPrtHeight )
+ {
+ HideHidden();
+ Shrink( nPrtHeight );
+ }
+ else
+ {
+ // OD 2004-01-20 #110582# - assure that objects anchored
+ // at paragraph resp. at/as character inside paragraph
+ // are hidden.
+ HideAndShowObjects();
+ }
+ ChgThisLines();
+ return;
+ }
+
+ // Waehrend wir formatieren, wollen wir nicht gestoert werden.
+ SwTxtFrmLocker aLock(this);
+ SwTxtLineAccess aAccess( this );
+ const sal_Bool bNew = !aAccess.SwTxtLineAccess::IsAvailable();
+ const sal_Bool bSetOfst = ( GetOfst() && GetOfst() > GetTxtNode()->GetTxt().Len() );
+
+ if( CalcPreps() )
+ ; // nothing
+ // Wir returnen, wenn schon formatiert wurde, nicht aber, wenn
+ // der TxtFrm gerade erzeugt wurde und ueberhaupt keine Format-
+ // informationen vorliegen.
+ else if( !bNew && !aAccess.GetPara()->GetReformat()->Len() )
+ {
+ if( GetTxtNode()->GetSwAttrSet().GetRegister().GetValue() )
+ {
+ aAccess.GetPara()->SetPrepAdjust( sal_True );
+ aAccess.GetPara()->SetPrep( sal_True );
+ CalcPreps();
+ }
+ SetWidow( sal_False );
+ }
+ else if( bSetOfst && IsFollow() )
+ {
+ SwTxtFrm *pMaster = FindMaster();
+ OSL_ENSURE( pMaster, "SwTxtFrm::Format: homeless follow" );
+ if( pMaster )
+ pMaster->Prepare( PREP_FOLLOW_FOLLOWS );
+ SwTwips nMaxY = (GetUpper()->*fnRect->fnGetPrtBottom)();
+ if( (Frm().*fnRect->fnOverStep)( nMaxY ) )
+ (this->*fnRect->fnSetLimit)( nMaxY );
+ else if( (Frm().*fnRect->fnBottomDist)( nMaxY ) < 0 )
+ (Frm().*fnRect->fnAddBottom)( -(Frm().*fnRect->fnGetHeight)() );
+ }
+ else
+ {
+ // bSetOfst here means that we have the "red arrow situation"
+ if ( bSetOfst )
+ _SetOfst( 0 );
+
+ const sal_Bool bOrphan = IsWidow();
+ const SwFtnBossFrm* pFtnBoss = HasFtn() ? FindFtnBossFrm() : 0;
+ SwTwips nFtnHeight = 0;
+ if( pFtnBoss )
+ {
+ const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont();
+ nFtnHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0;
+ }
+ do
+ {
+ _Format( aAccess.GetPara() );
+ if( pFtnBoss && nFtnHeight )
+ {
+ const SwFtnContFrm* pCont = pFtnBoss->FindFtnCont();
+ SwTwips nNewHeight = pCont ? (pCont->Frm().*fnRect->fnGetHeight)() : 0;
+ // If we lost some footnotes, we may have more space
+ // for our main text, so we have to format again ...
+ if( nNewHeight < nFtnHeight )
+ nFtnHeight = nNewHeight;
+ else
+ break;
+ }
+ else
+ break;
+ } while ( pFtnBoss );
+ if( bOrphan )
+ {
+ ValidateFrm();
+ SetWidow( sal_False );
+ }
+ }
+ if( IsEmptyMaster() )
+ {
+ SwFrm* pPre = GetPrev();
+ if( pPre &&
+ // --> FME 2004-07-22 #i10826# It's the first, it cannot keep!
+ pPre->GetIndPrev() &&
+ // <--
+ pPre->GetAttrSet()->GetKeep().GetValue() )
+ {
+ pPre->InvalidatePos();
+ }
+ }
+ }
+
+ ChgThisLines();
+
+ // the PrepMustFit should not survive a Format operation
+ SwParaPortion *pPara = GetPara();
+ if ( pPara )
+ pPara->SetPrepMustFit( sal_False );
+
+#if OSL_DEBUG_LEVEL > 1
+ // Hier ein Instrumentarium, um ungewoehnlichen Master/Follow-Kombinationen,
+ // insbesondere bei Fussnoten, auf die Schliche zu kommen
+ if( IsFollow() || GetFollow() )
+ {
+ SwTxtFrm *pTmpFrm = IsFollow() ? FindMaster() : this;
+ const SwPageFrm *pTmpPage = pTmpFrm->FindPageFrm();
+ MSHORT nPgNr = pTmpPage->GetPhyPageNum();
+ MSHORT nLast;
+ MSHORT nDummy = 0; // nur zum Breakpoint setzen
+ while( pTmpFrm->GetFollow() )
+ {
+ pTmpFrm = pTmpFrm->GetFollow();
+ nLast = nPgNr;
+ pTmpPage = pTmpFrm->FindPageFrm();
+ nPgNr = pTmpPage->GetPhyPageNum();
+ if( nLast > nPgNr )
+ ++nDummy; // schon fast eine Assertion wert
+ else if( nLast == nPgNr )
+ ++nDummy; // bei Spalten voellig normal, aber sonst!?
+ else if( nLast < nPgNr - 1 )
+ ++nDummy; // kann schon mal temporaer vorkommen
+ }
+ }
+#endif
+
+ CalcBaseOfstForFly();
+ // OD 2004-03-17 #i11860#
+ _CalcHeightOfLastLine();
+}
+
+/*************************************************************************
+ * SwTxtFrm::FormatQuick()
+ *
+ * bForceQuickFormat is set if GetFormatted() has been called during the
+ * painting process. Actually I cannot imagine a situation which requires
+ * a full formatting of the paragraph during painting, on the other hand
+ * a full formatting can cause the invalidation of other layout frames,
+ * e.g., if there are footnotes in this paragraph, and invalid layout
+ * frames will not calculated during the painting. So I actually want to
+ * avoid a formatting during painting, but since I'm a coward, I'll only
+ * force the quick formatting in the situation of issue i29062.
+ *************************************************************************/
+
+sal_Bool SwTxtFrm::FormatQuick( bool bForceQuickFormat )
+{
+ OSL_ENSURE( ! IsVertical() || ! IsSwapped(),
+ "SwTxtFrm::FormatQuick with swapped frame" );
+
+#if OSL_DEBUG_LEVEL > 1
+ const XubString aXXX = GetTxtNode()->GetTxt();
+ const SwTwips nDbgY = Frm().Top();
+ (void)nDbgY;
+ // nStopAt laesst sich vom CV bearbeiten.
+ static MSHORT nStopAt = 0;
+ if( nStopAt == GetFrmId() )
+ {
+ int i = GetFrmId();
+ (void)i;
+ }
+#endif
+
+ if( IsEmpty() && FormatEmpty() )
+ return sal_True;
+
+ // Wir sind sehr waehlerisch:
+ if( HasPara() || IsWidow() || IsLocked()
+ || !GetValidSizeFlag() ||
+ ( ( IsVertical() ? Prt().Width() : Prt().Height() ) && IsHiddenNow() ) )
+ return sal_False;
+
+ SwTxtLineAccess aAccess( this );
+ SwParaPortion *pPara = aAccess.GetPara();
+ if( !pPara )
+ return sal_False;
+
+ SwFrmSwapper aSwapper( this, sal_True );
+
+ SwTxtFrmLocker aLock(this);
+ SwTxtFormatInfo aInf( this, sal_False, sal_True );
+ if( 0 != aInf.MaxHyph() ) // 27483: MaxHyphen beachten!
+ return sal_False;
+
+ SwTxtFormatter aLine( this, &aInf );
+
+ // DropCaps sind zu kompliziert...
+ if( aLine.GetDropFmt() )
+ return sal_False;
+
+ xub_StrLen nStart = GetOfst();
+ const xub_StrLen nEnd = GetFollow()
+ ? GetFollow()->GetOfst() : aInf.GetTxt().Len();
+ do
+ {
+ nStart = aLine.FormatLine( nStart );
+ if( aInf.IsNewLine() || (!aInf.IsStop() && nStart < nEnd) )
+ aLine.Insert( new SwLineLayout() );
+ } while( aLine.Next() );
+
+ // Last exit: die Hoehen muessen uebereinstimmen.
+ Point aTopLeft( Frm().Pos() );
+ aTopLeft += Prt().Pos();
+ const SwTwips nNewHeight = aLine.Y() + aLine.GetLineHeight();
+ const SwTwips nOldHeight = aTopLeft.Y() + Prt().Height();
+
+ if( !bForceQuickFormat && nNewHeight != nOldHeight && !IsUndersized() )
+ {
+ // Achtung: Durch FormatLevel==12 kann diese Situation auftreten, don't panic!
+ const xub_StrLen nStrt = GetOfst();
+ _InvalidateRange( SwCharRange( nStrt, nEnd - nStrt) );
+ return sal_False;
+ }
+
+ if( pFollow && nStart != ((SwTxtFrm*)pFollow)->GetOfst() )
+ return sal_False; // kann z.B. durch Orphans auftreten (35083,35081)
+
+ // Geschafft, wir sind durch ...
+
+ // Repaint setzen
+ pPara->GetRepaint()->Pos( aTopLeft );
+ pPara->GetRepaint()->SSize( Prt().SSize() );
+
+ // Reformat loeschen
+ *(pPara->GetReformat()) = SwCharRange();
+ *(pPara->GetDelta()) = 0;
+
+ return sal_True;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */