/* -*- 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 .
*/
//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);
// Search the new anchor using the NodeIdx; the relation between old // and new NodeIdx determines the search direction const SwNodeIndex aNewIdx(*pAnch->GetAnchorNode());
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())); constbool 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 = rObj->DynCastFlyFrame(); 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;
if ( maObjPositions.size() == 20 )
{ // #i3317# position stack is full -> oscillation
bOscillationDetected = true;
} else
{
Point aNewObjPos = m_pFly->GetObjRect().Pos(); for ( autoconst & 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)
{ const SwDoc& rDoc = GetFormat()->GetDoc(); if (!rDoc.getIDocumentDrawModelAccess().IsVisibleLayerId(GetVirtDrawObj()->GetLayer()))
{ return;
}
if ( SwOszControl::IsInProgress( this ) || IsLocked() || IsColLocked() ) return;
// #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() ) return;
// #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. constbool 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);
constbool 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 =
*GetAnchorFrameContainingAnchPos()->DynCastTextFrame(); // #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. constbool 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 ); bool bPageHasFlysAnchoredBelowThis(false); if ( SwObjectFormatterTextFrame::CheckMovedFwdCondition( // TODO: what if this fly moved bc it's in table? does sth prevent that?
*this, *GetPageFrame(),
bAnchoredAtMaster, nToPageNum, bDummy,
bPageHasFlysAnchoredBelowThis) )
{ if (!bPageHasFlysAnchoredBelowThis)
{
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 ); if ( SwLayouter::FrameMovedFwdByObjPos(
rDoc, *pAnchorTextFrame, nAnchorFrameToPageNum ) )
{ if ( nAnchorFrameToPageNum < nToPageNum )
{ if (!bPageHasFlysAnchoredBelowThis)
{
SwLayouter::RemoveMovedFwdFrame(rDoc, *pAnchorTextFrame);
}
} else
bInsert = false;
} if ( bInsert )
{ if (!bPageHasFlysAnchoredBelowThis)
{
SwLayouter::InsertMovedFwdFrame(rDoc, *pAnchorTextFrame,
nToPageNum);
}
}
}
}
// 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( " - 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 &&
rDoc.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;
}
}
} // tdf#137803: Fix the position of the shape during autoSize
SwFrameFormat* pShapeFormat
= SwTextBoxHelper::getOtherTextBoxFormat(GetFormat(), RES_FLYFRMFMT); // FIXME: According to tdf37153, ignore FollowTextFlow objs, because // wrong position will applied in that case. FollowTextFlow needs fix. if (pShapeFormat && !pShapeFormat->GetFollowTextFlow().GetValue() &&
SwTextBoxHelper::getProperty(pShapeFormat,
UNO_NAME_FRAME_ISAUTOMATIC_HEIGHT).hasValue() &&
SwTextBoxHelper::getProperty(pShapeFormat,
UNO_NAME_FRAME_ISAUTOMATIC_HEIGHT).get<bool>() )
{ // get the text area of the shape const tools::Rectangle aTextRectangle
= SwTextBoxHelper::getRelativeTextRectangle(pShapeFormat->FindRealSdrObject()); // get the original textframe position
SwFormatHoriOrient aHOri = pShapeFormat->GetHoriOrient();
SwFormatVertOrient aVOri = pShapeFormat->GetVertOrient(); // calc the right position of the shape depending on text area
aHOri.SetPos(aHOri.GetPos() + aTextRectangle.Left());
aVOri.SetPos(aVOri.GetPos() + aTextRectangle.Top()); // save the new position for the shape auto pFormat = GetFormat(); constbool bLocked = pFormat->IsModifyLocked(); if (!bLocked)
pFormat->LockModify();
pFormat->SetFormatAttr(aHOri);
pFormat->SetFormatAttr(aVOri); if (!bLocked)
pFormat->UnlockModify();
} 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
static sal_uInt64 lcl_FindCntDiff( const Point &rPt, const SwLayoutFrame *pLay, const SwContentFrame *& rpCnt, constbool bBody, constbool 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.
staticconst SwContentFrame * lcl_FindCnt( const Point &rPt, const SwContentFrame *pCnt, constbool bBody, constbool 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?
/** 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, constbool 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. constbool bBody = pCnt->IsInDocBody() || bBodyOnly; constbool 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().Contains( aNew ) ) return pCnt; elseif ( 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().Contains( 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.m_nMain = LONG_MAX; if (nUp.m_nMain >= 0 && LONG_MAX != nUp.m_nMain)
{
bNegAllowed = false; if (nUpLst.m_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.m_nMain < 0) || (nUp <= nUpLst)));
const SwContentFrame *pDownLst; const SwContentFrame *pDownFrame = pCnt;
SwDistance nDownLst; if (nDown.m_nMain < 0)
nDown.m_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.m_nMain < 0)
nDown.m_nMain = LONG_MAX; //It makes sense to search further, if the distance grows inside //a table. if ( pDownLst->IsInTab() && pDownFrame->IsInTab() )
{ while (pDownFrame
&& ((nDown.m_nMain != LONG_MAX && pDownFrame->IsInTab())
|| bBody != pDownFrame->IsInDocBody()))
{
pDownFrame = pDownFrame->GetNextContentFrame(); if ( pDownFrame )
::lcl_CalcDownDist( nDown, aNew, pDownFrame ); if (nDown.m_nMain < 0)
nDown.m_nMain = LONG_MAX;
}
}
} if ( !pDownFrame )
nDown.m_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.m_nMain == LONG_MAX && nUpLst.m_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;
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().Contains( 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.m_nMain + aDist.m_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;
}
}
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.GetNodeIndex()))
{ const SwTextAttr *const pTextInputField =
pos.GetNode().GetTextNode()->GetTextAttrAt(
pos.GetContentIndex(), RES_TXTATR_INPUTFIELD, ::sw::GetTextAttrMode::Parent); if (pTextInputField != nullptr)
{
pos.SetContent( 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));
}
} elseif (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.Assign(*static_cast<SwNoTextFrame*>(pCnt)->GetNode());
}
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 );
}
} elseif ( pTmpPage && pTmpPage != GetPageFrame() )
GetPageFrame()->MoveFly( this, pTmpPage );
/** 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 )
{
RegisterAtPage(*pPageFrame);
}
}
void SwFlyAtContentFrame::RegisterAtPage(SwPageFrame & rPageFrame)
{ if (GetPageFrame())
{
GetPageFrame()->MoveFly( this, &rPageFrame );
} else
{
rPageFrame.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();
// forbiddance of base instance can't be over ruled. if ( bAllowed )
{ if ( _nInvalid == INVALID_POS ||
_nInvalid == INVALID_ALL )
{
bAllowed = InvalidationOfPosAllowed();
}
}
if (!pFlyAnchor)
{ // In case our fly frame is split already, but not yet moved, then FindAnchorCharFrame() // won't find the anchor, since it wants a follow anchor, but there is no follow anchor yet. // In this case work with a plain anchor, so FindSctFrame() works to find out we're in a // section. auto pAnchorFrame = const_cast<SwFrame*>(pFly->GetAnchorFrame()); if (pAnchorFrame && pAnchorFrame->IsTextFrame())
{
pFlyAnchor = static_cast<SwTextFrame*>(pAnchorFrame);
}
}
bool bBody = pFlyAnchor && pFlyAnchor->IsInDocBody();
SwLayoutFrame *pLayLeaf = nullptr; // Look up the first candidate.
SwSectionFrame* pFlyAnchorSection = pFlyAnchor ? pFlyAnchor->FindSctFrame() : nullptr; bool bNesting = false; if (pFlyAnchorSection)
{ // The anchor is in a section. if (pFlyAnchor)
{
SwTabFrame* pFlyAnchorTab = pFlyAnchor->FindTabFrame(); if (pFlyAnchorTab)
{ // The anchor is in table as well. if (pFlyAnchorTab->FindSctFrame() == pFlyAnchorSection)
{ // We're in a table-in-section, no anchor move in this case, because that would // mean we're not in a table anymore.
bNesting = true;
}
}
} if (!bNesting)
{ // We can't just move the split anchor to the next page, that would be outside the section. // Rather split that section as well.
pLayLeaf = pFlyAnchorSection->GetNextSctLeaf(eMakePage);
}
} elseif (IsTabFrame())
{ // If we're in a table, try to find the next frame of the table's last content.
SwFrame* pContent = static_cast<SwTabFrame*>(this)->FindLastContentOrTable();
pLayLeaf = pContent ? pContent->GetUpper() : nullptr;
} else
{
pLayLeaf = GetNextLayoutLeaf();
}
SwLayoutFrame* pOldLayLeaf = nullptr; while (true)
{ if (pLayLeaf)
{ // If we're anchored in a body frame, the candidate has to be in a body frame as well. bool bLeftBody = bBody && !pLayLeaf->IsInDocBody(); // If the candidate is in a fly, make sure that the candidate is a child of our follow. bool bLeftFly = pLayLeaf->IsInFly() && pLayLeaf->FindFlyFrame() != pFly->GetFollow(); bool bSameBody = false; if (bBody && pLayLeaf->IsInDocBody())
{ // Make sure the candidate is not inside the same body frame, that would prevent // inserting a new page.
SwBodyFrame const* pAnchorBody(pFlyAnchor->FindBodyFrame()); while (!pAnchorBody->IsPageBodyFrame())
{
pAnchorBody = pAnchorBody->GetUpper()->FindBodyFrame();
};
SwBodyFrame const* pLeafBody(pLayLeaf->FindBodyFrame()); while (!pLeafBody->IsPageBodyFrame())
{
pLeafBody = pLeafBody->GetUpper()->FindBodyFrame();
}; if (pAnchorBody == pLeafBody)
{
bSameBody = true;
}
}
if (bLeftFly && pFlyAnchor && pFlyAnchor->IsInTab()
&& FindTabFrame() == pLayLeaf->FindTabFrame())
{ // This is an inner fly (parent is an inline or a floating table), then the follow // anchor will be just next to us.
SwLayoutFrame* pFlyAnchorUpper = pFlyAnchor->GetUpper();
pOldLayLeaf = pLayLeaf;
pLayLeaf = pFlyAnchorUpper;
bLeftFly = false;
bNesting = true;
}
if (bLeftBody || bLeftFly || bSameBody)
{ // The above conditions are not held, reject.
pOldLayLeaf = pLayLeaf; do
{
pLayLeaf = pLayLeaf->GetNextLayoutLeaf();
} // skip deleted section frames - do not move into these while (pLayLeaf && pLayLeaf->FindSctFrame()
&& !pLayLeaf->FindSctFrame()->GetSection());
if (pLayLeaf && pLayLeaf->IsInDocBody() && !bSameBody && !pLayLeaf->IsInFly() && pLayLeaf->IsInTab())
{ // We found a next leaf in a next body frame, which is in an inline table. Make // sure we won't insert the follow anchor inside the table, but before it.
SwTabFrame* pTabFrame = pLayLeaf->FindTabFrame();
pLayLeaf = pTabFrame->GetUpper();
}
continue;
}
} else
{ // No candidate: insert a page and try again. if (eMakePage == MAKEPAGE_INSERT)
{
InsertPage(FindPageFrame(), false); // If we already had a candidate, continue trying with that instead of starting from // scratch.
pLayLeaf = pOldLayLeaf ? pOldLayLeaf : GetNextLayoutLeaf(); continue;
}
} break;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.