LibreOffice Module sw (master)  1
objectformattertxtfrm.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
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>
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>
38 
39 using namespace ::com::sun::star;
40 
41 namespace {
42 
43 // little helper class to forbid follow formatting for the given text frame
44 class SwForbidFollowFormat
45 {
46 private:
47  SwTextFrame& mrTextFrame;
48  const bool bOldFollowFormatAllowed;
49 
50 public:
51  explicit SwForbidFollowFormat( SwTextFrame& _rTextFrame )
52  : mrTextFrame( _rTextFrame ),
53  bOldFollowFormatAllowed( _rTextFrame.FollowFormatAllowed() )
54  {
55  mrTextFrame.ForbidFollowFormat();
56  }
57 
58  ~SwForbidFollowFormat()
59  {
60  if ( bOldFollowFormatAllowed )
61  {
62  mrTextFrame.AllowFollowFormat();
63  }
64  }
65 };
66 
67 }
68 
70  const SwPageFrame& _rPageFrame,
71  SwTextFrame* _pMasterAnchorTextFrame,
72  SwLayAction* _pLayAction )
73  : SwObjectFormatter( _rPageFrame, _pLayAction, true ),
74  mrAnchorTextFrame( _rAnchorTextFrame ),
75  mpMasterAnchorTextFrame( _pMasterAnchorTextFrame )
76 {
77 }
78 
80 {
81 }
82 
83 std::unique_ptr<SwObjectFormatterTextFrame> SwObjectFormatterTextFrame::CreateObjFormatter(
84  SwTextFrame& _rAnchorTextFrame,
85  const SwPageFrame& _rPageFrame,
86  SwLayAction* _pLayAction )
87 {
88  std::unique_ptr<SwObjectFormatterTextFrame> pObjFormatter;
89 
90  // determine 'master' of <_rAnchorTextFrame>, if anchor frame is a follow text frame.
91  SwTextFrame* pMasterOfAnchorFrame = nullptr;
92  if ( _rAnchorTextFrame.IsFollow() )
93  {
94  pMasterOfAnchorFrame = _rAnchorTextFrame.FindMaster();
95  while ( pMasterOfAnchorFrame && pMasterOfAnchorFrame->IsFollow() )
96  {
97  pMasterOfAnchorFrame = pMasterOfAnchorFrame->FindMaster();
98  }
99  }
100 
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() ) )
105  {
106  pObjFormatter.reset(
107  new SwObjectFormatterTextFrame( _rAnchorTextFrame, _rPageFrame,
108  pMasterOfAnchorFrame, _pLayAction ));
109  }
110 
111  return pObjFormatter;
112 }
113 
115 {
116  return mrAnchorTextFrame;
117 }
118 
119 // #i40147# - add parameter <_bCheckForMovedFwd>.
121  const bool _bCheckForMovedFwd )
122 {
123  // consider, if the layout action has to be
124  // restarted due to a delete of a page frame.
125  if ( GetLayAction() && GetLayAction()->IsAgain() )
126  {
127  return false;
128  }
129 
130  bool bSuccess( true );
131 
132  if ( _rAnchoredObj.IsFormatPossible() )
133  {
134  _rAnchoredObj.SetRestartLayoutProcess( false );
135 
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() )
140  {
141  return false;
142  }
143 
144  // check, if layout process has to be restarted.
145  // if yes, perform needed invalidations.
146 
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 )
156  {
157  bSuccess = false;
158  InvalidatePrevObjs( _rAnchoredObj );
159  InvalidateFollowObjs( _rAnchoredObj );
160  }
161 
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 ) )
179  {
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 );
184 
185  // #i40141# - use new method - it also formats the
186  // section the anchor frame is in.
188 
189  // #i35911#
190  if ( _rAnchoredObj.HasClearedEnvironment() )
191  {
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() )
197  {
198  bool bInsert( true );
199  sal_uInt32 nToPageNum( 0 );
200  const SwDoc& rDoc = *(GetPageFrame().GetFormat()->GetDoc());
202  rDoc, mrAnchorTextFrame, nToPageNum ) )
203  {
204  if ( nToPageNum < pAnchorPageFrame->GetPhyPageNum() )
206  else
207  bInsert = false;
208  }
209  if ( bInsert )
210  {
212  pAnchorPageFrame->GetPhyPageNum() );
214  bSuccess = false;
215  InvalidatePrevObjs( _rAnchoredObj );
216  InvalidateFollowObjs( _rAnchoredObj );
217  }
218  else
219  {
220  OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObj(..)> - anchor frame not marked to move forward" );
221  }
222  }
223  }
224  else if ( !mrAnchorTextFrame.IsFollow() && bDoesAnchorHadPrev )
225  {
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;
232 
233  sal_uInt32 nToPageNum( 0 );
234  // #i43913#
235  bool bDummy( false );
236  bool bPageHasFlysAnchoredBelowThis(false);
237  // #i58182# - consider new method signature
239  GetPgNumOfCollected( nIdx ),
241  nToPageNum, bDummy,
242  bPageHasFlysAnchoredBelowThis))
243  {
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());
250  rDoc, mrAnchorTextFrame, nMovedFwdToPageNum ) )
251  {
252  if ( nMovedFwdToPageNum < nToPageNum )
253  {
254  if (!bPageHasFlysAnchoredBelowThis)
255  {
257  }
258  }
259  else
260  bInsert = false;
261  }
262  if ( bInsert )
263  {
264  // Indicate that anchor text frame has to move forward and
265  // invalidate its position to force a re-format.
266  if (!bPageHasFlysAnchoredBelowThis)
267  {
269  mrAnchorTextFrame, nToPageNum);
270  }
272 
273  // Indicate restart of the layout process
274  bSuccess = false;
275 
276  // If needed, invalidate previous objects anchored at same anchor
277  // text frame.
278  InvalidatePrevObjs( _rAnchoredObj );
279 
280  // Invalidate object and following objects for the restart of the
281  // layout process
282  InvalidateFollowObjs( _rAnchoredObj );
283  }
284  else
285  {
286  OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObj(..)> - anchor frame not marked to move forward" );
287  }
288  }
289  }
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() &&
295  {
299  }
300  }
301  }
302 
303  return bSuccess;
304 }
305 
307 {
309  {
310  if ( GetLayAction() &&
312  {
313  // notify layout action, thus is can restart the layout process on
314  // a previous page.
315  GetLayAction()->SetAgain();
316  }
317  else
318  {
319  // the anchor text frame has to be valid, thus assert.
320  OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObjs()> called for invalidate anchor text frame." );
321  }
322 
323  return false;
324  }
325 
326  bool bSuccess( true );
327 
328  if ( mrAnchorTextFrame.IsFollow() )
329  {
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'
334  // anchor text frame
335  OSL_ENSURE( mpMasterAnchorTextFrame,
336  "SwObjectFormatterTextFrame::DoFormatObjs() - missing 'master' anchor text frame" );
338 
339  if ( bSuccess )
340  {
341  // format of as-character anchored floating screen objects - no failure
342  // expected on the format of these objects.
343  bSuccess = FormatObjsAtFrame_();
344  }
345  }
346  else
347  {
348  bSuccess = FormatObjsAtFrame_();
349  }
350 
351  // consider anchored objects, whose wrapping style influence are temporarily
352  // considered.
353  if ( bSuccess &&
354  ( ConsiderWrapOnObjPos() ||
357  {
358  const bool bDoesAnchorHadPrev = ( mrAnchorTextFrame.GetIndPrev() != nullptr );
359 
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.
368 
369  sal_uInt32 nToPageNum( 0 );
370  // #i43913#
371  bool bInFollow( false );
372  bool bPageHasFlysAnchoredBelowThis(false);
373  SwAnchoredObject* pObj = nullptr;
374  if ( !mrAnchorTextFrame.IsFollow() )
375  {
377  // #i35017# - constant name has changed
378  text::WrapInfluenceOnPosition::ONCE_CONCURRENT,
379  nToPageNum, bInFollow, bPageHasFlysAnchoredBelowThis );
380  }
381  // #i35911#
382  if ( pObj && pObj->HasClearedEnvironment() )
383  {
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() ||
391  bInFollow )
392  {
393  bool bInsert( true );
394  sal_uInt32 nTmpToPageNum( 0 );
395  const SwDoc& rDoc = *(GetPageFrame().GetFormat()->GetDoc());
397  rDoc, mrAnchorTextFrame, nTmpToPageNum ) )
398  {
399  if ( nTmpToPageNum < pAnchorPageFrame->GetPhyPageNum() )
400  {
401  if (!bPageHasFlysAnchoredBelowThis)
402  {
404  }
405  }
406  else
407  bInsert = false;
408  }
409  if ( bInsert )
410  {
411  if (bPageHasFlysAnchoredBelowThis)
412  {
414  pAnchorPageFrame->GetPhyPageNum());
415  }
417  bSuccess = false;
418  InvalidatePrevObjs( *pObj );
419  InvalidateFollowObjs( *pObj );
420  }
421  else
422  {
423  OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObjs(..)> - anchor frame not marked to move forward" );
424  }
425  }
426  }
427  else if ( pObj && bDoesAnchorHadPrev )
428  {
429  // Object found, whose anchor is moved forward
430 
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());
437  rDoc, mrAnchorTextFrame, nMovedFwdToPageNum ) )
438  {
439  if ( nMovedFwdToPageNum < nToPageNum )
441  else
442  bInsert = false;
443  }
444  if ( bInsert )
445  {
446  // Indicate that anchor text frame has to move forward and
447  // invalidate its position to force a re-format.
450 
451  // Indicate restart of the layout process
452  bSuccess = false;
453 
454  // If needed, invalidate previous objects anchored at same anchor
455  // text frame.
456  InvalidatePrevObjs( *pObj );
457 
458  // Invalidate object and following objects for the restart of the
459  // layout process
460  InvalidateFollowObjs( *pObj );
461  }
462  else
463  {
464  OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObjs(..)> - anchor frame not marked to move forward" );
465  }
466  }
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() &&
472  {
476  }
477  }
478 
479  return bSuccess;
480 }
481 
483 {
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 )
492  return;
493 
494  const SwSortedObjs* pObjs = GetAnchorFrame().GetDrawObjs();
495  if ( !pObjs )
496  return;
497 
498  // determine start index
499  size_t i = pObjs->ListPosOf( _rAnchoredObj );
500  while (i > 0)
501  {
502  --i;
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 )
509  {
511  }
512  }
513 }
514 
516 {
518 
519  const SwSortedObjs* pObjs = GetPageFrame().GetSortedObjs();
520  if ( pObjs )
521  {
522  // determine start index
523  for ( size_t i = pObjs->ListPosOf( _rAnchoredObj ) + 1; i < pObjs->size(); ++i )
524  {
525  SwAnchoredObject* pAnchoredObj = (*pObjs)[i];
527  }
528  }
529 }
530 
532  const sal_Int16 _nWrapInfluenceOnPosition,
533  sal_uInt32& _noToPageNum,
534  bool& _boInFollow,
535  bool& o_rbPageHasFlysAnchoredBelowThis)
536 {
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>" );
541 
542  SwAnchoredObject* pRetAnchoredObj = nullptr;
543 
544  sal_uInt32 i = 0;
545  for ( ; i < CountOfCollected(); ++i )
546  {
547  SwAnchoredObject* pAnchoredObj = GetCollectedObj(i);
548  if ( pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() &&
549  pAnchoredObj->GetFrameFormat().GetWrapInfluenceOnObjPos().
550  // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE
551  GetWrapInfluenceOnObjPos( true ) == _nWrapInfluenceOnPosition )
552  {
553  // #i26945# - use new method <_CheckMovedFwdCondition(..)>
554  // #i43913#
555  // #i58182# - consider new method signature
557  GetPgNumOfCollected( i ),
559  _noToPageNum, _boInFollow,
560  o_rbPageHasFlysAnchoredBelowThis) )
561  {
562  pRetAnchoredObj = pAnchoredObj;
563  break;
564  }
565  }
566  }
567 
568  return pRetAnchoredObj;
569 }
570 
571 static SwRowFrame const* FindTopLevelRowFrame(SwFrame const*const pFrame)
572 {
573  SwRowFrame * pRow = const_cast<SwFrame*>(pFrame)->FindRowFrame();
574  // looks like SwTabFrame has mbInfTab = true so go up 2 levels
575  while (pRow->GetUpper()->GetUpper()->IsInTab())
576  {
577  pRow = pRow->GetUpper()->GetUpper()->FindRowFrame();
578  }
579  return pRow;
580 }
581 
582 static SwContentFrame const* FindFrameInBody(SwAnchoredObject const& rAnchored)
583 {
584  SwFrame const*const pAnchor(rAnchored.GetAnchorFrame());
585  assert(pAnchor);
586  if (pAnchor->IsPageFrame() || pAnchor->FindFooterOrHeader())
587  {
588  return nullptr;
589  }
590  if (pAnchor->IsInFly())
591  {
592  return FindFrameInBody(*pAnchor->FindFlyFrame());
593  }
594  if (pAnchor->IsInFootnote())
595  {
596  return pAnchor->FindFootnoteFrame()->GetRef();
597  }
598  assert(pAnchor->IsInDocBody());
599  assert(pAnchor->IsContentFrame());
600  return static_cast<SwContentFrame const*>(pAnchor);
601 }
602 
603 // #i58182#
604 // - replace private method by corresponding static public method
606  SwAnchoredObject& _rAnchoredObj,
607  const sal_uInt32 _nFromPageNum,
608  const bool _bAnchoredAtMasterBeforeFormatAnchor,
609  sal_uInt32& _noToPageNum,
610  bool& _boInFollow,
611  bool& o_rbPageHasFlysAnchoredBelowThis)
612 {
613  bool bAnchorIsMovedForward( false );
614 
615  SwPageFrame* pPageFrameOfAnchor = _rAnchoredObj.FindPageFrameOfAnchor();
616  if ( pPageFrameOfAnchor )
617  {
618  const sal_uInt32 nPageNum = pPageFrameOfAnchor->GetPhyPageNum();
619  if ( nPageNum > _nFromPageNum )
620  {
621  _noToPageNum = nPageNum;
622  // Handling of special case:
623  // If anchor frame is move forward into a follow flow row,
624  // <_noToPageNum> is set to <_nFromPageNum + 1>, because it is
625  // possible that the anchor page frame isn't valid, because the
626  // page distance between master row and follow flow row is greater
627  // than 1.
628  if ( _noToPageNum > (_nFromPageNum + 1) )
629  {
630  SwFrame* pAnchorFrame = _rAnchoredObj.GetAnchorFrameContainingAnchPos();
631  if ( pAnchorFrame->IsInTab() &&
632  pAnchorFrame->IsInFollowFlowRow() )
633  {
634  _noToPageNum = _nFromPageNum + 1;
635  }
636  }
637  bAnchorIsMovedForward = true;
638  }
639  }
640  // #i26945# - check, if an at-paragraph|at-character
641  // anchored object is now anchored at a follow text frame, which will be
642  // on the next page. Also check, if an at-character anchored object
643  // is now anchored at a text frame, which is in a follow flow row,
644  // which will be on the next page.
645  if ( !bAnchorIsMovedForward &&
646  _bAnchoredAtMasterBeforeFormatAnchor &&
647  ((_rAnchoredObj.GetFrameFormat().GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_CHAR) ||
648  (_rAnchoredObj.GetFrameFormat().GetAnchor().GetAnchorId() == RndStdIds::FLY_AT_PARA)))
649  {
650  SwFrame* pAnchorFrame = _rAnchoredObj.GetAnchorFrameContainingAnchPos();
651  OSL_ENSURE( pAnchorFrame->IsTextFrame(),
652  "<SwObjectFormatterTextFrame::CheckMovedFwdCondition(..) - wrong type of anchor frame>" );
653  SwTextFrame* pAnchorTextFrame = static_cast<SwTextFrame*>(pAnchorFrame);
654  bool bCheck( false );
655  if ( pAnchorTextFrame->IsFollow() )
656  {
657  bCheck = true;
658  }
659  else if( pAnchorTextFrame->IsInTab() )
660  {
661  const SwRowFrame* pMasterRow = pAnchorTextFrame->IsInFollowFlowRow();
662  if ( pMasterRow &&
663  pMasterRow->FindPageFrame() == pPageFrameOfAnchor )
664  {
665  bCheck = true;
666  }
667  }
668  if ( bCheck )
669  {
670  // check, if found text frame will be on the next page
671  // by checking, if it's in a column, which has no next.
672  SwFrame* pColFrame = pAnchorTextFrame->FindColFrame();
673  while ( pColFrame && !pColFrame->GetNext() )
674  {
675  pColFrame = pColFrame->FindColFrame();
676  }
677  if ( !pColFrame || !pColFrame->GetNext() )
678  {
679  _noToPageNum = _nFromPageNum + 1;
680  bAnchorIsMovedForward = true;
681  // #i43913#
682  _boInFollow = true;
683  }
684  }
685  }
686 
687  if (bAnchorIsMovedForward)
688  {
689  // tdf#138518 try to determine if there is a fly on page _nFromPageNum
690  // which is anchored in a frame that is "below" the anchor frame
691  // of _rAnchoredObj, such that it should move to the next page before
692  // _rAnchoredObj does
693  SwPageFrame const& rAnchoredObjPage(*_rAnchoredObj.GetPageFrame());
694  assert(rAnchoredObjPage.GetPhyPageNum() == _nFromPageNum);
695  if (auto * pObjs = rAnchoredObjPage.GetSortedObjs())
696  {
697  for (SwAnchoredObject *const pObj : *pObjs)
698  {
699  SwPageFrame const*const pObjAnchorPage(pObj->FindPageFrameOfAnchor());
700  assert(pObjAnchorPage);
701  if ((pObjAnchorPage == &rAnchoredObjPage
702  ? _boInFollow // same-page but will move forward
703  : rAnchoredObjPage.GetPhyPageNum() < pObjAnchorPage->GetPhyPageNum())
704  && pObj->GetFrameFormat().GetAnchor().GetAnchorId()
705  != RndStdIds::FLY_AS_CHAR)
706  {
707  if (pPageFrameOfAnchor->GetPhyPageNum() < pObjAnchorPage->GetPhyPageNum())
708  {
709  SAL_INFO("sw.layout", "SwObjectFormatterTextFrame::CheckMovedFwdCondition(): o_rbPageHasFlysAnchoredBelowThis because next page");
710  o_rbPageHasFlysAnchoredBelowThis = true;
711  break;
712  }
713  // on same page: check if it's in next-chain in the document body
714  // (in case both are in the same fly the flag must not be
715  // set because the whole fly moves at once)
716  SwContentFrame const*const pInBodyFrameObj(FindFrameInBody(*pObj));
717  SwContentFrame const*const pInBodyFrameAnchoredObj(FindFrameInBody(_rAnchoredObj));
718  if (pInBodyFrameObj && pInBodyFrameAnchoredObj)
719  {
720  bool isBreakMore(false);
721  // currently this ignores index of at-char flys
722  for (SwContentFrame const* pContentFrame = pInBodyFrameAnchoredObj->FindNextCnt();
723  pContentFrame;
724  pContentFrame = pContentFrame->FindNextCnt())
725  {
726  if (pInBodyFrameObj == pContentFrame)
727  {
728  // subsequent cells in a row are not automatically
729  // "below" and the row could potentially be split
730  // TODO refine check if needed
731  if (!pInBodyFrameAnchoredObj->IsInTab()
732  || FindTopLevelRowFrame(pInBodyFrameAnchoredObj)
733  != FindTopLevelRowFrame(pInBodyFrameAnchoredObj))
734  { // anchored in next chain on same page
735  SAL_INFO("sw.layout", "SwObjectFormatterTextFrame::CheckMovedFwdCondition(): o_rbPageHasFlysAnchoredBelowThis because next chain on same page");
736  o_rbPageHasFlysAnchoredBelowThis = true;
737  isBreakMore = true;
738  }
739  break;
740  }
741  }
742  if (isBreakMore)
743  {
744  break;
745  }
746  }
747  }
748  }
749  }
750  }
751 
752  return bAnchorIsMovedForward;
753 }
754 
755 static void CleanupEmptyFootnoteFrame(SwFrame* pLowerFrame)
756 {
757  // Calc on a SwTextFrame in a footnote can move it to the next page -
758  // deletion of the SwFootnoteFrame was disabled with SwFrameDeleteGuard
759  // but now we have to clean up empty footnote frames to prevent crashes.
760  // Note: check it at this level, not lower: both container and footnote
761  // can be deleted at the same time!
762  if (!pLowerFrame->IsFootnoteContFrame())
763  return;
764 
765  for (SwFrame * pFootnote = pLowerFrame->GetLower(); pFootnote; )
766  {
767  assert(pFootnote->IsFootnoteFrame());
768  SwFrame *const pNextNote = pFootnote->GetNext();
769  if (!pFootnote->IsDeleteForbidden() && !pFootnote->GetLower() && !pFootnote->IsColLocked() &&
770  !static_cast<SwFootnoteFrame*>(pFootnote)->IsBackMoveLocked())
771  {
772  pFootnote->Cut();
773  SwFrame::DestroyFrame(pFootnote);
774  }
775  pFootnote = pNextNote;
776  }
777 }
778 
779 // #i40140# - helper method to format layout frames used by
780 // method <SwObjectFormatterTextFrame::FormatAnchorFrameForCheckMoveFwd()>
781 // #i44049# - format till a certain lower frame, if provided.
783  SwFrame* pLastLowerFrame = nullptr )
784 {
785  SwFrame* pLowerFrame = pLayFrame->GetLower();
786  while ( pLowerFrame )
787  {
788  // #i44049#
789  if ( pLastLowerFrame && pLowerFrame == pLastLowerFrame )
790  {
791  break;
792  }
793  if ( pLowerFrame->IsLayoutFrame() )
794  {
795  SwFrameDeleteGuard aCrudeHack(pLowerFrame); // ??? any issue setting this for non-footnote frames?
796  lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pLowerFrame),
797  pLastLowerFrame );
798  }
799  else
800  pLowerFrame->Calc(pLowerFrame->getRootFrame()->GetCurrShell()->GetOut());
801 
802  // Calc on a SwTextFrame in a footnote can move it to the next page -
803  // deletion of the SwFootnoteFrame was disabled with SwFrameDeleteGuard
804  // but now we have to clean up empty footnote frames to prevent crashes.
805  // Note: check it at this level, not lower: both container and footnote
806  // can be deleted at the same time!
807  SwFrame *const pNext = pLowerFrame->GetNext();
808  CleanupEmptyFootnoteFrame(pLowerFrame);
809  pLowerFrame = pNext;
810  }
811 }
812 
822 {
823  // #i47014# - no format of section and previous columns
824  // for follow text frames.
825  if ( !_rAnchorTextFrame.IsFollow() )
826  {
827  // if anchor frame is directly inside a section, format this section and
828  // its previous frames.
829  // Note: It's a very simple format without formatting objects.
830  if ( _rAnchorTextFrame.IsInSct() )
831  {
832  SwFrame* pSectFrame = _rAnchorTextFrame.GetUpper();
833  while ( pSectFrame )
834  {
835  if ( pSectFrame->IsSctFrame() || pSectFrame->IsCellFrame() )
836  {
837  break;
838  }
839  pSectFrame = pSectFrame->GetUpper();
840  }
841  if ( pSectFrame && pSectFrame->IsSctFrame() )
842  {
843  SwFrameDeleteGuard aDeleteGuard(&_rAnchorTextFrame);
844  // #i44049#
845  _rAnchorTextFrame.LockJoin();
846  SwFrame* pFrame = pSectFrame->GetUpper()->GetLower();
847  // #i49605# - section frame could move forward
848  // by the format of its previous frame.
849  // Thus, check for valid <pFrame>.
850  while ( pFrame && pFrame != pSectFrame )
851  {
852  if ( pFrame->IsLayoutFrame() )
853  lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pFrame) );
854  else
855  pFrame->Calc(pFrame->getRootFrame()->GetCurrShell()->GetOut());
856 
857  pFrame = pFrame->GetNext();
858  }
859  lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pSectFrame),
860  &_rAnchorTextFrame );
861  // #i44049#
862  _rAnchorTextFrame.UnlockJoin();
863  }
864  }
865 
866  // #i40140# - if anchor frame is inside a column,
867  // format the content of the previous columns.
868  // Note: It's a very simple format without formatting objects.
869  SwFrame* pColFrameOfAnchor = _rAnchorTextFrame.FindColFrame();
870  SAL_WARN_IF(pColFrameOfAnchor && _rAnchorTextFrame.IsInFootnote(), "sw.layout", "tdf#122894 skipping anchor in column in footnote");
871  if (pColFrameOfAnchor && !_rAnchorTextFrame.IsInFootnote())
872  {
873  // #i44049#
874  _rAnchorTextFrame.LockJoin();
875  SwFrameDeleteGuard aDeleteGuard(&_rAnchorTextFrame);
876  SwFrame* pColFrame = pColFrameOfAnchor->GetUpper()->GetLower();
877  while ( pColFrame != pColFrameOfAnchor )
878  {
879  SwFrame* pFrame = pColFrame->GetLower();
880  while ( pFrame )
881  {
882  if ( pFrame->IsLayoutFrame() )
883  lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pFrame) );
884  else
885  pFrame->Calc(pFrame->getRootFrame()->GetCurrShell()->GetOut());
886 
887  pFrame = pFrame->GetNext();
888  }
889 
890  pColFrame = pColFrame->GetNext();
891  }
892  // #i44049#
893  _rAnchorTextFrame.UnlockJoin();
894  }
895  }
896 
897  // format anchor frame - format of its follow not needed
898  // #i43255# - forbid follow format, only if anchor text
899  // frame is in table
900  if ( _rAnchorTextFrame.IsInTab() )
901  {
902  SwForbidFollowFormat aForbidFollowFormat( _rAnchorTextFrame );
903  _rAnchorTextFrame.Calc(_rAnchorTextFrame.getRootFrame()->GetCurrShell()->GetOut());
904  }
905  else
906  {
907  _rAnchorTextFrame.Calc(_rAnchorTextFrame.getRootFrame()->GetCurrShell()->GetOut());
908  }
909 }
910 
916 {
918 }
919 
924 {
925  bool bRet( false );
926 
927  const SwSortedObjs* pObjs = GetAnchorFrame().GetDrawObjs();
928  if ( pObjs && pObjs->size() > 1 )
929  {
930  for (SwAnchoredObject* pAnchoredObj : *pObjs)
931  {
932  if ( pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() )
933  {
934  bRet = true;
935  break;
936  }
937  }
938  }
939 
940  return bRet;
941 }
942 
943 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
vcl::RenderContext * GetOut() const
Definition: viewsh.hxx:338
bool GetValue() const
virtual bool DoFormatObj(SwAnchoredObject &_rAnchoredObj, const bool _bCheckForMovedFwd=false) override
intrinsic method to format a certain floating screen object
Base class of the Writer layout elements.
Definition: frame.hxx:313
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:157
const SwPageFrame & GetPageFrame() const
void AllowFollowFormat()
Definition: txtfrm.hxx:745
bool IsFollow() const
Definition: flowfrm.hxx:166
const SwSortedObjs * GetDrawObjs() const
Definition: frame.hxx:563
void SetClearedEnvironment(const bool _bClearedEnvironment)
bool IsInFly() const
Definition: frame.hxx:957
bool IsInSct() const
Definition: frame.hxx:963
virtual SwFrame & GetAnchorFrame() override
bool IsInFootnote() const
Definition: frame.hxx:945
static std::unique_ptr< SwObjectFormatterTextFrame > CreateObjFormatter(SwTextFrame &_rAnchorTextFrame, const SwPageFrame &_rPageFrame, SwLayAction *_pLayAction)
method to create an instance of is necessary.
bool AtLeastOneObjIsTmpConsiderWrapInfluence()
method to determine if at least one anchored object has state
SwLayAction * GetLayAction()
static bool CheckMovedFwdCondition(SwAnchoredObject &_rAnchoredObj, const sal_uInt32 _nFromPageNum, const bool _bAnchoredAtMasterBeforeFormatAnchor, sal_uInt32 &_noToPageNum, bool &_boInFollow, bool &o_rbPageHasFlysAnchoredBelowThis)
method to check the conditions, if 'anchor is moved forward'
Definition: doc.hxx:187
void InvalidatePos()
Definition: frame.hxx:1039
bool ConsiderWrapOnObjPos() const
static void DestroyFrame(SwFrame *const pFrame)
this is the only way to delete a SwFrame instance
Definition: ssfrm.cxx:384
virtual void Calc(vcl::RenderContext *pRenderContext) const
Definition: trvlfrm.cxx:1788
bool IsCellFrame() const
Definition: frame.hxx:1222
bool isFrameAreaDefinitionValid() const
Definition: frame.hxx:170
sal_uInt16 GetPhyPageNum() const
Definition: pagefrm.hxx:188
void InvalidateObjPosForConsiderWrapInfluence()
method to perform necessary invalidations for the positioning of objects, for whose the wrapping styl...
wrapper class for the positioning of Writer fly frames and drawing objects
const BorderLinePrimitive2D *pCandidateB assert(pCandidateA)
bool IsInTab() const
Definition: frame.hxx:951
bool IsTextFrame() const
Definition: frame.hxx:1230
SwRowFrame * FindRowFrame()
Definition: findfrm.cxx:539
void InvalidatePrevObjs(SwAnchoredObject &_rAnchoredObj)
method to invalidate objects, anchored previous to given object at the anchor text frame ...
bool IsSctFrame() const
Definition: frame.hxx:1210
SwAnchoredObject * GetCollectedObj(const sal_uInt32 _nIndex)
accessor to collected anchored object
SwTextFrame * GetFollow()
Definition: txtfrm.hxx:852
TextFrameIndex GetOffset() const
Definition: txtfrm.hxx:435
virtual void Cut()=0
SwFootnoteFrame * FindFootnoteFrame()
Definition: frame.hxx:1103
const SwFormatFollowTextFlow & GetFollowTextFlow(bool=true) const
SwFrame * GetIndPrev() const
Definition: frame.hxx:722
const SwSortedObjs * GetSortedObjs() const
Definition: pagefrm.hxx:116
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:81
int i
The usage of LayAction is always the same:
Definition: layact.hxx:55
bool FormatObjsAtFrame_(SwTextFrame *_pMasterTextFrame=nullptr)
invokes the intrinsic format method for all floating screen objects, anchored at anchor frame on the ...
RndStdIds GetAnchorId() const
Definition: fmtanchr.hxx:65
sal_uInt32 GetPgNumOfCollected(const sal_uInt32 _nIndex)
accessor to 'anchor' page number of collected anchored object
size_t size() const
Definition: sortedobjs.cxx:43
SwPageFrame * FindPageFrame()
Definition: frame.hxx:678
static void RemoveMovedFwdFrame(const SwDoc &_rDoc, const SwTextFrame &_rTextFrame)
Definition: layouter.cxx:332
SwContentFrame * FindNextCnt(const bool _bInSameFootnote=false)
Definition: findfrm.cxx:191
SwAnchoredObject * GetFirstObjWithMovedFwdAnchor(const sal_Int16 _nWrapInfluenceOnPosition, sal_uInt32 &_noToPageNum, bool &_boInFollow, bool &o_rbPageHasFlysAnchoredBelowThis)
method to determine first anchored object, whose 'anchor is moved forward'.
void FormatObj_(SwAnchoredObject &_rAnchoredObj)
performs the intrinsic format of a given floating screen object and its content.
SwLayoutFrame * GetUpper()
Definition: frame.hxx:676
static SwContentFrame const * FindFrameInBody(SwAnchoredObject const &rAnchored)
void LockJoin()
Definition: flowfrm.hxx:139
const SwRowFrame * IsInFollowFlowRow() const
Definition: findfrm.cxx:1786
const SwDoc * GetDoc() const
The document is set in SwAttrPool now, therefore you always can access it.
Definition: format.hxx:123
void FormatAnchorFrameForCheckMoveFwd()
method to format the anchor frame for checking of the move forward condition
A page of the document layout.
Definition: pagefrm.hxx:41
SwFrame * GetAnchorFrameContainingAnchPos()
determine anchor frame containing the anchor position
bool RestartLayoutProcess() const
SwFrame * FindColFrame()
Definition: findfrm.cxx:530
void InvalidateFollowObjs(SwAnchoredObject &_rAnchoredObj)
method to invalidate objects, anchored after the given object at the page frame
static void lcl_FormatContentOfLayoutFrame(SwLayoutFrame *pLayFrame, SwFrame *pLastLowerFrame=nullptr)
bool IsLayoutFrame() const
Definition: frame.hxx:1166
virtual bool IsFormatPossible() const
method to determine, if a format on the anchored object is possible
bool ConsiderObjWrapInfluenceOnObjPos() const
method to determine, if wrapping style influence of the anchored object has to be considered on the o...
void UnlockJoin()
Definition: flowfrm.hxx:140
virtual SwFrameFormat & GetFrameFormat()=0
SwPageFrame * FindPageFrameOfAnchor()
method to determine the page frame, on which the 'anchor' of the given anchored object is...
void SetAgain()
Definition: layact.hxx:157
#define SAL_WARN_IF(condition, area, stream)
SwTextFrame * FindMaster() const
Definition: flowfrm.cxx:738
SwPageFrame * GetPageFrame()
sal_uInt16 GetPhyPageNum() const
Definition: trvlfrm.cxx:1695
bool HasClearedEnvironment() const
method to determine, if due to anchored object size and wrapping style, its layout environment is cle...
void ForbidFollowFormat()
Definition: txtfrm.hxx:750
#define SAL_INFO(area, stream)
virtual ~SwObjectFormatterTextFrame() override
SwFrame * GetLower()
Definition: findfrm.cxx:170
const SwContentFrame * GetRef() const
Definition: ftnfrm.cxx:2889
size_t ListPosOf(const SwAnchoredObject &_rAnchoredObj) const
Position of object <_rAnchoredObj> in sorted list.
Definition: sortedobjs.cxx:277
const SwFormatWrapInfluenceOnObjPos & GetWrapInfluenceOnObjPos(bool=true) const
bool IsCollectedAnchoredAtMaster(const sal_uInt32 _nIndex)
accessor to 'anchor' type of collected anchored object
A layout frame is a frame that contains other frames (m_pLower), e.g. SwPageFrame or SwTabFrame...
Definition: layfrm.hxx:35
static void CleanupEmptyFootnoteFrame(SwFrame *pLowerFrame)
const SwFrame * GetAnchorFrame() const
static bool FrameMovedFwdByObjPos(const SwDoc &_rDoc, const SwTextFrame &_rTextFrame, sal_uInt32 &_ornToPageNum)
Definition: layouter.cxx:342
bool IsFootnoteContFrame() const
Definition: frame.hxx:1194
static void FormatAnchorFrameAndItsPrevs(SwTextFrame &_rAnchorTextFrame)
method to format given anchor text frame and its previous frames
bool PositionLocked() const
SwViewShell * GetCurrShell() const
Definition: rootfrm.hxx:208
o3tl::strong_int< sal_Int32, struct Tag_TextFrameIndex > TextFrameIndex
Denotes a character index in a text frame at a layout level, after extent mapping from a text node at...
class for collecting anchored objects
Definition: sortedobjs.hxx:48
virtual bool DoFormatObjs() override
intrinsic method to format all floating screen objects
void SetRestartLayoutProcess(const bool _bRestartLayoutProcess)
SwObjectFormatterTextFrame(SwTextFrame &_rAnchorTextFrame, const SwPageFrame &_rPageFrame, SwTextFrame *_pMasterAnchorTextFrame, SwLayAction *_pLayAction)
SwRootFrame * getRootFrame()
Definition: frame.hxx:677
static void InsertMovedFwdFrame(const SwDoc &_rDoc, const SwTextFrame &_rMovedFwdFrameByObjPos, const sal_uInt32 _nToPageNum)
Definition: layouter.cxx:312
SwRowFrame is one table row in the document layout.
Definition: rowfrm.hxx:28
virtual const SwFrameFormat * GetFormat() const
Definition: ssfrm.cxx:395
SwFrame * GetNext()
Definition: frame.hxx:674
static SwRowFrame const * FindTopLevelRowFrame(SwFrame const *const pFrame)
sal_uInt32 CountOfCollected()
accessor to total number of collected anchored objects