android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / layout / frmtool.cxx
blob853f363f38e80926da9d19f922f8449dba6a7d03
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 <svx/svdpage.hxx>
23 #include <editeng/brushitem.hxx>
24 #include <editeng/shaditem.hxx>
25 #include <editeng/ulspitem.hxx>
26 #include <editeng/boxitem.hxx>
27 #include <editeng/lspcitem.hxx>
28 #include <editeng/fhgtitem.hxx>
29 #include <sal/log.hxx>
30 #include <o3tl/deleter.hxx>
31 #include <osl/diagnose.h>
33 #include <drawdoc.hxx>
34 #include <fmtornt.hxx>
35 #include <fmthdft.hxx>
36 #include <fmtfsize.hxx>
37 #include <fmtsrnd.hxx>
38 #include <docary.hxx>
39 #include <lineinfo.hxx>
40 #include <swmodule.hxx>
41 #include <pagefrm.hxx>
42 #include <colfrm.hxx>
43 #include <fesh.hxx>
44 #include <viewimp.hxx>
45 #include <viewopt.hxx>
46 #include <dflyobj.hxx>
47 #include <dcontact.hxx>
48 #include <frmatr.hxx>
49 #include <frmtool.hxx>
50 #include <tabfrm.hxx>
51 #include <rowfrm.hxx>
52 #include <ftnfrm.hxx>
53 #include <txtfrm.hxx>
54 #include <notxtfrm.hxx>
55 #include <flyfrms.hxx>
56 #include <layact.hxx>
57 #include <pagedesc.hxx>
58 #include <section.hxx>
59 #include <sectfrm.hxx>
60 #include <node2lay.hxx>
61 #include <ndole.hxx>
62 #include <hints.hxx>
63 #include "layhelp.hxx"
64 #include <laycache.hxx>
65 #include <rootfrm.hxx>
66 #include <paratr.hxx>
67 #include <redline.hxx>
68 #include <sortedobjs.hxx>
69 #include <objectformatter.hxx>
70 #include <calbck.hxx>
71 #include <ndtxt.hxx>
72 #include <undobj.hxx>
73 #include <DocumentSettingManager.hxx>
74 #include <IDocumentDrawModelAccess.hxx>
75 #include <IDocumentLayoutAccess.hxx>
76 #include <IDocumentTimerAccess.hxx>
77 #include <IDocumentRedlineAccess.hxx>
78 #include <IDocumentFieldsAccess.hxx>
79 #include <IDocumentState.hxx>
80 #include <frameformats.hxx>
81 #include <boost/circular_buffer.hpp>
82 #include <svx/sdr/attribute/sdrallfillattributeshelper.hxx>
84 using namespace ::com::sun::star;
86 namespace {
87 // FIXME: would likely better be a member of SwRootFrame instead of a global flag
88 bool isFlyCreationSuppressed = false;
90 namespace sw {
91 FlyCreationSuppressor::FlyCreationSuppressor(bool wasAlreadySuppressedAllowed)
92 : m_wasAlreadySuppressed(isFlyCreationSuppressed)
94 (void)wasAlreadySuppressedAllowed;
95 assert(wasAlreadySuppressedAllowed || !isFlyCreationSuppressed);
96 isFlyCreationSuppressed = true;
98 FlyCreationSuppressor::~FlyCreationSuppressor()
100 isFlyCreationSuppressed = m_wasAlreadySuppressed;
104 bool bObjsDirect = true;
105 bool bSetCompletePaintOnInvalidate = false;
107 sal_uInt8 StackHack::s_nCnt = 0;
108 bool StackHack::s_bLocked = false;
110 SwFrameNotify::SwFrameNotify( SwFrame *pF ) :
111 mpFrame( pF ),
112 maFrame( pF->getFrameArea() ),
113 maPrt( pF->getFramePrintArea() ),
114 mbInvaKeep( false ),
115 mbValidSize( pF->isFrameAreaSizeValid() )
117 if ( pF->IsTextFrame() )
119 mnFlyAnchorOfst = static_cast<SwTextFrame*>(pF)->GetBaseOffsetForFly( true );
120 mnFlyAnchorOfstNoWrap = static_cast<SwTextFrame*>(pF)->GetBaseOffsetForFly( false );
122 else
124 mnFlyAnchorOfst = 0;
125 mnFlyAnchorOfstNoWrap = 0;
128 mbHadFollow = pF->IsContentFrame() && static_cast<SwContentFrame*>(pF)->GetFollow();
131 SwFrameNotify::~SwFrameNotify()
133 suppress_fun_call_w_exception(ImplDestroy());
136 void SwFrameNotify::ImplDestroy()
138 SwRectFnSet aRectFnSet(mpFrame);
139 const bool bAbsP = aRectFnSet.PosDiff(maFrame, mpFrame->getFrameArea());
140 const bool bChgWidth =
141 aRectFnSet.GetWidth(maFrame) != aRectFnSet.GetWidth(mpFrame->getFrameArea());
142 const bool bChgHeight =
143 aRectFnSet.GetHeight(maFrame)!=aRectFnSet.GetHeight(mpFrame->getFrameArea());
144 const bool bChgFlyBasePos = mpFrame->IsTextFrame() &&
145 ( ( mnFlyAnchorOfst != static_cast<SwTextFrame*>(mpFrame)->GetBaseOffsetForFly( true ) ) ||
146 ( mnFlyAnchorOfstNoWrap != static_cast<SwTextFrame*>(mpFrame)->GetBaseOffsetForFly( false ) ) );
148 if ( mpFrame->IsFlowFrame() && !mpFrame->IsInFootnote() )
150 SwFlowFrame *pFlow = SwFlowFrame::CastFlowFrame( mpFrame );
152 if ( !pFlow->IsFollow() )
154 if ( !mpFrame->GetIndPrev() )
156 if ( mbInvaKeep )
158 SwFrame *pPre = mpFrame->FindPrev();
159 if ( pPre && pPre->IsFlowFrame() )
161 // 1. pPre wants to keep with me:
162 bool bInvalidPrePos = SwFlowFrame::CastFlowFrame(pPre)->IsKeep(pPre->GetAttrSet()->GetKeep(), pPre->GetBreakItem())
163 && pPre->GetIndPrev();
165 // 2. pPre is a table and the last row wants to keep with me:
166 if ( !bInvalidPrePos && pPre->IsTabFrame() )
168 SwTabFrame* pPreTab = static_cast<SwTabFrame*>(pPre);
169 if ( pPreTab->GetFormat()->GetDoc()->GetDocumentSettingManager().get(DocumentSettingId::TABLE_ROW_KEEP) )
171 SwRowFrame* pLastRow = static_cast<SwRowFrame*>(pPreTab->GetLastLower());
172 if ( pLastRow && pLastRow->ShouldRowKeepWithNext() )
173 bInvalidPrePos = true;
177 if ( bInvalidPrePos )
178 pPre->InvalidatePos();
182 else if ( !pFlow->HasFollow() )
184 tools::Long nOldHeight = aRectFnSet.GetHeight(maFrame);
185 tools::Long nNewHeight = aRectFnSet.GetHeight(mpFrame->getFrameArea());
186 if( (nOldHeight > nNewHeight) || (!nOldHeight && nNewHeight) )
187 pFlow->CheckKeep();
192 if ( bAbsP )
194 mpFrame->SetCompletePaint();
196 SwFrame* pNxt = mpFrame->GetIndNext();
197 // #121888# - skip empty section frames
198 while ( pNxt &&
199 pNxt->IsSctFrame() && !static_cast<SwSectionFrame*>(pNxt)->GetSection() )
201 pNxt = pNxt->GetIndNext();
204 if ( pNxt )
206 pNxt->InvalidatePos();
207 if (pNxt->IsTextFrame() && static_cast<SwTextFrame*>(pNxt)->IsUndersized())
208 { // tdf#137523 it could have more space at new pos
209 pNxt->InvalidateSize();
210 pNxt->Prepare(PrepareHint::AdjustSizeWithoutFormatting);
213 else
215 // #104100# - correct condition for setting retouche
216 // flag for vertical layout.
217 if( mpFrame->IsRetoucheFrame() &&
218 aRectFnSet.TopDist( maFrame, aRectFnSet.GetTop(mpFrame->getFrameArea()) ) > 0 )
220 mpFrame->SetRetouche();
223 // A fresh follow frame does not have to be invalidated, because
224 // it is already formatted:
225 if ( mbHadFollow || !mpFrame->IsContentFrame() || !static_cast<SwContentFrame*>(mpFrame)->GetFollow() )
227 if ( !mpFrame->IsTabFrame() || !static_cast<SwTabFrame*>(mpFrame)->GetFollow() )
228 mpFrame->InvalidateNextPos();
233 //For each resize of the background graphics is a repaint necessary.
234 const bool bPrtWidth =
235 aRectFnSet.GetWidth(maPrt) != aRectFnSet.GetWidth(mpFrame->getFramePrintArea());
236 const bool bPrtHeight =
237 aRectFnSet.GetHeight(maPrt)!=aRectFnSet.GetHeight(mpFrame->getFramePrintArea());
238 if ( bPrtWidth || bPrtHeight )
240 bool bUseNewFillProperties(false);
241 if (mpFrame->supportsFullDrawingLayerFillAttributeSet())
243 drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes(mpFrame->getSdrAllFillAttributesHelper());
244 if(aFillAttributes && aFillAttributes->isUsed())
246 bUseNewFillProperties = true;
247 // use SetCompletePaint if needed
248 if(aFillAttributes->needCompleteRepaint())
250 mpFrame->SetCompletePaint();
254 if (!bUseNewFillProperties)
256 const SvxGraphicPosition ePos = mpFrame->GetAttrSet()->GetBackground().GetGraphicPos();
257 if(GPOS_NONE != ePos && GPOS_TILED != ePos)
258 mpFrame->SetCompletePaint();
261 else
263 // #97597# - consider case that *only* margins between
264 // frame and printing area has changed. Then, frame has to be repainted,
265 // in order to force paint of the margin areas.
266 if ( !bAbsP && (bChgWidth || bChgHeight) )
268 mpFrame->SetCompletePaint();
272 const bool bPrtP = aRectFnSet.PosDiff( maPrt, mpFrame->getFramePrintArea() );
273 if ( bAbsP || bPrtP || bChgWidth || bChgHeight ||
274 bPrtWidth || bPrtHeight || bChgFlyBasePos )
276 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
277 if( mpFrame->IsAccessibleFrame() )
279 SwRootFrame *pRootFrame = mpFrame->getRootFrame();
280 if( pRootFrame && pRootFrame->IsAnyShellAccessible() &&
281 pRootFrame->GetCurrShell() )
283 pRootFrame->GetCurrShell()->Imp()->MoveAccessibleFrame( mpFrame, maFrame );
286 #endif
288 // Notification of anchored objects
289 if ( mpFrame->GetDrawObjs() )
291 const SwSortedObjs &rObjs = *mpFrame->GetDrawObjs();
292 SwPageFrame* pPageFrame = nullptr;
293 for (SwAnchoredObject* pObj : rObjs)
295 // OD 2004-03-31 #i26791# - no general distinction between
296 // Writer fly frames and drawing objects
297 bool bNotify = false;
298 bool bNotifySize = false;
299 SwContact* pContact = ::GetUserCall( pObj->GetDrawObj() );
300 const bool bAnchoredAsChar = pContact->ObjAnchoredAsChar();
301 if ( !bAnchoredAsChar )
303 // Notify object, which aren't anchored as-character:
305 // always notify objects, if frame position has changed
306 // or if the object is to-page|to-fly anchored.
307 if ( bAbsP ||
308 pContact->ObjAnchoredAtPage() ||
309 pContact->ObjAnchoredAtFly() )
311 bNotify = true;
313 // assure that to-fly anchored Writer fly frames are
314 // registered at the correct page frame, if frame
315 // position has changed.
316 if ( bAbsP && pContact->ObjAnchoredAtFly() &&
317 pObj->DynCastFlyFrame() != nullptr )
319 // determine to-fly anchored Writer fly frame
320 SwFlyFrame* pFlyFrame = static_cast<SwFlyFrame*>(pObj);
321 // determine page frame of to-fly anchored
322 // Writer fly frame
323 SwPageFrame* pFlyPageFrame = pFlyFrame->FindPageFrame();
324 // determine page frame, if needed.
325 if ( !pPageFrame )
327 pPageFrame = mpFrame->FindPageFrame();
329 if ( pPageFrame != pFlyPageFrame )
331 OSL_ENSURE( pFlyPageFrame, "~SwFrameNotify: Fly from Nowhere" );
332 if( pFlyPageFrame )
333 pFlyPageFrame->MoveFly( pFlyFrame, pPageFrame );
334 else
335 pPageFrame->AppendFlyToPage( pFlyFrame );
339 // otherwise the objects are notified in dependence to
340 // its positioning and alignment
341 else
343 const SwFormatVertOrient& rVert =
344 pContact->GetFormat()->GetVertOrient();
345 if ( ( rVert.GetVertOrient() == text::VertOrientation::CENTER ||
346 rVert.GetVertOrient() == text::VertOrientation::BOTTOM ||
347 rVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ) &&
348 ( bChgHeight || bPrtHeight ) )
350 bNotify = true;
352 if ( !bNotify )
354 const SwFormatHoriOrient& rHori =
355 pContact->GetFormat()->GetHoriOrient();
356 if ( ( rHori.GetHoriOrient() != text::HoriOrientation::NONE ||
357 rHori.GetRelationOrient()== text::RelOrientation::PRINT_AREA ||
358 rHori.GetRelationOrient()== text::RelOrientation::FRAME ) &&
359 ( bChgWidth || bPrtWidth || bChgFlyBasePos ) )
361 bNotify = true;
366 else if ( bPrtWidth )
368 // Notify as-character anchored objects, if printing area
369 // width has changed.
370 bNotify = true;
371 bNotifySize = true;
374 // perform notification via the corresponding invalidations
375 if ( bNotify )
377 if ( auto pFlyFrame = pObj->DynCastFlyFrame() )
379 if ( bNotifySize )
380 pFlyFrame->InvalidateSize_();
381 // #115759# - no invalidation of
382 // position for as-character anchored objects.
383 if ( !bAnchoredAsChar )
385 pFlyFrame->InvalidatePos_();
387 pFlyFrame->Invalidate_();
389 else if ( dynamic_cast<const SwAnchoredDrawObject*>( pObj) != nullptr )
391 // #115759# - no invalidation of
392 // position for as-character anchored objects.
393 if ( !bAnchoredAsChar )
395 pObj->InvalidateObjPos();
398 else
400 OSL_FAIL( "<SwContentNotify::~SwContentNotify()> - unknown anchored object type." );
406 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
407 else if( mpFrame->IsTextFrame() && mbValidSize != mpFrame->isFrameAreaSizeValid() )
409 SwRootFrame *pRootFrame = mpFrame->getRootFrame();
410 if( pRootFrame && pRootFrame->IsAnyShellAccessible() &&
411 pRootFrame->GetCurrShell() )
413 pRootFrame->GetCurrShell()->Imp()->InvalidateAccessibleFrameContent( mpFrame );
416 #endif
418 // #i9046# Automatic frame width
419 SwFlyFrame* pFly = nullptr;
420 // #i35879# Do not trust the inf flags. pFrame does not
421 // necessarily have to have an upper!
422 if ( mpFrame->IsFlyFrame() || nullptr == ( pFly = mpFrame->ImplFindFlyFrame() ))
423 return;
425 // #i61999#
426 // no invalidation of columned Writer fly frames, because automatic
427 // width doesn't make sense for such Writer fly frames.
428 if ( !pFly->Lower() || pFly->Lower()->IsColumnFrame() )
429 return;
431 const SwFormatFrameSize &rFrameSz = pFly->GetFormat()->GetFrameSize();
433 // This could be optimized. Basically the fly frame only has to
434 // be invalidated, if the first line of pFrame (if pFrame is a content
435 // frame, for other frame types it's the print area) has changed its
436 // size and pFrame was responsible for the current width of pFly. On
437 // the other hand, this is only rarely used and re-calculation of
438 // the fly frame does not cause too much trouble. So we keep it this
439 // way:
440 if ( SwFrameSize::Fixed != rFrameSz.GetWidthSizeType() )
442 // #i50668#, #i50998# - invalidation of position
443 // of as-character anchored fly frames not needed and can cause
444 // layout loops
445 if ( dynamic_cast<const SwFlyInContentFrame*>( pFly) == nullptr )
447 pFly->InvalidatePos();
449 pFly->InvalidateSize();
453 SwLayNotify::SwLayNotify( SwLayoutFrame *pLayFrame ) :
454 SwFrameNotify( pLayFrame ),
455 m_bLowersComplete( false )
459 // OD 2004-05-11 #i28701# - local method to invalidate the position of all
460 // frames inclusive its floating screen objects, which are lowers of the given
461 // layout frame
462 static void lcl_InvalidatePosOfLowers( SwLayoutFrame& _rLayoutFrame )
464 if( _rLayoutFrame.IsFlyFrame() && _rLayoutFrame.GetDrawObjs() )
466 _rLayoutFrame.InvalidateObjs( false );
469 SwFrame* pLowerFrame = _rLayoutFrame.Lower();
470 while ( pLowerFrame )
472 pLowerFrame->InvalidatePos();
473 if ( pLowerFrame->IsTextFrame() )
475 static_cast<SwTextFrame*>(pLowerFrame)->Prepare( PrepareHint::FramePositionChanged );
477 else if ( pLowerFrame->IsTabFrame() )
479 pLowerFrame->InvalidatePrt();
482 pLowerFrame->InvalidateObjs( false );
484 pLowerFrame = pLowerFrame->GetNext();
488 void SwLayNotify::ImplDestroy()
490 SwLayoutFrame *pLay = static_cast<SwLayoutFrame*>(mpFrame);
491 SwRectFnSet aRectFnSet(pLay);
492 bool bNotify = false;
493 if ( pLay->getFramePrintArea().SSize() != maPrt.SSize() )
495 if ( !IsLowersComplete() )
497 bool bInvaPercent;
499 if ( pLay->IsRowFrame() )
501 bInvaPercent = true;
502 tools::Long nNew = aRectFnSet.GetHeight(pLay->getFramePrintArea());
503 if( nNew != aRectFnSet.GetHeight(maPrt) )
504 static_cast<SwRowFrame*>(pLay)->AdjustCells( nNew, true);
505 if( aRectFnSet.GetWidth(pLay->getFramePrintArea())
506 != aRectFnSet.GetWidth(maPrt) )
507 static_cast<SwRowFrame*>(pLay)->AdjustCells( 0, false );
509 else
511 //Proportional adoption of the internal.
512 //1. If the formatted is no Fly
513 //2. If he contains no columns
514 //3. If the Fly has a fixed height and the columns
515 // are next to be.
516 // Hoehe danebenliegen.
517 //4. Never at SectionFrames.
518 bool bLow;
519 if( pLay->IsFlyFrame() )
521 if ( pLay->Lower() )
523 bLow = !pLay->Lower()->IsColumnFrame() ||
524 aRectFnSet.GetHeight(pLay->Lower()->getFrameArea())
525 != aRectFnSet.GetHeight(pLay->getFramePrintArea());
527 else
528 bLow = false;
530 else if( pLay->IsSctFrame() )
532 if ( pLay->Lower() )
534 if( pLay->Lower()->IsColumnFrame() && pLay->Lower()->GetNext() )
535 bLow = pLay->Lower()->getFrameArea().Height() != pLay->getFramePrintArea().Height();
536 else
537 bLow = pLay->getFramePrintArea().Width() != maPrt.Width();
539 else
540 bLow = false;
542 else if( pLay->IsFooterFrame() && !pLay->HasFixSize() )
543 bLow = pLay->getFramePrintArea().Width() != maPrt.Width();
544 else
545 bLow = true;
546 bInvaPercent = bLow;
547 if ( bLow )
549 pLay->ChgLowersProp( maPrt.SSize() );
551 // If the PrtArea has been extended, it might be possible that the chain of parts
552 // can take another frame. As a result, the "possible right one" needs to be
553 // invalidated. This only pays off if this or its Uppers are moveable sections.
554 // A PrtArea has been extended if width or height are larger than before.
555 if ( (pLay->getFramePrintArea().Height() > maPrt.Height() ||
556 pLay->getFramePrintArea().Width() > maPrt.Width()) &&
557 (pLay->IsMoveable() || pLay->IsFlyFrame()) )
559 SwFrame *pTmpFrame = pLay->Lower();
560 if ( pTmpFrame && pTmpFrame->IsFlowFrame() )
562 while ( pTmpFrame->GetNext() )
563 pTmpFrame = pTmpFrame->GetNext();
564 pTmpFrame->InvalidateNextPos();
568 bNotify = true;
569 //EXPENSIVE!! But how we do it more elegant?
570 if( bInvaPercent )
571 pLay->InvaPercentLowers( pLay->getFramePrintArea().Height() - maPrt.Height() );
573 if ( pLay->IsTabFrame() )
574 //So that _only_ the shadow is drawn while resizing.
575 static_cast<SwTabFrame*>(pLay)->SetComplete();
576 else
578 const SwViewShell *pSh = pLay->getRootFrame()->GetCurrShell();
579 if( !( pSh && pSh->GetViewOptions()->getBrowseMode() ) ||
580 !(pLay->GetType() & (SwFrameType::Body | SwFrameType::Page)) )
581 //Thereby the subordinates are retouched clean.
582 //Example problem: Take the Flys with the handles and downsize.
583 //Not for body and page, otherwise it flickers when loading HTML.
584 pLay->SetCompletePaint();
587 //Notify Lower if the position has changed.
588 const bool bPrtPos = aRectFnSet.PosDiff( maPrt, pLay->getFramePrintArea() );
589 const bool bPos = bPrtPos || aRectFnSet.PosDiff( maFrame, pLay->getFrameArea() );
590 const bool bSize = pLay->getFrameArea().SSize() != maFrame.SSize();
592 if ( bPos && pLay->Lower() && !IsLowersComplete() )
594 pLay->Lower()->InvalidatePos();
595 SwFootnoteFrame* pFtnFrame = pLay->Lower()->IsFootnoteFrame() ?
596 static_cast<SwFootnoteFrame*>(pLay->Lower()) : nullptr;
597 SwFrame* pFtnLower = pFtnFrame ? pFtnFrame->Lower() : nullptr;
598 if (pFtnLower)
599 pFtnLower->InvalidatePos();
602 if ( bPrtPos )
603 pLay->SetCompletePaint();
605 //Inform the Follower if the SSize has changed.
606 if ( bSize )
608 if( pLay->GetNext() )
610 if ( pLay->GetNext()->IsLayoutFrame() )
611 pLay->GetNext()->InvalidatePos_();
612 else
613 pLay->GetNext()->InvalidatePos();
615 else if( pLay->IsSctFrame() )
616 pLay->InvalidateNextPos();
618 if ( !IsLowersComplete() &&
619 !(pLay->GetType()&(SwFrameType::Fly|SwFrameType::Section) &&
620 pLay->Lower() && pLay->Lower()->IsColumnFrame()) &&
621 (bPos || bNotify) &&
622 !(pLay->GetType() & (SwFrameType::Row|SwFrameType::Tab|SwFrameType::FtnCont|SwFrameType::Page|SwFrameType::Root)))
624 // #i44016# - force unlock of position of lower objects.
625 // #i43913# - no unlock of position of objects,
626 // if <pLay> is a cell frame, and its table frame resp. its parent table
627 // frame is locked.
628 // #i47458# - force unlock of position of lower objects,
629 // only if position of layout frame has changed.
630 bool bUnlockPosOfObjs( bPos );
631 if ( bUnlockPosOfObjs && pLay->IsCellFrame() )
633 SwTabFrame* pTabFrame( pLay->FindTabFrame() );
634 if ( pTabFrame &&
635 ( pTabFrame->IsJoinLocked() ||
636 ( pTabFrame->IsFollow() &&
637 pTabFrame->FindMaster()->IsJoinLocked() ) ) )
639 bUnlockPosOfObjs = false;
642 // #i49383# - check for footnote frame, if unlock
643 // of position of lower objects is allowed.
644 else if ( bUnlockPosOfObjs && pLay->IsFootnoteFrame() )
646 bUnlockPosOfObjs = static_cast<SwFootnoteFrame*>(pLay)->IsUnlockPosOfLowerObjs();
648 // #i51303# - no unlock of object positions for sections
649 else if ( bUnlockPosOfObjs && pLay->IsSctFrame() )
651 bUnlockPosOfObjs = false;
653 pLay->NotifyLowerObjs( bUnlockPosOfObjs );
655 if ( bPos && pLay->IsFootnoteFrame() && pLay->Lower() )
657 // OD 2004-05-11 #i28701#
658 ::lcl_InvalidatePosOfLowers( *pLay );
660 if( ( bPos || bSize ) && pLay->IsFlyFrame() && static_cast<SwFlyFrame*>(pLay)->GetAnchorFrame()
661 && static_cast<SwFlyFrame*>(pLay)->GetAnchorFrame()->IsFlyFrame() )
662 static_cast<SwFlyFrame*>(pLay)->AnchorFrame()->InvalidateSize();
665 SwLayNotify::~SwLayNotify()
667 suppress_fun_call_w_exception(ImplDestroy());
670 SwFlyNotify::SwFlyNotify( SwFlyFrame *pFlyFrame ) :
671 SwLayNotify( pFlyFrame ),
672 // #115759# - keep correct page frame - the page frame
673 // the Writer fly frame is currently registered at.
674 m_pOldPage( pFlyFrame->GetPageFrame() ),
675 m_aFrameAndSpace( pFlyFrame->GetObjRectWithSpaces() )
679 void SwFlyNotify::ImplDestroy()
681 SwFlyFrame *pFly = static_cast<SwFlyFrame*>(mpFrame);
682 if ( pFly->IsNotifyBack() )
684 SwViewShell *pSh = pFly->getRootFrame()->GetCurrShell();
685 SwViewShellImp *pImp = pSh ? pSh->Imp() : nullptr;
686 if ( !pImp || !pImp->IsAction() || !pImp->GetLayAction().IsAgain() )
688 //If in the LayAction the IsAgain is set it can be
689 //that the old page is destroyed in the meantime!
690 ::Notify( pFly, m_pOldPage, m_aFrameAndSpace, &maPrt );
691 // #i35640# - additional notify anchor text frame,
692 // if Writer fly frame has changed its page
693 if ( pFly->GetAnchorFrame()->IsTextFrame() &&
694 pFly->GetPageFrame() != m_pOldPage )
696 pFly->AnchorFrame()->Prepare( PrepareHint::FlyFrameLeave );
699 pFly->ResetNotifyBack();
701 if (pFly->IsForceNotifyNewBackground())
703 pFly->NotifyBackground(pFly->FindPageFrame(), pFly->GetObjRectWithSpaces(), PrepareHint::FlyFrameArrive);
704 pFly->SetForceNotifyNewBackground(false);
707 //Have the size or the position changed,
708 //so should the view know this.
709 SwRectFnSet aRectFnSet(pFly);
710 const bool bPosChgd = aRectFnSet.PosDiff( maFrame, pFly->getFrameArea() );
711 const bool bFrameChgd = pFly->getFrameArea().SSize() != maFrame.SSize();
712 const bool bPrtChgd = maPrt != pFly->getFramePrintArea();
713 if ( bPosChgd || bFrameChgd || bPrtChgd )
715 pFly->NotifyDrawObj();
717 if ( bPosChgd && maFrame.Pos().X() != FAR_AWAY )
719 // OD 2004-05-10 #i28701# - no direct move of lower Writer fly frames.
720 // reason: New positioning and alignment (e.g. to-paragraph anchored,
721 // but aligned at page) are introduced.
722 // <SwLayNotify::~SwLayNotify()> takes care of invalidation of lower
723 // floating screen objects by calling method <SwLayoutFrame::NotifyLowerObjs()>.
725 if ( pFly->IsFlyAtContentFrame() )
727 SwFrame *pNxt = pFly->AnchorFrame()->FindNext();
728 while (pNxt)
730 pNxt->InvalidatePos();
731 if (!pNxt->IsSctFrame())
733 break;
735 // invalidating pos of a section frame doesn't have much
736 // effect, so try again with its lower
737 pNxt = static_cast<SwSectionFrame*>(pNxt)->Lower();
741 // #i26945# - notify anchor.
742 // Needed for negative positioned Writer fly frames
743 if ( pFly->GetAnchorFrame()->IsTextFrame() )
745 pFly->AnchorFrame()->Prepare( PrepareHint::FlyFrameLeave );
749 // OD 2004-05-13 #i28701#
750 // #i45180# - no adjustment of layout process flags and
751 // further notifications/invalidations, if format is called by grow/shrink
752 if ( !pFly->ConsiderObjWrapInfluenceOnObjPos() )
753 return;
754 if (pFly->IsFlyFreeFrame())
756 if (static_cast<SwFlyFreeFrame*>(pFly)->IsNoMoveOnCheckClip())
757 return;
760 // #i54138# - suppress restart of the layout process
761 // on changed frame height.
762 // Note: It doesn't seem to be necessary and can cause layout loops.
763 if ( bPosChgd )
765 // indicate a restart of the layout process
766 pFly->SetRestartLayoutProcess( true );
768 else
770 // lock position
771 pFly->LockPosition();
774 if ( pFly->ConsiderForTextWrap() )
775 return;
777 // indicate that object has to be considered for text wrap
778 pFly->SetConsiderForTextWrap( true );
779 // invalidate 'background' in order to allow its 'background'
780 // to wrap around it.
781 pFly->NotifyBackground( pFly->GetPageFrame(),
782 pFly->GetObjRectWithSpaces(),
783 PrepareHint::FlyFrameArrive );
784 // invalidate position of anchor frame in order to force
785 // a re-format of the anchor frame, which also causes a
786 // re-format of the invalid previous frames of the anchor frame.
787 pFly->AnchorFrame()->InvalidatePos();
790 SwFlyNotify::~SwFlyNotify()
792 suppress_fun_call_w_exception(ImplDestroy());
795 SwContentNotify::SwContentNotify( SwContentFrame *pContentFrame ) :
796 SwFrameNotify( pContentFrame ),
797 // OD 08.01.2004 #i11859#
798 mbChkHeightOfLastLine( false ),
799 mnHeightOfLastLine( 0 ),
800 // OD 2004-02-26 #i25029#
801 mbInvalidatePrevPrtArea( false ),
802 mbBordersJoinedWithPrev( false )
804 // OD 08.01.2004 #i11859#
805 if ( !pContentFrame->IsTextFrame() )
806 return;
808 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pContentFrame);
809 if (!pTextFrame->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::OLD_LINE_SPACING))
811 const SvxLineSpacingItem &rSpace = pTextFrame->GetAttrSet()->GetLineSpacing();
812 if ( rSpace.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Prop )
814 mbChkHeightOfLastLine = true;
815 mnHeightOfLastLine = pTextFrame->GetHeightOfLastLine();
820 void SwContentNotify::ImplDestroy()
822 SwContentFrame *pCnt = static_cast<SwContentFrame*>(mpFrame);
823 if ( bSetCompletePaintOnInvalidate )
824 pCnt->SetCompletePaint();
826 SwRectFnSet aRectFnSet(pCnt);
827 if ( pCnt->IsInTab() && ( aRectFnSet.PosDiff( pCnt->getFrameArea(), maFrame ) ||
828 pCnt->getFrameArea().SSize() != maFrame.SSize()))
830 SwLayoutFrame* pCell = pCnt->GetUpper();
831 while( !pCell->IsCellFrame() && pCell->GetUpper() )
832 pCell = pCell->GetUpper();
833 OSL_ENSURE( pCell->IsCellFrame(), "Where's my cell?" );
834 if ( text::VertOrientation::NONE != pCell->GetFormat()->GetVertOrient().GetVertOrient() )
835 pCell->InvalidatePrt(); //for the vertical align.
838 // OD 2004-02-26 #i25029#
839 if ( mbInvalidatePrevPrtArea && mbBordersJoinedWithPrev &&
840 pCnt->IsTextFrame() &&
841 !pCnt->IsFollow() && !pCnt->GetIndPrev() )
843 // determine previous frame
844 SwFrame* pPrevFrame = pCnt->FindPrev();
845 // skip empty section frames and hidden text frames
847 while ( pPrevFrame &&
848 ( ( pPrevFrame->IsSctFrame() &&
849 !static_cast<SwSectionFrame*>(pPrevFrame)->GetSection() ) ||
850 ( pPrevFrame->IsTextFrame() &&
851 static_cast<SwTextFrame*>(pPrevFrame)->IsHiddenNow() ) ) )
853 pPrevFrame = pPrevFrame->FindPrev();
857 // Invalidate printing area of found previous frame
858 if ( pPrevFrame )
860 if ( pPrevFrame->IsSctFrame() )
862 if ( pCnt->IsInSct() )
864 // Note: found previous frame is a section frame and
865 // <pCnt> is also inside a section.
866 // Thus due to <mbBordersJoinedWithPrev>,
867 // <pCnt> had joined its borders/shadow with the
868 // last content of the found section.
869 // Invalidate printing area of last content in found section.
870 SwFrame* pLstContentOfSctFrame =
871 static_cast<SwSectionFrame*>(pPrevFrame)->FindLastContent();
872 if ( pLstContentOfSctFrame )
874 pLstContentOfSctFrame->InvalidatePrt();
878 else
880 pPrevFrame->InvalidatePrt();
885 const bool bFirst = aRectFnSet.GetWidth(maFrame) == 0;
887 if ( pCnt->IsNoTextFrame() )
889 //Active PlugIn's or OLE-Objects should know something of the change
890 //thereby they move their window appropriate.
891 SwViewShell *pSh = pCnt->getRootFrame()->GetCurrShell();
892 if ( pSh )
894 SwOLENode *const pNd(static_cast<SwNoTextFrame*>(pCnt)->GetNode()->GetOLENode());
895 if (nullptr != pNd &&
896 (pNd->GetOLEObj().IsOleRef() ||
897 pNd->IsOLESizeInvalid()) )
899 const bool bNoTextFramePrtAreaChanged =
900 ( maPrt.SSize().Width() != 0 &&
901 maPrt.SSize().Height() != 0 ) &&
902 maPrt.SSize() != pCnt->getFramePrintArea().SSize();
903 OSL_ENSURE( pCnt->IsInFly(), "OLE not in FlyFrame" );
904 SwFlyFrame *pFly = pCnt->FindFlyFrame();
905 svt::EmbeddedObjectRef& xObj = pNd->GetOLEObj().GetObject();
906 SwFEShell *pFESh = nullptr;
907 for(SwViewShell& rCurrentShell : pSh->GetRingContainer())
908 { if ( dynamic_cast<const SwCursorShell*>( &rCurrentShell) != nullptr )
910 pFESh = static_cast<SwFEShell*>(&rCurrentShell);
911 // #108369#: Here used to be the condition if (!bFirst).
912 // I think this should mean "do not call CalcAndSetScale"
913 // if the frame is formatted for the first time.
914 // Unfortunately this is not valid anymore since the
915 // SwNoTextFrame already gets a width during CalcLowerPreps.
916 // Nevertheless, the indention of !bFirst seemed to be
917 // to assure that the OLE objects have already been notified
918 // if necessary before calling CalcAndSetScale.
919 // So I replaced !bFirst by !IsOLESizeInvalid. There is
920 // one additional problem specific to the word import:
921 // The layout is calculated _before_ calling PrtOLENotify,
922 // and the OLE objects are not invalidated during import.
923 // Therefore I added the condition !IsUpdateExpField,
924 // have a look at the occurrence of CalcLayout in
925 // uiview/view.cxx.
926 if ( !pNd->IsOLESizeInvalid() &&
927 !pSh->GetDoc()->getIDocumentState().IsUpdateExpField() )
928 pFESh->CalcAndSetScale( xObj,
929 &pFly->getFramePrintArea(), &pFly->getFrameArea(),
930 bNoTextFramePrtAreaChanged );
934 if ( pFESh && pNd->IsOLESizeInvalid() )
936 pNd->SetOLESizeInvalid( false );
937 pFESh->CalcAndSetScale( xObj ); // create client
940 // ditto animated graphics
941 if ( getFrameArea().HasArea() && static_cast<SwNoTextFrame*>(pCnt)->HasAnimation() )
943 static_cast<SwNoTextFrame*>(pCnt)->StopAnimation();
944 pSh->InvalidateWindows( getFrameArea() );
949 if ( bFirst )
951 pCnt->SetRetouche(); //fix(13870)
953 SwDoc& rDoc = pCnt->IsTextFrame()
954 ? static_cast<SwTextFrame*>(pCnt)->GetDoc()
955 : static_cast<SwNoTextFrame*>(pCnt)->GetNode()->GetDoc();
956 if ( !rDoc.GetSpzFrameFormats()->empty() &&
957 rDoc.DoesContainAtPageObjWithContentAnchor() && !rDoc.getIDocumentState().IsNewDoc() )
959 // If certain import filters for foreign file format import
960 // AT_PAGE anchored objects, the corresponding page number is
961 // typically not known. In this case the content position is
962 // stored at which the anchored object is found in the
963 // imported document.
964 // When this content is formatted it is the time at which
965 // the page is known. Thus, this data can be corrected now.
967 const SwPageFrame *pPage = nullptr;
968 for(sw::SpzFrameFormat* pFormat: *rDoc.GetSpzFrameFormats())
970 const SwFormatAnchor &rAnch = pFormat->GetAnchor();
971 if ( RndStdIds::FLY_AT_PAGE != rAnch.GetAnchorId() ||
972 rAnch.GetAnchorNode() == nullptr )
974 continue;
977 if (FrameContainsNode(*pCnt, rAnch.GetAnchorNode()->GetIndex()))
979 OSL_FAIL( "<SwContentNotify::~SwContentNotify()> - to page anchored object with content position." );
980 if ( !pPage )
982 pPage = pCnt->FindPageFrame();
984 SwFormatAnchor aAnch( rAnch );
985 aAnch.SetAnchor( nullptr );
986 aAnch.SetPageNum( pPage->GetPhyPageNum() );
987 pFormat->SetFormatAttr( aAnch );
988 if ( RES_DRAWFRMFMT != pFormat->Which() )
990 pFormat->MakeFrames();
997 // OD 12.01.2004 #i11859# - invalidate printing area of following frame,
998 // if height of last line has changed.
999 if ( pCnt->IsTextFrame() && mbChkHeightOfLastLine )
1001 if ( mnHeightOfLastLine != static_cast<SwTextFrame*>(pCnt)->GetHeightOfLastLine() )
1003 pCnt->InvalidateNextPrtArea();
1007 // #i44049#
1008 if ( pCnt->IsTextFrame() && aRectFnSet.PosDiff( maFrame, pCnt->getFrameArea() ) )
1010 pCnt->InvalidateObjs();
1013 // #i43255# - move code to invalidate at-character
1014 // anchored objects due to a change of its anchor character from
1015 // method <SwTextFrame::Format(..)>.
1016 if ( !pCnt->IsTextFrame() )
1017 return;
1019 SwTextFrame* pMasterFrame = pCnt->IsFollow()
1020 ? static_cast<SwTextFrame*>(pCnt)->FindMaster()
1021 : static_cast<SwTextFrame*>(pCnt);
1022 if ( pMasterFrame && !pMasterFrame->IsFlyLock() &&
1023 pMasterFrame->GetDrawObjs() )
1025 SwSortedObjs* pObjs = pMasterFrame->GetDrawObjs();
1026 for (SwAnchoredObject* pAnchoredObj : *pObjs)
1028 if ( pAnchoredObj->GetFrameFormat().GetAnchor().GetAnchorId()
1029 == RndStdIds::FLY_AT_CHAR )
1031 pAnchoredObj->CheckCharRectAndTopOfLine( !pMasterFrame->IsEmpty() );
1037 SwContentNotify::~SwContentNotify()
1039 suppress_fun_call_w_exception(ImplDestroy());
1042 // note this *cannot* be static because it's a friend
1043 void AppendObj(SwFrame *const pFrame, SwPageFrame *const pPage, SwFrameFormat *const pFormat, const SwFormatAnchor & rAnch)
1045 const bool bFlyAtFly = rAnch.GetAnchorId() == RndStdIds::FLY_AT_FLY; // LAYER_IMPL
1046 //Is a frame or a SdrObject described?
1047 const bool bSdrObj = RES_DRAWFRMFMT == pFormat->Which();
1048 // OD 23.06.2003 #108784# - append also drawing objects anchored
1049 // as character.
1050 const bool bDrawObjInContent = bSdrObj &&
1051 (rAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR);
1053 if( !(bFlyAtFly ||
1054 (rAnch.GetAnchorId() == RndStdIds::FLY_AT_PARA) ||
1055 (rAnch.GetAnchorId() == RndStdIds::FLY_AT_CHAR) ||
1056 bDrawObjInContent) )
1057 return;
1059 SdrObject* pSdrObj = nullptr;
1060 if ( bSdrObj && nullptr == (pSdrObj = pFormat->FindSdrObject()) )
1062 OSL_ENSURE( !bSdrObj, "DrawObject not found." );
1063 pFormat->GetDoc()->DelFrameFormat( pFormat );
1064 return;
1066 if ( pSdrObj )
1068 if ( !pSdrObj->getSdrPageFromSdrObject() )
1070 pFormat->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)->
1071 InsertObject(pSdrObj, pSdrObj->GetOrdNumDirect());
1074 SwDrawContact* pNew =
1075 static_cast<SwDrawContact*>(GetUserCall( pSdrObj ));
1076 if ( !pNew->GetAnchorFrame() )
1078 pFrame->AppendDrawObj( *(pNew->GetAnchoredObj( nullptr )) );
1080 // OD 19.06.2003 #108784# - add 'virtual' drawing object,
1081 // if necessary. But control objects have to be excluded.
1082 else if ( !::CheckControlLayer( pSdrObj ) &&
1083 pNew->GetAnchorFrame() != pFrame &&
1084 !pNew->GetDrawObjectByAnchorFrame( *pFrame ) )
1086 SwDrawVirtObj* pDrawVirtObj = pNew->AddVirtObj(*pFrame);
1087 pFrame->AppendDrawObj( *(pNew->GetAnchoredObj( pDrawVirtObj )) );
1089 pDrawVirtObj->ActionChanged();
1092 else
1094 SwFlyFrame *pFly;
1095 if( bFlyAtFly )
1096 pFly = new SwFlyLayFrame( static_cast<SwFlyFrameFormat*>(pFormat), pFrame, pFrame );
1097 else
1098 pFly = new SwFlyAtContentFrame( static_cast<SwFlyFrameFormat*>(pFormat), pFrame, pFrame );
1099 pFly->Lock();
1100 pFrame->AppendFly( pFly );
1101 pFly->Unlock();
1102 if ( pPage )
1103 ::RegistFlys( pPage, pFly );
1107 static bool IsShown(SwNodeOffset const nIndex,
1108 const SwFormatAnchor & rAnch,
1109 std::vector<sw::Extent>::const_iterator const*const pIter,
1110 std::vector<sw::Extent>::const_iterator const*const pEnd,
1111 SwTextNode const*const pFirstNode, SwTextNode const*const pLastNode)
1113 assert(!pIter || *pIter == *pEnd || (*pIter)->pNode->GetIndex() == nIndex);
1114 SwNode* pAnchorNode = rAnch.GetAnchorNode();
1115 if (pAnchorNode->GetIndex() != nIndex)
1117 return false;
1119 if (rAnch.GetAnchorId() == RndStdIds::FLY_AT_PARA)
1121 return pIter == nullptr // not merged
1122 || pIter != pEnd // at least one char visible in node
1123 || !IsSelectFrameAnchoredAtPara(*rAnch.GetContentAnchor(),
1124 SwPosition(*pFirstNode, 0),
1125 SwPosition(*pLastNode, pLastNode->Len()));
1127 if (pIter)
1129 // note: frames are not sorted by anchor position.
1130 assert(pEnd);
1131 assert(pFirstNode);
1132 assert(pLastNode);
1133 assert(rAnch.GetAnchorId() != RndStdIds::FLY_AT_FLY);
1134 if (*pIter == *pEnd && rAnch.GetAnchorId() == RndStdIds::FLY_AT_CHAR)
1135 { // tdf#149595 special case - it *could* be shown if first == last
1136 return !IsDestroyFrameAnchoredAtChar(*rAnch.GetContentAnchor(),
1137 SwPosition(*pFirstNode, 0),
1138 SwPosition(*pLastNode, pLastNode->Len()));
1140 for (auto iter = *pIter; iter != *pEnd; ++iter)
1142 assert(iter->nStart != iter->nEnd); // TODO possible?
1143 assert(iter->pNode->GetIndex() == nIndex);
1144 if (rAnch.GetAnchorContentOffset() < iter->nStart)
1146 return false;
1148 if (rAnch.GetAnchorId() == RndStdIds::FLY_AT_CHAR)
1150 // if there is an extent then obviously the node was not
1151 // deleted fully...
1152 // show if start <= pos <= end
1153 // *or* if first-node/0 *and* not StartOfSection
1154 // *or* if last-node/Len *and* not EndOfSection
1156 // first determine the extent to compare to, then
1157 // construct start/end positions for the deletion *before* the
1158 // extent and compare once.
1159 // the interesting corner cases are on the edge of the extent!
1160 // no need to check for > the last extent because those
1161 // are never visible.
1162 if (rAnch.GetAnchorContentOffset() <= iter->nEnd)
1164 if (iter->nStart == 0)
1166 return true;
1168 else
1170 SwPosition const start(
1171 iter == *pIter
1172 ? *pFirstNode // simplification
1173 : *iter->pNode,
1174 iter == *pIter // first extent?
1175 ? iter->pNode == pFirstNode
1176 ? 0 // at start of 1st node
1177 : pFirstNode->Len() // previous node; simplification but should get right result
1178 : (iter-1)->nEnd); // previous extent
1179 SwPosition const end(*iter->pNode, iter->nStart);
1180 return !IsDestroyFrameAnchoredAtChar(*rAnch.GetContentAnchor(), start, end);
1183 else if (iter == *pEnd - 1) // special case: after last extent
1185 if (iter->nEnd == iter->pNode->Len())
1187 return true; // special case: end of node
1189 else
1191 SwPosition const start(*iter->pNode, iter->nEnd);
1192 SwPosition const end(
1193 *pLastNode, // simplification
1194 iter->pNode == pLastNode
1195 ? iter->pNode->Len()
1196 : 0);
1197 return !IsDestroyFrameAnchoredAtChar(*rAnch.GetContentAnchor(), start, end);
1201 else
1203 assert(rAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR);
1204 // for AS_CHAR obviously must be <
1205 if (rAnch.GetAnchorContentOffset() < iter->nEnd)
1207 return true;
1211 return false;
1213 else
1215 return true;
1219 void RemoveHiddenObjsOfNode(SwTextNode const& rNode,
1220 std::vector<sw::Extent>::const_iterator const*const pIter,
1221 std::vector<sw::Extent>::const_iterator const*const pEnd,
1222 SwTextNode const*const pFirstNode, SwTextNode const*const pLastNode)
1224 std::vector<SwFrameFormat*> const & rFlys(rNode.GetAnchoredFlys());
1225 for (SwFrameFormat * pFrameFormat : rFlys)
1227 SwFormatAnchor const& rAnchor = pFrameFormat->GetAnchor();
1228 if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR
1229 || rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR)
1231 assert(rAnchor.GetAnchorNode()->GetIndex() == rNode.GetIndex());
1232 if (!IsShown(rNode.GetIndex(), rAnchor, pIter, pEnd, pFirstNode, pLastNode))
1234 pFrameFormat->DelFrames();
1240 void AppendObjsOfNode(sw::FrameFormats<sw::SpzFrameFormat*> const*const pTable, SwNodeOffset const nIndex,
1241 SwFrame *const pFrame, SwPageFrame *const pPage, SwDoc *const pDoc,
1242 std::vector<sw::Extent>::const_iterator const*const pIter,
1243 std::vector<sw::Extent>::const_iterator const*const pEnd,
1244 SwTextNode const*const pFirstNode, SwTextNode const*const pLastNode)
1246 #if OSL_DEBUG_LEVEL > 0
1247 std::vector<SwFrameFormat*> checkFormats;
1248 for(auto pFormat: *pTable)
1250 const SwFormatAnchor &rAnch = pFormat->GetAnchor();
1251 if ( rAnch.GetAnchorNode() &&
1252 IsShown(nIndex, rAnch, pIter, pEnd, pFirstNode, pLastNode))
1254 checkFormats.push_back( pFormat );
1257 #else
1258 (void)pTable;
1259 #endif
1261 SwNode const& rNode(*pDoc->GetNodes()[nIndex]);
1262 std::vector<SwFrameFormat*> const & rFlys(rNode.GetAnchoredFlys());
1263 for (size_t it = 0; it != rFlys.size(); )
1265 SwFrameFormat *const pFormat = rFlys[it];
1266 const SwFormatAnchor &rAnch = pFormat->GetAnchor();
1267 if ( rAnch.GetAnchorNode() &&
1268 IsShown(nIndex, rAnch, pIter, pEnd, pFirstNode, pLastNode))
1270 #if OSL_DEBUG_LEVEL > 0
1271 std::vector<SwFrameFormat*>::iterator checkPos = std::find( checkFormats.begin(), checkFormats.end(), pFormat );
1272 assert( checkPos != checkFormats.end());
1273 checkFormats.erase( checkPos );
1274 #endif
1275 AppendObj(pFrame, pPage, pFormat, rAnch);
1277 ++it;
1280 #if OSL_DEBUG_LEVEL > 0
1281 assert( checkFormats.empty());
1282 #endif
1286 void AppendObjs(const sw::FrameFormats<sw::SpzFrameFormat*> *const pTable, SwNodeOffset const nIndex,
1287 SwFrame *const pFrame, SwPageFrame *const pPage, SwDoc *const pDoc)
1289 if (pFrame->IsTextFrame())
1291 SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>(pFrame));
1292 if (sw::MergedPara const*const pMerged = pTextFrame->GetMergedPara())
1294 std::vector<sw::Extent>::const_iterator iterFirst(pMerged->extents.begin());
1295 std::vector<sw::Extent>::const_iterator iter(iterFirst);
1296 SwTextNode const* pNode(pMerged->pFirstNode);
1297 for ( ; ; ++iter)
1299 if (iter == pMerged->extents.end()
1300 || iter->pNode != pNode)
1302 AppendObjsOfNode(pTable, pNode->GetIndex(), pFrame, pPage, pDoc,
1303 &iterFirst, &iter, pMerged->pFirstNode, pMerged->pLastNode);
1304 SwNodeOffset const until = iter == pMerged->extents.end()
1305 ? pMerged->pLastNode->GetIndex() + 1
1306 : iter->pNode->GetIndex();
1307 for (SwNodeOffset i = pNode->GetIndex() + 1; i < until; ++i)
1309 // let's show at-para flys on nodes that contain start/end of
1310 // redline too, even if there's no text there
1311 SwNode const*const pTmp(pNode->GetNodes()[i]);
1312 if (pTmp->GetRedlineMergeFlag() == SwNode::Merge::NonFirst)
1314 AppendObjsOfNode(pTable, pTmp->GetIndex(), pFrame, pPage, pDoc, &iter, &iter, pMerged->pFirstNode, pMerged->pLastNode);
1317 if (iter == pMerged->extents.end())
1319 break;
1321 pNode = iter->pNode;
1322 iterFirst = iter;
1326 else
1328 return AppendObjsOfNode(pTable, nIndex, pFrame, pPage, pDoc, nullptr, nullptr, nullptr, nullptr);
1331 else
1333 return AppendObjsOfNode(pTable, nIndex, pFrame, pPage, pDoc, nullptr, nullptr, nullptr, nullptr);
1337 bool IsAnchoredObjShown(SwTextFrame const& rFrame, SwFormatAnchor const& rAnchor)
1339 assert(rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA ||
1340 rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR ||
1341 rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR);
1342 bool ret(true);
1343 if (auto const pMergedPara = rFrame.GetMergedPara())
1345 ret = false;
1346 SwNode* pAnchorNode(rAnchor.GetAnchorNode());
1347 auto iterFirst(pMergedPara->extents.cbegin());
1348 if (iterFirst == pMergedPara->extents.end()
1349 && (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA
1350 || rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR))
1352 ret = (pAnchorNode == pMergedPara->pFirstNode
1353 && (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA
1354 || rAnchor.GetAnchorContentOffset() == 0))
1355 || (pAnchorNode == pMergedPara->pLastNode
1356 && (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA
1357 || rAnchor.GetAnchorContentOffset() == pMergedPara->pLastNode->Len()));
1359 auto iter(iterFirst);
1360 SwTextNode const* pNode(pMergedPara->pFirstNode);
1361 for ( ; ; ++iter)
1363 if (iter == pMergedPara->extents.end()
1364 || iter->pNode != pNode)
1366 assert(pNode->GetRedlineMergeFlag() != SwNode::Merge::Hidden);
1367 if (pNode == pAnchorNode)
1369 ret = IsShown(pNode->GetIndex(), rAnchor, &iterFirst, &iter,
1370 pMergedPara->pFirstNode, pMergedPara->pLastNode);
1371 break;
1373 if (iter == pMergedPara->extents.end())
1375 break;
1377 pNode = iter->pNode;
1378 if (pAnchorNode->GetIndex() < pNode->GetIndex())
1380 break;
1382 iterFirst = iter;
1386 return ret;
1389 void AppendAllObjs(const sw::FrameFormats<sw::SpzFrameFormat*>* pTable, const SwFrame* pSib)
1391 //Connecting of all Objects, which are described in the SpzTable with the
1392 //layout.
1394 boost::circular_buffer<SwFrameFormat*> vFormatsToConnect(pTable->size());
1395 for(const auto& pFormat : *pTable)
1397 const auto& rAnch = pFormat->GetAnchor();
1398 // Formats can still remain, because we neither use character bound
1399 // frames nor objects which are anchored to character bounds.
1400 if ((rAnch.GetAnchorId() != RndStdIds::FLY_AT_PAGE) && (rAnch.GetAnchorId() != RndStdIds::FLY_AS_CHAR))
1402 const SwNode* pAnchorNode = rAnch.GetAnchorNode();
1403 // formats in header/footer have no dependencies
1404 if(pAnchorNode && pFormat->GetDoc()->IsInHeaderFooter(*pAnchorNode))
1405 pFormat->MakeFrames();
1406 else
1407 vFormatsToConnect.push_back(pFormat);
1410 const SwRootFrame* pRoot = pSib ? pSib->getRootFrame() : nullptr;
1411 const SwFrameFormat* pFirstRequeued(nullptr);
1412 while(!vFormatsToConnect.empty())
1414 SwFrameFormat* pFormat = vFormatsToConnect.front();
1415 bool isConnected(false);
1416 pFormat->CallSwClientNotify(sw::GetObjectConnectedHint(isConnected, pRoot));
1417 if(!isConnected)
1419 pFormat->MakeFrames();
1420 pFormat->CallSwClientNotify(sw::GetObjectConnectedHint(isConnected, pRoot));
1422 // do this *before* push_back! the circular_buffer can be "full"!
1423 vFormatsToConnect.pop_front();
1424 if (!isConnected)
1426 if(pFirstRequeued == pFormat)
1427 // If nothing happens anymore we can stop.
1428 break;
1429 if(!pFirstRequeued)
1430 pFirstRequeued = pFormat;
1431 assert(!vFormatsToConnect.full());
1432 vFormatsToConnect.push_back(pFormat);
1434 else
1436 pFirstRequeued = nullptr;
1441 namespace sw {
1443 void RecreateStartTextFrames(SwTextNode & rNode)
1445 std::vector<SwTextFrame*> frames;
1446 SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(rNode);
1447 for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
1449 if (pFrame->getRootFrame()->HasMergedParas())
1451 frames.push_back(pFrame);
1454 auto eMode(sw::FrameMode::Existing);
1455 for (SwTextFrame * pFrame : frames)
1457 // SplitNode could have moved the original frame to the start node
1458 // & created a new one on end, or could have created new frame on
1459 // start node... grab start node's frame and recreate MergedPara.
1460 SwTextNode & rFirstNode(pFrame->GetMergedPara()
1461 ? *pFrame->GetMergedPara()->pFirstNode
1462 : rNode);
1463 assert(rFirstNode.GetIndex() <= rNode.GetIndex());
1464 // clear old one first to avoid DelFrames confusing updates & asserts...
1465 pFrame->SetMergedPara(nullptr);
1466 pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
1467 *pFrame, rFirstNode, eMode));
1468 eMode = sw::FrameMode::New; // Existing is not idempotent!
1469 // note: this may or may not delete frames on the end node
1473 } // namespace sw
1475 /** local method to set 'working' position for newly inserted frames
1477 OD 12.08.2003 #i17969#
1479 static void lcl_SetPos( SwFrame& _rNewFrame,
1480 const SwLayoutFrame& _rLayFrame )
1482 SwRectFnSet aRectFnSet(&_rLayFrame);
1483 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(_rNewFrame);
1484 aRectFnSet.SetPos( aFrm, aRectFnSet.GetPos(_rLayFrame.getFrameArea()) );
1486 // move position by one SwTwip in text flow direction in order to get
1487 // notifications for a new calculated position after its formatting.
1488 if ( aRectFnSet.IsVert() )
1490 aFrm.Pos().AdjustX( -1 );
1492 else
1494 aFrm.Pos().AdjustY(1 );
1498 void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc,
1499 SwNodeOffset nIndex, bool bPages, SwNodeOffset nEndIndex,
1500 SwFrame *pPrv, sw::FrameMode const eMode )
1502 pDoc->getIDocumentTimerAccess().BlockIdling();
1503 SwRootFrame* pLayout = pLay->getRootFrame();
1504 const bool bOldCallbackActionEnabled = pLayout && pLayout->IsCallbackActionEnabled();
1505 if( bOldCallbackActionEnabled )
1506 pLayout->SetCallbackActionEnabled( false );
1508 //In the generation of the Layout bPages=true will be handed over.
1509 //Then will be new pages generated all x paragraphs already times in advance.
1510 //On breaks and/or pagedescriptorchanges the corresponding will be generated
1511 //immediately.
1512 //The advantage is, that on one hand already a nearly realistic number of
1513 //pages are created, but above all there are no almost endless long chain
1514 //of paragraphs, which must be moved expensively until it reaches a tolerable
1515 //reduced level.
1516 //We'd like to think that 20 Paragraphs fit on one page.
1517 //So that it does not become in extreme situations so violent we calculate depending
1518 //on the node something to it.
1519 //If in the DocStatistic a usable given pagenumber
1520 //(Will be cared for while writing), so it will be presumed that this will be
1521 //number of pages.
1522 const bool bStartPercent = bPages && !nEndIndex;
1524 SwPageFrame *pPage = pLay->FindPageFrame();
1525 sw::SpzFrameFormats* pTable = pDoc->GetSpzFrameFormats();
1526 SwFrame *pFrame = nullptr;
1527 std::unique_ptr<SwActualSection> pActualSection;
1528 std::unique_ptr<SwLayHelper> pPageMaker;
1530 //If the layout will be created (bPages == true) we do head on the progress
1531 //Flys and DrawObjects are not connected immediately, this
1532 //happens only at the end of the function.
1533 if ( bPages )
1535 // Attention: the SwLayHelper class uses references to the content-,
1536 // page-, layout-frame etc. and may change them!
1537 pPageMaker.reset(new SwLayHelper( pDoc, pFrame, pPrv, pPage, pLay,
1538 pActualSection, nIndex, SwNodeOffset(0) == nEndIndex ));
1539 if( bStartPercent )
1541 const sal_uLong nPageCount = pPageMaker->CalcPageCount();
1542 if( nPageCount )
1543 bObjsDirect = false;
1547 if( pLay->IsInSct() &&
1548 ( pLay->IsSctFrame() || pLay->GetUpper() ) ) // Hereby will newbies
1549 // be intercepted, of which flags could not determined yet,
1550 // for e.g. while inserting a table
1552 SwSectionFrame* pSct = pLay->FindSctFrame();
1553 // If content will be inserted in a footnote, which in a column area,
1554 // the column area it is not allowed to be broken up.
1555 // Only if in the inner of the footnote lies an area, is this a candidate
1556 // for pActualSection.
1557 // The same applies for areas in tables, if inside the table will be
1558 // something inserted, it's only allowed to break up areas, which
1559 // lies in the inside also.
1560 if( ( !pLay->IsInFootnote() || pSct->IsInFootnote() ) &&
1561 ( !pLay->IsInTab() || pSct->IsInTab() ) )
1563 pActualSection.reset(new SwActualSection(nullptr, pSct, pSct->GetSection()->GetFormat()->GetSectionNode()));
1564 // tdf#132236 for SwUndoDelete: find outer sections whose start
1565 // nodes aren't contained in the range but whose end nodes are,
1566 // because section frames may need to be created for them
1567 SwActualSection * pUpperSection(pActualSection.get());
1568 while (pUpperSection->GetSectionNode()->EndOfSectionIndex() < nEndIndex)
1570 SwStartNode *const pStart(pUpperSection->GetSectionNode()->StartOfSectionNode());
1571 if (!pStart->IsSectionNode())
1573 break;
1575 // note: these don't have a section frame, check it in EndNode case!
1576 auto const pTmp(new SwActualSection(nullptr, nullptr, static_cast<SwSectionNode*>(pStart)));
1577 pUpperSection->SetUpper(pTmp);
1578 pUpperSection = pTmp;
1580 OSL_ENSURE( !pLay->Lower() || !pLay->Lower()->IsColumnFrame(),
1581 "InsertCnt_: Wrong Call" );
1585 //If a section is "open", the pActualSection points to an SwActualSection.
1586 //If the page breaks, for "open" sections a follow will created.
1587 //For nested sections (which have, however, not a nested layout),
1588 //the SwActualSection class has a member, which points to an upper(section).
1589 //When the "inner" section finishes, the upper will used instead.
1591 // Do not consider the end node. The caller (Section/MakeFrames()) has to
1592 // ensure that the end of this range is positioned before EndIndex!
1593 for ( ; nEndIndex == SwNodeOffset(0) || nIndex < nEndIndex; ++nIndex)
1595 SwNode *pNd = pDoc->GetNodes()[nIndex];
1596 if ( pNd->IsContentNode() )
1598 SwContentNode* pNode = static_cast<SwContentNode*>(pNd);
1599 if (pLayout->HasMergedParas() && !pNd->IsCreateFrameWhenHidingRedlines())
1601 if (pNd->IsTextNode()
1602 && pNd->GetRedlineMergeFlag() == SwNode::Merge::NonFirst)
1603 { // must have a frame already
1604 assert(static_cast<SwTextFrame*>(pNode->getLayoutFrame(pLayout))->GetMergedPara());
1606 continue; // skip it
1608 pFrame = pNode->IsTextNode()
1609 ? sw::MakeTextFrame(*pNode->GetTextNode(), pLay, eMode)
1610 : pNode->MakeFrame(pLay);
1611 if( pPageMaker )
1612 pPageMaker->CheckInsert( nIndex );
1614 pFrame->InsertBehind( pLay, pPrv );
1615 if (!pPrv)
1617 if (SwSectionFrame *const pSection = pLay->FindSctFrame())
1619 if (pSection && pSection->ContainsAny() == pFrame)
1620 { // tdf#146258 section PrtArea depends on paragraph upper margin
1621 pSection->InvalidatePrt();
1625 // #i27138#
1626 // notify accessibility paragraphs objects about changed
1627 // CONTENT_FLOWS_FROM/_TO relation.
1628 // Relation CONTENT_FLOWS_FROM for next paragraph will change
1629 // and relation CONTENT_FLOWS_TO for previous paragraph will change.
1630 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1631 if ( pFrame->IsTextFrame() )
1633 SwViewShell* pViewShell( pFrame->getRootFrame()->GetCurrShell() );
1634 // no notification, if <SwViewShell> is in construction
1635 if ( pViewShell && !pViewShell->IsInConstructor() &&
1636 pViewShell->GetLayout() &&
1637 pViewShell->GetLayout()->IsAnyShellAccessible() &&
1638 pFrame->FindPageFrame() != nullptr)
1640 auto pNext = pFrame->FindNextCnt( true );
1641 auto pPrev = pFrame->FindPrevCnt();
1642 pViewShell->InvalidateAccessibleParaFlowRelation(
1643 pNext ? pNext->DynCastTextFrame() : nullptr,
1644 pPrev ? pPrev->DynCastTextFrame() : nullptr );
1645 // #i68958#
1646 // The information flags of the text frame are validated
1647 // in methods <FindNextCnt(..)> and <FindPrevCnt(..)>.
1648 // The information flags have to be invalidated, because
1649 // it is possible, that the one of its upper frames
1650 // isn't inserted into the layout.
1651 pFrame->InvalidateInfFlags();
1654 #endif
1655 // OD 12.08.2003 #i17969# - consider horizontal/vertical layout
1656 // for setting position at newly inserted frame
1657 lcl_SetPos( *pFrame, *pLay );
1658 pPrv = pFrame;
1660 if ( !pTable->empty() && bObjsDirect && !isFlyCreationSuppressed )
1661 AppendObjs( pTable, nIndex, pFrame, pPage, pDoc );
1663 else if ( pNd->IsTableNode() )
1664 { //Should we have encountered a table?
1665 SwTableNode *pTableNode = static_cast<SwTableNode*>(pNd);
1666 if (pLayout->IsHideRedlines())
1668 // in the problematic case, there can be only 1 redline...
1669 SwPosition const tmp(*pNd);
1670 SwRangeRedline const*const pRedline(
1671 pDoc->getIDocumentRedlineAccess().GetRedline(tmp, nullptr));
1672 // pathology: redline that starts on a TableNode; cannot
1673 // be created in UI but by import filters...
1674 if (pRedline
1675 && pRedline->GetType() == RedlineType::Delete
1676 && &pRedline->Start()->GetNode() == pNd)
1678 SAL_WARN("sw.pageframe", "skipping table frame creation on bizarre redline");
1679 while (true)
1681 pTableNode->GetNodes()[nIndex]->SetRedlineMergeFlag(SwNode::Merge::Hidden);
1682 if (nIndex == pTableNode->EndOfSectionIndex())
1684 break;
1686 ++nIndex;
1688 continue;
1691 if (pLayout->HasMergedParas() && !pNd->IsCreateFrameWhenHidingRedlines())
1693 assert(pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden);
1694 nIndex = pTableNode->EndOfSectionIndex();
1695 continue; // skip it
1698 pFrame = pTableNode->MakeFrame( pLay );
1700 // skip tables deleted with track changes
1701 if ( !static_cast<SwTabFrame*>(pFrame)->Lower() )
1703 nIndex = pTableNode->EndOfSectionIndex();
1704 continue; // skip it
1707 // #108116# loading may produce table structures that GCLines
1708 // needs to clean up. To keep table formulas correct, change
1709 // all table formulas to internal (BOXPTR) representation.
1710 pTableNode->GetTable().SwitchFormulasToInternalRepresentation();
1711 pTableNode->GetTable().GCLines();
1713 if( pPageMaker )
1714 pPageMaker->CheckInsert( nIndex );
1716 pFrame->InsertBehind( pLay, pPrv );
1717 if (pPage) // would null in SwCellFrame ctor
1718 { // tdf#134931 call ResetTurbo(); not sure if Paste() would be
1719 pFrame->InvalidatePage(pPage); // better than InsertBehind()?
1721 // #i27138#
1722 // notify accessibility paragraphs objects about changed
1723 // CONTENT_FLOWS_FROM/_TO relation.
1724 // Relation CONTENT_FLOWS_FROM for next paragraph will change
1725 // and relation CONTENT_FLOWS_TO for previous paragraph will change.
1726 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1728 SwViewShell* pViewShell( pFrame->getRootFrame()->GetCurrShell() );
1729 // no notification, if <SwViewShell> is in construction
1730 if ( pViewShell && !pViewShell->IsInConstructor() &&
1731 pViewShell->GetLayout() &&
1732 pViewShell->GetLayout()->IsAnyShellAccessible() &&
1733 pFrame->FindPageFrame() != nullptr)
1735 auto pNext = pFrame->FindNextCnt( true );
1736 auto pPrev = pFrame->FindPrevCnt();
1737 pViewShell->InvalidateAccessibleParaFlowRelation(
1738 pNext ? pNext->DynCastTextFrame() : nullptr,
1739 pPrev ? pPrev->DynCastTextFrame() : nullptr );
1742 #endif
1743 if ( bObjsDirect && !pTable->empty() )
1744 static_cast<SwTabFrame*>(pFrame)->RegistFlys();
1745 // OD 12.08.2003 #i17969# - consider horizontal/vertical layout
1746 // for setting position at newly inserted frame
1747 lcl_SetPos( *pFrame, *pLay );
1749 pPrv = pFrame;
1750 //Set the index to the endnode of the table section.
1751 nIndex = pTableNode->EndOfSectionIndex();
1753 SwTabFrame* pTmpFrame = static_cast<SwTabFrame*>(pFrame);
1754 while ( pTmpFrame )
1756 pTmpFrame->CheckDirChange();
1757 pTmpFrame = pTmpFrame->IsFollow() ? pTmpFrame->FindMaster() : nullptr;
1761 else if ( pNd->IsSectionNode() )
1763 if (pLayout->HasMergedParas() && !pNd->IsCreateFrameWhenHidingRedlines())
1765 assert(pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden);
1766 continue; // skip it
1768 SwSectionNode *pNode = static_cast<SwSectionNode*>(pNd);
1769 if( pNode->GetSection().CalcHiddenFlag() )
1770 // is hidden, skip the area
1771 nIndex = pNode->EndOfSectionIndex();
1772 else
1774 if (pActualSection)
1775 pActualSection->SetLastPos(pPrv);
1777 pFrame = pNode->MakeFrame( pLay );
1778 pActualSection.reset( new SwActualSection( pActualSection.release(),
1779 static_cast<SwSectionFrame*>(pFrame), pNode ) );
1780 if ( pActualSection->GetUpper() )
1782 //Insert behind the Upper, the "Follow" of the Upper will be
1783 //generated at the EndNode.
1784 SwSectionFrame *pTmp = pActualSection->GetUpper()->GetSectionFrame();
1785 pFrame->InsertBehind( pTmp->GetUpper(), pTmp );
1786 // OD 25.03.2003 #108339# - direct initialization of section
1787 // after insertion in the layout
1788 static_cast<SwSectionFrame*>(pFrame)->Init();
1790 else
1792 pFrame->InsertBehind( pLay, pPrv );
1793 // OD 25.03.2003 #108339# - direct initialization of section
1794 // after insertion in the layout
1795 static_cast<SwSectionFrame*>(pFrame)->Init();
1797 // #i33963#
1798 // Do not trust the IsInFootnote flag. If we are currently
1799 // building up a table, the upper of pPrv may be a cell
1800 // frame, but the cell frame does not have an upper yet.
1801 if( pPrv && nullptr != pPrv->ImplFindFootnoteFrame() )
1803 if( pPrv->IsSctFrame() )
1804 pPrv = static_cast<SwSectionFrame*>(pPrv)->ContainsContent();
1805 if( pPrv && pPrv->IsTextFrame() )
1806 static_cast<SwTextFrame*>(pPrv)->Prepare( PrepareHint::QuoVadis, nullptr, false );
1810 if (nIndex + 1 == nEndIndex
1811 // tdf#136452 may also be needed at end of section
1812 || pNode->EndOfSectionIndex() - 1 == nEndIndex)
1813 { // tdf#131684 tdf#132236 fix upper of frame moved in
1814 // SwUndoDelete; can't be done there unfortunately
1815 // because empty section frames are deleted here
1816 SwFrame *const pNext(
1817 // if there's a parent section, it has been split
1818 // into 2 SwSectionFrame already :(
1819 ( pFrame->GetNext()
1820 && pFrame->GetNext()->IsSctFrame()
1821 && pActualSection->GetUpper()
1822 && pActualSection->GetUpper()->GetSectionNode() ==
1823 static_cast<SwSectionFrame const*>(pFrame->GetNext())->GetSection()->GetFormat()->GetSectionNode())
1824 ? static_cast<SwSectionFrame *>(pFrame->GetNext())->ContainsContent()
1825 : pFrame->GetNext());
1826 if (pNext
1827 && pNext->IsTextFrame()
1828 && static_cast<SwTextFrame*>(pNext)->GetTextNodeFirst() == pDoc->GetNodes()[nEndIndex]
1829 && (pNext->GetUpper() == pFrame->GetUpper()
1830 || pFrame->GetNext()->IsSctFrame())) // checked above
1832 pNext->Cut();
1833 pNext->InvalidateInfFlags(); // mbInfSct changed
1834 // could have columns
1835 SwSectionFrame *const pSection(static_cast<SwSectionFrame*>(pFrame));
1836 assert(!pSection->Lower() || pSection->Lower()->IsLayoutFrame());
1837 SwLayoutFrame *const pParent(pSection->Lower() ? pSection->GetNextLayoutLeaf() : pSection);
1838 assert(!pParent->Lower());
1839 // paste invalidates, section could have indent...
1840 pNext->Paste(pParent, nullptr);
1843 // #i27138#
1844 // notify accessibility paragraphs objects about changed
1845 // CONTENT_FLOWS_FROM/_TO relation.
1846 // Relation CONTENT_FLOWS_FROM for next paragraph will change
1847 // and relation CONTENT_FLOWS_TO for previous paragraph will change.
1848 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
1850 SwViewShell* pViewShell( pFrame->getRootFrame()->GetCurrShell() );
1851 // no notification, if <SwViewShell> is in construction
1852 if ( pViewShell && !pViewShell->IsInConstructor() &&
1853 pViewShell->GetLayout() &&
1854 pViewShell->GetLayout()->IsAnyShellAccessible() &&
1855 pFrame->FindPageFrame() != nullptr)
1857 auto pNext = pFrame->FindNextCnt( true );
1858 auto pPrev = pFrame->FindPrevCnt();
1859 pViewShell->InvalidateAccessibleParaFlowRelation(
1860 pNext ? pNext->DynCastTextFrame() : nullptr,
1861 pPrev ? pPrev->DynCastTextFrame() : nullptr );
1864 #endif
1865 pFrame->CheckDirChange();
1867 // OD 12.08.2003 #i17969# - consider horizontal/vertical layout
1868 // for setting position at newly inserted frame
1869 lcl_SetPos( *pFrame, *pLay );
1871 // OD 20.11.2002 #105405# - no page, no invalidate.
1872 if ( pPage )
1874 // OD 18.09.2002 #100522#
1875 // invalidate page in order to force format and paint of
1876 // inserted section frame
1877 pFrame->InvalidatePage( pPage );
1879 // FME 10.11.2003 #112243#
1880 // Invalidate fly content flag:
1881 if ( pFrame->IsInFly() )
1882 pPage->InvalidateFlyContent();
1884 // OD 14.11.2002 #104684# - invalidate page content in order to
1885 // force format and paint of section content.
1886 pPage->InvalidateContent();
1889 pLay = static_cast<SwLayoutFrame*>(pFrame);
1890 if ( pLay->Lower() && pLay->Lower()->IsLayoutFrame() )
1891 pLay = pLay->GetNextLayoutLeaf();
1892 pPrv = nullptr;
1895 else if ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode() )
1897 if (pLayout->HasMergedParas() && !pNd->IsCreateFrameWhenHidingRedlines())
1899 assert(pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden);
1900 continue; // skip it
1902 if (pLayout->HasMergedParas() && !pNd->StartOfSectionNode()->IsCreateFrameWhenHidingRedlines())
1903 { // tdf#135014 section break in fieldmark (start inside, end outside)
1904 assert(pNd->StartOfSectionNode()->GetRedlineMergeFlag() == SwNode::Merge::Hidden);
1905 continue; // skip it
1907 assert(pActualSection && "Section end without section start?");
1908 assert(pActualSection->GetSectionNode() == pNd->StartOfSectionNode());
1910 //Close the section, where appropriate activate the surrounding
1911 //section again.
1912 pActualSection.reset(pActualSection->GetUpper());
1913 pLay = pLay->FindSctFrame();
1914 if ( pActualSection )
1916 //Could be, that the last SectionFrame remains empty.
1917 //Then now is the time to remove them.
1918 if ( !pLay->ContainsContent() )
1920 SwFrame *pTmpFrame = pLay;
1921 pLay = pTmpFrame->GetUpper();
1922 pPrv = pTmpFrame->GetPrev();
1923 pTmpFrame->RemoveFromLayout();
1924 SwFrame::DestroyFrame(pTmpFrame);
1926 else
1928 pPrv = pLay;
1929 pLay = pLay->GetUpper();
1932 // new section frame
1933 if (SwSectionFrame* pOuterSectionFrame = pActualSection->GetSectionFrame())
1935 // Splitting moves the trailing content to the next frame
1936 pFrame = pOuterSectionFrame->SplitSect(pActualSection->GetLastPos(), pPrv);
1938 // We don't want to leave empty parts back.
1939 if (! pOuterSectionFrame->IsColLocked() &&
1940 ! pOuterSectionFrame->ContainsContent() )
1942 pOuterSectionFrame->DelEmpty( true );
1943 SwFrame::DestroyFrame(pOuterSectionFrame);
1946 else
1948 pFrame = pActualSection->GetSectionNode()->MakeFrame( pLay );
1949 pFrame->InsertBehind( pLay, pPrv );
1950 static_cast<SwSectionFrame*>(pFrame)->Init();
1952 // OD 12.08.2003 #i17969# - consider horizontal/vertical layout
1953 // for setting position at newly inserted frame
1954 lcl_SetPos( *pFrame, *pLay );
1957 pActualSection->SetSectionFrame( static_cast<SwSectionFrame*>(pFrame) );
1959 pLay = static_cast<SwLayoutFrame*>(pFrame);
1960 if ( pLay->Lower() && pLay->Lower()->IsLayoutFrame() )
1961 pLay = pLay->GetNextLayoutLeaf();
1962 pPrv = nullptr;
1964 else
1966 //Nothing more with sections, it goes on right behind
1967 //the SectionFrame.
1968 pPrv = pLay;
1969 pLay = pLay->GetUpper();
1972 else if( pNd->IsStartNode() &&
1973 SwFlyStartNode == static_cast<SwStartNode*>(pNd)->GetStartNodeType() )
1975 if (pLayout->HasMergedParas() && !pNd->IsCreateFrameWhenHidingRedlines())
1977 assert(pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden);
1978 assert(false); // actually a fly-section can't be deleted?
1979 continue; // skip it
1981 if ( !pTable->empty() && bObjsDirect && !isFlyCreationSuppressed )
1983 SwFlyFrame* pFly = pLay->FindFlyFrame();
1984 if( pFly )
1985 AppendObjs( pTable, nIndex, pFly, pPage, pDoc );
1988 else
1990 assert(!pLayout->HasMergedParas()
1991 || pNd->GetRedlineMergeFlag() != SwNode::Merge::Hidden);
1992 // Neither Content nor table nor section, so we are done.
1993 break;
1997 if ( pActualSection )
1999 // Might happen that an empty (Follow-)Section is left over.
2000 if ( !(pLay = pActualSection->GetSectionFrame())->ContainsContent() )
2002 pLay->RemoveFromLayout();
2003 SwFrame::DestroyFrame(pLay);
2005 pActualSection.reset();
2008 if ( bPages ) // let the Flys connect to each other
2010 if ( !isFlyCreationSuppressed )
2011 AppendAllObjs( pTable, pLayout );
2012 bObjsDirect = true;
2015 if( pPageMaker )
2017 pPageMaker->CheckFlyCache( pPage );
2018 pPageMaker.reset();
2019 if( pDoc->GetLayoutCache() )
2021 #ifdef DBG_UTIL
2022 pDoc->GetLayoutCache()->CompareLayout( *pDoc );
2023 #endif
2024 pDoc->GetLayoutCache()->ClearImpl();
2028 pDoc->getIDocumentTimerAccess().UnblockIdling();
2029 if( bOldCallbackActionEnabled )
2030 pLayout->SetCallbackActionEnabled( bOldCallbackActionEnabled );
2033 void MakeFrames( SwDoc *pDoc, SwNode &rSttIdx, SwNode &rEndIdx )
2035 bObjsDirect = false;
2037 SwNodeOffset nEndIdx = rEndIdx.GetIndex();
2038 // TODO for multiple layouts there should be a loop here
2039 SwNode* pNd = pDoc->GetNodes().FindPrvNxtFrameNode( rSttIdx,
2040 pDoc->GetNodes()[ nEndIdx-1 ],
2041 pDoc->getIDocumentLayoutAccess().GetCurrentLayout());
2042 if ( pNd )
2044 bool bAfter = *pNd < rSttIdx;
2045 SwNode2Layout aNode2Layout( *pNd, rSttIdx.GetIndex() );
2046 sw::FrameMode eMode = sw::FrameMode::Existing;
2047 ::std::vector<SwFrame*> frames;
2048 while (SwFrame* pFrame = aNode2Layout.NextFrame())
2049 { // tdf#150500 new frames may be created that end up merged on pNd
2050 // so copy the currently existing ones; they shouldn't get deleted
2051 frames.push_back(pFrame);
2053 for (SwFrame *const pFrame : frames)
2055 SwLayoutFrame *pUpper = pFrame->GetUpper();
2056 SwFootnoteFrame* pFootnoteFrame = pUpper->FindFootnoteFrame();
2057 bool bOldLock, bOldFootnote;
2058 if( pFootnoteFrame )
2060 bOldFootnote = pFootnoteFrame->IsColLocked();
2061 pFootnoteFrame->ColLock();
2063 else
2064 bOldFootnote = true;
2065 SwSectionFrame* pSct = pUpper->FindSctFrame();
2066 // Inside of footnotes only those areas are interesting that are inside of them. But
2067 // not the ones (e.g. column areas) in which are the footnote containers positioned.
2068 // #109767# Table frame is in section, insert section in cell frame.
2069 if( pSct && ((pFootnoteFrame && !pSct->IsInFootnote()) || pUpper->IsCellFrame()) )
2070 pSct = nullptr;
2071 if( pSct )
2072 { // to prevent pTmp->MoveFwd from destroying the SectionFrame
2073 bOldLock = pSct->IsColLocked();
2074 pSct->ColLock();
2076 else
2077 bOldLock = true;
2079 // If pFrame cannot be moved, it is not possible to move it to the next page. This applies
2080 // also for frames (in the first column of a frame pFrame is moveable) and column
2081 // sections of tables (also here pFrame is moveable).
2082 bool bMoveNext = nEndIdx - rSttIdx.GetIndex() > SwNodeOffset(120);
2083 bool bAllowMove = !pFrame->IsInFly() && pFrame->IsMoveable() &&
2084 (!pFrame->IsInTab() || pFrame->IsTabFrame() );
2085 if ( bMoveNext && bAllowMove )
2087 SwFrame *pMove = pFrame;
2088 SwFrame *pPrev = pFrame->GetPrev();
2089 SwFlowFrame *pTmp = SwFlowFrame::CastFlowFrame( pMove );
2090 assert(pTmp);
2092 if ( bAfter )
2094 // The rest of this page should be empty. Thus, the following one has to move to
2095 // the next page (it might also be located in the following column).
2096 assert(!pTmp->HasFollow() && "prev. node's frame is not last");
2097 pPrev = pFrame;
2098 // If the surrounding SectionFrame has a "next" one,
2099 // so this one needs to be moved as well.
2100 pMove = pFrame->GetIndNext();
2101 SwColumnFrame* pCol = static_cast<SwColumnFrame*>(pFrame->FindColFrame());
2102 if( pCol )
2103 pCol = static_cast<SwColumnFrame*>(pCol->GetNext());
2106 if( pCol && !pMove )
2107 { // No successor so far, look into the next column
2108 pMove = pCol->ContainsAny();
2109 if( pCol->GetNext() )
2110 pCol = static_cast<SwColumnFrame*>(pCol->GetNext());
2111 else if( pCol->IsInSct() )
2112 { // If there is no following column but we are in a column frame,
2113 // there might be (page) columns outside of it.
2114 pCol = static_cast<SwColumnFrame*>(pCol->FindSctFrame()->FindColFrame());
2115 if( pCol )
2116 pCol = static_cast<SwColumnFrame*>(pCol->GetNext());
2118 else
2119 pCol = nullptr;
2121 // skip invalid SectionFrames
2122 while( pMove && pMove->IsSctFrame() &&
2123 !static_cast<SwSectionFrame*>(pMove)->GetSection() )
2124 pMove = pMove->GetNext();
2125 } while( !pMove && pCol );
2127 if( pMove )
2129 if ( pMove->IsContentFrame() )
2130 pTmp = static_cast<SwContentFrame*>(pMove);
2131 else if ( pMove->IsTabFrame() )
2132 pTmp = static_cast<SwTabFrame*>(pMove);
2133 else if ( pMove->IsSctFrame() )
2135 pMove = static_cast<SwSectionFrame*>(pMove)->ContainsAny();
2136 if( pMove )
2137 pTmp = SwFlowFrame::CastFlowFrame( pMove );
2138 else
2139 pTmp = nullptr;
2142 else
2143 pTmp = nullptr;
2145 else
2147 assert(!pTmp->IsFollow() && "next node's frame is not master");
2148 // move the _content_ of a section frame
2149 if( pMove->IsSctFrame() )
2151 while( pMove && pMove->IsSctFrame() &&
2152 !static_cast<SwSectionFrame*>(pMove)->GetSection() )
2153 pMove = pMove->GetNext();
2154 if( pMove && pMove->IsSctFrame() )
2155 pMove = static_cast<SwSectionFrame*>(pMove)->ContainsAny();
2156 if( pMove )
2157 pTmp = SwFlowFrame::CastFlowFrame( pMove );
2158 else
2159 pTmp = nullptr;
2163 if( pTmp )
2165 SwFrame* pOldUp = pTmp->GetFrame().GetUpper();
2166 // MoveFwd==true means that we are still on the same page.
2167 // But since we want to move if possible!
2168 bool bTmpOldLock = pTmp->IsJoinLocked();
2169 pTmp->LockJoin();
2170 while( pTmp->MoveFwd( true, false, true ) )
2172 if( pOldUp == pTmp->GetFrame().GetUpper() )
2173 break;
2174 pOldUp = pTmp->GetFrame().GetUpper();
2176 if( !bTmpOldLock )
2177 pTmp->UnlockJoin();
2179 ::InsertCnt_( pUpper, pDoc, rSttIdx.GetIndex(),
2180 pFrame->IsInDocBody(), nEndIdx, pPrev, eMode );
2182 else
2184 SwFrame* pPrv = bAfter ? pFrame : pFrame->GetPrev();
2186 ::InsertCnt_( pUpper, pDoc, rSttIdx.GetIndex(), false,
2187 nEndIdx, pPrv, eMode );
2188 // OD 23.06.2003 #108784# - correction: append objects doesn't
2189 // depend on value of <bAllowMove>
2190 if( !isFlyCreationSuppressed )
2192 const sw::SpzFrameFormats* pTable = pDoc->GetSpzFrameFormats();
2193 if( !pTable->empty() )
2194 AppendAllObjs( pTable, pUpper );
2197 if( pFrame->IsInFly() )
2198 pFrame->FindFlyFrame()->Invalidate_();
2199 if( pFrame->IsInTab() )
2200 pFrame->InvalidateSize();
2203 SwPageFrame *pPage = pUpper->FindPageFrame();
2204 SwFrame::CheckPageDescs( pPage, false );
2205 if( !bOldFootnote )
2206 pFootnoteFrame->ColUnlock();
2207 if( !bOldLock )
2209 pSct->ColUnlock();
2210 // pSct might be empty (e.g. when inserting linked section containing further
2211 // sections) and can be destroyed in such cases.
2212 if( !pSct->ContainsContent() )
2214 pSct->DelEmpty( true );
2215 pUpper->getRootFrame()->RemoveFromList( pSct );
2216 SwFrame::DestroyFrame(pSct);
2219 eMode = sw::FrameMode::New; // use Existing only once!
2223 bObjsDirect = true;
2226 SwBorderAttrs::SwBorderAttrs(const sw::BorderCacheOwner* pOwner, const SwFrame* pConstructor)
2227 : SwCacheObj(pOwner)
2228 , m_rAttrSet(pConstructor->IsContentFrame()
2229 ? pConstructor->IsTextFrame()
2230 ? static_cast<const SwTextFrame*>(pConstructor)->GetTextNodeForParaProps()->GetSwAttrSet()
2231 : static_cast<const SwNoTextFrame*>(pConstructor)->GetNode()->GetSwAttrSet()
2232 : static_cast<const SwLayoutFrame*>(pConstructor)->GetFormat()->GetAttrSet())
2233 , m_rUL(m_rAttrSet.GetULSpace())
2234 , m_rBox(m_rAttrSet.GetBox())
2235 , m_rShadow(m_rAttrSet.GetShadow())
2236 , m_aFrameSize(m_rAttrSet.GetFrameSize().GetSize())
2237 , m_bIsLine(false)
2238 , m_bJoinedWithPrev(false)
2239 , m_bJoinedWithNext(false)
2240 , m_nTopLine(0)
2241 , m_nBottomLine(0)
2242 , m_nLeftLine(0)
2243 , m_nRightLine(0)
2244 , m_nTop(0)
2245 , m_nBottom(0)
2246 , m_nGetTopLine(0)
2247 , m_nGetBottomLine(0)
2248 , m_nLineSpacing(0)
2250 // #i96772#
2251 const SwTextFrame* pTextFrame = pConstructor->DynCastTextFrame();
2252 if ( pTextFrame )
2254 m_pFirstLineIndent.reset(m_rAttrSet.GetFirstLineIndent().Clone());
2255 m_pTextLeftMargin.reset(m_rAttrSet.GetTextLeftMargin().Clone());
2256 m_pRightMargin.reset(m_rAttrSet.GetRightMargin().Clone());
2257 assert(m_pFirstLineIndent);
2258 assert(m_pTextLeftMargin);
2260 else
2262 // LRSpaceItem is copied due to the possibility that it is adjusted
2263 m_xLR.reset(m_rAttrSet.GetLRSpace().Clone());
2264 if (pConstructor->IsNoTextFrame())
2266 m_xLR = std::make_shared<SvxLRSpaceItem>(RES_LR_SPACE);
2268 assert(m_xLR);
2271 // Caution: The USHORTs for the cached values are not initialized by intention!
2273 // everything needs to be calculated at least once:
2274 m_bTopLine = m_bBottomLine = m_bLeftLine = m_bRightLine =
2275 m_bTop = m_bBottom = m_bLine = true;
2277 // except this one: calculate line spacing before cell border only for text frames
2278 m_bLineSpacing = bool(pTextFrame);
2280 m_bCacheGetLine = m_bCachedGetTopLine = m_bCachedGetBottomLine = false;
2281 // OD 21.05.2003 #108789# - init cache status for values <m_bJoinedWithPrev>
2282 // and <m_bJoinedWithNext>, which aren't initialized by default.
2283 m_bCachedJoinedWithPrev = false;
2284 m_bCachedJoinedWithNext = false;
2287 SwBorderAttrs::~SwBorderAttrs()
2289 const_cast<sw::BorderCacheOwner*>(static_cast<sw::BorderCacheOwner const *>(m_pOwner))->m_bInCache = false;
2292 /* All calc methods calculate a safety distance in addition to the values given by the attributes.
2293 * This safety distance is only added when working with borders and/or shadows to prevent that
2294 * e.g. borders are painted over.
2297 void SwBorderAttrs::CalcTop_()
2299 m_nTop = CalcTopLine() + m_rUL.GetUpper();
2301 bool bGutterAtTop = m_rAttrSet.GetDoc()->getIDocumentSettingAccess().get(
2302 DocumentSettingId::GUTTER_AT_TOP);
2303 if (bGutterAtTop && m_xLR)
2305 // Decrease the print area: the top space is the sum of top and gutter margins.
2306 m_nTop += m_xLR->GetGutterMargin();
2309 m_bTop = false;
2312 void SwBorderAttrs::CalcBottom_()
2314 m_nBottom = CalcBottomLine() + m_rUL.GetLower();
2315 m_bBottom = false;
2318 tools::Long SwBorderAttrs::CalcRight( const SwFrame* pCaller ) const
2320 tools::Long nRight=0;
2322 if (!pCaller->IsTextFrame() || !static_cast<const SwTextFrame*>(pCaller)->GetDoc().GetDocumentSettingManager().get(DocumentSettingId::INVERT_BORDER_SPACING)) {
2323 // OD 23.01.2003 #106895# - for cell frame in R2L text direction the left
2324 // and right border are painted on the right respectively left.
2325 if ( pCaller->IsCellFrame() && pCaller->IsRightToLeft() )
2326 nRight = CalcLeftLine();
2327 else
2328 nRight = CalcRightLine();
2331 // for paragraphs, "left" is "before text" and "right" is "after text"
2332 if (pCaller->IsTextFrame())
2334 if (pCaller->IsRightToLeft())
2336 nRight += m_pTextLeftMargin->GetLeft(*m_pFirstLineIndent);
2338 else
2340 nRight += m_pRightMargin->GetRight();
2343 else
2344 nRight += m_xLR->GetRight();
2346 // correction: retrieve left margin for numbering in R2L-layout
2347 if ( pCaller->IsTextFrame() && pCaller->IsRightToLeft() )
2349 nRight += static_cast<const SwTextFrame*>(pCaller)->GetTextNodeForParaProps()->GetLeftMarginWithNum();
2352 if (pCaller->IsPageFrame())
2354 const auto pPageFrame = static_cast<const SwPageFrame*>(pCaller);
2355 bool bGutterAtTop = pPageFrame->GetFormat()->getIDocumentSettingAccess().get(
2356 DocumentSettingId::GUTTER_AT_TOP);
2357 if (!bGutterAtTop)
2359 bool bRtlGutter = pPageFrame->GetAttrSet()->GetItem<SfxBoolItem>(RES_RTL_GUTTER)->GetValue();
2360 tools::Long nGutterMargin = bRtlGutter ? m_xLR->GetGutterMargin() : m_xLR->GetRightGutterMargin();
2361 // Decrease the print area: the right space is the sum of right and right gutter
2362 // margins.
2363 nRight += nGutterMargin;
2367 return nRight;
2370 tools::Long SwBorderAttrs::CalcLeft( const SwFrame *pCaller ) const
2372 tools::Long nLeft=0;
2374 if (!pCaller->IsTextFrame() || !static_cast<const SwTextFrame*>(pCaller)->GetDoc().GetDocumentSettingManager().get(DocumentSettingId::INVERT_BORDER_SPACING))
2376 // OD 23.01.2003 #106895# - for cell frame in R2L text direction the left
2377 // and right border are painted on the right respectively left.
2378 if ( pCaller->IsCellFrame() && pCaller->IsRightToLeft() )
2379 nLeft = CalcRightLine();
2380 else
2381 nLeft = CalcLeftLine();
2384 // for paragraphs, "left" is "before text" and "right" is "after text"
2385 if ( pCaller->IsTextFrame() && pCaller->IsRightToLeft() )
2386 nLeft += m_pRightMargin->GetRight();
2387 else
2389 if (pCaller->IsTextFrame())
2391 nLeft += m_pTextLeftMargin->GetLeft(*m_pFirstLineIndent);
2393 else
2394 nLeft += m_xLR->GetLeft();
2397 // correction: do not retrieve left margin for numbering in R2L-layout
2398 if ( pCaller->IsTextFrame() && !pCaller->IsRightToLeft() )
2400 nLeft += static_cast<const SwTextFrame*>(pCaller)->GetTextNodeForParaProps()->GetLeftMarginWithNum();
2403 if (pCaller->IsPageFrame())
2405 const auto pPageFrame = static_cast<const SwPageFrame*>(pCaller);
2406 bool bGutterAtTop = pPageFrame->GetFormat()->getIDocumentSettingAccess().get(
2407 DocumentSettingId::GUTTER_AT_TOP);
2408 if (!bGutterAtTop)
2410 bool bRtlGutter = pPageFrame->GetAttrSet()->GetItem<SfxBoolItem>(RES_RTL_GUTTER)->GetValue();
2411 tools::Long nGutterMargin = bRtlGutter ? m_xLR->GetRightGutterMargin() : m_xLR->GetGutterMargin();
2412 // Decrease the print area: the left space is the sum of left and gutter margins.
2413 nLeft += nGutterMargin;
2417 return nLeft;
2420 /* Calculated values for borders and shadows.
2421 * It might be that a distance is wanted even without lines. This will be
2422 * considered here and not by the attribute (e.g. bBorderDist for cells).
2425 void SwBorderAttrs::CalcTopLine_()
2427 m_nTopLine = m_rBox.CalcLineSpace( SvxBoxItemLine::TOP, /*bEvenIfNoLine*/true );
2428 m_nTopLine = m_nTopLine + m_rShadow.CalcShadowSpace(SvxShadowItemSide::TOP);
2429 m_bTopLine = false;
2432 void SwBorderAttrs::CalcBottomLine_()
2434 m_nBottomLine = m_rBox.CalcLineSpace( SvxBoxItemLine::BOTTOM, true );
2435 m_nBottomLine = m_nBottomLine + m_rShadow.CalcShadowSpace(SvxShadowItemSide::BOTTOM);
2436 m_bBottomLine = false;
2439 void SwBorderAttrs::CalcLeftLine_()
2441 m_nLeftLine = m_rBox.CalcLineSpace( SvxBoxItemLine::LEFT, true);
2442 m_nLeftLine = m_nLeftLine + m_rShadow.CalcShadowSpace(SvxShadowItemSide::LEFT);
2443 m_bLeftLine = false;
2446 void SwBorderAttrs::CalcRightLine_()
2448 m_nRightLine = m_rBox.CalcLineSpace( SvxBoxItemLine::RIGHT, true );
2449 m_nRightLine = m_nRightLine + m_rShadow.CalcShadowSpace(SvxShadowItemSide::RIGHT);
2450 m_bRightLine = false;
2453 void SwBorderAttrs::IsLine_()
2455 m_bIsLine = m_rBox.GetTop() || m_rBox.GetBottom() ||
2456 m_rBox.GetLeft()|| m_rBox.GetRight();
2457 m_bLine = false;
2460 /* The borders of neighboring paragraphs are condensed by following algorithm:
2462 * 1. No top border if the predecessor has the same top border and (3) applies.
2463 * In addition, the paragraph needs to have a border at least one side (left/right/bottom).
2464 * 2. No bottom border if the successor has the same bottom border and (3) applies.
2465 * In addition, the paragraph needs to have a border at least one side (left/right/top).
2466 * 3. The borders on the left and right side are identical between the current and the
2467 * pre-/succeeding paragraph.
2470 static bool CmpLines( const editeng::SvxBorderLine *pL1, const editeng::SvxBorderLine *pL2 )
2472 return ( ((pL1 && pL2) && (*pL1 == *pL2)) || (!pL1 && !pL2) );
2475 // OD 21.05.2003 #108789# - change name of 1st parameter - "rAttrs" -> "rCmpAttrs"
2476 // OD 21.05.2003 #108789# - compare <CalcRight()> and <rCmpAttrs.CalcRight()>
2477 // instead of only the right LR-spacing, because R2L-layout has to be
2478 // considered.
2479 bool SwBorderAttrs::CmpLeftRight( const SwBorderAttrs &rCmpAttrs,
2480 const SwFrame *pCaller,
2481 const SwFrame *pCmp ) const
2483 return ( CmpLines( rCmpAttrs.GetBox().GetLeft(), GetBox().GetLeft() ) &&
2484 CmpLines( rCmpAttrs.GetBox().GetRight(),GetBox().GetRight() ) &&
2485 CalcLeft( pCaller ) == rCmpAttrs.CalcLeft( pCmp ) &&
2486 // OD 21.05.2003 #108789# - compare <CalcRight> with <rCmpAttrs.CalcRight>.
2487 CalcRight( pCaller ) == rCmpAttrs.CalcRight( pCmp ) );
2490 bool SwBorderAttrs::JoinWithCmp( const SwFrame& _rCallerFrame,
2491 const SwFrame& _rCmpFrame ) const
2493 bool bReturnVal = false;
2495 SwBorderAttrAccess aCmpAccess( SwFrame::GetCache(), &_rCmpFrame );
2496 const SwBorderAttrs &rCmpAttrs = *aCmpAccess.Get();
2497 if ( m_rShadow == rCmpAttrs.GetShadow() &&
2498 CmpLines( m_rBox.GetTop(), rCmpAttrs.GetBox().GetTop() ) &&
2499 CmpLines( m_rBox.GetBottom(), rCmpAttrs.GetBox().GetBottom() ) &&
2500 CmpLeftRight( rCmpAttrs, &_rCallerFrame, &_rCmpFrame )
2503 bReturnVal = true;
2506 return bReturnVal;
2509 // OD 21.05.2003 #108789# - method to determine, if borders are joined with
2510 // previous frame. Calculated value saved in cached value <m_bJoinedWithPrev>
2511 // OD 2004-02-26 #i25029# - add 2nd parameter <_pPrevFrame>
2512 void SwBorderAttrs::CalcJoinedWithPrev( const SwFrame& _rFrame,
2513 const SwFrame* _pPrevFrame )
2515 // set default
2516 m_bJoinedWithPrev = false;
2518 if ( _rFrame.IsTextFrame() )
2520 // text frame can potentially join with previous text frame, if
2521 // corresponding attribute set is set at previous text frame.
2522 // OD 2004-02-26 #i25029# - If parameter <_pPrevFrame> is set, take this
2523 // one as previous frame.
2524 const SwFrame* pPrevFrame = _pPrevFrame ? _pPrevFrame : _rFrame.GetPrev();
2525 // OD 2004-02-13 #i25029# - skip hidden text frames.
2526 while ( pPrevFrame && pPrevFrame->IsTextFrame() &&
2527 static_cast<const SwTextFrame*>(pPrevFrame)->IsHiddenNow() )
2529 pPrevFrame = pPrevFrame->GetPrev();
2531 if ( pPrevFrame && pPrevFrame->IsTextFrame() &&
2532 pPrevFrame->GetAttrSet()->GetParaConnectBorder().GetValue()
2535 m_bJoinedWithPrev = JoinWithCmp( _rFrame, *pPrevFrame );
2539 // valid cache status, if demanded
2540 // OD 2004-02-26 #i25029# - Do not validate cache, if parameter <_pPrevFrame>
2541 // is set.
2542 m_bCachedJoinedWithPrev = m_bCacheGetLine && !_pPrevFrame;
2545 // OD 21.05.2003 #108789# - method to determine, if borders are joined with
2546 // next frame. Calculated value saved in cached value <m_bJoinedWithNext>
2547 void SwBorderAttrs::CalcJoinedWithNext( const SwFrame& _rFrame )
2549 // set default
2550 m_bJoinedWithNext = false;
2552 if ( _rFrame.IsTextFrame() )
2554 // text frame can potentially join with next text frame, if
2555 // corresponding attribute set is set at current text frame.
2556 // OD 2004-02-13 #i25029# - get next frame, but skip hidden text frames.
2557 const SwFrame* pNextFrame = _rFrame.GetNext();
2558 while ( pNextFrame && pNextFrame->IsTextFrame() &&
2559 static_cast<const SwTextFrame*>(pNextFrame)->IsHiddenNow() )
2561 pNextFrame = pNextFrame->GetNext();
2563 if ( pNextFrame && pNextFrame->IsTextFrame() &&
2564 _rFrame.GetAttrSet()->GetParaConnectBorder().GetValue()
2567 m_bJoinedWithNext = JoinWithCmp( _rFrame, *pNextFrame );
2571 // valid cache status, if demanded
2572 m_bCachedJoinedWithNext = m_bCacheGetLine;
2575 // OD 21.05.2003 #108789# - accessor for cached values <m_bJoinedWithPrev>
2576 // OD 2004-02-26 #i25029# - add 2nd parameter <_pPrevFrame>, which is passed to
2577 // method <_CalcJoindWithPrev(..)>.
2578 bool SwBorderAttrs::JoinedWithPrev( const SwFrame& _rFrame,
2579 const SwFrame* _pPrevFrame ) const
2581 if ( !m_bCachedJoinedWithPrev || _pPrevFrame )
2583 // OD 2004-02-26 #i25029# - pass <_pPrevFrame> as 2nd parameter
2584 const_cast<SwBorderAttrs*>(this)->CalcJoinedWithPrev( _rFrame, _pPrevFrame );
2587 return m_bJoinedWithPrev;
2590 bool SwBorderAttrs::JoinedWithNext( const SwFrame& _rFrame ) const
2592 if ( !m_bCachedJoinedWithNext )
2594 const_cast<SwBorderAttrs*>(this)->CalcJoinedWithNext( _rFrame );
2597 return m_bJoinedWithNext;
2600 // OD 2004-02-26 #i25029# - added 2nd parameter <_pPrevFrame>, which is passed to
2601 // method <JoinedWithPrev>
2602 void SwBorderAttrs::GetTopLine_( const SwFrame& _rFrame,
2603 const SwFrame* _pPrevFrame )
2605 sal_uInt16 nRet = CalcTopLine();
2607 // OD 21.05.2003 #108789# - use new method <JoinWithPrev()>
2608 // OD 2004-02-26 #i25029# - add 2nd parameter
2609 if ( JoinedWithPrev( _rFrame, _pPrevFrame ) )
2611 nRet = 0;
2614 m_bCachedGetTopLine = m_bCacheGetLine;
2616 m_nGetTopLine = nRet;
2619 void SwBorderAttrs::GetBottomLine_( const SwFrame& _rFrame )
2621 sal_uInt16 nRet = CalcBottomLine();
2623 // OD 21.05.2003 #108789# - use new method <JoinWithPrev()>
2624 if ( JoinedWithNext( _rFrame ) )
2626 nRet = 0;
2629 m_bCachedGetBottomLine = m_bCacheGetLine;
2631 m_nGetBottomLine = nRet;
2634 void SwBorderAttrs::CalcLineSpacing_()
2636 // tdf#125300 compatibility option AddParaLineSpacingToTableCells needs also line spacing
2637 const SvxLineSpacingItem &rSpace = m_rAttrSet.GetLineSpacing();
2638 if ( rSpace.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Prop && rSpace.GetPropLineSpace() > 100 )
2640 sal_Int32 nFontSize = m_rAttrSet.Get(RES_CHRATR_FONTSIZE).GetHeight();
2641 m_nLineSpacing = nFontSize * (rSpace.GetPropLineSpace() - 100) * 1.15 / 100;
2643 m_bLineSpacing = false;
2646 static sw::BorderCacheOwner const* GetBorderCacheOwner(SwFrame const& rFrame)
2648 return rFrame.IsContentFrame()
2649 ? static_cast<sw::BorderCacheOwner const*>(rFrame.IsTextFrame()
2650 // sw_redlinehide: presumably this caches the border attrs at the model level and can be shared across different layouts so we want the ParaProps node here
2651 ? static_cast<const SwTextFrame&>(rFrame).GetTextNodeForParaProps()
2652 : static_cast<const SwNoTextFrame&>(rFrame).GetNode())
2653 : static_cast<sw::BorderCacheOwner const*>(static_cast<const SwLayoutFrame&>(rFrame).GetFormat());
2656 SwBorderAttrAccess::SwBorderAttrAccess( SwCache &rCach, const SwFrame *pFrame ) :
2657 SwCacheAccess( rCach,
2658 static_cast<void const *>(GetBorderCacheOwner(*pFrame)),
2659 GetBorderCacheOwner(*pFrame)->IsInCache()),
2660 m_pConstructor( pFrame )
2664 SwCacheObj *SwBorderAttrAccess::NewObj()
2666 const_cast<sw::BorderCacheOwner *>(static_cast<sw::BorderCacheOwner const *>(m_pOwner))->m_bInCache = true;
2667 return new SwBorderAttrs( static_cast<sw::BorderCacheOwner const *>(m_pOwner), m_pConstructor );
2670 SwBorderAttrs *SwBorderAttrAccess::Get()
2672 return static_cast<SwBorderAttrs*>(SwCacheAccess::Get());
2675 SwOrderIter::SwOrderIter( const SwPageFrame *pPg ) :
2676 m_pPage( pPg ),
2677 m_pCurrent( nullptr )
2681 void SwOrderIter::Top()
2683 m_pCurrent = nullptr;
2684 if ( !m_pPage->GetSortedObjs() )
2685 return;
2687 const SwSortedObjs *pObjs = m_pPage->GetSortedObjs();
2688 if ( !pObjs->size() )
2689 return;
2691 sal_uInt32 nTopOrd = 0;
2692 (*pObjs)[0]->GetDrawObj()->GetOrdNum(); // force updating
2693 for (SwAnchoredObject* i : *pObjs)
2695 const SdrObject* pObj = i->GetDrawObj();
2696 if ( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) == nullptr )
2697 continue;
2698 sal_uInt32 nTmp = pObj->GetOrdNumDirect();
2699 if ( nTmp >= nTopOrd )
2701 nTopOrd = nTmp;
2702 m_pCurrent = pObj;
2707 const SdrObject *SwOrderIter::Bottom()
2709 m_pCurrent = nullptr;
2710 if ( m_pPage->GetSortedObjs() )
2712 sal_uInt32 nBotOrd = USHRT_MAX;
2713 const SwSortedObjs *pObjs = m_pPage->GetSortedObjs();
2714 if ( pObjs->size() )
2716 (*pObjs)[0]->GetDrawObj()->GetOrdNum(); // force updating
2717 for (SwAnchoredObject* i : *pObjs)
2719 const SdrObject* pObj = i->GetDrawObj();
2720 if ( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) == nullptr )
2721 continue;
2722 sal_uInt32 nTmp = pObj->GetOrdNumDirect();
2723 if ( nTmp < nBotOrd )
2725 nBotOrd = nTmp;
2726 m_pCurrent = pObj;
2731 return m_pCurrent;
2734 const SdrObject *SwOrderIter::Next()
2736 const sal_uInt32 nCurOrd = m_pCurrent ? m_pCurrent->GetOrdNumDirect() : 0;
2737 m_pCurrent = nullptr;
2738 if ( m_pPage->GetSortedObjs() )
2740 sal_uInt32 nOrd = USHRT_MAX;
2741 const SwSortedObjs *pObjs = m_pPage->GetSortedObjs();
2742 if ( pObjs->size() )
2744 (*pObjs)[0]->GetDrawObj()->GetOrdNum(); // force updating
2745 for (SwAnchoredObject* i : *pObjs)
2747 const SdrObject* pObj = i->GetDrawObj();
2748 if ( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) == nullptr )
2749 continue;
2750 sal_uInt32 nTmp = pObj->GetOrdNumDirect();
2751 if ( nTmp > nCurOrd && nTmp < nOrd )
2753 nOrd = nTmp;
2754 m_pCurrent = pObj;
2759 return m_pCurrent;
2762 void SwOrderIter::Prev()
2764 const sal_uInt32 nCurOrd = m_pCurrent ? m_pCurrent->GetOrdNumDirect() : 0;
2765 m_pCurrent = nullptr;
2766 if ( !m_pPage->GetSortedObjs() )
2767 return;
2769 const SwSortedObjs *pObjs = m_pPage->GetSortedObjs();
2770 if ( !pObjs->size() )
2771 return;
2773 sal_uInt32 nOrd = 0;
2774 (*pObjs)[0]->GetDrawObj()->GetOrdNum(); // force updating
2775 for (SwAnchoredObject* i : *pObjs)
2777 const SdrObject* pObj = i->GetDrawObj();
2778 if ( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) == nullptr )
2779 continue;
2780 sal_uInt32 nTmp = pObj->GetOrdNumDirect();
2781 if ( nTmp < nCurOrd && nTmp >= nOrd )
2783 nOrd = nTmp;
2784 m_pCurrent = pObj;
2789 /// Keep and restore the substructure of a layout frame for an action.
2790 // New algorithm:
2791 // Do not look at each neighbor one by one to set all pointers correctly.
2792 // It is sufficient to detach a part of a chain and check if another chain needs to be added
2793 // when attaching it again. Only the pointers necessary for the chain connection need to be
2794 // adjusted. The correction happens in RestoreContent(). In between all access is restricted.
2795 // During this action, the Flys are detached from the page.
2797 // #115759# - 'remove' also drawing object from page and
2798 // at-fly anchored objects from page
2799 static void lcl_RemoveObjsFromPage( SwFrame* _pFrame )
2801 OSL_ENSURE( _pFrame->GetDrawObjs(), "no DrawObjs in lcl_RemoveObjsFromPage." );
2802 SwSortedObjs &rObjs = *_pFrame->GetDrawObjs();
2803 for (SwAnchoredObject* pObj : rObjs)
2805 // #115759# - reset member, at which the anchored
2806 // object orients its vertical position
2807 pObj->ClearVertPosOrientFrame();
2808 // #i43913#
2809 pObj->ResetLayoutProcessBools();
2810 // #115759# - remove also lower objects of as-character
2811 // anchored Writer fly frames from page
2812 if ( auto pFlyFrame = pObj->DynCastFlyFrame() )
2814 // #115759# - remove also direct lowers of Writer
2815 // fly frame from page
2816 if ( pFlyFrame->GetDrawObjs() )
2818 ::lcl_RemoveObjsFromPage( pFlyFrame );
2821 SwContentFrame* pCnt = pFlyFrame->ContainsContent();
2822 while ( pCnt )
2824 if ( pCnt->GetDrawObjs() )
2825 ::lcl_RemoveObjsFromPage( pCnt );
2826 pCnt = pCnt->GetNextContentFrame();
2828 if ( pFlyFrame->IsFlyFreeFrame() )
2830 // #i28701# - use new method <GetPageFrame()>
2831 if (SwPageFrame *pPg = pFlyFrame->GetPageFrame())
2832 pPg->RemoveFlyFromPage(pFlyFrame);
2835 // #115759# - remove also drawing objects from page
2836 else if ( auto pDrawObj = dynamic_cast<SwAnchoredDrawObject*>( pObj) )
2838 if (pObj->GetFrameFormat().GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR)
2840 if (SwPageFrame *pPg = pObj->GetPageFrame())
2841 pPg->RemoveDrawObjFromPage( *pDrawObj );
2847 SwFrame *SaveContent( SwLayoutFrame *pLay, SwFrame *pStart )
2849 if( pLay->IsSctFrame() && pLay->Lower() && pLay->Lower()->IsColumnFrame() )
2850 sw_RemoveFootnotes( static_cast<SwColumnFrame*>(pLay->Lower()), true, true );
2852 SwFrame *pSav = pLay->ContainsAny();
2853 if ( nullptr == pSav )
2854 return nullptr;
2856 if( pSav->IsInFootnote() && !pLay->IsInFootnote() )
2859 pSav = pSav->FindNext();
2860 while( pSav && pSav->IsInFootnote() );
2861 if( !pSav || !pLay->IsAnLower( pSav ) )
2862 return nullptr;
2865 // Tables should be saved as a whole, exception:
2866 // The contents of a section or a cell inside a table should be saved
2867 if ( pSav->IsInTab() && !( ( pLay->IsSctFrame() || pLay->IsCellFrame() ) && pLay->IsInTab() ) )
2868 while ( !pSav->IsTabFrame() )
2869 pSav = pSav->GetUpper();
2871 if( pSav->IsInSct() )
2872 { // search the upmost section inside of pLay
2873 SwFrame* pSect = pLay->FindSctFrame();
2874 SwFrame *pTmp = pSav;
2877 pSav = pTmp;
2878 pTmp = (pSav && pSav->GetUpper()) ? pSav->GetUpper()->FindSctFrame() : nullptr;
2879 } while ( pTmp != pSect );
2882 SwFrame *pFloat = pSav;
2883 if( !pStart )
2884 pStart = pSav;
2885 bool bGo = pStart == pSav;
2888 if( bGo )
2889 pFloat->GetUpper()->m_pLower = nullptr; // detach the chain part
2891 // search the end of the chain part, remove Flys on the way
2894 if( bGo )
2896 if ( pFloat->IsContentFrame() )
2898 if ( pFloat->GetDrawObjs() )
2899 ::lcl_RemoveObjsFromPage( static_cast<SwContentFrame*>(pFloat) );
2901 else if ( pFloat->IsTabFrame() || pFloat->IsSctFrame() )
2903 SwContentFrame *pCnt = static_cast<SwLayoutFrame*>(pFloat)->ContainsContent();
2904 if( pCnt )
2907 { if ( pCnt->GetDrawObjs() )
2908 ::lcl_RemoveObjsFromPage( pCnt );
2909 pCnt = pCnt->GetNextContentFrame();
2910 } while ( pCnt && static_cast<SwLayoutFrame*>(pFloat)->IsAnLower( pCnt ) );
2913 else {
2914 OSL_ENSURE( !pFloat, "new FloatFrame?" );
2917 if ( pFloat->GetNext() )
2919 if( bGo )
2920 pFloat->mpUpper = nullptr;
2921 pFloat = pFloat->GetNext();
2922 if( !bGo && pFloat == pStart )
2924 bGo = true;
2925 pFloat->mpPrev->mpNext = nullptr;
2926 pFloat->mpPrev = nullptr;
2929 else
2930 break;
2932 } while ( pFloat );
2934 // search next chain part and connect both chains
2935 SwFrame *pTmp = pFloat->FindNext();
2936 if( bGo )
2937 pFloat->mpUpper = nullptr;
2939 if( !pLay->IsInFootnote() )
2940 while( pTmp && pTmp->IsInFootnote() )
2941 pTmp = pTmp->FindNext();
2943 if ( !pLay->IsAnLower( pTmp ) )
2944 pTmp = nullptr;
2946 if ( pTmp && bGo )
2948 pFloat->mpNext = pTmp; // connect both chains
2949 pFloat->mpNext->mpPrev = pFloat;
2951 pFloat = pTmp;
2952 bGo = bGo || ( pStart == pFloat );
2953 } while ( pFloat );
2955 return bGo ? pStart : nullptr;
2958 // #115759# - add also drawing objects to page and at-fly
2959 // anchored objects to page
2960 static void lcl_AddObjsToPage( SwFrame* _pFrame, SwPageFrame* _pPage )
2962 OSL_ENSURE( _pFrame->GetDrawObjs(), "no DrawObjs in lcl_AddObjsToPage." );
2963 SwSortedObjs &rObjs = *_pFrame->GetDrawObjs();
2964 for (SwAnchoredObject* pObj : rObjs)
2966 // #115759# - unlock position of anchored object
2967 // in order to get the object's position calculated.
2968 pObj->UnlockPosition();
2969 // #115759# - add also lower objects of as-character
2970 // anchored Writer fly frames from page
2971 if ( auto pFlyFrame = pObj->DynCastFlyFrame() )
2973 if (pFlyFrame->IsFlyFreeFrame())
2975 _pPage->AppendFlyToPage( pFlyFrame );
2977 pFlyFrame->InvalidatePos_();
2978 pFlyFrame->InvalidateSize_();
2979 pFlyFrame->InvalidatePage( _pPage );
2981 // #115759# - add also at-fly anchored objects
2982 // to page
2983 if ( pFlyFrame->GetDrawObjs() )
2985 ::lcl_AddObjsToPage( pFlyFrame, _pPage );
2988 SwContentFrame *pCnt = pFlyFrame->ContainsContent();
2989 while ( pCnt )
2991 if ( pCnt->GetDrawObjs() )
2992 ::lcl_AddObjsToPage( pCnt, _pPage );
2993 pCnt = pCnt->GetNextContentFrame();
2996 // #115759# - remove also drawing objects from page
2997 else if ( dynamic_cast<const SwAnchoredDrawObject*>( pObj) != nullptr )
2999 if (pObj->GetFrameFormat().GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR)
3001 pObj->InvalidateObjPos();
3002 _pPage->AppendDrawObjToPage(
3003 *static_cast<SwAnchoredDrawObject*>(pObj) );
3009 void RestoreContent( SwFrame *pSav, SwLayoutFrame *pParent, SwFrame *pSibling )
3011 OSL_ENSURE( pSav && pParent, "no Save or Parent provided for RestoreContent." );
3012 SwRectFnSet aRectFnSet(pParent);
3014 // If there are already FlowFrames below the new parent, so add the chain (starting with pSav)
3015 // after the last one. The parts are inserted and invalidated if needed.
3016 // On the way, the Flys of the ContentFrames are registered at the page.
3018 SwPageFrame *pPage = pParent->FindPageFrame();
3020 if ( pPage )
3021 pPage->InvalidatePage( pPage );
3023 // determine predecessor and establish connection or initialize
3024 pSav->mpPrev = pSibling;
3025 SwFrame* pNxt;
3026 if ( pSibling )
3028 pNxt = pSibling->mpNext;
3029 pSibling->mpNext = pSav;
3030 pSibling->InvalidatePrt_();
3031 pSibling->InvalidatePage( pPage );
3032 SwFlowFrame *pFlowFrame = dynamic_cast<SwFlowFrame*>(pSibling);
3033 if (pFlowFrame && pFlowFrame->GetFollow())
3034 pSibling->Prepare( PrepareHint::Clear, nullptr, false );
3036 else
3037 { pNxt = pParent->m_pLower;
3038 pParent->m_pLower = pSav;
3039 pSav->mpUpper = pParent; // set here already, so that it is explicit when invalidating
3041 if ( pSav->IsContentFrame() )
3042 static_cast<SwContentFrame*>(pSav)->InvalidatePage( pPage );
3043 else
3044 { // pSav might be an empty SectFrame
3045 SwContentFrame* pCnt = pParent->ContainsContent();
3046 if( pCnt )
3047 pCnt->InvalidatePage( pPage );
3051 // the parent needs to grow appropriately
3052 SwTwips nGrowVal = 0;
3053 SwFrame* pLast;
3055 { pSav->mpUpper = pParent;
3056 nGrowVal += aRectFnSet.GetHeight(pSav->getFrameArea());
3057 pSav->InvalidateAll_();
3059 // register Flys, if TextFrames than also invalidate appropriately
3060 if ( pSav->IsContentFrame() )
3062 if ( pSav->IsTextFrame() &&
3063 static_cast<SwTextFrame*>(pSav)->GetCacheIdx() != USHRT_MAX )
3064 static_cast<SwTextFrame*>(pSav)->Init(); // I am its friend
3066 if ( pPage && pSav->GetDrawObjs() )
3067 ::lcl_AddObjsToPage( static_cast<SwContentFrame*>(pSav), pPage );
3069 else
3070 { SwContentFrame *pBlub = static_cast<SwLayoutFrame*>(pSav)->ContainsContent();
3071 if( pBlub )
3074 { if ( pPage && pBlub->GetDrawObjs() )
3075 ::lcl_AddObjsToPage( pBlub, pPage );
3076 if( pBlub->IsTextFrame() && static_cast<SwTextFrame*>(pBlub)->HasFootnote() &&
3077 static_cast<SwTextFrame*>(pBlub)->GetCacheIdx() != USHRT_MAX )
3078 static_cast<SwTextFrame*>(pBlub)->Init(); // I am its friend
3079 pBlub = pBlub->GetNextContentFrame();
3080 } while ( pBlub && static_cast<SwLayoutFrame*>(pSav)->IsAnLower( pBlub ));
3083 pLast = pSav;
3084 pSav = pSav->GetNext();
3086 } while ( pSav );
3088 if( pNxt )
3090 pLast->mpNext = pNxt;
3091 pNxt->mpPrev = pLast;
3094 pParent->Grow( nGrowVal );
3097 namespace sw {
3099 bool IsRightPageByNumber(SwRootFrame const& rLayout, sal_uInt16 const nPageNum)
3101 assert(rLayout.GetLower());
3102 // unfortunately can only get SwPageDesc, not SwFormatPageDesc here...
3103 auto const nFirstVirtPageNum(rLayout.GetLower()->GetVirtPageNum());
3104 bool const isFirstPageOfLayoutOdd(nFirstVirtPageNum % 2 == 1);
3105 return ((nPageNum % 2) == 1) == isFirstPageOfLayoutOdd;
3108 } // namespace sw
3110 SwPageFrame * InsertNewPage( SwPageDesc &rDesc, SwFrame *pUpper,
3111 bool const isRightPage, bool const bFirst, bool bInsertEmpty,
3112 bool const bFootnote,
3113 SwFrame *pSibling,
3114 bool const bVeryFirstPage )
3116 assert(pUpper);
3117 assert(pUpper->IsRootFrame());
3118 assert(!pSibling || static_cast<SwLayoutFrame const*>(pUpper)->Lower() != pSibling); // currently no insert before 1st page
3119 SwPageFrame *pRet;
3120 SwDoc *pDoc = static_cast<SwLayoutFrame*>(pUpper)->GetFormat()->GetDoc();
3121 if (bFirst)
3123 if (rDesc.IsFirstShared())
3125 // We need to fallback to left or right page format, decide it now.
3126 // FIXME: is this still needed?
3127 if (isRightPage)
3129 rDesc.GetFirstMaster().SetFormatAttr( rDesc.GetMaster().GetHeader() );
3130 rDesc.GetFirstMaster().SetFormatAttr( rDesc.GetMaster().GetFooter() );
3131 // fdo#60250 copy margins for mirrored pages
3132 rDesc.GetFirstMaster().SetFormatAttr( rDesc.GetMaster().GetLRSpace() );
3134 else
3136 rDesc.GetFirstLeft().SetFormatAttr( rDesc.GetLeft().GetHeader() );
3137 rDesc.GetFirstLeft().SetFormatAttr( rDesc.GetLeft().GetFooter() );
3138 rDesc.GetFirstLeft().SetFormatAttr( rDesc.GetLeft().GetLRSpace() );
3142 SwFrameFormat *pFormat(isRightPage ? rDesc.GetRightFormat(bFirst) : rDesc.GetLeftFormat(bFirst));
3143 // If there is no FrameFormat for this page, add an empty page
3144 if ( !pFormat )
3146 pFormat = isRightPage ? rDesc.GetLeftFormat(bVeryFirstPage) : rDesc.GetRightFormat(bVeryFirstPage);
3147 OSL_ENSURE( pFormat, "Descriptor without any format?!" );
3148 bInsertEmpty = !bInsertEmpty;
3150 if( bInsertEmpty )
3152 SwPageDesc *pTmpDesc = pSibling && pSibling->GetPrev() ?
3153 static_cast<SwPageFrame*>(pSibling->GetPrev())->GetPageDesc() : &rDesc;
3154 pRet = new SwPageFrame( pDoc->GetEmptyPageFormat(), pUpper, pTmpDesc );
3155 SAL_INFO( "sw.pageframe", "InsertNewPage - insert empty p: " << pRet << " d: " << pTmpDesc );
3156 pRet->Paste( pUpper, pSibling );
3157 pRet->PreparePage( bFootnote );
3159 pRet = new SwPageFrame( pFormat, pUpper, &rDesc );
3160 SAL_INFO( "sw.pageframe", "InsertNewPage p: " << pRet << " d: " << &rDesc << " f: " << pFormat );
3161 pRet->Paste( pUpper, pSibling );
3162 pRet->PreparePage( bFootnote );
3163 if ( pRet->GetNext() )
3164 SwRootFrame::AssertPageFlys( pRet );
3165 return pRet;
3168 /* The following two methods search the layout structure recursively and
3169 * register all Flys at the page that have a Frame in this structure as an anchor.
3172 static void lcl_Regist( SwPageFrame *pPage, const SwFrame *pAnch )
3174 SwSortedObjs *pObjs = const_cast<SwSortedObjs*>(pAnch->GetDrawObjs());
3175 for (SwAnchoredObject* pObj : *pObjs)
3177 if (SwFlyFrame* pFly = pObj->DynCastFlyFrame())
3179 // register (not if already known)
3180 // #i28701# - use new method <GetPageFrame()>
3181 SwPageFrame *pPg = pFly->IsFlyFreeFrame()
3182 ? pFly->GetPageFrame() : pFly->FindPageFrame();
3183 if ( pPg != pPage )
3185 if ( pPg )
3186 pPg->RemoveFlyFromPage( pFly );
3187 pPage->AppendFlyToPage( pFly );
3189 ::RegistFlys( pPage, pFly );
3191 else
3193 // #i87493#
3194 if ( pPage != pObj->GetPageFrame() )
3196 // #i28701#
3197 if (SwPageFrame *pPg = pObj->GetPageFrame())
3198 pPg->RemoveDrawObjFromPage( *pObj );
3199 pPage->AppendDrawObjToPage( *pObj );
3203 const SwFlyFrame* pFly = pAnch->FindFlyFrame();
3204 if ( pFly &&
3205 pObj->GetDrawObj()->GetOrdNum() < pFly->GetVirtDrawObj()->GetOrdNum() &&
3206 pObj->GetDrawObj()->getSdrPageFromSdrObject() )
3208 //#i119945# set pFly's OrdNum to pObj's. So when pFly is removed by Undo, the original OrdNum will not be changed.
3209 pObj->DrawObj()->getSdrPageFromSdrObject()->SetObjectOrdNum( pFly->GetVirtDrawObj()->GetOrdNumDirect(),
3210 pObj->GetDrawObj()->GetOrdNumDirect() );
3215 void RegistFlys( SwPageFrame *pPage, const SwLayoutFrame *pLay )
3217 if ( pLay->GetDrawObjs() )
3218 ::lcl_Regist( pPage, pLay );
3219 const SwFrame *pFrame = pLay->Lower();
3220 while ( pFrame )
3222 if ( pFrame->IsLayoutFrame() )
3223 ::RegistFlys( pPage, static_cast<const SwLayoutFrame*>(pFrame) );
3224 else if ( pFrame->GetDrawObjs() )
3225 ::lcl_Regist( pPage, pFrame );
3226 pFrame = pFrame->GetNext();
3230 /// Notify the background based on the difference between old and new rectangle
3231 void Notify( SwFlyFrame *pFly, SwPageFrame *pOld, const SwRect &rOld,
3232 const SwRect* pOldPrt )
3234 const SwRect aFrame( pFly->GetObjRectWithSpaces() );
3235 if ( rOld.Pos() != aFrame.Pos() )
3236 { // changed position, invalidate old and new area
3237 if ( rOld.HasArea() &&
3238 rOld.Left()+pFly->GetFormat()->GetLRSpace().GetLeft() < FAR_AWAY )
3240 pFly->NotifyBackground( pOld, rOld, PrepareHint::FlyFrameLeave );
3242 pFly->NotifyBackground( pFly->FindPageFrame(), aFrame, PrepareHint::FlyFrameArrive );
3244 else if ( rOld.SSize() != aFrame.SSize() )
3245 { // changed size, invalidate the area that was left or is now overlapped
3246 // For simplicity, we purposely invalidate a Twip even if not needed.
3248 SwViewShell *pSh = pFly->getRootFrame()->GetCurrShell();
3249 if( pSh && rOld.HasArea() )
3250 pSh->InvalidateWindows( rOld );
3252 // #i51941# - consider case that fly frame isn't
3253 // registered at the old page <pOld>
3254 SwPageFrame* pPageFrame = pFly->FindPageFrame();
3255 if ( pOld != pPageFrame )
3257 pFly->NotifyBackground( pPageFrame, aFrame, PrepareHint::FlyFrameArrive );
3260 if ( rOld.Left() != aFrame.Left() )
3262 SwRect aTmp( rOld );
3263 aTmp.Union( aFrame );
3264 aTmp.Left( std::min(aFrame.Left(), rOld.Left()) );
3265 aTmp.Right( std::max(aFrame.Left(), rOld.Left()) );
3266 pFly->NotifyBackground( pOld, aTmp, PrepareHint::FlyFrameSizeChanged );
3268 SwTwips nOld = rOld.Right();
3269 SwTwips nNew = aFrame.Right();
3270 if ( nOld != nNew )
3272 SwRect aTmp( rOld );
3273 aTmp.Union( aFrame );
3274 aTmp.Left( std::min(nNew, nOld) );
3275 aTmp.Right( std::max(nNew, nOld) );
3276 pFly->NotifyBackground( pOld, aTmp, PrepareHint::FlyFrameSizeChanged );
3278 if ( rOld.Top() != aFrame.Top() )
3280 SwRect aTmp( rOld );
3281 aTmp.Union( aFrame );
3282 aTmp.Top( std::min(aFrame.Top(), rOld.Top()) );
3283 aTmp.Bottom( std::max(aFrame.Top(), rOld.Top()) );
3284 pFly->NotifyBackground( pOld, aTmp, PrepareHint::FlyFrameSizeChanged );
3286 nOld = rOld.Bottom();
3287 nNew = aFrame.Bottom();
3288 if ( nOld != nNew )
3290 SwRect aTmp( rOld );
3291 aTmp.Union( aFrame );
3292 aTmp.Top( std::min(nNew, nOld) );
3293 aTmp.Bottom( std::max(nNew, nOld) );
3294 pFly->NotifyBackground( pOld, aTmp, PrepareHint::FlyFrameSizeChanged );
3297 else if(pOldPrt && *pOldPrt != pFly->getFramePrintArea())
3299 bool bNotifyBackground(pFly->GetFormat()->GetSurround().IsContour());
3301 if(!bNotifyBackground &&
3302 pFly->IsFlyFreeFrame() &&
3303 static_cast< const SwFlyFreeFrame* >(pFly)->supportsAutoContour())
3305 // RotateFlyFrame3: Also notify for FlyFrames which allow AutoContour
3306 bNotifyBackground = true;
3309 if(bNotifyBackground)
3311 // #i24097#
3312 pFly->NotifyBackground( pFly->FindPageFrame(), aFrame, PrepareHint::FlyFrameArrive );
3317 static void lcl_CheckFlowBack( SwFrame* pFrame, const SwRect &rRect )
3319 SwTwips nBottom = rRect.Bottom();
3320 while( pFrame )
3322 if( pFrame->IsLayoutFrame() )
3324 if( rRect.Overlaps( pFrame->getFrameArea() ) )
3325 lcl_CheckFlowBack( static_cast<SwLayoutFrame*>(pFrame)->Lower(), rRect );
3327 else if( !pFrame->GetNext() && nBottom > pFrame->getFrameArea().Bottom() )
3329 if( pFrame->IsContentFrame() && static_cast<SwContentFrame*>(pFrame)->HasFollow() )
3330 pFrame->InvalidateSize();
3331 else
3332 pFrame->InvalidateNextPos();
3334 pFrame = pFrame->GetNext();
3338 static void lcl_NotifyContent( const SdrObject *pThis, SwContentFrame *pCnt,
3339 const SwRect &rRect, const PrepareHint eHint )
3341 if ( !pCnt->IsTextFrame() )
3342 return;
3344 auto pTextFrame = static_cast<SwTextFrame*>(pCnt);
3345 SwRect aCntPrt( pCnt->getFramePrintArea() );
3346 aCntPrt.Pos() += pCnt->getFrameArea().Pos();
3348 if (eHint == PrepareHint::FlyFrameArrive)
3350 SwTwips nLower = pTextFrame->GetLowerMarginForFlyIntersect();
3351 if (nLower > 0)
3353 aCntPrt.AddBottom(nLower);
3357 if ( eHint == PrepareHint::FlyFrameAttributesChanged )
3359 // #i35640# - use given rectangle <rRect> instead
3360 // of current bound rectangle
3361 if ( aCntPrt.Overlaps( rRect ) )
3362 pCnt->Prepare( PrepareHint::FlyFrameAttributesChanged );
3364 // #i23129# - only invalidate, if the text frame
3365 // printing area overlaps with the given rectangle.
3366 else if ( aCntPrt.Overlaps( rRect ) )
3367 pCnt->Prepare( eHint, static_cast<void*>(&aCntPrt.Intersection_( rRect )) );
3368 if ( !pCnt->GetDrawObjs() )
3369 return;
3371 const SwSortedObjs &rObjs = *pCnt->GetDrawObjs();
3372 for (SwAnchoredObject* pObj : rObjs)
3374 if ( auto pFly = pObj->DynCastFlyFrame() )
3376 if ( pFly->IsFlyInContentFrame() )
3378 SwContentFrame *pContent = pFly->ContainsContent();
3379 while ( pContent )
3381 ::lcl_NotifyContent( pThis, pContent, rRect, eHint );
3382 pContent = pContent->GetNextContentFrame();
3389 void Notify_Background( const SdrObject* pObj,
3390 SwPageFrame* pPage,
3391 const SwRect& rRect,
3392 const PrepareHint eHint,
3393 const bool bInva )
3395 // If the frame was positioned correctly for the first time, do not inform the old area
3396 if ( eHint == PrepareHint::FlyFrameLeave && rRect.Top() == FAR_AWAY )
3397 return;
3399 SwLayoutFrame* pArea;
3400 SwFlyFrame *pFlyFrame = nullptr;
3401 SwFrame* pAnchor;
3402 if( auto pVirtFlyDrawObj = dynamic_cast<const SwVirtFlyDrawObj*>( pObj) )
3404 pFlyFrame = const_cast<SwVirtFlyDrawObj*>(pVirtFlyDrawObj)->GetFlyFrame();
3405 pAnchor = pFlyFrame->AnchorFrame();
3407 else
3409 pFlyFrame = nullptr;
3410 pAnchor = const_cast<SwFrame*>(
3411 GetUserCall(pObj)->GetAnchoredObj( pObj )->GetAnchorFrame() );
3413 if( PrepareHint::FlyFrameLeave != eHint && pAnchor->IsInFly() )
3414 pArea = pAnchor->FindFlyFrame();
3415 else
3416 pArea = pPage;
3417 SwContentFrame *pCnt = nullptr;
3418 if ( pArea )
3420 if( PrepareHint::FlyFrameArrive != eHint )
3421 lcl_CheckFlowBack( pArea, rRect );
3423 // Only the Flys following this anchor are reacting. Thus, those do not
3424 // need to be processed.
3425 // An exception is LEAVE, since the Fly might come "from above".
3426 // If the anchor is positioned on the previous page, the whole page
3427 // needs to be processed (47722).
3428 // OD 2004-05-13 #i28701# - If the wrapping style has to be considered
3429 // on the object positioning, the complete area has to be processed,
3430 // because content frames before the anchor frame also have to consider
3431 // the object for the text wrapping.
3432 // #i3317# - The complete area has always been
3433 // processed.
3435 pCnt = pArea->ContainsContent();
3438 SwFrame *pLastTab = nullptr;
3440 bool isValidTableBeforeAnchor(false);
3441 while ( pCnt && pArea && pArea->IsAnLower( pCnt ) )
3443 ::lcl_NotifyContent( pObj, pCnt, rRect, eHint );
3444 if ( pCnt->IsInTab() )
3446 SwTabFrame *pTab = pCnt->FindTabFrame();
3447 if ( pTab != pLastTab )
3449 pLastTab = pTab;
3450 isValidTableBeforeAnchor = false;
3451 if (PrepareHint::FlyFrameArrive == eHint
3452 && pFlyFrame // TODO: do it for draw objects too?
3453 && pTab->IsFollow() // table starts on previous page?
3454 // "through" means they will actually overlap anyway
3455 && css::text::WrapTextMode_THROUGH != pFlyFrame->GetFormat()->GetSurround().GetSurround()
3456 // if it's anchored in footer it can't move to other page
3457 && !pAnchor->FindFooterOrHeader())
3459 SwFrame * pTmp(pAnchor->GetPrev());
3460 while (pTmp)
3462 if (pTmp == pTab)
3464 // tdf#99460 the table shouldn't be moved by the fly
3465 isValidTableBeforeAnchor = true;
3466 break;
3468 pTmp = pTmp->GetPrev();
3471 // #i40606# - use <GetLastBoundRect()>
3472 // instead of <GetCurrentBoundRect()>, because a recalculation
3473 // of the bounding rectangle isn't intended here.
3474 if (!isValidTableBeforeAnchor
3475 && (pTab->getFrameArea().Overlaps(SwRect(pObj->GetLastBoundRect())) ||
3476 pTab->getFrameArea().Overlaps(rRect)))
3478 if ( !pFlyFrame || !pFlyFrame->IsLowerOf( pTab ) )
3479 pTab->InvalidatePrt();
3482 SwLayoutFrame* pCell = pCnt->GetUpper();
3483 // #i40606# - use <GetLastBoundRect()>
3484 // instead of <GetCurrentBoundRect()>, because a recalculation
3485 // of the bounding rectangle isn't intended here.
3486 if (!isValidTableBeforeAnchor && pCell->IsCellFrame() &&
3487 ( pCell->getFrameArea().Overlaps( SwRect(pObj->GetLastBoundRect()) ) ||
3488 pCell->getFrameArea().Overlaps( rRect ) ) )
3490 const SwFormatVertOrient &rOri = pCell->GetFormat()->GetVertOrient();
3491 if ( text::VertOrientation::NONE != rOri.GetVertOrient() )
3492 pCell->InvalidatePrt();
3495 pCnt = pCnt->GetNextContentFrame();
3497 // #128702# - make code robust
3498 if ( pPage && pPage->GetSortedObjs() )
3500 pObj->GetOrdNum();
3501 const SwSortedObjs &rObjs = *pPage->GetSortedObjs();
3502 for (SwAnchoredObject* pAnchoredObj : rObjs)
3504 if ( pAnchoredObj->DynCastFlyFrame() != nullptr )
3506 if( pAnchoredObj->GetDrawObj() == pObj )
3507 continue;
3508 SwFlyFrame *pFly = static_cast<SwFlyFrame*>(pAnchoredObj);
3509 if ( pFly->getFrameArea().Top() == FAR_AWAY )
3510 continue;
3512 if ( !pFlyFrame ||
3513 (!pFly->IsLowerOf( pFlyFrame ) &&
3514 pFly->GetVirtDrawObj()->GetOrdNumDirect() < pObj->GetOrdNumDirect()))
3516 pCnt = pFly->ContainsContent();
3517 while ( pCnt )
3519 ::lcl_NotifyContent( pObj, pCnt, rRect, eHint );
3520 pCnt = pCnt->GetNextContentFrame();
3523 if( pFly->IsFlyLayFrame() )
3525 if( pFly->Lower() && pFly->Lower()->IsColumnFrame() &&
3526 pFly->getFrameArea().Bottom() >= rRect.Top() &&
3527 pFly->getFrameArea().Top() <= rRect.Bottom() &&
3528 pFly->getFrameArea().Right() >= rRect.Left() &&
3529 pFly->getFrameArea().Left() <= rRect.Right() )
3531 pFly->InvalidateSize();
3534 // Flys above myself might sidestep if they have an automatic
3535 // alignment. This happens independently of my attributes since
3536 // this might have been changed as well.
3537 else if ( pFly->IsFlyAtContentFrame() &&
3538 pObj->GetOrdNumDirect() <
3539 pFly->GetVirtDrawObj()->GetOrdNumDirect() &&
3540 pFlyFrame && !pFly->IsLowerOf( pFlyFrame ) )
3542 const SwFormatHoriOrient &rH = pFly->GetFormat()->GetHoriOrient();
3543 if ( text::HoriOrientation::NONE != rH.GetHoriOrient() &&
3544 text::HoriOrientation::CENTER != rH.GetHoriOrient() &&
3545 ( !pFly->IsAutoPos() || text::RelOrientation::CHAR != rH.GetRelationOrient() ) &&
3546 (pFly->getFrameArea().Bottom() >= rRect.Top() &&
3547 pFly->getFrameArea().Top() <= rRect.Bottom()) )
3548 pFly->InvalidatePos();
3553 if ( pFlyFrame && pAnchor->GetUpper() && pAnchor->IsInTab() )//MA_FLY_HEIGHT
3554 pAnchor->GetUpper()->InvalidateSize();
3556 // #i82258# - make code robust
3557 SwViewShell* pSh = nullptr;
3558 if ( bInva && pPage &&
3559 nullptr != (pSh = pPage->getRootFrame()->GetCurrShell()) )
3561 pSh->InvalidateWindows( rRect );
3565 /// Provides the Upper of an anchor in paragraph-bound objects. If the latter
3566 /// is a chained border or a footnote, the "virtual" Upper might be returned.
3567 const SwFrame* GetVirtualUpper( const SwFrame* pFrame, const Point& rPos )
3569 if( pFrame->IsTextFrame() )
3571 pFrame = pFrame->GetUpper();
3572 if( !pFrame->getFrameArea().Contains( rPos ) )
3574 if( pFrame->IsFootnoteFrame() )
3576 const SwFootnoteFrame* pTmp = static_cast<const SwFootnoteFrame*>(pFrame)->GetFollow();
3577 while( pTmp )
3579 if( pTmp->getFrameArea().Contains( rPos ) )
3580 return pTmp;
3581 pTmp = pTmp->GetFollow();
3584 else
3586 SwFlyFrame* pTmp = const_cast<SwFlyFrame*>(pFrame->FindFlyFrame());
3587 while( pTmp )
3589 if( pTmp->getFrameArea().Contains( rPos ) )
3590 return pTmp;
3591 pTmp = pTmp->GetNextLink();
3596 return pFrame;
3599 bool Is_Lower_Of(const SwFrame *pCurrFrame, const SdrObject* pObj)
3601 Point aPos;
3602 const SwFrame* pFrame;
3603 if (const SwVirtFlyDrawObj *pFlyDrawObj = dynamic_cast<const SwVirtFlyDrawObj*>(pObj))
3605 const SwFlyFrame* pFly = pFlyDrawObj->GetFlyFrame();
3606 pFrame = pFly->GetAnchorFrame();
3607 aPos = pFly->getFrameArea().Pos();
3609 else
3611 pFrame = static_cast<SwDrawContact*>(GetUserCall(pObj))->GetAnchorFrame(pObj);
3612 aPos = pObj->GetCurrentBoundRect().TopLeft();
3614 OSL_ENSURE( pFrame, "8-( Fly is lost in Space." );
3615 pFrame = GetVirtualUpper( pFrame, aPos );
3617 { if ( pFrame == pCurrFrame )
3618 return true;
3619 if( pFrame->IsFlyFrame() )
3621 aPos = pFrame->getFrameArea().Pos();
3622 pFrame = GetVirtualUpper( static_cast<const SwFlyFrame*>(pFrame)->GetAnchorFrame(), aPos );
3624 else
3625 pFrame = pFrame->GetUpper();
3626 } while ( pFrame );
3627 return false;
3630 /// provides the area of a frame in that no Fly from another area can overlap
3631 const SwFrame *FindContext( const SwFrame *pFrame, SwFrameType nAdditionalContextType )
3633 const SwFrameType nTyp = SwFrameType::Root | SwFrameType::Header | SwFrameType::Footer | SwFrameType::FtnCont |
3634 SwFrameType::Ftn | SwFrameType::Fly |
3635 SwFrameType::Tab | SwFrameType::Row | SwFrameType::Cell |
3636 nAdditionalContextType;
3638 { if ( pFrame->GetType() & nTyp )
3639 break;
3640 pFrame = pFrame->GetUpper();
3641 } while( pFrame );
3642 return pFrame;
3645 bool IsFrameInSameContext( const SwFrame *pInnerFrame, const SwFrame *pFrame )
3647 const SwFrame *pContext = FindContext( pInnerFrame, SwFrameType::None );
3649 const SwFrameType nTyp = SwFrameType::Root | SwFrameType::Header | SwFrameType::Footer | SwFrameType::FtnCont |
3650 SwFrameType::Ftn | SwFrameType::Fly |
3651 SwFrameType::Tab | SwFrameType::Row | SwFrameType::Cell;
3653 { if ( pFrame->GetType() & nTyp )
3655 if( pFrame == pContext )
3656 return true;
3657 if( pFrame->IsCellFrame() )
3658 return false;
3660 if( pFrame->IsFlyFrame() )
3662 Point aPos( pFrame->getFrameArea().Pos() );
3663 pFrame = GetVirtualUpper( static_cast<const SwFlyFrame*>(pFrame)->GetAnchorFrame(), aPos );
3665 else
3666 pFrame = pFrame->GetUpper();
3667 } while( pFrame );
3669 return false;
3672 static SwTwips lcl_CalcCellRstHeight( SwLayoutFrame *pCell )
3674 SwFrame *pLow = pCell->Lower();
3675 if ( pLow && (pLow->IsContentFrame() || pLow->IsSctFrame()) )
3677 tools::Long nHeight = 0, nFlyAdd = 0;
3680 tools::Long nLow = pLow->getFrameArea().Height();
3681 if( pLow->IsTextFrame() && static_cast<SwTextFrame*>(pLow)->IsUndersized() )
3682 nLow += static_cast<SwTextFrame*>(pLow)->GetParHeight()-pLow->getFramePrintArea().Height();
3683 else if( pLow->IsSctFrame() && static_cast<SwSectionFrame*>(pLow)->IsUndersized() )
3684 nLow += static_cast<SwSectionFrame*>(pLow)->Undersize();
3685 nFlyAdd = std::max( tools::Long(0), nFlyAdd - nLow );
3686 nFlyAdd = std::max( nFlyAdd, ::CalcHeightWithFlys( pLow ) );
3687 nHeight += nLow;
3688 pLow = pLow->GetNext();
3689 } while ( pLow );
3690 if ( nFlyAdd )
3691 nHeight += nFlyAdd;
3693 // The border cannot be calculated based on PrtArea and Frame, since both can be invalid.
3694 SwBorderAttrAccess aAccess( SwFrame::GetCache(), pCell );
3695 const SwBorderAttrs &rAttrs = *aAccess.Get();
3696 nHeight += rAttrs.CalcTop() + rAttrs.CalcBottom();
3698 return pCell->getFrameArea().Height() - nHeight;
3700 else
3702 tools::Long nRstHeight = 0;
3703 while (pLow && pLow->IsLayoutFrame())
3705 nRstHeight += ::CalcRowRstHeight(static_cast<SwLayoutFrame*>(pLow));
3706 pLow = pLow->GetNext();
3708 return nRstHeight;
3712 SwTwips CalcRowRstHeight( SwLayoutFrame *pRow )
3714 SwFrame *pLow = pRow->Lower();
3715 if (!(pLow && pLow->IsLayoutFrame()))
3717 return 0;
3719 SwTwips nRstHeight = LONG_MAX;
3720 while (pLow && pLow->IsLayoutFrame())
3722 nRstHeight = std::min(nRstHeight, ::lcl_CalcCellRstHeight(static_cast<SwLayoutFrame*>(pLow)));
3723 pLow = pLow->GetNext();
3725 return nRstHeight;
3728 const SwFrame* FindPage( const SwRect &rRect, const SwFrame *pPage )
3730 if ( !rRect.Overlaps( pPage->getFrameArea() ) )
3732 const SwRootFrame* pRootFrame = static_cast<const SwRootFrame*>(pPage->GetUpper());
3733 const SwFrame* pTmpPage = pRootFrame ? pRootFrame->GetPageAtPos( rRect.TopLeft(), &rRect.SSize(), true ) : nullptr;
3734 if ( pTmpPage )
3735 pPage = pTmpPage;
3738 return pPage;
3741 namespace {
3743 class SwFrameHolder : private SfxListener
3745 SwFrame* m_pFrame;
3746 bool m_bSet;
3747 virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
3748 public:
3749 SwFrameHolder()
3750 : m_pFrame(nullptr)
3751 , m_bSet(false)
3754 void SetFrame( SwFrame* pHold );
3755 SwFrame* GetFrame() { return m_pFrame; }
3756 void Reset();
3757 bool IsSet() const { return m_bSet; }
3762 void SwFrameHolder::SetFrame( SwFrame* pHold )
3764 m_bSet = true;
3765 if (m_pFrame != pHold)
3767 if (m_pFrame)
3768 EndListening(*m_pFrame);
3769 StartListening(*pHold);
3770 m_pFrame = pHold;
3774 void SwFrameHolder::Reset()
3776 if (m_pFrame)
3777 EndListening(*m_pFrame);
3778 m_bSet = false;
3779 m_pFrame = nullptr;
3782 void SwFrameHolder::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
3784 if (rHint.GetId() == SfxHintId::Dying && &rBC == m_pFrame)
3786 m_pFrame = nullptr;
3790 SwFrame* GetFrameOfModify(SwRootFrame const*const pLayout, sw::BroadcastingModify const& rMod,
3791 SwFrameType const nFrameType, SwPosition const*const pPos,
3792 std::pair<Point, bool> const*const pViewPosAndCalcFrame)
3794 SwFrame *pMinFrame = nullptr, *pTmpFrame;
3795 SwFrameHolder aHolder;
3796 SwRect aCalcRect;
3797 bool bClientIterChanged = false;
3799 SwIterator<SwFrame, sw::BroadcastingModify, sw::IteratorMode::UnwrapMulti> aIter(rMod);
3800 do {
3801 pMinFrame = nullptr;
3802 aHolder.Reset();
3803 sal_uInt64 nMinDist = 0;
3804 bClientIterChanged = false;
3806 for( pTmpFrame = aIter.First(); pTmpFrame; pTmpFrame = aIter.Next() )
3808 if( pTmpFrame->GetType() & nFrameType &&
3809 ( !pLayout || pLayout == pTmpFrame->getRootFrame() ) &&
3810 (!pTmpFrame->IsFlowFrame() ||
3811 !SwFlowFrame::CastFlowFrame( pTmpFrame )->IsFollow() ))
3813 if (pViewPosAndCalcFrame)
3815 // watch for Frame being deleted
3816 if ( pMinFrame )
3817 aHolder.SetFrame( pMinFrame );
3818 else
3819 aHolder.Reset();
3821 if (pViewPosAndCalcFrame->second)
3823 // tdf#108118 prevent recursion
3824 DisableCallbackAction a(*pTmpFrame->getRootFrame());
3825 // - format parent Writer
3826 // fly frame, if it isn't been formatted yet.
3827 // Note: The Writer fly frame could be the frame itself.
3828 SwFlyFrame* pFlyFrame( pTmpFrame->FindFlyFrame() );
3829 if ( pFlyFrame &&
3830 pFlyFrame->getFrameArea().Pos().X() == FAR_AWAY &&
3831 pFlyFrame->getFrameArea().Pos().Y() == FAR_AWAY )
3833 SwObjectFormatter::FormatObj( *pFlyFrame );
3835 pTmpFrame->Calc(pLayout ? pLayout->GetCurrShell()->GetOut() : nullptr);
3838 // aIter.IsChanged checks if the current pTmpFrame has been deleted while
3839 // it is the current iterator
3840 // FrameHolder watches for deletion of the current pMinFrame
3841 if( aIter.IsChanged() || ( aHolder.IsSet() && !aHolder.GetFrame() ) )
3843 // restart iteration
3844 bClientIterChanged = true;
3845 break;
3848 // for Flys go via the parent if the Fly is not yet "formatted"
3849 if (!pViewPosAndCalcFrame->second &&
3850 pTmpFrame->GetType() & SwFrameType::Fly &&
3851 static_cast<SwFlyFrame*>(pTmpFrame)->GetAnchorFrame() &&
3852 FAR_AWAY == pTmpFrame->getFrameArea().Pos().getX() &&
3853 FAR_AWAY == pTmpFrame->getFrameArea().Pos().getY() )
3854 aCalcRect = static_cast<SwFlyFrame*>(pTmpFrame)->GetAnchorFrame()->getFrameArea();
3855 else
3856 aCalcRect = pTmpFrame->getFrameArea();
3858 if (aCalcRect.Contains(pViewPosAndCalcFrame->first))
3860 pMinFrame = pTmpFrame;
3861 break;
3864 // Point not in rectangle. Compare distances:
3865 const Point aCalcRectCenter = aCalcRect.Center();
3866 const Point aDiff = aCalcRectCenter - pViewPosAndCalcFrame->first;
3867 const sal_uInt64 nCurrentDist = sal_Int64(aDiff.getX()) * sal_Int64(aDiff.getX()) + sal_Int64(aDiff.getY()) * sal_Int64(aDiff.getY()); // opt: no sqrt
3868 if ( !pMinFrame || nCurrentDist < nMinDist )
3870 pMinFrame = pTmpFrame;
3871 nMinDist = nCurrentDist;
3874 else
3876 // if no pViewPosAndCalcFrame is provided, take the first one
3877 pMinFrame = pTmpFrame;
3878 break;
3882 } while( bClientIterChanged );
3884 if( pPos && pMinFrame && pMinFrame->IsTextFrame() )
3885 return static_cast<SwTextFrame*>(pMinFrame)->GetFrameAtPos( *pPos );
3887 return pMinFrame;
3890 bool IsExtraData( const SwDoc *pDoc )
3892 const SwLineNumberInfo &rInf = pDoc->GetLineNumberInfo();
3893 if (rInf.IsPaintLineNumbers() ||
3894 rInf.IsCountInFlys() ||
3895 (static_cast<sal_Int16>(SW_MOD()->GetRedlineMarkPos()) != text::HoriOrientation::NONE &&
3896 !pDoc->getIDocumentRedlineAccess().GetRedlineTable().empty()))
3898 return true;
3901 const SwEditShell* pSh = pDoc->GetEditShell();
3902 const SwViewOption* pViewOptions = pSh ? pSh->GetViewOptions() : nullptr;
3903 return pViewOptions && pViewOptions->IsShowOutlineContentVisibilityButton();
3906 // OD 22.09.2003 #110978#
3907 SwRect SwPageFrame::PrtWithoutHeaderAndFooter() const
3909 SwRect aPrtWithoutHeaderFooter( getFramePrintArea() );
3910 aPrtWithoutHeaderFooter.Pos() += getFrameArea().Pos();
3912 const SwFrame* pLowerFrame = Lower();
3913 while ( pLowerFrame )
3915 // Note: independent on text direction page header and page footer are
3916 // always at top respectively at bottom of the page frame.
3917 if ( pLowerFrame->IsHeaderFrame() )
3919 aPrtWithoutHeaderFooter.AddTop( pLowerFrame->getFrameArea().Height() );
3921 if ( pLowerFrame->IsFooterFrame() )
3923 aPrtWithoutHeaderFooter.AddBottom( - pLowerFrame->getFrameArea().Height() );
3926 pLowerFrame = pLowerFrame->GetNext();
3929 return aPrtWithoutHeaderFooter;
3932 /** method to determine the spacing values of a frame
3934 OD 2004-03-10 #i28701#
3935 OD 2009-08-28 #i102458#
3936 Add output parameter <obIsLineSpacingProportional>
3938 void GetSpacingValuesOfFrame( const SwFrame& rFrame,
3939 SwTwips& onLowerSpacing,
3940 SwTwips& onLineSpacing,
3941 bool& obIsLineSpacingProportional,
3942 bool bIdenticalStyles )
3944 if ( !rFrame.IsFlowFrame() )
3946 onLowerSpacing = 0;
3947 onLineSpacing = 0;
3949 else
3951 const SvxULSpaceItem& rULSpace = rFrame.GetAttrSet()->GetULSpace();
3952 // check contextual spacing if the style of actual and next paragraphs are identical
3953 if (bIdenticalStyles)
3954 onLowerSpacing = (rULSpace.GetContext() ? 0 : rULSpace.GetLower());
3955 else
3956 onLowerSpacing = rULSpace.GetLower();
3958 onLineSpacing = 0;
3959 obIsLineSpacingProportional = false;
3960 if ( rFrame.IsTextFrame() )
3962 onLineSpacing = static_cast<const SwTextFrame&>(rFrame).GetLineSpace();
3963 obIsLineSpacingProportional =
3964 onLineSpacing != 0 &&
3965 static_cast<const SwTextFrame&>(rFrame).GetLineSpace( true ) == 0;
3968 OSL_ENSURE( onLowerSpacing >= 0 && onLineSpacing >= 0,
3969 "<GetSpacingValuesOfFrame(..)> - spacing values aren't positive!" );
3973 /// get the content of the table cell, skipping content from nested tables
3974 const SwContentFrame* GetCellContent( const SwLayoutFrame& rCell )
3976 const SwContentFrame* pContent = rCell.ContainsContent();
3977 const SwTabFrame* pTab = rCell.FindTabFrame();
3979 while ( pContent && rCell.IsAnLower( pContent ) )
3981 const SwTabFrame* pTmpTab = pContent->FindTabFrame();
3982 if ( pTmpTab != pTab )
3984 SwFrame const*const pTmp = pTmpTab->FindLastContentOrTable();
3985 if (pTmp)
3987 pContent = pTmp->FindNextCnt();
3989 else
3991 pContent = nullptr;
3994 else
3995 break;
3997 return pContent;
4000 SwDeletionChecker::SwDeletionChecker(const SwFrame* pFrame)
4001 : mpFrame( pFrame )
4002 , mpRegIn( pFrame
4003 ? pFrame->IsTextFrame()
4004 // sw_redlinehide: GetDep() may be a member of SwTextFrame!
4005 ? static_cast<SwTextFrame const*>(pFrame)->GetTextNodeFirst()
4006 : const_cast<SwFrame*>(pFrame)->GetDep()
4007 : nullptr )
4011 /// Can be used to check if a frame has been deleted
4012 bool SwDeletionChecker::HasBeenDeleted() const
4014 if ( !mpFrame || !mpRegIn )
4015 return false;
4017 SwIterator<SwFrame, sw::BroadcastingModify, sw::IteratorMode::UnwrapMulti> aIter(*mpRegIn);
4018 SwFrame* pLast = aIter.First();
4019 while ( pLast )
4021 if ( pLast == mpFrame )
4022 return false;
4023 pLast = aIter.Next();
4026 return true;
4029 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */