/* -*- 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include 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 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() == ATT_VAR_SIZE ? MINFLY : rFrameSize.GetHeight() ); } // Fixed or variable Height? if ( rFrameSize.GetHeightSizeType() == ATT_MIN_SIZE ) m_bMinHeight = true; else if ( rFrameSize.GetHeightSizeType() == ATT_FIX_SIZE ) 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 neighboor doesn't exist - the construction of the // neighboor 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(static_cast(Lower())->Lower()) : static_cast(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(), " - 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() ) { // OD 2004-01-19 #110582# Unchain(); // OD 2004-01-19 #110582# DeleteCnt(); if ( GetAnchorFrame() ) AnchorFrame()->RemoveFly( this ); } FinitDrawObj(); SwLayoutFrame::DestroyImpl(); } SwFlyFrame::~SwFlyFrame() { } const IDocumentDrawModelAccess& SwFlyFrame::getIDocumentDrawModelAccess() { return GetFormat()->getIDocumentDrawModelAccess(); } // OD 2004-01-19 #110582# void SwFlyFrame::Unchain() { if ( GetPrevLink() ) UnchainFrames( GetPrevLink(), this ); if ( GetNextLink() ) UnchainFrames( this, GetNextLink() ); } // OD 2004-01-19 #110582# void SwFlyFrame::DeleteCnt() { SwFrame* pFrame = m_pLower; while ( pFrame ) { while ( pFrame->GetDrawObjs() && pFrame->GetDrawObjs()->size() ) { SwAnchoredObject *pAnchoredObj = (*pFrame->GetDrawObjs())[0]; if ( dynamic_cast( pAnchoredObj) != nullptr ) { SwFrame::DestroyFrame(static_cast(pAnchoredObj)); } else if ( dynamic_cast( pAnchoredObj) != nullptr ) { // OD 23.06.2003 #108784# - consider 'virtual' drawing objects SdrObject* pObj = pAnchoredObj->DrawObj(); if ( dynamic_cast( pObj) != nullptr ) { SwDrawVirtObj* pDrawVirtObj = static_cast(pObj); pDrawVirtObj->RemoveFromWriterLayout(); pDrawVirtObj->RemoveFromDrawingPage(); } else { SwDrawContact* pContact = static_cast(::GetUserCall( pObj )); if ( pContact ) { pContact->DisconnectFromLayout(); } } } } pFrame->RemoveFromLayout(); SwFrame::DestroyFrame(pFrame); pFrame = m_pLower; } InvalidatePage(); } void SwFlyFrame::InitDrawObj() { // OD 2004-03-22 #i26791# SetDrawObj(*SwFlyDrawContact::CreateNewRef(this, GetFormat())); // Set the right Layer // OD 2004-01-19 #110582# IDocumentDrawModelAccess& rIDDMA = GetFormat()->getIDocumentDrawModelAccess(); SdrLayerID nHeavenId = rIDDMA.GetHeavenId(); SdrLayerID nHellId = rIDDMA.GetHellId(); // OD 2004-03-22 #i26791# GetVirtDrawObj()->SetLayer( GetFormat()->GetOpaque().GetValue() ? nHeavenId : nHellId ); } 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()->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(pUpper->GetLastLower()); pUpper = static_cast(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(static_cast(static_cast(pFollow->Lower())->Lower())) : static_cast(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 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() == ATT_VAR_SIZE ) mbFixSize = m_bMinHeight = false; else { if ( rFrameSize.GetHeightSizeType() == ATT_FIX_SIZE ) { mbFixSize = true; m_bMinHeight = false; } else if ( rFrameSize.GetHeightSizeType() == ATT_MIN_SIZE ) { 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(&rHint)) { const auto& rFormat(dynamic_cast(rMod)); if (rFormat.Which() == RES_FLYFRMFMT && rFormat.getIDocumentLayoutAccess().GetCurrentViewShell()) // #i11176# pGetZOrdnerHint->m_rnZOrder = GetVirtDrawObj()->GetOrdNum(); } else if (auto pConnectedHint = dynamic_cast(&rHint)) { const auto& rFormat(dynamic_cast(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(pNew)->GetChgSet() ); SfxItemIter aOIter( *static_cast(pOld)->GetChgSet() ); SwAttrSetChg aOldSet( *static_cast(pOld) ); SwAttrSetChg aNewSet( *static_cast(pNew) ); while( true ) { UpdateAttr_( aOIter.GetCurItem(), aNIter.GetCurItem(), nInvFlags, &aOldSet, &aNewSet ); if( aNIter.IsAtEnd() ) break; aNIter.NextItem(); aOIter.NextItem(); } 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: // OD 22.09.2003 #i18732# - consider new option 'follow text flow' case RES_FOLLOW_TEXT_FLOW: { // ATTENTION: Always also change Action in ChgRePos()! rInvFlags |= 0x09; } break; // OD 2004-07-01 #i28701# - consider new option 'wrap influence on position' case RES_WRAP_INFLUENCE_ON_OBJPOS: { rInvFlags |= 0x89; } break; case RES_SURROUND: { // OD 2004-05-13 #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, PREP_FLY_ATTR_CHG ); // 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(static_cast(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(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(pOld), *static_cast(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(pOld)->pChangedFormat->GetULSpace(); aOld.Top( std::max( aOld.Top() - long(rUL.GetUpper()), 0L ) ); aOld.SSize().AdjustHeight(rUL.GetLower() ); const SvxLRSpaceItem &rLR = static_cast(pOld)->pChangedFormat->GetLRSpace(); aOld.Left ( std::max( aOld.Left() - rLR.GetLeft(), 0L ) ); aOld.SSize().AdjustWidth(rLR.GetRight() ); aNew.Union( aOld ); NotifyBackground( FindPageFrame(), aNew, PREP_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(static_cast(pNew)); else pOldFormatChg = const_cast(static_cast(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(static_cast(Lower())->GetNode()); if ( pNd->HasContour() ) pNd->SetContour( nullptr ); } else if( !Lower()->IsColumnFrame() ) { SwFrame* pFrame = GetLastLower(); if( pFrame->IsTextFrame() && static_cast(pFrame)->IsUndersized() ) pFrame->Prepare( PREP_ADJUST_FRM ); } } // #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(pNew); aOld.Top( std::max( aOld.Top() - long(rUL.GetUpper()), 0L ) ); aOld.SSize().AdjustHeight(rUL.GetLower() ); } else { const SvxLRSpaceItem &rLR = *static_cast(pNew); aOld.Left ( std::max( aOld.Left() - rLR.GetLeft(), 0L ) ); aOld.SSize().AdjustWidth(rLR.GetRight() ); } } aNew.Union( aOld ); NotifyBackground( FindPageFrame(), aNew, PREP_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(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(pNew)->GetMap() && static_cast(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(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 ); } SAL_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{}); 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(GetAnchorFrame()); TextFrameIndex const nOfs(pAutoFrame->MapModelToViewPos( *pFormat->GetAnchor().GetContentAnchor())); while( pAutoFrame->GetFollow() && pAutoFrame->GetFollow()->GetOfst() <= nOfs ) { if( pAutoFrame == GetAnchorFrame() ) nTmpY += pAutoFrame->GetRelPos().Y(); nTmpY -= pAutoFrame->GetUpper()->getFramePrintArea().Height(); pAutoFrame = pAutoFrame->GetFollow(); } nTmpY = static_cast(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(GetAnchorFrame()); TextFrameIndex const nOfs(pAutoFrame->MapModelToViewPos( *pFormat->GetAnchor().GetContentAnchor())); while( pAutoFrame->GetFollow() && pAutoFrame->GetFollow()->GetOfst() <= nOfs ) pAutoFrame = pAutoFrame->GetFollow(); } nTmpX -= static_cast(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( pShape) ) { // The shape is a customshape: then inform it about the calculated fly size. Size aSize(aRectFnSet.GetWidth(getFrameArea()), aRectFnSet.GetHeight(getFrameArea())); 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() != ATT_FIX_SIZE ) { // #i9046# Autowidth for fly frames const SwTwips nAutoWidth = lcl_CalcAutoWidth( *this ); if ( nAutoWidth ) { if( ATT_MIN_SIZE == 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(); } // OD 14.03.2003 #i11760# - change parameter : type ; // default value = false. // OD 14.03.2003 #i11760# - add new parameter with // default value = false. // OD 11.04.2003 #108824# - new parameter was used by method // to avoid follow formatting // for text frames. But, unformatted follows causes // problems in method , // which assumes that the follows are formatted. // Thus, no longer used by . void CalcContent( SwLayoutFrame *pLay, bool bNoColl ) { vcl::RenderContext* pRenderContext = pLay->getRootFrame()->GetCurrShell()->GetOut(); SwSectionFrame* pSect; bool bCollect = false; if( pLay->IsSctFrame() ) { pSect = static_cast(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( PREP_FIXSIZE_CHG ); pFrame->InvalidateSize_(); } if ( pFrame->IsTabFrame() ) { static_cast(pFrame)->m_bCalcLowers = true; // OD 26.08.2003 #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(pFrame)->IsFollow() && ( !pSect || pSect == pFrame->FindSctFrame() ) ) { static_cast(pFrame)->m_bLockBackMove = true; } } { SwFrameDeleteGuard aDeletePageGuard(pSect ? pSect->FindPageFrame() : nullptr); SwFrameDeleteGuard aDeleteGuard(pSect); pFrame->Calc(pRenderContext); } // OD 14.03.2003 #i11760# - reset control flag for follow format. if ( pFrame->IsTextFrame() ) { static_cast(pFrame)->AllowFollowFormat(); } // #111937# The keep-attribute can cause the position // of the prev to be invalid: // OD 2004-03-15 #116560# - 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() ) && 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]; // 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; } // OD 2004-05-17 #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(pFrame)->IsFollow() ) static_cast(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(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(pFrame)->IsAnFollow( pSect ) ) ) { pFrame = static_cast(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 ); } // OD 2004-03-23 #i26791# void SwFlyFrame::MakeObjPos() { if ( !isFrameAreaPositionValid() ) { vcl::RenderContext* pRenderContext = getRootFrame()->GetCurrShell()->GetOut(); setFrameAreaPositionValid(true); // OD 29.10.2003 #113049# - 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); // OD 31.07.2003 #110978# - 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; 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_(); } 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 . // 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 // for the lower frame, which initiated this grow. const bool bOldFormatHeightOnly = m_bFormatHeightOnly; const SwFormatFrameSize& rFrameSz = GetFormat()->GetFrameSize(); if ( rFrameSz.GetWidthSizeType() != ATT_FIX_SIZE ) { m_bFormatHeightOnly = true; } SwViewShell* pSh = getRootFrame()->GetCurrShell(); if (pSh) { static_cast(this)->SetNoMoveOnCheckClip( true ); static_cast(this)->SwFlyFreeFrame::MakeAll(pSh->GetOut()); static_cast(this)->SetNoMoveOnCheckClip( false ); } // #i55416# if ( rFrameSz.GetWidthSizeType() != ATT_FIX_SIZE ) { 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 . // 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 // for the lower frame, which initiated this shrink. const bool bOldFormatHeightOnly = m_bFormatHeightOnly; const SwFormatFrameSize& rFrameSz = GetFormat()->GetFrameSize(); if ( rFrameSz.GetWidthSizeType() != ATT_FIX_SIZE ) { m_bFormatHeightOnly = true; } static_cast(this)->SetNoMoveOnCheckClip( true ); static_cast(this)->SwFlyFreeFrame::MakeAll(getRootFrame()->GetCurrShell()->GetOut()); static_cast(this)->SetNoMoveOnCheckClip( false ); // #i55416# if ( rFrameSz.GetWidthSizeType() != ATT_FIX_SIZE ) { 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(this) && Lower() && dynamic_cast(Lower()) && static_cast(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(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( &_rNewObj) == nullptr ) { OSL_FAIL( "SwFrame::AppendDrawObj(..) - anchored object of unexpected type -> object not appended" ); return; } if ( dynamic_cast(_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(::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( pAnchoredObj) != nullptr ) { SwFlyFrame* pFly = static_cast(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( pObj) != nullptr ) { SwFlyFrame* pFly = static_cast(pObj); if ( pFly->getFrameArea().Left() == FAR_AWAY ) continue; if ( pFly->IsAnLower( this ) ) continue; // #i26945# - use 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( pObj) != nullptr, " 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(pFrame) ); } if ( pFrame->IsTextFrame() ) { nMin = const_cast(static_cast(pFrame))->CalcFitToContent(); const SvxLRSpaceItem &rSpace = static_cast(pFrame)->GetTextNodeForParaProps()->GetSwAttrSet().GetLRSpace(); if (!static_cast(pFrame)->IsLocked()) nMin += rSpace.GetRight() + rSpace.GetTextLeft() + rSpace.GetTextFirstLineOfst(); } else if ( pFrame->IsTabFrame() ) { const SwFormatFrameSize& rTableFormatSz = static_cast(pFrame)->GetTable()->GetFrameFormat()->GetFrameSize(); if ( USHRT_MAX == rTableFormatSz.GetSize().Width() || text::HoriOrientation::NONE == static_cast(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; } /// OD 16.04.2003 #i13147# - If called for paint and the 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(static_cast(static_cast(Lower())->GetNode())); // OD 16.04.2003 #i13147# - determine instead of // in order to avoid load of graphic, if contains a graphic // node and method is called for paint. std::unique_ptr 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 ."); if (pGrfObj->GetType() != GraphicType::NONE) { if( !pNd->HasContour() ) { // OD 16.04.2003 #i13147# - no for a graphic // during paint. Thus, return (value of should be ). if ( pGrfNd && _bForPaint ) { OSL_FAIL( "SwFlyFrame::GetContour() - No Contour found at 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(Lower())->GetGrfArea( aClip, &aOrig ); // OD 16.04.2003 #i13147# - copy method code // 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(aOrig.Width()) / aOrgSize.Width(); double fScaleY = static_cast(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 ) ); } } } } // OD 17.04.2003 #i13147# - destroy created . 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; } // OD 2004-03-25 #i26791# const SwVirtFlyDrawObj* SwFlyFrame::GetVirtDrawObj() const { return static_cast(GetDrawObj()); } SwVirtFlyDrawObj* SwFlyFrame::GetVirtDrawObj() { return static_cast(DrawObj()); } // OD 2004-03-24 #i26791# - implementation of pure virtual method declared in // base class void SwFlyFrame::InvalidateObjPos() { InvalidatePos(); // #i68520# InvalidateObjRectWithSpaces(); } SwFrameFormat& SwFlyFrame::GetFrameFormat() { OSL_ENSURE( GetFormat(), " - missing frame format -> crash." ); return *GetFormat(); } const SwFrameFormat& SwFlyFrame::GetFrameFormat() const { OSL_ENSURE( GetFormat(), " - missing frame format -> crash." ); return *GetFormat(); } const SwRect SwFlyFrame::GetObjRect() const { return getFrameArea(); } // #i70122# // for Writer fly frames the bounding rectangle equals the object rectangles const 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 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& aVector, const SwFormat& rFormat ) { SwIterator 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(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(pFrame)->IsUndersized() ) // This TextFrame would like to be a bit larger nHeight += static_cast(pFrame)->GetParHeight() - aRectFnSet.GetHeight(pFrame->getFramePrintArea()); else if( pFrame->IsSctFrame() && static_cast(pFrame)->IsUndersized() ) nHeight += static_cast(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( pAnchoredObj) != nullptr ) { SwFlyFrame* pFly = static_cast(pAnchoredObj); // OD 06.11.2003 #i22305# - 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: */