/* -*- 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 <pagefrm.hxx>
#include <rootfrm.hxx>
#include <cntfrm.hxx>
#include <dflyobj.hxx>
#include <dcontact.hxx>
#include <ftnfrm.hxx>
#include <frmtool.hxx>
#include <hints.hxx>
#include <sectfrm.hxx>
#include <notxtfrm.hxx>
#include <txtfly.hxx>
#include <svx/svdpage.hxx>
#include <editeng/ulspitem.hxx>
#include <fmtornt.hxx>
#include <fmtfsize.hxx>
#include <ndole.hxx>
#include <tabfrm.hxx>
#include <flyfrms.hxx>
#include <fmtfollowtextflow.hxx>
#include <environmentofanchoredobject.hxx>
#include <sortedobjs.hxx>
#include <viewimp.hxx>
#include <IDocumentSettingAccess.hxx>
#include <IDocumentDrawModelAccess.hxx>
#include <pam.hxx>
#include <ndindex.hxx>
#include <basegfx/matrix/b2dhommatrixtools.hxx>
#include <svx/sdr/attribute/sdrallfillattributeshelper.hxx>
using namespace ::com::sun::star;
SwFlyFreeFrame::SwFlyFreeFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch )
: SwFlyFrame( pFormat, pSib, pAnch ),
// #i34753#
mbNoMakePos( false ),
// #i37068#
mbNoMoveOnCheckClip( false ),
maUnclippedFrame(),
// RotateFlyFrame3
mpTransformableSwFrame()
{
}
void SwFlyFreeFrame::DestroyImpl()
{
// #i28701# - use new method <GetPageFrame()>
if( GetPageFrame() )
{
if( GetFormat()->GetDoc()->IsInDtor() )
{
// #i29879# - remove also to-frame anchored Writer
// fly frame from page.
const bool bRemoveFromPage =
GetPageFrame()->GetSortedObjs() &&
( IsFlyAtContentFrame() ||
( GetAnchorFrame() && GetAnchorFrame()->IsFlyFrame() ) );
if ( bRemoveFromPage )
{
GetPageFrame()->GetSortedObjs()->Remove( *this );
}
}
else
{
SwRect aTmp( GetObjRectWithSpaces() );
SwFlyFreeFrame::NotifyBackground( GetPageFrame(), aTmp, PREP_FLY_LEAVE );
}
}
SwFlyFrame::DestroyImpl();
}
SwFlyFreeFrame::~SwFlyFreeFrame()
{
#if 0
// we are possibly in ContourCache, make sure we vanish
::ClrContourCache(GetVirtDrawObj());
#endif
}
// #i28701#
/** Notifies the background (all ContentFrames that currently are overlapping).
*
* Additionally, the window is also directly invalidated (especially where
* there are no overlapping ContentFrames).
* This also takes ContentFrames within other Flys into account.
*/
void SwFlyFreeFrame::NotifyBackground( SwPageFrame *pPageFrame,
const SwRect& rRect, PrepareHint eHint )
{
::Notify_Background( GetVirtDrawObj(), pPageFrame, rRect, eHint, true );
}
void SwFlyFreeFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
{
if ( !GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) )
{
return;
}
if ( !GetAnchorFrame() || IsLocked() || IsColLocked() )
{
return;
}
// #i28701# - use new method <GetPageFrame()>
if( !GetPageFrame() && GetAnchorFrame() && GetAnchorFrame()->IsInFly() )
{
SwFlyFrame* pFly = AnchorFrame()->FindFlyFrame();
SwPageFrame *pPageFrame = pFly ? pFly->FindPageFrame() : nullptr;
if( pPageFrame )
pPageFrame->AppendFlyToPage( this );
}
if( !GetPageFrame() )
{
return;
}
Lock(); // The curtain drops
// takes care of the notification in the dtor
const SwFlyNotify aNotify( this );
if ( IsClipped() )
{
setFrameAreaSizeValid(false);
m_bHeightClipped = m_bWidthClipped = false;
// no invalidation of position,
// if anchored object is anchored inside a Writer fly frame,
// its position is already locked, and it follows the text flow.
// #i34753# - add condition:
// no invalidation of position, if no direct move is requested in <CheckClip(..)>
if ( !IsNoMoveOnCheckClip() &&
!( PositionLocked() &&
GetAnchorFrame()->IsInFly() &&
GetFrameFormat().GetFollowTextFlow().GetValue() ) )
{
setFrameAreaPositionValid(false);
}
}
// #i81146# new loop control
int nLoopControlRuns = 0;
const int nLoopControlMax = 10;
// RotateFlyFrame3 - outer frame
const double fRotation(getLocalFrameRotation());
const bool bRotated(!basegfx::fTools::equalZero(fRotation));
if(bRotated)
{
// Re-layout may be partially (see all isFrameAreaDefinitionValid() flags),
// so resetting the local SwFrame(s) in the local SwFrameAreaDefinition is
// needed. Reset to BoundAreas will be done below automatically
if(isTransformableSwFrame())
{
getTransformableSwFrame()->restoreFrameAreas();
}
}
while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() || m_bFormatHeightOnly || !m_bValidContentPos )
{
SwRectFnSet aRectFnSet(this);
const SwFormatFrameSize *pSz;
{ // Additional scope, so aAccess will be destroyed before the check!
SwBorderAttrAccess aAccess( SwFrame::GetCache(), this );
const SwBorderAttrs &rAttrs = *aAccess.Get();
pSz = &rAttrs.GetAttrSet().GetFrameSize();
// Only set when the flag is set!
if ( !isFrameAreaSizeValid() )
{
setFramePrintAreaValid(false);
}
if ( !isFramePrintAreaValid() )
{
MakePrtArea( rAttrs );
m_bValidContentPos = false;
}
if ( !isFrameAreaSizeValid() || m_bFormatHeightOnly )
{
setFrameAreaSizeValid(false);
Format( getRootFrame()->GetCurrShell()->GetOut(), &rAttrs );
m_bFormatHeightOnly = false;
}
}
if ( !isFrameAreaPositionValid() )
{
const Point aOldPos( aRectFnSet.GetPos(getFrameArea()) );
// #i26791# - use new method <MakeObjPos()>
// #i34753# - no positioning, if requested.
if ( IsNoMakePos() )
{
setFrameAreaPositionValid(true);
}
else
// #i26791# - use new method <MakeObjPos()>
MakeObjPos();
if( aOldPos == aRectFnSet.GetPos(getFrameArea()) )
{
if( !isFrameAreaPositionValid() && GetAnchorFrame()->IsInSct() &&
!GetAnchorFrame()->FindSctFrame()->isFrameAreaDefinitionValid() )
{
setFrameAreaPositionValid(true);
}
}
else
{
setFrameAreaSizeValid(false);
}
}
if ( !m_bValidContentPos )
{
SwBorderAttrAccess aAccess( SwFrame::GetCache(), this );
const SwBorderAttrs &rAttrs = *aAccess.Get();
MakeContentPos( rAttrs );
}
if ( isFrameAreaPositionValid() && isFrameAreaSizeValid() )
{
++nLoopControlRuns;
OSL_ENSURE( nLoopControlRuns < nLoopControlMax, "LoopControl in SwFlyFreeFrame::MakeAll" );
if ( nLoopControlRuns < nLoopControlMax )
CheckClip( *pSz );
}
else
nLoopControlRuns = 0;
}
// RotateFlyFrame3 - outer frame
// Do not refresh transforms/Areas self here, this will be done
// when inner and outer frame are layouted, in SwNoTextFrame::MakeAll
if(bRotated)
{
// RotateFlyFrame3: Safe changes locally
// get center from outer frame (layout frame) to be on the safe side
const Point aCenter(getFrameArea().Center());
const basegfx::B2DPoint aB2DCenter(aCenter.X(), aCenter.Y());
if(!mpTransformableSwFrame)
{
mpTransformableSwFrame.reset(new TransformableSwFrame(*this));
}
getTransformableSwFrame()->createFrameAreaTransformations(
fRotation,
aB2DCenter);
getTransformableSwFrame()->adaptFrameAreasToTransformations();
}
else
{
// RotateFlyFrame3: Also need to clear ContourCache (if used),
// usually done in SwFlyFrame::NotifyDrawObj, but there relies on
// being in transform mode which is already resetted then
if(isTransformableSwFrame())
{
::ClrContourCache(GetVirtDrawObj());
}
// reset transformations to show that they are not used
mpTransformableSwFrame.reset();
}
Unlock();
#if OSL_DEBUG_LEVEL > 0
SwRectFnSet aRectFnSet(this);
OSL_ENSURE( m_bHeightClipped || ( aRectFnSet.GetHeight(getFrameArea()) > 0 &&
aRectFnSet.GetHeight(getFramePrintArea()) > 0),
"SwFlyFreeFrame::Format(), flipping Fly." );
#endif
}
bool SwFlyFreeFrame::supportsAutoContour() const
{
static bool bOverrideHandleContourToAlwaysOff(true);
// RotateFlyFrameFix: For LO6.0 we need to deactivate the AutoContour feature again, it is simply
// not clear how/if to use and save/load it in ODF. This has to be discussed.
// The reason not to remove is that this may be used as-is now, using a new switch.
// Even when not, the detection if it is possible will be needed in any case later.
if(bOverrideHandleContourToAlwaysOff)
{
return false;
}
if(!isTransformableSwFrame())
{
// support only when transformed, else there is no free space
return false;
}
// Check for Borders. If we have Borders, do (currently) not support,
// since borders do not transform with the object.
// (Will need to be enhanced to take into account if we have Borders and if these
// transform with the object)
SwBorderAttrAccess aAccess(SwFrame::GetCache(), this);
const SwBorderAttrs &rAttrs(*aAccess.Get());
if(rAttrs.IsLine())
{
return false;
}
// Check for Padding. Do not support when padding is used, this will
// produce a covered space around the object (filled with fill defines)
const SfxPoolItem* pItem(nullptr);
if(GetFormat() && SfxItemState::SET == GetFormat()->GetItemState(RES_BOX, false, &pItem))
{
const SvxBoxItem& rBox = *static_cast< const SvxBoxItem* >(pItem);
if(rBox.HasBorder(/*bTreatPaddingAsBorder*/true))
{
return false;
}
}
// check for Fill - if we have fill, it will fill the gaps and we will not
// support AutoContour
if(GetFormat() && GetFormat()->supportsFullDrawingLayerFillAttributeSet())
{
const drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes(GetFormat()->getSdrAllFillAttributesHelper());
if(aFillAttributes.get() && aFillAttributes->isUsed())
{
return false;
}
}
else
{
const SvxBrushItem aBack(GetFormat()->makeBackgroundBrushItem());
if(aBack.isUsed())
{
return false;
}
}
// else, support
return true;
}
// RotateFlyFrame3 - Support for Transformations - outer frame
basegfx::B2DHomMatrix SwFlyFreeFrame::getFrameAreaTransformation() const
{
if(isTransformableSwFrame())
{
// use pre-created transformation
return getTransformableSwFrame()->getLocalFrameAreaTransformation();
}
// call parent
return SwFlyFrame::getFrameAreaTransformation();
}
basegfx::B2DHomMatrix SwFlyFreeFrame::getFramePrintAreaTransformation() const
{
if(isTransformableSwFrame())
{
// use pre-created transformation
return getTransformableSwFrame()->getLocalFramePrintAreaTransformation();
}
// call parent
return SwFlyFrame::getFramePrintAreaTransformation();
}
// RotateFlyFrame3 - Support for Transformations
void SwFlyFreeFrame::transform_translate(const Point& rOffset)
{
// call parent - this will do the basic transform for SwRect(s)
// in the SwFrameAreaDefinition
SwFlyFrame::transform_translate(rOffset);
// check if the Transformations need to be adapted
if(isTransformableSwFrame())
{
const basegfx::B2DHomMatrix aTransform(
basegfx::utils::createTranslateB2DHomMatrix(
rOffset.X(), rOffset.Y()));
// transform using TransformableSwFrame
getTransformableSwFrame()->transform(aTransform);
}
}
// RotateFlyFrame3 - outer frame
double getLocalFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame)
{
return rNoTextFrame.getLocalFrameRotation();
}
double SwFlyFreeFrame::getLocalFrameRotation() const
{
// SwLayoutFrame::Lower() != SwFrame::GetLower(), but SwFrame::GetLower()
// calls SwLayoutFrame::Lower() when it's a SwLayoutFrame - so use GetLower()
const SwNoTextFrame* pSwNoTextFrame(dynamic_cast< const SwNoTextFrame* >(GetLower()));
if(nullptr != pSwNoTextFrame)
{
return getLocalFrameRotation_from_SwNoTextFrame(*pSwNoTextFrame);
}
// no rotation
return 0.0;
}
/** determines, if direct environment of fly frame has 'auto' size
#i17297#
start with anchor frame and search via <GetUpper()> for a header, footer,
row or fly frame stopping at page frame.
return <true>, if such a frame is found and it has 'auto' size.
otherwise <false> is returned.
@return boolean indicating, that direct environment has 'auto' size
*/
bool SwFlyFreeFrame::HasEnvironmentAutoSize() const
{
bool bRetVal = false;
const SwFrame* pToBeCheckedFrame = GetAnchorFrame();
while ( pToBeCheckedFrame &&
!pToBeCheckedFrame->IsPageFrame() )
{
if ( pToBeCheckedFrame->IsHeaderFrame() ||
pToBeCheckedFrame->IsFooterFrame() ||
pToBeCheckedFrame->IsRowFrame() ||
pToBeCheckedFrame->IsFlyFrame() )
{
bRetVal = ATT_FIX_SIZE !=
pToBeCheckedFrame->GetAttrSet()->GetFrameSize().GetHeightSizeType();
break;
}
else
{
pToBeCheckedFrame = pToBeCheckedFrame->GetUpper();
}
}
return bRetVal;
}
void SwFlyFreeFrame::CheckClip( const SwFormatFrameSize &rSz )
{
// It's probably time now to take appropriate measures, if the Fly
// doesn't fit into its surrounding.
// First, the Fly gives up its position, then it's formatted.
// Only if it still doesn't fit after giving up its position, the
// width or height are given up as well. The frame will be squeezed
// as much as needed.
const SwVirtFlyDrawObj *pObj = GetVirtDrawObj();
SwRect aClip, aTmpStretch;
::CalcClipRect( pObj, aClip );
::CalcClipRect( pObj, aTmpStretch, false );
aClip.Intersection_( aTmpStretch );
const long nBot = getFrameArea().Top() + getFrameArea().Height();
const long nRig = getFrameArea().Left() + getFrameArea().Width();
const long nClipBot = aClip.Top() + aClip.Height();
const long nClipRig = aClip.Left() + aClip.Width();
const bool bBot = nBot > nClipBot;
const bool bRig = nRig > nClipRig;
if ( bBot || bRig )
{
bool bAgain = false;
// #i37068# - no move, if it's requested
if ( bBot && !IsNoMoveOnCheckClip() &&
!GetDrawObjs() && !GetAnchorFrame()->IsInTab() )
{
SwFrame* pHeader = FindFooterOrHeader();
// In a header, correction of the position is no good idea.
// If the fly moves, some paragraphs have to be formatted, this
// could cause a change of the height of the headerframe,
// now the flyframe can change its position and so on ...
if ( !pHeader || !pHeader->IsHeaderFrame() )
{
const long nOld = getFrameArea().Top();
// tdf#112443 disable positioning if content is completely off page
bool bDisableOffPagePositioning = GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);
if ( !bDisableOffPagePositioning || nOld <= nClipBot)
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aFrm.Pos().setY( std::max( aClip.Top(), nClipBot - aFrm.Height() ) );
}
if ( getFrameArea().Top() != nOld )
{
bAgain = true;
}
m_bHeightClipped = true;
}
}
if ( bRig )
{
const long nOld = getFrameArea().Left();
// tdf#112443 disable positioning if content is completely off page
bool bDisableOffPagePositioning = GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);
if ( !bDisableOffPagePositioning || nOld <= nClipRig )
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aFrm.Pos().setX( std::max( aClip.Left(), nClipRig - aFrm.Width() ) );
}
if ( getFrameArea().Left() != nOld )
{
const SwFormatHoriOrient &rH = GetFormat()->GetHoriOrient();
// Left-aligned ones may not be moved to the left when they
// are avoiding another one.
if( rH.GetHoriOrient() == text::HoriOrientation::LEFT )
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aFrm.Pos().setX( nOld );
}
else
{
bAgain = true;
}
}
m_bWidthClipped = true;
}
if ( bAgain )
{
setFrameAreaSizeValid(false);
}
else
{
// If we reach this branch, the Frame protrudes into forbidden
// areas, and correcting the position is not allowed or not
// possible or not required.
// For Flys with OLE objects as lower, we make sure that
// we always resize proportionally
Size aOldSize( getFrameArea().SSize() );
// First, setup the FrameRect, then transfer it to the Frame.
SwRect aFrameRect( getFrameArea() );
if ( bBot )
{
long nDiff = nClipBot;
nDiff -= aFrameRect.Top(); // nDiff represents the available distance
nDiff = aFrameRect.Height() - nDiff;
aFrameRect.Height( aFrameRect.Height() - nDiff );
m_bHeightClipped = true;
}
if ( bRig )
{
long nDiff = nClipRig;
nDiff -= aFrameRect.Left();// nDiff represents the available distance
nDiff = aFrameRect.Width() - nDiff;
aFrameRect.Width( aFrameRect.Width() - nDiff );
m_bWidthClipped = true;
}
// #i17297# - no proportional
// scaling of graphics in environments, which determines its size
// by its content ('auto' size). Otherwise layout loops can occur and
// layout sizes of the environment can be incorrect.
// Such environment are:
// (1) header and footer frames with 'auto' size
// (2) table row frames with 'auto' size
// (3) fly frames with 'auto' size
// Note: section frames seems to be not critical - didn't found
// any critical layout situation so far.
if ( Lower() && Lower()->IsNoTextFrame() &&
(static_cast<SwNoTextFrame*>(Lower())->GetNode()->GetOLENode() ||
!HasEnvironmentAutoSize() ) )
{
// If width and height got adjusted, then the bigger
// change is relevant.
if ( aFrameRect.Width() != aOldSize.Width() &&
aFrameRect.Height()!= aOldSize.Height() )
{
if ( (aOldSize.Width() - aFrameRect.Width()) >
(aOldSize.Height()- aFrameRect.Height()) )
aFrameRect.Height( aOldSize.Height() );
else
aFrameRect.Width( aOldSize.Width() );
}
// Adjusted the width? change height proportionally
if( aFrameRect.Width() != aOldSize.Width() )
{
aFrameRect.Height( aFrameRect.Width() * aOldSize.Height() /
aOldSize.Width() );
m_bHeightClipped = true;
}
// Adjusted the height? change width proportionally
else if( aFrameRect.Height() != aOldSize.Height() )
{
aFrameRect.Width( aFrameRect.Height() * aOldSize.Width() /
aOldSize.Height() );
m_bWidthClipped = true;
}
// #i17297# - reactivate change
// of size attribute for fly frames containing an ole object.
// Added the aFrameRect.HasArea() hack, because
// the environment of the ole object does not have to be valid
// at this moment, or even worse, it does not have to have a
// reasonable size. In this case we do not want to change to
// attributes permanently. Maybe one day somebody dares to remove
// this code.
if ( aFrameRect.HasArea() &&
static_cast<SwNoTextFrame*>(Lower())->GetNode()->GetOLENode() &&
( m_bWidthClipped || m_bHeightClipped ) )
{
SwFlyFrameFormat *pFormat = GetFormat();
pFormat->LockModify();
SwFormatFrameSize aFrameSize( rSz );
aFrameSize.SetWidth( aFrameRect.Width() );
aFrameSize.SetHeight( aFrameRect.Height() );
pFormat->SetFormatAttr( aFrameSize );
pFormat->UnlockModify();
}
}
// Now change the Frame; for columns, we put the new values into the attributes,
// otherwise we'll end up with unwanted side-effects/oscillations
const long nPrtHeightDiff = getFrameArea().Height() - getFramePrintArea().Height();
const long nPrtWidthDiff = getFrameArea().Width() - getFramePrintArea().Width();
maUnclippedFrame = getFrameArea();
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aFrm.Height( aFrameRect.Height() );
aFrm.Width ( std::max( long(MINLAY), aFrameRect.Width() ) );
}
if ( Lower() && Lower()->IsColumnFrame() )
{
ColLock(); //lock grow/shrink
const Size aTmpOldSize( getFramePrintArea().SSize() );
{
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
aPrt.Height( getFrameArea().Height() - nPrtHeightDiff );
aPrt.Width ( getFrameArea().Width() - nPrtWidthDiff );
}
ChgLowersProp( aTmpOldSize );
SwFrame *pLow = Lower();
do
{
pLow->Calc(getRootFrame()->GetCurrShell()->GetOut());
// also calculate the (Column)BodyFrame
static_cast<SwLayoutFrame*>(pLow)->Lower()->Calc(getRootFrame()->GetCurrShell()->GetOut());
pLow = pLow->GetNext();
} while ( pLow );
::CalcContent( this );
ColUnlock();
if ( !isFrameAreaSizeValid() && !m_bWidthClipped )
{
setFrameAreaSizeValid(true);
m_bFormatHeightOnly = true;
}
}
else
{
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
aPrt.Height( getFrameArea().Height() - nPrtHeightDiff );
aPrt.Width ( getFrameArea().Width() - nPrtWidthDiff );
}
}
}
// #i26945#
OSL_ENSURE( getFrameArea().Height() >= 0,
"<SwFlyFreeFrame::CheckClip(..)> - fly frame has negative height now." );
}
/** method to determine, if a <MakeAll()> on the Writer fly frame is possible
#i43771#
*/
bool SwFlyFreeFrame::IsFormatPossible() const
{
return SwFlyFrame::IsFormatPossible() &&
( GetPageFrame() ||
( GetAnchorFrame() && GetAnchorFrame()->IsInFly() ) );
}
SwFlyLayFrame::SwFlyLayFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch ) :
SwFlyFreeFrame( pFormat, pSib, pAnch )
{
m_bLayout = true;
}
// #i28701#
void SwFlyLayFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
{
const SwFormatAnchor *pAnch = nullptr;
if (pNew)
{
const sal_uInt16 nWhich = pNew->Which();
if( RES_ATTRSET_CHG == nWhich && SfxItemState::SET ==
static_cast<const SwAttrSetChg*>(pNew)->GetChgSet()->GetItemState( RES_ANCHOR, false,
reinterpret_cast<const SfxPoolItem**>(&pAnch) ))
; // GetItemState sets the anchor pointer!
else if( RES_ANCHOR == nWhich )
{
// Change of anchor. I'm attaching myself to the new place.
// It's not allowed to change the anchor type. This is only
// possible via SwFEShell.
pAnch = static_cast<const SwFormatAnchor*>(pNew);
}
}
if( pAnch )
{
OSL_ENSURE( pAnch->GetAnchorId() ==
GetFormat()->GetAnchor().GetAnchorId(),
"8-) Invalid change of anchor type." );
// Unregister, get hold of the page, attach to the corresponding LayoutFrame.
SwRect aOld( GetObjRectWithSpaces() );
// #i28701# - use new method <GetPageFrame()>
SwPageFrame *pOldPage = GetPageFrame();
AnchorFrame()->RemoveFly( this );
if ( RndStdIds::FLY_AT_PAGE == pAnch->GetAnchorId() )
{
sal_uInt16 nPgNum = pAnch->GetPageNum();
SwRootFrame *pRoot = getRootFrame();
SwPageFrame *pTmpPage = static_cast<SwPageFrame*>(pRoot->Lower());
for ( sal_uInt16 i = 1; (i <= nPgNum) && pTmpPage; ++i,
pTmpPage = static_cast<SwPageFrame*>(pTmpPage->GetNext()) )
{
if ( i == nPgNum )
{
// #i50432# - adjust synopsis of <PlaceFly(..)>
pTmpPage->PlaceFly( this, nullptr );
}
}
if( !pTmpPage )
{
pRoot->SetAssertFlyPages();
pRoot->AssertFlyPages();
}
}
else
{
SwNodeIndex aIdx( pAnch->GetContentAnchor()->nNode );
SwContentFrame *pContent = GetFormat()->GetDoc()->GetNodes().GoNext( &aIdx )->
GetContentNode()->getLayoutFrame( getRootFrame(), nullptr, nullptr, false );
if( pContent )
{
SwFlyFrame *pTmp = pContent->FindFlyFrame();
if( pTmp )
pTmp->AppendFly( this );
}
}
// #i28701# - use new method <GetPageFrame()>
if ( pOldPage && pOldPage != GetPageFrame() )
NotifyBackground( pOldPage, aOld, PREP_FLY_LEAVE );
SetCompletePaint();
InvalidateAll();
SetNotifyBack();
}
else
SwFlyFrame::Modify( pOld, pNew );
}
void SwPageFrame::AppendFlyToPage( SwFlyFrame *pNew )
{
if ( !pNew->GetVirtDrawObj()->IsInserted() )
getRootFrame()->GetDrawPage()->InsertObject(
static_cast<SdrObject*>(pNew->GetVirtDrawObj()),
pNew->GetVirtDrawObj()->GetReferencedObj().GetOrdNumDirect() );
InvalidateSpelling();
InvalidateSmartTags();
InvalidateAutoCompleteWords();
InvalidateWordCount();
if ( GetUpper() )
{
static_cast<SwRootFrame*>(GetUpper())->SetIdleFlags();
static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth();
}
SdrObject* pObj = pNew->GetVirtDrawObj();
OSL_ENSURE( pNew->GetAnchorFrame(), "Fly without Anchor" );
SwFlyFrame* pFly = const_cast<SwFlyFrame*>(pNew->GetAnchorFrame()->FindFlyFrame());
if ( pFly && pObj->GetOrdNum() < pFly->GetVirtDrawObj()->GetOrdNum() )
{
//#i119945# set pFly's OrdNum to _rNewObj's. So when pFly is removed by Undo, the original OrdNum will not be changed.
sal_uInt32 nNewNum = pObj->GetOrdNumDirect();
if ( pObj->getSdrPageFromSdrObject() )
pObj->getSdrPageFromSdrObject()->SetObjectOrdNum( pFly->GetVirtDrawObj()->GetOrdNumDirect(), nNewNum );
else
pFly->GetVirtDrawObj()->SetOrdNum( nNewNum );
}
// Don't look further at Flys that sit inside the Content.
if ( pNew->IsFlyInContentFrame() )
InvalidateFlyInCnt();
else
{
InvalidateFlyContent();
if ( !m_pSortedObjs )
{
m_pSortedObjs.reset(new SwSortedObjs());
}
const bool bSuccessInserted = m_pSortedObjs->Insert( *pNew );
OSL_ENSURE( bSuccessInserted, "Fly not inserted in Sorted." );
// #i87493#
OSL_ENSURE( pNew->GetPageFrame() == nullptr || pNew->GetPageFrame() == this,
"<SwPageFrame::AppendFlyToPage(..)> - anchored fly frame seems to be registered at another page frame. Serious defect." );
// #i28701# - use new method <SetPageFrame(..)>
pNew->SetPageFrame( this );
pNew->InvalidatePage( this );
// #i28701#
pNew->UnlockPosition();
// Notify accessible layout. That's required at this place for
// frames only where the anchor is moved. Creation of new frames
// is additionally handled by the SwFrameNotify class.
if( GetUpper() &&
static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
{
static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
->AddAccessibleFrame( pNew );
}
}
// #i28701# - correction: consider also drawing objects
if ( pNew->GetDrawObjs() )
{
SwSortedObjs &rObjs = *pNew->GetDrawObjs();
for (SwAnchoredObject* pTmpObj : rObjs)
{
if ( dynamic_cast<const SwFlyFrame*>( pTmpObj) != nullptr )
{
SwFlyFrame* pTmpFly = static_cast<SwFlyFrame*>(pTmpObj);
// #i28701# - use new method <GetPageFrame()>
if ( pTmpFly->IsFlyFreeFrame() && !pTmpFly->GetPageFrame() )
AppendFlyToPage( pTmpFly );
}
else if ( dynamic_cast<const SwAnchoredDrawObject*>( pTmpObj) != nullptr )
{
// #i87493#
if ( pTmpObj->GetPageFrame() != this )
{
if ( pTmpObj->GetPageFrame() != nullptr )
{
pTmpObj->GetPageFrame()->RemoveDrawObjFromPage( *pTmpObj );
}
AppendDrawObjToPage( *pTmpObj );
}
}
}
}
}
void SwPageFrame::RemoveFlyFromPage( SwFlyFrame *pToRemove )
{
const sal_uInt32 nOrdNum = pToRemove->GetVirtDrawObj()->GetOrdNum();
getRootFrame()->GetDrawPage()->RemoveObject( nOrdNum );
pToRemove->GetVirtDrawObj()->ReferencedObj().SetOrdNum( nOrdNum );
if ( GetUpper() )
{
if ( !pToRemove->IsFlyInContentFrame() )
static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous();
static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth();
}
// Don't look further at Flys that sit inside the Content.
if ( pToRemove->IsFlyInContentFrame() )
return;
// Don't delete collections just yet. This will happen at the end of the
// action in the RemoveSuperfluous of the page, kicked off by a method of
// the same name in the root.
// The FlyColl might be gone already, because the page's dtor is being
// executed.
// Remove it _before_ disposing accessible frames to avoid accesses to
// the Frame from event handlers.
if (m_pSortedObjs)
{
m_pSortedObjs->Remove(*pToRemove);
if (!m_pSortedObjs->size())
{
m_pSortedObjs.reset();
}
}
// Notify accessible layout. That's required at this place for
// frames only where the anchor is moved. Creation of new frames
// is additionally handled by the SwFrameNotify class.
if( GetUpper() &&
static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
{
static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
->DisposeAccessibleFrame( pToRemove, true );
}
// #i28701# - use new method <SetPageFrame(..)>
pToRemove->SetPageFrame( nullptr );
}
void SwPageFrame::MoveFly( SwFlyFrame *pToMove, SwPageFrame *pDest )
{
// Invalidations
if ( GetUpper() )
{
static_cast<SwRootFrame*>(GetUpper())->SetIdleFlags();
if ( !pToMove->IsFlyInContentFrame() && pDest->GetPhyPageNum() < GetPhyPageNum() )
static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous();
}
pDest->InvalidateSpelling();
pDest->InvalidateSmartTags();
pDest->InvalidateAutoCompleteWords();
pDest->InvalidateWordCount();
if ( pToMove->IsFlyInContentFrame() )
{
pDest->InvalidateFlyInCnt();
return;
}
// Notify accessible layout. That's required at this place for
// frames only where the anchor is moved. Creation of new frames
// is additionally handled by the SwFrameNotify class.
if( GetUpper() &&
static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
{
static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
->DisposeAccessibleFrame( pToMove, true );
}
// The FlyColl might be gone already, because the page's dtor is being executed.
if ( m_pSortedObjs )
{
m_pSortedObjs->Remove( *pToMove );
if ( !m_pSortedObjs->size() )
{
m_pSortedObjs.reset();
}
}
// Register
if ( !pDest->GetSortedObjs() )
pDest->m_pSortedObjs.reset(new SwSortedObjs());
const bool bSuccessInserted = pDest->GetSortedObjs()->Insert( *pToMove );
OSL_ENSURE( bSuccessInserted, "Fly not inserted in Sorted." );
// #i28701# - use new method <SetPageFrame(..)>
pToMove->SetPageFrame( pDest );
pToMove->InvalidatePage( pDest );
pToMove->SetNotifyBack();
pDest->InvalidateFlyContent();
// #i28701#
pToMove->UnlockPosition();
// Notify accessible layout. That's required at this place for
// frames only where the anchor is moved. Creation of new frames
// is additionally handled by the SwFrameNotify class.
if( GetUpper() &&
static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
{
static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
->AddAccessibleFrame( pToMove );
}
// #i28701# - correction: move lowers of Writer fly frame
if ( pToMove->GetDrawObjs() )
{
SwSortedObjs &rObjs = *pToMove->GetDrawObjs();
for (SwAnchoredObject* pObj : rObjs)
{
if ( dynamic_cast<const SwFlyFrame*>( pObj) != nullptr )
{
SwFlyFrame* pFly = static_cast<SwFlyFrame*>(pObj);
if ( pFly->IsFlyFreeFrame() )
{
// #i28701# - use new method <GetPageFrame()>
SwPageFrame* pPageFrame = pFly->GetPageFrame();
if ( pPageFrame )
pPageFrame->MoveFly( pFly, pDest );
else
pDest->AppendFlyToPage( pFly );
}
}
else if ( dynamic_cast<const SwAnchoredDrawObject*>( pObj) != nullptr )
{
RemoveDrawObjFromPage( *pObj );
pDest->AppendDrawObjToPage( *pObj );
}
}
}
}
void SwPageFrame::AppendDrawObjToPage( SwAnchoredObject& _rNewObj )
{
if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rNewObj) == nullptr )
{
OSL_FAIL( "SwPageFrame::AppendDrawObjToPage(..) - anchored object of unexpected type -> object not appended" );
return;
}
if ( GetUpper() )
{
static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth();
}
assert(_rNewObj.GetAnchorFrame());
SwFlyFrame* pFlyFrame = const_cast<SwFlyFrame*>(_rNewObj.GetAnchorFrame()->FindFlyFrame());
if ( pFlyFrame &&
_rNewObj.GetDrawObj()->GetOrdNum() < pFlyFrame->GetVirtDrawObj()->GetOrdNum() )
{
//#i119945# set pFly's OrdNum to _rNewObj's. So when pFly is removed by Undo, the original OrdNum will not be changed.
sal_uInt32 nNewNum = _rNewObj.GetDrawObj()->GetOrdNumDirect();
if ( _rNewObj.GetDrawObj()->getSdrPageFromSdrObject() )
_rNewObj.DrawObj()->getSdrPageFromSdrObject()->SetObjectOrdNum( pFlyFrame->GetVirtDrawObj()->GetOrdNumDirect(), nNewNum );
else
pFlyFrame->GetVirtDrawObj()->SetOrdNum( nNewNum );
}
if ( RndStdIds::FLY_AS_CHAR == _rNewObj.GetFrameFormat().GetAnchor().GetAnchorId() )
{
return;
}
if ( !m_pSortedObjs )
{
m_pSortedObjs.reset(new SwSortedObjs());
}
if ( !m_pSortedObjs->Insert( _rNewObj ) )
{
OSL_ENSURE( m_pSortedObjs->Contains( _rNewObj ),
"Drawing object not appended into list <pSortedObjs>." );
}
// #i87493#
OSL_ENSURE( _rNewObj.GetPageFrame() == nullptr || _rNewObj.GetPageFrame() == this,
"<SwPageFrame::AppendDrawObjToPage(..)> - anchored draw object seems to be registered at another page frame. Serious defect." );
_rNewObj.SetPageFrame( this );
// invalidate page in order to force a reformat of object layout of the page.
InvalidateFlyLayout();
}
void SwPageFrame::RemoveDrawObjFromPage( SwAnchoredObject& _rToRemoveObj )
{
if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rToRemoveObj) == nullptr )
{
OSL_FAIL( "SwPageFrame::RemoveDrawObjFromPage(..) - anchored object of unexpected type -> object not removed" );
return;
}
if ( m_pSortedObjs )
{
m_pSortedObjs->Remove( _rToRemoveObj );
if ( !m_pSortedObjs->size() )
{
m_pSortedObjs.reset();
}
if ( GetUpper() )
{
if (RndStdIds::FLY_AS_CHAR !=
_rToRemoveObj.GetFrameFormat().GetAnchor().GetAnchorId())
{
static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous();
InvalidatePage();
}
static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth();
}
}
_rToRemoveObj.SetPageFrame( nullptr );
}
// #i50432# - adjust method description and synopsis.
void SwPageFrame::PlaceFly( SwFlyFrame* pFly, SwFlyFrameFormat* pFormat )
{
// #i50432# - consider the case that page is an empty page:
// In this case append the fly frame at the next page
OSL_ENSURE( !IsEmptyPage() || GetNext(),
"<SwPageFrame::PlaceFly(..)> - empty page with no next page! -> fly frame appended at empty page" );
if ( IsEmptyPage() && GetNext() )
{
static_cast<SwPageFrame*>(GetNext())->PlaceFly( pFly, pFormat );
}
else
{
// If we received a Fly, we use that one. Otherwise, create a new
// one using the Format.
if ( pFly )
AppendFly( pFly );
else
{
OSL_ENSURE( pFormat, ":-( No Format given for Fly." );
pFly = new SwFlyLayFrame( pFormat, this, this );
AppendFly( pFly );
::RegistFlys( this, pFly );
}
}
}
// #i18732# - adjustments for following text flow or not
// AND alignment at 'page areas' for to paragraph/to character anchored objects
// #i22305# - adjustment for following text flow for to frame anchored objects
// #i29778# - Because calculating the floating screen object's position
// (Writer fly frame or drawing object) doesn't perform a calculation on its
// upper frames and its anchor frame, a calculation of the upper frames in this
// method is no longer sensible.
// #i28701# - if document compatibility option 'Consider wrapping style influence
// on object positioning' is ON, the clip area corresponds to the one as the
// object doesn't follow the text flow.
bool CalcClipRect( const SdrObject *pSdrObj, SwRect &rRect, bool bMove )
{
bool bRet = true;
if ( auto pVirtFlyDrawObj = dynamic_cast<const SwVirtFlyDrawObj*>(pSdrObj) )
{
const SwFlyFrame* pFly = pVirtFlyDrawObj->GetFlyFrame();
const bool bFollowTextFlow = pFly->GetFormat()->GetFollowTextFlow().GetValue();
// #i28701#
const bool bConsiderWrapOnObjPos =
pFly->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION);
const SwFormatVertOrient &rV = pFly->GetFormat()->GetVertOrient();
if( pFly->IsFlyLayFrame() )
{
const SwFrame* pClip;
// #i22305#
// #i28701#
if ( !bFollowTextFlow || bConsiderWrapOnObjPos )
{
pClip = pFly->GetAnchorFrame()->FindPageFrame();
}
else
{
pClip = pFly->GetAnchorFrame();
}
rRect = pClip->getFrameArea();
SwRectFnSet aRectFnSet(pClip);
// vertical clipping: Top and Bottom, also to PrtArea if necessary
if( rV.GetVertOrient() != text::VertOrientation::NONE &&
rV.GetRelationOrient() == text::RelOrientation::PRINT_AREA )
{
aRectFnSet.SetTop( rRect, aRectFnSet.GetPrtTop(*pClip) );
aRectFnSet.SetBottom( rRect, aRectFnSet.GetPrtBottom(*pClip) );
}
// horizontal clipping: Top and Bottom, also to PrtArea if necessary
const SwFormatHoriOrient &rH = pFly->GetFormat()->GetHoriOrient();
if( rH.GetHoriOrient() != text::HoriOrientation::NONE &&
rH.GetRelationOrient() == text::RelOrientation::PRINT_AREA )
{
aRectFnSet.SetLeft( rRect, aRectFnSet.GetPrtLeft(*pClip) );
aRectFnSet.SetRight(rRect, aRectFnSet.GetPrtRight(*pClip));
}
}
else if( pFly->IsFlyAtContentFrame() )
{
// #i18732# - consider following text flow or not
// AND alignment at 'page areas'
const SwFrame* pVertPosOrientFrame = pFly->GetVertPosOrientFrame();
if ( !pVertPosOrientFrame )
{
OSL_FAIL( "::CalcClipRect(..) - frame, vertical position is oriented at, is missing .");
pVertPosOrientFrame = pFly->GetAnchorFrame();
}
if ( !bFollowTextFlow || bConsiderWrapOnObjPos )
{
const SwLayoutFrame* pClipFrame = pVertPosOrientFrame->FindPageFrame();
if (!pClipFrame)
{
OSL_FAIL("!pClipFrame: "
"if you can reproduce this please file a bug");
return false;
}
rRect = bMove ? pClipFrame->GetUpper()->getFrameArea()
: pClipFrame->getFrameArea();
// #i26945# - consider that a table, during
// its format, can exceed its upper printing area bottom.
// Thus, enlarge the clip rectangle, if such a case occurred
if ( pFly->GetAnchorFrame()->IsInTab() )
{
const SwTabFrame* pTabFrame = const_cast<SwFlyFrame*>(pFly)
->GetAnchorFrameContainingAnchPos()->FindTabFrame();
SwRect aTmp( pTabFrame->getFramePrintArea() );
aTmp += pTabFrame->getFrameArea().Pos();
rRect.Union( aTmp );
// #i43913# - consider also the cell frame
const SwFrame* pCellFrame = const_cast<SwFlyFrame*>(pFly)
->GetAnchorFrameContainingAnchPos()->GetUpper();
while ( pCellFrame && !pCellFrame->IsCellFrame() )
{
pCellFrame = pCellFrame->GetUpper();
}
if ( pCellFrame )
{
aTmp = pCellFrame->getFramePrintArea();
aTmp += pCellFrame->getFrameArea().Pos();
rRect.Union( aTmp );
}
}
}
else if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_FRAME ||
rV.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA )
{
// new class <SwEnvironmentOfAnchoredObject>
objectpositioning::SwEnvironmentOfAnchoredObject
aEnvOfObj( bFollowTextFlow );
const SwLayoutFrame& rVertClipFrame =
aEnvOfObj.GetVertEnvironmentLayoutFrame( *pVertPosOrientFrame );
if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_FRAME )
{
rRect = rVertClipFrame.getFrameArea();
}
else if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA )
{
if ( rVertClipFrame.IsPageFrame() )
{
rRect = static_cast<const SwPageFrame&>(rVertClipFrame).PrtWithoutHeaderAndFooter();
}
else
{
rRect = rVertClipFrame.getFrameArea();
}
}
const SwLayoutFrame* pHoriClipFrame =
pFly->GetAnchorFrame()->FindPageFrame()->GetUpper();
SwRectFnSet aRectFnSet(pFly->GetAnchorFrame());
aRectFnSet.SetLeft( rRect, aRectFnSet.GetLeft(pHoriClipFrame->getFrameArea()) );
aRectFnSet.SetRight(rRect, aRectFnSet.GetRight(pHoriClipFrame->getFrameArea()));
}
else
{
// #i26945#
const SwFrame *pClip =
const_cast<SwFlyFrame*>(pFly)->GetAnchorFrameContainingAnchPos();
SwRectFnSet aRectFnSet(pClip);
const SwLayoutFrame *pUp = pClip->GetUpper();
const SwFrame *pCell = pUp->IsCellFrame() ? pUp : nullptr;
const SwFrameType nType = bMove
? SwFrameType::Root | SwFrameType::Fly | SwFrameType::Header |
SwFrameType::Footer | SwFrameType::Ftn
: SwFrameType::Body | SwFrameType::Fly | SwFrameType::Header |
SwFrameType::Footer | SwFrameType::Cell| SwFrameType::Ftn;
while ( !(pUp->GetType() & nType) || pUp->IsColBodyFrame() )
{
pUp = pUp->GetUpper();
if ( !pCell && pUp->IsCellFrame() )
pCell = pUp;
}
if ( bMove )
{
if ( pUp->IsRootFrame() )
{
rRect = pUp->getFramePrintArea();
rRect += pUp->getFrameArea().Pos();
pUp = nullptr;
}
}
if ( pUp )
{
if ( pUp->GetType() & SwFrameType::Body )
{
const SwPageFrame *pPg;
if ( pUp->GetUpper() != (pPg = pFly->FindPageFrame()) )
pUp = pPg->FindBodyCont();
if (pUp)
{
rRect = pUp->GetUpper()->getFrameArea();
aRectFnSet.SetTop( rRect, aRectFnSet.GetPrtTop(*pUp) );
aRectFnSet.SetBottom(rRect, aRectFnSet.GetPrtBottom(*pUp));
}
}
else
{
if( ( pUp->GetType() & (SwFrameType::Fly | SwFrameType::Ftn ) ) &&
!pUp->getFrameArea().IsInside( pFly->getFrameArea().Pos() ) )
{
if( pUp->IsFlyFrame() )
{
const SwFlyFrame *pTmpFly = static_cast<const SwFlyFrame*>(pUp);
while( pTmpFly->GetNextLink() )
{
pTmpFly = pTmpFly->GetNextLink();
if( pTmpFly->getFrameArea().IsInside( pFly->getFrameArea().Pos() ) )
break;
}
pUp = pTmpFly;
}
else if( pUp->IsInFootnote() )
{
const SwFootnoteFrame *pTmp = pUp->FindFootnoteFrame();
while( pTmp->GetFollow() )
{
pTmp = pTmp->GetFollow();
if( pTmp->getFrameArea().IsInside( pFly->getFrameArea().Pos() ) )
break;
}
pUp = pTmp;
}
}
rRect = pUp->getFramePrintArea();
rRect.Pos() += pUp->getFrameArea().Pos();
if ( pUp->GetType() & (SwFrameType::Header | SwFrameType::Footer) )
{
rRect.Left ( pUp->GetUpper()->getFrameArea().Left() );
rRect.Width( pUp->GetUpper()->getFrameArea().Width());
}
else if ( pUp->IsCellFrame() ) //MA_FLY_HEIGHT
{
const SwFrame *pTab = pUp->FindTabFrame();
aRectFnSet.SetBottom( rRect, aRectFnSet.GetPrtBottom(*pTab->GetUpper()) );
// expand to left and right cell border
rRect.Left ( pUp->getFrameArea().Left() );
rRect.Width( pUp->getFrameArea().Width() );
}
}
}
if ( pCell )
{
// CellFrames might also sit in unallowed areas. In this case,
// the Fly is allowed to do so as well
SwRect aTmp( pCell->getFramePrintArea() );
aTmp += pCell->getFrameArea().Pos();
rRect.Union( aTmp );
}
}
}
else
{
const SwFrame *pUp = pFly->GetAnchorFrame()->GetUpper();
SwRectFnSet aRectFnSet(pFly->GetAnchorFrame());
while( pUp->IsColumnFrame() || pUp->IsSctFrame() || pUp->IsColBodyFrame())
pUp = pUp->GetUpper();
rRect = pUp->getFrameArea();
if( !pUp->IsBodyFrame() )
{
rRect += pUp->getFramePrintArea().Pos();
rRect.SSize( pUp->getFramePrintArea().SSize() );
if ( pUp->IsCellFrame() )
{
const SwFrame *pTab = pUp->FindTabFrame();
aRectFnSet.SetBottom( rRect, aRectFnSet.GetPrtBottom(*pTab->GetUpper()) );
}
}
else if ( pUp->GetUpper()->IsPageFrame() )
{
// Objects anchored as character may exceed right margin
// of body frame:
aRectFnSet.SetRight( rRect, aRectFnSet.GetRight(pUp->GetUpper()->getFrameArea()) );
}
long nHeight = (9*aRectFnSet.GetHeight(rRect))/10;
long nTop;
const SwFormat *pFormat = GetUserCall(pSdrObj)->GetFormat();
const SvxULSpaceItem &rUL = pFormat->GetULSpace();
if( bMove )
{
nTop = aRectFnSet.IsVert() ? static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().X() :
static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().Y();
nTop = aRectFnSet.YInc( nTop, -nHeight );
long nWidth = aRectFnSet.GetWidth(pFly->getFrameArea());
aRectFnSet.SetLeftAndWidth( rRect, aRectFnSet.IsVert() ?
static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().Y() :
static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().X(), nWidth );
nHeight = 2*nHeight - rUL.GetLower() - rUL.GetUpper();
}
else
{
nTop = aRectFnSet.YInc( aRectFnSet.GetBottom(pFly->getFrameArea()),
rUL.GetLower() - nHeight );
nHeight = 2*nHeight - aRectFnSet.GetHeight(pFly->getFrameArea())
- rUL.GetLower() - rUL.GetUpper();
}
aRectFnSet.SetTopAndHeight( rRect, nTop, nHeight );
}
}
else
{
const SwDrawContact *pC = static_cast<const SwDrawContact*>(GetUserCall(pSdrObj));
const SwFrameFormat *pFormat = pC->GetFormat();
const SwFormatAnchor &rAnch = pFormat->GetAnchor();
if ( RndStdIds::FLY_AS_CHAR == rAnch.GetAnchorId() )
{
const SwFrame* pAnchorFrame = pC->GetAnchorFrame( pSdrObj );
if( !pAnchorFrame )
{
OSL_FAIL( "<::CalcClipRect(..)> - missing anchor frame." );
const_cast<SwDrawContact*>(pC)->ConnectToLayout();
pAnchorFrame = pC->GetAnchorFrame();
}
const SwFrame* pUp = pAnchorFrame->GetUpper();
rRect = pUp->getFramePrintArea();
rRect += pUp->getFrameArea().Pos();
SwRectFnSet aRectFnSet(pAnchorFrame);
long nHeight = (9*aRectFnSet.GetHeight(rRect))/10;
long nTop;
const SvxULSpaceItem &rUL = pFormat->GetULSpace();
SwRect aSnapRect( pSdrObj->GetSnapRect() );
long nTmpH = 0;
if( bMove )
{
nTop = aRectFnSet.YInc( aRectFnSet.IsVert() ? pSdrObj->GetAnchorPos().X() :
pSdrObj->GetAnchorPos().Y(), -nHeight );
long nWidth = aRectFnSet.GetWidth(aSnapRect);
aRectFnSet.SetLeftAndWidth( rRect, aRectFnSet.IsVert() ?
pSdrObj->GetAnchorPos().Y() :
pSdrObj->GetAnchorPos().X(), nWidth );
}
else
{
// #i26791# - value of <nTmpH> is needed to
// calculate value of <nTop>.
nTmpH = aRectFnSet.IsVert() ? pSdrObj->GetCurrentBoundRect().GetWidth() :
pSdrObj->GetCurrentBoundRect().GetHeight();
nTop = aRectFnSet.YInc( aRectFnSet.GetTop(aSnapRect),
rUL.GetLower() + nTmpH - nHeight );
}
nHeight = 2*nHeight - nTmpH - rUL.GetLower() - rUL.GetUpper();
aRectFnSet.SetTopAndHeight( rRect, nTop, nHeight );
}
else
{
// restrict clip rectangle for drawing
// objects in header/footer to the page frame.
// #i26791#
const SwFrame* pAnchorFrame = pC->GetAnchorFrame( pSdrObj );
if ( pAnchorFrame && pAnchorFrame->FindFooterOrHeader() )
{
// clip frame is the page frame the header/footer is on.
const SwFrame* pClipFrame = pAnchorFrame->FindPageFrame();
rRect = pClipFrame->getFrameArea();
}
else
{
bRet = false;
}
}
}
return bRet;
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V560 A part of conditional expression is always true: GetAnchorFrame().