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