1563 lines
60 KiB
C++
1563 lines
60 KiB
C++
/* -*- 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 <config_wasm_strip.h>
|
|
|
|
#include <pagefrm.hxx>
|
|
#include <rootfrm.hxx>
|
|
#include <cntfrm.hxx>
|
|
#include <dflyobj.hxx>
|
|
#include <dcontact.hxx>
|
|
#include <ftnfrm.hxx>
|
|
#include <frmatr.hxx>
|
|
#include <frmtool.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>
|
|
#include <osl/diagnose.h>
|
|
|
|
using namespace ::com::sun::star;
|
|
|
|
SwFlyFreeFrame::SwFlyFreeFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch, bool bFollow )
|
|
: SwFlyFrame( pFormat, pSib, pAnch, bFollow ),
|
|
// #i34753#
|
|
mbNoMakePos( false ),
|
|
// #i37068#
|
|
mbNoMoveOnCheckClip( false )
|
|
{
|
|
}
|
|
|
|
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, PrepareHint::FlyFrameLeave );
|
|
}
|
|
}
|
|
|
|
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()->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 (!IsForceNotifyNewBackground() && 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 reset 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); // loplugin:constvars:ignore
|
|
|
|
// 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 SvxBoxItem* pBoxItem(nullptr);
|
|
|
|
if(GetFormat() && (pBoxItem = GetFormat()->GetItemIfSet(RES_BOX, false)))
|
|
{
|
|
if(pBoxItem->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 && aFillAttributes->isUsed())
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const std::unique_ptr<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 = SwFrameSize::Fixed !=
|
|
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 tools::Long nBot = getFrameArea().Top() + getFrameArea().Height();
|
|
const tools::Long nRig = getFrameArea().Left() + getFrameArea().Width();
|
|
const tools::Long nClipBot = aClip.Top() + aClip.Height();
|
|
const tools::Long nClipRig = aClip.Left() + aClip.Width();
|
|
|
|
const bool bBot = nBot > nClipBot;
|
|
const bool bRig = nRig > nClipRig;
|
|
if (( bBot || bRig ) && !IsDraggingOffPageAllowed(FindFrameFormat(GetDrawObj())))
|
|
{
|
|
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 tools::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 tools::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 )
|
|
{
|
|
tools::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 )
|
|
{
|
|
tools::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 tools::Long nPrtHeightDiff = getFrameArea().Height() - getFramePrintArea().Height();
|
|
const tools::Long nPrtWidthDiff = getFrameArea().Width() - getFramePrintArea().Width();
|
|
maUnclippedFrame = getFrameArea();
|
|
|
|
{
|
|
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
|
|
aFrm.Height( aFrameRect.Height() );
|
|
aFrm.Width ( std::max( tools::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;
|
|
}
|
|
|
|
void SwFlyLayFrame::RegisterAtPage(SwPageFrame & rPageFrame)
|
|
{
|
|
assert(GetPageFrame() != &rPageFrame);
|
|
if (GetPageFrame())
|
|
{
|
|
GetPageFrame()->MoveFly( this, &rPageFrame );
|
|
}
|
|
else
|
|
{
|
|
rPageFrame.AppendFlyToPage( this );
|
|
}
|
|
}
|
|
|
|
// #i28701#
|
|
|
|
void SwFlyLayFrame::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
|
|
{
|
|
if (rHint.GetId() == SfxHintId::SwAutoFormatUsedHint)
|
|
{
|
|
// There's a FlyFrame, so use it
|
|
static_cast<const sw::AutoFormatUsedHint&>(rHint).SetUsed();
|
|
return;
|
|
}
|
|
if (rHint.GetId() == SfxHintId::SwFormatChange)
|
|
{
|
|
auto pChangeHint = static_cast<const SwFormatChangeHint*>(&rHint);
|
|
if(pChangeHint->m_pNewFormat)
|
|
SwFlyFrame::SwClientNotify(rMod, rHint);
|
|
return;
|
|
}
|
|
if (rHint.GetId() != SfxHintId::SwLegacyModify)
|
|
return;
|
|
auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
|
|
if(!pLegacy->m_pNew)
|
|
return;
|
|
const auto pAnch = GetAnchorFromPoolItem(*pLegacy->m_pNew);
|
|
|
|
if(!pAnch)
|
|
{
|
|
SwFlyFrame::SwClientNotify(rMod, rHint);
|
|
return;
|
|
}
|
|
SAL_WARN_IF(pAnch->GetAnchorId() == GetFormat()->GetAnchor().GetAnchorId(), "sw.core", "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())
|
|
{
|
|
SwRootFrame* pRoot = getRootFrame();
|
|
SwPageFrame* pTmpPage = static_cast<SwPageFrame*>(pRoot->Lower());
|
|
sal_uInt16 nPagesToFlip = pAnch->GetPageNum()-1;
|
|
while(pTmpPage && nPagesToFlip)
|
|
{
|
|
pTmpPage = static_cast<SwPageFrame*>(pTmpPage->GetNext());
|
|
--nPagesToFlip;
|
|
}
|
|
if(pTmpPage && !nPagesToFlip)
|
|
{
|
|
// #i50432# - adjust synopsis of <PlaceFly(..)>
|
|
pTmpPage->PlaceFly(this, nullptr);
|
|
}
|
|
if(!pTmpPage)
|
|
{
|
|
pRoot->SetAssertFlyPages();
|
|
pRoot->AssertFlyPages();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SwNodeIndex aIdx(*pAnch->GetAnchorNode());
|
|
SwContentFrame* pContent = SwNodes::GoNext(&aIdx)->
|
|
GetContentNode()->getLayoutFrame(getRootFrame(), nullptr, nullptr);
|
|
if(pContent)
|
|
{
|
|
SwFlyFrame *pTmp = pContent->FindFlyFrame();
|
|
if(pTmp)
|
|
pTmp->AppendFly(this);
|
|
}
|
|
}
|
|
// #i28701# - use new method <GetPageFrame()>
|
|
if ( pOldPage && pOldPage != GetPageFrame() )
|
|
NotifyBackground( pOldPage, aOld, PrepareHint::FlyFrameLeave );
|
|
SetCompletePaint();
|
|
InvalidateAll();
|
|
SetNotifyBack();
|
|
}
|
|
|
|
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();
|
|
SdrObject* pDrawObj = nullptr;
|
|
if (auto pFormat = pFly->GetFormat())
|
|
if (auto pShapeFormat = SwTextBoxHelper::getOtherTextBoxFormat(pFormat, RES_FLYFRMFMT))
|
|
pDrawObj = pShapeFormat->FindRealSdrObject();
|
|
|
|
if (pDrawObj)
|
|
{
|
|
if (auto pPage = pDrawObj->getSdrPageFromSdrObject())
|
|
pPage->SetObjectOrdNum(pDrawObj->GetOrdNumDirect(), nNewNum);
|
|
else
|
|
pDrawObj->SetOrdNum(nNewNum);
|
|
}
|
|
|
|
if ( pObj->getSdrPageFromSdrObject() )
|
|
pObj->getSdrPageFromSdrObject()->SetObjectOrdNum( pFly->GetVirtDrawObj()->GetOrdNumDirect(), nNewNum + (pDrawObj ? 1 : 0) );
|
|
else
|
|
pFly->GetVirtDrawObj()->SetOrdNum( nNewNum + (pDrawObj ? 1 : 0));
|
|
}
|
|
|
|
// 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();
|
|
// needed to reposition at-page anchored flys moved from different page
|
|
pNew->InvalidateObjPos();
|
|
|
|
// 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 !ENABLE_WASM_STRIP_ACCESSIBILITY
|
|
if( GetUpper() &&
|
|
static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
|
|
static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
|
|
{
|
|
static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
|
|
->AddAccessibleFrame( pNew );
|
|
}
|
|
#endif
|
|
}
|
|
|
|
// #i28701# - correction: consider also drawing objects
|
|
if ( !pNew->GetDrawObjs() )
|
|
return;
|
|
|
|
SwSortedObjs &rObjs = *pNew->GetDrawObjs();
|
|
for (SwAnchoredObject* pTmpObj : rObjs)
|
|
{
|
|
if ( auto pTmpFly = pTmpObj->DynCastFlyFrame() )
|
|
{
|
|
// #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 )
|
|
{
|
|
pTmpObj->RegisterAtPage(*this);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
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 !ENABLE_WASM_STRIP_ACCESSIBILITY
|
|
if( GetUpper() &&
|
|
static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
|
|
static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
|
|
{
|
|
static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
|
|
->DisposeAccessibleFrame( pToRemove, true );
|
|
}
|
|
#endif
|
|
|
|
// #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 !ENABLE_WASM_STRIP_ACCESSIBILITY
|
|
if( GetUpper() &&
|
|
static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
|
|
static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
|
|
{
|
|
static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
|
|
->DisposeAccessibleFrame( pToMove, true );
|
|
}
|
|
#endif
|
|
|
|
// 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();
|
|
}
|
|
|
|
// Removing a fly from the page affects the margin of tables, so update the frame print area
|
|
// of the lowers of my body frame.
|
|
SwFrame* pBodyFrame = FindBodyCont();
|
|
if (pBodyFrame)
|
|
{
|
|
for (SwFrame* pFrame = pBodyFrame->GetLower(); pFrame; pFrame = pFrame->GetNext())
|
|
{
|
|
if (!pFrame->IsTabFrame())
|
|
{
|
|
// This is meant to match SwTabFrame::CalcFlyOffsets(), so not relevant for
|
|
// other frame types.
|
|
continue;
|
|
}
|
|
|
|
pFrame->InvalidatePrt();
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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();
|
|
|
|
if (pToMove->IsFlySplitAllowed())
|
|
{
|
|
// Inserting a fly to the page affects the fly portions of the intersecting paragraphs, so
|
|
// update the portions of the anchor of the fly frame.
|
|
SwTextFrame* pAnchor = pToMove->FindAnchorCharFrame();
|
|
if (pAnchor)
|
|
{
|
|
pAnchor->ClearPara();
|
|
}
|
|
}
|
|
|
|
// 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 !ENABLE_WASM_STRIP_ACCESSIBILITY
|
|
if( GetUpper() &&
|
|
static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
|
|
static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
|
|
{
|
|
static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
|
|
->AddAccessibleFrame( pToMove );
|
|
}
|
|
#endif
|
|
|
|
// #i28701# - correction: move lowers of Writer fly frame
|
|
if ( !pToMove->GetDrawObjs() )
|
|
return;
|
|
|
|
SwSortedObjs &rObjs = *pToMove->GetDrawObjs();
|
|
for (SwAnchoredObject* pObj : rObjs)
|
|
{
|
|
pObj->RegisterAtPage(*pDest);
|
|
}
|
|
}
|
|
|
|
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() )
|
|
{
|
|
const SwFrameFormat* pObjFormat = _rToRemoveObj.GetFrameFormat();
|
|
if (pObjFormat
|
|
&& RndStdIds::FLY_AS_CHAR != pObjFormat->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 && 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().Contains( pFly->getFrameArea().Pos() ) )
|
|
{
|
|
if( pUp->IsFlyFrame() )
|
|
{
|
|
const SwFlyFrame *pTmpFly = static_cast<const SwFlyFrame*>(pUp);
|
|
while( pTmpFly->GetNextLink() )
|
|
{
|
|
pTmpFly = pTmpFly->GetNextLink();
|
|
if( pTmpFly->getFrameArea().Contains( pFly->getFrameArea().Pos() ) )
|
|
break;
|
|
}
|
|
pUp = pTmpFly;
|
|
}
|
|
else if( pUp->IsInFootnote() )
|
|
{
|
|
const SwFootnoteFrame *pTmp = pUp->FindFootnoteFrame();
|
|
while( pTmp->GetFollow() )
|
|
{
|
|
pTmp = pTmp->GetFollow();
|
|
if( pTmp->getFrameArea().Contains( 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());
|
|
bool bOnlyCellFrame = pUp->IsCellFrame();
|
|
while( pUp->IsColumnFrame() || pUp->IsSctFrame() || pUp->IsColBodyFrame())
|
|
pUp = pUp->GetUpper();
|
|
rRect = pUp->getFrameArea();
|
|
if( !pUp->IsBodyFrame() )
|
|
{
|
|
bool bCropByFixedHeightCell = false;
|
|
// allow zoom image cropped by fixed height table cell
|
|
if ( bOnlyCellFrame && pUp->IsCellFrame() && pUp->GetUpper() &&
|
|
// is a fixed height table row?
|
|
pUp->GetUpper()->IsRowFrame() && SwFrameSize::Fixed ==
|
|
pUp->GetUpper()->GetAttrSet()->GetFrameSize().GetHeightSizeType() )
|
|
{
|
|
// is image anchored as character?
|
|
if ( const SwContact* pC = GetUserCall(pSdrObj) )
|
|
{
|
|
const SwFrameFormat* pFormat = pC->GetFormat();
|
|
const SwFormatAnchor& rAnch = pFormat->GetAnchor();
|
|
if ( RndStdIds::FLY_AS_CHAR == rAnch.GetAnchorId() )
|
|
{
|
|
const SwPageFrame *pPageFrame = pFly->FindPageFrame();
|
|
Size aSize( pPageFrame->getFramePrintArea().SSize() );
|
|
// TODO doubled print area is still cropped by full page size, yet
|
|
rRect.SSize(Size(aSize.getWidth() * 2, aSize.getHeight() * 2));
|
|
bCropByFixedHeightCell = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( !bCropByFixedHeightCell )
|
|
{
|
|
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()) );
|
|
}
|
|
tools::Long nHeight = (9*aRectFnSet.GetHeight(rRect))/10;
|
|
tools::Long nTop;
|
|
if (const SwContact* pContact = ::GetUserCall( pSdrObj ))
|
|
{
|
|
const SwFormat *pFormat = pContact->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 );
|
|
tools::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
|
|
{
|
|
if (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);
|
|
tools::Long nHeight = (9 * aRectFnSet.GetHeight(rRect)) / 10;
|
|
tools::Long nTop;
|
|
const SvxULSpaceItem& rUL = pFormat->GetULSpace();
|
|
SwRect aSnapRect(pSdrObj->GetSnapRect());
|
|
tools::Long nTmpH = 0;
|
|
if (bMove)
|
|
{
|
|
nTop = aRectFnSet.YInc(aRectFnSet.IsVert() ? pSdrObj->GetAnchorPos().X()
|
|
: pSdrObj->GetAnchorPos().Y(),
|
|
-nHeight);
|
|
tools::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: */
|