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