/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
/// Return value tells whether the Frame should be moved. bool SwContentFrame::ShouldBwdMoved( SwLayoutFrame *pNewUpper, bool & )
{ if ( SwFlowFrame::IsMoveBwdJump() || !IsPrevObjMove() )
{ // Floating back a frm uses a bit of time unfortunately. // The most common case is the following: The Frame wants to float to // somewhere where the FixSize is the same that the Frame itself has already. // In that case it's pretty easy to check if the Frame has enough space // for its VarSize. If this is NOT the case, we already know that // we don't need to move. // The Frame checks itself whether it has enough space - respecting the fact // that it could possibly split itself if needed. // If, however, the FixSize differs from the Frame or Flys are involved // (either in the old or the new position), checking is pointless, // and we have to move the Frame just to see what happens - if there's // some space available to do it, that is.
// The FixSize of the containers of Contents is always the width.
// If we moved more than one sheet back (for example jumping over empty // pages), we have to move either way. Otherwise, if the Frame doesn't fit // into the page, empty pages wouldn't be respected anymore.
sal_uInt8 nMoveAnyway = 0;
SwPageFrame * const pNewPage = pNewUpper->FindPageFrame();
SwPageFrame *pOldPage = FindPageFrame();
if ( SwFlowFrame::IsMoveBwdJump() ) returntrue;
if( IsInFootnote() && IsInSct() )
{
SwFootnoteFrame* pFootnote = FindFootnoteFrame();
SwSectionFrame* pMySect = pFootnote->FindSctFrame(); if( pMySect && pMySect->IsFootnoteLock() )
{
SwSectionFrame *pSect = pNewUpper->FindSctFrame(); while( pSect && pSect->IsInFootnote() )
pSect = pSect->GetUpper()->FindSctFrame();
OSL_ENSURE( pSect, "Escaping footnote" ); if( pSect != pMySect ) returnfalse;
}
}
SwRectFnSet aRectFnSet(this);
SwRectFnSet fnRectX(pNewUpper); if( std::abs( fnRectX.GetWidth(pNewUpper->getFramePrintArea()) -
aRectFnSet.GetWidth(GetUpper()->getFramePrintArea()) ) > 1 ) { // In this case, only a WouldFit_ with test move is possible
nMoveAnyway = 2;
}
// Do *not* move backward, if <nMoveAnyway> equals 3 and no space is left in new upper.
nMoveAnyway |= BwdMoveNecessary( pOldPage, getFrameArea() );
{ const IDocumentSettingAccess& rIDSA = pNewPage->GetFormat()->getIDocumentSettingAccess();
SwTwips nSpace = 0;
SwRect aRect( pNewUpper->getFramePrintArea() );
aRect.Pos() += pNewUpper->getFrameArea().Pos(); const SwFrame *pPrevFrame = pNewUpper->Lower(); while ( pPrevFrame )
{
SwTwips nNewTop = fnRectX.GetBottom(pPrevFrame->getFrameArea()); // Consider lower spacing of last frame in a table cell
{ // Check if last frame is inside table and if it includes its lower spacing. if ( !pPrevFrame->GetNext() && pPrevFrame->IsInTab() &&
rIDSA.get(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS) )
{ const SwFrame* pLastFrame = pPrevFrame; // if last frame is a section, take its last content if ( pPrevFrame->IsSctFrame() )
{
pLastFrame = static_cast<const SwSectionFrame*>(pPrevFrame)->FindLastContent(); if ( pLastFrame &&
pLastFrame->FindTabFrame() != pPrevFrame->FindTabFrame() )
{
pLastFrame = pLastFrame->FindTabFrame();
}
}
//determine space left in new upper frame
nSpace = fnRectX.GetHeight(aRect); const SwViewShell *pSh = pNewUpper->getRootFrame()->GetCurrShell(); if ( IsInFootnote() ||
(pSh && pSh->GetViewOptions()->getBrowseMode()) ||
pNewUpper->IsCellFrame() ||
( pNewUpper->IsInSct() && ( pNewUpper->IsSctFrame() ||
( pNewUpper->IsColBodyFrame() &&
!pNewUpper->GetUpper()->GetPrev() &&
!pNewUpper->GetUpper()->GetNext() ) ) ) )
nSpace += pNewUpper->Grow( LONG_MAX, true );
auto pTextFrame = DynCastTextFrame(); if (pTextFrame)
{ // This is a text frame. Check if it's an anchor for a non-last element in a split // fly chain. If so, we can only move back in case not only the text frame itself, // but also its fly fits nSpace.
SwFlyAtContentFrame* pFly = pTextFrame->HasNonLastSplitFlyDrawObj(); if (pFly && pFly->getFrameArea().Height() > nSpace)
{ returnfalse;
}
}
if ( nMoveAnyway < 3 )
{ if (nSpace || IsHiddenNow())
{ // Do not notify footnotes which are stuck to the paragraph: // This would require extremely confusing code, taking into // account the widths // and Flys, that in turn influence the footnotes, ...
// WouldFit_ can only be used if the width is the same and // ONLY self-anchored Flys are present.
// WouldFit_ can also be used if ONLY Flys anchored // somewhere else are present. // In this case, the width doesn't even matter, // because we're running a TestFormat in the new upper. const sal_uInt8 nBwdMoveNecessaryResult =
BwdMoveNecessary( pNewPage, aRect); constbool bObjsInNewUpper( nBwdMoveNecessaryResult == 2 ||
nBwdMoveNecessaryResult == 3 );
return WouldFit_( nSpace, pNewUpper, nMoveAnyway == 2,
bObjsInNewUpper );
} // It's impossible for WouldFit_ to return a usable result if // we have a fresh multi-column section - so we really have to // float back unless there is no space. return pNewUpper->IsInSct() && pNewUpper->IsColBodyFrame() &&
!fnRectX.GetWidth(pNewUpper->getFramePrintArea()) &&
( pNewUpper->GetUpper()->GetPrev() ||
pNewUpper->GetUpper()->GetNext() );
}
// Check for space left in new upper return nSpace != 0 || IsHiddenNow();
}
} returnfalse;
}
// Calc methods
// Two little friendships form a secret society inlinevoid PrepareLock( SwFlowFrame *pTab )
{
pTab->LockJoin();
} inlinevoid PrepareUnlock( SwFlowFrame *pTab )
{
pTab->UnlockJoin();
}
// hopefully, one day this function simply will return 'false' staticbool lcl_IsCalcUpperAllowed( const SwFrame& rFrame )
{ return !rFrame.GetUpper()->IsSctFrame() &&
!rFrame.GetUpper()->IsFooterFrame() && // No format of upper Writer fly frame
!rFrame.GetUpper()->IsFlyFrame() &&
!( rFrame.GetUpper()->IsTabFrame() && rFrame.GetUpper()->GetUpper()->IsInTab() ) &&
!( rFrame.IsTabFrame() && rFrame.GetUpper()->IsInTab() );
}
/** Prepares the Frame for "formatting" (MakeAll()). * * This method serves to save stack space: To calculate the position of the Frame * we have to make sure that the positions of Upper and Prev respectively are * valid. This may require a recursive call (a loop would be quite expensive, * as it's not required very often). * * Every call of MakeAll requires around 500 bytes on the stack - you easily * see where this leads to. This method requires only a little bit of stack * space, so the recursive call should not be a problem here. * * Another advantage is that one nice day, this method and with it the * formatting of predecessors could be avoided. Then it could probably be * possible to jump "quickly" to the document's end. * * @see MakeAll()
*/ void SwFrame::PrepareMake(vcl::RenderContext* pRenderContext)
{
StackHack aHack; if ( GetUpper() )
{
SwFrameDeleteGuard aDeleteGuard(this); if ( lcl_IsCalcUpperAllowed( *this ) )
GetUpper()->Calc(pRenderContext);
OSL_ENSURE( GetUpper(), ":-( Layout unstable (Upper gone)." ); if ( !GetUpper() ) return;
if ( bTab )
{
pThis = static_cast<SwTabFrame*>(this);
bOldTabLock = static_cast<SwTabFrame*>(this)->IsJoinLocked();
::PrepareLock( static_cast<SwTabFrame*>(this) );
bFoll = pThis->IsFollow();
} elseif( IsSctFrame() )
{
pThis = static_cast<SwSectionFrame*>(this);
bFoll = pThis->IsFollow();
bNoSect = false;
} elseif ( bCnt )
{
bFoll = pThis->IsFollow(); if ( bFoll && GetPrev() )
{ // Do not follow the chain when we need only one instance const SwTextFrame* pMaster = static_cast<SwContentFrame*>(this)->FindMaster(); if ( pMaster && pMaster->IsLocked() )
{
MakeAll(pRenderContext); return;
}
}
}
// There is no format of previous frame, if current frame is a table // frame and its previous frame wants to keep with it. bool bFormatPrev{!bTab}; if (!bFormatPrev)
{
SwFrame const* pPrev{this}; do
{
pPrev = pPrev->GetPrev();
} while (pPrev && pPrev->IsHiddenNow());
bFormatPrev = pPrev && !pPrev->GetAttrSet()->GetKeep().GetValue();
} if ( bFormatPrev )
{
SwFrame *pFrame = GetUpper()->Lower(); while ( pFrame != this )
{
OSL_ENSURE( pFrame, ":-( Layout unstable (this not found)." ); if ( !pFrame ) return; //Oioioioi ...
if ( !pFrame->isFrameAreaDefinitionValid() )
{ // A small interference that hopefully improves on the stability: // If I'm Follow AND neighbor of a Frame before me, it would delete // me when formatting. This as you can see could easily become a // confusing situation that we want to avoid. if ( bFoll && pFrame->IsFlowFrame() &&
SwFlowFrame::CastFlowFrame(pFrame)->IsAnFollow( pThis ) ) break;
boolconst isLast(pFrame->GetNext() == this); // note: this seems obvious but does *not* hold, a MakeAll() // could move more than 1 frame backwards! // that's why FindNext() is used below // assert(pFrame->GetUpper() == GetUpper());
pFrame->MakeAll(pRenderContext); if( IsSctFrame() && !static_cast<SwSectionFrame*>(this)->GetSection() ) break; if (isLast && pFrame->GetUpper() != GetUpper())
{
assert(GetUpper()->Lower() == this // empty section frames are created all the time...
|| GetUpper()->Lower()->IsSctFrame() // tab frame/section frame may split multiple times
|| ( SwFlowFrame::CastFlowFrame(pFrame)
&& SwFlowFrame::CastFlowFrame(GetUpper()->Lower())
&& SwFlowFrame::CastFlowFrame(pFrame)->IsAnFollow(
SwFlowFrame::CastFlowFrame(GetUpper()->Lower()))
&& (GetUpper()->Lower()->GetNext() == this // if it's more than 10 pages long...
|| (SwFlowFrame::CastFlowFrame(GetUpper()->Lower())->GetFollow()
== SwFlowFrame::CastFlowFrame(GetUpper()->Lower()->GetNext())
&& GetUpper()->Lower()->GetNext()->GetNext() == this) // pre-existing empty section frames may end up between them...
|| GetUpper()->Lower()->GetNext()->IsSctFrame()))); break; // tdf#119109 frame was moved backward, prevent // FindNext() returning a frame inside this if
} // this is a table!
} // With ContentFrames, the chain may be broken while walking through // it. Therefore we have to figure out the next frame in a bit more // complicated way. However, I'll HAVE to get back to myself // sometime again.
pFrame = pFrame->FindNext();
// If we started out in a SectionFrame, it might have happened that // we landed in a Section Follow via the MakeAll calls. // FindNext only gives us the SectionFrame, not it's content - we // won't find ourselves anymore! if( bNoSect && pFrame && pFrame->IsSctFrame() )
{
SwFrame* pCnt = static_cast<SwSectionFrame*>(pFrame)->ContainsAny(); if( pCnt )
pFrame = pCnt;
}
}
OSL_ENSURE( GetUpper(), "Layout unstable (Upper gone II)." ); if ( !GetUpper() ) return;
if ( lcl_IsCalcUpperAllowed( *this ) )
GetUpper()->Calc(pRenderContext);
SwFrame *pFrame = GetUpper()->Lower(); while ( pFrame != this )
{
OSL_ENSURE( pFrame, ":-( Layout unstable (this not found)." ); if ( !pFrame ) return; //Oioioioi ...
if ( !pFrame->isFrameAreaDefinitionValid() )
{ // A small interference that hopefully improves on the stability: // If I'm Follow AND neighbor of a Frame before me, it would delete // me when formatting. This as you can see could easily become a // confusing situation that we want to avoid. if ( bFoll && pFrame->IsFlowFrame() &&
SwFlowFrame::CastFlowFrame(pFrame)->IsAnFollow( pThis ) ) break;
boolconst isLast(pFrame->GetNext() == this);
pFrame->MakeAll(getRootFrame()->GetCurrShell()->GetOut()); if (isLast && pFrame->GetUpper() != GetUpper())
{
assert(GetUpper()->Lower() == this // empty section frames are created all the time...
|| GetUpper()->Lower()->IsSctFrame() // tab frame/section frame may split multiple times
|| ( SwFlowFrame::CastFlowFrame(pFrame)
&& SwFlowFrame::CastFlowFrame(GetUpper()->Lower())
&& SwFlowFrame::CastFlowFrame(pFrame)->IsAnFollow(
SwFlowFrame::CastFlowFrame(GetUpper()->Lower()))
&& (GetUpper()->Lower()->GetNext() == this // if it's more than 10 pages long...
|| (SwFlowFrame::CastFlowFrame(GetUpper()->Lower())->GetFollow()
== SwFlowFrame::CastFlowFrame(GetUpper()->Lower()->GetNext())
&& GetUpper()->Lower()->GetNext()->GetNext() == this) // pre-existing empty section frames may end up between them...
|| GetUpper()->Lower()->GetNext()->IsSctFrame()))); break; // tdf#119109 frame was moved backward, prevent // FindNext() returning a frame inside this if
} // this is a table!
} // With ContentFrames, the chain may be broken while walking through // it. Therefore we have to figure out the next frame in a bit more // complicated way. However, I'll HAVE to get back to myself // sometime again.
pFrame = pFrame->FindNext(); if( bNoSect && pFrame && pFrame->IsSctFrame() )
{
SwFrame* pCnt = static_cast<SwSectionFrame*>(pFrame)->ContainsAny(); if( pCnt )
pFrame = pCnt;
}
}
OSL_ENSURE( GetUpper(), "Layout unstable (Upper gone II)." ); if ( !GetUpper() ) return;
// Here we return GetPrev(); however we will ignore empty SectionFrames static SwFrame* lcl_Prev( SwFrame* pFrame, bool bSectPrv = true )
{
SwFrame* pRet = pFrame->GetPrev(); if( !pRet && pFrame->GetUpper() && pFrame->GetUpper()->IsSctFrame() &&
bSectPrv && !pFrame->IsColumnFrame() )
pRet = pFrame->GetUpper()->GetPrev(); while( pRet && pRet->IsSctFrame() &&
!static_cast<SwSectionFrame*>(pRet)->GetSection() )
pRet = pRet->GetPrev(); return pRet;
}
static SwFrame* lcl_NotHiddenPrev( SwFrame* pFrame )
{
SwFrame *pRet = pFrame; do
{
pRet = lcl_Prev( pRet );
} while ( pRet && pRet->IsHiddenNow() ); return pRet;
}
void SwFrame::MakePos()
{ if ( isFrameAreaPositionValid() ) return;
setFrameAreaPositionValid(true); bool bUseUpper = false;
SwFrame* pPrv = lcl_Prev( this ); if ( pPrv &&
( !pPrv->IsContentFrame() ||
( static_cast<SwContentFrame*>(pPrv)->GetFollow() != this ) )
)
{ if ( !StackHack::IsLocked() &&
( !IsInSct() || IsSctFrame() ) &&
!pPrv->IsSctFrame() &&
!pPrv->GetAttrSet()->GetKeep().GetValue()
)
{ // tdf#151866 pPrv may MoveBwd and if this is a newly created // section frame then CheckPageDescs() may delete the whole page!
SwFrameDeleteGuard g(this); // Prevent it.
pPrv->Calc(getRootFrame()->GetCurrShell() ? getRootFrame()->GetCurrShell()->GetOut() : nullptr); // This may cause Prev to vanish!
} elseif ( pPrv->getFrameArea().Top() == 0 )
{
bUseUpper = true;
}
}
// cells may now leave their uppers if( aRectFnSet.IsVert() && SwFrameType::Cell & nMyType )
{
aFrm.Pos().setX(aFrm.Pos().getX() - aFrm.Width() + pPrv->getFrameArea().Width());
}
} elseif( aRectFnSet.IsVert() && FRM_NOTE_VERT & nMyType )
{ if ( aRectFnSet.IsVertL2R() )
{
aFrm.Pos().setX(aFrm.Pos().getX() + pPrv->getFrameArea().Width());
} else
{
aFrm.Pos().setX(aFrm.Pos().getX() - aFrm.Width());
}
} else
{
aFrm.Pos().setY(aFrm.Pos().getY() + pPrv->getFrameArea().Height());
}
} elseif ( GetUpper() )
{ // If parent frame is a footer frame and its <ColLocked()>, then // do *not* calculate it. // NOTE: Footer frame is <ColLocked()> during its // <FormatSize(..)>, which is called from <Format(..)>, which // is called from <MakeAll()>, which is called from <Calc()>. // #i56850# // - no format of upper Writer fly frame, which is anchored // at-paragraph or at-character. if ( !GetUpper()->IsTabFrame() &&
!( IsTabFrame() && GetUpper()->IsInTab() ) &&
!GetUpper()->IsSctFrame() &&
!dynamic_cast<SwFlyAtContentFrame*>(GetUpper()) &&
!( GetUpper()->IsFooterFrame() &&
GetUpper()->IsColLocked() )
)
{
GetUpper()->Calc(getRootFrame()->GetCurrShell()->GetOut());
}
pPrv = lcl_Prev( this, false ); if ( !bUseUpper && pPrv )
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aFrm.Pos( pPrv->getFrameArea().Pos() );
const SwRect aOldRect( getFrameArea() ); // Adjust root size const SwLayNotify aNotify( this ); // takes care of the notification in the dtor
std::optional<SwBorderAttrAccess> oAccess; const SwBorderAttrs*pAttrs = nullptr;
while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
{ if ( !isFrameAreaPositionValid() )
{
setFrameAreaPositionValid(true); // positioning of the pages is taken care of by the root frame
}
if ( !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
{ if ( IsEmptyPage() )
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aFrm.Width( 0 );
aFrm.Height( 0 );
SwLayoutFrame *pBody = FindBodyCont(); if ( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrame() )
{ // Columns have a fixed height
aFrm.Height( pAttrs->GetSize().Height() );
} else
{ // In pages without columns, the content defines the size.
tools::Long nBot = GetContentHeight(nTop, nBottom);
// #i35143# - If second page frame // exists, the first page doesn't have to fulfill the // visible area. if ( !GetPrev() && !GetNext() )
{
nBot = std::max( nBot, pSh->VisArea().Height() );
} // #i35143# - Assure, that the page // doesn't exceed the defined browse height.
aFrm.Height( std::min( nBot, BROWSE_HEIGHT ) );
}
}
setFrameAreaSizeValid(true);
setFramePrintAreaValid(true); continue;
} elseif (pSh && pSh->GetViewOptions()->IsWhitespaceHidden())
{
tools::Long height = 0;
SwLayoutFrame *pBody = FindBodyCont();
SwTwips nFullBodyHeight = pAttrs->GetSize().Height() - pAttrs->CalcTop() - pAttrs->CalcBottom(); if (pRootFrame->GetLastPage() == this)
{ // Last page is only reduced by the top/bottom margin, the body frame height // is not reduced.
height = nFullBodyHeight;
} elseif ( pBody && pBody->Lower() && pBody->Lower()->IsColumnFrame() )
{ // Columns have a fixed height
height = pAttrs->GetSize().Height();
} else
{ // No need for borders.
height = GetContentHeight(0, 0); if (height > nFullBodyHeight)
{ // Content height would be larger than the show-whitespace body height, // limit it.
height = nFullBodyHeight;
}
}
// Fallback to default formatting. Especially relevant // when loading a doc when Hide Whitespace is enabled. // Heights are zero initially.
}
// Set FixSize. For pages, this is not done from Upper, but from // the attribute. //FIXME: This resets the size when (isFrameAreaSizeValid() && !isFramePrintAreaValid()).
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aFrm.SSize( pAttrs->GetSize() );
}
Format( pRenderContext, pAttrs );
}
}
} //while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
OSL_ENSURE( !GetUpper() || GetUpper()->getFramePrintArea().Width() >= getFrameArea().Width(), "Upper (Root) must be wide enough to contain the widest page");
}
while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
{ if ( !isFrameAreaPositionValid() )
{
MakePos();
}
if (IsHiddenNow())
{
MakeValidZeroHeight();
}
if ( GetUpper() )
{ // NEW TABLES if ( IsLeaveUpperAllowed() )
{ if ( !isFrameAreaSizeValid() )
{
setFramePrintAreaValid(false);
}
} else
{ if ( !isFrameAreaSizeValid() )
{ // Set FixSize; VarSize is set by Format() after calculating the PrtArea
setFramePrintAreaValid(false);
bool SwFrame::IsCollapse() const
{ if (!IsTextFrame()) returnfalse;
const SwTextFrame *pTextFrame = static_cast<const SwTextFrame*>(this); const SwTextNode *pTextNode = pTextFrame->GetTextNodeForParaProps(); // TODO this SwTextNode function is pointless and should be merged in here return pTextFrame->GetText().isEmpty() && pTextNode && pTextNode->IsCollapse();
}
const SwDoc& rDoc = pTextFrame->GetDoc(); const IDocumentSettingAccess& rIDSA = rDoc.getIDocumentSettingAccess(); if (!rIDSA.get(DocumentSettingId::TAB_OVER_SPACING) || rIDSA.get(DocumentSettingId::TAB_OVER_MARGIN))
{ // Writer or Word Word <= 2010 style: upper margin is never ignored. returnfalse;
}
if (IsInFly())
{ // Not in a page's body. returnfalse;
}
// Word >= 2013 style: when we're at the top of the page's body, but not on the first page, then // ignore the upper margin for paragraphs. if (GetPrev() || !GetUpper() || !GetUpper()->IsBodyFrame())
{ returnfalse;
}
// Avoid the ignore after applying a new page style (but do it after page breaks). const SwTextNode* pTextNode = pTextFrame->GetTextNodeForParaProps(); if (pTextNode)
{ if (pTextNode->HasSwAttrSet() && pTextNode->GetSwAttrSet().HasItem(RES_PAGEDESC))
{ returnfalse;
}
}
nUpper = -( aRectFnSet.GetHeight(getFrameArea()) );
} else
{ // Simplification: ContentFrames are always variable in height!
// At the FixSize, the surrounding Frame enforces the size; // the borders are simply subtracted. const tools::Long nLeft = rAttrs.CalcLeft( this ); const tools::Long nRight = rAttrs.CalcRight( this );
aRectFnSet.SetXMargins( *this, nLeft, nRight );
SwViewShell *pSh = getRootFrame()->GetCurrShell();
SwTwips nWidthArea; if( pSh && 0!=(nWidthArea=aRectFnSet.GetWidth(pSh->VisArea())) &&
GetUpper()->IsPageBodyFrame() && // but not for BodyFrames in Columns
pSh->GetViewOptions()->getBrowseMode() )
{ // Do not protrude the edge of the visible area. The page may be // wider, because there may be objects with excess width // (RootFrame::ImplCalcBrowseWidth())
tools::Long nMinWidth = 0;
for (size_t i = 0; GetDrawObjs() && i < GetDrawObjs()->size(); ++i)
{ // #i28701# - consider changed type of // <SwSortedObjs> entries
SwAnchoredObject* pObj = (*GetDrawObjs())[i]; const SwFrameFormat* pFormat = pObj->GetFrameFormat(); constbool bFly = pObj->DynCastFlyFrame() != nullptr; if ((bFly && (FAR_AWAY == pObj->GetObjRect().Width()))
|| pFormat->GetFrameSize().GetWidthPercent())
{ continue;
}
if ( aRectFnSet.GetWidth(getFramePrintArea()) <= MINLAY )
{ // The PrtArea should already be at least MINLAY wide, matching the // minimal values of the UI
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
aRectFnSet.SetWidth( aPrt, std::min( tools::Long(MINLAY), aRectFnSet.GetWidth(getFrameArea()) ) );
SwTwips nTmp = aRectFnSet.GetWidth(getFrameArea()) - aRectFnSet.GetWidth(aPrt);
// The following rules apply for VarSize: // 1. The first entry of a chain has no top border // 2. There is never a bottom border // 3. The top border is the maximum of the distance // of Prev downwards and our own distance upwards // Those three rules apply when calculating spacings // that are given by UL- and LRSpace. There might be a spacing // in all directions however; this may be caused by borders // and / or shadows. // 4. The spacing for TextFrames corresponds to the interline lead, // at a minimum.
nUpper += nLower;
nUpper -= aRectFnSet.GetHeight(getFrameArea()) - aRectFnSet.GetHeight(getFramePrintArea());
} // If there's a difference between old and new size, call Grow() or // Shrink() respectively. if ( nUpper )
{ if ( nUpper > 0 )
GrowFrame( nUpper ); else
ShrinkFrame( -nUpper );
}
}
// takes care of the notification in the dtor
std::optional<SwContentNotify> oNotify( std::in_place, this );
// as long as bMakePage is true, a new page can be created (exactly once) bool bMakePage = true; // bMovedBwd gets set to true when the frame flows backwards bool bMovedBwd = false; // as long as bMovedFwd is false, the Frame may flow backwards (until // it has been moved forward once) bool bMovedFwd = false;
sal_Bool bFormatted = false; // For the widow/orphan rules, we encourage the // last ContentFrame of a chain to format. This only // needs to happen once. Every time the Frame is // moved, the flag will have to be reset. bool bMustFit = false; // Once the emergency brake is pulled, // no other prepares will be triggered bool bFitPromise = false; // If a paragraph didn't fit, but promises // with WouldFit that it would adjust accordingly, // this flag is set. If it turns out that it // didn't keep it's promise, we can act in a // controlled fashion. constbool bFly = IsInFly(); constbool bTab = IsInTab(); constbool bFootnote = IsInFootnote(); constbool bSct = IsInSct();
Point aOldFramePos; // This is so we can compare with the last pos
Point aOldPrtPos; // and determine whether it makes sense to Prepare
SwBorderAttrAccess aAccess( SwFrame::GetCache(), this ); const SwBorderAttrs &rAttrs = *aAccess.Get();
// #i28701# - move master forward, if it has to move, // because of its object positioning. if (!IsFollow())
{
sal_uInt32 nToPageNum = 0; constbool bMoveFwdByObjPos = SwLayouter::FrameMovedFwdByObjPos(
GetAttrSet()->GetDoc(),
*static_cast<SwTextFrame*>(this),
nToPageNum ); // #i58182# // Also move a paragraph forward, which is the first one inside a table cell. if ( bMoveFwdByObjPos &&
FindPageFrame()->GetPhyPageNum() < nToPageNum &&
( lcl_Prev( this ) ||
GetUpper()->IsCellFrame() ||
( GetUpper()->IsSctFrame() &&
GetUpper()->GetUpper()->IsCellFrame() ) ) &&
IsMoveable() )
{
bMovedFwd = true;
MoveFwd( bMakePage, false );
}
} elseif (auto* prev = lcl_Prev(this); prev && IsMoveable())
{ // If a Follow sits next to its Master and doesn't fit, we know it can be moved right now.
bMovedFwd = true; // If follow frame is in table, its master will be the last in the // current table cell. Thus, invalidate the printing area of the master. if ( IsInTab() )
{
prev->InvalidatePrt();
}
MoveFwd( bMakePage, false );
}
// Check footnote content for forward move. // If a content of a footnote is on a prior page/column as its invalid // reference, it can be moved forward. if ( bFootnote && !isFrameAreaPositionValid() )
{
SwFootnoteFrame* pFootnote = FindFootnoteFrame();
SwContentFrame* pRefCnt = pFootnote ? pFootnote->GetRef() : nullptr;
if ( pRefCnt && !pRefCnt->isFrameAreaDefinitionValid() )
{
SwFootnoteBossFrame* pFootnoteBossOfFootnote = pFootnote->FindFootnoteBossFrame();
SwFootnoteBossFrame* pFootnoteBossOfRef = pRefCnt->FindFootnoteBossFrame(); //<loop of movefwd until condition held or no move> if ( pFootnoteBossOfFootnote && pFootnoteBossOfRef &&
pFootnoteBossOfFootnote != pFootnoteBossOfRef &&
pFootnoteBossOfFootnote->IsBefore( pFootnoteBossOfRef ) )
{
bMovedFwd = true;
MoveFwd( bMakePage, false );
}
}
}
bool bMoveable = IsMoveable(); if (bMoveable)
{
SwFrame *pPre = GetIndPrev(); if ( CheckMoveFwd( bMakePage, bKeep, bMovedBwd ) )
{
aRectFnSet.Refresh(this);
bMovedFwd = true; if ( bMovedBwd )
{ // While flowing back, the Upper was encouraged to // completely re-paint itself. We can skip this now after // flowing back and forth.
GetUpper()->ResetCompletePaint(); // The predecessor was invalidated, so this is obsolete as well now.
assert(pPre); if ((pPre == pMoveBwdPre && isMoveBwdPreValid) && !pPre->IsSctFrame())
::ValidateSz( pPre );
}
bMoveable = IsMoveable();
}
}
if (isHiddenNow)
{ // call this after MakePos() otherwise Shrink may not work
MakeValidZeroHeight();
}
//Set FixSize. VarSize is being adjusted by Format(). if ( !isFrameAreaSizeValid() )
{
assert(!isHiddenNow); // hidden frame must not be formatted // invalidate printing area flag, if the following conditions are hold: // - current frame width is 0. // - current printing area width is 0. // - frame width is adjusted to a value greater than 0. // - printing area flag is true. // Thus, it's assured that the printing area is adjusted, if the // frame area width changes its width from 0 to something greater // than 0. // Note: A text frame can be in such a situation, if the format is // triggered by method call <SwCursorShell::SetCursor()> after // loading the document. const SwTwips nNewFrameWidth = aRectFnSet.GetWidth(GetUpper()->getFramePrintArea());
// When a lower of a vertically aligned fly frame changes its size we need to recalculate content pos. if( GetUpper() && GetUpper()->IsFlyFrame() &&
GetUpper()->GetFormat()->GetTextVertAdjust().GetValue() != SDRTEXTVERTADJUST_TOP )
{ static_cast<SwFlyFrame*>(GetUpper())->InvalidateContentPos();
GetUpper()->SetCompletePaint();
}
} if ( !isFramePrintAreaValid() )
{
assert(!isHiddenNow); // hidden frame must not be formatted const tools::Long nOldW = aRectFnSet.GetWidth(getFramePrintArea()); // #i34730# - keep current frame height const SwTwips nOldH = aRectFnSet.GetHeight(getFrameArea());
MakePrtArea( rAttrs ); if ( nOldW != aRectFnSet.GetWidth(getFramePrintArea()) )
Prepare( PrepareHint::FixSizeChanged ); // #i34730# - check, if frame height has changed. // If yes, send a PrepareHint::AdjustSizeWithoutFormatting and invalidate the size flag to // force a format. The format will check in its method // <SwTextFrame::CalcPreps()>, if the already formatted lines still // fit and if not, performs necessary actions. // #i40150# - no check, if frame is undersized. if ( isFrameAreaSizeValid() && !IsUndersized() && nOldH != aRectFnSet.GetHeight(getFrameArea()) )
{ // #115759# - no PrepareHint::AdjustSizeWithoutFormatting and size // invalidation, if height decreases only by the additional // lower space as last content of a table cell and an existing // follow containing one line exists. const SwTwips nHDiff = nOldH - aRectFnSet.GetHeight(getFrameArea()); constbool bNoPrepAdjustFrame =
nHDiff > 0 && IsInTab() && GetFollow() &&
(1 == static_cast<SwTextFrame*>(GetFollow())->GetLineCount(TextFrameIndex(COMPLETE_STRING))
|| aRectFnSet.GetWidth(static_cast<SwTextFrame*>(GetFollow())->getFrameArea()) < 0) &&
GetFollow()->CalcAddLowerSpaceAsLastInTableCell() == nHDiff; if ( !bNoPrepAdjustFrame )
{
Prepare( PrepareHint::AdjustSizeWithoutFormatting );
setFrameAreaSizeValid(false);
}
}
}
// To make the widow and orphan rules work, we need to notify the ContentFrame. // Criteria: // - It needs to be movable (otherwise, splitting doesn't make sense) // - It needs to overlap with the lower edge of the PrtArea of the Upper if (!bMustFit && !isHiddenNow)
{ bool bWidow = true; const SwTwips nDeadLine = aRectFnSet.GetPrtBottom(*GetUpper()); if( bMoveable && !bFormatted &&
( GetFollow() || aRectFnSet.OverStep( getFrameArea(), nDeadLine ) ) )
{
Prepare( PrepareHint::WidowsOrphans, nullptr, false );
setFrameAreaSizeValid(false);
bWidow = false;
} if( aRectFnSet.GetPos(getFrameArea()) != aOldFramePos ||
aRectFnSet.GetPos(getFramePrintArea()) != aOldPrtPos )
{ // In this Prepare, an InvalidateSize_() might happen.
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.67 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.