forcepoint#93 fix crash on layout of specific rtf
[LibreOffice.git] / sw / source / core / layout / objectformattertxtfrm.cxx
blob2fb0ced8129154460fbcbb4ccc6ec464dd2327ab
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
25 #include <txtfrm.hxx>
26 #include <pagefrm.hxx>
27 #include <rowfrm.hxx>
28 #include <layouter.hxx>
29 #include <fmtanchr.hxx>
30 #include <fmtwrapinfluenceonobjpos.hxx>
31 #include <fmtfollowtextflow.hxx>
32 #include <layact.hxx>
33 #include <flyfrm.hxx>
34 #include <ftnfrm.hxx>
35 #include <fmtornt.hxx>
36 #include <textboxhelper.hxx>
37 #include <osl/diagnose.h>
39 using namespace ::com::sun::star;
41 namespace {
43 // little helper class to forbid follow formatting for the given text frame
44 class SwForbidFollowFormat
46 private:
47 SwTextFrame& mrTextFrame;
48 const bool bOldFollowFormatAllowed;
50 public:
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() ) )
106 pObjFormatter.reset(
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() )
127 return false;
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() )
141 return false;
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() );
155 if ( bRestart )
157 bSuccess = false;
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()>
171 if ( bSuccess &&
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
181 // anchor text frame
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();
189 // #i35911#
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 );
206 else
207 bInsert = false;
209 if ( bInsert )
211 SwLayouter::InsertMovedFwdFrame( rDoc, mrAnchorTextFrame,
212 pAnchorPageFrame->GetPhyPageNum() );
213 mrAnchorTextFrame.InvalidatePos();
214 bSuccess = false;
215 InvalidatePrevObjs( _rAnchoredObj );
216 InvalidateFollowObjs( _rAnchoredObj );
218 else
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
227 // anchor types
228 sal_uInt32 nIdx( CountOfCollected() );
229 OSL_ENSURE( nIdx > 0,
230 "<SwObjectFormatterTextFrame::DoFormatObj(..)> - anchored object not collected!?" );
231 --nIdx;
233 sal_uInt32 nToPageNum( 0 );
234 // #i43913#
235 bool bDummy( false );
236 bool bPageHasFlysAnchoredBelowThis(false);
237 // see how SwObjectFormatter::FormatObjsAtFrame_() checks
238 // "pPageFrameOfAnchor == &mrPageFrame" - only caller relevant for
239 // this subclass
240 assert(GetPageFrame().GetPhyPageNum() == GetPgNumOfCollected(nIdx));
241 if ( SwObjectFormatterTextFrame::CheckMovedFwdCondition( *GetCollectedObj( nIdx ),
242 GetPageFrame(),
243 IsCollectedAnchoredAtMaster( nIdx ),
244 nToPageNum, bDummy,
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);
262 else
263 bInsert = false;
265 if ( bInsert )
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
277 bSuccess = false;
279 // If needed, invalidate previous objects anchored at same anchor
280 // text frame.
281 InvalidatePrevObjs( _rAnchoredObj );
283 // Invalidate object and following objects for the restart of the
284 // layout process
285 InvalidateFollowObjs( _rAnchoredObj );
287 else
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()),
301 mrAnchorTextFrame );
306 return bSuccess;
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
317 // a previous page.
318 GetLayAction()->SetAgain(true);
320 else
322 // the anchor text frame has to be valid, thus assert.
323 OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObjs()> called for invalidate anchor text frame." );
326 return false;
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'
337 // anchor text frame
338 OSL_ENSURE( mpMasterAnchorTextFrame,
339 "SwObjectFormatterTextFrame::DoFormatObjs() - missing 'master' anchor text frame" );
340 bSuccess = FormatObjsAtFrame_( mpMasterAnchorTextFrame );
342 if ( bSuccess )
344 // format of as-character anchored floating screen objects - no failure
345 // expected on the format of these objects.
346 bSuccess = FormatObjsAtFrame_();
349 else
351 bSuccess = FormatObjsAtFrame_();
354 // consider anchored objects, whose wrapping style influence are temporarily
355 // considered.
356 if ( bSuccess &&
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 );
373 // #i43913#
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 );
384 // #i35911#
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() ||
394 bInFollow )
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);
409 else
410 bInsert = false;
412 if ( bInsert )
414 if (!bPageHasFlysAnchoredBelowThis)
416 SwLayouter::InsertMovedFwdFrame(rDoc, mrAnchorTextFrame,
417 pAnchorPageFrame->GetPhyPageNum());
419 mrAnchorTextFrame.InvalidatePos();
420 bSuccess = false;
421 InvalidatePrevObjs( *pObj );
422 InvalidateFollowObjs( *pObj );
424 else
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 );
444 else
445 bInsert = false;
447 if ( bInsert )
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
455 bSuccess = false;
457 // If needed, invalidate previous objects anchored at same anchor
458 // text frame.
459 InvalidatePrevObjs( *pObj );
461 // Invalidate object and following objects for the restart of the
462 // layout process
463 InvalidateFollowObjs( *pObj );
465 else
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()),
478 mrAnchorTextFrame );
482 return bSuccess;
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 )
495 return;
497 const SwSortedObjs* pObjs = GetAnchorFrame().GetDrawObjs();
498 if ( !pObjs )
499 return;
501 // determine start index
502 size_t i = pObjs->ListPosOf( _rAnchoredObj );
503 while (i > 0)
505 --i;
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();
523 if ( pObjs )
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,
537 bool& _boInFollow,
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;
547 sal_uInt32 i = 0;
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
558 // this subclass
559 assert(GetPageFrame().GetPhyPageNum() == GetPgNumOfCollected(i));
560 // #i26945# - use new method <_CheckMovedFwdCondition(..)>
561 // #i43913#
562 if ( SwObjectFormatterTextFrame::CheckMovedFwdCondition( *GetCollectedObj( i ),
563 GetPageFrame(),
564 IsCollectedAnchoredAtMaster( i ),
565 _noToPageNum, _boInFollow,
566 o_rbPageHasFlysAnchoredBelowThis) )
568 pRetAnchoredObj = pAnchoredObj;
569 break;
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();
585 return pRow;
588 static SwContentFrame const* FindFrameInBody(SwAnchoredObject const& rAnchored)
590 SwFrame const*const pAnchor(rAnchored.GetAnchorFrame());
591 assert(pAnchor);
592 if (pAnchor->IsPageFrame() || pAnchor->FindFooterOrHeader())
594 return nullptr;
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);
609 // #i58182#
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,
616 bool& _boInFollow,
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
634 // than 1.
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() )
664 bCheck = true;
666 else if( pAnchorTextFrame->IsInTab() )
668 const SwRowFrame* pMasterRow = pAnchorTextFrame->IsInFollowFlowRow();
669 if ( pMasterRow &&
670 pMasterRow->FindPageFrame() == pPageFrameOfAnchor )
672 bCheck = true;
675 if ( bCheck )
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;
688 // #i43913#
689 _boInFollow = 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;
716 break;
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();
728 pContentFrame;
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;
742 isBreakMore = true;
744 break;
747 if (isBreakMore)
749 break;
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())
768 return;
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())
777 pFootnote->Cut();
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 )
793 // #i44049#
794 if ( pLastLowerFrame && pLowerFrame == pLastLowerFrame )
796 break;
798 if ( pLowerFrame->IsLayoutFrame() )
800 SwFrameDeleteGuard aCrudeHack(pLowerFrame); // ??? any issue setting this for non-footnote frames?
801 lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pLowerFrame),
802 pLastLowerFrame );
804 else
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);
814 pLowerFrame = pNext;
818 /** method to format given anchor text frame and its previous frames
820 #i56300#
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;
853 pSectFrame = pUpper;
854 break;
856 if (pColFrameOfAnchor != nullptr)
857 { // parent of column not a section frame => column not in section
858 break;
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.
869 if (pSectFrame)
871 assert(pSectFrame->IsSctFrame());
873 SwFrameDeleteGuard aDeleteGuard(&_rAnchorTextFrame);
874 // #i44049#
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) );
886 else
887 pFrame->Calc(pFrame->getRootFrame()->GetCurrShell()->GetOut());
889 pFrame = pFrame->GetNext();
891 lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pSectFrame),
892 &_rAnchorTextFrame );
893 // #i44049#
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());
904 // #i44049#
905 _rAnchorTextFrame.LockJoin();
906 SwFrameDeleteGuard aDeleteGuard(&_rAnchorTextFrame);
907 SwFrame* pColFrame = pColFrameOfAnchor->GetUpper()->GetLower();
908 while ( pColFrame != pColFrameOfAnchor )
910 SwFrame* pFrame = pColFrame->GetLower();
911 while ( pFrame )
913 if ( pFrame->IsLayoutFrame() )
914 lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pFrame) );
915 else
916 pFrame->Calc(pFrame->getRootFrame()->GetCurrShell()->GetOut());
918 pFrame = pFrame->GetNext();
921 pColFrame = pColFrame->GetNext();
923 // #i44049#
924 _rAnchorTextFrame.UnlockJoin();
928 // format anchor frame - format of its follow not needed
929 // #i43255# - forbid follow format, only if anchor text
930 // frame is in table
931 if ( _rAnchorTextFrame.IsInTab() )
933 SwForbidFollowFormat aForbidFollowFormat( _rAnchorTextFrame );
934 _rAnchorTextFrame.Calc(_rAnchorTextFrame.getRootFrame()->GetCurrShell()->GetOut());
936 else
938 _rAnchorTextFrame.Calc(_rAnchorTextFrame.getRootFrame()->GetCurrShell()->GetOut());
942 /** method to format the anchor frame for checking of the move forward condition
944 #i40141#
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()
956 bool bRet( false );
958 const SwSortedObjs* pObjs = GetAnchorFrame().GetDrawObjs();
959 if ( pObjs && pObjs->size() > 1 )
961 for (SwAnchoredObject* pAnchoredObj : *pObjs)
963 if ( pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() )
965 bRet = true;
966 break;
971 return bRet;
974 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */