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