LibreOffice Module sw (master)  1
tabfrm.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 
20 #include <pagefrm.hxx>
21 #include <rootfrm.hxx>
23 #include <viewimp.hxx>
24 #include <fesh.hxx>
25 #include <swtable.hxx>
26 #include <dflyobj.hxx>
27 #include <anchoreddrawobject.hxx>
28 #include <fmtanchr.hxx>
29 #include <viewopt.hxx>
30 #include <hints.hxx>
31 #include <dbg_lay.hxx>
32 #include <ftnidx.hxx>
33 #include <svl/itemiter.hxx>
34 #include <editeng/keepitem.hxx>
35 #include <editeng/ulspitem.hxx>
36 #include <editeng/brushitem.hxx>
37 #include <editeng/boxitem.hxx>
39 #include <fmtlsplt.hxx>
40 #include <fmtrowsplt.hxx>
41 #include <fmtsrnd.hxx>
42 #include <fmtornt.hxx>
43 #include <fmtpdsc.hxx>
44 #include <fmtfsize.hxx>
45 #include <swtblfmt.hxx>
46 #include <tabfrm.hxx>
47 #include <rowfrm.hxx>
48 #include <cellfrm.hxx>
49 #include <flyfrms.hxx>
50 #include <txtfrm.hxx>
51 #include <ftnfrm.hxx>
52 #include <notxtfrm.hxx>
53 #include <htmltbl.hxx>
54 #include <sectfrm.hxx>
55 #include <fmtfollowtextflow.hxx>
56 #include <sortedobjs.hxx>
57 #include <objectformatter.hxx>
58 #include <layouter.hxx>
59 #include <calbck.hxx>
61 #include <sal/log.hxx>
62 #include <osl/diagnose.h>
63 #include <frmatr.hxx>
64 #include <frmtool.hxx>
65 #include <ndtxt.hxx>
66 #include <frameformats.hxx>
67 
68 using namespace ::com::sun::star;
69 
71  : SwLayoutFrame( rTab.GetFrameFormat(), pSib )
72  , SwFlowFrame( static_cast<SwFrame&>(*this) )
73  , m_pTable( &rTab )
74  , m_bComplete(false)
75  , m_bCalcLowers(false)
76  , m_bLowersFormatted(false)
77  , m_bLockBackMove(false)
78  , m_bResizeHTMLTable(false)
79  , m_bONECalcLowers(false)
80  , m_bHasFollowFlowLine(false)
81  , m_bIsRebuildLastLine(false)
82  , m_bRestrictTableGrowth(false)
83  , m_bRemoveFollowFlowLinePending(false)
84  , m_bConsiderObjsForMinCellHeight(true)
85  , m_bObjsDoesFit(true)
86  , m_bInRecalcLowerRow(false)
87  , m_bSplitRowDisabled(false)
88 {
89  mbFixSize = false; //Don't fall for import filter again.
91 
92  //Create the lines and insert them.
93  const SwTableLines &rLines = rTab.GetTabLines();
94  SwFrame *pTmpPrev = nullptr;
95  for ( size_t i = 0; i < rLines.size(); ++i )
96  {
97  SwRowFrame *pNew = new SwRowFrame( *rLines[i], this );
98  if( pNew->Lower() )
99  {
100  pNew->InsertBehind( this, pTmpPrev );
101  pTmpPrev = pNew;
102  }
103  else
104  SwFrame::DestroyFrame(pNew);
105  }
106  OSL_ENSURE( Lower() && Lower()->IsRowFrame(), "SwTabFrame::SwTabFrame: No rows." );
107 }
108 
110  : SwLayoutFrame( rTab.GetFormat(), &rTab )
111  , SwFlowFrame( static_cast<SwFrame&>(*this) )
112  , m_pTable( rTab.GetTable() )
113  , m_bComplete(false)
114  , m_bCalcLowers(false)
115  , m_bLowersFormatted(false)
116  , m_bLockBackMove(false)
117  , m_bResizeHTMLTable(false)
118  , m_bONECalcLowers(false)
119  , m_bHasFollowFlowLine(false)
120  , m_bIsRebuildLastLine(false)
121  , m_bRestrictTableGrowth(false)
122  , m_bRemoveFollowFlowLinePending(false)
123  , m_bConsiderObjsForMinCellHeight(true)
124  , m_bObjsDoesFit(true)
125  , m_bInRecalcLowerRow(false)
126  , m_bSplitRowDisabled(false)
127 {
128  mbFixSize = false; //Don't fall for import filter again.
130 
131  SetFollow( rTab.GetFollow() );
132  rTab.SetFollow( this );
133 }
134 
136 {
137  // There is some terrible code in fetab.cxx, that
138  // caches pointers to SwTabFrames.
139  ::ClearFEShellTabCols(*GetFormat()->GetDoc(), this);
140 
142 }
143 
145 {
146 }
147 
149 {
150  SwTabFrame *pFoll = GetFollow();
151  if ( pFoll->HasFollow() )
152  pFoll->JoinAndDelFollows();
153  pFoll->Cut();
154  SetFollow( pFoll->GetFollow() );
155  SwFrame::DestroyFrame(pFoll);
156 }
157 
159 {
160  OSL_ENSURE( Lower() && Lower()->IsRowFrame(), "No rows." );
161 
162  SwPageFrame *pPage = FindPageFrame();
163  if ( pPage )
164  {
165  SwRowFrame *pRow = static_cast<SwRowFrame*>(Lower());
166  do
167  {
168  pRow->RegistFlys( pPage );
169  pRow = static_cast<SwRowFrame*>(pRow->GetNext());
170  } while ( pRow );
171  }
172 }
173 
174 static void SwInvalidateAll( SwFrame *pFrame, tools::Long nBottom );
175 static void lcl_RecalcRow( SwRowFrame& rRow, tools::Long nBottom );
176 static bool lcl_ArrangeLowers( SwLayoutFrame *pLay, tools::Long lYStart, bool bInva );
177 // #i26945# - add parameter <_bOnlyRowsAndCells> to control
178 // that only row and cell frames are formatted.
179 static bool lcl_InnerCalcLayout( SwFrame *pFrame,
180  tools::Long nBottom,
181  bool _bOnlyRowsAndCells = false );
182 // OD 2004-02-18 #106629# - correct type of 1st parameter
183 // #i26945# - add parameter <_bConsiderObjs> in order to
184 // control, if floating screen objects have to be considered for the minimal
185 // cell height.
186 static SwTwips lcl_CalcMinRowHeight( const SwRowFrame *pRow,
187  const bool _bConsiderObjs );
189 
191 
192 static SwTwips lcl_GetHeightOfRows( const SwFrame* pStart, tools::Long nCount )
193 {
194  if ( !nCount || !pStart)
195  return 0;
196 
197  SwTwips nRet = 0;
198  SwRectFnSet aRectFnSet(pStart);
199  while ( pStart && nCount > 0 )
200  {
201  nRet += aRectFnSet.GetHeight(pStart->getFrameArea());
202  pStart = pStart->GetNext();
203  --nCount;
204  }
205 
206  return nRet;
207 }
208 
209 // Local helper function to insert a new follow flow line
210 static SwRowFrame* lcl_InsertNewFollowFlowLine( SwTabFrame& rTab, const SwFrame& rTmpRow, bool bRowSpanLine )
211 {
212  OSL_ENSURE( rTmpRow.IsRowFrame(), "No row frame to copy for FollowFlowLine" );
213  const SwRowFrame& rRow = static_cast<const SwRowFrame&>(rTmpRow);
214 
215  rTab.SetFollowFlowLine( true );
216  SwRowFrame *pFollowFlowLine = new SwRowFrame(*rRow.GetTabLine(), &rTab, false );
217  pFollowFlowLine->SetRowSpanLine( bRowSpanLine );
218  SwFrame* pFirstRow = rTab.GetFollow()->GetFirstNonHeadlineRow();
219  pFollowFlowLine->InsertBefore( rTab.GetFollow(), pFirstRow );
220  return pFollowFlowLine;
221 }
222 
223 // #i26945# - local helper function to invalidate all lower
224 // objects. By parameter <_bMoveObjsOutOfRange> it can be controlled, if
225 // additionally the objects are moved 'out of range'.
226 static void lcl_InvalidateLowerObjs( SwLayoutFrame& _rLayoutFrame,
227  const bool _bMoveObjsOutOfRange = false,
228  SwPageFrame* _pPageFrame = nullptr )
229 {
230  // determine page frame, if needed
231  if ( !_pPageFrame )
232  {
233  _pPageFrame = _rLayoutFrame.FindPageFrame();
234  OSL_ENSURE( _pPageFrame,
235  "<lcl_InvalidateLowerObjs(..)> - missing page frame -> no move of lower objects out of range" );
236  if ( !_pPageFrame )
237  {
238  return;
239  }
240  }
241 
242  // loop on lower frames
243  SwFrame* pLowerFrame = _rLayoutFrame.Lower();
244  while ( pLowerFrame )
245  {
246  if ( pLowerFrame->IsLayoutFrame() )
247  {
248  ::lcl_InvalidateLowerObjs( *static_cast<SwLayoutFrame*>(pLowerFrame),
249  _bMoveObjsOutOfRange, _pPageFrame );
250  }
251  if ( pLowerFrame->GetDrawObjs() )
252  {
253  for (size_t i = 0, nCount = pLowerFrame->GetDrawObjs()->size(); i < nCount; ++i)
254  {
255  SwAnchoredObject* pAnchoredObj = (*pLowerFrame->GetDrawObjs())[i];
256 
257  // invalidate position of anchored object
258  pAnchoredObj->SetTmpConsiderWrapInfluence( false );
259  pAnchoredObj->SetConsiderForTextWrap( false );
260  pAnchoredObj->UnlockPosition();
261  pAnchoredObj->InvalidateObjPos();
262 
263  SwFlyFrame *pFly = dynamic_cast<SwFlyFrame*>(pAnchoredObj);
264 
265  // move anchored object 'out of range'
266  if ( _bMoveObjsOutOfRange )
267  {
268  // indicate, that positioning is progress to avoid
269  // modification of the anchored object resp. it's attributes
270  // due to the movement
271  SwObjPositioningInProgress aObjPosInProgress( *pAnchoredObj );
272  pAnchoredObj->SetObjLeft( _pPageFrame->getFrameArea().Right() );
273  // #115759# - reset character rectangle,
274  // top of line and relative position in order to assure,
275  // that anchored object is correctly positioned.
276  pAnchoredObj->ClearCharRectAndTopOfLine();
277  pAnchoredObj->SetCurrRelPos( Point( 0, 0 ) );
278  if ( pAnchoredObj->GetFrameFormat().GetAnchor().GetAnchorId()
279  == RndStdIds::FLY_AS_CHAR )
280  {
281  pAnchoredObj->AnchorFrame()
283  &(pAnchoredObj->GetFrameFormat()) );
284  }
285  if ( pFly != nullptr )
286  {
287  pFly->GetVirtDrawObj()->SetRectsDirty();
288  pFly->GetVirtDrawObj()->SetChanged();
289  }
290  }
291 
292  // If anchored object is a fly frame, invalidate its lower objects
293  if ( pFly != nullptr )
294  {
295  ::lcl_InvalidateLowerObjs( *pFly, _bMoveObjsOutOfRange, _pPageFrame );
296  }
297  }
298  }
299  pLowerFrame = pLowerFrame->GetNext();
300  }
301 }
302 
303 // Local helper function to shrink all lowers of pRow to 0 height
305 {
306  SwCellFrame* pCurrMasterCell = static_cast<SwCellFrame*>(rRow.Lower());
307  SwRectFnSet aRectFnSet(pCurrMasterCell);
308 
309  bool bAllCellsCollapsed = true;
310  while ( pCurrMasterCell )
311  {
312  // NEW TABLES
313  SwCellFrame& rToAdjust = pCurrMasterCell->GetTabBox()->getRowSpan() < 1 ?
314  const_cast<SwCellFrame&>(pCurrMasterCell->FindStartEndOfRowSpanCell( true )) :
315  *pCurrMasterCell;
316 
317  // #i26945#
318  // all lowers should have the correct position
319  lcl_ArrangeLowers( &rToAdjust,
320  aRectFnSet.GetPrtTop(rToAdjust),
321  false );
322  // TODO: Optimize number of frames which are set to 0 height
323  // we have to start with the last lower frame, otherwise
324  // the shrink will not shrink the current cell
325  SwFrame* pTmp = rToAdjust.GetLastLower();
326  bool bAllLowersCollapsed = true;
327 
328  if ( pTmp && pTmp->IsRowFrame() )
329  {
330  SwRowFrame* pTmpRow = static_cast<SwRowFrame*>(pTmp);
331  lcl_ShrinkCellsAndAllContent( *pTmpRow );
332  }
333  else
334  {
335  // TODO: Optimize number of frames which are set to 0 height
336  while ( pTmp )
337  {
338  // the frames have to be shrunk
339  if ( pTmp->IsTabFrame() )
340  {
341  SwRowFrame* pTmpRow = static_cast<SwRowFrame*>(static_cast<SwTabFrame*>(pTmp)->Lower());
342  bool bAllRowsCollapsed = true;
343 
344  while ( pTmpRow )
345  {
346  lcl_ShrinkCellsAndAllContent( *pTmpRow );
347 
348  if (aRectFnSet.GetHeight(pTmpRow->getFrameArea()) > 0)
349  bAllRowsCollapsed = false;
350 
351  pTmpRow = static_cast<SwRowFrame*>(pTmpRow->GetNext());
352  }
353 
354  if (bAllRowsCollapsed)
355  {
356  // All rows of this table have 0 height -> set height of the table itself as well.
358  aRectFnSet.SetHeight(aFrm, 0);
359 
361  aRectFnSet.SetTop(aPrt, 0);
362  aRectFnSet.SetHeight(aPrt, 0);
363  }
364  else
365  bAllLowersCollapsed = false;
366  }
367  else
368  {
369  pTmp->Shrink(aRectFnSet.GetHeight(pTmp->getFrameArea()));
371  aRectFnSet.SetTop(aPrt, 0);
372  aRectFnSet.SetHeight(aPrt, 0);
373 
374  if (aRectFnSet.GetHeight(pTmp->getFrameArea()) > 0)
375  {
376  bAllLowersCollapsed = false;
377  }
378  }
379 
380  pTmp = pTmp->GetPrev();
381  }
382 
383  // all lowers should have the correct position
384  lcl_ArrangeLowers( &rToAdjust,
385  aRectFnSet.GetPrtTop(rToAdjust),
386  false );
387  }
388 
389  if (bAllLowersCollapsed)
390  {
391  // All lower frame of this cell have 0 height -> set height of the cell itself as well.
392  SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pCurrMasterCell);
393  aRectFnSet.SetHeight(aFrm, 0);
394 
396  aRectFnSet.SetTop(aPrt, 0);
397  aRectFnSet.SetHeight(aPrt, 0);
398  }
399  else
400  bAllCellsCollapsed = false;
401 
402  pCurrMasterCell = static_cast<SwCellFrame*>(pCurrMasterCell->GetNext());
403  }
404 
405  if (bAllCellsCollapsed)
406  {
407  // All cells have 0 height -> set height of row as well.
409  aRectFnSet.SetHeight(aFrm, 0);
410 
412  aRectFnSet.SetTop(aPrt, 0);
413  aRectFnSet.SetHeight(aPrt, 0);
414  }
415 }
416 
417 // Local helper function to move the content from rSourceLine to rDestLine
418 // The content is inserted behind the last content in the corresponding
419 // cell in rDestLine.
420 static void lcl_MoveRowContent( SwRowFrame& rSourceLine, SwRowFrame& rDestLine )
421 {
422  SwCellFrame* pCurrDestCell = static_cast<SwCellFrame*>(rDestLine.Lower());
423  SwCellFrame* pCurrSourceCell = static_cast<SwCellFrame*>(rSourceLine.Lower());
424 
425  // Move content of follow cells into master cells
426  while ( pCurrSourceCell )
427  {
428  if ( pCurrSourceCell->Lower() && pCurrSourceCell->Lower()->IsRowFrame() )
429  {
430  SwRowFrame* pTmpSourceRow = static_cast<SwRowFrame*>(pCurrSourceCell->Lower());
431  while ( pTmpSourceRow )
432  {
433  // #125926# Attention! It is possible,
434  // that pTmpSourceRow->IsFollowFlowRow() but pTmpDestRow
435  // cannot be found. In this case, we have to move the complete
436  // row.
437  SwRowFrame* pTmpDestRow = static_cast<SwRowFrame*>(pCurrDestCell->Lower());
438 
439  if ( pTmpSourceRow->IsFollowFlowRow() && pTmpDestRow )
440  {
441  // move content from follow flow row to pTmpDestRow:
442  while ( pTmpDestRow->GetNext() )
443  pTmpDestRow = static_cast<SwRowFrame*>(pTmpDestRow->GetNext());
444 
445  assert(pTmpDestRow->GetFollowRow() == pTmpSourceRow);
446 
447  lcl_MoveRowContent( *pTmpSourceRow, *pTmpDestRow );
448  pTmpDestRow->SetFollowRow( pTmpSourceRow->GetFollowRow() );
449  pTmpSourceRow->RemoveFromLayout();
450  SwFrame::DestroyFrame(pTmpSourceRow);
451  }
452  else
453  {
454  // move complete row:
455  pTmpSourceRow->RemoveFromLayout();
456  pTmpSourceRow->InsertBefore( pCurrDestCell, nullptr );
457  }
458 
459  pTmpSourceRow = static_cast<SwRowFrame*>(pCurrSourceCell->Lower());
460  }
461  }
462  else
463  {
464  SwFrame *pTmp = ::SaveContent( pCurrSourceCell );
465  if ( pTmp )
466  {
467  // NEW TABLES
468  SwCellFrame* pDestCell = pCurrDestCell;
469  if ( pDestCell->GetTabBox()->getRowSpan() < 1 )
470  pDestCell = & const_cast<SwCellFrame&>(pDestCell->FindStartEndOfRowSpanCell( true ));
471 
472  // Find last content
473  SwFrame* pFrame = pDestCell->GetLastLower();
474  ::RestoreContent( pTmp, pDestCell, pFrame );
475  }
476  }
477  pCurrDestCell = static_cast<SwCellFrame*>(pCurrDestCell->GetNext());
478  pCurrSourceCell = static_cast<SwCellFrame*>(pCurrSourceCell->GetNext());
479  }
480 }
481 
482 // Local helper function to move all footnotes in rRowFrame from
483 // the footnote boss of rSource to the footnote boss of rDest.
484 static void lcl_MoveFootnotes( SwTabFrame& rSource, SwTabFrame& rDest, SwLayoutFrame& rRowFrame )
485 {
486  if ( !rSource.GetFormat()->GetDoc()->GetFootnoteIdxs().empty() )
487  {
488  SwFootnoteBossFrame* pOldBoss = rSource.FindFootnoteBossFrame( true );
489  SwFootnoteBossFrame* pNewBoss = rDest.FindFootnoteBossFrame( true );
490  rRowFrame.MoveLowerFootnotes( nullptr, pOldBoss, pNewBoss, true );
491  }
492 }
493 
494 // Local helper function to handle nested table cells before the split process
495 static void lcl_PreprocessRowsInCells( SwTabFrame& rTab, SwRowFrame& rLastLine,
496  SwRowFrame& rFollowFlowLine, SwTwips nRemain )
497 {
498  SwCellFrame* pCurrLastLineCell = static_cast<SwCellFrame*>(rLastLine.Lower());
499  SwCellFrame* pCurrFollowFlowLineCell = static_cast<SwCellFrame*>(rFollowFlowLine.Lower());
500 
501  SwRectFnSet aRectFnSet(pCurrLastLineCell);
502 
503  // Move content of follow cells into master cells
504  while ( pCurrLastLineCell )
505  {
506  if ( pCurrLastLineCell->Lower() && pCurrLastLineCell->Lower()->IsRowFrame() )
507  {
508  SwTwips nTmpCut = nRemain;
509  SwRowFrame* pTmpLastLineRow = static_cast<SwRowFrame*>(pCurrLastLineCell->Lower());
510 
511  // #i26945#
512  SwTwips nCurrentHeight =
513  lcl_CalcMinRowHeight( pTmpLastLineRow,
515  while ( pTmpLastLineRow->GetNext() && nTmpCut > nCurrentHeight )
516  {
517  nTmpCut -= nCurrentHeight;
518  pTmpLastLineRow = static_cast<SwRowFrame*>(pTmpLastLineRow->GetNext());
519  // #i26945#
520  nCurrentHeight =
521  lcl_CalcMinRowHeight( pTmpLastLineRow,
523  }
524 
525  // pTmpLastLineRow does not fit to the line or it is the last line
526  // Check if we can move pTmpLastLineRow to the follow table,
527  // or if we have to split the line:
528  bool bTableLayoutTooComplex = false;
529  tools::Long nMinHeight = 0;
530 
531  // We have to take into account:
532  // 1. The fixed height of the row
533  // 2. The borders of the cells inside the row
534  // 3. The minimum height of the row
535  if ( pTmpLastLineRow->HasFixSize() )
536  nMinHeight = aRectFnSet.GetHeight(pTmpLastLineRow->getFrameArea());
537  else
538  {
539  {
540  const SwFormatFrameSize &rSz = pTmpLastLineRow->GetFormat()->GetFrameSize();
542  nMinHeight = rSz.GetHeight() - lcl_calcHeightOfRowBeforeThisFrame(*pTmpLastLineRow);
543  }
544 
545  SwFrame* pCell = pTmpLastLineRow->Lower();
546  while ( pCell )
547  {
548  if ( static_cast<SwCellFrame*>(pCell)->Lower() &&
549  static_cast<SwCellFrame*>(pCell)->Lower()->IsRowFrame() )
550  {
551  bTableLayoutTooComplex = true;
552  break;
553  }
554 
555  SwBorderAttrAccess aAccess( SwFrame::GetCache(), pCell );
556  const SwBorderAttrs &rAttrs = *aAccess.Get();
557  nMinHeight = std::max( nMinHeight, tools::Long(lcl_CalcTopAndBottomMargin( *static_cast<SwLayoutFrame*>(pCell), rAttrs )) );
558  pCell = pCell->GetNext();
559  }
560  }
561 
562  // 1. Case:
563  // The line completely fits into the master table.
564  // Nevertheless, we build a follow (otherwise painting problems
565  // with empty cell).
566 
567  // 2. Case:
568  // The line has to be split, the minimum height still fits into
569  // the master table, and the table structure is not too complex.
570  if ( nTmpCut > nCurrentHeight ||
571  ( pTmpLastLineRow->IsRowSplitAllowed() &&
572  !bTableLayoutTooComplex && nMinHeight < nTmpCut ) )
573  {
574  // The line has to be split:
575  SwRowFrame* pNewRow = new SwRowFrame( *pTmpLastLineRow->GetTabLine(), &rTab, false );
576  pNewRow->SetFollowFlowRow( true );
577  pNewRow->SetFollowRow( pTmpLastLineRow->GetFollowRow() );
578  pTmpLastLineRow->SetFollowRow( pNewRow );
579  pNewRow->InsertBehind( pCurrFollowFlowLineCell, nullptr );
580  pTmpLastLineRow = static_cast<SwRowFrame*>(pTmpLastLineRow->GetNext());
581  }
582 
583  // The following lines have to be moved:
584  while ( pTmpLastLineRow )
585  {
586  SwRowFrame* pTmp = static_cast<SwRowFrame*>(pTmpLastLineRow->GetNext());
587  lcl_MoveFootnotes( rTab, *rTab.GetFollow(), *pTmpLastLineRow );
588  pTmpLastLineRow->RemoveFromLayout();
589  pTmpLastLineRow->InsertBefore( pCurrFollowFlowLineCell, nullptr );
590  pTmpLastLineRow->Shrink( aRectFnSet.GetHeight(pTmpLastLineRow->getFrameArea()) );
591  pCurrFollowFlowLineCell->Grow( aRectFnSet.GetHeight(pTmpLastLineRow->getFrameArea()) );
592  pTmpLastLineRow = pTmp;
593  }
594  }
595 
596  pCurrLastLineCell = static_cast<SwCellFrame*>(pCurrLastLineCell->GetNext());
597  pCurrFollowFlowLineCell = static_cast<SwCellFrame*>(pCurrFollowFlowLineCell->GetNext());
598  }
599 }
600 
601 // Local helper function to handle nested table cells after the split process
602 static void lcl_PostprocessRowsInCells( SwTabFrame& rTab, SwRowFrame& rLastLine )
603 {
604  SwCellFrame* pCurrMasterCell = static_cast<SwCellFrame*>(rLastLine.Lower());
605  while ( pCurrMasterCell )
606  {
607  if ( pCurrMasterCell->Lower() &&
608  pCurrMasterCell->Lower()->IsRowFrame() )
609  {
610  SwRowFrame* pRowFrame = static_cast<SwRowFrame*>(pCurrMasterCell->GetLastLower());
611 
612  if ( nullptr != pRowFrame->GetPrev() && !pRowFrame->ContainsContent() )
613  {
614  OSL_ENSURE( pRowFrame->GetFollowRow(), "Deleting row frame without follow" );
615 
616  // The footnotes have to be moved:
617  lcl_MoveFootnotes( rTab, *rTab.GetFollow(), *pRowFrame );
618  pRowFrame->Cut();
619  SwRowFrame* pFollowRow = pRowFrame->GetFollowRow();
620  pRowFrame->Paste( pFollowRow->GetUpper(), pFollowRow );
621  pRowFrame->SetFollowRow( pFollowRow->GetFollowRow() );
622  lcl_MoveRowContent( *pFollowRow, *pRowFrame );
623  pFollowRow->Cut();
624  SwFrame::DestroyFrame(pFollowRow);
625  ::SwInvalidateAll( pCurrMasterCell, LONG_MAX );
626  }
627  }
628 
629  pCurrMasterCell = static_cast<SwCellFrame*>(pCurrMasterCell->GetNext());
630  }
631 }
632 
633 // Local helper function to re-calculate the split line.
634 inline void TableSplitRecalcLock( SwFlowFrame *pTab ) { pTab->LockJoin(); }
635 inline void TableSplitRecalcUnlock( SwFlowFrame *pTab ) { pTab->UnlockJoin(); }
636 
637 static bool lcl_RecalcSplitLine( SwRowFrame& rLastLine, SwRowFrame& rFollowLine,
638  SwTwips nRemainingSpaceForLastRow, SwTwips nAlreadyFree )
639 {
640  bool bRet = true;
641 
642  vcl::RenderContext* pRenderContext = rLastLine.getRootFrame()->GetCurrShell()->GetOut();
643  SwTabFrame& rTab = static_cast<SwTabFrame&>(*rLastLine.GetUpper());
644  SwRectFnSet aRectFnSet(rTab.GetUpper());
645  SwTwips nCurLastLineHeight = aRectFnSet.GetHeight(rLastLine.getFrameArea());
646 
647  // If there are nested cells in rLastLine, the recalculation of the last
648  // line needs some preprocessing.
649  lcl_PreprocessRowsInCells( rTab, rLastLine, rFollowLine, nRemainingSpaceForLastRow );
650 
651  // Here the recalculation process starts:
652  rTab.SetRebuildLastLine( true );
653  // #i26945#
654  rTab.SetDoesObjsFit( true );
655 
656  // #i26945# - invalidate and move floating screen
657  // objects 'out of range'
658  ::lcl_InvalidateLowerObjs( rLastLine, true );
659 
660  // manipulate row and cell sizes
661 
662  // #i26945# - Do *not* consider floating screen objects
663  // for the minimal cell height.
664  rTab.SetConsiderObjsForMinCellHeight( false );
665  ::lcl_ShrinkCellsAndAllContent( rLastLine );
666  rTab.SetConsiderObjsForMinCellHeight( true );
667 
668  // invalidate last line
669  ::SwInvalidateAll( &rLastLine, LONG_MAX );
670 
671  // Shrink the table to account for the shrunk last row, as well as lower rows
672  // that had been moved to follow table in SwTabFrame::Split.
673  // It will grow later when last line will recalc its height.
674  rTab.Shrink(nAlreadyFree + nCurLastLineHeight - nRemainingSpaceForLastRow + 1);
675 
676  // Lock this tab frame and its follow
677  bool bUnlockMaster = false;
678  SwFlowFrame * pFollow = nullptr;
679  SwTabFrame* pMaster = rTab.IsFollow() ? rTab.FindMaster() : nullptr;
680  if ( pMaster && !pMaster->IsJoinLocked() )
681  {
682  bUnlockMaster = true;
683  ::TableSplitRecalcLock( pMaster );
684  }
685  if ( !rTab.GetFollow()->IsJoinLocked() )
686  {
687  pFollow = rTab.GetFollow();
688  ::TableSplitRecalcLock( pFollow );
689  }
690 
691  bool bInSplit = rLastLine.IsInSplit();
692  rLastLine.SetInSplit();
693 
694  // Do the recalculation
695  lcl_RecalcRow( rLastLine, LONG_MAX );
696  // #115759# - force a format of the last line in order to
697  // get the correct height.
698  rLastLine.InvalidateSize();
699  rLastLine.Calc(pRenderContext);
700 
701  rLastLine.SetInSplit(bInSplit);
702 
703  // Unlock this tab frame and its follow
704  if ( pFollow )
705  ::TableSplitRecalcUnlock( pFollow );
706  if ( bUnlockMaster )
707  ::TableSplitRecalcUnlock( pMaster );
708 
709  // If there are nested cells in rLastLine, the recalculation of the last
710  // line needs some postprocessing.
711  lcl_PostprocessRowsInCells( rTab, rLastLine );
712 
713  // Do a couple of checks on the current situation.
714 
715  // If we are not happy with the current situation we return false.
716  // This will start a new try to split the table, this time we do not
717  // try to split the table rows.
718 
719  // 1. Check if table fits to its upper.
720  // #i26945# - include check, if objects fit
721  const SwTwips nDistanceToUpperPrtBottom =
722  aRectFnSet.BottomDist(rTab.getFrameArea(), aRectFnSet.GetPrtBottom(*rTab.GetUpper()));
723  // tdf#125685 ignore footnotes that are anchored in follow-table of this
724  // table - if split is successful they move to the next page/column anyway
725  assert(rTab.GetFollow() == rFollowLine.GetUpper());
726  SwTwips nFollowFootnotes(0);
727  // actually there should always be a boss frame, except if "this" isn't
728  // connected to a page yet; not sure if that can happen
729  if (SwFootnoteBossFrame const*const pBoss = rTab.FindFootnoteBossFrame())
730  {
731  if (SwFootnoteContFrame const*const pCont = pBoss->FindFootnoteCont())
732  {
733  for (SwFootnoteFrame const* pFootnote = static_cast<SwFootnoteFrame const*>(pCont->Lower());
734  pFootnote != nullptr;
735  pFootnote = static_cast<SwFootnoteFrame const*>(pFootnote->GetNext()))
736  {
737  SwContentFrame const*const pAnchor = pFootnote->GetRef();
738  SwTabFrame const* pTab = pAnchor->FindTabFrame();
739  if (pTab)
740  {
741  while (pTab->GetUpper()->IsInTab())
742  {
743  pTab = pTab->GetUpper()->FindTabFrame();
744  }
745  // TODO currently do this only for top-level tables?
746  // otherwise would need to check rTab's follow and any upper table's follow?
747  if (pTab == rTab.GetFollow())
748  {
749  nFollowFootnotes += aRectFnSet.GetHeight(pFootnote->getFrameArea());
750  }
751  }
752  }
753  }
754  }
755  if (nDistanceToUpperPrtBottom + nFollowFootnotes < 0 || !rTab.DoesObjsFit())
756  bRet = false;
757 
758  // 2. Check if each cell in the last line has at least one content frame.
759 
760  // Note: a FollowFlowRow may contains empty cells!
761  if ( bRet )
762  {
763  if ( !rLastLine.IsInFollowFlowRow() )
764  {
765  SwCellFrame* pCurrMasterCell = static_cast<SwCellFrame*>(rLastLine.Lower());
766  while ( pCurrMasterCell )
767  {
768  if ( !pCurrMasterCell->ContainsContent() && pCurrMasterCell->GetTabBox()->getRowSpan() >= 1 )
769  {
770  bRet = false;
771  break;
772  }
773  pCurrMasterCell = static_cast<SwCellFrame*>(pCurrMasterCell->GetNext());
774  }
775  }
776  }
777 
778  // 3. Check if last line does not contain any content:
779  if ( bRet )
780  {
781  if ( !rLastLine.ContainsContent() )
782  {
783  bRet = false;
784  }
785  }
786 
787  // 4. Check if follow flow line does not contain content:
788  if ( bRet )
789  {
790  if ( !rFollowLine.IsRowSpanLine() && !rFollowLine.ContainsContent() )
791  {
792  bRet = false;
793  }
794  }
795 
796  if ( bRet )
797  {
798  // Everything looks fine. Splitting seems to be successful. We invalidate
799  // rFollowLine to force a new formatting.
800  ::SwInvalidateAll( &rFollowLine, LONG_MAX );
801  }
802  else
803  {
804  // Splitting the table row gave us an unexpected result.
805  // Everything has to be prepared for a second try to split
806  // the table, this time without splitting the row.
807  ::SwInvalidateAll( &rLastLine, LONG_MAX );
808  }
809 
810  rTab.SetRebuildLastLine( false );
811  // #i26945#
812  rTab.SetDoesObjsFit( true );
813 
814  return bRet;
815 }
816 
817 // Sets the correct height for all spanned cells
818 static void lcl_AdjustRowSpanCells( SwRowFrame* pRow )
819 {
820  SwRectFnSet aRectFnSet(pRow);
821  SwCellFrame* pCellFrame = static_cast<SwCellFrame*>(pRow->GetLower());
822  while ( pCellFrame )
823  {
824  const tools::Long nLayoutRowSpan = pCellFrame->GetLayoutRowSpan();
825  if ( nLayoutRowSpan > 1 )
826  {
827  // calculate height of cell:
828  const tools::Long nNewCellHeight = lcl_GetHeightOfRows( pRow, nLayoutRowSpan );
829  const tools::Long nDiff = nNewCellHeight - aRectFnSet.GetHeight(pCellFrame->getFrameArea());
830 
831  if ( nDiff )
832  {
834  aRectFnSet.AddBottom(aFrm, nDiff);
835  }
836  }
837 
838  pCellFrame = static_cast<SwCellFrame*>(pCellFrame->GetNext());
839  }
840 }
841 
842 // Returns the maximum layout row span of the row
843 // Looking for the next row that contains no covered cells:
845 {
846  tools::Long nRet = 1;
847 
848  const SwRowFrame* pCurrentRowFrame = static_cast<const SwRowFrame*>(rRow.GetNext());
849  bool bNextRow = false;
850 
851  while ( pCurrentRowFrame )
852  {
853  // if there is any covered cell, we proceed to the next row frame
854  const SwCellFrame* pLower = static_cast<const SwCellFrame*>( pCurrentRowFrame->Lower());
855  while ( pLower )
856  {
857  if ( pLower->GetTabBox()->getRowSpan() < 0 )
858  {
859  ++nRet;
860  bNextRow = true;
861  break;
862  }
863  pLower = static_cast<const SwCellFrame*>(pLower->GetNext());
864  }
865  pCurrentRowFrame = bNextRow ?
866  static_cast<const SwRowFrame*>(pCurrentRowFrame->GetNext() ) :
867  nullptr;
868  }
869 
870  return nRet;
871 }
872 
873 // Function to remove the FollowFlowLine of rTab.
874 // The content of the FollowFlowLine is moved to the associated line in the
875 // master table.
877 {
878  // find FollowFlowLine
879  SwTabFrame *pFoll = GetFollow();
880  SwRowFrame* pFollowFlowLine = pFoll ? pFoll->GetFirstNonHeadlineRow() : nullptr;
881 
882  // find last row in master
883  SwFrame* pLastLine = GetLastLower();
884 
885  OSL_ENSURE( HasFollowFlowLine() &&
886  pFollowFlowLine &&
887  pLastLine, "There should be a flowline in the follow" );
888 
889  // #140081# Make code robust.
890  if ( !pFollowFlowLine || !pLastLine )
891  return true;
892  if (pFollowFlowLine->IsDeleteForbidden())
893  {
894  SAL_WARN("sw.layout", "Cannot remove in-use Follow Flow Line");
895  return false;
896  }
897 
898  // We have to reset the flag here, because lcl_MoveRowContent
899  // calls a GrowFrame(), which has a different behavior if
900  // this flag is set.
901  SetFollowFlowLine( false );
902 
903  // Move content
904  lcl_MoveRowContent( *pFollowFlowLine, *static_cast<SwRowFrame*>(pLastLine) );
905 
906  // NEW TABLES
907  // If a row span follow flow line is removed, we want to move the whole span
908  // to the master:
909  tools::Long nRowsToMove = lcl_GetMaximumLayoutRowSpan( *pFollowFlowLine );
910 
911  if ( nRowsToMove > 1 )
912  {
913  SwRectFnSet aRectFnSet(this);
914  SwFrame* pRow = pFollowFlowLine->GetNext();
915  SwFrame* pInsertBehind = GetLastLower();
916  SwTwips nGrow = 0;
917 
918  while ( pRow && nRowsToMove-- > 1 )
919  {
920  SwFrame* pNxt = pRow->GetNext();
921  nGrow += aRectFnSet.GetHeight(pRow->getFrameArea());
922 
923  // The footnotes have to be moved:
924  lcl_MoveFootnotes( *GetFollow(), *this, static_cast<SwRowFrame&>(*pRow) );
925 
926  pRow->RemoveFromLayout();
927  pRow->InsertBehind( this, pInsertBehind );
928  pRow->InvalidateAll_();
929  pRow->CheckDirChange();
930  pInsertBehind = pRow;
931  pRow = pNxt;
932  }
933 
934  SwFrame* pFirstRow = Lower();
935  while ( pFirstRow )
936  {
937  lcl_AdjustRowSpanCells( static_cast<SwRowFrame*>(pFirstRow) );
938  pFirstRow = pFirstRow->GetNext();
939  }
940 
941  Grow( nGrow );
942  GetFollow()->Shrink( nGrow );
943  }
944 
945  bool bJoin = !pFollowFlowLine->GetNext();
946  pFollowFlowLine->Cut();
947  SwFrame::DestroyFrame(pFollowFlowLine);
948 
949  return bJoin;
950 }
951 
952 // #i26945# - Floating screen objects are no longer searched.
953 static bool lcl_FindSectionsInRow( const SwRowFrame& rRow )
954 {
955  bool bRet = false;
956  const SwCellFrame* pLower = static_cast<const SwCellFrame*>(rRow.Lower());
957  while ( pLower )
958  {
959  if ( pLower->IsVertical() != rRow.IsVertical() )
960  return true;
961 
962  const SwFrame* pTmpFrame = pLower->Lower();
963  while ( pTmpFrame )
964  {
965  if ( pTmpFrame->IsRowFrame() )
966  {
967  bRet = lcl_FindSectionsInRow( *static_cast<const SwRowFrame*>(pTmpFrame) );
968  }
969  else
970  {
971  // #i26945# - search only for sections
972  if (pTmpFrame->IsSctFrame())
973  {
974  bRet = true;
975 
976  if (!rRow.IsInSct())
977  {
978  // This row is not in a section.
979  if (const SwFrame* pSectionLower = pTmpFrame->GetLower())
980  {
981  if (!pSectionLower->IsColumnFrame())
982  {
983  // Section has a single column only, try to
984  // split that.
985  bRet = false;
986 
987  for (const SwFrame* pFrame = pSectionLower; pFrame; pFrame = pFrame->GetNext())
988  {
989  if (pFrame->IsTabFrame())
990  {
991  // Section contains a table, no split in that case.
992  bRet = true;
993  break;
994  }
995  }
996  }
997  }
998  }
999  }
1000  }
1001 
1002  if ( bRet )
1003  return true;
1004  pTmpFrame = pTmpFrame->GetNext();
1005  }
1006 
1007  pLower = static_cast<const SwCellFrame*>(pLower->GetNext());
1008  }
1009  return bRet;
1010 }
1011 
1012 bool SwTabFrame::Split( const SwTwips nCutPos, bool bTryToSplit, bool bTableRowKeep )
1013 {
1014  bool bRet = true;
1015 
1016  SwRectFnSet aRectFnSet(this);
1017 
1018  // #i26745# - format row and cell frames of table
1019  {
1020  Lower()->InvalidatePos_();
1021  // #i43913# - correction
1022  // call method <lcl_InnerCalcLayout> with first lower.
1023  lcl_InnerCalcLayout( Lower(), LONG_MAX, true );
1024  }
1025 
1026  //In order to be able to compare the positions of the cells with CutPos,
1027  //they have to be calculated consecutively starting from the table.
1028  //They can definitely be invalid because of position changes of the table.
1029  SwRowFrame *pRow = static_cast<SwRowFrame*>(Lower());
1030  if( !pRow )
1031  return bRet;
1032 
1033  const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat();
1034  sal_uInt16 nRowCount = 0; // pRow currently points to the first row
1035 
1036  SwTwips nRemainingSpaceForLastRow =
1037  aRectFnSet.YDiff(nCutPos, aRectFnSet.GetTop(getFrameArea()));
1038  nRemainingSpaceForLastRow -= aRectFnSet.GetTopMargin(*this);
1039 
1040  // Make pRow point to the line that does not fit anymore:
1041  while( pRow->GetNext() &&
1042  nRemainingSpaceForLastRow >= ( aRectFnSet.GetHeight(pRow->getFrameArea()) +
1043  (IsCollapsingBorders() ?
1044  pRow->GetBottomLineSize() :
1045  0 ) ) )
1046  {
1047  if( bTryToSplit || !pRow->IsRowSpanLine() ||
1048  0 != aRectFnSet.GetHeight(pRow->getFrameArea()) )
1049  ++nRowCount;
1050  nRemainingSpaceForLastRow -= aRectFnSet.GetHeight(pRow->getFrameArea());
1051  pRow = static_cast<SwRowFrame*>(pRow->GetNext());
1052  }
1053 
1054  // bSplitRowAllowed: Row may be split according to its attributes.
1055  // bTryToSplit: Row will never be split if bTryToSplit = false.
1056  // This can either be passed as a parameter, indicating
1057  // that we are currently doing the second try to split the
1058  // table, or it will be set to false under certain
1059  // conditions that are not suitable for splitting
1060  // the row.
1061  bool bSplitRowAllowed = !IsSplitRowDisabled();
1062  if ( bSplitRowAllowed && !pRow->IsRowSplitAllowed() )
1063  {
1064  // A row larger than the entire page ought to be allowed to split regardless of setting,
1065  // otherwise it has hidden content and that makes no sense
1066  if ( pRow->getFrameArea().Height() > FindPageFrame()->getFramePrintArea().Height() )
1067  pRow->SetForceRowSplitAllowed( true );
1068  else
1069  bSplitRowAllowed = false;
1070  }
1071  // #i29438#
1072  // #i26945# - Floating screen objects no longer forbid
1073  // a splitting of the table row.
1074  // Special DoNotSplit case 1:
1075  // Search for sections inside pRow:
1076  if ( lcl_FindSectionsInRow( *pRow ) )
1077  {
1078  bTryToSplit = false;
1079  }
1080 
1081  // #i29771#
1082  // To avoid loops, we do some checks before actually trying to split
1083  // the row. Maybe we should keep the next row in this table.
1084  // Note: This is only done if we are at the beginning of our upper
1085  bool bKeepNextRow = false;
1086  if ( nRowCount < nRepeat )
1087  {
1088  // First case: One of the repeated headline does not fit to the page anymore.
1089  // tdf#88496 Disable repeated headline (like for #i44910#) to avoid loops and
1090  // to fix interoperability problems (very long tables only with headline)
1091  OSL_ENSURE( !GetIndPrev(), "Table is supposed to be at beginning" );
1093  return false;
1094  }
1095  else if ( !GetIndPrev() && nRepeat == nRowCount )
1096  {
1097  // Second case: The first non-headline row does not fit to the page.
1098  // If it is not allowed to be split, or it contains a sub-row that
1099  // is not allowed to be split, we keep the row in this table:
1100  if ( bTryToSplit && bSplitRowAllowed )
1101  {
1102  // Check if there are (first) rows inside this row,
1103  // which are not allowed to be split.
1104  SwCellFrame* pLowerCell = static_cast<SwCellFrame*>(pRow->Lower());
1105  while ( pLowerCell )
1106  {
1107  if ( pLowerCell->Lower() && pLowerCell->Lower()->IsRowFrame() )
1108  {
1109  const SwRowFrame* pLowerRow = static_cast<SwRowFrame*>(pLowerCell->Lower());
1110  if ( !pLowerRow->IsRowSplitAllowed() &&
1111  aRectFnSet.GetHeight(pLowerRow->getFrameArea()) > nRemainingSpaceForLastRow )
1112  {
1113  bKeepNextRow = true;
1114  break;
1115  }
1116  }
1117  pLowerCell = static_cast<SwCellFrame*>(pLowerCell->GetNext());
1118  }
1119  }
1120  else
1121  bKeepNextRow = true;
1122  }
1123 
1124  // Better keep the next row in this table:
1125  if ( bKeepNextRow )
1126  {
1127  pRow = GetFirstNonHeadlineRow();
1128  if ( pRow && pRow->IsRowSpanLine() && 0 == aRectFnSet.GetHeight(pRow->getFrameArea()) )
1129  pRow = static_cast<SwRowFrame*>(pRow->GetNext());
1130  if ( pRow )
1131  {
1132  pRow = static_cast<SwRowFrame*>(pRow->GetNext());
1133  ++nRowCount;
1134  }
1135  }
1136 
1137  // No more row to split or to move to follow table:
1138  if ( !pRow )
1139  return bRet;
1140 
1141  // We try to split the row if
1142  // - the attributes of the row are set accordingly and
1143  // - we are allowed to do so
1144  // - it should not be kept with the next row
1145  bSplitRowAllowed = bSplitRowAllowed && bTryToSplit &&
1146  ( !bTableRowKeep ||
1147  !pRow->ShouldRowKeepWithNext() );
1148 
1149  // Adjust pRow according to the keep-with-next attribute:
1150  if ( !bSplitRowAllowed && bTableRowKeep )
1151  {
1152  SwRowFrame* pTmpRow = static_cast<SwRowFrame*>(pRow->GetPrev());
1153  SwRowFrame* pOldRow = pRow;
1154  while ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() &&
1155  nRowCount > nRepeat )
1156  {
1157  pRow = pTmpRow;
1158  --nRowCount;
1159  pTmpRow = static_cast<SwRowFrame*>(pTmpRow->GetPrev());
1160  }
1161 
1162  // loop prevention
1163  if ( nRowCount == nRepeat && !GetIndPrev())
1164  {
1165  pRow = pOldRow;
1166  }
1167  }
1168 
1169  // If we do not intend to split pRow, we check if we are
1170  // allowed to move pRow to a follow. Otherwise we return
1171  // false, indicating an error
1172  if ( !bSplitRowAllowed )
1173  {
1174  SwRowFrame* pFirstNonHeadlineRow = GetFirstNonHeadlineRow();
1175  if ( pRow == pFirstNonHeadlineRow )
1176  return false;
1177 
1178  // #i91764#
1179  // Ignore row span lines
1180  SwRowFrame* pTmpRow = pFirstNonHeadlineRow;
1181  while ( pTmpRow && pTmpRow->IsRowSpanLine() )
1182  {
1183  pTmpRow = static_cast<SwRowFrame*>(pTmpRow->GetNext());
1184  }
1185  if ( !pTmpRow || pRow == pTmpRow )
1186  {
1187  return false;
1188  }
1189  }
1190 
1191  // Build follow table if not already done:
1192  bool bNewFollow;
1193  SwTabFrame *pFoll;
1194  if ( GetFollow() )
1195  {
1196  pFoll = GetFollow();
1197  bNewFollow = false;
1198  }
1199  else
1200  {
1201  bNewFollow = true;
1202  pFoll = new SwTabFrame( *this );
1203 
1204  // We give the follow table an initial width.
1205  {
1207  aRectFnSet.AddWidth(aFrm, aRectFnSet.GetWidth(getFrameArea()));
1208  aRectFnSet.SetLeft(aFrm, aRectFnSet.GetLeft(getFrameArea()));
1209  }
1210 
1211  {
1213  aRectFnSet.AddWidth(aPrt, aRectFnSet.GetWidth(getFramePrintArea()));
1214  }
1215 
1216  // Insert the new follow table
1217  pFoll->InsertBehind( GetUpper(), this );
1218 
1219  // Repeat the headlines.
1220  for ( nRowCount = 0; nRowCount < nRepeat; ++nRowCount )
1221  {
1222  // Insert new headlines:
1223  bDontCreateObjects = true; //frmtool
1224  SwRowFrame* pHeadline = new SwRowFrame(
1225  *GetTable()->GetTabLines()[ nRowCount ], this );
1226  pHeadline->SetRepeatedHeadline( true );
1227  bDontCreateObjects = false;
1228  pHeadline->InsertBefore( pFoll, nullptr );
1229 
1230  SwPageFrame *pPage = pHeadline->FindPageFrame();
1231  const SwFrameFormats *pTable = GetFormat()->GetDoc()->GetSpzFrameFormats();
1232  if( !pTable->empty() )
1233  {
1234  sal_uLong nIndex;
1235  SwContentFrame* pFrame = pHeadline->ContainsContent();
1236  while( pFrame )
1237  {
1238  // sw_redlinehide: the implementation of AppendObjs
1239  // takes care of iterating merged SwTextFrame
1240  nIndex = pFrame->IsTextFrame()
1241  ? static_cast<SwTextFrame*>(pFrame)->GetTextNodeFirst()->GetIndex()
1242  : static_cast<SwNoTextFrame*>(pFrame)->GetNode()->GetIndex();
1243  AppendObjs( pTable, nIndex, pFrame, pPage, GetFormat()->GetDoc());
1244  pFrame = pFrame->GetNextContentFrame();
1245  if( !pHeadline->IsAnLower( pFrame ) )
1246  break;
1247  }
1248  }
1249  }
1250  }
1251 
1252  SwRowFrame* pLastRow = nullptr; // points to the last remaining line in master
1253  SwRowFrame* pFollowRow = nullptr; // points to either the follow flow line or the
1254  // first regular line in the follow
1255 
1256  if ( bSplitRowAllowed )
1257  {
1258  // If the row that does not fit anymore is allowed
1259  // to be split, the next row has to be moved to the follow table.
1260  pLastRow = pRow;
1261  pRow = static_cast<SwRowFrame*>(pRow->GetNext());
1262 
1263  // new follow flow line for last row of master table
1264  pFollowRow = lcl_InsertNewFollowFlowLine( *this, *pLastRow, false );
1265  }
1266  else
1267  {
1268  pFollowRow = pRow;
1269 
1270  // NEW TABLES
1271  // check if we will break a row span by moving pFollowRow to the follow:
1272  // In this case we want to reformat the last line.
1273  const SwCellFrame* pCellFrame = static_cast<const SwCellFrame*>(pFollowRow->GetLower());
1274  while ( pCellFrame )
1275  {
1276  if ( pCellFrame->GetTabBox()->getRowSpan() < 1 )
1277  {
1278  pLastRow = static_cast<SwRowFrame*>(pRow->GetPrev());
1279  break;
1280  }
1281 
1282  pCellFrame = static_cast<const SwCellFrame*>(pCellFrame->GetNext());
1283  }
1284 
1285  // new follow flow line for last row of master table
1286  if ( pLastRow )
1287  pFollowRow = lcl_InsertNewFollowFlowLine( *this, *pLastRow, true );
1288  }
1289 
1290  SwTwips nShrink = 0;
1291 
1292  //Optimization: There is no paste needed for the new Follow and the
1293  //optimized insert can be used (large numbers of rows luckily only occur in
1294  //such situations).
1295  if ( bNewFollow )
1296  {
1297  SwFrame* pInsertBehind = pFoll->GetLastLower();
1298 
1299  while ( pRow )
1300  {
1301  SwFrame* pNxt = pRow->GetNext();
1302  nShrink += aRectFnSet.GetHeight(pRow->getFrameArea());
1303  // The footnotes do not have to be moved, this is done in the
1304  // MoveFwd of the follow table!!!
1305  pRow->RemoveFromLayout();
1306  pRow->InsertBehind( pFoll, pInsertBehind );
1307  pRow->InvalidateAll_();
1308  pInsertBehind = pRow;
1309  pRow = static_cast<SwRowFrame*>(pNxt);
1310  }
1311  }
1312  else
1313  {
1314  SwFrame* pPasteBefore = HasFollowFlowLine() ?
1315  pFollowRow->GetNext() :
1316  pFoll->GetFirstNonHeadlineRow();
1317 
1318  while ( pRow )
1319  {
1320  SwFrame* pNxt = pRow->GetNext();
1321  nShrink += aRectFnSet.GetHeight(pRow->getFrameArea());
1322 
1323  // The footnotes have to be moved:
1324  lcl_MoveFootnotes( *this, *GetFollow(), *pRow );
1325 
1326  pRow->RemoveFromLayout();
1327  pRow->Paste( pFoll, pPasteBefore );
1328 
1329  pRow->CheckDirChange();
1330  pRow = static_cast<SwRowFrame*>(pNxt);
1331  }
1332  }
1333 
1334  if ( !pLastRow )
1335  Shrink( nShrink );
1336  else
1337  {
1338  // we rebuild the last line to assure that it will be fully formatted
1339  // we also don't shrink here, because we will be doing that in lcl_RecalcSplitLine
1340 
1341  // recalculate the split line
1342  bRet = lcl_RecalcSplitLine( *pLastRow, *pFollowRow, nRemainingSpaceForLastRow, nShrink );
1343 
1344  // RecalcSplitLine did not work. In this case we conceal the split error:
1345  if (!bRet && !bSplitRowAllowed)
1346  {
1347  bRet = true;
1348  }
1349 
1350  // NEW TABLES
1351  // check if each cell in the row span line has a good height
1352  if ( bRet && pFollowRow->IsRowSpanLine() )
1353  lcl_AdjustRowSpanCells( pFollowRow );
1354  }
1355 
1356  return bRet;
1357 }
1358 
1360 {
1361  OSL_ENSURE( !HasFollowFlowLine(), "Joining follow flow line" );
1362 
1363  SwTabFrame *pFoll = GetFollow();
1364 
1365  if (!pFoll || pFoll->IsJoinLocked())
1366  return;
1367 
1368  SwRectFnSet aRectFnSet(this);
1369  pFoll->Cut(); //Cut out first to avoid unnecessary notifications.
1370 
1371  SwFrame *pRow = pFoll->GetFirstNonHeadlineRow(),
1372  *pNxt;
1373 
1374  SwFrame* pPrv = GetLastLower();
1375 
1376  SwTwips nHeight = 0; //Total height of the inserted rows as return value.
1377 
1378  while ( pRow )
1379  {
1380  pNxt = pRow->GetNext();
1381  nHeight += aRectFnSet.GetHeight(pRow->getFrameArea());
1382  pRow->RemoveFromLayout();
1383  pRow->InvalidateAll_();
1384  pRow->InsertBehind( this, pPrv );
1385  pRow->CheckDirChange();
1386  pPrv = pRow;
1387  pRow = pNxt;
1388  }
1389 
1390  SetFollow( pFoll->GetFollow() );
1392  SwFrame::DestroyFrame(pFoll);
1393 
1394  Grow( nHeight );
1395 }
1396 
1397 static void SwInvalidatePositions( SwFrame *pFrame, tools::Long nBottom )
1398 {
1399  // LONG_MAX == nBottom means we have to calculate all
1400  bool bAll = LONG_MAX == nBottom;
1401  SwRectFnSet aRectFnSet(pFrame);
1402  do
1403  { pFrame->InvalidatePos_();
1404  pFrame->InvalidateSize_();
1405  if( pFrame->IsLayoutFrame() )
1406  {
1407  if ( static_cast<SwLayoutFrame*>(pFrame)->Lower() )
1408  {
1409  ::SwInvalidatePositions( static_cast<SwLayoutFrame*>(pFrame)->Lower(), nBottom);
1410  // #i26945#
1411  ::lcl_InvalidateLowerObjs( *static_cast<SwLayoutFrame*>(pFrame) );
1412  }
1413  }
1414  else
1416  pFrame = pFrame->GetNext();
1417  } while ( pFrame &&
1418  ( bAll ||
1419  aRectFnSet.YDiff( aRectFnSet.GetTop(pFrame->getFrameArea()), nBottom ) < 0 ) );
1420 }
1421 
1422 void SwInvalidateAll( SwFrame *pFrame, tools::Long nBottom )
1423 {
1424  // LONG_MAX == nBottom means we have to calculate all
1425  bool bAll = LONG_MAX == nBottom;
1426  SwRectFnSet aRectFnSet(pFrame);
1427  do
1428  {
1429  pFrame->InvalidatePos_();
1430  pFrame->InvalidateSize_();
1431  pFrame->InvalidatePrt_();
1432  if( pFrame->IsLayoutFrame() )
1433  {
1434  // NEW TABLES
1435  SwLayoutFrame* pToInvalidate = static_cast<SwLayoutFrame*>(pFrame);
1436  SwCellFrame* pThisCell = dynamic_cast<SwCellFrame*>(pFrame);
1437  if ( pThisCell && pThisCell->GetTabBox()->getRowSpan() < 1 )
1438  {
1439  pToInvalidate = & const_cast<SwCellFrame&>(pThisCell->FindStartEndOfRowSpanCell( true ));
1440  pToInvalidate->InvalidatePos_();
1441  pToInvalidate->InvalidateSize_();
1442  pToInvalidate->InvalidatePrt_();
1443  }
1444 
1445  if ( pToInvalidate->Lower() )
1446  ::SwInvalidateAll( pToInvalidate->Lower(), nBottom);
1447  }
1448  else
1449  pFrame->Prepare();
1450 
1451  pFrame = pFrame->GetNext();
1452  } while ( pFrame &&
1453  ( bAll ||
1454  aRectFnSet.YDiff( aRectFnSet.GetTop(pFrame->getFrameArea()), nBottom ) < 0 ) );
1455 }
1456 
1457 // #i29550#
1459 {
1460  pLayFrame->InvalidatePrt_();
1461  pLayFrame->InvalidateSize_();
1462  pLayFrame->SetCompletePaint();
1463 
1464  SwFrame* pFrame = pLayFrame->Lower();
1465 
1466  while ( pFrame )
1467  {
1468  if ( pFrame->IsLayoutFrame() )
1469  lcl_InvalidateAllLowersPrt( static_cast<SwLayoutFrame*>(pFrame) );
1470  else
1471  {
1472  pFrame->InvalidatePrt_();
1473  pFrame->InvalidateSize_();
1474  pFrame->SetCompletePaint();
1475  }
1476 
1477  pFrame = pFrame->GetNext();
1478  }
1479 }
1480 
1482  tools::Long nBottom, bool bSkipRowSpanCells )
1483 {
1484  vcl::RenderContext* pRenderContext = rLay.getRootFrame()->GetCurrShell()->GetOut();
1485  // LONG_MAX == nBottom means we have to calculate all
1486  bool bAll = LONG_MAX == nBottom;
1487  bool bRet = false;
1488  SwContentFrame *pCnt = rLay.ContainsContent();
1489  SwRectFnSet aRectFnSet(&rLay);
1490 
1491  // FME 2007-08-30 #i81146# new loop control
1492  int nLoopControlRuns = 0;
1493  const int nLoopControlMax = 10;
1494  const sw::BroadcastingModify* pLoopControlCond = nullptr;
1495 
1496  while (pCnt && rDontLeave.IsAnLower(pCnt))
1497  {
1498  // #115759# - check, if a format of content frame is
1499  // possible. Thus, 'copy' conditions, found at the beginning of
1500  // <SwContentFrame::MakeAll(..)>, and check these.
1501  const bool bFormatPossible = !pCnt->IsJoinLocked() &&
1502  ( !pCnt->IsTextFrame() ||
1503  !static_cast<SwTextFrame*>(pCnt)->IsLocked() ) &&
1504  ( pCnt->IsFollow() || !StackHack::IsLocked() );
1505 
1506  // NEW TABLES
1507  bool bSkipContent = false;
1508  if ( bSkipRowSpanCells && pCnt->IsInTab() )
1509  {
1510  const SwFrame* pCell = pCnt->GetUpper();
1511  while ( pCell && !pCell->IsCellFrame() )
1512  pCell = pCell->GetUpper();
1513  if ( pCell && 1 != static_cast<const SwCellFrame*>( pCell )->GetLayoutRowSpan() )
1514  bSkipContent = true;
1515  }
1516 
1517  if ( bFormatPossible && !bSkipContent )
1518  {
1519  bRet |= !pCnt->isFrameAreaDefinitionValid();
1520  // #i26945# - no extra invalidation of floating
1521  // screen objects needed.
1522  // Thus, delete call of method <SwFrame::InvalidateObjs( true )>
1523  pCnt->Calc(pRenderContext);
1524  // #i46941# - frame has to be valid
1525  // Note: frame could be invalid after calling its format, if it's locked.
1526  OSL_ENSURE( !pCnt->IsTextFrame() ||
1527  pCnt->isFrameAreaDefinitionValid() ||
1528  static_cast<SwTextFrame*>(pCnt)->IsJoinLocked(),
1529  "<SwContentFrame::CalcLowers(..)> - text frame invalid and not locked." );
1530  if ( pCnt->IsTextFrame() && pCnt->isFrameAreaDefinitionValid() )
1531  {
1532  // #i23129#, #i36347# - pass correct page frame to
1533  // the object formatter
1535  *(pCnt->FindPageFrame()) ) )
1536  {
1537  SwTextNode const*const pTextNode(
1538  static_cast<SwTextFrame*>(pCnt)->GetTextNodeFirst());
1539  if (pTextNode == pLoopControlCond)
1540  ++nLoopControlRuns;
1541  else
1542  {
1543  nLoopControlRuns = 0;
1544  pLoopControlCond = pTextNode;
1545  }
1546 
1547  if ( nLoopControlRuns < nLoopControlMax )
1548  {
1549  // restart format with first content
1550  pCnt = rLay.ContainsContent();
1551  continue;
1552  }
1553 
1554 #if OSL_DEBUG_LEVEL > 1
1555  OSL_FAIL( "LoopControl in SwContentFrame::CalcLowers" );
1556 #endif
1557  }
1558  }
1559  if (!rDontLeave.IsAnLower(pCnt)) // moved backward?
1560  {
1561  pCnt = rLay.ContainsContent();
1562  continue; // avoid formatting new upper on different page
1563  }
1564  pCnt->GetUpper()->Calc(pRenderContext);
1565  }
1566  if( ! bAll && aRectFnSet.YDiff(aRectFnSet.GetTop(pCnt->getFrameArea()), nBottom) > 0 )
1567  break;
1568  pCnt = pCnt->GetNextContentFrame();
1569  }
1570  return bRet;
1571 }
1572 
1573 // #i26945# - add parameter <_bOnlyRowsAndCells> to control
1574 // that only row and cell frames are formatted.
1575 static bool lcl_InnerCalcLayout( SwFrame *pFrame,
1576  tools::Long nBottom,
1577  bool _bOnlyRowsAndCells )
1578 {
1579  vcl::RenderContext* pRenderContext = pFrame->getRootFrame()->GetCurrShell() ? pFrame->getRootFrame()->GetCurrShell()->GetOut() : nullptr;
1580  // LONG_MAX == nBottom means we have to calculate all
1581  bool bAll = LONG_MAX == nBottom;
1582  bool bRet = false;
1583  const SwFrame* pOldUp = pFrame->GetUpper();
1584  SwRectFnSet aRectFnSet(pFrame);
1585  do
1586  {
1587  // #i26945# - parameter <_bOnlyRowsAndCells> controls,
1588  // if only row and cell frames are formatted.
1589  if ( pFrame->IsLayoutFrame() &&
1590  ( !_bOnlyRowsAndCells || pFrame->IsRowFrame() || pFrame->IsCellFrame() ) )
1591  {
1592  // #130744# An invalid locked table frame will
1593  // not be calculated => It will not become valid =>
1594  // Loop in lcl_RecalcRow(). Therefore we do not consider them for bRet.
1595  bRet |= !pFrame->isFrameAreaDefinitionValid() && ( !pFrame->IsTabFrame() || !static_cast<SwTabFrame*>(pFrame)->IsJoinLocked() );
1596  pFrame->Calc(pRenderContext);
1597  if( static_cast<SwLayoutFrame*>(pFrame)->Lower() )
1598  bRet |= lcl_InnerCalcLayout( static_cast<SwLayoutFrame*>(pFrame)->Lower(), nBottom);
1599 
1600  // NEW TABLES
1601  SwCellFrame* pThisCell = dynamic_cast<SwCellFrame*>(pFrame);
1602  if ( pThisCell && pThisCell->GetTabBox()->getRowSpan() < 1 )
1603  {
1604  SwCellFrame& rToCalc = const_cast<SwCellFrame&>(pThisCell->FindStartEndOfRowSpanCell( true ));
1605  bRet |= !rToCalc.isFrameAreaDefinitionValid();
1606  rToCalc.Calc(pRenderContext);
1607  if ( rToCalc.Lower() )
1608  bRet |= lcl_InnerCalcLayout( rToCalc.Lower(), nBottom);
1609  }
1610  }
1611  pFrame = pFrame->GetNext();
1612  } while( pFrame &&
1613  ( bAll ||
1614  aRectFnSet.YDiff(aRectFnSet.GetTop(pFrame->getFrameArea()), nBottom) < 0 )
1615  && pFrame->GetUpper() == pOldUp );
1616  return bRet;
1617 }
1618 
1619 static void lcl_RecalcRow(SwRowFrame & rRow, tools::Long const nBottom)
1620 {
1621  // FME 2007-08-30 #i81146# new loop control
1622  int nLoopControlRuns_1 = 0;
1623  sal_uInt16 nLoopControlStage_1 = 0;
1624  const int nLoopControlMax = 10;
1625 
1626  bool bCheck = true;
1627  do
1628  {
1629  // FME 2007-08-30 #i81146# new loop control
1630  int nLoopControlRuns_2 = 0;
1631  sal_uInt16 nLoopControlStage_2 = 0;
1632 
1633  while (lcl_InnerCalcLayout(&rRow, nBottom))
1634  {
1635  if ( ++nLoopControlRuns_2 > nLoopControlMax )
1636  {
1637  SAL_WARN_IF(nLoopControlStage_2 == 0, "sw.layout", "LoopControl_2 in lcl_RecalcRow: Stage 1!");
1638  SAL_WARN_IF(nLoopControlStage_2 == 1, "sw.layout", "LoopControl_2 in lcl_RecalcRow: Stage 2!!");
1639  SAL_WARN_IF(nLoopControlStage_2 >= 2, "sw.layout", "LoopControl_2 in lcl_RecalcRow: Stage 3!!!");
1640  rRow.ValidateThisAndAllLowers( nLoopControlStage_2++ );
1641  nLoopControlRuns_2 = 0;
1642  if( nLoopControlStage_2 > 2 )
1643  break;
1644  }
1645 
1646  bCheck = true;
1647  }
1648 
1649  if( bCheck )
1650  {
1651  // #115759# - force another format of the
1652  // lowers, if at least one of it was invalid.
1653  bCheck = SwContentFrame::CalcLowers(rRow, *rRow.GetUpper(), nBottom, true);
1654 
1655  // NEW TABLES
1656  // First we calculate the cells with row span of < 1, afterwards
1657  // all cells with row span of > 1:
1658  for ( int i = 0; i < 2; ++i )
1659  {
1660  SwCellFrame* pCellFrame = static_cast<SwCellFrame*>(rRow.Lower());
1661  while ( pCellFrame )
1662  {
1663  const bool bCalc = 0 == i ?
1664  pCellFrame->GetLayoutRowSpan() < 1 :
1665  pCellFrame->GetLayoutRowSpan() > 1;
1666 
1667  if ( bCalc )
1668  {
1669  SwCellFrame& rToRecalc = 0 == i ?
1670  const_cast<SwCellFrame&>(pCellFrame->FindStartEndOfRowSpanCell( true )) :
1671  *pCellFrame;
1672  bCheck |= SwContentFrame::CalcLowers(rToRecalc, rToRecalc, nBottom, false);
1673  }
1674 
1675  pCellFrame = static_cast<SwCellFrame*>(pCellFrame->GetNext());
1676  }
1677  }
1678 
1679  if ( bCheck )
1680  {
1681  if ( ++nLoopControlRuns_1 > nLoopControlMax )
1682  {
1683  SAL_WARN_IF(nLoopControlStage_1 == 0, "sw.layout", "LoopControl_1 in lcl_RecalcRow: Stage 1!");
1684  SAL_WARN_IF(nLoopControlStage_1 == 1, "sw.layout", "LoopControl_1 in lcl_RecalcRow: Stage 2!!");
1685  SAL_WARN_IF(nLoopControlStage_1 >= 2, "sw.layout", "LoopControl_1 in lcl_RecalcRow: Stage 3!!!");
1686  rRow.ValidateThisAndAllLowers( nLoopControlStage_1++ );
1687  nLoopControlRuns_1 = 0;
1688  if( nLoopControlStage_1 > 2 )
1689  break;
1690  }
1691 
1692  continue;
1693  }
1694  }
1695  break;
1696  } while( true );
1697 }
1698 
1699 static void lcl_RecalcTable( SwTabFrame& rTab,
1700  SwLayoutFrame *pFirstRow,
1701  SwLayNotify &rNotify )
1702 {
1703  if ( rTab.Lower() )
1704  {
1705  if ( !pFirstRow )
1706  {
1707  pFirstRow = static_cast<SwLayoutFrame*>(rTab.Lower());
1708  rNotify.SetLowersComplete( true );
1709  }
1710  ::SwInvalidatePositions( pFirstRow, LONG_MAX );
1711  lcl_RecalcRow( *static_cast<SwRowFrame*>(pFirstRow), LONG_MAX );
1712  }
1713 }
1714 
1715 // This is a new function to check the first condition whether
1716 // a tab frame may move backward. It replaces the formerly used
1717 // GetIndPrev(), which did not work correctly for #i5947#
1718 static bool lcl_NoPrev( const SwFrame& rFrame )
1719 {
1720  // #i79774#
1721  // skip empty sections on investigation of direct previous frame.
1722  // use information, that at least one empty section is skipped in the following code.
1723  bool bSkippedDirectPrevEmptySection( false );
1724  if ( rFrame.GetPrev() )
1725  {
1726  const SwFrame* pPrev( rFrame.GetPrev() );
1727  while ( pPrev &&
1728  pPrev->IsSctFrame() &&
1729  !dynamic_cast<const SwSectionFrame&>(*pPrev).GetSection() )
1730  {
1731  pPrev = pPrev->GetPrev();
1732  bSkippedDirectPrevEmptySection = true;
1733  }
1734  if ( pPrev )
1735  {
1736  return false;
1737  }
1738  }
1739 
1740  if ( ( !bSkippedDirectPrevEmptySection && !rFrame.GetIndPrev() ) ||
1741  ( bSkippedDirectPrevEmptySection &&
1742  ( !rFrame.IsInSct() || !rFrame.GetIndPrev_() ) ) )
1743  {
1744  return true;
1745  }
1746 
1747  // I do not have a direct prev, but I have an indirect prev.
1748  // In section frames I have to check if I'm located inside
1749  // the first column:
1750  if ( rFrame.IsInSct() )
1751  {
1752  const SwFrame* pSct = rFrame.GetUpper();
1753  if ( pSct && pSct->IsColBodyFrame() &&
1754  pSct->GetUpper()->GetUpper()->IsSctFrame() )
1755  {
1756  const SwFrame* pPrevCol = rFrame.GetUpper()->GetUpper()->GetPrev();
1757  if ( pPrevCol )
1758  // I'm not inside the first column and do not have a direct
1759  // prev. I can try to go backward.
1760  return true;
1761  }
1762  }
1763 
1764  return false;
1765 }
1766 
1767 #define KEEPTAB ( !GetFollow() && !IsFollow() )
1768 
1769 // - helper method to find next content frame of
1770 // a table frame and format it to assure keep attribute.
1771 // method return true, if a next content frame is formatted.
1772 // Precondition: The given table frame hasn't a follow and isn't a follow.
1774 {
1775  vcl::RenderContext* pRenderContext = pTabFrame->getRootFrame()->GetCurrShell()->GetOut();
1776  // find next content, table or section
1777  SwFrame* pNxt = pTabFrame->FindNext();
1778 
1779  // skip empty sections
1780  while ( pNxt && pNxt->IsSctFrame() &&
1781  !static_cast<SwSectionFrame*>(pNxt)->GetSection() )
1782  {
1783  pNxt = pNxt->FindNext();
1784  }
1785 
1786  // if found next frame is a section, get its first content.
1787  if ( pNxt && pNxt->IsSctFrame() )
1788  {
1789  pNxt = static_cast<SwSectionFrame*>(pNxt)->ContainsAny();
1790  }
1791 
1792  // format found next frame.
1793  // if table frame is inside another table, method <SwFrame::MakeAll()> is
1794  // called to avoid that the superior table frame is formatted.
1795  if ( pNxt )
1796  {
1797  if ( pTabFrame->GetUpper()->IsInTab() )
1798  pNxt->MakeAll(pNxt->getRootFrame()->GetCurrShell()->GetOut());
1799  else
1800  pNxt->Calc(pRenderContext);
1801  }
1802 
1803  return pNxt;
1804 }
1805 
1806 namespace {
1807  bool AreAllRowsKeepWithNext( const SwRowFrame* pFirstRowFrame, const bool bCheckParents = true )
1808  {
1809  bool bRet = pFirstRowFrame != nullptr &&
1810  pFirstRowFrame->ShouldRowKeepWithNext( bCheckParents );
1811 
1812  while ( bRet && pFirstRowFrame->GetNext() != nullptr )
1813  {
1814  pFirstRowFrame = dynamic_cast<const SwRowFrame*>(pFirstRowFrame->GetNext());
1815  bRet = pFirstRowFrame != nullptr &&
1816  pFirstRowFrame->ShouldRowKeepWithNext( bCheckParents );
1817  }
1818 
1819  return bRet;
1820  }
1821 }
1822 
1823 // extern because static can't be friend
1825 {
1826  // hilariously static_cast<SwTabFrame*>(GetLower()) would not require friend declaration, but it's UB...
1827  rRowFrame.setFrameAreaPositionValid(false);
1828 }
1829 
1830 static void InvalidateFramePositions(SwFrame * pFrame)
1831 {
1832  while (pFrame)
1833  {
1834  if (pFrame->IsLayoutFrame())
1835  {
1837  }
1838  else if (pFrame->IsTextFrame())
1839  {
1841  }
1842  pFrame = pFrame->GetNext();
1843  }
1844 }
1845 
1847 {
1848  if ( IsJoinLocked() || StackHack::IsLocked() || StackHack::Count() > 50 )
1849  return;
1850 
1851  if ( HasFollow() )
1852  {
1853  SwTabFrame* pFollowFrame = GetFollow();
1854  OSL_ENSURE( !pFollowFrame->IsJoinLocked() || !pFollowFrame->IsRebuildLastLine(),
1855  "SwTabFrame::MakeAll for master while follow is in RebuildLastLine()" );
1856  if ( pFollowFrame->IsJoinLocked() && pFollowFrame->IsRebuildLastLine() )
1857  return;
1858  }
1859 
1860  PROTOCOL_ENTER( this, PROT::MakeAll, DbgAction::NONE, nullptr )
1861 
1862  LockJoin(); //I don't want to be destroyed on the way.
1863  SwLayNotify aNotify( this ); //does the notification in the DTor
1864  // If pos is invalid, we have to call a SetInvaKeep at aNotify.
1865  // Otherwise the keep attribute would not work in front of a table.
1866  const bool bOldValidPos = isFrameAreaPositionValid();
1867 
1868  //If my neighbour is my Follow at the same time, I'll swallow it up.
1869  // OD 09.04.2003 #108698# - join all follows, which are placed on the
1870  // same page/column.
1871  // OD 29.04.2003 #109213# - join follow, only if join for the follow
1872  // is not locked. Otherwise, join will not be performed and this loop
1873  // will be endless.
1874  while ( GetNext() && GetNext() == GetFollow() &&
1875  !GetFollow()->IsJoinLocked()
1876  )
1877  {
1878  if ( HasFollowFlowLine() )
1880  Join();
1881  }
1882 
1883  // The bRemoveFollowFlowLinePending is set if the split attribute of the
1884  // last line is set:
1886  {
1887  if ( RemoveFollowFlowLine() )
1888  Join();
1890  }
1891 
1892  if (m_bResizeHTMLTable) //Optimized interplay with grow/shrink of the content
1893  {
1894  m_bResizeHTMLTable = false;
1896  if ( pLayout )
1897  m_bCalcLowers = pLayout->Resize(
1898  pLayout->GetBrowseWidthByTabFrame( *this ) );
1899  }
1900 
1901  // as long as bMakePage is true, a new page can be created (exactly once)
1902  bool bMakePage = true;
1903  // bMovedBwd gets set to true when the frame flows backwards
1904  bool bMovedBwd = false;
1905  // as long as bMovedFwd is false, the Frame may flow backwards (until
1906  // it has been moved forward once)
1907  bool bMovedFwd = false;
1908  // gets set to true when the Frame is split
1909  bool bSplit = false;
1910  const bool bFootnotesInDoc = !GetFormat()->GetDoc()->GetFootnoteIdxs().empty();
1911  const bool bFly = IsInFly();
1912 
1913  auto pAccess = std::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
1914  const SwBorderAttrs *pAttrs = pAccess->Get();
1915 
1916  // All rows should keep together
1917  const bool bDontSplit = !IsFollow() &&
1918  ( !GetFormat()->GetLayoutSplit().GetValue() );
1919 
1920  // The number of repeated headlines
1921  const sal_uInt16 nRepeat = GetTable()->GetRowsToRepeat();
1922 
1923  // This flag indicates that we are allowed to try to split the
1924  // table rows.
1925  bool bTryToSplit = true;
1926 
1927  // Indicates that two individual rows may keep together, based on the keep
1928  // attribute set at the first paragraph in the first cell.
1929  const bool bTableRowKeep = !bDontSplit && GetFormat()->GetDoc()->GetDocumentSettingManager().get(DocumentSettingId::TABLE_ROW_KEEP);
1930 
1931  // The Magic Move: Used for the table row keep feature.
1932  // If only the last row of the table wants to keep (implicitly by setting
1933  // keep for the first paragraph in the first cell), and this table does
1934  // not have a next, the last line will be cut. Loop prevention: Only
1935  // one try.
1936  // WHAT IS THIS??? It "magically" hides last line (paragraph) in a table,
1937  // if first is set to keep with next???
1938  bool bLastRowHasToMoveToFollow = false;
1939  bool bLastRowMoveNoMoreTries = false;
1940 
1941  const bool bLargeTable = GetTable()->GetTabLines().size() > 64; //arbitrary value, virtually guaranteed to be larger than one page.
1942  const bool bEmulateTableKeep = !bLargeTable && bTableRowKeep && AreAllRowsKeepWithNext( GetFirstNonHeadlineRow(), /*bCheckParents=*/false );
1943  // The beloved keep attribute
1944  const bool bKeep = IsKeep(pAttrs->GetAttrSet().GetKeep(), GetBreakItem(), bEmulateTableKeep);
1945 
1946  // Join follow table, if this table is not allowed to split:
1947  if ( bDontSplit )
1948  {
1949  while ( GetFollow() && !GetFollow()->IsJoinLocked() )
1950  {
1951  if ( HasFollowFlowLine() )
1953  Join();
1954  }
1955  }
1956 
1957  // Join follow table, if this does not have enough (repeated) lines:
1958  if ( nRepeat )
1959  {
1960  if( GetFollow() && !GetFollow()->IsJoinLocked() &&
1961  nullptr == GetFirstNonHeadlineRow() )
1962  {
1963  if ( HasFollowFlowLine() )
1965  Join();
1966  }
1967  }
1968 
1969  // Join follow table, if last row of this table should keep:
1970  if ( bTableRowKeep && GetFollow() && !GetFollow()->IsJoinLocked() )
1971  {
1972  const SwRowFrame* pTmpRow = static_cast<const SwRowFrame*>(GetLastLower());
1973  if ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() )
1974  {
1975  if ( HasFollowFlowLine() )
1977  Join();
1978  }
1979  }
1980 
1981  // a new one is moved forwards immediately
1982  if ( !getFrameArea().Top() && IsFollow() )
1983  {
1984  SwFrame *pPre = GetPrev();
1985  if ( pPre && pPre->IsTabFrame() && static_cast<SwTabFrame*>(pPre)->GetFollow() == this)
1986  {
1987  // don't make the effort to move fwd if its known
1988  // conditions that are known not to work
1990  bMakePage = false;
1991  else if (!MoveFwd(bMakePage, false))
1992  bMakePage = false;
1993  bMovedFwd = true;
1994  }
1995  }
1996 
1997  int nUnSplitted = 5; // Just another loop control :-(
1998  int nThrowAwayValidLayoutLimit = 5; // And another one :-(
1999  SwRectFnSet aRectFnSet(this);
2001  {
2002  const bool bMoveable = IsMoveable();
2003  if (bMoveable &&
2004  !(bMovedFwd && bEmulateTableKeep) )
2005  if ( CheckMoveFwd( bMakePage, bKeep && KEEPTAB, bEmulateTableKeep ) )
2006  {
2007  bMovedFwd = true;
2008  m_bCalcLowers = true;
2009  // #i99267#
2010  // reset <bSplit> after forward move to assure that follows
2011  // can be joined, if further space is available.
2012  bSplit = false;
2013  }
2014 
2015  Point aOldPos( aRectFnSet.GetPos(getFrameArea()) );
2016  MakePos();
2017 
2018  if ( aOldPos != aRectFnSet.GetPos(getFrameArea()) )
2019  {
2020  if ( aOldPos.Y() != aRectFnSet.GetTop(getFrameArea()) )
2021  {
2023  if( pLayout )
2024  {
2025  pAccess.reset();
2026  m_bCalcLowers |= pLayout->Resize(
2027  pLayout->GetBrowseWidthByTabFrame( *this ) );
2028  pAccess = std::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
2029  pAttrs = pAccess->Get();
2030  }
2031 
2032  setFramePrintAreaValid(false);
2033  aNotify.SetLowersComplete( false );
2034  }
2035  SwFrame *pPre;
2036  if ( bKeep || (nullptr != (pPre = FindPrev()) &&
2037  pPre->GetAttrSet()->GetKeep().GetValue()) )
2038  {
2039  m_bCalcLowers = true;
2040  }
2041  if (GetLower())
2042  { // it's possible that the rows already have valid pos - but it is surely wrong if the table's pos changed!
2044  // invalidate text frames to get rid of their SwFlyPortions
2046  }
2047  }
2048 
2049  //We need to know the height of the first row, because the master needs
2050  //to be invalidated if it shrinks and then absorb the row if possible.
2051  tools::Long n1StLineHeight = 0;
2052  if ( IsFollow() )
2053  {
2054  SwFrame* pFrame = GetFirstNonHeadlineRow();
2055  if ( pFrame )
2056  n1StLineHeight = aRectFnSet.GetHeight(pFrame->getFrameArea());
2057  }
2058 
2060  {
2061  const tools::Long nOldPrtWidth = aRectFnSet.GetWidth(getFramePrintArea());
2062  const tools::Long nOldFrameWidth = aRectFnSet.GetWidth(getFrameArea());
2063  const Point aOldPrtPos = aRectFnSet.GetPos(getFramePrintArea());
2064  Format( getRootFrame()->GetCurrShell()->GetOut(), pAttrs );
2065 
2067  if ( pLayout &&
2068  (aRectFnSet.GetWidth(getFramePrintArea()) != nOldPrtWidth ||
2069  aRectFnSet.GetWidth(getFrameArea()) != nOldFrameWidth) )
2070  {
2071  pAccess.reset();
2072  m_bCalcLowers |= pLayout->Resize(
2073  pLayout->GetBrowseWidthByTabFrame( *this ) );
2074  pAccess = std::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
2075  pAttrs = pAccess->Get();
2076  }
2077  if ( aOldPrtPos != aRectFnSet.GetPos(getFramePrintArea()) )
2078  aNotify.SetLowersComplete( false );
2079  }
2080 
2081  // If this is the first one in a chain, check if this can flow
2082  // backwards (if this is movable at all).
2083  // To prevent oscillations/loops, check that this has not just
2084  // flowed forwards.
2085  if ( !bMovedFwd && (bMoveable || bFly) && lcl_NoPrev( *this ) )
2086  {
2087  // for Follows notify Master.
2088  // only move Follow if it has to skip empty pages.
2089  if ( IsFollow() )
2090  {
2091  // Only if the height of the first line got smaller.
2092  SwFrame *pFrame = GetFirstNonHeadlineRow();
2093  if( pFrame && n1StLineHeight >aRectFnSet.GetHeight(pFrame->getFrameArea()) )
2094  {
2095  SwTabFrame *pMaster = FindMaster();
2096  bool bDummy;
2097  if ( ShouldBwdMoved( pMaster->GetUpper(), bDummy ) )
2098  pMaster->InvalidatePos();
2099  }
2100  }
2101  SwFootnoteBossFrame *pOldBoss = bFootnotesInDoc ? FindFootnoteBossFrame( true ) : nullptr;
2102  bool bReformat;
2103  if ( MoveBwd( bReformat ) )
2104  {
2105  aRectFnSet.Refresh(this);
2106  bMovedBwd = true;
2107  aNotify.SetLowersComplete( false );
2108  if ( bFootnotesInDoc )
2109  MoveLowerFootnotes( nullptr, pOldBoss, nullptr, true );
2110  if ( bReformat || bKeep )
2111  {
2112  tools::Long nOldTop = aRectFnSet.GetTop(getFrameArea());
2113  MakePos();
2114  if( nOldTop != aRectFnSet.GetTop(getFrameArea()) )
2115  {
2116  SwHTMLTableLayout *pHTMLLayout =
2118  if( pHTMLLayout )
2119  {
2120  pAccess.reset();
2121  m_bCalcLowers |= pHTMLLayout->Resize(
2122  pHTMLLayout->GetBrowseWidthByTabFrame( *this ) );
2123 
2124  pAccess = std::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
2125  pAttrs = pAccess->Get();
2126  }
2127 
2128  setFramePrintAreaValid(false);
2129  Format( getRootFrame()->GetCurrShell()->GetOut(), pAttrs );
2130  }
2131  lcl_RecalcTable( *this, nullptr, aNotify );
2132  m_bLowersFormatted = true;
2133  if ( bKeep && KEEPTAB )
2134  {
2135 
2136  // Consider case that table is inside another table,
2137  // because it has to be avoided, that superior table
2138  // is formatted.
2139  // Thus, find next content, table or section
2140  // and, if a section is found, get its first
2141  // content.
2142  if ( nullptr != sw_FormatNextContentForKeep( this ) && !GetNext() )
2143  {
2145  }
2146  }
2147  }
2148  }
2149  }
2150 
2151  //Again an invalid value? - do it again...
2153  continue;
2154 
2155  // check, if calculation of table frame is ready.
2156 
2157  // Local variable <nDistanceToUpperPrtBottom>
2158  // Introduce local variable and init it with the distance from the
2159  // table frame bottom to the bottom of the upper printing area.
2160  // Note: negative values denotes the situation that table frame doesn't fit in its upper.
2161  SwTwips nDistanceToUpperPrtBottom =
2162  aRectFnSet.BottomDist(getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()));
2163 
2165  const SwViewShell *pSh = getRootFrame()->GetCurrShell();
2166  const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
2167  if ( nDistanceToUpperPrtBottom < 0 && bBrowseMode )
2168  {
2169  if ( GetUpper()->Grow( -nDistanceToUpperPrtBottom ) )
2170  {
2171  // upper is grown --> recalculate <nDistanceToUpperPrtBottom>
2172  nDistanceToUpperPrtBottom = aRectFnSet.BottomDist(getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()));
2173  }
2174  }
2175 
2176  // If there is still some space left in the upper, we check if we
2177  // can join some rows of the follow.
2178  // Setting bLastRowHasToMoveToFollow to true means we want to force
2179  // the table to be split! Only skip this if condition once.
2180  if( nDistanceToUpperPrtBottom >= 0 && !bLastRowHasToMoveToFollow )
2181  {
2182  // If there is space left in the upper printing area, join as for trial
2183  // at least one further row of an existing follow.
2184  if ( !bSplit && GetFollow() )
2185  {
2186  bool bDummy;
2187  if ( GetFollow()->ShouldBwdMoved( GetUpper(), bDummy ) )
2188  {
2189  SwFrame *pTmp = GetUpper();
2190  SwTwips nDeadLine = aRectFnSet.GetPrtBottom(*pTmp);
2191  if ( bBrowseMode )
2192  nDeadLine += pTmp->Grow( LONG_MAX, true );
2193  bool bFits = aRectFnSet.BottomDist(getFrameArea(), nDeadLine) > 0;
2194  if (!bFits && aRectFnSet.GetHeight(GetFollow()->getFrameArea()) == 0)
2195  // The follow should move backwards, so allow the case
2196  // when the upper has no space, but the follow is
2197  // empty.
2198  bFits = aRectFnSet.BottomDist(getFrameArea(), nDeadLine) >= 0;
2199  if (bFits)
2200  {
2201  // First, we remove an existing follow flow line.
2202  if ( HasFollowFlowLine() )
2203  {
2204  SwFrame* pLastLine = GetLastLower();
2206  // invalidate and rebuild last row
2207  if ( pLastLine )
2208  {
2209  ::SwInvalidateAll( pLastLine, LONG_MAX );
2210  SetRebuildLastLine( true );
2211  lcl_RecalcRow(*static_cast<SwRowFrame*>(pLastLine), LONG_MAX);
2212  SetRebuildLastLine( false );
2213  }
2214 
2216 
2217  if ( !pRow || !pRow->GetNext() )
2218  // The follow became empty and hence useless
2219  Join();
2220 
2221  continue;
2222  }
2223 
2224  // If there is no follow flow line, we move the first
2225  // row in the follow table to the master table.
2227 
2228  // The follow became empty and hence useless
2229  if ( !pRow )
2230  {
2231  Join();
2232  continue;
2233  }
2234 
2235  const SwTwips nOld = aRectFnSet.GetHeight(getFrameArea());
2236  tools::Long nRowsToMove = lcl_GetMaximumLayoutRowSpan( *pRow );
2237  SwFrame* pRowToMove = pRow;
2238 
2239  while ( pRowToMove && nRowsToMove-- > 0 )
2240  {
2241  const bool bMoveFootnotes = bFootnotesInDoc && !GetFollow()->IsJoinLocked();
2242 
2243  SwFootnoteBossFrame *pOldBoss = nullptr;
2244  if ( bMoveFootnotes )
2245  pOldBoss = pRowToMove->FindFootnoteBossFrame( true );
2246 
2247  SwFrame* pNextRow = pRowToMove->GetNext();
2248 
2249  if ( !pNextRow )
2250  {
2251  // The follow became empty and hence useless
2252  Join();
2253  }
2254  else
2255  {
2256  pRowToMove->Cut();
2257  pRowToMove->Paste( this );
2258  }
2259 
2260  // Move the footnotes!
2261  if ( bMoveFootnotes )
2262  if ( static_cast<SwLayoutFrame*>(pRowToMove)->MoveLowerFootnotes( nullptr, pOldBoss, FindFootnoteBossFrame( true ), true ) )
2263  GetUpper()->Calc(pRenderContext);
2264 
2265  pRowToMove = pNextRow;
2266  }
2267 
2268  if ( nOld != aRectFnSet.GetHeight(getFrameArea()) )
2269  lcl_RecalcTable( *this, static_cast<SwLayoutFrame*>(pRow), aNotify );
2270 
2271  continue;
2272  }
2273  }
2274  }
2275  else if ( KEEPTAB )
2276  {
2277  bool bFormat = false;
2278  if ( bKeep )
2279  bFormat = true;
2280  else if ( bTableRowKeep && !bLastRowMoveNoMoreTries )
2281  {
2282  // We only want to give the last row one chance to move
2283  // to the follow table. Set the flag as early as possible:
2284  bLastRowMoveNoMoreTries = true;
2285 
2286  // The last line of the table has to be cut off if:
2287  // 1. The table does not want to keep with its next
2288  // 2. The compatibility option is set and the table is allowed to split
2289  // 3. We did not already cut off the last row
2290  // 4. There is not break after attribute set at the table
2291  // 5. There is no break before attribute set behind the table
2292  // 6. There is no section change behind the table (see IsKeep)
2293  // 7. The last table row wants to keep with its next.
2294  const SwRowFrame* pLastRow = static_cast<const SwRowFrame*>(GetLastLower());
2295  if (pLastRow
2296  && IsKeep(pAttrs->GetAttrSet().GetKeep(), GetBreakItem(), true)
2297  && pLastRow->ShouldRowKeepWithNext())
2298  {
2299  bFormat = true;
2300  }
2301  }
2302 
2303  if ( bFormat )
2304  {
2305  pAccess.reset();
2306 
2307  // Consider case that table is inside another table, because
2308  // it has to be avoided, that superior table is formatted.
2309  // Thus, find next content, table or section and, if a section
2310  // is found, get its first content.
2311  const SwFrame* pTmpNxt = sw_FormatNextContentForKeep( this );
2312 
2313  pAccess = std::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
2314  pAttrs = pAccess->Get();
2315 
2316  // The last row wants to keep with the frame behind the table.
2317  // Check if the next frame is on a different page and valid.
2318  // In this case we do a magic trick:
2319  if ( !bKeep && !GetNext() && pTmpNxt && pTmpNxt->isFrameAreaDefinitionValid() )
2320  {
2322  bLastRowHasToMoveToFollow = true;
2323  }
2324  }
2325  }
2326 
2328  {
2329  if (m_bCalcLowers)
2330  {
2331  lcl_RecalcTable( *this, nullptr, aNotify );
2332  m_bLowersFormatted = true;
2333  m_bCalcLowers = false;
2334  }
2335  else if (m_bONECalcLowers)
2336  {
2337  lcl_RecalcRow(*static_cast<SwRowFrame*>(Lower()), LONG_MAX);
2338  m_bONECalcLowers = false;
2339  }
2340  }
2341  continue;
2342  }
2343 
2344  // I don't fit in the upper Frame anymore, therefore it's the
2345  // right moment to do some preferably constructive changes.
2346 
2347  // If I'm NOT allowed to leave the upper Frame, I've got a problem.
2348  // Following Arthur Dent, we do the only thing that you can do with
2349  // an unsolvable problem: We ignore it with all our power.
2350  if ( !bMoveable )
2351  {
2353  {
2354  lcl_RecalcTable( *this, nullptr, aNotify );
2355  m_bLowersFormatted = true;
2356  m_bCalcLowers = false;
2357  }
2358  else if (m_bONECalcLowers)
2359  {
2360  lcl_RecalcRow(*static_cast<SwRowFrame*>(Lower()), LONG_MAX);
2361  m_bONECalcLowers = false;
2362  }
2363 
2364  // It does not make sense to cut off the last line if we are
2365  // not moveable:
2366  bLastRowHasToMoveToFollow = false;
2367 
2368  continue;
2369  }
2370 
2372  {
2373  lcl_RecalcTable( *this, nullptr, aNotify );
2374  m_bLowersFormatted = true;
2375  m_bCalcLowers = false;
2377  continue;
2378  }
2379 
2380  // First try to split the table. Condition:
2381  // 1. We have at least one non headline row
2382  // 2. If this row wants to keep, we need an additional row
2383  // 3. The table is allowed to split or we do not have a pIndPrev:
2384  SwFrame* pIndPrev = GetIndPrev();
2385  const SwRowFrame* pFirstNonHeadlineRow = GetFirstNonHeadlineRow();
2386  // #i120016# if this row wants to keep, allow split in case that all rows want to keep with next,
2387  // the table can not move forward as it is the first one and a split is in general allowed.
2388  const bool bAllowSplitOfRow = bTableRowKeep && !pIndPrev && AreAllRowsKeepWithNext(pFirstNonHeadlineRow);
2389  // tdf91083 MSCompat: this extends bAllowSplitOfRow (and perhaps should just replace it).
2390  // If the kept-together items cannot move to a new page, a table split is in general allowed.
2391  const bool bEmulateTableKeepSplitAllowed = bEmulateTableKeep && !IsKeepFwdMoveAllowed(/*IgnoreMyOwnKeepValue=*/true);
2392 
2393  if ( pFirstNonHeadlineRow && nUnSplitted > 0 &&
2394  ( bEmulateTableKeepSplitAllowed || bAllowSplitOfRow ||
2395  ( ( !bTableRowKeep || pFirstNonHeadlineRow->GetNext() ||
2396  !pFirstNonHeadlineRow->ShouldRowKeepWithNext()
2397  ) && ( !bDontSplit || !pIndPrev )
2398  ) ) )
2399  {
2400  // #i29438#
2401  // Special DoNotSplit cases:
2402  // We better avoid splitting of a row frame if we are inside a columned
2403  // section which has a height of 0, because this is not growable and thus
2404  // all kinds of unexpected things could happen.
2405  if ( IsInSct() && FindSctFrame()->Lower()->IsColumnFrame() &&
2406  0 == aRectFnSet.GetHeight(GetUpper()->getFrameArea())
2407  )
2408  {
2409  bTryToSplit = false;
2410  }
2411 
2412  // 1. Try: bTryToSplit = true => Try to split the row.
2413  // 2. Try: bTryToSplit = false => Split the table between the rows.
2414  if ( pFirstNonHeadlineRow->GetNext() || bTryToSplit )
2415  {
2416  SwTwips nDeadLine = aRectFnSet.GetPrtBottom(*GetUpper());
2417  if( IsInSct() || GetUpper()->IsInTab() ) // TABLE IN TABLE)
2418  nDeadLine = aRectFnSet.YInc( nDeadLine,
2419  GetUpper()->Grow( LONG_MAX, true ) );
2420 
2421  {
2422  SwFrameDeleteGuard g(Lower()); // tdf#134965 prevent RemoveFollowFlowLine()
2423  SetInRecalcLowerRow( true );
2424  ::lcl_RecalcRow(*static_cast<SwRowFrame*>(Lower()), nDeadLine);
2425  SetInRecalcLowerRow( false );
2426  }
2427  m_bLowersFormatted = true;
2428  aNotify.SetLowersComplete( true );
2429 
2430  // One more check if it's really necessary to split the table.
2431  // 1. The table either has to exceed the deadline or
2432  // 2. We explicitly want to cut off the last row.
2433  if( aRectFnSet.BottomDist( getFrameArea(), nDeadLine ) > 0 && !bLastRowHasToMoveToFollow )
2434  {
2435  continue;
2436  }
2437 
2438  // Set to false again as early as possible.
2439  bLastRowHasToMoveToFollow = false;
2440 
2441  // #i52781#
2442  // YaSC - Yet another special case:
2443  // If our upper is inside a table cell which is not allowed
2444  // to split, we do not try to split:
2445  if ( GetUpper()->IsInTab() )
2446  {
2447  const SwFrame* pTmpRow = GetUpper();
2448  while ( pTmpRow && !pTmpRow->IsRowFrame() )
2449  pTmpRow = pTmpRow->GetUpper();
2450  if ( pTmpRow && !static_cast<const SwRowFrame*>(pTmpRow)->IsRowSplitAllowed() )
2451  continue;
2452  }
2453 
2454  sal_uInt16 nMinNumOfLines = nRepeat;
2455 
2456  if ( bTableRowKeep )
2457  {
2458  const SwRowFrame* pTmpRow = GetFirstNonHeadlineRow();
2459  while ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() )
2460  {
2461  ++nMinNumOfLines;
2462  pTmpRow = static_cast<const SwRowFrame*>(pTmpRow->GetNext());
2463  }
2464  }
2465 
2466  if ( !bTryToSplit )
2467  ++nMinNumOfLines;
2468 
2469  const SwTwips nBreakLine = aRectFnSet.YInc(
2470  aRectFnSet.GetTop(getFrameArea()),
2471  aRectFnSet.GetTopMargin(*this) +
2472  lcl_GetHeightOfRows( GetLower(), nMinNumOfLines ) );
2473 
2474  // Some more checks if we want to call the split algorithm or not:
2475  // The repeating lines / keeping lines still fit into the upper or
2476  // if we do not have an (in)direct Prev, we split anyway.
2477  if( aRectFnSet.YDiff(nDeadLine, nBreakLine) >=0
2478  || !pIndPrev || bEmulateTableKeepSplitAllowed )
2479  {
2480  aNotify.SetLowersComplete( false );
2481  bSplit = true;
2482 
2483  // An existing follow flow line has to be removed.
2484  if ( HasFollowFlowLine() )
2485  {
2486  if (!nThrowAwayValidLayoutLimit)
2487  continue;
2488  const bool bInitialLoopEndCondition(isFrameAreaDefinitionValid());
2490  const bool bFinalLoopEndCondition(isFrameAreaDefinitionValid());
2491 
2492  if (bInitialLoopEndCondition && !bFinalLoopEndCondition)
2493  {
2494  --nThrowAwayValidLayoutLimit;
2495  }
2496  }
2497 
2498  const bool bSplitError = !Split( nDeadLine, bTryToSplit, ( bTableRowKeep && !(bAllowSplitOfRow || bEmulateTableKeepSplitAllowed) ) );
2499 
2500  // tdf#130639 don't start table on a new page after the fallback "switch off repeating header"
2501  if (bSplitError && nRepeat > GetTable()->GetRowsToRepeat())
2502  {
2504  break;
2505  }
2506 
2507  if (!bTryToSplit && !bSplitError)
2508  {
2509  --nUnSplitted;
2510  }
2511 
2512  // #i29771# Two tries to split the table
2513  // If an error occurred during splitting. We start a second
2514  // try, this time without splitting of table rows.
2515  if ( bSplitError && HasFollowFlowLine() )
2517 
2518  // If splitting the table was successful or not,
2519  // we do not want to have 'empty' follow tables.
2520  if ( GetFollow() && !GetFollow()->GetFirstNonHeadlineRow() )
2521  Join();
2522 
2523  // We want to restore the situation before the failed
2524  // split operation as good as possible. Therefore we
2525  // do some more calculations. Note: Restricting this
2526  // to nDeadLine may not be enough.
2527  if ( bSplitError && bTryToSplit ) // no restart if we did not try to split: i72847, i79426
2528  {
2529  lcl_RecalcRow(*static_cast<SwRowFrame*>(Lower()), LONG_MAX);
2531  bTryToSplit = false;
2532  continue;
2533  }
2534 
2535  bTryToSplit = !bSplitError;
2536 
2537  //To avoid oscillations the Follow must become valid now
2538  if ( GetFollow() )
2539  {
2540  // #i80924#
2541  // After a successful split assure that the first row
2542  // is invalid. When graphics are present, this isn't hold.
2543  // Note: defect i80924 could also be fixed, if it is
2544  // assured, that <SwLayNotify::bLowersComplete> is only
2545  // set, if all lower are valid *and* are correct laid out.
2546  if ( !bSplitError && GetFollow()->GetLower() )
2547  {
2549  }
2550  SwRectFnSet fnRectX(GetFollow());
2551 
2552  static sal_uInt8 nStack = 0;
2553  if ( !StackHack::IsLocked() && nStack < 4 )
2554  {
2555  ++nStack;
2556  StackHack aHack;
2557  pAccess.reset();
2558 
2559  GetFollow()->MakeAll(pRenderContext);
2560 
2561  pAccess = std::make_unique<SwBorderAttrAccess>(SwFrame::GetCache(), this);
2562  pAttrs = pAccess->Get();
2563 
2564  GetFollow()->SetLowersFormatted(false);
2565  // #i43913# - lock follow table
2566  // to avoid its formatting during the format of
2567  // its content.
2568  const bool bOldJoinLock = GetFollow()->IsJoinLocked();
2569  GetFollow()->LockJoin();
2570  ::lcl_RecalcRow(*static_cast<SwRowFrame*>(GetFollow()->Lower()),
2571  fnRectX.GetBottom(GetFollow()->GetUpper()->getFrameArea()) );
2572  // #i43913#
2573  // #i63632# Do not unlock the
2574  // follow if it wasn't locked before.
2575  if ( !bOldJoinLock )
2576  GetFollow()->UnlockJoin();
2577 
2578  if ( !GetFollow()->GetFollow() )
2579  {
2580  SwFrame* pNxt = static_cast<SwFrame*>(GetFollow())->FindNext();
2581  if ( pNxt )
2582  {
2583  // #i18103# - no formatting of found next
2584  // frame, if it's a follow section of the
2585  // 'ColLocked' section, the follow table is
2586  // in.
2587  bool bCalcNxt = true;
2588  if ( GetFollow()->IsInSct() && pNxt->IsSctFrame() )
2589  {
2590  SwSectionFrame* pSct = GetFollow()->FindSctFrame();
2591  if ( pSct->IsColLocked() &&
2592  pSct->GetFollow() == pNxt )
2593  {
2594  bCalcNxt = false;
2595  }
2596  }
2597  if ( bCalcNxt )
2598  {
2599  // tdf#119109 follow was just formatted,
2600  // don't do it again now
2602  pNxt->Calc(pRenderContext);
2603  }
2604  }
2605  }
2606  --nStack;
2607  }
2608  else if ( GetFollow() == GetNext() )
2609  GetFollow()->MoveFwd( true, false );
2610  }
2611  continue;
2612  }
2613  }
2614  }
2615 
2616  // Set to false again as early as possible.
2617  bLastRowHasToMoveToFollow = false;
2618 
2619  if( IsInSct() && bMovedFwd && bMakePage && GetUpper()->IsColBodyFrame() &&
2620  GetUpper()->GetUpper()->GetUpper()->IsSctFrame() &&
2621  ( GetUpper()->GetUpper()->GetPrev() || GetIndPrev() ) &&
2622  static_cast<SwSectionFrame*>(GetUpper()->GetUpper()->GetUpper())->MoveAllowed(this) )
2623  {
2624  bMovedFwd = false;
2625  }
2626 
2627  // #i29771# Reset bTryToSplit flag on change of upper
2628  const SwFrame* pOldUpper = GetUpper();
2629 
2630  //Let's see if we find some place anywhere...
2631  if (!bMovedFwd)
2632  {
2633  // don't make the effort to move fwd if its known
2634  // conditions that are known not to work
2636  bMakePage = false;
2637  else if (!MoveFwd(bMakePage, false))
2638  bMakePage = false;
2639  }
2640 
2641  // #i29771# Reset bSplitError flag on change of upper
2642  if ( GetUpper() != pOldUpper )
2643  {
2644  bTryToSplit = true;
2645  nUnSplitted = 5;
2646  }
2647 
2648  aRectFnSet.Refresh(this);
2649  m_bCalcLowers = true;
2650  bMovedFwd = true;
2651  aNotify.SetLowersComplete( false );
2652  if ( IsFollow() )
2653  {
2654  // To avoid oscillations, master should not remain invalid
2655  SwTabFrame *pTab = FindMaster();
2656  if ( pTab->GetUpper() )
2657  pTab->GetUpper()->Calc(pRenderContext);
2658  pTab->Calc(pRenderContext);
2659  pTab->SetLowersFormatted( false );
2660  }
2661 
2662  //If my neighbour is my Follow at the same time, I'll swallow it up.
2663  if ( ( GetNext() && GetNext() == GetFollow() ) || !GetLower() )
2664  {
2665  if ( HasFollowFlowLine() )
2667  if ( GetFollow() )
2668  Join();
2669  }
2670 
2671  if ( bMovedBwd && GetUpper() )
2672  {
2673  //During flowing back the upper was animated to do a full repaint,
2674  //we can now skip this after the whole flowing back and forth.
2676  }
2677 
2679  {
2680  // #i44910# - format of lower frames unnecessary
2681  // and can cause layout loops, if table doesn't fit and isn't
2682  // allowed to split.
2683  SwTwips nDistToUpperPrtBottom =
2684  aRectFnSet.BottomDist( getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()));
2685  if ( nDistToUpperPrtBottom >= 0 || bTryToSplit )
2686  {
2687  lcl_RecalcTable( *this, nullptr, aNotify );
2688  m_bLowersFormatted = true;
2689  m_bCalcLowers = false;
2690  if (!isFramePrintAreaValid())
2692  }
2693 #if OSL_DEBUG_LEVEL > 0
2694  else
2695  {
2696  OSL_FAIL( "debug assertion: <SwTabFrame::MakeAll()> - format of table lowers suppressed by fix i44910" );
2697  }
2698 #endif
2699  }
2700 
2701  } //while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() )
2702 
2703  //If my direct predecessor is my master now, it can destroy me during the
2704  //next best opportunity.
2705  if ( IsFollow() )
2706  {
2707  SwFrame *pPre = GetPrev();
2708  if ( pPre && pPre->IsTabFrame() && static_cast<SwTabFrame*>(pPre)->GetFollow() == this)
2709  pPre->InvalidatePos();
2710  }
2711 
2712  m_bCalcLowers = m_bONECalcLowers = false;
2713  pAccess.reset();
2714  UnlockJoin();
2715  if ( bMovedFwd || bMovedBwd || !bOldValidPos )
2716  aNotify.SetInvaKeep();
2717 }
2718 
2719 static bool IsNextOnSamePage(SwPageFrame const& rPage,
2720  SwTabFrame const& rTabFrame, SwTextFrame const& rAnchorFrame)
2721 {
2722  for (SwContentFrame const* pContentFrame = rTabFrame.FindNextCnt();
2723  pContentFrame && pContentFrame->FindPageFrame() == &rPage;
2724  pContentFrame = pContentFrame->FindNextCnt())
2725  {
2726  if (pContentFrame == &rAnchorFrame)
2727  {
2728  return true;
2729  }
2730  }
2731  return false;
2732 }
2733 
2736  tools::Long& rLeftOffset,
2737  tools::Long& rRightOffset ) const
2738 {
2739  bool bInvalidatePrtArea = false;
2740  const SwPageFrame *pPage = FindPageFrame();
2741  const SwFlyFrame* pMyFly = FindFlyFrame();
2742 
2743  // --> #108724# Page header/footer content doesn't have to wrap around
2744  // floating screen objects
2745 
2747  const bool bWrapAllowed = rIDSA.get(DocumentSettingId::USE_FORMER_TEXT_WRAPPING) ||
2748  ( !IsInFootnote() && nullptr == FindFooterOrHeader() );
2749 
2750  if ( pPage->GetSortedObjs() && bWrapAllowed )
2751  {
2752  SwRectFnSet aRectFnSet(this);
2753  const bool bConsiderWrapOnObjPos = rIDSA.get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION);
2754  tools::Long nPrtPos = aRectFnSet.GetTop(getFrameArea());
2755  nPrtPos = aRectFnSet.YInc( nPrtPos, rUpper );
2756  SwRect aRect( getFrameArea() );
2757  tools::Long nYDiff = aRectFnSet.YDiff( aRectFnSet.GetTop(getFramePrintArea()), rUpper );
2758  if( nYDiff > 0 )
2759  aRectFnSet.AddBottom( aRect, -nYDiff );
2760 
2761  bool bAddVerticalFlyOffsets = rIDSA.get(DocumentSettingId::ADD_VERTICAL_FLY_OFFSETS);
2762 
2763  for ( size_t i = 0; i < pPage->GetSortedObjs()->size(); ++i )
2764  {
2765  SwAnchoredObject* pAnchoredObj = (*pPage->GetSortedObjs())[i];
2766  if ( auto pFly = dynamic_cast<SwFlyFrame *>( pAnchoredObj ) )
2767  {
2768  const SwRect aFlyRect = pFly->GetObjRectWithSpaces();
2769  // #i26945# - correction of conditions,
2770  // if Writer fly frame has to be considered:
2771  // - no need to check, if top of Writer fly frame differs
2772  // from FAR_AWAY, because it's also checked, if the Writer
2773  // fly frame rectangle overlaps with <aRect>
2774  // - no check, if bottom of anchor frame is prior the top of
2775  // the table, because Writer fly frames can be negative positioned.
2776  // - correct check, if the Writer fly frame is a lower of the
2777  // table, because table lines/rows can split and an at-character
2778  // anchored Writer fly frame could be positioned in the follow
2779  // flow line.
2780  // - add condition, that an existing anchor character text frame
2781  // has to be on the same page as the table.
2782  // E.g., it could happen, that the fly frame is still registered
2783  // at the page frame, the table is on, but it's anchor character
2784  // text frame has already changed its page.
2785  const SwTextFrame* pAnchorCharFrame = pFly->FindAnchorCharFrame();
2786  bool bConsiderFly =
2787  // #i46807# - do not consider invalid
2788  // Writer fly frames.
2789  (pFly->isFrameAreaDefinitionValid() || bAddVerticalFlyOffsets) &&
2790  // fly anchored at character or at paragraph
2791  pFly->IsFlyAtContentFrame() &&
2792  // fly overlaps with corresponding table rectangle
2793  aFlyRect.IsOver( aRect ) &&
2794  // fly isn't lower of table and
2795  // anchor character frame of fly isn't lower of table
2796  ( !IsAnLower( pFly ) &&
2797  ( !pAnchorCharFrame || !IsAnLower( pAnchorCharFrame ) ) ) &&
2798  // table isn't lower of fly
2799  !pFly->IsAnLower( this ) &&
2800  // fly is lower of fly, the table is in
2801  // #123274# - correction
2802  // assure that fly isn't a lower of a fly, the table isn't in.
2803  // E.g., a table in the body doesn't wrap around a graphic,
2804  // which is inside a frame.
2805  ( ( !pMyFly ||
2806  pMyFly->IsAnLower( pFly ) ) &&
2807  pMyFly == pFly->GetAnchorFrameContainingAnchPos()->FindFlyFrame() ) &&
2808  // anchor frame not on following page
2809  pPage->GetPhyPageNum() >=
2810  pFly->GetAnchorFrame()->FindPageFrame()->GetPhyPageNum() &&
2811  // anchor character text frame on same page
2812  ( !pAnchorCharFrame ||
2813  pAnchorCharFrame->FindPageFrame()->GetPhyPageNum() ==
2814  pPage->GetPhyPageNum() );
2815 
2816  if ( bConsiderFly )
2817  {
2818  const SwFrame* pFlyHeaderFooterFrame = pFly->GetAnchorFrame()->FindFooterOrHeader();
2819  const SwFrame* pThisHeaderFooterFrame = FindFooterOrHeader();
2820 
2821  if ( pFlyHeaderFooterFrame != pThisHeaderFooterFrame &&
2822  // #148493# If bConsiderWrapOnObjPos is set,
2823  // we want to consider the fly if it is located in the header and
2824  // the table is located in the body:
2825  ( !bConsiderWrapOnObjPos || nullptr != pThisHeaderFooterFrame || !pFlyHeaderFooterFrame->IsHeaderFrame() ) )
2826  bConsiderFly = false;
2827  }
2828 
2829  if ( bConsiderFly )
2830  {
2831  const SwFormatSurround &rSur = pFly->GetFormat()->GetSurround();
2832  const SwFormatHoriOrient &rHori= pFly->GetFormat()->GetHoriOrient();
2833  bool bShiftDown = css::text::WrapTextMode_NONE == rSur.GetSurround();
2834  if (!bShiftDown && bAddVerticalFlyOffsets)
2835  {
2836  if (rSur.GetSurround() == text::WrapTextMode_PARALLEL
2838  {
2839  // We know that wrapping was requested and the table frame overlaps with
2840  // the fly frame. Check if the print area overlaps with the fly frame as
2841  // well (in case the table does not use all the available width).
2842  basegfx::B1DRange aTabRange(
2843  aRectFnSet.GetLeft(aRect) + aRectFnSet.GetLeft(getFramePrintArea()),
2844  aRectFnSet.GetLeft(aRect) + aRectFnSet.GetLeft(getFramePrintArea())
2845  + aRectFnSet.GetWidth(getFramePrintArea()));
2846 
2847  // Ignore spacing when determining the left/right edge of the fly, like
2848  // Word does.
2849  const SwRect aFlyRectWithoutSpaces = pFly->GetObjRect();
2850  basegfx::B1DRange aFlyRange(aRectFnSet.GetLeft(aFlyRectWithoutSpaces),
2851  aRectFnSet.GetRight(aFlyRectWithoutSpaces));
2852 
2853  // If it does, shift the table down. Do this only in the compat case,
2854  // normally an SwFlyPortion is created instead that increases the height
2855  // of the first table row.
2856  bShiftDown = aTabRange.overlaps(aFlyRange);
2857  }
2858  }
2859 
2860  if (bShiftDown)
2861  {
2862  // possible cases:
2863  // both in body
2864  // both in same fly
2865  // any comb. of body, footnote, header/footer
2866  // to keep it safe, check only in doc body vs page margin for now
2867  tools::Long nBottom = aRectFnSet.GetBottom(aFlyRect);
2868  // tdf#138039 don't grow beyond the page body
2869  // if the fly is anchored below the table; the fly
2870  // must move with its anchor frame to the next page
2871  SwRectFnSet fnPage(pPage);
2872  if (!IsInDocBody() // TODO
2873  || fnPage.YDiff(fnPage.GetBottom(aFlyRect), fnPage.GetPrtBottom(*pPage)) <= 0
2874  || !IsNextOnSamePage(*pPage, *this,
2875  *static_cast<SwTextFrame*>(pFly->GetAnchorFrameContainingAnchPos())))
2876  {
2877  if (aRectFnSet.YDiff( nPrtPos, nBottom ) < 0)
2878  nPrtPos = nBottom;
2879  bInvalidatePrtArea = true;
2880  }
2881  }
2882  if ( (css::text::WrapTextMode_RIGHT == rSur.GetSurround() ||
2883  css::text::WrapTextMode_PARALLEL == rSur.GetSurround())&&
2884  text::HoriOrientation::LEFT == rHori.GetHoriOrient() )
2885  {
2886  const tools::Long nWidth = aRectFnSet.XDiff(
2887  aRectFnSet.GetRight(aFlyRect),
2888  aRectFnSet.GetLeft(pFly->GetAnchorFrame()->getFrameArea()) );
2889  rLeftOffset = std::max( rLeftOffset, nWidth );
2890  bInvalidatePrtArea = true;
2891  }
2892  if ( (css::text::WrapTextMode_LEFT == rSur.GetSurround() ||
2893  css::text::WrapTextMode_PARALLEL == rSur.GetSurround())&&
2894  text::HoriOrientation::RIGHT == rHori.GetHoriOrient() )
2895  {
2896  const tools::Long nWidth = aRectFnSet.XDiff(
2897  aRectFnSet.GetRight(pFly->GetAnchorFrame()->getFrameArea()),
2898  aRectFnSet.GetLeft(aFlyRect) );
2899  rRightOffset = std::max( rRightOffset, nWidth );
2900  bInvalidatePrtArea = true;
2901  }
2902  }
2903  }
2904  }
2905  rUpper = aRectFnSet.YDiff( nPrtPos, aRectFnSet.GetTop(getFrameArea()) );
2906  }
2907 
2908  return bInvalidatePrtArea;
2909 }
2910 
2913 void SwTabFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs *pAttrs )
2914 {
2915  OSL_ENSURE( pAttrs, "TabFrame::Format, pAttrs is 0." );
2916 
2917  SwRectFnSet aRectFnSet(this);
2918  if ( !isFrameAreaSizeValid() )
2919  {
2920  tools::Long nDiff = aRectFnSet.GetWidth(GetUpper()->getFramePrintArea()) -
2921  aRectFnSet.GetWidth(getFrameArea());
2922  if( nDiff )
2923  {
2925  aRectFnSet.AddRight( aFrm, nDiff );
2926  }
2927  }
2928 
2929  //VarSize is always the height.
2930  //For the upper/lower margins the same rules apply as for ContentFrames (see
2931  //MakePrtArea() of those).
2932 
2933  SwTwips nUpper = CalcUpperSpace( pAttrs );
2934 
2935  // We want to dodge the flys. Two possibilities:
2936  // 1. There are flys with SurroundNone, dodge them completely
2937  // 2. There are flys which only wrap on the right or the left side and
2938  // those are right or left aligned, those set the minimum for the margins
2939  tools::Long nTmpRight = -1000000,
2940  nLeftOffset = 0;
2941  if( CalcFlyOffsets( nUpper, nLeftOffset, nTmpRight ) )
2942  {
2943  setFramePrintAreaValid(false);
2944  }
2945 
2946  tools::Long nRightOffset = std::max( tools::Long(0), nTmpRight );
2947 
2948  SwTwips nLower = pAttrs->CalcBottomLine();
2949  // #i29550#
2950  if ( IsCollapsingBorders() )
2951  nLower += GetBottomLineSize();
2952 
2953  if ( !isFramePrintAreaValid() )
2954  {
2955  setFramePrintAreaValid(true);
2956 
2957  // The width of the PrintArea is given by the FrameFormat, the margins
2958  // have to be set accordingly.
2959  // Minimum margins are determined depending on borders and shadows.
2960  // The margins are set so that the PrintArea is aligned into the
2961  // Frame according to the adjustment.
2962  // If the adjustment is 0, the margins are set according to the border
2963  // attributes.
2964 
2965  const SwTwips nOldHeight = aRectFnSet.GetHeight(getFramePrintArea());
2966  const SwTwips nMax = aRectFnSet.GetWidth(getFrameArea());
2967 
2968  // OD 14.03.2003 #i9040# - adjust variable names.
2969  const SwTwips nLeftLine = pAttrs->CalcLeftLine();
2970  const SwTwips nRightLine = pAttrs->CalcRightLine();
2971 
2972  // The width possibly is a percentage value. If the table is inside
2973  // something else, the value refers to the environment. If it's in the
2974  // body then in the BrowseView the value refers to the screen width.
2975  const SwFormatFrameSize &rSz = GetFormat()->GetFrameSize();
2976  // OD 14.03.2003 #i9040# - adjust variable name.
2977  const SwTwips nWishedTableWidth = CalcRel( rSz );
2978 
2979  bool bCheckBrowseWidth = false;
2980 
2981  // OD 14.03.2003 #i9040# - insert new variables for left/right spacing.
2982  SwTwips nLeftSpacing = 0;
2983  SwTwips nRightSpacing = 0;
2984  switch ( GetFormat()->GetHoriOrient().GetHoriOrient() )
2985  {
2986  case text::HoriOrientation::LEFT:
2987  {
2988  // left indent:
2989  nLeftSpacing = nLeftLine + nLeftOffset;
2990  // OD 06.03.2003 #i9040# - correct calculation of right indent:
2991  // - Consider right indent given by right line attributes.
2992  // - Consider negative right indent.
2993  // wished right indent determined by wished table width and
2994  // left offset given by surround fly frames on the left:
2995  const SwTwips nWishRight = nMax - nWishedTableWidth - nLeftOffset;
2996  if ( nRightOffset > 0 )
2997  {
2998  // surrounding fly frames on the right
2999  // -> right indent is maximum of given right offset
3000  // and wished right offset.
3001  nRightSpacing = nRightLine + std::max( SwTwips(nRightOffset), nWishRight );
3002  }
3003  else
3004  {
3005  // no surrounding fly frames on the right
3006  // If intrinsic right indent (intrinsic means not considering
3007  // determined left indent) is negative,
3008  // then hold this intrinsic indent,
3009  // otherwise non negative wished right indent is hold.
3010  nRightSpacing = nRightLine +
3011  ( ( (nWishRight+nLeftOffset) < 0 ) ?
3012  (nWishRight+nLeftOffset) :
3013  std::max( SwTwips(0), nWishRight ) );
3014  }
3015  }
3016  break;
3017  case text::HoriOrientation::RIGHT:
3018  {
3019  // right indent:
3020  nRightSpacing = nRightLine + nRightOffset;
3021  // OD 06.03.2003 #i9040# - correct calculation of left indent:
3022  // - Consider left indent given by left line attributes.
3023  // - Consider negative left indent.
3024  // wished left indent determined by wished table width and
3025  // right offset given by surrounding fly frames on the right:
3026  const SwTwips nWishLeft = nMax - nWishedTableWidth - nRightOffset;
3027  if ( nLeftOffset > 0 )
3028  {
3029  // surrounding fly frames on the left
3030  // -> right indent is maximum of given left offset
3031  // and wished left offset.
3032  nLeftSpacing = nLeftLine + std::max( SwTwips(nLeftOffset), nWishLeft );
3033  }
3034  else
3035  {
3036  // no surrounding fly frames on the left
3037  // If intrinsic left indent (intrinsic = not considering
3038  // determined right indent) is negative,
3039  // then hold this intrinsic indent,
3040  // otherwise non negative wished left indent is hold.
3041  nLeftSpacing = nLeftLine +
3042  ( ( (nWishLeft+nRightOffset) < 0 ) ?
3043  (nWishLeft+nRightOffset) :
3044  std::max( SwTwips(0), nWishLeft ) );
3045  }
3046  }
3047  break;
3048  case text::HoriOrientation::CENTER:
3049  {
3050  // OD 07.03.2003 #i9040# - consider left/right line attribute.
3051  const SwTwips nCenterSpacing = ( nMax - nWishedTableWidth ) / 2;
3052  nLeftSpacing = nLeftLine +
3053  ( (nLeftOffset > 0) ?
3054  std::max( nCenterSpacing, SwTwips(nLeftOffset) ) :
3055  nCenterSpacing );
3056  nRightSpacing = nRightLine +
3057  ( (nRightOffset > 0) ?
3058  std::max( nCenterSpacing, SwTwips(nRightOffset) ) :
3059  nCenterSpacing );
3060  }
3061  break;
3062  case text::HoriOrientation::FULL:
3063  //This things grows over the whole width.
3064  //Only the free space needed for the border is taken into
3065  //account. The attribute values of LRSpace are ignored
3066  //intentionally.
3067  bCheckBrowseWidth = true;
3068  nLeftSpacing = nLeftLine + nLeftOffset;
3069  nRightSpacing = nRightLine + nRightOffset;
3070  break;
3072  {
3073  // The margins are defined by the LRSpace attribute.
3074  nLeftSpacing = pAttrs->CalcLeft( this );
3075  if( nLeftOffset )
3076  {
3077  // OD 07.03.2003 #i9040# - surround fly frames only, if
3078  // they overlap with the table.
3079  // Thus, take maximum of left spacing and left offset.
3080  // OD 10.03.2003 #i9040# - consider left line attribute.
3081  nLeftSpacing = std::max( nLeftSpacing, SwTwips( nLeftOffset + nLeftLine ) );
3082  }
3083  // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
3084  nRightSpacing = pAttrs->CalcRight( this );
3085  if( nRightOffset )
3086  {
3087  // OD 07.03.2003 #i9040# - surround fly frames only, if
3088  // they overlap with the table.
3089  // Thus, take maximum of right spacing and right offset.
3090  // OD 10.03.2003 #i9040# - consider right line attribute.
3091  nRightSpacing = std::max( nRightSpacing, SwTwips( nRightOffset + nRightLine ) );
3092  }
3093  }
3094  break;
3095  case text::HoriOrientation::LEFT_AND_WIDTH:
3096  {
3097  // count left border and width (Word specialty)
3098  // OD 10.03.2003 #i9040# - no width alignment in online mode.
3099  //bCheckBrowseWidth = true;
3100  nLeftSpacing = pAttrs->CalcLeft( this );
3101  if( nLeftOffset )
3102  {
3103  // OD 10.03.2003 #i9040# - surround fly frames only, if
3104  // they overlap with the table.
3105  // Thus, take maximum of right spacing and right offset.
3106  // OD 10.03.2003 #i9040# - consider left line attribute.
3107  nLeftSpacing = std::max( nLeftSpacing, SwTwips( pAttrs->CalcLeftLine() + nLeftOffset ) );
3108  }
3109  // OD 10.03.2003 #i9040# - consider right and left line attribute.
3110  const SwTwips nWishRight =
3111  nMax - (nLeftSpacing-pAttrs->CalcLeftLine()) - nWishedTableWidth;
3112  nRightSpacing = nRightLine +
3113  ( (nRightOffset > 0) ?
3114  std::max( nWishRight, SwTwips(nRightOffset) ) :
3115  nWishRight );
3116  }
3117  break;
3118  default:
3119  OSL_FAIL( "Invalid orientation for table." );
3120  }
3121 
3122  // #i26250# - extend bottom printing area, if table
3123  // is last content inside a table cell.
3124  if ( GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS) &&
3125  GetUpper()->IsInTab() && !GetIndNext() )
3126  {
3127  nLower += pAttrs->GetULSpace().GetLower();
3128  }
3129  aRectFnSet.SetYMargins( *this, nUpper, nLower );
3130  if( (nMax - MINLAY) < (nLeftSpacing + nRightSpacing) )
3131  aRectFnSet.SetXMargins( *this, 0, 0 );
3132  else
3133  aRectFnSet.SetXMargins( *this, nLeftSpacing, nRightSpacing );
3134 
3136  if ( bCheckBrowseWidth &&
3137  pSh && pSh->GetViewOptions()->getBrowseMode() &&
3138  GetUpper()->IsPageBodyFrame() && // only PageBodyFrames and not ColBodyFrames
3139  pSh->VisArea().Width() )
3140  {
3141  //Don't go beyond the edge of the visible area.
3142  //The page width can be bigger because objects with
3143  //"over-size" are possible (RootFrame::ImplCalcBrowseWidth())
3144  tools::Long nWidth = pSh->GetBrowseWidth();
3145  nWidth -= getFramePrintArea().Left();
3146  nWidth -= pAttrs->CalcRightLine();
3147 
3149  aPrt.Width( std::min( nWidth, aPrt.Width() ) );
3150  }
3151 
3152  if ( nOldHeight != aRectFnSet.GetHeight(getFramePrintArea()) )
3153  {
3154  setFrameAreaSizeValid(false);
3155  }
3156  }
3157 
3158  if ( isFrameAreaSizeValid() )
3159  return;
3160 
3161  setFrameAreaSizeValid(true);
3162 
3163  // The size is defined by the content plus the margins.
3164  SwTwips nRemaining = 0, nDiff;
3165  SwFrame *pFrame = m_pLower;
3166  while ( pFrame )
3167  {
3168  nRemaining += aRectFnSet.GetHeight(pFrame->getFrameArea());
3169  pFrame = pFrame->GetNext();
3170  }
3171  // And now add the margins
3172  nRemaining += nUpper + nLower;
3173 
3174  nDiff = aRectFnSet.GetHeight(getFrameArea()) - nRemaining;
3175  if ( nDiff > 0 )
3176  Shrink( nDiff );
3177  else if ( nDiff < 0 )
3178  Grow( -nDiff );
3179 }
3180 
3181 SwTwips SwTabFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo )
3182 {
3183  SwRectFnSet aRectFnSet(this);
3184  SwTwips nHeight = aRectFnSet.GetHeight(getFrameArea());
3185  if( nHeight > 0 && nDist > ( LONG_MAX - nHeight ) )
3186  nDist = LONG_MAX - nHeight;
3187 
3188  if ( bTst && !IsRestrictTableGrowth() )
3189  return nDist;
3190 
3191  if ( GetUpper() )
3192  {
3193  SwRect aOldFrame( getFrameArea() );
3194 
3195  //The upper only grows as far as needed. nReal provides the distance
3196  //which is already available.
3197  SwTwips nReal = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea());
3198  SwFrame *pFrame = GetUpper()->Lower();
3199  while ( pFrame && GetFollow() != pFrame )
3200  {
3201  nReal -= aRectFnSet.GetHeight(pFrame->getFrameArea());
3202  pFrame = pFrame->GetNext();
3203  }
3204 
3205  if ( nReal < nDist )
3206  {
3207  tools::Long nTmp = GetUpper()->Grow( nDist - std::max<tools::Long>(nReal, 0), bTst, bInfo );
3208 
3209  if ( IsRestrictTableGrowth() )
3210  {
3211  nTmp = std::min( tools::Long(nDist), nReal + nTmp );
3212  nDist = nTmp < 0 ? 0 : nTmp;
3213  }
3214  }
3215 
3216  if ( !bTst )
3217  {
3218  {
3220  aRectFnSet.AddBottom( aFrm, nDist );
3221  }
3222 
3223  SwRootFrame *pRootFrame = getRootFrame();
3224  if( pRootFrame && pRootFrame->IsAnyShellAccessible() &&
3225  pRootFrame->GetCurrShell() )
3226  {
3227  pRootFrame->GetCurrShell()->Imp()->MoveAccessibleFrame( this, aOldFrame );
3228  }
3229  }
3230  }
3231 
3232  if ( !bTst && ( nDist || IsRestrictTableGrowth() ) )
3233  {
3234  SwPageFrame *pPage = FindPageFrame();
3235  if ( GetNext() )
3236  {
3237  GetNext()->InvalidatePos_();
3238  if ( GetNext()->IsContentFrame() )
3239  GetNext()->InvalidatePage( pPage );
3240  }
3241  // #i28701# - Due to the new object positioning the
3242  // frame on the next page/column can flow backward (e.g. it was moved
3243  // forward due to the positioning of its objects ). Thus, invalivate this
3244  // next frame, if document compatibility option 'Consider wrapping style
3245  // influence on object positioning' is ON.
3246  else if ( GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) )
3247  {
3249  }
3250  InvalidateAll_();
3251  InvalidatePage( pPage );
3252  SetComplete();
3253 
3254  std::unique_ptr<SvxBrushItem> aBack = GetFormat()->makeBackgroundBrushItem();
3255  const SvxGraphicPosition ePos = aBack ? aBack->GetGraphicPos() : GPOS_NONE;
3256  if ( GPOS_NONE != ePos && GPOS_TILED != ePos )
3257  SetCompletePaint();
3258  }
3259 
3260  return nDist;
3261 }
3262 
3263 void SwTabFrame::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
3264 {
3265  auto pLegacy = dynamic_cast<const sw::LegacyModifyHint*>(&rHint);
3266  if(!pLegacy)
3267  return;
3268  sal_uInt8 nInvFlags = 0;
3269  bool bAttrSetChg = pLegacy->m_pNew && RES_ATTRSET_CHG == pLegacy->m_pNew->Which();
3270 
3271  if(bAttrSetChg)
3272  {
3273  auto& rOldSetChg = *static_cast<const SwAttrSetChg*>(pLegacy->m_pOld);
3274  auto& rNewSetChg = *static_cast<const SwAttrSetChg*>(pLegacy->m_pNew);
3275  SfxItemIter aOIter(*rOldSetChg.GetChgSet());
3276  SfxItemIter aNIter(*rNewSetChg.GetChgSet());
3277  const SfxPoolItem* pOItem = aOIter.GetCurItem();
3278  const SfxPoolItem* pNItem = aNIter.GetCurItem();
3279  SwAttrSetChg aOldSet(rOldSetChg);
3280  SwAttrSetChg aNewSet(rNewSetChg);
3281  do
3282  {
3283  UpdateAttr_(pOItem, pNItem, nInvFlags, &aOldSet, &aNewSet);
3284  pNItem = aNIter.NextItem();
3285  pOItem = aOIter.NextItem();
3286  } while(pNItem);
3287  if(aOldSet.Count() || aNewSet.Count())
3288  SwLayoutFrame::SwClientNotify(rMod, sw::LegacyModifyHint(&aOldSet, &aNewSet));
3289  }
3290  else
3291  UpdateAttr_(pLegacy->m_pOld, pLegacy->m_pNew, nInvFlags);
3292 
3293  if(nInvFlags == 0)
3294  return;
3295 
3296  SwPageFrame* pPage = FindPageFrame();
3297  InvalidatePage(pPage);
3298  if(nInvFlags & 0x02)
3299  InvalidatePrt_();
3300  if(nInvFlags & 0x40)
3301  InvalidatePos_();
3302  SwFrame* pTmp = GetIndNext();
3303  if(nullptr != pTmp)
3304  {
3305  if(nInvFlags & 0x04)
3306  {
3307  pTmp->InvalidatePrt_();
3308  if(pTmp->IsContentFrame())
3309  pTmp->InvalidatePage(pPage);
3310  }
3311  if(nInvFlags & 0x10)
3312  pTmp->SetCompletePaint();
3313  }
3314  if(nInvFlags & 0x08 && nullptr != (pTmp = GetPrev()))
3315  {
3316  pTmp->InvalidatePrt_();
3317  if(pTmp->IsContentFrame())
3318  pTmp->InvalidatePage( pPage );
3319  }
3320  if(nInvFlags & 0x20)
3321  {
3322  if(pPage && pPage->GetUpper() && !IsFollow())
3323  static_cast<SwRootFrame*>(pPage->GetUpper())->InvalidateBrowseWidth();
3324  }
3325  if(nInvFlags & 0x80)
3327 }
3328 
3329 void SwTabFrame::UpdateAttr_( const SfxPoolItem *pOld, const SfxPoolItem *pNew,
3330  sal_uInt8 &rInvFlags,
3331  SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet )
3332 {
3333  bool bClear = true;
3334  const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
3335  switch( nWhich )
3336  {
3337  case RES_TBLHEADLINECHG:
3338  if ( IsFollow() )
3339  {
3340  // Delete remaining headlines:
3341  SwRowFrame* pLowerRow = nullptr;
3342  while ( nullptr != ( pLowerRow = static_cast<SwRowFrame*>(Lower()) ) && pLowerRow->IsRepeatedHeadline() )
3343  {
3344  pLowerRow->Cut();
3345  SwFrame::DestroyFrame(pLowerRow);
3346  }
3347 
3348  // insert new headlines
3349  const sal_uInt16 nNewRepeat = GetTable()->GetRowsToRepeat();
3350  for ( sal_uInt16 nIdx = 0; nIdx < nNewRepeat; ++nIdx )
3351  {
3352  bDontCreateObjects = true; //frmtool
3353  SwRowFrame* pHeadline = new SwRowFrame( *GetTable()->GetTabLines()[ nIdx ], this );
3354  pHeadline->SetRepeatedHeadline( true );
3355  bDontCreateObjects = false;
3356  pHeadline->Paste( this, pLowerRow );
3357  }
3358  }
3359  rInvFlags |= 0x02;
3360  break;
3361 
3362  case RES_FRM_SIZE:
3363  case RES_HORI_ORIENT:
3364  rInvFlags |= 0x22;
3365  break;
3366 
3367  case RES_PAGEDESC: //Attribute changes (on/off)
3368  if ( IsInDocBody() )
3369  {
3370  rInvFlags |= 0x40;
3371  SwPageFrame *pPage = FindPageFrame();
3372  if (pPage)
3373  {
3374  if ( !GetPrev() )
3375  CheckPageDescs( pPage );
3376  if (GetFormat()->GetPageDesc().GetNumOffset())
3377  static_cast<SwRootFrame*>(pPage->GetUpper())->SetVirtPageNum( true );
3378  SwDocPosUpdate aMsgHint( pPage->getFrameArea().Top() );
3380  }
3381  }
3382  break;
3383 
3384  case RES_BREAK:
3385  rInvFlags |= 0xC0;
3386  break;
3387 
3388  case RES_LAYOUT_SPLIT:
3389  if ( !IsFollow() )
3390  rInvFlags |= 0x40;
3391  break;
3392  case RES_FRAMEDIR :
3393  SetDerivedR2L( false );
3394  CheckDirChange();
3395  break;
3396  case RES_COLLAPSING_BORDERS :
3397  rInvFlags |= 0x02;
3399  break;
3400  case RES_UL_SPACE:
3401  rInvFlags |= 0x1C;
3402  [[fallthrough]];
3403 
3404  default:
3405  bClear = false;
3406  }
3407  if ( !bClear )
3408  return;
3409 
3410  if ( pOldSet || pNewSet )
3411  {
3412  if ( pOldSet )
3413  pOldSet->ClearItem( nWhich );
3414  if ( pNewSet )
3415  pNewSet->ClearItem( nWhich );
3416  }
3417  else
3418  {
3419  SwModify aMod;
3421  }
3422 }
3423 
3424 bool SwTabFrame::GetInfo( SfxPoolItem &rHint ) const
3425 {
3426  if ( RES_VIRTPAGENUM_INFO == rHint.Which() && IsInDocBody() && !IsFollow() )
3427  {
3428  SwVirtPageNumInfo &rInfo = static_cast<SwVirtPageNumInfo&>(rHint);
3429  const SwPageFrame *pPage = FindPageFrame();
3430  if ( pPage )
3431  {
3432  if ( pPage == rInfo.GetOrigPage() && !GetPrev() )
3433  {
3434  // Should be the one (can temporarily be different, should we be
3435  // concerned about this possibility?)
3436  rInfo.SetInfo( pPage, this );
3437  return false;
3438  }
3439  if ( pPage->GetPhyPageNum() < rInfo.GetOrigPage()->GetPhyPageNum() &&
3440  (!rInfo.GetPage() || pPage->GetPhyPageNum() > rInfo.GetPage()->GetPhyPageNum()))
3441  {
3442  //This could be the one.
3443  rInfo.SetInfo( pPage, this );
3444  }
3445  }
3446  }
3447  return true;
3448 }
3449 
3451 {
3452  SwFrame *pRet = m_pLower;
3453 
3454  while ( pRet && !pRet->IsContentFrame() )
3455  {
3456  SwFrame *pOld = pRet;
3457 
3458  SwFrame *pTmp = pRet; // To skip empty section frames
3459  while ( pRet->GetNext() )
3460  {
3461  pRet = pRet->GetNext();
3462  if( !pRet->IsSctFrame() || static_cast<SwSectionFrame*>(pRet)->GetSection() )
3463  pTmp = pRet;
3464  }
3465  pRet = pTmp;
3466 
3467  if ( pRet->GetLower() )
3468  pRet = pRet->GetLower();
3469  if ( pRet == pOld )
3470  {
3471  // Check all other columns if there is a column based section with
3472  // an empty last column at the end of the last cell - this is done
3473  // by SwSectionFrame::FindLastContent
3474  if( pRet->IsColBodyFrame() )
3475  {
3476 #if OSL_DEBUG_LEVEL > 0
3477  SwSectionFrame* pSect = pRet->FindSctFrame();
3478  OSL_ENSURE( pSect, "Where does this column come from?");
3479  OSL_ENSURE( IsAnLower( pSect ), "Split cell?" );
3480 #endif
3481  return pRet->FindSctFrame()->FindLastContent();
3482  }
3483 
3484  // pRet may be a cell frame without a lower (cell has been split).
3485  // We have to find the last content the hard way:
3486 
3487  OSL_ENSURE( pRet->IsCellFrame(), "SwTabFrame::FindLastContent failed" );
3488  const SwFrame* pRow = pRet->GetUpper();
3489  while ( pRow && !pRow->GetUpper()->IsTabFrame() )
3490  pRow = pRow->GetUpper();
3491  const SwContentFrame* pContentFrame = pRow ? static_cast<const SwLayoutFrame*>(pRow)->ContainsContent() : nullptr;
3492  pRet = nullptr;
3493 
3494  while ( pContentFrame && static_cast<const SwLayoutFrame*>(pRow)->IsAnLower( pContentFrame ) )
3495  {
3496  pRet = const_cast<SwContentFrame*>(pContentFrame);
3497  pContentFrame = pContentFrame->GetNextContentFrame();
3498  }
3499  }
3500  }
3501 
3502  // #112929# There actually is a situation, which results in pRet = 0:
3503  // Insert frame, insert table via text <-> table. This gives you a frame
3504  // containing a table without any other content frames. Split the table
3505  // and undo the splitting. This operation gives us a table frame without
3506  // a lower.
3507  if ( pRet )
3508  {
3509  while ( pRet->GetNext() )
3510  pRet = pRet->GetNext();
3511 
3512  if (pRet->IsSctFrame())
3513  pRet = static_cast<SwSectionFrame*>(pRet)->FindLastContent();
3514  }
3515 
3516  assert(pRet == nullptr || dynamic_cast<SwContentFrame*>(pRet) || dynamic_cast<SwTabFrame*>(pRet));
3517  return pRet;
3518 }
3519 
3521 {
3522  SwFrame * pRet(FindLastContentOrTable());
3523 
3524  while (pRet && pRet->IsTabFrame()) // possibly there's only tables here!
3525  { // tdf#126138 skip table, don't look inside
3526  pRet = pRet->GetPrev();
3527  }
3528 
3529  assert(pRet == nullptr || dynamic_cast<SwContentFrame*>(pRet));
3530  return static_cast<SwContentFrame*>(pRet);
3531 }
3532 
3534 bool SwTabFrame::ShouldBwdMoved( SwLayoutFrame *pNewUpper, bool &rReformat )
3535 {
3536  rReformat = false;
3538  {
3539  //Flowing back Frames is quite time consuming unfortunately.
3540  //Most often the location where the Frame wants to flow to has the same
3541  //FixSize as the Frame itself. In such a situation it's easy to check if
3542  //the Frame will find enough space for its VarSize, if this is not the
3543  //case, the relocation can be skipped.
3544  //Checking if the Frame will find enough space is done by the Frame itself,
3545  //this also takes the possibility of splitting the Frame into account.
3546  //If the FixSize is different or Flys are involved (at the old or the
3547  //new position) the checks are pointless, the Frame then
3548  //needs to be relocated tentatively (if a bit of space is available).
3549 
3550  //The FixSize of the environments which contain tables is always the
3551  //width.
3552 
3553  SwPageFrame *pOldPage = FindPageFrame(),
3554  *pNewPage = pNewUpper->FindPageFrame();
3555  bool bMoveAnyway = false;
3556  SwTwips nSpace = 0;
3557 
3558  SwRectFnSet aRectFnSet(this);
3559  if ( !SwFlowFrame::IsMoveBwdJump() )
3560  {
3561 
3562  tools::Long nOldWidth = aRectFnSet.GetWidth(GetUpper()->getFramePrintArea());
3563  SwRectFnSet fnRectX(pNewUpper);
3564  tools::Long nNewWidth = fnRectX.GetWidth(pNewUpper->getFramePrintArea());
3565  if( std::abs( nNewWidth - nOldWidth ) < 2 )
3566  {
3567  bMoveAnyway = BwdMoveNecessary( pOldPage, getFrameArea() ) > 1;
3568  if( !bMoveAnyway )
3569  {
3570  SwRect aRect( pNewUpper->getFramePrintArea() );
3571  aRect.Pos() += pNewUpper->getFrameArea().Pos();
3572  const SwFrame *pPrevFrame = pNewUpper->Lower();
3573  while ( pPrevFrame && pPrevFrame != this )
3574  {
3575  fnRectX.SetTop( aRect, fnRectX.GetBottom(pPrevFrame->getFrameArea()) );
3576  pPrevFrame = pPrevFrame->GetNext();
3577  }
3578  bMoveAnyway = BwdMoveNecessary( pNewPage, aRect) > 1;
3579 
3580  // #i54861# Due to changes made in PrepareMake,
3581  // the tabfrm may not have a correct position. Therefore
3582  // it is possible that pNewUpper->getFramePrintArea().Height == 0. In this
3583  // case the above calculation of nSpace might give wrong
3584  // results and we really do not want to MoveBackward into a
3585  // 0 height frame. If nTmpSpace is already <= 0, we take this
3586  // value:
3587  const SwTwips nTmpSpace = fnRectX.GetHeight(aRect);
3588  if ( fnRectX.GetHeight(pNewUpper->getFramePrintArea()) > 0 || nTmpSpace <= 0 )
3589  nSpace = nTmpSpace;
3590 
3591  const SwViewShell *pSh = getRootFrame()->GetCurrShell();
3592  if( pSh && pSh->GetViewOptions()->getBrowseMode() )
3593  nSpace += pNewUpper->Grow( LONG_MAX, true );
3594  }
3595  }
3596  else if (!m_bLockBackMove)
3597  bMoveAnyway = true;
3598  }
3599  else if (!m_bLockBackMove)
3600  bMoveAnyway = true;
3601 
3602  if ( bMoveAnyway )
3603  {
3604  rReformat = true;
3605  return true;
3606  }
3607 
3608  bool bFits = nSpace > 0;
3609  if (!bFits && aRectFnSet.GetHeight(getFrameArea()) == 0)
3610  // This frame fits into pNewUpper in case it has no space, but this
3611  // frame is empty.
3612  bFits = nSpace >= 0;
3613  if (!m_bLockBackMove && bFits)
3614  {
3615  // #i26945# - check, if follow flow line
3616  // contains frame, which are moved forward due to its object
3617  // positioning.
3618  const SwRowFrame* pFirstRow = GetFirstNonHeadlineRow();
3619  if ( pFirstRow && pFirstRow->IsInFollowFlowRow() &&
3621  *(pFirstRow->GetFormat()->GetDoc()),
3622  *pFirstRow ) )
3623  {
3624  return false;
3625  }
3626  SwTwips nTmpHeight = CalcHeightOfFirstContentLine();
3627 
3628  // For some mysterious reason, I changed the good old
3629  // 'return nHeight <= nSpace' to 'return nTmpHeight < nSpace'.
3630  // This obviously results in problems with table frames in
3631  // sections. Remember: Every twip is sacred.
3632  return nTmpHeight <= nSpace;
3633  }
3634  }
3635  return false;
3636 }
3637 
3639 {
3640  OSL_ENSURE( GetUpper(), "Cut without Upper()." );
3641 
3642  SwPageFrame *pPage = FindPageFrame();
3643  InvalidatePage( pPage );
3644  SwFrame *pFrame = GetNext();
3645  if( pFrame )
3646  {
3647  // Possibly the old follow calculated a spacing to the predecessor
3648  // which is obsolete now when it becomes the first frame
3649  pFrame->InvalidatePrt_();
3650  pFrame->InvalidatePos_();
3651  if ( pFrame->IsContentFrame() )
3652  pFrame->InvalidatePage( pPage );
3653  if( IsInSct() && !GetPrev() )
3654  {
3655  SwSectionFrame* pSct = FindSctFrame();
3656  if( !pSct->IsFollow() )
3657  {
3658  pSct->InvalidatePrt_();
3659  pSct->InvalidatePage( pPage );
3660  }
3661  }
3662  }
3663  else
3664  {
3666  //Someone has to do the retouch: predecessor or upper
3667  pFrame = GetPrev();
3668  if ( nullptr != pFrame )
3669  {
3670  pFrame->SetRetouche();
3672  pFrame->InvalidatePos_();
3673  if ( pFrame->IsContentFrame() )
3674  pFrame->InvalidatePage( pPage );
3675  }
3676  //If I am (was) the only FlowFrame in my own upper, it has to do
3677  //the retouch. Moreover a new empty page might be created.
3678  else
3679  { SwRootFrame *pRoot = static_cast<SwRootFrame*>(pPage->GetUpper());
3680  pRoot->SetSuperfluous();
3682  if( IsInSct() )
3683  {
3684  SwSectionFrame* pSct = FindSctFrame();
3685  if( !pSct->IsFollow() )
3686  {
3687  pSct->InvalidatePrt_();
3688  pSct->InvalidatePage( pPage );
3689  }
3690  }
3691  }
3692  }
3693 
3694  //First remove, then shrink the upper.
3695  SwLayoutFrame *pUp = GetUpper();
3696  SwRectFnSet aRectFnSet(this);
3697  RemoveFromLayout();
3698  if ( pUp )
3699  {
3700  OSL_ENSURE( !pUp->IsFootnoteFrame(), "Table in Footnote." );
3701  SwSectionFrame *pSct = nullptr;
3702  // #126020# - adjust check for empty section
3703  // #130797# - correct fix #126020#
3704  if ( !pUp->Lower() && pUp->IsInSct() &&
3705  !(pSct = pUp->FindSctFrame())->ContainsContent() &&
3706  !pSct->ContainsAny( true ) )
3707  {
3708  if ( pUp->GetUpper() )
3709  {
3710  pSct->DelEmpty( false );
3711  pSct->InvalidateSize_();
3712  }
3713  }
3714  // table-in-footnote: delete empty footnote frames (like SwContentFrame::Cut)
3715  else if (!pUp->Lower() && pUp->IsFootnoteFrame() && !pUp->IsColLocked())
3716  {
3717  if (pUp->GetNext() && !pUp->GetPrev())
3718  {
3719  if (SwFrame *const pTmp = static_cast<SwLayoutFrame*>(pUp->GetNext())->ContainsAny())
3720  {
3721  pTmp->InvalidatePrt_();
3722  }
3723  }
3724  if (!pUp->IsDeleteForbidden())
3725  {
3726  pUp->Cut();
3727  SwFrame::DestroyFrame(pUp);
3728  }
3729  }
3730  else if( aRectFnSet.GetHeight(getFrameArea()) )
3731  {
3732  // OD 26.08.2003 #i18103# - *no* 'ColUnlock' of section -
3733  // undo changes of fix for #104992#
3734  pUp->Shrink( getFrameArea().Height() );
3735  }
3736  }
3737 
3738 
3739  if ( pPage && !IsFollow() && pPage->GetUpper() )
3740  static_cast<SwRootFrame*>(pPage->GetUpper())->InvalidateBrowseWidth();
3741 }
3742 
3743 void SwTabFrame::Paste( SwFrame* pParent, SwFrame* pSibling )
3744 {
3745  OSL_ENSURE( pParent, "No parent for pasting." );
3746  OSL_ENSURE( pParent->IsLayoutFrame(), "Parent is ContentFrame." );
3747  OSL_ENSURE( pParent != this, "I'm the parent myself." );
3748  OSL_ENSURE( pSibling != this, "I'm my own neighbour." );
3749  OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(),
3750  "I'm still registered somewhere." );
3751 
3752  //Insert in the tree.
3753  InsertBefore( static_cast<SwLayoutFrame*>(pParent), pSibling );
3754 
3755  InvalidateAll_();
3756  SwPageFrame *pPage = FindPageFrame();
3757  InvalidatePage( pPage );
3758 
3759  if ( GetNext() )
3760  {
3761  GetNext()->InvalidatePos_();
3762  GetNext()->InvalidatePrt_();
3763  if ( GetNext()->IsContentFrame() )
3764  GetNext()->InvalidatePage( pPage );
3765  }
3766 
3767  SwRectFnSet aRectFnSet(this);
3768  if( aRectFnSet.GetHeight(getFrameArea()) )
3769  pParent->Grow( aRectFnSet.GetHeight(getFrameArea()) );
3770 
3771  if( aRectFnSet.GetWidth(getFrameArea()) != aRectFnSet.GetWidth(pParent->getFramePrintArea()) )
3773  if ( GetPrev() )
3774  {
3775  if ( !IsFollow() )
3776  {
3777  GetPrev()->InvalidateSize();
3778  if ( GetPrev()->IsContentFrame() )
3779  GetPrev()->InvalidatePage( pPage );
3780  }
3781  }
3782  else if ( GetNext() )
3783  // Take the spacing into account when dealing with ContentFrames.
3784  // There are two situations (both always happen at the same time):
3785  // a) The Content becomes the first in a chain
3786  // b) The new follower was previously the first in a chain
3787  GetNext()->InvalidatePrt_();
3788 
3789  if ( !pPage || IsFollow() )
3790  return;
3791 
3792  if ( pPage->GetUpper() )
3793  static_cast<SwRootFrame*>(pPage->GetUpper())->InvalidateBrowseWidth();
3794 
3795  if ( !GetPrev() )//At least needed for HTML with a table at the beginning.
3796  {
3798  if ( (pDesc && pDesc != pPage->GetPageDesc()) ||
3799  (!pDesc && pPage->GetPageDesc() != &GetFormat()->GetDoc()->GetPageDesc(0)) )
3800  CheckPageDescs( pPage );
3801  }
3802 }
3803 
3804 bool SwTabFrame::Prepare( const PrepareHint eHint, const void *, bool )
3805 {
3806  if( PrepareHint::BossChanged == eHint )
3807  CheckDirChange();
3808  return false;
3809 }
3810 
3811 SwRowFrame::SwRowFrame(const SwTableLine &rLine, SwFrame* pSib, bool bInsertContent)
3812  : SwLayoutFrame( rLine.GetFrameFormat(), pSib )
3813  , m_pTabLine( &rLine )
3814  , m_pFollowRow( nullptr )
3815  // #i29550#
3816  , mnTopMarginForLowers( 0 )
3817  , mnBottomMarginForLowers( 0 )
3818  , mnBottomLineSize( 0 )
3819  // --> split table rows
3820  , m_bIsFollowFlowRow( false )
3821  // <-- split table rows
3822  , m_bIsRepeatedHeadline( false )
3823  , m_bIsRowSpanLine( false )
3824  , m_bForceRowSplitAllowed( false )
3825  , m_bIsInSplit( false )
3826 {
3828 
3829  //Create the boxes and insert them.
3830  const SwTableBoxes &rBoxes = rLine.GetTabBoxes();
3831  SwFrame *pTmpPrev = nullptr;
3832  for ( size_t i = 0; i < rBoxes.size(); ++i )
3833  {
3834  SwCellFrame *pNew = new SwCellFrame( *rBoxes[i], this, bInsertContent );
3835  pNew->InsertBehind( this, pTmpPrev );
3836  pTmpPrev = pNew;
3837  }
3838 }
3839 
3841 {
3843  if( pMod )
3844  {
3845  pMod->Remove( this );
3846  if( !pMod->HasWriterListeners() )
3847  delete pMod;
3848  }
3849 
3851 }
3852 
3854 {
3855 }
3856 
3858 {
3859  ::RegistFlys( pPage ? pPage : FindPageFrame(), this );
3860 }
3861 
3863 {
3864  SwTabFrame* pTab = FindTabFrame();
3865  if(pTab)
3866  {
3867  const bool bInFirstNonHeadlineRow = pTab->IsFollow() && this == pTab->GetFirstNonHeadlineRow();
3868  // #i35063#
3869  // Invalidation required is pRow is last row
3870  if(bInFirstNonHeadlineRow)
3871  pTab = pTab->FindMaster();
3872  if(bInFirstNonHeadlineRow || !GetNext())
3873  pTab->InvalidatePos();
3874  }
3875  const sw::BroadcastingModify aMod;
3876  SwLayoutFrame::SwClientNotify(aMod, sw::LegacyModifyHint(nullptr, &rSize));
3877 }
3878 
3879 void SwRowFrame::SwClientNotify(const SwModify& rModify, const SfxHint& rHint)
3880 {
3881  if(auto pMoveTableLineHint = dynamic_cast<const sw::MoveTableLineHint*>(&rHint))
3882  {
3883 
3884  if(GetTabLine() != &pMoveTableLineHint->m_rTableLine)
3885  return;
3886  const_cast<SwFrameFormat*>(&pMoveTableLineHint->m_rNewFormat)->Add(this);
3887  InvalidateAll();
3889  return;
3890  }
3891  auto pLegacy = dynamic_cast<const sw::LegacyModifyHint*>(&rHint);
3892  if(!pLegacy)
3893  return;
3894  if(!pLegacy->m_pNew)
3895  {
3896  // possibly not needed?
3897  SwLayoutFrame::SwClientNotify(rModify, rHint);
3898  return;
3899  }
3900  switch(pLegacy->m_pNew->Which())
3901  {
3902  case RES_ATTRSET_CHG:
3903  {
3904  const SwAttrSet* pChgSet = static_cast<const SwAttrSetChg*>(pLegacy->m_pNew)->GetChgSet();
3905  const SfxPoolItem* pItem = nullptr;
3906  pChgSet->GetItemState(RES_FRM_SIZE, false, &pItem);
3907  if(!pItem)
3908  pChgSet->GetItemState(RES_ROW_SPLIT, false, &pItem);
3909  if(pItem)
3910  OnFrameSize(*pItem);
3911  else
3912  SwLayoutFrame::SwClientNotify(rModify, rHint); // possibly not needed?
3913  return;
3914  }
3915  case RES_FRM_SIZE:
3916  case RES_ROW_SPLIT:
3917  OnFrameSize(*static_cast<const SwFormatFrameSize*>(pLegacy->m_pNew));
3918  return;
3919  }
3920 }
3921 
3923 {
3924  if ( !GetNext() )
3925  {
3926  setFrameAreaSizeValid(false);
3927  }
3928 
3929  SwLayoutFrame::MakeAll(pRenderContext);
3930 }
3931 
3933 {
3934  SwRectFnSet aRectFnSet(pFrame);
3935  tools::Long nHeight = 0;
3936  const SwFrame* pTmp = pFrame->IsSctFrame() ?
3937  static_cast<const SwSectionFrame*>(pFrame)->ContainsContent() : pFrame;
3938  while( pTmp )
3939  {
3940  // #i26945# - consider follow text frames
3941  const SwSortedObjs* pObjs( nullptr );
3942  bool bIsFollow( false );
3943  if ( pTmp->IsTextFrame() && static_cast<const SwTextFrame*>(pTmp)->IsFollow() )
3944  {
3945  const SwFrame* pMaster;
3946  // #i46450# Master does not necessarily have
3947  // to exist if this function is called from JoinFrame() ->
3948  // Cut() -> Shrink()
3949  const SwTextFrame* pTmpFrame = static_cast<const SwTextFrame*>(pTmp);
3950  if ( pTmpFrame->GetPrev() && pTmpFrame->GetPrev()->IsTextFrame() &&
3951  static_cast<const SwTextFrame*>(pTmpFrame->GetPrev())->GetFollow() &&
3952  static_cast<const SwTextFrame*>(pTmpFrame->GetPrev())->GetFollow() != pTmp )
3953  pMaster = nullptr;
3954  else
3955  pMaster = pTmpFrame->FindMaster();
3956 
3957  if ( pMaster )
3958  {
3959  pObjs = static_cast<const SwTextFrame*>(pTmp)->FindMaster()->GetDrawObjs();
3960  bIsFollow = true;
3961  }
3962  }
3963  else
3964  {
3965  pObjs = pTmp->GetDrawObjs();
3966  }
3967  if ( pObjs )
3968  {
3969  for (SwAnchoredObject* pAnchoredObj : *pObjs)
3970  {
3971  // #i26945# - if <pTmp> is follow, the
3972  // anchor character frame has to be <pTmp>.
3973  if ( bIsFollow &&
3974  pAnchoredObj->FindAnchorCharFrame() != pTmp )
3975  {
3976  continue;
3977  }
3978  // #i26945# - consider also drawing objects
3979  {
3980  // OD 30.09.2003 #i18732# - only objects, which follow
3981  // the text flow have to be considered.
3982  const SwFrameFormat& rFrameFormat = pAnchoredObj->GetFrameFormat();
3983  bool bFollowTextFlow = rFrameFormat.GetFollowTextFlow().GetValue();
3984  bool bIsFarAway = pAnchoredObj->GetObjRect().Top() != FAR_AWAY;
3985  const SwPageFrame* pPageFrm = pTmp->FindPageFrame();
3986  bool bIsAnchoredToTmpFrm = false;
3987  if ( pPageFrm && pPageFrm->IsPageFrame() && pAnchoredObj->GetPageFrame())
3988  bIsAnchoredToTmpFrm = pAnchoredObj->GetPageFrame() == pPageFrm ||
3989  (pPageFrm->GetFormatPage().GetPhyPageNum() == pAnchoredObj->GetPageFrame()->GetFormatPage().GetPhyPageNum() + 1);
3990  const bool bConsiderObj =
3991  (rFrameFormat.GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR) &&
3992  bIsFarAway &&
3993  bFollowTextFlow && bIsAnchoredToTmpFrm;
3994  bool bWrapThrough = rFrameFormat.GetSurround().GetValue() == text::WrapTextMode_THROUGH;
3995  if (pFrame->IsInTab() && bFollowTextFlow && bWrapThrough)
3996  {
3997  // Ignore wrap-through objects when determining the cell height.
3998  // Normally FollowTextFlow requires a resize of the cell, but not in case of
3999  // wrap-through.
4000  continue;
4001  }
4002 
4003  if ( bConsiderObj )
4004  {
4005  const SwFormatFrameSize &rSz = rFrameFormat.GetFrameSize();
4006  if( !rSz.GetHeightPercent() )
4007  {
4008  const SwTwips nDistOfFlyBottomToAnchorTop =
4009  aRectFnSet.GetHeight(pAnchoredObj->GetObjRect()) +
4010  ( aRectFnSet.IsVert() ?
4011  pAnchoredObj->GetCurrRelPos().X() :
4012  pAnchoredObj->GetCurrRelPos().Y() );
4013 
4014  const SwTwips nFrameDiff =
4015  aRectFnSet.YDiff(
4016  aRectFnSet.GetTop(pTmp->getFrameArea()),
4017  aRectFnSet.GetTop(pFrame->getFrameArea()) );
4018 
4019  nHeight = std::max( nHeight, nDistOfFlyBottomToAnchorTop + nFrameDiff -
4020  aRectFnSet.GetHeight(pFrame->getFrameArea()) );
4021 
4022  // #i56115# The first height calculation
4023  // gives wrong results if pFrame->getFramePrintArea().Y() > 0. We do
4024  // a second calculation based on the actual rectangles of
4025  // pFrame and pAnchoredObj, and use the maximum of the results.
4026  // I do not want to remove the first calculation because
4027  // if clipping has been applied, using the GetCurrRelPos
4028  // might be the better option to calculate nHeight.
4029  const SwTwips nDistOfFlyBottomToAnchorTop2 = aRectFnSet.YDiff(
4030  aRectFnSet.GetBottom(pAnchoredObj->GetObjRect()),
4031  aRectFnSet.GetBottom(pFrame->getFrameArea()) );
4032 
4033  nHeight = std::max( nHeight, tools::Long(nDistOfFlyBottomToAnchorTop2 ));
4034  }
4035  }
4036  }
4037  }
4038  }
4039  if( !pFrame->IsSctFrame() )
4040  break;
4041  pTmp = pTmp->FindNextCnt();
4042  if( !static_cast<const SwSectionFrame*>(pFrame)->IsAnLower( pTmp ) )
4043  break;
4044  }
4045  return nHeight;
4046 }
4047 
4048 static SwTwips lcl_CalcTopAndBottomMargin( const SwLayoutFrame& rCell, const SwBorderAttrs& rAttrs )
4049 {
4050  const SwTabFrame* pTab = rCell.FindTabFrame();
4051  SwTwips nTopSpace = 0;
4052  SwTwips nBottomSpace = 0;
4053 
4054  // #i29550#
4055  if ( pTab->IsCollapsingBorders() && rCell.Lower() && !rCell.Lower()->IsRowFrame() )
4056  {
4057  nTopSpace = static_cast<const SwRowFrame*>(rCell.GetUpper())->GetTopMarginForLowers();
4058  nBottomSpace = static_cast<const SwRowFrame*>(rCell.GetUpper())->GetBottomMarginForLowers();
4059  }
4060  else
4061  {
4062  if ( pTab->IsVertical() != rCell.IsVertical() )
4063  {
4064  nTopSpace = rAttrs.CalcLeft( &rCell );
4065  nBottomSpace = rAttrs.CalcRight( &rCell );
4066  }
4067  else
4068  {
4069  nTopSpace = rAttrs.CalcTop();
4070  nBottomSpace = rAttrs.CalcBottom();
4071  }
4072  }
4073 
4074  return nTopSpace + nBottomSpace;
4075 }
4076 
4077 // #i26945# - add parameter <_bConsiderObjs> in order to
4078 // control, if floating screen objects have to be considered for the minimal
4079 // cell height.
4081  const bool _bConsiderObjs,
4082  const SwBorderAttrs *pAttrs = nullptr )
4083 {
4084  SwRectFnSet aRectFnSet(_pCell);
4085  SwTwips nHeight = 0;
4086  const SwFrame* pLow = _pCell->Lower();
4087  if ( pLow )
4088  {
4089  tools::Long nFlyAdd = 0;
4090  while ( pLow )
4091  {
4092  if ( pLow->IsRowFrame() )
4093  {
4094  // #i26945#
4095  nHeight += ::lcl_CalcMinRowHeight( static_cast<const SwRowFrame*>(pLow),
4096  _bConsiderObjs );
4097  }
4098  else
4099  {
4100  tools::Long nLowHeight = aRectFnSet.GetHeight(pLow->getFrameArea());
4101  nHeight += nLowHeight;
4102  // #i26945#
4103  if ( _bConsiderObjs )
4104  {
4105  nFlyAdd = std::max( tools::Long(0), nFlyAdd - nLowHeight );
4106  nFlyAdd = std::max( nFlyAdd, ::CalcHeightWithFlys( pLow ) );
4107  }
4108  }
4109 
4110  pLow = pLow->GetNext();
4111  }
4112  if ( nFlyAdd )
4113  nHeight += nFlyAdd;
4114  }
4115  // The border/margin needs to be considered too, unfortunately it can't be
4116  // calculated using PrintArea and FrameArea because any or all of those
4117  // may be invalid.
4118  if ( _pCell->Lower() )
4119  {
4120  if ( pAttrs )
4121  nHeight += lcl_CalcTopAndBottomMargin( *_pCell, *pAttrs );
4122  else
4123  {
4124  SwBorderAttrAccess aAccess( SwFrame::GetCache(), _pCell );
4125  const SwBorderAttrs &rAttrs = *aAccess.Get();
4126  nHeight += lcl_CalcTopAndBottomMargin( *_pCell, rAttrs );
4127  }
4128  }
4129  return nHeight;
4130 }
4131 
4132 // #i26945# - add parameter <_bConsiderObjs> in order to control,
4133 // if floating screen objects have to be considered for the minimal cell height
4135  const bool _bConsiderObjs )
4136 {
4137  SwTwips nHeight = 0;
4138  if ( !_pRow->IsRowSpanLine() )
4139  {
4140  const SwFormatFrameSize &rSz = _pRow->GetFormat()->GetFrameSize();
4141  if ( _pRow->HasFixSize() )
4142  {
4143  OSL_ENSURE(SwFrameSize::Fixed == rSz.GetHeightSizeType(), "pRow claims to have fixed size");
4144  return rSz.GetHeight();
4145  }
4146  // If this row frame is being split, then row's minimal height shouldn't restrict
4147  // this frame's minimal height, because the rest will go to follow frame.
4148  else if ( !_pRow->IsInSplit() && rSz.GetHeightSizeType() == SwFrameSize::Minimum )
4149  {
4150  nHeight = rSz.GetHeight() - lcl_calcHeightOfRowBeforeThisFrame(*_pRow);
4151  }
4152  }
4153 
4154  SwRectFnSet aRectFnSet(_pRow);
4155  const SwCellFrame* pLow = static_cast<const SwCellFrame*>(_pRow->Lower());
4156  while ( pLow )
4157  {
4158  SwTwips nTmp = 0;
4159  const tools::Long nRowSpan = pLow->GetLayoutRowSpan();
4160  // --> NEW TABLES
4161  // Consider height of
4162  // 1. current cell if RowSpan == 1
4163  // 2. current cell if cell is "follow" cell of a cell with RowSpan == -1
4164  // 3. master cell if RowSpan == -1
4165  if ( 1 == nRowSpan )
4166  {
4167  nTmp = ::lcl_CalcMinCellHeight( pLow, _bConsiderObjs );
4168  }
4169  else if ( -1 == nRowSpan )
4170  {
4171  // Height of the last cell of a row span is height of master cell
4172  // minus the height of the other rows which are covered by the master
4173  // cell:
4174  const SwCellFrame& rMaster = pLow->FindStartEndOfRowSpanCell( true );
4175  nTmp = ::lcl_CalcMinCellHeight( &rMaster, _bConsiderObjs );
4176  const SwFrame* pMasterRow = rMaster.GetUpper();
4177  while ( pMasterRow && pMasterRow != _pRow )
4178  {
4179  nTmp -= aRectFnSet.GetHeight(pMasterRow->getFrameArea());
4180  pMasterRow = pMasterRow->GetNext();
4181  }
4182  }
4183  // <-- NEW TABLES
4184 
4185  // Do not consider rotated cells:
4186  if ( pLow->IsVertical() == aRectFnSet.IsVert() && nTmp > nHeight )
4187  nHeight = nTmp;
4188 
4189  pLow = static_cast<const SwCellFrame*>(pLow->GetNext());
4190  }
4191 
4192  return nHeight;
4193 }
4194 
4195 // #i29550#
4196 
4197 // Calculate the maximum of (TopLineSize + TopLineDist) over all lowers:
4198 static sal_uInt16 lcl_GetTopSpace( const SwRowFrame& rRow )
4199 {
4200  sal_uInt16 nTopSpace = 0;
4201  for ( const SwCellFrame* pCurrLower = static_cast<const SwCellFrame*>(rRow.Lower()); pCurrLower;
4202  pCurrLower = static_cast<const SwCellFrame*>(pCurrLower->GetNext()) )
4203  {
4204  sal_uInt16 nTmpTopSpace = 0;
4205  if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrame() )
4206  nTmpTopSpace = lcl_GetTopSpace( *static_cast<const SwRowFrame*>(pCurrLower->Lower()) );
4207  else
4208  {
4209  const SwAttrSet& rSet = const_cast<SwCellFrame*>(pCurrLower)->GetFormat()->GetAttrSet();
4210  const SvxBoxItem& rBoxItem = rSet.GetBox();
4211  nTmpTopSpace = rBoxItem.CalcLineSpace( SvxBoxItemLine::TOP, true );
4212  }
4213  nTopSpace = std::max( nTopSpace, nTmpTopSpace );
4214  }
4215  return nTopSpace;
4216 }
4217 
4218 // Calculate the maximum of TopLineDist over all lowers:
4219 static sal_uInt16 lcl_GetTopLineDist( const SwRowFrame& rRow )
4220 {
4221  sal_uInt16 nTopLineDist = 0;
4222  for ( const SwCellFrame* pCurrLower = static_cast<const SwCellFrame*>(rRow.Lower()); pCurrLower;
4223  pCurrLower = static_cast<const SwCellFrame*>(pCurrLower->GetNext()) )
4224  {
4225  sal_uInt16 nTmpTopLineDist = 0;
4226  if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrame() )
4227  nTmpTopLineDist = lcl_GetTopLineDist( *static_cast<const SwRowFrame*>(pCurrLower->Lower()) );
4228  else
4229  {
4230  const SwAttrSet& rSet = const_cast<SwCellFrame*>(pCurrLower)->GetFormat()->GetAttrSet();
4231  const SvxBoxItem& rBoxItem = rSet.GetBox();
4232  nTmpTopLineDist = rBoxItem.GetDistance( SvxBoxItemLine::TOP );
4233  }
4234  nTopLineDist = std::max( nTopLineDist, nTmpTopLineDist );
4235  }
4236  return nTopLineDist;
4237 }
4238 
4239 // Calculate the maximum of BottomLineSize over all lowers:
4240 static sal_uInt16 lcl_GetBottomLineSize( const SwRowFrame& rRow )
4241 {
4242  sal_uInt16 nBottomLineSize = 0;
4243  for ( const SwCellFrame* pCurrLower = static_cast<const SwCellFrame*>(rRow.Lower()); pCurrLower;
4244  pCurrLower = static_cast<const SwCellFrame*>(pCurrLower->GetNext()) )
4245  {
4246  sal_uInt16 nTmpBottomLineSize = 0;
4247  if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrame() )
4248  {
4249  const SwFrame* pRow = pCurrLower->GetLastLower();
4250  nTmpBottomLineSize = lcl_GetBottomLineSize( *static_cast<const SwRowFrame*>(pRow) );
4251  }
4252  else
4253  {
4254  const SwAttrSet& rSet = const_cast<SwCellFrame*>(pCurrLower)->GetFormat()->GetAttrSet();
4255  const SvxBoxItem& rBoxItem = rSet.GetBox();
4256  nTmpBottomLineSize = rBoxItem.CalcLineSpace( SvxBoxItemLine::BOTTOM, true ) -
4257  rBoxItem.GetDistance( SvxBoxItemLine::BOTTOM );
4258  }
4259  nBottomLineSize = std::max( nBottomLineSize, nTmpBottomLineSize );
4260  }
4261  return nBottomLineSize;
4262 }
4263 
4264 // Calculate the maximum of BottomLineDist over all lowers:
4265 static sal_uInt16 lcl_GetBottomLineDist( const SwRowFrame& rRow )
4266 {
4267  sal_uInt16 nBottomLineDist = 0;
4268  for ( const SwCellFrame* pCurrLower = static_cast<const SwCellFrame*>(rRow.Lower()); pCurrLower;
4269  pCurrLower = static_cast<const SwCellFrame*>(pCurrLower->GetNext()) )
4270  {
4271  sal_uInt16 nTmpBottomLineDist = 0;
4272  if ( pCurrLower->Lower() && pCurrLower->Lower()->IsRowFrame() )
4273  {
4274  const SwFrame* pRow = pCurrLower->GetLastLower();
4275  nTmpBottomLineDist = lcl_GetBottomLineDist( *static_cast<const SwRowFrame*>(pRow) );
4276  }
4277  else
4278  {
4279  const SwAttrSet& rSet = const_cast<SwCellFrame*>(pCurrLower)->GetFormat()->GetAttrSet();
4280  const SvxBoxItem& rBoxItem = rSet.GetBox();
4281  nTmpBottomLineDist = rBoxItem.GetDistance( SvxBoxItemLine::BOTTOM );
4282  }
4283  nBottomLineDist = std::max( nBottomLineDist, nTmpBottomLineDist );
4284  }
4285  return nBottomLineDist;
4286 }
4287 
4288 // tdf#104425: calculate the height of all row frames,
4289 // for which this frame is a follow.
4290 // When a row has fixed/minimum height, it may span over
4291 // several pages. The minimal height on this page should
4292 // take into account the sum of all the heights of previous
4293 // frames that constitute the table row on previous pages.
4294 // Otherwise, trying to split a too high row frame will
4295 // result in loop trying to create that too high row
4296 // on each following page
4298 {
4299  // We don't need to account for previous instances of repeated headlines
4300  if (rRow.IsRepeatedHeadline())
4301  return 0;
4302  SwRectFnSet aRectFnSet(&rRow);
4303  const SwTableLine* pLine = rRow.GetTabLine();
4304  const SwTabFrame* pTab = rRow.FindTabFrame();
4305  if (!pLine || !pTab || !pTab->IsFollow())
4306  return 0;
4307  SwTwips nResult = 0;
4309  for (const SwRowFrame* pCurRow = aIter.First(); pCurRow; pCurRow = aIter.Next())
4310  {
4311  if (pCurRow != &rRow && pCurRow->GetTabLine() == pLine)
4312  {
4313  // We've found another row frame that is part of the same table row
4314  const SwTabFrame* pCurTab = pCurRow->FindTabFrame();
4315  // A row frame may not belong to a table frame, when it is being cut, e.g., in
4316  // lcl_PostprocessRowsInCells().
4317  // Its SwRowFrame::Cut() has been called; it in turn called SwLayoutFrame::Cut(),
4318  // which nullified row's upper in RemoveFromLayout(), and then called Shrink()
4319  // for its former upper.
4320  // Regardless of whether it will be pasted back, or destroyed, currently it's not
4321  // part of layout, and its height does not count
4322  if (pCurTab && pCurTab->IsAnFollow(pTab))
4323  {
4324  // The found row frame belongs to a table frame that precedes
4325  // (above) this one in chain. So, include it in the sum
4326  nResult += aRectFnSet.GetHeight(pCurRow->getFrameArea());
4327  }
4328  }
4329  }
4330  return nResult;
4331 }
4332 
4333 void SwRowFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs *pAttrs )
4334 {
4335  SwRectFnSet aRectFnSet(this);
4336  OSL_ENSURE( pAttrs, "SwRowFrame::Format without Attrs." );
4337 
4338  const bool bFix = mbFixSize;
4339 
4340  if ( !isFramePrintAreaValid() )
4341  {
4342  // RowFrames don't have borders/margins therefore the PrintArea always
4343  // matches the FrameArea.
4344  setFramePrintAreaValid(true);
4345 
4346  {
4348  aPrt.Left( 0 );
4349  aPrt.Top( 0 );
4350  aPrt.Width ( getFrameArea().Width() );
4351  aPrt.Height( getFrameArea().Height() );
4352  }
4353 
4354  // #i29550#
4355  // Here we calculate the top-printing area for the lower cell frames
4356  SwTabFrame* pTabFrame = FindTabFrame();
4357  if ( pTabFrame->IsCollapsingBorders() )
4358  {
4359  const sal_uInt16 nTopSpace = lcl_GetTopSpace( *this );
4360  const sal_uInt16 nTopLineDist = lcl_GetTopLineDist( *this );
4361  const sal_uInt16 nBottomLineSize = lcl_GetBottomLineSize( *this );
4362  const sal_uInt16 nBottomLineDist = lcl_GetBottomLineDist( *this );
4363 
4364  const SwRowFrame* pPreviousRow = nullptr;
4365 
4366  // #i32456#
4367  // In order to calculate the top printing area for the lower cell
4368  // frames, we have to find the 'previous' row frame and compare
4369  // the bottom values of the 'previous' row with the 'top' values
4370  // of this row. The best way to find the 'previous' row is to
4371  // use the table structure:
4372  const SwTable* pTable = pTabFrame->GetTable();
4373  const SwTableLine* pPrevTabLine = nullptr;
4374  const SwRowFrame* pTmpRow = this;
4375 
4376  while ( pTmpRow && !pPrevTabLine )
4377  {
4378  size_t nIdx = 0;
4379  const SwTableLines& rLines = pTmpRow->GetTabLine()->GetUpper() ?
4380  pTmpRow->GetTabLine()->GetUpper()->GetTabLines() :
4381  pTable->GetTabLines();
4382 
4383  while ( rLines[ nIdx ] != pTmpRow->GetTabLine() )
4384  ++nIdx;
4385 
4386  if ( nIdx > 0 )
4387  {
4388  // pTmpRow has a 'previous' row in the table structure:
4389  pPrevTabLine = rLines[ nIdx - 1 ];
4390  }
4391  else
4392  {
4393  // pTmpRow is a first row in the table structure.
4394  // We go up in the table structure:
4395  pTmpRow = pTmpRow->GetUpper()->GetUpper() &&
4396  pTmpRow->GetUpper()->GetUpper()->IsRowFrame() ?
4397  static_cast<const SwRowFrame*>( pTmpRow->GetUpper()->GetUpper() ) :
4398  nullptr;
4399  }
4400  }
4401 
4402  // If we found a 'previous' row, we look for the appropriate row frame:
4403  if ( pPrevTabLine )
4404  {
4405  SwIterator<SwRowFrame,SwFormat> aIter( *pPrevTabLine->GetFrameFormat() );
4406  for ( SwRowFrame* pRow = aIter.First(); pRow; pRow = aIter.Next() )
4407  {
4408  // #115759# - do *not* take repeated
4409  // headlines, because during split of table it can be
4410  // invalid and thus can't provide correct border values.
4411  if ( pRow->GetTabLine() == pPrevTabLine &&
4412  !pRow->IsRepeatedHeadline() )
4413  {
4414  pPreviousRow = pRow;
4415  break;
4416  }
4417  }
4418  }
4419 
4420  sal_uInt16 nTopPrtMargin = nTopSpace;
4421  if ( pPreviousRow )
4422  {
4423  const sal_uInt16 nTmpPrtMargin = pPreviousRow->GetBottomLineSize() + nTopLineDist;
4424  if ( nTmpPrtMargin > nTopPrtMargin )
4425  nTopPrtMargin = nTmpPrtMargin;
4426  }
4427 
4428  // table has to be notified if it has to change its lower
4429  // margin due to changes of nBottomLineSize:
4430  if ( !GetNext() && nBottomLineSize != GetBottomLineSize() )
4431  pTabFrame->InvalidatePrt_();
4432 
4433  // If there are rows nested inside this row, the nested rows
4434  // may not have been calculated yet. Therefore the
4435  // ::lcl_CalcMinRowHeight( this ) operation later in this
4436  // function cannot consider the correct border values. We
4437  // have to trigger the invalidation of the outer row frame
4438  // manually:
4439  // Note: If any further invalidations should be necessary, we
4440  // should consider moving the invalidation stuff to the
4441  // appropriate SwNotify object.
4442  if ( GetUpper()->GetUpper()->IsRowFrame() &&
4443  ( nBottomLineDist != GetBottomMarginForLowers() ||
4444  nTopPrtMargin != GetTopMarginForLowers() ) )
4446 
4447  SetBottomMarginForLowers( nBottomLineDist ); // 3.
4448  SetBottomLineSize( nBottomLineSize ); // 4.
4449  SetTopMarginForLowers( nTopPrtMargin ); // 5.
4450 
4451  }
4452  }
4453 
4454  while ( !isFrameAreaSizeValid() )
4455  {
4456  setFrameAreaSizeValid(true);
4457 
4458 #if OSL_DEBUG_LEVEL > 0
4459  if ( HasFixSize() )
4460  {
4461  const SwFormatFrameSize &rFrameSize = GetFormat()->GetFrameSize();
4462  OSL_ENSURE( rFrameSize.GetSize().Height() > 0, "Has it" );
4463  }
4464 #endif
4465  const SwTwips nDiff = aRectFnSet.GetHeight(getFrameArea()) -
4466  ( HasFixSize() && !IsRowSpanLine()
4467  ? pAttrs->GetSize().Height()
4468  // #i26945#
4469  : ::lcl_CalcMinRowHeight( this,
4470  FindTabFrame()->IsConsiderObjsForMinCellHeight() ) );
4471  if ( nDiff )
4472  {
4473  mbFixSize = false;
4474  if ( nDiff > 0 )
4475  Shrink( nDiff, false, true );
4476  else if ( nDiff < 0 )
4477  Grow( -nDiff );
4478  mbFixSize = bFix;
4479  }
4480  }
4481 
4482  // last row will fill the space in its upper.
4483  if ( GetNext() )
4484  return;
4485 
4486  //The last fills the remaining space in the upper.
4487  SwTwips nDiff = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea());
4488  SwFrame *pSibling = GetUpper()->Lower();
4489  do
4490  { nDiff -= aRectFnSet.GetHeight(pSibling->getFrameArea());
4491  pSibling = pSibling->GetNext();
4492  } while ( pSibling );
4493  if ( nDiff > 0 )
4494  {
4495  mbFixSize = false;
4496  Grow( nDiff );
4497  mbFixSize = bFix;
4498  setFrameAreaSizeValid(true);
4499  }
4500 }
4501 
4502 void SwRowFrame::AdjustCells( const SwTwips nHeight, const bool bHeight )
4503 {
4504  SwFrame *pFrame = Lower();
4505  if ( bHeight )
4506  {
4507  SwRootFrame *pRootFrame = getRootFrame();
4508  SwRectFnSet aRectFnSet(this);
4509  SwRect aOldFrame;
4510 
4511  while ( pFrame )
4512  {
4513  SwFrame* pNotify = nullptr;
4514 
4515  SwCellFrame* pCellFrame = static_cast<SwCellFrame*>(pFrame);
4516 
4517  // NEW TABLES
4518  // Which cells need to be adjusted if the current row changes
4519  // its height?
4520 
4521  // Current frame is a covered frame:
4522  // Set new height for covered cell and adjust master cell:
4523  if ( pCellFrame->GetTabBox()->getRowSpan() < 1 )
4524  {
4525  // Set height of current (covered) cell to new line height.
4526  const tools::Long nDiff = nHeight - aRectFnSet.GetHeight(pCellFrame->getFrameArea());
4527  if ( nDiff )
4528  {
4529  {
4531  aRectFnSet.AddBottom( aFrm, nDiff );
4532  }
4533 
4534  pCellFrame->InvalidatePrt_();
4535  }
4536  }
4537 
4538  SwCellFrame* pToAdjust = nullptr;
4539  SwFrame* pToAdjustRow = nullptr;
4540 
4541  // If current frame is covered frame, we still want to adjust the
4542  // height of the cell starting the row span
4543  if ( pCellFrame->GetLayoutRowSpan() < 1 )
4544  {
4545  pToAdjust = const_cast< SwCellFrame*>(&pCellFrame->FindStartEndOfRowSpanCell( true ));
4546  pToAdjustRow = pToAdjust->GetUpper();
4547  }
4548  else
4549  {
4550  pToAdjust = pCellFrame;
4551  pToAdjustRow = this;
4552  }
4553 
4554  // Set height of master cell to height of all lines spanned by this line.
4555  tools::Long nRowSpan = pToAdjust->GetLayoutRowSpan();
4556  SwTwips nSumRowHeight = 0;
4557  while ( pToAdjustRow )
4558  {
4559  // Use new height for the current row:
4560  nSumRowHeight += pToAdjustRow == this ?
4561  nHeight :
4562  aRectFnSet.GetHeight(pToAdjustRow->getFrameArea());
4563 
4564  if ( nRowSpan-- == 1 )
4565  break;
4566 
4567  pToAdjustRow = pToAdjustRow->GetNext();
4568  }
4569 
4570  if ( pToAdjustRow && pToAdjustRow != this )
4571  pToAdjustRow->InvalidateSize_();
4572 
4573  const tools::Long nDiff = nSumRowHeight - aRectFnSet.GetHeight(pToAdjust->getFrameArea());
4574  if ( nDiff )
4575  {
4576  aOldFrame = pToAdjust->getFrameArea();
4578  aRectFnSet.AddBottom( aFrm, nDiff );
4579  pNotify = pToAdjust;
4580  }
4581 
4582  if ( pNotify )
4583  {
4584  if( pRootFrame && pRootFrame->IsAnyShellAccessible() && pRootFrame->GetCurrShell() )
4585  pRootFrame->GetCurrShell()->Imp()->MoveAccessibleFrame( pNotify, aOldFrame );
4586 
4587  pNotify->InvalidatePrt_();
4588  }
4589 
4590  pFrame = pFrame->GetNext();
4591  }
4592  }
4593  else
4594  { while ( pFrame )
4595  {
4596  pFrame->InvalidateAll_();
4597  pFrame = pFrame->GetNext();
4598  }
4599  }
4600  InvalidatePage();
4601 }
4602 
4604 {
4605  SwTabFrame *pTab = FindTabFrame();
4606  if ( pTab && pTab->IsFollow() && this == pTab->GetFirstNonHeadlineRow() )
4607  {
4608  pTab->FindMaster()->InvalidatePos();
4609  }
4610 
4612 }
4613 
4614 SwTwips SwRowFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo )
4615 {
4616  SwTwips nReal = 0;
4617 
4618  SwTabFrame* pTab = FindTabFrame();
4619  SwRectFnSet aRectFnSet(pTab);
4620 
4621  bool bRestrictTableGrowth;
4622  bool bHasFollowFlowLine = pTab->HasFollowFlowLine();
4623 
4624  if ( GetUpper()->IsTabFrame() )
4625  {
4626  const SwRowFrame* pFollowFlowRow = IsInSplitTableRow();
4627  bRestrictTableGrowth = pFollowFlowRow && !pFollowFlowRow->IsRowSpanLine();
4628  }
4629  else
4630  {
4631  OSL_ENSURE( GetUpper()->IsCellFrame(), "RowFrame->GetUpper neither table nor cell" );
4632  bRestrictTableGrowth = GetFollowRow() && bHasFollowFlowLine;
4633  OSL_ENSURE( !bRestrictTableGrowth || !GetNext(),
4634  "GetFollowRow for row frame that has a Next" );
4635 
4636  // There may still be some space left in my direct upper:
4637  const SwTwips nAdditionalSpace =
4638  aRectFnSet.BottomDist( getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()->GetUpper()) );
4639  if ( bRestrictTableGrowth && nAdditionalSpace > 0 )
4640  {
4641  nReal = std::min( nAdditionalSpace, nDist );
4642  nDist -= nReal;
4643  if ( !bTst )
4644  {
4646  aRectFnSet.AddBottom( aFrm, nReal );
4647  }
4648  }
4649  }
4650 
4651  if ( bRestrictTableGrowth )
4652  pTab->SetRestrictTableGrowth( true );
4653  else
4654  {
4655  // Ok, this looks like a hack, indeed, it is a hack.
4656  // If the current row frame is inside another cell frame,
4657  // and the current row frame has no follow, it should not
4658  // be allowed to grow. In fact, setting bRestrictTableGrowth
4659  // to 'false' does not work, because the surrounding RowFrame
4660  // would set this to 'true'.
4661  pTab->SetFollowFlowLine( false );
4662  }
4663 
4664  nReal += SwLayoutFrame::GrowFrame( nDist, bTst, bInfo);
4665 
4666  pTab->SetRestrictTableGrowth( false );
4667  pTab->SetFollowFlowLine( bHasFollowFlowLine );
4668 
4669  //Update the height of the cells to the newest value.
4670  if ( !bTst )
4671  {
4672  SwRectFnSet fnRectX(this);
4673  AdjustCells( fnRectX.GetHeight(getFramePrintArea()) + nReal, true );
4674  if ( nReal )
4675  SetCompletePaint();
4676  }
4677 
4678  return nReal;
4679 }
4680 
4681 SwTwips SwRowFrame::ShrinkFrame( SwTwips nDist, bool bTst, bool bInfo )
4682 {
4683  SwRectFnSet aRectFnSet(this);
4684  if( HasFixSize() )
4685  {
4686  AdjustCells( aRectFnSet.GetHeight(getFramePrintArea()), true );
4687  return 0;
4688  }
4689 
4690  // bInfo may be set to true by SwRowFrame::Format; we need to handle this
4691  // here accordingly
4692  const bool bShrinkAnyway = bInfo;
4693 
4694  //Only shrink as much as the content of the biggest cell allows.
4695  SwTwips nRealDist = nDist;
4696  SwFormat* pMod = GetFormat();
4697  if (pMod)
4698  {
4699  const SwFormatFrameSize &rSz = pMod->GetFrameSize();
4700  SwTwips nMinHeight = 0;
4702  nMinHeight = std::max(rSz.GetHeight() - lcl_calcHeightOfRowBeforeThisFrame(*this),
4703  tools::Long(0));
4704 
4705  // Only necessary to calculate minimal row height if height
4706  // of pRow is at least nMinHeight. Otherwise nMinHeight is the
4707  // minimum height.
4708  if( nMinHeight < aRectFnSet.GetHeight(getFrameArea()) )
4709  {
4710  // #i26945#
4711  OSL_ENSURE( FindTabFrame(), "<SwRowFrame::ShrinkFrame(..)> - no table frame -> crash." );
4712  const bool bConsiderObjs( FindTabFrame()->IsConsiderObjsForMinCellHeight() );
4713  nMinHeight = lcl_CalcMinRowHeight( this, bConsiderObjs );
4714  }
4715 
4716  if ( (aRectFnSet.GetHeight(getFrameArea()) - nRealDist) < nMinHeight )
4717  nRealDist = aRectFnSet.GetHeight(getFrameArea()) - nMinHeight;
4718  }
4719  if ( nRealDist < 0 )
4720  nRealDist = 0;
4721 
4722  SwTwips nReal = nRealDist;
4723  if ( nReal )
4724  {
4725  if ( !bTst )
4726  {
4727  SwTwips nHeight = aRectFnSet.GetHeight(getFrameArea());
4729  aRectFnSet.SetHeight( aFrm, nHeight - nReal );
4730 
4731  if( IsVertical() && !IsVertLR() )
4732  {
4733  aFrm.Pos().AdjustX(nReal );
4734  }
4735  }
4736 
4737  SwLayoutFrame* pFrame = GetUpper();
4738  SwTwips nTmp = pFrame ? pFrame->Shrink(nReal, bTst) : 0;
4739  if ( !bShrinkAnyway && !GetNext() && nTmp != nReal )
4740  {
4741  //The last one gets the leftover in the upper and therefore takes
4742  //care (otherwise: endless loop)
4743  if ( !bTst )
4744  {
4745  nReal -= nTmp;
4746  SwTwips nHeight = aRectFnSet.GetHeight(getFrameArea());
4748  aRectFnSet.SetHeight( aFrm, nHeight + nReal );
4749 
4750  if( IsVertical() && !IsVertLR() )
4751  {
4752  aFrm.Pos().AdjustX( -nReal );
4753  }
4754  }
4755  nReal = nTmp;
4756  }
4757  }
4758 
4759  // Invalidate appropriately and update the height to the newest value.
4760  if ( !bTst )
4761  {
4762  if ( nReal )
4763  {
4764  if ( GetNext() )
4765  GetNext()->InvalidatePos_();
4766  InvalidateAll_();
4767  SetCompletePaint();
4768 
4769  SwTabFrame *pTab = FindTabFrame();
4770  if ( !pTab->IsRebuildLastLine()
4771  && pTab->IsFollow()
4772  && this == pTab->GetFirstNonHeadlineRow()
4773  && !pTab->IsInRecalcLowerRow() )
4774  {
4775  SwTabFrame* pMasterTab = pTab->FindMaster();
4776  pMasterTab->InvalidatePos();
4777  }
4778  }
4779  AdjustCells( aRectFnSet.GetHeight(getFramePrintArea()) - nReal, true );
4780  }
4781  return nReal;
4782 }
4783 
4785 {
4786  // Fixed size rows are never allowed to split:
4787  if ( HasFixSize() )
4788  {
4789  OSL_ENSURE( SwFrameSize::Fixed == GetFormat()->GetFrameSize().GetHeightSizeType(), "pRow claims to have fixed size" );
4790  return false;
4791  }
4792 
4793  // Repeated headlines are never allowed to split:
4794  const SwTabFrame* pTabFrame = FindTabFrame();
4795  if ( pTabFrame->GetTable()->GetRowsToRepeat() > 0 &&
4796  pTabFrame->IsInHeadline( *this ) )
4797  return false;
4798 
4799  if ( IsForceRowSplitAllowed() )
4800  return true;
4801 
4802  const SwTableLineFormat* pFrameFormat = static_cast<SwTableLineFormat*>(GetTabLine()->GetFrameFormat());
4803  const SwFormatRowSplit& rLP = pFrameFormat->GetRowSplit();
4804  return rLP.GetValue();
4805 }
4806 
4807 bool SwRowFrame::ShouldRowKeepWithNext( const bool bCheckParents ) const
4808 {
4809  // No KeepWithNext if nested in another table
4810  if ( GetUpper()->GetUpper()->IsCellFrame() )
4811  return false;
4812 
4813  const SwCellFrame* pCell = static_cast<const SwCellFrame*>(Lower());
4814  const SwFrame* pText = pCell->Lower();
4815 
4816  return pText && pText->IsTextFrame() &&
4817  static_cast<const SwTextFrame*>(pText)->GetTextNodeForParaProps()->GetSwAttrSet().GetKeep(bCheckParents).GetValue();
4818 }
4819 
4820 SwCellFrame::SwCellFrame(const SwTableBox &rBox, SwFrame* pSib, bool bInsertContent)
4821  : SwLayoutFrame( rBox.GetFrameFormat(), pSib )
4822  , m_pTabBox( &rBox )
4823 {
4825 
4826  if ( !bInsertContent )
4827  return;
4828 
4829  //If a StartIdx is available, ContentFrames are added in the cell, otherwise
4830  //Rows have to be present and those are added.
4831  if ( rBox.GetSttIdx() )
4832  {
4833  sal_uLong nIndex = rBox.GetSttIdx();
4834  ::InsertCnt_( this, rBox.GetFrameFormat()->GetDoc(), ++nIndex );
4835  }
4836  else
4837  {
4838  const SwTableLines &rLines = rBox.GetTabLines();
4839  SwFrame *pTmpPrev = nullptr;
4840  for ( size_t i = 0; i < rLines.size(); ++i )
4841  {
4842  SwRowFrame *pNew = new SwRowFrame( *rLines[i], this, bInsertContent );
4843  pNew->InsertBehind( this, pTmpPrev );
4844  pTmpPrev = pNew;
4845  }
4846  }
4847 }
4848 
4850 {
4852  if( pMod )
4853  {
4854  // At this stage the lower frames aren't destroyed already,
4855  // therefore we have to do a recursive dispose.
4856  SwRootFrame *pRootFrame = getRootFrame();
4857  if( pRootFrame && pRootFrame->IsAnyShellAccessible() &&
4858  pRootFrame->GetCurrShell() )
4859  {
4860  pRootFrame->GetCurrShell()->Imp()->DisposeAccessibleFrame( this, true );
4861  }
4862 
4863  pMod->Remove( this );
4864  if( !pMod->HasWriterListeners() )
4865  delete pMod;
4866  }
4867 
4869 }
4870 
4872 {
4873 }
4874 
4875 static bool lcl_ArrangeLowers( SwLayoutFrame *pLay, tools::Long lYStart, bool bInva )
4876 {
4877  bool bRet = false;
4878  SwFrame *pFrame = pLay->Lower();
4879  SwRectFnSet aRectFnSet(pLay);
4880  while ( pFrame )
4881  {
4882  tools::Long nFrameTop = aRectFnSet.GetTop(pFrame->getFrameArea());
4883  if( nFrameTop != lYStart )
4884  {
4885  bRet = true;
4886  const tools::Long lDiff = aRectFnSet.YDiff( lYStart, nFrameTop );
4887  const tools::Long lDiffX = lYStart - nFrameTop;
4888 
4889  {
4891  aRectFnSet.SubTop( aFrm, -lDiff );
4892  aRectFnSet.AddBottom( aFrm, lDiff );
4893  }
4894 
4895  pFrame->SetCompletePaint();
4896 
4897  if ( !pFrame->GetNext() )
4898  pFrame->SetRetouche();
4899  if( bInva )
4901  if ( pFrame->IsLayoutFrame() && static_cast<SwLayoutFrame*>(pFrame)->Lower() )
4902  lcl_ArrangeLowers( static_cast<SwLayoutFrame*>(pFrame),
4903  aRectFnSet.GetTop(static_cast<SwLayoutFrame*>(pFrame)->Lower()->getFrameArea())
4904  + lDiffX, bInva );
4905  if ( pFrame->GetDrawObjs() )
4906  {
4907  for ( size_t i = 0; i < pFrame->GetDrawObjs()->size(); ++i )
4908  {
4909  SwAnchoredObject* pAnchoredObj = (*pFrame->GetDrawObjs())[i];
4910  // #i26945# - check, if anchored object
4911  // is lower of layout frame by checking, if the anchor
4912  // frame, which contains the anchor position, is a lower
4913  // of the layout frame.
4914  if ( !pLay->IsAnLower( pAnchoredObj->GetAnchorFrameContainingAnchPos() ) )
4915  {
4916  continue;
4917  }
4918  // #i52904# - distinguish between anchored
4919  // objects, whose vertical position depends on its anchor
4920  // frame and whose vertical position is independent
4921  // from its anchor frame.
4922  bool bVertPosDepOnAnchor( true );
4923  {
4924  SwFormatVertOrient aVert( pAnchoredObj->GetFrameFormat().GetVertOrient() );
4925  switch ( aVert.GetRelationOrient() )
4926  {
4927  case text::RelOrientation::PAGE_FRAME:
4928  case text::RelOrientation::PAGE_PRINT_AREA:
4929  bVertPosDepOnAnchor = false;
4930  break;
4931  default: break;
4932  }
4933  }
4934  if ( auto pFly = dynamic_cast<SwFlyFrame *>( pAnchoredObj ) )
4935  {
4936 
4937  // OD 2004-05-18 #i28701# - no direct move of objects,
4938  // which are anchored to-paragraph/to-character, if
4939  // the wrapping style influence has to be considered
4940  // on the object positioning.
4941  // #i52904# - no direct move of objects,
4942  // whose vertical position doesn't depend on anchor frame.
4943  const bool bDirectMove =
4944  FAR_AWAY != pFly->getFrameArea().Top() &&
4945  bVertPosDepOnAnchor &&
4946  !pFly->ConsiderObjWrapInfluenceOnObjPos();
4947  if ( bDirectMove )
4948  {
4949  {
4951  aRectFnSet.SubTop( aFrm, -lDiff );
4952  aRectFnSet.AddBottom( aFrm, lDiff );
4953  }
4954 
4955  pFly->GetVirtDrawObj()->SetRectsDirty();
4956  // --> OD 2004-08-17 - also notify view of <SdrObject>
4957  // instance, which represents the Writer fly frame in
4958  // the drawing layer
4959  pFly->GetVirtDrawObj()->SetChanged();
4960  // #i58280#
4961  pFly->InvalidateObjRectWithSpaces();
4962  }
4963 
4964  if ( pFly->IsFlyInContentFrame() )
4965  {
4966  static_cast<SwFlyInContentFrame*>(pFly)->AddRefOfst( lDiff );
4967  // #115759# - reset current relative
4968  // position to get re-positioned, if not directly moved.
4969  if ( !bDirectMove )
4970  {
4971  pAnchoredObj->SetCurrRelPos( Point( 0, 0 ) );
4972  }
4973  }
4974  else if( pFly->IsAutoPos() )
4975  {
4976  pFly->AddLastCharY( lDiff );
4977  // OD 2004-05-18 #i28701# - follow-up of #i22341#
4978  // <mnLastTopOfLine> has also been adjusted.
4979  pFly->AddLastTopOfLineY( lDiff );
4980  }
4981  // #i26945# - re-registration at
4982  // page frame of anchor frame, if table frame isn't
4983  // a follow table and table frame isn't in its
4984  // rebuild of last line.
4985  const SwTabFrame* pTabFrame = pLay->FindTabFrame();
4986  // - save: check, if table frame is found.
4987  if ( pTabFrame &&
4988  !( pTabFrame->IsFollow() &&
4989  pTabFrame->FindMaster()->IsRebuildLastLine() ) &&
4990  pFly->IsFlyFreeFrame() )
4991  {
4992  SwPageFrame* pPageFrame = pFly->GetPageFrame();
4993  SwPageFrame* pPageOfAnchor = pFrame->FindPageFrame();
4994  if ( pPageFrame != pPageOfAnchor )
4995  {
4996  pFly->InvalidatePos();
4997  if ( pPageFrame )
4998  pPageFrame->MoveFly( pFly, pPageOfAnchor );
4999  else
5000  pPageOfAnchor->AppendFlyToPage( pFly );
5001  }
5002  }
5003  // OD 2004-05-11 #i28701# - Because of the introduction
5004  // of new positionings and alignments (e.g. aligned at
5005  // page area, but anchored at-character), the position
5006  // of the Writer fly frame has to be invalidated.
5007  pFly->InvalidatePos();
5008 
5009  // #i26945# - follow-up of #i3317#
5010  // No arrangement of lowers, if Writer fly frame isn't
5011  // moved
5012  if ( bDirectMove &&
5013  ::lcl_ArrangeLowers( pFly,
5014  aRectFnSet.GetPrtTop(*pFly),
5015  bInva ) )
5016  {
5017  pFly->SetCompletePaint();
5018  }
5019  }
5020  else if ( dynamic_cast< const SwAnchoredDrawObject *>( pAnchoredObj ) != nullptr )
5021  {
5022  // #i26945#
5023  const SwTabFrame* pTabFrame = pLay->FindTabFrame();
5024  if ( pTabFrame &&
5025  !( pTabFrame->IsFollow() &&
5026  pTabFrame->FindMaster()->IsRebuildLastLine() ) &&
5027  (pAnchoredObj->GetFrameFormat().GetAnchor().GetAnchorId()
5028  != RndStdIds::FLY_AS_CHAR))
5029  {
5030  SwPageFrame* pPageFrame = pAnchoredObj->GetPageFrame();
5031  SwPageFrame* pPageOfAnchor = pFrame->FindPageFrame();
5032  if ( pPageFrame != pPageOfAnchor )
5033  {
5034  pAnchoredObj->InvalidateObjPos();
5035  if ( pPageFrame )
5036  {
5037  pPageFrame->RemoveDrawObjFromPage( *pAnchoredObj );
5038  }
5039  pPageOfAnchor->AppendDrawObjToPage( *pAnchoredObj );
5040  }
5041  }
5042  // #i28701# - adjust last character
5043  // rectangle and last top of line.
5044  pAnchoredObj->AddLastCharY( lDiff );
5045  pAnchoredObj->AddLastTopOfLineY( lDiff );
5046  // #i52904# - re-introduce direct move
5047  // of drawing objects
5048  const bool bDirectMove =
5049  static_cast<const SwDrawFrameFormat&>(pAnchoredObj->GetFrameFormat()).IsPosAttrSet() &&
5050  bVertPosDepOnAnchor &&
5051  !pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos();
5052  if ( bDirectMove )
5053  {
5054  SwObjPositioningInProgress aObjPosInProgress( *pAnchoredObj );
5055  if ( aRectFnSet.IsVert() )
5056  {
5057  pAnchoredObj->DrawObj()->Move( Size( lDiff, 0 ) );
5058  }
5059  else
5060  {
5061  pAnchoredObj->DrawObj()->Move( Size( 0, lDiff ) );
5062  }
5063  // #i58280#
5064  pAnchoredObj->InvalidateObjRectWithSpaces();
5065  }
5066  pAnchoredObj->InvalidateObjPos();
5067  }
5068  else
5069  {
5070  OSL_FAIL( "<lcl_ArrangeLowers(..)> - unknown type of anchored object!" );
5071  }
5072  }
5073  }
5074  }
5075  // Columns and cells are ordered horizontal, not vertical
5076  if( !pFrame->IsColumnFrame() && !pFrame->IsCellFrame() )
5077  lYStart = aRectFnSet.YInc( lYStart,
5078  aRectFnSet.GetHeight(pFrame->getFrameArea()) );
5079 
5080  // Nowadays, the content inside a cell can flow into the follow table.
5081  // Thus, the cell may only grow up to the end of the environment.
5082  // So the content may have grown, but the cell could not grow.
5083  // Therefore we have to trigger a formatting for the frames, which do
5084  // not fit into the cell anymore:
5085  SwTwips nDistanceToUpperPrtBottom =
5086  aRectFnSet.BottomDist( pFrame->getFrameArea(), aRectFnSet.GetPrtBottom(*pLay) );
5087  // #i56146# - Revise fix of issue #i26945#
5088  // do *not* consider content inside fly frames, if it's an undersized paragraph.
5089  // #i26945# - consider content inside fly frames
5090  if ( nDistanceToUpperPrtBottom < 0 &&
5091  ( ( pFrame->IsInFly() &&
5092  ( !pFrame->IsTextFrame() ||
5093  !static_cast<SwTextFrame*>(pFrame)->IsUndersized() ) ) ||
5094  pFrame->IsInSplitTableRow() ) )
5095  {
5096  pFrame->InvalidatePos();
5097  }
5098 
5099  pFrame = pFrame->GetNext();
5100  }
5101  return bRet;
5102 }
5103 
5104 void SwCellFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs *pAttrs )
5105 {
5106  OSL_ENSURE( pAttrs, "CellFrame::Format, pAttrs is 0." );
5107  const SwTabFrame* pTab = FindTabFrame();
5108  SwRectFnSet aRectFnSet(pTab);
5109 
5110  if ( !isFramePrintAreaValid() )
5111  {
5112  setFramePrintAreaValid(true);
5113 
5114  //Adjust position.
5115  if ( Lower() )
5116  {
5117  SwTwips nTopSpace, nBottomSpace, nLeftSpace, nRightSpace;
5118  // #i29550#
5119  if ( pTab->IsCollapsingBorders() && !Lower()->IsRowFrame() )
5120  {
5121  const SvxBoxItem& rBoxItem = pAttrs->GetBox();
5122  nLeftSpace = rBoxItem.GetDistance( SvxBoxItemLine::LEFT );
5123  nRightSpace = rBoxItem.GetDistance( SvxBoxItemLine::RIGHT );
5124  nTopSpace = static_cast<SwRowFrame*>(GetUpper())->GetTopMarginForLowers();
5125  nBottomSpace = static_cast<SwRowFrame*>(GetUpper())->GetBottomMarginForLowers();
5126  }
5127  else
5128  {
5129  // OD 23.01.2003 #106895# - add 1st param to <SwBorderAttrs::CalcRight(..)>
5130  nLeftSpace = pAttrs->CalcLeft( this );
5131  nRightSpace = pAttrs->CalcRight( this );
5132  nTopSpace = pAttrs->CalcTop();
5133  nBottomSpace = pAttrs->CalcBottom();
5134  }
5135  aRectFnSet.SetXMargins( *this, nLeftSpace, nRightSpace );
5136  aRectFnSet.SetYMargins( *this, nTopSpace, nBottomSpace );
5137  }
5138  }
5139  // #i26945#
5140  tools::Long nRemaining = GetTabBox()->getRowSpan() >= 1 ?
5141  ::lcl_CalcMinCellHeight( this, pTab->IsConsiderObjsForMinCellHeight(), pAttrs ) :
5142  0;
5143  if ( !isFrameAreaSizeValid() )
5144  {
5145  setFrameAreaSizeValid(true);
5146 
5147  //The VarSize of the CellFrames is always the width.
5148  //The width is not variable though, it is defined by the format.
5149  //This predefined value however does not necessary match the actual
5150  //width. The width is calculated based on the attribute, the value in
5151  //the attribute matches the desired value of the TabFrame. Changes which
5152  //were done there are taken into account here proportionately.
5153  //If the cell doesn't have a neighbour anymore, it does not take the
5154  //attribute into account and takes the rest of the upper instead.
5155  SwTwips nWidth;
5156  if ( GetNext() )
5157  {
5158  const SwTwips nWish = pTab->GetFormat()->GetFrameSize().GetWidth();
5159  nWidth = pAttrs->GetSize().Width();
5160 
5161  OSL_ENSURE( nWish, "Table without width?" );
5162  OSL_ENSURE( nWidth <= nWish, "Width of cell larger than table." );
5163  OSL_ENSURE( nWidth > 0, "Box without width" );
5164 
5165  const tools::Long nPrtWidth = aRectFnSet.GetWidth(pTab->getFramePrintArea());
5166  if ( nWish != nPrtWidth )
5167  {
5168  // Avoid rounding problems, at least for the new table model
5169  if ( pTab->GetTable()->IsNewModel() )
5170  {
5171  // 1. sum of widths of cells up to this cell (in model)
5172  const SwTableLine* pTabLine = GetTabBox()->GetUpper();
5173  const SwTableBoxes& rBoxes = pTabLine->GetTabBoxes();
5174  const SwTableBox* pTmpBox = nullptr;
5175 
5176  SwTwips nSumWidth = 0;
5177  size_t i = 0;
5178  do
5179  {
5180  pTmpBox = rBoxes[ i++ ];
5181  nSumWidth += pTmpBox->GetFrameFormat()->GetFrameSize().GetWidth();
5182  }
5183  while ( pTmpBox != GetTabBox() );
5184 
5185  // 2. calculate actual width of cells up to this one
5186  double nTmpWidth = nSumWidth;
5187  nTmpWidth *= nPrtWidth;
5188  nTmpWidth /= nWish;
5189  nWidth = static_cast<SwTwips>(nTmpWidth);
5190 
5191  // 3. calculate frame widths of cells up to this one:
5192  const SwFrame* pTmpCell = static_cast<const SwLayoutFrame*>(GetUpper())->Lower();
5193  SwTwips nSumFrameWidths = 0;
5194  while ( pTmpCell != this )
5195  {
5196  nSumFrameWidths += aRectFnSet.GetWidth(pTmpCell->getFrameArea());
5197  pTmpCell = pTmpCell->GetNext();
5198  }
5199 
5200  nWidth = nWidth - nSumFrameWidths;
5201  }
5202  else
5203  {
5204  // #i12092# use double instead of long,
5205  // otherwise this could lead to overflows
5206  double nTmpWidth = nWidth;
5207  nTmpWidth *= nPrtWidth;
5208  nTmpWidth /= nWish;
5209  nWidth = static_cast<SwTwips>(nTmpWidth);
5210  }
5211  }
5212  }
5213  else
5214  {
5215  OSL_ENSURE( pAttrs->GetSize().Width() > 0, "Box without width" );
5216  nWidth = aRectFnSet.GetWidth(GetUpper()->getFramePrintArea());
5217  SwFrame *pPre = GetUpper()->Lower();
5218  while ( pPre != this )
5219  {
5220  nWidth -= aRectFnSet.GetWidth(pPre->getFrameArea());
5221  pPre = pPre->GetNext();
5222  }
5223  }
5224 
5225  const tools::Long nDiff = nWidth - aRectFnSet.GetWidth(getFrameArea());
5226 
5227  {
5229 
5230  if( IsNeighbourFrame() && IsRightToLeft() )
5231  {
5232  aRectFnSet.SubLeft( aFrm, nDiff );
5233  }
5234  else
5235  {
5236  aRectFnSet.AddRight( aFrm, nDiff );
5237  }
5238  }
5239 
5240  {
5242  aRectFnSet.AddRight( aPrt, nDiff );
5243  }
5244 
5245  //Adjust the height, it's defined through the content and the margins.
5246  const tools::Long nDiffHeight = nRemaining - aRectFnSet.GetHeight(getFrameArea());
5247  if ( nDiffHeight )
5248  {
5249  if ( nDiffHeight > 0 )
5250  {
5251  //Validate again if no growth happened. Invalidation is done
5252  //through AdjustCells of the row.
5253  if ( !Grow( nDiffHeight ) )
5254  {
5255  setFrameAreaSizeValid(true);
5256  setFramePrintAreaValid(true);
5257  }
5258  }
5259  else
5260  {
5261  // Only keep invalidated if shrinking was actually done; the
5262  // attempt can be ignored because all horizontally adjoined
5263  // cells have to be the same height.
5264  if ( !Shrink( -nDiffHeight ) )
5265  {
5266  setFrameAreaSizeValid(true);
5267  setFramePrintAreaValid(true);
5268  }
5269  }
5270  }
5271  }
5272  const SwFormatVertOrient &rOri = pAttrs->GetAttrSet().GetVertOrient();
5273 
5274  if ( !Lower() )
5275  return;
5276 
5277  // From now on, all operations are related to the table cell.
5278  aRectFnSet.Refresh(this);
5279 
5280  SwPageFrame* pPg = nullptr;
5281  if ( !FindTabFrame()->IsRebuildLastLine() && text::VertOrientation::NONE != rOri.GetVertOrient() &&
5282  // #158225# no vertical alignment of covered cells
5283  !IsCoveredCell() &&
5284  (pPg = FindPageFrame())!=nullptr )
5285  {
5286  if ( !Lower()->IsContentFrame() && !Lower()->IsSctFrame() && !Lower()->IsTabFrame() )
5287  {
5288  // OSL_ENSURE(for HTML-import!
5289  OSL_ENSURE( false, "VAlign to cell without content" );
5290  return;
5291  }
5292  bool bVertDir = true;
5293  // #i43913# - no vertical alignment, if wrapping
5294  // style influence is considered on object positioning and
5295  // an object is anchored inside the cell.
5296  const bool bConsiderWrapOnObjPos( GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) );
5297  // No alignment if fly with wrap overlaps the cell.
5298  if ( pPg->GetSortedObjs() )
5299  {
5300  SwRect aRect( getFramePrintArea() ); aRect += getFrameArea().Pos();
5301  for (SwAnchoredObject* pAnchoredObj : *pPg->GetSortedObjs())
5302  {
5303  SwRect aTmp( pAnchoredObj->GetObjRect() );
5304  const SwFrame* pAnch = pAnchoredObj->GetAnchorFrame();
5305  if ( (bConsiderWrapOnObjPos && IsAnLower( pAnch )) || (!bConsiderWrapOnObjPos && aTmp.IsOver( aRect )) )
5306  {
5307  const SwFrameFormat& rAnchoredObjFrameFormat = pAnchoredObj->GetFrameFormat();
5308  const SwFormatSurround &rSur = rAnchoredObjFrameFormat.GetSurround();
5309 
5310  if ( bConsiderWrapOnObjPos || css::text::WrapTextMode_THROUGH != rSur.GetSurround() )
5311  {
5312  // frames, which the cell is a lower of, aren't relevant
5313  if ( auto pFly = dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) )
5314  {
5315  if ( pFly->IsAnLower( this ) )
5316  continue;
5317  }
5318 
5319  // #i43913#
5320  // #i52904# - no vertical alignment,
5321  // if object, anchored inside cell, has temporarily
5322  // consider its wrapping style on object positioning.
5323  // #i58806# - no vertical alignment
5324  // if object does not follow the text flow.
5325  if ( bConsiderWrapOnObjPos ||
5326  !IsAnLower( pAnch ) ||
5327  pAnchoredObj->IsTmpConsiderWrapInfluence() ||
5328  !rAnchoredObjFrameFormat.GetFollowTextFlow().GetValue() )
5329  {
5330  bVertDir = false;
5331  break;
5332  }
5333  }
5334  }
5335  }
5336  }
5337 
5338  tools::Long nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
5339  if( ( bVertDir && ( nRemaining -= lcl_CalcTopAndBottomMargin( *this, *pAttrs ) ) < nPrtHeight ) ||
5340  aRectFnSet.GetTop(Lower()->getFrameArea()) != aRectFnSet.GetPrtTop(*this) )
5341  {
5342  tools::Long nDiff = aRectFnSet.GetHeight(getFramePrintArea()) - nRemaining;
5343  if ( nDiff >= 0 )
5344  {
5345  tools::Long lTopOfst = 0;
5346  if ( bVertDir )
5347  {
5348  switch ( rOri.GetVertOrient() )
5349  {
5350  case text::VertOrientation::CENTER: lTopOfst = nDiff / 2; break;
5351  case text::VertOrientation::BOTTOM: lTopOfst = nDiff; break;
5352  default: break;
5353  }
5354  }
5355  tools::Long nTmp = aRectFnSet.YInc(
5356  aRectFnSet.GetPrtTop(*this), lTopOfst );
5357  if ( lcl_ArrangeLowers( this, nTmp, !bVertDir ) )
5358  SetCompletePaint();
5359  }
5360  }
5361  }
5362  else
5363  {
5364  //Was an old alignment taken into account?
5365  if ( Lower()->IsContentFrame() )
5366  {
5367  const tools::Long lYStart = aRectFnSet.GetPrtTop(*this);
5368  lcl_ArrangeLowers( this, lYStart, true );
5369  }
5370  }
5371 
5372  // Handle rotated portions of lowers: it's possible that we have changed amount of vertical
5373  // space since the last format, and this affects how many rotated portions we need. So throw
5374  // away the current portions to build them using the new line width.
5375  for (SwFrame* pFrame = Lower(); pFrame; pFrame = pFrame->GetNext())
5376  {
5377  if (!pFrame->IsTextFrame())
5378  {
5379  continue;
5380  }
5381 
5382  auto pTextFrame = static_cast<SwTextFrame*>(pFrame);
5383  if (!pTextFrame->GetHasRotatedPortions())
5384  {
5385  continue;
5386  }
5387 
5388  pTextFrame->Prepare();
5389  }
5390 }
5391 
5392 void SwCellFrame::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
5393 {
5394  if(auto pMoveTableBoxHint = dynamic_cast<const sw::MoveTableBoxHint*>(&rHint))
5395  {
5396  if(GetTabBox() != &pMoveTableBoxHint->m_rTableBox)
5397  return;
5398  const_cast<SwFrameFormat*>(&pMoveTableBoxHint->m_rNewFormat)->Add(this);
5399  InvalidateAll();
5401  SetDerivedVert(false);
5402  CheckDirChange();
5403  return;
5404  }
5405  else if(auto pLegacy = dynamic_cast<const sw::LegacyModifyHint*>(&rHint))
5406  {
5407  const SfxPoolItem* pVertOrientItem = nullptr;
5408  const SfxPoolItem* pProtectItem = nullptr;
5409  const SfxPoolItem* pFrameDirItem = nullptr;
5410  const SfxPoolItem* pBoxItem = nullptr;
5411  const auto nWhich = pLegacy->m_pNew ? pLegacy->m_pNew->Which() : 0;
5412  switch(nWhich)
5413  {
5414  case RES_ATTRSET_CHG:
5415  {
5416  auto& rChgSet = *static_cast<const SwAttrSetChg*>(pLegacy->m_pNew)->GetChgSet();
5417  rChgSet.GetItemState(RES_VERT_ORIENT, false, &pVertOrientItem);
5418  rChg