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 "objectformattertxtfrm.hxx"
21 #include <IDocumentUndoRedo.hxx>
22 #include <sortedobjs.hxx>
23 #include <rootfrm.hxx>
24 #include <anchoredobject.hxx>
26 #include <pagefrm.hxx>
28 #include <layouter.hxx>
29 #include <fmtanchr.hxx>
30 #include <fmtwrapinfluenceonobjpos.hxx>
31 #include <fmtfollowtextflow.hxx>
35 #include <fmtornt.hxx>
36 #include <textboxhelper.hxx>
37 #include <osl/diagnose.h>
39 using namespace ::com::sun::star
;
43 // little helper class to forbid follow formatting for the given text frame
44 class SwForbidFollowFormat
47 SwTextFrame
& mrTextFrame
;
48 const bool bOldFollowFormatAllowed
;
51 explicit SwForbidFollowFormat( SwTextFrame
& _rTextFrame
)
52 : mrTextFrame( _rTextFrame
),
53 bOldFollowFormatAllowed( _rTextFrame
.FollowFormatAllowed() )
55 mrTextFrame
.ForbidFollowFormat();
58 ~SwForbidFollowFormat()
60 if ( bOldFollowFormatAllowed
)
62 mrTextFrame
.AllowFollowFormat();
69 SwObjectFormatterTextFrame::SwObjectFormatterTextFrame( SwTextFrame
& _rAnchorTextFrame
,
70 const SwPageFrame
& _rPageFrame
,
71 SwTextFrame
* _pMasterAnchorTextFrame
,
72 SwLayAction
* _pLayAction
)
73 : SwObjectFormatter( _rPageFrame
, _pLayAction
, true ),
74 mrAnchorTextFrame( _rAnchorTextFrame
),
75 mpMasterAnchorTextFrame( _pMasterAnchorTextFrame
)
79 SwObjectFormatterTextFrame::~SwObjectFormatterTextFrame()
83 std::unique_ptr
<SwObjectFormatterTextFrame
> SwObjectFormatterTextFrame::CreateObjFormatter(
84 SwTextFrame
& _rAnchorTextFrame
,
85 const SwPageFrame
& _rPageFrame
,
86 SwLayAction
* _pLayAction
)
88 std::unique_ptr
<SwObjectFormatterTextFrame
> pObjFormatter
;
90 // determine 'master' of <_rAnchorTextFrame>, if anchor frame is a follow text frame.
91 SwTextFrame
* pMasterOfAnchorFrame
= nullptr;
92 if ( _rAnchorTextFrame
.IsFollow() )
94 pMasterOfAnchorFrame
= _rAnchorTextFrame
.FindMaster();
95 while ( pMasterOfAnchorFrame
&& pMasterOfAnchorFrame
->IsFollow() )
97 pMasterOfAnchorFrame
= pMasterOfAnchorFrame
->FindMaster();
101 // create object formatter, if floating screen objects are registered
102 // at anchor frame (or at 'master' anchor frame)
103 if ( _rAnchorTextFrame
.GetDrawObjs() ||
104 ( pMasterOfAnchorFrame
&& pMasterOfAnchorFrame
->GetDrawObjs() ) )
107 new SwObjectFormatterTextFrame( _rAnchorTextFrame
, _rPageFrame
,
108 pMasterOfAnchorFrame
, _pLayAction
));
111 return pObjFormatter
;
114 SwFrame
& SwObjectFormatterTextFrame::GetAnchorFrame()
116 return mrAnchorTextFrame
;
119 // #i40147# - add parameter <_bCheckForMovedFwd>.
120 bool SwObjectFormatterTextFrame::DoFormatObj( SwAnchoredObject
& _rAnchoredObj
,
121 const bool _bCheckForMovedFwd
)
123 // consider, if the layout action has to be
124 // restarted due to a delete of a page frame.
125 if ( GetLayAction() && GetLayAction()->IsAgain() )
130 bool bSuccess( true );
132 if ( _rAnchoredObj
.IsFormatPossible() )
134 _rAnchoredObj
.SetRestartLayoutProcess( false );
136 FormatObj_( _rAnchoredObj
);
137 // consider, if the layout action has to be
138 // restarted due to a delete of a page frame.
139 if ( GetLayAction() && GetLayAction()->IsAgain() )
144 // check, if layout process has to be restarted.
145 // if yes, perform needed invalidations.
147 // no restart of layout process,
148 // if anchored object is anchored inside a Writer fly frame,
149 // its position is already locked, and it follows the text flow.
150 const bool bRestart
=
151 _rAnchoredObj
.RestartLayoutProcess() &&
152 !( _rAnchoredObj
.PositionLocked() &&
153 _rAnchoredObj
.GetAnchorFrame()->IsInFly() &&
154 _rAnchoredObj
.GetFrameFormat().GetFollowTextFlow().GetValue() );
158 InvalidatePrevObjs( _rAnchoredObj
);
159 InvalidateFollowObjs( _rAnchoredObj
);
162 // format anchor text frame, if wrapping style influence of the object
163 // has to be considered and it's <NONE_SUCCESSIVE_POSITIONED>
164 // #i3317# - consider also anchored objects, whose
165 // wrapping style influence is temporarily considered.
166 // #i40147# - consider also anchored objects, for
167 // whose the check of a moved forward anchor frame is requested.
168 // revise decision made for i3317:
169 // anchored objects, whose wrapping style influence is temporarily considered,
170 // have to be considered in method <SwObjectFormatterTextFrame::DoFormatObjs()>
172 _rAnchoredObj
.ConsiderObjWrapInfluenceOnObjPos() &&
173 ( _bCheckForMovedFwd
||
174 _rAnchoredObj
.GetFrameFormat().GetWrapInfluenceOnObjPos().
175 // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE
176 GetWrapInfluenceOnObjPos( true ) ==
177 // #i35017# - constant name has changed
178 text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE
) )
180 // #i26945# - check conditions for move forward of
182 // determine, if anchor text frame has previous frame
183 const bool bDoesAnchorHadPrev
= ( mrAnchorTextFrame
.GetIndPrev() != nullptr );
185 // #i40141# - use new method - it also formats the
186 // section the anchor frame is in.
187 FormatAnchorFrameForCheckMoveFwd();
190 if ( _rAnchoredObj
.HasClearedEnvironment() )
192 _rAnchoredObj
.SetClearedEnvironment( true );
193 // #i44049# - consider, that anchor frame
194 // could already been marked to move forward.
195 SwPageFrame
* pAnchorPageFrame( mrAnchorTextFrame
.FindPageFrame() );
196 if ( pAnchorPageFrame
!= _rAnchoredObj
.GetPageFrame() )
198 bool bInsert( true );
199 sal_uInt32
nToPageNum( 0 );
200 const SwDoc
& rDoc
= *(GetPageFrame().GetFormat()->GetDoc());
201 if ( SwLayouter::FrameMovedFwdByObjPos(
202 rDoc
, mrAnchorTextFrame
, nToPageNum
) )
204 if ( nToPageNum
< pAnchorPageFrame
->GetPhyPageNum() )
205 SwLayouter::RemoveMovedFwdFrame( rDoc
, mrAnchorTextFrame
);
211 SwLayouter::InsertMovedFwdFrame( rDoc
, mrAnchorTextFrame
,
212 pAnchorPageFrame
->GetPhyPageNum() );
213 mrAnchorTextFrame
.InvalidatePos();
215 InvalidatePrevObjs( _rAnchoredObj
);
216 InvalidateFollowObjs( _rAnchoredObj
);
220 OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObj(..)> - anchor frame not marked to move forward" );
224 else if ( !mrAnchorTextFrame
.IsFollow() && bDoesAnchorHadPrev
)
226 // index of anchored object in collection of page numbers and
228 sal_uInt32
nIdx( CountOfCollected() );
229 OSL_ENSURE( nIdx
> 0,
230 "<SwObjectFormatterTextFrame::DoFormatObj(..)> - anchored object not collected!?" );
233 sal_uInt32
nToPageNum( 0 );
235 bool bDummy( false );
236 bool bPageHasFlysAnchoredBelowThis(false);
237 // see how SwObjectFormatter::FormatObjsAtFrame_() checks
238 // "pPageFrameOfAnchor == &mrPageFrame" - only caller relevant for
240 assert(GetPageFrame().GetPhyPageNum() == GetPgNumOfCollected(nIdx
));
241 if ( SwObjectFormatterTextFrame::CheckMovedFwdCondition( *GetCollectedObj( nIdx
),
243 IsCollectedAnchoredAtMaster( nIdx
),
245 bPageHasFlysAnchoredBelowThis
))
247 // #i49987# - consider, that anchor frame
248 // could already been marked to move forward.
249 bool bInsert( true );
250 sal_uInt32
nMovedFwdToPageNum( 0 );
251 const SwDoc
& rDoc
= *(GetPageFrame().GetFormat()->GetDoc());
252 if ( SwLayouter::FrameMovedFwdByObjPos(
253 rDoc
, mrAnchorTextFrame
, nMovedFwdToPageNum
) )
255 if ( nMovedFwdToPageNum
< nToPageNum
)
257 if (!bPageHasFlysAnchoredBelowThis
)
259 SwLayouter::RemoveMovedFwdFrame(rDoc
, mrAnchorTextFrame
);
267 // Indicate that anchor text frame has to move forward and
268 // invalidate its position to force a re-format.
269 if (!bPageHasFlysAnchoredBelowThis
)
271 SwLayouter::InsertMovedFwdFrame(rDoc
,
272 mrAnchorTextFrame
, nToPageNum
);
274 mrAnchorTextFrame
.InvalidatePos();
276 // Indicate restart of the layout process
279 // If needed, invalidate previous objects anchored at same anchor
281 InvalidatePrevObjs( _rAnchoredObj
);
283 // Invalidate object and following objects for the restart of the
285 InvalidateFollowObjs( _rAnchoredObj
);
289 OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObj(..)> - anchor frame not marked to move forward" );
293 // i40155# - mark anchor frame not to wrap around
294 // objects under the condition, that its follow contains all its text.
295 else if ( !mrAnchorTextFrame
.IsFollow() &&
296 mrAnchorTextFrame
.GetFollow() &&
297 mrAnchorTextFrame
.GetFollow()->GetOffset() == TextFrameIndex(0))
299 SwLayouter::RemoveMovedFwdFrame(
300 *(mrAnchorTextFrame
.FindPageFrame()->GetFormat()->GetDoc()),
309 bool SwObjectFormatterTextFrame::DoFormatObjs()
311 if ( !mrAnchorTextFrame
.isFrameAreaDefinitionValid() )
313 if ( GetLayAction() &&
314 mrAnchorTextFrame
.FindPageFrame() != &GetPageFrame() )
316 // notify layout action, thus is can restart the layout process on
318 GetLayAction()->SetAgain(true);
322 // the anchor text frame has to be valid, thus assert.
323 OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObjs()> called for invalidate anchor text frame." );
329 bool bSuccess( true );
331 if ( mrAnchorTextFrame
.IsFollow() )
333 // Only floating screen objects anchored as-character are directly
334 // registered at a follow text frame. The other floating screen objects
335 // are registered at the 'master' anchor text frame.
336 // Thus, format the other floating screen objects through the 'master'
338 OSL_ENSURE( mpMasterAnchorTextFrame
,
339 "SwObjectFormatterTextFrame::DoFormatObjs() - missing 'master' anchor text frame" );
340 bSuccess
= FormatObjsAtFrame_( mpMasterAnchorTextFrame
);
344 // format of as-character anchored floating screen objects - no failure
345 // expected on the format of these objects.
346 bSuccess
= FormatObjsAtFrame_();
351 bSuccess
= FormatObjsAtFrame_();
354 // consider anchored objects, whose wrapping style influence are temporarily
357 ( ConsiderWrapOnObjPos() ||
358 ( !mrAnchorTextFrame
.IsFollow() &&
359 AtLeastOneObjIsTmpConsiderWrapInfluence() ) ) )
361 const bool bDoesAnchorHadPrev
= ( mrAnchorTextFrame
.GetIndPrev() != nullptr );
363 // Format anchor text frame after its objects are formatted.
364 // Note: The format of the anchor frame also formats the invalid
365 // previous frames of the anchor frame. The format of the previous
366 // frames is needed to get a correct result of format of the
367 // anchor frame for the following check for moved forward anchors
368 // #i40141# - use new method - it also formats the
369 // section the anchor frame is in.
370 FormatAnchorFrameForCheckMoveFwd();
372 sal_uInt32
nToPageNum( 0 );
374 bool bInFollow( false );
375 bool bPageHasFlysAnchoredBelowThis(false);
376 SwAnchoredObject
* pObj
= nullptr;
377 if ( !mrAnchorTextFrame
.IsFollow() )
379 pObj
= GetFirstObjWithMovedFwdAnchor(
380 // #i35017# - constant name has changed
381 text::WrapInfluenceOnPosition::ONCE_CONCURRENT
,
382 nToPageNum
, bInFollow
, bPageHasFlysAnchoredBelowThis
);
385 if ( pObj
&& pObj
->HasClearedEnvironment() )
387 pObj
->SetClearedEnvironment( true );
388 // #i44049# - consider, that anchor frame
389 // could already been marked to move forward.
390 SwPageFrame
* pAnchorPageFrame( mrAnchorTextFrame
.FindPageFrame() );
391 // #i43913# - consider, that anchor frame
392 // is a follow or is in a follow row, which will move forward.
393 if ( pAnchorPageFrame
!= pObj
->GetPageFrame() ||
396 bool bInsert( true );
397 sal_uInt32
nTmpToPageNum( 0 );
398 const SwDoc
& rDoc
= *(GetPageFrame().GetFormat()->GetDoc());
399 if ( SwLayouter::FrameMovedFwdByObjPos(
400 rDoc
, mrAnchorTextFrame
, nTmpToPageNum
) )
402 if ( nTmpToPageNum
< pAnchorPageFrame
->GetPhyPageNum() )
404 if (!bPageHasFlysAnchoredBelowThis
)
406 SwLayouter::RemoveMovedFwdFrame(rDoc
, mrAnchorTextFrame
);
414 if (!bPageHasFlysAnchoredBelowThis
)
416 SwLayouter::InsertMovedFwdFrame(rDoc
, mrAnchorTextFrame
,
417 pAnchorPageFrame
->GetPhyPageNum());
419 mrAnchorTextFrame
.InvalidatePos();
421 InvalidatePrevObjs( *pObj
);
422 InvalidateFollowObjs( *pObj
);
426 OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObjs(..)> - anchor frame not marked to move forward" );
430 else if ( pObj
&& bDoesAnchorHadPrev
)
432 // Object found, whose anchor is moved forward
434 // #i49987# - consider, that anchor frame
435 // could already been marked to move forward.
436 bool bInsert( true );
437 sal_uInt32
nMovedFwdToPageNum( 0 );
438 const SwDoc
& rDoc
= *(GetPageFrame().GetFormat()->GetDoc());
439 if ( SwLayouter::FrameMovedFwdByObjPos(
440 rDoc
, mrAnchorTextFrame
, nMovedFwdToPageNum
) )
442 if ( nMovedFwdToPageNum
< nToPageNum
)
443 SwLayouter::RemoveMovedFwdFrame( rDoc
, mrAnchorTextFrame
);
449 // Indicate that anchor text frame has to move forward and
450 // invalidate its position to force a re-format.
451 SwLayouter::InsertMovedFwdFrame( rDoc
, mrAnchorTextFrame
, nToPageNum
);
452 mrAnchorTextFrame
.InvalidatePos();
454 // Indicate restart of the layout process
457 // If needed, invalidate previous objects anchored at same anchor
459 InvalidatePrevObjs( *pObj
);
461 // Invalidate object and following objects for the restart of the
463 InvalidateFollowObjs( *pObj
);
467 OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObjs(..)> - anchor frame not marked to move forward" );
470 // #i40155# - mark anchor frame not to wrap around
471 // objects under the condition, that its follow contains all its text.
472 else if ( !mrAnchorTextFrame
.IsFollow() &&
473 mrAnchorTextFrame
.GetFollow() &&
474 mrAnchorTextFrame
.GetFollow()->GetOffset() == TextFrameIndex(0))
476 SwLayouter::RemoveMovedFwdFrame(
477 *(mrAnchorTextFrame
.FindPageFrame()->GetFormat()->GetDoc()),
485 void SwObjectFormatterTextFrame::InvalidatePrevObjs( SwAnchoredObject
& _rAnchoredObj
)
487 // invalidate all previous objects, whose wrapping influence on the object
488 // positioning is <NONE_CONCURRENT_POSITIONED>.
489 // Note: list of objects at anchor frame is sorted by this property.
490 if ( _rAnchoredObj
.GetFrameFormat().GetWrapInfluenceOnObjPos().
491 // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE
492 GetWrapInfluenceOnObjPos( true ) !=
493 // #i35017# - constant name has changed
494 text::WrapInfluenceOnPosition::ONCE_CONCURRENT
)
497 const SwSortedObjs
* pObjs
= GetAnchorFrame().GetDrawObjs();
501 // determine start index
502 size_t i
= pObjs
->ListPosOf( _rAnchoredObj
);
506 SwAnchoredObject
* pAnchoredObj
= (*pObjs
)[i
];
507 if ( pAnchoredObj
->GetFrameFormat().GetWrapInfluenceOnObjPos().
508 // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE
509 GetWrapInfluenceOnObjPos( true ) ==
510 // #i35017# - constant name has changed
511 text::WrapInfluenceOnPosition::ONCE_CONCURRENT
)
513 pAnchoredObj
->InvalidateObjPosForConsiderWrapInfluence();
518 void SwObjectFormatterTextFrame::InvalidateFollowObjs( SwAnchoredObject
& _rAnchoredObj
)
520 _rAnchoredObj
.InvalidateObjPosForConsiderWrapInfluence();
522 const SwSortedObjs
* pObjs
= GetPageFrame().GetSortedObjs();
525 // determine start index
526 for ( size_t i
= pObjs
->ListPosOf( _rAnchoredObj
) + 1; i
< pObjs
->size(); ++i
)
528 SwAnchoredObject
* pAnchoredObj
= (*pObjs
)[i
];
529 pAnchoredObj
->InvalidateObjPosForConsiderWrapInfluence();
534 SwAnchoredObject
* SwObjectFormatterTextFrame::GetFirstObjWithMovedFwdAnchor(
535 const sal_Int16 _nWrapInfluenceOnPosition
,
536 sal_uInt32
& _noToPageNum
,
538 bool& o_rbPageHasFlysAnchoredBelowThis
)
540 // #i35017# - constant names have changed
541 OSL_ENSURE( _nWrapInfluenceOnPosition
== text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE
||
542 _nWrapInfluenceOnPosition
== text::WrapInfluenceOnPosition::ONCE_CONCURRENT
,
543 "<SwObjectFormatterTextFrame::GetFirstObjWithMovedFwdAnchor(..)> - invalid value for parameter <_nWrapInfluenceOnPosition>" );
545 SwAnchoredObject
* pRetAnchoredObj
= nullptr;
548 for ( ; i
< CountOfCollected(); ++i
)
550 SwAnchoredObject
* pAnchoredObj
= GetCollectedObj(i
);
551 if ( pAnchoredObj
->ConsiderObjWrapInfluenceOnObjPos() &&
552 pAnchoredObj
->GetFrameFormat().GetWrapInfluenceOnObjPos().
553 // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE
554 GetWrapInfluenceOnObjPos( true ) == _nWrapInfluenceOnPosition
)
556 // see how SwObjectFormatter::FormatObjsAtFrame_() checks
557 // "pPageFrameOfAnchor == &mrPageFrame" - only caller relevant for
559 assert(GetPageFrame().GetPhyPageNum() == GetPgNumOfCollected(i
));
560 // #i26945# - use new method <_CheckMovedFwdCondition(..)>
562 if ( SwObjectFormatterTextFrame::CheckMovedFwdCondition( *GetCollectedObj( i
),
564 IsCollectedAnchoredAtMaster( i
),
565 _noToPageNum
, _boInFollow
,
566 o_rbPageHasFlysAnchoredBelowThis
) )
568 pRetAnchoredObj
= pAnchoredObj
;
574 return pRetAnchoredObj
;
577 static SwRowFrame
const* FindTopLevelRowFrame(SwFrame
const*const pFrame
)
579 SwRowFrame
* pRow
= const_cast<SwFrame
*>(pFrame
)->FindRowFrame();
580 // looks like SwTabFrame has mbInfTab = true so go up 2 levels
581 while (pRow
->GetUpper()->GetUpper()->IsInTab())
583 pRow
= pRow
->GetUpper()->GetUpper()->FindRowFrame();
588 static SwContentFrame
const* FindFrameInBody(SwAnchoredObject
const& rAnchored
)
590 SwFrame
const*const pAnchor(rAnchored
.GetAnchorFrame());
592 if (pAnchor
->IsPageFrame() || pAnchor
->FindFooterOrHeader())
596 if (pAnchor
->IsInFly())
598 return FindFrameInBody(*pAnchor
->FindFlyFrame());
600 if (pAnchor
->IsInFootnote())
602 return pAnchor
->FindFootnoteFrame()->GetRef();
604 assert(pAnchor
->IsInDocBody());
605 assert(pAnchor
->IsContentFrame());
606 return static_cast<SwContentFrame
const*>(pAnchor
);
610 // - replace private method by corresponding static public method
611 bool SwObjectFormatterTextFrame::CheckMovedFwdCondition(
612 SwAnchoredObject
& _rAnchoredObj
,
613 SwPageFrame
const& rFromPageFrame
,
614 const bool _bAnchoredAtMasterBeforeFormatAnchor
,
615 sal_uInt32
& _noToPageNum
,
617 bool& o_rbPageHasFlysAnchoredBelowThis
)
619 const sal_uInt32
_nFromPageNum(rFromPageFrame
.GetPhyPageNum());
620 bool bAnchorIsMovedForward( false );
622 SwPageFrame
* pPageFrameOfAnchor
= _rAnchoredObj
.FindPageFrameOfAnchor();
623 if ( pPageFrameOfAnchor
)
625 const sal_uInt32 nPageNum
= pPageFrameOfAnchor
->GetPhyPageNum();
626 if ( nPageNum
> _nFromPageNum
)
628 _noToPageNum
= nPageNum
;
629 // Handling of special case:
630 // If anchor frame is move forward into a follow flow row,
631 // <_noToPageNum> is set to <_nFromPageNum + 1>, because it is
632 // possible that the anchor page frame isn't valid, because the
633 // page distance between master row and follow flow row is greater
635 if ( _noToPageNum
> (_nFromPageNum
+ 1) )
637 SwFrame
* pAnchorFrame
= _rAnchoredObj
.GetAnchorFrameContainingAnchPos();
638 if ( pAnchorFrame
->IsInTab() &&
639 pAnchorFrame
->IsInFollowFlowRow() )
641 _noToPageNum
= _nFromPageNum
+ 1;
644 bAnchorIsMovedForward
= true;
647 // #i26945# - check, if an at-paragraph|at-character
648 // anchored object is now anchored at a follow text frame, which will be
649 // on the next page. Also check, if an at-character anchored object
650 // is now anchored at a text frame, which is in a follow flow row,
651 // which will be on the next page.
652 if ( !bAnchorIsMovedForward
&&
653 _bAnchoredAtMasterBeforeFormatAnchor
&&
654 ((_rAnchoredObj
.GetFrameFormat().GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_CHAR
) ||
655 (_rAnchoredObj
.GetFrameFormat().GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PARA
)))
657 SwFrame
* pAnchorFrame
= _rAnchoredObj
.GetAnchorFrameContainingAnchPos();
658 OSL_ENSURE( pAnchorFrame
->IsTextFrame(),
659 "<SwObjectFormatterTextFrame::CheckMovedFwdCondition(..) - wrong type of anchor frame>" );
660 SwTextFrame
* pAnchorTextFrame
= static_cast<SwTextFrame
*>(pAnchorFrame
);
661 bool bCheck( false );
662 if ( pAnchorTextFrame
->IsFollow() )
666 else if( pAnchorTextFrame
->IsInTab() )
668 const SwRowFrame
* pMasterRow
= pAnchorTextFrame
->IsInFollowFlowRow();
670 pMasterRow
->FindPageFrame() == pPageFrameOfAnchor
)
677 // check, if found text frame will be on the next page
678 // by checking, if it's in a column, which has no next.
679 SwFrame
* pColFrame
= pAnchorTextFrame
->FindColFrame();
680 while ( pColFrame
&& !pColFrame
->GetNext() )
682 pColFrame
= pColFrame
->FindColFrame();
684 if ( !pColFrame
|| !pColFrame
->GetNext() )
686 _noToPageNum
= _nFromPageNum
+ 1;
687 bAnchorIsMovedForward
= true;
694 if (bAnchorIsMovedForward
)
696 // tdf#138518 try to determine if there is a fly on page rFromPageFrame
697 // which is anchored in a frame that is "below" the anchor frame
698 // of _rAnchoredObj, such that it should move to the next page before
699 // _rAnchoredObj does
700 if (auto * pObjs
= rFromPageFrame
.GetSortedObjs())
702 for (SwAnchoredObject
*const pObj
: *pObjs
)
704 SwPageFrame
const*const pObjAnchorPage(pObj
->FindPageFrameOfAnchor());
705 assert(pObjAnchorPage
);
706 if ((pObjAnchorPage
== &rFromPageFrame
707 ? _boInFollow
// same-page but will move forward
708 : rFromPageFrame
.GetPhyPageNum() < pObjAnchorPage
->GetPhyPageNum())
709 && pObj
->GetFrameFormat().GetAnchor().GetAnchorId()
710 != RndStdIds::FLY_AS_CHAR
)
712 if (pPageFrameOfAnchor
->GetPhyPageNum() < pObjAnchorPage
->GetPhyPageNum())
714 SAL_INFO("sw.layout", "SwObjectFormatterTextFrame::CheckMovedFwdCondition(): o_rbPageHasFlysAnchoredBelowThis because next page");
715 o_rbPageHasFlysAnchoredBelowThis
= true;
718 // on same page: check if it's in next-chain in the document body
719 // (in case both are in the same fly the flag must not be
720 // set because the whole fly moves at once)
721 SwContentFrame
const*const pInBodyFrameObj(FindFrameInBody(*pObj
));
722 SwContentFrame
const*const pInBodyFrameAnchoredObj(FindFrameInBody(_rAnchoredObj
));
723 if (pInBodyFrameObj
&& pInBodyFrameAnchoredObj
)
725 bool isBreakMore(false);
726 // currently this ignores index of at-char flys
727 for (SwContentFrame
const* pContentFrame
= pInBodyFrameAnchoredObj
->FindNextCnt();
729 pContentFrame
= pContentFrame
->FindNextCnt())
731 if (pInBodyFrameObj
== pContentFrame
)
733 // subsequent cells in a row are not automatically
734 // "below" and the row could potentially be split
735 // TODO refine check if needed
736 if (!pInBodyFrameAnchoredObj
->IsInTab()
737 || FindTopLevelRowFrame(pInBodyFrameAnchoredObj
)
738 != FindTopLevelRowFrame(pInBodyFrameAnchoredObj
))
739 { // anchored in next chain on same page
740 SAL_INFO("sw.layout", "SwObjectFormatterTextFrame::CheckMovedFwdCondition(): o_rbPageHasFlysAnchoredBelowThis because next chain on same page");
741 o_rbPageHasFlysAnchoredBelowThis
= true;
757 return bAnchorIsMovedForward
;
760 static void CleanupEmptyFootnoteFrame(SwFrame
* pLowerFrame
)
762 // Calc on a SwTextFrame in a footnote can move it to the next page -
763 // deletion of the SwFootnoteFrame was disabled with SwFrameDeleteGuard
764 // but now we have to clean up empty footnote frames to prevent crashes.
765 // Note: check it at this level, not lower: both container and footnote
766 // can be deleted at the same time!
767 if (!pLowerFrame
->IsFootnoteContFrame())
770 for (SwFrame
* pFootnote
= pLowerFrame
->GetLower(); pFootnote
; )
772 assert(pFootnote
->IsFootnoteFrame());
773 SwFrame
*const pNextNote
= pFootnote
->GetNext();
774 if (!pFootnote
->IsDeleteForbidden() && !pFootnote
->GetLower() && !pFootnote
->IsColLocked() &&
775 !static_cast<SwFootnoteFrame
*>(pFootnote
)->IsBackMoveLocked())
778 SwFrame::DestroyFrame(pFootnote
);
780 pFootnote
= pNextNote
;
784 // #i40140# - helper method to format layout frames used by
785 // method <SwObjectFormatterTextFrame::FormatAnchorFrameForCheckMoveFwd()>
786 // #i44049# - format till a certain lower frame, if provided.
787 static void lcl_FormatContentOfLayoutFrame( SwLayoutFrame
* pLayFrame
,
788 SwFrame
* pLastLowerFrame
= nullptr )
790 SwFrame
* pLowerFrame
= pLayFrame
->GetLower();
791 while ( pLowerFrame
)
794 if ( pLastLowerFrame
&& pLowerFrame
== pLastLowerFrame
)
798 if ( pLowerFrame
->IsLayoutFrame() )
800 SwFrameDeleteGuard
aCrudeHack(pLowerFrame
); // ??? any issue setting this for non-footnote frames?
801 lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame
*>(pLowerFrame
),
805 pLowerFrame
->Calc(pLowerFrame
->getRootFrame()->GetCurrShell()->GetOut());
807 // Calc on a SwTextFrame in a footnote can move it to the next page -
808 // deletion of the SwFootnoteFrame was disabled with SwFrameDeleteGuard
809 // but now we have to clean up empty footnote frames to prevent crashes.
810 // Note: check it at this level, not lower: both container and footnote
811 // can be deleted at the same time!
812 SwFrame
*const pNext
= pLowerFrame
->GetNext();
813 CleanupEmptyFootnoteFrame(pLowerFrame
);
818 /** method to format given anchor text frame and its previous frames
821 Usage: Needed to check, if the anchor text frame is moved forward
822 due to the positioning and wrapping of its anchored objects, and
823 to format the frames, which have become invalid due to the anchored
824 object formatting in the iterative object positioning algorithm
826 void SwObjectFormatterTextFrame::FormatAnchorFrameAndItsPrevs( SwTextFrame
& _rAnchorTextFrame
)
828 // #i47014# - no format of section and previous columns
829 // for follow text frames.
830 if ( !_rAnchorTextFrame
.IsFollow() )
832 // In case the anchor frame is in a column or section, format its
833 // previous frames first - but don't jump out of the current layout
834 // environment, e.g. from footnotes into the footnote boss.
835 SwFrame
* pSectFrame(nullptr);
836 SwFrame
* pColFrameOfAnchor(nullptr);
837 for (SwFrame
* pUpper
= _rAnchorTextFrame
.GetUpper();
838 pUpper
!= nullptr; pUpper
= pUpper
->GetUpper())
840 if (pUpper
->IsCellFrame())
842 break; // apparently nothing to be done?
844 if (pUpper
->IsFootnoteFrame())
846 SAL_INFO_IF(pColFrameOfAnchor
== nullptr && pUpper
->FindColFrame(),
847 "sw.layout", "tdf#122894 skipping column for footnote in column");
848 break; // stop: prevent crash in case footnotes are being moved
850 if (pUpper
->IsSctFrame())
852 pColFrameOfAnchor
= nullptr;
856 if (pColFrameOfAnchor
!= nullptr)
857 { // parent of column not a section frame => column not in section
860 if (pUpper
->IsColumnFrame())
862 pColFrameOfAnchor
= pUpper
;
866 // if anchor frame is directly inside a section, format this section and
867 // its previous frames.
868 // Note: It's a very simple format without formatting objects.
871 assert(pSectFrame
->IsSctFrame());
873 SwFrameDeleteGuard
aDeleteGuard(&_rAnchorTextFrame
);
875 _rAnchorTextFrame
.LockJoin();
876 SwFrame
* pFrame
= pSectFrame
->GetUpper()->GetLower();
877 // #i49605# - section frame could move forward
878 // by the format of its previous frame.
879 // Thus, check for valid <pFrame>.
880 while ( pFrame
&& pFrame
!= pSectFrame
)
882 SwFrameDeleteGuard
aDeleteFrameGuard(pFrame
);
884 if ( pFrame
->IsLayoutFrame() )
885 lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame
*>(pFrame
) );
887 pFrame
->Calc(pFrame
->getRootFrame()->GetCurrShell()->GetOut());
889 pFrame
= pFrame
->GetNext();
891 lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame
*>(pSectFrame
),
892 &_rAnchorTextFrame
);
894 _rAnchorTextFrame
.UnlockJoin();
898 // #i40140# - if anchor frame is inside a column,
899 // format the content of the previous columns.
900 // Note: It's a very simple format without formatting objects.
901 if (pColFrameOfAnchor
)
903 assert(pColFrameOfAnchor
->IsColumnFrame());
905 _rAnchorTextFrame
.LockJoin();
906 SwFrameDeleteGuard
aDeleteGuard(&_rAnchorTextFrame
);
907 SwFrame
* pColFrame
= pColFrameOfAnchor
->GetUpper()->GetLower();
908 while ( pColFrame
!= pColFrameOfAnchor
)
910 SwFrame
* pFrame
= pColFrame
->GetLower();
913 if ( pFrame
->IsLayoutFrame() )
914 lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame
*>(pFrame
) );
916 pFrame
->Calc(pFrame
->getRootFrame()->GetCurrShell()->GetOut());
918 pFrame
= pFrame
->GetNext();
921 pColFrame
= pColFrame
->GetNext();
924 _rAnchorTextFrame
.UnlockJoin();
928 // format anchor frame - format of its follow not needed
929 // #i43255# - forbid follow format, only if anchor text
931 if ( _rAnchorTextFrame
.IsInTab() )
933 SwForbidFollowFormat
aForbidFollowFormat( _rAnchorTextFrame
);
934 _rAnchorTextFrame
.Calc(_rAnchorTextFrame
.getRootFrame()->GetCurrShell()->GetOut());
938 _rAnchorTextFrame
.Calc(_rAnchorTextFrame
.getRootFrame()->GetCurrShell()->GetOut());
942 /** method to format the anchor frame for checking of the move forward condition
946 void SwObjectFormatterTextFrame::FormatAnchorFrameForCheckMoveFwd()
948 SwObjectFormatterTextFrame::FormatAnchorFrameAndItsPrevs( mrAnchorTextFrame
);
951 /** method to determine if at least one anchored object has state
952 <temporarily consider wrapping style influence> set.
954 bool SwObjectFormatterTextFrame::AtLeastOneObjIsTmpConsiderWrapInfluence()
958 const SwSortedObjs
* pObjs
= GetAnchorFrame().GetDrawObjs();
959 if ( pObjs
&& pObjs
->size() > 1 )
961 for (SwAnchoredObject
* pAnchoredObj
: *pObjs
)
963 if ( pAnchoredObj
->ConsiderObjWrapInfluenceOnObjPos() )
974 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */