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