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