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 <sortedobjs.hxx>
22 #include <rootfrm.hxx>
23 #include <anchoredobject.hxx>
24 #include <txtfrm.hxx>
25 #include <pagefrm.hxx>
26 #include <rowfrm.hxx>
27 #include <layouter.hxx>
28 #include <fmtanchr.hxx>
30 #include <fmtfollowtextflow.hxx>
31 #include <layact.hxx>
32 #include <flyfrm.hxx>
33 #include <ftnfrm.hxx>
34 #include <osl/diagnose.h>
35 
36 using namespace ::com::sun::star;
37 
38 namespace {
39 
40 // little helper class to forbid follow formatting for the given text frame
41 class SwForbidFollowFormat
42 {
43 private:
44  SwTextFrame& mrTextFrame;
45  const bool bOldFollowFormatAllowed;
46 
47 public:
48  explicit SwForbidFollowFormat( SwTextFrame& _rTextFrame )
49  : mrTextFrame( _rTextFrame ),
50  bOldFollowFormatAllowed( _rTextFrame.FollowFormatAllowed() )
51  {
52  mrTextFrame.ForbidFollowFormat();
53  }
54 
55  ~SwForbidFollowFormat()
56  {
57  if ( bOldFollowFormatAllowed )
58  {
59  mrTextFrame.AllowFollowFormat();
60  }
61  }
62 };
63 
64 }
65 
67  const SwPageFrame& _rPageFrame,
68  SwTextFrame* _pMasterAnchorTextFrame,
69  SwLayAction* _pLayAction )
70  : SwObjectFormatter( _rPageFrame, _pLayAction, true ),
71  mrAnchorTextFrame( _rAnchorTextFrame ),
72  mpMasterAnchorTextFrame( _pMasterAnchorTextFrame )
73 {
74 }
75 
77 {
78 }
79 
80 std::unique_ptr<SwObjectFormatterTextFrame> SwObjectFormatterTextFrame::CreateObjFormatter(
81  SwTextFrame& _rAnchorTextFrame,
82  const SwPageFrame& _rPageFrame,
83  SwLayAction* _pLayAction )
84 {
85  std::unique_ptr<SwObjectFormatterTextFrame> pObjFormatter;
86 
87  // determine 'master' of <_rAnchorTextFrame>, if anchor frame is a follow text frame.
88  SwTextFrame* pMasterOfAnchorFrame = nullptr;
89  if ( _rAnchorTextFrame.IsFollow() )
90  {
91  pMasterOfAnchorFrame = _rAnchorTextFrame.FindMaster();
92  while ( pMasterOfAnchorFrame && pMasterOfAnchorFrame->IsFollow() )
93  {
94  pMasterOfAnchorFrame = pMasterOfAnchorFrame->FindMaster();
95  }
96  }
97 
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() ) )
102  {
103  pObjFormatter.reset(
104  new SwObjectFormatterTextFrame( _rAnchorTextFrame, _rPageFrame,
105  pMasterOfAnchorFrame, _pLayAction ));
106  }
107 
108  return pObjFormatter;
109 }
110 
112 {
113  return mrAnchorTextFrame;
114 }
115 
116 // #i40147# - add parameter <_bCheckForMovedFwd>.
118  const bool _bCheckForMovedFwd )
119 {
120  // consider, if the layout action has to be
121  // restarted due to a delete of a page frame.
122  if ( GetLayAction() && GetLayAction()->IsAgain() )
123  {
124  return false;
125  }
126 
127  bool bSuccess( true );
128 
129  if ( _rAnchoredObj.IsFormatPossible() )
130  {
131  _rAnchoredObj.SetRestartLayoutProcess( false );
132 
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() )
137  {
138  return false;
139  }
140 
141  // check, if layout process has to be restarted.
142  // if yes, perform needed invalidations.
143 
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() );
152  if ( bRestart )
153  {
154  bSuccess = false;
155  InvalidatePrevObjs( _rAnchoredObj );
156  InvalidateFollowObjs( _rAnchoredObj );
157  }
158 
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()>
168  if ( bSuccess &&
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 ) )
176  {
177  // #i26945# - check conditions for move forward of
178  // anchor text frame
179  // determine, if anchor text frame has previous frame
180  const bool bDoesAnchorHadPrev = ( mrAnchorTextFrame.GetIndPrev() != nullptr );
181 
182  // #i40141# - use new method - it also formats the
183  // section the anchor frame is in.
185 
186  // #i35911#
187  if ( _rAnchoredObj.HasClearedEnvironment() )
188  {
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() )
194  {
195  bool bInsert( true );
196  sal_uInt32 nToPageNum( 0 );
197  const SwDoc& rDoc = *(GetPageFrame().GetFormat()->GetDoc());
199  rDoc, mrAnchorTextFrame, nToPageNum ) )
200  {
201  if ( nToPageNum < pAnchorPageFrame->GetPhyPageNum() )
203  else
204  bInsert = false;
205  }
206  if ( bInsert )
207  {
209  pAnchorPageFrame->GetPhyPageNum() );
211  bSuccess = false;
212  InvalidatePrevObjs( _rAnchoredObj );
213  InvalidateFollowObjs( _rAnchoredObj );
214  }
215  else
216  {
217  OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObj(..)> - anchor frame not marked to move forward" );
218  }
219  }
220  }
221  else if ( !mrAnchorTextFrame.IsFollow() && bDoesAnchorHadPrev )
222  {
223  // index of anchored object in collection of page numbers and
224  // anchor types
225  sal_uInt32 nIdx( CountOfCollected() );
226  OSL_ENSURE( nIdx > 0,
227  "<SwObjectFormatterTextFrame::DoFormatObj(..)> - anchored object not collected!?" );
228  --nIdx;
229 
230  sal_uInt32 nToPageNum( 0 );
231  // #i43913#
232  bool bDummy( false );
233  bool bPageHasFlysAnchoredBelowThis(false);
234  // see how SwObjectFormatter::FormatObjsAtFrame_() checks
235  // "pPageFrameOfAnchor == &mrPageFrame" - only caller relevant for
236  // this subclass
237  assert(GetPageFrame().GetPhyPageNum() == GetPgNumOfCollected(nIdx));
239  GetPageFrame(),
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(true);
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  // see how SwObjectFormatter::FormatObjsAtFrame_() checks
554  // "pPageFrameOfAnchor == &mrPageFrame" - only caller relevant for
555  // this subclass
556  assert(GetPageFrame().GetPhyPageNum() == GetPgNumOfCollected(i));
557  // #i26945# - use new method <_CheckMovedFwdCondition(..)>
558  // #i43913#
560  GetPageFrame(),
562  _noToPageNum, _boInFollow,
563  o_rbPageHasFlysAnchoredBelowThis) )
564  {
565  pRetAnchoredObj = pAnchoredObj;
566  break;
567  }
568  }
569  }
570 
571  return pRetAnchoredObj;
572 }
573 
574 static SwRowFrame const* FindTopLevelRowFrame(SwFrame const*const pFrame)
575 {
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())
579  {
580  pRow = pRow->GetUpper()->GetUpper()->FindRowFrame();
581  }
582  return pRow;
583 }
584 
585 static SwContentFrame const* FindFrameInBody(SwAnchoredObject const& rAnchored)
586 {
587  SwFrame const*const pAnchor(rAnchored.GetAnchorFrame());
588  assert(pAnchor);
589  if (pAnchor->IsPageFrame() || pAnchor->FindFooterOrHeader())
590  {
591  return nullptr;
592  }
593  if (pAnchor->IsInFly())
594  {
595  return FindFrameInBody(*pAnchor->FindFlyFrame());
596  }
597  if (pAnchor->IsInFootnote())
598  {
599  return pAnchor->FindFootnoteFrame()->GetRef();
600  }
601  assert(pAnchor->IsInDocBody());
602  assert(pAnchor->IsContentFrame());
603  return static_cast<SwContentFrame const*>(pAnchor);
604 }
605 
606 // #i58182#
607 // - replace private method by corresponding static public method
609  SwAnchoredObject& _rAnchoredObj,
610  SwPageFrame const& rFromPageFrame,
611  const bool _bAnchoredAtMasterBeforeFormatAnchor,
612  sal_uInt32& _noToPageNum,
613  bool& _boInFollow,
614  bool& o_rbPageHasFlysAnchoredBelowThis)
615 {
616  const sal_uInt32 _nFromPageNum(rFromPageFrame.GetPhyPageNum());
617  bool bAnchorIsMovedForward( false );
618 
619  SwPageFrame* pPageFrameOfAnchor = _rAnchoredObj.FindPageFrameOfAnchor();
620  if ( pPageFrameOfAnchor )
621  {
622  const sal_uInt32 nPageNum = pPageFrameOfAnchor->GetPhyPageNum();
623  if ( nPageNum > _nFromPageNum )
624  {
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
631  // than 1.
632  if ( _noToPageNum > (_nFromPageNum + 1) )
633  {
634  SwFrame* pAnchorFrame = _rAnchoredObj.GetAnchorFrameContainingAnchPos();
635  if ( pAnchorFrame->IsInTab() &&
636  pAnchorFrame->IsInFollowFlowRow() )
637  {
638  _noToPageNum = _nFromPageNum + 1;
639  }
640  }
641  bAnchorIsMovedForward = true;
642  }
643  }
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)))
653  {
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() )
660  {
661  bCheck = true;
662  }
663  else if( pAnchorTextFrame->IsInTab() )
664  {
665  const SwRowFrame* pMasterRow = pAnchorTextFrame->IsInFollowFlowRow();
666  if ( pMasterRow &&
667  pMasterRow->FindPageFrame() == pPageFrameOfAnchor )
668  {
669  bCheck = true;
670  }
671  }
672  if ( bCheck )
673  {
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() )
678  {
679  pColFrame = pColFrame->FindColFrame();
680  }
681  if ( !pColFrame || !pColFrame->GetNext() )
682  {
683  _noToPageNum = _nFromPageNum + 1;
684  bAnchorIsMovedForward = true;
685  // #i43913#
686  _boInFollow = true;
687  }
688  }
689  }
690 
691  if (bAnchorIsMovedForward)
692  {
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())
698  {
699  for (SwAnchoredObject *const pObj : *pObjs)
700  {
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)
708  {
709  if (pPageFrameOfAnchor->GetPhyPageNum() < pObjAnchorPage->GetPhyPageNum())
710  {
711  SAL_INFO("sw.layout", "SwObjectFormatterTextFrame::CheckMovedFwdCondition(): o_rbPageHasFlysAnchoredBelowThis because next page");
712  o_rbPageHasFlysAnchoredBelowThis = true;
713  break;
714  }
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)
721  {
722  bool isBreakMore(false);
723  // currently this ignores index of at-char flys
724  for (SwContentFrame const* pContentFrame = pInBodyFrameAnchoredObj->FindNextCnt();
725  pContentFrame;
726  pContentFrame = pContentFrame->FindNextCnt())
727  {
728  if (pInBodyFrameObj == pContentFrame)
729  {
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;
739  isBreakMore = true;
740  }
741  break;
742  }
743  }
744  if (isBreakMore)
745  {
746  break;
747  }
748  }
749  }
750  }
751  }
752  }
753 
754  return bAnchorIsMovedForward;
755 }
756 
757 static void CleanupEmptyFootnoteFrame(SwFrame* pLowerFrame)
758 {
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())
765  return;
766 
767  for (SwFrame * pFootnote = pLowerFrame->GetLower(); pFootnote; )
768  {
769  assert(pFootnote->IsFootnoteFrame());
770  SwFrame *const pNextNote = pFootnote->GetNext();
771  if (!pFootnote->IsDeleteForbidden() && !pFootnote->GetLower() && !pFootnote->IsColLocked() &&
772  !static_cast<SwFootnoteFrame*>(pFootnote)->IsBackMoveLocked())
773  {
774  pFootnote->Cut();
775  SwFrame::DestroyFrame(pFootnote);
776  }
777  pFootnote = pNextNote;
778  }
779 }
780 
781 // #i40140# - helper method to format layout frames used by
782 // method <SwObjectFormatterTextFrame::FormatAnchorFrameForCheckMoveFwd()>
783 // #i44049# - format till a certain lower frame, if provided.
785  SwFrame* pLastLowerFrame = nullptr )
786 {
787  SwFrame* pLowerFrame = pLayFrame->GetLower();
788  while ( pLowerFrame )
789  {
790  // #i44049#
791  if ( pLastLowerFrame && pLowerFrame == pLastLowerFrame )
792  {
793  break;
794  }
795  if ( pLowerFrame->IsLayoutFrame() )
796  {
797  SwFrameDeleteGuard aCrudeHack(pLowerFrame); // ??? any issue setting this for non-footnote frames?
798  lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pLowerFrame),
799  pLastLowerFrame );
800  }
801  else
802  pLowerFrame->Calc(pLowerFrame->getRootFrame()->GetCurrShell()->GetOut());
803 
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);
811  pLowerFrame = pNext;
812  }
813 }
814 
824 {
825  // #i47014# - no format of section and previous columns
826  // for follow text frames.
827  if ( !_rAnchorTextFrame.IsFollow() )
828  {
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())
836  {
837  if (pUpper->IsCellFrame())
838  {
839  break; // apparently nothing to be done?
840  }
841  if (pUpper->IsFootnoteFrame())
842  {
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
846  }
847  if (pUpper->IsSctFrame())
848  {
849  pColFrameOfAnchor = nullptr;
850  pSectFrame = pUpper;
851  break;
852  }
853  if (pColFrameOfAnchor != nullptr)
854  { // parent of column not a section frame => column not in section
855  break;
856  }
857  if (pUpper->IsColumnFrame())
858  {
859  pColFrameOfAnchor = pUpper;
860  }
861  }
862 
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.
866  if (pSectFrame)
867  {
868  assert(pSectFrame->IsSctFrame());
869  {
870  SwFrameDeleteGuard aDeleteGuard(&_rAnchorTextFrame);
871  // #i44049#
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 )
878  {
879  SwFrameDeleteGuard aDeleteFrameGuard(pFrame);
880 
881  if ( pFrame->IsLayoutFrame() )
882  lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pFrame) );
883  else
884  pFrame->Calc(pFrame->getRootFrame()->GetCurrShell()->GetOut());
885 
886  pFrame = pFrame->GetNext();
887  }
888  lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pSectFrame),
889  &_rAnchorTextFrame );
890  // #i44049#
891  _rAnchorTextFrame.UnlockJoin();
892  }
893  }
894 
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)
899  {
900  assert(pColFrameOfAnchor->IsColumnFrame());
901  // #i44049#
902  _rAnchorTextFrame.LockJoin();
903  SwFrameDeleteGuard aDeleteGuard(&_rAnchorTextFrame);
904  SwFrame* pColFrame = pColFrameOfAnchor->GetUpper()->GetLower();
905  while ( pColFrame != pColFrameOfAnchor )
906  {
907  SwFrame* pFrame = pColFrame->GetLower();
908  while ( pFrame )
909  {
910  if ( pFrame->IsLayoutFrame() )
911  lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pFrame) );
912  else
913  pFrame->Calc(pFrame->getRootFrame()->GetCurrShell()->GetOut());
914 
915  pFrame = pFrame->GetNext();
916  }
917 
918  pColFrame = pColFrame->GetNext();
919  }
920  // #i44049#
921  _rAnchorTextFrame.UnlockJoin();
922  }
923  }
924 
925  // format anchor frame - format of its follow not needed
926  // #i43255# - forbid follow format, only if anchor text
927  // frame is in table
928  if ( _rAnchorTextFrame.IsInTab() )
929  {
930  SwForbidFollowFormat aForbidFollowFormat( _rAnchorTextFrame );
931  _rAnchorTextFrame.Calc(_rAnchorTextFrame.getRootFrame()->GetCurrShell()->GetOut());
932  }
933  else
934  {
935  _rAnchorTextFrame.Calc(_rAnchorTextFrame.getRootFrame()->GetCurrShell()->GetOut());
936  }
937 }
938 
944 {
946 }
947 
952 {
953  bool bRet( false );
954 
955  const SwSortedObjs* pObjs = GetAnchorFrame().GetDrawObjs();
956  if ( pObjs && pObjs->size() > 1 )
957  {
958  for (SwAnchoredObject* pAnchoredObj : *pObjs)
959  {
960  if ( pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() )
961  {
962  bRet = true;
963  break;
964  }
965  }
966  }
967 
968  return bRet;
969 }
970 
971 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
vcl::RenderContext * GetOut() const
Definition: viewsh.hxx:339
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:314
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:159
const SwPageFrame & GetPageFrame() const
void AllowFollowFormat()
Definition: txtfrm.hxx:749
bool IsFollow() const
Definition: flowfrm.hxx:166
const SwSortedObjs * GetDrawObjs() const
Definition: frame.hxx:564
void SetClearedEnvironment(const bool _bClearedEnvironment)
bool IsInFly() const
Definition: frame.hxx:961
virtual SwFrame & GetAnchorFrame() override
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()
#define SAL_INFO_IF(condition, area, stream)
Definition: doc.hxx:187
void InvalidatePos()
Definition: frame.hxx:1043
bool ConsiderWrapOnObjPos() const
static void DestroyFrame(SwFrame *const pFrame)
this is the only way to delete a SwFrame instance
Definition: ssfrm.cxx:388
virtual void Calc(vcl::RenderContext *pRenderContext) const
Definition: trvlfrm.cxx:1788
bool isFrameAreaDefinitionValid() const
Definition: frame.hxx:171
sal_uInt16 GetPhyPageNum() const
Definition: pagefrm.hxx:204
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
bool IsInTab() const
Definition: frame.hxx:955
bool IsTextFrame() const
Definition: frame.hxx:1234
SwRowFrame * FindRowFrame()
Definition: findfrm.cxx:593
void InvalidatePrevObjs(SwAnchoredObject &_rAnchoredObj)
method to invalidate objects, anchored previous to given object at the anchor text frame ...
bool IsSctFrame() const
Definition: frame.hxx:1214
SwAnchoredObject * GetCollectedObj(const sal_uInt32 _nIndex)
accessor to collected anchored object
SwTextFrame * GetFollow()
Definition: txtfrm.hxx:856
TextFrameIndex GetOffset() const
Definition: txtfrm.hxx:439
static bool CheckMovedFwdCondition(SwAnchoredObject &_rAnchoredObj, SwPageFrame const &rFromPageFrame, const bool _bAnchoredAtMasterBeforeFormatAnchor, sal_uInt32 &_noToPageNum, bool &_boInFollow, bool &o_rbPageHasFlysAnchoredBelowThis)
method to check the conditions, if 'anchor is moved forward'
virtual void Cut()=0
bool IsColumnFrame() const
Definition: frame.hxx:1182
SwFootnoteFrame * FindFootnoteFrame()
Definition: frame.hxx:1107
const SwFormatFollowTextFlow & GetFollowTextFlow(bool=true) const
SwFrame * GetIndPrev() const
Definition: frame.hxx:724
const SwSortedObjs * GetSortedObjs() const
Definition: pagefrm.hxx:132
const SwFormatAnchor & GetAnchor(bool=true) const
Definition: fmtanchr.hxx:81
int i
The usage of LayAction is always the same:
Definition: layact.hxx:58
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:680
static void RemoveMovedFwdFrame(const SwDoc &_rDoc, const SwTextFrame &_rTextFrame)
Definition: layouter.cxx:332
SwContentFrame * FindNextCnt(const bool _bInSameFootnote=false)
Definition: findfrm.cxx:215
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:678
static SwContentFrame const * FindFrameInBody(SwAnchoredObject const &rAnchored)
void LockJoin()
Definition: flowfrm.hxx:139
const SwRowFrame * IsInFollowFlowRow() const
Definition: findfrm.cxx:1842
const SwDoc * GetDoc() const
The document is set in SwAttrPool now, therefore you always can access it.
Definition: format.hxx:139
void FormatAnchorFrameForCheckMoveFwd()
method to format the anchor frame for checking of the move forward condition
A page of the document layout.
Definition: pagefrm.hxx:57
SwFrame * GetAnchorFrameContainingAnchPos()
determine anchor frame containing the anchor position
bool RestartLayoutProcess() const
SwFrame * FindColFrame()
Definition: findfrm.cxx:584
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:1170
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...
SwTextFrame * FindMaster() const
Definition: flowfrm.cxx:737
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:754
#define SAL_INFO(area, stream)
virtual ~SwObjectFormatterTextFrame() override
SwFrame * GetLower()
Definition: findfrm.cxx:194
const SwContentFrame * GetRef() const
Definition: ftnfrm.cxx:2906
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:1198
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:206
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)
void SetAgain(bool bAgain)
Definition: layact.cxx:316
SwObjectFormatterTextFrame(SwTextFrame &_rAnchorTextFrame, const SwPageFrame &_rPageFrame, SwTextFrame *_pMasterAnchorTextFrame, SwLayAction *_pLayAction)
SwRootFrame * getRootFrame()
Definition: frame.hxx:679
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:399
SwFrame * GetNext()
Definition: frame.hxx:676
static SwRowFrame const * FindTopLevelRowFrame(SwFrame const *const pFrame)
sal_uInt32 CountOfCollected()
accessor to total number of collected anchored objects