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