Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / layout / wsfrm.cxx
blob9d696a2650f73825155f913d080797ed64a782b3
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_wasm_strip.h>
22 #include <hints.hxx>
23 #include <osl/diagnose.h>
24 #include <o3tl/safeint.hxx>
25 #include <svl/itemiter.hxx>
26 #include <editeng/brushitem.hxx>
27 #include <sfx2/viewsh.hxx>
28 #include <fmtornt.hxx>
29 #include <pagefrm.hxx>
30 #include <section.hxx>
31 #include <rootfrm.hxx>
32 #include <anchoreddrawobject.hxx>
33 #include <fmtanchr.hxx>
34 #include <viewimp.hxx>
35 #include <viewopt.hxx>
36 #include <IDocumentSettingAccess.hxx>
37 #include <IDocumentFieldsAccess.hxx>
38 #include <IDocumentRedlineAccess.hxx>
39 #include <redline.hxx>
40 #include <docsh.hxx>
41 #include <ftninfo.hxx>
42 #include <ftnidx.hxx>
43 #include <fmtclbl.hxx>
44 #include <fmtfsize.hxx>
45 #include <fmtpdsc.hxx>
46 #include <txtftn.hxx>
47 #include <fmtftn.hxx>
48 #include <fmtsrnd.hxx>
49 #include <fmtcntnt.hxx>
50 #include <ftnfrm.hxx>
51 #include <tabfrm.hxx>
52 #include <rowfrm.hxx>
53 #include <flyfrm.hxx>
54 #include <sectfrm.hxx>
55 #include <fmtclds.hxx>
56 #include <txtfrm.hxx>
57 #include <bodyfrm.hxx>
58 #include <cellfrm.hxx>
59 #include <dbg_lay.hxx>
60 #include <editeng/frmdiritem.hxx>
61 #include <sortedobjs.hxx>
62 #include <frmatr.hxx>
63 #include <frmtool.hxx>
64 #include <layact.hxx>
65 #include <ndtxt.hxx>
66 #include <swtable.hxx>
67 #include <view.hxx>
69 // RotateFlyFrame3
70 #include <basegfx/matrix/b2dhommatrixtools.hxx>
72 using namespace ::com::sun::star;
74 SwFrameAreaDefinition::SwFrameAreaDefinition()
75 : mbFrameAreaPositionValid(false),
76 mbFrameAreaSizeValid(false),
77 mbFramePrintAreaValid(false),
78 mnFrameId(SwFrameAreaDefinition::snLastFrameId++)
82 SwFrameAreaDefinition::~SwFrameAreaDefinition()
86 void SwFrameAreaDefinition::setFrameAreaPositionValid(bool bNew)
88 if(mbFrameAreaPositionValid != bNew)
90 mbFrameAreaPositionValid = bNew;
94 void SwFrameAreaDefinition::setFrameAreaSizeValid(bool bNew)
96 if(mbFrameAreaSizeValid != bNew)
98 mbFrameAreaSizeValid = bNew;
102 void SwFrameAreaDefinition::setFramePrintAreaValid(bool bNew)
104 if(mbFramePrintAreaValid != bNew)
106 mbFramePrintAreaValid = bNew;
110 SwFrameAreaDefinition::FrameAreaWriteAccess::~FrameAreaWriteAccess()
112 if(mrTarget.maFrameArea != *this)
114 mrTarget.maFrameArea = *this;
118 SwFrameAreaDefinition::FramePrintAreaWriteAccess::~FramePrintAreaWriteAccess()
120 if(mrTarget.maFramePrintArea != *this)
122 mrTarget.maFramePrintArea = *this;
126 // RotateFlyFrame3 - Support for Transformations
127 basegfx::B2DHomMatrix SwFrameAreaDefinition::getFrameAreaTransformation() const
129 // default implementation hands out FrameArea (outer frame)
130 const SwRect& rFrameArea(getFrameArea());
132 return basegfx::utils::createScaleTranslateB2DHomMatrix(
133 rFrameArea.Width(), rFrameArea.Height(),
134 rFrameArea.Left(), rFrameArea.Top());
137 basegfx::B2DHomMatrix SwFrameAreaDefinition::getFramePrintAreaTransformation() const
139 // default implementation hands out FramePrintArea (outer frame)
140 // Take into account that FramePrintArea is relative to FrameArea
141 const SwRect& rFrameArea(getFrameArea());
142 const SwRect& rFramePrintArea(getFramePrintArea());
144 return basegfx::utils::createScaleTranslateB2DHomMatrix(
145 rFramePrintArea.Width(), rFramePrintArea.Height(),
146 rFramePrintArea.Left() + rFrameArea.Left(),
147 rFramePrintArea.Top() + rFrameArea.Top());
150 void SwFrameAreaDefinition::transform_translate(const Point& rOffset)
152 // RotateFlyFrame3: default is to change the FrameArea, FramePrintArea needs no
153 // change since it is relative to FrameArea
154 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
156 if (aFrm.Pos().X() != FAR_AWAY)
158 aFrm.Pos().AdjustX(rOffset.X() );
161 if (aFrm.Pos().Y() != FAR_AWAY)
163 aFrm.Pos().AdjustY(rOffset.Y() );
167 SwRect TransformableSwFrame::getUntransformedFrameArea() const
169 const basegfx::B2DHomMatrix& rSource(getLocalFrameAreaTransformation());
171 if(rSource.isIdentity())
173 return mrSwFrameAreaDefinition.getFrameArea();
175 else
177 basegfx::B2DVector aScale, aTranslate;
178 double fRotate, fShearX;
179 rSource.decompose(aScale, aTranslate, fRotate, fShearX);
180 const basegfx::B2DPoint aCenter(rSource * basegfx::B2DPoint(0.5, 0.5));
181 const basegfx::B2DVector aAbsScale(basegfx::absolute(aScale));
183 return SwRect(
184 basegfx::fround(aCenter.getX() - (0.5 * aAbsScale.getX())),
185 basegfx::fround(aCenter.getY() - (0.5 * aAbsScale.getY())),
186 basegfx::fround(aAbsScale.getX()),
187 basegfx::fround(aAbsScale.getY()));
191 SwRect TransformableSwFrame::getUntransformedFramePrintArea() const
193 const basegfx::B2DHomMatrix& rSource(getLocalFramePrintAreaTransformation());
195 if(rSource.isIdentity())
197 return mrSwFrameAreaDefinition.getFramePrintArea();
199 else
201 basegfx::B2DVector aScale, aTranslate;
202 double fRotate, fShearX;
203 rSource.decompose(aScale, aTranslate, fRotate, fShearX);
204 const basegfx::B2DPoint aCenter(rSource * basegfx::B2DPoint(0.5, 0.5));
205 const basegfx::B2DVector aAbsScale(basegfx::absolute(aScale));
206 const SwRect aUntransformedFrameArea(getUntransformedFrameArea());
208 return SwRect(
209 basegfx::fround(aCenter.getX() - (0.5 * aAbsScale.getX())) - aUntransformedFrameArea.Left(),
210 basegfx::fround(aCenter.getY() - (0.5 * aAbsScale.getY())) - aUntransformedFrameArea.Top(),
211 basegfx::fround(aAbsScale.getX()),
212 basegfx::fround(aAbsScale.getY()));
216 void TransformableSwFrame::createFrameAreaTransformations(
217 double fRotation,
218 const basegfx::B2DPoint& rCenter)
220 const basegfx::B2DHomMatrix aRotateAroundCenter(
221 basegfx::utils::createRotateAroundPoint(
222 rCenter.getX(),
223 rCenter.getY(),
224 fRotation));
225 const SwRect& rFrameArea(mrSwFrameAreaDefinition.getFrameArea());
226 const SwRect& rFramePrintArea(mrSwFrameAreaDefinition.getFramePrintArea());
228 maFrameAreaTransformation = aRotateAroundCenter * basegfx::utils::createScaleTranslateB2DHomMatrix(
229 rFrameArea.Width(), rFrameArea.Height(),
230 rFrameArea.Left(), rFrameArea.Top());
231 maFramePrintAreaTransformation = aRotateAroundCenter * basegfx::utils::createScaleTranslateB2DHomMatrix(
232 rFramePrintArea.Width(), rFramePrintArea.Height(),
233 rFramePrintArea.Left() + rFrameArea.Left(), rFramePrintArea.Top() + rFrameArea.Top());
236 void TransformableSwFrame::adaptFrameAreasToTransformations()
238 if(!getLocalFrameAreaTransformation().isIdentity())
240 basegfx::B2DRange aRangeFrameArea(0.0, 0.0, 1.0, 1.0);
241 aRangeFrameArea.transform(getLocalFrameAreaTransformation());
242 const SwRect aNewFrm(
243 basegfx::fround(aRangeFrameArea.getMinX()), basegfx::fround(aRangeFrameArea.getMinY()),
244 basegfx::fround(aRangeFrameArea.getWidth()), basegfx::fround(aRangeFrameArea.getHeight()));
246 if(aNewFrm != mrSwFrameAreaDefinition.getFrameArea())
248 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(mrSwFrameAreaDefinition);
249 aFrm.setSwRect(aNewFrm);
253 if(getLocalFramePrintAreaTransformation().isIdentity())
254 return;
256 basegfx::B2DRange aRangeFramePrintArea(0.0, 0.0, 1.0, 1.0);
257 aRangeFramePrintArea.transform(getLocalFramePrintAreaTransformation());
258 const SwRect aNewPrt(
259 basegfx::fround(aRangeFramePrintArea.getMinX()) - mrSwFrameAreaDefinition.getFrameArea().Left(),
260 basegfx::fround(aRangeFramePrintArea.getMinY()) - mrSwFrameAreaDefinition.getFrameArea().Top(),
261 basegfx::fround(aRangeFramePrintArea.getWidth()),
262 basegfx::fround(aRangeFramePrintArea.getHeight()));
264 if(aNewPrt != mrSwFrameAreaDefinition.getFramePrintArea())
266 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(mrSwFrameAreaDefinition);
267 aPrt.setSwRect(aNewPrt);
271 void TransformableSwFrame::restoreFrameAreas()
273 // This can be done fully based on the Transformations currently
274 // set, so use this. Only needed when transformation *is* used
275 if(!getLocalFrameAreaTransformation().isIdentity())
277 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(mrSwFrameAreaDefinition);
278 aFrm.setSwRect(getUntransformedFrameArea());
281 if(!getLocalFramePrintAreaTransformation().isIdentity())
283 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(mrSwFrameAreaDefinition);
284 aPrt.setSwRect(getUntransformedFramePrintArea());
288 // transform by given B2DHomMatrix
289 void TransformableSwFrame::transform(const basegfx::B2DHomMatrix& aTransform)
291 maFrameAreaTransformation *= aTransform;
292 maFramePrintAreaTransformation *= aTransform;
295 SwFrame::SwFrame( sw::BroadcastingModify *pMod, SwFrame* pSib )
296 : SwClient( pMod ),
297 mpRoot( pSib ? pSib->getRootFrame() : nullptr ),
298 mpUpper(nullptr),
299 mpNext(nullptr),
300 mpPrev(nullptr),
301 mnFrameType(SwFrameType::None),
302 mbInDtor(false),
303 mbInvalidR2L(true),
304 mbDerivedR2L(false),
305 mbRightToLeft(false),
306 mbInvalidVert(true),
307 mbDerivedVert(false),
308 mbVertical(false),
309 mbVertLR(false),
310 mbVertLRBT(false),
311 mbValidLineNum(false),
312 mbFixSize(false),
313 mbCompletePaint(true),
314 mbRetouche(false),
315 mbInfInvalid(true),
316 mbInfBody( false ),
317 mbInfTab ( false ),
318 mbInfFly ( false ),
319 mbInfFootnote ( false ),
320 mbInfSct ( false ),
321 mbColLocked(false),
322 m_isInDestroy(false),
323 mnForbidDelete(0)
325 OSL_ENSURE( pMod, "No frame format given." );
328 const IDocumentDrawModelAccess& SwFrame::getIDocumentDrawModelAccess()
330 return GetUpper()->GetFormat()->getIDocumentDrawModelAccess();
333 bool SwFrame::KnowsFormat( const SwFormat& rFormat ) const
335 return GetRegisteredIn() == &rFormat;
338 void SwFrame::RegisterToFormat( SwFormat& rFormat )
340 rFormat.Add( this );
343 void SwFrame::CheckDir( SvxFrameDirection nDir, bool bVert, bool bOnlyBiDi, bool bBrowse )
345 if( SvxFrameDirection::Environment == nDir || ( bVert && bOnlyBiDi ) )
347 mbDerivedVert = true;
348 if( SvxFrameDirection::Environment == nDir )
349 mbDerivedR2L = true;
350 SetDirFlags( bVert );
352 else if( bVert )
354 mbInvalidVert = false;
355 if( SvxFrameDirection::Horizontal_LR_TB == nDir || SvxFrameDirection::Horizontal_RL_TB == nDir
356 || bBrowse )
358 mbVertical = false;
359 mbVertLR = false;
360 mbVertLRBT = false;
362 else
364 mbVertical = true;
365 if(SvxFrameDirection::Vertical_RL_TB == nDir)
367 mbVertLR = false;
368 mbVertLRBT = false;
370 else if(SvxFrameDirection::Vertical_LR_TB==nDir)
372 mbVertLR = true;
373 mbVertLRBT = false;
375 else if (nDir == SvxFrameDirection::Vertical_LR_BT)
377 mbVertLR = true;
378 mbVertLRBT = true;
380 else if (nDir == SvxFrameDirection::Vertical_RL_TB90)
382 // not yet implemented, render as RL_TB
383 mbVertLR = false;
384 mbVertLRBT = false;
388 else
390 mbInvalidR2L = false;
391 if( SvxFrameDirection::Horizontal_RL_TB == nDir )
392 mbRightToLeft = true;
393 else
394 mbRightToLeft = false;
398 void SwFrame::CheckDirection( bool bVert )
400 if( bVert )
402 if( !IsHeaderFrame() && !IsFooterFrame() )
404 mbDerivedVert = true;
405 SetDirFlags( bVert );
408 else
410 mbDerivedR2L = true;
411 SetDirFlags( bVert );
415 void SwSectionFrame::CheckDirection( bool bVert )
417 const SwFrameFormat* pFormat = GetFormat();
418 if( pFormat )
420 const SwViewShell *pSh = getRootFrame()->GetCurrShell();
421 const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
422 CheckDir(pFormat->GetFormatAttr(RES_FRAMEDIR).GetValue(),
423 bVert, true, bBrowseMode );
425 else
426 SwFrame::CheckDirection( bVert );
429 void SwFlyFrame::CheckDirection( bool bVert )
431 const SwFrameFormat* pFormat = GetFormat();
432 if( pFormat )
434 const SwViewShell *pSh = getRootFrame()->GetCurrShell();
435 const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
436 CheckDir(pFormat->GetFormatAttr(RES_FRAMEDIR).GetValue(),
437 bVert, false, bBrowseMode );
439 else
440 SwFrame::CheckDirection( bVert );
443 void SwTabFrame::CheckDirection( bool bVert )
445 const SwFrameFormat* pFormat = GetFormat();
446 if( pFormat )
448 const SwViewShell *pSh = getRootFrame()->GetCurrShell();
449 const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
450 CheckDir(pFormat->GetFormatAttr(RES_FRAMEDIR).GetValue(),
451 bVert, true, bBrowseMode );
453 else
454 SwFrame::CheckDirection( bVert );
457 void SwCellFrame::CheckDirection( bool bVert )
459 const SwFrameFormat* pFormat = GetFormat();
460 const SvxFrameDirectionItem* pFrameDirItem;
461 // Check if the item is set, before actually
462 // using it. Otherwise the dynamic pool default is used, which may be set
463 // to LTR in case of OOo 1.0 documents.
464 if( pFormat && (pFrameDirItem = pFormat->GetItemIfSet( RES_FRAMEDIR ) ) )
466 const SwViewShell *pSh = getRootFrame()->GetCurrShell();
467 const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
468 CheckDir( pFrameDirItem->GetValue(), bVert, false, bBrowseMode );
470 else
471 SwFrame::CheckDirection( bVert );
474 void SwTextFrame::CheckDirection( bool bVert )
476 const SwViewShell *pSh = getRootFrame()->GetCurrShell();
477 const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
478 CheckDir(GetTextNodeForParaProps()->GetSwAttrSet().GetFrameDir().GetValue(),
479 bVert, true, bBrowseMode);
482 void SwFrame::SwClientNotify(const SwModify&, const SfxHint& rHint)
484 if (rHint.GetId() != SfxHintId::SwLegacyModify)
485 return;
486 auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
487 SwFrameInvFlags eInvFlags = SwFrameInvFlags::NONE;
489 if(pLegacy->m_pOld && pLegacy->m_pNew && RES_ATTRSET_CHG == pLegacy->m_pNew->Which())
491 SfxItemIter aNIter(*static_cast<const SwAttrSetChg*>(pLegacy->m_pNew)->GetChgSet());
492 SfxItemIter aOIter(*static_cast<const SwAttrSetChg*>(pLegacy->m_pOld)->GetChgSet());
493 const SfxPoolItem* pNItem = aNIter.GetCurItem();
494 const SfxPoolItem* pOItem = aOIter.GetCurItem();
497 UpdateAttrFrame(pOItem, pNItem, eInvFlags);
498 pNItem = aNIter.NextItem();
499 pOItem = aOIter.NextItem();
500 } while (pNItem);
502 else
503 UpdateAttrFrame(pLegacy->m_pOld, pLegacy->m_pNew, eInvFlags);
505 if(eInvFlags == SwFrameInvFlags::NONE)
506 return;
508 SwPageFrame* pPage = FindPageFrame();
509 InvalidatePage(pPage);
510 if(eInvFlags & SwFrameInvFlags::InvalidatePrt)
512 InvalidatePrt_();
513 if(!GetPrev() && IsTabFrame() && IsInSct())
514 FindSctFrame()->InvalidatePrt_();
516 if(eInvFlags & SwFrameInvFlags::InvalidateSize)
517 InvalidateSize_();
518 if(eInvFlags & SwFrameInvFlags::InvalidatePos)
519 InvalidatePos_();
520 if(eInvFlags & SwFrameInvFlags::SetCompletePaint)
521 SetCompletePaint();
522 SwFrame *pNxt;
523 if (eInvFlags & (SwFrameInvFlags::NextInvalidatePos | SwFrameInvFlags::NextSetCompletePaint)
524 && nullptr != (pNxt = GetNext()))
526 pNxt->InvalidatePage(pPage);
527 if(eInvFlags & SwFrameInvFlags::NextInvalidatePos)
528 pNxt->InvalidatePos_();
529 if(eInvFlags & SwFrameInvFlags::NextSetCompletePaint)
530 pNxt->SetCompletePaint();
534 void SwFrame::UpdateAttrFrame( const SfxPoolItem *pOld, const SfxPoolItem *pNew,
535 SwFrameInvFlags &rInvFlags )
537 sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
538 switch( nWhich )
540 case RES_BOX:
541 case RES_SHADOW:
542 Prepare( PrepareHint::FixSizeChanged );
543 [[fallthrough]];
544 case RES_MARGIN_FIRSTLINE:
545 case RES_MARGIN_TEXTLEFT:
546 case RES_MARGIN_RIGHT:
547 case RES_LR_SPACE:
548 case RES_UL_SPACE:
549 case RES_RTL_GUTTER:
550 rInvFlags |= SwFrameInvFlags::InvalidatePrt | SwFrameInvFlags::InvalidateSize
551 | SwFrameInvFlags::SetCompletePaint;
552 break;
554 case RES_HEADER_FOOTER_EAT_SPACING:
555 rInvFlags |= SwFrameInvFlags::InvalidatePrt | SwFrameInvFlags::InvalidateSize;
556 break;
558 case RES_BACKGROUND:
559 case RES_BACKGROUND_FULL_SIZE:
560 rInvFlags |= SwFrameInvFlags::SetCompletePaint | SwFrameInvFlags::NextSetCompletePaint;
561 break;
563 case RES_KEEP:
564 rInvFlags |= SwFrameInvFlags::InvalidatePos;
565 break;
567 case RES_FRM_SIZE:
568 ReinitializeFrameSizeAttrFlags();
569 rInvFlags |= SwFrameInvFlags::InvalidatePrt | SwFrameInvFlags::InvalidateSize
570 | SwFrameInvFlags::NextInvalidatePos;
571 break;
573 case RES_FMT_CHG:
574 rInvFlags |= SwFrameInvFlags::InvalidatePrt | SwFrameInvFlags::InvalidateSize
575 | SwFrameInvFlags::InvalidatePos | SwFrameInvFlags::SetCompletePaint;
576 break;
578 case RES_ROW_SPLIT:
580 if ( IsRowFrame() )
582 bool bInFollowFlowRow = nullptr != IsInFollowFlowRow();
583 if ( bInFollowFlowRow || nullptr != IsInSplitTableRow() )
585 SwTabFrame* pTab = FindTabFrame();
586 if ( bInFollowFlowRow )
587 pTab = pTab->FindMaster();
588 pTab->SetRemoveFollowFlowLinePending( true );
591 break;
593 case RES_COL:
594 OSL_FAIL( "Columns for new FrameType?" );
595 break;
597 default:
598 // the new FillStyle has to do the same as previous RES_BACKGROUND
599 if(nWhich >= XATTR_FILL_FIRST && nWhich <= XATTR_FILL_LAST)
601 rInvFlags
602 |= SwFrameInvFlags::SetCompletePaint | SwFrameInvFlags::NextSetCompletePaint;
604 /* do Nothing */;
608 bool SwFrame::Prepare( const PrepareHint, const void *, bool )
610 /* Do nothing */
611 return false;
615 * Invalidates the page in which the Frame is currently placed.
616 * The page is invalidated depending on the type (Layout, Content, FlyFrame)
618 void SwFrame::InvalidatePage( const SwPageFrame *pPage ) const
620 if ( !pPage )
622 pPage = FindPageFrame();
623 // #i28701# - for at-character and as-character
624 // anchored Writer fly frames additionally invalidate also page frame
625 // its 'anchor character' is on.
626 if ( pPage && pPage->GetUpper() && IsFlyFrame() )
628 const SwFlyFrame* pFlyFrame = static_cast<const SwFlyFrame*>(this);
629 if ( pFlyFrame->IsAutoPos() || pFlyFrame->IsFlyInContentFrame() )
631 // #i33751#, #i34060# - method <GetPageFrameOfAnchor()>
632 // is replaced by method <FindPageFrameOfAnchor()>. It's return value
633 // have to be checked.
634 SwPageFrame* pPageFrameOfAnchor =
635 const_cast<SwFlyFrame*>(pFlyFrame)->FindPageFrameOfAnchor();
636 if ( pPageFrameOfAnchor && pPageFrameOfAnchor != pPage )
638 InvalidatePage( pPageFrameOfAnchor );
644 if ( !(pPage && pPage->GetUpper()) )
645 return;
647 if ( pPage->GetFormat()->GetDoc()->IsInDtor() )
648 return;
650 SwRootFrame *pRoot = const_cast<SwRootFrame*>(static_cast<const SwRootFrame*>(pPage->GetUpper()));
651 const SwFlyFrame *pFly = FindFlyFrame();
652 if ( IsContentFrame() )
654 if ( pRoot->IsTurboAllowed() )
656 // If a ContentFrame wants to register for a second time, make it a TurboAction.
657 if ( !pRoot->GetTurbo() || this == pRoot->GetTurbo() )
658 pRoot->SetTurbo( static_cast<const SwContentFrame*>(this) );
659 else
661 pRoot->DisallowTurbo();
662 //The page of the Turbo could be a different one then mine,
663 //therefore we have to invalidate it.
664 const SwFrame *pTmp = pRoot->GetTurbo();
665 pRoot->ResetTurbo();
666 pTmp->InvalidatePage();
669 if ( !pRoot->GetTurbo() )
671 if ( pFly )
672 { if( !pFly->IsLocked() )
674 if ( pFly->IsFlyInContentFrame() )
675 { pPage->InvalidateFlyInCnt();
676 pFly->GetAnchorFrame()->InvalidatePage();
678 else
679 pPage->InvalidateFlyContent();
682 else
683 pPage->InvalidateContent();
686 else
688 pRoot->DisallowTurbo();
689 if ( pFly )
691 if ( !pFly->IsLocked() )
693 if ( pFly->IsFlyInContentFrame() )
695 pPage->InvalidateFlyInCnt();
696 pFly->GetAnchorFrame()->InvalidatePage();
698 else
699 pPage->InvalidateFlyLayout();
702 else
703 pPage->InvalidateLayout();
705 if ( pRoot->GetTurbo() )
706 { const SwFrame *pTmp = pRoot->GetTurbo();
707 pRoot->ResetTurbo();
708 pTmp->InvalidatePage();
711 pRoot->SetIdleFlags();
713 if (!IsTextFrame())
714 return;
716 SwTextFrame const*const pText(static_cast<SwTextFrame const*>(this));
717 if (sw::MergedPara const*const pMergedPara = pText->GetMergedPara())
719 SwTextNode const* pNode(nullptr);
720 for (auto const& e : pMergedPara->extents)
722 if (e.pNode != pNode)
724 pNode = e.pNode;
725 if (pNode->IsGrammarCheckDirty())
727 pRoot->SetNeedGrammarCheck( true );
728 break;
733 else
735 if (pText->GetTextNodeFirst()->IsGrammarCheckDirty())
737 pRoot->SetNeedGrammarCheck( true );
742 Size SwFrame::ChgSize( const Size& aNewSize )
744 mbFixSize = true;
745 const Size aOldSize( getFrameArea().SSize() );
746 if ( aNewSize == aOldSize )
747 return aOldSize;
749 if ( GetUpper() )
751 bool bNeighb = IsNeighbourFrame();
752 SwRectFn fnRect = IsVertical() == bNeighb ? fnRectHori : ( IsVertLR() ? (IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert );
753 SwRect aNew( Point(0,0), aNewSize );
756 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
757 (aFrm.*fnRect->fnSetWidth)( (aNew.*fnRect->fnGetWidth)() );
760 tools::Long nNew = (aNew.*fnRect->fnGetHeight)();
761 tools::Long nDiff = nNew - (getFrameArea().*fnRect->fnGetHeight)();
763 if( nDiff )
765 if ( GetUpper()->IsFootnoteBossFrame() && HasFixSize() &&
766 SwNeighbourAdjust::GrowShrink !=
767 static_cast<SwFootnoteBossFrame*>(GetUpper())->NeighbourhoodAdjustment() )
770 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
771 (aFrm.*fnRect->fnSetHeight)( nNew );
774 SwTwips nReal = static_cast<SwLayoutFrame*>(this)->AdjustNeighbourhood(nDiff);
776 if ( nReal != nDiff )
778 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
779 (aFrm.*fnRect->fnSetHeight)( nNew - nDiff + nReal );
782 else
784 // OD 24.10.2002 #97265# - grow/shrink not for neighbour frames
785 // NOTE: neighbour frames are cell and column frames.
786 if ( !bNeighb )
788 if ( nDiff > 0 )
789 Grow( nDiff );
790 else
791 Shrink( -nDiff );
793 if ( GetUpper() && (getFrameArea().*fnRect->fnGetHeight)() != nNew )
795 GetUpper()->InvalidateSize_();
799 // Even if grow/shrink did not yet set the desired width, for
800 // example when called by ChgColumns to set the column width, we
801 // set the right width now.
802 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
803 (aFrm.*fnRect->fnSetHeight)( nNew );
807 else
809 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
810 aFrm.SSize( aNewSize );
813 if ( getFrameArea().SSize() != aOldSize )
815 SwPageFrame *pPage = FindPageFrame();
816 if ( GetNext() )
818 GetNext()->InvalidatePos_();
819 GetNext()->InvalidatePage( pPage );
821 if( IsLayoutFrame() )
823 if( IsRightToLeft() )
824 InvalidatePos_();
825 if( static_cast<SwLayoutFrame*>(this)->Lower() )
826 static_cast<SwLayoutFrame*>(this)->Lower()->InvalidateSize_();
828 InvalidatePrt_();
829 InvalidateSize_();
830 InvalidatePage( pPage );
833 return getFrameArea().SSize();
836 /** Insert SwFrame into existing structure.
838 * Insertion is done below the parent either before pBehind or
839 * at the end of the chain if pBehind is empty.
841 void SwFrame::InsertBefore( SwLayoutFrame* pParent, SwFrame* pBehind )
843 OSL_ENSURE( pParent, "No parent for insert." );
844 OSL_ENSURE( (!pBehind || pParent == pBehind->GetUpper()),
845 "Frame tree is inconsistent." );
847 mpUpper = pParent;
848 mpNext = pBehind;
849 if( pBehind )
850 { //Insert before pBehind.
851 mpPrev = pBehind->mpPrev;
852 if( nullptr != mpPrev )
853 mpPrev->mpNext = this;
854 else
855 mpUpper->m_pLower = this;
856 pBehind->mpPrev = this;
858 else
859 { //Insert at the end, or as first node in the sub tree
860 mpPrev = mpUpper->Lower();
861 if ( mpPrev )
863 while( mpPrev->mpNext )
864 mpPrev = mpPrev->mpNext;
865 mpPrev->mpNext = this;
867 else
868 mpUpper->m_pLower = this;
872 /** Insert SwFrame into existing structure.
874 * Insertion is done below the parent either after pBehind or
875 * at the beginning of the chain if pBehind is empty.
877 void SwFrame::InsertBehind( SwLayoutFrame *pParent, SwFrame *pBefore )
879 OSL_ENSURE( pParent, "No Parent for Insert." );
880 OSL_ENSURE( (!pBefore || pParent == pBefore->GetUpper()),
881 "Frame tree is inconsistent." );
883 mpUpper = pParent;
884 mpPrev = pBefore;
885 if ( pBefore )
887 //Insert after pBefore
888 mpNext = pBefore->mpNext;
889 if ( nullptr != mpNext )
890 mpNext->mpPrev = this;
891 pBefore->mpNext = this;
893 else
895 //Insert at the beginning of the chain
896 mpNext = pParent->Lower();
897 if ( pParent->Lower() )
898 pParent->Lower()->mpPrev = this;
899 pParent->m_pLower = this;
903 /** Insert a chain of SwFrames into an existing structure
905 * Currently, this method is used to insert a SectionFrame (which may have some siblings) into an
906 * existing structure. If the third parameter is NULL, this method is (besides handling the
907 * siblings) equal to SwFrame::InsertBefore(..).
909 * If the third parameter is passed, the following happens:
910 * - this becomes mpNext of pParent
911 * - pSct becomes mpNext of the last one in the this-chain
912 * - pBehind is reconnected from pParent to pSct
913 * The purpose is: a SectionFrame (this) won't become a child of another SectionFrame (pParent), but
914 * pParent gets split into two siblings (pParent+pSect) and this is inserted between.
916 bool SwFrame::InsertGroupBefore( SwFrame* pParent, SwFrame* pBehind, SwFrame* pSct )
918 OSL_ENSURE( pParent, "No parent for insert." );
919 OSL_ENSURE( (!pBehind || ( (pBehind && (pParent == pBehind->GetUpper()))
920 || ((pParent->IsSctFrame() && pBehind->GetUpper()->IsColBodyFrame())) ) ),
921 "Frame tree inconsistent." );
922 if( pSct )
924 mpUpper = pParent->GetUpper();
925 SwFrame *pLast = this;
926 while( pLast->GetNext() )
928 pLast = pLast->GetNext();
929 pLast->mpUpper = GetUpper();
931 if( pBehind )
933 pLast->mpNext = pSct;
934 pSct->mpPrev = pLast;
935 pSct->mpNext = pParent->GetNext();
937 else
939 pLast->mpNext = pParent->GetNext();
940 if( pLast->GetNext() )
941 pLast->GetNext()->mpPrev = pLast;
943 pParent->mpNext = this;
944 mpPrev = pParent;
945 if( pSct->GetNext() )
946 pSct->GetNext()->mpPrev = pSct;
947 while( pLast->GetNext() )
949 pLast = pLast->GetNext();
950 pLast->mpUpper = GetUpper();
952 if( pBehind )
953 { // Insert before pBehind.
954 if( pBehind->GetPrev() )
955 pBehind->GetPrev()->mpNext = nullptr;
956 else
957 pBehind->GetUpper()->m_pLower = nullptr;
958 pBehind->mpPrev = nullptr;
959 SwLayoutFrame* pTmp = static_cast<SwLayoutFrame*>(pSct);
960 if( pTmp->Lower() )
962 OSL_ENSURE( pTmp->Lower()->IsColumnFrame(), "InsertGrp: Used SectionFrame" );
963 pTmp = static_cast<SwLayoutFrame*>(static_cast<SwLayoutFrame*>(pTmp->Lower())->Lower());
964 OSL_ENSURE( pTmp, "InsertGrp: Missing ColBody" );
966 pBehind->mpUpper = pTmp;
967 pBehind->GetUpper()->m_pLower = pBehind;
968 pLast = pBehind->GetNext();
969 while ( pLast )
971 pLast->mpUpper = pBehind->GetUpper();
972 pLast = pLast->GetNext();
975 else
977 OSL_ENSURE( pSct->IsSctFrame(), "InsertGroup: For SectionFrames only" );
978 SwFrame::DestroyFrame(pSct);
979 return false;
982 else
984 mpUpper = static_cast<SwLayoutFrame*>(pParent);
985 SwFrame *pLast = this;
986 while( pLast->GetNext() )
988 pLast = pLast->GetNext();
989 pLast->mpUpper = GetUpper();
991 pLast->mpNext = pBehind;
992 if( pBehind )
993 { // Insert before pBehind.
994 mpPrev = pBehind->mpPrev;
995 if( nullptr != mpPrev )
996 mpPrev->mpNext = this;
997 else
998 mpUpper->m_pLower = this;
999 pBehind->mpPrev = pLast;
1001 else
1003 //Insert at the end, or ... the first node in the subtree
1004 mpPrev = mpUpper->Lower();
1005 if ( mpPrev )
1007 while( mpPrev->mpNext )
1008 mpPrev = mpPrev->mpNext;
1009 mpPrev->mpNext = this;
1011 else
1012 mpUpper->m_pLower = this;
1015 return true;
1018 void SwFrame::RemoveFromLayout()
1020 OSL_ENSURE( mpUpper, "Remove without upper?" );
1022 if (mpPrev)
1023 // one out of the middle is removed
1024 mpPrev->mpNext = mpNext;
1025 else if (mpUpper)
1026 { // the first in a list is removed //TODO
1027 OSL_ENSURE( mpUpper->m_pLower == this, "Layout is inconsistent." );
1028 mpUpper->m_pLower = mpNext;
1030 if( mpNext )
1031 mpNext->mpPrev = mpPrev;
1033 // Remove link
1034 mpNext = mpPrev = nullptr;
1035 mpUpper = nullptr;
1038 void SwContentFrame::Paste( SwFrame* pParent, SwFrame* pSibling)
1040 OSL_ENSURE( pParent, "No parent for pasting." );
1041 OSL_ENSURE( pParent->IsLayoutFrame(), "Parent is ContentFrame." );
1042 OSL_ENSURE( pParent != this, "I'm the parent." );
1043 OSL_ENSURE( pSibling != this, "I'm my own neighbour." );
1044 OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(),
1045 "I'm still registered somewhere" );
1046 OSL_ENSURE( !pSibling || pSibling->IsFlowFrame(),
1047 "<SwContentFrame::Paste(..)> - sibling not of expected type." );
1049 //Insert in the tree.
1050 InsertBefore( static_cast<SwLayoutFrame*>(pParent), pSibling );
1052 SwPageFrame *pPage = FindPageFrame();
1053 InvalidateAll_();
1054 InvalidatePage( pPage );
1056 if( pPage )
1058 pPage->InvalidateSpelling();
1059 pPage->InvalidateSmartTags();
1060 pPage->InvalidateAutoCompleteWords();
1061 pPage->InvalidateWordCount();
1064 if ( GetNext() )
1066 SwFrame* pNxt = GetNext();
1067 pNxt->InvalidatePrt_();
1068 pNxt->InvalidatePos_();
1069 pNxt->InvalidatePage( pPage );
1070 if( pNxt->IsSctFrame() )
1071 pNxt = static_cast<SwSectionFrame*>(pNxt)->ContainsContent();
1072 if( pNxt && pNxt->IsTextFrame() && pNxt->IsInFootnote() )
1073 pNxt->Prepare( PrepareHint::FootnoteInvalidation, nullptr, false );
1076 if ( getFrameArea().Height() )
1077 pParent->Grow( getFrameArea().Height() );
1079 if ( getFrameArea().Width() != pParent->getFramePrintArea().Width() )
1080 Prepare( PrepareHint::FixSizeChanged );
1082 if ( GetPrev() )
1084 if ( IsFollow() )
1085 //I'm a direct follower of my master now
1086 static_cast<SwContentFrame*>(GetPrev())->Prepare( PrepareHint::FollowFollows );
1087 else
1089 if ( GetPrev()->getFrameArea().Height() !=
1090 GetPrev()->getFramePrintArea().Height() + GetPrev()->getFramePrintArea().Top() )
1092 // Take the border into account?
1093 GetPrev()->InvalidatePrt_();
1095 // OD 18.02.2003 #104989# - force complete paint of previous frame,
1096 // if frame is inserted at the end of a section frame, in order to
1097 // get subsidiary lines repainted for the section.
1098 if ( pParent->IsSctFrame() && !GetNext() )
1100 // force complete paint of previous frame, if new inserted frame
1101 // in the section is the last one.
1102 GetPrev()->SetCompletePaint();
1104 GetPrev()->InvalidatePage( pPage );
1107 if ( IsInFootnote() )
1109 SwFrame* pFrame = GetIndPrev();
1110 if( pFrame && pFrame->IsSctFrame() )
1111 pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
1112 if( pFrame )
1113 pFrame->Prepare( PrepareHint::QuoVadis, nullptr, false );
1114 if( !GetNext() )
1116 pFrame = FindFootnoteFrame()->GetNext();
1117 if( pFrame && nullptr != (pFrame=static_cast<SwLayoutFrame*>(pFrame)->ContainsAny()) )
1118 pFrame->InvalidatePrt_();
1122 InvalidateLineNum_();
1123 SwFrame *pNxt = FindNextCnt();
1124 if ( !pNxt )
1125 return;
1127 while ( pNxt && pNxt->IsInTab() )
1129 pNxt = pNxt->FindTabFrame();
1130 if( nullptr != pNxt )
1131 pNxt = pNxt->FindNextCnt();
1133 if ( pNxt )
1135 pNxt->InvalidateLineNum_();
1136 if ( pNxt != GetNext() )
1137 pNxt->InvalidatePage();
1141 void SwContentFrame::Cut()
1143 OSL_ENSURE( GetUpper(), "Cut without Upper()." );
1145 SwPageFrame *pPage = FindPageFrame();
1146 InvalidatePage( pPage );
1147 SwFrame *pFrame = GetIndPrev();
1148 if( pFrame )
1150 if( pFrame->IsSctFrame() )
1151 pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
1152 if ( pFrame && pFrame->IsContentFrame() )
1154 pFrame->InvalidatePrt_();
1155 if( IsInFootnote() )
1156 pFrame->Prepare( PrepareHint::QuoVadis, nullptr, false );
1158 // #i26250# - invalidate printing area of previous
1159 // table frame.
1160 else if ( pFrame && pFrame->IsTabFrame() )
1162 pFrame->InvalidatePrt();
1166 SwFrame *pNxt = FindNextCnt();
1167 if ( pNxt )
1169 while ( pNxt && pNxt->IsInTab() )
1171 pNxt = pNxt->FindTabFrame();
1172 if( nullptr != pNxt )
1173 pNxt = pNxt->FindNextCnt();
1175 if ( pNxt )
1177 pNxt->InvalidateLineNum_();
1178 if ( pNxt != GetNext() )
1179 pNxt->InvalidatePage();
1183 SwTabFrame* pMasterTab(nullptr);
1184 pFrame = GetIndNext();
1185 if( pFrame )
1187 // The old follow may have calculated a gap to the predecessor which
1188 // now becomes obsolete or different as it becomes the first one itself
1189 pFrame->InvalidatePrt_();
1190 pFrame->InvalidatePos_();
1191 pFrame->InvalidatePage( pPage );
1192 if( pFrame->IsSctFrame() )
1194 pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
1195 if( pFrame )
1197 pFrame->InvalidatePrt_();
1198 pFrame->InvalidatePos_();
1199 pFrame->InvalidatePage( pPage );
1202 if( pFrame && IsInFootnote() )
1203 pFrame->Prepare( PrepareHint::ErgoSum, nullptr, false );
1204 if( IsInSct() && !GetPrev() )
1206 SwSectionFrame* pSct = FindSctFrame();
1207 if( !pSct->IsFollow() )
1209 pSct->InvalidatePrt_();
1210 pSct->InvalidatePage( pPage );
1214 else
1216 InvalidateNextPos();
1217 //Someone needs to do the retouching: predecessor or upper
1218 pFrame = GetPrev();
1219 if ( nullptr != pFrame )
1220 { pFrame->SetRetouche();
1221 pFrame->Prepare( PrepareHint::WidowsOrphans );
1222 pFrame->InvalidatePos_();
1223 pFrame->InvalidatePage( pPage );
1225 // If I'm (was) the only ContentFrame in my upper, it has to do the
1226 // retouching. Also, perhaps a page became empty.
1227 else
1228 { SwRootFrame *pRoot = getRootFrame();
1229 if ( pRoot )
1231 pRoot->SetSuperfluous();
1232 // RemoveSuperfluous can only remove empty pages at the end;
1233 // find if there are pages without content following pPage
1234 // and if so request a call to CheckPageDescs()
1235 SwViewShell *pSh = pRoot->GetCurrShell();
1236 // tdf#152983 pPage is null when called from SwHeadFootFrame ctor
1237 if (pPage && pSh && pSh->Imp()->IsAction())
1239 SwPageFrame const* pNext(pPage);
1240 while ((pNext = static_cast<SwPageFrame const*>(pNext->GetNext())))
1242 if (!sw::IsPageFrameEmpty(*pNext) && !pNext->IsFootnotePage())
1244 pSh->Imp()->GetLayAction().SetCheckPageNum(pPage->GetPhyPageNum());
1245 break;
1249 GetUpper()->SetCompletePaint();
1250 GetUpper()->InvalidatePage( pPage );
1252 if( IsInSct() )
1254 SwSectionFrame* pSct = FindSctFrame();
1255 if( !pSct->IsFollow() )
1257 pSct->InvalidatePrt_();
1258 pSct->InvalidatePage( pPage );
1261 // #i52253# The master table should take care
1262 // of removing the follow flow line.
1263 if ( IsInTab() )
1265 SwTabFrame* pThisTab = FindTabFrame();
1266 if (pThisTab && pThisTab->IsFollow())
1268 pMasterTab = pThisTab->FindMaster();
1273 //Remove first, then shrink the upper.
1274 SwLayoutFrame *pUp = GetUpper();
1275 RemoveFromLayout();
1276 if ( !pUp )
1278 assert(!pMasterTab);
1279 return;
1282 if (pMasterTab
1283 && !pMasterTab->GetFollow()->GetFirstNonHeadlineRow()->ContainsContent())
1284 { // only do this if there's no content in other cells of the row!
1285 pMasterTab->InvalidatePos_();
1286 pMasterTab->SetRemoveFollowFlowLinePending(true);
1289 SwSectionFrame *pSct = nullptr;
1290 if ( !pUp->Lower() &&
1291 ( ( pUp->IsFootnoteFrame() && !pUp->IsColLocked() ) ||
1292 ( pUp->IsInSct() &&
1293 // #i29438#
1294 // We have to consider the case that the section may be "empty"
1295 // except from a temporary empty table frame.
1296 // This can happen due to the new cell split feature.
1297 !pUp->IsCellFrame() &&
1298 // #126020# - adjust check for empty section
1299 // #130797# - correct fix #126020#
1300 !(pSct = pUp->FindSctFrame())->ContainsContent() &&
1301 !pSct->ContainsAny( true ) ) ) )
1303 if ( pUp->GetUpper() )
1306 // prevent delete of <ColLocked> footnote frame
1307 if ( pUp->IsFootnoteFrame() && !pUp->IsColLocked())
1309 if( pUp->GetNext() && !pUp->GetPrev() )
1311 SwFrame* pTmp = static_cast<SwLayoutFrame*>(pUp->GetNext())->ContainsAny();
1312 if( pTmp )
1313 pTmp->InvalidatePrt_();
1315 if (!pUp->IsDeleteForbidden())
1317 pUp->Cut();
1318 SwFrame::DestroyFrame(pUp);
1321 else
1324 if ( pSct->IsColLocked() || !pSct->IsInFootnote() ||
1325 ( pUp->IsFootnoteFrame() && pUp->IsColLocked() ) )
1327 pSct->DelEmpty( false );
1328 // If a locked section may not be deleted then at least
1329 // its size became invalid after removing its last
1330 // content.
1331 pSct->InvalidateSize_();
1333 else
1335 pSct->DelEmpty( true );
1336 SwFrame::DestroyFrame(pSct);
1341 else
1343 SwRectFnSet aRectFnSet(this);
1344 tools::Long nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
1345 if( nFrameHeight )
1346 pUp->Shrink( nFrameHeight );
1350 void SwLayoutFrame::Paste( SwFrame* pParent, SwFrame* pSibling)
1352 OSL_ENSURE( pParent, "No parent for pasting." );
1353 OSL_ENSURE( pParent->IsLayoutFrame(), "Parent is ContentFrame." );
1354 OSL_ENSURE( pParent != this, "I'm the parent oneself." );
1355 OSL_ENSURE( pSibling != this, "I'm my own neighbour." );
1356 OSL_ENSURE( !GetPrev() && !GetNext() && !GetUpper(),
1357 "I'm still registered somewhere." );
1359 //Insert in the tree.
1360 InsertBefore( static_cast<SwLayoutFrame*>(pParent), pSibling );
1362 // OD 24.10.2002 #103517# - correct setting of variable <fnRect>
1363 // <fnRect> is used for the following:
1364 // (1) To invalidate the frame's size, if its size, which has to be the
1365 // same as its upper/parent, differs from its upper's/parent's.
1366 // (2) To adjust/grow the frame's upper/parent, if it has a dimension in its
1367 // size, which is not determined by its upper/parent.
1368 // Which size is which depends on the frame type and the layout direction
1369 // (vertical or horizontal).
1370 // There are the following cases:
1371 // (A) Header and footer frames both in vertical and in horizontal layout
1372 // have to size the width to the upper/parent. A dimension in the height
1373 // has to cause an adjustment/grow of the upper/parent.
1374 // --> <fnRect> = fnRectHori
1375 // (B) Cell and column frames in vertical layout, the width has to be the
1376 // same as upper/parent and a dimension in height causes adjustment/grow
1377 // of the upper/parent.
1378 // --> <fnRect> = fnRectHori
1379 // in horizontal layout the other way around
1380 // --> <fnRect> = fnRectVert
1381 // (C) Other frames in vertical layout, the height has to be the
1382 // same as upper/parent and a dimension in width causes adjustment/grow
1383 // of the upper/parent.
1384 // --> <fnRect> = fnRectVert
1385 // in horizontal layout the other way around
1386 // --> <fnRect> = fnRectHori
1387 //SwRectFn fnRect = IsVertical() ? fnRectHori : fnRectVert;
1388 SwRectFn fnRect;
1389 if ( IsHeaderFrame() || IsFooterFrame() )
1390 fnRect = fnRectHori;
1391 else if ( IsCellFrame() || IsColumnFrame() )
1392 fnRect = GetUpper()->IsVertical() ? fnRectHori : ( GetUpper()->IsVertLR() ? (GetUpper()->IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert );
1393 else
1394 fnRect = GetUpper()->IsVertical() ? ( GetUpper()->IsVertLR() ? (GetUpper()->IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert ) : fnRectHori;
1396 if( (getFrameArea().*fnRect->fnGetWidth)() != (pParent->getFramePrintArea().*fnRect->fnGetWidth)())
1397 InvalidateSize_();
1398 InvalidatePos_();
1399 const SwPageFrame *pPage = FindPageFrame();
1400 InvalidatePage( pPage );
1401 if( !IsColumnFrame() )
1403 SwFrame *pFrame = GetIndNext();
1404 if( nullptr != pFrame )
1406 pFrame->InvalidatePos_();
1407 if( IsInFootnote() )
1409 if( pFrame->IsSctFrame() )
1410 pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
1411 if( pFrame )
1412 pFrame->Prepare( PrepareHint::ErgoSum, nullptr, false );
1415 if ( IsInFootnote() && nullptr != ( pFrame = GetIndPrev() ) )
1417 if( pFrame->IsSctFrame() )
1418 pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
1419 if( pFrame )
1420 pFrame->Prepare( PrepareHint::QuoVadis, nullptr, false );
1424 if( !(getFrameArea().*fnRect->fnGetHeight)() )
1425 return;
1427 // AdjustNeighbourhood is now also called in columns which are not
1428 // placed inside a frame
1429 SwNeighbourAdjust nAdjust = GetUpper()->IsFootnoteBossFrame() ?
1430 static_cast<SwFootnoteBossFrame*>(GetUpper())->NeighbourhoodAdjustment()
1431 : SwNeighbourAdjust::GrowShrink;
1432 SwTwips nGrow = (getFrameArea().*fnRect->fnGetHeight)();
1433 if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
1434 AdjustNeighbourhood( nGrow );
1435 else
1437 SwTwips nReal = 0;
1438 if( SwNeighbourAdjust::AdjustGrow == nAdjust )
1439 nReal = AdjustNeighbourhood( nGrow );
1440 if( nReal < nGrow )
1441 nReal += pParent->Grow( nGrow - nReal );
1442 if( SwNeighbourAdjust::GrowAdjust == nAdjust && nReal < nGrow )
1443 AdjustNeighbourhood( nGrow - nReal );
1447 void SwLayoutFrame::Cut()
1449 if ( GetNext() )
1450 GetNext()->InvalidatePos_();
1452 SwRectFnSet aRectFnSet(this);
1453 SwTwips nShrink = aRectFnSet.GetHeight(getFrameArea());
1455 // Remove first, then shrink upper.
1456 SwLayoutFrame *pUp = GetUpper();
1458 // AdjustNeighbourhood is now also called in columns which are not
1459 // placed inside a frame.
1461 // Remove must not be called before an AdjustNeighbourhood, but it has to
1462 // be called before the upper-shrink-call, if the upper-shrink takes care
1463 // of its content.
1464 if ( pUp && nShrink )
1466 if( pUp->IsFootnoteBossFrame() )
1468 SwNeighbourAdjust nAdjust= static_cast<SwFootnoteBossFrame*>(pUp)->NeighbourhoodAdjustment();
1469 if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
1470 AdjustNeighbourhood( -nShrink );
1471 else
1473 SwTwips nReal = 0;
1474 if( SwNeighbourAdjust::AdjustGrow == nAdjust )
1475 nReal = -AdjustNeighbourhood( -nShrink );
1476 if( nReal < nShrink )
1478 const SwTwips nOldHeight = aRectFnSet.GetHeight(getFrameArea());
1480 // seems as if this needs to be forwarded to the SwFrame already here,
1481 // changing to zero seems temporary anyways
1483 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
1484 aRectFnSet.SetHeight( aFrm, 0 );
1487 nReal += pUp->Shrink( nShrink - nReal );
1490 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
1491 aRectFnSet.SetHeight( aFrm, nOldHeight );
1495 if( SwNeighbourAdjust::GrowAdjust == nAdjust && nReal < nShrink )
1496 AdjustNeighbourhood( nReal - nShrink );
1498 RemoveFromLayout();
1500 else
1502 RemoveFromLayout();
1503 pUp->Shrink( nShrink );
1506 else
1507 RemoveFromLayout();
1509 if( pUp && !pUp->Lower() )
1511 pUp->SetCompletePaint();
1512 pUp->InvalidatePage();
1516 SwTwips SwFrame::Grow( SwTwips nDist, bool bTst, bool bInfo )
1518 OSL_ENSURE( nDist >= 0, "Negative growth?" );
1520 PROTOCOL_ENTER( this, bTst ? PROT::GrowTest : PROT::Grow, DbgAction::NONE, &nDist )
1522 if ( nDist )
1524 SwRectFnSet aRectFnSet(this);
1526 SwTwips nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
1527 if( nPrtHeight > 0 && nDist > (LONG_MAX - nPrtHeight) )
1528 nDist = LONG_MAX - nPrtHeight;
1530 if ( IsFlyFrame() )
1531 return static_cast<SwFlyFrame*>(this)->Grow_( nDist, bTst );
1532 else if( IsSctFrame() )
1533 return static_cast<SwSectionFrame*>(this)->Grow_( nDist, bTst );
1534 else
1536 if (IsCellFrame())
1538 const SwCellFrame* pThisCell = static_cast<const SwCellFrame*>(this);
1539 const SwTabFrame* pTab = FindTabFrame();
1541 // NEW TABLES
1542 if ( pTab->IsVertical() != IsVertical() ||
1543 pThisCell->GetLayoutRowSpan() < 1 )
1544 return 0;
1546 const SwTwips nReal = GrowFrame( nDist, bTst, bInfo );
1547 if( !bTst )
1549 nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
1551 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
1552 aRectFnSet.SetHeight( aPrt, nPrtHeight + ( IsContentFrame() ? nDist : nReal ) );
1554 return nReal;
1557 return 0;
1560 SwTwips SwFrame::Shrink( SwTwips nDist, bool bTst, bool bInfo )
1562 OSL_ENSURE( nDist >= 0, "Negative reduction?" );
1564 PROTOCOL_ENTER( this, bTst ? PROT::ShrinkTest : PROT::Shrink, DbgAction::NONE, &nDist )
1566 if ( nDist )
1568 if ( IsFlyFrame() )
1569 return static_cast<SwFlyFrame*>(this)->Shrink_( nDist, bTst );
1570 else if( IsSctFrame() )
1571 return static_cast<SwSectionFrame*>(this)->Shrink_( nDist, bTst );
1572 else
1574 if (IsCellFrame())
1576 const SwCellFrame* pThisCell = static_cast<const SwCellFrame*>(this);
1577 const SwTabFrame* pTab = FindTabFrame();
1579 // NEW TABLES
1580 if ( (pTab && pTab->IsVertical() != IsVertical()) ||
1581 pThisCell->GetLayoutRowSpan() < 1 )
1582 return 0;
1584 SwRectFnSet aRectFnSet(this);
1585 SwTwips nReal = aRectFnSet.GetHeight(getFrameArea());
1586 ShrinkFrame( nDist, bTst, bInfo );
1587 nReal -= aRectFnSet.GetHeight(getFrameArea());
1588 if( !bTst )
1590 const SwTwips nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
1591 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
1592 aRectFnSet.SetHeight( aPrt, nPrtHeight - ( IsContentFrame() ? nDist : nReal ) );
1594 return nReal;
1597 return 0;
1600 /** Adjust surrounding neighbourhood after insertion
1602 * A Frame needs "normalization" if it is directly placed below a footnote boss (page/column) and its
1603 * size changes. There is always a frame that takes the maximum possible space (the frame that
1604 * contains the Body text) and zero or more frames which only take the space needed (header/footer
1605 * area, footnote container). If one of these frames changes, the body-text-frame has to grow or
1606 * shrink accordingly, even though it's fixed.
1608 * !! Is it possible to do this in a generic way and not restrict it to the page and a distinct
1609 * frame which takes the maximum space (controlled using the FrameSize attribute)?
1610 * Problems:
1611 * - What if multiple frames taking the maximum space are placed next to each other?
1612 * - How is the maximum space calculated?
1613 * - How small can those frames become?
1615 * In any case, only a certain amount of space is allowed, so we never go below a minimum value for
1616 * the height of the body.
1618 * @param nDiff the value around which the space has to be allocated
1620 SwTwips SwFrame::AdjustNeighbourhood( SwTwips nDiff, bool bTst )
1622 PROTOCOL_ENTER( this, PROT::AdjustN, DbgAction::NONE, &nDiff );
1624 if ( !nDiff || !GetUpper()->IsFootnoteBossFrame() ) // only inside pages/columns
1625 return 0;
1627 const SwViewShell *pSh = getRootFrame()->GetCurrShell();
1628 const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
1630 //The (Page-)Body only changes in BrowseMode, but only if it does not
1631 //contain columns.
1632 if ( IsPageBodyFrame() && (!bBrowse ||
1633 (static_cast<SwLayoutFrame*>(this)->Lower() &&
1634 static_cast<SwLayoutFrame*>(this)->Lower()->IsColumnFrame())) )
1635 return 0;
1637 //In BrowseView mode the PageFrame can handle some of the requests.
1638 tools::Long nBrowseAdd = 0;
1639 if ( bBrowse && GetUpper()->IsPageFrame() ) // only (Page-)BodyFrames
1641 SwViewShell *pViewShell = getRootFrame()->GetCurrShell();
1642 SwLayoutFrame *pUp = GetUpper();
1643 tools::Long nChg;
1644 const tools::Long nUpPrtBottom = pUp->getFrameArea().Height() -
1645 pUp->getFramePrintArea().Height() - pUp->getFramePrintArea().Top();
1646 SwRect aInva( pUp->getFrameArea() );
1647 if ( pViewShell )
1649 aInva.Pos().setX( pViewShell->VisArea().Left() );
1650 aInva.Width( pViewShell->VisArea().Width() );
1652 if ( nDiff > 0 )
1654 nChg = BROWSE_HEIGHT - pUp->getFrameArea().Height();
1655 nChg = std::min( nDiff, SwTwips(nChg) );
1657 if ( !IsBodyFrame() )
1659 SetCompletePaint();
1660 if ( !pViewShell || pViewShell->VisArea().Height() >= pUp->getFrameArea().Height() )
1662 //First minimize Body, it will grow again later.
1663 SwFrame *pBody = static_cast<SwFootnoteBossFrame*>(pUp)->FindBodyCont();
1664 const tools::Long nTmp = nChg - pBody->getFramePrintArea().Height();
1665 if ( !bTst )
1668 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pBody);
1669 aFrm.Height(std::max( tools::Long(0), aFrm.Height() - nChg ));
1672 pBody->InvalidatePrt_();
1673 pBody->InvalidateSize_();
1674 if ( pBody->GetNext() )
1675 pBody->GetNext()->InvalidatePos_();
1676 if ( !IsHeaderFrame() )
1677 pBody->SetCompletePaint();
1679 nChg = nTmp <= 0 ? 0 : nTmp;
1683 const tools::Long nTmp = nUpPrtBottom + 20;
1684 aInva.Top( aInva.Bottom() - nTmp );
1685 aInva.Height( nChg + nTmp );
1687 else
1689 //The page can shrink to 0. The first page keeps the same size like
1690 //VisArea.
1691 nChg = nDiff;
1692 tools::Long nInvaAdd = 0;
1693 if ( pViewShell && !pUp->GetPrev() &&
1694 pUp->getFrameArea().Height() + nDiff < pViewShell->VisArea().Height() )
1696 // This means that we have to invalidate adequately.
1697 nChg = pViewShell->VisArea().Height() - pUp->getFrameArea().Height();
1698 nInvaAdd = -(nDiff - nChg);
1701 //Invalidate including bottom border.
1702 tools::Long nBorder = nUpPrtBottom + 20;
1703 nBorder -= nChg;
1704 aInva.Top( aInva.Bottom() - (nBorder+nInvaAdd) );
1705 if ( !IsBodyFrame() )
1707 SetCompletePaint();
1708 if ( !IsHeaderFrame() )
1709 static_cast<SwFootnoteBossFrame*>(pUp)->FindBodyCont()->SetCompletePaint();
1711 //Invalidate the page because of the frames. Thereby the page becomes
1712 //the right size again if a frame didn't fit. This only works
1713 //randomly for paragraph bound frames otherwise (NotifyFlys).
1714 pUp->InvalidateSize();
1716 if ( !bTst )
1718 //Independent from nChg
1719 if ( pViewShell && aInva.HasArea() && pUp->GetUpper() )
1720 pViewShell->InvalidateWindows( aInva );
1722 if ( !bTst && nChg )
1725 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pUp);
1726 aFrm.AddHeight(nChg );
1730 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*pUp);
1731 aPrt.AddHeight(nChg );
1734 if ( pViewShell )
1735 pViewShell->Imp()->SetFirstVisPageInvalid();
1737 if ( GetNext() )
1738 GetNext()->InvalidatePos_();
1740 //Trigger a repaint if necessary.
1741 std::unique_ptr<SvxBrushItem> aBack(pUp->GetFormat()->makeBackgroundBrushItem());
1742 const SvxGraphicPosition ePos = aBack->GetGraphicPos();
1743 if ( ePos != GPOS_NONE && ePos != GPOS_TILED )
1744 pViewShell->InvalidateWindows( pUp->getFrameArea() );
1746 if ( pUp->GetUpper() )
1748 if ( pUp->GetNext() )
1749 pUp->GetNext()->InvalidatePos();
1751 //Sad but true: during notify on ViewImp a Calc on the page and
1752 //its Lower may be called. The values should not be changed
1753 //because the caller takes care of the adjustment of Frame and
1754 //Prt.
1755 const tools::Long nOldFrameHeight = getFrameArea().Height();
1756 const tools::Long nOldPrtHeight = getFramePrintArea().Height();
1757 const bool bOldComplete = IsCompletePaint();
1759 if ( IsBodyFrame() )
1761 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
1762 aPrt.Height( nOldFrameHeight );
1765 if ( pUp->GetUpper() )
1767 static_cast<SwRootFrame*>(pUp->GetUpper())->CheckViewLayout( nullptr, nullptr );
1770 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
1771 aFrm.Height( nOldFrameHeight );
1773 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
1774 aPrt.Height( nOldPrtHeight );
1776 mbCompletePaint = bOldComplete;
1778 if ( !IsBodyFrame() )
1779 pUp->InvalidateSize_();
1780 InvalidatePage( static_cast<SwPageFrame*>(pUp) );
1782 nDiff -= nChg;
1783 if ( !nDiff )
1784 return nChg;
1785 else
1786 nBrowseAdd = nChg;
1789 const SwFootnoteBossFrame *pBoss = static_cast<SwFootnoteBossFrame*>(GetUpper());
1791 SwTwips nReal = 0,
1792 nAdd = 0;
1793 SwFrame *pFrame = nullptr;
1794 SwRectFnSet aRectFnSet(this);
1796 if( IsBodyFrame() )
1798 if( IsInSct() )
1800 SwSectionFrame *pSect = FindSctFrame();
1801 if( nDiff > 0 && pSect->IsEndnAtEnd() && GetNext() &&
1802 GetNext()->IsFootnoteContFrame() )
1804 SwFootnoteContFrame* pCont = static_cast<SwFootnoteContFrame*>(GetNext());
1805 SwTwips nMinH = 0;
1806 SwFootnoteFrame* pFootnote = static_cast<SwFootnoteFrame*>(pCont->Lower());
1807 bool bFootnote = false;
1808 while( pFootnote )
1810 if( !pFootnote->GetAttr()->GetFootnote().IsEndNote() )
1812 nMinH += aRectFnSet.GetHeight(pFootnote->getFrameArea());
1813 bFootnote = true;
1815 pFootnote = static_cast<SwFootnoteFrame*>(pFootnote->GetNext());
1817 if( bFootnote )
1818 nMinH += aRectFnSet.GetTop(pCont->getFramePrintArea());
1819 nReal = aRectFnSet.GetHeight(pCont->getFrameArea()) - nMinH;
1820 if( nReal > nDiff )
1821 nReal = nDiff;
1822 if( nReal > 0 )
1823 pFrame = GetNext();
1824 else
1825 nReal = 0;
1827 if( !bTst && !pSect->IsColLocked() )
1828 pSect->InvalidateSize();
1830 if( !pFrame )
1831 return nBrowseAdd;
1833 else
1835 const bool bFootnotePage = pBoss->IsPageFrame() && static_cast<const SwPageFrame*>(pBoss)->IsFootnotePage();
1836 if ( bFootnotePage && !IsFootnoteContFrame() )
1837 pFrame = const_cast<SwFrame*>(static_cast<SwFrame const *>(pBoss->FindFootnoteCont()));
1838 if ( !pFrame )
1839 pFrame = const_cast<SwFrame*>(static_cast<SwFrame const *>(pBoss->FindBodyCont()));
1841 if ( !pFrame )
1842 return 0;
1844 //If not one is found, everything else is solved.
1845 nReal = aRectFnSet.GetHeight(pFrame->getFrameArea());
1846 if( nReal > nDiff )
1847 nReal = nDiff;
1848 if( !bFootnotePage )
1850 //Respect the minimal boundary!
1851 if( nReal )
1853 const SwTwips nMax = pBoss->GetVarSpace();
1854 if ( nReal > nMax )
1855 nReal = nMax;
1857 if( !IsFootnoteContFrame() && nDiff > nReal &&
1858 pFrame->GetNext() && pFrame->GetNext()->IsFootnoteContFrame()
1859 && ( pFrame->GetNext()->IsVertical() == IsVertical() )
1862 //If the Body doesn't return enough, we look for a footnote, if
1863 //there is one, we steal there accordingly.
1864 const SwTwips nAddMax = aRectFnSet.GetHeight(pFrame->GetNext()->getFrameArea());
1865 nAdd = nDiff - nReal;
1866 if ( nAdd > nAddMax )
1867 nAdd = nAddMax;
1868 if ( !bTst )
1871 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFrame->GetNext());
1872 aRectFnSet.SetHeight(aFrm, nAddMax-nAdd);
1874 if( aRectFnSet.IsVert() && !aRectFnSet.IsVertL2R() )
1876 aFrm.Pos().AdjustX(nAdd );
1880 pFrame->GetNext()->InvalidatePrt();
1882 if ( pFrame->GetNext()->GetNext() )
1884 pFrame->GetNext()->GetNext()->InvalidatePos_();
1891 if ( !bTst && nReal )
1893 SwTwips nTmp = aRectFnSet.GetHeight(pFrame->getFrameArea());
1896 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFrame);
1897 aRectFnSet.SetHeight( aFrm, nTmp - nReal );
1899 if( aRectFnSet.IsVert() && !aRectFnSet.IsVertL2R() )
1901 aFrm.Pos().AdjustX(nReal );
1905 pFrame->InvalidatePrt();
1907 if ( pFrame->GetNext() )
1908 pFrame->GetNext()->InvalidatePos_();
1910 if( nReal < 0 && pFrame->IsInSct() )
1912 SwLayoutFrame* pUp = pFrame->GetUpper();
1913 if( pUp && nullptr != ( pUp = pUp->GetUpper() ) && pUp->IsSctFrame() &&
1914 !pUp->IsColLocked() )
1915 pUp->InvalidateSize();
1917 if( ( IsHeaderFrame() || IsFooterFrame() ) && pBoss->GetDrawObjs() )
1919 const SwSortedObjs &rObjs = *pBoss->GetDrawObjs();
1920 OSL_ENSURE( pBoss->IsPageFrame(), "Header/Footer out of page?" );
1921 for (SwAnchoredObject* pAnchoredObj : rObjs)
1923 if ( auto pFly = pAnchoredObj->DynCastFlyFrame() )
1925 OSL_ENSURE( !pFly->IsFlyInContentFrame(), "FlyInCnt at Page?" );
1926 const SwFormatVertOrient &rVert =
1927 pFly->GetFormat()->GetVertOrient();
1928 // When do we have to invalidate?
1929 // If a frame is aligned on a PageTextArea and the header
1930 // changes a TOP, MIDDLE or NONE aligned frame needs to
1931 // recalculate it's position; if the footer changes a BOTTOM
1932 // or MIDDLE aligned frame needs to recalculate it's
1933 // position.
1934 if( ( rVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ||
1935 rVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA ) &&
1936 ((IsHeaderFrame() && rVert.GetVertOrient()!=text::VertOrientation::BOTTOM) ||
1937 (IsFooterFrame() && rVert.GetVertOrient()!=text::VertOrientation::NONE &&
1938 rVert.GetVertOrient() != text::VertOrientation::TOP)) )
1940 pFly->InvalidatePos_();
1941 pFly->Invalidate_();
1947 return (nBrowseAdd + nReal + nAdd);
1950 /** method to perform additional actions on an invalidation (2004-05-19 #i28701#) */
1951 void SwFrame::ActionOnInvalidation( const InvalidationType )
1953 // default behaviour is to perform no additional action
1956 /** method to determine, if an invalidation is allowed (2004-05-19 #i28701#) */
1957 bool SwFrame::InvalidationAllowed( const InvalidationType ) const
1959 // default behaviour is to allow invalidation
1960 return true;
1963 void SwFrame::ImplInvalidateSize()
1965 if ( InvalidationAllowed( INVALID_SIZE ) )
1967 setFrameAreaSizeValid(false);
1969 if ( IsFlyFrame() )
1970 static_cast<SwFlyFrame*>(this)->Invalidate_();
1971 else
1972 InvalidatePage();
1974 // OD 2004-05-19 #i28701#
1975 ActionOnInvalidation( INVALID_SIZE );
1979 void SwFrame::ImplInvalidatePrt()
1981 if ( InvalidationAllowed( INVALID_PRTAREA ) )
1983 setFramePrintAreaValid(false);
1985 if ( IsFlyFrame() )
1986 static_cast<SwFlyFrame*>(this)->Invalidate_();
1987 else
1988 InvalidatePage();
1990 // OD 2004-05-19 #i28701#
1991 ActionOnInvalidation( INVALID_PRTAREA );
1995 void SwFrame::ImplInvalidatePos()
1997 if ( !InvalidationAllowed( INVALID_POS ) )
1998 return;
2000 setFrameAreaPositionValid(false);
2002 if ( IsFlyFrame() )
2004 static_cast<SwFlyFrame*>(this)->Invalidate_();
2006 else
2008 InvalidatePage();
2011 // OD 2004-05-19 #i28701#
2012 ActionOnInvalidation( INVALID_POS );
2015 void SwFrame::ImplInvalidateLineNum()
2017 if ( InvalidationAllowed( INVALID_LINENUM ) )
2019 mbValidLineNum = false;
2020 OSL_ENSURE( IsTextFrame(), "line numbers are implemented for text only" );
2021 InvalidatePage();
2023 // OD 2004-05-19 #i28701#
2024 ActionOnInvalidation( INVALID_LINENUM );
2028 void SwFrame::ReinitializeFrameSizeAttrFlags()
2030 const SwFormatFrameSize &rFormatSize = GetAttrSet()->GetFrameSize();
2031 if ( SwFrameSize::Variable == rFormatSize.GetHeightSizeType() ||
2032 SwFrameSize::Minimum == rFormatSize.GetHeightSizeType())
2034 mbFixSize = false;
2035 if ( GetType() & (SwFrameType::Header | SwFrameType::Footer | SwFrameType::Row) )
2037 SwFrame *pFrame = static_cast<SwLayoutFrame*>(this)->Lower();
2038 while ( pFrame )
2039 { pFrame->InvalidateSize_();
2040 pFrame->InvalidatePrt_();
2041 pFrame = pFrame->GetNext();
2043 SwContentFrame *pCnt = static_cast<SwLayoutFrame*>(this)->ContainsContent();
2044 // #i36991# - be save.
2045 // E.g., a row can contain *no* content.
2046 if ( pCnt )
2048 pCnt->InvalidatePage();
2051 pCnt->Prepare( PrepareHint::AdjustSizeWithoutFormatting );
2052 pCnt->InvalidateSize_();
2053 pCnt = pCnt->GetNextContentFrame();
2054 } while ( static_cast<SwLayoutFrame*>(this)->IsAnLower( pCnt ) );
2058 else if ( rFormatSize.GetHeightSizeType() == SwFrameSize::Fixed )
2060 if( IsVertical() )
2061 ChgSize( Size( rFormatSize.GetWidth(), getFrameArea().Height()));
2062 else
2063 ChgSize( Size( getFrameArea().Width(), rFormatSize.GetHeight()));
2067 void SwFrame::ValidateThisAndAllLowers( const sal_uInt16 nStage )
2069 // Stage 0: Only validate frames. Do not process any objects.
2070 // Stage 1: Only validate fly frames and all of their contents.
2071 // Stage 2: Validate all.
2073 const bool bOnlyObject = 1 == nStage;
2074 const bool bIncludeObjects = 1 <= nStage;
2076 if ( !bOnlyObject || IsFlyFrame() )
2078 setFrameAreaSizeValid(true);
2079 setFramePrintAreaValid(true);
2080 setFrameAreaPositionValid(true);
2083 if ( bIncludeObjects )
2085 const SwSortedObjs* pObjs = GetDrawObjs();
2086 if ( pObjs )
2088 const size_t nCnt = pObjs->size();
2089 for ( size_t i = 0; i < nCnt; ++i )
2091 SwAnchoredObject* pAnchObj = (*pObjs)[i];
2092 if ( auto pFlyFrame = pAnchObj->DynCastFlyFrame() )
2093 pFlyFrame->ValidateThisAndAllLowers( 2 );
2094 else if ( auto pAnchoredDrawObj = dynamic_cast<SwAnchoredDrawObject *>( pAnchObj ) )
2095 pAnchoredDrawObj->ValidateThis();
2100 if ( IsLayoutFrame() )
2102 SwFrame* pLower = static_cast<SwLayoutFrame*>(this)->Lower();
2103 while ( pLower )
2105 pLower->ValidateThisAndAllLowers( nStage );
2106 pLower = pLower->GetNext();
2111 SwTwips SwContentFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo )
2113 SwRectFnSet aRectFnSet(this);
2115 SwTwips nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
2116 if( nFrameHeight > 0 &&
2117 nDist > (LONG_MAX - nFrameHeight ) )
2118 nDist = LONG_MAX - nFrameHeight;
2120 const SwViewShell *pSh = getRootFrame()->GetCurrShell();
2121 const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
2122 SwFrameType nTmpType = SwFrameType::Cell | SwFrameType::Column;
2123 if (bBrowse)
2124 nTmpType |= SwFrameType::Body;
2125 if( !(GetUpper()->GetType() & nTmpType) && GetUpper()->HasFixSize() )
2127 if ( !bTst )
2130 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
2131 aRectFnSet.SetHeight( aFrm, nFrameHeight + nDist );
2133 if( IsVertical() && !IsVertLR() )
2135 aFrm.Pos().AdjustX( -nDist );
2139 if ( GetNext() )
2141 GetNext()->InvalidatePos();
2143 // #i28701# - Due to the new object positioning the
2144 // frame on the next page/column can flow backward (e.g. it was moved forward
2145 // due to the positioning of its objects ). Thus, invalivate this next frame,
2146 // if document compatibility option 'Consider wrapping style influence on
2147 // object positioning' is ON.
2148 else if ( GetUpper()->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) )
2150 InvalidateNextPos();
2153 return 0;
2156 SwTwips nReal = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea());
2157 SwFrame *pFrame = GetUpper()->Lower();
2158 while( pFrame && nReal > 0 )
2159 { nReal -= aRectFnSet.GetHeight(pFrame->getFrameArea());
2160 pFrame = pFrame->GetNext();
2163 if ( !bTst )
2165 //Contents are always resized to the wished value.
2166 tools::Long nOld = aRectFnSet.GetHeight(getFrameArea());
2169 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
2171 aRectFnSet.SetHeight( aFrm, nOld + nDist );
2173 if( IsVertical()&& !IsVertLR() )
2175 aFrm.Pos().AdjustX( -nDist );
2179 SwTabFrame *pTab = (nOld && IsInTab()) ? FindTabFrame() : nullptr;
2180 if (pTab)
2182 if ( pTab->GetTable()->GetHTMLTableLayout() &&
2183 !pTab->IsJoinLocked() &&
2184 !pTab->GetFormat()->GetDoc()->GetDocShell()->IsReadOnly() )
2186 pTab->InvalidatePos();
2187 pTab->SetResizeHTMLTable();
2192 //Only grow Upper if necessary.
2193 if ( nReal < nDist )
2195 if( GetUpper() )
2197 if( bTst || !GetUpper()->IsFooterFrame() )
2198 nReal = GetUpper()->Grow( nDist - std::max<tools::Long>(nReal, 0),
2199 bTst, bInfo );
2200 else
2202 nReal = 0;
2203 GetUpper()->InvalidateSize();
2206 else
2207 nReal = 0;
2209 else
2210 nReal = nDist;
2212 // #i28701# - Due to the new object positioning the
2213 // frame on the next page/column can flow backward (e.g. it was moved forward
2214 // due to the positioning of its objects ). Thus, invalivate this next frame,
2215 // if document compatibility option 'Consider wrapping style influence on
2216 // object positioning' is ON.
2217 if ( !bTst )
2219 if ( GetNext() )
2221 GetNext()->InvalidatePos();
2223 else if ( GetUpper()->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) )
2225 InvalidateNextPos();
2229 return nReal;
2232 SwTwips SwContentFrame::ShrinkFrame( SwTwips nDist, bool bTst, bool bInfo )
2234 SwRectFnSet aRectFnSet(this);
2235 OSL_ENSURE( nDist >= 0, "nDist < 0" );
2236 OSL_ENSURE( nDist <= aRectFnSet.GetHeight(getFrameArea()),
2237 "nDist > than current size." );
2239 if ( !bTst )
2241 SwTwips nRstHeight;
2242 if( GetUpper() )
2243 nRstHeight = aRectFnSet.BottomDist( getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()) );
2244 else
2245 nRstHeight = 0;
2246 if( nRstHeight < 0 )
2248 SwTwips nNextHeight = 0;
2249 if( GetUpper()->IsSctFrame() && nDist > LONG_MAX/2 )
2251 SwFrame *pNxt = GetNext();
2252 while( pNxt )
2254 nNextHeight += aRectFnSet.GetHeight(pNxt->getFrameArea());
2255 pNxt = pNxt->GetNext();
2258 nRstHeight = nDist + nRstHeight - nNextHeight;
2260 else
2262 nRstHeight = nDist;
2266 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
2267 aRectFnSet.SetHeight( aFrm, aRectFnSet.GetHeight(aFrm) - nDist );
2269 if( IsVertical() && !IsVertLR() )
2271 aFrm.Pos().AdjustX(nDist );
2275 nDist = nRstHeight;
2276 SwTabFrame *pTab = IsInTab() ? FindTabFrame() : nullptr;
2277 if (pTab)
2279 if ( pTab->GetTable()->GetHTMLTableLayout() &&
2280 !pTab->IsJoinLocked() &&
2281 !pTab->GetFormat()->GetDoc()->GetDocShell()->IsReadOnly() )
2283 pTab->InvalidatePos();
2284 pTab->SetResizeHTMLTable();
2289 SwTwips nReal;
2290 if( GetUpper() && nDist > 0 )
2292 if( bTst || !GetUpper()->IsFooterFrame() )
2293 nReal = GetUpper()->Shrink( nDist, bTst, bInfo );
2294 else
2296 nReal = 0;
2298 // #108745# Sorry, dear old footer friend, I'm not gonna invalidate you,
2299 // if there are any objects anchored inside your content, which
2300 // overlap with the shrinking frame.
2301 // This may lead to a footer frame that is too big, but this is better
2302 // than looping.
2303 // #109722# : The fix for #108745# was too strict.
2305 bool bInvalidate = true;
2306 const SwRect aRect( getFrameArea() );
2307 const SwPageFrame* pPage = FindPageFrame();
2308 const SwSortedObjs* pSorted = pPage ? pPage->GetSortedObjs() : nullptr;
2309 if( pSorted )
2311 for (SwAnchoredObject* pAnchoredObj : *pSorted)
2313 const SwRect aBound( pAnchoredObj->GetObjRectWithSpaces() );
2315 if( aBound.Left() > aRect.Right() )
2316 continue;
2318 if( aBound.Overlaps( aRect ) )
2320 const SwFrameFormat& rFormat = pAnchoredObj->GetFrameFormat();
2321 if( css::text::WrapTextMode_THROUGH != rFormat.GetSurround().GetSurround() )
2323 const SwFrame* pAnchor = pAnchoredObj->GetAnchorFrame();
2324 if ( pAnchor && pAnchor->FindFooterOrHeader() == GetUpper() )
2326 bInvalidate = false;
2327 break;
2334 if ( bInvalidate )
2335 GetUpper()->InvalidateSize();
2338 else
2339 nReal = 0;
2341 if ( !bTst )
2343 //The position of the next Frame changes for sure.
2344 InvalidateNextPos();
2346 //If I don't have a successor I have to do the retouch by myself.
2347 if ( !GetNext() )
2348 SetRetouche();
2350 return nReal;
2353 void SwContentFrame::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
2355 if (rHint.GetId() != SfxHintId::SwLegacyModify)
2356 return;
2357 auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
2358 SwContentFrameInvFlags eInvFlags = SwContentFrameInvFlags::NONE;
2359 if(pLegacy->m_pNew && RES_ATTRSET_CHG == pLegacy->m_pNew->Which() && pLegacy->m_pOld)
2361 auto& rOldSetChg = *static_cast<const SwAttrSetChg*>(pLegacy->m_pOld);
2362 auto& rNewSetChg = *static_cast<const SwAttrSetChg*>(pLegacy->m_pNew);
2363 SfxItemIter aOIter(*rOldSetChg.GetChgSet());
2364 SfxItemIter aNIter(*rNewSetChg.GetChgSet());
2365 const SfxPoolItem* pNItem = aNIter.GetCurItem();
2366 const SfxPoolItem* pOItem = aOIter.GetCurItem();
2367 SwAttrSetChg aOldSet(rOldSetChg);
2368 SwAttrSetChg aNewSet(rNewSetChg);
2371 UpdateAttr_(pOItem, pNItem, eInvFlags, &aOldSet, &aNewSet);
2372 pNItem = aNIter.NextItem();
2373 pOItem = aOIter.NextItem();
2374 } while(pNItem);
2375 if(aOldSet.Count() || aNewSet.Count())
2376 SwFrame::SwClientNotify(rMod, sw::LegacyModifyHint(&aOldSet, &aNewSet));
2378 else
2379 UpdateAttr_(pLegacy->m_pOld, pLegacy->m_pNew, eInvFlags);
2381 if(eInvFlags == SwContentFrameInvFlags::NONE)
2382 return;
2384 SwPageFrame* pPage = FindPageFrame();
2385 InvalidatePage(pPage);
2386 if(eInvFlags & SwContentFrameInvFlags::SetCompletePaint)
2387 SetCompletePaint();
2388 if(eInvFlags & SwContentFrameInvFlags::InvalidatePos)
2389 InvalidatePos_();
2390 if(eInvFlags & SwContentFrameInvFlags::InvalidateSize)
2391 InvalidateSize_();
2392 if(eInvFlags & (SwContentFrameInvFlags::InvalidateSectPrt | SwContentFrameInvFlags::SetNextCompletePaint))
2394 if(IsInSct() && !GetPrev())
2396 SwSectionFrame* pSect = FindSctFrame();
2397 if(pSect->ContainsAny() == this)
2399 pSect->InvalidatePrt_();
2400 pSect->InvalidatePage(pPage);
2403 InvalidatePrt_();
2405 SwFrame* pNextFrame = GetIndNext();
2406 if(pNextFrame && eInvFlags & SwContentFrameInvFlags::InvalidateNextPrt)
2408 pNextFrame->InvalidatePrt_();
2409 pNextFrame->InvalidatePage(pPage);
2411 if(pNextFrame && eInvFlags & SwContentFrameInvFlags::SetNextCompletePaint)
2413 pNextFrame->SetCompletePaint();
2415 if(eInvFlags & SwContentFrameInvFlags::InvalidatePrevPrt)
2417 SwFrame* pPrevFrame = GetPrev();
2418 if(pPrevFrame)
2420 pPrevFrame->InvalidatePrt_();
2421 pPrevFrame->InvalidatePage(pPage);
2424 if(eInvFlags & SwContentFrameInvFlags::InvalidateNextPos)
2425 InvalidateNextPos();
2428 void SwContentFrame::UpdateAttr_( const SfxPoolItem* pOld, const SfxPoolItem* pNew,
2429 SwContentFrameInvFlags &rInvFlags,
2430 SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet )
2432 bool bClear = true;
2433 sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
2434 switch ( nWhich )
2436 case RES_FMT_CHG:
2437 rInvFlags = SwContentFrameInvFlags::SetCompletePaint
2438 | SwContentFrameInvFlags::InvalidatePos
2439 | SwContentFrameInvFlags::InvalidateSize
2440 | SwContentFrameInvFlags::InvalidateSectPrt
2441 | SwContentFrameInvFlags::InvalidateNextPrt
2442 | SwContentFrameInvFlags::InvalidatePrevPrt
2443 | SwContentFrameInvFlags::InvalidateNextPos
2444 | SwContentFrameInvFlags::SetNextCompletePaint;
2445 [[fallthrough]];
2447 case RES_PAGEDESC: //attribute changes (on/off)
2448 if ( IsInDocBody() && !IsInTab() )
2450 rInvFlags |= SwContentFrameInvFlags::InvalidatePos;
2451 SwPageFrame *pPage = FindPageFrame();
2452 if ( !GetPrev() )
2453 CheckPageDescs( pPage );
2454 if (GetPageDescItem().GetNumOffset())
2455 static_cast<SwRootFrame*>(pPage->GetUpper())->SetVirtPageNum( true );
2456 pPage->GetFormat()->GetDoc()->getIDocumentFieldsAccess().UpdatePageFields(pPage->getFrameArea().Top());
2458 break;
2460 case RES_UL_SPACE:
2462 // OD 2004-02-18 #106629# - correction
2463 // Invalidation of the printing area of next frame, not only
2464 // for footnote content.
2465 if ( !GetIndNext() )
2467 SwFrame* pNxt = FindNext();
2468 if ( pNxt )
2470 SwPageFrame* pPg = pNxt->FindPageFrame();
2471 pNxt->InvalidatePage( pPg );
2472 pNxt->InvalidatePrt_();
2473 if( pNxt->IsSctFrame() )
2475 SwFrame* pCnt = static_cast<SwSectionFrame*>(pNxt)->ContainsAny();
2476 if( pCnt )
2478 pCnt->InvalidatePrt_();
2479 pCnt->InvalidatePage( pPg );
2482 pNxt->SetCompletePaint();
2485 // OD 2004-03-17 #i11860#
2486 if ( GetIndNext() &&
2487 !GetUpper()->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::USE_FORMER_OBJECT_POS) )
2489 // OD 2004-07-01 #i28701# - use new method <InvalidateObjs(..)>
2490 GetIndNext()->InvalidateObjs();
2492 Prepare( PrepareHint::ULSpaceChanged ); //TextFrame has to correct line spacing.
2493 rInvFlags |= SwContentFrameInvFlags::SetNextCompletePaint;
2494 [[fallthrough]];
2496 case RES_MARGIN_FIRSTLINE:
2497 case RES_MARGIN_TEXTLEFT:
2498 case RES_MARGIN_RIGHT:
2499 case RES_LR_SPACE:
2500 case RES_BOX:
2501 case RES_SHADOW:
2503 Prepare( PrepareHint::FixSizeChanged );
2504 SwModify aMod;
2505 SwFrame::SwClientNotify(aMod, sw::LegacyModifyHint(pOld, pNew));
2506 rInvFlags |= SwContentFrameInvFlags::InvalidateNextPrt | SwContentFrameInvFlags::InvalidatePrevPrt;
2507 break;
2509 case RES_BREAK:
2511 rInvFlags |= SwContentFrameInvFlags::InvalidatePos | SwContentFrameInvFlags::InvalidateNextPos;
2512 const IDocumentSettingAccess& rIDSA = GetUpper()->GetFormat()->getIDocumentSettingAccess();
2513 if( rIDSA.get(DocumentSettingId::PARA_SPACE_MAX) ||
2514 rIDSA.get(DocumentSettingId::PARA_SPACE_MAX_AT_PAGES) )
2516 rInvFlags |= SwContentFrameInvFlags::SetCompletePaint;
2517 SwFrame* pNxt = FindNext();
2518 if( pNxt )
2520 SwPageFrame* pPg = pNxt->FindPageFrame();
2521 pNxt->InvalidatePage( pPg );
2522 pNxt->InvalidatePrt_();
2523 if( pNxt->IsSctFrame() )
2525 SwFrame* pCnt = static_cast<SwSectionFrame*>(pNxt)->ContainsAny();
2526 if( pCnt )
2528 pCnt->InvalidatePrt_();
2529 pCnt->InvalidatePage( pPg );
2532 pNxt->SetCompletePaint();
2536 break;
2538 // OD 2004-02-26 #i25029#
2539 case RES_PARATR_CONNECT_BORDER:
2541 rInvFlags |= SwContentFrameInvFlags::SetCompletePaint;
2542 if ( IsTextFrame() )
2544 InvalidateNextPrtArea();
2546 if ( !GetIndNext() && IsInTab() && IsInSplitTableRow() )
2548 FindTabFrame()->InvalidateSize();
2551 break;
2553 case RES_PARATR_TABSTOP:
2554 case RES_CHRATR_SHADOWED:
2555 case RES_CHRATR_AUTOKERN:
2556 case RES_CHRATR_UNDERLINE:
2557 case RES_CHRATR_OVERLINE:
2558 case RES_CHRATR_KERNING:
2559 case RES_CHRATR_FONT:
2560 case RES_CHRATR_FONTSIZE:
2561 case RES_CHRATR_ESCAPEMENT:
2562 case RES_CHRATR_CONTOUR:
2563 case RES_PARATR_NUMRULE:
2564 rInvFlags |= SwContentFrameInvFlags::SetCompletePaint;
2565 break;
2567 case RES_FRM_SIZE:
2568 rInvFlags |= SwContentFrameInvFlags::SetCompletePaint;
2569 [[fallthrough]];
2571 default:
2572 bClear = false;
2574 if ( !bClear )
2575 return;
2577 if ( pOldSet || pNewSet )
2579 if ( pOldSet )
2580 pOldSet->ClearItem( nWhich );
2581 if ( pNewSet )
2582 pNewSet->ClearItem( nWhich );
2584 else
2586 SwModify aMod;
2587 SwFrame::SwClientNotify(aMod, sw::LegacyModifyHint(pOld, pNew));
2591 SwLayoutFrame::SwLayoutFrame(SwFrameFormat *const pFormat, SwFrame *const pSib)
2592 : SwFrame(pFormat, pSib)
2593 , m_pLower(nullptr)
2595 const SwFormatFrameSize &rFormatSize = pFormat->GetFrameSize();
2596 if ( rFormatSize.GetHeightSizeType() == SwFrameSize::Fixed )
2597 mbFixSize = true;
2600 // #i28701#
2602 SwTwips SwLayoutFrame::InnerHeight() const
2604 const SwFrame* pCnt = Lower();
2605 if (!pCnt)
2606 return 0;
2608 SwRectFnSet aRectFnSet(this);
2609 SwTwips nRet = 0;
2610 if( pCnt->IsColumnFrame() || pCnt->IsCellFrame() )
2614 SwTwips nTmp = static_cast<const SwLayoutFrame*>(pCnt)->InnerHeight();
2615 if( pCnt->isFramePrintAreaValid() )
2616 nTmp += aRectFnSet.GetHeight(pCnt->getFrameArea()) -
2617 aRectFnSet.GetHeight(pCnt->getFramePrintArea());
2618 if( nRet < nTmp )
2619 nRet = nTmp;
2620 pCnt = pCnt->GetNext();
2621 } while ( pCnt );
2623 else
2627 nRet += aRectFnSet.GetHeight(pCnt->getFrameArea());
2628 if( pCnt->IsContentFrame() && static_cast<const SwTextFrame*>(pCnt)->IsUndersized() )
2629 nRet += static_cast<const SwTextFrame*>(pCnt)->GetParHeight() -
2630 aRectFnSet.GetHeight(pCnt->getFramePrintArea());
2631 if( pCnt->IsLayoutFrame() && !pCnt->IsTabFrame() )
2632 nRet += static_cast<const SwLayoutFrame*>(pCnt)->InnerHeight() -
2633 aRectFnSet.GetHeight(pCnt->getFramePrintArea());
2634 pCnt = pCnt->GetNext();
2635 } while( pCnt );
2638 return nRet;
2641 SwTwips SwLayoutFrame::GrowFrame( SwTwips nDist, bool bTst, bool bInfo )
2643 const SwViewShell *pSh = getRootFrame()->GetCurrShell();
2644 const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
2645 SwFrameType nTmpType = SwFrameType::Cell | SwFrameType::Column;
2646 if (bBrowse)
2647 nTmpType |= SwFrameType::Body;
2648 if( !(GetType() & nTmpType) && HasFixSize() )
2649 return 0;
2651 SwRectFnSet aRectFnSet(this);
2652 const SwTwips nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
2653 const SwTwips nFramePos = getFrameArea().Pos().X();
2655 if ( nFrameHeight > 0 && nDist > (LONG_MAX - nFrameHeight) )
2656 nDist = LONG_MAX - nFrameHeight;
2658 SwTwips nMin = 0;
2659 if ( GetUpper() && !IsCellFrame() )
2661 SwFrame *pFrame = GetUpper()->Lower();
2662 while( pFrame )
2663 { nMin += aRectFnSet.GetHeight(pFrame->getFrameArea());
2664 pFrame = pFrame->GetNext();
2666 nMin = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea()) - nMin;
2667 if ( nMin < 0 )
2668 nMin = 0;
2671 SwRect aOldFrame( getFrameArea() );
2672 bool bMoveAccFrame = false;
2674 bool bChgPos = IsVertical();
2675 if ( !bTst )
2677 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
2678 aRectFnSet.SetHeight( aFrm, nFrameHeight + nDist );
2680 if( bChgPos && !IsVertLR() )
2682 aFrm.Pos().AdjustX( -nDist );
2685 bMoveAccFrame = true;
2688 SwTwips nReal = nDist - nMin;
2689 if ( nReal > 0 )
2691 if ( GetUpper() )
2692 { // AdjustNeighbourhood now only for the columns (but not in frames)
2693 SwNeighbourAdjust nAdjust = GetUpper()->IsFootnoteBossFrame() ?
2694 static_cast<SwFootnoteBossFrame*>(GetUpper())->NeighbourhoodAdjustment()
2695 : SwNeighbourAdjust::GrowShrink;
2696 if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
2697 nReal = AdjustNeighbourhood( nReal, bTst );
2698 else
2700 if( SwNeighbourAdjust::AdjustGrow == nAdjust )
2701 nReal += AdjustNeighbourhood( nReal, bTst );
2703 SwTwips nGrow = 0;
2704 if( 0 < nReal )
2706 SwFrame* pToGrow = GetUpper();
2707 // NEW TABLES
2708 // A cell with a row span of > 1 is allowed to grow the
2709 // line containing the end of the row span if it is
2710 // located in the same table frame:
2711 if (IsCellFrame())
2713 const SwCellFrame* pThisCell = static_cast<const SwCellFrame*>(this);
2714 if ( pThisCell->GetLayoutRowSpan() > 1 )
2716 SwCellFrame& rEndCell = const_cast<SwCellFrame&>(pThisCell->FindStartEndOfRowSpanCell( false ));
2717 if ( -1 == rEndCell.GetTabBox()->getRowSpan() )
2718 pToGrow = rEndCell.GetUpper();
2719 else
2720 pToGrow = nullptr;
2723 nGrow = pToGrow ? pToGrow->Grow( nReal, bTst, bInfo ) : 0;
2726 if( SwNeighbourAdjust::GrowAdjust == nAdjust && nGrow < nReal )
2727 nReal = o3tl::saturating_add(nReal, AdjustNeighbourhood( nReal - nGrow, bTst ));
2729 if ( IsFootnoteFrame() && (nGrow != nReal) && GetNext() )
2731 //Footnotes can replace their successor.
2732 SwTwips nSpace = bTst ? 0 : -nDist;
2733 const SwFrame *pFrame = GetUpper()->Lower();
2735 { nSpace += aRectFnSet.GetHeight(pFrame->getFrameArea());
2736 pFrame = pFrame->GetNext();
2737 } while ( pFrame != GetNext() );
2738 nSpace = aRectFnSet.GetHeight(GetUpper()->getFramePrintArea()) -nSpace;
2739 if ( nSpace < 0 )
2740 nSpace = 0;
2741 nSpace += nGrow;
2742 if ( nReal > nSpace )
2743 nReal = nSpace;
2744 if ( nReal && !bTst )
2745 static_cast<SwFootnoteFrame*>(this)->InvalidateNxtFootnoteCnts( FindPageFrame() );
2747 else
2748 nReal = nGrow;
2751 else
2752 nReal = 0;
2754 nReal += nMin;
2756 else
2757 nReal = nDist;
2759 if ( !bTst )
2761 if( nReal != nDist &&
2762 // NEW TABLES
2763 ( !IsCellFrame() || static_cast<SwCellFrame*>(this)->GetLayoutRowSpan() > 1 ) )
2765 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
2766 aRectFnSet.SetHeight( aFrm, nFrameHeight + nReal );
2768 if( bChgPos && !IsVertLR() )
2770 aFrm.Pos().setX( nFramePos - nReal );
2773 bMoveAccFrame = true;
2776 if ( nReal )
2778 SwPageFrame *pPage = FindPageFrame();
2779 if ( GetNext() )
2781 GetNext()->InvalidatePos_();
2782 if (GetNext()->IsRowFrame())
2783 { // also invalidate first cell
2784 static_cast<SwLayoutFrame*>(GetNext())->Lower()->InvalidatePos_();
2786 if ( GetNext()->IsContentFrame() )
2787 GetNext()->InvalidatePage( pPage );
2789 if ( !IsPageBodyFrame() )
2791 InvalidateAll_();
2792 InvalidatePage( pPage );
2794 if (!(GetType() & (SwFrameType::Row|SwFrameType::Tab|SwFrameType::FtnCont|SwFrameType::Page|SwFrameType::Root)))
2795 NotifyLowerObjs();
2797 if( IsCellFrame() )
2798 InvaPercentLowers( nReal );
2800 std::unique_ptr<SvxBrushItem> aBack(GetFormat()->makeBackgroundBrushItem());
2801 const SvxGraphicPosition ePos = aBack->GetGraphicPos();
2802 if ( GPOS_NONE != ePos && GPOS_TILED != ePos )
2803 SetCompletePaint();
2807 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
2808 if( bMoveAccFrame && IsAccessibleFrame() )
2810 SwRootFrame *pRootFrame = getRootFrame();
2811 if( pRootFrame && pRootFrame->IsAnyShellAccessible() &&
2812 pRootFrame->GetCurrShell() )
2814 pRootFrame->GetCurrShell()->Imp()->MoveAccessibleFrame( this, aOldFrame );
2817 #else
2818 (void)bMoveAccFrame;
2819 (void)aOldFrame;
2820 #endif
2822 return nReal;
2825 SwTwips SwLayoutFrame::ShrinkFrame( SwTwips nDist, bool bTst, bool bInfo )
2827 const SwViewShell *pSh = getRootFrame()->GetCurrShell();
2828 const bool bBrowse = pSh && pSh->GetViewOptions()->getBrowseMode();
2829 SwFrameType nTmpType = SwFrameType::Cell | SwFrameType::Column;
2830 if (bBrowse)
2831 nTmpType |= SwFrameType::Body;
2833 if (pSh && pSh->GetViewOptions()->IsWhitespaceHidden())
2835 if (IsBodyFrame())
2837 // Whitespace is hidden and this body frame will not shrink, as it
2838 // has a fix size.
2839 // Invalidate the page frame size, so in case the reason for the
2840 // shrink was that there is more whitespace on this page, the size
2841 // without whitespace will be recalculated correctly.
2842 SwPageFrame* pPageFrame = FindPageFrame();
2843 pPageFrame->InvalidateSize();
2847 if( !(GetType() & nTmpType) && HasFixSize() )
2848 return 0;
2850 OSL_ENSURE( nDist >= 0, "nDist < 0" );
2851 SwRectFnSet aRectFnSet(this);
2852 SwTwips nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
2853 if ( nDist > nFrameHeight )
2854 nDist = nFrameHeight;
2856 SwTwips nMin = 0;
2857 bool bChgPos = IsVertical();
2858 if ( Lower() )
2860 if( !Lower()->IsNeighbourFrame() )
2861 { const SwFrame *pFrame = Lower();
2862 const tools::Long nTmp = aRectFnSet.GetHeight(getFramePrintArea());
2863 while( pFrame && nMin < nTmp )
2864 { nMin += aRectFnSet.GetHeight(pFrame->getFrameArea());
2865 pFrame = pFrame->GetNext();
2869 SwTwips nReal = nDist;
2870 SwTwips nMinDiff = aRectFnSet.GetHeight(getFramePrintArea()) - nMin;
2871 if( nReal > nMinDiff )
2872 nReal = nMinDiff;
2873 if( nReal <= 0 )
2874 return nDist;
2876 SwRect aOldFrame( getFrameArea() );
2877 bool bMoveAccFrame = false;
2879 SwTwips nRealDist = nReal;
2880 if ( !bTst )
2882 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
2883 aRectFnSet.SetHeight( aFrm, nFrameHeight - nReal );
2885 if( bChgPos && !IsVertLR() )
2887 aFrm.Pos().AdjustX(nReal );
2890 bMoveAccFrame = true;
2893 SwNeighbourAdjust nAdjust = GetUpper() && GetUpper()->IsFootnoteBossFrame() ?
2894 static_cast<SwFootnoteBossFrame*>(GetUpper())->NeighbourhoodAdjustment()
2895 : SwNeighbourAdjust::GrowShrink;
2897 // AdjustNeighbourhood also in columns (but not in frames)
2898 if( SwNeighbourAdjust::OnlyAdjust == nAdjust )
2900 if ( IsPageBodyFrame() && !bBrowse )
2901 nReal = nDist;
2902 else
2903 { nReal = AdjustNeighbourhood( -nReal, bTst );
2904 nReal *= -1;
2905 if ( !bTst && IsBodyFrame() && nReal < nRealDist )
2907 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
2908 aRectFnSet.SetHeight( aFrm, aRectFnSet.GetHeight(aFrm) + nRealDist - nReal );
2910 if( bChgPos && !IsVertLR() )
2912 aFrm.Pos().AdjustX(nRealDist - nReal );
2915 OSL_ENSURE( !IsAccessibleFrame(), "bMoveAccFrame has to be set!" );
2919 else if( IsColumnFrame() || IsColBodyFrame() )
2921 SwTwips nTmp = GetUpper()->Shrink( nReal, bTst, bInfo );
2922 if ( nTmp != nReal )
2924 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
2925 aRectFnSet.SetHeight( aFrm, aRectFnSet.GetHeight(aFrm) + nReal - nTmp );
2927 if( bChgPos && !IsVertLR() )
2929 aFrm.Pos().AdjustX(nTmp - nReal );
2932 OSL_ENSURE( !IsAccessibleFrame(), "bMoveAccFrame has to be set!" );
2933 nReal = nTmp;
2936 else
2938 SwTwips nShrink = nReal;
2939 SwFrame* pToShrink = GetUpper();
2940 // NEW TABLES
2941 if ( IsCellFrame() )
2943 const SwCellFrame* pThisCell = static_cast<const SwCellFrame*>(this);
2944 if ( pThisCell->GetLayoutRowSpan() > 1 )
2946 SwCellFrame& rEndCell = const_cast<SwCellFrame&>(pThisCell->FindStartEndOfRowSpanCell( false ));
2947 pToShrink = rEndCell.GetUpper();
2951 nReal = pToShrink ? pToShrink->Shrink( nShrink, bTst, bInfo ) : 0;
2952 if( ( SwNeighbourAdjust::GrowAdjust == nAdjust || SwNeighbourAdjust::AdjustGrow == nAdjust )
2953 && nReal < nShrink )
2954 AdjustNeighbourhood( nReal - nShrink );
2957 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
2958 if( bMoveAccFrame && IsAccessibleFrame() )
2960 SwRootFrame *pRootFrame = getRootFrame();
2961 if( pRootFrame && pRootFrame->IsAnyShellAccessible() &&
2962 pRootFrame->GetCurrShell() )
2964 pRootFrame->GetCurrShell()->Imp()->MoveAccessibleFrame( this, aOldFrame );
2967 #else
2968 (void)aOldFrame;
2969 (void)bMoveAccFrame;
2970 #endif
2972 if ( !bTst && (IsCellFrame() || IsColumnFrame() ? nReal : nRealDist) )
2974 SwPageFrame *pPage = FindPageFrame();
2975 if ( GetNext() )
2977 GetNext()->InvalidatePos_();
2978 if ( GetNext()->IsContentFrame() )
2979 GetNext()->InvalidatePage( pPage );
2980 if ( IsTabFrame() )
2981 static_cast<SwTabFrame*>(this)->SetComplete();
2983 else
2984 { if ( IsRetoucheFrame() )
2985 SetRetouche();
2986 if ( IsTabFrame() )
2988 static_cast<SwTabFrame*>(this)->SetComplete();
2989 if ( Lower() ) // Can also be in the Join and be empty!
2990 InvalidateNextPos();
2993 if ( !IsBodyFrame() )
2995 InvalidateAll_();
2996 InvalidatePage( pPage );
2997 bool bCompletePaint = true;
2998 const SwFrameFormat* pFormat = GetFormat();
2999 if (pFormat)
3001 std::unique_ptr<SvxBrushItem> aBack(pFormat->makeBackgroundBrushItem());
3002 const SvxGraphicPosition ePos = aBack->GetGraphicPos();
3003 if ( GPOS_NONE == ePos || GPOS_TILED == ePos )
3004 bCompletePaint = false;
3006 if (bCompletePaint)
3007 SetCompletePaint();
3010 if (!(GetType() & (SwFrameType::Row|SwFrameType::Tab|SwFrameType::FtnCont|SwFrameType::Page|SwFrameType::Root)))
3011 NotifyLowerObjs();
3013 if( IsCellFrame() )
3014 InvaPercentLowers( nReal );
3016 SwContentFrame *pCnt;
3017 if( IsFootnoteFrame() && !static_cast<SwFootnoteFrame*>(this)->GetAttr()->GetFootnote().IsEndNote() &&
3018 ( GetFormat()->GetDoc()->GetFootnoteInfo().m_ePos != FTNPOS_CHAPTER ||
3019 ( IsInSct() && FindSctFrame()->IsFootnoteAtEnd() ) ) &&
3020 nullptr != (pCnt = static_cast<SwFootnoteFrame*>(this)->GetRefFromAttr() ) )
3022 if ( pCnt->IsFollow() )
3023 { // If we are in another column/page than the frame with the
3024 // reference, we don't need to invalidate its master.
3025 SwFrame *pTmp = pCnt->FindFootnoteBossFrame(true) == FindFootnoteBossFrame(true)
3026 ? &pCnt->FindMaster()->GetFrame() : pCnt;
3027 pTmp->Prepare( PrepareHint::AdjustSizeWithoutFormatting );
3028 pTmp->InvalidateSize();
3030 else
3032 if (pCnt->FindPageFrame() == FindPageFrame())
3034 pCnt->InvalidatePos();
3036 else
3038 SAL_WARN("sw.layout", "footnote frame on different page than ref frame?");
3043 return nReal;
3047 * Changes the size of the directly subsidiary Frame's that have a fixed size, proportionally to the
3048 * size change of the PrtArea of the Frame's.
3050 * The variable Frames are also proportionally adapted; they will grow/shrink again by themselves.
3052 void SwLayoutFrame::ChgLowersProp( const Size& rOldSize )
3054 // no change of lower properties for root frame or if no lower exists.
3055 if ( IsRootFrame() || !Lower() )
3056 return;
3058 // declare and init <SwFrame* pLowerFrame> with first lower
3059 SwFrame *pLowerFrame = Lower();
3061 // declare and init const booleans <bHeightChgd> and <bWidthChg>
3062 const bool bHeightChgd = rOldSize.Height() != getFramePrintArea().Height();
3063 const bool bWidthChgd = rOldSize.Width() != getFramePrintArea().Width();
3065 SwRectFnSet aRectFnSet(this);
3067 // This shortcut basically tries to handle only lower frames that
3068 // are affected by the size change. Otherwise much more lower frames
3069 // are invalidated.
3070 if ( !( aRectFnSet.IsVert() ? bHeightChgd : bWidthChgd ) &&
3071 ! Lower()->IsColumnFrame() &&
3072 ( ( IsBodyFrame() && IsInDocBody() && ( !IsInSct() || !FindSctFrame()->IsColLocked() ) ) ||
3073 // #i10826# Section frames without columns should not
3074 // invalidate all lowers!
3075 IsSctFrame() ) )
3077 // Determine page frame the body frame resp. the section frame belongs to.
3078 SwPageFrame *pPage = FindPageFrame();
3079 // Determine last lower by traveling through them using <GetNext()>.
3080 // During travel check each section frame, if it will be sized to
3081 // maximum. If Yes, invalidate size of section frame and set
3082 // corresponding flags at the page.
3085 if( pLowerFrame->IsSctFrame() && static_cast<SwSectionFrame*>(pLowerFrame)->ToMaximize_() )
3087 pLowerFrame->InvalidateSize_();
3088 pLowerFrame->InvalidatePage( pPage );
3090 if( pLowerFrame->GetNext() )
3091 pLowerFrame = pLowerFrame->GetNext();
3092 else
3093 break;
3094 } while( true );
3095 // If found last lower is a section frame containing no section
3096 // (section frame isn't valid and will be deleted in the future),
3097 // travel backwards.
3098 while( pLowerFrame->IsSctFrame() && !static_cast<SwSectionFrame*>(pLowerFrame)->GetSection() &&
3099 pLowerFrame->GetPrev() )
3100 pLowerFrame = pLowerFrame->GetPrev();
3101 // If found last lower is a section frame, set <pLowerFrame> to its last
3102 // content, if the section frame is valid and is not sized to maximum.
3103 // Otherwise set <pLowerFrame> to NULL - In this case body frame only
3104 // contains invalid section frames.
3105 if( pLowerFrame->IsSctFrame() )
3106 pLowerFrame = static_cast<SwSectionFrame*>(pLowerFrame)->GetSection() &&
3107 !static_cast<SwSectionFrame*>(pLowerFrame)->ToMaximize( false ) ?
3108 static_cast<SwSectionFrame*>(pLowerFrame)->FindLastContent() : nullptr;
3110 // continue with found last lower, probably the last content of a section
3111 if ( pLowerFrame )
3113 // If <pLowerFrame> is in a table frame, set <pLowerFrame> to this table
3114 // frame and continue.
3115 if ( pLowerFrame->IsInTab() )
3117 // OD 28.10.2002 #97265# - safeguard for setting <pLowerFrame> to
3118 // its table frame - check, if the table frame is also a lower
3119 // of the body frame, in order to assure that <pLowerFrame> is not
3120 // set to a frame, which is an *upper* of the body frame.
3121 SwFrame* pTableFrame = pLowerFrame->FindTabFrame();
3122 if ( IsAnLower( pTableFrame ) )
3124 pLowerFrame = pTableFrame;
3127 // Check, if variable size of body frame resp. section frame has grown
3128 // OD 28.10.2002 #97265# - correct check, if variable size has grown.
3129 SwTwips nOldHeight = aRectFnSet.IsVert() ? rOldSize.Width() : rOldSize.Height();
3130 if( nOldHeight < aRectFnSet.GetHeight(getFramePrintArea()) )
3132 // If variable size of body|section frame has grown, only found
3133 // last lower and the position of the its next have to be invalidated.
3134 pLowerFrame->InvalidateAll_();
3135 pLowerFrame->InvalidatePage( pPage );
3136 if( !pLowerFrame->IsFlowFrame() ||
3137 !SwFlowFrame::CastFlowFrame( pLowerFrame )->HasFollow() )
3138 pLowerFrame->InvalidateNextPos( true );
3139 if ( pLowerFrame->IsTextFrame() )
3140 static_cast<SwContentFrame*>(pLowerFrame)->Prepare( PrepareHint::AdjustSizeWithoutFormatting );
3142 else
3144 SwFrame const* pFirstInvalid(nullptr);
3145 for (SwFrame const* pLow = Lower();
3146 pLow && pLow != pLowerFrame; pLow = pLow->GetNext())
3148 if (!pLow->isFrameAreaDefinitionValid())
3150 pFirstInvalid = pLow;
3151 break;
3154 // variable size of body|section frame has shrunk. Thus,
3155 // invalidate all lowers not matching the new body|section size
3156 // and the dedicated new last lower.
3157 if( aRectFnSet.IsVert() )
3159 SwTwips nBot = getFrameArea().Left() + getFramePrintArea().Left();
3160 while (pLowerFrame && pLowerFrame->GetPrev()
3161 && (pFirstInvalid != nullptr // tdf#152307 trust nothing after invalid frame
3162 || pLowerFrame->getFrameArea().Left() < nBot))
3164 pLowerFrame->InvalidateAll_();
3165 pLowerFrame->InvalidatePage( pPage );
3166 if (pLowerFrame == pFirstInvalid)
3168 pFirstInvalid = nullptr; // continue checking nBot
3170 pLowerFrame = pLowerFrame->GetPrev();
3173 else
3175 SwTwips nBot = getFrameArea().Top() + getFramePrintArea().Bottom();
3176 while (pLowerFrame && pLowerFrame->GetPrev()
3177 && (pFirstInvalid != nullptr // tdf#152307 trust nothing after invalid frame
3178 || nBot < pLowerFrame->getFrameArea().Top()))
3180 pLowerFrame->InvalidateAll_();
3181 pLowerFrame->InvalidatePage( pPage );
3182 if (pLowerFrame == pFirstInvalid)
3184 pFirstInvalid = nullptr; // continue checking nBot
3186 pLowerFrame = pLowerFrame->GetPrev();
3189 if ( pLowerFrame )
3191 pLowerFrame->InvalidateSize_();
3192 pLowerFrame->InvalidatePage( pPage );
3193 if ( pLowerFrame->IsTextFrame() )
3194 static_cast<SwContentFrame*>(pLowerFrame)->Prepare( PrepareHint::AdjustSizeWithoutFormatting );
3197 // #i41694# - improvement by removing duplicates
3198 if ( pLowerFrame )
3200 if ( pLowerFrame->IsInSct() )
3202 // #i41694# - follow-up of issue #i10826#
3203 // No invalidation of section frame, if it's the this.
3204 SwFrame* pSectFrame = pLowerFrame->FindSctFrame();
3205 if( pSectFrame != this && IsAnLower( pSectFrame ) )
3207 pSectFrame->InvalidateSize_();
3208 pSectFrame->InvalidatePage( pPage );
3213 return;
3214 } // end of { special case }
3216 // Invalidate page for content only once.
3217 bool bInvaPageForContent = true;
3219 // Declare booleans <bFixChgd> and <bVarChgd>, indicating for text frame
3220 // adjustment, if fixed/variable size has changed.
3221 bool bFixChgd, bVarChgd;
3222 if( aRectFnSet.IsVert() == pLowerFrame->IsNeighbourFrame() )
3224 bFixChgd = bWidthChgd;
3225 bVarChgd = bHeightChgd;
3227 else
3229 bFixChgd = bHeightChgd;
3230 bVarChgd = bWidthChgd;
3233 // Declare const unsigned short <nFixWidth> and init it this frame types
3234 // which has fixed width in vertical respectively horizontal layout.
3235 // In vertical layout these are neighbour frames (cell and column frames),
3236 // header frames and footer frames.
3237 // In horizontal layout these are all frames, which aren't neighbour frames.
3238 const SwFrameType nFixWidth = aRectFnSet.IsVert() ? (FRM_NEIGHBOUR | FRM_HEADFOOT)
3239 : ~SwFrameType(FRM_NEIGHBOUR);
3241 // Declare const unsigned short <nFixHeight> and init it this frame types
3242 // which has fixed height in vertical respectively horizontal layout.
3243 // In vertical layout these are all frames, which aren't neighbour frames,
3244 // header frames, footer frames, body frames or foot note container frames.
3245 // In horizontal layout these are neighbour frames.
3246 const SwFrameType nFixHeight = aRectFnSet.IsVert() ? ~SwFrameType(FRM_NEIGHBOUR | FRM_HEADFOOT | FRM_BODYFTNC)
3247 : FRM_NEIGHBOUR;
3249 // Travel through all lowers using <GetNext()>
3250 while ( pLowerFrame )
3252 if ( pLowerFrame->IsTextFrame() )
3254 // Text frames will only be invalidated - prepare invalidation
3255 if ( bFixChgd )
3256 static_cast<SwContentFrame*>(pLowerFrame)->Prepare( PrepareHint::FixSizeChanged );
3257 if ( bVarChgd )
3258 static_cast<SwContentFrame*>(pLowerFrame)->Prepare( PrepareHint::AdjustSizeWithoutFormatting );
3260 else
3262 // If lower isn't a table, row, cell or section frame, adjust its
3263 // frame size.
3264 const SwFrameType nLowerType = pLowerFrame->GetType();
3265 if ( !(nLowerType & (SwFrameType::Tab|SwFrameType::Row|SwFrameType::Cell|SwFrameType::Section)) )
3267 if ( bWidthChgd )
3269 if( nLowerType & nFixWidth )
3271 // Considering previous conditions:
3272 // In vertical layout set width of column, header and
3273 // footer frames to its upper width.
3274 // In horizontal layout set width of header, footer,
3275 // foot note container, foot note, body and no-text
3276 // frames to its upper width.
3277 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pLowerFrame);
3278 aFrm.Width( getFramePrintArea().Width() );
3280 else if( rOldSize.Width() && !pLowerFrame->IsFootnoteFrame() )
3282 // Adjust frame width proportional, if lower isn't a
3283 // foot note frame and condition <nLowerType & nFixWidth>
3284 // isn't true.
3285 // Considering previous conditions:
3286 // In vertical layout these are foot note container,
3287 // body and no-text frames.
3288 // In horizontal layout these are column and no-text frames.
3289 // OD 24.10.2002 #97265# - <double> calculation
3290 // Perform <double> calculation of new width, if
3291 // one of the coefficients is greater than 50000
3292 SwTwips nNewWidth;
3293 if ( (pLowerFrame->getFrameArea().Width() > 50000) ||
3294 (getFramePrintArea().Width() > 50000) )
3296 double nNewWidthTmp =
3297 ( double(pLowerFrame->getFrameArea().Width())
3298 * double(getFramePrintArea().Width()) )
3299 / double(rOldSize.Width());
3300 nNewWidth = SwTwips(nNewWidthTmp);
3302 else
3304 nNewWidth =
3305 (pLowerFrame->getFrameArea().Width() * getFramePrintArea().Width()) / rOldSize.Width();
3308 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pLowerFrame);
3309 aFrm.Width( nNewWidth );
3312 if ( bHeightChgd )
3314 if( nLowerType & nFixHeight )
3316 // Considering previous conditions:
3317 // In vertical layout set height of foot note and
3318 // no-text frames to its upper height.
3319 // In horizontal layout set height of column frames
3320 // to its upper height.
3321 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pLowerFrame);
3322 aFrm.Height( getFramePrintArea().Height() );
3324 // OD 01.10.2002 #102211#
3325 // add conditions <!pLowerFrame->IsHeaderFrame()> and
3326 // <!pLowerFrame->IsFooterFrame()> in order to avoid that
3327 // the <Grow> of header or footer are overwritten.
3328 // NOTE: Height of header/footer frame is determined by contents.
3329 else if ( rOldSize.Height() &&
3330 !pLowerFrame->IsFootnoteFrame() &&
3331 !pLowerFrame->IsHeaderFrame() &&
3332 !pLowerFrame->IsFooterFrame()
3335 // Adjust frame height proportional, if lower isn't a
3336 // foot note, a header or a footer frame and
3337 // condition <nLowerType & nFixHeight> isn't true.
3338 // Considering previous conditions:
3339 // In vertical layout these are column, foot note container,
3340 // body and no-text frames.
3341 // In horizontal layout these are column, foot note
3342 // container, body and no-text frames.
3344 // OD 29.10.2002 #97265# - special case for page lowers
3345 // The page lowers that have to be adjusted on page height
3346 // change are the body frame and the foot note container
3347 // frame.
3348 // In vertical layout the height of both is directly
3349 // adjusted to the page height change.
3350 // In horizontal layout the height of the body frame is
3351 // directly adjusted to the page height change and the
3352 // foot note frame height isn't touched, because its
3353 // determined by its content.
3354 // OD 31.03.2003 #108446# - apply special case for page
3355 // lowers - see description above - also for section columns.
3356 if ( IsPageFrame() ||
3357 ( IsColumnFrame() && IsInSct() )
3360 OSL_ENSURE( pLowerFrame->IsBodyFrame() || pLowerFrame->IsFootnoteContFrame(),
3361 "ChgLowersProp - only for body or foot note container" );
3362 if ( pLowerFrame->IsBodyFrame() || pLowerFrame->IsFootnoteContFrame() )
3364 if ( IsVertical() || pLowerFrame->IsBodyFrame() )
3366 SwTwips nNewHeight =
3367 pLowerFrame->getFrameArea().Height() +
3368 ( getFramePrintArea().Height() - rOldSize.Height() );
3369 if ( nNewHeight < 0)
3371 // OD 01.04.2003 #108446# - adjust assertion condition and text
3372 OSL_ENSURE( !( IsPageFrame() &&
3373 (pLowerFrame->getFrameArea().Height()>0) &&
3374 (pLowerFrame->isFrameAreaDefinitionValid()) ),
3375 "ChgLowersProg - negative height for lower.");
3376 nNewHeight = 0;
3379 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pLowerFrame);
3380 aFrm.Height( nNewHeight );
3384 else
3386 SwTwips nNewHeight;
3387 // OD 24.10.2002 #97265# - <double> calculation
3388 // Perform <double> calculation of new height, if
3389 // one of the coefficients is greater than 50000
3390 if ( (pLowerFrame->getFrameArea().Height() > 50000) ||
3391 (getFramePrintArea().Height() > 50000) )
3393 double nNewHeightTmp =
3394 ( double(pLowerFrame->getFrameArea().Height())
3395 * double(getFramePrintArea().Height()) )
3396 / double(rOldSize.Height());
3397 nNewHeight = SwTwips(nNewHeightTmp);
3399 else
3401 nNewHeight = ( pLowerFrame->getFrameArea().Height()
3402 * getFramePrintArea().Height() ) / rOldSize.Height();
3404 if( !pLowerFrame->GetNext() )
3406 SwTwips nSum = getFramePrintArea().Height();
3407 SwFrame* pTmp = Lower();
3408 while( pTmp->GetNext() )
3410 if( !pTmp->IsFootnoteContFrame() || !pTmp->IsVertical() )
3411 nSum -= pTmp->getFrameArea().Height();
3412 pTmp = pTmp->GetNext();
3414 if( nSum - nNewHeight == 1 &&
3415 nSum == pLowerFrame->getFrameArea().Height() )
3416 nNewHeight = nSum;
3419 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pLowerFrame);
3420 aFrm.Height( nNewHeight );
3425 } // end of else { NOT text frame }
3427 pLowerFrame->InvalidateAll_();
3428 if ( bInvaPageForContent && pLowerFrame->IsContentFrame() )
3430 pLowerFrame->InvalidatePage();
3431 bInvaPageForContent = false;
3434 if ( !pLowerFrame->GetNext() && pLowerFrame->IsRetoucheFrame() )
3436 //If a growth took place and the subordinate elements can retouch
3437 //itself (currently Tabs, Sections and Content) we trigger it.
3438 if ( rOldSize.Height() < getFramePrintArea().SSize().Height() ||
3439 rOldSize.Width() < getFramePrintArea().SSize().Width() )
3440 pLowerFrame->SetRetouche();
3442 pLowerFrame = pLowerFrame->GetNext();
3445 // Finally adjust the columns if width is set to auto
3446 // Possible optimization: execute this code earlier in this function and
3447 // return???
3448 if ( !(( (aRectFnSet.IsVert() && bHeightChgd) || (! aRectFnSet.IsVert() && bWidthChgd) ) &&
3449 Lower()->IsColumnFrame()) )
3450 return;
3452 // get column attribute
3453 const SwFormatCol* pColAttr = nullptr;
3454 if ( IsPageBodyFrame() )
3456 OSL_ENSURE( GetUpper()->IsPageFrame(), "Upper is not page frame" );
3457 pColAttr = &GetUpper()->GetFormat()->GetCol();
3459 else
3461 OSL_ENSURE( IsFlyFrame() || IsSctFrame(), "Columns not in fly or section" );
3462 pColAttr = &GetFormat()->GetCol();
3465 if ( pColAttr->IsOrtho() && pColAttr->GetNumCols() > 1 )
3466 AdjustColumns( pColAttr, false );
3469 /** "Formats" the Frame; Frame and PrtArea.
3471 * The Fixsize is not set here.
3473 void SwLayoutFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs *pAttrs )
3475 OSL_ENSURE( pAttrs, "LayoutFrame::Format, pAttrs is 0." );
3477 if ( isFramePrintAreaValid() && isFrameAreaSizeValid() )
3478 return;
3480 bool bHideWhitespace = false;
3481 if (IsPageFrame())
3483 SwViewShell* pShell = getRootFrame()->GetCurrShell();
3484 if (pShell && pShell->GetViewOptions()->IsWhitespaceHidden())
3486 // This is needed so that no space is reserved for the margin on
3487 // the last page of the document. Other pages would have no margin
3488 // set even without this, as their frame height is the content
3489 // height already.
3490 bHideWhitespace = true;
3494 const sal_uInt16 nLeft = o3tl::narrowing<sal_uInt16>(pAttrs->CalcLeft(this));
3495 const sal_uInt16 nUpper = bHideWhitespace ? 0 : pAttrs->CalcTop();
3497 const sal_uInt16 nRight = o3tl::narrowing<sal_uInt16>(pAttrs->CalcRight(this));
3498 const sal_uInt16 nLower = bHideWhitespace ? 0 : pAttrs->CalcBottom();
3500 const bool bVert = IsVertical() && !IsPageFrame();
3501 SwRectFn fnRect = bVert ? ( IsVertLR() ? (IsVertLRBT() ? fnRectVertL2RB2T : fnRectVertL2R) : fnRectVert ) : fnRectHori;
3502 if ( !isFramePrintAreaValid() )
3504 setFramePrintAreaValid(true);
3505 (this->*fnRect->fnSetXMargins)( nLeft, nRight );
3506 (this->*fnRect->fnSetYMargins)( nUpper, nLower );
3509 if ( isFrameAreaSizeValid() )
3510 return;
3512 if ( !HasFixSize() )
3514 const SwTwips nBorder = nUpper + nLower;
3515 const SwFormatFrameSize &rSz = GetFormat()->GetFrameSize();
3516 SwTwips nMinHeight = rSz.GetHeightSizeType() == SwFrameSize::Minimum ? rSz.GetHeight() : 0;
3519 setFrameAreaSizeValid(true);
3521 //The size in VarSize is calculated using the content plus the
3522 // borders.
3523 SwTwips nRemaining = 0;
3524 SwFrame *pFrame = Lower();
3525 while ( pFrame )
3526 { nRemaining += (pFrame->getFrameArea().*fnRect->fnGetHeight)();
3527 if( pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsUndersized() )
3528 // This TextFrame would like to be a bit bigger
3529 nRemaining += static_cast<SwTextFrame*>(pFrame)->GetParHeight()
3530 - (pFrame->getFramePrintArea().*fnRect->fnGetHeight)();
3531 else if( pFrame->IsSctFrame() && static_cast<SwSectionFrame*>(pFrame)->IsUndersized() )
3532 nRemaining += static_cast<SwSectionFrame*>(pFrame)->Undersize();
3533 pFrame = pFrame->GetNext();
3535 nRemaining += nBorder;
3536 nRemaining = std::max( nRemaining, nMinHeight );
3537 const SwTwips nDiff = nRemaining-(getFrameArea().*fnRect->fnGetHeight)();
3538 const tools::Long nOldLeft = (getFrameArea().*fnRect->fnGetLeft)();
3539 const tools::Long nOldTop = (getFrameArea().*fnRect->fnGetTop)();
3540 if ( nDiff )
3542 if ( nDiff > 0 )
3543 Grow( nDiff );
3544 else
3545 Shrink( -nDiff );
3546 //Updates the positions using the fast channel.
3547 MakePos();
3549 //Don't exceed the bottom edge of the Upper.
3550 if ( GetUpper() && (getFrameArea().*fnRect->fnGetHeight)() )
3552 const SwTwips nLimit = (GetUpper()->*fnRect->fnGetPrtBottom)();
3553 if( (this->*fnRect->fnSetLimit)( nLimit ) &&
3554 nOldLeft == (getFrameArea().*fnRect->fnGetLeft)() &&
3555 nOldTop == (getFrameArea().*fnRect->fnGetTop)() )
3557 setFrameAreaSizeValid(true);
3558 setFramePrintAreaValid(true);
3561 } while ( !isFrameAreaSizeValid() );
3563 else if (GetType() & FRM_HEADFOOT)
3566 { if ( getFrameArea().Height() != pAttrs->GetSize().Height() )
3568 ChgSize( Size( getFrameArea().Width(), pAttrs->GetSize().Height()));
3571 setFrameAreaSizeValid(true);
3572 MakePos();
3573 } while ( !isFrameAreaSizeValid() );
3575 else
3577 setFrameAreaSizeValid(true);
3580 // While updating the size, PrtArea might be invalidated.
3581 if (!isFramePrintAreaValid())
3583 setFramePrintAreaValid(true);
3584 (this->*fnRect->fnSetXMargins)(nLeft, nRight);
3585 (this->*fnRect->fnSetYMargins)(nUpper, nLower);
3589 static void InvaPercentFlys( SwFrame *pFrame, SwTwips nDiff )
3591 OSL_ENSURE( pFrame->GetDrawObjs(), "Can't find any Objects" );
3592 for (SwAnchoredObject* pAnchoredObj : *pFrame->GetDrawObjs())
3594 if ( auto pFly = pAnchoredObj->DynCastFlyFrame() )
3596 const SwFormatFrameSize &rSz = pFly->GetFormat()->GetFrameSize();
3597 if ( rSz.GetWidthPercent() || rSz.GetHeightPercent() )
3599 bool bNotify = true;
3600 // If we've a fly with more than 90% relative height...
3601 if( rSz.GetHeightPercent() > 90 && pFly->GetAnchorFrame() &&
3602 rSz.GetHeightPercent() != SwFormatFrameSize::SYNCED && nDiff )
3604 const SwFrame *pRel = pFly->IsFlyLayFrame() ? pFly->GetAnchorFrame():
3605 pFly->GetAnchorFrame()->GetUpper();
3606 // ... and we have already more than 90% height and we
3607 // not allow the text to go through...
3608 // then a notification could cause an endless loop, e.g.
3609 // 100% height and no text wrap inside a cell of a table.
3610 if( pFly->getFrameArea().Height()*10 >
3611 ( nDiff + pRel->getFramePrintArea().Height() )*9 &&
3612 pFly->GetFormat()->GetSurround().GetSurround() !=
3613 css::text::WrapTextMode_THROUGH )
3614 bNotify = false;
3616 if( bNotify )
3617 pFly->InvalidateSize();
3623 void SwLayoutFrame::InvaPercentLowers( SwTwips nDiff )
3625 if ( GetDrawObjs() )
3626 ::InvaPercentFlys( this, nDiff );
3628 SwFrame *pFrame = ContainsContent();
3629 if ( !pFrame )
3630 return;
3634 if ( pFrame->IsInTab() && !IsTabFrame() )
3636 SwFrame *pTmp = pFrame->FindTabFrame();
3637 OSL_ENSURE( pTmp, "Where's my TabFrame?" );
3638 if( IsAnLower( pTmp ) )
3639 pFrame = pTmp;
3642 if ( pFrame->IsTabFrame() )
3644 const SwFormatFrameSize &rSz = static_cast<SwLayoutFrame*>(pFrame)->GetFormat()->GetFrameSize();
3645 if ( rSz.GetWidthPercent() || rSz.GetHeightPercent() )
3646 pFrame->InvalidatePrt();
3648 else if ( pFrame->GetDrawObjs() )
3649 ::InvaPercentFlys( pFrame, nDiff );
3650 pFrame = pFrame->FindNextCnt();
3651 } while ( pFrame && IsAnLower( pFrame ) ) ;
3654 tools::Long SwLayoutFrame::CalcRel( const SwFormatFrameSize &rSz ) const
3656 tools::Long nRet = rSz.GetWidth(),
3657 nPercent = rSz.GetWidthPercent();
3659 if ( nPercent )
3661 const SwFrame *pRel = GetUpper();
3662 tools::Long nRel = LONG_MAX;
3663 const SwViewShell *pSh = getRootFrame()->GetCurrShell();
3664 const bool bBrowseMode = pSh && pSh->GetViewOptions()->getBrowseMode();
3665 if( pRel->IsPageBodyFrame() && pSh && bBrowseMode && pSh->VisArea().Width() )
3667 nRel = pSh->GetBrowseWidth();
3668 tools::Long nDiff = nRel - pRel->getFramePrintArea().Width();
3669 if ( nDiff > 0 )
3670 nRel -= nDiff;
3672 nRel = std::min( nRel, pRel->getFramePrintArea().Width() );
3673 nRet = nRel * nPercent / 100;
3675 return nRet;
3678 // Local helpers for SwLayoutFrame::FormatWidthCols()
3680 static tools::Long lcl_CalcMinColDiff( SwLayoutFrame *pLayFrame )
3682 tools::Long nDiff = 0, nFirstDiff = 0;
3683 SwLayoutFrame *pCol = static_cast<SwLayoutFrame*>(pLayFrame->Lower());
3684 OSL_ENSURE( pCol, "Where's the columnframe?" );
3685 SwFrame *pFrame = pCol->Lower();
3688 if( pFrame && pFrame->IsBodyFrame() )
3689 pFrame = static_cast<SwBodyFrame*>(pFrame)->Lower();
3690 if ( pFrame && pFrame->IsTextFrame() )
3692 const tools::Long nTmp = static_cast<SwTextFrame*>(pFrame)->FirstLineHeight();
3693 if ( nTmp != USHRT_MAX )
3695 if ( pCol == pLayFrame->Lower() )
3696 nFirstDiff = nTmp;
3697 else
3698 nDiff = nDiff ? std::min( nDiff, nTmp ) : nTmp;
3701 //Skip empty columns!
3702 pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
3703 while ( pCol && nullptr == (pFrame = pCol->Lower()) )
3704 pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
3706 } while ( pFrame && pCol );
3708 return nDiff ? nDiff : nFirstDiff ? nFirstDiff : 240;
3711 static bool lcl_IsFlyHeightClipped( SwLayoutFrame *pLay )
3713 SwFrame *pFrame = pLay->ContainsContent();
3714 while ( pFrame )
3716 if ( pFrame->IsInTab() )
3717 pFrame = pFrame->FindTabFrame();
3719 if ( pFrame->GetDrawObjs() )
3721 const size_t nCnt = pFrame->GetDrawObjs()->size();
3722 for ( size_t i = 0; i < nCnt; ++i )
3724 SwAnchoredObject* pAnchoredObj = (*pFrame->GetDrawObjs())[i];
3725 if ( auto pFly = pAnchoredObj->DynCastFlyFrame() )
3727 if ( pFly->IsHeightClipped() &&
3728 ( !pFly->IsFlyFreeFrame() || pFly->GetPageFrame() ) )
3729 return true;
3733 pFrame = pFrame->FindNextCnt();
3735 return false;
3738 void SwLayoutFrame::FormatWidthCols( const SwBorderAttrs &rAttrs,
3739 const SwTwips nBorder, const SwTwips nMinHeight )
3741 //If there are columns involved, the size is adjusted using the last column.
3742 //1. Format content.
3743 //2. Calculate height of the last column: if it's too big, the Fly has to
3744 // grow. The amount by which the Fly grows is not the amount of the
3745 // overhang because we have to act on the assumption that some text flows
3746 // back which will generate some more space.
3747 // The amount which we grow by equals the overhang
3748 // divided by the amount of columns or the overhang itself if it's smaller
3749 // than the amount of columns.
3750 //3. Go back to 1. until everything is stable.
3752 const SwFormatCol &rCol = rAttrs.GetAttrSet().GetCol();
3753 const sal_uInt16 nNumCols = rCol.GetNumCols();
3755 bool bEnd = false;
3756 bool bBackLock = false;
3757 SwViewShell *pSh = getRootFrame()->GetCurrShell();
3758 SwViewShellImp *pImp = pSh ? pSh->Imp() : nullptr;
3759 vcl::RenderContext* pRenderContext = pSh ? pSh->GetOut() : nullptr;
3761 // Underlying algorithm
3762 // We try to find the optimal height for the column.
3763 // nMinimum starts with the passed minimum height and is then remembered
3764 // as the maximum height on which column content still juts out of a
3765 // column.
3766 // nMaximum starts with LONG_MAX and is then remembered as the minimum
3767 // width on which the content fitted.
3768 // In column based sections nMaximum starts at the maximum value which
3769 // the surrounding defines, this can certainly be a value on which
3770 // content still juts out.
3771 // The columns are formatted. If content still juts out, nMinimum is
3772 // adjusted accordingly, then we grow, at least by uMinDiff but not
3773 // over a certain nMaximum. If no content juts out but there is still
3774 // some space left in the column, shrinking is done accordingly, at
3775 // least by nMindIff but not below the nMinimum.
3776 // Cancel as soon as no content juts out and the difference from minimum
3777 // to maximum is less than MinDiff or the maximum which was defined by
3778 // the surrounding is reached even if some content still juts out.
3780 // Criticism of this implementation
3781 // 1. Theoretically situations are possible in which the content fits in
3782 // a lower height but not in a higher height. To ensure that the code
3783 // handles such situations the code contains a few checks concerning
3784 // minimum and maximum which probably are never triggered.
3785 // 2. We use the same nMinDiff for shrinking and growing, but nMinDiff
3786 // is more or less the smallest first line height and doesn't seem ideal
3787 // as minimum value.
3789 tools::Long nMinimum = nMinHeight;
3790 tools::Long nMaximum;
3791 bool bNoBalance = false;
3792 SwRectFnSet aRectFnSet(this);
3793 if( IsSctFrame() )
3795 nMaximum = aRectFnSet.GetHeight(getFrameArea()) - nBorder +
3796 aRectFnSet.BottomDist(getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper()));
3797 nMaximum += GetUpper()->Grow( LONG_MAX, true );
3798 if( nMaximum < nMinimum )
3800 if( nMaximum < 0 )
3801 nMinimum = nMaximum = 0;
3802 else
3803 nMinimum = nMaximum;
3805 if( nMaximum > BROWSE_HEIGHT )
3806 nMaximum = BROWSE_HEIGHT;
3808 bNoBalance = static_cast<SwSectionFrame*>(this)->GetSection()->GetFormat()->
3809 GetBalancedColumns().GetValue();
3810 SwFrame* pAny = ContainsAny();
3811 if( bNoBalance ||
3812 ( !aRectFnSet.GetHeight(getFrameArea()) && pAny ) )
3814 tools::Long nTop = aRectFnSet.GetTopMargin(*this);
3815 // #i23129# - correction
3816 // to the calculated maximum height.
3818 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
3819 aRectFnSet.AddBottom( aFrm, nMaximum - aRectFnSet.GetHeight(getFrameArea()) );
3822 if( nTop > nMaximum )
3823 nTop = nMaximum;
3824 aRectFnSet.SetYMargins( *this, nTop, 0 );
3826 if( !pAny && !static_cast<SwSectionFrame*>(this)->IsFootnoteLock() )
3828 SwFootnoteContFrame* pFootnoteCont = static_cast<SwSectionFrame*>(this)->ContainsFootnoteCont();
3829 if( pFootnoteCont )
3831 SwFrame* pFootnoteAny = pFootnoteCont->ContainsAny();
3832 if( pFootnoteAny && pFootnoteAny->isFrameAreaDefinitionValid() )
3834 bBackLock = true;
3835 static_cast<SwSectionFrame*>(this)->SetFootnoteLock( true );
3840 else
3841 nMaximum = LONG_MAX;
3843 // #i3317# - reset temporarily consideration
3844 // of wrapping style influence
3845 SwPageFrame* pPageFrame = FindPageFrame();
3846 SwSortedObjs* pObjs = pPageFrame ? pPageFrame->GetSortedObjs() : nullptr;
3847 if ( pObjs )
3849 for (SwAnchoredObject* pAnchoredObj : *pObjs)
3851 if ( IsAnLower( pAnchoredObj->GetAnchorFrame() ) )
3853 pAnchoredObj->SetTmpConsiderWrapInfluence( false );
3859 //Could take a while therefore check for Waitcrsr here.
3860 if ( pImp )
3861 pImp->CheckWaitCursor();
3863 setFrameAreaSizeValid(true);
3864 //First format the column as this will relieve the stack a bit.
3865 //Also set width and height of the column (if they are wrong)
3866 //while we are at it.
3867 SwLayoutFrame *pCol = static_cast<SwLayoutFrame*>(Lower());
3869 // #i27399#
3870 // Simply setting the column width based on the values returned by
3871 // CalcColWidth does not work for automatic column width.
3872 AdjustColumns( &rCol, false );
3874 for ( sal_uInt16 i = 0; i < nNumCols; ++i )
3876 pCol->Calc(pRenderContext);
3877 // ColumnFrames have a BodyFrame now, which needs to be calculated
3878 pCol->Lower()->Calc(pRenderContext);
3879 if( pCol->Lower()->GetNext() )
3880 pCol->Lower()->GetNext()->Calc(pRenderContext); // SwFootnoteCont
3881 pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
3884 ::CalcContent( this );
3886 pCol = static_cast<SwLayoutFrame*>(Lower());
3887 OSL_ENSURE( pCol && pCol->GetNext(), ":-( column making holidays?");
3888 // set bMinDiff if no empty columns exist
3889 bool bMinDiff = true;
3890 // OD 28.03.2003 #108446# - check for all column content and all columns
3891 while ( bMinDiff && pCol )
3893 bMinDiff = nullptr != pCol->ContainsContent();
3894 pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
3896 pCol = static_cast<SwLayoutFrame*>(Lower());
3897 // OD 28.03.2003 #108446# - initialize local variable
3898 SwTwips nDiff = 0;
3899 SwTwips nMaxFree = 0;
3900 SwTwips nAllFree = LONG_MAX;
3901 // set bFoundLower if there is at least one non-empty column
3902 bool bFoundLower = false;
3903 while( pCol )
3905 SwLayoutFrame* pLay = static_cast<SwLayoutFrame*>(pCol->Lower());
3906 SwTwips nInnerHeight = aRectFnSet.GetHeight(pLay->getFrameArea()) -
3907 aRectFnSet.GetHeight(pLay->getFramePrintArea());
3908 if( pLay->Lower() )
3910 bFoundLower = true;
3911 nInnerHeight += pLay->InnerHeight();
3913 else if( nInnerHeight < 0 )
3914 nInnerHeight = 0;
3916 if( pLay->GetNext() )
3918 bFoundLower = true;
3919 pLay = static_cast<SwLayoutFrame*>(pLay->GetNext());
3920 OSL_ENSURE( pLay->IsFootnoteContFrame(),"FootnoteContainer expected" );
3921 nInnerHeight += pLay->InnerHeight();
3922 nInnerHeight += aRectFnSet.GetHeight(pLay->getFrameArea()) -
3923 aRectFnSet.GetHeight(pLay->getFramePrintArea());
3925 nInnerHeight -= aRectFnSet.GetHeight(pCol->getFramePrintArea());
3926 if( nInnerHeight > nDiff )
3928 nDiff = nInnerHeight;
3929 nAllFree = 0;
3931 else
3933 if( nMaxFree < -nInnerHeight )
3934 nMaxFree = -nInnerHeight;
3935 if( nAllFree > -nInnerHeight )
3936 nAllFree = -nInnerHeight;
3938 pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
3941 if ( bFoundLower || ( IsSctFrame() && static_cast<SwSectionFrame*>(this)->HasFollow() ) )
3943 SwTwips nMinDiff = ::lcl_CalcMinColDiff( this );
3944 // Here we decide if growing is needed - this is the case, if
3945 // column content (nDiff) or a Fly juts over.
3946 // In sections with columns we take into account to set the size
3947 // when having a non-empty Follow.
3948 if ( nDiff || ::lcl_IsFlyHeightClipped( this ) ||
3949 ( IsSctFrame() && static_cast<SwSectionFrame*>(this)->CalcMinDiff( nMinDiff ) ) )
3951 tools::Long nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
3952 // The minimum must not be smaller than our PrtHeight as
3953 // long as something juts over.
3954 if( nMinimum < nPrtHeight )
3955 nMinimum = nPrtHeight;
3956 // The maximum must not be smaller than PrtHeight if
3957 // something still juts over.
3958 if( nMaximum < nPrtHeight )
3959 nMaximum = nPrtHeight; // Robust, but will this ever happen?
3960 if( !nDiff ) // If only Flys jut over, we grow by nMinDiff
3961 nDiff = nMinDiff;
3962 // If we should grow more than by nMinDiff we split it over
3963 // the columns
3964 if ( std::abs(nDiff - nMinDiff) > nNumCols && nDiff > static_cast<tools::Long>(nNumCols) )
3965 nDiff /= nNumCols;
3967 if ( bMinDiff )
3968 { // If no empty column exists, we want to grow at least
3969 // by nMinDiff. Special case: If we are smaller than the
3970 // minimal FrameHeight and PrtHeight is smaller than
3971 // nMindiff we grow in a way that PrtHeight is exactly
3972 // nMinDiff afterwards.
3973 tools::Long nFrameHeight = aRectFnSet.GetHeight(getFrameArea());
3974 if ( nFrameHeight > nMinHeight || nPrtHeight >= nMinDiff )
3975 nDiff = std::max( nDiff, nMinDiff );
3976 else if( nDiff < nMinDiff )
3977 nDiff = nMinDiff - nPrtHeight + 1;
3979 // nMaximum has a size which fits the content or the
3980 // requested value from the surrounding therefore we don't
3981 // need to exceed this value.
3982 if( nDiff + nPrtHeight > nMaximum )
3983 nDiff = nMaximum - nPrtHeight;
3985 else if( nMaximum > nMinimum ) // We fit, do we still have some margin?
3987 tools::Long nPrtHeight = aRectFnSet.GetHeight(getFramePrintArea());
3988 if ( nMaximum < nPrtHeight )
3989 nDiff = nMaximum - nPrtHeight; // We grew over a working
3990 // height and shrink back to it, but will this ever
3991 // happen?
3992 else
3993 { // We have a new maximum, a size which fits for the content.
3994 nMaximum = nPrtHeight;
3995 // If the margin in the column is bigger than nMinDiff
3996 // and we therefore drop under the minimum, we deflate
3997 // a bit.
3998 if ( !bNoBalance &&
3999 // #i23129# - <nMinDiff> can be
4000 // big, because of an object at the beginning of
4001 // a column. Thus, decrease optimization here.
4002 //nMaxFree >= nMinDiff &&
4003 nMaxFree > 0 &&
4004 ( !nAllFree ||
4005 nMinimum < nPrtHeight - nMinDiff ) )
4007 nMaxFree /= nNumCols; // disperse over the columns
4008 nDiff = nMaxFree < nMinDiff ? -nMinDiff : -nMaxFree; // min nMinDiff
4009 if( nPrtHeight + nDiff <= nMinimum ) // below the minimum?
4010 nDiff = ( nMinimum - nMaximum ) / 2; // Take the center
4012 else if( nAllFree )
4014 nDiff = -nAllFree;
4015 if( nPrtHeight + nDiff <= nMinimum ) // Less than minimum?
4016 nDiff = ( nMinimum - nMaximum ) / 2; // Take the center
4020 if( nDiff ) // now we shrink or grow...
4022 Size aOldSz( getFramePrintArea().SSize() );
4023 tools::Long nTop = aRectFnSet.GetTopMargin(*this);
4024 nDiff = aRectFnSet.GetHeight(getFramePrintArea()) + nDiff + nBorder - aRectFnSet.GetHeight(getFrameArea());
4027 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
4028 aRectFnSet.AddBottom( aFrm, nDiff );
4031 // #i68520#
4032 SwFlyFrame *pFlyFrame = IsFlyFrame() ? static_cast<SwFlyFrame*>(this) : nullptr;
4033 if (pFlyFrame)
4035 pFlyFrame->InvalidateObjRectWithSpaces();
4037 aRectFnSet.SetYMargins( *this, nTop, nBorder - nTop );
4038 ChgLowersProp( aOldSz );
4039 NotifyLowerObjs();
4041 // #i3317# - reset temporarily consideration
4042 // of wrapping style influence
4043 SwPageFrame* pTmpPageFrame = FindPageFrame();
4044 SwSortedObjs* pTmpObjs = pTmpPageFrame ? pTmpPageFrame->GetSortedObjs() : nullptr;
4045 if ( pTmpObjs )
4047 for (SwAnchoredObject* pAnchoredObj : *pTmpObjs)
4049 if ( IsAnLower( pAnchoredObj->GetAnchorFrame() ) )
4051 pAnchoredObj->SetTmpConsiderWrapInfluence( false );
4055 //Invalidate suitable to nicely balance the Frames.
4056 //- Every first one after the second column gets a
4057 // InvalidatePos();
4058 pCol = static_cast<SwLayoutFrame*>(Lower()->GetNext());
4059 while ( pCol )
4061 SwFrame *pLow = pCol->Lower();
4062 if ( pLow )
4063 pLow->InvalidatePos_();
4064 pCol = static_cast<SwLayoutFrame*>(pCol->GetNext());
4066 if( IsSctFrame() && static_cast<SwSectionFrame*>(this)->HasFollow() )
4068 // If we created a Follow, we need to give its content
4069 // the opportunity to flow back inside the CalcContent
4070 SwContentFrame* pTmpContent =
4071 static_cast<SwSectionFrame*>(this)->GetFollow()->ContainsContent();
4072 if( pTmpContent )
4073 pTmpContent->InvalidatePos_();
4076 else
4077 bEnd = true;
4079 else
4080 bEnd = true;
4082 } while ( !bEnd || !isFrameAreaSizeValid() );
4084 // OD 01.04.2003 #108446# - Don't collect endnotes for sections. Thus, set
4085 // 2nd parameter to <true>.
4086 ::CalcContent( this, true );
4087 if( IsSctFrame() )
4089 // OD 14.03.2003 #i11760# - adjust 2nd parameter - sal_True --> true
4090 setFrameAreaSizeValid(true);
4091 ::CalcContent( this, true );
4092 if( bBackLock )
4093 static_cast<SwSectionFrame*>(this)->SetFootnoteLock( false );
4097 static SwContentFrame* lcl_InvalidateSection( SwFrame *pCnt, SwInvalidateFlags nInv )
4099 SwSectionFrame* pSect = pCnt->FindSctFrame();
4100 // If our ContentFrame is placed inside a table or a footnote, only sections
4101 // which are also placed inside are meant.
4102 // Exception: If a table is directly passed.
4103 if( ( ( pCnt->IsInTab() && !pSect->IsInTab() ) ||
4104 ( pCnt->IsInFootnote() && !pSect->IsInFootnote() ) ) && !pCnt->IsTabFrame() )
4105 return nullptr;
4106 if( nInv & SwInvalidateFlags::Size )
4107 pSect->InvalidateSize_();
4108 if( nInv & SwInvalidateFlags::Pos )
4109 pSect->InvalidatePos_();
4110 if( nInv & SwInvalidateFlags::PrtArea )
4111 pSect->InvalidatePrt_();
4112 SwFlowFrame *pFoll = pSect->GetFollow();
4113 // Temporary separation from follow
4114 pSect->SetFollow( nullptr );
4115 SwContentFrame* pRet = pSect->FindLastContent();
4116 pSect->SetFollow( pFoll );
4117 return pRet;
4120 static SwContentFrame* lcl_InvalidateTable( SwTabFrame *pTable, SwInvalidateFlags nInv )
4122 if( ( nInv & SwInvalidateFlags::Section ) && pTable->IsInSct() )
4123 lcl_InvalidateSection( pTable, nInv );
4124 if( nInv & SwInvalidateFlags::Size )
4125 pTable->InvalidateSize_();
4126 if( nInv & SwInvalidateFlags::Pos )
4127 pTable->InvalidatePos_();
4128 if( nInv & SwInvalidateFlags::PrtArea )
4129 pTable->InvalidatePrt_();
4130 return pTable->FindLastContent();
4133 static void lcl_InvalidateAllContent( SwContentFrame *pCnt, SwInvalidateFlags nInv );
4135 static void lcl_InvalidateContent( SwContentFrame *pCnt, SwInvalidateFlags nInv )
4137 SwContentFrame *pLastTabCnt = nullptr;
4138 SwContentFrame *pLastSctCnt = nullptr;
4139 while ( pCnt )
4141 if( nInv & SwInvalidateFlags::Section )
4143 if( pCnt->IsInSct() )
4145 // See above at tables
4146 if( !pLastSctCnt )
4147 pLastSctCnt = lcl_InvalidateSection( pCnt, nInv );
4148 if( pLastSctCnt == pCnt )
4149 pLastSctCnt = nullptr;
4151 #if OSL_DEBUG_LEVEL > 0
4152 else
4153 OSL_ENSURE( !pLastSctCnt, "Where's the last SctContent?" );
4154 #endif
4156 if( nInv & SwInvalidateFlags::Table )
4158 if( pCnt->IsInTab() )
4160 // To not call FindTabFrame() for each ContentFrame of a table and
4161 // then invalidate the table, we remember the last ContentFrame of
4162 // the table and ignore IsInTab() until we are past it.
4163 // When entering the table, LastSctCnt is set to null, so
4164 // sections inside the table are correctly invalidated.
4165 // If the table itself is in a section the
4166 // invalidation is done three times, which is acceptable.
4167 if( !pLastTabCnt )
4169 pLastTabCnt = lcl_InvalidateTable( pCnt->FindTabFrame(), nInv );
4170 pLastSctCnt = nullptr;
4172 if( pLastTabCnt == pCnt )
4174 pLastTabCnt = nullptr;
4175 pLastSctCnt = nullptr;
4178 #if OSL_DEBUG_LEVEL > 0
4179 else
4180 OSL_ENSURE( !pLastTabCnt, "Where's the last TabContent?" );
4181 #endif
4184 if( nInv & SwInvalidateFlags::Size )
4185 pCnt->Prepare( PrepareHint::Clear, nullptr, false );
4186 if( nInv & SwInvalidateFlags::Pos )
4187 pCnt->InvalidatePos_();
4188 if( nInv & SwInvalidateFlags::PrtArea )
4189 pCnt->InvalidatePrt_();
4190 if ( nInv & SwInvalidateFlags::LineNum )
4191 pCnt->InvalidateLineNum();
4192 if ( pCnt->GetDrawObjs() )
4193 lcl_InvalidateAllContent( pCnt, nInv );
4194 pCnt = pCnt->GetNextContentFrame();
4198 static void lcl_InvalidateAllContent( SwContentFrame *pCnt, SwInvalidateFlags nInv )
4200 SwSortedObjs &rObjs = *pCnt->GetDrawObjs();
4201 for (SwAnchoredObject* pAnchoredObj : rObjs)
4203 if ( auto pFly = pAnchoredObj->DynCastFlyFrame() )
4205 if ( pFly->IsFlyInContentFrame() )
4207 ::lcl_InvalidateContent( pFly->ContainsContent(), nInv );
4208 if( nInv & SwInvalidateFlags::Direction )
4209 pFly->CheckDirChange();
4215 void SwRootFrame::InvalidateAllContent( SwInvalidateFlags nInv )
4217 // First process all page bound FlyFrames.
4218 SwPageFrame *pPage = static_cast<SwPageFrame*>(Lower());
4219 while( pPage )
4221 pPage->InvalidateFlyLayout();
4222 pPage->InvalidateFlyContent();
4223 pPage->InvalidateFlyInCnt();
4224 pPage->InvalidateLayout();
4225 pPage->InvalidateContent();
4226 pPage->InvalidatePage( pPage ); // So even the Turbo disappears if applicable
4228 if ( pPage->GetSortedObjs() )
4230 const SwSortedObjs &rObjs = *pPage->GetSortedObjs();
4231 for (SwAnchoredObject* pAnchoredObj : rObjs)
4233 if ( auto pFly = pAnchoredObj->DynCastFlyFrame() )
4235 ::lcl_InvalidateContent( pFly->ContainsContent(), nInv );
4236 if ( nInv & SwInvalidateFlags::Direction )
4237 pFly->CheckDirChange();
4241 if( nInv & SwInvalidateFlags::Direction )
4242 pPage->CheckDirChange();
4243 pPage = static_cast<SwPageFrame*>(pPage->GetNext());
4246 //Invalidate the whole document content and the character bound Flys here.
4247 ::lcl_InvalidateContent( ContainsContent(), nInv );
4249 if( nInv & SwInvalidateFlags::PrtArea )
4251 SwViewShell *pSh = getRootFrame()->GetCurrShell();
4252 if( pSh )
4253 pSh->InvalidateWindows( getFrameArea() );
4258 * Invalidate/re-calculate the position of all floating screen objects (Writer fly frames and
4259 * drawing objects), that are anchored to paragraph or to character. (2004-03-16 #i11860#)
4261 void SwRootFrame::InvalidateAllObjPos()
4263 const SwPageFrame* pPageFrame = static_cast<const SwPageFrame*>(Lower());
4264 while( pPageFrame )
4266 pPageFrame->InvalidateFlyLayout();
4268 if ( pPageFrame->GetSortedObjs() )
4270 const SwSortedObjs& rObjs = *(pPageFrame->GetSortedObjs());
4271 for (SwAnchoredObject* pAnchoredObj : rObjs)
4273 const SwFormatAnchor& rAnch = pAnchoredObj->GetFrameFormat().GetAnchor();
4274 if ((rAnch.GetAnchorId() != RndStdIds::FLY_AT_PARA) &&
4275 (rAnch.GetAnchorId() != RndStdIds::FLY_AT_CHAR))
4277 // only to paragraph and to character anchored objects are considered.
4278 continue;
4280 // #i28701# - special invalidation for anchored
4281 // objects, whose wrapping style influence has to be considered.
4282 if ( pAnchoredObj->ConsiderObjWrapInfluenceOnObjPos() )
4283 pAnchoredObj->InvalidateObjPosForConsiderWrapInfluence();
4284 else
4285 pAnchoredObj->InvalidateObjPos();
4289 pPageFrame = static_cast<const SwPageFrame*>(pPageFrame->GetNext());
4293 static void AddRemoveFlysForNode(
4294 SwTextFrame & rFrame, SwTextNode & rTextNode,
4295 std::set<SwNodeOffset> *const pSkipped,
4296 const sw::FrameFormats<sw::SpzFrameFormat*>& rTable,
4297 SwPageFrame *const pPage,
4298 SwTextNode const*const pNode,
4299 std::vector<sw::Extent>::const_iterator const& rIterFirst,
4300 std::vector<sw::Extent>::const_iterator const& rIterEnd,
4301 SwTextNode const*const pFirstNode, SwTextNode const*const pLastNode)
4303 if (pNode == &rTextNode)
4304 { // remove existing hidden at-char anchored flys
4305 RemoveHiddenObjsOfNode(rTextNode, &rIterFirst, &rIterEnd, pFirstNode, pLastNode);
4307 else if (rTextNode.GetIndex() < pNode->GetIndex())
4309 // pNode's frame has been deleted by CheckParaRedlineMerge()
4310 AppendObjsOfNode(&rTable,
4311 pNode->GetIndex(), &rFrame, pPage, &rTextNode.GetDoc(),
4312 &rIterFirst, &rIterEnd, pFirstNode, pLastNode);
4313 if (pSkipped)
4315 // if a fly has been added by AppendObjsOfNode, it must be skipped; if not, then it doesn't matter if it's skipped or not because it has no frames and because of that it would be skipped anyway
4316 for (auto const pFly : pNode->GetAnchoredFlys())
4318 if (pFly->Which() != RES_DRAWFRMFMT)
4320 pSkipped->insert(pFly->GetContent().GetContentIdx()->GetIndex());
4327 namespace sw {
4329 /// rTextNode is the first one of the "new" merge - if rTextNode isn't the same
4330 /// as MergedPara::pFirstNode, then nodes before rTextNode have their flys
4331 /// already properly attached, so only the other nodes need handling here.
4332 void AddRemoveFlysAnchoredToFrameStartingAtNode(
4333 SwTextFrame & rFrame, SwTextNode & rTextNode,
4334 std::set<SwNodeOffset> *const pSkipped)
4336 auto const pMerged(rFrame.GetMergedPara());
4337 if (!pMerged
4338 // do this only *once*, for the *last* frame
4339 // otherwise AppendObj would create multiple frames for fly-frames!
4340 || rFrame.GetFollow())
4341 return;
4343 assert(pMerged->pFirstNode->GetIndex() <= rTextNode.GetIndex()
4344 && rTextNode.GetIndex() <= pMerged->pLastNode->GetIndex());
4345 // add visible flys in non-first node to merged frame
4346 // (hidden flys remain and are deleted via DelFrames())
4347 sw::SpzFrameFormats& rTable(*rTextNode.GetDoc().GetSpzFrameFormats());
4348 SwPageFrame *const pPage(rFrame.FindPageFrame());
4349 std::vector<sw::Extent>::const_iterator iterFirst(pMerged->extents.begin());
4350 std::vector<sw::Extent>::const_iterator iter(iterFirst);
4351 SwTextNode const* pNode(pMerged->pFirstNode);
4352 for ( ; ; ++iter)
4354 if (iter == pMerged->extents.end()
4355 || iter->pNode != pNode)
4357 AddRemoveFlysForNode(rFrame, rTextNode, pSkipped, rTable, pPage,
4358 pNode, iterFirst, iter,
4359 pMerged->pFirstNode, pMerged->pLastNode);
4360 SwNodeOffset const until = iter == pMerged->extents.end()
4361 ? pMerged->pLastNode->GetIndex() + 1
4362 : iter->pNode->GetIndex();
4363 for (SwNodeOffset i = pNode->GetIndex() + 1; i < until; ++i)
4365 // let's show at-para flys on nodes that contain start/end of
4366 // redline too, even if there's no text there
4367 SwNode const*const pTmp(pNode->GetNodes()[i]);
4368 if (pTmp->GetRedlineMergeFlag() == SwNode::Merge::NonFirst)
4370 AddRemoveFlysForNode(rFrame, rTextNode, pSkipped,
4371 rTable, pPage, pTmp->GetTextNode(), iter, iter,
4372 pMerged->pFirstNode, pMerged->pLastNode);
4375 if (iter == pMerged->extents.end())
4377 break;
4379 pNode = iter->pNode;
4380 iterFirst = iter;
4385 } // namespace sw
4387 static void UnHideRedlines(SwRootFrame & rLayout,
4388 SwNodes & rNodes, SwNode const& rEndOfSectionNode,
4389 std::set<SwNodeOffset> *const pSkipped)
4391 assert(rEndOfSectionNode.IsEndNode());
4392 assert(rNodes[rEndOfSectionNode.StartOfSectionNode()->GetIndex() + 1]->IsCreateFrameWhenHidingRedlines()); // first node is never hidden
4393 for (SwNodeOffset i = rEndOfSectionNode.StartOfSectionNode()->GetIndex() + 1;
4394 i < rEndOfSectionNode.GetIndex(); ++i)
4396 SwNode & rNode(*rNodes[i]);
4397 if (rNode.IsTextNode()) // only text nodes are 1st node of a merge
4399 SwTextNode & rTextNode(*rNode.GetTextNode());
4400 SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(rTextNode);
4401 std::vector<SwTextFrame*> frames;
4402 for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
4404 if (pFrame->getRootFrame() == &rLayout)
4406 if (pFrame->IsFollow())
4408 frames.push_back(pFrame);
4409 } // when hiding, the loop must remove the anchored flys
4410 else // *before* resetting SetMergedPara anywhere - else
4411 { // the fly deletion code will access multiple of the
4412 // frames with inconsistent MergedPara and assert
4413 frames.insert(frames.begin(), pFrame);
4417 // this messes with pRegisteredIn so do it outside SwIterator
4418 auto eMode(sw::FrameMode::Existing);
4419 for (SwTextFrame * pFrame : frames)
4421 if (rLayout.HasMergedParas())
4423 assert(!pFrame->GetMergedPara() ||
4424 !rNode.IsCreateFrameWhenHidingRedlines() ||
4425 // FIXME: skip this assert in tables with deleted rows
4426 pFrame->IsInTab());
4427 if (rNode.IsCreateFrameWhenHidingRedlines())
4430 auto pMerged(CheckParaRedlineMerge(*pFrame,
4431 rTextNode, eMode));
4432 pFrame->SetMergedPara(std::move(pMerged));
4434 auto const pMerged(pFrame->GetMergedPara());
4435 if (pMerged)
4437 // invalidate SwInvalidateFlags::Size
4438 pFrame->Prepare(PrepareHint::Clear, nullptr, false);
4439 pFrame->InvalidatePage();
4440 if (auto const pObjs = pFrame->GetDrawObjs())
4441 { // also invalidate position of existing flys
4442 // because they may need to be moved
4443 for (auto const pObject : *pObjs)
4445 pObject->InvalidateObjPos();
4449 sw::AddRemoveFlysAnchoredToFrameStartingAtNode(*pFrame, rTextNode, pSkipped);
4450 // only *first* frame of node gets Existing because it
4451 eMode = sw::FrameMode::New; // is not idempotent!
4454 else
4456 if (auto const& pMergedPara = pFrame->GetMergedPara())
4458 // invalidate SwInvalidateFlags::Size
4459 pFrame->Prepare(PrepareHint::Clear, nullptr, false);
4460 pFrame->InvalidatePage();
4461 if (auto const pObjs = pFrame->GetDrawObjs())
4462 { // also invalidate position of existing flys
4463 for (auto const pObject : *pObjs)
4465 pObject->InvalidateObjPos();
4468 // SwFlyAtContentFrame::SwClientNotify() always appends to
4469 // the master frame, so do the same here.
4470 // (RemoveFootnotesForNode must be called at least once)
4471 if (!pFrame->IsFollow())
4473 // the new text frames don't exist yet, so at this point
4474 // we can only delete the footnote frames so they don't
4475 // point to the merged SwTextFrame any more...
4476 assert(&rTextNode == pMergedPara->pFirstNode);
4477 // iterate over nodes, not extents: if a node has
4478 // no extents now but did have extents initially,
4479 // its flys need their frames deleted too!
4480 for (SwNodeOffset j = rTextNode.GetIndex() + 1;
4481 j <= pMergedPara->pLastNode->GetIndex(); ++j)
4483 SwNode *const pNode(rTextNode.GetNodes()[j]);
4484 assert(!pNode->IsEndNode());
4485 if (pNode->IsStartNode())
4487 j = pNode->EndOfSectionIndex();
4489 else if (pNode->IsTextNode())
4491 sw::RemoveFootnotesForNode(rLayout, *pNode->GetTextNode(), nullptr);
4492 // similarly, remove the anchored flys
4493 for (SwFrameFormat * pFormat : pNode->GetAnchoredFlys())
4495 pFormat->DelFrames(/*&rLayout*/);
4499 // rely on AppendAllObjs call at the end to add
4500 // all flys in first node that are hidden
4502 pFrame->SetMergedPara(nullptr);
4505 pFrame->Broadcast(SfxHint()); // notify SwAccessibleParagraph
4507 // all nodes, not just merged ones! it may be in the same list as
4508 if (rTextNode.IsNumbered(nullptr)) // a preceding merged one...
4509 { // notify frames so they reformat numbering portions
4510 rTextNode.NumRuleChgd();
4513 else if (rNode.IsTableNode() && rLayout.IsHideRedlines())
4515 SwTableNode * pTableNd = rNode.GetTableNode();
4516 SwPosition const tmp(rNode);
4517 SwRangeRedline const*const pRedline(
4518 rLayout.GetFormat()->GetDoc()->getIDocumentRedlineAccess().GetRedline(tmp, nullptr));
4519 // pathology: redline that starts on a TableNode; cannot
4520 // be created in UI but by import filters...
4521 if (pRedline
4522 && pRedline->GetType() == RedlineType::Delete
4523 && &pRedline->Start()->GetNode() == &rNode)
4525 for (SwNodeOffset j = rNode.GetIndex(); j <= rNode.EndOfSectionIndex(); ++j)
4527 rNode.GetNodes()[j]->SetRedlineMergeFlag(SwNode::Merge::Hidden);
4529 pTableNd->DelFrames(&rLayout);
4531 else if ( pTableNd->GetTable().HasDeletedRowOrCell() )
4533 pTableNd->DelFrames(&rLayout);
4534 if ( !pTableNd->GetTable().IsDeleted() )
4536 pTableNd->MakeOwnFrames();
4540 else if (rNode.IsTableNode() && !rLayout.IsHideRedlines() &&
4541 rNode.GetTableNode()->GetTable().HasDeletedRowOrCell() )
4543 SwTableNode * pTableNd = rNode.GetTableNode();
4544 pTableNd->DelFrames(&rLayout);
4545 pTableNd->MakeOwnFrames();
4548 if (!rNode.IsCreateFrameWhenHidingRedlines())
4550 if (rLayout.HasMergedParas())
4552 if (rNode.IsContentNode())
4554 // note: nothing to do here, already done
4555 #ifndef NDEBUG
4556 auto const pFrame(static_cast<SwContentNode&>(rNode).getLayoutFrame(&rLayout));
4557 assert(!pFrame || static_cast<SwTextFrame*>(pFrame)->GetMergedPara()->pFirstNode != &rNode);
4558 #endif
4561 else
4563 assert(!rNode.IsContentNode() || !rNode.GetContentNode()->getLayoutFrame(&rLayout) ||
4564 // FIXME: skip this assert in tables with deleted rows
4565 rNode.GetContentNode()->getLayoutFrame(&rLayout)->IsInTab());
4566 SwNodeOffset j = i + 1;
4567 for ( ; j < rEndOfSectionNode.GetIndex(); ++j)
4569 if (rNodes[j]->IsCreateFrameWhenHidingRedlines())
4571 break;
4574 // call MakeFrames once, because sections/tables
4575 // InsertCnt_ also checks for hidden sections
4577 sw::FlyCreationSuppressor aSuppressor(false);
4578 ::MakeFrames(rLayout.GetFormat()->GetDoc(), *rNodes[i], *rNodes[j]);
4580 i = j - 1; // will be incremented again
4586 static void UnHideRedlinesExtras(SwRootFrame & rLayout,
4587 SwNodes & rNodes, SwNode const& rEndOfExtraSectionNode,
4588 std::set<SwNodeOffset> *const pSkipped)
4590 assert(rEndOfExtraSectionNode.IsEndNode());
4591 for (SwNodeOffset i = rEndOfExtraSectionNode.StartOfSectionNode()->GetIndex()
4592 + 1; i < rEndOfExtraSectionNode.GetIndex(); ++i)
4594 SwNode const& rStartNode(*rNodes[i]);
4595 assert(rStartNode.IsStartNode());
4596 assert(rStartNode.GetRedlineMergeFlag() == SwNode::Merge::None);
4597 SwNode const& rEndNode(*rStartNode.EndOfSectionNode());
4598 bool bSkip(pSkipped && pSkipped->find(i) != pSkipped->end());
4599 i = rEndNode.GetIndex();
4600 for (SwNodeOffset j = rStartNode.GetIndex() + 1; j < i; ++j)
4602 // note: SwStartNode has no way to access the frames, so check
4603 // whether the first content-node inside the section has frames
4604 SwNode const& rNode(*rNodes[j]);
4605 if (rNode.IsSectionNode() &&
4606 static_cast<SwSectionNode const&>(rNode).GetSection().IsHiddenFlag())
4607 { // skip hidden sections - they can be inserted in fly-frames :(
4608 j = rNode.EndOfSectionNode()->GetIndex();
4609 continue;
4611 if (rNode.IsContentNode())
4613 SwContentNode const& rCNode(static_cast<SwContentNode const&>(rNode));
4614 if (!rCNode.getLayoutFrame(&rLayout))
4615 { // ignore footnote/fly/header/footer with no layout frame
4616 bSkip = true; // they will be created from scratch later if needed
4618 break;
4621 if (!bSkip)
4623 UnHideRedlines(rLayout, rNodes, rEndNode, pSkipped);
4628 static void UnHide(SwRootFrame & rLayout)
4630 assert(rLayout.GetCurrShell()->ActionPend()); // tdf#125754 avoid recursive layout
4631 SwDoc & rDoc(*rLayout.GetFormat()->GetDoc());
4632 // don't do early return if there are no redlines:
4633 // Show->Hide must init hidden number trees
4634 // Hide->Show may be called after all redlines have been deleted but there
4635 // may still be MergedParas because those aren't deleted yet...
4636 #if 0
4637 if (!bHideRedlines
4638 && rDoc.getIDocumentRedlineAccess().GetRedlineTable().empty())
4640 return;
4642 #endif
4643 // Hide->Show: clear MergedPara, create frames
4644 // Show->Hide: call CheckParaRedlineMerge, delete frames
4645 // Traverse the document via the nodes-array; traversing via the layout
4646 // wouldn't find the nodes that don't have frames in the ->Show case.
4647 // In-order traversal of each nodes array section should init the flags
4648 // in nodes before they are iterated.
4649 // Actual creation of frames should be done with existing functions
4650 // if possible, particularly InsertCnt_() or its wrapper ::MakeFrames().
4651 SwNodes /*const*/& rNodes(rDoc.GetNodes());
4652 // Flys/footnotes: must iterate and find all the ones that already exist
4653 // with frames and have redlines inside them; if any don't have frames at
4654 // all, they will be created (if necessary) from scratch and completely by
4655 // MakeFrames().
4657 // Flys before footnotes: because footnotes may contain flys but not
4658 // vice-versa; alas flys may contain flys, so we skip some of them
4659 // if they have already been created from scratch via their anchor flys.
4660 std::set<SwNodeOffset> skippedFlys;
4661 UnHideRedlinesExtras(rLayout, rNodes, rNodes.GetEndOfAutotext(),
4662 // when un-hiding, delay all fly frame creation to AppendAllObjs below
4663 rLayout.HasMergedParas() ? &skippedFlys : nullptr);
4664 // Footnotes are created automatically (after invalidation etc.) by
4665 // ConnectFootnote(), but need to be deleted manually. Footnotes do not
4666 // occur in flys or headers/footers.
4667 UnHideRedlinesExtras(rLayout, rNodes, rNodes.GetEndOfInserts(), nullptr);
4668 UnHideRedlines(rLayout, rNodes, rNodes.GetEndOfContent(), nullptr);
4670 if (!rLayout.HasMergedParas())
4671 { // create all previously hidden flys at once:
4672 // * Flys on first node of pre-existing merged frames that are hidden
4673 // (in delete redline), to be added to the existing frame
4674 // * Flys on non-first (hidden/merged) nodes of pre-existing merged
4675 // frames, to be added to the new frame of their node
4676 // * Flys anchored in other flys that are hidden
4677 AppendAllObjs(rDoc.GetSpzFrameFormats(), &rLayout);
4680 const bool bIsShowChangesInMargin = rLayout.GetCurrShell()->GetViewOptions()->IsShowChangesInMargin();
4681 for (auto const pRedline : rDoc.getIDocumentRedlineAccess().GetRedlineTable())
4682 { // DELETE are handled by the code above; for other types, need to
4683 // trigger repaint of text frames to add/remove the redline color font
4684 // (handle deletions showed in margin also here)
4685 if (bIsShowChangesInMargin || pRedline->GetType() != RedlineType::Delete)
4687 pRedline->InvalidateRange(SwRangeRedline::Invalidation::Add);
4691 SwFootnoteIdxs & rFootnotes(rDoc.GetFootnoteIdxs());
4692 if (rDoc.GetFootnoteInfo().m_eNum == FTNNUM_CHAPTER)
4694 // sadly determining which node is outline node requires hidden layout
4695 rFootnotes.UpdateAllFootnote();
4697 // invalidate all footnotes to reformat their numbers
4698 for (SwTextFootnote *const pFootnote : rFootnotes)
4700 SwFormatFootnote const& rFootnote(pFootnote->GetFootnote());
4701 if (rFootnote.GetNumber() != rFootnote.GetNumberRLHidden()
4702 && rFootnote.GetNumStr().isEmpty())
4704 pFootnote->InvalidateNumberInLayout();
4707 // update various fields to re-expand them with the new layout
4708 IDocumentFieldsAccess & rIDFA(rDoc.getIDocumentFieldsAccess());
4709 auto const pAuthType(rIDFA.GetFieldType(
4710 SwFieldIds::TableOfAuthorities, OUString(), false));
4711 if (pAuthType) // created on demand...
4712 { // calling DelSequenceArray() should be unnecessary here since the
4713 // sequence doesn't depend on frames
4714 pAuthType->UpdateFields();
4716 rIDFA.GetFieldType(SwFieldIds::RefPageGet, OUString(), false)->UpdateFields();
4717 rIDFA.GetSysFieldType(SwFieldIds::Chapter)->UpdateFields();
4718 rIDFA.UpdateExpFields(nullptr, false);
4719 rIDFA.UpdateRefFields();
4721 // update SwPostItMgr / notes in the margin
4722 // note: as long as all shells share layout, broadcast to all shells!
4723 rDoc.GetDocShell()->Broadcast( SwFormatFieldHint(nullptr, rLayout.HasMergedParas()
4724 ? SwFormatFieldHintWhich::REMOVED
4725 : SwFormatFieldHintWhich::INSERTED) );
4728 // InvalidateAllContent(SwInvalidateFlags::Size); // ??? TODO what to invalidate? this is the big hammer
4731 void SwRootFrame::SetHideRedlines(bool const bHideRedlines)
4733 if (bHideRedlines == mbHideRedlines)
4735 return;
4737 // TODO: remove temporary ShowBoth
4738 sw::FieldmarkMode const eMode(m_FieldmarkMode);
4739 sw::ParagraphBreakMode const ePBMode(m_ParagraphBreakMode);
4740 if (HasMergedParas())
4742 m_FieldmarkMode = sw::FieldmarkMode::ShowBoth;
4743 m_ParagraphBreakMode = sw::ParagraphBreakMode::Shown;
4744 mbHideRedlines = false;
4745 UnHide(*this);
4747 if (bHideRedlines || eMode != m_FieldmarkMode || ePBMode != m_ParagraphBreakMode)
4749 m_FieldmarkMode = eMode;
4750 m_ParagraphBreakMode = ePBMode;
4751 mbHideRedlines = bHideRedlines;
4752 UnHide(*this);
4756 void SwRootFrame::SetFieldmarkMode(sw::FieldmarkMode const eFMMode, sw::ParagraphBreakMode const ePBMode)
4758 if (eFMMode == m_FieldmarkMode && ePBMode == m_ParagraphBreakMode)
4760 return;
4762 // TODO: remove temporary ShowBoth
4763 bool const isHideRedlines(mbHideRedlines);
4764 if (HasMergedParas())
4766 mbHideRedlines = false;
4767 m_FieldmarkMode = sw::FieldmarkMode::ShowBoth;
4768 m_ParagraphBreakMode = sw::ParagraphBreakMode::Shown;
4769 UnHide(*this);
4771 if (isHideRedlines || eFMMode != sw::FieldmarkMode::ShowBoth || ePBMode == sw::ParagraphBreakMode::Hidden)
4773 mbHideRedlines = isHideRedlines;
4774 m_FieldmarkMode = eFMMode;
4775 m_ParagraphBreakMode = ePBMode;
4776 UnHide(*this);
4780 bool SwRootFrame::HasMergedParas() const
4782 return IsHideRedlines()
4783 || GetFieldmarkMode() != sw::FieldmarkMode::ShowBoth
4784 || GetParagraphBreakMode() == sw::ParagraphBreakMode::Hidden;
4787 namespace {
4788 xmlTextWriterPtr lcl_createDefaultWriter()
4790 xmlTextWriterPtr writer = xmlNewTextWriterFilename( "layout.xml", 0 );
4791 xmlTextWriterSetIndent(writer,1);
4792 (void)xmlTextWriterSetIndentString(writer, BAD_CAST(" "));
4793 (void)xmlTextWriterStartDocument( writer, nullptr, nullptr, nullptr );
4794 return writer;
4797 void lcl_freeWriter( xmlTextWriterPtr writer )
4799 (void)xmlTextWriterEndDocument( writer );
4800 xmlFreeTextWriter( writer );
4804 void SwRootFrame::dumpAsXml(xmlTextWriterPtr writer) const
4806 bool bCreateWriter = (nullptr == writer);
4807 if (bCreateWriter)
4808 writer = lcl_createDefaultWriter();
4810 (void)xmlTextWriterStartElement(writer, reinterpret_cast<const xmlChar*>("root"));
4811 dumpAsXmlAttributes(writer);
4813 (void)xmlTextWriterStartElement(writer, BAD_CAST("sfxViewShells"));
4814 SwView* pView = static_cast<SwView*>(SfxViewShell::GetFirst(true, checkSfxViewShell<SwView>));
4815 while (pView)
4817 if (GetCurrShell()->GetSfxViewShell() && pView->GetObjectShell() == GetCurrShell()->GetSfxViewShell()->GetObjectShell())
4818 pView->dumpAsXml(writer);
4819 pView = static_cast<SwView*>(SfxViewShell::GetNext(*pView, true, checkSfxViewShell<SwView>));
4821 (void)xmlTextWriterEndElement(writer);
4823 (void)xmlTextWriterStartElement(writer, BAD_CAST("infos"));
4824 dumpInfosAsXml(writer);
4825 (void)xmlTextWriterEndElement(writer);
4826 dumpChildrenAsXml(writer);
4827 (void)xmlTextWriterEndElement(writer);
4829 if (bCreateWriter)
4830 lcl_freeWriter(writer);
4833 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */