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