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