/* -*- 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 .
*/
#include <hints.hxx>
#include <svl/itemiter.hxx>
#include <editeng/brushitem.hxx>
#include <fmtornt.hxx>
#include <pagefrm.hxx>
#include <section.hxx>
#include <rootfrm.hxx>
#include <anchoreddrawobject.hxx>
#include <fmtanchr.hxx>
#include <viewimp.hxx>
#include <viewopt.hxx>
#include <IDocumentSettingAccess.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <fesh.hxx>
#include <docsh.hxx>
#include <ftninfo.hxx>
#include <fmtclbl.hxx>
#include <fmtfsize.hxx>
#include <fmtpdsc.hxx>
#include <txtftn.hxx>
#include <fmtftn.hxx>
#include <fmtsrnd.hxx>
#include <ftnfrm.hxx>
#include <tabfrm.hxx>
#include <flyfrms.hxx>
#include <sectfrm.hxx>
#include <fmtclds.hxx>
#include <txtfrm.hxx>
#include <bodyfrm.hxx>
#include <cellfrm.hxx>
#include <dbg_lay.hxx>
#include <editeng/frmdiritem.hxx>
#include <sortedobjs.hxx>
// RotateFlyFrame3
#include <basegfx/matrix/b2dhommatrixtools.hxx>
using namespace ::com::sun::star;
SwFrameAreaDefinition::SwFrameAreaDefinition()
: maFrameArea(),
maFramePrintArea(),
mbFrameAreaPositionValid(false),
mbFrameAreaSizeValid(false),
mbFramePrintAreaValid(false)
{
}
SwFrameAreaDefinition::~SwFrameAreaDefinition()
{
}
void SwFrameAreaDefinition::setFrameAreaPositionValid(bool bNew)
{
if(mbFrameAreaPositionValid != bNew)
{
mbFrameAreaPositionValid = bNew;
}
}
void SwFrameAreaDefinition::setFrameAreaSizeValid(bool bNew)
{
if(mbFrameAreaSizeValid != bNew)
{
mbFrameAreaSizeValid = bNew;
}
}
void SwFrameAreaDefinition::setFramePrintAreaValid(bool bNew)
{
if(mbFramePrintAreaValid != bNew)
{
mbFramePrintAreaValid = bNew;
}
}
SwFrameAreaDefinition::FrameAreaWriteAccess::~FrameAreaWriteAccess()
{
if(mrTarget.maFrameArea != *this)
{
mrTarget.maFrameArea = *this;
}
}
SwFrameAreaDefinition::FramePrintAreaWriteAccess::~FramePrintAreaWriteAccess()
{
if(mrTarget.maFramePrintArea != *this)
{
mrTarget.maFramePrintArea = *this;
}
}
// RotateFlyFrame3 - Support for Transformations
basegfx::B2DHomMatrix SwFrameAreaDefinition::getFrameAreaTransformation() const
{
// default implementation hands out FrameArea (outer frame)
const SwRect& rFrameArea(getFrameArea());
return basegfx::utils::createScaleTranslateB2DHomMatrix(
rFrameArea.Width(), rFrameArea.Height(),
rFrameArea.Left(), rFrameArea.Top());
}
basegfx::B2DHomMatrix SwFrameAreaDefinition::getFramePrintAreaTransformation() const
{
// default implementation hands out FramePrintArea (outer frame)
// Take into account that FramePrintArea is relative to FrameArea
const SwRect& rFrameArea(getFrameArea());
const SwRect& rFramePrintArea(getFramePrintArea());
return basegfx::utils::createScaleTranslateB2DHomMatrix(
rFramePrintArea.Width(), rFramePrintArea.Height(),
rFramePrintArea.Left() + rFrameArea.Left(),
rFramePrintArea.Top() + rFrameArea.Top());
}
void SwFrameAreaDefinition::transform_translate(const Point& rOffset)
{
// RotateFlyFrame3: default is to change the FrameArea, FramePrintArea needs no
// change since it is relative to FrameArea
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
if (aFrm.Pos().X() != FAR_AWAY)
{
aFrm.Pos().AdjustX(rOffset.X() );
}
if (aFrm.Pos().Y() != FAR_AWAY)
{
aFrm.Pos().AdjustY(rOffset.Y() );
}
}
SwRect TransformableSwFrame::getUntransformedFrameArea() const
{
const basegfx::B2DHomMatrix& rSource(getLocalFrameAreaTransformation());
if(rSource.isIdentity())
{
return mrSwFrameAreaDefinition.getFrameArea();
}
else
{
basegfx::B2DVector aScale, aTranslate;
double fRotate, fShearX;
rSource.decompose(aScale, aTranslate, fRotate, fShearX);
const basegfx::B2DPoint aCenter(rSource * basegfx::B2DPoint(0.5, 0.5));
const basegfx::B2DVector aAbsScale(basegfx::absolute(aScale));
return SwRect(
basegfx::fround(aCenter.getX() - (0.5 * aAbsScale.getX())),
basegfx::fround(aCenter.getY() - (0.5 * aAbsScale.getY())),
basegfx::fround(aAbsScale.getX()),
basegfx::fround(aAbsScale.getY()));
}
}
SwRect TransformableSwFrame::getUntransformedFramePrintArea() const
{
const basegfx::B2DHomMatrix& rSource(getLocalFramePrintAreaTransformation());
if(rSource.isIdentity())
{
return mrSwFrameAreaDefinition.getFramePrintArea();
}
else
{
basegfx::B2DVector aScale, aTranslate;
double fRotate, fShearX;
rSource.decompose(aScale, aTranslate, fRotate, fShearX);
const basegfx::B2DPoint aCenter(rSource * basegfx::B2DPoint(0.5, 0.5));
const basegfx::B2DVector aAbsScale(basegfx::absolute(aScale));
const SwRect aUntransformedFrameArea(getUntransformedFrameArea());
return SwRect(
basegfx::fround(aCenter.getX() - (0.5 * aAbsScale.getX())) - aUntransformedFrameArea.Left(),
basegfx::fround(aCenter.getY() - (0.5 * aAbsScale.getY())) - aUntransformedFrameArea.Top(),
basegfx::fround(aAbsScale.getX()),
basegfx::fround(aAbsScale.getY()));
}
}
void TransformableSwFrame::createFrameAreaTransformations(
double fRotation,
const basegfx::B2DPoint& rCenter)
{
const basegfx::B2DHomMatrix aRotateAroundCenter(
basegfx::utils::createRotateAroundPoint(
rCenter.getX(),
rCenter.getY(),
fRotation));
const SwRect& rFrameArea(mrSwFrameAreaDefinition.getFrameArea());
const SwRect& rFramePrintArea(mrSwFrameAreaDefinition.getFramePrintArea());
maFrameAreaTransformation = aRotateAroundCenter * basegfx::utils::createScaleTranslateB2DHomMatrix(
rFrameArea.Width(), rFrameArea.Height(),
rFrameArea.Left(), rFrameArea.Top());
maFramePrintAreaTransformation = aRotateAroundCenter * basegfx::utils::createScaleTranslateB2DHomMatrix(
rFramePrintArea.Width(), rFramePrintArea.Height(),
rFramePrintArea.Left() + rFrameArea.Left(), rFramePrintArea.Top() + rFrameArea.Top());
}
void TransformableSwFrame::adaptFrameAreasToTransformations()
{
if(!getLocalFrameAreaTransformation().isIdentity())
{
basegfx::B2DRange aRangeFrameArea(0.0, 0.0, 1.0, 1.0);
aRangeFrameArea.transform(getLocalFrameAreaTransformation());
const SwRect aNewFrm(
basegfx::fround(aRangeFrameArea.getMinX()), basegfx::fround(aRangeFrameArea.getMinY()),
basegfx::fround(aRangeFrameArea.getWidth()), basegfx::fround(aRangeFrameArea.getHeight()));
if(aNewFrm != mrSwFrameAreaDefinition.getFrameArea())
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(mrSwFrameAreaDefinition);
aFrm.setSwRect(aNewFrm);
}
}
if(!getLocalFramePrintAreaTransformation().isIdentity())
{
basegfx::B2DRange aRangeFramePrintArea(0.0, 0.0, 1.0, 1.0);
aRangeFramePrintArea.transform(getLocalFramePrintAreaTransformation());
const SwRect aNewPrt(
basegfx::fround(aRangeFramePrintArea.getMinX()) - mrSwFrameAreaDefinition.getFrameArea().Left(),
basegfx::fround(aRangeFramePrintArea.getMinY()) - mrSwFrameAreaDefinition.getFrameArea().Top(),
basegfx::fround(aRangeFramePrintArea.getWidth()),
basegfx::fround(aRangeFramePrintArea.getHeight()));
if(aNewPrt != mrSwFrameAreaDefinition.getFramePrintArea())
{
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(mrSwFrameAreaDefinition);
aPrt.setSwRect(aNewPrt);
}
}
}
void TransformableSwFrame::restoreFrameAreas()
{
// This can be done fully based on the Transformations currently
// set, so use this. Only needed when transformation *is* used
if(!getLocalFrameAreaTransformation().isIdentity())
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(mrSwFrameAreaDefinition);
aFrm.setSwRect(getUntransformedFrameArea());
}
if(!getLocalFramePrintAreaTransformation().isIdentity())
{
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(mrSwFrameAreaDefinition);
aPrt.setSwRect(getUntransformedFramePrintArea());
}
}
// transform by given B2DHomMatrix
void TransformableSwFrame::transform(const basegfx::B2DHomMatrix& aTransform)
{
maFrameAreaTransformation *= aTransform;
maFramePrintAreaTransformation *= aTransform;
}
SwFrame::SwFrame( SwModify *pMod, SwFrame* pSib )
: SwFrameAreaDefinition(),
SwClient( pMod ),
SfxBroadcaster(),
mnFrameId( SwFrame::mnLastFrameId++ ),
mpRoot( pSib ? pSib->getRootFrame() : nullptr ),
mpUpper(nullptr),
mpNext(nullptr),
mpPrev(nullptr),
mnFrameType(SwFrameType::None),
mbInDtor(false),
mbInvalidR2L(true),
mbDerivedR2L(false),
mbRightToLeft(false),
mbInvalidVert(true),
mbDerivedVert(false),
mbVertical(false),
mbVertLR(false),
mbValidLineNum(false),
mbFixSize(false),
mbCompletePaint(true),
mbRetouche(false),
mbInfInvalid(true),
mbInfBody( false ),
mbInfTab ( false ),
mbInfFly ( false ),
mbInfFootnote ( false ),
mbInfSct ( false ),
mbColLocked(false),
m_isInDestroy(false),
mbForbidDelete(false)
{
OSL_ENSURE( pMod, "No frame format given." );
}
const IDocumentDrawModelAccess& SwFrame::getIDocumentDrawModelAccess()
{
return GetUpper()->GetFormat()->getIDocumentDrawModelAccess();
}
bool SwFrame::KnowsFormat( const SwFormat& rFormat ) const
{
return GetRegisteredIn() == &rFormat;
}
void SwFrame::RegisterToFormat( SwFormat& rFormat )
{
rFormat.Add( this );
}
void SwFrame::CheckDir( SvxFrameDirection nDir, bool bVert, bool bOnlyBiDi, bool bBrowse )
{
if( SvxFrameDirection::Environment == nDir || ( bVert && bOnlyBiDi ) )
{
mbDerivedVert = true;
if( SvxFrameDirection::Environment == nDir )
mbDerivedR2L = true;
SetDirFlags( bVert );
}
else if( bVert )
{
mbInvalidVert = false;
if( SvxFrameDirection::Horizontal_LR_TB == nDir || SvxFrameDirection::Horizontal_RL_TB == nDir
|| bBrowse )
{
mbVertical = false;
mbVertLR = false;
}
else
{
mbVertical = true;
if(SvxFrameDirection::Vertical_RL_TB == nDir)
mbVertLR = false;
else if(SvxFrameDirection::Vertical_LR_TB==nDir)
mbVertLR = true;
}
}
else
{
mbInvalidR2L = false;
if( SvxFrameDirection::Horizontal_RL_TB == nDir )
mbRightToLeft = true;
else
mbRightToLeft = false;
}
}
void SwFrame::CheckDirection( bool bVert )
{
if( bVert )
{
if( !IsHeaderFrame() && !IsFooterFrame() )
{
mbDerivedVert = true;
SetDirFlags( bVert );
}
}
else
{
mbDerivedR2L = true;
SetDirFlags( bVert );
}
}
void SwSectionFrame::CheckDirection( bool bVert )
{
const SwFrameFormat* pFormat = GetFormat();
if( pFormat )
{
const SwViewShell *pSh = getRootFrame()->GetCurrShell();
const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
CheckDir(pFormat->GetFormatAttr(RES_FRAMEDIR).GetValue(),
bVert, true, bBrowseMode );
}
else
SwFrame::CheckDirection( bVert );
}
void SwFlyFrame::CheckDirection( bool bVert )
{
const SwFrameFormat* pFormat = GetFormat();
if( pFormat )
{
const SwViewShell *pSh = getRootFrame()->GetCurrShell();
const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
CheckDir(pFormat->GetFormatAttr(RES_FRAMEDIR).GetValue(),
bVert, false, bBrowseMode );
}
else
SwFrame::CheckDirection( bVert );
}
void SwTabFrame::CheckDirection( bool bVert )
{
const SwFrameFormat* pFormat = GetFormat();
if( pFormat )
{
const SwViewShell *pSh = getRootFrame()->GetCurrShell();
const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
CheckDir(pFormat->GetFormatAttr(RES_FRAMEDIR).GetValue(),
bVert, true, bBrowseMode );
}
else
SwFrame::CheckDirection( bVert );
}
void SwCellFrame::CheckDirection( bool bVert )
{
const SwFrameFormat* pFormat = GetFormat();
const SfxPoolItem* pItem;
// Check if the item is set, before actually
// using it. Otherwise the dynamic pool default is used, which may be set
// to LTR in case of OOo 1.0 documents.
if( pFormat && SfxItemState::SET == pFormat->GetItemState( RES_FRAMEDIR, true, &pItem ) )
{
const SvxFrameDirectionItem* pFrameDirItem = static_cast<const SvxFrameDirectionItem*>(pItem);
const SwViewShell *pSh = getRootFrame()->GetCurrShell();
const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
CheckDir( pFrameDirItem->GetValue(), bVert, false, bBrowseMode );
}
else
SwFrame::CheckDirection( bVert );
}
void SwTextFrame::CheckDirection( bool bVert )
{
const SwViewShell *pSh = getRootFrame()->GetCurrShell();
const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
CheckDir(GetTextNodeForParaProps()->GetSwAttrSet().GetFrameDir().GetValue(),
bVert, true, bBrowseMode);
}
void SwFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew )
{
sal_uInt8 nInvFlags = 0;
if( pOld && pNew && RES_ATTRSET_CHG == pNew->Which() )
{
SfxItemIter aNIter( *static_cast<const SwAttrSetChg*>(pNew)->GetChgSet() );
SfxItemIter aOIter( *static_cast<const SwAttrSetChg*>(pOld)->GetChgSet() );
while( true )
{
UpdateAttrFrame( aOIter.GetCurItem(),
aNIter.GetCurItem(), nInvFlags );
if( aNIter.IsAtEnd() )
break;
aNIter.NextItem();
aOIter.NextItem();
}
}
else
UpdateAttrFrame( pOld, pNew, nInvFlags );
if ( nInvFlags != 0 )
{
SwPageFrame *pPage = FindPageFrame();
InvalidatePage( pPage );
if ( nInvFlags & 0x01 )
{
InvalidatePrt_();
if( !GetPrev() && IsTabFrame() && IsInSct() )
FindSctFrame()->InvalidatePrt_();
}
if ( nInvFlags & 0x02 )
InvalidateSize_();
if ( nInvFlags & 0x04 )
InvalidatePos_();
if ( nInvFlags & 0x08 )
SetCompletePaint();
SwFrame *pNxt;
if ( nInvFlags & 0x30 && nullptr != (pNxt = GetNext()) )
{
pNxt->InvalidatePage( pPage );
if ( nInvFlags & 0x10 )
pNxt->InvalidatePos_();
if ( nInvFlags & 0x20 )
pNxt->SetCompletePaint();
}
}
}
void SwFrame::UpdateAttrFrame( const SfxPoolItem *pOld, const SfxPoolItem *pNew,
sal_uInt8 &rInvFlags )
{
sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
switch( nWhich )
{
case RES_BOX:
case RES_SHADOW:
Prepare( PREP_FIXSIZE_CHG );
SAL_FALLTHROUGH;
case RES_LR_SPACE:
case RES_UL_SPACE:
rInvFlags |= 0x0B;
break;
case RES_HEADER_FOOTER_EAT_SPACING:
rInvFlags |= 0x03;
break;
case RES_BACKGROUND:
rInvFlags |= 0x28;
break;
case RES_KEEP:
rInvFlags |= 0x04;
break;
case RES_FRM_SIZE:
ReinitializeFrameSizeAttrFlags();
rInvFlags |= 0x13;
break;
case RES_FMT_CHG:
rInvFlags |= 0x0F;
break;
case RES_ROW_SPLIT:
{
if ( IsRowFrame() )
{
bool bInFollowFlowRow = nullptr != IsInFollowFlowRow();
if ( bInFollowFlowRow || nullptr != IsInSplitTableRow() )
{
SwTabFrame* pTab = FindTabFrame();
if ( bInFollowFlowRow )
pTab = pTab->FindMaster();
pTab->SetRemoveFollowFlowLinePending( true );
}
}
break;
}
case RES_COL:
OSL_FAIL( "Columns for new FrameType?" );
break;
default:
// the new FillStyle has to do the same as previous RES_BACKGROUND
if(nWhich >= XATTR_FILL_FIRST && nWhich <= XATTR_FILL_LAST)
{
rInvFlags |= 0x28;
}
/* do Nothing */;
}
}
bool SwFrame::Prepare( const PrepareHint, const void *, bool )
{
/* Do nothing */
return false;
}
/**
* Invalidates the page in which the Frame is currently placed.
* The page is invalidated depending on the type (Layout, Content, FlyFrame)
*/
void SwFrame::InvalidatePage( const SwPageFrame *pPage ) const
{
if ( !pPage )
{
pPage = FindPageFrame();
// #i28701# - for at-character and as-character
// anchored Writer fly frames additionally invalidate also page frame
// its 'anchor character' is on.
if ( pPage && pPage->GetUpper() && IsFlyFrame() )
{
const SwFlyFrame* pFlyFrame = static_cast<const SwFlyFrame*>(this);
if ( pFlyFrame->IsAutoPos() || pFlyFrame->IsFlyInContentFrame() )
{
// #i33751#, #i34060# - method <GetPageFrameOfAnchor()>
// is replaced by method <FindPageFrameOfAnchor()>. It's return value
// have to be checked.
SwPageFrame* pPageFrameOfAnchor =
const_cast<SwFlyFrame*>(pFlyFrame)->FindPageFrameOfAnchor();
if ( pPageFrameOfAnchor && pPageFrameOfAnchor != pPage )
{
InvalidatePage( pPageFrameOfAnchor );
}
}
}
}
if ( pPage && pPage->GetUpper() )
{
if ( pPage->GetFormat()->GetDoc()->IsInDtor() )
return;
SwRootFrame *pRoot = const_cast<SwRootFrame*>(static_cast<const SwRootFrame*>(pPage->GetUpper()));
const SwFlyFrame *pFly = FindFlyFrame();
if ( IsContentFrame() )
{
if ( pRoot->IsTurboAllowed() )
{
// If a ContentFrame wants to register for a second time, make it a TurboAction.
if ( !pRoot->GetTurbo() || this == pRoot->GetTurbo() )
pRoot->SetTurbo( static_cast<const SwContentFrame*>(this) );
else
{
pRoot->DisallowTurbo();
//The page of the Turbo could be a different one then mine,
//therefore we have to invalidate it.
const SwFrame *pTmp = pRoot->GetTurbo();
pRoot->ResetTurbo();
pTmp->InvalidatePage();
}
}
if ( !pRoot->GetTurbo() )
{
if ( pFly )
{ if( !pFly->IsLocked() )
{
if ( pFly->IsFlyInContentFrame() )
{ pPage->InvalidateFlyInCnt();
pFly->GetAnchorFrame()->InvalidatePage();
}
else
pPage->InvalidateFlyContent();
}
}
else
pPage->InvalidateContent();
}
}
else
{
pRoot->DisallowTurbo();
if ( pFly )
{
if ( !pFly->IsLocked() )
{
if ( pFly->IsFlyInContentFrame() )
{
pPage->InvalidateFlyInCnt();
pFly->GetAnchorFrame()->InvalidatePage();
}
else
pPage->InvalidateFlyLayout();
}
}
else
pPage->InvalidateLayout();
if ( pRoot->GetTurbo() )
{ const SwFrame *pTmp = pRoot->GetTurbo();
pRoot->ResetTurbo();
pTmp->InvalidatePage();
}
}
pRoot->SetIdleFlags();
if (IsTextFrame())
{
SwTextFrame const*const pText(static_cast<SwTextFrame const*>(this));
if (sw::MergedPara const*const pMergedPara = pText->GetMergedPara())
{
SwTextNode const* pNode(nullptr);
for (auto const& e : pMergedPara->extents)
{
if (e.pNode != pNode)
{
pNode = e.pNode;
if (pNode->IsGrammarCheckDirty())
{
pRoot->SetNeedGrammarCheck( true );
break;
}
}
}
}
else
{
if (pText->GetTextNodeFirst()->IsGrammarCheckDirty())
{
pRoot->SetNeedGrammarCheck( true );
}
}
}
}
}
Size SwFrame::ChgSize( const Size& aNewSize )
{
mbFixSize = true;
const Size aOldSize( getFrameArea().SSize() );
if ( aNewSize == aOldSize )
return aOldSize;
if ( GetUpper() )
{
bool bNeighb = IsNeighbourFrame();
SwRectFn fnRect = IsVertical() == bNeighb ? fnRectHori : ( IsVertLR() ? fnRectVertL2R : fnRectVert );
SwRect aNew( Point(0,0), aNewSize );
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
(aFrm.*fnRect->fnSetWidth)( (aNew.*fnRect->fnGetWidth)() );
}
long nNew = (aNew.*fnRect->fnGetHeight)();
long nDiff = nNew - (getFrameArea().*fnRect->fnGetHeight)();
if( nDiff )
{
if ( GetUpper()->IsFootnoteBossFrame() && HasFixSize() &&
SwNeighbourAdjust::GrowShrink !=
static_cast<SwFootnoteBossFrame*>(GetUpper())->NeighbourhoodAdjustment() )
{
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
(aFrm.*fnRect->fnSetHeight)( nNew );
}
SwTwips nReal = static_cast<SwLayoutFrame*>(this)->AdjustNeighbourhood(nDiff);
if ( nReal != nDiff )
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
(aFrm.*fnRect->fnSetHeight)( nNew - nDiff + nReal );
}
}
else
{
// OD 24.10.2002 #97265# - grow/shrink not for neighbour frames
// NOTE: neighbour frames are cell and column frames.
if ( !bNeighb )
{
if ( nDiff > 0 )
Grow( nDiff );
else
Shrink( -nDiff );
if ( GetUpper() && (getFrameArea().*fnRect->fnGetHeight)() != nNew )
{
GetUpper()->InvalidateSize_();
}
}
// Even if grow/shrink did not yet set the desired width, for
// example when called by ChgColumns to set the column width, we
// set the right width now.
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
(aFrm.*fnRect->fnSetHeight)( nNew );
}
}
}
else
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aFrm.SSize( aNewSize );
}
if ( getFrameArea().SSize() != aOldSize )
{
SwPageFrame *pPage = FindPageFrame();
if ( GetNext() )
{
GetNext()->InvalidatePos_();
GetNext()->InvalidatePage( pPage );
}
if( IsLayoutFrame() )
{
if( IsRightToLeft() )
InvalidatePos_();
if( static_cast<SwLayoutFrame*>(this)->Lower() )
static_cast<SwLayoutFrame*>(this)->Lower()->InvalidateSize_();
}
InvalidatePrt_();
InvalidateSize_();
InvalidatePage( pPage );
}
return getFrameArea().SSize();
}
/** Insert SwFrame into existing structure.
*
* Insertion is done below the parent either before pBehind or
* at the end of the chain if pBehind is empty.
*/
void SwFrame::InsertBefore( SwLayoutFrame* pParent, SwFrame* pBehind )
{
OSL_ENSURE( pParent, "No parent for insert." );
OSL_ENSURE( (!pBehind || pParent == pBehind->GetUpper()),
"Frame tree is inconsistent." );
mpUpper = pParent;
mpNext = pBehind;
if( pBehind )
{ //Insert before pBehind.
if( nullptr != (mpPrev = pBehind->mpPrev) )
mpPrev->mpNext = this;
else
mpUpper->m_pLower = this;
pBehind->mpPrev = this;
}
else
{ //Insert at the end, or as first node in the sub tree
mpPrev = mpUpper->Lower();
if ( mpPrev )
{
while( mpPrev->mpNext )
mpPrev = mpPrev->mpNext;
mpPrev->mpNext = this;
}
else
mpUpper->m_pLower = this;
}
}
/** Insert SwFrame into existing structure.
*
* Insertion is done below the parent either after pBehind or
* at the beginning of the chain if pBehind is empty.
*/
void SwFrame::InsertBehind( SwLayoutFrame *pParent, SwFrame *pBefore )
{
OSL_ENSURE( pParent, "No Parent for Insert." );
OSL_ENSURE( (!pBefore || pParent == pBefore->GetUpper()),
"Frame tree is inconsistent." );
mpUpper = pParent;
mpPrev = pBefore;
if ( pBefore )
{
//Insert after pBefore
if ( nullptr != (mpNext = pBefore->mpNext) )
mpNext->mpPrev = this;
pBefore->mpNext = this;
}
else
{
//Insert at the beginning of the chain
mpNext = pParent->Lower();
if ( pParent->Lower() )
pParent->Lower()->mpPrev = this;
pParent->m_pLower = this;
}
}
/** Insert a chain of SwFrames into an existing structure
*
* Currently, this method is used to insert a SectionFrame (which may have some siblings) into an
* existing structure. If the third parameter is NULL, this method is (besides handling the
* siblings) equal to SwFrame::InsertBefore(..).
*
* If the third parameter is passed, the following happens:
* - this becomes mpNext of pParent
* - pSct becomes mpNext of the last one in the this-chain
* - pBehind is reconnected from pParent to pSct
* The purpose is: a SectionFrame (this) won't become a child of another SectionFrame (pParent), but
* pParent gets split into two siblings (pParent+pSect) and this is inserted between.
*/
bool SwFrame::InsertGroupBefore( SwFrame* pParent, SwFrame* pBehind, SwFrame* pSct )
{
OSL_ENSURE( pParent, "No parent for insert." );
OSL_ENSURE( (!pBehind || ( (pBehind && (pParent == pBehind->GetUpper()))
|| ((pParent->IsSctFrame() && pBehind->GetUpper()->IsColBodyFrame())) ) ),
"Frame tree inconsistent." );
if( pSct )
{
mpUpper = pParent->GetUpper();
SwFrame *pLast = this;
while( pLast->GetNext() )
{
pLast = pLast->GetNext();
pLast->mpUpper = GetUpper();
}
if( pBehind )
{
pLast->mpNext = pSct;
pSct->mpPrev = pLast;
pSct->mpNext = pParent->GetNext();
}
else
{
pLast->mpNext = pParent->GetNext();
if( pLast->GetNext() )
pLast->GetNext()->mpPrev = pLast;
}
pParent->mpNext = this;
mpPrev = pParent;
if( pSct->GetNext() )
pSct->GetNext()->mpPrev = pSct;
while( pLast->GetNext() )
{
pLast = pLast->GetNext();
pLast->mpUpper = GetUpper();
}
if( pBehind )
{ // Insert before pBehind.
if( pBehind->GetPrev() )
pBehind->GetPrev()->mpNext = nullptr;
else
pBehind->GetUpper()->m_pLower = nullptr;
pBehind->mpPrev = nullptr;
SwLayoutFrame* pTmp = static_cast<SwLayoutFrame*>(pSct);
if( pTmp->Lower() )
{
OSL_ENSURE( pTmp->Lower()->IsColumnFrame(), "InsertGrp: Used SectionFrame" );
pTmp = static_cast<SwLayoutFrame*>(static_cast<SwLayoutFrame*>(pTmp->Lower())->Lower());
OSL_ENSURE( pTmp, "InsertGrp: Missing ColBody" );
}
pBehind->mpUpper = pTmp;
pBehind->GetUpper()->m_pLower = pBehind;
pLast = pBehind->GetNext();
while ( pLast )
{
pLast->mpUpper = pBehind->GetUpper();
pLast = pLast->GetNext();
}
}
else
{
OSL_ENSURE( pSct->IsSctFrame(), "InsertGroup: For SectionFrames only" );
SwFrame::DestroyFrame(pSct);
return false;
}
}
else
{
mpUpper = static_cast<SwLayoutFrame*>(pParent);
SwFrame *pLast = this;
while( pLast->GetNext() )
{
pLast = pLast->GetNext();
pLast->mpUpper = GetUpper();
}
pLast->mpNext = pBehind;
if( pBehind )
{ // Insert before pBehind.
if( nullptr != (mpPrev = pBehind->mpPrev) )
mpPrev->mpNext = this;
else
mpUpper->m_pLower = this;
pBehind->mpPrev = pLast;
}
else
{
//Insert at the end, or ... the first node in the subtree
mpPrev = mpUpper->Lower();
if ( mpPrev )
{
while( mpPrev->mpNext )
mpPrev = mpPrev->mpNext;
mpPrev->mpNext = this;
}
else
mpUpper->m_pLower = this;
}
}
return true;
}
void SwFrame::RemoveFromLayout()
{
OSL_ENSURE( mpUpper, "Remove without upper?" );
if( mpPrev )
// one out of the middle is removed
mpPrev->mpNext = mpNext;
else
{ // the first in a list is removed //TODO
OSL_ENSURE( mpUpper->m_pLower == this, "Layout is inconsistent." );
mpUpper->m_pLower = mpNext;
}
if( mpNext )
mpNext->mpPrev = mpPrev;
// Remove link
mpNext = mpPrev = nullptr;
mpUpper = nullptr;
}
void SwContentFrame::Paste( SwFrame* pParent, SwFrame* pSibling)
{
OSL_ENSURE( pParent, "No parent for pasting." );
OSL_ENSURE( pParent->IsLayoutFrame(), "Parent is ContentFrame." );
OSL_ENSURE( pParent != this, "I'm the parent." );
OSL_ENSURE( pSibling != this, "I'm my own neighbour." );
OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(),
"I'm still registered somewhere" );
OSL_ENSURE( !pSibling || pSibling->IsFlowFrame(),
"<SwContentFrame::Paste(..)> - sibling not of expected type." );
//Insert in the tree.
InsertBefore( static_cast<SwLayoutFrame*>(pParent), pSibling );
SwPageFrame *pPage = FindPageFrame();
InvalidateAll_();
InvalidatePage( pPage );
if( pPage )
{
pPage->InvalidateSpelling();
pPage->InvalidateSmartTags();
pPage->InvalidateAutoCompleteWords();
pPage->InvalidateWordCount();
}
if ( GetNext() )
{
SwFrame* pNxt = GetNext();
pNxt->InvalidatePrt_();
pNxt->InvalidatePos_();
pNxt->InvalidatePage( pPage );
if( pNxt->IsSctFrame() )
pNxt = static_cast<SwSectionFrame*>(pNxt)->ContainsContent();
if( pNxt && pNxt->IsTextFrame() && pNxt->IsInFootnote() )
pNxt->Prepare( PREP_FTN, nullptr, false );
}
if ( getFrameArea().Height() )
pParent->Grow( getFrameArea().Height() );
if ( getFrameArea().Width() != pParent->getFramePrintArea().Width() )
Prepare( PREP_FIXSIZE_CHG );
if ( GetPrev() )
{
if ( IsFollow() )
//I'm a direct follower of my master now
static_cast<SwContentFrame*>(GetPrev())->Prepare( PREP_FOLLOW_FOLLOWS );
else
{
if ( GetPrev()->getFrameArea().Height() !=
GetPrev()->getFramePrintArea().Height() + GetPrev()->getFramePrintArea().Top() )
{
// Take the border into account?
GetPrev()->InvalidatePrt_();
}
// OD 18.02.2003 #104989# - force complete paint of previous frame,
// if frame is inserted at the end of a section frame, in order to
// get subsidiary lines repainted for the section.
if ( pParent->IsSctFrame() && !GetNext() )
{
// force complete paint of previous frame, if new inserted frame
// in the section is the last one.
GetPrev()->SetCompletePaint();
}
GetPrev()->InvalidatePage( pPage );
}
}
if ( IsInFootnote() )
{
SwFrame* pFrame = GetIndPrev();
if( pFrame && pFrame->IsSctFrame() )
pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
if( pFrame )
pFrame->Prepare( PREP_QUOVADIS, nullptr, false );
if( !GetNext() )
{
pFrame = FindFootnoteFrame()->GetNext();
if( pFrame && nullptr != (pFrame=static_cast<SwLayoutFrame*>(pFrame)->ContainsAny()) )
pFrame->InvalidatePrt_();
}
}
InvalidateLineNum_();
SwFrame *pNxt = FindNextCnt();
if ( pNxt )
{
while ( pNxt && pNxt->IsInTab() )
{
if( nullptr != (pNxt = pNxt->FindTabFrame()) )
pNxt = pNxt->FindNextCnt();
}
if ( pNxt )
{
pNxt->InvalidateLineNum_();
if ( pNxt != GetNext() )
pNxt->InvalidatePage();
}
}
}
void SwContentFrame::Cut()
{
OSL_ENSURE( GetUpper(), "Cut without Upper()." );
SwPageFrame *pPage = FindPageFrame();
InvalidatePage( pPage );
SwFrame *pFrame = GetIndPrev();
if( pFrame )
{
if( pFrame->IsSctFrame() )
pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
if ( pFrame && pFrame->IsContentFrame() )
{
pFrame->InvalidatePrt_();
if( IsInFootnote() )
pFrame->Prepare( PREP_QUOVADIS, nullptr, false );
}
// #i26250# - invalidate printing area of previous
// table frame.
else if ( pFrame && pFrame->IsTabFrame() )
{
pFrame->InvalidatePrt();
}
}
SwFrame *pNxt = FindNextCnt();
if ( pNxt )
{
while ( pNxt && pNxt->IsInTab() )
{
if( nullptr != (pNxt = pNxt->FindTabFrame()) )
pNxt = pNxt->FindNextCnt();
}
if ( pNxt )
{
pNxt->InvalidateLineNum_();
if ( pNxt != GetNext() )
pNxt->InvalidatePage();
}
}
if( nullptr != (pFrame = GetIndNext()) )
{
// The old follow may have calculated a gap to the predecessor which
// now becomes obsolete or different as it becomes the first one itself
pFrame->InvalidatePrt_();
pFrame->InvalidatePos_();
pFrame->InvalidatePage( pPage );
if( pFrame->IsSctFrame() )
{
pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
if( pFrame )
{
pFrame->InvalidatePrt_();
pFrame->InvalidatePos_();
pFrame->InvalidatePage( pPage );
}
}
if( pFrame && IsInFootnote() )
pFrame->Prepare( PREP_ERGOSUM, nullptr, false );
if( IsInSct() && !GetPrev() )
{
SwSectionFrame* pSct = FindSctFrame();
if( !pSct->IsFollow() )
{
pSct->InvalidatePrt_();
pSct->InvalidatePage( pPage );
}
}
}
else
{
InvalidateNextPos();
//Someone needs to do the retouching: predecessor or upper
if ( nullptr != (pFrame = GetPrev()) )
{ pFrame->SetRetouche();
pFrame->Prepare( PREP_WIDOWS_ORPHANS );
pFrame->InvalidatePos_();
pFrame->InvalidatePage( pPage );
}
// If I'm (was) the only ContentFrame in my upper, it has to do the
// retouching. Also, perhaps a page became empty.
else
{ SwRootFrame *pRoot = getRootFrame();
if ( pRoot )
{
pRoot->SetSuperfluous();
GetUpper()->SetCompletePaint();
GetUpper()->InvalidatePage( pPage );
}
if( IsInSct() )
{
SwSectionFrame* pSct = FindSctFrame();
if( !pSct->IsFollow() )
{
pSct->InvalidatePrt_();
pSct->InvalidatePage( pPage );
}
}
// #i52253# The master table should take care
// of removing the follow flow line.
if ( IsInTab() )
{
SwTabFrame* pThisTab = FindTabFrame();
SwTabFrame* pMasterTab = pThisTab && pThisTab->IsFollow() ? pThisTab->FindMaster() : nullptr;
if ( pMasterTab )
{
pMasterTab->InvalidatePos_();
pMasterTab->SetRemoveFollowFlowLinePending( true );
}
}
}
}
//Remove first, then shrink the upper.
SwLayoutFrame *pUp = GetUpper();
RemoveFromLayout();
if ( pUp )
{
SwSectionFrame *pSct = nullptr;
if ( !pUp->Lower() &&
( ( pUp->IsFootnoteFrame() && !pUp->IsColLocked() ) ||
( pUp->IsInSct() &&
// #i29438#
// We have to consider the case that the section may be "empty"
// except from a temporary empty table frame.
// This can happen due to the new cell split feature.
!pUp->IsCellFrame() &&
// #126020# - adjust check for empty section
// #130797# - correct fix #126020#
!(pSct = pUp->FindSctFrame())->ContainsContent() &&
!pSct->ContainsAny( true ) ) ) )
{
if ( pUp->GetUpper() )
{
// prevent delete of <ColLocked> footnote frame
if ( pUp->IsFootnoteFrame() && !pUp->IsColLocked())
{
if( pUp->GetNext() && !pUp->GetPrev() )
{
SwFrame* pTmp = static_cast<SwLayoutFrame*>(pUp->GetNext())->ContainsAny();
if( pTmp )
pTmp->InvalidatePrt_();
}
if (!pUp->IsDeleteForbidden())
{
pUp->Cut();
SwFrame::DestroyFrame(pUp);
}
}
else
{
if ( pSct->IsColLocked() || !pSct->IsInFootnote() ||
( pUp->IsFootnoteFrame() && pUp->IsColLocked() ) )
{
pSct->DelEmpty( false );
// If a locked section may not be deleted then at least
// its size became invalid after removing its last
// content.
pSct->InvalidateSize_();
}
else
{
pSct->DelEmpty( true );
SwFrame::DestroyFrame(pSct);
}
}
}
}
else
{
SwRectFnSet aRectFnSet(this);
long nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
if( nFrameHeight )
pUp->Shrink( nFrameHeight );
}
}
}
void SwLayoutFrame::Paste( SwFrame* pParent, SwFrame* pSibling)
{
OSL_ENSURE( pParent, "No parent for pasting." );
OSL_ENSURE( pParent->IsLayoutFrame(), "Parent is ContentFrame." );
OSL_ENSURE( pParent != this, "I'm the parent oneself." );
OSL_ENSURE( pSibling != this, "I'm my own neighbour." );
OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(),
"I'm still registered somewhere." );
//Insert in the tree.
InsertBefore( static_cast<SwLayoutFrame*>(pParent), pSibling );
// OD 24.10.2002 #103517# - correct setting of variable <fnRect>
// <fnRect> is used for the following:
// (1) To invalidate the frame's size, if its size, which has to be the
// same as its upper/parent, differs from its upper's/parent's.
// (2) To adjust/grow the frame's upper/parent, if it has a dimension in its
// size, which is not determined by its upper/parent.
// Which size is which depends on the frame type and the layout direction
// (vertical or horizontal).
// There are the following cases:
// (A) Header and footer frames both in vertical and in horizontal layout
// have to size the width to the upper/parent. A dimension in the height
// has to cause a adjustment/grow of the upper/parent.
// --> <fnRect> = fnRectHori
// (B) Cell and column frames in vertical layout, the width has to be the
// same as upper/parent and a dimension in height causes adjustment/grow
// of the upper/parent.
// --> <fnRect> = fnRectHori
// in horizontal layout the other way around
// --> <fnRect> = fnRectVert
// (C) Other frames in vertical layout, the height has to be the
// same as upper/parent and a dimension in width causes adjustment/grow
// of the upper/parent.
// --> <fnRect> = fnRectVert
// in horizontal layout the other way around
// --> <fnRect> = fnRectHori
//SwRectFn fnRect = IsVertical() ? fnRectHori : fnRectVert;
SwRectFn fnRect;
if ( IsHeaderFrame() || IsFooterFrame() )
fnRect = fnRectHori;
else if ( IsCellFrame() || IsColumnFrame() )
fnRect = GetUpper()->IsVertical() ? fnRectHori : ( GetUpper()->IsVertLR() ? fnRectVertL2R : fnRectVert );
else
fnRect = GetUpper()->IsVertical() ? ( GetUpper()->IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori;
if( (getFrameArea().*fnRect->fnGetWidth)() != (pParent->getFramePrintArea().*fnRect->fnGetWidth)())
InvalidateSize_();
InvalidatePos_();
const SwPageFrame *pPage = FindPageFrame();
InvalidatePage( pPage );
if( !IsColumnFrame() )
{
SwFrame *pFrame = GetIndNext();
if( nullptr != pFrame )
{
pFrame->InvalidatePos_();
if( IsInFootnote() )
{
if( pFrame->IsSctFrame() )
pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
if( pFrame )
pFrame->Prepare( PREP_ERGOSUM, nullptr, false );
}
}
if ( IsInFootnote() && nullptr != ( pFrame = GetIndPrev() ) )
{
if( pFrame->IsSctFrame() )
pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
if( pFrame )
pFrame->Prepare( PREP_QUOVADIS, nullptr, false );
}
}
if( (getFrameArea().*fnRect->fnGetHeight)() )
{
// AdjustNeighbourhood is now also called in columns which are not
// placed inside a frame
SwNeighbourAdjust nAdjust = GetUpper()->IsFootnoteBossFrame() ?
static_cast<SwFootnoteBossFrame*>(GetUpper())->NeighbourhoodAdjustment()
: SwNeighbourAdjust::GrowShrink;
SwTwips nGrow = (getFrameArea().*fnRect->fnGetHeight)();
if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
AdjustNeighbourhood( nGrow );
else
{
SwTwips nReal = 0;
if( SwNeighbourAdjust::AdjustGrow == nAdjust )
nReal = AdjustNeighbourhood( nGrow );
if( nReal < nGrow )
nReal += pParent->Grow( nGrow - nReal );
if( SwNeighbourAdjust::GrowAdjust == nAdjust && nReal < nGrow )
AdjustNeighbourhood( nGrow - nReal );
}
}
}
void SwLayoutFrame::Cut()
{
if ( GetNext() )
GetNext()->InvalidatePos_();
SwRectFnSet aRectFnSet(this);
SwTwips nShrink = aRectFnSet.GetHeight(getFrameArea());
// Remove first, then shrink upper.
SwLayoutFrame *pUp = GetUpper();
// AdjustNeighbourhood is now also called in columns which are not
// placed inside a frame.
// Remove must not be called before an AdjustNeighbourhood, but it has to
// be called before the upper-shrink-call, if the upper-shrink takes care
// of its content.
if ( pUp && nShrink )
{
if( pUp->IsFootnoteBossFrame() )
{
SwNeighbourAdjust nAdjust= static_cast<SwFootnoteBossFrame*>(pUp)->NeighbourhoodAdjustment();
if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
AdjustNeighbourhood( -nShrink );
else
{
SwTwips nReal = 0;
if( SwNeighbourAdjust::AdjustGrow == nAdjust )
nReal = -AdjustNeighbourhood( -nShrink );
if( nReal < nShrink )
{
const SwTwips nOldHeight = aRectFnSet.GetHeight(getFrameArea());
// seems as if this needs to be forwarded to the SwFrame already here,
// changing to zero seems temporary anyways
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.SetHeight( aFrm, 0 );
}
nReal += pUp->Shrink( nShrink - nReal );
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.SetHeight( aFrm, nOldHeight );
}
}
if( SwNeighbourAdjust::GrowAdjust == nAdjust && nReal < nShrink )
AdjustNeighbourhood( nReal - nShrink );
}
RemoveFromLayout();
}
else
{
RemoveFromLayout();
pUp->Shrink( nShrink );
}
}
else
RemoveFromLayout();
if( pUp && !pUp->Lower() )
{
pUp->SetCompletePaint();
pUp->InvalidatePage();
}
}
SwTwips SwFrame::Grow( SwTwips nDist, bool bTst, bool bInfo )
{
OSL_ENSURE( nDist >= 0, "Negative growth?" );
PROTOCOL_ENTER( this, bTst ? PROT::GrowTest : PROT::Grow, DbgAction::NONE, &nDist )
if ( nDist )
{
SwRectFnSet aRectFnSet(this);
SwTwips nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
if( nPrtHeight > 0 && nDist > (LONG_MAX - nPrtHeight) )
nDist = LONG_MAX - nPrtHeight;
if ( IsFlyFrame() )
return static_cast<SwFlyFrame*>(this)->Grow_( nDist, bTst );
else if( IsSctFrame() )
return static_cast<SwSectionFrame*>(this)->Grow_( nDist, bTst );
else
{
const SwCellFrame* pThisCell = dynamic_cast<const SwCellFrame*>(this);
if ( pThisCell )
{
const SwTabFrame* pTab = FindTabFrame();
// NEW TABLES
if ( pTab->IsVertical() != IsVertical() ||
pThisCell->GetLayoutRowSpan() < 1 )
return 0;
}
const SwTwips nReal = GrowFrame( nDist, bTst, bInfo );
if( !bTst )
{
nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
aRectFnSet.SetHeight( aPrt, nPrtHeight + ( IsContentFrame() ? nDist : nReal ) );
}
return nReal;
}
}
return 0;
}
SwTwips SwFrame::Shrink( SwTwips nDist, bool bTst, bool bInfo )
{
OSL_ENSURE( nDist >= 0, "Negative reduction?" );
PROTOCOL_ENTER( this, bTst ? PROT::ShrinkTest : PROT::Shrink, DbgAction::NONE, &nDist )
if ( nDist )
{
if ( IsFlyFrame() )
return static_cast<SwFlyFrame*>(this)->Shrink_( nDist, bTst );
else if( IsSctFrame() )
return static_cast<SwSectionFrame*>(this)->Shrink_( nDist, bTst );
else
{
const SwCellFrame* pThisCell = dynamic_cast<const SwCellFrame*>(this);
if ( pThisCell )
{
const SwTabFrame* pTab = FindTabFrame();
// NEW TABLES
if ( (pTab && pTab->IsVertical() != IsVertical()) ||
pThisCell->GetLayoutRowSpan() < 1 )
return 0;
}
SwRectFnSet aRectFnSet(this);
SwTwips nReal = aRectFnSet.GetHeight(getFrameArea());
ShrinkFrame( nDist, bTst, bInfo );
nReal -= aRectFnSet.GetHeight(getFrameArea());
if( !bTst )
{
const SwTwips nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
aRectFnSet.SetHeight( aPrt, nPrtHeight - ( IsContentFrame() ? nDist : nReal ) );
}
return nReal;
}
}
return 0;
}
/** Adjust surrounding neighbourhood after insertion
*
* A Frame needs "normalization" if it is directly placed below a footnote boss (page/column) and its
* size changes. There is always a frame that takes the maximum possible space (the frame that
* contains the Body text) and zero or more frames which only take the space needed (header/footer
* area, footnote container). If one of these frames changes, the body-text-frame has to grow or
* shrink accordingly, even though it's fixed.
*
* !! Is it possible to do this in a generic way and not restrict it to the page and a distinct
* frame which takes the maximum space (controlled using the FrameSize attribute)?
* Problems:
* - What if multiple frames taking the maximum space are placed next to each other?
* - How is the maximum space calculated?
* - How small can those frames become?
*
* In any case, only a certain amount of space is allowed, so we never go below a minimum value for
* the height of the body.
*
* @param nDiff the value around which the space has to be allocated
*/
SwTwips SwFrame::AdjustNeighbourhood( SwTwips nDiff, bool bTst )
{
PROTOCOL_ENTER( this, PROT::AdjustN, DbgAction::NONE, &nDiff );
if ( !nDiff || !GetUpper()->IsFootnoteBossFrame() ) // only inside pages/columns
return 0;
const SwViewShell *pSh = getRootFrame()->GetCurrShell();
const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
//The (Page-)Body only changes in BrowseMode, but only if it does not
//contain columns.
if ( IsPageBodyFrame() && (!bBrowse ||
(static_cast<SwLayoutFrame*>(this)->Lower() &&
static_cast<SwLayoutFrame*>(this)->Lower()->IsColumnFrame())) )
return 0;
//In BrowseView mode the PageFrame can handle some of the requests.
long nBrowseAdd = 0;
if ( bBrowse && GetUpper()->IsPageFrame() ) // only (Page-)BodyFrames
{
SwViewShell *pViewShell = getRootFrame()->GetCurrShell();
SwLayoutFrame *pUp = GetUpper();
long nChg;
const long nUpPrtBottom = pUp->getFrameArea().Height() -
pUp->getFramePrintArea().Height() - pUp->getFramePrintArea().Top();
SwRect aInva( pUp->getFrameArea() );
if ( pViewShell )
{
aInva.Pos().setX( pViewShell->VisArea().Left() );
aInva.Width( pViewShell->VisArea().Width() );
}
if ( nDiff > 0 )
{
nChg = BROWSE_HEIGHT - pUp->getFrameArea().Height();
nChg = std::min( nDiff, nChg );
if ( !IsBodyFrame() )
{
SetCompletePaint();
if ( !pViewShell || pViewShell->VisArea().Height() >= pUp->getFrameArea().Height() )
{
//First minimize Body, it will grow again later.
SwFrame *pBody = static_cast<SwFootnoteBossFrame*>(pUp)->FindBodyCont();
const long nTmp = nChg - pBody->getFramePrintArea().Height();
if ( !bTst )
{
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pBody);
aFrm.Height(std::max( 0L, aFrm.Height() - nChg ));
}
pBody->InvalidatePrt_();
pBody->InvalidateSize_();
if ( pBody->GetNext() )
pBody->GetNext()->InvalidatePos_();
if ( !IsHeaderFrame() )
pBody->SetCompletePaint();
}
nChg = nTmp <= 0 ? 0 : nTmp;
}
}
const long nTmp = nUpPrtBottom + 20;
aInva.Top( aInva.Bottom() - nTmp );
aInva.Height( nChg + nTmp );
}
else
{
//The page can shrink to 0. The first page keeps the same size like
//VisArea.
nChg = nDiff;
long nInvaAdd = 0;
if ( pViewShell && !pUp->GetPrev() &&
pUp->getFrameArea().Height() + nDiff < pViewShell->VisArea().Height() )
{
// This means that we have to invalidate adequately.
nChg = pViewShell->VisArea().Height() - pUp->getFrameArea().Height();
nInvaAdd = -(nDiff - nChg);
}
//Invalidate including bottom border.
long nBorder = nUpPrtBottom + 20;
nBorder -= nChg;
aInva.Top( aInva.Bottom() - (nBorder+nInvaAdd) );
if ( !IsBodyFrame() )
{
SetCompletePaint();
if ( !IsHeaderFrame() )
static_cast<SwFootnoteBossFrame*>(pUp)->FindBodyCont()->SetCompletePaint();
}
//Invalidate the page because of the frames. Thereby the page becomes
//the right size again if a frame didn't fit. This only works
//randomly for paragraph bound frames otherwise (NotifyFlys).
pUp->InvalidateSize();
}
if ( !bTst )
{
//Independent from nChg
if ( pViewShell && aInva.HasArea() && pUp->GetUpper() )
pViewShell->InvalidateWindows( aInva );
}
if ( !bTst && nChg )
{
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pUp);
aFrm.SSize().AdjustHeight(nChg );
}
{
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pUp);
aPrt.SSize().AdjustHeight(nChg );
}
if ( pViewShell )
pViewShell->Imp()->SetFirstVisPageInvalid();
if ( GetNext() )
GetNext()->InvalidatePos_();
//Trigger a repaint if necessary.
SvxBrushItem aBack(pUp->GetFormat()->makeBackgroundBrushItem());
const SvxGraphicPosition ePos = aBack.GetGraphicPos();
if ( ePos != GPOS_NONE && ePos != GPOS_TILED )
pViewShell->InvalidateWindows( pUp->getFrameArea() );
if ( pUp->GetUpper() )
{
if ( pUp->GetNext() )
pUp->GetNext()->InvalidatePos();
//Sad but true: during notify on ViewImp a Calc on the page and
//its Lower may be called. The values should not be changed
//because the caller takes care of the adjustment of Frame and
//Prt.
const long nOldFrameHeight = getFrameArea().Height();
const long nOldPrtHeight = getFramePrintArea().Height();
const bool bOldComplete = IsCompletePaint();
if ( IsBodyFrame() )
{
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
aPrt.SSize().setHeight( nOldFrameHeight );
}
if ( pUp->GetUpper() )
{
static_cast<SwRootFrame*>(pUp->GetUpper())->CheckViewLayout( nullptr, nullptr );
}
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aFrm.SSize().setHeight( nOldFrameHeight );
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
aPrt.SSize().setHeight( nOldPrtHeight );
mbCompletePaint = bOldComplete;
}
if ( !IsBodyFrame() )
pUp->InvalidateSize_();
InvalidatePage( static_cast<SwPageFrame*>(pUp) );
}
nDiff -= nChg;
if ( !nDiff )
return nChg;
else
nBrowseAdd = nChg;
}
const SwFootnoteBossFrame *pBoss = static_cast<SwFootnoteBossFrame*>(GetUpper());
SwTwips nReal = 0,
nAdd = 0;
SwFrame *pFrame = nullptr;
SwRectFnSet aRectFnSet(this);
if( IsBodyFrame() )
{
if( IsInSct() )
{
SwSectionFrame *pSect = FindSctFrame();
if( nDiff > 0 && pSect->IsEndnAtEnd() && GetNext() &&
GetNext()->IsFootnoteContFrame() )
{
SwFootnoteContFrame* pCont = static_cast<SwFootnoteContFrame*>(GetNext());
SwTwips nMinH = 0;
SwFootnoteFrame* pFootnote = static_cast<SwFootnoteFrame*>(pCont->Lower());
bool bFootnote = false;
while( pFootnote )
{
if( !pFootnote->GetAttr()->GetFootnote().IsEndNote() )
{
nMinH += aRectFnSet.GetHeight(pFootnote->getFrameArea());
bFootnote = true;
}
pFootnote = static_cast<SwFootnoteFrame*>(pFootnote->GetNext());
}
if( bFootnote )
nMinH += aRectFnSet.GetTop(pCont->getFramePrintArea());
nReal = aRectFnSet.GetHeight(pCont->getFrameArea()) - nMinH;
if( nReal > nDiff )
nReal = nDiff;
if( nReal > 0 )
pFrame = GetNext();
else
nReal = 0;
}
if( !bTst && !pSect->IsColLocked() )
pSect->InvalidateSize();
}
if( !pFrame )
return nBrowseAdd;
}
else
{
const bool bFootnotePage = pBoss->IsPageFrame() && static_cast<const SwPageFrame*>(pBoss)->IsFootnotePage();
if ( bFootnotePage && !IsFootnoteContFrame() )
pFrame = const_cast<SwFrame*>(static_cast<SwFrame const *>(pBoss->FindFootnoteCont()));
if ( !pFrame )
pFrame = const_cast<SwFrame*>(static_cast<SwFrame const *>(pBoss->FindBodyCont()));
if ( !pFrame )
return 0;
//If not one is found, everything else is solved.
nReal = aRectFnSet.GetHeight(pFrame->getFrameArea());
if( nReal > nDiff )
nReal = nDiff;
if( !bFootnotePage )
{
//Respect the minimal boundary!
if( nReal )
{
const SwTwips nMax = pBoss->GetVarSpace();
if ( nReal > nMax )
nReal = nMax;
}
if( !IsFootnoteContFrame() && nDiff > nReal &&
pFrame->GetNext() && pFrame->GetNext()->IsFootnoteContFrame()
&& ( pFrame->GetNext()->IsVertical() == IsVertical() )
)
{
//If the Body doesn't return enough, we look for a footnote, if
//there is one, we steal there accordingly.
const SwTwips nAddMax = aRectFnSet.GetHeight(pFrame->GetNext()->getFrameArea());
nAdd = nDiff - nReal;
if ( nAdd > nAddMax )
nAdd = nAddMax;
if ( !bTst )
{
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFrame->GetNext());
aRectFnSet.SetHeight(aFrm, nAddMax-nAdd);
if( aRectFnSet.IsVert() && !aRectFnSet.IsVertL2R() )
{
aFrm.Pos().AdjustX(nAdd );
}
}
pFrame->GetNext()->InvalidatePrt();
if ( pFrame->GetNext()->GetNext() )
{
pFrame->GetNext()->GetNext()->InvalidatePos_();
}
}
}
}
}
if ( !bTst && nReal )
{
SwTwips nTmp = aRectFnSet.GetHeight(pFrame->getFrameArea());
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFrame);
aRectFnSet.SetHeight( aFrm, nTmp - nReal );
if( aRectFnSet.IsVert() && !aRectFnSet.IsVertL2R() )
{
aFrm.Pos().AdjustX(nReal );
}
}
pFrame->InvalidatePrt();
if ( pFrame->GetNext() )
pFrame->GetNext()->InvalidatePos_();
if( nReal < 0 && pFrame->IsInSct() )
{
SwLayoutFrame* pUp = pFrame->GetUpper();
if( pUp && nullptr != ( pUp = pUp->GetUpper() ) && pUp->IsSctFrame() &&
!pUp->IsColLocked() )
pUp->InvalidateSize();
}
if( ( IsHeaderFrame() || IsFooterFrame() ) && pBoss->GetDrawObjs() )
{
const SwSortedObjs &rObjs = *pBoss->GetDrawObjs();
OSL_ENSURE( pBoss->IsPageFrame(), "Header/Footer out of page?" );
for (SwAnchoredObject* pAnchoredObj : rObjs)
{
if ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) != nullptr )
{
SwFlyFrame* pFly = static_cast<SwFlyFrame*>(pAnchoredObj);
OSL_ENSURE( !pFly->IsFlyInContentFrame(), "FlyInCnt at Page?" );
const SwFormatVertOrient &rVert =
pFly->GetFormat()->GetVertOrient();
// When do we have to invalidate?
// If a frame is aligned on a PageTextArea and the header
// changes a TOP, MIDDLE or NONE aligned frame needs to
// recalculate it's position; if the footer changes a BOTTOM
// or MIDDLE aligned frame needs to recalculate it's
// position.
if( ( rVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ||
rVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA ) &&
((IsHeaderFrame() && rVert.GetVertOrient()!=text::VertOrientation::BOTTOM) ||
(IsFooterFrame() && rVert.GetVertOrient()!=text::VertOrientation::NONE &&
rVert.GetVertOrient() != text::VertOrientation::TOP)) )
{
pFly->InvalidatePos_();
pFly->Invalidate_();
}
}
}
}
}
return (nBrowseAdd + nReal + nAdd);
}
/** method to perform additional actions on an invalidation (2004-05-19 #i28701#) */
void SwFrame::ActionOnInvalidation( const InvalidationType )
{
// default behaviour is to perform no additional action
}
/** method to determine, if an invalidation is allowed (2004-05-19 #i28701#) */
bool SwFrame::InvalidationAllowed( const InvalidationType ) const
{
// default behaviour is to allow invalidation
return true;
}
void SwFrame::ImplInvalidateSize()
{
if ( InvalidationAllowed( INVALID_SIZE ) )
{
setFrameAreaSizeValid(false);
if ( IsFlyFrame() )
static_cast<SwFlyFrame*>(this)->Invalidate_();
else
InvalidatePage();
// OD 2004-05-19 #i28701#
ActionOnInvalidation( INVALID_SIZE );
}
}
void SwFrame::ImplInvalidatePrt()
{
if ( InvalidationAllowed( INVALID_PRTAREA ) )
{
setFramePrintAreaValid(false);
if ( IsFlyFrame() )
static_cast<SwFlyFrame*>(this)->Invalidate_();
else
InvalidatePage();
// OD 2004-05-19 #i28701#
ActionOnInvalidation( INVALID_PRTAREA );
}
}
void SwFrame::ImplInvalidatePos()
{
if ( InvalidationAllowed( INVALID_POS ) )
{
setFrameAreaPositionValid(false);
if ( IsFlyFrame() )
{
static_cast<SwFlyFrame*>(this)->Invalidate_();
}
else
{
InvalidatePage();
}
// OD 2004-05-19 #i28701#
ActionOnInvalidation( INVALID_POS );
}
}
void SwFrame::ImplInvalidateLineNum()
{
if ( InvalidationAllowed( INVALID_LINENUM ) )
{
mbValidLineNum = false;
OSL_ENSURE( IsTextFrame(), "line numbers are implemented for text only" );
InvalidatePage();
// OD 2004-05-19 #i28701#
ActionOnInvalidation( INVALID_LINENUM );
}
}
void SwFrame::ReinitializeFrameSizeAttrFlags()
{
const SwFormatFrameSize &rFormatSize = GetAttrSet()->GetFrameSize();
if ( ATT_VAR_SIZE == rFormatSize.GetHeightSizeType() ||
ATT_MIN_SIZE == rFormatSize.GetHeightSizeType())
{
mbFixSize = false;
if ( GetType() & (SwFrameType::Header | SwFrameType::Footer | SwFrameType::Row) )
{
SwFrame *pFrame = static_cast<SwLayoutFrame*>(this)->Lower();
while ( pFrame )
{ pFrame->InvalidateSize_();
pFrame->InvalidatePrt_();
pFrame = pFrame->GetNext();
}
SwContentFrame *pCnt = static_cast<SwLayoutFrame*>(this)->ContainsContent();
// #i36991# - be save.
// E.g., a row can contain *no* content.
if ( pCnt )
{
pCnt->InvalidatePage();
do
{
pCnt->Prepare( PREP_ADJUST_FRM );
pCnt->InvalidateSize_();
pCnt = pCnt->GetNextContentFrame();
} while ( static_cast<SwLayoutFrame*>(this)->IsAnLower( pCnt ) );
}
}
}
else if ( rFormatSize.GetHeightSizeType() == ATT_FIX_SIZE )
{
if( IsVertical() )
ChgSize( Size( rFormatSize.GetWidth(), getFrameArea().Height()));
else
ChgSize( Size( getFrameArea().Width(), rFormatSize.GetHeight()));
}
}
void SwFrame::ValidateThisAndAllLowers( const sal_uInt16 nStage )
{
// Stage 0: Only validate frames. Do not process any objects.
// Stage 1: Only validate fly frames and all of their contents.
// Stage 2: Validate all.
const bool bOnlyObject = 1 == nStage;
const bool bIncludeObjects = 1 <= nStage;
if ( !bOnlyObject || dynamic_cast< const SwFlyFrame *>( this ) != nullptr )
{
setFrameAreaSizeValid(true);
setFramePrintAreaValid(true);
setFrameAreaPositionValid(true);
}
if ( bIncludeObjects )
{
const SwSortedObjs* pObjs = GetDrawObjs();
if ( pObjs )
{
const size_t nCnt = pObjs->size();
for ( size_t i = 0; i < nCnt; ++i )
{
SwAnchoredObject* pAnchObj = (*pObjs)[i];
if ( dynamic_cast< const SwFlyFrame *>( pAnchObj ) != nullptr )
static_cast<SwFlyFrame*>(pAnchObj)->ValidateThisAndAllLowers( 2 );
else if ( dynamic_cast< const SwAnchoredDrawObject *>( pAnchObj ) != nullptr )
static_cast<SwAnchoredDrawObject*>(pAnchObj)->ValidateThis();
}
}
}
if ( IsLayoutFrame() )
{
SwFrame* pLower = static_cast<SwLayoutFrame*>(this)->Lower();
while ( pLower )
{
pLower->ValidateThisAndAllLowers( nStage );
pLower = pLower->GetNext();
}
}
}
SwTwips SwContentFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo )
{
SwRectFnSet aRectFnSet(this);
SwTwips nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
if( nFrameHeight > 0 &&
nDist > (LONG_MAX - nFrameHeight ) )
nDist = LONG_MAX - nFrameHeight;
const SwViewShell *pSh = getRootFrame()->GetCurrShell();
const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
SwFrameType nTmpType = SwFrameType::Cell | SwFrameType::Column;
if (bBrowse)
nTmpType |= SwFrameType::Body;
if( !(GetUpper()->GetType() & nTmpType) && GetUpper()->HasFixSize() )
{
if ( !bTst )
{
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.SetHeight( aFrm, nFrameHeight + nDist );
if( IsVertical() && !IsVertLR() )
{
aFrm.Pos().AdjustX( -nDist );
}
}
if ( GetNext() )
{
GetNext()->InvalidatePos();
}
// #i28701# - Due to the new object positioning the
// frame on the next page/column can flow backward (e.g. it was moved forward
// due to the positioning of its objects ). Thus, invalivate this next frame,
// if document compatibility option 'Consider wrapping style influence on
// object positioning' is ON.
else if ( GetUpper()->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) )
{
InvalidateNextPos();
}
}
return 0;
}
SwTwips nReal = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea());
SwFrame *pFrame = GetUpper()->Lower();
while( pFrame && nReal > 0 )
{ nReal -= aRectFnSet.GetHeight(pFrame->getFrameArea());
pFrame = pFrame->GetNext();
}
if ( !bTst )
{
//Contents are always resized to the wished value.
long nOld = aRectFnSet.GetHeight(getFrameArea());
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.SetHeight( aFrm, nOld + nDist );
if( IsVertical()&& !IsVertLR() )
{
aFrm.Pos().AdjustX( -nDist );
}
}
SwTabFrame *pTab = (nOld && IsInTab()) ? FindTabFrame() : nullptr;
if (pTab)
{
if ( pTab->GetTable()->GetHTMLTableLayout() &&
!pTab->IsJoinLocked() &&
!pTab->GetFormat()->GetDoc()->GetDocShell()->IsReadOnly() )
{
pTab->InvalidatePos();
pTab->SetResizeHTMLTable();
}
}
}
//Only grow Upper if necessary.
if ( nReal < nDist )
{
if( GetUpper() )
{
if( bTst || !GetUpper()->IsFooterFrame() )
nReal = GetUpper()->Grow( nDist - std::max<long>(nReal, 0),
bTst, bInfo );
else
{
nReal = 0;
GetUpper()->InvalidateSize();
}
}
else
nReal = 0;
}
else
nReal = nDist;
// #i28701# - Due to the new object positioning the
// frame on the next page/column can flow backward (e.g. it was moved forward
// due to the positioning of its objects ). Thus, invalivate this next frame,
// if document compatibility option 'Consider wrapping style influence on
// object positioning' is ON.
if ( !bTst )
{
if ( GetNext() )
{
GetNext()->InvalidatePos();
}
else if ( GetUpper()->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) )
{
InvalidateNextPos();
}
}
return nReal;
}
SwTwips SwContentFrame::ShrinkFrame( SwTwips nDist, bool bTst, bool bInfo )
{
SwRectFnSet aRectFnSet(this);
OSL_ENSURE( nDist >= 0, "nDist < 0" );
OSL_ENSURE( nDist <= aRectFnSet.GetHeight(getFrameArea()),
"nDist > than current size." );
if ( !bTst )
{
SwTwips nRstHeight;
if( GetUpper() )
nRstHeight = aRectFnSet.BottomDist( getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()) );
else
nRstHeight = 0;
if( nRstHeight < 0 )
{
SwTwips nNextHeight = 0;
if( GetUpper()->IsSctFrame() && nDist > LONG_MAX/2 )
{
SwFrame *pNxt = GetNext();
while( pNxt )
{
nNextHeight += aRectFnSet.GetHeight(pNxt->getFrameArea());
pNxt = pNxt->GetNext();
}
}
nRstHeight = nDist + nRstHeight - nNextHeight;
}
else
{
nRstHeight = nDist;
}
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.SetHeight( aFrm, aRectFnSet.GetHeight(aFrm) - nDist );
if( IsVertical() && !IsVertLR() )
{
aFrm.Pos().AdjustX(nDist );
}
}
nDist = nRstHeight;
SwTabFrame *pTab = IsInTab() ? FindTabFrame() : nullptr;
if (pTab)
{
if ( pTab->GetTable()->GetHTMLTableLayout() &&
!pTab->IsJoinLocked() &&
!pTab->GetFormat()->GetDoc()->GetDocShell()->IsReadOnly() )
{
pTab->InvalidatePos();
pTab->SetResizeHTMLTable();
}
}
}
SwTwips nReal;
if( GetUpper() && nDist > 0 )
{
if( bTst || !GetUpper()->IsFooterFrame() )
nReal = GetUpper()->Shrink( nDist, bTst, bInfo );
else
{
nReal = 0;
// #108745# Sorry, dear old footer friend, I'm not gonna invalidate you,
// if there are any objects anchored inside your content, which
// overlap with the shrinking frame.
// This may lead to a footer frame that is too big, but this is better
// than looping.
// #109722# : The fix for #108745# was too strict.
bool bInvalidate = true;
const SwRect aRect( getFrameArea() );
const SwPageFrame* pPage = FindPageFrame();
const SwSortedObjs* pSorted = pPage ? pPage->GetSortedObjs() : nullptr;
if( pSorted )
{
for (SwAnchoredObject* pAnchoredObj : *pSorted)
{
const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
if( aBound.Left() > aRect.Right() )
continue;
if( aBound.IsOver( aRect ) )
{
const SwFrameFormat& rFormat = pAnchoredObj->GetFrameFormat();
if( css::text::WrapTextMode_THROUGH != rFormat.GetSurround().GetSurround() )
{
const SwFrame* pAnchor = pAnchoredObj->GetAnchorFrame();
if ( pAnchor && pAnchor->FindFooterOrHeader() == GetUpper() )
{
bInvalidate = false;
break;
}
}
}
}
}
if ( bInvalidate )
GetUpper()->InvalidateSize();
}
}
else
nReal = 0;
if ( !bTst )
{
//The position of the next Frame changes for sure.
InvalidateNextPos();
//If I don't have a successor I have to do the retouch by myself.
if ( !GetNext() )
SetRetouche();
}
return nReal;
}
void SwContentFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew )
{
sal_uInt8 nInvFlags = 0;
if( pNew && RES_ATTRSET_CHG == pNew->Which() && pOld )
{
SfxItemIter aNIter( *static_cast<const SwAttrSetChg*>(pNew)->GetChgSet() );
SfxItemIter aOIter( *static_cast<const SwAttrSetChg*>(pOld)->GetChgSet() );
SwAttrSetChg aOldSet( *static_cast<const SwAttrSetChg*>(pOld) );
SwAttrSetChg aNewSet( *static_cast<const SwAttrSetChg*>(pNew) );
while( true )
{
UpdateAttr_( aOIter.GetCurItem(),
aNIter.GetCurItem(), nInvFlags,
&aOldSet, &aNewSet );
if( aNIter.IsAtEnd() )
break;
aNIter.NextItem();
aOIter.NextItem();
}
if ( aOldSet.Count() || aNewSet.Count() )
SwFrame::Modify( &aOldSet, &aNewSet );
}
else
UpdateAttr_( pOld, pNew, nInvFlags );
if ( nInvFlags == 0 )
return;
SwPageFrame *pPage = FindPageFrame();
InvalidatePage( pPage );
if ( nInvFlags & 0x01 )
SetCompletePaint();
if ( nInvFlags & 0x02 )
InvalidatePos_();
if ( nInvFlags & 0x04 )
InvalidateSize_();
if ( nInvFlags & 0x88 )
{
if( IsInSct() && !GetPrev() )
{
SwSectionFrame *pSect = FindSctFrame();
if( pSect->ContainsAny() == this )
{
pSect->InvalidatePrt_();
pSect->InvalidatePage( pPage );
}
}
InvalidatePrt_();
}
SwFrame* pNextFrame = GetIndNext();
if ( pNextFrame && nInvFlags & 0x10)
{
pNextFrame->InvalidatePrt_();
pNextFrame->InvalidatePage( pPage );
}
if ( pNextFrame && nInvFlags & 0x80 )
{
pNextFrame->SetCompletePaint();
}
if ( nInvFlags & 0x20 )
{
SwFrame* pPrevFrame = GetPrev();
if ( pPrevFrame )
{
pPrevFrame->InvalidatePrt_();
pPrevFrame->InvalidatePage( pPage );
}
}
if ( nInvFlags & 0x40 )
InvalidateNextPos();
}
void SwContentFrame::UpdateAttr_( const SfxPoolItem* pOld, const SfxPoolItem* pNew,
sal_uInt8 &rInvFlags,
SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet )
{
bool bClear = true;
sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
switch ( nWhich )
{
case RES_FMT_CHG:
rInvFlags = 0xFF;
SAL_FALLTHROUGH;
case RES_PAGEDESC: //attribute changes (on/off)
if ( IsInDocBody() && !IsInTab() )
{
rInvFlags |= 0x02;
SwPageFrame *pPage = FindPageFrame();
if ( !GetPrev() )
CheckPageDescs( pPage );
if (GetPageDescItem().GetNumOffset())
static_cast<SwRootFrame*>(pPage->GetUpper())->SetVirtPageNum( true );
SwDocPosUpdate aMsgHint( pPage->getFrameArea().Top() );
pPage->GetFormat()->GetDoc()->getIDocumentFieldsAccess().UpdatePageFields( &aMsgHint );
}
break;
case RES_UL_SPACE:
{
// OD 2004-02-18 #106629# - correction
// Invalidation of the printing area of next frame, not only
// for footnote content.
if ( !GetIndNext() )
{
SwFrame* pNxt = FindNext();
if ( pNxt )
{
SwPageFrame* pPg = pNxt->FindPageFrame();
pNxt->InvalidatePage( pPg );
pNxt->InvalidatePrt_();
if( pNxt->IsSctFrame() )
{
SwFrame* pCnt = static_cast<SwSectionFrame*>(pNxt)->ContainsAny();
if( pCnt )
{
pCnt->InvalidatePrt_();
pCnt->InvalidatePage( pPg );
}
}
pNxt->SetCompletePaint();
}
}
// OD 2004-03-17 #i11860#
if ( GetIndNext() &&
!GetUpper()->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::USE_FORMER_OBJECT_POS) )
{
// OD 2004-07-01 #i28701# - use new method <InvalidateObjs(..)>
GetIndNext()->InvalidateObjs();
}
Prepare( PREP_UL_SPACE ); //TextFrame has to correct line spacing.
rInvFlags |= 0x80;
SAL_FALLTHROUGH;
}
case RES_LR_SPACE:
case RES_BOX:
case RES_SHADOW:
Prepare( PREP_FIXSIZE_CHG );
SwFrame::Modify( pOld, pNew );
rInvFlags |= 0x30;
break;
case RES_BREAK:
{
rInvFlags |= 0x42;
const IDocumentSettingAccess& rIDSA = GetUpper()->GetFormat()->getIDocumentSettingAccess();
if( rIDSA.get(DocumentSettingId::PARA_SPACE_MAX) ||
rIDSA.get(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES) )
{
rInvFlags |= 0x1;
SwFrame* pNxt = FindNext();
if( pNxt )
{
SwPageFrame* pPg = pNxt->FindPageFrame();
pNxt->InvalidatePage( pPg );
pNxt->InvalidatePrt_();
if( pNxt->IsSctFrame() )
{
SwFrame* pCnt = static_cast<SwSectionFrame*>(pNxt)->ContainsAny();
if( pCnt )
{
pCnt->InvalidatePrt_();
pCnt->InvalidatePage( pPg );
}
}
pNxt->SetCompletePaint();
}
}
}
break;
// OD 2004-02-26 #i25029#
case RES_PARATR_CONNECT_BORDER:
{
rInvFlags |= 0x01;
if ( IsTextFrame() )
{
InvalidateNextPrtArea();
}
if ( !GetIndNext() && IsInTab() && IsInSplitTableRow() )
{
FindTabFrame()->InvalidateSize();
}
}
break;
case RES_PARATR_TABSTOP:
case RES_CHRATR_SHADOWED:
case RES_CHRATR_AUTOKERN:
case RES_CHRATR_UNDERLINE:
case RES_CHRATR_OVERLINE:
case RES_CHRATR_KERNING:
case RES_CHRATR_FONT:
case RES_CHRATR_FONTSIZE:
case RES_CHRATR_ESCAPEMENT:
case RES_CHRATR_CONTOUR:
case RES_PARATR_NUMRULE:
rInvFlags |= 0x01;
break;
case RES_FRM_SIZE:
rInvFlags |= 0x01;
SAL_FALLTHROUGH;
default:
bClear = false;
}
if ( bClear )
{
if ( pOldSet || pNewSet )
{
if ( pOldSet )
pOldSet->ClearItem( nWhich );
if ( pNewSet )
pNewSet->ClearItem( nWhich );
}
else
SwFrame::Modify( pOld, pNew );
}
}
SwLayoutFrame::SwLayoutFrame(SwFrameFormat *const pFormat, SwFrame *const pSib)
: SwFrame(pFormat, pSib)
, m_pLower(nullptr)
{
const SwFormatFrameSize &rFormatSize = pFormat->GetFrameSize();
if ( rFormatSize.GetHeightSizeType() == ATT_FIX_SIZE )
mbFixSize = true;
}
// #i28701#
SwTwips SwLayoutFrame::InnerHeight() const
{
const SwFrame* pCnt = Lower();
if (!pCnt)
return 0;
SwRectFnSet aRectFnSet(this);
SwTwips nRet = 0;
if( pCnt->IsColumnFrame() || pCnt->IsCellFrame() )
{
do
{
SwTwips nTmp = static_cast<const SwLayoutFrame*>(pCnt)->InnerHeight();
if( pCnt->isFramePrintAreaValid() )
nTmp += aRectFnSet.GetHeight(pCnt->getFrameArea()) -
aRectFnSet.GetHeight(pCnt->getFramePrintArea());
if( nRet < nTmp )
nRet = nTmp;
pCnt = pCnt->GetNext();
} while ( pCnt );
}
else
{
do
{
nRet += aRectFnSet.GetHeight(pCnt->getFrameArea());
if( pCnt->IsContentFrame() && static_cast<const SwTextFrame*>(pCnt)->IsUndersized() )
nRet += static_cast<const SwTextFrame*>(pCnt)->GetParHeight() -
aRectFnSet.GetHeight(pCnt->getFramePrintArea());
if( pCnt->IsLayoutFrame() && !pCnt->IsTabFrame() )
nRet += static_cast<const SwLayoutFrame*>(pCnt)->InnerHeight() -
aRectFnSet.GetHeight(pCnt->getFramePrintArea());
pCnt = pCnt->GetNext();
} while( pCnt );
}
return nRet;
}
SwTwips SwLayoutFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo )
{
const SwViewShell *pSh = getRootFrame()->GetCurrShell();
const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
SwFrameType nTmpType = SwFrameType::Cell | SwFrameType::Column;
if (bBrowse)
nTmpType |= SwFrameType::Body;
if( !(GetType() & nTmpType) && HasFixSize() )
return 0;
SwRectFnSet aRectFnSet(this);
const SwTwips nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
const SwTwips nFramePos = getFrameArea().Pos().X();
if ( nFrameHeight > 0 && nDist > (LONG_MAX - nFrameHeight) )
nDist = LONG_MAX - nFrameHeight;
SwTwips nMin = 0;
if ( GetUpper() && !IsCellFrame() )
{
SwFrame *pFrame = GetUpper()->Lower();
while( pFrame )
{ nMin += aRectFnSet.GetHeight(pFrame->getFrameArea());
pFrame = pFrame->GetNext();
}
nMin = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea()) - nMin;
if ( nMin < 0 )
nMin = 0;
}
SwRect aOldFrame( getFrameArea() );
bool bMoveAccFrame = false;
bool bChgPos = IsVertical();
if ( !bTst )
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.SetHeight( aFrm, nFrameHeight + nDist );
if( bChgPos && !IsVertLR() )
{
aFrm.Pos().AdjustX( -nDist );
}
bMoveAccFrame = true;
}
SwTwips nReal = nDist - nMin;
if ( nReal > 0 )
{
if ( GetUpper() )
{ // AdjustNeighbourhood now only for the columns (but not in frames)
SwNeighbourAdjust nAdjust = GetUpper()->IsFootnoteBossFrame() ?
static_cast<SwFootnoteBossFrame*>(GetUpper())->NeighbourhoodAdjustment()
: SwNeighbourAdjust::GrowShrink;
if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
nReal = AdjustNeighbourhood( nReal, bTst );
else
{
if( SwNeighbourAdjust::AdjustGrow == nAdjust )
nReal += AdjustNeighbourhood( nReal, bTst );
SwTwips nGrow = 0;
if( 0 < nReal )
{
SwFrame* pToGrow = GetUpper();
// NEW TABLES
// A cell with a row span of > 1 is allowed to grow the
// line containing the end of the row span if it is
// located in the same table frame:
const SwCellFrame* pThisCell = dynamic_cast<const SwCellFrame*>(this);
if ( pThisCell && pThisCell->GetLayoutRowSpan() > 1 )
{
SwCellFrame& rEndCell = const_cast<SwCellFrame&>(pThisCell->FindStartEndOfRowSpanCell( false ));
if ( -1 == rEndCell.GetTabBox()->getRowSpan() )
pToGrow = rEndCell.GetUpper();
else
pToGrow = nullptr;
}
nGrow = pToGrow ? pToGrow->Grow( nReal, bTst, bInfo ) : 0;
}
if( SwNeighbourAdjust::GrowAdjust == nAdjust && nGrow < nReal )
nReal += AdjustNeighbourhood( nReal - nGrow, bTst );
if ( IsFootnoteFrame() && (nGrow != nReal) && GetNext() )
{
//Footnotes can replace their successor.
SwTwips nSpace = bTst ? 0 : -nDist;
const SwFrame *pFrame = GetUpper()->Lower();
do
{ nSpace += aRectFnSet.GetHeight(pFrame->getFrameArea());
pFrame = pFrame->GetNext();
} while ( pFrame != GetNext() );
nSpace = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea()) -nSpace;
if ( nSpace < 0 )
nSpace = 0;
nSpace += nGrow;
if ( nReal > nSpace )
nReal = nSpace;
if ( nReal && !bTst )
static_cast<SwFootnoteFrame*>(this)->InvalidateNxtFootnoteCnts( FindPageFrame() );
}
else
nReal = nGrow;
}
}
else
nReal = 0;
nReal += nMin;
}
else
nReal = nDist;
if ( !bTst )
{
if( nReal != nDist &&
// NEW TABLES
( !IsCellFrame() || static_cast<SwCellFrame*>(this)->GetLayoutRowSpan() > 1 ) )
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.SetHeight( aFrm, nFrameHeight + nReal );
if( bChgPos && !IsVertLR() )
{
aFrm.Pos().setX( nFramePos - nReal );
}
bMoveAccFrame = true;
}
if ( nReal )
{
SwPageFrame *pPage = FindPageFrame();
if ( GetNext() )
{
GetNext()->InvalidatePos_();
if ( GetNext()->IsContentFrame() )
GetNext()->InvalidatePage( pPage );
}
if ( !IsPageBodyFrame() )
{
InvalidateAll_();
InvalidatePage( pPage );
}
if (!(GetType() & (SwFrameType::Row|SwFrameType::Tab|SwFrameType::FtnCont|SwFrameType::Page|SwFrameType::Root)))
NotifyLowerObjs();
if( IsCellFrame() )
InvaPercentLowers( nReal );
SvxBrushItem aBack(GetFormat()->makeBackgroundBrushItem());
const SvxGraphicPosition ePos = aBack.GetGraphicPos();
if ( GPOS_NONE != ePos && GPOS_TILED != ePos )
SetCompletePaint();
}
}
if( bMoveAccFrame && IsAccessibleFrame() )
{
SwRootFrame *pRootFrame = getRootFrame();
if( pRootFrame && pRootFrame->IsAnyShellAccessible() &&
pRootFrame->GetCurrShell() )
{
pRootFrame->GetCurrShell()->Imp()->MoveAccessibleFrame( this, aOldFrame );
}
}
return nReal;
}
SwTwips SwLayoutFrame::ShrinkFrame( SwTwips nDist, bool bTst, bool bInfo )
{
const SwViewShell *pSh = getRootFrame()->GetCurrShell();
const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
SwFrameType nTmpType = SwFrameType::Cell | SwFrameType::Column;
if (bBrowse)
nTmpType |= SwFrameType::Body;
if (pSh && pSh->GetViewOptions()->IsWhitespaceHidden())
{
if (IsBodyFrame())
{
// Whitespace is hidden and this body frame will not shrink, as it
// has a fix size.
// Invalidate the page frame size, so in case the reason for the
// shrink was that there is more whitespace on this page, the size
// without whitespace will be recalculated correctly.
SwPageFrame* pPageFrame = FindPageFrame();
pPageFrame->InvalidateSize();
}
}
if( !(GetType() & nTmpType) && HasFixSize() )
return 0;
OSL_ENSURE( nDist >= 0, "nDist < 0" );
SwRectFnSet aRectFnSet(this);
SwTwips nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
if ( nDist > nFrameHeight )
nDist = nFrameHeight;
SwTwips nMin = 0;
bool bChgPos = IsVertical();
if ( Lower() )
{
if( !Lower()->IsNeighbourFrame() )
{ const SwFrame *pFrame = Lower();
const long nTmp = aRectFnSet.GetHeight(getFramePrintArea());
while( pFrame && nMin < nTmp )
{ nMin += aRectFnSet.GetHeight(pFrame->getFrameArea());
pFrame = pFrame->GetNext();
}
}
}
SwTwips nReal = nDist;
SwTwips nMinDiff = aRectFnSet.GetHeight(getFramePrintArea()) - nMin;
if( nReal > nMinDiff )
nReal = nMinDiff;
if( nReal <= 0 )
return nDist;
SwRect aOldFrame( getFrameArea() );
bool bMoveAccFrame = false;
SwTwips nRealDist = nReal;
if ( !bTst )
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.SetHeight( aFrm, nFrameHeight - nReal );
if( bChgPos && !IsVertLR() )
{
aFrm.Pos().AdjustX(nReal );
}
bMoveAccFrame = true;
}
SwNeighbourAdjust nAdjust = GetUpper() && GetUpper()->IsFootnoteBossFrame() ?
static_cast<SwFootnoteBossFrame*>(GetUpper())->NeighbourhoodAdjustment()
: SwNeighbourAdjust::GrowShrink;
// AdjustNeighbourhood also in columns (but not in frames)
if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
{
if ( IsPageBodyFrame() && !bBrowse )
nReal = nDist;
else
{ nReal = AdjustNeighbourhood( -nReal, bTst );
nReal *= -1;
if ( !bTst && IsBodyFrame() && nReal < nRealDist )
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.SetHeight( aFrm, aRectFnSet.GetHeight(aFrm) + nRealDist - nReal );
if( bChgPos && !IsVertLR() )
{
aFrm.Pos().AdjustX(nRealDist - nReal );
}
OSL_ENSURE( !IsAccessibleFrame(), "bMoveAccFrame has to be set!" );
}
}
}
else if( IsColumnFrame() || IsColBodyFrame() )
{
SwTwips nTmp = GetUpper()->Shrink( nReal, bTst, bInfo );
if ( nTmp != nReal )
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.SetHeight( aFrm, aRectFnSet.GetHeight(aFrm) + nReal - nTmp );
if( bChgPos && !IsVertLR() )
{
aFrm.Pos().AdjustX(nTmp - nReal );
}
OSL_ENSURE( !IsAccessibleFrame(), "bMoveAccFrame has to be set!" );
nReal = nTmp;
}
}
else
{
SwTwips nShrink = nReal;
SwFrame* pToShrink = GetUpper();
const SwCellFrame* pThisCell = dynamic_cast<const SwCellFrame*>(this);
// NEW TABLES
if ( pThisCell && pThisCell->GetLayoutRowSpan() > 1 )
{
SwCellFrame& rEndCell = const_cast<SwCellFrame&>(pThisCell->FindStartEndOfRowSpanCell( false ));
pToShrink = rEndCell.GetUpper();
}
nReal = pToShrink ? pToShrink->Shrink( nShrink, bTst, bInfo ) : 0;
if( ( SwNeighbourAdjust::GrowAdjust == nAdjust || SwNeighbourAdjust::AdjustGrow == nAdjust )
&& nReal < nShrink )
AdjustNeighbourhood( nReal - nShrink );
}
if( bMoveAccFrame && IsAccessibleFrame() )
{
SwRootFrame *pRootFrame = getRootFrame();
if( pRootFrame && pRootFrame->IsAnyShellAccessible() &&
pRootFrame->GetCurrShell() )
{
pRootFrame->GetCurrShell()->Imp()->MoveAccessibleFrame( this, aOldFrame );
}
}
if ( !bTst && (IsCellFrame() || IsColumnFrame() ? nReal : nRealDist) )
{
SwPageFrame *pPage = FindPageFrame();
if ( GetNext() )
{
GetNext()->InvalidatePos_();
if ( GetNext()->IsContentFrame() )
GetNext()->InvalidatePage( pPage );
if ( IsTabFrame() )
static_cast<SwTabFrame*>(this)->SetComplete();
}
else
{ if ( IsRetoucheFrame() )
SetRetouche();
if ( IsTabFrame() )
{
if( IsTabFrame() )
static_cast<SwTabFrame*>(this)->SetComplete();
if ( Lower() ) // Can also be in the Join and be empty!
InvalidateNextPos();
}
}
if ( !IsBodyFrame() )
{
InvalidateAll_();
InvalidatePage( pPage );
bool bCompletePaint = true;
const SwFrameFormat* pFormat = GetFormat();
if (pFormat)
{
SvxBrushItem aBack(pFormat->makeBackgroundBrushItem());
const SvxGraphicPosition ePos = aBack.GetGraphicPos();
if ( GPOS_NONE == ePos || GPOS_TILED == ePos )
bCompletePaint = false;
}
if (bCompletePaint)
SetCompletePaint();
}
if (!(GetType() & (SwFrameType::Row|SwFrameType::Tab|SwFrameType::FtnCont|SwFrameType::Page|SwFrameType::Root)))
NotifyLowerObjs();
if( IsCellFrame() )
InvaPercentLowers( nReal );
SwContentFrame *pCnt;
if( IsFootnoteFrame() && !static_cast<SwFootnoteFrame*>(this)->GetAttr()->GetFootnote().IsEndNote() &&
( GetFormat()->GetDoc()->GetFootnoteInfo().ePos != FTNPOS_CHAPTER ||
( IsInSct() && FindSctFrame()->IsFootnoteAtEnd() ) ) &&
nullptr != (pCnt = static_cast<SwFootnoteFrame*>(this)->GetRefFromAttr() ) )
{
if ( pCnt->IsFollow() )
{ // If we are in an other column/page than the frame with the
// reference, we don't need to invalidate its master.
SwFrame *pTmp = pCnt->FindFootnoteBossFrame(true) == FindFootnoteBossFrame(true)
? &pCnt->FindMaster()->GetFrame() : pCnt;
pTmp->Prepare( PREP_ADJUST_FRM );
pTmp->InvalidateSize();
}
else
pCnt->InvalidatePos();
}
}
return nReal;
}
/**
* Changes the size of the directly subsidiary Frame's that have a fixed size, proportionally to the
* size change of the PrtArea of the Frame's.
*
* The variable Frames are also proportionally adapted; they will grow/shrink again by themselves.
*/
void SwLayoutFrame::ChgLowersProp( const Size& rOldSize )
{
// no change of lower properties for root frame or if no lower exists.
if ( IsRootFrame() || !Lower() )
return;
// declare and init <SwFrame* pLowerFrame> with first lower
SwFrame *pLowerFrame = Lower();
// declare and init const booleans <bHeightChgd> and <bWidthChg>
const bool bHeightChgd = rOldSize.Height() != getFramePrintArea().Height();
const bool bWidthChgd = rOldSize.Width() != getFramePrintArea().Width();
SwRectFnSet aRectFnSet(this);
// This shortcut basically tries to handle only lower frames that
// are affected by the size change. Otherwise much more lower frames
// are invalidated.
if ( !( aRectFnSet.IsVert() ? bHeightChgd : bWidthChgd ) &&
! Lower()->IsColumnFrame() &&
( ( IsBodyFrame() && IsInDocBody() && ( !IsInSct() || !FindSctFrame()->IsColLocked() ) ) ||
// #i10826# Section frames without columns should not
// invalidate all lowers!
IsSctFrame() ) )
{
// Determine page frame the body frame resp. the section frame belongs to.
SwPageFrame *pPage = FindPageFrame();
// Determine last lower by traveling through them using <GetNext()>.
// During travel check each section frame, if it will be sized to
// maximum. If Yes, invalidate size of section frame and set
// corresponding flags at the page.
do
{
if( pLowerFrame->IsSctFrame() && static_cast<SwSectionFrame*>(pLowerFrame)->ToMaximize_() )
{
pLowerFrame->InvalidateSize_();
pLowerFrame->InvalidatePage( pPage );
}
if( pLowerFrame->GetNext() )
pLowerFrame = pLowerFrame->GetNext();
else
break;
} while( true );
// If found last lower is a section frame containing no section
// (section frame isn't valid and will be deleted in the future),
// travel backwards.
while( pLowerFrame->IsSctFrame() && !static_cast<SwSectionFrame*>(pLowerFrame)->GetSection() &&
pLowerFrame->GetPrev() )
pLowerFrame = pLowerFrame->GetPrev();
// If found last lower is a section frame, set <pLowerFrame> to its last
// content, if the section frame is valid and is not sized to maximum.
// Otherwise set <pLowerFrame> to NULL - In this case body frame only
// contains invalid section frames.
if( pLowerFrame->IsSctFrame() )
pLowerFrame = static_cast<SwSectionFrame*>(pLowerFrame)->GetSection() &&
!static_cast<SwSectionFrame*>(pLowerFrame)->ToMaximize( false ) ?
static_cast<SwSectionFrame*>(pLowerFrame)->FindLastContent() : nullptr;
// continue with found last lower, probably the last content of a section
if ( pLowerFrame )
{
// If <pLowerFrame> is in a table frame, set <pLowerFrame> to this table
// frame and continue.
if ( pLowerFrame->IsInTab() )
{
// OD 28.10.2002 #97265# - safeguard for setting <pLowerFrame> to
// its table frame - check, if the table frame is also a lower
// of the body frame, in order to assure that <pLowerFrame> is not
// set to a frame, which is an *upper* of the body frame.
SwFrame* pTableFrame = pLowerFrame->FindTabFrame();
if ( IsAnLower( pTableFrame ) )
{
pLowerFrame = pTableFrame;
}
}
// Check, if variable size of body frame resp. section frame has grown
// OD 28.10.2002 #97265# - correct check, if variable size has grown.
SwTwips nOldHeight = aRectFnSet.IsVert() ? rOldSize.Width() : rOldSize.Height();
if( nOldHeight < aRectFnSet.GetHeight(getFramePrintArea()) )
{
// If variable size of body|section frame has grown, only found
// last lower and the position of the its next have to be invalidated.
pLowerFrame->InvalidateAll_();
pLowerFrame->InvalidatePage( pPage );
if( !pLowerFrame->IsFlowFrame() ||
!SwFlowFrame::CastFlowFrame( pLowerFrame )->HasFollow() )
pLowerFrame->InvalidateNextPos( true );
if ( pLowerFrame->IsTextFrame() )
static_cast<SwContentFrame*>(pLowerFrame)->Prepare( PREP_ADJUST_FRM );
}
else
{
// variable size of body|section frame has shrunk. Thus,
// invalidate all lowers not matching the new body|section size
// and the dedicated new last lower.
if( aRectFnSet.IsVert() )
{
SwTwips nBot = getFrameArea().Left() + getFramePrintArea().Left();
while ( pLowerFrame && pLowerFrame->GetPrev() && pLowerFrame->getFrameArea().Left() < nBot )
{
pLowerFrame->InvalidateAll_();
pLowerFrame->InvalidatePage( pPage );
pLowerFrame = pLowerFrame->GetPrev();
}
}
else
{
SwTwips nBot = getFrameArea().Top() + getFramePrintArea().Bottom();
while ( pLowerFrame && pLowerFrame->GetPrev() && pLowerFrame->getFrameArea().Top() > nBot )
{
pLowerFrame->InvalidateAll_();
pLowerFrame->InvalidatePage( pPage );
pLowerFrame = pLowerFrame->GetPrev();
}
}
if ( pLowerFrame )
{
pLowerFrame->InvalidateSize_();
pLowerFrame->InvalidatePage( pPage );
if ( pLowerFrame->IsTextFrame() )
static_cast<SwContentFrame*>(pLowerFrame)->Prepare( PREP_ADJUST_FRM );
}
}
// #i41694# - improvement by removing duplicates
if ( pLowerFrame )
{
if ( pLowerFrame->IsInSct() )
{
// #i41694# - follow-up of issue #i10826#
// No invalidation of section frame, if it's the this.
SwFrame* pSectFrame = pLowerFrame->FindSctFrame();
if( pSectFrame != this && IsAnLower( pSectFrame ) )
{
pSectFrame->InvalidateSize_();
pSectFrame->InvalidatePage( pPage );
}
}
}
}
return;
} // end of { special case }
// Invalidate page for content only once.
bool bInvaPageForContent = true;
// Declare booleans <bFixChgd> and <bVarChgd>, indicating for text frame
// adjustment, if fixed/variable size has changed.
bool bFixChgd, bVarChgd;
if( aRectFnSet.IsVert() == pLowerFrame->IsNeighbourFrame() )
{
bFixChgd = bWidthChgd;
bVarChgd = bHeightChgd;
}
else
{
bFixChgd = bHeightChgd;
bVarChgd = bWidthChgd;
}
// Declare const unsigned short <nFixWidth> and init it this frame types
// which has fixed width in vertical respectively horizontal layout.
// In vertical layout these are neighbour frames (cell and column frames),
// header frames and footer frames.
// In horizontal layout these are all frames, which aren't neighbour frames.
const SwFrameType nFixWidth = aRectFnSet.IsVert() ? (FRM_NEIGHBOUR | FRM_HEADFOOT)
: ~SwFrameType(FRM_NEIGHBOUR);
// Declare const unsigned short <nFixHeight> and init it this frame types
// which has fixed height in vertical respectively horizontal layout.
// In vertical layout these are all frames, which aren't neighbour frames,
// header frames, footer frames, body frames or foot note container frames.
// In horizontal layout these are neighbour frames.
const SwFrameType nFixHeight = aRectFnSet.IsVert() ? ~SwFrameType(FRM_NEIGHBOUR | FRM_HEADFOOT | FRM_BODYFTNC)
: FRM_NEIGHBOUR;
// Travel through all lowers using <GetNext()>
while ( pLowerFrame )
{
if ( pLowerFrame->IsTextFrame() )
{
// Text frames will only be invalidated - prepare invalidation
if ( bFixChgd )
static_cast<SwContentFrame*>(pLowerFrame)->Prepare( PREP_FIXSIZE_CHG );
if ( bVarChgd )
static_cast<SwContentFrame*>(pLowerFrame)->Prepare( PREP_ADJUST_FRM );
}
else
{
// If lower isn't a table, row, cell or section frame, adjust its
// frame size.
const SwFrameType nLowerType = pLowerFrame->GetType();
if ( !(nLowerType & (SwFrameType::Tab|SwFrameType::Row|SwFrameType::Cell|SwFrameType::Section)) )
{
if ( bWidthChgd )
{
if( nLowerType & nFixWidth )
{
// Considering previous conditions:
// In vertical layout set width of column, header and
// footer frames to its upper width.
// In horizontal layout set width of header, footer,
// foot note container, foot note, body and no-text
// frames to its upper width.
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pLowerFrame);
aFrm.Width( getFramePrintArea().Width() );
}
else if( rOldSize.Width() && !pLowerFrame->IsFootnoteFrame() )
{
// Adjust frame width proportional, if lower isn't a
// foot note frame and condition <nLowerType & nFixWidth>
// isn't true.
// Considering previous conditions:
// In vertical layout these are foot note container,
// body and no-text frames.
// In horizontal layout these are column and no-text frames.
// OD 24.10.2002 #97265# - <double> calculation
// Perform <double> calculation of new width, if
// one of the coefficients is greater than 50000
SwTwips nNewWidth;
if ( (pLowerFrame->getFrameArea().Width() > 50000) ||
(getFramePrintArea().Width() > 50000) )
{
double nNewWidthTmp =
( double(pLowerFrame->getFrameArea().Width())
* double(getFramePrintArea().Width()) )
/ double(rOldSize.Width());
nNewWidth = SwTwips(nNewWidthTmp);
}
else
{
nNewWidth =
(pLowerFrame->getFrameArea().Width() * getFramePrintArea().Width()) / rOldSize.Width();
}
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pLowerFrame);
aFrm.Width( nNewWidth );
}
}
if ( bHeightChgd )
{
if( nLowerType & nFixHeight )
{
// Considering previous conditions:
// In vertical layout set height of foot note and
// no-text frames to its upper height.
// In horizontal layout set height of column frames
// to its upper height.
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pLowerFrame);
aFrm.Height( getFramePrintArea().Height() );
}
// OD 01.10.2002 #102211#
// add conditions <!pLowerFrame->IsHeaderFrame()> and
// <!pLowerFrame->IsFooterFrame()> in order to avoid that
// the <Grow> of header or footer are overwritten.
// NOTE: Height of header/footer frame is determined by contents.
else if ( rOldSize.Height() &&
!pLowerFrame->IsFootnoteFrame() &&
!pLowerFrame->IsHeaderFrame() &&
!pLowerFrame->IsFooterFrame()
)
{
// Adjust frame height proportional, if lower isn't a
// foot note, a header or a footer frame and
// condition <nLowerType & nFixHeight> isn't true.
// Considering previous conditions:
// In vertical layout these are column, foot note container,
// body and no-text frames.
// In horizontal layout these are column, foot note
// container, body and no-text frames.
// OD 29.10.2002 #97265# - special case for page lowers
// The page lowers that have to be adjusted on page height
// change are the body frame and the foot note container
// frame.
// In vertical layout the height of both is directly
// adjusted to the page height change.
// In horizontal layout the height of the body frame is
// directly adjusted to the page height change and the
// foot note frame height isn't touched, because its
// determined by its content.
// OD 31.03.2003 #108446# - apply special case for page
// lowers - see description above - also for section columns.
if ( IsPageFrame() ||
( IsColumnFrame() && IsInSct() )
)
{
OSL_ENSURE( pLowerFrame->IsBodyFrame() || pLowerFrame->IsFootnoteContFrame(),
"ChgLowersProp - only for body or foot note container" );
if ( pLowerFrame->IsBodyFrame() || pLowerFrame->IsFootnoteContFrame() )
{
if ( IsVertical() || pLowerFrame->IsBodyFrame() )
{
SwTwips nNewHeight =
pLowerFrame->getFrameArea().Height() +
( getFramePrintArea().Height() - rOldSize.Height() );
if ( nNewHeight < 0)
{
// OD 01.04.2003 #108446# - adjust assertion condition and text
OSL_ENSURE( !( IsPageFrame() &&
(pLowerFrame->getFrameArea().Height()>0) &&
(pLowerFrame->isFrameAreaDefinitionValid()) ),
"ChgLowersProg - negative height for lower.");
nNewHeight = 0;
}
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pLowerFrame);
aFrm.Height( nNewHeight );
}
}
}
else
{
SwTwips nNewHeight;
// OD 24.10.2002 #97265# - <double> calculation
// Perform <double> calculation of new height, if
// one of the coefficients is greater than 50000
if ( (pLowerFrame->getFrameArea().Height() > 50000) ||
(getFramePrintArea().Height() > 50000) )
{
double nNewHeightTmp =
( double(pLowerFrame->getFrameArea().Height())
* double(getFramePrintArea().Height()) )
/ double(rOldSize.Height());
nNewHeight = SwTwips(nNewHeightTmp);
}
else
{
nNewHeight = ( pLowerFrame->getFrameArea().Height()
* getFramePrintArea().Height() ) / rOldSize.Height();
}
if( !pLowerFrame->GetNext() )
{
SwTwips nSum = getFramePrintArea().Height();
SwFrame* pTmp = Lower();
while( pTmp->GetNext() )
{
if( !pTmp->IsFootnoteContFrame() || !pTmp->IsVertical() )
nSum -= pTmp->getFrameArea().Height();
pTmp = pTmp->GetNext();
}
if( nSum - nNewHeight == 1 &&
nSum == pLowerFrame->getFrameArea().Height() )
nNewHeight = nSum;
}
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pLowerFrame);
aFrm.Height( nNewHeight );
}
}
}
}
} // end of else { NOT text frame }
pLowerFrame->InvalidateAll_();
if ( bInvaPageForContent && pLowerFrame->IsContentFrame() )
{
pLowerFrame->InvalidatePage();
bInvaPageForContent = false;
}
if ( !pLowerFrame->GetNext() && pLowerFrame->IsRetoucheFrame() )
{
//If a growth took place and the subordinate elements can retouch
//itself (currently Tabs, Sections and Content) we trigger it.
if ( rOldSize.Height() < getFramePrintArea().SSize().Height() ||
rOldSize.Width() < getFramePrintArea().SSize().Width() )
pLowerFrame->SetRetouche();
}
pLowerFrame = pLowerFrame->GetNext();
}
// Finally adjust the columns if width is set to auto
// Possible optimization: execute this code earlier in this function and
// return???
if ( ( (aRectFnSet.IsVert() && bHeightChgd) || (! aRectFnSet.IsVert() && bWidthChgd) ) &&
Lower()->IsColumnFrame() )
{
// get column attribute
const SwFormatCol* pColAttr = nullptr;
if ( IsPageBodyFrame() )
{
OSL_ENSURE( GetUpper()->IsPageFrame(), "Upper is not page frame" );
pColAttr = &GetUpper()->GetFormat()->GetCol();
}
else
{
OSL_ENSURE( IsFlyFrame() || IsSctFrame(), "Columns not in fly or section" );
pColAttr = &GetFormat()->GetCol();
}
if ( pColAttr->IsOrtho() && pColAttr->GetNumCols() > 1 )
AdjustColumns( pColAttr, false );
}
}
/** "Formats" the Frame; Frame and PrtArea.
*
* The Fixsize is not set here.
*/
void SwLayoutFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs *pAttrs )
{
OSL_ENSURE( pAttrs, "LayoutFrame::Format, pAttrs is 0." );
if ( isFramePrintAreaValid() && isFrameAreaSizeValid() )
return;
bool bHideWhitespace = false;
if (IsPageFrame())
{
SwViewShell* pShell = getRootFrame()->GetCurrShell();
if (pShell && pShell->GetViewOptions()->IsWhitespaceHidden())
{
// This is needed so that no space is reserved for the margin on
// the last page of the document. Other pages would have no margin
// set even without this, as their frame height is the content
// height already.
bHideWhitespace = true;
}
}
const sal_uInt16 nLeft = static_cast<sal_uInt16>(pAttrs->CalcLeft(this));
const sal_uInt16 nUpper = bHideWhitespace ? 0 : pAttrs->CalcTop();
const sal_uInt16 nRight = static_cast<sal_uInt16>(pAttrs->CalcRight(this));
const sal_uInt16 nLower = bHideWhitespace ? 0 : pAttrs->CalcBottom();
const bool bVert = IsVertical() && !IsPageFrame();
SwRectFn fnRect = bVert ? ( IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori;
if ( !isFramePrintAreaValid() )
{
setFramePrintAreaValid(true);
(this->*fnRect->fnSetXMargins)( nLeft, nRight );
(this->*fnRect->fnSetYMargins)( nUpper, nLower );
}
if ( !isFrameAreaSizeValid() )
{
if ( !HasFixSize() )
{
const SwTwips nBorder = nUpper + nLower;
const SwFormatFrameSize &rSz = GetFormat()->GetFrameSize();
SwTwips nMinHeight = rSz.GetHeightSizeType() == ATT_MIN_SIZE ? rSz.GetHeight() : 0;
do
{
setFrameAreaSizeValid(true);
//The size in VarSize is calculated using the content plus the
// borders.
SwTwips nRemaining = 0;
SwFrame *pFrame = Lower();
while ( pFrame )
{ nRemaining += (pFrame->getFrameArea().*fnRect->fnGetHeight)();
if( pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsUndersized() )
// This TextFrame would like to be a bit bigger
nRemaining += static_cast<SwTextFrame*>(pFrame)->GetParHeight()
- (pFrame->getFramePrintArea().*fnRect->fnGetHeight)();
else if( pFrame->IsSctFrame() && static_cast<SwSectionFrame*>(pFrame)->IsUndersized() )
nRemaining += static_cast<SwSectionFrame*>(pFrame)->Undersize();
pFrame = pFrame->GetNext();
}
nRemaining += nBorder;
nRemaining = std::max( nRemaining, nMinHeight );
const SwTwips nDiff = nRemaining-(getFrameArea().*fnRect->fnGetHeight)();
const long nOldLeft = (getFrameArea().*fnRect->fnGetLeft)();
const long nOldTop = (getFrameArea().*fnRect->fnGetTop)();
if ( nDiff )
{
if ( nDiff > 0 )
Grow( nDiff );
else
Shrink( -nDiff );
//Updates the positions using the fast channel.
MakePos();
}
//Don't exceed the bottom edge of the Upper.
if ( GetUpper() && (getFrameArea().*fnRect->fnGetHeight)() )
{
const SwTwips nLimit = (GetUpper()->*fnRect->fnGetPrtBottom)();
if( (this->*fnRect->fnSetLimit)( nLimit ) &&
nOldLeft == (getFrameArea().*fnRect->fnGetLeft)() &&
nOldTop == (getFrameArea().*fnRect->fnGetTop)() )
{
setFrameAreaSizeValid(true);
setFramePrintAreaValid(true);
}
}
} while ( !isFrameAreaSizeValid() );
}
else if (GetType() & FRM_HEADFOOT)
{
do
{ if ( getFrameArea().Height() != pAttrs->GetSize().Height() )
{
ChgSize( Size( getFrameArea().Width(), pAttrs->GetSize().Height()));
}
setFrameAreaSizeValid(true);
MakePos();
} while ( !isFrameAreaSizeValid() );
}
else
{
setFrameAreaSizeValid(true);
}
// While updating the size, PrtArea might be invalidated.
if (!isFramePrintAreaValid())
{
setFramePrintAreaValid(true);
(this->*fnRect->fnSetXMargins)(nLeft, nRight);
(this->*fnRect->fnSetYMargins)(nUpper, nLower);
}
}
}
static void InvaPercentFlys( SwFrame *pFrame, SwTwips nDiff )
{
OSL_ENSURE( pFrame->GetDrawObjs(), "Can't find any Objects" );
for (SwAnchoredObject* pAnchoredObj : *pFrame->GetDrawObjs())
{
if ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) != nullptr )
{
SwFlyFrame *pFly = static_cast<SwFlyFrame*>(pAnchoredObj);
const SwFormatFrameSize &rSz = pFly->GetFormat()->GetFrameSize();
if ( rSz.GetWidthPercent() || rSz.GetHeightPercent() )
{
bool bNotify = true;
// If we've a fly with more than 90% relative height...
if( rSz.GetHeightPercent() > 90 && pFly->GetAnchorFrame() &&
rSz.GetHeightPercent() != SwFormatFrameSize::SYNCED && nDiff )
{
const SwFrame *pRel = pFly->IsFlyLayFrame() ? pFly->GetAnchorFrame():
pFly->GetAnchorFrame()->GetUpper();
// ... and we have already more than 90% height and we
// not allow the text to go through...
// then a notification could cause an endless loop, e.g.
// 100% height and no text wrap inside a cell of a table.
if( pFly->getFrameArea().Height()*10 >
( nDiff + pRel->getFramePrintArea().Height() )*9 &&
pFly->GetFormat()->GetSurround().GetSurround() !=
css::text::WrapTextMode_THROUGH )
bNotify = false;
}
if( bNotify )
pFly->InvalidateSize();
}
}
}
}
void SwLayoutFrame::InvaPercentLowers( SwTwips nDiff )
{
if ( GetDrawObjs() )
::InvaPercentFlys( this, nDiff );
SwFrame *pFrame = ContainsContent();
if ( pFrame )
do
{
if ( pFrame->IsInTab() && !IsTabFrame() )
{
SwFrame *pTmp = pFrame->FindTabFrame();
OSL_ENSURE( pTmp, "Where's my TabFrame?" );
if( IsAnLower( pTmp ) )
pFrame = pTmp;
}
if ( pFrame->IsTabFrame() )
{
const SwFormatFrameSize &rSz = static_cast<SwLayoutFrame*>(pFrame)->GetFormat()->GetFrameSize();
if ( rSz.GetWidthPercent() || rSz.GetHeightPercent() )
pFrame->InvalidatePrt();
}
else if ( pFrame->GetDrawObjs() )
::InvaPercentFlys( pFrame, nDiff );
pFrame = pFrame->FindNextCnt();
} while ( pFrame && IsAnLower( pFrame ) ) ;
}
long SwLayoutFrame::CalcRel( const SwFormatFrameSize &rSz ) const
{
long nRet = rSz.GetWidth(),
nPercent = rSz.GetWidthPercent();
if ( nPercent )
{
const SwFrame *pRel = GetUpper();
long nRel = LONG_MAX;
const SwViewShell *pSh = getRootFrame()->GetCurrShell();
const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
if( pRel->IsPageBodyFrame() && pSh && bBrowseMode && pSh->VisArea().Width() )
{
nRel = pSh->GetBrowseWidth();
long nDiff = nRel - pRel->getFramePrintArea().Width();
if ( nDiff > 0 )
nRel -= nDiff;
}
nRel = std::min( nRel, pRel->getFramePrintArea().Width() );
nRet = nRel * nPercent / 100;
}
return nRet;
}
// Local helpers for SwLayoutFrame::FormatWidthCols()
static long lcl_CalcMinColDiff( SwLayoutFrame *pLayFrame )
{
long nDiff = 0, nFirstDiff = 0;
SwLayoutFrame *pCol = static_cast<SwLayoutFrame*>(pLayFrame->Lower());
OSL_ENSURE( pCol, "Where's the columnframe?" );
SwFrame *pFrame = pCol->Lower();
do
{
if( pFrame && pFrame->IsBodyFrame() )
pFrame = static_cast<SwBodyFrame*>(pFrame)->Lower();
if ( pFrame && pFrame->IsTextFrame() )
{
const long nTmp = static_cast<SwTextFrame*>(pFrame)->FirstLineHeight();
if ( nTmp != USHRT_MAX )
{
if ( pCol == pLayFrame->Lower() )
nFirstDiff = nTmp;
else
nDiff = nDiff ? std::min( nDiff, nTmp ) : nTmp;
}
}
//Skip empty columns!
pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
while ( pCol && nullptr == (pFrame = pCol->Lower()) )
pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
} while ( pFrame && pCol );
return nDiff ? nDiff : nFirstDiff ? nFirstDiff : 240;
}
static bool lcl_IsFlyHeightClipped( SwLayoutFrame *pLay )
{
SwFrame *pFrame = pLay->ContainsContent();
while ( pFrame )
{
if ( pFrame->IsInTab() )
pFrame = pFrame->FindTabFrame();
if ( pFrame->GetDrawObjs() )
{
const size_t nCnt = pFrame->GetDrawObjs()->size();
for ( size_t i = 0; i < nCnt; ++i )
{
SwAnchoredObject* pAnchoredObj = (*pFrame->GetDrawObjs())[i];
if ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) != nullptr )
{
SwFlyFrame* pFly = static_cast<SwFlyFrame*>(pAnchoredObj);
if ( pFly->IsHeightClipped() &&
( !pFly->IsFlyFreeFrame() || pFly->GetPageFrame() ) )
return true;
}
}
}
pFrame = pFrame->FindNextCnt();
}
return false;
}
void SwLayoutFrame::FormatWidthCols( const SwBorderAttrs &rAttrs,
const SwTwips nBorder, const SwTwips nMinHeight )
{
//If there are columns involved, the size is adjusted using the last column.
//1. Format content.
//2. Calculate height of the last column: if it's too big, the Fly has to
// grow. The amount by which the Fly grows is not the amount of the
// overhang because we have to act on the assumption that some text flows
// back which will generate some more space.
// The amount which we grow by equals the overhang
// divided by the amount of columns or the overhang itself if it's smaller
// than the amount of columns.
//3. Go back to 1. until everything is stable.
const SwFormatCol &rCol = rAttrs.GetAttrSet().GetCol();
const sal_uInt16 nNumCols = rCol.GetNumCols();
bool bEnd = false;
bool bBackLock = false;
SwViewShell *pSh = getRootFrame()->GetCurrShell();
SwViewShellImp *pImp = pSh ? pSh->Imp() : nullptr;
vcl::RenderContext* pRenderContext = pSh ? pSh->GetOut() : nullptr;
{
// Underlying algorithm
// We try to find the optimal height for the column.
// nMinimum starts with the passed minimum height and is then remembered
// as the maximum height on which column content still juts out of a
// column.
// nMaximum starts with LONG_MAX and is then remembered as the minimum
// width on which the content fitted.
// In column based sections nMaximum starts at the maximum value which
// the surrounding defines, this can certainly be a value on which
// content still juts out.
// The columns are formatted. If content still juts out, nMinimum is
// adjusted accordingly, then we grow, at least by uMinDiff but not
// over a certain nMaximum. If no content juts out but there is still
// some space left in the column, shrinking is done accordingly, at
// least by nMindIff but not below the nMinimum.
// Cancel as soon as no content juts out and the difference from minimum
// to maximum is less than MinDiff or the maximum which was defined by
// the surrounding is reached even if some content still juts out.
// Criticism of this implementation
// 1. Theoretically situations are possible in which the content fits in
// a lower height but not in a higher height. To ensure that the code
// handles such situations the code contains a few checks concerning
// minimum and maximum which probably are never triggered.
// 2. We use the same nMinDiff for shrinking and growing, but nMinDiff
// is more or less the smallest first line height and doesn't seem ideal
// as minimum value.
long nMinimum = nMinHeight;
long nMaximum;
bool bNoBalance = false;
SwRectFnSet aRectFnSet(this);
if( IsSctFrame() )
{
nMaximum = aRectFnSet.GetHeight(getFrameArea()) - nBorder +
aRectFnSet.BottomDist(getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()));
nMaximum += GetUpper()->Grow( LONG_MAX, true );
if( nMaximum < nMinimum )
{
if( nMaximum < 0 )
nMinimum = nMaximum = 0;
else
nMinimum = nMaximum;
}
if( nMaximum > BROWSE_HEIGHT )
nMaximum = BROWSE_HEIGHT;
bNoBalance = static_cast<SwSectionFrame*>(this)->GetSection()->GetFormat()->
GetBalancedColumns().GetValue();
SwFrame* pAny = ContainsAny();
if( bNoBalance ||
( !aRectFnSet.GetHeight(getFrameArea()) && pAny ) )
{
long nTop = aRectFnSet.GetTopMargin(*this);
// #i23129# - correction
// to the calculated maximum height.
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.AddBottom( aFrm, nMaximum - aRectFnSet.GetHeight(getFrameArea()) );
}
if( nTop > nMaximum )
nTop = nMaximum;
aRectFnSet.SetYMargins( *this, nTop, 0 );
}
if( !pAny && !static_cast<SwSectionFrame*>(this)->IsFootnoteLock() )
{
SwFootnoteContFrame* pFootnoteCont = static_cast<SwSectionFrame*>(this)->ContainsFootnoteCont();
if( pFootnoteCont )
{
SwFrame* pFootnoteAny = pFootnoteCont->ContainsAny();
if( pFootnoteAny && pFootnoteAny->isFrameAreaDefinitionValid() )
{
bBackLock = true;
static_cast<SwSectionFrame*>(this)->SetFootnoteLock( true );
}
}
}
}
else
nMaximum = LONG_MAX;
// #i3317# - reset temporarily consideration
// of wrapping style influence
SwPageFrame* pPageFrame = FindPageFrame();
SwSortedObjs* pObjs = pPageFrame ? pPageFrame->GetSortedObjs() : nullptr;
if ( pObjs )
{
for (SwAnchoredObject* pAnchoredObj : *pObjs)
{
if ( IsAnLower( pAnchoredObj->GetAnchorFrame() ) )
{
pAnchoredObj->SetTmpConsiderWrapInfluence( false );
}
}
}
do
{
//Could take a while therefore check for Waitcrsr here.
if ( pImp )
pImp->CheckWaitCursor();
setFrameAreaSizeValid(true);
//First format the column as this will relieve the stack a bit.
//Also set width and height of the column (if they are wrong)
//while we are at it.
SwLayoutFrame *pCol = static_cast<SwLayoutFrame*>(Lower());
// #i27399#
// Simply setting the column width based on the values returned by
// CalcColWidth does not work for automatic column width.
AdjustColumns( &rCol, false );
for ( sal_uInt16 i = 0; i < nNumCols; ++i )
{
pCol->Calc(pRenderContext);
// ColumnFrames have a BodyFrame now, which needs to be calculated
pCol->Lower()->Calc(pRenderContext);
if( pCol->Lower()->GetNext() )
pCol->Lower()->GetNext()->Calc(pRenderContext); // SwFootnoteCont
pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
}
::CalcContent( this );
pCol = static_cast<SwLayoutFrame*>(Lower());
OSL_ENSURE( pCol && pCol->GetNext(), ":-( column making holidays?");
// set bMinDiff if no empty columns exist
bool bMinDiff = true;
// OD 28.03.2003 #108446# - check for all column content and all columns
while ( bMinDiff && pCol )
{
bMinDiff = nullptr != pCol->ContainsContent();
pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
}
pCol = static_cast<SwLayoutFrame*>(Lower());
// OD 28.03.2003 #108446# - initialize local variable
SwTwips nDiff = 0;
SwTwips nMaxFree = 0;
SwTwips nAllFree = LONG_MAX;
// set bFoundLower if there is at least one non-empty column
bool bFoundLower = false;
while( pCol )
{
SwLayoutFrame* pLay = static_cast<SwLayoutFrame*>(pCol->Lower());
SwTwips nInnerHeight = aRectFnSet.GetHeight(pLay->getFrameArea()) -
aRectFnSet.GetHeight(pLay->getFramePrintArea());
if( pLay->Lower() )
{
bFoundLower = true;
nInnerHeight += pLay->InnerHeight();
}
else if( nInnerHeight < 0 )
nInnerHeight = 0;
if( pLay->GetNext() )
{
bFoundLower = true;
pLay = static_cast<SwLayoutFrame*>(pLay->GetNext());
OSL_ENSURE( pLay->IsFootnoteContFrame(),"FootnoteContainer expected" );
nInnerHeight += pLay->InnerHeight();
nInnerHeight += aRectFnSet.GetHeight(pLay->getFrameArea()) -
aRectFnSet.GetHeight(pLay->getFramePrintArea());
}
nInnerHeight -= aRectFnSet.GetHeight(pCol->getFramePrintArea());
if( nInnerHeight > nDiff )
{
nDiff = nInnerHeight;
nAllFree = 0;
}
else
{
if( nMaxFree < -nInnerHeight )
nMaxFree = -nInnerHeight;
if( nAllFree > -nInnerHeight )
nAllFree = -nInnerHeight;
}
pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
}
if ( bFoundLower || ( IsSctFrame() && static_cast<SwSectionFrame*>(this)->HasFollow() ) )
{
SwTwips nMinDiff = ::lcl_CalcMinColDiff( this );
// Here we decide if growing is needed - this is the case, if
// column content (nDiff) or a Fly juts over.
// In sections with columns we take into account to set the size
// when having a non-empty Follow.
if ( nDiff || ::lcl_IsFlyHeightClipped( this ) ||
( IsSctFrame() && static_cast<SwSectionFrame*>(this)->CalcMinDiff( nMinDiff ) ) )
{
long nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
// The minimum must not be smaller than our PrtHeight as
// long as something juts over.
if( nMinimum < nPrtHeight )
nMinimum = nPrtHeight;
// The maximum must not be smaller than PrtHeight if
// something still juts over.
if( nMaximum < nPrtHeight )
nMaximum = nPrtHeight; // Robust, but will this ever happen?
if( !nDiff ) // If only Flys jut over, we grow by nMinDiff
nDiff = nMinDiff;
// If we should grow more than by nMinDiff we split it over
// the columns
if ( std::abs(nDiff - nMinDiff) > nNumCols && nDiff > static_cast<long>(nNumCols) )
nDiff /= nNumCols;
if ( bMinDiff )
{ // If no empty column exists, we want to grow at least
// by nMinDiff. Special case: If we are smaller than the
// minimal FrameHeight and PrtHeight is smaller than
// nMindiff we grow in a way that PrtHeight is exactly
// nMinDiff afterwards.
long nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
if ( nFrameHeight > nMinHeight || nPrtHeight >= nMinDiff )
nDiff = std::max( nDiff, nMinDiff );
else if( nDiff < nMinDiff )
nDiff = nMinDiff - nPrtHeight + 1;
}
// nMaximum has a size which fits the content or the
// requested value from the surrounding therefore we don't
// need to exceed this value.
if( nDiff + nPrtHeight > nMaximum )
nDiff = nMaximum - nPrtHeight;
}
else if( nMaximum > nMinimum ) // We fit, do we still have some margin?
{
long nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
if ( nMaximum < nPrtHeight )
nDiff = nMaximum - nPrtHeight; // We grew over a working
// height and shrink back to it, but will this ever
// happen?
else
{ // We have a new maximum, a size which fits for the content.
nMaximum = nPrtHeight;
// If the margin in the column is bigger than nMinDiff
// and we therefore drop under the minimum, we deflate
// a bit.
if ( !bNoBalance &&
// #i23129# - <nMinDiff> can be
// big, because of an object at the beginning of
// a column. Thus, decrease optimization here.
//nMaxFree >= nMinDiff &&
nMaxFree > 0 &&
( !nAllFree ||
nMinimum < nPrtHeight - nMinDiff ) )
{
nMaxFree /= nNumCols; // disperse over the columns
nDiff = nMaxFree < nMinDiff ? -nMinDiff : -nMaxFree; // min nMinDiff
if( nPrtHeight + nDiff <= nMinimum ) // below the minimum?
nDiff = ( nMinimum - nMaximum ) / 2; // Take the center
}
else if( nAllFree )
{
nDiff = -nAllFree;
if( nPrtHeight + nDiff <= nMinimum ) // Less than minimum?
nDiff = ( nMinimum - nMaximum ) / 2; // Take the center
}
}
}
if( nDiff ) // now we shrink or grow...
{
Size aOldSz( getFramePrintArea().SSize() );
long nTop = aRectFnSet.GetTopMargin(*this);
nDiff = aRectFnSet.GetHeight(getFramePrintArea()) + nDiff + nBorder - aRectFnSet.GetHeight(getFrameArea());
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.AddBottom( aFrm, nDiff );
}
// #i68520#
SwFlyFrame *pFlyFrame = dynamic_cast<SwFlyFrame*>(this);
if (pFlyFrame)
{
pFlyFrame->InvalidateObjRectWithSpaces();
}
aRectFnSet.SetYMargins( *this, nTop, nBorder - nTop );
ChgLowersProp( aOldSz );
NotifyLowerObjs();
// #i3317# - reset temporarily consideration
// of wrapping style influence
SwPageFrame* pTmpPageFrame = FindPageFrame();
SwSortedObjs* pTmpObjs = pTmpPageFrame ? pTmpPageFrame->GetSortedObjs() : nullptr;
if ( pTmpObjs )
{
for (SwAnchoredObject* pAnchoredObj : *pTmpObjs)
{
if ( IsAnLower( pAnchoredObj->GetAnchorFrame() ) )
{
pAnchoredObj->SetTmpConsiderWrapInfluence( false );
}
}
}
//Invalidate suitable to nicely balance the Frames.
//- Every first one after the second column gets a
// InvalidatePos();
pCol = static_cast<SwLayoutFrame*>(Lower()->GetNext());
while ( pCol )
{
SwFrame *pLow = pCol->Lower();
if ( pLow )
pLow->InvalidatePos_();
pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
}
if( IsSctFrame() && static_cast<SwSectionFrame*>(this)->HasFollow() )
{
// If we created a Follow, we need to give its content
// the opportunity to flow back inside the CalcContent
SwContentFrame* pTmpContent =
static_cast<SwSectionFrame*>(this)->GetFollow()->ContainsContent();
if( pTmpContent )
pTmpContent->InvalidatePos_();
}
}
else
bEnd = true;
}
else
bEnd = true;
} while ( !bEnd || !isFrameAreaSizeValid() );
}
// OD 01.04.2003 #108446# - Don't collect endnotes for sections. Thus, set
// 2nd parameter to <true>.
::CalcContent( this, true );
if( IsSctFrame() )
{
// OD 14.03.2003 #i11760# - adjust 2nd parameter - sal_True --> true
::CalcContent( this, true );
if( bBackLock )
static_cast<SwSectionFrame*>(this)->SetFootnoteLock( false );
}
}
static SwContentFrame* lcl_InvalidateSection( SwFrame *pCnt, SwInvalidateFlags nInv )
{
SwSectionFrame* pSect = pCnt->FindSctFrame();
// If our ContentFrame is placed inside a table or a footnote, only sections
// which are also placed inside are meant.
// Exception: If a table is directly passed.
if( ( ( pCnt->IsInTab() && !pSect->IsInTab() ) ||
( pCnt->IsInFootnote() && !pSect->IsInFootnote() ) ) && !pCnt->IsTabFrame() )
return nullptr;
if( nInv & SwInvalidateFlags::Size )
pSect->InvalidateSize_();
if( nInv & SwInvalidateFlags::Pos )
pSect->InvalidatePos_();
if( nInv & SwInvalidateFlags::PrtArea )
pSect->InvalidatePrt_();
SwFlowFrame *pFoll = pSect->GetFollow();
// Temporary separation from follow
pSect->SetFollow( nullptr );
SwContentFrame* pRet = pSect->FindLastContent();
pSect->SetFollow( pFoll );
return pRet;
}
static SwContentFrame* lcl_InvalidateTable( SwTabFrame *pTable, SwInvalidateFlags nInv )
{
if( ( nInv & SwInvalidateFlags::Section ) && pTable->IsInSct() )
lcl_InvalidateSection( pTable, nInv );
if( nInv & SwInvalidateFlags::Size )
pTable->InvalidateSize_();
if( nInv & SwInvalidateFlags::Pos )
pTable->InvalidatePos_();
if( nInv & SwInvalidateFlags::PrtArea )
pTable->InvalidatePrt_();
return pTable->FindLastContent();
}
static void lcl_InvalidateAllContent( SwContentFrame *pCnt, SwInvalidateFlags nInv );
static void lcl_InvalidateContent( SwContentFrame *pCnt, SwInvalidateFlags nInv )
{
SwContentFrame *pLastTabCnt = nullptr;
SwContentFrame *pLastSctCnt = nullptr;
while ( pCnt )
{
if( nInv & SwInvalidateFlags::Section )
{
if( pCnt->IsInSct() )
{
// See above at tables
if( !pLastSctCnt )
pLastSctCnt = lcl_InvalidateSection( pCnt, nInv );
if( pLastSctCnt == pCnt )
pLastSctCnt = nullptr;
}
#if OSL_DEBUG_LEVEL > 0
else
OSL_ENSURE( !pLastSctCnt, "Where's the last SctContent?" );
#endif
}
if( nInv & SwInvalidateFlags::Table )
{
if( pCnt->IsInTab() )
{
// To not call FindTabFrame() for each ContentFrame of a table and
// then invalidate the table, we remember the last ContentFrame of
// the table and ignore IsInTab() until we are past it.
// When entering the table, LastSctCnt is set to null, so
// sections inside the table are correctly invalidated.
// If the table itself is in a section the
// invalidation is done three times, which is acceptable.
if( !pLastTabCnt )
{
pLastTabCnt = lcl_InvalidateTable( pCnt->FindTabFrame(), nInv );
pLastSctCnt = nullptr;
}
if( pLastTabCnt == pCnt )
{
pLastTabCnt = nullptr;
pLastSctCnt = nullptr;
}
}
#if OSL_DEBUG_LEVEL > 0
else
OSL_ENSURE( !pLastTabCnt, "Where's the last TabContent?" );
#endif
}
if( nInv & SwInvalidateFlags::Size )
pCnt->Prepare( PREP_CLEAR, nullptr, false );
if( nInv & SwInvalidateFlags::Pos )
pCnt->InvalidatePos_();
if( nInv & SwInvalidateFlags::PrtArea )
pCnt->InvalidatePrt_();
if ( nInv & SwInvalidateFlags::LineNum )
pCnt->InvalidateLineNum();
if ( pCnt->GetDrawObjs() )
lcl_InvalidateAllContent( pCnt, nInv );
pCnt = pCnt->GetNextContentFrame();
}
}
static void lcl_InvalidateAllContent( SwContentFrame *pCnt, SwInvalidateFlags nInv )
{
SwSortedObjs &rObjs = *pCnt->GetDrawObjs();
for (SwAnchoredObject* pAnchoredObj : rObjs)
{
if ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) != nullptr )
{
SwFlyFrame *pFly = static_cast<SwFlyFrame*>(pAnchoredObj);
if ( pFly->IsFlyInContentFrame() )
{
::lcl_InvalidateContent( pFly->ContainsContent(), nInv );
if( nInv & SwInvalidateFlags::Direction )
pFly->CheckDirChange();
}
}
}
}
void SwRootFrame::InvalidateAllContent( SwInvalidateFlags nInv )
{
// First process all page bound FlyFrames.
SwPageFrame *pPage = static_cast<SwPageFrame*>(Lower());
while( pPage )
{
pPage->InvalidateFlyLayout();
pPage->InvalidateFlyContent();
pPage->InvalidateFlyInCnt();
pPage->InvalidateLayout();
pPage->InvalidateContent();
pPage->InvalidatePage( pPage ); // So even the Turbo disappears if applicable
if ( pPage->GetSortedObjs() )
{
const SwSortedObjs &rObjs = *pPage->GetSortedObjs();
for (SwAnchoredObject* pAnchoredObj : rObjs)
{
if ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) != nullptr )
{
SwFlyFrame* pFly = static_cast<SwFlyFrame*>(pAnchoredObj);
::lcl_InvalidateContent( pFly->ContainsContent(), nInv );
if ( nInv & SwInvalidateFlags::Direction )
pFly->CheckDirChange();
}
}
}
if( nInv & SwInvalidateFlags::Direction )
pPage->CheckDirChange();
pPage = static_cast<SwPageFrame*>(pPage->GetNext());
}
//Invalidate the whole document content and the character bound Flys here.
::lcl_InvalidateContent( ContainsContent(), nInv );
if( nInv & SwInvalidateFlags::PrtArea )
{
SwViewShell *pSh = getRootFrame()->GetCurrShell();
if( pSh )
pSh->InvalidateWindows( getFrameArea() );
}
}
/**
* Invalidate/re-calculate the position of all floating screen objects (Writer fly frames and
* drawing objects), that are anchored to paragraph or to character. (2004-03-16 #i11860#)
*/
void SwRootFrame::InvalidateAllObjPos()
{
const SwPageFrame* pPageFrame = static_cast<const SwPageFrame*>(Lower());
while( pPageFrame )
{
pPageFrame->InvalidateFlyLayout();
if ( pPageFrame->GetSortedObjs() )
{
const SwSortedObjs& rObjs = *(pPageFrame->GetSortedObjs());
for (SwAnchoredObject* pAnchoredObj : rObjs)
{
const SwFormatAnchor& rAnch = pAnchoredObj->GetFrameFormat().GetAnchor();
if ((rAnch.GetAnchorId() != RndStdIds::FLY_AT_PARA) &&
(rAnch.GetAnchorId() != RndStdIds::FLY_AT_CHAR))
{
// only to paragraph and to character anchored objects are considered.
continue;
}
// #i28701# - special invalidation for anchored
// objects, whose wrapping style influence has to be considered.
if ( pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() )
pAnchoredObj->InvalidateObjPosForConsiderWrapInfluence();
else
pAnchoredObj->InvalidateObjPos();
}
}
pPageFrame = static_cast<const SwPageFrame*>(pPageFrame->GetNext());
}
}
void SwRootFrame::SetHideRedlines(bool const bHideRedlines)
{
if (bHideRedlines == mbHideRedlines)
{
return;
}
mbHideRedlines = bHideRedlines;
SwNodes const& rNodes(GetFormat()->GetDoc()->GetNodes());
// Hide->Show: clear MergedPara, create frames
// Show->Hide: call CheckParaRedlineMerge, delete frames
// TODO how to traverse
// * via layout
// - but that won't find nodes that don't have frames in ->Show case
// * via nodes
// - what about special sections before content? flys? footnotes?
// is order of these predictable? flys not anchored in content?
// * ideally should call something existing that tries to create everything?
// - is that done automatically somewhere already?
// * other direction ->Hide - delete frames!
// in-order traversal should init flags in nodes *before* the nodes are found
for (sal_uLong i = 0; i < rNodes.Count(); ++i)
{
SwNode *const pNode(rNodes[i]);
if (pNode->IsTextNode())
{
SwTextNode & rTextNode(*pNode->GetTextNode());
SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(rTextNode);
std::vector<SwTextFrame*> frames;
for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
{
if (pFrame->getRootFrame() == this)
{
frames.push_back(pFrame);
}
}
// this messes with pRegisteredIn so do it outside SwIterator
for (SwTextFrame * pFrame : frames)
{
if (mbHideRedlines && pNode->IsCreateFrameWhenHidingRedlines())
{
pFrame->SetMergedPara(CheckParaRedlineMerge(*pFrame, rTextNode));
}
else
{
if (pFrame->GetMergedPara())
{
pFrame->SetMergedPara(nullptr);
rTextNode.DelFrames(); // FIXME only those in this layout?
}
}
}
}
}
InvalidateAllContent(SwInvalidateFlags::Size); // ??? TODO what to invalidate?
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V571 Recurring check. The 'if (IsTabFrame())' condition was already verified in line 2879.
↑ V678 An object is used as an argument to its own method. Consider checking the first actual argument of the 'InvalidatePage' function.
↑ V592 The expression was enclosed by parentheses twice: ((expression)). One pair of parentheses is unnecessary or misprint is present.
↑ V592 The expression was enclosed by parentheses twice: ((expression)). One pair of parentheses is unnecessary or misprint is present.