diff options
Diffstat (limited to 'sw/source/core/layout/fly.cxx')
-rw-r--r-- | sw/source/core/layout/fly.cxx | 2917 |
1 files changed, 2917 insertions, 0 deletions
diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx new file mode 100644 index 000000000..e3c52a035 --- /dev/null +++ b/sw/source/core/layout/fly.cxx @@ -0,0 +1,2917 @@ +/* -*- 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 <svl/itemiter.hxx> +#include <vcl/imap.hxx> +#include <tools/helpers.hxx> +#include <editeng/protitem.hxx> +#include <editeng/opaqitem.hxx> +#include <editeng/ulspitem.hxx> +#include <editeng/frmdiritem.hxx> +#include <editeng/outlobj.hxx> +#include <fmtfsize.hxx> +#include <fmtclds.hxx> +#include <fmtcntnt.hxx> +#include <fmturl.hxx> +#include <fmtsrnd.hxx> +#include <fmtornt.hxx> +#include <fmtcnct.hxx> +#include <ndgrf.hxx> +#include <tolayoutanchoredobjectposition.hxx> +#include <fmtfollowtextflow.hxx> +#include <sortedobjs.hxx> +#include <objectformatter.hxx> +#include <ndole.hxx> +#include <swtable.hxx> +#include <svx/svdoashp.hxx> +#include <layouter.hxx> +#include <pagefrm.hxx> +#include <rootfrm.hxx> +#include <viewimp.hxx> +#include <viewopt.hxx> +#include <dcontact.hxx> +#include <dflyobj.hxx> +#include <dview.hxx> +#include <frmatr.hxx> +#include <frmtool.hxx> +#include <hints.hxx> +#include <tabfrm.hxx> +#include <txtfrm.hxx> +#include <notxtfrm.hxx> +#include <flyfrms.hxx> +#include <sectfrm.hxx> +#include <vcl/svapp.hxx> +#include <calbck.hxx> +#include <IDocumentDrawModelAccess.hxx> +#include <IDocumentSettingAccess.hxx> +#include <IDocumentLayoutAccess.hxx> +#include <textboxhelper.hxx> +#include <txtfly.hxx> +#include <ndindex.hxx> +#include <basegfx/matrix/b2dhommatrixtools.hxx> + +#include <wrtsh.hxx> +#include <view.hxx> +#include <edtwin.hxx> +#include <bodyfrm.hxx> +#include <FrameControlsManager.hxx> +#include <ndtxt.hxx> + +using namespace ::com::sun::star; + +static SwTwips lcl_CalcAutoWidth( const SwLayoutFrame& rFrame ); + +SwFlyFrame::SwFlyFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch ) : + SwLayoutFrame( pFormat, pSib ), + SwAnchoredObject(), // #i26791# + m_pPrevLink( nullptr ), + m_pNextLink( nullptr ), + m_bInCnt( false ), + m_bAtCnt( false ), + m_bLayout( false ), + m_bAutoPosition( false ), + m_bValidContentPos( false ) +{ + mnFrameType = SwFrameType::Fly; + + m_bInvalid = m_bNotifyBack = true; + m_bLocked = m_bMinHeight = + m_bHeightClipped = m_bWidthClipped = m_bFormatHeightOnly = false; + + // Size setting: Fixed size is always the width + const SwFormatFrameSize &rFrameSize = pFormat->GetFrameSize(); + const SvxFrameDirection nDir = pFormat->GetFormatAttr( RES_FRAMEDIR ).GetValue(); + if( SvxFrameDirection::Environment == nDir ) + { + mbDerivedVert = true; + mbDerivedR2L = true; + } + else + { + mbInvalidVert = false; + mbDerivedVert = false; + mbDerivedR2L = false; + if( SvxFrameDirection::Horizontal_LR_TB == nDir || SvxFrameDirection::Horizontal_RL_TB == nDir ) + { + mbVertLR = false; + mbVertical = false; + } + else + { + const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr; + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + { + mbVertLR = false; + mbVertical = false; + } + else + { + mbVertical = true; + + if ( SvxFrameDirection::Vertical_LR_TB == nDir ) + mbVertLR = true; + else if (nDir == SvxFrameDirection::Vertical_LR_BT) + { + mbVertLR = true; + mbVertLRBT = true; + } + else + mbVertLR = false; + } + } + + mbInvalidR2L = false; + if( SvxFrameDirection::Horizontal_RL_TB == nDir ) + mbRightToLeft = true; + else + mbRightToLeft = false; + } + + { + SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); + aFrm.Width( rFrameSize.GetWidth() ); + aFrm.Height( rFrameSize.GetHeightSizeType() == SwFrameSize::Variable ? MINFLY : rFrameSize.GetHeight() ); + } + + // Fixed or variable Height? + if ( rFrameSize.GetHeightSizeType() == SwFrameSize::Minimum ) + m_bMinHeight = true; + else if ( rFrameSize.GetHeightSizeType() == SwFrameSize::Fixed ) + mbFixSize = true; + + // insert columns, if necessary + InsertColumns(); + + // First the Init, then the Content: + // This is due to the fact that the Content may have Objects/Frames, + // which are then registered + InitDrawObj(); + + Chain( pAnch ); + + InsertCnt(); + + // Put it somewhere outside so that out document is not formatted unnecessarily often + SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); + aFrm.Pos().setX(FAR_AWAY); + aFrm.Pos().setY(FAR_AWAY); +} + +void SwFlyFrame::Chain( SwFrame* _pAnch ) +{ + // Connect to chain neighbours. + // No problem, if a neighbor doesn't exist - the construction of the + // neighbor will make the connection + const SwFormatChain& rChain = GetFormat()->GetChain(); + if ( rChain.GetPrev() || rChain.GetNext() ) + { + if ( rChain.GetNext() ) + { + SwFlyFrame* pFollow = FindChainNeighbour( *rChain.GetNext(), _pAnch ); + if ( pFollow ) + { + OSL_ENSURE( !pFollow->GetPrevLink(), "wrong chain detected" ); + if ( !pFollow->GetPrevLink() ) + SwFlyFrame::ChainFrames( this, pFollow ); + } + } + if ( rChain.GetPrev() ) + { + SwFlyFrame *pMaster = FindChainNeighbour( *rChain.GetPrev(), _pAnch ); + if ( pMaster ) + { + OSL_ENSURE( !pMaster->GetNextLink(), "wrong chain detected" ); + if ( !pMaster->GetNextLink() ) + SwFlyFrame::ChainFrames( pMaster, this ); + } + } + } +} + +void SwFlyFrame::InsertCnt() +{ + if ( !GetPrevLink() ) + { + const SwFormatContent& rContent = GetFormat()->GetContent(); + OSL_ENSURE( rContent.GetContentIdx(), ":-( no content prepared." ); + sal_uLong nIndex = rContent.GetContentIdx()->GetIndex(); + // Lower() means SwColumnFrame; the Content then needs to be inserted into the (Column)BodyFrame + ::InsertCnt_( Lower() ? static_cast<SwLayoutFrame*>(static_cast<SwLayoutFrame*>(Lower())->Lower()) : static_cast<SwLayoutFrame*>(this), + GetFormat()->GetDoc(), nIndex ); + + // NoText always have a fixed height. + if ( Lower() && Lower()->IsNoTextFrame() ) + { + mbFixSize = true; + m_bMinHeight = false; + } + } +} + +void SwFlyFrame::InsertColumns() +{ + // #i97379# + // Check, if column are allowed. + // Columns are not allowed for fly frames, which represent graphics or embedded objects. + const SwFormatContent& rContent = GetFormat()->GetContent(); + OSL_ENSURE( rContent.GetContentIdx(), "<SwFlyFrame::InsertColumns()> - no content prepared." ); + SwNodeIndex aFirstContent( *(rContent.GetContentIdx()), 1 ); + if ( aFirstContent.GetNode().IsNoTextNode() ) + { + return; + } + + const SwFormatCol &rCol = GetFormat()->GetCol(); + if ( rCol.GetNumCols() > 1 ) + { + // Start off PrtArea to be as large as Frame, so that we can put in the columns + // properly. It'll adjust later on. + { + SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); + aPrt.Width( getFrameArea().Width() ); + aPrt.Height( getFrameArea().Height() ); + } + + const SwFormatCol aOld; // ChgColumns() also needs an old value passed + ChgColumns( aOld, rCol ); + } +} + +void SwFlyFrame::DestroyImpl() +{ + // Accessible objects for fly frames will be destroyed in this destructor. + // For frames bound as char or frames that don't have an anchor we have + // to do that ourselves. For any other frame the call RemoveFly at the + // anchor will do that. + if( IsAccessibleFrame() && GetFormat() && (IsFlyInContentFrame() || !GetAnchorFrame()) ) + { + SwRootFrame *pRootFrame = getRootFrame(); + if( pRootFrame && pRootFrame->IsAnyShellAccessible() ) + { + SwViewShell *pVSh = pRootFrame->GetCurrShell(); + if( pVSh && pVSh->Imp() ) + { + // Lowers aren't disposed already, so we have to do a recursive + // dispose + pVSh->Imp()->DisposeAccessibleFrame( this, true ); + } + } + } + + if( GetFormat() && !GetFormat()->GetDoc()->IsInDtor() ) + { + ClearTmpConsiderWrapInfluence(); // remove this from SwLayouter + + Unchain(); + + DeleteCnt(); + + if ( GetAnchorFrame() ) + AnchorFrame()->RemoveFly( this ); + } + + FinitDrawObj(); + + SwLayoutFrame::DestroyImpl(); + + SwWrtShell* pWrtSh = dynamic_cast<SwWrtShell*>(getRootFrame()->GetCurrShell()); + UpdateUnfloatButton(pWrtSh, false); +} + +SwFlyFrame::~SwFlyFrame() +{ +} + +const IDocumentDrawModelAccess& SwFlyFrame::getIDocumentDrawModelAccess() +{ + return GetFormat()->getIDocumentDrawModelAccess(); +} + +void SwFlyFrame::Unchain() +{ + if ( GetPrevLink() ) + UnchainFrames( GetPrevLink(), this ); + if ( GetNextLink() ) + UnchainFrames( this, GetNextLink() ); +} + +void SwFlyFrame::DeleteCnt() +{ + SwFrame* pFrame = m_pLower; + while ( pFrame ) + { + while ( pFrame->GetDrawObjs() && pFrame->GetDrawObjs()->size() ) + { + SwAnchoredObject *pAnchoredObj = (*pFrame->GetDrawObjs())[0]; + if ( dynamic_cast<const SwFlyFrame*>( pAnchoredObj) != nullptr ) + { + SwFrame::DestroyFrame(static_cast<SwFlyFrame*>(pAnchoredObj)); + } + else if ( dynamic_cast<const SwAnchoredDrawObject*>( pAnchoredObj) != nullptr ) + { + // consider 'virtual' drawing objects + SdrObject* pObj = pAnchoredObj->DrawObj(); + if ( dynamic_cast<const SwDrawVirtObj*>( pObj) != nullptr ) + { + SwDrawVirtObj* pDrawVirtObj = static_cast<SwDrawVirtObj*>(pObj); + pDrawVirtObj->RemoveFromWriterLayout(); + pDrawVirtObj->RemoveFromDrawingPage(); + } + else + { + SwDrawContact* pContact = + static_cast<SwDrawContact*>(::GetUserCall( pObj )); + if ( pContact ) + { + pContact->DisconnectFromLayout(); + } + } + } + } + + pFrame->RemoveFromLayout(); + SwFrame::DestroyFrame(pFrame); + pFrame = m_pLower; + } + + InvalidatePage(); +} + +void SwFlyFrame::InitDrawObj() +{ + SetDrawObj(*SwFlyDrawContact::CreateNewRef(this, GetFormat())); + + // Set the right Layer + IDocumentDrawModelAccess& rIDDMA = GetFormat()->getIDocumentDrawModelAccess(); + SdrLayerID nHeavenId = rIDDMA.GetHeavenId(); + SdrLayerID nHellId = rIDDMA.GetHellId(); + GetVirtDrawObj()->SetLayer( GetFormat()->GetOpaque().GetValue() + ? nHeavenId + : nHellId ); +} + +static SwPosition ResolveFlyAnchor(SwFrameFormat const& rFlyFrame) +{ + SwFormatAnchor const& rAnch(rFlyFrame.GetAnchor()); + if (rAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE) + { // arbitrarily pick last node + return SwPosition(SwNodeIndex(rFlyFrame.GetDoc()->GetNodes().GetEndOfContent(), -1)); + } + else + { + SwPosition const*const pPos(rAnch.GetContentAnchor()); + assert(pPos); + if (SwFrameFormat const*const pParent = pPos->nNode.GetNode().GetFlyFormat()) + { + return ResolveFlyAnchor(*pParent); + } + else if (pPos->nContent.GetIdxReg()) + { + return *pPos; + } + else + { + return SwPosition(*pPos->nNode.GetNode().GetContentNode(), 0); + } + } +} + +void SwFlyFrame::FinitDrawObj() +{ + if(!GetVirtDrawObj() ) + return; + SwFormat* pFormat = GetFormat(); + // Deregister from SdrPageViews if the Objects is still selected there. + if(!pFormat->GetDoc()->IsInDtor()) + { + SwViewShell* p1St = getRootFrame()->GetCurrShell(); + if(p1St) + { + for(SwViewShell& rCurrentShell : p1St->GetRingContainer()) + { // At the moment the Drawing can do just do an Unmark on everything, + // as the Object was already removed + if (rCurrentShell.HasDrawView() && + rCurrentShell.Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount()) + { + if (SwFEShell *const pFEShell = dynamic_cast<SwFEShell*>(&rCurrentShell)) + { // tdf#131679 move any cursor out of fly + SwFlyFrame const*const pOldSelFly = ::GetFlyFromMarked(nullptr, pFEShell); + rCurrentShell.Imp()->GetDrawView()->UnmarkAll(); + if (pOldSelFly) + { + SwPosition const pos(ResolveFlyAnchor(*pOldSelFly->GetFormat())); + SwPaM const temp(pos); + pFEShell->SetSelection(temp); + // could also call SetCursor() like SwFEShell::SelectObj() + // does, but that would access layout a bit much... + } + } + else + { + rCurrentShell.Imp()->GetDrawView()->UnmarkAll(); + } + } + } + } + } + + // Else calls delete of the ContactObj + GetVirtDrawObj()->SetUserCall(nullptr); + + // Deregisters itself at the Master + // always use SdrObject::Free(...) for SdrObjects (!) + SdrObject* pTemp(GetVirtDrawObj()); + SdrObject::Free(pTemp); +} + +void SwFlyFrame::ChainFrames( SwFlyFrame *pMaster, SwFlyFrame *pFollow ) +{ + OSL_ENSURE( pMaster && pFollow, "incomplete chain" ); + OSL_ENSURE( !pMaster->GetNextLink(), "link can not be changed" ); + OSL_ENSURE( !pFollow->GetPrevLink(), "link can not be changed" ); + + pMaster->m_pNextLink = pFollow; + pFollow->m_pPrevLink = pMaster; + + if ( pMaster->ContainsContent() ) + { + // To get a text flow we need to invalidate + SwFrame *pInva = pMaster->FindLastLower(); + SwRectFnSet aRectFnSet(pMaster); + const long nBottom = aRectFnSet.GetPrtBottom(*pMaster); + while ( pInva ) + { + if( aRectFnSet.BottomDist( pInva->getFrameArea(), nBottom ) <= 0 ) + { + pInva->InvalidateSize(); + pInva->Prepare(); + pInva = pInva->FindPrev(); + } + else + pInva = nullptr; + } + } + + if ( pFollow->ContainsContent() ) + { + // There's only the content from the Masters left; the content from the Follow + // does not have any Frames left (should always be exactly one empty TextNode). + SwFrame *pFrame = pFollow->ContainsContent(); + OSL_ENSURE( !pFrame->IsTabFrame() && !pFrame->FindNext(), "follow in chain contains content" ); + pFrame->Cut(); + SwFrame::DestroyFrame(pFrame); + } + + // invalidate accessible relation set (accessibility wrapper) + SwViewShell* pSh = pMaster->getRootFrame()->GetCurrShell(); + if( pSh ) + { + SwRootFrame* pLayout = pMaster->getRootFrame(); + if( pLayout && pLayout->IsAnyShellAccessible() ) + pSh->Imp()->InvalidateAccessibleRelationSet( pMaster, pFollow ); + } +} + +void SwFlyFrame::UnchainFrames( SwFlyFrame *pMaster, SwFlyFrame *pFollow ) +{ + pMaster->m_pNextLink = nullptr; + pFollow->m_pPrevLink = nullptr; + + if ( pFollow->ContainsContent() ) + { + // The Master sucks up the content of the Follow + SwLayoutFrame *pUpper = pMaster; + if ( pUpper->Lower()->IsColumnFrame() ) + { + pUpper = static_cast<SwLayoutFrame*>(pUpper->GetLastLower()); + pUpper = static_cast<SwLayoutFrame*>(pUpper->Lower()); // The (Column)BodyFrame + OSL_ENSURE( pUpper && pUpper->IsColBodyFrame(), "Missing ColumnBody" ); + } + SwFlyFrame *pFoll = pFollow; + while ( pFoll ) + { + SwFrame *pTmp = ::SaveContent( pFoll ); + if ( pTmp ) + ::RestoreContent( pTmp, pUpper, pMaster->FindLastLower() ); + pFoll->SetCompletePaint(); + pFoll->InvalidateSize(); + pFoll = pFoll->GetNextLink(); + } + } + + // The Follow needs his own content to be served + const SwFormatContent &rContent = pFollow->GetFormat()->GetContent(); + OSL_ENSURE( rContent.GetContentIdx(), ":-( No content prepared." ); + sal_uLong nIndex = rContent.GetContentIdx()->GetIndex(); + // Lower() means SwColumnFrame: this one contains another SwBodyFrame + ::InsertCnt_( pFollow->Lower() ? const_cast<SwLayoutFrame*>(static_cast<const SwLayoutFrame*>(static_cast<const SwLayoutFrame*>(pFollow->Lower())->Lower())) + : static_cast<SwLayoutFrame*>(pFollow), + pFollow->GetFormat()->GetDoc(), ++nIndex ); + + // invalidate accessible relation set (accessibility wrapper) + SwViewShell* pSh = pMaster->getRootFrame()->GetCurrShell(); + if( pSh ) + { + SwRootFrame* pLayout = pMaster->getRootFrame(); + if( pLayout && pLayout->IsAnyShellAccessible() ) + pSh->Imp()->InvalidateAccessibleRelationSet( pMaster, pFollow ); + } +} + +SwFlyFrame *SwFlyFrame::FindChainNeighbour( SwFrameFormat const &rChain, SwFrame *pAnch ) +{ + // We look for the Fly that's in the same Area. + // Areas can for now only be Head/Footer or Flys. + + if ( !pAnch ) // If an Anchor was passed along, that one counts (ctor!) + pAnch = AnchorFrame(); + + SwLayoutFrame *pLay; + if ( pAnch->IsInFly() ) + pLay = pAnch->FindFlyFrame(); + else + { + // FindFooterOrHeader is not appropriate here, as we may not have a + // connection to the Anchor yet. + pLay = pAnch->GetUpper(); + while ( pLay && !(pLay->GetType() & (SwFrameType::Header|SwFrameType::Footer)) ) + pLay = pLay->GetUpper(); + } + + SwIterator<SwFlyFrame,SwFormat> aIter( rChain ); + SwFlyFrame *pFly = aIter.First(); + if ( pLay ) + { + while ( pFly ) + { + if ( pFly->GetAnchorFrame() ) + { + if ( pFly->GetAnchorFrame()->IsInFly() ) + { + if ( pFly->AnchorFrame()->FindFlyFrame() == pLay ) + break; + } + else if ( pLay == pFly->FindFooterOrHeader() ) + break; + } + pFly = aIter.Next(); + } + } + else if ( pFly ) + { + OSL_ENSURE( !aIter.Next(), "chain with more than one instance" ); + } + return pFly; +} + +SwFrame *SwFlyFrame::FindLastLower() +{ + SwFrame *pRet = ContainsAny(); + if ( pRet && pRet->IsInTab() ) + pRet = pRet->FindTabFrame(); + SwFrame *pNxt = pRet; + while ( pNxt && IsAnLower( pNxt ) ) + { pRet = pNxt; + pNxt = pNxt->FindNext(); + } + return pRet; +} + +bool SwFlyFrame::FrameSizeChg( const SwFormatFrameSize &rFrameSize ) +{ + bool bRet = false; + SwTwips nDiffHeight = getFrameArea().Height(); + if ( rFrameSize.GetHeightSizeType() == SwFrameSize::Variable ) + mbFixSize = m_bMinHeight = false; + else + { + if ( rFrameSize.GetHeightSizeType() == SwFrameSize::Fixed ) + { + mbFixSize = true; + m_bMinHeight = false; + } + else if ( rFrameSize.GetHeightSizeType() == SwFrameSize::Minimum ) + { + mbFixSize = false; + m_bMinHeight = true; + } + nDiffHeight -= rFrameSize.GetHeight(); + } + // If the Fly contains columns, we already need to set the Fly + // and the Columns to the required value or else we run into problems. + if ( Lower() ) + { + if ( Lower()->IsColumnFrame() ) + { + const SwRect aOld( GetObjRectWithSpaces() ); + const Size aOldSz( getFramePrintArea().SSize() ); + const SwTwips nDiffWidth = getFrameArea().Width() - rFrameSize.GetWidth(); + + { + SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); + aFrm.Height( aFrm.Height() - nDiffHeight ); + aFrm.Width ( aFrm.Width() - nDiffWidth ); + } + + // #i68520# + InvalidateObjRectWithSpaces(); + + { + SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); + aPrt.Height( aPrt.Height() - nDiffHeight ); + aPrt.Width ( aPrt.Width() - nDiffWidth ); + } + + ChgLowersProp( aOldSz ); + ::Notify( this, FindPageFrame(), aOld ); + setFrameAreaPositionValid(false); + bRet = true; + } + else if ( Lower()->IsNoTextFrame() ) + { + mbFixSize = true; + m_bMinHeight = false; + } + } + return bRet; +} + +void SwFlyFrame::SwClientNotify(const SwModify& rMod, const SfxHint& rHint) +{ + SwFrame::SwClientNotify(rMod, rHint); + if (auto pGetZOrdnerHint = dynamic_cast<const sw::GetZOrderHint*>(&rHint)) + { + const auto& rFormat(dynamic_cast<const SwFrameFormat&>(rMod)); + if (rFormat.Which() == RES_FLYFRMFMT && rFormat.getIDocumentLayoutAccess().GetCurrentViewShell()) // #i11176# + pGetZOrdnerHint->m_rnZOrder = GetVirtDrawObj()->GetOrdNum(); + } + else if (auto pConnectedHint = dynamic_cast<const sw::GetObjectConnectedHint*>(&rHint)) + { + const auto& rFormat(dynamic_cast<const SwFrameFormat&>(rMod)); + if (!pConnectedHint->m_risConnected && rFormat.Which() == RES_FLYFRMFMT && (!pConnectedHint->m_pRoot || pConnectedHint->m_pRoot == getRootFrame())) + pConnectedHint->m_risConnected = true; + } +} + +void SwFlyFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem * pNew ) +{ + sal_uInt8 nInvFlags = 0; + + if (pNew && pOld && RES_ATTRSET_CHG == pNew->Which()) + { + SfxItemIter aNIter( *static_cast<const SwAttrSetChg*>(pNew)->GetChgSet() ); + SfxItemIter aOIter( *static_cast<const SwAttrSetChg*>(pOld)->GetChgSet() ); + const SfxPoolItem* pNItem = aNIter.GetCurItem(); + const SfxPoolItem* pOItem = aOIter.GetCurItem(); + SwAttrSetChg aOldSet( *static_cast<const SwAttrSetChg*>(pOld) ); + SwAttrSetChg aNewSet( *static_cast<const SwAttrSetChg*>(pNew) ); + do + { + UpdateAttr_(pOItem, pNItem, nInvFlags, &aOldSet, &aNewSet); + pNItem = aNIter.NextItem(); + pOItem = aOIter.NextItem(); + } while (pNItem); + if ( aOldSet.Count() || aNewSet.Count() ) + SwLayoutFrame::Modify( &aOldSet, &aNewSet ); + } + else + UpdateAttr_( pOld, pNew, nInvFlags ); + + if ( nInvFlags == 0 ) + return; + + Invalidate_(); + if ( nInvFlags & 0x01 ) + { + InvalidatePos_(); + // #i68520# + InvalidateObjRectWithSpaces(); + } + if ( nInvFlags & 0x02 ) + { + InvalidateSize_(); + // #i68520# + InvalidateObjRectWithSpaces(); + } + if ( nInvFlags & 0x04 ) + InvalidatePrt_(); + if ( nInvFlags & 0x08 ) + SetNotifyBack(); + if ( nInvFlags & 0x10 ) + SetCompletePaint(); + if ( ( nInvFlags & 0x40 ) && Lower() && Lower()->IsNoTextFrame() ) + ClrContourCache( GetVirtDrawObj() ); + SwRootFrame *pRoot; + if ( nInvFlags & 0x20 && nullptr != (pRoot = getRootFrame()) ) + pRoot->InvalidateBrowseWidth(); + // #i28701# + if ( nInvFlags & 0x80 ) + { + // update sorted object lists, the Writer fly frame is registered at. + UpdateObjInSortedList(); + } + + // #i87645# - reset flags for the layout process (only if something has been invalidated) + ResetLayoutProcessBools(); + +} + +void SwFlyFrame::UpdateAttr_( const SfxPoolItem *pOld, const SfxPoolItem *pNew, + sal_uInt8 &rInvFlags, + SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet ) +{ + bool bClear = true; + const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0; + SwViewShell *pSh = getRootFrame()->GetCurrShell(); + switch( nWhich ) + { + case RES_VERT_ORIENT: + case RES_HORI_ORIENT: + // #i18732# - consider new option 'follow text flow' + case RES_FOLLOW_TEXT_FLOW: + { + // ATTENTION: Always also change Action in ChgRePos()! + rInvFlags |= 0x09; + } + break; + // #i28701# - consider new option 'wrap influence on position' + case RES_WRAP_INFLUENCE_ON_OBJPOS: + { + rInvFlags |= 0x89; + } + break; + case RES_SURROUND: + { + //#i28701# - invalidate position on change of + // wrapping style. + //rInvFlags |= 0x40; + rInvFlags |= 0x41; + // The background needs to be messaged and invalidated + const SwRect aTmp( GetObjRectWithSpaces() ); + NotifyBackground( FindPageFrame(), aTmp, PrepareHint::FlyFrameAttributesChanged ); + + // By changing the flow of frame-bound Frames, a vertical alignment + // can be activated/deactivated => MakeFlyPos + if( RndStdIds::FLY_AT_FLY == GetFormat()->GetAnchor().GetAnchorId() ) + rInvFlags |= 0x09; + + // Delete contour in the Node if necessary + if ( Lower() && Lower()->IsNoTextFrame() && + !GetFormat()->GetSurround().IsContour() ) + { + SwNoTextNode *pNd = static_cast<SwNoTextNode*>(static_cast<SwNoTextFrame*>(Lower())->GetNode()); + if ( pNd->HasContour() ) + pNd->SetContour( nullptr ); + } + // #i28701# - perform reorder of object lists + // at anchor frame and at page frame. + rInvFlags |= 0x80; + } + break; + + case RES_PROTECT: + if (pNew) + { + const SvxProtectItem *pP = static_cast<const SvxProtectItem*>(pNew); + GetVirtDrawObj()->SetMoveProtect( pP->IsPosProtected() ); + GetVirtDrawObj()->SetResizeProtect( pP->IsSizeProtected() ); + if( pSh ) + { + SwRootFrame* pLayout = getRootFrame(); + if( pLayout && pLayout->IsAnyShellAccessible() ) + pSh->Imp()->InvalidateAccessibleEditableState( true, this ); + } + } + break; + case RES_COL: + if (pOld && pNew) + { + ChgColumns( *static_cast<const SwFormatCol*>(pOld), *static_cast<const SwFormatCol*>(pNew) ); + const SwFormatFrameSize &rNew = GetFormat()->GetFrameSize(); + if ( FrameSizeChg( rNew ) ) + NotifyDrawObj(); + rInvFlags |= 0x1A; + } + break; + + case RES_FRM_SIZE: + case RES_FMT_CHG: + { + const SwFormatFrameSize &rNew = GetFormat()->GetFrameSize(); + if ( FrameSizeChg( rNew ) ) + NotifyDrawObj(); + rInvFlags |= 0x7F; + if (pOld && RES_FMT_CHG == nWhich) + { + SwRect aNew( GetObjRectWithSpaces() ); + SwRect aOld( getFrameArea() ); + const SvxULSpaceItem &rUL = static_cast<const SwFormatChg*>(pOld)->pChangedFormat->GetULSpace(); + aOld.Top( std::max( aOld.Top() - long(rUL.GetUpper()), 0L ) ); + aOld.AddHeight(rUL.GetLower() ); + const SvxLRSpaceItem &rLR = static_cast<const SwFormatChg*>(pOld)->pChangedFormat->GetLRSpace(); + aOld.Left ( std::max( aOld.Left() - rLR.GetLeft(), 0L ) ); + aOld.AddWidth(rLR.GetRight() ); + aNew.Union( aOld ); + NotifyBackground( FindPageFrame(), aNew, PrepareHint::Clear ); + + // Special case: + // When assigning a template we cannot rely on the old column + // attribute. As there need to be at least enough for ChgColumns, + // we need to create a temporary attribute. + SwFormatCol aCol; + if ( Lower() && Lower()->IsColumnFrame() ) + { + sal_uInt16 nCol = 0; + SwFrame *pTmp = Lower(); + do + { ++nCol; + pTmp = pTmp->GetNext(); + } while ( pTmp ); + aCol.Init( nCol, 0, 1000 ); + } + ChgColumns( aCol, GetFormat()->GetCol() ); + } + + SwFormatURL aURL( GetFormat()->GetURL() ); + + SwFormatFrameSize *pNewFormatFrameSize = nullptr; + SwFormatChg *pOldFormatChg = nullptr; + if (nWhich == RES_FRM_SIZE) + pNewFormatFrameSize = const_cast<SwFormatFrameSize*>(static_cast<const SwFormatFrameSize*>(pNew)); + else + pOldFormatChg = const_cast<SwFormatChg*>(static_cast<const SwFormatChg*>(pOld)); + + if (aURL.GetMap() && (pNewFormatFrameSize || pOldFormatChg)) + { + const SwFormatFrameSize &rOld = pNewFormatFrameSize ? + *pNewFormatFrameSize : + pOldFormatChg->pChangedFormat->GetFrameSize(); + //#35091# Can be "times zero", when loading the template + if ( rOld.GetWidth() && rOld.GetHeight() ) + { + + Fraction aScaleX( rOld.GetWidth(), rNew.GetWidth() ); + Fraction aScaleY( rOld.GetHeight(), rOld.GetHeight() ); + aURL.GetMap()->Scale( aScaleX, aScaleY ); + SwFrameFormat *pFormat = GetFormat(); + pFormat->LockModify(); + pFormat->SetFormatAttr( aURL ); + pFormat->UnlockModify(); + } + } + const SvxProtectItem &rP = GetFormat()->GetProtect(); + GetVirtDrawObj()->SetMoveProtect( rP.IsPosProtected() ); + GetVirtDrawObj()->SetResizeProtect( rP.IsSizeProtected() ); + + if ( pSh ) + pSh->InvalidateWindows( getFrameArea() ); + const IDocumentDrawModelAccess& rIDDMA = GetFormat()->getIDocumentDrawModelAccess(); + const SdrLayerID nId = GetFormat()->GetOpaque().GetValue() ? + rIDDMA.GetHeavenId() : + rIDDMA.GetHellId(); + GetVirtDrawObj()->SetLayer( nId ); + + if ( Lower() ) + { + // Delete contour in the Node if necessary + if( Lower()->IsNoTextFrame() && + !GetFormat()->GetSurround().IsContour() ) + { + SwNoTextNode *pNd = static_cast<SwNoTextNode*>(static_cast<SwNoTextFrame*>(Lower())->GetNode()); + if ( pNd->HasContour() ) + pNd->SetContour( nullptr ); + } + else if( !Lower()->IsColumnFrame() ) + { + SwFrame* pFrame = GetLastLower(); + if( pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsUndersized() ) + pFrame->Prepare( PrepareHint::AdjustSizeWithoutFormatting ); + } + } + + // #i28701# - perform reorder of object lists + // at anchor frame and at page frame. + rInvFlags |= 0x80; + + break; + } + case RES_UL_SPACE: + case RES_LR_SPACE: + { + rInvFlags |= 0x41; + if( pSh && pSh->GetViewOptions()->getBrowseMode() ) + getRootFrame()->InvalidateBrowseWidth(); + SwRect aNew( GetObjRectWithSpaces() ); + SwRect aOld( getFrameArea() ); + if (pNew) + { + if ( RES_UL_SPACE == nWhich ) + { + const SvxULSpaceItem &rUL = *static_cast<const SvxULSpaceItem*>(pNew); + aOld.Top( std::max( aOld.Top() - long(rUL.GetUpper()), 0L ) ); + aOld.AddHeight(rUL.GetLower() ); + } + else + { + const SvxLRSpaceItem &rLR = *static_cast<const SvxLRSpaceItem*>(pNew); + aOld.Left ( std::max( aOld.Left() - rLR.GetLeft(), 0L ) ); + aOld.AddWidth(rLR.GetRight() ); + } + } + aNew.Union( aOld ); + NotifyBackground( FindPageFrame(), aNew, PrepareHint::Clear ); + } + break; + + case RES_TEXT_VERT_ADJUST: + { + InvalidateContentPos(); + rInvFlags |= 0x10; + } + break; + + case RES_BOX: + case RES_SHADOW: + rInvFlags |= 0x17; + break; + + case RES_FRAMEDIR : + SetDerivedVert( false ); + SetDerivedR2L( false ); + CheckDirChange(); + break; + + case RES_OPAQUE: + { + if ( pSh ) + pSh->InvalidateWindows( getFrameArea() ); + + const IDocumentDrawModelAccess& rIDDMA = GetFormat()->getIDocumentDrawModelAccess(); + const SdrLayerID nId = static_cast<const SvxOpaqueItem*>(pNew)->GetValue() ? + rIDDMA.GetHeavenId() : + rIDDMA.GetHellId(); + GetVirtDrawObj()->SetLayer( nId ); + if( pSh ) + { + SwRootFrame* pLayout = getRootFrame(); + if( pLayout && pLayout->IsAnyShellAccessible() ) + { + pSh->Imp()->DisposeAccessibleFrame( this ); + pSh->Imp()->AddAccessibleFrame( this ); + } + } + // #i28701# - perform reorder of object lists + // at anchor frame and at page frame. + rInvFlags |= 0x80; + } + break; + + case RES_URL: + // The interface changes the frame size when interacting with text frames, + // the Map, however, needs to be relative to FrameSize(). + if ( (!Lower() || !Lower()->IsNoTextFrame()) && pNew && pOld && + static_cast<const SwFormatURL*>(pNew)->GetMap() && static_cast<const SwFormatURL*>(pOld)->GetMap() ) + { + const SwFormatFrameSize &rSz = GetFormat()->GetFrameSize(); + if ( rSz.GetHeight() != getFrameArea().Height() || + rSz.GetWidth() != getFrameArea().Width() ) + { + SwFormatURL aURL( GetFormat()->GetURL() ); + Fraction aScaleX( getFrameArea().Width(), rSz.GetWidth() ); + Fraction aScaleY( getFrameArea().Height(), rSz.GetHeight() ); + aURL.GetMap()->Scale( aScaleX, aScaleY ); + SwFrameFormat *pFormat = GetFormat(); + pFormat->LockModify(); + pFormat->SetFormatAttr( aURL ); + pFormat->UnlockModify(); + } + } + // No invalidation necessary + break; + + case RES_CHAIN: + if (pNew) + { + const SwFormatChain *pChain = static_cast<const SwFormatChain*>(pNew); + if ( pChain->GetNext() ) + { + SwFlyFrame *pFollow = FindChainNeighbour( *pChain->GetNext() ); + if ( GetNextLink() && pFollow != GetNextLink() ) + SwFlyFrame::UnchainFrames( this, GetNextLink()); + if ( pFollow ) + { + if ( pFollow->GetPrevLink() && + pFollow->GetPrevLink() != this ) + SwFlyFrame::UnchainFrames( pFollow->GetPrevLink(), + pFollow ); + if ( !GetNextLink() ) + SwFlyFrame::ChainFrames( this, pFollow ); + } + } + else if ( GetNextLink() ) + SwFlyFrame::UnchainFrames( this, GetNextLink() ); + if ( pChain->GetPrev() ) + { + SwFlyFrame *pMaster = FindChainNeighbour( *pChain->GetPrev() ); + if ( GetPrevLink() && pMaster != GetPrevLink() ) + SwFlyFrame::UnchainFrames( GetPrevLink(), this ); + if ( pMaster ) + { + if ( pMaster->GetNextLink() && + pMaster->GetNextLink() != this ) + SwFlyFrame::UnchainFrames( pMaster, + pMaster->GetNextLink() ); + if ( !GetPrevLink() ) + SwFlyFrame::ChainFrames( pMaster, this ); + } + } + else if ( GetPrevLink() ) + SwFlyFrame::UnchainFrames( GetPrevLink(), this ); + } + [[fallthrough]]; + default: + bClear = false; + } + if ( bClear ) + { + if ( pOldSet || pNewSet ) + { + if ( pOldSet ) + pOldSet->ClearItem( nWhich ); + if ( pNewSet ) + pNewSet->ClearItem( nWhich ); + } + else + SwLayoutFrame::Modify( pOld, pNew ); + } +} + +/// Gets information from the Modify +bool SwFlyFrame::GetInfo( SfxPoolItem & rInfo ) const +{ + if( RES_AUTOFMT_DOCNODE == rInfo.Which() ) + return false; // There's a FlyFrame, so use it + return true; // Continue searching +} + +void SwFlyFrame::Invalidate_( SwPageFrame const *pPage ) +{ + InvalidatePage( pPage ); + m_bNotifyBack = m_bInvalid = true; + + SwFlyFrame *pFrame; + if ( GetAnchorFrame() && nullptr != (pFrame = AnchorFrame()->FindFlyFrame()) ) + { + // Very bad case: If the Fly is bound within another Fly which + // contains columns, the Format should be from that one. + if ( !pFrame->IsLocked() && !pFrame->IsColLocked() && + pFrame->Lower() && pFrame->Lower()->IsColumnFrame() ) + pFrame->InvalidateSize(); + } + + // #i85216# + // if vertical position is oriented at a layout frame inside a ghost section, + // assure that the position is invalidated and that the information about + // the vertical position oriented frame is cleared + if ( GetVertPosOrientFrame() && GetVertPosOrientFrame()->IsLayoutFrame() ) + { + const SwSectionFrame* pSectFrame( GetVertPosOrientFrame()->FindSctFrame() ); + if ( pSectFrame && pSectFrame->GetSection() == nullptr ) + { + InvalidatePos(); + ClearVertPosOrientFrame(); + } + } +} + +/** Change the relative position + * + * The position will be Fix automatically and the attribute is changed accordingly. + */ +void SwFlyFrame::ChgRelPos( const Point &rNewPos ) +{ + if ( GetCurrRelPos() == rNewPos ) + return; + + SwFrameFormat *pFormat = GetFormat(); + const bool bVert = GetAnchorFrame()->IsVertical(); + const SwTwips nNewY = bVert ? rNewPos.X() : rNewPos.Y(); + SwTwips nTmpY = nNewY == LONG_MAX ? 0 : nNewY; + if( bVert ) + nTmpY = -nTmpY; + SfxItemSet aSet( pFormat->GetDoc()->GetAttrPool(), + svl::Items<RES_VERT_ORIENT, RES_HORI_ORIENT>{}); + + SwFormatVertOrient aVert( pFormat->GetVertOrient() ); + const SwTextFrame *pAutoFrame = nullptr; + // #i34948# - handle also at-page and at-fly anchored + // Writer fly frames + const RndStdIds eAnchorType = GetFrameFormat().GetAnchor().GetAnchorId(); + if ( eAnchorType == RndStdIds::FLY_AT_PAGE ) + { + aVert.SetVertOrient( text::VertOrientation::NONE ); + aVert.SetRelationOrient( text::RelOrientation::PAGE_FRAME ); + } + else if ( eAnchorType == RndStdIds::FLY_AT_FLY ) + { + aVert.SetVertOrient( text::VertOrientation::NONE ); + aVert.SetRelationOrient( text::RelOrientation::FRAME ); + } + else if ( IsFlyAtContentFrame() || text::VertOrientation::NONE != aVert.GetVertOrient() ) + { + if( text::RelOrientation::CHAR == aVert.GetRelationOrient() && IsAutoPos() ) + { + if( LONG_MAX != nNewY ) + { + aVert.SetVertOrient( text::VertOrientation::NONE ); + assert(GetAnchorFrame()->IsTextFrame()); + pAutoFrame = static_cast<const SwTextFrame*>(GetAnchorFrame()); + TextFrameIndex const nOfs(pAutoFrame->MapModelToViewPos( + *pFormat->GetAnchor().GetContentAnchor())); + while( pAutoFrame->GetFollow() && + pAutoFrame->GetFollow()->GetOffset() <= nOfs ) + { + if( pAutoFrame == GetAnchorFrame() ) + nTmpY += pAutoFrame->GetRelPos().Y(); + nTmpY -= pAutoFrame->GetUpper()->getFramePrintArea().Height(); + pAutoFrame = pAutoFrame->GetFollow(); + } + nTmpY = static_cast<SwFlyAtContentFrame*>(this)->GetRelCharY(pAutoFrame)-nTmpY; + } + else + aVert.SetVertOrient( text::VertOrientation::CHAR_BOTTOM ); + } + else + { + aVert.SetVertOrient( text::VertOrientation::NONE ); + aVert.SetRelationOrient( text::RelOrientation::FRAME ); + } + } + aVert.SetPos( nTmpY ); + aSet.Put( aVert ); + + // For Flys in the Cnt, the horizontal orientation is of no interest, + // as it's always 0 + if ( !IsFlyInContentFrame() ) + { + const SwTwips nNewX = bVert ? rNewPos.Y() : rNewPos.X(); + SwTwips nTmpX = nNewX == LONG_MAX ? 0 : nNewX; + SwFormatHoriOrient aHori( pFormat->GetHoriOrient() ); + // #i34948# - handle also at-page and at-fly anchored + // Writer fly frames + if ( eAnchorType == RndStdIds::FLY_AT_PAGE ) + { + aHori.SetHoriOrient( text::HoriOrientation::NONE ); + aHori.SetRelationOrient( text::RelOrientation::PAGE_FRAME ); + aHori.SetPosToggle( false ); + } + else if ( eAnchorType == RndStdIds::FLY_AT_FLY ) + { + aHori.SetHoriOrient( text::HoriOrientation::NONE ); + aHori.SetRelationOrient( text::RelOrientation::FRAME ); + aHori.SetPosToggle( false ); + } + else if ( IsFlyAtContentFrame() || text::HoriOrientation::NONE != aHori.GetHoriOrient() ) + { + aHori.SetHoriOrient( text::HoriOrientation::NONE ); + if( text::RelOrientation::CHAR == aHori.GetRelationOrient() && IsAutoPos() ) + { + if( LONG_MAX != nNewX ) + { + if( !pAutoFrame ) + { + assert(GetAnchorFrame()->IsTextFrame()); + pAutoFrame = static_cast<const SwTextFrame*>(GetAnchorFrame()); + TextFrameIndex const nOfs(pAutoFrame->MapModelToViewPos( + *pFormat->GetAnchor().GetContentAnchor())); + while( pAutoFrame->GetFollow() && + pAutoFrame->GetFollow()->GetOffset() <= nOfs ) + pAutoFrame = pAutoFrame->GetFollow(); + } + nTmpX -= static_cast<SwFlyAtContentFrame*>(this)->GetRelCharX(pAutoFrame); + } + } + else + aHori.SetRelationOrient( text::RelOrientation::FRAME ); + aHori.SetPosToggle( false ); + } + aHori.SetPos( nTmpX ); + aSet.Put( aHori ); + } + SetCurrRelPos( rNewPos ); + pFormat->GetDoc()->SetAttr( aSet, *pFormat ); + +} + +/** "Formats" the Frame; Frame and PrtArea. + * + * The FixSize is not inserted here. + */ +void SwFlyFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs *pAttrs ) +{ + OSL_ENSURE( pAttrs, "FlyFrame::Format, pAttrs is 0." ); + + ColLock(); + + if ( !isFrameAreaSizeValid() ) + { + if ( getFrameArea().Top() == FAR_AWAY && getFrameArea().Left() == FAR_AWAY ) + { + // Remove safety switch (see SwFrame::CTor) + { + SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); + aFrm.Pos().setX(0); + aFrm.Pos().setY(0); + } + + // #i68520# + InvalidateObjRectWithSpaces(); + } + + // Check column width and set it if needed + if ( Lower() && Lower()->IsColumnFrame() ) + AdjustColumns( nullptr, false ); + + setFrameAreaSizeValid(true); + + const SwTwips nUL = pAttrs->CalcTopLine() + pAttrs->CalcBottomLine(); + const SwTwips nLR = pAttrs->CalcLeftLine() + pAttrs->CalcRightLine(); + const SwFormatFrameSize &rFrameSz = GetFormat()->GetFrameSize(); + Size aRelSize( CalcRel( rFrameSz ) ); + + OSL_ENSURE( pAttrs->GetSize().Height() != 0 || rFrameSz.GetHeightPercent(), "FrameAttr height is 0." ); + OSL_ENSURE( pAttrs->GetSize().Width() != 0 || rFrameSz.GetWidthPercent(), "FrameAttr width is 0." ); + + SwRectFnSet aRectFnSet(this); + if( !HasFixSize() ) + { + long nMinHeight = 0; + if( IsMinHeight() ) + nMinHeight = aRectFnSet.IsVert() ? aRelSize.Width() : aRelSize.Height(); + + SwTwips nRemaining = CalcContentHeight(pAttrs, nMinHeight, nUL); + if( IsMinHeight() && (nRemaining + nUL) < nMinHeight ) + nRemaining = nMinHeight - nUL; + // Because the Grow/Shrink of the Flys does not directly + // set the size - only indirectly by triggering a Format() + // via Invalidate() - the sizes need to be set here. + // Notification is running along already. + // As we already got a lot of zeros per attribute, we block them + // from now on. + + if ( nRemaining < MINFLY ) + nRemaining = MINFLY; + + { + SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); + aRectFnSet.SetHeight( aPrt, nRemaining ); + } + + nRemaining -= aRectFnSet.GetHeight(getFrameArea()); + + { + SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); + aRectFnSet.AddBottom( aFrm, nRemaining + nUL ); + } + + // #i68520# + if ( nRemaining + nUL != 0 ) + { + InvalidateObjRectWithSpaces(); + } + + setFrameAreaSizeValid(true); + + if (SwFrameFormat* pShapeFormat = SwTextBoxHelper::getOtherTextBoxFormat(GetFormat(), RES_FLYFRMFMT)) + { + // This fly is a textbox of a draw shape. + SdrObject* pShape = pShapeFormat->FindSdrObject(); + if (SdrObjCustomShape* pCustomShape = dynamic_cast<SdrObjCustomShape*>( pShape) ) + { + // The shape is a customshape: then inform it about the calculated fly size. + Size aSize(getFrameArea().Width(), getFrameArea().Height()); + pCustomShape->SuggestTextFrameSize(aSize); + // Do the calculations normally done after touching editeng text of the shape. + pCustomShape->NbcSetOutlinerParaObjectForText(nullptr, nullptr); + } + } + } + else + { + // Fixed Frames do not Format itself + setFrameAreaSizeValid(true); + + // Flys set their size using the attr + SwTwips nNewSize = aRectFnSet.IsVert() ? aRelSize.Width() : aRelSize.Height(); + nNewSize -= nUL; + if( nNewSize < MINFLY ) + nNewSize = MINFLY; + + { + SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); + aRectFnSet.SetHeight( aPrt, nNewSize ); + } + + nNewSize += nUL - aRectFnSet.GetHeight(getFrameArea()); + + { + SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); + aRectFnSet.AddBottom( aFrm, nNewSize ); + } + + // #i68520# + if ( nNewSize != 0 ) + { + InvalidateObjRectWithSpaces(); + } + } + + if ( !m_bFormatHeightOnly ) + { + OSL_ENSURE( aRelSize == CalcRel( rFrameSz ), "SwFlyFrame::Format CalcRel problem" ); + SwTwips nNewSize = aRectFnSet.IsVert() ? aRelSize.Height() : aRelSize.Width(); + + if ( rFrameSz.GetWidthSizeType() != SwFrameSize::Fixed ) + { + // #i9046# Autowidth for fly frames + const SwTwips nAutoWidth = lcl_CalcAutoWidth( *this ); + if ( nAutoWidth ) + { + if( SwFrameSize::Minimum == rFrameSz.GetWidthSizeType() ) + nNewSize = std::max( nNewSize - nLR, nAutoWidth ); + else + nNewSize = nAutoWidth; + } + } + else + nNewSize -= nLR; + + if( nNewSize < MINFLY ) + nNewSize = MINFLY; + + { + SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); + aRectFnSet.SetWidth( aPrt, nNewSize ); + } + + nNewSize += nLR - aRectFnSet.GetWidth(getFrameArea()); + + { + SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); + aRectFnSet.AddRight( aFrm, nNewSize ); + } + + // #i68520# + if ( nNewSize != 0 ) + { + InvalidateObjRectWithSpaces(); + } + } + } + ColUnlock(); +} + +// #i11760# - change parameter <bNoColl>: type <bool>; +// add new parameter <bNoCalcFollow> with +// new parameter <bNoCalcFollow> was used by method +// <FormatWidthCols(..)> to avoid follow formatting +// for text frames. But, unformatted follows causes +// problems in method <SwContentFrame::WouldFit_(..)>, +// which assumes that the follows are formatted. +// Thus, <bNoCalcFollow> no longer used by <FormatWidthCols(..)>. +void CalcContent( SwLayoutFrame *pLay, bool bNoColl ) +{ + vcl::RenderContext* pRenderContext = pLay->getRootFrame()->GetCurrShell()->GetOut(); + SwSectionFrame* pSect; + bool bCollect = false; + if( pLay->IsSctFrame() ) + { + pSect = static_cast<SwSectionFrame*>(pLay); + if( pSect->IsEndnAtEnd() && !bNoColl ) + { + bCollect = true; + SwLayouter::CollectEndnotes( pLay->GetFormat()->GetDoc(), pSect ); + } + pSect->CalcFootnoteContent(); + } + else + pSect = nullptr; + SwFrame *pFrame = pLay->ContainsAny(); + if ( !pFrame ) + { + if( pSect ) + { + if( pSect->HasFollow() ) + pFrame = pSect->GetFollow()->ContainsAny(); + if( !pFrame ) + { + if( pSect->IsEndnAtEnd() ) + { + if( bCollect ) + pLay->GetFormat()->GetDoc()->getIDocumentLayoutAccess().GetLayouter()-> + InsertEndnotes( pSect ); + bool bLock = pSect->IsFootnoteLock(); + pSect->SetFootnoteLock( true ); + pSect->CalcFootnoteContent(); + pSect->CalcFootnoteContent(); + pSect->SetFootnoteLock( bLock ); + } + return; + } + pFrame->InvalidatePos_(); + } + else + return; + } + pFrame->InvalidatePage(); + + do + { + // local variables to avoid loops caused by anchored object positioning + SwAnchoredObject* pAgainObj1 = nullptr; + SwAnchoredObject* pAgainObj2 = nullptr; + + // FME 2007-08-30 #i81146# new loop control + int nLoopControlRuns = 0; + const int nLoopControlMax = 20; + const SwFrame* pLoopControlCond = nullptr; + + SwFrame* pLast; + do + { + pLast = pFrame; + if( pFrame->IsVertical() ? + ( pFrame->GetUpper()->getFramePrintArea().Height() != pFrame->getFrameArea().Height() ) + : ( pFrame->GetUpper()->getFramePrintArea().Width() != pFrame->getFrameArea().Width() ) ) + { + pFrame->Prepare( PrepareHint::FixSizeChanged ); + pFrame->InvalidateSize_(); + } + + if ( pFrame->IsTabFrame() ) + { + static_cast<SwTabFrame*>(pFrame)->m_bCalcLowers = true; + // #i18103# - lock move backward of follow table, + // if no section content is formatted or follow table belongs + // to the section, which content is formatted. + if ( static_cast<SwTabFrame*>(pFrame)->IsFollow() && + ( !pSect || pSect == pFrame->FindSctFrame() ) ) + { + static_cast<SwTabFrame*>(pFrame)->m_bLockBackMove = true; + } + } + + { + SwFrameDeleteGuard aDeletePageGuard(pSect ? pSect->FindPageFrame() : nullptr); + SwFrameDeleteGuard aDeleteGuard(pSect); + pFrame->Calc(pRenderContext); + } + + // #i11760# - reset control flag for follow format. + if ( pFrame->IsTextFrame() ) + { + static_cast<SwTextFrame*>(pFrame)->AllowFollowFormat(); + } + + // The keep-attribute can cause the position + // of the prev to be invalid: + // Do not consider invalid previous frame + // due to its keep-attribute, if current frame is a follow or is locked. + // #i44049# - do not consider invalid previous + // frame due to its keep-attribute, if it can't move forward. + // #i57765# - do not consider invalid previous + // frame, if current frame has a column/page break before attribute. + SwFrame* pTmpPrev = pFrame->FindPrev(); + SwFlowFrame* pTmpPrevFlowFrame = pTmpPrev && pTmpPrev->IsFlowFrame() ? SwFlowFrame::CastFlowFrame(pTmpPrev) : nullptr; + SwFlowFrame* pTmpFlowFrame = pFrame->IsFlowFrame() ? SwFlowFrame::CastFlowFrame(pFrame) : nullptr; + + bool bPrevInvalid = pTmpPrevFlowFrame && pTmpFlowFrame && + !pTmpFlowFrame->IsFollow() && + !StackHack::IsLocked() && // #i76382# + !pTmpFlowFrame->IsJoinLocked() && + !pTmpPrev->isFrameAreaPositionValid() && + pLay->IsAnLower( pTmpPrev ) && + pTmpPrevFlowFrame->IsKeep(pTmpPrev->GetAttrSet()->GetKeep(), pTmpPrev->GetBreakItem()) && + pTmpPrevFlowFrame->IsKeepFwdMoveAllowed(); + + // format floating screen objects anchored to the frame. + if ( !bPrevInvalid && pFrame->GetDrawObjs() && pLay->IsAnLower( pFrame ) ) + { + bool bAgain = false; + bool bRestartLayoutProcess = false; + SwPageFrame* pPageFrame = pFrame->FindPageFrame(); + size_t nCnt = pFrame->GetDrawObjs()->size(); + size_t i = 0; + while ( i < nCnt ) + { + // #i28701# + SwAnchoredObject* pAnchoredObj = (*pFrame->GetDrawObjs())[i]; + assert(pAnchoredObj); + + // determine if anchored object has to be + // formatted and, in case, format it + if ( !pAnchoredObj->PositionLocked() && pAnchoredObj->IsFormatPossible() ) + { + // #i43737# - no invalidation of + // anchored object needed - causes loops for as-character + // anchored objects. + //pAnchoredObj->InvalidateObjPos(); + SwRect aRect( pAnchoredObj->GetObjRect() ); + if ( !SwObjectFormatter::FormatObj( *pAnchoredObj, pFrame, pPageFrame ) ) + { + bRestartLayoutProcess = true; + break; + } + // #i3317# - restart layout process, + // if the position of the anchored object is locked now. + if ( pAnchoredObj->PositionLocked() ) + { + bRestartLayoutProcess = true; + break; + } + + if ( aRect != pAnchoredObj->GetObjRect() ) + { + bAgain = true; + if ( pAgainObj2 == pAnchoredObj ) + { + OSL_FAIL( "::CalcContent(..) - loop detected, perform attribute changes to avoid the loop" ); + // Prevent oscillation + SwFrameFormat& rFormat = pAnchoredObj->GetFrameFormat(); + SwFormatSurround aAttr( rFormat.GetSurround() ); + if( css::text::WrapTextMode_THROUGH != aAttr.GetSurround() ) + { + // When on auto position, we can only set it to + // flow through + if ((rFormat.GetAnchor().GetAnchorId() == + RndStdIds::FLY_AT_CHAR) && + (css::text::WrapTextMode_PARALLEL == + aAttr.GetSurround())) + { + aAttr.SetSurround( css::text::WrapTextMode_THROUGH ); + } + else + { + aAttr.SetSurround( css::text::WrapTextMode_PARALLEL ); + } + rFormat.LockModify(); + rFormat.SetFormatAttr( aAttr ); + rFormat.UnlockModify(); + } + } + else + { + if ( pAgainObj1 == pAnchoredObj ) + pAgainObj2 = pAnchoredObj; + pAgainObj1 = pAnchoredObj; + } + } + + if ( !pFrame->GetDrawObjs() ) + break; + if ( pFrame->GetDrawObjs()->size() < nCnt ) + { + --nCnt; + // Do not increment index, in this case + continue; + } + } + ++i; + } + + // #i28701# - restart layout process, if + // requested by floating screen object formatting + if ( bRestartLayoutProcess ) + { + pFrame = pLay->ContainsAny(); + pAgainObj1 = nullptr; + pAgainObj2 = nullptr; + continue; + } + + // #i28701# - format anchor frame after its objects + // are formatted, if the wrapping style influence has to be considered. + if ( pLay->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) ) + { + pFrame->Calc(pRenderContext); + } + + if ( bAgain ) + { + pFrame = pLay->ContainsContent(); + if ( pFrame && pFrame->IsInTab() ) + pFrame = pFrame->FindTabFrame(); + if( pFrame && pFrame->IsInSct() ) + { + SwSectionFrame* pTmp = pFrame->FindSctFrame(); + if( pTmp != pLay && pLay->IsAnLower( pTmp ) ) + pFrame = pTmp; + } + + if ( pFrame == pLoopControlCond ) + ++nLoopControlRuns; + else + { + nLoopControlRuns = 0; + pLoopControlCond = pFrame; + } + + if ( nLoopControlRuns < nLoopControlMax ) + continue; + + OSL_FAIL( "LoopControl in CalcContent" ); + } + } + if ( pFrame->IsTabFrame() ) + { + if ( static_cast<SwTabFrame*>(pFrame)->IsFollow() ) + static_cast<SwTabFrame*>(pFrame)->m_bLockBackMove = false; + } + + pFrame = bPrevInvalid ? pTmpPrev : pFrame->FindNext(); + if( !bPrevInvalid && pFrame && pFrame->IsSctFrame() && pSect ) + { + // Empty SectionFrames could be present here + while( pFrame && pFrame->IsSctFrame() && !static_cast<SwSectionFrame*>(pFrame)->GetSection() ) + pFrame = pFrame->FindNext(); + + // If FindNext returns the Follow of the original Area, we want to + // continue with this content as long as it flows back. + if( pFrame && pFrame->IsSctFrame() && ( pFrame == pSect->GetFollow() || + static_cast<SwSectionFrame*>(pFrame)->IsAnFollow( pSect ) ) ) + { + pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny(); + if( pFrame ) + pFrame->InvalidatePos_(); + } + } + // Stay in the pLay + // Except for SectionFrames with Follow: the first ContentFrame of the Follow + // will be formatted, so that it gets a chance to load in the pLay. + // As long as these Frames are loading in pLay, we continue + } while ( pFrame && + ( pLay->IsAnLower( pFrame ) || + ( pSect && + ( ( pSect->HasFollow() && + ( pLay->IsAnLower( pLast ) || + ( pLast->IsInSct() && + pLast->FindSctFrame()->IsAnFollow(pSect) ) ) && + pSect->GetFollow()->IsAnLower( pFrame ) ) || + ( pFrame->IsInSct() && + pFrame->FindSctFrame()->IsAnFollow( pSect ) ) ) ) ) ); + if( pSect ) + { + if( bCollect ) + { + pLay->GetFormat()->GetDoc()->getIDocumentLayoutAccess().GetLayouter()->InsertEndnotes(pSect); + pSect->CalcFootnoteContent(); + } + if( pSect->HasFollow() ) + { + SwSectionFrame* pNxt = pSect->GetFollow(); + while( pNxt && !pNxt->ContainsContent() ) + pNxt = pNxt->GetFollow(); + if( pNxt ) + pNxt->CalcFootnoteContent(); + } + if( bCollect ) + { + pFrame = pLay->ContainsAny(); + bCollect = false; + if( pFrame ) + continue; + } + } + break; + } + while( true ); +} + +void SwFlyFrame::MakeObjPos() +{ + if ( !isFrameAreaPositionValid() ) + { + vcl::RenderContext* pRenderContext = getRootFrame()->GetCurrShell()->GetOut(); + setFrameAreaPositionValid(true); + + // use new class to position object + GetAnchorFrame()->Calc(pRenderContext); + objectpositioning::SwToLayoutAnchoredObjectPosition + aObjPositioning( *GetVirtDrawObj() ); + aObjPositioning.CalcPosition(); + + // #i58280# + // update relative position + SetCurrRelPos( aObjPositioning.GetRelPos() ); + + { + SwRectFnSet aRectFnSet(GetAnchorFrame()); + SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); + aFrm.Pos( aObjPositioning.GetRelPos() ); + aFrm.Pos() += aRectFnSet.GetPos(GetAnchorFrame()->getFrameArea()); + } + + // #i69335# + InvalidateObjRectWithSpaces(); + } +} + +void SwFlyFrame::MakePrtArea( const SwBorderAttrs &rAttrs ) +{ + if ( !isFramePrintAreaValid() ) + { + setFramePrintAreaValid(true); + + // consider vertical layout + SwRectFnSet aRectFnSet(this); + aRectFnSet.SetXMargins( *this, rAttrs.CalcLeftLine(), + rAttrs.CalcRightLine() ); + aRectFnSet.SetYMargins( *this, rAttrs.CalcTopLine(), + rAttrs.CalcBottomLine() ); + } +} + +void SwFlyFrame::MakeContentPos( const SwBorderAttrs &rAttrs ) +{ + if ( m_bValidContentPos ) + return; + + m_bValidContentPos = true; + + const SwTwips nUL = rAttrs.CalcTopLine() + rAttrs.CalcBottomLine(); + Size aRelSize( CalcRel( GetFormat()->GetFrameSize() ) ); + + SwRectFnSet aRectFnSet(this); + long nMinHeight = 0; + if( IsMinHeight() ) + nMinHeight = aRectFnSet.IsVert() ? aRelSize.Width() : aRelSize.Height(); + + Point aNewContentPos = getFramePrintArea().Pos(); + const SdrTextVertAdjust nAdjust = GetFormat()->GetTextVertAdjust().GetValue(); + + if( nAdjust != SDRTEXTVERTADJUST_TOP ) + { + const SwTwips nContentHeight = CalcContentHeight(&rAttrs, nMinHeight, nUL); + SwTwips nDiff = 0; + + if( nContentHeight != 0) + nDiff = aRectFnSet.GetHeight(getFramePrintArea()) - nContentHeight; + + if( nDiff > 0 ) + { + if( nAdjust == SDRTEXTVERTADJUST_CENTER ) + { + if( aRectFnSet.IsVertL2R() ) + aNewContentPos.setX(aNewContentPos.getX() + nDiff/2); + else if( aRectFnSet.IsVert() ) + aNewContentPos.setX(aNewContentPos.getX() - nDiff/2); + else + aNewContentPos.setY(aNewContentPos.getY() + nDiff/2); + } + else if( nAdjust == SDRTEXTVERTADJUST_BOTTOM ) + { + if( aRectFnSet.IsVertL2R() ) + aNewContentPos.setX(aNewContentPos.getX() + nDiff); + else if( aRectFnSet.IsVert() ) + aNewContentPos.setX(aNewContentPos.getX() - nDiff); + else + aNewContentPos.setY(aNewContentPos.getY() + nDiff); + } + } + } + if( aNewContentPos != ContentPos() ) + { + ContentPos() = aNewContentPos; + for( SwFrame *pFrame = Lower(); pFrame; pFrame = pFrame->GetNext()) + { + pFrame->InvalidatePos(); + } + } + +} + +void SwFlyFrame::InvalidateContentPos() +{ + m_bValidContentPos = false; + Invalidate_(); +} + +void SwFlyFrame::SelectionHasChanged(SwFEShell* pShell) +{ + SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >(pShell); + if (pWrtSh == nullptr) + return; + + UpdateUnfloatButton(pWrtSh, IsShowUnfloatButton(pWrtSh)); +} + +bool SwFlyFrame::IsShowUnfloatButton(SwWrtShell* pWrtSh) const +{ + if (pWrtSh == nullptr) + return false; + + // In read only mode we don't allow unfloat operation + if (pWrtSh->GetViewOptions()->IsReadonly()) + return false; + + const SdrObject *pObj = GetFrameFormat().FindRealSdrObject(); + if (pObj == nullptr) + return false; + + // SwFlyFrame itself can mean images, ole objects, etc, but we interested in actual text frames + if (SwFEShell::GetObjCntType(*pObj) != OBJCNT_FLY) + return false; + + // We show the button only for the selected text frame + SwDrawView *pView = pWrtSh->Imp()->GetDrawView(); + if (pView == nullptr) + return false; + + // Fly frame can be selected only alone + if (pView->GetMarkedObjectList().GetMarkCount() != 1) + return false; + + if(!pView->IsObjMarked(pObj)) + return false; + + // A frame is a floating table if there is only one table (and maybe some whitespaces) inside it + int nTableCount = 0; + const SwFrame* pLower = GetLower(); + const SwTabFrame* pTable = nullptr; + while (pLower) + { + if (pLower->IsTabFrame()) + { + pTable = static_cast<const SwTabFrame*>(pLower); + ++nTableCount; + if (nTableCount > 1 || pTable == nullptr) + return false; + } + + if (pLower->IsTextFrame()) + { + const SwTextFrame* pTextFrame = static_cast<const SwTextFrame*>(pLower); + if (!pTextFrame->GetText().trim().isEmpty()) + return false; + } + pLower = pLower->GetNext(); + } + + if (nTableCount != 1 || pTable == nullptr) + return false; + + // Show the unfold button only for multipage tables + const SwBodyFrame *pBody = GetAnchorFrame()->FindBodyFrame(); + if (pBody == nullptr) + return false; + + long nBodyHeight = pBody->getFrameArea().Height(); + long nTableHeight = pTable->getFrameArea().Height(); + long nFrameOffset = std::abs(GetAnchorFrame()->getFrameArea().Top() - pBody->getFrameArea().Top()); + + return nBodyHeight < nTableHeight + nFrameOffset; +} + +void SwFlyFrame::ActiveUnfloatButton(SwWrtShell* pWrtSh) +{ + SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin(); + SwFrameControlsManager& rMngr = rEditWin.GetFrameControlsManager(); + SwFrameControlPtr pControl = rMngr.GetControl(FrameControlType::FloatingTable, this); + if (pControl || pControl->GetWindow()) + { + pControl->GetWindow()->MouseButtonDown(MouseEvent()); + } +} + +void SwFlyFrame::UpdateUnfloatButton(SwWrtShell* pWrtSh, bool bShow) const +{ + if (pWrtSh == nullptr) + return; + + SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin(); + SwFrameControlsManager& rMngr = rEditWin.GetFrameControlsManager(); + Point aTopRightPixel = rEditWin.LogicToPixel( getFrameArea().TopRight() ); + rMngr.SetUnfloatTableButton(this, bShow, aTopRightPixel); +} + +SwTwips SwFlyFrame::Grow_( SwTwips nDist, bool bTst ) +{ + SwRectFnSet aRectFnSet(this); + if ( Lower() && !IsColLocked() && !HasFixSize() ) + { + SwTwips nSize = aRectFnSet.GetHeight(getFrameArea()); + if( nSize > 0 && nDist > ( LONG_MAX - nSize ) ) + nDist = LONG_MAX - nSize; + + if ( nDist <= 0 ) + return 0; + + if ( Lower()->IsColumnFrame() ) + { // If it's a Column Frame, the Format takes control of the + // resizing (due to the adjustment). + if ( !bTst ) + { + // #i28701# - unlock position of Writer fly frame + UnlockPosition(); + InvalidatePos_(); + InvalidateSize(); + } + return 0; + } + + if ( !bTst ) + { + const SwRect aOld( GetObjRectWithSpaces() ); + InvalidateSize_(); + const bool bOldLock = m_bLocked; + Unlock(); + if ( IsFlyFreeFrame() ) + { + // #i37068# - no format of position here + // and prevent move in method <CheckClip(..)>. + // This is needed to prevent layout loop caused by nested + // Writer fly frames - inner Writer fly frames format its + // anchor, which grows/shrinks the outer Writer fly frame. + // Note: position will be invalidated below. + setFrameAreaPositionValid(true); + + // #i55416# + // Suppress format of width for autowidth frame, because the + // format of the width would call <SwTextFrame::CalcFitToContent()> + // for the lower frame, which initiated this grow. + const bool bOldFormatHeightOnly = m_bFormatHeightOnly; + const SwFormatFrameSize& rFrameSz = GetFormat()->GetFrameSize(); + if ( rFrameSz.GetWidthSizeType() != SwFrameSize::Fixed ) + { + m_bFormatHeightOnly = true; + } + SwViewShell* pSh = getRootFrame()->GetCurrShell(); + if (pSh) + { + static_cast<SwFlyFreeFrame*>(this)->SetNoMoveOnCheckClip( true ); + static_cast<SwFlyFreeFrame*>(this)->SwFlyFreeFrame::MakeAll(pSh->GetOut()); + static_cast<SwFlyFreeFrame*>(this)->SetNoMoveOnCheckClip( false ); + } + // #i55416# + if ( rFrameSz.GetWidthSizeType() != SwFrameSize::Fixed ) + { + m_bFormatHeightOnly = bOldFormatHeightOnly; + } + } + else + MakeAll(getRootFrame()->GetCurrShell()->GetOut()); + InvalidateSize_(); + InvalidatePos(); + if ( bOldLock ) + Lock(); + const SwRect aNew( GetObjRectWithSpaces() ); + if ( aOld != aNew ) + ::Notify( this, FindPageFrame(), aOld ); + return aRectFnSet.GetHeight(aNew)-aRectFnSet.GetHeight(aOld); + } + return nDist; + } + return 0; +} + +SwTwips SwFlyFrame::Shrink_( SwTwips nDist, bool bTst ) +{ + if( Lower() && !IsColLocked() && !HasFixSize() ) + { + SwRectFnSet aRectFnSet(this); + SwTwips nHeight = aRectFnSet.GetHeight(getFrameArea()); + if ( nDist > nHeight ) + nDist = nHeight; + + SwTwips nVal = nDist; + if ( IsMinHeight() ) + { + const SwFormatFrameSize& rFormatSize = GetFormat()->GetFrameSize(); + SwTwips nFormatHeight = aRectFnSet.IsVert() ? rFormatSize.GetWidth() : rFormatSize.GetHeight(); + + nVal = std::min( nDist, nHeight - nFormatHeight ); + } + + if ( nVal <= 0 ) + return 0; + + if ( Lower()->IsColumnFrame() ) + { // If it's a Column Frame, the Format takes control of the + // resizing (due to the adjustment). + if ( !bTst ) + { + SwRect aOld( GetObjRectWithSpaces() ); + + { + SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); + aRectFnSet.SetHeight( aFrm, nHeight - nVal ); + } + + // #i68520# + if ( nHeight - nVal != 0 ) + { + InvalidateObjRectWithSpaces(); + } + + nHeight = aRectFnSet.GetHeight(getFramePrintArea()); + + { + SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this); + aRectFnSet.SetHeight( aPrt, nHeight - nVal ); + } + + InvalidatePos_(); + InvalidateSize(); + ::Notify( this, FindPageFrame(), aOld ); + NotifyDrawObj(); + if ( GetAnchorFrame()->IsInFly() ) + AnchorFrame()->FindFlyFrame()->Shrink( nDist, bTst ); + } + return 0; + } + + if ( !bTst ) + { + const SwRect aOld( GetObjRectWithSpaces() ); + InvalidateSize_(); + const bool bOldLocked = m_bLocked; + Unlock(); + if ( IsFlyFreeFrame() ) + { + // #i37068# - no format of position here + // and prevent move in method <CheckClip(..)>. + // This is needed to prevent layout loop caused by nested + // Writer fly frames - inner Writer fly frames format its + // anchor, which grows/shrinks the outer Writer fly frame. + // Note: position will be invalidated below. + setFrameAreaPositionValid(true); + + // #i55416# + // Suppress format of width for autowidth frame, because the + // format of the width would call <SwTextFrame::CalcFitToContent()> + // for the lower frame, which initiated this shrink. + const bool bOldFormatHeightOnly = m_bFormatHeightOnly; + const SwFormatFrameSize& rFrameSz = GetFormat()->GetFrameSize(); + if ( rFrameSz.GetWidthSizeType() != SwFrameSize::Fixed ) + { + m_bFormatHeightOnly = true; + } + static_cast<SwFlyFreeFrame*>(this)->SetNoMoveOnCheckClip( true ); + static_cast<SwFlyFreeFrame*>(this)->SwFlyFreeFrame::MakeAll(getRootFrame()->GetCurrShell()->GetOut()); + static_cast<SwFlyFreeFrame*>(this)->SetNoMoveOnCheckClip( false ); + // #i55416# + if ( rFrameSz.GetWidthSizeType() != SwFrameSize::Fixed ) + { + m_bFormatHeightOnly = bOldFormatHeightOnly; + } + } + else + MakeAll(getRootFrame()->GetCurrShell()->GetOut()); + InvalidateSize_(); + InvalidatePos(); + if ( bOldLocked ) + Lock(); + const SwRect aNew( GetObjRectWithSpaces() ); + if ( aOld != aNew ) + { + ::Notify( this, FindPageFrame(), aOld ); + if ( GetAnchorFrame()->IsInFly() ) + AnchorFrame()->FindFlyFrame()->Shrink( nDist, bTst ); + } + return aRectFnSet.GetHeight(aOld) - + aRectFnSet.GetHeight(aNew); + } + return nVal; + } + return 0; +} + +Size SwFlyFrame::ChgSize( const Size& aNewSize ) +{ + // #i53298# + // If the fly frame anchored at-paragraph or at-character contains an OLE + // object, assure that the new size fits into the current clipping area + // of the fly frame + Size aAdjustedNewSize( aNewSize ); + { + if ( dynamic_cast<SwFlyAtContentFrame*>(this) && + Lower() && dynamic_cast<SwNoTextFrame*>(Lower()) && + static_cast<SwNoTextFrame*>(Lower())->GetNode()->GetOLENode() ) + { + SwRect aClipRect; + ::CalcClipRect( GetVirtDrawObj(), aClipRect, false ); + if ( aAdjustedNewSize.Width() > aClipRect.Width() ) + { + aAdjustedNewSize.setWidth( aClipRect.Width() ); + } + if ( aAdjustedNewSize.Height() > aClipRect.Height() ) + { + aAdjustedNewSize.setWidth( aClipRect.Height() ); + } + } + } + + if ( aAdjustedNewSize != getFrameArea().SSize() ) + { + SwFrameFormat *pFormat = GetFormat(); + SwFormatFrameSize aSz( pFormat->GetFrameSize() ); + aSz.SetWidth( aAdjustedNewSize.Width() ); + aSz.SetHeight( aAdjustedNewSize.Height() ); + // go via the Doc for UNDO + pFormat->GetDoc()->SetAttr( aSz, *pFormat ); + return aSz.GetSize(); + } + else + return getFrameArea().SSize(); +} + +bool SwFlyFrame::IsLowerOf( const SwLayoutFrame* pUpperFrame ) const +{ + OSL_ENSURE( GetAnchorFrame(), "8-( Fly is lost in Space." ); + const SwFrame* pFrame = GetAnchorFrame(); + do + { + if ( pFrame == pUpperFrame ) + return true; + pFrame = pFrame->IsFlyFrame() + ? static_cast<const SwFlyFrame*>(pFrame)->GetAnchorFrame() + : pFrame->GetUpper(); + } while ( pFrame ); + return false; +} + +void SwFlyFrame::Cut() +{ +} + +void SwFrame::AppendFly( SwFlyFrame *pNew ) +{ + if (!m_pDrawObjs) + { + m_pDrawObjs.reset(new SwSortedObjs()); + } + m_pDrawObjs->Insert( *pNew ); + pNew->ChgAnchorFrame( this ); + + // Register at the page + // If there's none present, register via SwPageFrame::PreparePage + SwPageFrame* pPage = FindPageFrame(); + if ( pPage != nullptr ) + { + pPage->AppendFlyToPage( pNew ); + } +} + +void SwFrame::RemoveFly( SwFlyFrame *pToRemove ) +{ + // Deregister from the page + // Could already have happened, if the page was already destructed + SwPageFrame *pPage = pToRemove->FindPageFrame(); + if ( pPage && pPage->GetSortedObjs() ) + { + pPage->RemoveFlyFromPage( pToRemove ); + } + // #i73201# + else + { + if ( pToRemove->IsAccessibleFrame() && + pToRemove->GetFormat() && + !pToRemove->IsFlyInContentFrame() ) + { + SwRootFrame *pRootFrame = getRootFrame(); + if( pRootFrame && pRootFrame->IsAnyShellAccessible() ) + { + SwViewShell *pVSh = pRootFrame->GetCurrShell(); + if( pVSh && pVSh->Imp() ) + { + pVSh->Imp()->DisposeAccessibleFrame( pToRemove ); + } + } + } + } + + m_pDrawObjs->Remove(*pToRemove); + if (!m_pDrawObjs->size()) + { + m_pDrawObjs.reset(); + } + + pToRemove->ChgAnchorFrame( nullptr ); + + if ( !pToRemove->IsFlyInContentFrame() && GetUpper() && IsInTab() )//MA_FLY_HEIGHT + GetUpper()->InvalidateSize(); +} + +void SwFrame::AppendDrawObj( SwAnchoredObject& _rNewObj ) +{ + assert(!m_pDrawObjs || m_pDrawObjs->is_sorted()); + + if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rNewObj) == nullptr ) + { + OSL_FAIL( "SwFrame::AppendDrawObj(..) - anchored object of unexpected type -> object not appended" ); + return; + } + + if ( dynamic_cast<const SwDrawVirtObj*>(_rNewObj.GetDrawObj()) == nullptr && + _rNewObj.GetAnchorFrame() && _rNewObj.GetAnchorFrame() != this ) + { + assert(!m_pDrawObjs || m_pDrawObjs->is_sorted()); + // perform disconnect from layout, if 'master' drawing object is appended + // to a new frame. + static_cast<SwDrawContact*>(::GetUserCall( _rNewObj.GetDrawObj() ))-> + DisconnectFromLayout( false ); + assert(!m_pDrawObjs || m_pDrawObjs->is_sorted()); + } + + if ( _rNewObj.GetAnchorFrame() != this ) + { + if (!m_pDrawObjs) + { + m_pDrawObjs.reset(new SwSortedObjs()); + } + m_pDrawObjs->Insert(_rNewObj); + _rNewObj.ChgAnchorFrame( this ); + } + + // #i113730# + // Assure the control objects and group objects containing controls are on the control layer + if ( ::CheckControlLayer( _rNewObj.DrawObj() ) ) + { + const IDocumentDrawModelAccess& rIDDMA = getIDocumentDrawModelAccess(); + const SdrLayerID aCurrentLayer(_rNewObj.DrawObj()->GetLayer()); + const SdrLayerID aControlLayerID(rIDDMA.GetControlsId()); + const SdrLayerID aInvisibleControlLayerID(rIDDMA.GetInvisibleControlsId()); + + if(aCurrentLayer != aControlLayerID && aCurrentLayer != aInvisibleControlLayerID) + { + if ( aCurrentLayer == rIDDMA.GetInvisibleHellId() || + aCurrentLayer == rIDDMA.GetInvisibleHeavenId() ) + { + _rNewObj.DrawObj()->SetLayer(aInvisibleControlLayerID); + } + else + { + _rNewObj.DrawObj()->SetLayer(aControlLayerID); + } + //The layer is part of the key used to sort the obj, so update + //its position if the layer changed. + m_pDrawObjs->Update(_rNewObj); + } + } + + // no direct positioning needed, but invalidate the drawing object position + _rNewObj.InvalidateObjPos(); + + // register at page frame + SwPageFrame* pPage = FindPageFrame(); + if ( pPage ) + { + pPage->AppendDrawObjToPage( _rNewObj ); + } + + // Notify accessible layout. + SwViewShell* pSh = getRootFrame()->GetCurrShell(); + if( pSh ) + { + SwRootFrame* pLayout = getRootFrame(); + if( pLayout && pLayout->IsAnyShellAccessible() ) + { + pSh->Imp()->AddAccessibleObj( _rNewObj.GetDrawObj() ); + } + } + + assert(!m_pDrawObjs || m_pDrawObjs->is_sorted()); +} + +void SwFrame::RemoveDrawObj( SwAnchoredObject& _rToRemoveObj ) +{ + // Notify accessible layout. + SwViewShell* pSh = getRootFrame()->GetCurrShell(); + if( pSh ) + { + SwRootFrame* pLayout = getRootFrame(); + if (pLayout && pLayout->IsAnyShellAccessible()) + pSh->Imp()->DisposeAccessibleObj(_rToRemoveObj.GetDrawObj(), false); + } + + // deregister from page frame + SwPageFrame* pPage = _rToRemoveObj.GetPageFrame(); + if ( pPage && pPage->GetSortedObjs() ) + pPage->RemoveDrawObjFromPage( _rToRemoveObj ); + + m_pDrawObjs->Remove(_rToRemoveObj); + if (!m_pDrawObjs->size()) + { + m_pDrawObjs.reset(); + } + _rToRemoveObj.ChgAnchorFrame( nullptr ); + + assert(!m_pDrawObjs || m_pDrawObjs->is_sorted()); +} + +void SwFrame::InvalidateObjs( const bool _bNoInvaOfAsCharAnchoredObjs ) +{ + if ( GetDrawObjs() ) + { + // #i26945# - determine page the frame is on, + // in order to check, if anchored object is registered at the same + // page. + const SwPageFrame* pPageFrame = FindPageFrame(); + // #i28701# - re-factoring + for (SwAnchoredObject* pAnchoredObj : *GetDrawObjs()) + { + if ( _bNoInvaOfAsCharAnchoredObjs && + (pAnchoredObj->GetFrameFormat().GetAnchor().GetAnchorId() + == RndStdIds::FLY_AS_CHAR) ) + { + continue; + } + // #i26945# - no invalidation, if anchored object + // isn't registered at the same page and instead is registered at + // the page, where its anchor character text frame is on. + if ( pAnchoredObj->GetPageFrame() && + pAnchoredObj->GetPageFrame() != pPageFrame ) + { + SwTextFrame* pAnchorCharFrame = pAnchoredObj->FindAnchorCharFrame(); + if ( pAnchorCharFrame && + pAnchoredObj->GetPageFrame() == pAnchorCharFrame->FindPageFrame() ) + { + continue; + } + // #115759# - unlock its position, if anchored + // object isn't registered at the page, where its anchor + // character text frame is on, respectively if it has no + // anchor character text frame. + else + { + pAnchoredObj->UnlockPosition(); + } + } + // #i51474# - reset flag, that anchored object + // has cleared environment, and unlock its position, if the anchored + // object is registered at the same page as the anchor frame is on. + if ( pAnchoredObj->ClearedEnvironment() && + pAnchoredObj->GetPageFrame() && + pAnchoredObj->GetPageFrame() == pPageFrame ) + { + pAnchoredObj->UnlockPosition(); + pAnchoredObj->SetClearedEnvironment( false ); + } + // distinguish between writer fly frames and drawing objects + if ( dynamic_cast<const SwFlyFrame*>( pAnchoredObj) != nullptr ) + { + SwFlyFrame* pFly = static_cast<SwFlyFrame*>(pAnchoredObj); + pFly->Invalidate_(); + pFly->InvalidatePos_(); + } + else + { + pAnchoredObj->InvalidateObjPos(); + } + } // end of loop on objects, which are connected to the frame + } +} + +// #i26945# - correct check, if anchored object is a lower +// of the layout frame. E.g., anchor character text frame can be a follow text +// frame. +// #i44016# - add parameter <_bUnlockPosOfObjs> to +// force an unlockposition call for the lower objects. +void SwLayoutFrame::NotifyLowerObjs( const bool _bUnlockPosOfObjs ) +{ + // invalidate lower floating screen objects + SwPageFrame* pPageFrame = FindPageFrame(); + if ( pPageFrame && pPageFrame->GetSortedObjs() ) + { + SwSortedObjs& rObjs = *(pPageFrame->GetSortedObjs()); + for (SwAnchoredObject* pObj : rObjs) + { + // #i26945# - check, if anchored object is a lower + // of the layout frame is changed to check, if its anchor frame + // is a lower of the layout frame. + // determine the anchor frame - usually it's the anchor frame, + // for at-character/as-character anchored objects the anchor character + // text frame is taken. + const SwFrame* pAnchorFrame = pObj->GetAnchorFrameContainingAnchPos(); + if ( dynamic_cast<const SwFlyFrame*>( pObj) != nullptr ) + { + SwFlyFrame* pFly = static_cast<SwFlyFrame*>(pObj); + + if ( pFly->getFrameArea().Left() == FAR_AWAY ) + continue; + + if ( pFly->IsAnLower( this ) ) + continue; + + // #i26945# - use <pAnchorFrame> to check, if + // fly frame is lower of layout frame resp. if fly frame is + // at a different page registered as its anchor frame is on. + const bool bLow = IsAnLower( pAnchorFrame ); + if ( bLow || pAnchorFrame->FindPageFrame() != pPageFrame ) + { + pFly->Invalidate_( pPageFrame ); + if ( !bLow || pFly->IsFlyAtContentFrame() ) + { + // #i44016# + if ( _bUnlockPosOfObjs ) + { + pFly->UnlockPosition(); + } + pFly->InvalidatePos_(); + } + else + pFly->InvalidatePrt_(); + } + } + else + { + OSL_ENSURE( dynamic_cast<const SwAnchoredDrawObject*>( pObj) != nullptr, + "<SwLayoutFrame::NotifyFlys() - anchored object of unexpected type" ); + // #i26945# - use <pAnchorFrame> to check, if + // fly frame is lower of layout frame resp. if fly frame is + // at a different page registered as its anchor frame is on. + if ( IsAnLower( pAnchorFrame ) || + pAnchorFrame->FindPageFrame() != pPageFrame ) + { + // #i44016# + if ( _bUnlockPosOfObjs ) + { + pObj->UnlockPosition(); + } + pObj->InvalidateObjPos(); + } + } + } + } +} + +void SwFlyFrame::NotifyDrawObj() +{ + SwVirtFlyDrawObj* pObj = GetVirtDrawObj(); + pObj->SetRect(); + pObj->SetRectsDirty(); + pObj->SetChanged(); + pObj->BroadcastObjectChange(); + + if ( GetFormat()->GetSurround().IsContour() ) + { + ClrContourCache( pObj ); + } + else if(IsFlyFreeFrame() && static_cast< const SwFlyFreeFrame* >(this)->supportsAutoContour()) + { + // RotateFlyFrame3: Also need to clear when changes happen + // Caution: isTransformableSwFrame is already reset when resetting rotation, so + // *additionally* reset in SwFlyFreeFrame::MakeAll when no more rotation + ClrContourCache( pObj ); + } +} + +Size SwFlyFrame::CalcRel( const SwFormatFrameSize &rSz ) const +{ + Size aRet( rSz.GetSize() ); + + const SwFrame *pRel = IsFlyLayFrame() ? GetAnchorFrame() : GetAnchorFrame()->GetUpper(); + if( pRel ) // LAYER_IMPL + { + long nRelWidth = LONG_MAX, nRelHeight = LONG_MAX; + const SwViewShell *pSh = getRootFrame()->GetCurrShell(); + if ( ( pRel->IsBodyFrame() || pRel->IsPageFrame() ) && + pSh && pSh->GetViewOptions()->getBrowseMode() && + pSh->VisArea().HasArea() ) + { + nRelWidth = pSh->GetBrowseWidth(); + nRelHeight = pSh->VisArea().Height(); + Size aBorder = pSh->GetOut()->PixelToLogic( pSh->GetBrowseBorder() ); + nRelWidth = std::min( nRelWidth, pRel->getFramePrintArea().Width() ); + nRelHeight -= 2*aBorder.Height(); + nRelHeight = std::min( nRelHeight, pRel->getFramePrintArea().Height() ); + } + + // At the moment only the "== PAGE_FRAME" and "!= PAGE_FRAME" cases are handled. + // When size is a relative to page size, ignore size of SwBodyFrame. + if (rSz.GetWidthPercentRelation() != text::RelOrientation::PAGE_FRAME) + nRelWidth = std::min( nRelWidth, pRel->getFramePrintArea().Width() ); + else if ( pRel->IsPageFrame() ) + nRelWidth = std::min( nRelWidth, pRel->getFrameArea().Width() ); + + if (rSz.GetHeightPercentRelation() != text::RelOrientation::PAGE_FRAME) + nRelHeight = std::min( nRelHeight, pRel->getFramePrintArea().Height() ); + else if ( pRel->IsPageFrame() ) + nRelHeight = std::min( nRelHeight, pRel->getFrameArea().Height() ); + + if( !pRel->IsPageFrame() ) + { + const SwPageFrame* pPage = FindPageFrame(); + if( pPage ) + { + if (rSz.GetWidthPercentRelation() == text::RelOrientation::PAGE_FRAME) + // Ignore margins of pPage. + nRelWidth = std::min( nRelWidth, pPage->getFrameArea().Width() ); + else + nRelWidth = std::min( nRelWidth, pPage->getFramePrintArea().Width() ); + if (rSz.GetHeightPercentRelation() == text::RelOrientation::PAGE_FRAME) + // Ignore margins of pPage. + nRelHeight = std::min( nRelHeight, pPage->getFrameArea().Height() ); + else + nRelHeight = std::min( nRelHeight, pPage->getFramePrintArea().Height() ); + } + } + + if ( rSz.GetWidthPercent() && rSz.GetWidthPercent() != SwFormatFrameSize::SYNCED ) + aRet.setWidth( nRelWidth * rSz.GetWidthPercent() / 100 ); + if ( rSz.GetHeightPercent() && rSz.GetHeightPercent() != SwFormatFrameSize::SYNCED ) + aRet.setHeight( nRelHeight * rSz.GetHeightPercent() / 100 ); + + if ( rSz.GetWidthPercent() == SwFormatFrameSize::SYNCED ) + { + aRet.setWidth( aRet.Width() * ( aRet.Height()) ); + aRet.setWidth( aRet.Width() / ( rSz.GetHeight()) ); + } + else if ( rSz.GetHeightPercent() == SwFormatFrameSize::SYNCED ) + { + aRet.setHeight( aRet.Height() * ( aRet.Width()) ); + aRet.setHeight( aRet.Height() / ( rSz.GetWidth()) ); + } + } + return aRet; +} + +static SwTwips lcl_CalcAutoWidth( const SwLayoutFrame& rFrame ) +{ + SwTwips nRet = 0; + SwTwips nMin = 0; + const SwFrame* pFrame = rFrame.Lower(); + + // No autowidth defined for columned frames + if ( !pFrame || pFrame->IsColumnFrame() ) + return nRet; + + while ( pFrame ) + { + if ( pFrame->IsSctFrame() ) + { + nMin = lcl_CalcAutoWidth( *static_cast<const SwSectionFrame*>(pFrame) ); + } + if ( pFrame->IsTextFrame() ) + { + nMin = const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pFrame))->CalcFitToContent(); + const SvxLRSpaceItem &rSpace = + static_cast<const SwTextFrame*>(pFrame)->GetTextNodeForParaProps()->GetSwAttrSet().GetLRSpace(); + if (!static_cast<const SwTextFrame*>(pFrame)->IsLocked()) + nMin += rSpace.GetRight() + rSpace.GetTextLeft() + rSpace.GetTextFirstLineOffset(); + } + else if ( pFrame->IsTabFrame() ) + { + const SwFormatFrameSize& rTableFormatSz = static_cast<const SwTabFrame*>(pFrame)->GetTable()->GetFrameFormat()->GetFrameSize(); + if ( USHRT_MAX == rTableFormatSz.GetSize().Width() || + text::HoriOrientation::NONE == static_cast<const SwTabFrame*>(pFrame)->GetFormat()->GetHoriOrient().GetHoriOrient() ) + { + const SwPageFrame* pPage = rFrame.FindPageFrame(); + // auto width table + nMin = pFrame->GetUpper()->IsVertical() ? + pPage->getFramePrintArea().Height() : + pPage->getFramePrintArea().Width(); + } + else + { + nMin = rTableFormatSz.GetSize().Width(); + } + } + + if ( nMin > nRet ) + nRet = nMin; + + pFrame = pFrame->GetNext(); + } + + return nRet; +} + +/// #i13147# - If called for paint and the <SwNoTextFrame> contains +/// a graphic, load of intrinsic graphic has to be avoided. +bool SwFlyFrame::GetContour( tools::PolyPolygon& rContour, + const bool _bForPaint ) const +{ + vcl::RenderContext* pRenderContext = getRootFrame()->GetCurrShell()->GetOut(); + bool bRet = false; + const bool bIsCandidate(Lower() && Lower()->IsNoTextFrame()); + + if(bIsCandidate) + { + if(GetFormat()->GetSurround().IsContour()) + { + SwNoTextNode *pNd = const_cast<SwNoTextNode*>(static_cast<const SwNoTextNode*>(static_cast<const SwNoTextFrame*>(Lower())->GetNode())); + // #i13147# - determine <GraphicObject> instead of <Graphic> + // in order to avoid load of graphic, if <SwNoTextNode> contains a graphic + // node and method is called for paint. + std::unique_ptr<GraphicObject> xTmpGrfObj; + const GraphicObject* pGrfObj = nullptr; + const SwGrfNode* pGrfNd = pNd->GetGrfNode(); + if ( pGrfNd && _bForPaint ) + { + pGrfObj = &(pGrfNd->GetGrfObj()); + } + else + { + xTmpGrfObj.reset(new GraphicObject(pNd->GetGraphic())); + pGrfObj = xTmpGrfObj.get(); + } + assert(pGrfObj && "SwFlyFrame::GetContour() - No Graphic/GraphicObject found at <SwNoTextNode>."); + if (pGrfObj->GetType() != GraphicType::NONE) + { + if( !pNd->HasContour() ) + { + //#i13147# - no <CreateContour> for a graphic + // during paint. Thus, return (value of <bRet> should be <false>). + if ( pGrfNd && _bForPaint ) + { + OSL_FAIL( "SwFlyFrame::GetContour() - No Contour found at <SwNoTextNode> during paint." ); + return bRet; + } + pNd->CreateContour(); + } + pNd->GetContour( rContour ); + // The Node holds the Polygon matching the original size of the graphic + // We need to include the scaling here + SwRect aClip; + SwRect aOrig; + Lower()->Calc(pRenderContext); + static_cast<const SwNoTextFrame*>(Lower())->GetGrfArea( aClip, &aOrig ); + // #i13147# - copy method code <SvxContourDlg::ScaleContour(..)> + // in order to avoid that graphic has to be loaded for contour scale. + //SvxContourDlg::ScaleContour( rContour, aGrf, MapUnit::MapTwip, aOrig.SSize() ); + { + OutputDevice* pOutDev = Application::GetDefaultDevice(); + const MapMode aDispMap( MapUnit::MapTwip ); + const MapMode aGrfMap( pGrfObj->GetPrefMapMode() ); + const Size aGrfSize( pGrfObj->GetPrefSize() ); + Size aOrgSize; + Point aNewPoint; + bool bPixelMap = aGrfMap.GetMapUnit() == MapUnit::MapPixel; + + if ( bPixelMap ) + aOrgSize = pOutDev->PixelToLogic( aGrfSize, aDispMap ); + else + aOrgSize = OutputDevice::LogicToLogic( aGrfSize, aGrfMap, aDispMap ); + + if ( aOrgSize.Width() && aOrgSize.Height() ) + { + double fScaleX = static_cast<double>(aOrig.Width()) / aOrgSize.Width(); + double fScaleY = static_cast<double>(aOrig.Height()) / aOrgSize.Height(); + + for ( sal_uInt16 j = 0, nPolyCount = rContour.Count(); j < nPolyCount; j++ ) + { + tools::Polygon& rPoly = rContour[ j ]; + + for ( sal_uInt16 i = 0, nCount = rPoly.GetSize(); i < nCount; i++ ) + { + if ( bPixelMap ) + aNewPoint = pOutDev->PixelToLogic( rPoly[ i ], aDispMap ); + else + aNewPoint = OutputDevice::LogicToLogic( rPoly[ i ], aGrfMap, aDispMap ); + + rPoly[ i ] = Point( FRound( aNewPoint.getX() * fScaleX ), FRound( aNewPoint.getY() * fScaleY ) ); + } + } + } + } + // destroy created <GraphicObject>. + xTmpGrfObj.reset(); + rContour.Move( aOrig.Left(), aOrig.Top() ); + if( !aClip.Width() ) + aClip.Width( 1 ); + if( !aClip.Height() ) + aClip.Height( 1 ); + rContour.Clip( aClip.SVRect() ); + rContour.Optimize(PolyOptimizeFlags::CLOSE); + bRet = true; + } + } + else + { + const SwFlyFreeFrame* pSwFlyFreeFrame(dynamic_cast< const SwFlyFreeFrame* >(this)); + + if(nullptr != pSwFlyFreeFrame && + pSwFlyFreeFrame->supportsAutoContour() && + // isTransformableSwFrame already used in supportsAutoContour(), but + // better check twice when it may get changed there... + pSwFlyFreeFrame->isTransformableSwFrame()) + { + // RotateFlyFrame: use untransformed SwFrame to allow text floating around. + // Will be transformed below + const TransformableSwFrame* pTransformableSwFrame(pSwFlyFreeFrame->getTransformableSwFrame()); + const SwRect aFrameArea(pTransformableSwFrame->getUntransformedFrameArea()); + rContour = tools::PolyPolygon(tools::Polygon(aFrameArea.SVRect())); + bRet = (0 != rContour.Count()); + } + } + + if(bRet && 0 != rContour.Count()) + { + const SwFlyFreeFrame* pSwFlyFreeFrame(dynamic_cast< const SwFlyFreeFrame* >(this)); + + if(nullptr != pSwFlyFreeFrame && pSwFlyFreeFrame->isTransformableSwFrame()) + { + // Need to adapt contour to transformation + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + getFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX); + + if(!basegfx::fTools::equalZero(fRotate)) + { + basegfx::B2DPolyPolygon aSource(rContour.getB2DPolyPolygon()); + const basegfx::B2DPoint aCenter(getFrameAreaTransformation() * basegfx::B2DPoint(0.5, 0.5)); + const basegfx::B2DHomMatrix aRotateAroundCenter( + basegfx::utils::createRotateAroundPoint( + aCenter.getX(), + aCenter.getY(), + fRotate)); + aSource.transform(aRotateAroundCenter); + rContour = tools::PolyPolygon(aSource); + } + } + } + } + + return bRet; +} + + +const SwVirtFlyDrawObj* SwFlyFrame::GetVirtDrawObj() const +{ + return static_cast<const SwVirtFlyDrawObj*>(GetDrawObj()); +} +SwVirtFlyDrawObj* SwFlyFrame::GetVirtDrawObj() +{ + return static_cast<SwVirtFlyDrawObj*>(DrawObj()); +} + +// implementation of pure virtual method declared in +// base class <SwAnchoredObject> + +void SwFlyFrame::InvalidateObjPos() +{ + InvalidatePos(); + // #i68520# + InvalidateObjRectWithSpaces(); +} + +SwFrameFormat& SwFlyFrame::GetFrameFormat() +{ + OSL_ENSURE( GetFormat(), + "<SwFlyFrame::GetFrameFormat()> - missing frame format -> crash." ); + return *GetFormat(); +} +const SwFrameFormat& SwFlyFrame::GetFrameFormat() const +{ + OSL_ENSURE( GetFormat(), + "<SwFlyFrame::GetFrameFormat()> - missing frame format -> crash." ); + return *GetFormat(); +} + +SwRect SwFlyFrame::GetObjRect() const +{ + return getFrameArea(); +} + +// #i70122# +// for Writer fly frames the bounding rectangle equals the object rectangles +SwRect SwFlyFrame::GetObjBoundRect() const +{ + return GetObjRect(); +} + +// #i68520# +bool SwFlyFrame::SetObjTop_( const SwTwips _nTop ) +{ + const bool bChanged( getFrameArea().Pos().getY() != _nTop ); + SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); + aFrm.Pos().setY(_nTop); + + return bChanged; +} +bool SwFlyFrame::SetObjLeft_( const SwTwips _nLeft ) +{ + const bool bChanged( getFrameArea().Pos().getX() != _nLeft ); + SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this); + aFrm.Pos().setX(_nLeft); + + return bChanged; +} + +/** method to assure that anchored object is registered at the correct + page frame + + OD 2004-07-02 #i28701# +*/ +void SwFlyFrame::RegisterAtCorrectPage() +{ + // default behaviour is to do nothing. +} + +/** method to determine, if a <MakeAll()> on the Writer fly frame is possible + + OD 2004-05-11 #i28701# +*/ +bool SwFlyFrame::IsFormatPossible() const +{ + return SwAnchoredObject::IsFormatPossible() && + !IsLocked() && !IsColLocked(); +} + +void SwFlyFrame::GetAnchoredObjects( std::vector<SwAnchoredObject*>& aVector, const SwFormat& rFormat ) +{ + SwIterator<SwFlyFrame,SwFormat> aIter( rFormat ); + for( SwFlyFrame* pFlyFrame = aIter.First(); pFlyFrame; pFlyFrame = aIter.Next() ) + aVector.push_back( pFlyFrame ); +} + +const SwFlyFrameFormat * SwFlyFrame::GetFormat() const +{ + return static_cast< const SwFlyFrameFormat * >( GetDep() ); +} + +SwFlyFrameFormat * SwFlyFrame::GetFormat() +{ + return static_cast< SwFlyFrameFormat * >( GetDep() ); +} + +void SwFlyFrame::Calc(vcl::RenderContext* pRenderContext) const +{ + if ( !m_bValidContentPos ) + const_cast<SwFlyFrame*>(this)->PrepareMake(pRenderContext); + else + SwLayoutFrame::Calc(pRenderContext); +} + +SwTwips SwFlyFrame::CalcContentHeight(const SwBorderAttrs *pAttrs, const SwTwips nMinHeight, const SwTwips nUL) +{ + SwRectFnSet aRectFnSet(this); + SwTwips nHeight = 0; + if ( Lower() ) + { + if ( Lower()->IsColumnFrame() ) + { + FormatWidthCols( *pAttrs, nUL, nMinHeight ); + nHeight = aRectFnSet.GetHeight(Lower()->getFrameArea()); + } + else + { + SwFrame *pFrame = Lower(); + while ( pFrame ) + { + nHeight += aRectFnSet.GetHeight(pFrame->getFrameArea()); + if( pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsUndersized() ) + // This TextFrame would like to be a bit larger + nHeight += static_cast<SwTextFrame*>(pFrame)->GetParHeight() + - aRectFnSet.GetHeight(pFrame->getFramePrintArea()); + else if( pFrame->IsSctFrame() && static_cast<SwSectionFrame*>(pFrame)->IsUndersized() ) + nHeight += static_cast<SwSectionFrame*>(pFrame)->Undersize(); + pFrame = pFrame->GetNext(); + } + } + if ( GetDrawObjs() ) + { + const size_t nCnt = GetDrawObjs()->size(); + SwTwips nTop = aRectFnSet.GetTop(getFrameArea()); + SwTwips nBorder = aRectFnSet.GetHeight(getFrameArea()) - + aRectFnSet.GetHeight(getFramePrintArea()); + for ( size_t i = 0; i < nCnt; ++i ) + { + SwAnchoredObject* pAnchoredObj = (*GetDrawObjs())[i]; + if ( dynamic_cast<const SwFlyFrame*>( pAnchoredObj) != nullptr ) + { + SwFlyFrame* pFly = static_cast<SwFlyFrame*>(pAnchoredObj); + // consider only Writer fly frames, which follow the text flow. + if ( pFly->IsFlyLayFrame() && + pFly->getFrameArea().Top() != FAR_AWAY && + pFly->GetFormat()->GetFollowTextFlow().GetValue() ) + { + SwTwips nDist = -aRectFnSet.BottomDist( pFly->getFrameArea(), nTop ); + if( nDist > nBorder + nHeight ) + nHeight = nDist - nBorder; + } + } + } + } + } + return nHeight; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |