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