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