diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 16:51:28 +0000 |
commit | 940b4d1848e8c70ab7642901a68594e8016caffc (patch) | |
tree | eb72f344ee6c3d9b80a7ecc079ea79e9fba8676d /sw/source/core/layout/flycnt.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-upstream.tar.xz libreoffice-upstream.zip |
Adding upstream version 1:7.0.4.upstream/1%7.0.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/layout/flycnt.cxx')
-rw-r--r-- | sw/source/core/layout/flycnt.cxx | 1463 |
1 files changed, 1463 insertions, 0 deletions
diff --git a/sw/source/core/layout/flycnt.cxx b/sw/source/core/layout/flycnt.cxx new file mode 100644 index 000000000..71f6dff77 --- /dev/null +++ b/sw/source/core/layout/flycnt.cxx @@ -0,0 +1,1463 @@ +/* -*- 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 <sal/log.hxx> +#include <svx/swframetypes.hxx> +#include <pagefrm.hxx> +#include <txtfrm.hxx> +#include <notxtfrm.hxx> +#include <doc.hxx> +#include <pam.hxx> +#include <IDocumentUndoRedo.hxx> +#include <IDocumentSettingAccess.hxx> +#include <IDocumentDrawModelAccess.hxx> +#include <frmtool.hxx> +#include <dflyobj.hxx> +#include <hints.hxx> +#include <fmtanchr.hxx> +#include <fmtornt.hxx> +#include <fmtfsize.hxx> +#include <fmtsrnd.hxx> +#include <txatbase.hxx> + +#include <tabfrm.hxx> +#include <flyfrms.hxx> +#include <crstate.hxx> +#include <sectfrm.hxx> + +#include <tocntntanchoredobjectposition.hxx> +#include <sortedobjs.hxx> +#include <layouter.hxx> +#include "objectformattertxtfrm.hxx" +#include <HandleAnchorNodeChg.hxx> +#include <ndtxt.hxx> + +using namespace ::com::sun::star; + +namespace +{ + +SwTwips lcl_GetTopForObjPos(const SwContentFrame* pCnt, const bool bVert, const bool bVertL2R) +{ + if ( bVert ) + { + SwTwips aResult = pCnt->getFrameArea().Left(); + if ( bVertL2R ) + aResult += pCnt->GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid(); + else + aResult += pCnt->getFrameArea().Width() - pCnt->GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid(); + return aResult; + } + else + return pCnt->getFrameArea().Top() + pCnt->GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid(); +} + +} + +SwFlyAtContentFrame::SwFlyAtContentFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch ) : + SwFlyFreeFrame( pFormat, pSib, pAnch ) +{ + m_bAtCnt = true; + m_bAutoPosition = (RndStdIds::FLY_AT_CHAR == pFormat->GetAnchor().GetAnchorId()); +} + +// #i28701# + +void SwFlyAtContentFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew ) +{ + const SwFormatAnchor *pAnch = nullptr; + + if (pNew) + { + const sal_uInt16 nWhich = pNew->Which(); + if( RES_ATTRSET_CHG == nWhich && SfxItemState::SET == + static_cast<const SwAttrSetChg*>(pNew)->GetChgSet()->GetItemState( RES_ANCHOR, false, + reinterpret_cast<const SfxPoolItem**>(&pAnch) )) + ; // The anchor pointer is set at GetItemState! + + else if( RES_ANCHOR == nWhich ) + { + //Change anchor, I move myself to a new place. + //The anchor type must not change, this is only possible using + //SwFEShell. + pAnch = static_cast<const SwFormatAnchor*>(pNew); + } + } + + if( pAnch ) + { + OSL_ENSURE( pAnch->GetAnchorId() == GetFormat()->GetAnchor().GetAnchorId(), + "Illegal change of anchor type. " ); + + //Unregister, get hold of a new anchor and attach it + SwRect aOld( GetObjRectWithSpaces() ); + SwPageFrame *pOldPage = FindPageFrame(); + const SwFrame *pOldAnchor = GetAnchorFrame(); + SwContentFrame *pContent = const_cast<SwContentFrame*>(static_cast<const SwContentFrame*>(GetAnchorFrame())); + AnchorFrame()->RemoveFly( this ); + + const bool bBodyFootnote = (pContent->IsInDocBody() || pContent->IsInFootnote()); + + // Search the new anchor using the NodeIdx; the relation between old + // and new NodeIdx determines the search direction + const SwNodeIndex aNewIdx( pAnch->GetContentAnchor()->nNode ); + SwNodeIndex aOldIdx( pContent->IsTextFrame() + // sw_redlinehide: can pick any node here, the compare with + // FrameContainsNode should catch it + ? *static_cast<SwTextFrame *>(pContent)->GetTextNodeFirst() + : *static_cast<SwNoTextFrame *>(pContent)->GetNode() ); + + //fix: depending on which index was smaller, searching in the do-while + //loop previously was done forward or backwards respectively. This however + //could lead to an infinite loop. To at least avoid the loop, searching + //is now done in only one direction. Getting hold of a frame from the node + //is still possible if the new anchor could not be found. Chances are + //good that this will be the correct one. + // consider the case that at found anchor frame candidate already a + // fly frame of the given fly format is registered. + // consider, that <pContent> is the already + // the new anchor frame. + bool bFound( FrameContainsNode(*pContent, aNewIdx.GetIndex()) ); + const bool bNext = !bFound && aOldIdx < aNewIdx; + while ( pContent && !bFound ) + { + do + { + if ( bNext ) + pContent = pContent->GetNextContentFrame(); + else + pContent = pContent->GetPrevContentFrame(); + } while ( pContent && + ( bBodyFootnote != ( pContent->IsInDocBody() || + pContent->IsInFootnote() ) ) ); + if ( pContent ) + bFound = FrameContainsNode(*pContent, aNewIdx.GetIndex()); + + // check, if at found anchor frame candidate already a fly frame + // of the given fly frame format is registered. + if (bFound && pContent && pContent->GetDrawObjs()) + { + SwFrameFormat* pMyFlyFrameFormat( &GetFrameFormat() ); + SwSortedObjs &rObjs = *pContent->GetDrawObjs(); + for(SwAnchoredObject* rObj : rObjs) + { + SwFlyFrame* pFlyFrame = dynamic_cast<SwFlyFrame*>(rObj); + if ( pFlyFrame && + &(pFlyFrame->GetFrameFormat()) == pMyFlyFrameFormat ) + { + bFound = false; + break; + } + } + } + } + if ( !pContent ) + { + SwContentNode *pNode = aNewIdx.GetNode().GetContentNode(); + std::pair<Point, bool> const tmp(pOldAnchor->getFrameArea().Pos(), false); + pContent = pNode->getLayoutFrame(getRootFrame(), nullptr, &tmp); + OSL_ENSURE( pContent, "New anchor not found" ); + } + //Flys are never attached to a follow, but always on the master which + //we are going to search now. + SwContentFrame* pFlow = pContent; + while ( pFlow->IsFollow() ) + pFlow = pFlow->FindMaster(); + pContent = pFlow; + + //and *puff* it's attached... + pContent->AppendFly( this ); + if ( pOldPage && pOldPage != FindPageFrame() ) + NotifyBackground( pOldPage, aOld, PrepareHint::FlyFrameLeave ); + + //Fix(3495) + InvalidatePos_(); + InvalidatePage(); + SetNotifyBack(); + // #i28701# - reset member <maLastCharRect> and + // <mnLastTopOfLine> for to-character anchored objects. + ClearCharRectAndTopOfLine(); + } + else + SwFlyFrame::Modify( pOld, pNew ); +} + +//We need some helper classes to monitor the oscillation and a few functions +//to not get lost. + +namespace { + +// #i3317# - re-factoring of the position stack +class SwOszControl +{ + static const SwFlyFrame *pStack1; + static const SwFlyFrame *pStack2; + static const SwFlyFrame *pStack3; + static const SwFlyFrame *pStack4; + static const SwFlyFrame *pStack5; + + const SwFlyFrame *pFly; + std::vector<Point> maObjPositions; + +public: + explicit SwOszControl( const SwFlyFrame *pFrame ); + ~SwOszControl(); + bool ChkOsz(); + static bool IsInProgress( const SwFlyFrame *pFly ); +}; + +} + +const SwFlyFrame *SwOszControl::pStack1 = nullptr; +const SwFlyFrame *SwOszControl::pStack2 = nullptr; +const SwFlyFrame *SwOszControl::pStack3 = nullptr; +const SwFlyFrame *SwOszControl::pStack4 = nullptr; +const SwFlyFrame *SwOszControl::pStack5 = nullptr; + +SwOszControl::SwOszControl( const SwFlyFrame *pFrame ) + : pFly( pFrame ) +{ + if ( !SwOszControl::pStack1 ) + SwOszControl::pStack1 = pFly; + else if ( !SwOszControl::pStack2 ) + SwOszControl::pStack2 = pFly; + else if ( !SwOszControl::pStack3 ) + SwOszControl::pStack3 = pFly; + else if ( !SwOszControl::pStack4 ) + SwOszControl::pStack4 = pFly; + else if ( !SwOszControl::pStack5 ) + SwOszControl::pStack5 = pFly; +} + +SwOszControl::~SwOszControl() +{ + if ( SwOszControl::pStack1 == pFly ) + SwOszControl::pStack1 = nullptr; + else if ( SwOszControl::pStack2 == pFly ) + SwOszControl::pStack2 = nullptr; + else if ( SwOszControl::pStack3 == pFly ) + SwOszControl::pStack3 = nullptr; + else if ( SwOszControl::pStack4 == pFly ) + SwOszControl::pStack4 = nullptr; + else if ( SwOszControl::pStack5 == pFly ) + SwOszControl::pStack5 = nullptr; + // #i3317# + maObjPositions.clear(); +} + +bool SwOszControl::IsInProgress( const SwFlyFrame *pFly ) +{ + if ( SwOszControl::pStack1 && !pFly->IsLowerOf( SwOszControl::pStack1 ) ) + return true; + if ( SwOszControl::pStack2 && !pFly->IsLowerOf( SwOszControl::pStack2 ) ) + return true; + if ( SwOszControl::pStack3 && !pFly->IsLowerOf( SwOszControl::pStack3 ) ) + return true; + if ( SwOszControl::pStack4 && !pFly->IsLowerOf( SwOszControl::pStack4 ) ) + return true; + if ( SwOszControl::pStack5 && !pFly->IsLowerOf( SwOszControl::pStack5 ) ) + return true; + return false; +} + +bool SwOszControl::ChkOsz() +{ + bool bOscillationDetected = false; + + if ( maObjPositions.size() == 20 ) + { + // #i3317# position stack is full -> oscillation + bOscillationDetected = true; + } + else + { + Point aNewObjPos = pFly->GetObjRect().Pos(); + for ( auto const & pt : maObjPositions ) + { + if ( aNewObjPos == pt ) + { + // position already occurred -> oscillation + bOscillationDetected = true; + break; + } + } + if ( !bOscillationDetected ) + { + maObjPositions.push_back( aNewObjPos ); + } + } + + return bOscillationDetected; +} + +/** +|* With a paragraph-anchored fly it's absolutely possible that +|* the anchor reacts to changes of the fly. To this reaction the fly must +|* certainly react too. Sadly this can lead to oscillations; for example the +|* fly wants to go down therefore the content can go up - this leads to a +|* smaller TextFrame thus the fly needs to go up again whereby the text will +|* get pushed down... +|* To avoid such oscillations, a small position stack is built. If the fly +|* reaches a position which it already had once, the action is stopped. +|* To not run into problems, the stack is designed to hold five positions. +|* If the stack flows over, the action is stopped too. +|* Cancellation leads to the situation that the fly has a bad position in +|* the end. In case of cancellation, the frame is set to automatic top +|* alignment to not trigger a 'big oscillation' when calling from outside +|* again. +|*/ +void SwFlyAtContentFrame::MakeAll(vcl::RenderContext* pRenderContext) +{ + if ( !GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) ) + { + return; + } + + if ( !SwOszControl::IsInProgress( this ) && !IsLocked() && !IsColLocked() ) + { + // #i28701# - use new method <GetPageFrame()> + if( !GetPageFrame() && GetAnchorFrame() && GetAnchorFrame()->IsInFly() ) + { + SwFlyFrame* pFly = AnchorFrame()->FindFlyFrame(); + SwPageFrame *pTmpPage = pFly ? pFly->FindPageFrame() : nullptr; + if( pTmpPage ) + pTmpPage->AppendFlyToPage( this ); + } + // #i28701# - use new method <GetPageFrame()> + if( GetPageFrame() ) + { + bSetCompletePaintOnInvalidate = true; + { + SwFlyFrameFormat *pFormat = GetFormat(); + const SwFormatFrameSize &rFrameSz = GetFormat()->GetFrameSize(); + if( rFrameSz.GetHeightPercent() != SwFormatFrameSize::SYNCED && + rFrameSz.GetHeightPercent() >= 100 ) + { + pFormat->LockModify(); + SwFormatSurround aMain( pFormat->GetSurround() ); + if ( aMain.GetSurround() == css::text::WrapTextMode_NONE ) + { + aMain.SetSurround( css::text::WrapTextMode_THROUGH ); + pFormat->SetFormatAttr( aMain ); + } + pFormat->UnlockModify(); + } + } + + SwOszControl aOszCntrl( this ); + + // #i43255# + // #i50356# - format the anchor frame, which + // contains the anchor position. E.g., for at-character anchored + // object this can be the follow frame of the anchor frame. + const bool bFormatAnchor = + !static_cast<const SwTextFrame*>( GetAnchorFrameContainingAnchPos() )->IsAnyJoinLocked() && + !ConsiderObjWrapInfluenceOnObjPos() && + !ConsiderObjWrapInfluenceOfOtherObjs(); + + const SwFrame* pFooter = GetAnchorFrame()->FindFooterOrHeader(); + if( pFooter && !pFooter->IsFooterFrame() ) + pFooter = nullptr; + bool bOsz = false; + bool bExtra = Lower() && Lower()->IsColumnFrame(); + // #i3317# - boolean, to apply temporarily the + // 'straightforward positioning process' for the frame due to its + // overlapping with a previous column. + bool bConsiderWrapInfluenceDueToOverlapPrevCol( false ); + // #i35911# - boolean, to apply temporarily the + // 'straightforward positioning process' for the frame due to fact + // that it causes the complete content of its layout environment + // to move forward. + // #i40444# - extend usage of this boolean: + // apply temporarily the 'straightforward positioning process' for + // the frame due to the fact that the frame clears the area for + // the anchor frame, thus it has to move forward. + bool bConsiderWrapInfluenceDueToMovedFwdAnchor( false ); + do { + SwRectFnSet aRectFnSet(this); + Point aOldPos( aRectFnSet.GetPos(getFrameArea()) ); + SwFlyFreeFrame::MakeAll(pRenderContext); + const bool bPosChgDueToOwnFormat = + aOldPos != aRectFnSet.GetPos(getFrameArea()); + // #i3317# + if ( !ConsiderObjWrapInfluenceOnObjPos() && + OverlapsPrevColumn() ) + { + bConsiderWrapInfluenceDueToOverlapPrevCol = true; + } + // #i28701# - no format of anchor frame, if + // wrapping style influence is considered on object positioning + if ( bFormatAnchor ) + { + SwTextFrame& rAnchPosAnchorFrame = + dynamic_cast<SwTextFrame&>(*GetAnchorFrameContainingAnchPos()); + // #i58182# - For the usage of new method + // <SwObjectFormatterTextFrame::CheckMovedFwdCondition(..)> + // to check move forward of anchor frame due to the object + // positioning it's needed to know, if the object is anchored + // at the master frame before the anchor frame is formatted. + const bool bAnchoredAtMaster(!rAnchPosAnchorFrame.IsFollow()); + + // #i56300# + // perform complete format of anchor text frame and its + // previous frames, which have become invalid due to the + // fly frame format. + SwObjectFormatterTextFrame::FormatAnchorFrameAndItsPrevs( rAnchPosAnchorFrame ); + // #i35911# + // #i40444# + // #i58182# - usage of new method + // <SwObjectFormatterTextFrame::CheckMovedFwdCondition(..)> + sal_uInt32 nToPageNum( 0 ); + bool bDummy( false ); + if ( SwObjectFormatterTextFrame::CheckMovedFwdCondition( + *this, GetPageFrame()->GetPhyPageNum(), + bAnchoredAtMaster, nToPageNum, bDummy ) ) + { + bConsiderWrapInfluenceDueToMovedFwdAnchor = true; + // mark anchor text frame + // directly, that it is moved forward by object positioning. + SwTextFrame* pAnchorTextFrame( static_cast<SwTextFrame*>(AnchorFrame()) ); + bool bInsert( true ); + sal_uInt32 nAnchorFrameToPageNum( 0 ); + const SwDoc& rDoc = *(GetFrameFormat().GetDoc()); + if ( SwLayouter::FrameMovedFwdByObjPos( + rDoc, *pAnchorTextFrame, nAnchorFrameToPageNum ) ) + { + if ( nAnchorFrameToPageNum < nToPageNum ) + SwLayouter::RemoveMovedFwdFrame( rDoc, *pAnchorTextFrame ); + else + bInsert = false; + } + if ( bInsert ) + { + SwLayouter::InsertMovedFwdFrame( rDoc, *pAnchorTextFrame, + nToPageNum ); + } + } + } + + if ( aOldPos != aRectFnSet.GetPos(getFrameArea()) || + ( !isFrameAreaPositionValid() && + ( pFooter || bPosChgDueToOwnFormat ) ) ) + { + bOsz = aOszCntrl.ChkOsz(); + + // special loop prevention for dedicated document: + if ( bOsz && + HasFixSize() && IsClipped() && + GetAnchorFrame()->GetUpper()->IsCellFrame() ) + { + SwFrameFormat* pFormat = GetFormat(); + const SwFormatFrameSize& rFrameSz = pFormat->GetFrameSize(); + if ( rFrameSz.GetWidthPercent() && + rFrameSz.GetHeightPercent() == SwFormatFrameSize::SYNCED ) + { + SwFormatSurround aSurround( pFormat->GetSurround() ); + if ( aSurround.GetSurround() == css::text::WrapTextMode_NONE ) + { + pFormat->LockModify(); + aSurround.SetSurround( css::text::WrapTextMode_THROUGH ); + pFormat->SetFormatAttr( aSurround ); + pFormat->UnlockModify(); + bOsz = false; + OSL_FAIL( "<SwFlyAtContentFrame::MakeAll()> - special loop prevention for dedicated document of b6403541 applied" ); + } + } + } + } + + if ( bExtra && Lower() && !Lower()->isFrameAreaPositionValid() ) + { + // If a multi column frame leaves invalid columns because of + // a position change, we loop once more and format + // our content using FormatWidthCols again. + InvalidateSize_(); + bExtra = false; // Ensure only one additional loop run + } + } while ( !isFrameAreaDefinitionValid() && !bOsz && + // #i3317# + !bConsiderWrapInfluenceDueToOverlapPrevCol && + // #i40444# + !bConsiderWrapInfluenceDueToMovedFwdAnchor && + GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) ); + + // #i3317# - instead of attribute change apply + // temporarily the 'straightforward positioning process'. + // #i80924# + // handle special case during splitting of table rows + if ( bConsiderWrapInfluenceDueToMovedFwdAnchor && + GetAnchorFrame()->IsInTab() && + GetAnchorFrame()->IsInFollowFlowRow() ) + { + const SwFrame* pCellFrame = GetAnchorFrame(); + while ( pCellFrame && !pCellFrame->IsCellFrame() ) + { + pCellFrame = pCellFrame->GetUpper(); + } + if ( pCellFrame ) + { + SwRectFnSet aRectFnSet(pCellFrame); + if ( aRectFnSet.GetTop(pCellFrame->getFrameArea()) == 0 && + aRectFnSet.GetHeight(pCellFrame->getFrameArea()) == 0 ) + { + bConsiderWrapInfluenceDueToMovedFwdAnchor = false; + } + } + } + if ( bOsz || bConsiderWrapInfluenceDueToOverlapPrevCol || + // #i40444# + bConsiderWrapInfluenceDueToMovedFwdAnchor ) + { + SetTmpConsiderWrapInfluence( true ); + SetRestartLayoutProcess( true ); + SetTmpConsiderWrapInfluenceOfOtherObjs(); + } + bSetCompletePaintOnInvalidate = false; + } + } +} + +/** method to determine, if a <MakeAll()> on the Writer fly frame is possible + + #i28701# +*/ +bool SwFlyAtContentFrame::IsFormatPossible() const +{ + return SwFlyFreeFrame::IsFormatPossible() && + !SwOszControl::IsInProgress( this ); +} + +namespace { + +class SwDistance +{ +public: + SwTwips nMain, nSub; + SwDistance() : nMain(0), nSub(0) { } + bool operator<( const SwDistance& rTwo ) const + { return nMain < rTwo.nMain || ( nMain == rTwo.nMain && nSub && + rTwo.nSub && nSub < rTwo.nSub ); } + bool operator<=( const SwDistance& rTwo ) const + { return nMain < rTwo.nMain || ( nMain == rTwo.nMain && ( !nSub || + !rTwo.nSub || nSub <= rTwo.nSub ) ); } +}; + +} + +static const SwFrame * lcl_CalcDownDist( SwDistance &rRet, + const Point &rPt, + const SwContentFrame *pCnt ) +{ + rRet.nSub = 0; + //If the point stays inside the Cnt everything is clear already; the Content + //automatically has a distance of 0. + if ( pCnt->getFrameArea().IsInside( rPt ) ) + { + rRet.nMain = 0; + return pCnt; + } + else + { + const SwLayoutFrame *pUp = pCnt->IsInTab() ? pCnt->FindTabFrame()->GetUpper() : pCnt->GetUpper(); + // single column sections need to interconnect to their upper + while( pUp->IsSctFrame() ) + pUp = pUp->GetUpper(); + const bool bVert = pUp->IsVertical(); + + const bool bVertL2R = pUp->IsVertLR(); + + //Follow the text flow. + // #i70582# + // --> OD 2009-03-05 - adopted for Support for Classical Mongolian Script + const SwTwips nTopForObjPos = lcl_GetTopForObjPos(pCnt, bVert, bVertL2R); + if ( pUp->getFrameArea().IsInside( rPt ) ) + { + // <rPt> point is inside environment of given content frame + // #i70582# + if( bVert ) + { + if ( bVertL2R ) + rRet.nMain = rPt.X() - nTopForObjPos; + else + rRet.nMain = nTopForObjPos - rPt.X(); + } + else + rRet.nMain = rPt.Y() - nTopForObjPos; + return pCnt; + } + else if ( rPt.Y() <= pUp->getFrameArea().Top() ) + { + // <rPt> point is above environment of given content frame + // correct for vertical layout? + rRet.nMain = LONG_MAX; + } + else if( rPt.X() < pUp->getFrameArea().Left() && + rPt.Y() <= ( bVert ? pUp->getFrameArea().Top() : pUp->getFrameArea().Bottom() ) ) + { + // <rPt> point is left of environment of given content frame + // seems not to be correct for vertical layout!? + const SwFrame *pLay = pUp->GetLeaf( MAKEPAGE_NONE, false, pCnt ); + if( !pLay || + (bVert && (pLay->getFrameArea().Top() + pLay->getFramePrintArea().Bottom()) <rPt.Y())|| + (!bVert && (pLay->getFrameArea().Left() + pLay->getFramePrintArea().Right())<rPt.X()) ) + { + // <rPt> point is in left border of environment + // #i70582# + if( bVert ) + { + if ( bVertL2R ) + rRet.nMain = rPt.X() - nTopForObjPos; + else + rRet.nMain = nTopForObjPos - rPt.X(); + } + else + rRet.nMain = rPt.Y() - nTopForObjPos; + return pCnt; + } + else + rRet.nMain = LONG_MAX; + } + else + { + rRet.nMain = bVert + ? ( bVertL2R + ? ( (pUp->getFrameArea().Left() + pUp->getFramePrintArea().Right()) - nTopForObjPos ) + : ( nTopForObjPos - (pUp->getFrameArea().Left() + pUp->getFramePrintArea().Left() ) ) ) + : ( (pUp->getFrameArea().Top() + pUp->getFramePrintArea().Bottom()) - nTopForObjPos ); + + const SwFrame *pPre = pCnt; + const SwFrame *pLay = pUp->GetLeaf( MAKEPAGE_NONE, true, pCnt ); + SwTwips nFrameTop = 0; + SwTwips nPrtHeight = 0; + bool bSct = false; + const SwSectionFrame *pSect = pUp->FindSctFrame(); + if( pSect ) + { + rRet.nSub = rRet.nMain; + rRet.nMain = 0; + } + if( pSect && !pSect->IsAnLower( pLay ) ) + { + bSct = false; + const SwSectionFrame* pNxtSect = pLay ? pLay->FindSctFrame() : nullptr; + if (pSect->IsAnFollow(pNxtSect) && pLay) + { + if( pLay->IsVertical() ) + { + if ( pLay->IsVertLR() ) + nFrameTop = pLay->getFrameArea().Left(); + else + nFrameTop = pLay->getFrameArea().Left() + pLay->getFrameArea().Width(); + nPrtHeight = pLay->getFramePrintArea().Width(); + } + else + { + nFrameTop = pLay->getFrameArea().Top(); + nPrtHeight = pLay->getFramePrintArea().Height(); + } + pSect = pNxtSect; + } + else + { + pLay = pSect->GetUpper(); + if( pLay->IsVertical() ) + { + if ( pLay->IsVertLR() ) + { + nFrameTop = pSect->getFrameArea().Right(); + nPrtHeight = pLay->getFrameArea().Left() + pLay->getFramePrintArea().Left() + + pLay->getFramePrintArea().Width() - pSect->getFrameArea().Left() + - pSect->getFrameArea().Width(); + } + else + { + nFrameTop = pSect->getFrameArea().Left(); + nPrtHeight = pSect->getFrameArea().Left() - pLay->getFrameArea().Left() + - pLay->getFramePrintArea().Left(); + } + } + else + { + nFrameTop = pSect->getFrameArea().Bottom(); + nPrtHeight = pLay->getFrameArea().Top() + pLay->getFramePrintArea().Top() + + pLay->getFramePrintArea().Height() - pSect->getFrameArea().Top() + - pSect->getFrameArea().Height(); + } + pSect = nullptr; + } + } + else if( pLay ) + { + if( pLay->IsVertical() ) + { + if ( pLay->IsVertLR() ) + { + nFrameTop = pLay->getFrameArea().Left(); + nPrtHeight = pLay->getFramePrintArea().Width(); + } + else + { + nFrameTop = pLay->getFrameArea().Left() + pLay->getFrameArea().Width(); + nPrtHeight = pLay->getFramePrintArea().Width(); + } + } + else + { + nFrameTop = pLay->getFrameArea().Top(); + nPrtHeight = pLay->getFramePrintArea().Height(); + } + bSct = nullptr != pSect; + } + while ( pLay && !pLay->getFrameArea().IsInside( rPt ) && + ( pLay->getFrameArea().Top() <= rPt.Y() || pLay->IsInFly() || + ( pLay->IsInSct() && + pLay->FindSctFrame()->GetUpper()->getFrameArea().Top() <= rPt.Y())) ) + { + if ( pLay->IsFootnoteContFrame() ) + { + if ( !static_cast<const SwLayoutFrame*>(pLay)->Lower() ) + { + SwFrame *pDel = const_cast<SwFrame*>(pLay); + pDel->Cut(); + SwFrame::DestroyFrame(pDel); + return pPre; + } + return nullptr; + } + else + { + if( bSct || pSect ) + rRet.nSub += nPrtHeight; + else + rRet.nMain += nPrtHeight; + pPre = pLay; + pLay = pLay->GetLeaf( MAKEPAGE_NONE, true, pCnt ); + if( pSect && !pSect->IsAnLower( pLay ) ) + { // If we're leaving a SwSectionFrame, the next Leaf-Frame + // is the part of the upper below the SectionFrame. + const SwSectionFrame* pNxtSect = pLay ? + pLay->FindSctFrame() : nullptr; + bSct = false; + if (pLay && pSect->IsAnFollow(pNxtSect)) + { + pSect = pNxtSect; + if( pLay->IsVertical() ) + { + if ( pLay->IsVertLR() ) + { + nFrameTop = pLay->getFrameArea().Left(); + nPrtHeight = pLay->getFramePrintArea().Width(); + } + else + { + nFrameTop = pLay->getFrameArea().Left() + pLay->getFrameArea().Width(); + nPrtHeight = pLay->getFramePrintArea().Width(); + } + } + else + { + nFrameTop = pLay->getFrameArea().Top(); + nPrtHeight = pLay->getFramePrintArea().Height(); + } + } + else + { + pLay = pSect->GetUpper(); + if( pLay->IsVertical() ) + { + if ( pLay->IsVertLR() ) + { + nFrameTop = pSect->getFrameArea().Right(); + nPrtHeight = pLay->getFrameArea().Left()+pLay->getFramePrintArea().Left() + + pLay->getFramePrintArea().Width() - pSect->getFrameArea().Left() + - pSect->getFrameArea().Width(); + } + else + { + nFrameTop = pSect->getFrameArea().Left(); + nPrtHeight = pSect->getFrameArea().Left() - + pLay->getFrameArea().Left() - pLay->getFramePrintArea().Left(); + } + } + else + { + nFrameTop = pSect->getFrameArea().Bottom(); + nPrtHeight = pLay->getFrameArea().Top()+pLay->getFramePrintArea().Top() + + pLay->getFramePrintArea().Height() - pSect->getFrameArea().Top() + - pSect->getFrameArea().Height(); + } + pSect = nullptr; + } + } + else if( pLay ) + { + if( pLay->IsVertical() ) + { + if ( pLay->IsVertLR() ) + { + nFrameTop = pLay->getFrameArea().Left(); + nPrtHeight = pLay->getFramePrintArea().Width(); + } + else + { + nFrameTop = pLay->getFrameArea().Left() + pLay->getFrameArea().Width(); + nPrtHeight = pLay->getFramePrintArea().Width(); + } + } + else + { + nFrameTop = pLay->getFrameArea().Top(); + nPrtHeight = pLay->getFramePrintArea().Height(); + } + bSct = nullptr != pSect; + } + } + } + if ( pLay ) + { + if ( pLay->getFrameArea().IsInside( rPt ) ) + { + SwTwips nDiff = pLay->IsVertical() ? ( pLay->IsVertLR() ? ( rPt.X() - nFrameTop ) : ( nFrameTop - rPt.X() ) ) + : ( rPt.Y() - nFrameTop ); + if( bSct || pSect ) + rRet.nSub += nDiff; + else + rRet.nMain += nDiff; + } + if ( pLay->IsFootnoteContFrame() && !static_cast<const SwLayoutFrame*>(pLay)->Lower() ) + { + SwFrame *pDel = const_cast<SwFrame*>(pLay); + pDel->Cut(); + SwFrame::DestroyFrame(pDel); + return nullptr; + } + return pLay; + } + else + rRet.nMain = LONG_MAX; + } + } + return nullptr; +} + +static sal_uInt64 lcl_FindCntDiff( const Point &rPt, const SwLayoutFrame *pLay, + const SwContentFrame *& rpCnt, + const bool bBody, const bool bFootnote ) +{ + // Searches below pLay the nearest Cnt to the point. The reference point of + //the Contents is always the left upper corner. + //The Cnt should preferably be above the point. + + rpCnt = nullptr; + sal_uInt64 nDistance = SAL_MAX_UINT64; + sal_uInt64 nNearest = SAL_MAX_UINT64; + const SwContentFrame *pCnt = pLay ? pLay->ContainsContent() : nullptr; + + while ( pCnt && (bBody != pCnt->IsInDocBody() || bFootnote != pCnt->IsInFootnote())) + { + pCnt = pCnt->GetNextContentFrame(); + if ( !pLay->IsAnLower( pCnt ) ) + pCnt = nullptr; + } + const SwContentFrame *pNearest = pCnt; + if ( pCnt ) + { + do + { + //Calculate the distance between those two points. + //'delta' X^2 + 'delta' Y^2 = 'distance'^2 + sal_uInt64 dX = std::max( pCnt->getFrameArea().Left(), rPt.X() ) - + std::min( pCnt->getFrameArea().Left(), rPt.X() ), + dY = std::max( pCnt->getFrameArea().Top(), rPt.Y() ) - + std::min( pCnt->getFrameArea().Top(), rPt.Y() ); + // square of the difference will do fine here + const sal_uInt64 nDiff = (dX * dX) + (dY * dY); + if ( pCnt->getFrameArea().Top() <= rPt.Y() ) + { + if ( nDiff < nDistance ) + { + //This one is the nearer one + nDistance = nNearest = nDiff; + rpCnt = pNearest = pCnt; + } + } + else if ( nDiff < nNearest ) + { + nNearest = nDiff; + pNearest = pCnt; + } + pCnt = pCnt->GetNextContentFrame(); + while ( pCnt && + (bBody != pCnt->IsInDocBody() || bFootnote != pCnt->IsInFootnote())) + pCnt = pCnt->GetNextContentFrame(); + + } while ( pCnt && pLay->IsAnLower( pCnt ) ); + } + if (nDistance == SAL_MAX_UINT64) + { rpCnt = pNearest; + return nNearest; + } + return nDistance; +} + +static const SwContentFrame * lcl_FindCnt( const Point &rPt, const SwContentFrame *pCnt, + const bool bBody, const bool bFootnote ) +{ + //Starting from pCnt searches the ContentFrame whose left upper corner is the + //nearest to the point. + //Always returns a ContentFrame. + + //First the nearest Content inside the page which contains the Content is + //searched. Starting from this page the pages in both directions need to + //be considered. If possible a Content is returned whose Y-position is + //above the point. + const SwContentFrame *pRet, *pNew; + const SwLayoutFrame *pLay = pCnt->FindPageFrame(); + sal_uInt64 nDist; // not sure if a sal_Int32 would be enough? + + nDist = ::lcl_FindCntDiff( rPt, pLay, pNew, bBody, bFootnote ); + if ( pNew ) + pRet = pNew; + else + { pRet = pCnt; + nDist = SAL_MAX_UINT64; + } + const SwContentFrame *pNearest = pRet; + sal_uInt64 nNearest = nDist; + + if ( pLay ) + { + const SwLayoutFrame *pPge = pLay; + sal_uInt64 nOldNew = SAL_MAX_UINT64; + for ( int i = 0; pPge->GetPrev() && (i < 3); ++i ) + { + pPge = static_cast<const SwLayoutFrame*>(pPge->GetPrev()); + const sal_uInt64 nNew = ::lcl_FindCntDiff( rPt, pPge, pNew, bBody, bFootnote ); + if ( nNew < nDist ) + { + if ( pNew->getFrameArea().Top() <= rPt.Y() ) + { + pRet = pNearest = pNew; + nDist = nNearest = nNew; + } + else if ( nNew < nNearest ) + { + pNearest = pNew; + nNearest = nNew; + } + } + else if (nOldNew != SAL_MAX_UINT64 && nNew > nOldNew) + break; + else + nOldNew = nNew; + + } + pPge = pLay; + nOldNew = SAL_MAX_UINT64; + for ( int j = 0; pPge->GetNext() && (j < 3); ++j ) + { + pPge = static_cast<const SwLayoutFrame*>(pPge->GetNext()); + const sal_uInt64 nNew = ::lcl_FindCntDiff( rPt, pPge, pNew, bBody, bFootnote ); + if ( nNew < nDist ) + { + if ( pNew->getFrameArea().Top() <= rPt.Y() ) + { + pRet = pNearest = pNew; + nDist = nNearest = nNew; + } + else if ( nNew < nNearest ) + { + pNearest = pNew; + nNearest = nNew; + } + } + else if (nOldNew != SAL_MAX_UINT64 && nNew > nOldNew) + break; + else + nOldNew = nNew; + } + } + if ( pRet->getFrameArea().Top() > rPt.Y() ) + return pNearest; + else + return pRet; +} + +static void lcl_PointToPrt( Point &rPoint, const SwFrame *pFrame ) +{ + SwRect aTmp( pFrame->getFramePrintArea() ); + aTmp += pFrame->getFrameArea().Pos(); + if ( rPoint.getX() < aTmp.Left() ) + rPoint.setX(aTmp.Left()); + else if ( rPoint.getX() > aTmp.Right() ) + rPoint.setX(aTmp.Right()); + if ( rPoint.getY() < aTmp.Top() ) + rPoint.setY(aTmp.Top()); + else if ( rPoint.getY() > aTmp.Bottom() ) + rPoint.setY(aTmp.Bottom()); + +} + +/** Searches an anchor for paragraph bound objects starting from pOldAnch. + * + * This is used to show anchors as well as changing anchors + * when dragging paragraph bound objects. + */ +const SwContentFrame *FindAnchor( const SwFrame *pOldAnch, const Point &rNew, + const bool bBodyOnly ) +{ + //Search the nearest Cnt around the given document position in the text + //flow. The given anchor is the starting Frame. + const SwContentFrame* pCnt; + if ( pOldAnch->IsContentFrame() ) + { + pCnt = static_cast<const SwContentFrame*>(pOldAnch); + } + else + { + Point aTmp( rNew ); + const SwLayoutFrame *pTmpLay = static_cast<const SwLayoutFrame*>(pOldAnch); + if( pTmpLay->IsRootFrame() ) + { + SwRect aTmpRect( aTmp, Size(0,0) ); + pTmpLay = static_cast<const SwLayoutFrame*>(::FindPage( aTmpRect, pTmpLay->Lower() )); + } + pCnt = pTmpLay->GetContentPos( aTmp, false, bBodyOnly ); + } + + //Take care to use meaningful ranges during search. This means to not enter + //or leave header/footer in this case. + const bool bBody = pCnt->IsInDocBody() || bBodyOnly; + const bool bFootnote = !bBodyOnly && pCnt->IsInFootnote(); + + Point aNew( rNew ); + if ( bBody ) + { + //#38848 drag from page margin into the body. + const SwFrame *pPage = pCnt->FindPageFrame(); + ::lcl_PointToPrt( aNew, pPage->GetUpper() ); + SwRect aTmp( aNew, Size( 0, 0 ) ); + pPage = ::FindPage( aTmp, pPage ); + ::lcl_PointToPrt( aNew, pPage ); + } + + if ( pCnt->IsInDocBody() == bBody && pCnt->getFrameArea().IsInside( aNew ) ) + return pCnt; + else if ( pOldAnch->IsInDocBody() || pOldAnch->IsPageFrame() ) + { + // Maybe the selected anchor is on the same page as the current anchor. + // With this we won't run into problems with the columns. + Point aTmp( aNew ); + const SwContentFrame *pTmp = pCnt->FindPageFrame()-> + GetContentPos( aTmp, false, true ); + if ( pTmp && pTmp->getFrameArea().IsInside( aNew ) ) + return pTmp; + } + + //Starting from the anchor we now search in both directions until we found + //the nearest one respectively. + //Not the direct distance is relevant but the distance which needs to be + //traveled through the text flow. + const SwContentFrame *pUpLst; + const SwContentFrame *pUpFrame = pCnt; + SwDistance nUp, nUpLst; + ::lcl_CalcDownDist( nUp, aNew, pUpFrame ); + SwDistance nDown = nUp; + bool bNegAllowed = true;// Make it possible to leave the negative section once. + do + { + pUpLst = pUpFrame; nUpLst = nUp; + pUpFrame = pUpLst->GetPrevContentFrame(); + while ( pUpFrame && + (bBody != pUpFrame->IsInDocBody() || bFootnote != pUpFrame->IsInFootnote())) + pUpFrame = pUpFrame->GetPrevContentFrame(); + if ( pUpFrame ) + { + ::lcl_CalcDownDist( nUp, aNew, pUpFrame ); + //It makes sense to search further, if the distance grows inside + //a table. + if ( pUpLst->IsInTab() && pUpFrame->IsInTab() ) + { + while ( pUpFrame && ((nUpLst < nUp && pUpFrame->IsInTab()) || + bBody != pUpFrame->IsInDocBody()) ) + { + pUpFrame = pUpFrame->GetPrevContentFrame(); + if ( pUpFrame ) + ::lcl_CalcDownDist( nUp, aNew, pUpFrame ); + } + } + } + if ( !pUpFrame ) + nUp.nMain = LONG_MAX; + if ( nUp.nMain >= 0 && LONG_MAX != nUp.nMain ) + { + bNegAllowed = false; + if ( nUpLst.nMain < 0 ) //don't take the wrong one, if the value + //just changed from negative to positive. + { pUpLst = pUpFrame; + nUpLst = nUp; + } + } + } while ( pUpFrame && ( ( bNegAllowed && nUp.nMain < 0 ) || ( nUp <= nUpLst ) ) ); + + const SwContentFrame *pDownLst; + const SwContentFrame *pDownFrame = pCnt; + SwDistance nDownLst; + if ( nDown.nMain < 0 ) + nDown.nMain = LONG_MAX; + do + { + pDownLst = pDownFrame; nDownLst = nDown; + pDownFrame = pDownLst->GetNextContentFrame(); + while ( pDownFrame && + (bBody != pDownFrame->IsInDocBody() || bFootnote != pDownFrame->IsInFootnote())) + pDownFrame = pDownFrame->GetNextContentFrame(); + if ( pDownFrame ) + { + ::lcl_CalcDownDist( nDown, aNew, pDownFrame ); + if ( nDown.nMain < 0 ) + nDown.nMain = LONG_MAX; + //It makes sense to search further, if the distance grows inside + //a table. + if ( pDownLst->IsInTab() && pDownFrame->IsInTab() ) + { + while ( pDownFrame && ( ( nDown.nMain != LONG_MAX && pDownFrame->IsInTab()) || bBody != pDownFrame->IsInDocBody() ) ) + { + pDownFrame = pDownFrame->GetNextContentFrame(); + if ( pDownFrame ) + ::lcl_CalcDownDist( nDown, aNew, pDownFrame ); + if ( nDown.nMain < 0 ) + nDown.nMain = LONG_MAX; + } + } + } + if ( !pDownFrame ) + nDown.nMain = LONG_MAX; + + } while ( pDownFrame && nDown <= nDownLst && + nDown.nMain != LONG_MAX && nDownLst.nMain != LONG_MAX ); + + //If we couldn't find one in both directions, we'll search the Content whose + //left upper corner is the nearest to the point. Such a situation may + //happen, if the point doesn't lay in the text flow but in any margin. + if ( nDownLst.nMain == LONG_MAX && nUpLst.nMain == LONG_MAX ) + { + // If an OLE objects, which is contained in a fly frame + // is resized in inplace mode and the new Position is outside the + // fly frame, we do not want to leave our fly frame. + if ( pCnt->IsInFly() ) + return pCnt; + + return ::lcl_FindCnt( aNew, pCnt, bBody, bFootnote ); + } + else + return nDownLst < nUpLst ? pDownLst : pUpLst; +} + +void SwFlyAtContentFrame::SetAbsPos( const Point &rNew ) +{ + SwPageFrame *pOldPage = FindPageFrame(); + const SwRect aOld( GetObjRectWithSpaces() ); + Point aNew( rNew ); + + if( ( GetAnchorFrame()->IsVertical() && !GetAnchorFrame()->IsVertLR() ) || GetAnchorFrame()->IsRightToLeft() ) + aNew.setX(aNew.getX() + getFrameArea().Width()); + SwContentFrame *pCnt = const_cast<SwContentFrame*>(::FindAnchor( GetAnchorFrame(), aNew )); + if( pCnt->IsProtected() ) + pCnt = const_cast<SwContentFrame*>(static_cast<const SwContentFrame*>(GetAnchorFrame())); + + SwPageFrame *pTmpPage = nullptr; + const bool bVert = pCnt->IsVertical(); + + const bool bVertL2R = pCnt->IsVertLR(); + const bool bRTL = pCnt->IsRightToLeft(); + + if( ( !bVert != !GetAnchorFrame()->IsVertical() ) || + ( !bRTL != !GetAnchorFrame()->IsRightToLeft() ) ) + { + if( bVert || bRTL ) + aNew.setX(aNew.getX() + getFrameArea().Width()); + else + aNew.setX(aNew.getX() - getFrameArea().Width()); + } + + if ( pCnt->IsInDocBody() ) + { + //#38848 drag from page margin into the body. + pTmpPage = pCnt->FindPageFrame(); + ::lcl_PointToPrt( aNew, pTmpPage->GetUpper() ); + SwRect aTmp( aNew, Size( 0, 0 ) ); + pTmpPage = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aTmp, pTmpPage ))); + ::lcl_PointToPrt( aNew, pTmpPage ); + } + + //Setup RelPos, only invalidate if requested. + //rNew is an absolute position. We need to calculate the distance from rNew + //to the anchor inside the text flow to correctly set RelPos. +//!!!!!We can optimize here: FindAnchor could also return RelPos! + const SwFrame *pFrame = nullptr; + SwTwips nY; + if ( pCnt->getFrameArea().IsInside( aNew ) ) + { + // #i70582# + if ( bVert ) + { + nY = pCnt->getFrameArea().Left() - rNew.X(); + if ( bVertL2R ) + nY = -nY; + else + nY += pCnt->getFrameArea().Width() - getFrameArea().Width(); + nY -= pCnt->GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid(); + } + else + nY = rNew.Y() - pCnt->getFrameArea().Top() - pCnt->GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid(); + } + else + { + SwDistance aDist; + pFrame = ::lcl_CalcDownDist( aDist, aNew, pCnt ); + nY = aDist.nMain + aDist.nSub; + } + + SwTwips nX = 0; + + if ( pCnt->IsFollow() ) + { + // Flys are never attached to the follow but always to the master, + // which we're going to search now. + const SwContentFrame *pOriginal = pCnt; + const SwContentFrame *pFollow = pCnt; + while ( pCnt->IsFollow() ) + { + do + { + SwContentFrame* pPrev = pCnt->GetPrevContentFrame(); + if (!pPrev) + { + SAL_WARN("sw.core", "very unexpected missing PrevContentFrame"); + break; + } + pCnt = pPrev; + } + while ( pCnt->GetFollow() != pFollow ); + pFollow = pCnt; + } + SwTwips nDiff = 0; + do + { const SwFrame *pUp = pFollow->GetUpper(); + if( pUp->IsVertical() ) + { + if ( pUp->IsVertLR() ) + nDiff += pUp->getFramePrintArea().Width() - pFollow->GetRelPos().getX(); + else + nDiff += pFollow->getFrameArea().Left() + pFollow->getFrameArea().Width() + - pUp->getFrameArea().Left() - pUp->getFramePrintArea().Left(); + } + else + nDiff += pUp->getFramePrintArea().Height() - pFollow->GetRelPos().Y(); + pFollow = pFollow->GetFollow(); + } while ( pFollow != pOriginal ); + nY += nDiff; + if( bVert ) + nX = pCnt->getFrameArea().Top() - pOriginal->getFrameArea().Top(); + else + nX = pCnt->getFrameArea().Left() - pOriginal->getFrameArea().Left(); + } + + if ( nY == LONG_MAX ) + { + // #i70582# + const SwTwips nTopForObjPos = lcl_GetTopForObjPos(pCnt, bVert, bVertL2R); + if( bVert ) + { + if ( bVertL2R ) + nY = rNew.X() - nTopForObjPos; + else + nY = nTopForObjPos - rNew.X(); + } + else + { + nY = rNew.Y() - nTopForObjPos; + } + } + + SwFlyFrameFormat *pFormat = GetFormat(); + + if( bVert ) + { + if( !pFrame ) + nX += rNew.Y() - pCnt->getFrameArea().Top(); + else + nX = rNew.Y() - pFrame->getFrameArea().Top(); + } + else + { + if( !pFrame ) + { + if ( pCnt->IsRightToLeft() ) + nX += pCnt->getFrameArea().Right() - rNew.X() - getFrameArea().Width(); + else + nX += rNew.X() - pCnt->getFrameArea().Left(); + } + else + { + if ( pFrame->IsRightToLeft() ) + nX += pFrame->getFrameArea().Right() - rNew.X() - getFrameArea().Width(); + else + nX = rNew.X() - pFrame->getFrameArea().Left(); + } + } + GetFormat()->GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::START, nullptr ); + + if( pCnt != GetAnchorFrame() || ( IsAutoPos() && pCnt->IsTextFrame() && + GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE)) ) + { + //Set the anchor attribute according to the new Cnt. + SwFormatAnchor aAnch( pFormat->GetAnchor() ); + SwPosition pos = *aAnch.GetContentAnchor(); + if( IsAutoPos() && pCnt->IsTextFrame() ) + { + SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>(pCnt)); + SwCursorMoveState eTmpState( CursorMoveState::SetOnlyText ); + Point aPt( rNew ); + if( pCnt->GetModelPositionForViewPoint( &pos, aPt, &eTmpState ) + && FrameContainsNode(*pTextFrame, pos.nNode.GetIndex())) + { + const SwTextAttr *const pTextInputField = + pos.nNode.GetNode().GetTextNode()->GetTextAttrAt( + pos.nContent.GetIndex(), RES_TXTATR_INPUTFIELD, SwTextNode::PARENT ); + if (pTextInputField != nullptr) + { + pos.nContent = pTextInputField->GetStart(); + } + ResetLastCharRectHeight(); + if( text::RelOrientation::CHAR == pFormat->GetVertOrient().GetRelationOrient() ) + nY = LONG_MAX; + if( text::RelOrientation::CHAR == pFormat->GetHoriOrient().GetRelationOrient() ) + nX = LONG_MAX; + } + else + { + pos = pTextFrame->MapViewToModelPos(TextFrameIndex(0)); + } + } + else if (pCnt->IsTextFrame()) + { + pos = static_cast<SwTextFrame const*>(pCnt)->MapViewToModelPos(TextFrameIndex(0)); + } + else // is that even possible? maybe if there was a change of anchor type from AT_FLY or something? + { + assert(pCnt->IsNoTextFrame()); + pos.nNode = *static_cast<SwNoTextFrame*>(pCnt)->GetNode(); + pos.nContent.Assign(static_cast<SwNoTextFrame*>(pCnt)->GetNode(), 0); + } + aAnch.SetAnchor( &pos ); + + // handle change of anchor node: + // if count of the anchor frame also change, the fly frames have to be + // re-created. Thus, delete all fly frames except the <this> before the + // anchor attribute is change and re-create them afterwards. + { + SwHandleAnchorNodeChg aHandleAnchorNodeChg( *pFormat, aAnch, this ); + pFormat->GetDoc()->SetAttr( aAnch, *pFormat ); + } + } + else if ( pTmpPage && pTmpPage != GetPageFrame() ) + GetPageFrame()->MoveFly( this, pTmpPage ); + + const Point aRelPos = bVert ? Point( -nY, nX ) : Point( nX, nY ); + ChgRelPos( aRelPos ); + GetFormat()->GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr ); + + if ( pOldPage != FindPageFrame() ) + ::Notify_Background( GetVirtDrawObj(), pOldPage, aOld, PrepareHint::FlyFrameLeave, false ); +} + +/** method to assure that anchored object is registered at the correct + page frame + + #i28701# + takes over functionality of deleted method <SwFlyAtContentFrame::AssertPage()> +*/ +void SwFlyAtContentFrame::RegisterAtCorrectPage() +{ + SwPageFrame* pPageFrame( nullptr ); + if ( GetVertPosOrientFrame() ) + { + pPageFrame = const_cast<SwPageFrame*>(GetVertPosOrientFrame()->FindPageFrame()); + } + if ( pPageFrame && GetPageFrame() != pPageFrame ) + { + if ( GetPageFrame() ) + GetPageFrame()->MoveFly( this, pPageFrame ); + else + pPageFrame->AppendFlyToPage( this ); + } +} + +// #i26791# +void SwFlyAtContentFrame::MakeObjPos() +{ + // if fly frame position is valid, nothing is to do. Thus, return + if ( isFrameAreaPositionValid() ) + { + return; + } + + // #i26791# - validate position flag here. + setFrameAreaPositionValid(true); + + // #i35911# - no calculation of new position, if + // anchored object is marked that it clears its environment and its + // environment is already cleared. + // before checking for cleared environment + // check, if member <mpVertPosOrientFrame> is set. + if ( GetVertPosOrientFrame() && + ClearedEnvironment() && HasClearedEnvironment() ) + { + return; + } + + // use new class to position object + objectpositioning::SwToContentAnchoredObjectPosition + aObjPositioning( *GetVirtDrawObj() ); + aObjPositioning.CalcPosition(); + + SetVertPosOrientFrame ( aObjPositioning.GetVertPosOrientFrame() ); +} + +// #i28701# +bool SwFlyAtContentFrame::InvalidationAllowed( const InvalidationType _nInvalid ) const +{ + bool bAllowed( SwFlyFreeFrame::InvalidationAllowed( _nInvalid ) ); + + // forbiddance of base instance can't be over ruled. + if ( bAllowed ) + { + if ( _nInvalid == INVALID_POS || + _nInvalid == INVALID_ALL ) + { + bAllowed = InvalidationOfPosAllowed(); + } + } + + return bAllowed; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |