1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/log.hxx>
21 #include <osl/diagnose.h>
22 #include <svx/swframetypes.hxx>
23 #include <pagefrm.hxx>
25 #include <notxtfrm.hxx>
28 #include <IDocumentUndoRedo.hxx>
29 #include <IDocumentSettingAccess.hxx>
30 #include <IDocumentDrawModelAccess.hxx>
31 #include <frmtool.hxx>
32 #include <dflyobj.hxx>
33 #include <fmtanchr.hxx>
34 #include <fmtornt.hxx>
35 #include <fmtfsize.hxx>
36 #include <fmtsrnd.hxx>
37 #include <txatbase.hxx>
40 #include <flyfrms.hxx>
41 #include <crstate.hxx>
42 #include <sectfrm.hxx>
44 #include <tocntntanchoredobjectposition.hxx>
45 #include <sortedobjs.hxx>
46 #include <layouter.hxx>
47 #include "objectformattertxtfrm.hxx"
48 #include <HandleAnchorNodeChg.hxx>
50 #include <textboxhelper.hxx>
51 #include <fmtfollowtextflow.hxx>
52 #include <unoprnms.hxx>
53 #include <rootfrm.hxx>
54 #include <bodyfrm.hxx>
56 using namespace ::com::sun::star
;
61 SwTwips
lcl_GetTopForObjPos(const SwContentFrame
* pCnt
, const bool bVert
, const bool bVertL2R
)
65 SwTwips aResult
= pCnt
->getFrameArea().Left();
67 aResult
+= pCnt
->GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid();
69 aResult
+= pCnt
->getFrameArea().Width() - pCnt
->GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid();
73 return pCnt
->getFrameArea().Top() + pCnt
->GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid();
78 SwFlyAtContentFrame::SwFlyAtContentFrame( SwFlyFrameFormat
*pFormat
, SwFrame
* pSib
, SwFrame
*pAnch
, bool bFollow
) :
79 SwFlyFreeFrame( pFormat
, pSib
, pAnch
, bFollow
),
80 SwFlowFrame(static_cast<SwFrame
&>(*this))
83 m_bAutoPosition
= (RndStdIds::FLY_AT_CHAR
== pFormat
->GetAnchor().GetAnchorId());
86 SwFlyAtContentFrame::SwFlyAtContentFrame(SwFlyAtContentFrame
& rPrecede
)
87 : SwFlyAtContentFrame(rPrecede
.GetFormat(), const_cast<SwFrame
*>(rPrecede
.GetAnchorFrame()),
88 const_cast<SwFrame
*>(rPrecede
.GetAnchorFrame()), /*bFollow=*/true)
90 SetFollow(rPrecede
.GetFollow());
91 rPrecede
.SetFollow(this);
94 SwFlyAtContentFrame::~SwFlyAtContentFrame()
100 void SwFlyAtContentFrame::SwClientNotify(const SwModify
& rMod
, const SfxHint
& rHint
)
102 if (rHint
.GetId() != SfxHintId::SwLegacyModify
)
104 SwFlyFrame::SwClientNotify(rMod
, rHint
);
107 auto pLegacy
= static_cast<const sw::LegacyModifyHint
*>(&rHint
);
108 const SwFormatAnchor
* pAnch
= pLegacy
->m_pNew
? GetAnchorFromPoolItem(*pLegacy
->m_pNew
) : nullptr;
111 SwFlyFrame::SwClientNotify(rMod
, rHint
);
114 OSL_ENSURE(pAnch
->GetAnchorId() == GetFormat()->GetAnchor().GetAnchorId(),
115 "Illegal change of anchor type.");
117 //Unregister, get hold of a new anchor and attach it
118 SwRect
aOld(GetObjRectWithSpaces());
119 SwPageFrame
* pOldPage
= FindPageFrame();
120 const SwFrame
* pOldAnchor
= GetAnchorFrame();
121 SwContentFrame
* pContent
= const_cast<SwContentFrame
*>(static_cast<const SwContentFrame
*>(GetAnchorFrame()));
122 AnchorFrame()->RemoveFly(this);
124 const bool bBodyFootnote
= (pContent
->IsInDocBody() || pContent
->IsInFootnote());
126 // Search the new anchor using the NodeIdx; the relation between old
127 // and new NodeIdx determines the search direction
128 const SwNodeIndex
aNewIdx(*pAnch
->GetAnchorNode());
129 SwNodeIndex
aOldIdx(pContent
->IsTextFrame()
130 // sw_redlinehide: can pick any node here, the compare with
131 // FrameContainsNode should catch it
132 ? *static_cast<SwTextFrame
*>(pContent
)->GetTextNodeFirst()
133 : *static_cast<SwNoTextFrame
*>(pContent
)->GetNode());
135 //fix: depending on which index was smaller, searching in the do-while
136 //loop previously was done forward or backwards respectively. This however
137 //could lead to an infinite loop. To at least avoid the loop, searching
138 //is now done in only one direction. Getting hold of a frame from the node
139 //is still possible if the new anchor could not be found. Chances are
140 //good that this will be the correct one.
141 // consider the case that at found anchor frame candidate already a
142 // fly frame of the given fly format is registered.
143 // consider, that <pContent> is the already
144 // the new anchor frame.
145 bool bFound(FrameContainsNode(*pContent
, aNewIdx
.GetIndex()));
146 const bool bNext
= !bFound
&& aOldIdx
< aNewIdx
;
147 while(pContent
&& !bFound
)
152 pContent
= pContent
->GetNextContentFrame();
154 pContent
= pContent
->GetPrevContentFrame();
156 (bBodyFootnote
!= (pContent
->IsInDocBody() || pContent
->IsInFootnote())));
158 bFound
= FrameContainsNode(*pContent
, aNewIdx
.GetIndex());
160 // check, if at found anchor frame candidate already a fly frame
161 // of the given fly frame format is registered.
162 if(bFound
&& pContent
&& pContent
->GetDrawObjs())
164 SwFrameFormat
* pMyFlyFrameFormat(&GetFrameFormat());
165 SwSortedObjs
&rObjs
= *pContent
->GetDrawObjs();
166 for(SwAnchoredObject
* rObj
: rObjs
)
168 SwFlyFrame
* pFlyFrame
= rObj
->DynCastFlyFrame();
170 &(pFlyFrame
->GetFrameFormat()) == pMyFlyFrameFormat
)
180 SwContentNode
*pNode
= aNewIdx
.GetNode().GetContentNode();
181 std::pair
<Point
, bool> const tmp(pOldAnchor
->getFrameArea().Pos(), false);
182 pContent
= pNode
->getLayoutFrame(getRootFrame(), nullptr, &tmp
);
183 OSL_ENSURE(pContent
, "New anchor not found");
185 //Flys are never attached to a follow, but always on the master which
186 //we are going to search now.
187 SwContentFrame
* pFlow
= pContent
;
188 while(pFlow
->IsFollow())
189 pFlow
= pFlow
->FindMaster();
192 //and *puff* it's attached...
193 pContent
->AppendFly( this );
194 if(pOldPage
&& pOldPage
!= FindPageFrame())
195 NotifyBackground(pOldPage
, aOld
, PrepareHint::FlyFrameLeave
);
201 // #i28701# - reset member <maLastCharRect> and
202 // <mnLastTopOfLine> for to-character anchored objects.
203 ClearCharRectAndTopOfLine();
206 //We need some helper classes to monitor the oscillation and a few functions
211 // #i3317# - re-factoring of the position stack
214 static const SwFlyFrame
* s_pStack1
;
215 static const SwFlyFrame
* s_pStack2
;
216 static const SwFlyFrame
* s_pStack3
;
217 static const SwFlyFrame
* s_pStack4
;
218 static const SwFlyFrame
* s_pStack5
;
220 const SwFlyFrame
* m_pFly
;
221 std::vector
<Point
> maObjPositions
;
224 explicit SwOszControl( const SwFlyFrame
*pFrame
);
227 static bool IsInProgress( const SwFlyFrame
*pFly
);
232 const SwFlyFrame
* SwOszControl::s_pStack1
= nullptr;
233 const SwFlyFrame
* SwOszControl::s_pStack2
= nullptr;
234 const SwFlyFrame
* SwOszControl::s_pStack3
= nullptr;
235 const SwFlyFrame
* SwOszControl::s_pStack4
= nullptr;
236 const SwFlyFrame
* SwOszControl::s_pStack5
= nullptr;
238 SwOszControl::SwOszControl(const SwFlyFrame
* pFrame
)
241 if (!SwOszControl::s_pStack1
)
242 SwOszControl::s_pStack1
= m_pFly
;
243 else if (!SwOszControl::s_pStack2
)
244 SwOszControl::s_pStack2
= m_pFly
;
245 else if (!SwOszControl::s_pStack3
)
246 SwOszControl::s_pStack3
= m_pFly
;
247 else if (!SwOszControl::s_pStack4
)
248 SwOszControl::s_pStack4
= m_pFly
;
249 else if (!SwOszControl::s_pStack5
)
250 SwOszControl::s_pStack5
= m_pFly
;
253 SwOszControl::~SwOszControl()
255 if (SwOszControl::s_pStack1
== m_pFly
)
256 SwOszControl::s_pStack1
= nullptr;
257 else if (SwOszControl::s_pStack2
== m_pFly
)
258 SwOszControl::s_pStack2
= nullptr;
259 else if (SwOszControl::s_pStack3
== m_pFly
)
260 SwOszControl::s_pStack3
= nullptr;
261 else if (SwOszControl::s_pStack4
== m_pFly
)
262 SwOszControl::s_pStack4
= nullptr;
263 else if (SwOszControl::s_pStack5
== m_pFly
)
264 SwOszControl::s_pStack5
= nullptr;
266 maObjPositions
.clear();
269 bool SwOszControl::IsInProgress( const SwFlyFrame
*pFly
)
271 if (SwOszControl::s_pStack1
&& !pFly
->IsLowerOf(SwOszControl::s_pStack1
))
273 if (SwOszControl::s_pStack2
&& !pFly
->IsLowerOf(SwOszControl::s_pStack2
))
275 if (SwOszControl::s_pStack3
&& !pFly
->IsLowerOf(SwOszControl::s_pStack3
))
277 if (SwOszControl::s_pStack4
&& !pFly
->IsLowerOf(SwOszControl::s_pStack4
))
279 if (SwOszControl::s_pStack5
&& !pFly
->IsLowerOf(SwOszControl::s_pStack5
))
284 bool SwOszControl::ChkOsz()
286 bool bOscillationDetected
= false;
288 if ( maObjPositions
.size() == 20 )
290 // #i3317# position stack is full -> oscillation
291 bOscillationDetected
= true;
295 Point aNewObjPos
= m_pFly
->GetObjRect().Pos();
296 for ( auto const & pt
: maObjPositions
)
298 if ( aNewObjPos
== pt
)
300 // position already occurred -> oscillation
301 bOscillationDetected
= true;
305 if ( !bOscillationDetected
)
307 maObjPositions
.push_back( aNewObjPos
);
311 return bOscillationDetected
;
315 |* With a paragraph-anchored fly it's absolutely possible that
316 |* the anchor reacts to changes of the fly. To this reaction the fly must
317 |* certainly react too. Sadly this can lead to oscillations; for example the
318 |* fly wants to go down therefore the content can go up - this leads to a
319 |* smaller TextFrame thus the fly needs to go up again whereby the text will
320 |* get pushed down...
321 |* To avoid such oscillations, a small position stack is built. If the fly
322 |* reaches a position which it already had once, the action is stopped.
323 |* To not run into problems, the stack is designed to hold five positions.
324 |* If the stack flows over, the action is stopped too.
325 |* Cancellation leads to the situation that the fly has a bad position in
326 |* the end. In case of cancellation, the frame is set to automatic top
327 |* alignment to not trigger a 'big oscillation' when calling from outside
330 void SwFlyAtContentFrame::MakeAll(vcl::RenderContext
* pRenderContext
)
332 if ( !GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) )
337 if ( SwOszControl::IsInProgress( this ) || IsLocked() || IsColLocked() )
340 // #i28701# - use new method <GetPageFrame()>
341 if( !GetPageFrame() && GetAnchorFrame() && GetAnchorFrame()->IsInFly() )
343 SwFlyFrame
* pFly
= AnchorFrame()->FindFlyFrame();
344 SwPageFrame
*pTmpPage
= pFly
? pFly
->FindPageFrame() : nullptr;
346 pTmpPage
->AppendFlyToPage( this );
348 // #i28701# - use new method <GetPageFrame()>
349 if( !GetPageFrame() )
352 bSetCompletePaintOnInvalidate
= true;
354 SwFlyFrameFormat
*pFormat
= GetFormat();
355 const SwFormatFrameSize
&rFrameSz
= GetFormat()->GetFrameSize();
356 if( rFrameSz
.GetHeightPercent() != SwFormatFrameSize::SYNCED
&&
357 rFrameSz
.GetHeightPercent() >= 100 )
359 pFormat
->LockModify();
360 SwFormatSurround
aMain( pFormat
->GetSurround() );
361 if ( aMain
.GetSurround() == css::text::WrapTextMode_NONE
)
363 aMain
.SetSurround( css::text::WrapTextMode_THROUGH
);
364 pFormat
->SetFormatAttr( aMain
);
366 pFormat
->UnlockModify();
370 SwOszControl
aOszCntrl( this );
373 // #i50356# - format the anchor frame, which
374 // contains the anchor position. E.g., for at-character anchored
375 // object this can be the follow frame of the anchor frame.
376 const bool bFormatAnchor
=
377 !static_cast<const SwTextFrame
*>( GetAnchorFrameContainingAnchPos() )->IsAnyJoinLocked() &&
378 !ConsiderObjWrapInfluenceOnObjPos() &&
379 !ConsiderObjWrapInfluenceOfOtherObjs();
381 const SwFrame
* pFooter
= GetAnchorFrame()->FindFooterOrHeader();
382 if( pFooter
&& !pFooter
->IsFooterFrame() )
385 bool bExtra
= Lower() && Lower()->IsColumnFrame();
386 // #i3317# - boolean, to apply temporarily the
387 // 'straightforward positioning process' for the frame due to its
388 // overlapping with a previous column.
389 bool bConsiderWrapInfluenceDueToOverlapPrevCol( false );
390 // #i35911# - boolean, to apply temporarily the
391 // 'straightforward positioning process' for the frame due to fact
392 // that it causes the complete content of its layout environment
394 // #i40444# - extend usage of this boolean:
395 // apply temporarily the 'straightforward positioning process' for
396 // the frame due to the fact that the frame clears the area for
397 // the anchor frame, thus it has to move forward.
398 bool bConsiderWrapInfluenceDueToMovedFwdAnchor( false );
400 SwRectFnSet
aRectFnSet(this);
401 Point
aOldPos( aRectFnSet
.GetPos(getFrameArea()) );
402 SwFlyFreeFrame::MakeAll(pRenderContext
);
404 const bool bPosChgDueToOwnFormat
=
405 aOldPos
!= aRectFnSet
.GetPos(getFrameArea());
407 if ( !ConsiderObjWrapInfluenceOnObjPos() &&
408 OverlapsPrevColumn() )
410 bConsiderWrapInfluenceDueToOverlapPrevCol
= true;
412 // #i28701# - no format of anchor frame, if
413 // wrapping style influence is considered on object positioning
416 SwTextFrame
& rAnchPosAnchorFrame
=
417 *GetAnchorFrameContainingAnchPos()->DynCastTextFrame();
418 // #i58182# - For the usage of new method
419 // <SwObjectFormatterTextFrame::CheckMovedFwdCondition(..)>
420 // to check move forward of anchor frame due to the object
421 // positioning it's needed to know, if the object is anchored
422 // at the master frame before the anchor frame is formatted.
423 const bool bAnchoredAtMaster(!rAnchPosAnchorFrame
.IsFollow());
426 // perform complete format of anchor text frame and its
427 // previous frames, which have become invalid due to the
429 SwObjectFormatterTextFrame::FormatAnchorFrameAndItsPrevs( rAnchPosAnchorFrame
);
432 // #i58182# - usage of new method
433 // <SwObjectFormatterTextFrame::CheckMovedFwdCondition(..)>
434 sal_uInt32
nToPageNum( 0 );
435 bool bDummy( false );
436 bool bPageHasFlysAnchoredBelowThis(false);
437 if ( SwObjectFormatterTextFrame::CheckMovedFwdCondition(
438 // TODO: what if this fly moved bc it's in table? does sth prevent that?
439 *this, *GetPageFrame(),
440 bAnchoredAtMaster
, nToPageNum
, bDummy
,
441 bPageHasFlysAnchoredBelowThis
) )
443 if (!bPageHasFlysAnchoredBelowThis
)
445 bConsiderWrapInfluenceDueToMovedFwdAnchor
= true;
447 // mark anchor text frame
448 // directly, that it is moved forward by object positioning.
449 SwTextFrame
* pAnchorTextFrame( static_cast<SwTextFrame
*>(AnchorFrame()) );
450 bool bInsert( true );
451 sal_uInt32
nAnchorFrameToPageNum( 0 );
452 const SwDoc
& rDoc
= *(GetFrameFormat().GetDoc());
453 if ( SwLayouter::FrameMovedFwdByObjPos(
454 rDoc
, *pAnchorTextFrame
, nAnchorFrameToPageNum
) )
456 if ( nAnchorFrameToPageNum
< nToPageNum
)
458 if (!bPageHasFlysAnchoredBelowThis
)
460 SwLayouter::RemoveMovedFwdFrame(rDoc
, *pAnchorTextFrame
);
468 if (!bPageHasFlysAnchoredBelowThis
)
470 SwLayouter::InsertMovedFwdFrame(rDoc
, *pAnchorTextFrame
,
477 if ( aOldPos
!= aRectFnSet
.GetPos(getFrameArea()) ||
478 ( !isFrameAreaPositionValid() &&
479 ( pFooter
|| bPosChgDueToOwnFormat
) ) )
481 bOsz
= aOszCntrl
.ChkOsz();
483 // special loop prevention for dedicated document:
485 HasFixSize() && IsClipped() &&
486 GetAnchorFrame()->GetUpper()->IsCellFrame() )
488 SwFrameFormat
* pFormat
= GetFormat();
489 const SwFormatFrameSize
& rFrameSz
= pFormat
->GetFrameSize();
490 if ( rFrameSz
.GetWidthPercent() &&
491 rFrameSz
.GetHeightPercent() == SwFormatFrameSize::SYNCED
)
493 SwFormatSurround
aSurround( pFormat
->GetSurround() );
494 if ( aSurround
.GetSurround() == css::text::WrapTextMode_NONE
)
496 pFormat
->LockModify();
497 aSurround
.SetSurround( css::text::WrapTextMode_THROUGH
);
498 pFormat
->SetFormatAttr( aSurround
);
499 pFormat
->UnlockModify();
501 OSL_FAIL( "<SwFlyAtContentFrame::MakeAll()> - special loop prevention for dedicated document of b6403541 applied" );
507 if ( bExtra
&& Lower() && !Lower()->isFrameAreaPositionValid() )
509 // If a multi column frame leaves invalid columns because of
510 // a position change, we loop once more and format
511 // our content using FormatWidthCols again.
513 bExtra
= false; // Ensure only one additional loop run
515 } while ( !isFrameAreaDefinitionValid() && !bOsz
&&
517 !bConsiderWrapInfluenceDueToOverlapPrevCol
&&
519 !bConsiderWrapInfluenceDueToMovedFwdAnchor
&&
520 GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) );
522 // #i3317# - instead of attribute change apply
523 // temporarily the 'straightforward positioning process'.
525 // handle special case during splitting of table rows
526 if ( bConsiderWrapInfluenceDueToMovedFwdAnchor
&&
527 GetAnchorFrame()->IsInTab() &&
528 GetAnchorFrame()->IsInFollowFlowRow() )
530 const SwFrame
* pCellFrame
= GetAnchorFrame();
531 while ( pCellFrame
&& !pCellFrame
->IsCellFrame() )
533 pCellFrame
= pCellFrame
->GetUpper();
537 SwRectFnSet
aRectFnSet(pCellFrame
);
538 if ( aRectFnSet
.GetTop(pCellFrame
->getFrameArea()) == 0 &&
539 aRectFnSet
.GetHeight(pCellFrame
->getFrameArea()) == 0 )
541 bConsiderWrapInfluenceDueToMovedFwdAnchor
= false;
545 // tdf#137803: Fix the position of the shape during autoSize
546 SwFrameFormat
* pShapeFormat
547 = SwTextBoxHelper::getOtherTextBoxFormat(GetFormat(), RES_FLYFRMFMT
);
548 // FIXME: According to tdf37153, ignore FollowTextFlow objs, because
549 // wrong position will applied in that case. FollowTextFlow needs fix.
550 if (pShapeFormat
&& !pShapeFormat
->GetFollowTextFlow().GetValue() &&
551 SwTextBoxHelper::getProperty(pShapeFormat
,
552 UNO_NAME_FRAME_ISAUTOMATIC_HEIGHT
).hasValue() &&
553 SwTextBoxHelper::getProperty(pShapeFormat
,
554 UNO_NAME_FRAME_ISAUTOMATIC_HEIGHT
).get
<bool>() )
556 // get the text area of the shape
557 const tools::Rectangle aTextRectangle
558 = SwTextBoxHelper::getRelativeTextRectangle(pShapeFormat
->FindRealSdrObject());
559 // get the original textframe position
560 SwFormatHoriOrient aHOri
= pShapeFormat
->GetHoriOrient();
561 SwFormatVertOrient aVOri
= pShapeFormat
->GetVertOrient();
562 // calc the right position of the shape depending on text area
563 aHOri
.SetPos(aHOri
.GetPos() + aTextRectangle
.Left());
564 aVOri
.SetPos(aVOri
.GetPos() + aTextRectangle
.Top());
565 // save the new position for the shape
566 auto pFormat
= GetFormat();
567 const bool bLocked
= pFormat
->IsModifyLocked();
569 pFormat
->LockModify();
570 pFormat
->SetFormatAttr(aHOri
);
571 pFormat
->SetFormatAttr(aVOri
);
573 pFormat
->UnlockModify();
575 if ( bOsz
|| bConsiderWrapInfluenceDueToOverlapPrevCol
||
577 bConsiderWrapInfluenceDueToMovedFwdAnchor
)
579 SetTmpConsiderWrapInfluence( true );
580 SetRestartLayoutProcess( true );
581 SetTmpConsiderWrapInfluenceOfOtherObjs();
583 bSetCompletePaintOnInvalidate
= false;
586 /** method to determine, if a <MakeAll()> on the Writer fly frame is possible
590 bool SwFlyAtContentFrame::IsFormatPossible() const
592 return SwFlyFreeFrame::IsFormatPossible() &&
593 !SwOszControl::IsInProgress( this );
601 SwTwips m_nMain
, m_nSub
;
607 bool operator<( const SwDistance
& rTwo
) const
609 return m_nMain
< rTwo
.m_nMain
610 || (m_nMain
== rTwo
.m_nMain
&& m_nSub
&& rTwo
.m_nSub
&& m_nSub
< rTwo
.m_nSub
);
612 bool operator<=( const SwDistance
& rTwo
) const
614 return m_nMain
< rTwo
.m_nMain
615 || (m_nMain
== rTwo
.m_nMain
616 && (!m_nSub
|| !rTwo
.m_nSub
|| m_nSub
<= rTwo
.m_nSub
));
622 static const SwFrame
* lcl_CalcDownDist( SwDistance
&rRet
,
624 const SwContentFrame
*pCnt
)
627 //If the point stays inside the Cnt everything is clear already; the Content
628 //automatically has a distance of 0.
629 if ( pCnt
->getFrameArea().Contains( rPt
) )
636 const SwLayoutFrame
*pUp
= pCnt
->IsInTab() ? pCnt
->FindTabFrame()->GetUpper() : pCnt
->GetUpper();
637 // single column sections need to interconnect to their upper
638 while( pUp
->IsSctFrame() )
639 pUp
= pUp
->GetUpper();
640 const bool bVert
= pUp
->IsVertical();
642 const bool bVertL2R
= pUp
->IsVertLR();
644 //Follow the text flow.
646 // --> OD 2009-03-05 - adopted for Support for Classical Mongolian Script
647 const SwTwips nTopForObjPos
= lcl_GetTopForObjPos(pCnt
, bVert
, bVertL2R
);
648 if ( pUp
->getFrameArea().Contains( rPt
) )
650 // <rPt> point is inside environment of given content frame
655 rRet
.m_nMain
= rPt
.X() - nTopForObjPos
;
657 rRet
.m_nMain
= nTopForObjPos
- rPt
.X();
660 rRet
.m_nMain
= rPt
.Y() - nTopForObjPos
;
663 else if ( rPt
.Y() <= pUp
->getFrameArea().Top() )
665 // <rPt> point is above environment of given content frame
666 // correct for vertical layout?
667 rRet
.m_nMain
= LONG_MAX
;
669 else if( rPt
.X() < pUp
->getFrameArea().Left() &&
670 rPt
.Y() <= ( bVert
? pUp
->getFrameArea().Top() : pUp
->getFrameArea().Bottom() ) )
672 // <rPt> point is left of environment of given content frame
673 // seems not to be correct for vertical layout!?
674 const SwFrame
*pLay
= pUp
->GetLeaf( MAKEPAGE_NONE
, false, pCnt
);
676 (bVert
&& (pLay
->getFrameArea().Top() + pLay
->getFramePrintArea().Bottom()) <rPt
.Y())||
677 (!bVert
&& (pLay
->getFrameArea().Left() + pLay
->getFramePrintArea().Right())<rPt
.X()) )
679 // <rPt> point is in left border of environment
684 rRet
.m_nMain
= rPt
.X() - nTopForObjPos
;
686 rRet
.m_nMain
= nTopForObjPos
- rPt
.X();
689 rRet
.m_nMain
= rPt
.Y() - nTopForObjPos
;
693 rRet
.m_nMain
= LONG_MAX
;
699 ? ((pUp
->getFrameArea().Left() + pUp
->getFramePrintArea().Right())
702 - (pUp
->getFrameArea().Left() + pUp
->getFramePrintArea().Left())))
703 : ((pUp
->getFrameArea().Top() + pUp
->getFramePrintArea().Bottom())
706 const SwFrame
*pPre
= pCnt
;
707 const SwFrame
*pLay
= pUp
->GetLeaf( MAKEPAGE_NONE
, true, pCnt
);
708 SwTwips nFrameTop
= 0;
709 SwTwips nPrtHeight
= 0;
711 const SwSectionFrame
*pSect
= pUp
->FindSctFrame();
714 rRet
.m_nSub
= rRet
.m_nMain
;
717 if( pSect
&& !pSect
->IsAnLower( pLay
) )
720 const SwSectionFrame
* pNxtSect
= pLay
? pLay
->FindSctFrame() : nullptr;
721 if (pSect
->IsAnFollow(pNxtSect
) && pLay
)
723 if( pLay
->IsVertical() )
725 if ( pLay
->IsVertLR() )
726 nFrameTop
= pLay
->getFrameArea().Left();
728 nFrameTop
= pLay
->getFrameArea().Left() + pLay
->getFrameArea().Width();
729 nPrtHeight
= pLay
->getFramePrintArea().Width();
733 nFrameTop
= pLay
->getFrameArea().Top();
734 nPrtHeight
= pLay
->getFramePrintArea().Height();
740 pLay
= pSect
->GetUpper();
741 if( pLay
->IsVertical() )
743 if ( pLay
->IsVertLR() )
745 nFrameTop
= pSect
->getFrameArea().Right();
746 nPrtHeight
= pLay
->getFrameArea().Left() + pLay
->getFramePrintArea().Left()
747 + pLay
->getFramePrintArea().Width() - pSect
->getFrameArea().Left()
748 - pSect
->getFrameArea().Width();
752 nFrameTop
= pSect
->getFrameArea().Left();
753 nPrtHeight
= pSect
->getFrameArea().Left() - pLay
->getFrameArea().Left()
754 - pLay
->getFramePrintArea().Left();
759 nFrameTop
= pSect
->getFrameArea().Bottom();
760 nPrtHeight
= pLay
->getFrameArea().Top() + pLay
->getFramePrintArea().Top()
761 + pLay
->getFramePrintArea().Height() - pSect
->getFrameArea().Top()
762 - pSect
->getFrameArea().Height();
769 if( pLay
->IsVertical() )
771 if ( pLay
->IsVertLR() )
773 nFrameTop
= pLay
->getFrameArea().Left();
774 nPrtHeight
= pLay
->getFramePrintArea().Width();
778 nFrameTop
= pLay
->getFrameArea().Left() + pLay
->getFrameArea().Width();
779 nPrtHeight
= pLay
->getFramePrintArea().Width();
784 nFrameTop
= pLay
->getFrameArea().Top();
785 nPrtHeight
= pLay
->getFramePrintArea().Height();
787 bSct
= nullptr != pSect
;
789 while ( pLay
&& !pLay
->getFrameArea().Contains( rPt
) &&
790 ( pLay
->getFrameArea().Top() <= rPt
.Y() || pLay
->IsInFly() ||
792 pLay
->FindSctFrame()->GetUpper()->getFrameArea().Top() <= rPt
.Y())) )
794 if ( pLay
->IsFootnoteContFrame() )
796 if ( !static_cast<const SwLayoutFrame
*>(pLay
)->Lower() )
798 SwFrame
*pDel
= const_cast<SwFrame
*>(pLay
);
800 SwFrame::DestroyFrame(pDel
);
808 rRet
.m_nSub
+= nPrtHeight
;
810 rRet
.m_nMain
+= nPrtHeight
;
812 pLay
= pLay
->GetLeaf( MAKEPAGE_NONE
, true, pCnt
);
813 if( pSect
&& !pSect
->IsAnLower( pLay
) )
814 { // If we're leaving a SwSectionFrame, the next Leaf-Frame
815 // is the part of the upper below the SectionFrame.
816 const SwSectionFrame
* pNxtSect
= pLay
?
817 pLay
->FindSctFrame() : nullptr;
819 if (pLay
&& pSect
->IsAnFollow(pNxtSect
))
822 if( pLay
->IsVertical() )
824 if ( pLay
->IsVertLR() )
826 nFrameTop
= pLay
->getFrameArea().Left();
827 nPrtHeight
= pLay
->getFramePrintArea().Width();
831 nFrameTop
= pLay
->getFrameArea().Left() + pLay
->getFrameArea().Width();
832 nPrtHeight
= pLay
->getFramePrintArea().Width();
837 nFrameTop
= pLay
->getFrameArea().Top();
838 nPrtHeight
= pLay
->getFramePrintArea().Height();
843 pLay
= pSect
->GetUpper();
844 if( pLay
->IsVertical() )
846 if ( pLay
->IsVertLR() )
848 nFrameTop
= pSect
->getFrameArea().Right();
849 nPrtHeight
= pLay
->getFrameArea().Left()+pLay
->getFramePrintArea().Left()
850 + pLay
->getFramePrintArea().Width() - pSect
->getFrameArea().Left()
851 - pSect
->getFrameArea().Width();
855 nFrameTop
= pSect
->getFrameArea().Left();
856 nPrtHeight
= pSect
->getFrameArea().Left() -
857 pLay
->getFrameArea().Left() - pLay
->getFramePrintArea().Left();
862 nFrameTop
= pSect
->getFrameArea().Bottom();
863 nPrtHeight
= pLay
->getFrameArea().Top()+pLay
->getFramePrintArea().Top()
864 + pLay
->getFramePrintArea().Height() - pSect
->getFrameArea().Top()
865 - pSect
->getFrameArea().Height();
872 if( pLay
->IsVertical() )
874 if ( pLay
->IsVertLR() )
876 nFrameTop
= pLay
->getFrameArea().Left();
877 nPrtHeight
= pLay
->getFramePrintArea().Width();
881 nFrameTop
= pLay
->getFrameArea().Left() + pLay
->getFrameArea().Width();
882 nPrtHeight
= pLay
->getFramePrintArea().Width();
887 nFrameTop
= pLay
->getFrameArea().Top();
888 nPrtHeight
= pLay
->getFramePrintArea().Height();
890 bSct
= nullptr != pSect
;
896 if ( pLay
->getFrameArea().Contains( rPt
) )
898 SwTwips nDiff
= pLay
->IsVertical() ? ( pLay
->IsVertLR() ? ( rPt
.X() - nFrameTop
) : ( nFrameTop
- rPt
.X() ) )
899 : ( rPt
.Y() - nFrameTop
);
901 rRet
.m_nSub
+= nDiff
;
903 rRet
.m_nMain
+= nDiff
;
905 if ( pLay
->IsFootnoteContFrame() && !static_cast<const SwLayoutFrame
*>(pLay
)->Lower() )
907 SwFrame
*pDel
= const_cast<SwFrame
*>(pLay
);
909 SwFrame::DestroyFrame(pDel
);
915 rRet
.m_nMain
= LONG_MAX
;
921 static sal_uInt64
lcl_FindCntDiff( const Point
&rPt
, const SwLayoutFrame
*pLay
,
922 const SwContentFrame
*& rpCnt
,
923 const bool bBody
, const bool bFootnote
)
925 // Searches below pLay the nearest Cnt to the point. The reference point of
926 //the Contents is always the left upper corner.
927 //The Cnt should preferably be above the point.
930 sal_uInt64 nDistance
= SAL_MAX_UINT64
;
931 sal_uInt64 nNearest
= SAL_MAX_UINT64
;
932 const SwContentFrame
*pCnt
= pLay
? pLay
->ContainsContent() : nullptr;
934 while ( pCnt
&& (bBody
!= pCnt
->IsInDocBody() || bFootnote
!= pCnt
->IsInFootnote()))
936 pCnt
= pCnt
->GetNextContentFrame();
937 if ( !pLay
->IsAnLower( pCnt
) )
940 const SwContentFrame
*pNearest
= pCnt
;
945 //Calculate the distance between those two points.
946 //'delta' X^2 + 'delta' Y^2 = 'distance'^2
947 sal_uInt64 dX
= std::max( pCnt
->getFrameArea().Left(), rPt
.X() ) -
948 std::min( pCnt
->getFrameArea().Left(), rPt
.X() ),
949 dY
= std::max( pCnt
->getFrameArea().Top(), rPt
.Y() ) -
950 std::min( pCnt
->getFrameArea().Top(), rPt
.Y() );
951 // square of the difference will do fine here
952 const sal_uInt64 nDiff
= (dX
* dX
) + (dY
* dY
);
953 if ( pCnt
->getFrameArea().Top() <= rPt
.Y() )
955 if ( nDiff
< nDistance
)
957 //This one is the nearer one
958 nDistance
= nNearest
= nDiff
;
959 rpCnt
= pNearest
= pCnt
;
962 else if ( nDiff
< nNearest
)
967 pCnt
= pCnt
->GetNextContentFrame();
969 (bBody
!= pCnt
->IsInDocBody() || bFootnote
!= pCnt
->IsInFootnote()))
970 pCnt
= pCnt
->GetNextContentFrame();
972 } while ( pCnt
&& pLay
->IsAnLower( pCnt
) );
974 if (nDistance
== SAL_MAX_UINT64
)
981 static const SwContentFrame
* lcl_FindCnt( const Point
&rPt
, const SwContentFrame
*pCnt
,
982 const bool bBody
, const bool bFootnote
)
984 //Starting from pCnt searches the ContentFrame whose left upper corner is the
985 //nearest to the point.
986 //Always returns a ContentFrame.
988 //First the nearest Content inside the page which contains the Content is
989 //searched. Starting from this page the pages in both directions need to
990 //be considered. If possible a Content is returned whose Y-position is
992 const SwContentFrame
*pRet
, *pNew
;
993 const SwLayoutFrame
*pLay
= pCnt
->FindPageFrame();
994 sal_uInt64 nDist
; // not sure if a sal_Int32 would be enough?
996 nDist
= ::lcl_FindCntDiff( rPt
, pLay
, pNew
, bBody
, bFootnote
);
1001 nDist
= SAL_MAX_UINT64
;
1003 const SwContentFrame
*pNearest
= pRet
;
1004 sal_uInt64 nNearest
= nDist
;
1008 const SwLayoutFrame
*pPge
= pLay
;
1009 sal_uInt64 nOldNew
= SAL_MAX_UINT64
;
1010 for ( int i
= 0; pPge
->GetPrev() && (i
< 3); ++i
)
1012 pPge
= static_cast<const SwLayoutFrame
*>(pPge
->GetPrev());
1013 const sal_uInt64 nNew
= ::lcl_FindCntDiff( rPt
, pPge
, pNew
, bBody
, bFootnote
);
1016 if ( pNew
->getFrameArea().Top() <= rPt
.Y() )
1018 pRet
= pNearest
= pNew
;
1019 nDist
= nNearest
= nNew
;
1021 else if ( nNew
< nNearest
)
1027 else if (nOldNew
!= SAL_MAX_UINT64
&& nNew
> nOldNew
)
1034 nOldNew
= SAL_MAX_UINT64
;
1035 for ( int j
= 0; pPge
->GetNext() && (j
< 3); ++j
)
1037 pPge
= static_cast<const SwLayoutFrame
*>(pPge
->GetNext());
1038 const sal_uInt64 nNew
= ::lcl_FindCntDiff( rPt
, pPge
, pNew
, bBody
, bFootnote
);
1041 if ( pNew
->getFrameArea().Top() <= rPt
.Y() )
1043 pRet
= pNearest
= pNew
;
1044 nDist
= nNearest
= nNew
;
1046 else if ( nNew
< nNearest
)
1052 else if (nOldNew
!= SAL_MAX_UINT64
&& nNew
> nOldNew
)
1058 if ( pRet
->getFrameArea().Top() > rPt
.Y() )
1064 static void lcl_PointToPrt( Point
&rPoint
, const SwFrame
*pFrame
)
1066 SwRect
aTmp( pFrame
->getFramePrintArea() );
1067 aTmp
+= pFrame
->getFrameArea().Pos();
1068 if ( rPoint
.getX() < aTmp
.Left() )
1069 rPoint
.setX(aTmp
.Left());
1070 else if ( rPoint
.getX() > aTmp
.Right() )
1071 rPoint
.setX(aTmp
.Right());
1072 if ( rPoint
.getY() < aTmp
.Top() )
1073 rPoint
.setY(aTmp
.Top());
1074 else if ( rPoint
.getY() > aTmp
.Bottom() )
1075 rPoint
.setY(aTmp
.Bottom());
1079 /** Searches an anchor for paragraph bound objects starting from pOldAnch.
1081 * This is used to show anchors as well as changing anchors
1082 * when dragging paragraph bound objects.
1084 const SwContentFrame
*FindAnchor( const SwFrame
*pOldAnch
, const Point
&rNew
,
1085 const bool bBodyOnly
)
1087 //Search the nearest Cnt around the given document position in the text
1088 //flow. The given anchor is the starting Frame.
1089 const SwContentFrame
* pCnt
;
1090 if ( pOldAnch
->IsContentFrame() )
1092 pCnt
= static_cast<const SwContentFrame
*>(pOldAnch
);
1097 const SwLayoutFrame
*pTmpLay
= static_cast<const SwLayoutFrame
*>(pOldAnch
);
1098 if( pTmpLay
->IsRootFrame() )
1100 SwRect
aTmpRect( aTmp
, Size(0,0) );
1101 pTmpLay
= static_cast<const SwLayoutFrame
*>(::FindPage( aTmpRect
, pTmpLay
->Lower() ));
1103 pCnt
= pTmpLay
->GetContentPos( aTmp
, false, bBodyOnly
);
1106 //Take care to use meaningful ranges during search. This means to not enter
1107 //or leave header/footer in this case.
1108 const bool bBody
= pCnt
->IsInDocBody() || bBodyOnly
;
1109 const bool bFootnote
= !bBodyOnly
&& pCnt
->IsInFootnote();
1114 //#38848 drag from page margin into the body.
1115 const SwFrame
*pPage
= pCnt
->FindPageFrame();
1116 ::lcl_PointToPrt( aNew
, pPage
->GetUpper() );
1117 SwRect
aTmp( aNew
, Size( 0, 0 ) );
1118 pPage
= ::FindPage( aTmp
, pPage
);
1119 ::lcl_PointToPrt( aNew
, pPage
);
1122 if ( pCnt
->IsInDocBody() == bBody
&& pCnt
->getFrameArea().Contains( aNew
) )
1124 else if ( pOldAnch
->IsInDocBody() || pOldAnch
->IsPageFrame() )
1126 // Maybe the selected anchor is on the same page as the current anchor.
1127 // With this we won't run into problems with the columns.
1129 const SwContentFrame
*pTmp
= pCnt
->FindPageFrame()->
1130 GetContentPos( aTmp
, false, true );
1131 if ( pTmp
&& pTmp
->getFrameArea().Contains( aNew
) )
1135 //Starting from the anchor we now search in both directions until we found
1136 //the nearest one respectively.
1137 //Not the direct distance is relevant but the distance which needs to be
1138 //traveled through the text flow.
1139 const SwContentFrame
*pUpLst
;
1140 const SwContentFrame
*pUpFrame
= pCnt
;
1141 SwDistance nUp
, nUpLst
;
1142 ::lcl_CalcDownDist( nUp
, aNew
, pUpFrame
);
1143 SwDistance nDown
= nUp
;
1144 bool bNegAllowed
= true;// Make it possible to leave the negative section once.
1147 pUpLst
= pUpFrame
; nUpLst
= nUp
;
1148 pUpFrame
= pUpLst
->GetPrevContentFrame();
1150 (bBody
!= pUpFrame
->IsInDocBody() || bFootnote
!= pUpFrame
->IsInFootnote()))
1151 pUpFrame
= pUpFrame
->GetPrevContentFrame();
1154 ::lcl_CalcDownDist( nUp
, aNew
, pUpFrame
);
1155 //It makes sense to search further, if the distance grows inside
1157 if ( pUpLst
->IsInTab() && pUpFrame
->IsInTab() )
1159 while ( pUpFrame
&& ((nUpLst
< nUp
&& pUpFrame
->IsInTab()) ||
1160 bBody
!= pUpFrame
->IsInDocBody()) )
1162 pUpFrame
= pUpFrame
->GetPrevContentFrame();
1164 ::lcl_CalcDownDist( nUp
, aNew
, pUpFrame
);
1169 nUp
.m_nMain
= LONG_MAX
;
1170 if (nUp
.m_nMain
>= 0 && LONG_MAX
!= nUp
.m_nMain
)
1172 bNegAllowed
= false;
1173 if (nUpLst
.m_nMain
< 0) //don't take the wrong one, if the value
1174 //just changed from negative to positive.
1175 { pUpLst
= pUpFrame
;
1179 } while (pUpFrame
&& ((bNegAllowed
&& nUp
.m_nMain
< 0) || (nUp
<= nUpLst
)));
1181 const SwContentFrame
*pDownLst
;
1182 const SwContentFrame
*pDownFrame
= pCnt
;
1183 SwDistance nDownLst
;
1184 if (nDown
.m_nMain
< 0)
1185 nDown
.m_nMain
= LONG_MAX
;
1188 pDownLst
= pDownFrame
; nDownLst
= nDown
;
1189 pDownFrame
= pDownLst
->GetNextContentFrame();
1190 while ( pDownFrame
&&
1191 (bBody
!= pDownFrame
->IsInDocBody() || bFootnote
!= pDownFrame
->IsInFootnote()))
1192 pDownFrame
= pDownFrame
->GetNextContentFrame();
1195 ::lcl_CalcDownDist( nDown
, aNew
, pDownFrame
);
1196 if (nDown
.m_nMain
< 0)
1197 nDown
.m_nMain
= LONG_MAX
;
1198 //It makes sense to search further, if the distance grows inside
1200 if ( pDownLst
->IsInTab() && pDownFrame
->IsInTab() )
1203 && ((nDown
.m_nMain
!= LONG_MAX
&& pDownFrame
->IsInTab())
1204 || bBody
!= pDownFrame
->IsInDocBody()))
1206 pDownFrame
= pDownFrame
->GetNextContentFrame();
1208 ::lcl_CalcDownDist( nDown
, aNew
, pDownFrame
);
1209 if (nDown
.m_nMain
< 0)
1210 nDown
.m_nMain
= LONG_MAX
;
1215 nDown
.m_nMain
= LONG_MAX
;
1217 } while (pDownFrame
&& nDown
<= nDownLst
&& nDown
.m_nMain
!= LONG_MAX
1218 && nDownLst
.m_nMain
!= LONG_MAX
);
1220 //If we couldn't find one in both directions, we'll search the Content whose
1221 //left upper corner is the nearest to the point. Such a situation may
1222 //happen, if the point doesn't lay in the text flow but in any margin.
1223 if (nDownLst
.m_nMain
== LONG_MAX
&& nUpLst
.m_nMain
== LONG_MAX
)
1225 // If an OLE objects, which is contained in a fly frame
1226 // is resized in inplace mode and the new Position is outside the
1227 // fly frame, we do not want to leave our fly frame.
1228 if ( pCnt
->IsInFly() )
1231 return ::lcl_FindCnt( aNew
, pCnt
, bBody
, bFootnote
);
1234 return nDownLst
< nUpLst
? pDownLst
: pUpLst
;
1237 void SwFlyAtContentFrame::SetAbsPos( const Point
&rNew
)
1239 SwPageFrame
*pOldPage
= FindPageFrame();
1240 const SwRect
aOld( GetObjRectWithSpaces() );
1243 if( ( GetAnchorFrame()->IsVertical() && !GetAnchorFrame()->IsVertLR() ) || GetAnchorFrame()->IsRightToLeft() )
1244 aNew
.setX(aNew
.getX() + getFrameArea().Width());
1245 SwContentFrame
*pCnt
= const_cast<SwContentFrame
*>(::FindAnchor( GetAnchorFrame(), aNew
));
1246 if( pCnt
->IsProtected() )
1247 pCnt
= const_cast<SwContentFrame
*>(static_cast<const SwContentFrame
*>(GetAnchorFrame()));
1249 SwPageFrame
*pTmpPage
= nullptr;
1250 const bool bVert
= pCnt
->IsVertical();
1252 const bool bVertL2R
= pCnt
->IsVertLR();
1253 const bool bRTL
= pCnt
->IsRightToLeft();
1255 if( ( !bVert
!= !GetAnchorFrame()->IsVertical() ) ||
1256 ( !bRTL
!= !GetAnchorFrame()->IsRightToLeft() ) )
1259 aNew
.setX(aNew
.getX() + getFrameArea().Width());
1261 aNew
.setX(aNew
.getX() - getFrameArea().Width());
1264 if ( pCnt
->IsInDocBody() )
1266 //#38848 drag from page margin into the body.
1267 pTmpPage
= pCnt
->FindPageFrame();
1268 ::lcl_PointToPrt( aNew
, pTmpPage
->GetUpper() );
1269 SwRect
aTmp( aNew
, Size( 0, 0 ) );
1270 pTmpPage
= const_cast<SwPageFrame
*>(static_cast<const SwPageFrame
*>(::FindPage( aTmp
, pTmpPage
)));
1271 ::lcl_PointToPrt( aNew
, pTmpPage
);
1274 //Setup RelPos, only invalidate if requested.
1275 //rNew is an absolute position. We need to calculate the distance from rNew
1276 //to the anchor inside the text flow to correctly set RelPos.
1277 //!!!!!We can optimize here: FindAnchor could also return RelPos!
1278 const SwFrame
*pFrame
= nullptr;
1280 if ( pCnt
->getFrameArea().Contains( aNew
) )
1285 nY
= pCnt
->getFrameArea().Left() - rNew
.X();
1289 nY
+= pCnt
->getFrameArea().Width() - getFrameArea().Width();
1290 nY
-= pCnt
->GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid();
1293 nY
= rNew
.Y() - pCnt
->getFrameArea().Top() - pCnt
->GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid();
1298 pFrame
= ::lcl_CalcDownDist( aDist
, aNew
, pCnt
);
1299 nY
= aDist
.m_nMain
+ aDist
.m_nSub
;
1304 if ( pCnt
->IsFollow() )
1306 // Flys are never attached to the follow but always to the master,
1307 // which we're going to search now.
1308 const SwContentFrame
*pOriginal
= pCnt
;
1309 const SwContentFrame
*pFollow
= pCnt
;
1310 while ( pCnt
->IsFollow() )
1314 SwContentFrame
* pPrev
= pCnt
->GetPrevContentFrame();
1317 SAL_WARN("sw.core", "very unexpected missing PrevContentFrame");
1322 while ( pCnt
->GetFollow() != pFollow
);
1327 { const SwFrame
*pUp
= pFollow
->GetUpper();
1328 if( pUp
->IsVertical() )
1330 if ( pUp
->IsVertLR() )
1331 nDiff
+= pUp
->getFramePrintArea().Width() - pFollow
->GetRelPos().getX();
1333 nDiff
+= pFollow
->getFrameArea().Left() + pFollow
->getFrameArea().Width()
1334 - pUp
->getFrameArea().Left() - pUp
->getFramePrintArea().Left();
1337 nDiff
+= pUp
->getFramePrintArea().Height() - pFollow
->GetRelPos().Y();
1338 pFollow
= pFollow
->GetFollow();
1339 } while ( pFollow
!= pOriginal
);
1342 nX
= pCnt
->getFrameArea().Top() - pOriginal
->getFrameArea().Top();
1344 nX
= pCnt
->getFrameArea().Left() - pOriginal
->getFrameArea().Left();
1347 if ( nY
== LONG_MAX
)
1350 const SwTwips nTopForObjPos
= lcl_GetTopForObjPos(pCnt
, bVert
, bVertL2R
);
1354 nY
= rNew
.X() - nTopForObjPos
;
1356 nY
= nTopForObjPos
- rNew
.X();
1360 nY
= rNew
.Y() - nTopForObjPos
;
1364 SwFlyFrameFormat
*pFormat
= GetFormat();
1369 nX
+= rNew
.Y() - pCnt
->getFrameArea().Top();
1371 nX
= rNew
.Y() - pFrame
->getFrameArea().Top();
1377 if ( pCnt
->IsRightToLeft() )
1378 nX
+= pCnt
->getFrameArea().Right() - rNew
.X() - getFrameArea().Width();
1380 nX
+= rNew
.X() - pCnt
->getFrameArea().Left();
1384 if ( pFrame
->IsRightToLeft() )
1385 nX
+= pFrame
->getFrameArea().Right() - rNew
.X() - getFrameArea().Width();
1387 nX
= rNew
.X() - pFrame
->getFrameArea().Left();
1390 GetFormat()->GetDoc()->GetIDocumentUndoRedo().StartUndo( SwUndoId::START
, nullptr );
1392 if( pCnt
!= GetAnchorFrame() || ( IsAutoPos() && pCnt
->IsTextFrame() &&
1393 GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::HTML_MODE
)) )
1395 //Set the anchor attribute according to the new Cnt.
1396 SwFormatAnchor
aAnch( pFormat
->GetAnchor() );
1397 SwPosition pos
= *aAnch
.GetContentAnchor();
1398 if( IsAutoPos() && pCnt
->IsTextFrame() )
1400 SwTextFrame
const*const pTextFrame(static_cast<SwTextFrame
const*>(pCnt
));
1401 SwCursorMoveState
eTmpState( CursorMoveState::SetOnlyText
);
1403 if( pCnt
->GetModelPositionForViewPoint( &pos
, aPt
, &eTmpState
)
1404 && FrameContainsNode(*pTextFrame
, pos
.GetNodeIndex()))
1406 const SwTextAttr
*const pTextInputField
=
1407 pos
.GetNode().GetTextNode()->GetTextAttrAt(
1408 pos
.GetContentIndex(), RES_TXTATR_INPUTFIELD
, ::sw::GetTextAttrMode::Parent
);
1409 if (pTextInputField
!= nullptr)
1411 pos
.SetContent( pTextInputField
->GetStart() );
1413 ResetLastCharRectHeight();
1414 if( text::RelOrientation::CHAR
== pFormat
->GetVertOrient().GetRelationOrient() )
1416 if( text::RelOrientation::CHAR
== pFormat
->GetHoriOrient().GetRelationOrient() )
1421 pos
= pTextFrame
->MapViewToModelPos(TextFrameIndex(0));
1424 else if (pCnt
->IsTextFrame())
1426 pos
= static_cast<SwTextFrame
const*>(pCnt
)->MapViewToModelPos(TextFrameIndex(0));
1428 else // is that even possible? maybe if there was a change of anchor type from AT_FLY or something?
1430 assert(pCnt
->IsNoTextFrame());
1431 pos
.Assign(*static_cast<SwNoTextFrame
*>(pCnt
)->GetNode());
1433 aAnch
.SetAnchor( &pos
);
1435 // handle change of anchor node:
1436 // if count of the anchor frame also change, the fly frames have to be
1437 // re-created. Thus, delete all fly frames except the <this> before the
1438 // anchor attribute is change and re-create them afterwards.
1440 SwHandleAnchorNodeChg
aHandleAnchorNodeChg( *pFormat
, aAnch
, this );
1441 pFormat
->GetDoc()->SetAttr( aAnch
, *pFormat
);
1444 else if ( pTmpPage
&& pTmpPage
!= GetPageFrame() )
1445 GetPageFrame()->MoveFly( this, pTmpPage
);
1447 const Point aRelPos
= bVert
? Point( -nY
, nX
) : Point( nX
, nY
);
1448 ChgRelPos( aRelPos
);
1449 GetFormat()->GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::END
, nullptr );
1451 if ( pOldPage
!= FindPageFrame() )
1452 ::Notify_Background( GetVirtDrawObj(), pOldPage
, aOld
, PrepareHint::FlyFrameLeave
, false );
1455 /** method to assure that anchored object is registered at the correct
1459 takes over functionality of deleted method <SwFlyAtContentFrame::AssertPage()>
1461 void SwFlyAtContentFrame::RegisterAtCorrectPage()
1463 SwPageFrame
* pPageFrame( nullptr );
1464 if ( GetVertPosOrientFrame() )
1466 pPageFrame
= const_cast<SwPageFrame
*>(GetVertPosOrientFrame()->FindPageFrame());
1468 if ( pPageFrame
&& GetPageFrame() != pPageFrame
)
1470 RegisterAtPage(*pPageFrame
);
1474 void SwFlyAtContentFrame::RegisterAtPage(SwPageFrame
& rPageFrame
)
1476 assert(GetPageFrame() != &rPageFrame
);
1479 GetPageFrame()->MoveFly( this, &rPageFrame
);
1483 rPageFrame
.AppendFlyToPage( this );
1488 void SwFlyAtContentFrame::MakeObjPos()
1490 // if fly frame position is valid, nothing is to do. Thus, return
1491 if ( isFrameAreaPositionValid() )
1496 // #i26791# - validate position flag here.
1497 setFrameAreaPositionValid(true);
1499 // #i35911# - no calculation of new position, if
1500 // anchored object is marked that it clears its environment and its
1501 // environment is already cleared.
1502 // before checking for cleared environment
1503 // check, if member <mpVertPosOrientFrame> is set.
1504 if ( GetVertPosOrientFrame() &&
1505 ClearedEnvironment() && HasClearedEnvironment() )
1510 // use new class to position object
1511 objectpositioning::SwToContentAnchoredObjectPosition
1512 aObjPositioning( *GetVirtDrawObj() );
1513 aObjPositioning
.CalcPosition();
1515 SetVertPosOrientFrame ( aObjPositioning
.GetVertPosOrientFrame() );
1519 bool SwFlyAtContentFrame::InvalidationAllowed( const InvalidationType _nInvalid
) const
1521 bool bAllowed( SwFlyFreeFrame::InvalidationAllowed( _nInvalid
) );
1523 // forbiddance of base instance can't be over ruled.
1526 if ( _nInvalid
== INVALID_POS
||
1527 _nInvalid
== INVALID_ALL
)
1529 bAllowed
= InvalidationOfPosAllowed();
1536 bool SwFlyAtContentFrame::ShouldBwdMoved(SwLayoutFrame
* /*pNewUpper*/, bool& /*rReformat*/)
1541 const SwFlyAtContentFrame
* SwFlyAtContentFrame::GetFollow() const
1543 return static_cast<const SwFlyAtContentFrame
*>(SwFlowFrame::GetFollow());
1546 SwFlyAtContentFrame
* SwFlyAtContentFrame::GetFollow()
1548 return static_cast<SwFlyAtContentFrame
*>(SwFlowFrame::GetFollow());
1551 SwLayoutFrame
*SwFrame::GetNextFlyLeaf( MakePageType eMakePage
)
1553 auto pFly
= dynamic_cast<SwFlyAtContentFrame
*>(FindFlyFrame());
1554 assert(pFly
&& "GetNextFlyLeaf: missing fly frame");
1555 assert(pFly
->IsFlySplitAllowed() && "GetNextFlyLeaf: fly split not allowed");
1557 if (pFly
->HasFollow())
1559 // If we already have a follow, then no need to create a new one, just use it.
1560 return pFly
->GetFollow();
1563 SwTextFrame
* pFlyAnchor
= pFly
->FindAnchorCharFrame();
1567 // In case our fly frame is split already, but not yet moved, then FindAnchorCharFrame()
1568 // won't find the anchor, since it wants a follow anchor, but there is no follow anchor yet.
1569 // In this case work with a plain anchor, so FindSctFrame() works to find out we're in a
1571 auto pAnchorFrame
= const_cast<SwFrame
*>(pFly
->GetAnchorFrame());
1572 if (pAnchorFrame
&& pAnchorFrame
->IsTextFrame())
1574 pFlyAnchor
= static_cast<SwTextFrame
*>(pAnchorFrame
);
1578 bool bBody
= pFlyAnchor
&& pFlyAnchor
->IsInDocBody();
1579 SwLayoutFrame
*pLayLeaf
= nullptr;
1580 // Look up the first candidate.
1581 SwSectionFrame
* pFlyAnchorSection
= pFlyAnchor
? pFlyAnchor
->FindSctFrame() : nullptr;
1582 bool bNesting
= false;
1583 if (pFlyAnchorSection
)
1585 // The anchor is in a section.
1588 SwTabFrame
* pFlyAnchorTab
= pFlyAnchor
->FindTabFrame();
1591 // The anchor is in table as well.
1592 if (pFlyAnchorTab
->FindSctFrame() == pFlyAnchorSection
)
1594 // We're in a table-in-section, no anchor move in this case, because that would
1595 // mean we're not in a table anymore.
1602 // We can't just move the split anchor to the next page, that would be outside the section.
1603 // Rather split that section as well.
1604 pLayLeaf
= pFlyAnchorSection
->GetNextSctLeaf(eMakePage
);
1607 else if (IsTabFrame())
1609 // If we're in a table, try to find the next frame of the table's last content.
1610 SwFrame
* pContent
= static_cast<SwTabFrame
*>(this)->FindLastContentOrTable();
1611 pLayLeaf
= pContent
? pContent
->GetUpper() : nullptr;
1615 pLayLeaf
= GetNextLayoutLeaf();
1618 SwLayoutFrame
* pOldLayLeaf
= nullptr;
1623 // If we're anchored in a body frame, the candidate has to be in a body frame as well.
1624 bool bLeftBody
= bBody
&& !pLayLeaf
->IsInDocBody();
1625 // If the candidate is in a fly, make sure that the candidate is a child of our follow.
1626 bool bLeftFly
= pLayLeaf
->IsInFly() && pLayLeaf
->FindFlyFrame() != pFly
->GetFollow();
1627 bool bSameBody
= false;
1628 if (bBody
&& pLayLeaf
->IsInDocBody())
1630 // Make sure the candidate is not inside the same body frame, that would prevent
1631 // inserting a new page.
1632 if (pFlyAnchor
->FindBodyFrame() == pLayLeaf
->FindBodyFrame())
1638 if (bLeftFly
&& pFlyAnchor
&& pFlyAnchor
->IsInTab()
1639 && FindTabFrame() == pLayLeaf
->FindTabFrame())
1641 // This is an inner fly (parent is an inline or a floating table), then the follow
1642 // anchor will be just next to us.
1643 SwLayoutFrame
* pFlyAnchorUpper
= pFlyAnchor
->GetUpper();
1644 pOldLayLeaf
= pLayLeaf
;
1645 pLayLeaf
= pFlyAnchorUpper
;
1650 if (bLeftBody
|| bLeftFly
|| bSameBody
)
1652 // The above conditions are not held, reject.
1653 pOldLayLeaf
= pLayLeaf
;
1654 pLayLeaf
= pLayLeaf
->GetNextLayoutLeaf();
1656 if (pLayLeaf
&& pLayLeaf
->IsInDocBody() && !bSameBody
&& !pLayLeaf
->IsInFly() && pLayLeaf
->IsInTab())
1658 // We found a next leaf in a next body frame, which is in an inline table. Make
1659 // sure we won't insert the follow anchor inside the table, but before it.
1660 SwTabFrame
* pTabFrame
= pLayLeaf
->FindTabFrame();
1661 pLayLeaf
= pTabFrame
->GetUpper();
1669 // No candidate: insert a page and try again.
1670 if (eMakePage
== MAKEPAGE_INSERT
)
1672 InsertPage(FindPageFrame(), false);
1673 // If we already had a candidate, continue trying with that instead of starting from
1675 pLayLeaf
= pOldLayLeaf
? pOldLayLeaf
: GetNextLayoutLeaf();
1684 SwFlyAtContentFrame
* pNew
= nullptr;
1685 // Find the anchor frame to split.
1688 // Split the anchor at char 0: all the content goes to the follow of the anchor.
1689 pFlyAnchor
->SplitFrame(TextFrameIndex(0));
1690 auto pNext
= static_cast<SwTextFrame
*>(pFlyAnchor
->GetNext());
1691 // The nesting case just splits the inner fly; the outer fly will split and move.
1694 // Move the new anchor frame, before the first child of pLayLeaf.
1695 pNext
->MoveSubTree(pLayLeaf
, pLayLeaf
->Lower());
1698 // Now create the follow of the fly and anchor it in the master of the anchor.
1699 pNew
= new SwFlyAtContentFrame(*pFly
);
1700 while (pFlyAnchor
->IsFollow())
1702 pFlyAnchor
= pFlyAnchor
->FindMaster();
1704 pFlyAnchor
->AppendFly(pNew
);
1711 void SwRootFrame::DeleteEmptyFlys_()
1713 assert(mpFlyDestroy
);
1715 while (!mpFlyDestroy
->empty())
1717 SwFlyFrame
* pFly
= *mpFlyDestroy
->begin();
1718 mpFlyDestroy
->erase( mpFlyDestroy
->begin() );
1719 // Allow deletion of non-empty flys: a fly with no content is still formatted to have a
1720 // height of MINLAY.
1721 if (!pFly
->ContainsContent() && !pFly
->IsDeleteForbidden())
1723 SwFrame::DestroyFrame(pFly
);
1728 bool SwRootFrame::IsInFlyDelList( SwFlyFrame
* pFly
) const
1735 return mpFlyDestroy
->find(pFly
) != mpFlyDestroy
->end();
1738 const SwFlyAtContentFrame
* SwFlyAtContentFrame::GetPrecede() const
1740 return static_cast<const SwFlyAtContentFrame
*>(SwFlowFrame::GetPrecede());
1743 SwFlyAtContentFrame
* SwFlyAtContentFrame::GetPrecede()
1745 return static_cast<SwFlyAtContentFrame
*>(SwFlowFrame::GetPrecede());
1748 void SwFlyAtContentFrame::DelEmpty()
1750 SwTextFrame
* pAnchor
= FindAnchorCharFrame();
1753 if (SwFlowFrame
* pAnchorPrecede
= pAnchor
->GetPrecede())
1755 // The anchor has a precede: invalidate it so that JoinFrame() is called on it.
1756 pAnchorPrecede
->GetFrame().InvalidateSize();
1760 SwFlyAtContentFrame
* pMaster
= IsFollow() ? GetPrecede() : nullptr;
1763 pMaster
->SetFollow(GetFollow());
1766 SwFlyAtContentFrame
* pFollow
= GetFollow();
1769 // I'll be deleted, so invalidate the position of my follow, so it can move up.
1770 pFollow
->InvalidatePos();
1776 SwFrameAreaDefinition::FrameAreaWriteAccess
aFrm(*this);
1779 InvalidateObjRectWithSpaces();
1783 getRootFrame()->InsertEmptyFly(this);
1787 void SwRootFrame::InsertEmptyFly(SwFlyFrame
* pDel
)
1791 mpFlyDestroy
.reset(new SwFlyDestroyList
);
1794 mpFlyDestroy
->insert(pDel
);
1797 SwLayoutFrame
* SwFrame::GetPrevFlyLeaf()
1799 auto pFly
= dynamic_cast<SwFlyAtContentFrame
*>(FindFlyFrame());
1800 assert(pFly
&& "GetPrevFlyLeaf: missing fly frame");
1801 if (!pFly
->IsFlySplitAllowed())
1806 return pFly
->GetPrecede();
1809 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */