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  // see how SwObjectFormatter::FormatObjsAtFrame_() checks
238  // "pPageFrameOfAnchor == &mrPageFrame" - only caller relevant for
239  // this subclass
240  assert(GetPageFrame().GetPhyPageNum() == GetPgNumOfCollected(nIdx));
242  GetPageFrame(),
244  nToPageNum, bDummy,
245  bPageHasFlysAnchoredBelowThis))
246  {
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());
253  rDoc, mrAnchorTextFrame, nMovedFwdToPageNum ) )
254  {
255  if ( nMovedFwdToPageNum < nToPageNum )
256  {
257  if (!bPageHasFlysAnchoredBelowThis)
258  {
260  }
261  }
262  else
263  bInsert = false;
264  }
265  if ( bInsert )
266  {
267  // Indicate that anchor text frame has to move forward and
268  // invalidate its position to force a re-format.
269  if (!bPageHasFlysAnchoredBelowThis)
270  {
272  mrAnchorTextFrame, nToPageNum);
273  }
275 
276  // Indicate restart of the layout process
277  bSuccess = false;
278 
279  // If needed, invalidate previous objects anchored at same anchor
280  // text frame.
281  InvalidatePrevObjs( _rAnchoredObj );
282 
283  // Invalidate object and following objects for the restart of the
284  // layout process
285  InvalidateFollowObjs( _rAnchoredObj );
286  }
287  else
288  {
289  OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObj(..)> - anchor frame not marked to move forward" );
290  }
291  }
292  }
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() &&
298  {
302  }
303  }
304  }
305 
306  return bSuccess;
307 }
308 
310 {
312  {
313  if ( GetLayAction() &&
315  {
316  // notify layout action, thus is can restart the layout process on
317  // a previous page.
318  GetLayAction()->SetAgain(true);
319  }
320  else
321  {
322  // the anchor text frame has to be valid, thus assert.
323  OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObjs()> called for invalidate anchor text frame." );
324  }
325 
326  return false;
327  }
328 
329  bool bSuccess( true );
330 
331  if ( mrAnchorTextFrame.IsFollow() )
332  {
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" );
341 
342  if ( bSuccess )
343  {
344  // format of as-character anchored floating screen objects - no failure
345  // expected on the format of these objects.
346  bSuccess = FormatObjsAtFrame_();
347  }
348  }
349  else
350  {
351  bSuccess = FormatObjsAtFrame_();
352  }
353 
354  // consider anchored objects, whose wrapping style influence are temporarily
355  // considered.
356  if ( bSuccess &&
357  ( ConsiderWrapOnObjPos() ||
360  {
361  const bool bDoesAnchorHadPrev = ( mrAnchorTextFrame.GetIndPrev() != nullptr );
362 
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.
371 
372  sal_uInt32 nToPageNum( 0 );
373  // #i43913#
374  bool bInFollow( false );
375  bool bPageHasFlysAnchoredBelowThis(false);
376  SwAnchoredObject* pObj = nullptr;
377  if ( !mrAnchorTextFrame.IsFollow() )
378  {
380  // #i35017# - constant name has changed
381  text::WrapInfluenceOnPosition::ONCE_CONCURRENT,
382  nToPageNum, bInFollow, bPageHasFlysAnchoredBelowThis );
383  }
384  // #i35911#
385  if ( pObj && pObj->HasClearedEnvironment() )
386  {
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 )
395  {
396  bool bInsert( true );
397  sal_uInt32 nTmpToPageNum( 0 );
398  const SwDoc& rDoc = *(GetPageFrame().GetFormat()->GetDoc());
400  rDoc, mrAnchorTextFrame, nTmpToPageNum ) )
401  {
402  if ( nTmpToPageNum < pAnchorPageFrame->GetPhyPageNum() )
403  {
404  if (!bPageHasFlysAnchoredBelowThis)
405  {
407  }
408  }
409  else
410  bInsert = false;
411  }
412  if ( bInsert )
413  {
414  if (!bPageHasFlysAnchoredBelowThis)
415  {
417  pAnchorPageFrame->GetPhyPageNum());
418  }
420  bSuccess = false;
421  InvalidatePrevObjs( *pObj );
422  InvalidateFollowObjs( *pObj );
423  }
424  else
425  {
426  OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObjs(..)> - anchor frame not marked to move forward" );
427  }
428  }
429  }
430  else if ( pObj && bDoesAnchorHadPrev )
431  {
432  // Object found, whose anchor is moved forward
433 
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());
440  rDoc, mrAnchorTextFrame, nMovedFwdToPageNum ) )
441  {
442  if ( nMovedFwdToPageNum < nToPageNum )
444  else
445  bInsert = false;
446  }
447  if ( bInsert )
448  {
449  // Indicate that anchor text frame has to move forward and
450  // invalidate its position to force a re-format.
453 
454  // Indicate restart of the layout process
455  bSuccess = false;
456 
457  // If needed, invalidate previous objects anchored at same anchor
458  // text frame.
459  InvalidatePrevObjs( *pObj );
460 
461  // Invalidate object and following objects for the restart of the
462  // layout process
463  InvalidateFollowObjs( *pObj );
464  }
465  else
466  {
467  OSL_FAIL( "<SwObjectFormatterTextFrame::DoFormatObjs(..)> - anchor frame not marked to move forward" );
468  }
469  }
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() &&
475  {
479  }
480  }
481 
482  return bSuccess;
483 }
484 
486 {
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;
496 
497  const SwSortedObjs* pObjs = GetAnchorFrame().GetDrawObjs();
498  if ( !pObjs )
499  return;
500 
501  // determine start index
502  size_t i = pObjs->ListPosOf( _rAnchoredObj );
503  while (i > 0)
504  {
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 )
512  {
514  }
515  }
516 }
517 
519 {
521 
522  const SwSortedObjs* pObjs = GetPageFrame().GetSortedObjs();
523  if ( pObjs )
524  {
525  // determine start index
526  for ( size_t i = pObjs->ListPosOf( _rAnchoredObj ) + 1; i < pObjs->size(); ++i )
527  {
528  SwAnchoredObject* pAnchoredObj = (*pObjs)[i];
530  }
531  }
532 }
533 
535  const sal_Int16 _nWrapInfluenceOnPosition,
536  sal_uInt32& _noToPageNum,
537  bool& _boInFollow,
538  bool& o_rbPageHasFlysAnchoredBelowThis)
539 {
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>" );
544 
545  SwAnchoredObject* pRetAnchoredObj = nullptr;
546 
547  sal_uInt32 i = 0;
548  for ( ; i < CountOfCollected(); ++i )
549  {
550  SwAnchoredObject* pAnchoredObj = GetCollectedObj(i);
551  if ( pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() &&
552  pAnchoredObj->GetFrameFormat().GetWrapInfluenceOnObjPos().
553  // #i35017# - handle ITERATIVE as ONCE_SUCCESSIVE
554  GetWrapInfluenceOnObjPos( true ) == _nWrapInfluenceOnPosition )
555  {
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#
563  GetPageFrame(),
565  _noToPageNum, _boInFollow,
566  o_rbPageHasFlysAnchoredBelowThis) )
567  {
568  pRetAnchoredObj = pAnchoredObj;
569  break;
570  }
571  }
572  }
573 
574  return pRetAnchoredObj;
575 }
576 
577 static SwRowFrame const* FindTopLevelRowFrame(SwFrame const*const pFrame)
578 {
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())
582  {
583  pRow = pRow->GetUpper()->GetUpper()->FindRowFrame();
584  }
585  return pRow;
586 }
587 
588 static SwContentFrame const* FindFrameInBody(SwAnchoredObject const& rAnchored)
589 {
590  SwFrame const*const pAnchor(rAnchored.GetAnchorFrame());
591  assert(pAnchor);
592  if (pAnchor->IsPageFrame() || pAnchor->FindFooterOrHeader())
593  {
594  return nullptr;
595  }
596  if (pAnchor->IsInFly())
597  {
598  return FindFrameInBody(*pAnchor->FindFlyFrame());
599  }
600  if (pAnchor->IsInFootnote())
601  {
602  return pAnchor->FindFootnoteFrame()->GetRef();
603  }
604  assert(pAnchor->IsInDocBody());
605  assert(pAnchor->IsContentFrame());
606  return static_cast<SwContentFrame const*>(pAnchor);
607 }
608 
609 // #i58182#
610 // - replace private method by corresponding static public method
612  SwAnchoredObject& _rAnchoredObj,
613  SwPageFrame const& rFromPageFrame,
614  const bool _bAnchoredAtMasterBeforeFormatAnchor,
615  sal_uInt32& _noToPageNum,
616  bool& _boInFollow,
617  bool& o_rbPageHasFlysAnchoredBelowThis)
618 {
619  const sal_uInt32 _nFromPageNum(rFromPageFrame.GetPhyPageNum());
620  bool bAnchorIsMovedForward( false );
621 
622  SwPageFrame* pPageFrameOfAnchor = _rAnchoredObj.FindPageFrameOfAnchor();
623  if ( pPageFrameOfAnchor )
624  {
625  const sal_uInt32 nPageNum = pPageFrameOfAnchor->GetPhyPageNum();
626  if ( nPageNum > _nFromPageNum )
627  {
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) )
636  {
637  SwFrame* pAnchorFrame = _rAnchoredObj.GetAnchorFrameContainingAnchPos();
638  if ( pAnchorFrame->IsInTab() &&
639  pAnchorFrame->IsInFollowFlowRow() )
640  {
641  _noToPageNum = _nFromPageNum + 1;
642  }
643  }
644  bAnchorIsMovedForward = true;
645  }
646  }
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)))
656  {
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() )
663  {
664  bCheck = true;
665  }
666  else if( pAnchorTextFrame->IsInTab() )
667  {
668  const SwRowFrame* pMasterRow = pAnchorTextFrame->IsInFollowFlowRow();
669  if ( pMasterRow &&
670  pMasterRow->FindPageFrame() == pPageFrameOfAnchor )
671  {
672  bCheck = true;
673  }
674  }
675  if ( bCheck )
676  {
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() )
681  {
682  pColFrame = pColFrame->FindColFrame();
683  }
684  if ( !pColFrame || !pColFrame->GetNext() )
685  {
686  _noToPageNum = _nFromPageNum + 1;
687  bAnchorIsMovedForward = true;
688  // #i43913#
689  _boInFollow = true;
690  }
691  }
692  }
693 
694  if (bAnchorIsMovedForward)
695  {
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())
701  {
702  for (SwAnchoredObject *const pObj : *pObjs)
703  {
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)
711  {
712  if (pPageFrameOfAnchor->GetPhyPageNum() < pObjAnchorPage->GetPhyPageNum())
713  {
714  SAL_INFO("sw.layout", "SwObjectFormatterTextFrame::CheckMovedFwdCondition(): o_rbPageHasFlysAnchoredBelowThis because next page");
715  o_rbPageHasFlysAnchoredBelowThis = true;
716  break;
717  }
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)
724  {
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())
730  {
731  if (pInBodyFrameObj == pContentFrame)
732  {
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;
743  }
744  break;
745  }
746  }
747  if (isBreakMore)
748  {
749  break;
750  }
751  }
752  }
753  }
754  }
755  }
756 
757  return bAnchorIsMovedForward;
758 }
759 
760 static void CleanupEmptyFootnoteFrame(SwFrame* pLowerFrame)
761 {
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;
769 
770  for (SwFrame * pFootnote = pLowerFrame->GetLower(); pFootnote; )
771  {
772  assert(pFootnote->IsFootnoteFrame());
773  SwFrame *const pNextNote = pFootnote->GetNext();
774  if (!pFootnote->IsDeleteForbidden() && !pFootnote->GetLower() && !pFootnote->IsColLocked() &&
775  !static_cast<SwFootnoteFrame*>(pFootnote)->IsBackMoveLocked())
776  {
777  pFootnote->Cut();
778  SwFrame::DestroyFrame(pFootnote);
779  }
780  pFootnote = pNextNote;
781  }
782 }
783 
784 // #i40140# - helper method to format layout frames used by
785 // method <SwObjectFormatterTextFrame::FormatAnchorFrameForCheckMoveFwd()>
786 // #i44049# - format till a certain lower frame, if provided.
788  SwFrame* pLastLowerFrame = nullptr )
789 {
790  SwFrame* pLowerFrame = pLayFrame->GetLower();
791  while ( pLowerFrame )
792  {
793  // #i44049#
794  if ( pLastLowerFrame && pLowerFrame == pLastLowerFrame )
795  {
796  break;
797  }
798  if ( pLowerFrame->IsLayoutFrame() )
799  {
800  SwFrameDeleteGuard aCrudeHack(pLowerFrame); // ??? any issue setting this for non-footnote frames?
801  lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pLowerFrame),
802  pLastLowerFrame );
803  }
804  else
805  pLowerFrame->Calc(pLowerFrame->getRootFrame()->GetCurrShell()->GetOut());
806 
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;
815  }
816 }
817 
827 {
828  // #i47014# - no format of section and previous columns
829  // for follow text frames.
830  if ( !_rAnchorTextFrame.IsFollow() )
831  {
832  // if anchor frame is directly inside a section, format this section and
833  // its previous frames.
834  // Note: It's a very simple format without formatting objects.
835  if ( _rAnchorTextFrame.IsInSct() )
836  {
837  SwFrame* pSectFrame = _rAnchorTextFrame.GetUpper();
838  while ( pSectFrame )
839  {
840  if ( pSectFrame->IsSctFrame() || pSectFrame->IsCellFrame() )
841  {
842  break;
843  }
844  pSectFrame = pSectFrame->GetUpper();
845  }
846  if ( pSectFrame && pSectFrame->IsSctFrame() )
847  {
848  SwFrameDeleteGuard aDeleteGuard(&_rAnchorTextFrame);
849  // #i44049#
850  _rAnchorTextFrame.LockJoin();
851  SwFrame* pFrame = pSectFrame->GetUpper()->GetLower();
852  // #i49605# - section frame could move forward
853  // by the format of its previous frame.
854  // Thus, check for valid <pFrame>.
855  while ( pFrame && pFrame != pSectFrame )
856  {
857  if ( pFrame->IsLayoutFrame() )
858  lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pFrame) );
859  else
860  pFrame->Calc(pFrame->getRootFrame()->GetCurrShell()->GetOut());
861 
862  pFrame = pFrame->GetNext();
863  }
864  lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pSectFrame),
865  &_rAnchorTextFrame );
866  // #i44049#
867  _rAnchorTextFrame.UnlockJoin();
868  }
869  }
870 
871  // #i40140# - if anchor frame is inside a column,
872  // format the content of the previous columns.
873  // Note: It's a very simple format without formatting objects.
874  SwFrame* pColFrameOfAnchor = _rAnchorTextFrame.FindColFrame();
875  SAL_WARN_IF(pColFrameOfAnchor && _rAnchorTextFrame.IsInFootnote(), "sw.layout", "tdf#122894 skipping anchor in column in footnote");
876  if (pColFrameOfAnchor && !_rAnchorTextFrame.IsInFootnote())
877  {
878  // #i44049#
879  _rAnchorTextFrame.LockJoin();
880  SwFrameDeleteGuard aDeleteGuard(&_rAnchorTextFrame);
881  SwFrame* pColFrame = pColFrameOfAnchor->GetUpper()->GetLower();
882  while ( pColFrame != pColFrameOfAnchor )
883  {
884  SwFrame* pFrame = pColFrame->GetLower();
885  while ( pFrame )
886  {
887  if ( pFrame->IsLayoutFrame() )
888  lcl_FormatContentOfLayoutFrame( static_cast<SwLayoutFrame*>(pFrame) );
889  else
890  pFrame->Calc(pFrame->getRootFrame()->GetCurrShell()->GetOut());
891 
892  pFrame = pFrame->GetNext();
893  }
894 
895  pColFrame = pColFrame->GetNext();
896  }
897  // #i44049#
898  _rAnchorTextFrame.UnlockJoin();
899  }
900  }
901 
902  // format anchor frame - format of its follow not needed
903  // #i43255# - forbid follow format, only if anchor text
904  // frame is in table
905  if ( _rAnchorTextFrame.IsInTab() )
906  {
907  SwForbidFollowFormat aForbidFollowFormat( _rAnchorTextFrame );
908  _rAnchorTextFrame.Calc(_rAnchorTextFrame.getRootFrame()->GetCurrShell()->GetOut());
909  }
910  else
911  {
912  _rAnchorTextFrame.Calc(_rAnchorTextFrame.getRootFrame()->GetCurrShell()->GetOut());
913  }
914 }
915 
921 {
923 }
924 
929 {
930  bool bRet( false );
931 
932  const SwSortedObjs* pObjs = GetAnchorFrame().GetDrawObjs();
933  if ( pObjs && pObjs->size() > 1 )
934  {
935  for (SwAnchoredObject* pAnchoredObj : *pObjs)
936  {
937  if ( pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() )
938  {
939  bRet = true;
940  break;
941  }
942  }
943  }
944 
945  return bRet;
946 }
947 
948 /* 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:315
Represents the visualization of a paragraph.
Definition: txtfrm.hxx:158
const SwPageFrame & GetPageFrame() const
void AllowFollowFormat()
Definition: txtfrm.hxx:748
bool IsFollow() const
Definition: flowfrm.hxx:166
const SwSortedObjs * GetDrawObjs() const
Definition: frame.hxx:565
void SetClearedEnvironment(const bool _bClearedEnvironment)
bool IsInFly() const
Definition: frame.hxx:962
bool IsInSct() const
Definition: frame.hxx:968
virtual SwFrame & GetAnchorFrame() override
bool IsInFootnote() const
Definition: frame.hxx:950
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()
Definition: doc.hxx:188
void InvalidatePos()
Definition: frame.hxx:1044
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:1227
bool isFrameAreaDefinitionValid() const
Definition: frame.hxx:172
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:956
bool IsTextFrame() const
Definition: frame.hxx:1235
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:1215
SwAnchoredObject * GetCollectedObj(const sal_uInt32 _nIndex)
accessor to collected anchored object
SwTextFrame * GetFollow()
Definition: txtfrm.hxx:855
TextFrameIndex GetOffset() const
Definition: txtfrm.hxx:438
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
SwFootnoteFrame * FindFootnoteFrame()
Definition: frame.hxx:1108
const SwFormatFollowTextFlow & GetFollowTextFlow(bool=true) const
SwFrame * GetIndPrev() const
Definition: frame.hxx:725
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: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:681
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:679
static SwContentFrame const * FindFrameInBody(SwAnchoredObject const &rAnchored)
void LockJoin()
Definition: flowfrm.hxx:139
const SwRowFrame * IsInFollowFlowRow() const
Definition: findfrm.cxx:1788
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:57
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:1171
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...
#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:753
#define SAL_INFO(area, stream)
virtual ~SwObjectFormatterTextFrame() override
SwFrame * GetLower()
Definition: findfrm.cxx:170
const SwContentFrame * GetRef() const
Definition: ftnfrm.cxx:2891
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:1199
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:207
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:313
SwObjectFormatterTextFrame(SwTextFrame &_rAnchorTextFrame, const SwPageFrame &_rPageFrame, SwTextFrame *_pMasterAnchorTextFrame, SwLayAction *_pLayAction)
SwRootFrame * getRootFrame()
Definition: frame.hxx:680
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:677
static SwRowFrame const * FindTopLevelRowFrame(SwFrame const *const pFrame)
sal_uInt32 CountOfCollected()
accessor to total number of collected anchored objects