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 <sortedobjs.hxx>
22 #include <rootfrm.hxx>
23 #include <anchoredobject.hxx>
25 #include <pagefrm.hxx>
27 #include <layouter.hxx>
28 #include <fmtanchr.hxx>
29 #include <fmtwrapinfluenceonobjpos.hxx>
30 #include <fmtfollowtextflow.hxx>
34 #include <osl/diagnose.h>
36 using namespace ::com::sun::star
;
40 // little helper class to forbid follow formatting for the given text frame
41 class SwForbidFollowFormat
44 SwTextFrame
& mrTextFrame
;
45 const bool bOldFollowFormatAllowed
;
48 explicit SwForbidFollowFormat( SwTextFrame
& _rTextFrame
)
49 : mrTextFrame( _rTextFrame
),
50 bOldFollowFormatAllowed( _rTextFrame
.FollowFormatAllowed() )
52 mrTextFrame
.ForbidFollowFormat();
55 ~SwForbidFollowFormat()
57 if ( bOldFollowFormatAllowed
)
59 mrTextFrame
.AllowFollowFormat();
66 SwObjectFormatterTextFrame::SwObjectFormatterTextFrame( SwTextFrame
& _rAnchorTextFrame
,
67 const SwPageFrame
& _rPageFrame
,
68 SwTextFrame
* _pMasterAnchorTextFrame
,
69 SwLayAction
* _pLayAction
)
70 : SwObjectFormatter( _rPageFrame
, _pLayAction
, true ),
71 mrAnchorTextFrame( _rAnchorTextFrame
),
72 mpMasterAnchorTextFrame( _pMasterAnchorTextFrame
)
76 SwObjectFormatterTextFrame::~SwObjectFormatterTextFrame()
80 std::unique_ptr
<SwObjectFormatterTextFrame
> SwObjectFormatterTextFrame::CreateObjFormatter(
81 SwTextFrame
& _rAnchorTextFrame
,
82 const SwPageFrame
& _rPageFrame
,
83 SwLayAction
* _pLayAction
)
85 std::unique_ptr
<SwObjectFormatterTextFrame
> pObjFormatter
;
87 // determine 'master' of <_rAnchorTextFrame>, if anchor frame is a follow text frame.
88 SwTextFrame
* pMasterOfAnchorFrame
= nullptr;
89 if ( _rAnchorTextFrame
.IsFollow() )
91 pMasterOfAnchorFrame
= _rAnchorTextFrame
.FindMaster();
92 while ( pMasterOfAnchorFrame
&& pMasterOfAnchorFrame
->IsFollow() )
94 pMasterOfAnchorFrame
= pMasterOfAnchorFrame
->FindMaster();
98 // create object formatter, if floating screen objects are registered
99 // at anchor frame (or at 'master' anchor frame)
100 if ( _rAnchorTextFrame
.GetDrawObjs() ||
101 ( pMasterOfAnchorFrame
&& pMasterOfAnchorFrame
->GetDrawObjs() ) )
104 new SwObjectFormatterTextFrame( _rAnchorTextFrame
, _rPageFrame
,
105 pMasterOfAnchorFrame
, _pLayAction
));
108 return pObjFormatter
;
111 SwFrame
& SwObjectFormatterTextFrame::GetAnchorFrame()
113 return mrAnchorTextFrame
;
116 // #i40147# - add parameter <_bCheckForMovedFwd>.
117 bool SwObjectFormatterTextFrame::DoFormatObj( SwAnchoredObject
& _rAnchoredObj
,
118 const bool _bCheckForMovedFwd
)
120 // consider, if the layout action has to be
121 // restarted due to a delete of a page frame.
122 if ( GetLayAction() && GetLayAction()->IsAgain() )
127 bool bSuccess( true );
129 if ( _rAnchoredObj
.IsFormatPossible() )
131 _rAnchoredObj
.SetRestartLayoutProcess( false );
133 FormatObj_( _rAnchoredObj
);
134 // consider, if the layout action has to be
135 // restarted due to a delete of a page frame.
136 if ( GetLayAction() && GetLayAction()->IsAgain() )
141 // check, if layout process has to be restarted.
142 // if yes, perform needed invalidations.
144 // no restart of layout process,
145 // if anchored object is anchored inside a Writer fly frame,
146 // its position is already locked, and it follows the text flow.
147 const bool bRestart
=
148 _rAnchoredObj
.RestartLayoutProcess() &&
149 !( _rAnchoredObj
.PositionLocked() &&
150 _rAnchoredObj
.GetAnchorFrame()->IsInFly() &&
151 _rAnchoredObj
.GetFrameFormat().GetFollowTextFlow().GetValue() );
155 InvalidatePrevObjs( _rAnchoredObj
);
156 InvalidateFollowObjs( _rAnchoredObj
);
159 // format anchor text frame, if wrapping style influence of the object
160 // has to be considered and it's <NONE_SUCCESSIVE_POSITIONED>
161 // #i3317# - consider also anchored objects, whose
162 // wrapping style influence is temporarily considered.
163 // #i40147# - consider also anchored objects, for
164 // whose the check of a moved forward anchor frame is requested.
165 // revise decision made for i3317:
166 // anchored objects, whose wrapping style influence is temporarily considered,
167 // have to be considered in method <SwObjectFormatterTextFrame::DoFormatObjs()>
169 _rAnchoredObj
.ConsiderObjWrapInfluenceOnObjPos() &&
170 ( _bCheckForMovedFwd
||
171 _rAnchoredObj
.GetFrameFormat().GetWrapInfluenceOnObjPos().
172 // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE
173 GetWrapInfluenceOnObjPos( true ) ==
174 // #i35017# - constant name has changed
175 text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE
) )
177 // #i26945# - check conditions for move forward of
179 // determine, if anchor text frame has previous frame
180 const bool bDoesAnchorHadPrev
= ( mrAnchorTextFrame
.GetIndPrev() != nullptr );
182 // #i40141# - use new method - it also formats the
183 // section the anchor frame is in.
184 FormatAnchorFrameForCheckMoveFwd();
187 if ( _rAnchoredObj
.HasClearedEnvironment() )
189 _rAnchoredObj
.SetClearedEnvironment( true );
190 // #i44049# - consider, that anchor frame
191 // could already been marked to move forward.
192 SwPageFrame
* pAnchorPageFrame( mrAnchorTextFrame
.FindPageFrame() );
193 if ( pAnchorPageFrame
!= _rAnchoredObj
.GetPageFrame() )
195 bool bInsert( true );
196 sal_uInt32
nToPageNum( 0 );
197 const SwDoc
& rDoc
= *(GetPageFrame().GetFormat()->GetDoc());
198 if ( SwLayouter::FrameMovedFwdByObjPos(
199 rDoc
, mrAnchorTextFrame
, nToPageNum
) )
201 if ( nToPageNum
< pAnchorPageFrame
->GetPhyPageNum() )
202 SwLayouter::RemoveMovedFwdFrame( rDoc
, mrAnchorTextFrame
);
208 SwLayouter::InsertMovedFwdFrame( rDoc
, mrAnchorTextFrame
,
209 pAnchorPageFrame
->GetPhyPageNum() );
210 mrAnchorTextFrame
.InvalidatePos();
212 InvalidatePrevObjs( _rAnchoredObj
);
213 InvalidateFollowObjs( _rAnchoredObj
);
217 OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObj(..)> - anchor frame not marked to move forward" );
221 else if ( !mrAnchorTextFrame
.IsFollow() && bDoesAnchorHadPrev
)
223 // index of anchored object in collection of page numbers and
225 sal_uInt32
nIdx( CountOfCollected() );
226 OSL_ENSURE( nIdx
> 0,
227 "<SwObjectFormatterTextFrame::DoFormatObj(..)> - anchored object not collected!?" );
230 sal_uInt32
nToPageNum( 0 );
232 bool bDummy( false );
233 bool bPageHasFlysAnchoredBelowThis(false);
234 // see how SwObjectFormatter::FormatObjsAtFrame_() checks
235 // "pPageFrameOfAnchor == &mrPageFrame" - only caller relevant for
237 assert(GetPageFrame().GetPhyPageNum() == GetPgNumOfCollected(nIdx
));
238 if ( SwObjectFormatterTextFrame::CheckMovedFwdCondition( *GetCollectedObj( nIdx
),
240 IsCollectedAnchoredAtMaster( nIdx
),
242 bPageHasFlysAnchoredBelowThis
))
244 // #i49987# - consider, that anchor frame
245 // could already been marked to move forward.
246 bool bInsert( true );
247 sal_uInt32
nMovedFwdToPageNum( 0 );
248 const SwDoc
& rDoc
= *(GetPageFrame().GetFormat()->GetDoc());
249 if ( SwLayouter::FrameMovedFwdByObjPos(
250 rDoc
, mrAnchorTextFrame
, nMovedFwdToPageNum
) )
252 if ( nMovedFwdToPageNum
< nToPageNum
)
254 if (!bPageHasFlysAnchoredBelowThis
)
256 SwLayouter::RemoveMovedFwdFrame(rDoc
, mrAnchorTextFrame
);
264 // Indicate that anchor text frame has to move forward and
265 // invalidate its position to force a re-format.
266 if (!bPageHasFlysAnchoredBelowThis
)
268 SwLayouter::InsertMovedFwdFrame(rDoc
,
269 mrAnchorTextFrame
, nToPageNum
);
271 mrAnchorTextFrame
.InvalidatePos();
273 // Indicate restart of the layout process
276 // If needed, invalidate previous objects anchored at same anchor
278 InvalidatePrevObjs( _rAnchoredObj
);
280 // Invalidate object and following objects for the restart of the
282 InvalidateFollowObjs( _rAnchoredObj
);
286 OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObj(..)> - anchor frame not marked to move forward" );
290 // i40155# - mark anchor frame not to wrap around
291 // objects under the condition, that its follow contains all its text.
292 else if ( !mrAnchorTextFrame
.IsFollow() &&
293 mrAnchorTextFrame
.GetFollow() &&
294 mrAnchorTextFrame
.GetFollow()->GetOffset() == TextFrameIndex(0))
296 SwLayouter::RemoveMovedFwdFrame(
297 *(mrAnchorTextFrame
.FindPageFrame()->GetFormat()->GetDoc()),
306 bool SwObjectFormatterTextFrame::DoFormatObjs()
308 if ( !mrAnchorTextFrame
.isFrameAreaDefinitionValid() )
310 if ( GetLayAction() &&
311 mrAnchorTextFrame
.FindPageFrame() != &GetPageFrame() )
313 // notify layout action, thus is can restart the layout process on
315 GetLayAction()->SetAgain(true);
319 // the anchor text frame has to be valid, thus assert.
320 OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObjs()> called for invalidate anchor text frame." );
326 bool bSuccess( true );
328 if ( mrAnchorTextFrame
.IsFollow() )
330 // Only floating screen objects anchored as-character are directly
331 // registered at a follow text frame. The other floating screen objects
332 // are registered at the 'master' anchor text frame.
333 // Thus, format the other floating screen objects through the 'master'
335 OSL_ENSURE( mpMasterAnchorTextFrame
,
336 "SwObjectFormatterTextFrame::DoFormatObjs() - missing 'master' anchor text frame" );
337 bSuccess
= FormatObjsAtFrame_( mpMasterAnchorTextFrame
);
341 // format of as-character anchored floating screen objects - no failure
342 // expected on the format of these objects.
343 bSuccess
= FormatObjsAtFrame_();
348 bSuccess
= FormatObjsAtFrame_();
351 // consider anchored objects, whose wrapping style influence are temporarily
354 ( ConsiderWrapOnObjPos() ||
355 ( !mrAnchorTextFrame
.IsFollow() &&
356 AtLeastOneObjIsTmpConsiderWrapInfluence() ) ) )
358 const bool bDoesAnchorHadPrev
= ( mrAnchorTextFrame
.GetIndPrev() != nullptr );
360 // Format anchor text frame after its objects are formatted.
361 // Note: The format of the anchor frame also formats the invalid
362 // previous frames of the anchor frame. The format of the previous
363 // frames is needed to get a correct result of format of the
364 // anchor frame for the following check for moved forward anchors
365 // #i40141# - use new method - it also formats the
366 // section the anchor frame is in.
367 FormatAnchorFrameForCheckMoveFwd();
369 sal_uInt32
nToPageNum( 0 );
371 bool bInFollow( false );
372 bool bPageHasFlysAnchoredBelowThis(false);
373 SwAnchoredObject
* pObj
= nullptr;
374 if ( !mrAnchorTextFrame
.IsFollow() )
376 pObj
= GetFirstObjWithMovedFwdAnchor(
377 // #i35017# - constant name has changed
378 text::WrapInfluenceOnPosition::ONCE_CONCURRENT
,
379 nToPageNum
, bInFollow
, bPageHasFlysAnchoredBelowThis
);
382 if ( pObj
&& pObj
->HasClearedEnvironment() )
384 pObj
->SetClearedEnvironment( true );
385 // #i44049# - consider, that anchor frame
386 // could already been marked to move forward.
387 SwPageFrame
* pAnchorPageFrame( mrAnchorTextFrame
.FindPageFrame() );
388 // #i43913# - consider, that anchor frame
389 // is a follow or is in a follow row, which will move forward.
390 if ( pAnchorPageFrame
!= pObj
->GetPageFrame() ||
393 bool bInsert( true );
394 sal_uInt32
nTmpToPageNum( 0 );
395 const SwDoc
& rDoc
= *(GetPageFrame().GetFormat()->GetDoc());
396 if ( SwLayouter::FrameMovedFwdByObjPos(
397 rDoc
, mrAnchorTextFrame
, nTmpToPageNum
) )
399 if ( nTmpToPageNum
< pAnchorPageFrame
->GetPhyPageNum() )
401 if (!bPageHasFlysAnchoredBelowThis
)
403 SwLayouter::RemoveMovedFwdFrame(rDoc
, mrAnchorTextFrame
);
411 if (!bPageHasFlysAnchoredBelowThis
)
413 SwLayouter::InsertMovedFwdFrame(rDoc
, mrAnchorTextFrame
,
414 pAnchorPageFrame
->GetPhyPageNum());
416 mrAnchorTextFrame
.InvalidatePos();
418 InvalidatePrevObjs( *pObj
);
419 InvalidateFollowObjs( *pObj
);
423 OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObjs(..)> - anchor frame not marked to move forward" );
427 else if ( pObj
&& bDoesAnchorHadPrev
)
429 // Object found, whose anchor is moved forward
431 // #i49987# - consider, that anchor frame
432 // could already been marked to move forward.
433 bool bInsert( true );
434 sal_uInt32
nMovedFwdToPageNum( 0 );
435 const SwDoc
& rDoc
= *(GetPageFrame().GetFormat()->GetDoc());
436 if ( SwLayouter::FrameMovedFwdByObjPos(
437 rDoc
, mrAnchorTextFrame
, nMovedFwdToPageNum
) )
439 if ( nMovedFwdToPageNum
< nToPageNum
)
440 SwLayouter::RemoveMovedFwdFrame( rDoc
, mrAnchorTextFrame
);
446 // Indicate that anchor text frame has to move forward and
447 // invalidate its position to force a re-format.
448 SwLayouter::InsertMovedFwdFrame( rDoc
, mrAnchorTextFrame
, nToPageNum
);
449 mrAnchorTextFrame
.InvalidatePos();
451 // Indicate restart of the layout process
454 // If needed, invalidate previous objects anchored at same anchor
456 InvalidatePrevObjs( *pObj
);
458 // Invalidate object and following objects for the restart of the
460 InvalidateFollowObjs( *pObj
);
464 OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObjs(..)> - anchor frame not marked to move forward" );
467 // #i40155# - mark anchor frame not to wrap around
468 // objects under the condition, that its follow contains all its text.
469 else if ( !mrAnchorTextFrame
.IsFollow() &&
470 mrAnchorTextFrame
.GetFollow() &&
471 mrAnchorTextFrame
.GetFollow()->GetOffset() == TextFrameIndex(0))
473 SwLayouter::RemoveMovedFwdFrame(
474 *(mrAnchorTextFrame
.FindPageFrame()->GetFormat()->GetDoc()),
482 void SwObjectFormatterTextFrame::InvalidatePrevObjs( SwAnchoredObject
& _rAnchoredObj
)
484 // invalidate all previous objects, whose wrapping influence on the object
485 // positioning is <NONE_CONCURRENT_POSITIONED>.
486 // Note: list of objects at anchor frame is sorted by this property.
487 if ( _rAnchoredObj
.GetFrameFormat().GetWrapInfluenceOnObjPos().
488 // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE
489 GetWrapInfluenceOnObjPos( true ) !=
490 // #i35017# - constant name has changed
491 text::WrapInfluenceOnPosition::ONCE_CONCURRENT
)
494 const SwSortedObjs
* pObjs
= GetAnchorFrame().GetDrawObjs();
498 // determine start index
499 size_t i
= pObjs
->ListPosOf( _rAnchoredObj
);
503 SwAnchoredObject
* pAnchoredObj
= (*pObjs
)[i
];
504 if ( pAnchoredObj
->GetFrameFormat().GetWrapInfluenceOnObjPos().
505 // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE
506 GetWrapInfluenceOnObjPos( true ) ==
507 // #i35017# - constant name has changed
508 text::WrapInfluenceOnPosition::ONCE_CONCURRENT
)
510 pAnchoredObj
->InvalidateObjPosForConsiderWrapInfluence();
515 void SwObjectFormatterTextFrame::InvalidateFollowObjs( SwAnchoredObject
& _rAnchoredObj
)
517 _rAnchoredObj
.InvalidateObjPosForConsiderWrapInfluence();
519 const SwSortedObjs
* pObjs
= GetPageFrame().GetSortedObjs();
522 // determine start index
523 for ( size_t i
= pObjs
->ListPosOf( _rAnchoredObj
) + 1; i
< pObjs
->size(); ++i
)
525 SwAnchoredObject
* pAnchoredObj
= (*pObjs
)[i
];
526 pAnchoredObj
->InvalidateObjPosForConsiderWrapInfluence();
531 SwAnchoredObject
* SwObjectFormatterTextFrame::GetFirstObjWithMovedFwdAnchor(
532 const sal_Int16 _nWrapInfluenceOnPosition
,
533 sal_uInt32
& _noToPageNum
,
535 bool& o_rbPageHasFlysAnchoredBelowThis
)
537 // #i35017# - constant names have changed
538 OSL_ENSURE( _nWrapInfluenceOnPosition
== text::WrapInfluenceOnPosition::ONCE_SUCCESSIVE
||
539 _nWrapInfluenceOnPosition
== text::WrapInfluenceOnPosition::ONCE_CONCURRENT
,
540 "<SwObjectFormatterTextFrame::GetFirstObjWithMovedFwdAnchor(..)> - invalid value for parameter <_nWrapInfluenceOnPosition>" );
542 SwAnchoredObject
* pRetAnchoredObj
= nullptr;
545 for ( ; i
< CountOfCollected(); ++i
)
547 SwAnchoredObject
* pAnchoredObj
= GetCollectedObj(i
);
548 if ( pAnchoredObj
->ConsiderObjWrapInfluenceOnObjPos() &&
549 pAnchoredObj
->GetFrameFormat().GetWrapInfluenceOnObjPos().
550 // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE
551 GetWrapInfluenceOnObjPos( true ) == _nWrapInfluenceOnPosition
)
553 // see how SwObjectFormatter::FormatObjsAtFrame_() checks
554 // "pPageFrameOfAnchor == &mrPageFrame" - only caller relevant for
556 assert(GetPageFrame().GetPhyPageNum() == GetPgNumOfCollected(i
));
557 // #i26945# - use new method <_CheckMovedFwdCondition(..)>
559 if ( SwObjectFormatterTextFrame::CheckMovedFwdCondition( *GetCollectedObj( i
),
561 IsCollectedAnchoredAtMaster( i
),
562 _noToPageNum
, _boInFollow
,
563 o_rbPageHasFlysAnchoredBelowThis
) )
565 pRetAnchoredObj
= pAnchoredObj
;
571 return pRetAnchoredObj
;
574 static SwRowFrame
const* FindTopLevelRowFrame(SwFrame
const*const pFrame
)
576 SwRowFrame
* pRow
= const_cast<SwFrame
*>(pFrame
)->FindRowFrame();
577 // looks like SwTabFrame has mbInfTab = true so go up 2 levels
578 while (pRow
->GetUpper()->GetUpper()->IsInTab())
580 pRow
= pRow
->GetUpper()->GetUpper()->FindRowFrame();
585 static SwContentFrame
const* FindFrameInBody(SwAnchoredObject
const& rAnchored
)
587 SwFrame
const*const pAnchor(rAnchored
.GetAnchorFrame());
589 if (pAnchor
->IsPageFrame() || pAnchor
->FindFooterOrHeader())
593 if (pAnchor
->IsInFly())
595 return FindFrameInBody(*pAnchor
->FindFlyFrame());
597 if (pAnchor
->IsInFootnote())
599 return pAnchor
->FindFootnoteFrame()->GetRef();
601 assert(pAnchor
->IsInDocBody());
602 assert(pAnchor
->IsContentFrame());
603 return static_cast<SwContentFrame
const*>(pAnchor
);
607 // - replace private method by corresponding static public method
608 bool SwObjectFormatterTextFrame::CheckMovedFwdCondition(
609 SwAnchoredObject
& _rAnchoredObj
,
610 SwPageFrame
const& rFromPageFrame
,
611 const bool _bAnchoredAtMasterBeforeFormatAnchor
,
612 sal_uInt32
& _noToPageNum
,
614 bool& o_rbPageHasFlysAnchoredBelowThis
)
616 const sal_uInt32
_nFromPageNum(rFromPageFrame
.GetPhyPageNum());
617 bool bAnchorIsMovedForward( false );
619 SwPageFrame
* pPageFrameOfAnchor
= _rAnchoredObj
.FindPageFrameOfAnchor();
620 if ( pPageFrameOfAnchor
)
622 const sal_uInt32 nPageNum
= pPageFrameOfAnchor
->GetPhyPageNum();
623 if ( nPageNum
> _nFromPageNum
)
625 _noToPageNum
= nPageNum
;
626 // Handling of special case:
627 // If anchor frame is move forward into a follow flow row,
628 // <_noToPageNum> is set to <_nFromPageNum + 1>, because it is
629 // possible that the anchor page frame isn't valid, because the
630 // page distance between master row and follow flow row is greater
632 if ( _noToPageNum
> (_nFromPageNum
+ 1) )
634 SwFrame
* pAnchorFrame
= _rAnchoredObj
.GetAnchorFrameContainingAnchPos();
635 if ( pAnchorFrame
->IsInTab() &&
636 pAnchorFrame
->IsInFollowFlowRow() )
638 _noToPageNum
= _nFromPageNum
+ 1;
641 bAnchorIsMovedForward
= true;
644 // #i26945# - check, if an at-paragraph|at-character
645 // anchored object is now anchored at a follow text frame, which will be
646 // on the next page. Also check, if an at-character anchored object
647 // is now anchored at a text frame, which is in a follow flow row,
648 // which will be on the next page.
649 if ( !bAnchorIsMovedForward
&&
650 _bAnchoredAtMasterBeforeFormatAnchor
&&
651 ((_rAnchoredObj
.GetFrameFormat().GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_CHAR
) ||
652 (_rAnchoredObj
.GetFrameFormat().GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PARA
)))
654 SwFrame
* pAnchorFrame
= _rAnchoredObj
.GetAnchorFrameContainingAnchPos();
655 OSL_ENSURE( pAnchorFrame
->IsTextFrame(),
656 "<SwObjectFormatterTextFrame::CheckMovedFwdCondition(..) - wrong type of anchor frame>" );
657 SwTextFrame
* pAnchorTextFrame
= static_cast<SwTextFrame
*>(pAnchorFrame
);
658 bool bCheck( false );
659 if ( pAnchorTextFrame
->IsFollow() )
663 else if( pAnchorTextFrame
->IsInTab() )
665 const SwRowFrame
* pMasterRow
= pAnchorTextFrame
->IsInFollowFlowRow();
667 pMasterRow
->FindPageFrame() == pPageFrameOfAnchor
)
674 // check, if found text frame will be on the next page
675 // by checking, if it's in a column, which has no next.
676 SwFrame
* pColFrame
= pAnchorTextFrame
->FindColFrame();
677 while ( pColFrame
&& !pColFrame
->GetNext() )
679 pColFrame
= pColFrame
->FindColFrame();
681 if ( !pColFrame
|| !pColFrame
->GetNext() )
683 _noToPageNum
= _nFromPageNum
+ 1;
684 bAnchorIsMovedForward
= true;
691 if (bAnchorIsMovedForward
)
693 // tdf#138518 try to determine if there is a fly on page rFromPageFrame
694 // which is anchored in a frame that is "below" the anchor frame
695 // of _rAnchoredObj, such that it should move to the next page before
696 // _rAnchoredObj does
697 if (auto * pObjs
= rFromPageFrame
.GetSortedObjs())
699 for (SwAnchoredObject
*const pObj
: *pObjs
)
701 SwPageFrame
const*const pObjAnchorPage(pObj
->FindPageFrameOfAnchor());
702 assert(pObjAnchorPage
);
703 if ((pObjAnchorPage
== &rFromPageFrame
704 ? _boInFollow
// same-page but will move forward
705 : rFromPageFrame
.GetPhyPageNum() < pObjAnchorPage
->GetPhyPageNum())
706 && pObj
->GetFrameFormat().GetAnchor().GetAnchorId()
707 != RndStdIds::FLY_AS_CHAR
)
709 if (pPageFrameOfAnchor
->GetPhyPageNum() < pObjAnchorPage
->GetPhyPageNum())
711 SAL_INFO("sw.layout", "SwObjectFormatterTextFrame::CheckMovedFwdCondition(): o_rbPageHasFlysAnchoredBelowThis because next page");
712 o_rbPageHasFlysAnchoredBelowThis
= true;
715 // on same page: check if it's in next-chain in the document body
716 // (in case both are in the same fly the flag must not be
717 // set because the whole fly moves at once)
718 SwContentFrame
const*const pInBodyFrameObj(FindFrameInBody(*pObj
));
719 SwContentFrame
const*const pInBodyFrameAnchoredObj(FindFrameInBody(_rAnchoredObj
));
720 if (pInBodyFrameObj
&& pInBodyFrameAnchoredObj
)
722 bool isBreakMore(false);
723 // currently this ignores index of at-char flys
724 for (SwContentFrame
const* pContentFrame
= pInBodyFrameAnchoredObj
->FindNextCnt();
726 pContentFrame
= pContentFrame
->FindNextCnt())
728 if (pInBodyFrameObj
== pContentFrame
)
730 // subsequent cells in a row are not automatically
731 // "below" and the row could potentially be split
732 // TODO refine check if needed
733 if (!pInBodyFrameAnchoredObj
->IsInTab()
734 || FindTopLevelRowFrame(pInBodyFrameAnchoredObj
)
735 != FindTopLevelRowFrame(pInBodyFrameAnchoredObj
))
736 { // anchored in next chain on same page
737 SAL_INFO("sw.layout", "SwObjectFormatterTextFrame::CheckMovedFwdCondition(): o_rbPageHasFlysAnchoredBelowThis because next chain on same page");
738 o_rbPageHasFlysAnchoredBelowThis
= true;
754 return bAnchorIsMovedForward
;
757 static void CleanupEmptyFootnoteFrame(SwFrame
* pLowerFrame
)
759 // Calc on a SwTextFrame in a footnote can move it to the next page -
760 // deletion of the SwFootnoteFrame was disabled with SwFrameDeleteGuard
761 // but now we have to clean up empty footnote frames to prevent crashes.
762 // Note: check it at this level, not lower: both container and footnote
763 // can be deleted at the same time!
764 if (!pLowerFrame
->IsFootnoteContFrame())
767 for (SwFrame
* pFootnote
= pLowerFrame
->GetLower(); pFootnote
; )
769 assert(pFootnote
->IsFootnoteFrame());
770 SwFrame
*const pNextNote
= pFootnote
->GetNext();
771 if (!pFootnote
->IsDeleteForbidden() && !pFootnote
->GetLower() && !pFootnote
->IsColLocked() &&
772 !static_cast<SwFootnoteFrame
*>(pFootnote
)->IsBackMoveLocked())
775 SwFrame::DestroyFrame(pFootnote
);
777 pFootnote
= pNextNote
;
781 // #i40140# - helper method to format layout frames used by
782 // method <SwObjectFormatterTextFrame::FormatAnchorFrameForCheckMoveFwd()>
783 // #i44049# - format till a certain lower frame, if provided.
784 static void lcl_FormatContentOfLayoutFrame( SwLayoutFrame
* pLayFrame
,
785 SwFrame
* pLastLowerFrame
= nullptr )
787 SwFrame
* pLowerFrame
= pLayFrame
->GetLower();
788 while ( pLowerFrame
)
791 if ( pLastLowerFrame
&& pLowerFrame
== pLastLowerFrame
)
795 if ( pLowerFrame
->IsLayoutFrame() )
797 SwFrameDeleteGuard
aCrudeHack(pLowerFrame
); // ??? any issue setting this for non-footnote frames?
798 lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame
*>(pLowerFrame
),
802 pLowerFrame
->Calc(pLowerFrame
->getRootFrame()->GetCurrShell()->GetOut());
804 // Calc on a SwTextFrame in a footnote can move it to the next page -
805 // deletion of the SwFootnoteFrame was disabled with SwFrameDeleteGuard
806 // but now we have to clean up empty footnote frames to prevent crashes.
807 // Note: check it at this level, not lower: both container and footnote
808 // can be deleted at the same time!
809 SwFrame
*const pNext
= pLowerFrame
->GetNext();
810 CleanupEmptyFootnoteFrame(pLowerFrame
);
815 /** method to format given anchor text frame and its previous frames
818 Usage: Needed to check, if the anchor text frame is moved forward
819 due to the positioning and wrapping of its anchored objects, and
820 to format the frames, which have become invalid due to the anchored
821 object formatting in the iterative object positioning algorithm
823 void SwObjectFormatterTextFrame::FormatAnchorFrameAndItsPrevs( SwTextFrame
& _rAnchorTextFrame
)
825 // #i47014# - no format of section and previous columns
826 // for follow text frames.
827 if ( !_rAnchorTextFrame
.IsFollow() )
829 // In case the anchor frame is in a column or section, format its
830 // previous frames first - but don't jump out of the current layout
831 // environment, e.g. from footnotes into the footnote boss.
832 SwFrame
* pSectFrame(nullptr);
833 SwFrame
* pColFrameOfAnchor(nullptr);
834 for (SwFrame
* pUpper
= _rAnchorTextFrame
.GetUpper();
835 pUpper
!= nullptr; pUpper
= pUpper
->GetUpper())
837 if (pUpper
->IsCellFrame())
839 break; // apparently nothing to be done?
841 if (pUpper
->IsFootnoteFrame())
843 SAL_INFO_IF(pColFrameOfAnchor
== nullptr && pUpper
->FindColFrame(),
844 "sw.layout", "tdf#122894 skipping column for footnote in column");
845 break; // stop: prevent crash in case footnotes are being moved
847 if (pUpper
->IsSctFrame())
849 pColFrameOfAnchor
= nullptr;
853 if (pColFrameOfAnchor
!= nullptr)
854 { // parent of column not a section frame => column not in section
857 if (pUpper
->IsColumnFrame())
859 pColFrameOfAnchor
= pUpper
;
863 // if anchor frame is directly inside a section, format this section and
864 // its previous frames.
865 // Note: It's a very simple format without formatting objects.
868 assert(pSectFrame
->IsSctFrame());
870 SwFrameDeleteGuard
aDeleteGuard(&_rAnchorTextFrame
);
872 _rAnchorTextFrame
.LockJoin();
873 SwFrame
* pFrame
= pSectFrame
->GetUpper()->GetLower();
874 // #i49605# - section frame could move forward
875 // by the format of its previous frame.
876 // Thus, check for valid <pFrame>.
877 while ( pFrame
&& pFrame
!= pSectFrame
)
879 SwFrameDeleteGuard
aDeleteFrameGuard(pFrame
);
881 if ( pFrame
->IsLayoutFrame() )
882 lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame
*>(pFrame
) );
884 pFrame
->Calc(pFrame
->getRootFrame()->GetCurrShell()->GetOut());
886 pFrame
= pFrame
->GetNext();
888 lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame
*>(pSectFrame
),
889 &_rAnchorTextFrame
);
891 _rAnchorTextFrame
.UnlockJoin();
895 // #i40140# - if anchor frame is inside a column,
896 // format the content of the previous columns.
897 // Note: It's a very simple format without formatting objects.
898 if (pColFrameOfAnchor
)
900 assert(pColFrameOfAnchor
->IsColumnFrame());
902 _rAnchorTextFrame
.LockJoin();
903 SwFrameDeleteGuard
aDeleteGuard(&_rAnchorTextFrame
);
904 SwFrame
* pColFrame
= pColFrameOfAnchor
->GetUpper()->GetLower();
905 while ( pColFrame
!= pColFrameOfAnchor
)
907 SwFrame
* pFrame
= pColFrame
->GetLower();
910 if ( pFrame
->IsLayoutFrame() )
911 lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame
*>(pFrame
) );
913 pFrame
->Calc(pFrame
->getRootFrame()->GetCurrShell()->GetOut());
915 pFrame
= pFrame
->GetNext();
918 pColFrame
= pColFrame
->GetNext();
921 _rAnchorTextFrame
.UnlockJoin();
925 // format anchor frame - format of its follow not needed
926 // #i43255# - forbid follow format, only if anchor text
928 if ( _rAnchorTextFrame
.IsInTab() )
930 SwForbidFollowFormat
aForbidFollowFormat( _rAnchorTextFrame
);
931 _rAnchorTextFrame
.Calc(_rAnchorTextFrame
.getRootFrame()->GetCurrShell()->GetOut());
935 _rAnchorTextFrame
.Calc(_rAnchorTextFrame
.getRootFrame()->GetCurrShell()->GetOut());
939 /** method to format the anchor frame for checking of the move forward condition
943 void SwObjectFormatterTextFrame::FormatAnchorFrameForCheckMoveFwd()
945 SwObjectFormatterTextFrame::FormatAnchorFrameAndItsPrevs( mrAnchorTextFrame
);
948 /** method to determine if at least one anchored object has state
949 <temporarily consider wrapping style influence> set.
951 bool SwObjectFormatterTextFrame::AtLeastOneObjIsTmpConsiderWrapInfluence()
955 const SwSortedObjs
* pObjs
= GetAnchorFrame().GetDrawObjs();
956 if ( pObjs
&& pObjs
->size() > 1 )
958 for (SwAnchoredObject
* pAnchoredObj
: *pObjs
)
960 if ( pAnchoredObj
->ConsiderObjWrapInfluenceOnObjPos() )
971 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */