Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / layout / findfrm.cxx
blob5331baacd93e53c07217e86926fa8c2eea873c69
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 <pagefrm.hxx>
21 #include <rootfrm.hxx>
22 #include <cellfrm.hxx>
23 #include <rowfrm.hxx>
24 #include <swtable.hxx>
25 #include <notxtfrm.hxx>
26 #include <tabfrm.hxx>
27 #include <sectfrm.hxx>
28 #include <frmatr.hxx>
29 #include <flyfrm.hxx>
30 #include <ftnfrm.hxx>
31 #include <txtftn.hxx>
32 #include <fmtftn.hxx>
33 #include <fmtpdsc.hxx>
34 #include <fmtclbl.hxx>
35 #include <txtfrm.hxx>
36 #include <bodyfrm.hxx>
37 #include <calbck.hxx>
38 #include <viewopt.hxx>
39 #include <ndtxt.hxx>
40 #include <osl/diagnose.h>
41 #include <sal/log.hxx>
42 #include <IDocumentSettingAccess.hxx>
43 #include <formatflysplit.hxx>
44 #include <flyfrms.hxx>
47 /// Searches the first ContentFrame in BodyText below the page.
48 SwLayoutFrame *SwFootnoteBossFrame::FindBodyCont()
50 SwFrame *pLay = Lower();
51 while ( pLay && !pLay->IsBodyFrame() )
52 pLay = pLay->GetNext();
53 return static_cast<SwLayoutFrame*>(pLay);
56 /// Searches the last ContentFrame in BodyText below the page.
57 SwContentFrame *SwPageFrame::FindLastBodyContent()
59 SwContentFrame *pRet = FindFirstBodyContent();
60 SwContentFrame *pNxt = pRet;
61 while ( pNxt && pNxt->IsInDocBody() && IsAnLower( pNxt ) )
62 { pRet = pNxt;
63 pNxt = pNxt->FindNextCnt();
65 return pRet;
68 /**
69 * Checks if the frame contains one or more ContentFrame's anywhere in his
70 * subsidiary structure; if so the first found ContentFrame is returned.
72 const SwContentFrame *SwLayoutFrame::ContainsContent() const
74 //Search downwards the layout leaf and if there is no content, jump to the
75 //next leaf until content is found or we leave "this".
76 //Sections: Content next to sections would not be found this way (empty
77 //sections directly next to ContentFrame) therefore we need to recursively
78 //search for them even if it's more complex.
80 const SwLayoutFrame *pLayLeaf = this;
83 while ( (!pLayLeaf->IsSctFrame() || pLayLeaf == this ) &&
84 pLayLeaf->Lower() && pLayLeaf->Lower()->IsLayoutFrame() )
85 pLayLeaf = static_cast<const SwLayoutFrame*>(pLayLeaf->Lower());
87 if( pLayLeaf->IsSctFrame() && pLayLeaf != this )
89 const SwContentFrame *pCnt = pLayLeaf->ContainsContent();
90 if( pCnt )
91 return pCnt;
92 if( pLayLeaf->GetNext() )
94 if( pLayLeaf->GetNext()->IsLayoutFrame() )
96 pLayLeaf = static_cast<const SwLayoutFrame*>(pLayLeaf->GetNext());
97 continue;
99 else
100 return static_cast<const SwContentFrame*>(pLayLeaf->GetNext());
103 else if ( pLayLeaf->Lower() )
104 return static_cast<const SwContentFrame*>(pLayLeaf->Lower());
106 pLayLeaf = pLayLeaf->GetNextLayoutLeaf();
107 if( !IsAnLower( pLayLeaf) )
108 return nullptr;
109 } while( pLayLeaf );
110 return nullptr;
114 * Calls ContainsAny first to reach the innermost cell. From there we walk back
115 * up to the first SwCellFrame. Since we use SectionFrames, ContainsContent()->GetUpper()
116 * is not enough anymore.
118 const SwCellFrame *SwLayoutFrame::FirstCell() const
120 const SwFrame* pCnt = ContainsAny();
121 while( pCnt && !pCnt->IsCellFrame() )
122 pCnt = pCnt->GetUpper();
123 return static_cast<const SwCellFrame*>(pCnt);
126 /** return ContentFrames, sections, and tables.
128 * @param _bInvestigateFootnoteForSections controls investigation of content of footnotes for sections.
129 * @see ContainsContent
131 const SwFrame *SwLayoutFrame::ContainsAny( const bool _bInvestigateFootnoteForSections ) const
133 //Search downwards the layout leaf and if there is no content, jump to the
134 //next leaf until content is found, we leave "this" or until we found
135 //a SectionFrame or a TabFrame.
137 const SwLayoutFrame *pLayLeaf = this;
138 const bool bNoFootnote = IsSctFrame() && !_bInvestigateFootnoteForSections;
141 while ( ( (!pLayLeaf->IsSctFrame() && !pLayLeaf->IsTabFrame())
142 || pLayLeaf == this ) &&
143 pLayLeaf->Lower() && pLayLeaf->Lower()->IsLayoutFrame() )
144 pLayLeaf = static_cast<const SwLayoutFrame*>(pLayLeaf->Lower());
146 if( ( pLayLeaf->IsTabFrame() || pLayLeaf->IsSctFrame() )
147 && pLayLeaf != this )
149 // Now we also return "deleted" SectionFrames so they can be
150 // maintained on SaveContent and RestoreContent
151 return pLayLeaf;
153 else if ( pLayLeaf->Lower() )
154 return static_cast<const SwContentFrame*>(pLayLeaf->Lower());
156 pLayLeaf = pLayLeaf->GetNextLayoutLeaf();
157 if( bNoFootnote && pLayLeaf && pLayLeaf->IsInFootnote() )
161 pLayLeaf = pLayLeaf->GetNextLayoutLeaf();
162 } while( pLayLeaf && pLayLeaf->IsInFootnote() );
164 if( !IsAnLower( pLayLeaf) )
165 return nullptr;
166 } while( pLayLeaf );
167 return nullptr;
170 bool SwLayoutFrame::ContainsDeleteForbiddenLayFrame() const
172 if (IsDeleteForbidden())
174 return true;
176 for (SwFrame const* pFrame = Lower(); pFrame; pFrame = pFrame->GetNext())
178 if (!pFrame->IsLayoutFrame())
180 continue;
182 SwLayoutFrame const*const pLay(static_cast<SwLayoutFrame const*>(pFrame));
183 if (pLay->ContainsDeleteForbiddenLayFrame() || pLay->IsColLocked())
185 return true;
188 return false;
191 const SwFrame* SwFrame::GetLower() const
193 return IsLayoutFrame() ? static_cast<const SwLayoutFrame*>(this)->Lower() : nullptr;
196 SwFrame* SwFrame::GetLower()
198 return IsLayoutFrame() ? static_cast<SwLayoutFrame*>(this)->Lower() : nullptr;
201 SwContentFrame* SwFrame::FindPrevCnt( )
203 if ( GetPrev() && GetPrev()->IsContentFrame() )
204 return static_cast<SwContentFrame*>(GetPrev());
205 else
206 return FindPrevCnt_();
209 const SwContentFrame* SwFrame::FindPrevCnt() const
211 if ( GetPrev() && GetPrev()->IsContentFrame() )
212 return static_cast<const SwContentFrame*>(GetPrev());
213 else
214 return const_cast<SwFrame*>(this)->FindPrevCnt_();
217 SwContentFrame *SwFrame::FindNextCnt( const bool _bInSameFootnote )
219 if ( mpNext && mpNext->IsContentFrame() )
220 return static_cast<SwContentFrame*>(mpNext);
221 else
222 return FindNextCnt_( _bInSameFootnote );
225 const SwContentFrame *SwFrame::FindNextCnt( const bool _bInSameFootnote ) const
227 if ( mpNext && mpNext->IsContentFrame() )
228 return static_cast<SwContentFrame*>(mpNext);
229 else
230 return const_cast<SwFrame*>(this)->FindNextCnt_( _bInSameFootnote );
233 bool SwLayoutFrame::IsAnLower( const SwFrame *pAssumed ) const
235 const SwFrame *pUp = pAssumed;
236 while ( pUp )
238 if ( pUp == this )
239 return true;
240 if ( pUp->IsFlyFrame() )
241 pUp = static_cast<const SwFlyFrame*>(pUp)->GetAnchorFrame();
242 else
243 pUp = pUp->GetUpper();
245 return false;
248 /** method to check relative position of layout frame to
249 a given layout frame.
251 OD 08.11.2002 - refactoring of pseudo-local method <lcl_Apres(..)> in
252 <txtftn.cxx> for #104840#.
254 @param _aCheckRefLayFrame
255 constant reference of an instance of class <SwLayoutFrame> which
256 is used as the reference for the relative position check.
258 @return true, if <this> is positioned before the layout frame <p>
260 bool SwLayoutFrame::IsBefore( const SwLayoutFrame* _pCheckRefLayFrame ) const
262 OSL_ENSURE( !IsRootFrame() , "<IsBefore> called at a <SwRootFrame>.");
263 OSL_ENSURE( !_pCheckRefLayFrame->IsRootFrame() , "<IsBefore> called with a <SwRootFrame>.");
265 bool bReturn;
267 // check, if on different pages
268 const SwPageFrame *pMyPage = FindPageFrame();
269 const SwPageFrame *pCheckRefPage = _pCheckRefLayFrame->FindPageFrame();
270 if( pMyPage != pCheckRefPage )
272 // being on different page as check reference
273 bReturn = pMyPage->GetPhyPageNum() < pCheckRefPage->GetPhyPageNum();
275 else
277 // being on same page as check reference
278 // --> search my supreme parent <pUp>, which doesn't contain check reference.
279 const SwLayoutFrame* pUp = this;
280 while ( pUp->GetUpper() &&
281 !pUp->GetUpper()->IsAnLower( _pCheckRefLayFrame )
283 pUp = pUp->GetUpper();
284 if( !pUp->GetUpper() )
286 // can occur, if <this> is a fly frm
287 bReturn = false;
289 else
291 // travel through the next's of <pUp> and check if one of these
292 // contain the check reference.
293 const SwLayoutFrame* pUpNext = static_cast<const SwLayoutFrame*>(pUp->GetNext());
294 while ( pUpNext &&
295 !pUpNext->IsAnLower( _pCheckRefLayFrame ) )
297 pUpNext = static_cast<const SwLayoutFrame*>(pUpNext->GetNext());
299 bReturn = pUpNext != nullptr;
303 return bReturn;
306 // Local helper functions for GetNextLayoutLeaf
308 static const SwFrame* lcl_FindLayoutFrame( const SwFrame* pFrame, bool bNext )
310 const SwFrame* pRet = nullptr;
311 if ( pFrame->IsFlyFrame() )
313 auto pFlyFrame = static_cast<const SwFlyFrame*>(pFrame);
314 if (pFlyFrame->IsFlySplitAllowed())
316 // This is a flow frame, look up the follow/precede.
317 auto pFlyAtContent = static_cast<const SwFlyAtContentFrame*>(pFlyFrame);
318 pRet = bNext ? pFlyAtContent->GetFollow() : pFlyAtContent->GetPrecede();
320 else
322 pRet = bNext ? pFlyFrame->GetNextLink() : pFlyFrame->GetPrevLink();
325 else
326 pRet = bNext ? pFrame->GetNext() : pFrame->GetPrev();
328 return pRet;
331 static const SwFrame* lcl_GetLower( const SwFrame* pFrame, bool bFwd )
333 if ( !pFrame->IsLayoutFrame() )
334 return nullptr;
336 return bFwd ?
337 static_cast<const SwLayoutFrame*>(pFrame)->Lower() :
338 static_cast<const SwLayoutFrame*>(pFrame)->GetLastLower();
342 * Finds the next layout leaf. This is a layout frame, which does not
343 * have a lower which is a LayoutFrame. That means, pLower can be 0 or a
344 * content frame.
346 * However, pLower may be a TabFrame
348 const SwLayoutFrame *SwFrame::ImplGetNextLayoutLeaf( bool bFwd ) const
350 const SwFrame *pFrame = this;
351 const SwLayoutFrame *pLayoutFrame = nullptr;
352 const SwFrame *p = nullptr;
353 bool bGoingUp = !bFwd; // false for forward, true for backward
354 // The anchor is this frame, unless we traverse the anchor of a split fly.
355 const SwFrame* pAnchor = this;
356 do {
358 bool bGoingFwdOrBwd = false;
360 bool bGoingDown = !bGoingUp;
361 if (bGoingDown)
363 p = lcl_GetLower( pFrame, bFwd );
364 bGoingDown = nullptr != p;
366 if ( !bGoingDown )
368 // I cannot go down, because either I'm currently going up or
369 // because the is no lower.
370 // I'll try to go forward:
371 p = lcl_FindLayoutFrame( pFrame, bFwd );
372 bGoingFwdOrBwd = nullptr != p;
373 if ( !bGoingFwdOrBwd )
375 // I cannot go forward, because there is no next frame.
376 // I'll try to go up:
377 p = pFrame->GetUpper();
379 if (!p && pFrame->IsFlyFrame())
381 const SwFlyFrame* pFlyFrame = pFrame->FindFlyFrame();
382 if (pFlyFrame->IsFlySplitAllowed())
384 p = const_cast<SwFlyFrame*>(pFlyFrame)->FindAnchorCharFrame();
385 // Remember the anchor frame, so if we look for the leaf of a frame in a
386 // split fly (anchored in the master of a text frame, but rendered on the
387 // next page), we won't return a frame on the next page, rather return
388 // nullptr.
389 pAnchor = p;
393 bGoingUp = nullptr != p;
394 if ( !bGoingUp )
396 // I cannot go up, because there is no upper frame.
397 return nullptr;
402 // If I could not go down or forward, I'll have to go up
403 bGoingUp = !bGoingFwdOrBwd && !bGoingDown;
405 pFrame = p;
406 p = lcl_GetLower( pFrame, true );
408 } while( ( p && !p->IsFlowFrame() ) ||
409 pFrame == this ||
410 nullptr == ( pLayoutFrame = pFrame->IsLayoutFrame() ? static_cast<const SwLayoutFrame*>(pFrame) : nullptr ) ||
411 pLayoutFrame->IsAnLower( pAnchor ) );
413 return pLayoutFrame;
417 * Walk back inside the tree: grab the subordinate Frame if one exists and the
418 * last step was not moving up a level (this would lead to an infinite up/down
419 * loop!). With this we ensure that during walking back we search through all
420 * sub trees. If we walked downwards we have to go to the end of the chain first
421 * because we go backwards from the last Frame inside another Frame. Walking
422 * forward works the same.
424 * @warning fixes here may also need to be applied to the @{lcl_NextFrame} method above
426 const SwContentFrame* SwContentFrame::ImplGetNextContentFrame( bool bFwd ) const
428 const SwFrame *pFrame = this;
429 const SwContentFrame *pContentFrame = nullptr;
430 bool bGoingUp = false;
431 do {
432 const SwFrame *p = nullptr;
433 bool bGoingFwdOrBwd = false;
435 bool bGoingDown = !bGoingUp;
436 if (bGoingDown)
438 p = lcl_GetLower( pFrame, true ) ;
439 bGoingDown = nullptr != p;
441 if ( !bGoingDown )
443 p = lcl_FindLayoutFrame( pFrame, bFwd );
444 bGoingFwdOrBwd = nullptr != p;
445 if ( !bGoingFwdOrBwd )
447 p = pFrame->GetUpper();
448 bGoingUp = nullptr != p;
449 if ( !bGoingUp )
451 return nullptr;
456 bGoingUp = !(bGoingFwdOrBwd || bGoingDown);
457 assert(p);
458 if (!bFwd && bGoingDown)
460 while ( p->GetNext() )
461 p = p->GetNext();
464 pFrame = p;
465 } while ( nullptr == (pContentFrame = (pFrame->IsContentFrame() ? static_cast<const SwContentFrame*>(pFrame) : nullptr) ));
467 return pContentFrame;
470 SwPageFrame* SwFrame::ImplFindPageFrame()
472 SwFrame *pRet = this;
473 while ( pRet && !pRet->IsPageFrame() )
475 if ( pRet->GetUpper() )
476 pRet = pRet->GetUpper();
477 else if ( pRet->IsFlyFrame() )
479 // #i28701# - use new method <GetPageFrame()>
480 const auto pFly(static_cast<SwFlyFrame*>(pRet));
481 pRet = pFly->GetPageFrame();
482 if (pRet == nullptr)
483 pRet = pFly->AnchorFrame();
485 else
486 return nullptr;
488 return static_cast<SwPageFrame*>(pRet);
491 SwFootnoteBossFrame* SwFrame::FindFootnoteBossFrame( bool bFootnotes )
493 SwFrame *pRet = this;
494 // Footnote bosses can't exist inside a table; also sections with columns
495 // don't contain footnote texts there
496 if (SwFrame *pTabFrame = pRet->IsInTab() ? pRet->FindTabFrame() : nullptr)
497 pRet = pTabFrame;
499 // tdf139336: put the footnotes into the page frame (instead of a column frame)
500 // to avoid maximizing the section to the full page.... if:
501 // - it is in a section
502 // - collect footnotes at section end (FootnoteAtEnd) is not set
503 // - columns are evenly distributed (=balanced) is not set
504 // Note 1: at page end, the footnotes have no multi-column-capability,
505 // so this fix is used only where there is better chance to help
506 // Note 2: If balanced is not set, there is a higher chance that the 1. column will reach
507 // the end of the page... if that happens the section will be maximized anyway.
508 // Note 3: The user will be able to easily choose the old layout (with multi-column footnotes)
509 // with this setting.
510 // similar case can be reached with a page break + FootnoteAtEnd setting
511 SwSectionFrame* pSectframe = pRet->FindSctFrame();
512 bool bMoveToPageFrame = false;
513 // tdf146704: only if it is really a footnote, not an endnote.
514 // tdf54465: compatibility flag to make old odt files keep these full page sections.
515 if (bFootnotes && pSectframe
516 && pSectframe->GetFormat()->getIDocumentSettingAccess().get(
517 DocumentSettingId::FOOTNOTE_IN_COLUMN_TO_PAGEEND))
519 SwSection* pSect = pSectframe->GetSection();
520 if (pSect) {
521 bool bNoBalance = pSect->GetFormat()->GetBalancedColumns().GetValue();
522 bool bFAtEnd = pSectframe->IsFootnoteAtEnd();
523 bMoveToPageFrame = !bFAtEnd && !bNoBalance;
526 while (pRet
527 && ((!bMoveToPageFrame && !pRet->IsFootnoteBossFrame())
528 || (bMoveToPageFrame && !pRet->IsPageFrame())))
530 if ( pRet->GetUpper() )
531 pRet = pRet->GetUpper();
532 else if ( pRet->IsFlyFrame() )
534 // #i28701# - use new method <GetPageFrame()>
535 if ( static_cast<SwFlyFrame*>(pRet)->GetPageFrame() )
536 pRet = static_cast<SwFlyFrame*>(pRet)->GetPageFrame();
537 else
538 pRet = static_cast<SwFlyFrame*>(pRet)->AnchorFrame();
540 else
541 return nullptr;
543 if( bFootnotes && pRet && pRet->IsColumnFrame() &&
544 !pRet->GetNext() && !pRet->GetPrev() )
546 SwSectionFrame* pSct = pRet->FindSctFrame();
547 OSL_ENSURE( pSct, "FindFootnoteBossFrame: Single column outside section?" );
548 if( !pSct->IsFootnoteAtEnd() )
549 return pSct->FindFootnoteBossFrame( true );
551 return static_cast<SwFootnoteBossFrame*>(pRet);
554 SwTabFrame* SwFrame::ImplFindTabFrame()
556 SwFrame *pRet = this;
557 while ( !pRet->IsTabFrame() )
559 pRet = pRet->GetUpper();
560 if ( !pRet )
561 return nullptr;
563 return static_cast<SwTabFrame*>(pRet);
566 SwSectionFrame* SwFrame::ImplFindSctFrame()
568 SwFrame *pRet = this;
569 while ( !pRet->IsSctFrame() )
571 pRet = pRet->GetUpper();
572 if ( !pRet )
573 return nullptr;
575 return static_cast<SwSectionFrame*>(pRet);
578 const SwBodyFrame* SwFrame::ImplFindBodyFrame() const
580 const SwFrame *pRet = this;
581 while ( !pRet->IsBodyFrame() )
583 pRet = pRet->GetUpper();
584 if ( !pRet )
585 return nullptr;
587 return static_cast<const SwBodyFrame*>(pRet);
590 SwFootnoteFrame *SwFrame::ImplFindFootnoteFrame()
592 SwFrame *pRet = this;
593 while ( !pRet->IsFootnoteFrame() )
595 pRet = pRet->GetUpper();
596 if ( !pRet )
597 return nullptr;
599 return static_cast<SwFootnoteFrame*>(pRet);
602 SwFlyFrame *SwFrame::ImplFindFlyFrame()
604 SwFrame *pRet = this;
607 if ( pRet->IsFlyFrame() )
608 return static_cast<SwFlyFrame*>(pRet);
609 else
610 pRet = pRet->GetUpper();
611 } while ( pRet );
612 return nullptr;
615 SwFrame *SwFrame::FindColFrame()
617 SwFrame *pFrame = this;
619 { pFrame = pFrame->GetUpper();
620 } while ( pFrame && !pFrame->IsColumnFrame() );
621 return pFrame;
624 SwRowFrame *SwFrame::FindRowFrame()
626 SwFrame *pFrame = this;
628 { pFrame = pFrame->GetUpper();
629 } while ( pFrame && !pFrame->IsRowFrame() );
630 return dynamic_cast< SwRowFrame* >( pFrame );
633 SwFrame* SwFrame::FindFooterOrHeader()
635 SwFrame* pRet = this;
638 if (pRet->GetType() & FRM_HEADFOOT) //header and footer
639 return pRet;
640 else if ( pRet->GetUpper() )
641 pRet = pRet->GetUpper();
642 else if ( pRet->IsFlyFrame() )
643 pRet = static_cast<SwFlyFrame*>(pRet)->AnchorFrame();
644 else
645 return nullptr;
646 } while ( pRet );
647 return pRet;
650 const SwFootnoteFrame* SwFootnoteContFrame::FindFootNote() const
652 const SwFootnoteFrame* pRet = static_cast<const SwFootnoteFrame*>(Lower());
653 if( pRet && !pRet->GetAttr()->GetFootnote().IsEndNote() )
654 return pRet;
655 return nullptr;
658 const SwPageFrame* SwRootFrame::GetPageAtPos( const Point& rPt, const Size* pSize, bool bExtend ) const
660 const SwPageFrame* pRet = nullptr;
662 SwRect aRect;
663 if ( pSize )
665 aRect.Pos() = rPt;
666 aRect.SSize( *pSize );
669 const SwFrame* pPage = Lower();
671 if ( !bExtend )
673 if( !getFrameArea().Contains( rPt ) )
674 return nullptr;
676 // skip pages above point:
677 while( pPage && rPt.Y() > pPage->getFrameArea().Bottom() )
678 pPage = pPage->GetNext();
681 OSL_ENSURE( GetPageNum() <= maPageRects.size(), "number of pages differs from page rect array size" );
682 size_t nPageIdx = 0;
684 while ( pPage && !pRet )
686 const SwRect& rBoundRect = bExtend ? maPageRects[ nPageIdx++ ] : pPage->getFrameArea();
688 if ( (!pSize && rBoundRect.Contains(rPt)) ||
689 (pSize && rBoundRect.Overlaps(aRect)) )
691 pRet = static_cast<const SwPageFrame*>(pPage);
694 pPage = pPage->GetNext();
697 return pRet;
700 bool SwRootFrame::IsBetweenPages(const Point& rPt) const
702 if (!getFrameArea().Contains(rPt))
703 return false;
705 // top visible page
706 const SwFrame* pPage = Lower();
707 if (pPage == nullptr)
708 return false;
710 // skip pages above point:
711 while (pPage && rPt.Y() > pPage->getFrameArea().Bottom())
712 pPage = pPage->GetNext();
714 if (pPage &&
715 rPt.X() >= pPage->getFrameArea().Left() &&
716 rPt.X() <= pPage->getFrameArea().Right())
718 // Trivial case when we're right in between.
719 if (!pPage->getFrameArea().Contains(rPt))
720 return true;
722 // In normal mode the gap is large enough and
723 // header/footer mouse interaction competes with
724 // handling hide-whitespace within them.
725 // In hide-whitespace, however, the gap is too small
726 // for convenience and there are no headers/footers.
727 const SwViewShell *pSh = GetCurrShell();
728 if (pSh && pSh->GetViewOptions()->IsWhitespaceHidden())
730 constexpr SwTwips constMargin = o3tl::convert(tools::Long(2), o3tl::Length::mm, o3tl::Length::twip);
732 // If we are really close to the bottom or top of a page.
733 const auto toEdge = std::min(std::abs(pPage->getFrameArea().Top() - rPt.Y()),
734 std::abs(pPage->getFrameArea().Bottom() - rPt.Y()));
735 return toEdge <= constMargin;
739 return false;
742 const SvxFormatBreakItem& SwFrame::GetBreakItem() const
744 return GetAttrSet()->GetBreak();
747 const SwFormatPageDesc& SwFrame::GetPageDescItem() const
749 return GetAttrSet()->GetPageDesc();
752 const SvxFormatBreakItem& SwTextFrame::GetBreakItem() const
754 return GetTextNodeFirst()->GetSwAttrSet().GetBreak();
757 const SwFormatPageDesc& SwTextFrame::GetPageDescItem() const
759 return GetTextNodeFirst()->GetSwAttrSet().GetPageDesc();
762 const SwAttrSet* SwFrame::GetAttrSet() const
764 if (IsTextFrame())
766 return &static_cast<const SwTextFrame*>(this)->GetTextNodeForParaProps()->GetSwAttrSet();
768 else if (IsNoTextFrame())
770 return &static_cast<const SwNoTextFrame*>(this)->GetNode()->GetSwAttrSet();
772 else
774 assert(IsLayoutFrame());
775 return &static_cast<const SwLayoutFrame*>(this)->GetFormat()->GetAttrSet();
779 drawinglayer::attribute::SdrAllFillAttributesHelperPtr SwFrame::getSdrAllFillAttributesHelper() const
781 if (IsTextFrame())
783 return static_cast<const SwTextFrame*>(this)->GetTextNodeForParaProps()->getSdrAllFillAttributesHelper();
785 else if (IsNoTextFrame())
787 return static_cast<const SwNoTextFrame*>(this)->GetNode()->getSdrAllFillAttributesHelper();
789 else
791 return static_cast< const SwLayoutFrame* >(this)->GetFormat()->getSdrAllFillAttributesHelper();
795 bool SwFrame::supportsFullDrawingLayerFillAttributeSet() const
797 if (IsContentFrame())
799 return true;
801 else
803 return static_cast< const SwLayoutFrame* >(this)->GetFormat()->supportsFullDrawingLayerFillAttributeSet();
808 * SwFrame::FindNext_(), FindPrev_(), InvalidateNextPos()
809 * FindNextCnt_() visits tables and sections and only returns SwContentFrames.
811 * Description Invalidates the position of the next frame.
812 * This is the direct successor or in case of ContentFrames the next
813 * ContentFrame which sits in the same flow as I do:
814 * - body,
815 * - footnote,
816 * - in headers/footers the notification only needs to be forwarded
817 * inside the section
818 * - same for Flys
819 * - Contents in tabs remain only inside their cell
820 * - in principle tables behave exactly like the Contents
821 * - sections also
823 // This helper function is an equivalent to the ImplGetNextContentFrame() method,
824 // besides ContentFrames this function also returns TabFrames and SectionFrames.
825 static SwFrame* lcl_NextFrame( SwFrame* pFrame )
827 SwFrame *pRet = nullptr;
828 bool bGoingUp = false;
829 do {
830 SwFrame *p = nullptr;
832 bool bGoingFwd = false;
833 bool bGoingDown = !bGoingUp && pFrame->IsLayoutFrame();
834 if (bGoingDown)
836 p = static_cast<SwLayoutFrame*>(pFrame)->Lower();
837 bGoingDown = nullptr != p;
839 if( !bGoingDown )
841 p = pFrame->IsFlyFrame() ? static_cast<SwFlyFrame*>(pFrame)->GetNextLink() : pFrame->GetNext();
842 bGoingFwd = nullptr != p;
843 if ( !bGoingFwd )
845 p = pFrame->GetUpper();
846 bGoingUp = nullptr != p;
847 if ( !bGoingUp )
849 return nullptr;
853 bGoingUp = !(bGoingFwd || bGoingDown);
854 pFrame = p;
855 } while ( nullptr == (pRet = ( ( pFrame->IsContentFrame() || ( !bGoingUp &&
856 ( pFrame->IsTabFrame() || pFrame->IsSctFrame() ) ) )? pFrame : nullptr ) ) );
857 return pRet;
860 SwFrame *SwFrame::FindNext_()
862 bool bIgnoreTab = false;
863 SwFrame *pThis = this;
865 if ( IsTabFrame() )
867 //The last Content of the table gets picked up and his follower is
868 //returned. To be able to deactivate the special case for tables
869 //(see below) bIgnoreTab will be set.
870 if ( static_cast<SwTabFrame*>(this)->GetFollow() )
871 return static_cast<SwTabFrame*>(this)->GetFollow();
873 pThis = static_cast<SwTabFrame*>(this)->FindLastContentOrTable();
874 if ( !pThis )
875 pThis = this;
876 bIgnoreTab = true;
878 else if ( IsSctFrame() )
880 //The last Content of the section gets picked and his follower is returned.
881 if ( static_cast<SwSectionFrame*>(this)->GetFollow() )
882 return static_cast<SwSectionFrame*>(this)->GetFollow();
884 pThis = static_cast<SwSectionFrame*>(this)->FindLastContent();
885 if ( !pThis )
886 pThis = this;
888 else if ( IsContentFrame() )
890 if( static_cast<SwContentFrame*>(this)->GetFollow() )
891 return static_cast<SwContentFrame*>(this)->GetFollow();
893 else if ( IsRowFrame() )
895 SwFrame* pMyUpper = GetUpper();
896 if ( pMyUpper->IsTabFrame() && static_cast<SwTabFrame*>(pMyUpper)->GetFollow() )
897 return static_cast<SwTabFrame*>(pMyUpper)->GetFollow()->GetLower();
898 else return nullptr;
900 else
901 return nullptr;
903 SwFrame* pRet = nullptr;
904 const bool bFootnote = pThis->IsInFootnote();
905 if ( !bIgnoreTab && pThis->IsInTab() )
907 SwLayoutFrame *pUp = pThis->GetUpper();
908 while (pUp && !pUp->IsCellFrame())
909 pUp = pUp->GetUpper();
910 assert(pUp && "Content flag says it's in table but it's not in cell.");
911 SwFrame* pNxt = pUp ? static_cast<SwCellFrame*>(pUp)->GetFollowCell() : nullptr;
912 if ( pNxt )
913 pNxt = static_cast<SwCellFrame*>(pNxt)->ContainsContent();
914 if ( !pNxt )
916 pNxt = lcl_NextFrame( pThis );
917 if (pUp && pUp->IsAnLower(pNxt))
918 pRet = pNxt;
920 else
921 pRet = pNxt;
923 else
925 const bool bBody = pThis->IsInDocBody();
926 SwFrame *pNxtCnt = lcl_NextFrame( pThis );
927 if ( pNxtCnt )
929 if ( bBody || bFootnote )
931 while ( pNxtCnt )
933 // OD 02.04.2003 #108446# - check for endnote, only if found
934 // next content isn't contained in a section, that collect its
935 // endnotes at its end.
936 bool bEndn = IsInSct() && !IsSctFrame() &&
937 ( !pNxtCnt->IsInSct() ||
938 !pNxtCnt->FindSctFrame()->IsEndnAtEnd()
940 if ( ( bBody && pNxtCnt->IsInDocBody() ) ||
941 ( pNxtCnt->IsInFootnote() &&
942 ( bFootnote ||
943 ( bEndn && pNxtCnt->FindFootnoteFrame()->GetAttr()->GetFootnote().IsEndNote() )
948 if (pNxtCnt->IsInTab())
950 if (!IsTabFrame() || !static_cast<SwLayoutFrame*>(this)->IsAnLower(pNxtCnt))
952 pRet = pNxtCnt->FindTabFrame();
953 break;
956 else
958 pRet = pNxtCnt;
959 break;
962 pNxtCnt = lcl_NextFrame( pNxtCnt );
965 else if ( pThis->IsInFly() )
967 pRet = pNxtCnt->IsInTab() ? pNxtCnt->FindTabFrame()
968 : pNxtCnt;
970 else //footer-/or header section
972 const SwFrame *pUp = pThis->GetUpper();
973 const SwFrame *pCntUp = pNxtCnt->GetUpper();
974 while ( pUp && pUp->GetUpper() &&
975 !pUp->IsHeaderFrame() && !pUp->IsFooterFrame() )
976 pUp = pUp->GetUpper();
977 while ( pCntUp && pCntUp->GetUpper() &&
978 !pCntUp->IsHeaderFrame() && !pCntUp->IsFooterFrame() )
979 pCntUp = pCntUp->GetUpper();
980 if ( pCntUp == pUp )
982 pRet = pNxtCnt->IsInTab() ? pNxtCnt->FindTabFrame()
983 : pNxtCnt;
988 if( pRet && pRet->IsInSct() )
990 SwSectionFrame* pSct = pRet->FindSctFrame();
991 //Footnotes in frames with columns must not return the section which
992 //contains the footnote
993 if( !pSct->IsAnLower( this ) &&
994 (!bFootnote || pSct->IsInFootnote() ) )
995 return pSct;
997 return pRet;
1000 // #i27138# - add parameter <_bInSameFootnote>
1001 SwContentFrame *SwFrame::FindNextCnt_( const bool _bInSameFootnote )
1003 SwFrame *pThis = this;
1005 if ( IsTabFrame() )
1007 if ( static_cast<SwTabFrame*>(this)->GetFollow() )
1009 pThis = static_cast<SwTabFrame*>(this)->GetFollow()->ContainsContent();
1010 if( pThis )
1011 return static_cast<SwContentFrame*>(pThis);
1013 pThis = static_cast<SwTabFrame*>(this)->FindLastContentOrTable();
1014 if ( !pThis )
1015 return nullptr;
1017 else if ( IsSctFrame() )
1019 if ( static_cast<SwSectionFrame*>(this)->GetFollow() )
1021 pThis = static_cast<SwSectionFrame*>(this)->GetFollow()->ContainsContent();
1022 if( pThis )
1023 return static_cast<SwContentFrame*>(pThis);
1025 pThis = static_cast<SwSectionFrame*>(this)->FindLastContent();
1026 if ( !pThis )
1027 return nullptr;
1029 else if ( IsContentFrame() && static_cast<SwContentFrame*>(this)->GetFollow() )
1030 return static_cast<SwContentFrame*>(this)->GetFollow();
1032 if ( pThis->IsContentFrame() )
1034 const bool bBody = pThis->IsInDocBody();
1035 const bool bFootnote = pThis->IsInFootnote();
1036 SwContentFrame *pNxtCnt = static_cast<SwContentFrame*>(pThis)->GetNextContentFrame();
1037 if ( pNxtCnt )
1039 // #i27138#
1040 if ( bBody || ( bFootnote && !_bInSameFootnote ) )
1042 // handling for environments 'footnotes' and 'document body frames':
1043 while ( pNxtCnt )
1045 if ( (bBody && pNxtCnt->IsInDocBody()) ||
1046 (bFootnote && pNxtCnt->IsInFootnote()) )
1047 return pNxtCnt;
1048 pNxtCnt = pNxtCnt->GetNextContentFrame();
1051 // #i27138#
1052 else if ( bFootnote && _bInSameFootnote )
1054 // handling for environments 'each footnote':
1055 // Assure that found next content frame belongs to the same footnotes
1056 const SwFootnoteFrame* pFootnoteFrameOfNext( pNxtCnt->FindFootnoteFrame() );
1057 const SwFootnoteFrame* pFootnoteFrameOfCurr( pThis->FindFootnoteFrame() );
1058 OSL_ENSURE( pFootnoteFrameOfCurr,
1059 "<SwFrame::FindNextCnt_() - unknown layout situation: current frame has to have an upper footnote frame." );
1060 if ( pFootnoteFrameOfNext == pFootnoteFrameOfCurr )
1062 return pNxtCnt;
1064 else if ( pFootnoteFrameOfCurr->GetFollow() )
1066 // next content frame has to be the first content frame
1067 // in the follow footnote, which contains a content frame.
1068 SwFootnoteFrame* pFollowFootnoteFrameOfCurr(
1069 const_cast<SwFootnoteFrame*>(pFootnoteFrameOfCurr) );
1070 pNxtCnt = nullptr;
1071 do {
1072 pFollowFootnoteFrameOfCurr = pFollowFootnoteFrameOfCurr->GetFollow();
1073 pNxtCnt = pFollowFootnoteFrameOfCurr->ContainsContent();
1074 } while ( !pNxtCnt && pFollowFootnoteFrameOfCurr->GetFollow() );
1075 return pNxtCnt;
1077 else
1079 // current content frame is the last content frame in the
1080 // footnote - no next content frame exists.
1081 return nullptr;
1084 else if ( pThis->IsInFly() )
1085 // handling for environments 'unlinked fly frame' and
1086 // 'group of linked fly frames':
1087 return pNxtCnt;
1088 else
1090 // handling for environments 'page header' and 'page footer':
1091 const SwFrame *pUp = pThis->GetUpper();
1092 const SwFrame *pCntUp = pNxtCnt->GetUpper();
1093 while ( pUp && pUp->GetUpper() &&
1094 !pUp->IsHeaderFrame() && !pUp->IsFooterFrame() )
1095 pUp = pUp->GetUpper();
1096 while ( pCntUp && pCntUp->GetUpper() &&
1097 !pCntUp->IsHeaderFrame() && !pCntUp->IsFooterFrame() )
1098 pCntUp = pCntUp->GetUpper();
1099 if ( pCntUp == pUp )
1100 return pNxtCnt;
1104 return nullptr;
1107 /** method to determine previous content frame in the same environment
1108 for a flow frame (content frame, table frame, section frame)
1110 OD 2005-11-30 #i27138#
1112 SwContentFrame* SwFrame::FindPrevCnt_()
1114 if ( !IsFlowFrame() )
1116 // nothing to do, if current frame isn't a flow frame.
1117 return nullptr;
1120 SwContentFrame* pPrevContentFrame( nullptr );
1122 // Because method <SwContentFrame::GetPrevContentFrame()> is used to travel
1123 // through the layout, a content frame, at which the travel starts, is needed.
1124 SwContentFrame* pCurrContentFrame = dynamic_cast<SwContentFrame*>(this);
1126 // perform shortcut, if current frame is a follow, and
1127 // determine <pCurrContentFrame>, if current frame is a table or section frame
1128 if ( pCurrContentFrame && pCurrContentFrame->IsFollow() )
1130 // previous content frame is its master content frame
1131 pPrevContentFrame = pCurrContentFrame->FindMaster();
1133 else if ( IsTabFrame() )
1135 SwTabFrame* pTabFrame( static_cast<SwTabFrame*>(this) );
1136 if ( pTabFrame->IsFollow() )
1138 // previous content frame is the last content of its master table frame
1139 pPrevContentFrame = pTabFrame->FindMaster()->FindLastContent();
1141 else
1143 // start content frame for the search is the first content frame of
1144 // the table frame.
1145 pCurrContentFrame = pTabFrame->ContainsContent();
1148 else if ( IsSctFrame() )
1150 SwSectionFrame* pSectFrame( static_cast<SwSectionFrame*>(this) );
1151 if ( pSectFrame->IsFollow() )
1153 // previous content frame is the last content of its master section frame
1154 pPrevContentFrame = pSectFrame->FindMaster()->FindLastContent();
1156 else
1158 // start content frame for the search is the first content frame of
1159 // the section frame.
1160 pCurrContentFrame = pSectFrame->ContainsContent();
1164 // search for next content frame, depending on the environment, in which
1165 // the current frame is in.
1166 if ( !pPrevContentFrame && pCurrContentFrame )
1168 pPrevContentFrame = pCurrContentFrame->GetPrevContentFrame();
1169 if ( pPrevContentFrame )
1171 if ( pCurrContentFrame->IsInFly() )
1173 // handling for environments 'unlinked fly frame' and
1174 // 'group of linked fly frames':
1175 // Nothing to do, <pPrevContentFrame> is the one
1177 else
1179 const bool bInDocBody = pCurrContentFrame->IsInDocBody();
1180 const bool bInFootnote = pCurrContentFrame->IsInFootnote();
1181 if ( bInDocBody )
1183 // handling for environments 'footnotes' and 'document body frames':
1184 // Assure that found previous frame is also in one of these
1185 // environments. Otherwise, travel further
1186 while ( pPrevContentFrame )
1188 if ( ( bInDocBody && pPrevContentFrame->IsInDocBody() ) ||
1189 ( bInFootnote && pPrevContentFrame->IsInFootnote() ) )
1191 break;
1193 pPrevContentFrame = pPrevContentFrame->GetPrevContentFrame();
1196 else if ( bInFootnote )
1198 // handling for environments 'each footnote':
1199 // Assure that found next content frame belongs to the same footnotes
1200 const SwFootnoteFrame* pFootnoteFrameOfPrev( pPrevContentFrame->FindFootnoteFrame() );
1201 const SwFootnoteFrame* pFootnoteFrameOfCurr( pCurrContentFrame->FindFootnoteFrame() );
1202 if ( pFootnoteFrameOfPrev != pFootnoteFrameOfCurr )
1204 if ( pFootnoteFrameOfCurr->GetMaster() )
1206 SwFootnoteFrame* pMasterFootnoteFrameOfCurr(
1207 const_cast<SwFootnoteFrame*>(pFootnoteFrameOfCurr) );
1208 pPrevContentFrame = nullptr;
1209 // correct wrong loop-condition
1210 do {
1211 pMasterFootnoteFrameOfCurr = pMasterFootnoteFrameOfCurr->GetMaster();
1212 pPrevContentFrame = pMasterFootnoteFrameOfCurr->FindLastContent();
1213 } while ( !pPrevContentFrame &&
1214 pMasterFootnoteFrameOfCurr->GetMaster() );
1216 else
1218 // current content frame is the first content in the
1219 // footnote - no previous content exists.
1220 pPrevContentFrame = nullptr;
1224 else
1226 // handling for environments 'page header' and 'page footer':
1227 // Assure that found previous frame is also in the same
1228 // page header respectively page footer as <pCurrContentFrame>
1229 // Note: At this point it's clear that <pCurrContentFrame> has
1230 // to be inside a page header or page footer and that
1231 // neither <pCurrContentFrame> nor <pPrevContentFrame> are
1232 // inside a fly frame.
1233 // Thus, method <FindFooterOrHeader()> can be used.
1234 OSL_ENSURE( pCurrContentFrame->FindFooterOrHeader(),
1235 "<SwFrame::FindPrevCnt_()> - unknown layout situation: current frame should be in page header or page footer" );
1236 OSL_ENSURE( !pPrevContentFrame->IsInFly(),
1237 "<SwFrame::FindPrevCnt_()> - unknown layout situation: found previous frame should *not* be inside a fly frame." );
1238 if ( pPrevContentFrame->FindFooterOrHeader() !=
1239 pCurrContentFrame->FindFooterOrHeader() )
1241 pPrevContentFrame = nullptr;
1248 return pPrevContentFrame;
1251 SwFrame *SwFrame::FindPrev_()
1253 bool bIgnoreTab = false;
1254 SwFrame *pThis = this;
1256 if ( IsTabFrame() )
1258 //The first Content of the table gets picked up and his predecessor is
1259 //returned. To be able to deactivate the special case for tables
1260 //(see below) bIgnoreTab will be set.
1261 if ( static_cast<SwTabFrame*>(this)->IsFollow() )
1262 return static_cast<SwTabFrame*>(this)->FindMaster();
1263 else
1264 pThis = static_cast<SwTabFrame*>(this)->ContainsContent();
1265 bIgnoreTab = true;
1268 if ( pThis && pThis->IsContentFrame() )
1270 SwContentFrame *pPrvCnt = static_cast<SwContentFrame*>(pThis)->GetPrevContentFrame();
1271 if( !pPrvCnt )
1272 return nullptr;
1273 if ( !bIgnoreTab && pThis->IsInTab() )
1275 SwLayoutFrame *pUp = pThis->GetUpper();
1276 while (pUp && !pUp->IsCellFrame())
1277 pUp = pUp->GetUpper();
1278 assert(pUp && "Content flag says it's in table but it's not in cell.");
1279 if (pUp && pUp->IsAnLower(pPrvCnt))
1280 return pPrvCnt;
1282 else
1284 SwFrame* pRet;
1285 const bool bBody = pThis->IsInDocBody();
1286 const bool bFootnote = !bBody && pThis->IsInFootnote();
1287 if ( bBody || bFootnote )
1289 while ( pPrvCnt )
1291 if ( (bBody && pPrvCnt->IsInDocBody()) ||
1292 (bFootnote && pPrvCnt->IsInFootnote()) )
1294 pRet = pPrvCnt->IsInTab() ? pPrvCnt->FindTabFrame()
1295 : static_cast<SwFrame*>(pPrvCnt);
1296 return pRet;
1298 pPrvCnt = pPrvCnt->GetPrevContentFrame();
1301 else if ( pThis->IsInFly() )
1303 pRet = pPrvCnt->IsInTab() ? pPrvCnt->FindTabFrame()
1304 : static_cast<SwFrame*>(pPrvCnt);
1305 return pRet;
1307 else // footer or header or Fly
1309 const SwFrame *pUp = pThis->GetUpper();
1310 const SwFrame *pCntUp = pPrvCnt->GetUpper();
1311 while ( pUp && pUp->GetUpper() &&
1312 !pUp->IsHeaderFrame() && !pUp->IsFooterFrame() )
1313 pUp = pUp->GetUpper();
1314 while ( pCntUp && pCntUp->GetUpper() )
1315 pCntUp = pCntUp->GetUpper();
1316 if ( pCntUp == pUp )
1318 pRet = pPrvCnt->IsInTab() ? pPrvCnt->FindTabFrame()
1319 : static_cast<SwFrame*>(pPrvCnt);
1320 return pRet;
1325 return nullptr;
1328 void SwFrame::ImplInvalidateNextPos( bool bNoFootnote )
1330 SwFrame *pFrame = FindNext_();
1331 if ( nullptr == pFrame )
1332 return;
1334 if( pFrame->IsSctFrame() )
1336 while( pFrame && pFrame->IsSctFrame() )
1338 if( static_cast<SwSectionFrame*>(pFrame)->GetSection() )
1340 SwFrame* pTmp = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
1341 if( pTmp )
1342 pTmp->InvalidatePos();
1343 else if( !bNoFootnote )
1344 static_cast<SwSectionFrame*>(pFrame)->InvalidateFootnotePos();
1345 if( !IsInSct() || FindSctFrame()->GetFollow() != pFrame )
1346 pFrame->InvalidatePos();
1347 return;
1349 pFrame = pFrame->FindNext();
1351 if( pFrame )
1353 if ( pFrame->IsSctFrame())
1355 // We need to invalidate the section's content so it gets
1356 // the chance to flow to a different page.
1357 SwFrame* pTmp = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
1358 if( pTmp )
1359 pTmp->InvalidatePos();
1360 if( !IsInSct() || FindSctFrame()->GetFollow() != pFrame )
1361 pFrame->InvalidatePos();
1363 else
1364 pFrame->InvalidatePos();
1367 else
1368 pFrame->InvalidatePos();
1371 /** method to invalidate printing area of next frame
1373 OD 09.01.2004 #i11859#
1375 FME 2004-04-19 #i27145# Moved function from SwTextFrame to SwFrame
1377 void SwFrame::InvalidateNextPrtArea()
1379 // determine next frame
1380 SwFrame* pNextFrame = FindNext();
1381 // skip empty section frames and hidden text frames
1383 while ( pNextFrame &&
1384 ( ( pNextFrame->IsSctFrame() &&
1385 !static_cast<SwSectionFrame*>(pNextFrame)->GetSection() ) ||
1386 ( pNextFrame->IsTextFrame() &&
1387 static_cast<SwTextFrame*>(pNextFrame)->IsHiddenNow() ) ) )
1389 pNextFrame = pNextFrame->FindNext();
1393 // Invalidate printing area of found next frame
1394 if ( !pNextFrame )
1395 return;
1397 if ( pNextFrame->IsSctFrame() )
1399 // Invalidate printing area of found section frame, if
1400 // (1) this text frame isn't in a section OR
1401 // (2) found section frame isn't a follow of the section frame this
1402 // text frame is in.
1403 if ( !IsInSct() || FindSctFrame()->GetFollow() != pNextFrame )
1405 pNextFrame->InvalidatePrt();
1408 // Invalidate printing area of first content in found section.
1409 SwFrame* pFstContentOfSctFrame =
1410 static_cast<SwSectionFrame*>(pNextFrame)->ContainsAny();
1411 if ( pFstContentOfSctFrame )
1413 pFstContentOfSctFrame->InvalidatePrt();
1416 else
1418 pNextFrame->InvalidatePrt();
1422 /// @returns true if the frame _directly_ sits in a section
1423 /// but not if it sits in a table which itself sits in a section.
1424 static bool lcl_IsInSectionDirectly( const SwFrame *pUp )
1426 bool bSeenColumn = false;
1428 while( pUp )
1430 if( pUp->IsColumnFrame() )
1431 bSeenColumn = true;
1432 else if( pUp->IsSctFrame() )
1434 auto pSection = static_cast<const SwSectionFrame*>(pUp);
1435 const SwFrame* pHeaderFooter = pSection->FindFooterOrHeader();
1436 // When the section frame is not in header/footer:
1437 // Allow move of frame in case our only column is not growable.
1438 // Also allow if there is a previous section frame (to move back).
1439 bool bAllowOutsideHeaderFooter = !pSection->Growable() || pSection->GetPrecede();
1440 return bSeenColumn || (!pHeaderFooter && bAllowOutsideHeaderFooter);
1442 else if( pUp->IsTabFrame() )
1443 return false;
1444 pUp = pUp->GetUpper();
1446 return false;
1449 /** determine, if frame is moveable in given environment
1451 OD 08.08.2003 #110978#
1452 method replaced 'old' method <sal_Bool IsMoveable() const>.
1453 Determines, if frame is moveable in given environment. if no environment
1454 is given (parameter _pLayoutFrame == 0), the movability in the actual
1455 environment (<GetUpper()) is checked.
1457 bool SwFrame::IsMoveable( const SwLayoutFrame* _pLayoutFrame ) const
1459 bool bRetVal = false;
1461 if ( !_pLayoutFrame )
1463 _pLayoutFrame = GetUpper();
1466 if ( _pLayoutFrame && IsFlowFrame() )
1468 if ( _pLayoutFrame->IsInSct() && lcl_IsInSectionDirectly( _pLayoutFrame ) )
1470 bRetVal = true;
1472 else if ( _pLayoutFrame->IsInFly() ||
1473 _pLayoutFrame->IsInDocBody() ||
1474 _pLayoutFrame->IsInFootnote() )
1476 // If IsMovable() is called before a MoveFwd() the method
1477 // may return false if there is no NextCellLeaf. If
1478 // IsMovable() is called before a MoveBwd() the method may
1479 // return false if there is no PrevCellLeaf.
1480 if ( _pLayoutFrame->IsInTab() && !IsTabFrame() &&
1481 ( !IsContentFrame() || (!const_cast<SwFrame*>(this)->GetNextCellLeaf()
1482 && !const_cast<SwFrame*>(this)->GetPrevCellLeaf()) )
1485 bRetVal = false;
1487 else
1489 if ( _pLayoutFrame->IsInFly() )
1491 // if fly frame has a follow (next linked fly frame) or can split,
1492 // frame is moveable.
1493 SwFlyFrame* pFlyFrame = const_cast<SwLayoutFrame*>(_pLayoutFrame)->FindFlyFrame();
1494 if ( pFlyFrame->GetNextLink() || pFlyFrame->IsFlySplitAllowed() )
1496 bRetVal = true;
1498 else
1500 // if environment is columned, frame is moveable, if
1501 // it isn't in last column.
1502 // search for column frame
1503 const SwFrame* pCol = _pLayoutFrame;
1504 while ( pCol && !pCol->IsColumnFrame() )
1506 pCol = pCol->GetUpper();
1508 // frame is moveable, if found column frame isn't last one.
1509 if ( pCol && pCol->GetNext() )
1511 bRetVal = true;
1515 else if (!(_pLayoutFrame->IsInFootnote() && (IsTabFrame() || IsInTab())))
1517 bRetVal = true;
1523 return bRetVal;
1526 void SwFrame::SetInfFlags()
1528 if ( !IsFlyFrame() && !GetUpper() ) //not yet pasted, no information available
1529 return;
1531 mbInfInvalid = mbInfBody = mbInfTab = mbInfFly = mbInfFootnote = mbInfSct = false;
1533 SwFrame *pFrame = this;
1534 if( IsFootnoteContFrame() )
1535 mbInfFootnote = true;
1538 // mbInfBody is only set in the page body, but not in the column body
1539 if ( pFrame->IsBodyFrame() && !mbInfFootnote && pFrame->GetUpper()
1540 && pFrame->GetUpper()->IsPageFrame() )
1541 mbInfBody = true;
1542 else if ( pFrame->IsTabFrame() || pFrame->IsCellFrame() )
1544 mbInfTab = true;
1546 else if ( pFrame->IsFlyFrame() )
1547 mbInfFly = true;
1548 else if ( pFrame->IsSctFrame() )
1549 mbInfSct = true;
1550 else if ( pFrame->IsFootnoteFrame() )
1551 mbInfFootnote = true;
1553 pFrame = pFrame->GetUpper();
1555 } while ( pFrame && !pFrame->IsPageFrame() ); //there is nothing above the page
1558 /** Updates the vertical or the righttoleft-flags.
1560 * If the property is derived, it's from the upper or (for fly frames) from
1561 * the anchor. Otherwise we've to call a virtual method to check the property.
1563 void SwFrame::SetDirFlags( bool bVert )
1565 if( bVert )
1567 // OD 2004-01-21 #114969# - if derived, valid vertical flag only if
1568 // vertical flag of upper/anchor is valid.
1569 if( mbDerivedVert )
1571 const SwFrame* pAsk = IsFlyFrame() ?
1572 static_cast<SwFlyFrame*>(this)->GetAnchorFrame() : GetUpper();
1574 OSL_ENSURE( pAsk != this, "Autsch! Stack overflow is about to happen" );
1576 if( pAsk )
1578 mbVertical = pAsk->IsVertical();
1579 mbVertLR = pAsk->IsVertLR();
1580 mbVertLRBT = pAsk->IsVertLRBT();
1582 if ( !pAsk->mbInvalidVert )
1583 mbInvalidVert = false;
1585 if ( IsCellFrame() )
1587 SwCellFrame* pPrv = static_cast<SwCellFrame*>(this)->GetPreviousCell();
1588 if ( pPrv && !mbVertical && pPrv->IsVertical() )
1590 mbVertical = pPrv->IsVertical();
1591 mbVertLR = pPrv->IsVertLR();
1592 mbVertLRBT = pPrv->IsVertLRBT();
1597 else
1598 CheckDirection( bVert );
1600 else
1602 bool bInv = false;
1603 if( !mbDerivedR2L ) // CheckDirection is able to set bDerivedR2L!
1604 CheckDirection( bVert );
1605 if( mbDerivedR2L )
1607 const SwFrame* pAsk = IsFlyFrame() ?
1608 static_cast<SwFlyFrame*>(this)->GetAnchorFrame() : GetUpper();
1610 OSL_ENSURE( pAsk != this, "Oops! Stack overflow is about to happen" );
1612 if( pAsk )
1613 mbRightToLeft = pAsk->IsRightToLeft();
1614 if( !pAsk || pAsk->mbInvalidR2L )
1615 bInv = mbInvalidR2L;
1617 mbInvalidR2L = bInv;
1621 SwLayoutFrame* SwFrame::GetNextCellLeaf()
1623 SwFrame* pTmpFrame = this;
1624 while (pTmpFrame && !pTmpFrame->IsCellFrame())
1625 pTmpFrame = pTmpFrame->GetUpper();
1627 SAL_WARN_IF(!pTmpFrame, "sw.core", "SwFrame::GetNextCellLeaf() without cell");
1628 return pTmpFrame ? static_cast<SwCellFrame*>(pTmpFrame)->GetFollowCell() : nullptr;
1631 SwLayoutFrame* SwFrame::GetPrevCellLeaf()
1633 SwFrame* pTmpFrame = this;
1634 while (pTmpFrame && !pTmpFrame->IsCellFrame())
1635 pTmpFrame = pTmpFrame->GetUpper();
1637 SAL_WARN_IF(!pTmpFrame, "sw.core", "SwFrame::GetNextPreviousLeaf() without cell");
1638 return pTmpFrame ? static_cast<SwCellFrame*>(pTmpFrame)->GetPreviousCell() : nullptr;
1641 static SwCellFrame* lcl_FindCorrespondingCellFrame( const SwRowFrame& rOrigRow,
1642 const SwCellFrame& rOrigCell,
1643 const SwRowFrame& rCorrRow,
1644 bool bInFollow )
1646 SwCellFrame* pRet = nullptr;
1647 const SwCellFrame* pCell = static_cast<const SwCellFrame*>(rOrigRow.Lower());
1648 SwCellFrame* pCorrCell = const_cast<SwCellFrame*>(static_cast<const SwCellFrame*>(rCorrRow.Lower()));
1650 while ( pCell != &rOrigCell && !pCell->IsAnLower( &rOrigCell ) )
1652 pCell = static_cast<const SwCellFrame*>(pCell->GetNext());
1653 pCorrCell = static_cast<SwCellFrame*>(pCorrCell->GetNext());
1656 assert(pCell && pCorrCell && "lcl_FindCorrespondingCellFrame does not work");
1658 if ( pCell != &rOrigCell )
1660 // rOrigCell must be a lower of pCell. We need to recurse into the rows:
1661 assert(pCell->Lower() && pCell->Lower()->IsRowFrame() &&
1662 "lcl_FindCorrespondingCellFrame does not work");
1664 const SwRowFrame* pRow = static_cast<const SwRowFrame*>(pCell->Lower());
1665 while ( !pRow->IsAnLower( &rOrigCell ) )
1666 pRow = static_cast<const SwRowFrame*>(pRow->GetNext());
1668 SwRowFrame* pCorrRow = nullptr;
1669 if ( bInFollow )
1670 pCorrRow = pRow->GetFollowRow();
1671 else
1673 SwRowFrame* pTmpRow = static_cast<SwRowFrame*>(pCorrCell->GetLastLower());
1675 if ( pTmpRow && pTmpRow->GetFollowRow() == pRow )
1676 pCorrRow = pTmpRow;
1679 if ( pCorrRow )
1680 pRet = lcl_FindCorrespondingCellFrame( *pRow, rOrigCell, *pCorrRow, bInFollow );
1682 else
1683 pRet = pCorrCell;
1685 return pRet;
1688 // VERSION OF GetFollowCell() that assumes that we always have a follow flow line:
1689 SwCellFrame* SwCellFrame::GetFollowCell() const
1691 SwCellFrame* pRet = nullptr;
1693 // NEW TABLES
1694 // Covered cells do not have follow cells!
1695 const tools::Long nRowSpan = GetLayoutRowSpan();
1696 if ( nRowSpan < 1 )
1697 return nullptr;
1699 // find most upper row frame
1700 const SwFrame* pRow = GetUpper();
1702 while (pRow && (!pRow->IsRowFrame() || !pRow->GetUpper()->IsTabFrame()))
1703 pRow = pRow->GetUpper();
1705 if (!pRow)
1706 return nullptr;
1708 const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>(pRow->GetUpper());
1709 if (!pTabFrame || !pTabFrame->GetFollow() || !pTabFrame->HasFollowFlowLine())
1710 return nullptr;
1712 const SwCellFrame* pThisCell = this;
1714 // Get last cell of the current table frame that belongs to the rowspan:
1715 if ( nRowSpan > 1 )
1717 // optimization: Will end of row span be in last row or exceed row?
1718 tools::Long nMax = 0;
1719 while ( pRow->GetNext() && ++nMax < nRowSpan )
1720 pRow = pRow->GetNext();
1722 if ( !pRow->GetNext() )
1724 pThisCell = &pThisCell->FindStartEndOfRowSpanCell( false );
1725 pRow = pThisCell->GetUpper();
1729 const SwRowFrame* pFollowRow = nullptr;
1730 if ( !pRow->GetNext() &&
1731 nullptr != ( pFollowRow = pRow->IsInSplitTableRow() ) &&
1732 ( !pFollowRow->IsRowSpanLine() || nRowSpan > 1 ) )
1733 pRet = lcl_FindCorrespondingCellFrame( *static_cast<const SwRowFrame*>(pRow), *pThisCell, *pFollowRow, true );
1735 return pRet;
1738 // VERSION OF GetPreviousCell() THAT ASSUMES THAT WE ALWAYS HAVE A FFL
1739 SwCellFrame* SwCellFrame::GetPreviousCell() const
1741 SwCellFrame* pRet = nullptr;
1743 // NEW TABLES
1744 // Covered cells do not have previous cells!
1745 if ( GetLayoutRowSpan() < 1 )
1746 return nullptr;
1748 // find most upper row frame
1749 const SwFrame* pRow = GetUpper();
1750 while( !pRow->IsRowFrame() || (pRow->GetUpper() && !pRow->GetUpper()->IsTabFrame()) )
1751 pRow = pRow->GetUpper();
1753 OSL_ENSURE( pRow->GetUpper() && pRow->GetUpper()->IsTabFrame(), "GetPreviousCell without Table" );
1755 const SwTabFrame* pTab = static_cast<const SwTabFrame*>(pRow->GetUpper());
1757 if ( pTab && pTab->IsFollow() )
1759 const SwFrame* pTmp = pTab->GetFirstNonHeadlineRow();
1760 const bool bIsInFirstLine = ( pTmp == pRow );
1762 if ( bIsInFirstLine )
1764 SwTabFrame *pMaster = pTab->FindMaster();
1765 if ( pMaster && pMaster->HasFollowFlowLine() )
1767 SwRowFrame* pMasterRow = static_cast<SwRowFrame*>(pMaster->GetLastLower());
1768 if ( pMasterRow )
1769 pRet = lcl_FindCorrespondingCellFrame( *static_cast<const SwRowFrame*>(pRow), *this, *pMasterRow, false );
1770 if ( pRet && pRet->GetTabBox()->getRowSpan() < 1 )
1771 pRet = &const_cast<SwCellFrame&>(pRet->FindStartEndOfRowSpanCell( true ));
1776 return pRet;
1779 // --> NEW TABLES
1780 const SwCellFrame& SwCellFrame::FindStartEndOfRowSpanCell( bool bStart ) const
1782 const SwTabFrame* pTableFrame = dynamic_cast<const SwTabFrame*>(GetUpper()->GetUpper());
1784 if ( !bStart && pTableFrame && pTableFrame->IsFollow() && pTableFrame->IsInHeadline( *this ) )
1785 return *this;
1787 OSL_ENSURE( pTableFrame &&
1788 ( (bStart && GetTabBox()->getRowSpan() < 1) ||
1789 (!bStart && GetLayoutRowSpan() > 1) ),
1790 "SwCellFrame::FindStartRowSpanCell: No rowspan, no table, no cookies" );
1792 if ( pTableFrame )
1794 const SwTable* pTable = pTableFrame->GetTable();
1796 sal_uInt16 nMax = USHRT_MAX;
1797 const SwFrame* pCurrentRow = GetUpper();
1798 const bool bDoNotEnterHeadline = bStart && pTableFrame->IsFollow() &&
1799 !pTableFrame->IsInHeadline( *pCurrentRow );
1801 // check how many rows we are allowed to go up or down until we reach the end of
1802 // the current table frame:
1803 nMax = 0;
1804 while ( bStart ? pCurrentRow->GetPrev() : pCurrentRow->GetNext() )
1806 if ( bStart )
1808 // do not enter a repeated headline:
1809 if ( bDoNotEnterHeadline && pTableFrame->IsFollow() &&
1810 pTableFrame->IsInHeadline( *pCurrentRow->GetPrev() ) )
1811 break;
1813 pCurrentRow = pCurrentRow->GetPrev();
1815 else
1816 pCurrentRow = pCurrentRow->GetNext();
1818 ++nMax;
1821 // By passing the nMax value for Find*OfRowSpan (in case of bCurrentTableOnly
1822 // is set) we assure that we find a rMasterBox that has a SwCellFrame in
1823 // the current table frame:
1824 const SwTableBox& rMasterBox = bStart ?
1825 GetTabBox()->FindStartOfRowSpan( *pTable, nMax ) :
1826 GetTabBox()->FindEndOfRowSpan( *pTable, nMax );
1828 SwIterator<SwCellFrame,SwFormat> aIter( *rMasterBox.GetFrameFormat() );
1830 for ( SwCellFrame* pMasterCell = aIter.First(); pMasterCell; pMasterCell = aIter.Next() )
1832 if ( pMasterCell->GetTabBox() == &rMasterBox )
1834 const SwTabFrame* pMasterTable = static_cast<const SwTabFrame*>(pMasterCell->GetUpper()->GetUpper());
1836 if ( pMasterTable == pTableFrame )
1838 return *pMasterCell;
1844 SAL_WARN("sw.core", "SwCellFrame::FindStartRowSpanCell: No result");
1846 return *this;
1849 // <-- NEW TABLES
1851 const SwRowFrame* SwFrame::IsInSplitTableRow() const
1853 OSL_ENSURE( IsInTab(), "IsInSplitTableRow should only be called for frames in tables" );
1855 const SwFrame* pRow = this;
1857 // find most upper row frame
1858 while( pRow && ( !pRow->IsRowFrame() || !pRow->GetUpper()->IsTabFrame() ) )
1859 pRow = pRow->GetUpper();
1861 if ( !pRow ) return nullptr;
1863 OSL_ENSURE( pRow->GetUpper()->IsTabFrame(), "Confusion in table layout" );
1865 const SwTabFrame* pTab = static_cast<const SwTabFrame*>(pRow->GetUpper());
1867 // If most upper row frame is a headline row, the current frame
1868 // can't be in a split table row. Thus, add corresponding condition.
1869 if ( pRow->GetNext() ||
1870 pTab->GetTable()->IsHeadline(
1871 *(static_cast<const SwRowFrame*>(pRow)->GetTabLine()) ) ||
1872 !pTab->HasFollowFlowLine() ||
1873 !pTab->GetFollow() )
1874 return nullptr;
1876 // skip headline
1877 const SwRowFrame* pFollowRow = pTab->GetFollow()->GetFirstNonHeadlineRow();
1879 OSL_ENSURE( pFollowRow, "SwFrame::IsInSplitTableRow() does not work" );
1881 return pFollowRow;
1884 const SwRowFrame* SwFrame::IsInFollowFlowRow() const
1886 OSL_ENSURE( IsInTab(), "IsInSplitTableRow should only be called for frames in tables" );
1888 // find most upper row frame
1889 const SwFrame* pRow = this;
1890 while( pRow && ( !pRow->IsRowFrame() || !pRow->GetUpper()->IsTabFrame() ) )
1891 pRow = pRow->GetUpper();
1893 if ( !pRow ) return nullptr;
1895 OSL_ENSURE( pRow->GetUpper()->IsTabFrame(), "Confusion in table layout" );
1897 const SwTabFrame* pTab = static_cast<const SwTabFrame*>(pRow->GetUpper());
1899 const SwTabFrame* pMaster = pTab->IsFollow() ? pTab->FindMaster() : nullptr;
1901 if ( !pMaster || !pMaster->HasFollowFlowLine() )
1902 return nullptr;
1904 const SwFrame* pTmp = pTab->GetFirstNonHeadlineRow();
1905 const bool bIsInFirstLine = ( pTmp == pRow );
1907 if ( !bIsInFirstLine )
1908 return nullptr;
1910 const SwRowFrame* pMasterRow = static_cast<const SwRowFrame*>(pMaster->GetLastLower());
1911 return pMasterRow;
1914 bool SwFrame::IsInBalancedSection() const
1916 bool bRet = false;
1918 if ( IsInSct() )
1920 const SwSectionFrame* pSectionFrame = FindSctFrame();
1921 if ( pSectionFrame )
1922 bRet = pSectionFrame->IsBalancedSection();
1924 return bRet;
1927 const SwFrame* SwLayoutFrame::GetLastLower() const
1929 const SwFrame* pRet = Lower();
1930 if ( !pRet )
1931 return nullptr;
1932 while ( pRet->GetNext() )
1933 pRet = pRet->GetNext();
1934 return pRet;
1937 SwTextFrame* SwFrame::DynCastTextFrame()
1939 return IsTextFrame() ? static_cast<SwTextFrame*>(this) : nullptr;
1942 const SwTextFrame* SwFrame::DynCastTextFrame() const
1944 return IsTextFrame() ? static_cast<const SwTextFrame*>(this) : nullptr;
1947 SwPageFrame* SwFrame::DynCastPageFrame()
1949 return IsPageFrame() ? static_cast<SwPageFrame*>(this) : nullptr;
1952 const SwPageFrame* SwFrame::DynCastPageFrame() const
1954 return IsPageFrame() ? static_cast<const SwPageFrame*>(this) : nullptr;
1957 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */