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