tdf#91920 sw page gutter margin: handle mirrored margins
[LibreOffice.git] / sw / source / core / layout / frmtool.cxx
blobfa8603bcc9b3d743c8111293e1c6ef6389ce4ce0
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 <svx/svdmodel.hxx>
21 #include <svx/svdpage.hxx>
22 #include <editeng/brushitem.hxx>
23 #include <editeng/shaditem.hxx>
24 #include <editeng/ulspitem.hxx>
25 #include <editeng/boxitem.hxx>
26 #include <editeng/lspcitem.hxx>
27 #include <editeng/fhgtitem.hxx>
28 #include <sal/log.hxx>
30 #include <drawdoc.hxx>
31 #include <fmtornt.hxx>
32 #include <fmthdft.hxx>
33 #include <fmtfsize.hxx>
34 #include <fmtsrnd.hxx>
35 #include <docary.hxx>
36 #include <lineinfo.hxx>
37 #include <swmodule.hxx>
38 #include <pagefrm.hxx>
39 #include <colfrm.hxx>
40 #include <fesh.hxx>
41 #include <viewimp.hxx>
42 #include <viewopt.hxx>
43 #include <dflyobj.hxx>
44 #include <dcontact.hxx>
45 #include <frmatr.hxx>
46 #include <frmtool.hxx>
47 #include <tabfrm.hxx>
48 #include <rowfrm.hxx>
49 #include <ftnfrm.hxx>
50 #include <txtfrm.hxx>
51 #include <notxtfrm.hxx>
52 #include <flyfrms.hxx>
53 #include <layact.hxx>
54 #include <pagedesc.hxx>
55 #include <section.hxx>
56 #include <sectfrm.hxx>
57 #include <node2lay.hxx>
58 #include <ndole.hxx>
59 #include <hints.hxx>
60 #include "layhelp.hxx"
61 #include <laycache.hxx>
62 #include <rootfrm.hxx>
63 #include <paratr.hxx>
64 #include <redline.hxx>
65 #include <sortedobjs.hxx>
66 #include <objectformatter.hxx>
67 #include <calbck.hxx>
68 #include <ndtxt.hxx>
69 #include <undobj.hxx>
70 #include <DocumentSettingManager.hxx>
71 #include <IDocumentDrawModelAccess.hxx>
72 #include <IDocumentTimerAccess.hxx>
73 #include <IDocumentRedlineAccess.hxx>
74 #include <IDocumentFieldsAccess.hxx>
75 #include <IDocumentState.hxx>
76 #include <boost/circular_buffer.hpp>
77 #include <svx/sdr/attribute/sdrallfillattributeshelper.hxx>
79 using namespace ::com::sun::star;
81 bool bObjsDirect = true;
82 bool bDontCreateObjects = false;
83 bool bSetCompletePaintOnInvalidate = false;
85 sal_uInt8 StackHack::nCnt = 0;
86 bool StackHack::bLocked = false;
88 SwFrameNotify::SwFrameNotify( SwFrame *pF ) :
89 mpFrame( pF ),
90 maFrame( pF->getFrameArea() ),
91 maPrt( pF->getFramePrintArea() ),
92 mbInvaKeep( false ),
93 mbValidSize( pF->isFrameAreaSizeValid() )
95 if ( pF->IsTextFrame() )
97 mnFlyAnchorOfst = static_cast<SwTextFrame*>(pF)->GetBaseOfstForFly( true );
98 mnFlyAnchorOfstNoWrap = static_cast<SwTextFrame*>(pF)->GetBaseOfstForFly( false );
100 else
102 mnFlyAnchorOfst = 0;
103 mnFlyAnchorOfstNoWrap = 0;
106 mbHadFollow = pF->IsContentFrame() && static_cast<SwContentFrame*>(pF)->GetFollow();
109 SwFrameNotify::~SwFrameNotify() COVERITY_NOEXCEPT_FALSE
111 SwRectFnSet aRectFnSet(mpFrame);
112 const bool bAbsP = aRectFnSet.PosDiff(maFrame, mpFrame->getFrameArea());
113 const bool bChgWidth =
114 aRectFnSet.GetWidth(maFrame) != aRectFnSet.GetWidth(mpFrame->getFrameArea());
115 const bool bChgHeight =
116 aRectFnSet.GetHeight(maFrame)!=aRectFnSet.GetHeight(mpFrame->getFrameArea());
117 const bool bChgFlyBasePos = mpFrame->IsTextFrame() &&
118 ( ( mnFlyAnchorOfst != static_cast<SwTextFrame*>(mpFrame)->GetBaseOfstForFly( true ) ) ||
119 ( mnFlyAnchorOfstNoWrap != static_cast<SwTextFrame*>(mpFrame)->GetBaseOfstForFly( false ) ) );
121 if ( mpFrame->IsFlowFrame() && !mpFrame->IsInFootnote() )
123 SwFlowFrame *pFlow = SwFlowFrame::CastFlowFrame( mpFrame );
125 if ( !pFlow->IsFollow() )
127 if ( !mpFrame->GetIndPrev() )
129 if ( mbInvaKeep )
131 SwFrame *pPre = mpFrame->FindPrev();
132 if ( pPre && pPre->IsFlowFrame() )
134 // 1. pPre wants to keep with me:
135 bool bInvalidPrePos = SwFlowFrame::CastFlowFrame(pPre)->IsKeep(pPre->GetAttrSet()->GetKeep(), pPre->GetBreakItem())
136 && pPre->GetIndPrev();
138 // 2. pPre is a table and the last row wants to keep with me:
139 if ( !bInvalidPrePos && pPre->IsTabFrame() )
141 SwTabFrame* pPreTab = static_cast<SwTabFrame*>(pPre);
142 if ( pPreTab->GetFormat()->GetDoc()->GetDocumentSettingManager().get(DocumentSettingId::TABLE_ROW_KEEP) )
144 SwRowFrame* pLastRow = static_cast<SwRowFrame*>(pPreTab->GetLastLower());
145 if ( pLastRow && pLastRow->ShouldRowKeepWithNext() )
146 bInvalidPrePos = true;
150 if ( bInvalidPrePos )
151 pPre->InvalidatePos();
155 else if ( !pFlow->HasFollow() )
157 long nOldHeight = aRectFnSet.GetHeight(maFrame);
158 long nNewHeight = aRectFnSet.GetHeight(mpFrame->getFrameArea());
159 if( (nOldHeight > nNewHeight) || (!nOldHeight && nNewHeight) )
160 pFlow->CheckKeep();
165 if ( bAbsP )
167 mpFrame->SetCompletePaint();
169 SwFrame* pNxt = mpFrame->GetIndNext();
170 // #121888# - skip empty section frames
171 while ( pNxt &&
172 pNxt->IsSctFrame() && !static_cast<SwSectionFrame*>(pNxt)->GetSection() )
174 pNxt = pNxt->GetIndNext();
177 if ( pNxt )
178 pNxt->InvalidatePos();
179 else
181 // #104100# - correct condition for setting retouche
182 // flag for vertical layout.
183 if( mpFrame->IsRetoucheFrame() &&
184 aRectFnSet.TopDist( maFrame, aRectFnSet.GetTop(mpFrame->getFrameArea()) ) > 0 )
186 mpFrame->SetRetouche();
189 // A fresh follow frame does not have to be invalidated, because
190 // it is already formatted:
191 if ( mbHadFollow || !mpFrame->IsContentFrame() || !static_cast<SwContentFrame*>(mpFrame)->GetFollow() )
193 if ( !mpFrame->IsTabFrame() || !static_cast<SwTabFrame*>(mpFrame)->GetFollow() )
194 mpFrame->InvalidateNextPos();
199 //For each resize of the background graphics is a repaint necessary.
200 const bool bPrtWidth =
201 aRectFnSet.GetWidth(maPrt) != aRectFnSet.GetWidth(mpFrame->getFramePrintArea());
202 const bool bPrtHeight =
203 aRectFnSet.GetHeight(maPrt)!=aRectFnSet.GetHeight(mpFrame->getFramePrintArea());
204 if ( bPrtWidth || bPrtHeight )
206 bool bUseNewFillProperties(false);
207 if (mpFrame->supportsFullDrawingLayerFillAttributeSet())
209 drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes(mpFrame->getSdrAllFillAttributesHelper());
210 if(aFillAttributes.get() && aFillAttributes->isUsed())
212 bUseNewFillProperties = true;
213 // use SetCompletePaint if needed
214 if(aFillAttributes->needCompleteRepaint())
216 mpFrame->SetCompletePaint();
220 if (!bUseNewFillProperties)
222 const SvxGraphicPosition ePos = mpFrame->GetAttrSet()->GetBackground().GetGraphicPos();
223 if(GPOS_NONE != ePos && GPOS_TILED != ePos)
224 mpFrame->SetCompletePaint();
227 else
229 // #97597# - consider case that *only* margins between
230 // frame and printing area has changed. Then, frame has to be repainted,
231 // in order to force paint of the margin areas.
232 if ( !bAbsP && (bChgWidth || bChgHeight) )
234 mpFrame->SetCompletePaint();
238 const bool bPrtP = aRectFnSet.PosDiff( maPrt, mpFrame->getFramePrintArea() );
239 if ( bAbsP || bPrtP || bChgWidth || bChgHeight ||
240 bPrtWidth || bPrtHeight || bChgFlyBasePos )
242 if( mpFrame->IsAccessibleFrame() )
244 SwRootFrame *pRootFrame = mpFrame->getRootFrame();
245 if( pRootFrame && pRootFrame->IsAnyShellAccessible() &&
246 pRootFrame->GetCurrShell() )
248 pRootFrame->GetCurrShell()->Imp()->MoveAccessibleFrame( mpFrame, maFrame );
252 // Notification of anchored objects
253 if ( mpFrame->GetDrawObjs() )
255 const SwSortedObjs &rObjs = *mpFrame->GetDrawObjs();
256 SwPageFrame* pPageFrame = nullptr;
257 for (SwAnchoredObject* pObj : rObjs)
259 // OD 2004-03-31 #i26791# - no general distinction between
260 // Writer fly frames and drawing objects
261 bool bNotify = false;
262 bool bNotifySize = false;
263 SwContact* pContact = ::GetUserCall( pObj->GetDrawObj() );
264 const bool bAnchoredAsChar = pContact->ObjAnchoredAsChar();
265 if ( !bAnchoredAsChar )
267 // Notify object, which aren't anchored as-character:
269 // always notify objects, if frame position has changed
270 // or if the object is to-page|to-fly anchored.
271 if ( bAbsP ||
272 pContact->ObjAnchoredAtPage() ||
273 pContact->ObjAnchoredAtFly() )
275 bNotify = true;
277 // assure that to-fly anchored Writer fly frames are
278 // registered at the correct page frame, if frame
279 // position has changed.
280 if ( bAbsP && pContact->ObjAnchoredAtFly() &&
281 dynamic_cast<const SwFlyFrame*>( pObj) != nullptr )
283 // determine to-fly anchored Writer fly frame
284 SwFlyFrame* pFlyFrame = static_cast<SwFlyFrame*>(pObj);
285 // determine page frame of to-fly anchored
286 // Writer fly frame
287 SwPageFrame* pFlyPageFrame = pFlyFrame->FindPageFrame();
288 // determine page frame, if needed.
289 if ( !pPageFrame )
291 pPageFrame = mpFrame->FindPageFrame();
293 if ( pPageFrame != pFlyPageFrame )
295 OSL_ENSURE( pFlyPageFrame, "~SwFrameNotify: Fly from Nowhere" );
296 if( pFlyPageFrame )
297 pFlyPageFrame->MoveFly( pFlyFrame, pPageFrame );
298 else
299 pPageFrame->AppendFlyToPage( pFlyFrame );
303 // otherwise the objects are notified in dependence to
304 // its positioning and alignment
305 else
307 const SwFormatVertOrient& rVert =
308 pContact->GetFormat()->GetVertOrient();
309 if ( ( rVert.GetVertOrient() == text::VertOrientation::CENTER ||
310 rVert.GetVertOrient() == text::VertOrientation::BOTTOM ||
311 rVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ) &&
312 ( bChgHeight || bPrtHeight ) )
314 bNotify = true;
316 if ( !bNotify )
318 const SwFormatHoriOrient& rHori =
319 pContact->GetFormat()->GetHoriOrient();
320 if ( ( rHori.GetHoriOrient() != text::HoriOrientation::NONE ||
321 rHori.GetRelationOrient()== text::RelOrientation::PRINT_AREA ||
322 rHori.GetRelationOrient()== text::RelOrientation::FRAME ) &&
323 ( bChgWidth || bPrtWidth || bChgFlyBasePos ) )
325 bNotify = true;
330 else if ( bPrtWidth )
332 // Notify as-character anchored objects, if printing area
333 // width has changed.
334 bNotify = true;
335 bNotifySize = true;
338 // perform notification via the corresponding invalidations
339 if ( bNotify )
341 if ( dynamic_cast<const SwFlyFrame*>( pObj) != nullptr )
343 SwFlyFrame* pFlyFrame = static_cast<SwFlyFrame*>(pObj);
344 if ( bNotifySize )
345 pFlyFrame->InvalidateSize_();
346 // #115759# - no invalidation of
347 // position for as-character anchored objects.
348 if ( !bAnchoredAsChar )
350 pFlyFrame->InvalidatePos_();
352 pFlyFrame->Invalidate_();
354 else if ( dynamic_cast<const SwAnchoredDrawObject*>( pObj) != nullptr )
356 // #115759# - no invalidation of
357 // position for as-character anchored objects.
358 if ( !bAnchoredAsChar )
360 pObj->InvalidateObjPos();
363 else
365 OSL_FAIL( "<SwContentNotify::~SwContentNotify()> - unknown anchored object type." );
371 else if( mpFrame->IsTextFrame() && mbValidSize != mpFrame->isFrameAreaSizeValid() )
373 SwRootFrame *pRootFrame = mpFrame->getRootFrame();
374 if( pRootFrame && pRootFrame->IsAnyShellAccessible() &&
375 pRootFrame->GetCurrShell() )
377 pRootFrame->GetCurrShell()->Imp()->InvalidateAccessibleFrameContent( mpFrame );
381 // #i9046# Automatic frame width
382 SwFlyFrame* pFly = nullptr;
383 // #i35879# Do not trust the inf flags. pFrame does not
384 // necessarily have to have an upper!
385 if ( !mpFrame->IsFlyFrame() && nullptr != ( pFly = mpFrame->ImplFindFlyFrame() ) )
387 // #i61999#
388 // no invalidation of columned Writer fly frames, because automatic
389 // width doesn't make sense for such Writer fly frames.
390 if ( pFly->Lower() && !pFly->Lower()->IsColumnFrame() )
392 const SwFormatFrameSize &rFrameSz = pFly->GetFormat()->GetFrameSize();
394 // This could be optimized. Basically the fly frame only has to
395 // be invalidated, if the first line of pFrame (if pFrame is a content
396 // frame, for other frame types it's the print area) has changed its
397 // size and pFrame was responsible for the current width of pFly. On
398 // the other hand, this is only rarely used and re-calculation of
399 // the fly frame does not cause too much trouble. So we keep it this
400 // way:
401 if ( ATT_FIX_SIZE != rFrameSz.GetWidthSizeType() )
403 // #i50668#, #i50998# - invalidation of position
404 // of as-character anchored fly frames not needed and can cause
405 // layout loops
406 if ( dynamic_cast<const SwFlyInContentFrame*>( pFly) == nullptr )
408 pFly->InvalidatePos();
410 pFly->InvalidateSize();
416 SwLayNotify::SwLayNotify( SwLayoutFrame *pLayFrame ) :
417 SwFrameNotify( pLayFrame ),
418 m_bLowersComplete( false )
422 // OD 2004-05-11 #i28701# - local method to invalidate the position of all
423 // frames inclusive its floating screen objects, which are lowers of the given
424 // layout frame
425 static void lcl_InvalidatePosOfLowers( SwLayoutFrame& _rLayoutFrame )
427 if( _rLayoutFrame.IsFlyFrame() && _rLayoutFrame.GetDrawObjs() )
429 _rLayoutFrame.InvalidateObjs( false );
432 SwFrame* pLowerFrame = _rLayoutFrame.Lower();
433 while ( pLowerFrame )
435 pLowerFrame->InvalidatePos();
436 if ( pLowerFrame->IsTextFrame() )
438 static_cast<SwTextFrame*>(pLowerFrame)->Prepare( PREP_POS_CHGD );
440 else if ( pLowerFrame->IsTabFrame() )
442 pLowerFrame->InvalidatePrt();
445 pLowerFrame->InvalidateObjs( false );
447 pLowerFrame = pLowerFrame->GetNext();
451 SwLayNotify::~SwLayNotify()
453 SwLayoutFrame *pLay = static_cast<SwLayoutFrame*>(mpFrame);
454 SwRectFnSet aRectFnSet(pLay);
455 bool bNotify = false;
456 if ( pLay->getFramePrintArea().SSize() != maPrt.SSize() )
458 if ( !IsLowersComplete() )
460 bool bInvaPercent;
462 if ( pLay->IsRowFrame() )
464 bInvaPercent = true;
465 long nNew = aRectFnSet.GetHeight(pLay->getFramePrintArea());
466 if( nNew != aRectFnSet.GetHeight(maPrt) )
467 static_cast<SwRowFrame*>(pLay)->AdjustCells( nNew, true);
468 if( aRectFnSet.GetWidth(pLay->getFramePrintArea())
469 != aRectFnSet.GetWidth(maPrt) )
470 static_cast<SwRowFrame*>(pLay)->AdjustCells( 0, false );
472 else
474 //Proportional adoption of the internal.
475 //1. If the formatted is no Fly
476 //2. If he contains no columns
477 //3. If the Fly has a fixed height and the columns
478 // are next to be.
479 // Hoehe danebenliegen.
480 //4. Never at SectionFrames.
481 bool bLow;
482 if( pLay->IsFlyFrame() )
484 if ( pLay->Lower() )
486 bLow = !pLay->Lower()->IsColumnFrame() ||
487 aRectFnSet.GetHeight(pLay->Lower()->getFrameArea())
488 != aRectFnSet.GetHeight(pLay->getFramePrintArea());
490 else
491 bLow = false;
493 else if( pLay->IsSctFrame() )
495 if ( pLay->Lower() )
497 if( pLay->Lower()->IsColumnFrame() && pLay->Lower()->GetNext() )
498 bLow = pLay->Lower()->getFrameArea().Height() != pLay->getFramePrintArea().Height();
499 else
500 bLow = pLay->getFramePrintArea().Width() != maPrt.Width();
502 else
503 bLow = false;
505 else if( pLay->IsFooterFrame() && !pLay->HasFixSize() )
506 bLow = pLay->getFramePrintArea().Width() != maPrt.Width();
507 else
508 bLow = true;
509 bInvaPercent = bLow;
510 if ( bLow )
512 pLay->ChgLowersProp( maPrt.SSize() );
514 // If the PrtArea has been extended, it might be possible that the chain of parts
515 // can take another frame. As a result, the "possible right one" needs to be
516 // invalidated. This only pays off if this or its Uppers are moveable sections.
517 // A PrtArea has been extended if width or height are larger than before.
518 if ( (pLay->getFramePrintArea().Height() > maPrt.Height() ||
519 pLay->getFramePrintArea().Width() > maPrt.Width()) &&
520 (pLay->IsMoveable() || pLay->IsFlyFrame()) )
522 SwFrame *pTmpFrame = pLay->Lower();
523 if ( pTmpFrame && pTmpFrame->IsFlowFrame() )
525 while ( pTmpFrame->GetNext() )
526 pTmpFrame = pTmpFrame->GetNext();
527 pTmpFrame->InvalidateNextPos();
531 bNotify = true;
532 //EXPENSIVE!! But how we do it more elegant?
533 if( bInvaPercent )
534 pLay->InvaPercentLowers( pLay->getFramePrintArea().Height() - maPrt.Height() );
536 if ( pLay->IsTabFrame() )
537 //So that _only_ the shadow is drawn while resizing.
538 static_cast<SwTabFrame*>(pLay)->SetComplete();
539 else
541 const SwViewShell *pSh = pLay->getRootFrame()->GetCurrShell();
542 if( !( pSh && pSh->GetViewOptions()->getBrowseMode() ) ||
543 !(pLay->GetType() & (SwFrameType::Body | SwFrameType::Page)) )
544 //Thereby the subordinates are retouched clean.
545 //Example problem: Take the Flys with the handles and downsize.
546 //Not for body and page, otherwise it flickers when loading HTML.
547 pLay->SetCompletePaint();
550 //Notify Lower if the position has changed.
551 const bool bPrtPos = aRectFnSet.PosDiff( maPrt, pLay->getFramePrintArea() );
552 const bool bPos = bPrtPos || aRectFnSet.PosDiff( maFrame, pLay->getFrameArea() );
553 const bool bSize = pLay->getFrameArea().SSize() != maFrame.SSize();
555 if ( bPos && pLay->Lower() && !IsLowersComplete() )
557 pLay->Lower()->InvalidatePos();
558 SwFootnoteFrame* pFtnFrame = pLay->Lower()->IsFootnoteFrame() ?
559 static_cast<SwFootnoteFrame*>(pLay->Lower()) : nullptr;
560 SwFrame* pFtnLower = pFtnFrame ? pFtnFrame->Lower() : nullptr;
561 if (pFtnLower)
562 pFtnLower->InvalidatePos();
565 if ( bPrtPos )
566 pLay->SetCompletePaint();
568 //Inform the Follower if the SSize has changed.
569 if ( bSize )
571 if( pLay->GetNext() )
573 if ( pLay->GetNext()->IsLayoutFrame() )
574 pLay->GetNext()->InvalidatePos_();
575 else
576 pLay->GetNext()->InvalidatePos();
578 else if( pLay->IsSctFrame() )
579 pLay->InvalidateNextPos();
581 if ( !IsLowersComplete() &&
582 !(pLay->GetType()&(SwFrameType::Fly|SwFrameType::Section) &&
583 pLay->Lower() && pLay->Lower()->IsColumnFrame()) &&
584 (bPos || bNotify) &&
585 !(pLay->GetType() & (SwFrameType::Row|SwFrameType::Tab|SwFrameType::FtnCont|SwFrameType::Page|SwFrameType::Root)))
587 // #i44016# - force unlock of position of lower objects.
588 // #i43913# - no unlock of position of objects,
589 // if <pLay> is a cell frame, and its table frame resp. its parent table
590 // frame is locked.
591 // #i47458# - force unlock of position of lower objects,
592 // only if position of layout frame has changed.
593 bool bUnlockPosOfObjs( bPos );
594 if ( bUnlockPosOfObjs && pLay->IsCellFrame() )
596 SwTabFrame* pTabFrame( pLay->FindTabFrame() );
597 if ( pTabFrame &&
598 ( pTabFrame->IsJoinLocked() ||
599 ( pTabFrame->IsFollow() &&
600 pTabFrame->FindMaster()->IsJoinLocked() ) ) )
602 bUnlockPosOfObjs = false;
605 // #i49383# - check for footnote frame, if unlock
606 // of position of lower objects is allowed.
607 else if ( bUnlockPosOfObjs && pLay->IsFootnoteFrame() )
609 bUnlockPosOfObjs = static_cast<SwFootnoteFrame*>(pLay)->IsUnlockPosOfLowerObjs();
611 // #i51303# - no unlock of object positions for sections
612 else if ( bUnlockPosOfObjs && pLay->IsSctFrame() )
614 bUnlockPosOfObjs = false;
616 pLay->NotifyLowerObjs( bUnlockPosOfObjs );
618 if ( bPos && pLay->IsFootnoteFrame() && pLay->Lower() )
620 // OD 2004-05-11 #i28701#
621 ::lcl_InvalidatePosOfLowers( *pLay );
623 if( ( bPos || bSize ) && pLay->IsFlyFrame() && static_cast<SwFlyFrame*>(pLay)->GetAnchorFrame()
624 && static_cast<SwFlyFrame*>(pLay)->GetAnchorFrame()->IsFlyFrame() )
625 static_cast<SwFlyFrame*>(pLay)->AnchorFrame()->InvalidateSize();
628 SwFlyNotify::SwFlyNotify( SwFlyFrame *pFlyFrame ) :
629 SwLayNotify( pFlyFrame ),
630 // #115759# - keep correct page frame - the page frame
631 // the Writer fly frame is currently registered at.
632 pOldPage( pFlyFrame->GetPageFrame() ),
633 aFrameAndSpace( pFlyFrame->GetObjRectWithSpaces() )
637 SwFlyNotify::~SwFlyNotify()
639 SwFlyFrame *pFly = static_cast<SwFlyFrame*>(mpFrame);
640 if ( pFly->IsNotifyBack() )
642 SwViewShell *pSh = pFly->getRootFrame()->GetCurrShell();
643 SwViewShellImp *pImp = pSh ? pSh->Imp() : nullptr;
644 if ( !pImp || !pImp->IsAction() || !pImp->GetLayAction().IsAgain() )
646 //If in the LayAction the IsAgain is set it can be
647 //that the old page is destroyed in the meantime!
648 ::Notify( pFly, pOldPage, aFrameAndSpace, &maPrt );
649 // #i35640# - additional notify anchor text frame,
650 // if Writer fly frame has changed its page
651 if ( pFly->GetAnchorFrame()->IsTextFrame() &&
652 pFly->GetPageFrame() != pOldPage )
654 pFly->AnchorFrame()->Prepare( PREP_FLY_LEAVE );
657 pFly->ResetNotifyBack();
660 //Have the size or the position changed,
661 //so should the view know this.
662 SwRectFnSet aRectFnSet(pFly);
663 const bool bPosChgd = aRectFnSet.PosDiff( maFrame, pFly->getFrameArea() );
664 const bool bFrameChgd = pFly->getFrameArea().SSize() != maFrame.SSize();
665 const bool bPrtChgd = maPrt != pFly->getFramePrintArea();
666 if ( bPosChgd || bFrameChgd || bPrtChgd )
668 pFly->NotifyDrawObj();
670 if ( bPosChgd && maFrame.Pos().X() != FAR_AWAY )
672 // OD 2004-05-10 #i28701# - no direct move of lower Writer fly frames.
673 // reason: New positioning and alignment (e.g. to-paragraph anchored,
674 // but aligned at page) are introduced.
675 // <SwLayNotify::~SwLayNotify()> takes care of invalidation of lower
676 // floating screen objects by calling method <SwLayoutFrame::NotifyLowerObjs()>.
678 if ( pFly->IsFlyAtContentFrame() )
680 SwFrame *pNxt = pFly->AnchorFrame()->FindNext();
681 if ( pNxt )
683 pNxt->InvalidatePos();
687 // #i26945# - notify anchor.
688 // Needed for negative positioned Writer fly frames
689 if ( pFly->GetAnchorFrame()->IsTextFrame() )
691 pFly->AnchorFrame()->Prepare( PREP_FLY_LEAVE );
695 // OD 2004-05-13 #i28701#
696 // #i45180# - no adjustment of layout process flags and
697 // further notifications/invalidations, if format is called by grow/shrink
698 if ( pFly->ConsiderObjWrapInfluenceOnObjPos() &&
699 ( dynamic_cast<const SwFlyFreeFrame*>( pFly) == nullptr ||
700 !static_cast<SwFlyFreeFrame*>(pFly)->IsNoMoveOnCheckClip() ) )
702 // #i54138# - suppress restart of the layout process
703 // on changed frame height.
704 // Note: It doesn't seem to be necessary and can cause layout loops.
705 if ( bPosChgd )
707 // indicate a restart of the layout process
708 pFly->SetRestartLayoutProcess( true );
710 else
712 // lock position
713 pFly->LockPosition();
715 if ( !pFly->ConsiderForTextWrap() )
717 // indicate that object has to be considered for text wrap
718 pFly->SetConsiderForTextWrap( true );
719 // invalidate 'background' in order to allow its 'background'
720 // to wrap around it.
721 pFly->NotifyBackground( pFly->GetPageFrame(),
722 pFly->GetObjRectWithSpaces(),
723 PREP_FLY_ARRIVE );
724 // invalidate position of anchor frame in order to force
725 // a re-format of the anchor frame, which also causes a
726 // re-format of the invalid previous frames of the anchor frame.
727 pFly->AnchorFrame()->InvalidatePos();
733 SwContentNotify::SwContentNotify( SwContentFrame *pContentFrame ) :
734 SwFrameNotify( pContentFrame ),
735 // OD 08.01.2004 #i11859#
736 mbChkHeightOfLastLine( false ),
737 mnHeightOfLastLine( 0 ),
738 // OD 2004-02-26 #i25029#
739 mbInvalidatePrevPrtArea( false ),
740 mbBordersJoinedWithPrev( false )
742 // OD 08.01.2004 #i11859#
743 if ( pContentFrame->IsTextFrame() )
745 SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pContentFrame);
746 if (!pTextFrame->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::OLD_LINE_SPACING))
748 const SvxLineSpacingItem &rSpace = pTextFrame->GetAttrSet()->GetLineSpacing();
749 if ( rSpace.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Prop )
751 mbChkHeightOfLastLine = true;
752 mnHeightOfLastLine = pTextFrame->GetHeightOfLastLine();
758 SwContentNotify::~SwContentNotify()
760 SwContentFrame *pCnt = static_cast<SwContentFrame*>(mpFrame);
761 if ( bSetCompletePaintOnInvalidate )
762 pCnt->SetCompletePaint();
764 SwRectFnSet aRectFnSet(pCnt);
765 if ( pCnt->IsInTab() && ( aRectFnSet.PosDiff( pCnt->getFrameArea(), maFrame ) ||
766 pCnt->getFrameArea().SSize() != maFrame.SSize()))
768 SwLayoutFrame* pCell = pCnt->GetUpper();
769 while( !pCell->IsCellFrame() && pCell->GetUpper() )
770 pCell = pCell->GetUpper();
771 OSL_ENSURE( pCell->IsCellFrame(), "Where's my cell?" );
772 if ( text::VertOrientation::NONE != pCell->GetFormat()->GetVertOrient().GetVertOrient() )
773 pCell->InvalidatePrt(); //for the vertical align.
776 // OD 2004-02-26 #i25029#
777 if ( mbInvalidatePrevPrtArea && mbBordersJoinedWithPrev &&
778 pCnt->IsTextFrame() &&
779 !pCnt->IsFollow() && !pCnt->GetIndPrev() )
781 // determine previous frame
782 SwFrame* pPrevFrame = pCnt->FindPrev();
783 // skip empty section frames and hidden text frames
785 while ( pPrevFrame &&
786 ( ( pPrevFrame->IsSctFrame() &&
787 !static_cast<SwSectionFrame*>(pPrevFrame)->GetSection() ) ||
788 ( pPrevFrame->IsTextFrame() &&
789 static_cast<SwTextFrame*>(pPrevFrame)->IsHiddenNow() ) ) )
791 pPrevFrame = pPrevFrame->FindPrev();
795 // Invalidate printing area of found previous frame
796 if ( pPrevFrame )
798 if ( pPrevFrame->IsSctFrame() )
800 if ( pCnt->IsInSct() )
802 // Note: found previous frame is a section frame and
803 // <pCnt> is also inside a section.
804 // Thus due to <mbBordersJoinedWithPrev>,
805 // <pCnt> had joined its borders/shadow with the
806 // last content of the found section.
807 // Invalidate printing area of last content in found section.
808 SwFrame* pLstContentOfSctFrame =
809 static_cast<SwSectionFrame*>(pPrevFrame)->FindLastContent();
810 if ( pLstContentOfSctFrame )
812 pLstContentOfSctFrame->InvalidatePrt();
816 else
818 pPrevFrame->InvalidatePrt();
823 const bool bFirst = aRectFnSet.GetWidth(maFrame) == 0;
825 if ( pCnt->IsNoTextFrame() )
827 //Active PlugIn's or OLE-Objects should know something of the change
828 //thereby they move their window appropriate.
829 SwViewShell *pSh = pCnt->getRootFrame()->GetCurrShell();
830 if ( pSh )
832 SwOLENode *const pNd(static_cast<SwNoTextFrame*>(pCnt)->GetNode()->GetOLENode());
833 if (nullptr != pNd &&
834 (pNd->GetOLEObj().IsOleRef() ||
835 pNd->IsOLESizeInvalid()) )
837 const bool bNoTextFramePrtAreaChanged =
838 ( maPrt.SSize().Width() != 0 &&
839 maPrt.SSize().Height() != 0 ) &&
840 maPrt.SSize() != pCnt->getFramePrintArea().SSize();
841 OSL_ENSURE( pCnt->IsInFly(), "OLE not in FlyFrame" );
842 SwFlyFrame *pFly = pCnt->FindFlyFrame();
843 svt::EmbeddedObjectRef& xObj = pNd->GetOLEObj().GetObject();
844 SwFEShell *pFESh = nullptr;
845 for(SwViewShell& rCurrentShell : pSh->GetRingContainer())
846 { if ( dynamic_cast<const SwCursorShell*>( &rCurrentShell) != nullptr )
848 pFESh = static_cast<SwFEShell*>(&rCurrentShell);
849 // #108369#: Here used to be the condition if (!bFirst).
850 // I think this should mean "do not call CalcAndSetScale"
851 // if the frame is formatted for the first time.
852 // Unfortunately this is not valid anymore since the
853 // SwNoTextFrame already gets a width during CalcLowerPreps.
854 // Nevertheless, the indention of !bFirst seemed to be
855 // to assure that the OLE objects have already been notified
856 // if necessary before calling CalcAndSetScale.
857 // So I replaced !bFirst by !IsOLESizeInvalid. There is
858 // one additional problem specific to the word import:
859 // The layout is calculated _before_ calling PrtOLENotify,
860 // and the OLE objects are not invalidated during import.
861 // Therefore I added the condition !IsUpdateExpField,
862 // have a look at the occurrence of CalcLayout in
863 // uiview/view.cxx.
864 if ( !pNd->IsOLESizeInvalid() &&
865 !pSh->GetDoc()->getIDocumentState().IsUpdateExpField() )
866 pFESh->CalcAndSetScale( xObj,
867 &pFly->getFramePrintArea(), &pFly->getFrameArea(),
868 bNoTextFramePrtAreaChanged );
872 if ( pFESh && pNd->IsOLESizeInvalid() )
874 pNd->SetOLESizeInvalid( false );
875 pFESh->CalcAndSetScale( xObj ); // create client
878 //dito animated graphics
879 if ( getFrameArea().HasArea() && static_cast<SwNoTextFrame*>(pCnt)->HasAnimation() )
881 static_cast<SwNoTextFrame*>(pCnt)->StopAnimation();
882 pSh->InvalidateWindows( getFrameArea() );
887 if ( bFirst )
889 pCnt->SetRetouche(); //fix(13870)
891 SwDoc *const pDoc = pCnt->IsTextFrame()
892 ? &static_cast<SwTextFrame*>(pCnt)->GetDoc()
893 : static_cast<SwNoTextFrame*>(pCnt)->GetNode()->GetDoc();
894 if ( !pDoc->GetSpzFrameFormats()->empty() &&
895 pDoc->DoesContainAtPageObjWithContentAnchor() && !pDoc->getIDocumentState().IsNewDoc() )
897 // If certain import filters for foreign file format import
898 // AT_PAGE anchored objects, the corresponding page number is
899 // typically not known. In this case the content position is
900 // stored at which the anchored object is found in the
901 // imported document.
902 // When this content is formatted it is the time at which
903 // the page is known. Thus, this data can be corrected now.
905 const SwPageFrame *pPage = nullptr;
906 SwFrameFormats *pTable = pDoc->GetSpzFrameFormats();
908 for ( size_t i = 0; i < pTable->size(); ++i )
910 SwFrameFormat *pFormat = (*pTable)[i];
911 const SwFormatAnchor &rAnch = pFormat->GetAnchor();
912 if ( RndStdIds::FLY_AT_PAGE != rAnch.GetAnchorId() ||
913 rAnch.GetContentAnchor() == nullptr )
915 continue;
918 if (FrameContainsNode(*pCnt, rAnch.GetContentAnchor()->nNode.GetIndex()))
920 OSL_FAIL( "<SwContentNotify::~SwContentNotify()> - to page anchored object with content position." );
921 if ( !pPage )
923 pPage = pCnt->FindPageFrame();
925 SwFormatAnchor aAnch( rAnch );
926 aAnch.SetAnchor( nullptr );
927 aAnch.SetPageNum( pPage->GetPhyPageNum() );
928 pFormat->SetFormatAttr( aAnch );
929 if ( RES_DRAWFRMFMT != pFormat->Which() )
931 pFormat->MakeFrames();
938 // OD 12.01.2004 #i11859# - invalidate printing area of following frame,
939 // if height of last line has changed.
940 if ( pCnt->IsTextFrame() && mbChkHeightOfLastLine )
942 if ( mnHeightOfLastLine != static_cast<SwTextFrame*>(pCnt)->GetHeightOfLastLine() )
944 pCnt->InvalidateNextPrtArea();
948 // #i44049#
949 if ( pCnt->IsTextFrame() && aRectFnSet.PosDiff( maFrame, pCnt->getFrameArea() ) )
951 pCnt->InvalidateObjs();
954 // #i43255# - move code to invalidate at-character
955 // anchored objects due to a change of its anchor character from
956 // method <SwTextFrame::Format(..)>.
957 if ( pCnt->IsTextFrame() )
959 SwTextFrame* pMasterFrame = pCnt->IsFollow()
960 ? static_cast<SwTextFrame*>(pCnt)->FindMaster()
961 : static_cast<SwTextFrame*>(pCnt);
962 if ( pMasterFrame && !pMasterFrame->IsFlyLock() &&
963 pMasterFrame->GetDrawObjs() )
965 SwSortedObjs* pObjs = pMasterFrame->GetDrawObjs();
966 for (SwAnchoredObject* pAnchoredObj : *pObjs)
968 if ( pAnchoredObj->GetFrameFormat().GetAnchor().GetAnchorId()
969 == RndStdIds::FLY_AT_CHAR )
971 pAnchoredObj->CheckCharRectAndTopOfLine( !pMasterFrame->IsEmpty() );
978 // note this *cannot* be static because it's a friend
979 void AppendObj(SwFrame *const pFrame, SwPageFrame *const pPage, SwFrameFormat *const pFormat, const SwFormatAnchor & rAnch)
981 const bool bFlyAtFly = rAnch.GetAnchorId() == RndStdIds::FLY_AT_FLY; // LAYER_IMPL
982 //Is a frame or a SdrObject described?
983 const bool bSdrObj = RES_DRAWFRMFMT == pFormat->Which();
984 // OD 23.06.2003 #108784# - append also drawing objects anchored
985 // as character.
986 const bool bDrawObjInContent = bSdrObj &&
987 (rAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR);
989 if( bFlyAtFly ||
990 (rAnch.GetAnchorId() == RndStdIds::FLY_AT_PARA) ||
991 (rAnch.GetAnchorId() == RndStdIds::FLY_AT_CHAR) ||
992 bDrawObjInContent )
994 SdrObject* pSdrObj = nullptr;
995 if ( bSdrObj && nullptr == (pSdrObj = pFormat->FindSdrObject()) )
997 OSL_ENSURE( !bSdrObj, "DrawObject not found." );
998 pFormat->GetDoc()->DelFrameFormat( pFormat );
999 return;
1001 if ( pSdrObj )
1003 if ( !pSdrObj->getSdrPageFromSdrObject() )
1005 pFormat->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)->
1006 InsertObject(pSdrObj, pSdrObj->GetOrdNumDirect());
1009 SwDrawContact* pNew =
1010 static_cast<SwDrawContact*>(GetUserCall( pSdrObj ));
1011 if ( !pNew->GetAnchorFrame() )
1013 pFrame->AppendDrawObj( *(pNew->GetAnchoredObj( nullptr )) );
1015 // OD 19.06.2003 #108784# - add 'virtual' drawing object,
1016 // if necessary. But control objects have to be excluded.
1017 else if ( !::CheckControlLayer( pSdrObj ) &&
1018 pNew->GetAnchorFrame() != pFrame &&
1019 !pNew->GetDrawObjectByAnchorFrame( *pFrame ) )
1021 SwDrawVirtObj* pDrawVirtObj = pNew->AddVirtObj();
1022 pFrame->AppendDrawObj( *(pNew->GetAnchoredObj( pDrawVirtObj )) );
1024 pDrawVirtObj->ActionChanged();
1027 else
1029 SwFlyFrame *pFly;
1030 if( bFlyAtFly )
1031 pFly = new SwFlyLayFrame( static_cast<SwFlyFrameFormat*>(pFormat), pFrame, pFrame );
1032 else
1033 pFly = new SwFlyAtContentFrame( static_cast<SwFlyFrameFormat*>(pFormat), pFrame, pFrame );
1034 pFly->Lock();
1035 pFrame->AppendFly( pFly );
1036 pFly->Unlock();
1037 if ( pPage )
1038 ::RegistFlys( pPage, pFly );
1043 static bool IsShown(sal_uLong const nIndex,
1044 const SwFormatAnchor & rAnch,
1045 std::vector<sw::Extent>::const_iterator const*const pIter,
1046 std::vector<sw::Extent>::const_iterator const*const pEnd,
1047 SwTextNode const*const pFirstNode, SwTextNode const*const pLastNode)
1049 assert(!pIter || *pIter == *pEnd || (*pIter)->pNode->GetIndex() == nIndex);
1050 SwPosition const& rAnchor(*rAnch.GetContentAnchor());
1051 if (rAnchor.nNode.GetIndex() != nIndex)
1053 return false;
1055 if (rAnch.GetAnchorId() == RndStdIds::FLY_AT_PARA)
1057 return pIter == nullptr // not merged
1058 || pIter != pEnd // at least one char visible in node
1059 || !IsSelectFrameAnchoredAtPara(rAnchor,
1060 SwPosition(const_cast<SwTextNode&>(*pFirstNode), 0),
1061 SwPosition(const_cast<SwTextNode&>(*pLastNode), pLastNode->Len()));
1063 if (pIter)
1065 // note: frames are not sorted by anchor position.
1066 assert(pEnd);
1067 assert(pFirstNode);
1068 assert(pLastNode);
1069 assert(rAnch.GetAnchorId() != RndStdIds::FLY_AT_FLY);
1070 for (auto iter = *pIter; iter != *pEnd; ++iter)
1072 assert(iter->nStart != iter->nEnd); // TODO possible?
1073 assert(iter->pNode->GetIndex() == nIndex);
1074 if (rAnchor.nContent.GetIndex() < iter->nStart)
1076 return false;
1078 if (rAnch.GetAnchorId() == RndStdIds::FLY_AT_CHAR)
1080 // if there is an extent then obviously the node was not
1081 // deleted fully...
1082 // show if start <= pos <= end
1083 // *or* if first-node/0 *and* not StartOfSection
1084 // *or* if last-node/Len *and* not EndOfSection
1086 // first determine the extent to compare to, then
1087 // construct start/end positions for the deletion *before* the
1088 // extent and compare once.
1089 // the interesting corner cases are on the edge of the extent!
1090 // no need to check for > the last extent because those
1091 // are never visible.
1092 if (rAnchor.nContent.GetIndex() <= iter->nEnd)
1094 if (iter->nStart == 0)
1096 return true;
1098 else
1100 SwPosition const start(
1101 const_cast<SwTextNode&>(
1102 iter == *pIter
1103 ? *pFirstNode // simplification
1104 : *iter->pNode),
1105 iter == *pIter // first extent?
1106 ? iter->pNode == pFirstNode
1107 ? 0 // at start of 1st node
1108 : pFirstNode->Len() // previous node; simplification but should get right result
1109 : (iter-1)->nEnd); // previous extent
1110 SwPosition const end(*iter->pNode, iter->nStart);
1111 return !IsDestroyFrameAnchoredAtChar(rAnchor, start, end);
1114 else if (iter == *pEnd - 1) // special case: after last extent
1116 if (iter->nEnd == iter->pNode->Len())
1118 return true; // special case: end of node
1120 else
1122 SwPosition const start(*iter->pNode, iter->nEnd);
1123 SwPosition const end(
1124 const_cast<SwTextNode&>(*pLastNode), // simplification
1125 iter->pNode == pLastNode
1126 ? iter->pNode->Len()
1127 : 0);
1128 return !IsDestroyFrameAnchoredAtChar(rAnchor, start, end);
1132 else
1134 assert(rAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR);
1135 // for AS_CHAR obviously must be <
1136 if (rAnchor.nContent.GetIndex() < iter->nEnd)
1138 return true;
1142 return false;
1144 else
1146 return true;
1150 void RemoveHiddenObjsOfNode(SwTextNode const& rNode,
1151 std::vector<sw::Extent>::const_iterator const*const pIter,
1152 std::vector<sw::Extent>::const_iterator const*const pEnd,
1153 SwTextNode const*const pFirstNode, SwTextNode const*const pLastNode)
1155 std::vector<SwFrameFormat*> const*const pFlys(rNode.GetAnchoredFlys());
1156 if (!pFlys)
1158 return;
1160 for (SwFrameFormat * pFrameFormat : *pFlys)
1162 SwFormatAnchor const& rAnchor = pFrameFormat->GetAnchor();
1163 if (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR
1164 || (rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR
1165 && RES_DRAWFRMFMT == pFrameFormat->Which()))
1167 assert(rAnchor.GetContentAnchor()->nNode.GetIndex() == rNode.GetIndex());
1168 if (!IsShown(rNode.GetIndex(), rAnchor, pIter, pEnd, pFirstNode, pLastNode))
1170 pFrameFormat->DelFrames();
1176 void AppendObjsOfNode(SwFrameFormats const*const pTable, sal_uLong const nIndex,
1177 SwFrame *const pFrame, SwPageFrame *const pPage, SwDoc *const pDoc,
1178 std::vector<sw::Extent>::const_iterator const*const pIter,
1179 std::vector<sw::Extent>::const_iterator const*const pEnd,
1180 SwTextNode const*const pFirstNode, SwTextNode const*const pLastNode)
1182 #if OSL_DEBUG_LEVEL > 0
1183 std::vector<SwFrameFormat*> checkFormats;
1184 for ( size_t i = 0; i < pTable->size(); ++i )
1186 SwFrameFormat *pFormat = (*pTable)[i];
1187 const SwFormatAnchor &rAnch = pFormat->GetAnchor();
1188 if ( rAnch.GetContentAnchor() &&
1189 IsShown(nIndex, rAnch, pIter, pEnd, pFirstNode, pLastNode))
1191 checkFormats.push_back( pFormat );
1194 #else
1195 (void)pTable;
1196 #endif
1198 SwNode const& rNode(*pDoc->GetNodes()[nIndex]);
1199 std::vector<SwFrameFormat*> const*const pFlys(rNode.GetAnchoredFlys());
1200 for (size_t it = 0; pFlys && it != pFlys->size(); )
1202 SwFrameFormat *const pFormat = (*pFlys)[it];
1203 const SwFormatAnchor &rAnch = pFormat->GetAnchor();
1204 if ( rAnch.GetContentAnchor() &&
1205 IsShown(nIndex, rAnch, pIter, pEnd, pFirstNode, pLastNode))
1207 #if OSL_DEBUG_LEVEL > 0
1208 std::vector<SwFrameFormat*>::iterator checkPos = std::find( checkFormats.begin(), checkFormats.end(), pFormat );
1209 assert( checkPos != checkFormats.end());
1210 checkFormats.erase( checkPos );
1211 #endif
1212 AppendObj(pFrame, pPage, pFormat, rAnch);
1214 ++it;
1217 #if OSL_DEBUG_LEVEL > 0
1218 assert( checkFormats.empty());
1219 #endif
1223 void AppendObjs(const SwFrameFormats *const pTable, sal_uLong const nIndex,
1224 SwFrame *const pFrame, SwPageFrame *const pPage, SwDoc *const pDoc)
1226 if (pFrame->IsTextFrame())
1228 SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>(pFrame));
1229 if (sw::MergedPara const*const pMerged = pTextFrame->GetMergedPara())
1231 std::vector<sw::Extent>::const_iterator iterFirst(pMerged->extents.begin());
1232 std::vector<sw::Extent>::const_iterator iter(iterFirst);
1233 SwTextNode const* pNode(pMerged->pFirstNode);
1234 for ( ; ; ++iter)
1236 if (iter == pMerged->extents.end()
1237 || iter->pNode != pNode)
1239 AppendObjsOfNode(pTable, pNode->GetIndex(), pFrame, pPage, pDoc,
1240 &iterFirst, &iter, pMerged->pFirstNode, pMerged->pLastNode);
1241 sal_uLong const until = iter == pMerged->extents.end()
1242 ? pMerged->pLastNode->GetIndex() + 1
1243 : iter->pNode->GetIndex();
1244 for (sal_uLong i = pNode->GetIndex() + 1; i < until; ++i)
1246 // let's show at-para flys on nodes that contain start/end of
1247 // redline too, even if there's no text there
1248 SwNode const*const pTmp(pNode->GetNodes()[i]);
1249 if (pTmp->GetRedlineMergeFlag() == SwNode::Merge::NonFirst)
1251 AppendObjsOfNode(pTable, pTmp->GetIndex(), pFrame, pPage, pDoc, &iter, &iter, pMerged->pFirstNode, pMerged->pLastNode);
1254 if (iter == pMerged->extents.end())
1256 break;
1258 pNode = iter->pNode;
1259 iterFirst = iter;
1263 else
1265 return AppendObjsOfNode(pTable, nIndex, pFrame, pPage, pDoc, nullptr, nullptr, nullptr, nullptr);
1268 else
1270 return AppendObjsOfNode(pTable, nIndex, pFrame, pPage, pDoc, nullptr, nullptr, nullptr, nullptr);
1274 bool IsAnchoredObjShown(SwTextFrame const& rFrame, SwFormatAnchor const& rAnchor)
1276 assert(rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA ||
1277 rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR ||
1278 rAnchor.GetAnchorId() == RndStdIds::FLY_AS_CHAR);
1279 bool ret(true);
1280 if (auto const pMergedPara = rFrame.GetMergedPara())
1282 ret = false;
1283 auto const pAnchor(rAnchor.GetContentAnchor());
1284 auto iterFirst(pMergedPara->extents.cbegin());
1285 if (iterFirst == pMergedPara->extents.end()
1286 && (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA
1287 || rAnchor.GetAnchorId() == RndStdIds::FLY_AT_CHAR))
1289 ret = (&pAnchor->nNode.GetNode() == pMergedPara->pFirstNode
1290 && (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA
1291 || pAnchor->nContent == 0))
1292 || (&pAnchor->nNode.GetNode() == pMergedPara->pLastNode
1293 && (rAnchor.GetAnchorId() == RndStdIds::FLY_AT_PARA
1294 || pAnchor->nContent == pMergedPara->pLastNode->Len()));
1296 auto iter(iterFirst);
1297 SwTextNode const* pNode(pMergedPara->pFirstNode);
1298 for ( ; ; ++iter)
1300 if (iter == pMergedPara->extents.end()
1301 || iter->pNode != pNode)
1303 assert(pNode->GetRedlineMergeFlag() != SwNode::Merge::Hidden);
1304 if (pNode == &pAnchor->nNode.GetNode())
1306 ret = IsShown(pNode->GetIndex(), rAnchor, &iterFirst, &iter,
1307 pMergedPara->pFirstNode, pMergedPara->pLastNode);
1308 break;
1310 if (iter == pMergedPara->extents.end())
1312 break;
1314 pNode = iter->pNode;
1315 if (pAnchor->nNode.GetIndex() < pNode->GetIndex())
1317 break;
1319 iterFirst = iter;
1323 return ret;
1326 void AppendAllObjs(const SwFrameFormats* pTable, const SwFrame* pSib)
1328 //Connecting of all Objects, which are described in the SpzTable with the
1329 //layout.
1331 boost::circular_buffer<SwFrameFormat*> vFormatsToConnect(pTable->size());
1332 for(const auto& pFormat : *pTable)
1334 const auto& rAnch = pFormat->GetAnchor();
1335 // Formats can still remain, because we neither use character bound
1336 // frames nor objects which are anchored to character bounds.
1337 if ((rAnch.GetAnchorId() != RndStdIds::FLY_AT_PAGE) && (rAnch.GetAnchorId() != RndStdIds::FLY_AS_CHAR))
1339 auto pContentAnchor = rAnch.GetContentAnchor();
1340 // formats in header/footer have no dependencies
1341 if(pContentAnchor && pFormat->GetDoc()->IsInHeaderFooter(pContentAnchor->nNode))
1342 pFormat->MakeFrames();
1343 else
1344 vFormatsToConnect.push_back(pFormat);
1347 const SwRootFrame* pRoot = pSib ? pSib->getRootFrame() : nullptr;
1348 const SwFrameFormat* pFirstRequeued(nullptr);
1349 while(!vFormatsToConnect.empty())
1351 auto& pFormat = vFormatsToConnect.front();
1352 bool isConnected(false);
1353 pFormat->CallSwClientNotify(sw::GetObjectConnectedHint(isConnected, pRoot));
1354 if(!isConnected)
1356 pFormat->MakeFrames();
1357 pFormat->CallSwClientNotify(sw::GetObjectConnectedHint(isConnected, pRoot));
1359 // do this *before* push_back! the circular_buffer can be "full"!
1360 vFormatsToConnect.pop_front();
1361 if (!isConnected)
1363 if(pFirstRequeued == pFormat)
1364 // If nothing happens anymore we can stop.
1365 break;
1366 if(!pFirstRequeued)
1367 pFirstRequeued = pFormat;
1368 assert(!vFormatsToConnect.full());
1369 vFormatsToConnect.push_back(pFormat);
1371 else
1373 pFirstRequeued = nullptr;
1378 namespace sw {
1380 void RecreateStartTextFrames(SwTextNode & rNode)
1382 std::vector<SwTextFrame*> frames;
1383 SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(rNode);
1384 for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
1386 if (pFrame->getRootFrame()->IsHideRedlines())
1388 frames.push_back(pFrame);
1391 auto eMode(sw::FrameMode::Existing);
1392 for (SwTextFrame * pFrame : frames)
1394 // SplitNode could have moved the original frame to the start node
1395 // & created a new one on end, or could have created new frame on
1396 // start node... grab start node's frame and recreate MergedPara.
1397 SwTextNode & rFirstNode(pFrame->GetMergedPara()
1398 ? *pFrame->GetMergedPara()->pFirstNode
1399 : rNode);
1400 assert(rFirstNode.GetIndex() <= rNode.GetIndex());
1401 // clear old one first to avoid DelFrames confusing updates & asserts...
1402 pFrame->SetMergedPara(nullptr);
1403 pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
1404 *pFrame, rFirstNode, eMode));
1405 eMode = sw::FrameMode::New; // Existing is not idempotent!
1406 // note: this may or may not delete frames on the end node
1410 } // namespace sw
1412 /** local method to set 'working' position for newly inserted frames
1414 OD 12.08.2003 #i17969#
1416 static void lcl_SetPos( SwFrame& _rNewFrame,
1417 const SwLayoutFrame& _rLayFrame )
1419 SwRectFnSet aRectFnSet(&_rLayFrame);
1420 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(_rNewFrame);
1421 aRectFnSet.SetPos( aFrm, aRectFnSet.GetPos(_rLayFrame.getFrameArea()) );
1423 // move position by one SwTwip in text flow direction in order to get
1424 // notifications for a new calculated position after its formatting.
1425 if ( aRectFnSet.IsVert() )
1427 aFrm.Pos().AdjustX( -1 );
1429 else
1431 aFrm.Pos().AdjustY(1 );
1435 void InsertCnt_( SwLayoutFrame *pLay, SwDoc *pDoc,
1436 sal_uLong nIndex, bool bPages, sal_uLong nEndIndex,
1437 SwFrame *pPrv, sw::FrameMode const eMode )
1439 pDoc->getIDocumentTimerAccess().BlockIdling();
1440 SwRootFrame* pLayout = pLay->getRootFrame();
1441 const bool bOldCallbackActionEnabled = pLayout && pLayout->IsCallbackActionEnabled();
1442 if( bOldCallbackActionEnabled )
1443 pLayout->SetCallbackActionEnabled( false );
1445 //In the generation of the Layout bPages=true will be handed over.
1446 //Then will be new pages generated all x paragraphs already times in advance.
1447 //On breaks and/or pagedescriptorchanges the corresponding will be generated
1448 //immediately.
1449 //The advantage is, that on one hand already a nearly realistic number of
1450 //pages are created, but above all there are no almost endless long chain
1451 //of paragraphs, which must be moved expensively until it reaches a tolerable
1452 //reduced level.
1453 //We'd like to think that 20 Paragraphs fit on one page.
1454 //So that it does not become in extreme situations so violent we calculate depending
1455 //on the node something to it.
1456 //If in the DocStatistic a usable given pagenumber
1457 //(Will be cared for while writing), so it will be presumed that this will be
1458 //number of pages.
1459 const bool bStartPercent = bPages && !nEndIndex;
1461 SwPageFrame *pPage = pLay->FindPageFrame();
1462 const SwFrameFormats *pTable = pDoc->GetSpzFrameFormats();
1463 SwFrame *pFrame = nullptr;
1464 std::unique_ptr<SwActualSection> pActualSection;
1465 std::unique_ptr<SwLayHelper> pPageMaker;
1467 //If the layout will be created (bPages == true) we do head on the progress
1468 //Flys and DrawObjects are not connected immediately, this
1469 //happens only at the end of the function.
1470 if ( bPages )
1472 // Attention: the SwLayHelper class uses references to the content-,
1473 // page-, layout-frame etc. and may change them!
1474 pPageMaker.reset(new SwLayHelper( pDoc, pFrame, pPrv, pPage, pLay,
1475 pActualSection, nIndex, 0 == nEndIndex ));
1476 if( bStartPercent )
1478 const sal_uLong nPageCount = pPageMaker->CalcPageCount();
1479 if( nPageCount )
1480 bObjsDirect = false;
1483 else
1484 pPageMaker = nullptr;
1486 if( pLay->IsInSct() &&
1487 ( pLay->IsSctFrame() || pLay->GetUpper() ) ) // Hereby will newbies
1488 // be intercepted, of which flags could not determined yet,
1489 // for e.g. while inserting a table
1491 SwSectionFrame* pSct = pLay->FindSctFrame();
1492 // If content will be inserted in a footnote, which in a column area,
1493 // the column area it is not allowed to be broken up.
1494 // Only if in the inner of the footnote lies an area, is this a candidate
1495 // for pActualSection.
1496 // The same applies for areas in tables, if inside the table will be
1497 // something inserted, it's only allowed to break up areas, which
1498 // lies in the inside also.
1499 if( ( !pLay->IsInFootnote() || pSct->IsInFootnote() ) &&
1500 ( !pLay->IsInTab() || pSct->IsInTab() ) )
1502 pActualSection.reset(new SwActualSection(nullptr, pSct, pSct->GetSection()->GetFormat()->GetSectionNode()));
1503 // tdf#132236 for SwUndoDelete: find outer sections whose start
1504 // nodes aren't contained in the range but whose end nodes are,
1505 // because section frames may need to be created for them
1506 SwActualSection * pUpperSection(pActualSection.get());
1507 while (pUpperSection->GetSectionNode()->EndOfSectionIndex() < nEndIndex)
1509 SwStartNode *const pStart(pUpperSection->GetSectionNode()->StartOfSectionNode());
1510 if (!pStart->IsSectionNode())
1512 break;
1514 // note: these don't have a section frame, check it in EndNode case!
1515 auto const pTmp(new SwActualSection(nullptr, nullptr, static_cast<SwSectionNode*>(pStart)));
1516 pUpperSection->SetUpper(pTmp);
1517 pUpperSection = pTmp;
1519 OSL_ENSURE( !pLay->Lower() || !pLay->Lower()->IsColumnFrame(),
1520 "InsertCnt_: Wrong Call" );
1524 //If a section is "open", the pActualSection points to an SwActualSection.
1525 //If the page breaks, for "open" sections a follow will created.
1526 //For nested sections (which have, however, not a nested layout),
1527 //the SwActualSection class has a member, which points to an upper(section).
1528 //When the "inner" section finishes, the upper will used instead.
1530 // Do not consider the end node. The caller (Section/MakeFrames()) has to
1531 // ensure that the end of this range is positioned before EndIndex!
1532 for ( ; nEndIndex == 0 || nIndex < nEndIndex; ++nIndex)
1534 SwNode *pNd = pDoc->GetNodes()[nIndex];
1535 if ( pNd->IsContentNode() )
1537 SwContentNode* pNode = static_cast<SwContentNode*>(pNd);
1538 if (pLayout->IsHideRedlines() && !pNd->IsCreateFrameWhenHidingRedlines())
1540 if (pNd->IsTextNode()
1541 && pNd->GetRedlineMergeFlag() == SwNode::Merge::NonFirst)
1542 { // must have a frame already
1543 assert(static_cast<SwTextFrame*>(pNode->getLayoutFrame(pLayout))->GetMergedPara());
1545 continue; // skip it
1547 pFrame = pNode->IsTextNode()
1548 ? sw::MakeTextFrame(*pNode->GetTextNode(), pLay, eMode)
1549 : pNode->MakeFrame(pLay);
1550 if( pPageMaker )
1551 pPageMaker->CheckInsert( nIndex );
1553 pFrame->InsertBehind( pLay, pPrv );
1554 // #i27138#
1555 // notify accessibility paragraphs objects about changed
1556 // CONTENT_FLOWS_FROM/_TO relation.
1557 // Relation CONTENT_FLOWS_FROM for next paragraph will change
1558 // and relation CONTENT_FLOWS_TO for previous paragraph will change.
1559 if ( pFrame->IsTextFrame() )
1561 SwViewShell* pViewShell( pFrame->getRootFrame()->GetCurrShell() );
1562 // no notification, if <SwViewShell> is in construction
1563 if ( pViewShell && !pViewShell->IsInConstructor() &&
1564 pViewShell->GetLayout() &&
1565 pViewShell->GetLayout()->IsAnyShellAccessible() &&
1566 pFrame->FindPageFrame() != nullptr)
1568 pViewShell->InvalidateAccessibleParaFlowRelation(
1569 dynamic_cast<SwTextFrame*>(pFrame->FindNextCnt( true )),
1570 dynamic_cast<SwTextFrame*>(pFrame->FindPrevCnt()) );
1571 // #i68958#
1572 // The information flags of the text frame are validated
1573 // in methods <FindNextCnt(..)> and <FindPrevCnt(..)>.
1574 // The information flags have to be invalidated, because
1575 // it is possible, that the one of its upper frames
1576 // isn't inserted into the layout.
1577 pFrame->InvalidateInfFlags();
1580 // OD 12.08.2003 #i17969# - consider horizontal/vertical layout
1581 // for setting position at newly inserted frame
1582 lcl_SetPos( *pFrame, *pLay );
1583 pPrv = pFrame;
1585 if ( !pTable->empty() && bObjsDirect && !bDontCreateObjects )
1586 AppendObjs( pTable, nIndex, pFrame, pPage, pDoc );
1588 else if ( pNd->IsTableNode() )
1589 { //Should we have encountered a table?
1590 SwTableNode *pTableNode = static_cast<SwTableNode*>(pNd);
1591 if (pLayout->IsHideRedlines())
1593 // in the problematic case, there can be only 1 redline...
1594 SwPosition const tmp(*pNd);
1595 SwRangeRedline const*const pRedline(
1596 pDoc->getIDocumentRedlineAccess().GetRedline(tmp, nullptr));
1597 // pathology: redline that starts on a TableNode; cannot
1598 // be created in UI but by import filters...
1599 if (pRedline
1600 && pRedline->GetType() == RedlineType::Delete
1601 && &pRedline->Start()->nNode.GetNode() == pNd)
1603 SAL_WARN("sw.pageframe", "skipping table frame creation on bizarre redline");
1604 while (true)
1606 pTableNode->GetNodes()[nIndex]->SetRedlineMergeFlag(SwNode::Merge::Hidden);
1607 if (nIndex == pTableNode->EndOfSectionIndex())
1609 break;
1611 ++nIndex;
1613 continue;
1616 if (pLayout->IsHideRedlines() && !pNd->IsCreateFrameWhenHidingRedlines())
1618 assert(pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden);
1619 nIndex = pTableNode->EndOfSectionIndex();
1620 continue; // skip it
1623 // #108116# loading may produce table structures that GCLines
1624 // needs to clean up. To keep table formulas correct, change
1625 // all table formulas to internal (BOXPTR) representation.
1626 SwTableFormulaUpdate aMsgHint( &pTableNode->GetTable() );
1627 aMsgHint.m_eFlags = TBL_BOXPTR;
1628 pDoc->getIDocumentFieldsAccess().UpdateTableFields( &aMsgHint );
1629 pTableNode->GetTable().GCLines();
1631 pFrame = pTableNode->MakeFrame( pLay );
1633 if( pPageMaker )
1634 pPageMaker->CheckInsert( nIndex );
1636 pFrame->InsertBehind( pLay, pPrv );
1637 if (pPage) // would null in SwCellFrame ctor
1638 { // tdf#134931 call ResetTurbo(); not sure if Paste() would be
1639 pFrame->InvalidatePage(pPage); // better than InsertBehind()?
1641 // #i27138#
1642 // notify accessibility paragraphs objects about changed
1643 // CONTENT_FLOWS_FROM/_TO relation.
1644 // Relation CONTENT_FLOWS_FROM for next paragraph will change
1645 // and relation CONTENT_FLOWS_TO for previous paragraph will change.
1647 SwViewShell* pViewShell( pFrame->getRootFrame()->GetCurrShell() );
1648 // no notification, if <SwViewShell> is in construction
1649 if ( pViewShell && !pViewShell->IsInConstructor() &&
1650 pViewShell->GetLayout() &&
1651 pViewShell->GetLayout()->IsAnyShellAccessible() &&
1652 pFrame->FindPageFrame() != nullptr)
1654 pViewShell->InvalidateAccessibleParaFlowRelation(
1655 dynamic_cast<SwTextFrame*>(pFrame->FindNextCnt( true )),
1656 dynamic_cast<SwTextFrame*>(pFrame->FindPrevCnt()) );
1659 if ( bObjsDirect && !pTable->empty() )
1660 static_cast<SwTabFrame*>(pFrame)->RegistFlys();
1661 // OD 12.08.2003 #i17969# - consider horizontal/vertical layout
1662 // for setting position at newly inserted frame
1663 lcl_SetPos( *pFrame, *pLay );
1665 pPrv = pFrame;
1666 //Set the index to the endnode of the table section.
1667 nIndex = pTableNode->EndOfSectionIndex();
1669 SwTabFrame* pTmpFrame = static_cast<SwTabFrame*>(pFrame);
1670 while ( pTmpFrame )
1672 pTmpFrame->CheckDirChange();
1673 pTmpFrame = pTmpFrame->IsFollow() ? pTmpFrame->FindMaster() : nullptr;
1677 else if ( pNd->IsSectionNode() )
1679 if (pLayout->IsHideRedlines() && !pNd->IsCreateFrameWhenHidingRedlines())
1681 assert(pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden);
1682 continue; // skip it
1684 SwSectionNode *pNode = static_cast<SwSectionNode*>(pNd);
1685 if( pNode->GetSection().CalcHiddenFlag() )
1686 // is hidden, skip the area
1687 nIndex = pNode->EndOfSectionIndex();
1688 else
1690 pFrame = pNode->MakeFrame( pLay );
1691 pActualSection.reset( new SwActualSection( pActualSection.release(),
1692 static_cast<SwSectionFrame*>(pFrame), pNode ) );
1693 if ( pActualSection->GetUpper() )
1695 //Insert behind the Upper, the "Follow" of the Upper will be
1696 //generated at the EndNode.
1697 SwSectionFrame *pTmp = pActualSection->GetUpper()->GetSectionFrame();
1698 pFrame->InsertBehind( pTmp->GetUpper(), pTmp );
1699 // OD 25.03.2003 #108339# - direct initialization of section
1700 // after insertion in the layout
1701 static_cast<SwSectionFrame*>(pFrame)->Init();
1703 else
1705 pFrame->InsertBehind( pLay, pPrv );
1706 // OD 25.03.2003 #108339# - direct initialization of section
1707 // after insertion in the layout
1708 static_cast<SwSectionFrame*>(pFrame)->Init();
1710 // #i33963#
1711 // Do not trust the IsInFootnote flag. If we are currently
1712 // building up a table, the upper of pPrv may be a cell
1713 // frame, but the cell frame does not have an upper yet.
1714 if( pPrv && nullptr != pPrv->ImplFindFootnoteFrame() )
1716 if( pPrv->IsSctFrame() )
1717 pPrv = static_cast<SwSectionFrame*>(pPrv)->ContainsContent();
1718 if( pPrv && pPrv->IsTextFrame() )
1719 static_cast<SwTextFrame*>(pPrv)->Prepare( PREP_QUOVADIS, nullptr, false );
1722 if (nIndex + 1 == nEndIndex)
1723 { // tdf#131684 tdf#132236 fix upper of frame moved in
1724 // SwUndoDelete; can't be done there unfortunately
1725 // because empty section frames are deleted here
1726 SwFrame *const pNext(
1727 // if there's a parent section, it has been split
1728 // into 2 SwSectionFrame already :(
1729 ( pFrame->GetNext()
1730 && pFrame->GetNext()->IsSctFrame()
1731 && pActualSection->GetUpper()
1732 && pActualSection->GetUpper()->GetSectionNode() ==
1733 static_cast<SwSectionFrame const*>(pFrame->GetNext())->GetSection()->GetFormat()->GetSectionNode())
1734 ? static_cast<SwSectionFrame *>(pFrame->GetNext())->ContainsContent()
1735 : pFrame->GetNext());
1736 if (pNext
1737 && pNext->IsTextFrame()
1738 && static_cast<SwTextFrame*>(pNext)->GetTextNodeFirst() == pDoc->GetNodes()[nEndIndex]
1739 && (pNext->GetUpper() == pFrame->GetUpper()
1740 || pFrame->GetNext()->IsSctFrame())) // checked above
1742 pNext->Cut();
1743 pNext->InvalidateInfFlags(); // mbInfSct changed
1744 // could have columns
1745 SwSectionFrame *const pSection(static_cast<SwSectionFrame*>(pFrame));
1746 assert(!pSection->Lower() || pSection->Lower()->IsLayoutFrame());
1747 SwLayoutFrame *const pParent(pSection->Lower() ? pSection->GetNextLayoutLeaf() : pSection);
1748 assert(!pParent->Lower());
1749 // paste invalidates, section could have indent...
1750 pNext->Paste(pParent, nullptr);
1753 // #i27138#
1754 // notify accessibility paragraphs objects about changed
1755 // CONTENT_FLOWS_FROM/_TO relation.
1756 // Relation CONTENT_FLOWS_FROM for next paragraph will change
1757 // and relation CONTENT_FLOWS_TO for previous paragraph will change.
1759 SwViewShell* pViewShell( pFrame->getRootFrame()->GetCurrShell() );
1760 // no notification, if <SwViewShell> is in construction
1761 if ( pViewShell && !pViewShell->IsInConstructor() &&
1762 pViewShell->GetLayout() &&
1763 pViewShell->GetLayout()->IsAnyShellAccessible() &&
1764 pFrame->FindPageFrame() != nullptr)
1766 pViewShell->InvalidateAccessibleParaFlowRelation(
1767 dynamic_cast<SwTextFrame*>(pFrame->FindNextCnt( true )),
1768 dynamic_cast<SwTextFrame*>(pFrame->FindPrevCnt()) );
1771 pFrame->CheckDirChange();
1773 // OD 12.08.2003 #i17969# - consider horizontal/vertical layout
1774 // for setting position at newly inserted frame
1775 lcl_SetPos( *pFrame, *pLay );
1777 // OD 20.11.2002 #105405# - no page, no invalidate.
1778 if ( pPage )
1780 // OD 18.09.2002 #100522#
1781 // invalidate page in order to force format and paint of
1782 // inserted section frame
1783 pFrame->InvalidatePage( pPage );
1785 // FME 10.11.2003 #112243#
1786 // Invalidate fly content flag:
1787 if ( pFrame->IsInFly() )
1788 pPage->InvalidateFlyContent();
1790 // OD 14.11.2002 #104684# - invalidate page content in order to
1791 // force format and paint of section content.
1792 pPage->InvalidateContent();
1795 pLay = static_cast<SwLayoutFrame*>(pFrame);
1796 if ( pLay->Lower() && pLay->Lower()->IsLayoutFrame() )
1797 pLay = pLay->GetNextLayoutLeaf();
1798 pPrv = nullptr;
1801 else if ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode() )
1803 if (pLayout->IsHideRedlines() && !pNd->IsCreateFrameWhenHidingRedlines())
1805 assert(pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden);
1806 continue; // skip it
1808 assert(pActualSection && "Section end without section start?");
1809 assert(pActualSection->GetSectionNode() == pNd->StartOfSectionNode());
1811 //Close the section, where appropriate activate the surrounding
1812 //section again.
1813 pActualSection.reset(pActualSection->GetUpper());
1814 pLay = pLay->FindSctFrame();
1815 if ( pActualSection )
1817 //Could be, that the last SectionFrame remains empty.
1818 //Then now is the time to remove them.
1819 if ( !pLay->ContainsContent() )
1821 SwFrame *pTmpFrame = pLay;
1822 pLay = pTmpFrame->GetUpper();
1823 pPrv = pTmpFrame->GetPrev();
1824 pTmpFrame->RemoveFromLayout();
1825 SwFrame::DestroyFrame(pTmpFrame);
1827 else
1829 pPrv = pLay;
1830 pLay = pLay->GetUpper();
1833 // new section frame
1834 pFrame = pActualSection->GetSectionNode()->MakeFrame( pLay );
1835 pFrame->InsertBehind( pLay, pPrv );
1836 static_cast<SwSectionFrame*>(pFrame)->Init();
1838 // OD 12.08.2003 #i17969# - consider horizontal/vertical layout
1839 // for setting position at newly inserted frame
1840 lcl_SetPos( *pFrame, *pLay );
1842 SwSectionFrame* pOuterSectionFrame = pActualSection->GetSectionFrame();
1844 // a follow has to be appended to the new section frame
1845 SwSectionFrame* pFollow = pOuterSectionFrame ? pOuterSectionFrame->GetFollow() : nullptr;
1846 if ( pFollow )
1848 pOuterSectionFrame->SetFollow( nullptr );
1849 pOuterSectionFrame->InvalidateSize();
1850 static_cast<SwSectionFrame*>(pFrame)->SetFollow( pFollow );
1853 // We don't want to leave empty parts back.
1854 if (pOuterSectionFrame &&
1855 ! pOuterSectionFrame->IsColLocked() &&
1856 ! pOuterSectionFrame->ContainsContent() )
1858 pOuterSectionFrame->DelEmpty( true );
1859 SwFrame::DestroyFrame(pOuterSectionFrame);
1861 pActualSection->SetSectionFrame( static_cast<SwSectionFrame*>(pFrame) );
1863 pLay = static_cast<SwLayoutFrame*>(pFrame);
1864 if ( pLay->Lower() && pLay->Lower()->IsLayoutFrame() )
1865 pLay = pLay->GetNextLayoutLeaf();
1866 pPrv = nullptr;
1868 else
1870 //Nothing more with sections, it goes on right behind
1871 //the SectionFrame.
1872 pPrv = pLay;
1873 pLay = pLay->GetUpper();
1876 else if( pNd->IsStartNode() &&
1877 SwFlyStartNode == static_cast<SwStartNode*>(pNd)->GetStartNodeType() )
1879 if (pLayout->IsHideRedlines() && !pNd->IsCreateFrameWhenHidingRedlines())
1881 assert(pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden);
1882 assert(false); // actually a fly-section can't be deleted?
1883 continue; // skip it
1885 if ( !pTable->empty() && bObjsDirect && !bDontCreateObjects )
1887 SwFlyFrame* pFly = pLay->FindFlyFrame();
1888 if( pFly )
1889 AppendObjs( pTable, nIndex, pFly, pPage, pDoc );
1892 else
1894 assert(!pLayout->IsHideRedlines()
1895 || pNd->GetRedlineMergeFlag() != SwNode::Merge::Hidden);
1896 // Neither Content nor table nor section, so we are done.
1897 break;
1901 if ( pActualSection )
1903 // Might happen that an empty (Follow-)Section is left over.
1904 if ( !(pLay = pActualSection->GetSectionFrame())->ContainsContent() )
1906 pLay->RemoveFromLayout();
1907 SwFrame::DestroyFrame(pLay);
1909 pActualSection.reset();
1912 if ( bPages ) // let the Flys connect to each other
1914 if ( !bDontCreateObjects )
1915 AppendAllObjs( pTable, pLayout );
1916 bObjsDirect = true;
1919 if( pPageMaker )
1921 pPageMaker->CheckFlyCache( pPage );
1922 pPageMaker.reset();
1923 if( pDoc->GetLayoutCache() )
1925 #ifdef DBG_UTIL
1926 pDoc->GetLayoutCache()->CompareLayout( *pDoc );
1927 #endif
1928 pDoc->GetLayoutCache()->ClearImpl();
1932 pDoc->getIDocumentTimerAccess().UnblockIdling();
1933 if( bOldCallbackActionEnabled )
1934 pLayout->SetCallbackActionEnabled( bOldCallbackActionEnabled );
1937 void MakeFrames( SwDoc *pDoc, const SwNodeIndex &rSttIdx,
1938 const SwNodeIndex &rEndIdx )
1940 bObjsDirect = false;
1942 SwNodeIndex aTmp( rSttIdx );
1943 sal_uLong nEndIdx = rEndIdx.GetIndex();
1944 SwNode* pNd = pDoc->GetNodes().FindPrvNxtFrameNode( aTmp,
1945 pDoc->GetNodes()[ nEndIdx-1 ]);
1946 if ( pNd )
1948 bool bApres = aTmp < rSttIdx;
1949 SwNode2Layout aNode2Layout( *pNd, rSttIdx.GetIndex() );
1950 SwFrame* pFrame;
1951 sw::FrameMode eMode = sw::FrameMode::Existing;
1952 while( nullptr != (pFrame = aNode2Layout.NextFrame()) )
1954 SwLayoutFrame *pUpper = pFrame->GetUpper();
1955 SwFootnoteFrame* pFootnoteFrame = pUpper->FindFootnoteFrame();
1956 bool bOldLock, bOldFootnote;
1957 if( pFootnoteFrame )
1959 bOldFootnote = pFootnoteFrame->IsColLocked();
1960 pFootnoteFrame->ColLock();
1962 else
1963 bOldFootnote = true;
1964 SwSectionFrame* pSct = pUpper->FindSctFrame();
1965 // Inside of footnotes only those areas are interesting that are inside of them. But
1966 // not the ones (e.g. column areas) in which are the footnote containers positioned.
1967 // #109767# Table frame is in section, insert section in cell frame.
1968 if( pSct && ((pFootnoteFrame && !pSct->IsInFootnote()) || pUpper->IsCellFrame()) )
1969 pSct = nullptr;
1970 if( pSct )
1971 { // to prevent pTmp->MoveFwd from destroying the SectionFrame
1972 bOldLock = pSct->IsColLocked();
1973 pSct->ColLock();
1975 else
1976 bOldLock = true;
1978 // If pFrame cannot be moved, it is not possible to move it to the next page. This applies
1979 // also for frames (in the first column of a frame pFrame is moveable) and column
1980 // sections of tables (also here pFrame is moveable).
1981 bool bMoveNext = nEndIdx - rSttIdx.GetIndex() > 120;
1982 bool bAllowMove = !pFrame->IsInFly() && pFrame->IsMoveable() &&
1983 (!pFrame->IsInTab() || pFrame->IsTabFrame() );
1984 if ( bMoveNext && bAllowMove )
1986 SwFrame *pMove = pFrame;
1987 SwFrame *pPrev = pFrame->GetPrev();
1988 SwFlowFrame *pTmp = SwFlowFrame::CastFlowFrame( pMove );
1989 assert(pTmp);
1991 if ( bApres )
1993 // The rest of this page should be empty. Thus, the following one has to move to
1994 // the next page (it might also be located in the following column).
1995 assert(!pTmp->HasFollow() && "prev. node's frame is not last");
1996 pPrev = pFrame;
1997 // If the surrounding SectionFrame has a "next" one,
1998 // so this one needs to be moved as well.
1999 pMove = pFrame->GetIndNext();
2000 SwColumnFrame* pCol = static_cast<SwColumnFrame*>(pFrame->FindColFrame());
2001 if( pCol )
2002 pCol = static_cast<SwColumnFrame*>(pCol->GetNext());
2005 if( pCol && !pMove )
2006 { // No successor so far, look into the next column
2007 pMove = pCol->ContainsAny();
2008 if( pCol->GetNext() )
2009 pCol = static_cast<SwColumnFrame*>(pCol->GetNext());
2010 else if( pCol->IsInSct() )
2011 { // If there is no following column but we are in a column frame,
2012 // there might be (page) columns outside of it.
2013 pCol = static_cast<SwColumnFrame*>(pCol->FindSctFrame()->FindColFrame());
2014 if( pCol )
2015 pCol = static_cast<SwColumnFrame*>(pCol->GetNext());
2017 else
2018 pCol = nullptr;
2020 // skip invalid SectionFrames
2021 while( pMove && pMove->IsSctFrame() &&
2022 !static_cast<SwSectionFrame*>(pMove)->GetSection() )
2023 pMove = pMove->GetNext();
2024 } while( !pMove && pCol );
2026 if( pMove )
2028 if ( pMove->IsContentFrame() )
2029 pTmp = static_cast<SwContentFrame*>(pMove);
2030 else if ( pMove->IsTabFrame() )
2031 pTmp = static_cast<SwTabFrame*>(pMove);
2032 else if ( pMove->IsSctFrame() )
2034 pMove = static_cast<SwSectionFrame*>(pMove)->ContainsAny();
2035 if( pMove )
2036 pTmp = SwFlowFrame::CastFlowFrame( pMove );
2037 else
2038 pTmp = nullptr;
2041 else
2042 pTmp = nullptr;
2044 else
2046 assert(!pTmp->IsFollow() && "next node's frame is not master");
2047 // move the _content_ of a section frame
2048 if( pMove->IsSctFrame() )
2050 while( pMove && pMove->IsSctFrame() &&
2051 !static_cast<SwSectionFrame*>(pMove)->GetSection() )
2052 pMove = pMove->GetNext();
2053 if( pMove && pMove->IsSctFrame() )
2054 pMove = static_cast<SwSectionFrame*>(pMove)->ContainsAny();
2055 if( pMove )
2056 pTmp = SwFlowFrame::CastFlowFrame( pMove );
2057 else
2058 pTmp = nullptr;
2062 if( pTmp )
2064 SwFrame* pOldUp = pTmp->GetFrame().GetUpper();
2065 // MoveFwd==true means that we are still on the same page.
2066 // But since we want to move if possible!
2067 bool bTmpOldLock = pTmp->IsJoinLocked();
2068 pTmp->LockJoin();
2069 while( pTmp->MoveFwd( true, false, true ) )
2071 if( pOldUp == pTmp->GetFrame().GetUpper() )
2072 break;
2073 pOldUp = pTmp->GetFrame().GetUpper();
2075 if( !bTmpOldLock )
2076 pTmp->UnlockJoin();
2078 ::InsertCnt_( pUpper, pDoc, rSttIdx.GetIndex(),
2079 pFrame->IsInDocBody(), nEndIdx, pPrev, eMode );
2081 else
2083 bool bSplit;
2084 SwFrame* pPrv = bApres ? pFrame : pFrame->GetPrev();
2085 // If the section frame is inserted into another one, it must be split.
2086 if( pSct && rSttIdx.GetNode().IsSectionNode() )
2088 bSplit = pSct->SplitSect( pFrame, bApres );
2089 if( !bSplit && !bApres )
2091 pUpper = pSct->GetUpper();
2092 pPrv = pSct->GetPrev();
2095 else
2096 bSplit = false;
2098 ::InsertCnt_( pUpper, pDoc, rSttIdx.GetIndex(), false,
2099 nEndIdx, pPrv, eMode );
2100 // OD 23.06.2003 #108784# - correction: append objects doesn't
2101 // depend on value of <bAllowMove>
2102 if( !bDontCreateObjects )
2104 const SwFrameFormats *pTable = pDoc->GetSpzFrameFormats();
2105 if( !pTable->empty() )
2106 AppendAllObjs( pTable, pUpper );
2109 // If nothing was added (e.g. a hidden section), the split must be reversed.
2110 if( bSplit && pSct && pSct->GetNext()
2111 && pSct->GetNext()->IsSctFrame() )
2112 pSct->MergeNext( static_cast<SwSectionFrame*>(pSct->GetNext()) );
2113 if( pFrame->IsInFly() )
2114 pFrame->FindFlyFrame()->Invalidate_();
2115 if( pFrame->IsInTab() )
2116 pFrame->InvalidateSize();
2119 SwPageFrame *pPage = pUpper->FindPageFrame();
2120 SwFrame::CheckPageDescs( pPage, false );
2121 if( !bOldFootnote )
2122 pFootnoteFrame->ColUnlock();
2123 if( !bOldLock )
2125 pSct->ColUnlock();
2126 // pSct might be empty (e.g. when inserting linked section containing further
2127 // sections) and can be destroyed in such cases.
2128 if( !pSct->ContainsContent() )
2130 pSct->DelEmpty( true );
2131 pUpper->getRootFrame()->RemoveFromList( pSct );
2132 SwFrame::DestroyFrame(pSct);
2135 eMode = sw::FrameMode::New; // use Existing only once!
2139 bObjsDirect = true;
2142 SwBorderAttrs::SwBorderAttrs(const SwModify *pMod, const SwFrame *pConstructor)
2143 : SwCacheObj(pMod)
2144 , m_rAttrSet(pConstructor->IsContentFrame()
2145 ? pConstructor->IsTextFrame()
2146 ? static_cast<const SwTextFrame*>(pConstructor)->GetTextNodeForParaProps()->GetSwAttrSet()
2147 : static_cast<const SwNoTextFrame*>(pConstructor)->GetNode()->GetSwAttrSet()
2148 : static_cast<const SwLayoutFrame*>(pConstructor)->GetFormat()->GetAttrSet())
2149 , m_rUL(m_rAttrSet.GetULSpace())
2150 // #i96772#
2151 // LRSpaceItem is copied due to the possibility that it is adjusted - see below
2152 , m_rLR(static_cast<SvxLRSpaceItem*>(m_rAttrSet.GetLRSpace().Clone()))
2153 , m_rBox(m_rAttrSet.GetBox())
2154 , m_rShadow(m_rAttrSet.GetShadow())
2155 , m_aFrameSize(m_rAttrSet.GetFrameSize().GetSize())
2156 , m_bIsLine(false)
2157 , m_bJoinedWithPrev(false)
2158 , m_bJoinedWithNext(false)
2159 , m_nTopLine(0)
2160 , m_nBottomLine(0)
2161 , m_nLeftLine(0)
2162 , m_nRightLine(0)
2163 , m_nTop(0)
2164 , m_nBottom(0)
2165 , m_nGetTopLine(0)
2166 , m_nGetBottomLine(0)
2167 , m_nLineSpacing(0)
2169 // #i96772#
2170 const SwTextFrame* pTextFrame = dynamic_cast<const SwTextFrame*>(pConstructor);
2171 if ( pTextFrame )
2173 pTextFrame->GetTextNodeForParaProps()->ClearLRSpaceItemDueToListLevelIndents( m_rLR );
2175 else if ( pConstructor->IsNoTextFrame() )
2177 m_rLR = std::make_shared<SvxLRSpaceItem>(RES_LR_SPACE);
2180 // Caution: The USHORTs for the cached values are not initialized by intention!
2182 // everything needs to be calculated at least once:
2183 m_bTopLine = m_bBottomLine = m_bLeftLine = m_bRightLine =
2184 m_bTop = m_bBottom = m_bLine = true;
2186 // except this one: calculate line spacing before cell border only for text frames
2187 m_bLineSpacing = bool(pTextFrame);
2189 m_bCacheGetLine = m_bCachedGetTopLine = m_bCachedGetBottomLine = false;
2190 // OD 21.05.2003 #108789# - init cache status for values <m_bJoinedWithPrev>
2191 // and <m_bJoinedWithNext>, which aren't initialized by default.
2192 m_bCachedJoinedWithPrev = false;
2193 m_bCachedJoinedWithNext = false;
2196 SwBorderAttrs::~SwBorderAttrs()
2198 const_cast<SwModify *>(static_cast<SwModify const *>(m_pOwner))->SetInCache( false );
2201 /* All calc methods calculate a safety distance in addition to the values given by the attributes.
2202 * This safety distance is only added when working with borders and/or shadows to prevent that
2203 * e.g. borders are painted over.
2206 void SwBorderAttrs::CalcTop_()
2208 m_nTop = CalcTopLine() + m_rUL.GetUpper();
2210 if (m_rLR)
2212 bool bGutterAtTop = m_rAttrSet.GetDoc()->getIDocumentSettingAccess().get(
2213 DocumentSettingId::GUTTER_AT_TOP);
2214 if (bGutterAtTop)
2216 // Decrease the print area: the top space is the sum of top and gutter margins.
2217 m_nTop += m_rLR->GetGutterMargin();
2221 m_bTop = false;
2224 void SwBorderAttrs::CalcBottom_()
2226 m_nBottom = CalcBottomLine() + m_rUL.GetLower();
2227 m_bBottom = false;
2230 long SwBorderAttrs::CalcRight( const SwFrame* pCaller ) const
2232 long nRight=0;
2234 if (!pCaller->IsTextFrame() || !static_cast<const SwTextFrame*>(pCaller)->GetDoc().GetDocumentSettingManager().get(DocumentSettingId::INVERT_BORDER_SPACING)) {
2235 // OD 23.01.2003 #106895# - for cell frame in R2L text direction the left
2236 // and right border are painted on the right respectively left.
2237 if ( pCaller->IsCellFrame() && pCaller->IsRightToLeft() )
2238 nRight = CalcLeftLine();
2239 else
2240 nRight = CalcRightLine();
2243 // for paragraphs, "left" is "before text" and "right" is "after text"
2244 if ( pCaller->IsTextFrame() && pCaller->IsRightToLeft() )
2245 nRight += m_rLR->GetLeft();
2246 else
2247 nRight += m_rLR->GetRight();
2249 // correction: retrieve left margin for numbering in R2L-layout
2250 if ( pCaller->IsTextFrame() && pCaller->IsRightToLeft() )
2252 nRight += static_cast<const SwTextFrame*>(pCaller)->GetTextNodeForParaProps()->GetLeftMarginWithNum();
2255 if (pCaller->IsPageFrame() && m_rLR)
2257 const auto pPageFrame = static_cast<const SwPageFrame*>(pCaller);
2258 bool bGutterAtTop = pPageFrame->GetFormat()->getIDocumentSettingAccess().get(
2259 DocumentSettingId::GUTTER_AT_TOP);
2260 if (!bGutterAtTop)
2262 // Decrease the print area: the right space is the sum of right and right gutter
2263 // margins.
2264 nRight += m_rLR->GetRightGutterMargin();
2268 return nRight;
2271 /// Tries to detect if this paragraph has a floating table attached.
2272 static bool lcl_hasTabFrame(const SwTextFrame* pTextFrame)
2274 if (pTextFrame->GetDrawObjs())
2276 const SwSortedObjs* pSortedObjs = pTextFrame->GetDrawObjs();
2277 if (pSortedObjs->size() > 0)
2279 SwAnchoredObject* pObject = (*pSortedObjs)[0];
2280 if (dynamic_cast<const SwFlyFrame*>(pObject) != nullptr)
2282 SwFlyFrame* pFly = static_cast<SwFlyFrame*>(pObject);
2283 if (pFly->Lower() && pFly->Lower()->IsTabFrame())
2284 return true;
2288 return false;
2291 long SwBorderAttrs::CalcLeft( const SwFrame *pCaller ) const
2293 long nLeft=0;
2295 if (!pCaller->IsTextFrame() || !static_cast<const SwTextFrame*>(pCaller)->GetDoc().GetDocumentSettingManager().get(DocumentSettingId::INVERT_BORDER_SPACING))
2297 // OD 23.01.2003 #106895# - for cell frame in R2L text direction the left
2298 // and right border are painted on the right respectively left.
2299 if ( pCaller->IsCellFrame() && pCaller->IsRightToLeft() )
2300 nLeft = CalcRightLine();
2301 else
2302 nLeft = CalcLeftLine();
2305 // for paragraphs, "left" is "before text" and "right" is "after text"
2306 if ( pCaller->IsTextFrame() && pCaller->IsRightToLeft() )
2307 nLeft += m_rLR->GetRight();
2308 else
2310 bool bIgnoreMargin = false;
2311 if (pCaller->IsTextFrame())
2313 const SwTextFrame* pTextFrame = static_cast<const SwTextFrame*>(pCaller);
2314 if (pTextFrame->GetDoc().GetDocumentSettingManager().get(DocumentSettingId::FLOATTABLE_NOMARGINS))
2316 // If this is explicitly requested, ignore the margins next to the floating table.
2317 if (lcl_hasTabFrame(pTextFrame))
2318 bIgnoreMargin = true;
2319 // TODO here we only handle the first two paragraphs, would be nice to generalize this.
2320 else if (pTextFrame->FindPrev() && pTextFrame->FindPrev()->IsTextFrame() && lcl_hasTabFrame(static_cast<const SwTextFrame*>(pTextFrame->FindPrev())))
2321 bIgnoreMargin = true;
2324 if (!bIgnoreMargin)
2325 nLeft += m_rLR->GetLeft();
2328 // correction: do not retrieve left margin for numbering in R2L-layout
2329 if ( pCaller->IsTextFrame() && !pCaller->IsRightToLeft() )
2331 nLeft += static_cast<const SwTextFrame*>(pCaller)->GetTextNodeForParaProps()->GetLeftMarginWithNum();
2334 if (pCaller->IsPageFrame() && m_rLR)
2336 const auto pPageFrame = static_cast<const SwPageFrame*>(pCaller);
2337 bool bGutterAtTop = pPageFrame->GetFormat()->getIDocumentSettingAccess().get(
2338 DocumentSettingId::GUTTER_AT_TOP);
2339 if (!bGutterAtTop)
2341 // Decrease the print area: the left space is the sum of left and gutter margins.
2342 nLeft += m_rLR->GetGutterMargin();
2346 return nLeft;
2349 /* Calculated values for borders and shadows.
2350 * It might be that a distance is wanted even without lines. This will be
2351 * considered here and not by the attribute (e.g. bBorderDist for cells).
2354 void SwBorderAttrs::CalcTopLine_()
2356 m_nTopLine = m_rBox.CalcLineSpace( SvxBoxItemLine::TOP, /*bEvenIfNoLine*/true );
2357 m_nTopLine = m_nTopLine + m_rShadow.CalcShadowSpace(SvxShadowItemSide::TOP);
2358 m_bTopLine = false;
2361 void SwBorderAttrs::CalcBottomLine_()
2363 m_nBottomLine = m_rBox.CalcLineSpace( SvxBoxItemLine::BOTTOM, true );
2364 m_nBottomLine = m_nBottomLine + m_rShadow.CalcShadowSpace(SvxShadowItemSide::BOTTOM);
2365 m_bBottomLine = false;
2368 void SwBorderAttrs::CalcLeftLine_()
2370 m_nLeftLine = m_rBox.CalcLineSpace( SvxBoxItemLine::LEFT, true);
2371 m_nLeftLine = m_nLeftLine + m_rShadow.CalcShadowSpace(SvxShadowItemSide::LEFT);
2372 m_bLeftLine = false;
2375 void SwBorderAttrs::CalcRightLine_()
2377 m_nRightLine = m_rBox.CalcLineSpace( SvxBoxItemLine::RIGHT, true );
2378 m_nRightLine = m_nRightLine + m_rShadow.CalcShadowSpace(SvxShadowItemSide::RIGHT);
2379 m_bRightLine = false;
2382 void SwBorderAttrs::IsLine_()
2384 m_bIsLine = m_rBox.GetTop() || m_rBox.GetBottom() ||
2385 m_rBox.GetLeft()|| m_rBox.GetRight();
2386 m_bLine = false;
2389 /* The borders of neighboring paragraphs are condensed by following algorithm:
2391 * 1. No top border if the predecessor has the same top border and (3) applies.
2392 * In addition, the paragraph needs to have a border at least one side (left/right/bottom).
2393 * 2. No bottom border if the successor has the same bottom border and (3) applies.
2394 * In addition, the paragraph needs to have a border at least one side (left/right/top).
2395 * 3. The borders on the left and right side are identical between the current and the
2396 * pre-/succeeding paragraph.
2399 static bool CmpLines( const editeng::SvxBorderLine *pL1, const editeng::SvxBorderLine *pL2 )
2401 return ( ((pL1 && pL2) && (*pL1 == *pL2)) || (!pL1 && !pL2) );
2404 // OD 21.05.2003 #108789# - change name of 1st parameter - "rAttrs" -> "rCmpAttrs"
2405 // OD 21.05.2003 #108789# - compare <CalcRight()> and <rCmpAttrs.CalcRight()>
2406 // instead of only the right LR-spacing, because R2L-layout has to be
2407 // considered.
2408 bool SwBorderAttrs::CmpLeftRight( const SwBorderAttrs &rCmpAttrs,
2409 const SwFrame *pCaller,
2410 const SwFrame *pCmp ) const
2412 return ( CmpLines( rCmpAttrs.GetBox().GetLeft(), GetBox().GetLeft() ) &&
2413 CmpLines( rCmpAttrs.GetBox().GetRight(),GetBox().GetRight() ) &&
2414 CalcLeft( pCaller ) == rCmpAttrs.CalcLeft( pCmp ) &&
2415 // OD 21.05.2003 #108789# - compare <CalcRight> with <rCmpAttrs.CalcRight>.
2416 CalcRight( pCaller ) == rCmpAttrs.CalcRight( pCmp ) );
2419 bool SwBorderAttrs::JoinWithCmp( const SwFrame& _rCallerFrame,
2420 const SwFrame& _rCmpFrame ) const
2422 bool bReturnVal = false;
2424 SwBorderAttrAccess aCmpAccess( SwFrame::GetCache(), &_rCmpFrame );
2425 const SwBorderAttrs &rCmpAttrs = *aCmpAccess.Get();
2426 if ( m_rShadow == rCmpAttrs.GetShadow() &&
2427 CmpLines( m_rBox.GetTop(), rCmpAttrs.GetBox().GetTop() ) &&
2428 CmpLines( m_rBox.GetBottom(), rCmpAttrs.GetBox().GetBottom() ) &&
2429 CmpLeftRight( rCmpAttrs, &_rCallerFrame, &_rCmpFrame )
2432 bReturnVal = true;
2435 return bReturnVal;
2438 // OD 21.05.2003 #108789# - method to determine, if borders are joined with
2439 // previous frame. Calculated value saved in cached value <m_bJoinedWithPrev>
2440 // OD 2004-02-26 #i25029# - add 2nd parameter <_pPrevFrame>
2441 void SwBorderAttrs::CalcJoinedWithPrev( const SwFrame& _rFrame,
2442 const SwFrame* _pPrevFrame )
2444 // set default
2445 m_bJoinedWithPrev = false;
2447 if ( _rFrame.IsTextFrame() )
2449 // text frame can potentially join with previous text frame, if
2450 // corresponding attribute set is set at previous text frame.
2451 // OD 2004-02-26 #i25029# - If parameter <_pPrevFrame> is set, take this
2452 // one as previous frame.
2453 const SwFrame* pPrevFrame = _pPrevFrame ? _pPrevFrame : _rFrame.GetPrev();
2454 // OD 2004-02-13 #i25029# - skip hidden text frames.
2455 while ( pPrevFrame && pPrevFrame->IsTextFrame() &&
2456 static_cast<const SwTextFrame*>(pPrevFrame)->IsHiddenNow() )
2458 pPrevFrame = pPrevFrame->GetPrev();
2460 if ( pPrevFrame && pPrevFrame->IsTextFrame() &&
2461 pPrevFrame->GetAttrSet()->GetParaConnectBorder().GetValue()
2464 m_bJoinedWithPrev = JoinWithCmp( _rFrame, *pPrevFrame );
2468 // valid cache status, if demanded
2469 // OD 2004-02-26 #i25029# - Do not validate cache, if parameter <_pPrevFrame>
2470 // is set.
2471 m_bCachedJoinedWithPrev = m_bCacheGetLine && !_pPrevFrame;
2474 // OD 21.05.2003 #108789# - method to determine, if borders are joined with
2475 // next frame. Calculated value saved in cached value <m_bJoinedWithNext>
2476 void SwBorderAttrs::CalcJoinedWithNext( const SwFrame& _rFrame )
2478 // set default
2479 m_bJoinedWithNext = false;
2481 if ( _rFrame.IsTextFrame() )
2483 // text frame can potentially join with next text frame, if
2484 // corresponding attribute set is set at current text frame.
2485 // OD 2004-02-13 #i25029# - get next frame, but skip hidden text frames.
2486 const SwFrame* pNextFrame = _rFrame.GetNext();
2487 while ( pNextFrame && pNextFrame->IsTextFrame() &&
2488 static_cast<const SwTextFrame*>(pNextFrame)->IsHiddenNow() )
2490 pNextFrame = pNextFrame->GetNext();
2492 if ( pNextFrame && pNextFrame->IsTextFrame() &&
2493 _rFrame.GetAttrSet()->GetParaConnectBorder().GetValue()
2496 m_bJoinedWithNext = JoinWithCmp( _rFrame, *pNextFrame );
2500 // valid cache status, if demanded
2501 m_bCachedJoinedWithNext = m_bCacheGetLine;
2504 // OD 21.05.2003 #108789# - accessor for cached values <m_bJoinedWithPrev>
2505 // OD 2004-02-26 #i25029# - add 2nd parameter <_pPrevFrame>, which is passed to
2506 // method <_CalcJoindWithPrev(..)>.
2507 bool SwBorderAttrs::JoinedWithPrev( const SwFrame& _rFrame,
2508 const SwFrame* _pPrevFrame ) const
2510 if ( !m_bCachedJoinedWithPrev || _pPrevFrame )
2512 // OD 2004-02-26 #i25029# - pass <_pPrevFrame> as 2nd parameter
2513 const_cast<SwBorderAttrs*>(this)->CalcJoinedWithPrev( _rFrame, _pPrevFrame );
2516 return m_bJoinedWithPrev;
2519 bool SwBorderAttrs::JoinedWithNext( const SwFrame& _rFrame ) const
2521 if ( !m_bCachedJoinedWithNext )
2523 const_cast<SwBorderAttrs*>(this)->CalcJoinedWithNext( _rFrame );
2526 return m_bJoinedWithNext;
2529 // OD 2004-02-26 #i25029# - added 2nd parameter <_pPrevFrame>, which is passed to
2530 // method <JoinedWithPrev>
2531 void SwBorderAttrs::GetTopLine_( const SwFrame& _rFrame,
2532 const SwFrame* _pPrevFrame )
2534 sal_uInt16 nRet = CalcTopLine();
2536 // OD 21.05.2003 #108789# - use new method <JoinWithPrev()>
2537 // OD 2004-02-26 #i25029# - add 2nd parameter
2538 if ( JoinedWithPrev( _rFrame, _pPrevFrame ) )
2540 nRet = 0;
2543 m_bCachedGetTopLine = m_bCacheGetLine;
2545 m_nGetTopLine = nRet;
2548 void SwBorderAttrs::GetBottomLine_( const SwFrame& _rFrame )
2550 sal_uInt16 nRet = CalcBottomLine();
2552 // OD 21.05.2003 #108789# - use new method <JoinWithPrev()>
2553 if ( JoinedWithNext( _rFrame ) )
2555 nRet = 0;
2558 m_bCachedGetBottomLine = m_bCacheGetLine;
2560 m_nGetBottomLine = nRet;
2563 void SwBorderAttrs::CalcLineSpacing_()
2565 // tdf#125300 compatibility option AddParaLineSpacingToTableCells needs also line spacing
2566 const SvxLineSpacingItem &rSpace = m_rAttrSet.GetLineSpacing();
2567 if ( rSpace.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Prop && rSpace.GetPropLineSpace() > 100 )
2569 sal_Int32 nFontSize = m_rAttrSet.Get(RES_CHRATR_FONTSIZE).GetHeight();
2570 m_nLineSpacing = nFontSize * (rSpace.GetPropLineSpace() - 100) * 1.15 / 100;
2572 m_bLineSpacing = false;
2575 static SwModify const* GetCacheOwner(SwFrame const& rFrame)
2577 return rFrame.IsContentFrame()
2578 ? static_cast<SwModify const*>(rFrame.IsTextFrame()
2579 // 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
2580 ? static_cast<const SwTextFrame&>(rFrame).GetTextNodeForParaProps()
2581 : static_cast<const SwNoTextFrame&>(rFrame).GetNode())
2582 : static_cast<SwModify const*>(static_cast<const SwLayoutFrame&>(rFrame).GetFormat());
2585 SwBorderAttrAccess::SwBorderAttrAccess( SwCache &rCach, const SwFrame *pFrame ) :
2586 SwCacheAccess( rCach,
2587 static_cast<void const *>(GetCacheOwner(*pFrame)),
2588 GetCacheOwner(*pFrame)->IsInCache()),
2589 m_pConstructor( pFrame )
2593 SwCacheObj *SwBorderAttrAccess::NewObj()
2595 const_cast<SwModify *>(static_cast<SwModify const *>(m_pOwner))->SetInCache( true );
2596 return new SwBorderAttrs( static_cast<SwModify const *>(m_pOwner), m_pConstructor );
2599 SwBorderAttrs *SwBorderAttrAccess::Get()
2601 return static_cast<SwBorderAttrs*>(SwCacheAccess::Get());
2604 SwOrderIter::SwOrderIter( const SwPageFrame *pPg ) :
2605 m_pPage( pPg ),
2606 m_pCurrent( nullptr )
2610 void SwOrderIter::Top()
2612 m_pCurrent = nullptr;
2613 if ( m_pPage->GetSortedObjs() )
2615 const SwSortedObjs *pObjs = m_pPage->GetSortedObjs();
2616 if ( pObjs->size() )
2618 sal_uInt32 nTopOrd = 0;
2619 (*pObjs)[0]->GetDrawObj()->GetOrdNum(); // force updating
2620 for (SwAnchoredObject* i : *pObjs)
2622 const SdrObject* pObj = i->GetDrawObj();
2623 if ( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) == nullptr )
2624 continue;
2625 sal_uInt32 nTmp = pObj->GetOrdNumDirect();
2626 if ( nTmp >= nTopOrd )
2628 nTopOrd = nTmp;
2629 m_pCurrent = pObj;
2636 const SdrObject *SwOrderIter::Bottom()
2638 m_pCurrent = nullptr;
2639 if ( m_pPage->GetSortedObjs() )
2641 sal_uInt32 nBotOrd = USHRT_MAX;
2642 const SwSortedObjs *pObjs = m_pPage->GetSortedObjs();
2643 if ( pObjs->size() )
2645 (*pObjs)[0]->GetDrawObj()->GetOrdNum(); // force updating
2646 for (SwAnchoredObject* i : *pObjs)
2648 const SdrObject* pObj = i->GetDrawObj();
2649 if ( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) == nullptr )
2650 continue;
2651 sal_uInt32 nTmp = pObj->GetOrdNumDirect();
2652 if ( nTmp < nBotOrd )
2654 nBotOrd = nTmp;
2655 m_pCurrent = pObj;
2660 return m_pCurrent;
2663 const SdrObject *SwOrderIter::Next()
2665 const sal_uInt32 nCurOrd = m_pCurrent ? m_pCurrent->GetOrdNumDirect() : 0;
2666 m_pCurrent = nullptr;
2667 if ( m_pPage->GetSortedObjs() )
2669 sal_uInt32 nOrd = USHRT_MAX;
2670 const SwSortedObjs *pObjs = m_pPage->GetSortedObjs();
2671 if ( pObjs->size() )
2673 (*pObjs)[0]->GetDrawObj()->GetOrdNum(); // force updating
2674 for (SwAnchoredObject* i : *pObjs)
2676 const SdrObject* pObj = i->GetDrawObj();
2677 if ( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) == nullptr )
2678 continue;
2679 sal_uInt32 nTmp = pObj->GetOrdNumDirect();
2680 if ( nTmp > nCurOrd && nTmp < nOrd )
2682 nOrd = nTmp;
2683 m_pCurrent = pObj;
2688 return m_pCurrent;
2691 void SwOrderIter::Prev()
2693 const sal_uInt32 nCurOrd = m_pCurrent ? m_pCurrent->GetOrdNumDirect() : 0;
2694 m_pCurrent = nullptr;
2695 if ( m_pPage->GetSortedObjs() )
2697 const SwSortedObjs *pObjs = m_pPage->GetSortedObjs();
2698 if ( pObjs->size() )
2700 sal_uInt32 nOrd = 0;
2701 (*pObjs)[0]->GetDrawObj()->GetOrdNum(); // force updating
2702 for (SwAnchoredObject* i : *pObjs)
2704 const SdrObject* pObj = i->GetDrawObj();
2705 if ( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) == nullptr )
2706 continue;
2707 sal_uInt32 nTmp = pObj->GetOrdNumDirect();
2708 if ( nTmp < nCurOrd && nTmp >= nOrd )
2710 nOrd = nTmp;
2711 m_pCurrent = pObj;
2718 /// Keep and restore the substructure of a layout frame for an action.
2719 // New algorithm:
2720 // Do not look at each neighbor one by one to set all pointers correctly.
2721 // It is sufficient to detach a part of a chain and check if another chain needs to be added
2722 // when attaching it again. Only the pointers necessary for the chain connection need to be
2723 // adjusted. The correction happens in RestoreContent(). In between all access is restricted.
2724 // During this action, the Flys are detached from the page.
2726 // #115759# - 'remove' also drawing object from page and
2727 // at-fly anchored objects from page
2728 static void lcl_RemoveObjsFromPage( SwFrame* _pFrame )
2730 OSL_ENSURE( _pFrame->GetDrawObjs(), "no DrawObjs in lcl_RemoveObjsFromPage." );
2731 SwSortedObjs &rObjs = *_pFrame->GetDrawObjs();
2732 for (SwAnchoredObject* pObj : rObjs)
2734 // #115759# - reset member, at which the anchored
2735 // object orients its vertical position
2736 pObj->ClearVertPosOrientFrame();
2737 // #i43913#
2738 pObj->ResetLayoutProcessBools();
2739 // #115759# - remove also lower objects of as-character
2740 // anchored Writer fly frames from page
2741 if ( dynamic_cast<const SwFlyFrame*>( pObj) != nullptr )
2743 SwFlyFrame* pFlyFrame = static_cast<SwFlyFrame*>(pObj);
2745 // #115759# - remove also direct lowers of Writer
2746 // fly frame from page
2747 if ( pFlyFrame->GetDrawObjs() )
2749 ::lcl_RemoveObjsFromPage( pFlyFrame );
2752 SwContentFrame* pCnt = pFlyFrame->ContainsContent();
2753 while ( pCnt )
2755 if ( pCnt->GetDrawObjs() )
2756 ::lcl_RemoveObjsFromPage( pCnt );
2757 pCnt = pCnt->GetNextContentFrame();
2759 if ( pFlyFrame->IsFlyFreeFrame() )
2761 // #i28701# - use new method <GetPageFrame()>
2762 pFlyFrame->GetPageFrame()->RemoveFlyFromPage( pFlyFrame );
2765 // #115759# - remove also drawing objects from page
2766 else if ( dynamic_cast<const SwAnchoredDrawObject*>( pObj) != nullptr )
2768 if (pObj->GetFrameFormat().GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR)
2770 if (SwPageFrame *pPg = pObj->GetPageFrame())
2771 pPg->RemoveDrawObjFromPage(
2772 *static_cast<SwAnchoredDrawObject*>(pObj) );
2778 SwFrame *SaveContent( SwLayoutFrame *pLay, SwFrame *pStart )
2780 if( pLay->IsSctFrame() && pLay->Lower() && pLay->Lower()->IsColumnFrame() )
2781 sw_RemoveFootnotes( static_cast<SwColumnFrame*>(pLay->Lower()), true, true );
2783 SwFrame *pSav;
2784 if ( nullptr == (pSav = pLay->ContainsAny()) )
2785 return nullptr;
2787 if( pSav->IsInFootnote() && !pLay->IsInFootnote() )
2790 pSav = pSav->FindNext();
2791 while( pSav && pSav->IsInFootnote() );
2792 if( !pSav || !pLay->IsAnLower( pSav ) )
2793 return nullptr;
2796 // Tables should be saved as a whole, exception:
2797 // The contents of a section or a cell inside a table should be saved
2798 if ( pSav->IsInTab() && !( ( pLay->IsSctFrame() || pLay->IsCellFrame() ) && pLay->IsInTab() ) )
2799 while ( !pSav->IsTabFrame() )
2800 pSav = pSav->GetUpper();
2802 if( pSav->IsInSct() )
2803 { // search the upmost section inside of pLay
2804 SwFrame* pSect = pLay->FindSctFrame();
2805 SwFrame *pTmp = pSav;
2808 pSav = pTmp;
2809 pTmp = (pSav && pSav->GetUpper()) ? pSav->GetUpper()->FindSctFrame() : nullptr;
2810 } while ( pTmp != pSect );
2813 SwFrame *pFloat = pSav;
2814 if( !pStart )
2815 pStart = pSav;
2816 bool bGo = pStart == pSav;
2819 if( bGo )
2820 pFloat->GetUpper()->m_pLower = nullptr; // detach the chain part
2822 // search the end of the chain part, remove Flys on the way
2825 if( bGo )
2827 if ( pFloat->IsContentFrame() )
2829 if ( pFloat->GetDrawObjs() )
2830 ::lcl_RemoveObjsFromPage( static_cast<SwContentFrame*>(pFloat) );
2832 else if ( pFloat->IsTabFrame() || pFloat->IsSctFrame() )
2834 SwContentFrame *pCnt = static_cast<SwLayoutFrame*>(pFloat)->ContainsContent();
2835 if( pCnt )
2838 { if ( pCnt->GetDrawObjs() )
2839 ::lcl_RemoveObjsFromPage( pCnt );
2840 pCnt = pCnt->GetNextContentFrame();
2841 } while ( pCnt && static_cast<SwLayoutFrame*>(pFloat)->IsAnLower( pCnt ) );
2844 else {
2845 OSL_ENSURE( !pFloat, "new FloatFrame?" );
2848 if ( pFloat->GetNext() )
2850 if( bGo )
2851 pFloat->mpUpper = nullptr;
2852 pFloat = pFloat->GetNext();
2853 if( !bGo && pFloat == pStart )
2855 bGo = true;
2856 pFloat->mpPrev->mpNext = nullptr;
2857 pFloat->mpPrev = nullptr;
2860 else
2861 break;
2863 } while ( pFloat );
2865 // search next chain part and connect both chains
2866 SwFrame *pTmp = pFloat->FindNext();
2867 if( bGo )
2868 pFloat->mpUpper = nullptr;
2870 if( !pLay->IsInFootnote() )
2871 while( pTmp && pTmp->IsInFootnote() )
2872 pTmp = pTmp->FindNext();
2874 if ( !pLay->IsAnLower( pTmp ) )
2875 pTmp = nullptr;
2877 if ( pTmp && bGo )
2879 pFloat->mpNext = pTmp; // connect both chains
2880 pFloat->mpNext->mpPrev = pFloat;
2882 pFloat = pTmp;
2883 bGo = bGo || ( pStart == pFloat );
2884 } while ( pFloat );
2886 return bGo ? pStart : nullptr;
2889 // #115759# - add also drawing objects to page and at-fly
2890 // anchored objects to page
2891 static void lcl_AddObjsToPage( SwFrame* _pFrame, SwPageFrame* _pPage )
2893 OSL_ENSURE( _pFrame->GetDrawObjs(), "no DrawObjs in lcl_AddObjsToPage." );
2894 SwSortedObjs &rObjs = *_pFrame->GetDrawObjs();
2895 for (SwAnchoredObject* pObj : rObjs)
2897 // #115759# - unlock position of anchored object
2898 // in order to get the object's position calculated.
2899 pObj->UnlockPosition();
2900 // #115759# - add also lower objects of as-character
2901 // anchored Writer fly frames from page
2902 if ( dynamic_cast<const SwFlyFrame*>( pObj) != nullptr )
2904 SwFlyFrame* pFlyFrame = static_cast<SwFlyFrame*>(pObj);
2905 if ( dynamic_cast<const SwFlyFreeFrame*>( pObj) != nullptr )
2907 _pPage->AppendFlyToPage( pFlyFrame );
2909 pFlyFrame->InvalidatePos_();
2910 pFlyFrame->InvalidateSize_();
2911 pFlyFrame->InvalidatePage( _pPage );
2913 // #115759# - add also at-fly anchored objects
2914 // to page
2915 if ( pFlyFrame->GetDrawObjs() )
2917 ::lcl_AddObjsToPage( pFlyFrame, _pPage );
2920 SwContentFrame *pCnt = pFlyFrame->ContainsContent();
2921 while ( pCnt )
2923 if ( pCnt->GetDrawObjs() )
2924 ::lcl_AddObjsToPage( pCnt, _pPage );
2925 pCnt = pCnt->GetNextContentFrame();
2928 // #115759# - remove also drawing objects from page
2929 else if ( dynamic_cast<const SwAnchoredDrawObject*>( pObj) != nullptr )
2931 if (pObj->GetFrameFormat().GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR)
2933 pObj->InvalidateObjPos();
2934 _pPage->AppendDrawObjToPage(
2935 *static_cast<SwAnchoredDrawObject*>(pObj) );
2941 void RestoreContent( SwFrame *pSav, SwLayoutFrame *pParent, SwFrame *pSibling )
2943 OSL_ENSURE( pSav && pParent, "no Save or Parent provided for RestoreContent." );
2944 SwRectFnSet aRectFnSet(pParent);
2946 // If there are already FlowFrames below the new parent, so add the chain (starting with pSav)
2947 // after the last one. The parts are inserted and invalidated if needed.
2948 // On the way, the Flys of the ContentFrames are registered at the page.
2950 SwPageFrame *pPage = pParent->FindPageFrame();
2952 if ( pPage )
2953 pPage->InvalidatePage( pPage );
2955 // determine predecessor and establish connection or initialize
2956 pSav->mpPrev = pSibling;
2957 SwFrame* pNxt;
2958 if ( pSibling )
2960 pNxt = pSibling->mpNext;
2961 pSibling->mpNext = pSav;
2962 pSibling->InvalidatePrt_();
2963 pSibling->InvalidatePage( pPage );
2964 SwFlowFrame *pFlowFrame = dynamic_cast<SwFlowFrame*>(pSibling);
2965 if (pFlowFrame && pFlowFrame->GetFollow())
2966 pSibling->Prepare( PREP_CLEAR, nullptr, false );
2968 else
2969 { pNxt = pParent->m_pLower;
2970 pParent->m_pLower = pSav;
2971 pSav->mpUpper = pParent; // set here already, so that it is explicit when invalidating
2973 if ( pSav->IsContentFrame() )
2974 static_cast<SwContentFrame*>(pSav)->InvalidatePage( pPage );
2975 else
2976 { // pSav might be an empty SectFrame
2977 SwContentFrame* pCnt = pParent->ContainsContent();
2978 if( pCnt )
2979 pCnt->InvalidatePage( pPage );
2983 // the parent needs to grow appropriately
2984 SwTwips nGrowVal = 0;
2985 SwFrame* pLast;
2987 { pSav->mpUpper = pParent;
2988 nGrowVal += aRectFnSet.GetHeight(pSav->getFrameArea());
2989 pSav->InvalidateAll_();
2991 // register Flys, if TextFrames than also invalidate appropriately
2992 if ( pSav->IsContentFrame() )
2994 if ( pSav->IsTextFrame() &&
2995 static_cast<SwTextFrame*>(pSav)->GetCacheIdx() != USHRT_MAX )
2996 static_cast<SwTextFrame*>(pSav)->Init(); // I am its friend
2998 if ( pPage && pSav->GetDrawObjs() )
2999 ::lcl_AddObjsToPage( static_cast<SwContentFrame*>(pSav), pPage );
3001 else
3002 { SwContentFrame *pBlub = static_cast<SwLayoutFrame*>(pSav)->ContainsContent();
3003 if( pBlub )
3006 { if ( pPage && pBlub->GetDrawObjs() )
3007 ::lcl_AddObjsToPage( pBlub, pPage );
3008 if( pBlub->IsTextFrame() && static_cast<SwTextFrame*>(pBlub)->HasFootnote() &&
3009 static_cast<SwTextFrame*>(pBlub)->GetCacheIdx() != USHRT_MAX )
3010 static_cast<SwTextFrame*>(pBlub)->Init(); // I am its friend
3011 pBlub = pBlub->GetNextContentFrame();
3012 } while ( pBlub && static_cast<SwLayoutFrame*>(pSav)->IsAnLower( pBlub ));
3015 pLast = pSav;
3016 pSav = pSav->GetNext();
3018 } while ( pSav );
3020 if( pNxt )
3022 pLast->mpNext = pNxt;
3023 pNxt->mpPrev = pLast;
3026 pParent->Grow( nGrowVal );
3029 namespace sw {
3031 bool IsRightPageByNumber(SwRootFrame const& rLayout, sal_uInt16 const nPageNum)
3033 assert(rLayout.GetLower());
3034 // unfortunately can only get SwPageDesc, not SwFormatPageDesc here...
3035 auto const nFirstVirtPageNum(rLayout.GetLower()->GetVirtPageNum());
3036 bool const isFirstPageOfLayoutOdd(nFirstVirtPageNum % 2 == 1);
3037 return ((nPageNum % 2) == 1) == isFirstPageOfLayoutOdd;
3040 } // namespace sw
3042 SwPageFrame * InsertNewPage( SwPageDesc &rDesc, SwFrame *pUpper,
3043 bool const isRightPage, bool const bFirst, bool bInsertEmpty,
3044 bool const bFootnote,
3045 SwFrame *pSibling )
3047 assert(pUpper);
3048 assert(pUpper->IsRootFrame());
3049 assert(!pSibling || static_cast<SwLayoutFrame const*>(pUpper)->Lower() != pSibling); // currently no insert before 1st page
3050 SwPageFrame *pRet;
3051 SwDoc *pDoc = static_cast<SwLayoutFrame*>(pUpper)->GetFormat()->GetDoc();
3052 if (bFirst)
3054 if (rDesc.IsFirstShared())
3056 // We need to fallback to left or right page format, decide it now.
3057 // FIXME: is this still needed?
3058 if (isRightPage)
3060 rDesc.GetFirstMaster().SetFormatAttr( rDesc.GetMaster().GetHeader() );
3061 rDesc.GetFirstMaster().SetFormatAttr( rDesc.GetMaster().GetFooter() );
3062 // fdo#60250 copy margins for mirrored pages
3063 rDesc.GetFirstMaster().SetFormatAttr( rDesc.GetMaster().GetLRSpace() );
3065 else
3067 rDesc.GetFirstLeft().SetFormatAttr( rDesc.GetLeft().GetHeader() );
3068 rDesc.GetFirstLeft().SetFormatAttr( rDesc.GetLeft().GetFooter() );
3069 rDesc.GetFirstLeft().SetFormatAttr( rDesc.GetLeft().GetLRSpace() );
3073 SwFrameFormat *pFormat(isRightPage ? rDesc.GetRightFormat(bFirst) : rDesc.GetLeftFormat(bFirst));
3074 // If there is no FrameFormat for this page, add an empty page
3075 if ( !pFormat )
3077 pFormat = isRightPage ? rDesc.GetLeftFormat() : rDesc.GetRightFormat();
3078 OSL_ENSURE( pFormat, "Descriptor without any format?!" );
3079 bInsertEmpty = !bInsertEmpty;
3081 if( bInsertEmpty )
3083 SwPageDesc *pTmpDesc = pSibling && pSibling->GetPrev() ?
3084 static_cast<SwPageFrame*>(pSibling->GetPrev())->GetPageDesc() : &rDesc;
3085 pRet = new SwPageFrame( pDoc->GetEmptyPageFormat(), pUpper, pTmpDesc );
3086 SAL_INFO( "sw.pageframe", "InsertNewPage - insert empty p: " << pRet << " d: " << pTmpDesc );
3087 pRet->Paste( pUpper, pSibling );
3088 pRet->PreparePage( bFootnote );
3090 pRet = new SwPageFrame( pFormat, pUpper, &rDesc );
3091 SAL_INFO( "sw.pageframe", "InsertNewPage p: " << pRet << " d: " << &rDesc << " f: " << pFormat );
3092 pRet->Paste( pUpper, pSibling );
3093 pRet->PreparePage( bFootnote );
3094 if ( pRet->GetNext() )
3095 SwRootFrame::AssertPageFlys( pRet );
3096 return pRet;
3099 /* The following two methods search the layout structure recursively and
3100 * register all Flys at the page that have a Frame in this structure as an anchor.
3103 static void lcl_Regist( SwPageFrame *pPage, const SwFrame *pAnch )
3105 SwSortedObjs *pObjs = const_cast<SwSortedObjs*>(pAnch->GetDrawObjs());
3106 for (SwAnchoredObject* pObj : *pObjs)
3108 if ( dynamic_cast<const SwFlyFrame*>( pObj) != nullptr )
3110 SwFlyFrame *pFly = static_cast<SwFlyFrame*>(pObj);
3111 // register (not if already known)
3112 // #i28701# - use new method <GetPageFrame()>
3113 SwPageFrame *pPg = pFly->IsFlyFreeFrame()
3114 ? pFly->GetPageFrame() : pFly->FindPageFrame();
3115 if ( pPg != pPage )
3117 if ( pPg )
3118 pPg->RemoveFlyFromPage( pFly );
3119 pPage->AppendFlyToPage( pFly );
3121 ::RegistFlys( pPage, pFly );
3123 else
3125 // #i87493#
3126 if ( pPage != pObj->GetPageFrame() )
3128 // #i28701#
3129 if (SwPageFrame *pPg = pObj->GetPageFrame())
3130 pPg->RemoveDrawObjFromPage( *pObj );
3131 pPage->AppendDrawObjToPage( *pObj );
3135 const SwFlyFrame* pFly = pAnch->FindFlyFrame();
3136 if ( pFly &&
3137 pObj->GetDrawObj()->GetOrdNum() < pFly->GetVirtDrawObj()->GetOrdNum() &&
3138 pObj->GetDrawObj()->getSdrPageFromSdrObject() )
3140 //#i119945# set pFly's OrdNum to pObj's. So when pFly is removed by Undo, the original OrdNum will not be changed.
3141 pObj->DrawObj()->getSdrPageFromSdrObject()->SetObjectOrdNum( pFly->GetVirtDrawObj()->GetOrdNumDirect(),
3142 pObj->GetDrawObj()->GetOrdNumDirect() );
3147 void RegistFlys( SwPageFrame *pPage, const SwLayoutFrame *pLay )
3149 if ( pLay->GetDrawObjs() )
3150 ::lcl_Regist( pPage, pLay );
3151 const SwFrame *pFrame = pLay->Lower();
3152 while ( pFrame )
3154 if ( pFrame->IsLayoutFrame() )
3155 ::RegistFlys( pPage, static_cast<const SwLayoutFrame*>(pFrame) );
3156 else if ( pFrame->GetDrawObjs() )
3157 ::lcl_Regist( pPage, pFrame );
3158 pFrame = pFrame->GetNext();
3162 /// Notify the background based on the difference between old and new rectangle
3163 void Notify( SwFlyFrame *pFly, SwPageFrame *pOld, const SwRect &rOld,
3164 const SwRect* pOldPrt )
3166 const SwRect aFrame( pFly->GetObjRectWithSpaces() );
3167 if ( rOld.Pos() != aFrame.Pos() )
3168 { // changed position, invalidate old and new area
3169 if ( rOld.HasArea() &&
3170 rOld.Left()+pFly->GetFormat()->GetLRSpace().GetLeft() < FAR_AWAY )
3172 pFly->NotifyBackground( pOld, rOld, PREP_FLY_LEAVE );
3174 pFly->NotifyBackground( pFly->FindPageFrame(), aFrame, PREP_FLY_ARRIVE );
3176 else if ( rOld.SSize() != aFrame.SSize() )
3177 { // changed size, invalidate the area that was left or is now overlapped
3178 // For simplicity, we purposely invalidate a Twip even if not needed.
3180 SwViewShell *pSh = pFly->getRootFrame()->GetCurrShell();
3181 if( pSh && rOld.HasArea() )
3182 pSh->InvalidateWindows( rOld );
3184 // #i51941# - consider case that fly frame isn't
3185 // registered at the old page <pOld>
3186 SwPageFrame* pPageFrame = pFly->FindPageFrame();
3187 if ( pOld != pPageFrame )
3189 pFly->NotifyBackground( pPageFrame, aFrame, PREP_FLY_ARRIVE );
3192 if ( rOld.Left() != aFrame.Left() )
3194 SwRect aTmp( rOld );
3195 aTmp.Union( aFrame );
3196 aTmp.Left( std::min(aFrame.Left(), rOld.Left()) );
3197 aTmp.Right( std::max(aFrame.Left(), rOld.Left()) );
3198 pFly->NotifyBackground( pOld, aTmp, PREP_FLY_CHGD );
3200 SwTwips nOld = rOld.Right();
3201 SwTwips nNew = aFrame.Right();
3202 if ( nOld != nNew )
3204 SwRect aTmp( rOld );
3205 aTmp.Union( aFrame );
3206 aTmp.Left( std::min(nNew, nOld) );
3207 aTmp.Right( std::max(nNew, nOld) );
3208 pFly->NotifyBackground( pOld, aTmp, PREP_FLY_CHGD );
3210 if ( rOld.Top() != aFrame.Top() )
3212 SwRect aTmp( rOld );
3213 aTmp.Union( aFrame );
3214 aTmp.Top( std::min(aFrame.Top(), rOld.Top()) );
3215 aTmp.Bottom( std::max(aFrame.Top(), rOld.Top()) );
3216 pFly->NotifyBackground( pOld, aTmp, PREP_FLY_CHGD );
3218 nOld = rOld.Bottom();
3219 nNew = aFrame.Bottom();
3220 if ( nOld != nNew )
3222 SwRect aTmp( rOld );
3223 aTmp.Union( aFrame );
3224 aTmp.Top( std::min(nNew, nOld) );
3225 aTmp.Bottom( std::max(nNew, nOld) );
3226 pFly->NotifyBackground( pOld, aTmp, PREP_FLY_CHGD );
3229 else if(pOldPrt && *pOldPrt != pFly->getFramePrintArea())
3231 bool bNotifyBackground(pFly->GetFormat()->GetSurround().IsContour());
3233 if(!bNotifyBackground &&
3234 pFly->IsFlyFreeFrame() &&
3235 static_cast< const SwFlyFreeFrame* >(pFly)->supportsAutoContour())
3237 // RotateFlyFrame3: Also notify for FlyFrames which allow AutoContour
3238 bNotifyBackground = true;
3241 if(bNotifyBackground)
3243 // #i24097#
3244 pFly->NotifyBackground( pFly->FindPageFrame(), aFrame, PREP_FLY_ARRIVE );
3249 static void lcl_CheckFlowBack( SwFrame* pFrame, const SwRect &rRect )
3251 SwTwips nBottom = rRect.Bottom();
3252 while( pFrame )
3254 if( pFrame->IsLayoutFrame() )
3256 if( rRect.IsOver( pFrame->getFrameArea() ) )
3257 lcl_CheckFlowBack( static_cast<SwLayoutFrame*>(pFrame)->Lower(), rRect );
3259 else if( !pFrame->GetNext() && nBottom > pFrame->getFrameArea().Bottom() )
3261 if( pFrame->IsContentFrame() && static_cast<SwContentFrame*>(pFrame)->HasFollow() )
3262 pFrame->InvalidateSize();
3263 else
3264 pFrame->InvalidateNextPos();
3266 pFrame = pFrame->GetNext();
3270 static void lcl_NotifyContent( const SdrObject *pThis, SwContentFrame *pCnt,
3271 const SwRect &rRect, const PrepareHint eHint )
3273 if ( pCnt->IsTextFrame() )
3275 SwRect aCntPrt( pCnt->getFramePrintArea() );
3276 aCntPrt.Pos() += pCnt->getFrameArea().Pos();
3277 if ( eHint == PREP_FLY_ATTR_CHG )
3279 // #i35640# - use given rectangle <rRect> instead
3280 // of current bound rectangle
3281 if ( aCntPrt.IsOver( rRect ) )
3282 pCnt->Prepare( PREP_FLY_ATTR_CHG );
3284 // #i23129# - only invalidate, if the text frame
3285 // printing area overlaps with the given rectangle.
3286 else if ( aCntPrt.IsOver( rRect ) )
3287 pCnt->Prepare( eHint, static_cast<void*>(&aCntPrt.Intersection_( rRect )) );
3288 if ( pCnt->GetDrawObjs() )
3290 const SwSortedObjs &rObjs = *pCnt->GetDrawObjs();
3291 for (SwAnchoredObject* pObj : rObjs)
3293 if ( dynamic_cast<const SwFlyFrame*>( pObj) != nullptr )
3295 SwFlyFrame *pFly = static_cast<SwFlyFrame*>(pObj);
3296 if ( pFly->IsFlyInContentFrame() )
3298 SwContentFrame *pContent = pFly->ContainsContent();
3299 while ( pContent )
3301 ::lcl_NotifyContent( pThis, pContent, rRect, eHint );
3302 pContent = pContent->GetNextContentFrame();
3311 void Notify_Background( const SdrObject* pObj,
3312 SwPageFrame* pPage,
3313 const SwRect& rRect,
3314 const PrepareHint eHint,
3315 const bool bInva )
3317 // If the frame was positioned correctly for the first time, do not inform the old area
3318 if ( eHint == PREP_FLY_LEAVE && rRect.Top() == FAR_AWAY )
3319 return;
3321 SwLayoutFrame* pArea;
3322 SwFlyFrame *pFlyFrame = nullptr;
3323 SwFrame* pAnchor;
3324 if( auto pVirtFlyDrawObj = dynamic_cast<const SwVirtFlyDrawObj*>( pObj) )
3326 pFlyFrame = const_cast<SwVirtFlyDrawObj*>(pVirtFlyDrawObj)->GetFlyFrame();
3327 pAnchor = pFlyFrame->AnchorFrame();
3329 else
3331 pFlyFrame = nullptr;
3332 pAnchor = const_cast<SwFrame*>(
3333 GetUserCall(pObj)->GetAnchoredObj( pObj )->GetAnchorFrame() );
3335 if( PREP_FLY_LEAVE != eHint && pAnchor->IsInFly() )
3336 pArea = pAnchor->FindFlyFrame();
3337 else
3338 pArea = pPage;
3339 SwContentFrame *pCnt = nullptr;
3340 if ( pArea )
3342 if( PREP_FLY_ARRIVE != eHint )
3343 lcl_CheckFlowBack( pArea, rRect );
3345 // Only the Flys following this anchor are reacting. Thus, those do not
3346 // need to be processed.
3347 // An exception is LEAVE, since the Fly might come "from above".
3348 // If the anchor is positioned on the previous page, the whole page
3349 // needs to be processed (47722).
3350 // OD 2004-05-13 #i28701# - If the wrapping style has to be considered
3351 // on the object positioning, the complete area has to be processed,
3352 // because content frames before the anchor frame also have to consider
3353 // the object for the text wrapping.
3354 // #i3317# - The complete area has always been
3355 // processed.
3357 pCnt = pArea->ContainsContent();
3360 SwFrame *pLastTab = nullptr;
3362 bool isValidTableBeforeAnchor(false);
3363 while ( pCnt && pArea && pArea->IsAnLower( pCnt ) )
3365 ::lcl_NotifyContent( pObj, pCnt, rRect, eHint );
3366 if ( pCnt->IsInTab() )
3368 SwTabFrame *pTab = pCnt->FindTabFrame();
3369 if ( pTab != pLastTab )
3371 pLastTab = pTab;
3372 isValidTableBeforeAnchor = false;
3373 if (PREP_FLY_ARRIVE == eHint
3374 && pFlyFrame // TODO: do it for draw objects too?
3375 && pTab->IsFollow() // table starts on previous page?
3376 // "through" means they will actually overlap anyway
3377 && css::text::WrapTextMode_THROUGH != pFlyFrame->GetFormat()->GetSurround().GetSurround()
3378 // if it's anchored in footer it can't move to other page
3379 && !pAnchor->FindFooterOrHeader())
3381 SwFrame * pTmp(pAnchor->GetPrev());
3382 while (pTmp)
3384 if (pTmp == pTab)
3386 // tdf#99460 the table shouldn't be moved by the fly
3387 isValidTableBeforeAnchor = true;
3388 break;
3390 pTmp = pTmp->GetPrev();
3393 // #i40606# - use <GetLastBoundRect()>
3394 // instead of <GetCurrentBoundRect()>, because a recalculation
3395 // of the bounding rectangle isn't intended here.
3396 if (!isValidTableBeforeAnchor
3397 && (pTab->getFrameArea().IsOver(pObj->GetLastBoundRect()) ||
3398 pTab->getFrameArea().IsOver(rRect)))
3400 if ( !pFlyFrame || !pFlyFrame->IsLowerOf( pTab ) )
3401 pTab->InvalidatePrt();
3404 SwLayoutFrame* pCell = pCnt->GetUpper();
3405 // #i40606# - use <GetLastBoundRect()>
3406 // instead of <GetCurrentBoundRect()>, because a recalculation
3407 // of the bounding rectangle isn't intended here.
3408 if (!isValidTableBeforeAnchor && pCell->IsCellFrame() &&
3409 ( pCell->getFrameArea().IsOver( pObj->GetLastBoundRect() ) ||
3410 pCell->getFrameArea().IsOver( rRect ) ) )
3412 const SwFormatVertOrient &rOri = pCell->GetFormat()->GetVertOrient();
3413 if ( text::VertOrientation::NONE != rOri.GetVertOrient() )
3414 pCell->InvalidatePrt();
3417 pCnt = pCnt->GetNextContentFrame();
3419 // #128702# - make code robust
3420 if ( pPage && pPage->GetSortedObjs() )
3422 pObj->GetOrdNum();
3423 const SwSortedObjs &rObjs = *pPage->GetSortedObjs();
3424 for (SwAnchoredObject* pAnchoredObj : rObjs)
3426 if ( dynamic_cast<const SwFlyFrame*>( pAnchoredObj) != nullptr )
3428 if( pAnchoredObj->GetDrawObj() == pObj )
3429 continue;
3430 SwFlyFrame *pFly = static_cast<SwFlyFrame*>(pAnchoredObj);
3431 if ( pFly->getFrameArea().Top() == FAR_AWAY )
3432 continue;
3434 if ( !pFlyFrame ||
3435 (!pFly->IsLowerOf( pFlyFrame ) &&
3436 pFly->GetVirtDrawObj()->GetOrdNumDirect() < pObj->GetOrdNumDirect()))
3438 pCnt = pFly->ContainsContent();
3439 while ( pCnt )
3441 ::lcl_NotifyContent( pObj, pCnt, rRect, eHint );
3442 pCnt = pCnt->GetNextContentFrame();
3445 if( pFly->IsFlyLayFrame() )
3447 if( pFly->Lower() && pFly->Lower()->IsColumnFrame() &&
3448 pFly->getFrameArea().Bottom() >= rRect.Top() &&
3449 pFly->getFrameArea().Top() <= rRect.Bottom() &&
3450 pFly->getFrameArea().Right() >= rRect.Left() &&
3451 pFly->getFrameArea().Left() <= rRect.Right() )
3453 pFly->InvalidateSize();
3456 // Flys above myself might sidestep if they have an automatic
3457 // alignment. This happens independently of my attributes since
3458 // this might have been changed as well.
3459 else if ( pFly->IsFlyAtContentFrame() &&
3460 pObj->GetOrdNumDirect() <
3461 pFly->GetVirtDrawObj()->GetOrdNumDirect() &&
3462 pFlyFrame && !pFly->IsLowerOf( pFlyFrame ) )
3464 const SwFormatHoriOrient &rH = pFly->GetFormat()->GetHoriOrient();
3465 if ( text::HoriOrientation::NONE != rH.GetHoriOrient() &&
3466 text::HoriOrientation::CENTER != rH.GetHoriOrient() &&
3467 ( !pFly->IsAutoPos() || text::RelOrientation::CHAR != rH.GetRelationOrient() ) &&
3468 (pFly->getFrameArea().Bottom() >= rRect.Top() &&
3469 pFly->getFrameArea().Top() <= rRect.Bottom()) )
3470 pFly->InvalidatePos();
3475 if ( pFlyFrame && pAnchor->GetUpper() && pAnchor->IsInTab() )//MA_FLY_HEIGHT
3476 pAnchor->GetUpper()->InvalidateSize();
3478 // #i82258# - make code robust
3479 SwViewShell* pSh = nullptr;
3480 if ( bInva && pPage &&
3481 nullptr != (pSh = pPage->getRootFrame()->GetCurrShell()) )
3483 pSh->InvalidateWindows( rRect );
3487 /// Provides the Upper of an anchor in paragraph-bound objects. If the latter
3488 /// is a chained border or a footnote, the "virtual" Upper might be returned.
3489 const SwFrame* GetVirtualUpper( const SwFrame* pFrame, const Point& rPos )
3491 if( pFrame->IsTextFrame() )
3493 pFrame = pFrame->GetUpper();
3494 if( !pFrame->getFrameArea().IsInside( rPos ) )
3496 if( pFrame->IsFootnoteFrame() )
3498 const SwFootnoteFrame* pTmp = static_cast<const SwFootnoteFrame*>(pFrame)->GetFollow();
3499 while( pTmp )
3501 if( pTmp->getFrameArea().IsInside( rPos ) )
3502 return pTmp;
3503 pTmp = pTmp->GetFollow();
3506 else
3508 SwFlyFrame* pTmp = const_cast<SwFlyFrame*>(pFrame->FindFlyFrame());
3509 while( pTmp )
3511 if( pTmp->getFrameArea().IsInside( rPos ) )
3512 return pTmp;
3513 pTmp = pTmp->GetNextLink();
3518 return pFrame;
3521 bool Is_Lower_Of(const SwFrame *pCurrFrame, const SdrObject* pObj)
3523 Point aPos;
3524 const SwFrame* pFrame;
3525 if (const SwVirtFlyDrawObj *pFlyDrawObj = dynamic_cast<const SwVirtFlyDrawObj*>(pObj))
3527 const SwFlyFrame* pFly = pFlyDrawObj->GetFlyFrame();
3528 pFrame = pFly->GetAnchorFrame();
3529 aPos = pFly->getFrameArea().Pos();
3531 else
3533 pFrame = static_cast<SwDrawContact*>(GetUserCall(pObj))->GetAnchorFrame(pObj);
3534 aPos = pObj->GetCurrentBoundRect().TopLeft();
3536 OSL_ENSURE( pFrame, "8-( Fly is lost in Space." );
3537 pFrame = GetVirtualUpper( pFrame, aPos );
3539 { if ( pFrame == pCurrFrame )
3540 return true;
3541 if( pFrame->IsFlyFrame() )
3543 aPos = pFrame->getFrameArea().Pos();
3544 pFrame = GetVirtualUpper( static_cast<const SwFlyFrame*>(pFrame)->GetAnchorFrame(), aPos );
3546 else
3547 pFrame = pFrame->GetUpper();
3548 } while ( pFrame );
3549 return false;
3552 /// provides the area of a frame in that no Fly from another area can overlap
3553 const SwFrame *FindContext( const SwFrame *pFrame, SwFrameType nAdditionalContextType )
3555 const SwFrameType nTyp = SwFrameType::Root | SwFrameType::Header | SwFrameType::Footer | SwFrameType::FtnCont |
3556 SwFrameType::Ftn | SwFrameType::Fly |
3557 SwFrameType::Tab | SwFrameType::Row | SwFrameType::Cell |
3558 nAdditionalContextType;
3560 { if ( pFrame->GetType() & nTyp )
3561 break;
3562 pFrame = pFrame->GetUpper();
3563 } while( pFrame );
3564 return pFrame;
3567 bool IsFrameInSameContext( const SwFrame *pInnerFrame, const SwFrame *pFrame )
3569 const SwFrame *pContext = FindContext( pInnerFrame, SwFrameType::None );
3571 const SwFrameType nTyp = SwFrameType::Root | SwFrameType::Header | SwFrameType::Footer | SwFrameType::FtnCont |
3572 SwFrameType::Ftn | SwFrameType::Fly |
3573 SwFrameType::Tab | SwFrameType::Row | SwFrameType::Cell;
3575 { if ( pFrame->GetType() & nTyp )
3577 if( pFrame == pContext )
3578 return true;
3579 if( pFrame->IsCellFrame() )
3580 return false;
3582 if( pFrame->IsFlyFrame() )
3584 Point aPos( pFrame->getFrameArea().Pos() );
3585 pFrame = GetVirtualUpper( static_cast<const SwFlyFrame*>(pFrame)->GetAnchorFrame(), aPos );
3587 else
3588 pFrame = pFrame->GetUpper();
3589 } while( pFrame );
3591 return false;
3594 static SwTwips lcl_CalcCellRstHeight( SwLayoutFrame *pCell )
3596 SwFrame *pLow = pCell->Lower();
3597 if ( pLow && (pLow->IsContentFrame() || pLow->IsSctFrame()) )
3599 long nHeight = 0, nFlyAdd = 0;
3602 long nLow = pLow->getFrameArea().Height();
3603 if( pLow->IsTextFrame() && static_cast<SwTextFrame*>(pLow)->IsUndersized() )
3604 nLow += static_cast<SwTextFrame*>(pLow)->GetParHeight()-pLow->getFramePrintArea().Height();
3605 else if( pLow->IsSctFrame() && static_cast<SwSectionFrame*>(pLow)->IsUndersized() )
3606 nLow += static_cast<SwSectionFrame*>(pLow)->Undersize();
3607 nFlyAdd = std::max( 0L, nFlyAdd - nLow );
3608 nFlyAdd = std::max( nFlyAdd, ::CalcHeightWithFlys( pLow ) );
3609 nHeight += nLow;
3610 pLow = pLow->GetNext();
3611 } while ( pLow );
3612 if ( nFlyAdd )
3613 nHeight += nFlyAdd;
3615 // The border cannot be calculated based on PrtArea and Frame, since both can be invalid.
3616 SwBorderAttrAccess aAccess( SwFrame::GetCache(), pCell );
3617 const SwBorderAttrs &rAttrs = *aAccess.Get();
3618 nHeight += rAttrs.CalcTop() + rAttrs.CalcBottom();
3620 return pCell->getFrameArea().Height() - nHeight;
3622 else
3624 long nRstHeight = 0;
3625 while (pLow && pLow->IsLayoutFrame())
3627 nRstHeight += ::CalcRowRstHeight(static_cast<SwLayoutFrame*>(pLow));
3628 pLow = pLow->GetNext();
3630 return nRstHeight;
3634 SwTwips CalcRowRstHeight( SwLayoutFrame *pRow )
3636 SwFrame *pLow = pRow->Lower();
3637 if (!(pLow && pLow->IsLayoutFrame()))
3639 return 0;
3641 SwTwips nRstHeight = LONG_MAX;
3642 while (pLow && pLow->IsLayoutFrame())
3644 nRstHeight = std::min(nRstHeight, ::lcl_CalcCellRstHeight(static_cast<SwLayoutFrame*>(pLow)));
3645 pLow = pLow->GetNext();
3647 return nRstHeight;
3650 const SwFrame* FindPage( const SwRect &rRect, const SwFrame *pPage )
3652 if ( !rRect.IsOver( pPage->getFrameArea() ) )
3654 const SwRootFrame* pRootFrame = static_cast<const SwRootFrame*>(pPage->GetUpper());
3655 const SwFrame* pTmpPage = pRootFrame ? pRootFrame->GetPageAtPos( rRect.TopLeft(), &rRect.SSize(), true ) : nullptr;
3656 if ( pTmpPage )
3657 pPage = pTmpPage;
3660 return pPage;
3663 class SwFrameHolder : private SfxListener
3665 SwFrame* pFrame;
3666 bool bSet;
3667 virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
3668 public:
3669 SwFrameHolder() : pFrame(nullptr), bSet(false) {}
3670 void SetFrame( SwFrame* pHold );
3671 SwFrame* GetFrame() { return pFrame; }
3672 void Reset();
3673 bool IsSet() const { return bSet; }
3676 void SwFrameHolder::SetFrame( SwFrame* pHold )
3678 bSet = true;
3679 if (pFrame != pHold)
3681 if (pFrame)
3682 EndListening(*pFrame);
3683 StartListening(*pHold);
3684 pFrame = pHold;
3688 void SwFrameHolder::Reset()
3690 if (pFrame)
3691 EndListening(*pFrame);
3692 bSet = false;
3693 pFrame = nullptr;
3696 void SwFrameHolder::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
3698 if ( rHint.GetId() == SfxHintId::Dying && &rBC == pFrame )
3700 pFrame = nullptr;
3704 SwFrame* GetFrameOfModify(SwRootFrame const*const pLayout, SwModify const& rMod,
3705 SwFrameType const nFrameType, SwPosition const*const pPos,
3706 std::pair<Point, bool> const*const pViewPosAndCalcFrame)
3708 SwFrame *pMinFrame = nullptr, *pTmpFrame;
3709 SwFrameHolder aHolder;
3710 SwRect aCalcRect;
3711 bool bClientIterChanged = false;
3713 SwIterator<SwFrame, SwModify, sw::IteratorMode::UnwrapMulti> aIter(rMod);
3714 do {
3715 pMinFrame = nullptr;
3716 aHolder.Reset();
3717 sal_uInt64 nMinDist = 0;
3718 bClientIterChanged = false;
3720 for( pTmpFrame = aIter.First(); pTmpFrame; pTmpFrame = aIter.Next() )
3722 if( pTmpFrame->GetType() & nFrameType &&
3723 ( !pLayout || pLayout == pTmpFrame->getRootFrame() ) &&
3724 (!pTmpFrame->IsFlowFrame() ||
3725 !SwFlowFrame::CastFlowFrame( pTmpFrame )->IsFollow() ))
3727 if (pViewPosAndCalcFrame)
3729 // watch for Frame being deleted
3730 if ( pMinFrame )
3731 aHolder.SetFrame( pMinFrame );
3732 else
3733 aHolder.Reset();
3735 if (pViewPosAndCalcFrame->second)
3737 // tdf#108118 prevent recursion
3738 DisableCallbackAction a(*pTmpFrame->getRootFrame());
3739 // - format parent Writer
3740 // fly frame, if it isn't been formatted yet.
3741 // Note: The Writer fly frame could be the frame itself.
3742 SwFlyFrame* pFlyFrame( pTmpFrame->FindFlyFrame() );
3743 if ( pFlyFrame &&
3744 pFlyFrame->getFrameArea().Pos().X() == FAR_AWAY &&
3745 pFlyFrame->getFrameArea().Pos().Y() == FAR_AWAY )
3747 SwObjectFormatter::FormatObj( *pFlyFrame );
3749 pTmpFrame->Calc(pLayout ? pLayout->GetCurrShell()->GetOut() : nullptr);
3752 // aIter.IsChanged checks if the current pTmpFrame has been deleted while
3753 // it is the current iterator
3754 // FrameHolder watches for deletion of the current pMinFrame
3755 if( aIter.IsChanged() || ( aHolder.IsSet() && !aHolder.GetFrame() ) )
3757 // restart iteration
3758 bClientIterChanged = true;
3759 break;
3762 // for Flys go via the parent if the Fly is not yet "formatted"
3763 if (!pViewPosAndCalcFrame->second &&
3764 pTmpFrame->GetType() & SwFrameType::Fly &&
3765 static_cast<SwFlyFrame*>(pTmpFrame)->GetAnchorFrame() &&
3766 FAR_AWAY == pTmpFrame->getFrameArea().Pos().getX() &&
3767 FAR_AWAY == pTmpFrame->getFrameArea().Pos().getY() )
3768 aCalcRect = static_cast<SwFlyFrame*>(pTmpFrame)->GetAnchorFrame()->getFrameArea();
3769 else
3770 aCalcRect = pTmpFrame->getFrameArea();
3772 if (aCalcRect.IsInside(pViewPosAndCalcFrame->first))
3774 pMinFrame = pTmpFrame;
3775 break;
3778 // Point not in rectangle. Compare distances:
3779 const Point aCalcRectCenter = aCalcRect.Center();
3780 const Point aDiff = aCalcRectCenter - pViewPosAndCalcFrame->first;
3781 const sal_uInt64 nCurrentDist = sal_Int64(aDiff.getX()) * sal_Int64(aDiff.getX()) + sal_Int64(aDiff.getY()) * sal_Int64(aDiff.getY()); // opt: no sqrt
3782 if ( !pMinFrame || nCurrentDist < nMinDist )
3784 pMinFrame = pTmpFrame;
3785 nMinDist = nCurrentDist;
3788 else
3790 // if no pViewPosAndCalcFrame is provided, take the first one
3791 pMinFrame = pTmpFrame;
3792 break;
3796 } while( bClientIterChanged );
3798 if( pPos && pMinFrame && pMinFrame->IsTextFrame() )
3799 return static_cast<SwTextFrame*>(pMinFrame)->GetFrameAtPos( *pPos );
3801 return pMinFrame;
3804 bool IsExtraData( const SwDoc *pDoc )
3806 const SwLineNumberInfo &rInf = pDoc->GetLineNumberInfo();
3807 return rInf.IsPaintLineNumbers() ||
3808 rInf.IsCountInFlys() ||
3809 (static_cast<sal_Int16>(SW_MOD()->GetRedlineMarkPos()) != text::HoriOrientation::NONE &&
3810 !pDoc->getIDocumentRedlineAccess().GetRedlineTable().empty());
3813 // OD 22.09.2003 #110978#
3814 SwRect SwPageFrame::PrtWithoutHeaderAndFooter() const
3816 SwRect aPrtWithoutHeaderFooter( getFramePrintArea() );
3817 aPrtWithoutHeaderFooter.Pos() += getFrameArea().Pos();
3819 const SwFrame* pLowerFrame = Lower();
3820 while ( pLowerFrame )
3822 // Note: independent on text direction page header and page footer are
3823 // always at top respectively at bottom of the page frame.
3824 if ( pLowerFrame->IsHeaderFrame() )
3826 aPrtWithoutHeaderFooter.Top( aPrtWithoutHeaderFooter.Top() +
3827 pLowerFrame->getFrameArea().Height() );
3829 if ( pLowerFrame->IsFooterFrame() )
3831 aPrtWithoutHeaderFooter.Bottom( aPrtWithoutHeaderFooter.Bottom() -
3832 pLowerFrame->getFrameArea().Height() );
3835 pLowerFrame = pLowerFrame->GetNext();
3838 return aPrtWithoutHeaderFooter;
3841 /** method to determine the spacing values of a frame
3843 OD 2004-03-10 #i28701#
3844 OD 2009-08-28 #i102458#
3845 Add output parameter <obIsLineSpacingProportional>
3847 void GetSpacingValuesOfFrame( const SwFrame& rFrame,
3848 SwTwips& onLowerSpacing,
3849 SwTwips& onLineSpacing,
3850 bool& obIsLineSpacingProportional )
3852 if ( !rFrame.IsFlowFrame() )
3854 onLowerSpacing = 0;
3855 onLineSpacing = 0;
3857 else
3859 const SvxULSpaceItem& rULSpace = rFrame.GetAttrSet()->GetULSpace();
3860 onLowerSpacing = rULSpace.GetLower();
3862 onLineSpacing = 0;
3863 obIsLineSpacingProportional = false;
3864 if ( rFrame.IsTextFrame() )
3866 onLineSpacing = static_cast<const SwTextFrame&>(rFrame).GetLineSpace();
3867 obIsLineSpacingProportional =
3868 onLineSpacing != 0 &&
3869 static_cast<const SwTextFrame&>(rFrame).GetLineSpace( true ) == 0;
3872 OSL_ENSURE( onLowerSpacing >= 0 && onLineSpacing >= 0,
3873 "<GetSpacingValuesOfFrame(..)> - spacing values aren't positive!" );
3877 /// get the content of the table cell, skipping content from nested tables
3878 const SwContentFrame* GetCellContent( const SwLayoutFrame& rCell )
3880 const SwContentFrame* pContent = rCell.ContainsContent();
3881 const SwTabFrame* pTab = rCell.FindTabFrame();
3883 while ( pContent && rCell.IsAnLower( pContent ) )
3885 const SwTabFrame* pTmpTab = pContent->FindTabFrame();
3886 if ( pTmpTab != pTab )
3888 SwFrame const*const pTmp = pTmpTab->FindLastContentOrTable();
3889 if (pTmp)
3891 pContent = pTmp->FindNextCnt();
3893 else
3895 pContent = nullptr;
3898 else
3899 break;
3901 return pContent;
3904 SwDeletionChecker::SwDeletionChecker(const SwFrame* pFrame)
3905 : mpFrame( pFrame )
3906 , mpRegIn( pFrame
3907 ? pFrame->IsTextFrame()
3908 // sw_redlinehide: GetDep() may be a member of SwTextFrame!
3909 ? static_cast<SwTextFrame const*>(pFrame)->GetTextNodeFirst()
3910 : const_cast<SwFrame*>(pFrame)->GetDep()
3911 : nullptr )
3915 /// Can be used to check if a frame has been deleted
3916 bool SwDeletionChecker::HasBeenDeleted() const
3918 if ( !mpFrame || !mpRegIn )
3919 return false;
3921 SwIterator<SwFrame, SwModify, sw::IteratorMode::UnwrapMulti> aIter(*mpRegIn);
3922 SwFrame* pLast = aIter.First();
3923 while ( pLast )
3925 if ( pLast == mpFrame )
3926 return false;
3927 pLast = aIter.Next();
3930 return true;
3933 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */