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