/* -*- 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 .
*/
namespace
{ /// Gets the bottom position which is a deadline for a split fly.
SwTwips GetFlyAnchorBottom(SwFlyFrame* pFly, const SwFrame& rAnchor)
{
SwRectFnSet aRectFnSet(pFly);
constauto* pFrameFormat = pFly->GetFrameFormat(); const IDocumentSettingAccess& rIDSA = pFrameFormat->getIDocumentSettingAccess(); // Allow overlap with bottom margin / footer only in case we're relative to the page frame. bool bVertPageFrame = pFrameFormat->GetVertOrient().GetRelationOrient() == text::RelOrientation::PAGE_FRAME; bool bInBody = rAnchor.IsInDocBody(); bool bLegacy = rIDSA.get(DocumentSettingId::TAB_OVER_MARGIN) && (bVertPageFrame || !bInBody); if (bLegacy)
{ // Word <= 2010 style: the fly can overlap with the bottom margin / footer area in case the // fly height fits the body height and the fly bottom fits the page. // See if the fly height would fit at least the page height, ignoring the vertical offset.
SwTwips nFlyHeight = aRectFnSet.GetHeight(pFly->getFrameArea());
SwTwips nPageHeight = aRectFnSet.GetHeight(pPage->getFramePrintArea());
SwTwips nFlyTop = aRectFnSet.GetTop(pFly->getFrameArea());
SwTwips nBodyTop = aRectFnSet.GetTop(pBody->getFrameArea()); if (nFlyTop < nBodyTop)
{ // Fly frame overlaps with the top margin area, ignore that part of the fly frame for // top/height purposes.
nFlyHeight -= nBodyTop - nFlyTop;
nFlyTop = nBodyTop;
} if (nFlyHeight <= nPageHeight)
{ // Yes, it would fit: allow overlap if there is no problematic vertical offset.
SwTwips nDeadline = aRectFnSet.GetBottom(pPage->getFrameArea());
SwTwips nBodyHeight = aRectFnSet.GetHeight(pBody->getFramePrintArea()); if (nDeadline - nFlyTop > nBodyHeight)
{ // If the fly would now grow to nDeadline then it would not fit the body height, so // limit the height.
nDeadline = nFlyTop + nBodyHeight;
} return nDeadline;
}
}
// Word >= 2013 style: the fly has to stay inside the body frame. return aRectFnSet.GetPrtBottom(*pBody);
}
}
// First the Init, then the Content: // This is due to the fact that the Content may have Objects/Frames, // which are then registered
InitDrawObj(*pAnch);
Chain( pAnch );
if (!bFollow)
{
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()) ) return;
void SwFlyFrame::InsertCnt()
{ if ( GetPrevLink() ) return;
const SwFormatContent& rContent = GetFormat()->GetContent();
OSL_ENSURE( rContent.GetContentIdx(), ":-( no content prepared." );
SwNodeOffset 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.
SwFrame* pLower = Lower(); if ( pLower && pLower->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;
}
// 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 !ENABLE_WASM_STRIP_ACCESSIBILITY 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 );
}
}
} #endif
if( GetFormat() && !GetFormat()->GetDoc().IsInDtor() )
{
ClearTmpConsiderWrapInfluence(); // remove this from SwLayouter
Unchain();
DeleteCnt();
if ( GetAnchorFrame() )
AnchorFrame()->RemoveFly( this );
}
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())
{
SwFlyFrame const*const pOldSelFly = ::GetFlyFromMarked(nullptr, &rCurrentShell); if (pOldSelFly == this)
{
assert(rCurrentShell.Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() == 1); if (SwFEShell *const pFEShell = dynamic_cast<SwFEShell*>(&rCurrentShell))
{ // tdf#131679 move any cursor out of fly
rCurrentShell.Imp()->GetDrawView()->UnmarkAll();
SwPaM const temp(ResolveFlyAnchor(*pOldSelFly->GetFormat()));
pFEShell->SetSelection(temp); // could also call SetCursor() like SwFEShell::SelectObj() // does, but that would access layout a bit much...
} else
{
rCurrentShell.Imp()->GetDrawView()->UnmarkAll();
}
}
}
}
}
}
SwVirtFlyDrawObj* pVirtDrawObj = GetVirtDrawObj(); // Else calls delete of the ContactObj
pVirtDrawObj->SetUserCall(nullptr);
if ( pVirtDrawObj->getSdrPageFromSdrObject() )
pVirtDrawObj->getSdrPageFromSdrObject()->RemoveObject( pVirtDrawObj->GetOrdNum() );
ClearDrawObj();
}
void SwFlyFrame::ChainFrames( SwFlyFrame &rMaster, SwFlyFrame &rFollow )
{
OSL_ENSURE( !rMaster.GetNextLink(), "link can not be changed" );
OSL_ENSURE( !rFollow.GetPrevLink(), "link can not be changed" );
if ( rMaster.ContainsContent() )
{ // To get a text flow we need to invalidate
SwFrame *pInva = rMaster.FindLastLower();
SwRectFnSet aRectFnSet(&rMaster); const tools::Long nBottom = aRectFnSet.GetPrtBottom(rMaster); while ( pInva )
{ if( aRectFnSet.BottomDist( pInva->getFrameArea(), nBottom ) <= 0 )
{
pInva->InvalidateSize();
pInva->Prepare();
pInva = pInva->FindPrev();
} else
pInva = nullptr;
}
}
if ( rFollow.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 = rFollow.ContainsContent();
OSL_ENSURE( !pFrame->IsTabFrame() && !pFrame->FindNext(), "follow in chain contains content");
pFrame->Cut();
SwFrame::DestroyFrame(pFrame);
}
if ( rFollow.ContainsContent() )
{ // The Master sucks up the content of the Follow
SwLayoutFrame *pUpper = &rMaster;
SwFrame* pLower = pUpper->Lower(); if ( pLower && pLower->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 = &rFollow; while ( pFoll )
{
SwFrame *pTmp = ::SaveContent( pFoll ); if ( pTmp )
::RestoreContent( pTmp, pUpper, rMaster.FindLastLower() );
pFoll->SetCompletePaint();
pFoll->InvalidateSize();
pFoll = pFoll->GetNextLink();
}
}
// The Follow needs his own content to be served const SwFormatContent &rContent = rFollow.GetFormat()->GetContent();
OSL_ENSURE( rContent.GetContentIdx(), ":-( No content prepared." );
SwNodeOffset nIndex = rContent.GetContentIdx()->GetIndex(); // Lower() means SwColumnFrame: this one contains another SwBodyFrame
SwFrame* pLower = rFollow.Lower();
::InsertCnt_( pLower ? const_cast<SwLayoutFrame*>(static_cast<const SwLayoutFrame*>(static_cast<const SwLayoutFrame*>(pLower)->Lower()))
: static_cast<SwLayoutFrame*>(&rFollow),
rFollow.GetFormat()->GetDoc(), ++nIndex );
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;
} elseif ( pLay == pFly->FindFooterOrHeader() ) break;
}
pFly = aIter.Next();
}
} elseif ( pFly )
{
OSL_ENSURE( !aIter.Next(), "chain with more than one instance" );
} return pFly;
}
bool SwFlyFrame::IsFlySplitAllowed() const
{ if (!IsFlyAtContentFrame())
{ returnfalse;
}
const IDocumentSettingAccess& rIDSA = GetFormat()->getIDocumentSettingAccess(); if (rIDSA.get(DocumentSettingId::DO_NOT_BREAK_WRAPPED_TABLES))
{ returnfalse;
}
if (FindFooterOrHeader())
{ // Adding a new page would not increase the header/footer area. returnfalse;
}
const SwFrame* pFlyAnchor = GetAnchorFrame(); if (pFlyAnchor && pFlyAnchor->FindColFrame())
{ // No split in multi-column sections, so GetFlyAnchorBottom() can assume that our innermost // body frame and the page's body frame is the same. // This is also consistent with the Word behavior. returnfalse;
}
if (pFlyAnchor && pFlyAnchor->IsInFootnote())
{ // No split in footnotes. returnfalse;
}
const SwFlyFrameFormat* pFormat = GetFormat(); const SwFormatVertOrient& rVertOrient = pFormat->GetVertOrient(); if (rVertOrient.GetVertOrient() == text::VertOrientation::BOTTOM)
{ // We have to grow from bottom to top, and the fly split code assumes that we grow from top // to bottom, so don't split for now. if (rVertOrient.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA)
{ // Growing from the bottom of the body frame. returnfalse;
}
}
return pFormat->GetFlySplit().GetValue();
}
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;
} elseif ( 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 (SwFrame* pLower = Lower())
{ if ( pLower->IsColumnFrame() )
{ const SwRect aOld( GetObjRectWithSpaces() ); const Size aOldSz( getFramePrintArea().SSize() ); const SwTwips nDiffWidth = getFrameArea().Width() - rFrameSize.GetWidth();
// #i87645# - reset flags for the layout process (only if something has been invalidated)
ResetLayoutProcessBools();
} elseif (rHint.GetId() == SfxHintId::SwAutoFormatUsedHint)
{ // There's a FlyFrame, so use it static_cast<const sw::AutoFormatUsedHint&>(rHint).SetUsed(); return;
} elseif (rHint.GetId() == SfxHintId::SwGetZOrder)
{ auto pGetZOrdnerHint = static_cast<const sw::GetZOrderHint*>(&rHint); constauto& rFormat(dynamic_cast<const SwFrameFormat&>(rMod)); if (rFormat.Which() == RES_FLYFRMFMT && rFormat.getIDocumentLayoutAccess().GetCurrentViewShell()) // #i11176#
pGetZOrdnerHint->m_rnZOrder = GetVirtDrawObj()->GetOrdNum();
} elseif (rHint.GetId() == SfxHintId::SwGetObjectConnected)
{ auto pConnectedHint = static_cast<const sw::GetObjectConnectedHint*>(&rHint); constauto& 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::UpdateAttr_( const SfxPoolItem *pOld, const SfxPoolItem *pNew,
SwFlyFrameInvFlags &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 |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::SetNotifyBack;
} break; // #i28701# - consider new option 'wrap influence on position' case RES_WRAP_INFLUENCE_ON_OBJPOS:
{
rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::SetNotifyBack
| SwFlyFrameInvFlags::UpdateObjInSortedList;
} break; case RES_SURROUND:
{ //#i28701# - invalidate position on change of // wrapping style.
rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::ClearContourCache; // 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 |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::SetNotifyBack;
// Delete contour in the Node if necessary
SwFrame* pLower = Lower(); if ( pLower && pLower->IsNoTextFrame() &&
!GetFormat()->GetSurround().IsContour() )
{
SwNoTextNode *pNd = static_cast<SwNoTextNode*>(static_cast<SwNoTextFrame*>(pLower)->GetNode()); if ( pNd->HasContour() )
pNd->SetContour( nullptr );
} // #i28701# - perform reorder of object lists // at anchor frame and at page frame.
rInvFlags |= SwFlyFrameInvFlags::UpdateObjInSortedList;
} break;
SwFormatFrameSize *pNewFormatFrameSize = nullptr; if (nWhich == RES_FRM_SIZE)
pNewFormatFrameSize = const_cast<SwFormatFrameSize*>(static_cast<const SwFormatFrameSize*>(pNew)); elseif (nWhich == RES_FLY_SPLIT)
{ // If the fly frame has a table lower, invalidate that, so it joins its follow tab // frames and re-splits according to the new fly split rule. if (Lower() && Lower()->IsTabFrame())
{
Lower()->InvalidateAll_();
}
}
if (aURL.GetMap() && pNewFormatFrameSize)
{ const SwFormatFrameSize &rOld = *pNewFormatFrameSize; //#35091# Can be "times zero", when loading the template if ( rOld.GetWidth() && rOld.GetHeight() )
{
// 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() );
if (aURL.GetMap() && pOldFormat)
{ const SwFormatFrameSize &rOld = pOldFormat->GetFrameSize(); //#35091# Can be "times zero", when loading the template if ( rOld.GetWidth() && rOld.GetHeight() )
{
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.
SwFrame* pLower = pFrame->Lower(); if ( !pFrame->IsLocked() && !pFrame->IsColLocked() &&
pLower && pLower->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;
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;
const SwFrame* pAnchor = GetAnchorFrame(); if (SwFrame* pAnchorChar = FindAnchorCharFrame())
{ // If we find a follow of the anchor that is effectively the anchor of this fly, // then use that as the anchor for sizing purposes.
pAnchor = pAnchorChar;
} if (pAnchor && IsFlySplitAllowed())
{ // If the fly is allowed to be split, then limit its size to the upper of the // anchor.
SwTwips nDeadline = GetFlyAnchorBottom(this, *pAnchor);
SwTwips nTop = aRectFnSet.GetTop(getFrameArea());
SwTwips nBottom = aRectFnSet.GetTop(getFrameArea()) + nRemaining; if (nBottom > nDeadline)
{ if (nDeadline > nTop)
{
nRemaining = nDeadline - nTop;
} else
{ // Even the top is below the deadline, set size to empty and mark it as // clipped so we re-format later.
nRemaining = 0;
m_bHeightClipped = 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(std::nullopt, 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;
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;
}
}
// #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.
assert(pFrame->IsFlowFrame());
SwFlowFrame* pTmpFlowFrame = SwFlowFrame::CastFlowFrame(pFrame);
SwFrame* pTmpPrev = pTmpFlowFrame->FindPrevIgnoreHidden();
SwFlowFrame* pTmpPrevFlowFrame = pTmpPrev && pTmpPrev->IsFlowFrame() ? SwFlowFrame::CastFlowFrame(pTmpPrev) : nullptr;
// format floating screen objects anchored to the frame. if ( !bPrevInvalid && pFrame->GetDrawObjs() && pLay->IsAnLower( pFrame ) )
{ bool bAgain = false; bool bRestartLayoutProcess = false;
size_t nCnt = pFrame->GetDrawObjs()->size();
size_t i = 0; while ( i < nCnt )
{ // pFrame can move to a different page in FormatObj()
SwPageFrame *const pPageFrame = pFrame->FindPageFrame();
// 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() );
SwFrame* pAnchorFrame = pFrame;
SwPageFrame* pAnchorPageFrame = pPageFrame; if (SwFlyFrame* pFlyFrame = pAnchoredObj->DynCastFlyFrame())
{ if (pFlyFrame->IsFlySplitAllowed())
{ // Split flys are at-para anchored, but the follow fly's anchor char // frame is not the master frame but can be also a follow of pFrame.
SwTextFrame* pAnchorCharFrame = pFlyFrame->FindAnchorCharFrame(); if (pAnchorCharFrame)
{ // Found an anchor char frame, update the anchor frame and the // anchor page frame accordingly.
pAnchorFrame = pAnchorCharFrame;
pAnchorPageFrame = pAnchorCharFrame->FindPageFrame();
}
}
}
if (!SwObjectFormatter::FormatObj(*pAnchoredObj, pAnchorFrame, pAnchorPageFrame,
rShell.Imp()->IsAction() ? &rShell.Imp()->GetLayAction() : nullptr))
{ if (rShell.Imp()->IsAction() && rShell.Imp()->GetLayAction().IsAgain())
{ // tdf#159015 will always fail, don't loop return;
}
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* pFormat = pAnchoredObj->GetFrameFormat();
SwFormatSurround aAttr( pFormat->GetSurround() ); if( css::text::WrapTextMode_THROUGH != aAttr.GetSurround() )
{ // When on auto position, we can only set it to // flow through if ((pFormat->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 );
}
pFormat->LockModify();
pFormat->SetFormatAttr( aAttr );
pFormat->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 // tdf#152106 loop control in multi-column sections to avoid of freezing
&& nLoopControlRunsInMultiCol < nLoopControlMax // tdf#142080 if it was already on next page, and still is, // ignore restart, as restart could cause infinite loop
&& (wasFrameLowerOfLay || pLay->IsAnLower(pFrame)))
{ bool bIsMultiColumn = pSect && pSect->GetSection() && pSect->Lower() &&
pSect->Lower()->IsColumnFrame() && pSect->Lower()->GetNext(); if ( bIsMultiColumn )
++nLoopControlRunsInMultiCol;
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 ( nLoopControlRuns < nLoopControlMax ) continue;
OSL_FAIL( "LoopControl in CalcContent" );
}
} if ( pFrame->IsTabFrame() )
{ if (static_cast<SwTabFrame*>(pFrame)->m_bLockBackMove)
{
assert(static_cast<SwTabFrame*>(pFrame)->IsFollow()); static_cast<SwTabFrame*>(pFrame)->m_bLockBackMove = false; // tdf#150606 encourage it to move back in FormatLayout() if (static_cast<SwTabFrame*>(pFrame)->m_bWantBackMove)
{ static_cast<SwTabFrame*>(pFrame)->m_bWantBackMove = false;
pFrame->InvalidatePos();
}
}
}
// use new class to position object
GetAnchorFrame()->Calc(pRenderContext);
objectpositioning::SwToLayoutAnchoredObjectPosition
aObjPositioning( *GetVirtDrawObj() );
aObjPositioning.CalcPosition();
// #i58280# // update relative position
SetCurrRelPos( aObjPositioning.GetRelPos() );
// The fly frame may be partially outside the page, check for this case.
SwPageFrame* pPageFrame = FindPageFrame();
SwFrameFormat* pFlyFormat = GetFormat();
SwFrameFormat* pDrawFormat = SwTextBoxHelper::getOtherTextBoxFormat(pFlyFormat, RES_FLYFRMFMT); const SwFrameFormat* pFormat = pDrawFormat ? pDrawFormat : pFlyFormat; // Don't increase the left padding if the wrap mode is through. bool bIsWrapThrough = pFormat && pFormat->GetSurround().GetSurround() == text::WrapTextMode::WrapTextMode_THROUGH; if (pPageFrame && pFlyFormat && !bIsWrapThrough)
{ const IDocumentSettingAccess& rIDSA = pFlyFormat->getIDocumentSettingAccess(); bool bDoNotCaptureDrawObjsOnPage = rIDSA.get(DocumentSettingId::DO_NOT_CAPTURE_DRAW_OBJS_ON_PAGE); bool bLRTB = pFlyFormat->GetFrameDir().GetValue() == SvxFrameDirection::Horizontal_LR_TB;
SwTwips nFlyLeft = getFrameArea().Left();
SwTwips nPageLeft = pPageFrame->getFrameArea().Left(); if (bDoNotCaptureDrawObjsOnPage && bLRTB && nFlyLeft < nPageLeft)
{ // It is outside: only start the left padding of the text inside the page frame, // when we're in Word compatibility mode.
nLeftLine += (nPageLeft - nFlyLeft);
}
}
bool SwFlyFrame::IsShowUnfloatButton(SwWrtShell* pWrtSh) const
{ if (pWrtSh == nullptr) returnfalse;
// In read only mode we don't allow unfloat operation if (pWrtSh->GetViewOptions()->IsReadonly()) returnfalse;
const SdrObject *pObj = GetFrameFormat()->FindRealSdrObject(); if (pObj == nullptr) returnfalse;
// SwFlyFrame itself can mean images, ole objects, etc, but we interested in actual text frames if (SwFEShell::GetObjCntType(*pObj) != OBJCNT_FLY) returnfalse;
// We show the button only for the selected text frame
SwDrawView *pView = pWrtSh->Imp()->GetDrawView(); if (pView == nullptr) returnfalse;
// Fly frame can be selected only alone if (pView->GetMarkedObjectList().GetMarkCount() != 1) returnfalse;
if(!pView->IsObjMarked(pObj)) returnfalse;
// 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) returnfalse;
}
if (pLower->IsTextFrame())
{ const SwTextFrame* pTextFrame = static_cast<const SwTextFrame*>(pLower); if (!o3tl::trim(pTextFrame->GetText()).empty()) returnfalse;
}
pLower = pLower->GetNext();
}
if (nTableCount != 1 || pTable == nullptr) returnfalse;
// Show the unfold button only for multipage tables const SwBodyFrame *pBody = GetAnchorFrame()->FindBodyFrame(); if (pBody == nullptr) returnfalse;
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();
}
reason = SwResizeLimitReason::BalancedColumns; return 0;
}
reason = SwResizeLimitReason::Unspecified;
if (bTst)
{ // We're in test mode. Don't promise infinite growth for split flys, rather limit the // max size to the bottom of the upper. const SwFrame* pAnchor = GetAnchorFrame(); if (SwFrame* pAnchorChar = FindAnchorCharFrame())
{
pAnchor = pAnchorChar;
} if (pAnchor && IsFlySplitAllowed())
{
SwTwips nDeadline = GetFlyAnchorBottom(this, *pAnchor);
SwTwips nTop = aRectFnSet.GetTop(getFrameArea());
SwTwips nBottom = nTop + aRectFnSet.GetHeight(getFrameArea()); // Calculate max grow and compare to the requested growth, adding to nDist may // overflow when it's LONG_MAX.
SwTwips nMaxGrow = nDeadline - nBottom; if (nDist > nMaxGrow)
{
nDist = nMaxGrow;
reason = SwResizeLimitReason::FlowToFollow;
}
} return nDist;
}
const SwRect aOld( GetObjRectWithSpaces() );
InvalidateSize_(); constbool 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. constbool 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();
SwRect aNew(GetObjRectWithSpaces()); if (IsFlySplitAllowed() && aNew.Height() - aOld.Height() < nDist)
{ // We are allowed to split and the actual growth is less than the requested growth. const SwFrame* pAnchor = GetAnchorFrame(); if (SwFrame* pAnchorChar = FindAnchorCharFrame())
{
pAnchor = pAnchorChar;
} if (pAnchor)
{
SwTwips nDeadline = GetFlyAnchorBottom(this, *pAnchor);
SwTwips nTop = aRectFnSet.GetTop(getFrameArea());
SwTwips nBottom = nTop + aRectFnSet.GetHeight(getFrameArea());
SwTwips nMaxGrow = nDeadline - nBottom; if (nDist > nMaxGrow)
{ // The requested growth is more than what we can provide, limit it.
nDist = nMaxGrow;
reason = SwResizeLimitReason::FlowToFollow;
} // Grow & invalidate the size.
SwTwips nRemaining = nDist - (aNew.Height() - aOld.Height());
{
SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
aRectFnSet.AddBottom(aFrm, nRemaining);
}
InvalidateObjRectWithSpaces();
{ // Margins are unchanged, so increase the print height similar to the frame // height.
SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
aRectFnSet.AddBottom(aPrt, nRemaining );
}
aNew = GetObjRectWithSpaces();
}
} if ( aOld != aNew )
::Notify( this, FindPageFrame(), aOld ); return aRectFnSet.GetHeight(aNew)-aRectFnSet.GetHeight(aOld);
}
if ( pLower->IsColumnFrame() )
{ // If it's a Column Frame, the Format takes control of the // resizing (due to the adjustment). if ( !bTst )
{
SwRect aOld( GetObjRectWithSpaces() );
if ( !bTst )
{ const SwRect aOld( GetObjRectWithSpaces() );
InvalidateSize_(); constbool 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. constbool 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;
}
if (!bAutosizeHeight && !bAutosizeWidth) returntrue;
bool bIsValidResize = true;
/** if (either AutoSizeWidth or AutoSizeHeight, not both), if the autosize dimension goes smaller than min value and the other dimension changed return valid else remember invalid
*/
tools::Long nMinFrameHeight = 0; if (bAutosizeHeight)
{ const SwTwips nUL = pAttrs->CalcTopLine() + pAttrs->CalcBottomLine();
rFrameSz.SetHeight(aTargetSize.Height());
rFrameSz.SetWidth(aTargetSize.Width());
Size aRelSize( CalcRel( rFrameSz ) );
if (nMinHeight < nMinFrameHeight)
{
bIsValidResize = false; // if height less than minHeight and width changed when not AutoSizeWidth if (!bAutosizeWidth && aTargetSize.Width() != aFrameSize.Width()) returntrue;
}
}
if (aTargetSize.Width() < nMinFrameWidth)
bIsValidResize = false; if (!bAutosizeHeight && aTargetSize.Height() != aFrameSize.Height()) returntrue;
}
// if not valid resize, and both AutoSizeWidth and AutoSizeHeight, // then consider resize is valid if any one of the dimensions was changed from its original size // (the frame's dimensions), and the destination dimension is a valid one. if (bAutosizeWidth && bAutosizeHeight && !bIsValidResize)
{ return (aTargetSize.Width() != aFrameSize.Width() && aTargetSize.Width() >= nMinFrameWidth) ||
(aTargetSize.Height() != aFrameSize.Height() && aTargetSize.Height() >= nMinFrameHeight);
}
return bIsValidResize;
}
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))
{ auto pLower = dynamic_cast<SwNoTextFrame*>(Lower()); if ( pLower && pLower->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 ) returntrue;
pFrame = pFrame->IsFlyFrame()
? static_cast<const SwFlyFrame*>(pFrame)->GetAnchorFrame()
: pFrame->GetUpper();
} while ( pFrame ); returnfalse;
}
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# #if !ENABLE_WASM_STRIP_ACCESSIBILITY 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 );
}
}
}
} #endif
m_pDrawObjs->Remove(*pToRemove); if (!m_pDrawObjs->size())
{
m_pDrawObjs.reset();
}
pToRemove->ChgAnchorFrame( nullptr );
if ( !pToRemove->IsFlyInContentFrame() && GetUpper() && IsInTab() )//MA_FLY_HEIGHT
GetUpper()->InvalidateSize();
}
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. if (SwDrawContact* pContact = static_cast<SwDrawContact*>(::GetUserCall( _rNewObj.GetDrawObj() )))
pContact->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 );
}
// #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 ( auto pFly = pAnchoredObj->DynCastFlyFrame() )
{
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( constbool _bUnlockPosOfObjs )
{ // invalidate lower floating screen objects
SwPageFrame* pPageFrame = FindPageFrame(); if ( !(pPageFrame && pPageFrame->GetSortedObjs()) ) return;
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 ( auto pFly = pObj->DynCastFlyFrame() )
{ 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. constbool 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
{
assert( dynamic_cast<const SwAnchoredDrawObject*>( pObj) && "<SwLayoutFrame::NotifyFlys() - anchored object of unexpected type" ); // tdf#156728 invalidate fly positioned dependent on header/footer size bool isPositionedByHF(false); if (IsHeaderFrame() || IsFooterFrame())
{ autoconst nO(pObj->GetFrameFormat()->GetVertOrient().GetRelationOrient()); if (nO == text::RelOrientation::PAGE_PRINT_AREA
|| nO == text::RelOrientation::PAGE_PRINT_AREA_BOTTOM
|| nO == text::RelOrientation::PAGE_PRINT_AREA_TOP)
{
isPositionedByHF = true;
}
} // #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 ) ||
isPositionedByHF ||
pAnchorFrame->FindPageFrame() != pPageFrame )
{ // #i44016# if ( _bUnlockPosOfObjs )
{
pObj->UnlockPosition();
}
pObj->InvalidateObjPos();
}
}
}
}
if ( GetFormat()->GetSurround().IsContour() )
{
ClrContourCache( pObj );
} elseif(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 );
}
}
// 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() ); elseif ( pRel->IsPageFrame() )
nRelWidth = std::min( nRelWidth, pRel->getFrameArea().Width() );
// tdf#124423 In Microsoft compatibility mode: widen the frame to max (PrintArea of the frame it anchored to) if it contains at least 2 paragraphs, // or 1 paragraph wider than its parent area. if (rFrame.GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::FRAME_AUTOWIDTH_WITH_MORE_PARA))
{ const SwFrame* pFrameRect = nullptr; if (rFrame.IsFlyFrame())
pFrameRect = static_cast<const SwFlyFrame*>(&rFrame)->GetAnchorFrame(); else
{ if (const SwFrame* pLower = rFrame.Lower())
pFrameRect = pLower->FindPageFrame();
} if (pFrameRect)
{
SwTwips nParentWidth = rFrame.IsVertical() ? pFrameRect->getFramePrintArea().Height() : pFrameRect->getFramePrintArea().Width(); if (nParagraphCount > 1 || nRet > nParentWidth)
{ return nParentWidth;
}
}
}
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, constbool _bForPaint ) const
{
vcl::RenderContext* pRenderContext = getRootFrame()->GetCurrShell()->GetOut(); bool bRet = false; const SwFrame* pLower = Lower(); constbool bIsCandidate(pLower && pLower->IsNoTextFrame());
if(bIsCandidate)
{ if(GetFormat()->GetSurround().IsContour())
{
SwNoTextNode *pNd = const_cast<SwNoTextNode*>(static_cast<const SwNoTextNode*>(static_cast<const SwNoTextFrame*>(pLower)->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(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())
{ if (IsFlyFreeFrame() && static_cast< const SwFlyFreeFrame* >(this)->isTransformableSwFrame())
{ // Need to adapt contour to transformation
basegfx::B2DVector aScale, aTranslate; double fRotate, fShearX;
getFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.