xref: /core/sw/source/core/layout/findfrm.cxx (revision 6450159e)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <pagefrm.hxx>
21 #include <colfrm.hxx>
22 #include <rootfrm.hxx>
23 #include <cellfrm.hxx>
24 #include <rowfrm.hxx>
25 #include <swtable.hxx>
26 #include <notxtfrm.hxx>
27 #include <tabfrm.hxx>
28 #include <sectfrm.hxx>
29 #include <frmatr.hxx>
30 #include <flyfrm.hxx>
31 #include <ftnfrm.hxx>
32 #include <txtftn.hxx>
33 #include <fmtftn.hxx>
34 #include <fmtpdsc.hxx>
35 #include <fmtclbl.hxx>
36 #include <txtfrm.hxx>
37 #include <bodyfrm.hxx>
38 #include <calbck.hxx>
39 #include <viewopt.hxx>
40 #include <ndtxt.hxx>
41 #include <osl/diagnose.h>
42 #include <sal/log.hxx>
43 #include <IDocumentSettingAccess.hxx>
44 #include <formatflysplit.hxx>
45 #include <flyfrms.hxx>
46 
47 
48 /// Searches the first ContentFrame in BodyText below the page.
FindBodyCont()49 SwLayoutFrame *SwFootnoteBossFrame::FindBodyCont()
50 {
51     SwFrame *pLay = Lower();
52     while ( pLay && !pLay->IsBodyFrame() )
53         pLay = pLay->GetNext();
54     return static_cast<SwLayoutFrame*>(pLay);
55 }
56 
57 /// Searches the last ContentFrame in BodyText below the page.
FindLastBodyContent()58 SwContentFrame *SwPageFrame::FindLastBodyContent()
59 {
60     SwContentFrame *pRet = FindFirstBodyContent();
61     SwContentFrame *pNxt = pRet;
62     while ( pNxt && pNxt->IsInDocBody() && IsAnLower( pNxt ) )
63     {   pRet = pNxt;
64         pNxt = pNxt->FindNextCnt();
65     }
66     return pRet;
67 }
68 
GetEndNoteSection()69 SwSectionFrame* SwPageFrame::GetEndNoteSection()
70 {
71     SwLayoutFrame* pBody = FindBodyCont();
72     if (!pBody)
73     {
74         return nullptr;
75     }
76 
77     SwFrame* pLast = pBody->GetLastLower();
78     if (!pLast || !pLast->IsSctFrame())
79     {
80         return nullptr;
81     }
82 
83     auto pLastSection = static_cast<SwSectionFrame*>(pLast);
84     if (!pLastSection->IsEndNoteSection())
85     {
86         return nullptr;
87     }
88 
89     return pLastSection;
90 }
91 
92 /**
93  * Checks if the frame contains one or more ContentFrame's anywhere in his
94  * subsidiary structure; if so the first found ContentFrame is returned.
95  */
ContainsContent() const96 const SwContentFrame *SwLayoutFrame::ContainsContent() const
97 {
98     //Search downwards the layout leaf and if there is no content, jump to the
99     //next leaf until content is found or we leave "this".
100     //Sections: Content next to sections would not be found this way (empty
101     //sections directly next to ContentFrame) therefore we need to recursively
102     //search for them even if it's more complex.
103 
104     const SwLayoutFrame *pLayLeaf = this;
105     do
106     {
107         while ( (!pLayLeaf->IsSctFrame() || pLayLeaf == this ) &&
108                 pLayLeaf->Lower() && pLayLeaf->Lower()->IsLayoutFrame() )
109             pLayLeaf = static_cast<const SwLayoutFrame*>(pLayLeaf->Lower());
110 
111         if( pLayLeaf->IsSctFrame() && pLayLeaf != this )
112         {
113             const SwContentFrame *pCnt = pLayLeaf->ContainsContent();
114             if( pCnt )
115                 return pCnt;
116             if( pLayLeaf->GetNext() )
117             {
118                 if( pLayLeaf->GetNext()->IsLayoutFrame() )
119                 {
120                     pLayLeaf = static_cast<const SwLayoutFrame*>(pLayLeaf->GetNext());
121                     continue;
122                 }
123                 else
124                     return static_cast<const SwContentFrame*>(pLayLeaf->GetNext());
125             }
126         }
127         else if ( pLayLeaf->Lower() )
128             return static_cast<const SwContentFrame*>(pLayLeaf->Lower());
129 
130         pLayLeaf = pLayLeaf->GetNextLayoutLeaf();
131         if( !IsAnLower( pLayLeaf) )
132             return nullptr;
133     } while( pLayLeaf );
134     return nullptr;
135 }
136 
137 /**
138  * Calls ContainsAny first to reach the innermost cell. From there we walk back
139  * up to the first SwCellFrame. Since we use SectionFrames, ContainsContent()->GetUpper()
140  * is not enough anymore.
141  */
FirstCell() const142 const SwCellFrame *SwLayoutFrame::FirstCell() const
143 {
144     const SwFrame* pCnt = ContainsAny();
145     while( pCnt && !pCnt->IsCellFrame() )
146         pCnt = pCnt->GetUpper();
147     return static_cast<const SwCellFrame*>(pCnt);
148 }
149 
150 /** return ContentFrames, sections, and tables.
151  *
152  * @param _bInvestigateFootnoteForSections controls investigation of content of footnotes for sections.
153  * @see ContainsContent
154  */
ContainsAny(const bool _bInvestigateFootnoteForSections) const155 const SwFrame *SwLayoutFrame::ContainsAny( const bool _bInvestigateFootnoteForSections ) const
156 {
157     //Search downwards the layout leaf and if there is no content, jump to the
158     //next leaf until content is found, we leave "this" or until we found
159     //a SectionFrame or a TabFrame.
160 
161     const SwLayoutFrame *pLayLeaf = this;
162     const bool bNoFootnote = IsSctFrame() && !_bInvestigateFootnoteForSections;
163     do
164     {
165         while ( ( (!pLayLeaf->IsSctFrame() && !pLayLeaf->IsTabFrame())
166                  || pLayLeaf == this ) &&
167                 pLayLeaf->Lower() && pLayLeaf->Lower()->IsLayoutFrame() )
168             pLayLeaf = static_cast<const SwLayoutFrame*>(pLayLeaf->Lower());
169 
170         if( ( pLayLeaf->IsTabFrame() || pLayLeaf->IsSctFrame() )
171             && pLayLeaf != this )
172         {
173             // Now we also return "deleted" SectionFrames so they can be
174             // maintained on SaveContent and RestoreContent
175             return pLayLeaf;
176         }
177         else if ( pLayLeaf->Lower() )
178             return static_cast<const SwContentFrame*>(pLayLeaf->Lower());
179 
180         pLayLeaf = pLayLeaf->GetNextLayoutLeaf();
181         if( bNoFootnote && pLayLeaf && pLayLeaf->IsInFootnote() )
182         {
183             do
184             {
185                 pLayLeaf = pLayLeaf->GetNextLayoutLeaf();
186             } while( pLayLeaf && pLayLeaf->IsInFootnote() );
187         }
188         if( !IsAnLower( pLayLeaf) )
189             return nullptr;
190     } while( pLayLeaf );
191     return nullptr;
192 }
193 
ContainsDeleteForbiddenLayFrame() const194 bool SwLayoutFrame::ContainsDeleteForbiddenLayFrame() const
195 {
196     if (IsDeleteForbidden())
197     {
198         return true;
199     }
200     for (SwFrame const* pFrame = Lower(); pFrame; pFrame = pFrame->GetNext())
201     {
202         if (!pFrame->IsLayoutFrame())
203         {
204             continue;
205         }
206         SwLayoutFrame const*const pLay(static_cast<SwLayoutFrame const*>(pFrame));
207         if (pLay->ContainsDeleteForbiddenLayFrame() || pLay->IsColLocked())
208         {
209             return true;
210         }
211     }
212     return false;
213 }
214 
GetLower() const215 const SwFrame* SwFrame::GetLower() const
216 {
217     return IsLayoutFrame() ? static_cast<const SwLayoutFrame*>(this)->Lower() : nullptr;
218 }
219 
GetLower()220 SwFrame* SwFrame::GetLower()
221 {
222     return IsLayoutFrame() ? static_cast<SwLayoutFrame*>(this)->Lower() : nullptr;
223 }
224 
FindPrevCnt()225 SwContentFrame* SwFrame::FindPrevCnt( )
226 {
227     if ( GetPrev() && GetPrev()->IsContentFrame() )
228         return static_cast<SwContentFrame*>(GetPrev());
229     else
230         return FindPrevCnt_();
231 }
232 
FindPrevCnt() const233 const SwContentFrame* SwFrame::FindPrevCnt() const
234 {
235     if ( GetPrev() && GetPrev()->IsContentFrame() )
236         return static_cast<const SwContentFrame*>(GetPrev());
237     else
238         return const_cast<SwFrame*>(this)->FindPrevCnt_();
239 }
240 
FindNextCnt(const bool _bInSameFootnote)241 SwContentFrame *SwFrame::FindNextCnt( const bool _bInSameFootnote )
242 {
243     if ( mpNext && mpNext->IsContentFrame() )
244         return static_cast<SwContentFrame*>(mpNext);
245     else
246         return FindNextCnt_( _bInSameFootnote );
247 }
248 
FindNextCnt(const bool _bInSameFootnote) const249 const SwContentFrame *SwFrame::FindNextCnt( const bool _bInSameFootnote ) const
250 {
251     if ( mpNext && mpNext->IsContentFrame() )
252         return static_cast<SwContentFrame*>(mpNext);
253     else
254         return const_cast<SwFrame*>(this)->FindNextCnt_( _bInSameFootnote );
255 }
256 
IsAnLower(const SwFrame * pAssumed) const257 bool SwLayoutFrame::IsAnLower( const SwFrame *pAssumed ) const
258 {
259     const SwFrame *pUp = pAssumed;
260     while ( pUp )
261     {
262         if (!pUp->IsInDtor())
263         {
264             if (pUp == this)
265                 return true;
266             if (pUp->IsFlyFrame())
267                 pUp = static_cast<const SwFlyFrame*>(pUp)->GetAnchorFrame();
268             else
269                 pUp = pUp->GetUpper();
270         }
271         else
272             break;
273     }
274     return false;
275 }
276 
277 /** method to check relative position of layout frame to
278     a given layout frame.
279 
280     OD 08.11.2002 - refactoring of pseudo-local method <lcl_Apres(..)> in
281     <txtftn.cxx> for #104840#.
282 
283     @param _aCheckRefLayFrame
284     constant reference of an instance of class <SwLayoutFrame> which
285     is used as the reference for the relative position check.
286 
287     @return true, if <this> is positioned before the layout frame <p>
288 */
IsBefore(const SwLayoutFrame * _pCheckRefLayFrame) const289 bool SwLayoutFrame::IsBefore( const SwLayoutFrame* _pCheckRefLayFrame ) const
290 {
291     OSL_ENSURE( !IsRootFrame() , "<IsBefore> called at a <SwRootFrame>.");
292     OSL_ENSURE( !_pCheckRefLayFrame->IsRootFrame() , "<IsBefore> called with a <SwRootFrame>.");
293 
294     bool bReturn;
295 
296     // check, if on different pages
297     const SwPageFrame *pMyPage = FindPageFrame();
298     const SwPageFrame *pCheckRefPage = _pCheckRefLayFrame->FindPageFrame();
299     if( pMyPage != pCheckRefPage )
300     {
301         // being on different page as check reference
302         bReturn = pMyPage->GetPhyPageNum() < pCheckRefPage->GetPhyPageNum();
303     }
304     else
305     {
306         // being on same page as check reference
307         // --> search my supreme parent <pUp>, which doesn't contain check reference.
308         const SwLayoutFrame* pUp = this;
309         while ( pUp->GetUpper() &&
310                 !pUp->GetUpper()->IsAnLower( _pCheckRefLayFrame )
311               )
312             pUp = pUp->GetUpper();
313         if( !pUp->GetUpper() )
314         {
315             // can occur, if <this> is a fly frm
316             bReturn = false;
317         }
318         else
319         {
320             // travel through the next's of <pUp> and check if one of these
321             // contain the check reference.
322             const SwLayoutFrame* pUpNext = static_cast<const SwLayoutFrame*>(pUp->GetNext());
323             while ( pUpNext &&
324                     !pUpNext->IsAnLower( _pCheckRefLayFrame ) )
325             {
326                 pUpNext = static_cast<const SwLayoutFrame*>(pUpNext->GetNext());
327             }
328             bReturn = pUpNext != nullptr;
329         }
330     }
331 
332     return bReturn;
333 }
334 
335 // Local helper functions for GetNextLayoutLeaf
336 
lcl_FindLayoutFrame(const SwFrame * pFrame,bool bNext)337 static const SwFrame* lcl_FindLayoutFrame( const SwFrame* pFrame, bool bNext )
338 {
339     const SwFrame* pRet = nullptr;
340     if ( pFrame->IsFlyFrame() )
341     {
342         auto pFlyFrame = static_cast<const SwFlyFrame*>(pFrame);
343         if (pFlyFrame->IsFlySplitAllowed())
344         {
345             // This is a flow frame, look up the follow/precede.
346             auto pFlyAtContent = static_cast<const SwFlyAtContentFrame*>(pFlyFrame);
347             pRet = bNext ? pFlyAtContent->GetFollow() : pFlyAtContent->GetPrecede();
348         }
349         else
350         {
351             pRet = bNext ? pFlyFrame->GetNextLink() : pFlyFrame->GetPrevLink();
352         }
353     }
354     else
355         pRet = bNext ? pFrame->GetNext() : pFrame->GetPrev();
356 
357     return pRet;
358 }
359 
lcl_GetLower(const SwFrame * pFrame,bool bFwd)360 static const SwFrame* lcl_GetLower( const SwFrame* pFrame, bool bFwd )
361 {
362     if ( !pFrame->IsLayoutFrame() )
363         return nullptr;
364 
365     return bFwd ?
366            static_cast<const SwLayoutFrame*>(pFrame)->Lower() :
367            static_cast<const SwLayoutFrame*>(pFrame)->GetLastLower();
368 }
369 
370 /**
371  * Finds the next layout leaf. This is a layout frame, which does not
372  * have a lower which is a LayoutFrame. That means, pLower can be 0 or a
373  * content frame.
374  *
375  * However, pLower may be a TabFrame
376  */
ImplGetNextLayoutLeaf(bool bFwd) const377 const SwLayoutFrame *SwFrame::ImplGetNextLayoutLeaf( bool bFwd ) const
378 {
379     const SwFrame       *pFrame = this;
380     const SwLayoutFrame *pLayoutFrame = nullptr;
381     const SwFrame       *p = nullptr;
382     bool bGoingUp = !bFwd;          // false for forward, true for backward
383     // The anchor is this frame, unless we traverse the anchor of a split fly.
384     const SwFrame* pAnchor = this;
385     do {
386 
387          bool bGoingFwdOrBwd = false;
388 
389          bool bGoingDown = !bGoingUp;
390          if (bGoingDown)
391          {
392             p = lcl_GetLower( pFrame, bFwd );
393             bGoingDown = nullptr != p;
394          }
395          if ( !bGoingDown )
396          {
397              // I cannot go down, because either I'm currently going up or
398              // because the is no lower.
399              // I'll try to go forward:
400              p = lcl_FindLayoutFrame( pFrame, bFwd );
401              bGoingFwdOrBwd = nullptr != p;
402              if ( !bGoingFwdOrBwd )
403              {
404                  // I cannot go forward, because there is no next frame.
405                  // I'll try to go up:
406                  p = pFrame->GetUpper();
407 
408                  if (!p && pFrame->IsFlyFrame())
409                  {
410                      const SwFlyFrame* pFlyFrame = pFrame->FindFlyFrame();
411                      if (pFlyFrame->IsFlySplitAllowed())
412                      {
413                          p = const_cast<SwFlyFrame*>(pFlyFrame)->FindAnchorCharFrame();
414                          // Remember the anchor frame, so if we look for the leaf of a frame in a
415                          // split fly (anchored in the master of a text frame, but rendered on the
416                          // next page), we won't return a frame on the next page, rather return
417                          // nullptr.
418                          pAnchor = p;
419                      }
420                  }
421 
422                  bGoingUp = nullptr != p;
423                  if ( !bGoingUp )
424                  {
425                     // I cannot go up, because there is no upper frame.
426                     return nullptr;
427                  }
428              }
429          }
430 
431          // If I could not go down or forward, I'll have to go up
432          bGoingUp = !bGoingFwdOrBwd && !bGoingDown;
433 
434          pFrame = p;
435          p = lcl_GetLower( pFrame, true );
436 
437     } while( ( p && !p->IsFlowFrame() ) ||
438              pFrame == this ||
439              nullptr == ( pLayoutFrame = pFrame->IsLayoutFrame() ? static_cast<const SwLayoutFrame*>(pFrame) : nullptr ) ||
440              pLayoutFrame->IsAnLower( pAnchor ) );
441 
442     return pLayoutFrame;
443 }
444 
445 /**
446  * Walk back inside the tree: grab the subordinate Frame if one exists and the
447  * last step was not moving up a level (this would lead to an infinite up/down
448  * loop!). With this we ensure that during walking back we search through all
449  * sub trees. If we walked downwards we have to go to the end of the chain first
450  * because we go backwards from the last Frame inside another Frame. Walking
451  * forward works the same.
452  *
453  * @warning fixes here may also need to be applied to the @{lcl_NextFrame} method above
454  */
ImplGetNextContentFrame(bool bFwd) const455 const SwContentFrame* SwContentFrame::ImplGetNextContentFrame( bool bFwd ) const
456 {
457     const SwFrame *pFrame = this;
458     const SwContentFrame *pContentFrame = nullptr;
459     bool bGoingUp = false;
460     do {
461         const SwFrame *p = nullptr;
462         bool bGoingFwdOrBwd = false;
463 
464         bool bGoingDown = !bGoingUp;
465         if (bGoingDown)
466         {
467             p = lcl_GetLower( pFrame, true ) ;
468             bGoingDown = nullptr != p;
469         }
470         if ( !bGoingDown )
471         {
472             p = lcl_FindLayoutFrame( pFrame, bFwd );
473             bGoingFwdOrBwd = nullptr != p;
474             if ( !bGoingFwdOrBwd )
475             {
476                 p = pFrame->GetUpper();
477                 bGoingUp = nullptr != p;
478                 if ( !bGoingUp )
479                 {
480                     return nullptr;
481                 }
482             }
483         }
484 
485         bGoingUp = !(bGoingFwdOrBwd || bGoingDown);
486         assert(p);
487         if (!bFwd && bGoingDown)
488         {
489                 while ( p->GetNext() )
490                     p = p->GetNext();
491         }
492 
493         pFrame = p;
494     } while ( nullptr == (pContentFrame = (pFrame->IsContentFrame() ? static_cast<const SwContentFrame*>(pFrame) : nullptr) ));
495 
496     return pContentFrame;
497 }
498 
ImplFindPageFrame()499 SwPageFrame* SwFrame::ImplFindPageFrame()
500 {
501     SwFrame *pRet = this;
502     while ( pRet )
503     {
504         if (pRet->IsInDtor())
505             return nullptr;
506 
507         if (pRet->IsPageFrame())
508             break;
509 
510         if ( pRet->GetUpper() )
511             pRet = pRet->GetUpper();
512         else if ( pRet->IsFlyFrame() )
513         {
514             // #i28701# - use new method <GetPageFrame()>
515             const auto pFly(static_cast<SwFlyFrame*>(pRet));
516             pRet = pFly->GetPageFrame();
517             if (pRet == nullptr)
518                 pRet = pFly->AnchorFrame();
519         }
520         else
521             return nullptr;
522     }
523     return static_cast<SwPageFrame*>(pRet);
524 }
525 
FindFootnoteBossFrame(bool bFootnotes)526 SwFootnoteBossFrame* SwFrame::FindFootnoteBossFrame( bool bFootnotes )
527 {
528     SwFrame *pRet = this;
529     // Footnote bosses can't exist inside a table; also sections with columns
530     // don't contain footnote texts there
531     if (SwFrame *pTabFrame = pRet->IsInTab() ? pRet->FindTabFrame() : nullptr)
532         pRet = pTabFrame;
533 
534     // tdf139336: put the footnotes into the page frame (instead of a column frame)
535     // to avoid maximizing the section to the full page.... if:
536     // - it is in a section
537     // - collect footnotes at section end (FootnoteAtEnd) is not set
538     // - columns are evenly distributed (=balanced) is not set
539     // Note 1: at page end, the footnotes have no multi-column-capability,
540     //         so this fix is used only where there is better chance to help
541     // Note 2: If balanced is not set, there is a higher chance that the 1. column will reach
542     //         the end of the page... if that happens the section will be maximized anyway.
543     // Note 3: The user will be able to easily choose the old layout (with multi-column footnotes)
544     //         with this setting.
545     //         similar case can be reached with a page break + FootnoteAtEnd setting
546     SwSectionFrame* pSectframe = pRet->FindSctFrame();
547     bool bMoveToPageFrame = false;
548     // tdf146704: only if it is really a footnote, not an endnote.
549     // tdf54465: compatibility flag to make old odt files keep these full page sections.
550     if (bFootnotes && pSectframe
551         && pSectframe->GetFormat()->getIDocumentSettingAccess().get(
552             DocumentSettingId::FOOTNOTE_IN_COLUMN_TO_PAGEEND))
553     {
554         SwSection* pSect = pSectframe->GetSection();
555         if (pSect) {
556             bool bNoBalance = pSect->GetFormat()->GetBalancedColumns().GetValue();
557             bool bFAtEnd = pSectframe->IsFootnoteAtEnd();
558             bMoveToPageFrame = !bFAtEnd && !bNoBalance;
559         }
560     }
561     while (pRet && !pRet->IsInDtor()
562            && ((!bMoveToPageFrame && !pRet->IsFootnoteBossFrame())
563                || (bMoveToPageFrame && !pRet->IsPageFrame())))
564     {
565         if ( pRet->GetUpper() )
566             pRet = pRet->GetUpper();
567         else if ( pRet->IsFlyFrame() )
568         {
569             // #i28701# - use new method <GetPageFrame()>
570             if ( static_cast<SwFlyFrame*>(pRet)->GetPageFrame() )
571                 pRet = static_cast<SwFlyFrame*>(pRet)->GetPageFrame();
572             else
573                 pRet = static_cast<SwFlyFrame*>(pRet)->AnchorFrame();
574         }
575         else
576             return nullptr;
577     }
578     if( bFootnotes && pRet && pRet->IsColumnFrame() &&
579         !pRet->GetNext() && !pRet->GetPrev() )
580     {
581         SwSectionFrame* pSct = pRet->FindSctFrame();
582         assert(pSct && "FindFootnoteBossFrame: Single column outside section?");
583         if( !pSct->IsFootnoteAtEnd() )
584             return pSct->FindFootnoteBossFrame( true );
585     }
586     return static_cast<SwFootnoteBossFrame*>(pRet);
587 }
588 
ImplFindTabFrame()589 SwTabFrame* SwFrame::ImplFindTabFrame()
590 {
591     SwFrame *pRet = this;
592     if (pRet->IsInDtor())
593         return nullptr;
594     while ( !pRet->IsTabFrame() )
595     {
596         pRet = pRet->GetUpper();
597         if ( !pRet )
598             return nullptr;
599         if (pRet->IsInDtor())
600             return nullptr;
601     }
602     return static_cast<SwTabFrame*>(pRet);
603 }
604 
ImplFindSctFrame()605 SwSectionFrame* SwFrame::ImplFindSctFrame()
606 {
607     SwFrame *pRet = this;
608     if (pRet->IsInDtor())
609         return nullptr;
610     while ( !pRet->IsSctFrame() )
611     {
612         pRet = pRet->GetUpper();
613         if ( !pRet )
614             return nullptr;
615         if (pRet->IsInDtor())
616             return nullptr;
617     }
618     return static_cast<SwSectionFrame*>(pRet);
619 }
620 
ImplFindBodyFrame() const621 const SwBodyFrame* SwFrame::ImplFindBodyFrame() const
622 {
623     const SwFrame *pRet = this;
624     while ( !pRet->IsBodyFrame() )
625     {
626         pRet = pRet->GetUpper();
627         if ( !pRet )
628             return nullptr;
629     }
630     return static_cast<const SwBodyFrame*>(pRet);
631 }
632 
ImplFindFootnoteFrame()633 SwFootnoteFrame *SwFrame::ImplFindFootnoteFrame()
634 {
635     SwFrame *pRet = this;
636     while ( !pRet->IsFootnoteFrame() )
637     {
638         pRet = pRet->GetUpper();
639         if ( !pRet )
640             return nullptr;
641     }
642     return static_cast<SwFootnoteFrame*>(pRet);
643 }
644 
ImplFindFlyFrame()645 SwFlyFrame *SwFrame::ImplFindFlyFrame()
646 {
647     SwFrame *pRet = this;
648     do
649     {
650         if ( pRet->IsFlyFrame() )
651             return static_cast<SwFlyFrame*>(pRet);
652         else
653             pRet = pRet->GetUpper();
654     } while ( pRet );
655     return nullptr;
656 }
657 
FindColFrame()658 SwFrame *SwFrame::FindColFrame()
659 {
660     SwFrame *pFrame = this;
661     do
662     {   pFrame = pFrame->GetUpper();
663     } while ( pFrame && !pFrame->IsColumnFrame() );
664     return pFrame;
665 }
666 
FindRowFrame()667 SwRowFrame *SwFrame::FindRowFrame()
668 {
669     SwFrame *pFrame = this;
670     do
671     {   pFrame = pFrame->GetUpper();
672     } while ( pFrame && !pFrame->IsRowFrame() );
673     return dynamic_cast< SwRowFrame* >( pFrame );
674 }
675 
FindFooterOrHeader()676 SwFrame* SwFrame::FindFooterOrHeader()
677 {
678     SwFrame* pRet = this;
679     do
680     {
681         if (pRet->GetType() & FRM_HEADFOOT) //header and footer
682             return pRet;
683         else if ( pRet->GetUpper() )
684             pRet = pRet->GetUpper();
685         else if ( pRet->IsFlyFrame() )
686             pRet = static_cast<SwFlyFrame*>(pRet)->AnchorFrame();
687         else
688             return nullptr;
689     } while ( pRet );
690     return pRet;
691 }
692 
FindFootNote() const693 const SwFootnoteFrame* SwFootnoteContFrame::FindFootNote() const
694 {
695     const SwFootnoteFrame* pRet = static_cast<const SwFootnoteFrame*>(Lower());
696     if( pRet && !pRet->GetAttr()->GetFootnote().IsEndNote() )
697         return pRet;
698     return nullptr;
699 }
700 
FindEndNote() const701 const SwFootnoteFrame* SwFootnoteContFrame::FindEndNote() const
702 {
703     auto pRet = static_cast<const SwFootnoteFrame*>(Lower());
704     if (pRet && pRet->GetAttr()->GetFootnote().IsEndNote())
705     {
706         return pRet;
707     }
708 
709     return nullptr;
710 }
711 
GetPageAtPos(const Point & rPt,const Size * pSize,bool bExtend) const712 const SwPageFrame* SwRootFrame::GetPageAtPos( const Point& rPt, const Size* pSize, bool bExtend ) const
713 {
714     const SwPageFrame* pRet = nullptr;
715 
716     SwRect aRect;
717     if ( pSize )
718     {
719         aRect.Pos()  = rPt;
720         aRect.SSize( *pSize );
721     }
722 
723     const SwFrame* pPage = Lower();
724 
725     if ( !bExtend )
726     {
727         if( !getFrameArea().Contains( rPt ) )
728             return nullptr;
729 
730         // skip pages above point:
731         while( pPage && rPt.Y() > pPage->getFrameArea().Bottom() )
732             pPage = pPage->GetNext();
733     }
734 
735     OSL_ENSURE( GetPageNum() <= maPageRects.size(), "number of pages differs from page rect array size" );
736     size_t nPageIdx = 0;
737 
738     while ( pPage && !pRet )
739     {
740         const SwRect& rBoundRect = bExtend ? maPageRects[ nPageIdx++ ] : pPage->getFrameArea();
741 
742         if ( (!pSize && rBoundRect.Contains(rPt)) ||
743               (pSize && rBoundRect.Overlaps(aRect)) )
744         {
745             pRet = static_cast<const SwPageFrame*>(pPage);
746         }
747 
748         pPage = pPage->GetNext();
749     }
750 
751     return pRet;
752 }
753 
IsBetweenPages(const Point & rPt) const754 bool SwRootFrame::IsBetweenPages(const Point& rPt) const
755 {
756     if (!getFrameArea().Contains(rPt))
757         return false;
758 
759     // top visible page
760     const SwFrame* pPage = Lower();
761     if (pPage == nullptr)
762         return false;
763 
764     // skip pages above point:
765     while (pPage && rPt.Y() > pPage->getFrameArea().Bottom())
766         pPage = pPage->GetNext();
767 
768     if (pPage &&
769         rPt.X() >= pPage->getFrameArea().Left() &&
770         rPt.X() <= pPage->getFrameArea().Right())
771     {
772         // Trivial case when we're right in between.
773         if (!pPage->getFrameArea().Contains(rPt))
774             return true;
775 
776         // In normal mode the gap is large enough and
777         // header/footer mouse interaction competes with
778         // handling hide-whitespace within them.
779         // In hide-whitespace, however, the gap is too small
780         // for convenience and there are no headers/footers.
781         const SwViewShell *pSh = GetCurrShell();
782         if (pSh && pSh->GetViewOptions()->IsWhitespaceHidden())
783         {
784             constexpr SwTwips constMargin = o3tl::convert(tools::Long(2), o3tl::Length::mm, o3tl::Length::twip);
785 
786             // If we are really close to the bottom or top of a page.
787             const auto toEdge = std::min(std::abs(pPage->getFrameArea().Top() - rPt.Y()),
788                                          std::abs(pPage->getFrameArea().Bottom() - rPt.Y()));
789             return toEdge <= constMargin;
790         }
791     }
792 
793     return false;
794 }
795 
GetBreakItem() const796 const SvxFormatBreakItem& SwFrame::GetBreakItem() const
797 {
798     return GetAttrSet()->GetBreak();
799 }
800 
GetPageDescItem() const801 const SwFormatPageDesc& SwFrame::GetPageDescItem() const
802 {
803     return GetAttrSet()->GetPageDesc();
804 }
805 
GetBreakItem() const806 const SvxFormatBreakItem& SwTextFrame::GetBreakItem() const
807 {
808     return GetTextNodeFirst()->GetSwAttrSet().GetBreak();
809 }
810 
GetPageDescItem() const811 const SwFormatPageDesc& SwTextFrame::GetPageDescItem() const
812 {
813     return GetTextNodeFirst()->GetSwAttrSet().GetPageDesc();
814 }
815 
GetAttrSet() const816 const SwAttrSet* SwFrame::GetAttrSet() const
817 {
818     if (IsTextFrame())
819     {
820         return &static_cast<const SwTextFrame*>(this)->GetTextNodeForParaProps()->GetSwAttrSet();
821     }
822     else if (IsNoTextFrame())
823     {
824         return &static_cast<const SwNoTextFrame*>(this)->GetNode()->GetSwAttrSet();
825     }
826     else
827     {
828         assert(IsLayoutFrame());
829         return &static_cast<const SwLayoutFrame*>(this)->GetFormat()->GetAttrSet();
830     }
831 }
832 
getSdrAllFillAttributesHelper() const833 drawinglayer::attribute::SdrAllFillAttributesHelperPtr SwFrame::getSdrAllFillAttributesHelper() const
834 {
835     if (IsTextFrame())
836     {
837         return static_cast<const SwTextFrame*>(this)->GetTextNodeForParaProps()->getSdrAllFillAttributesHelper();
838     }
839     else if (IsNoTextFrame())
840     {
841         return static_cast<const SwNoTextFrame*>(this)->GetNode()->getSdrAllFillAttributesHelper();
842     }
843     else
844     {
845         return static_cast< const SwLayoutFrame* >(this)->GetFormat()->getSdrAllFillAttributesHelper();
846     }
847 }
848 
supportsFullDrawingLayerFillAttributeSet() const849 bool SwFrame::supportsFullDrawingLayerFillAttributeSet() const
850 {
851     if (IsContentFrame())
852     {
853         return true;
854     }
855     else
856     {
857         return static_cast< const SwLayoutFrame* >(this)->GetFormat()->supportsFullDrawingLayerFillAttributeSet();
858     }
859 }
860 
861 /*
862  *  SwFrame::FindNext_(), FindPrev_(), InvalidateNextPos()
863  *         FindNextCnt_() visits tables and sections and only returns SwContentFrames.
864  *
865  *  Description         Invalidates the position of the next frame.
866  *      This is the direct successor or in case of ContentFrames the next
867  *      ContentFrame which sits in the same flow as I do:
868  *      - body,
869  *      - footnote,
870  *      - in headers/footers the notification only needs to be forwarded
871  *        inside the section
872  *      - same for Flys
873  *      - Contents in tabs remain only inside their cell
874  *      - in principle tables behave exactly like the Contents
875  *      - sections also
876  */
877 // This helper function is an equivalent to the ImplGetNextContentFrame() method,
878 // besides ContentFrames this function also returns TabFrames and SectionFrames.
lcl_NextFrame(SwFrame * pFrame)879 static SwFrame* lcl_NextFrame( SwFrame* pFrame )
880 {
881     SwFrame *pRet = nullptr;
882     bool bGoingUp = false;
883     do {
884         SwFrame *p = nullptr;
885 
886         bool bGoingFwd = false;
887         bool bGoingDown = !bGoingUp && pFrame->IsLayoutFrame();
888         if (bGoingDown)
889         {
890             p = static_cast<SwLayoutFrame*>(pFrame)->Lower();
891             bGoingDown = nullptr != p;
892         }
893         if( !bGoingDown )
894         {
895             p = pFrame->IsFlyFrame() ? static_cast<SwFlyFrame*>(pFrame)->GetNextLink() : pFrame->GetNext();
896             bGoingFwd = nullptr != p;
897             if ( !bGoingFwd )
898             {
899                 p = pFrame->GetUpper();
900                 bGoingUp = nullptr != p;
901                 if ( !bGoingUp )
902                 {
903                     return nullptr;
904                 }
905             }
906         }
907         bGoingUp = !(bGoingFwd || bGoingDown);
908         pFrame = p;
909     } while ( nullptr == (pRet = ( ( pFrame->IsContentFrame() || ( !bGoingUp &&
910             ( pFrame->IsTabFrame() || pFrame->IsSctFrame() ) ) )? pFrame : nullptr ) ) );
911     return pRet;
912 }
913 
FindNext_()914 SwFrame *SwFrame::FindNext_()
915 {
916     bool bIgnoreTab = false;
917     SwFrame *pThis = this;
918 
919     if ( IsTabFrame() )
920     {
921         //The last Content of the table gets picked up and his follower is
922         //returned. To be able to deactivate the special case for tables
923         //(see below) bIgnoreTab will be set.
924         if ( static_cast<SwTabFrame*>(this)->GetFollow() )
925             return static_cast<SwTabFrame*>(this)->GetFollow();
926 
927         pThis = static_cast<SwTabFrame*>(this)->FindLastContentOrTable();
928         if ( !pThis )
929             pThis = this;
930         bIgnoreTab = true;
931     }
932     else if ( IsSctFrame() )
933     {
934         //The last Content of the section gets picked and his follower is returned.
935         if ( static_cast<SwSectionFrame*>(this)->GetFollow() )
936             return static_cast<SwSectionFrame*>(this)->GetFollow();
937 
938         pThis = static_cast<SwSectionFrame*>(this)->FindLastContent();
939         if ( !pThis )
940             pThis = this;
941     }
942     else if ( IsContentFrame() )
943     {
944         if( static_cast<SwContentFrame*>(this)->GetFollow() )
945             return static_cast<SwContentFrame*>(this)->GetFollow();
946     }
947     else if ( IsRowFrame() )
948     {
949         SwFrame* pMyUpper = GetUpper();
950         if ( pMyUpper->IsTabFrame() && static_cast<SwTabFrame*>(pMyUpper)->GetFollow() )
951             return static_cast<SwTabFrame*>(pMyUpper)->GetFollow()->GetLower();
952         else return nullptr;
953     }
954     else
955         return nullptr;
956 
957     SwFrame* pRet = nullptr;
958     const bool bFootnote  = pThis->IsInFootnote();
959     if ( !bIgnoreTab && pThis->IsInTab() )
960     {
961         SwLayoutFrame *pUp = pThis->GetUpper();
962         while (pUp && !pUp->IsCellFrame())
963             pUp = pUp->GetUpper();
964         assert(pUp && "Content flag says it's in table but it's not in cell.");
965         SwFrame* pNxt = pUp ? static_cast<SwCellFrame*>(pUp)->GetFollowCell() : nullptr;
966         if ( pNxt )
967             pNxt = static_cast<SwCellFrame*>(pNxt)->ContainsContent();
968         if ( !pNxt )
969         {
970             pNxt = lcl_NextFrame( pThis );
971             if (pUp && pUp->IsAnLower(pNxt))
972                 pRet = pNxt;
973         }
974         else
975             pRet = pNxt;
976     }
977     else
978     {
979         const bool bBody = pThis->IsInDocBody();
980         SwFrame *pNxtCnt = lcl_NextFrame( pThis );
981         if ( pNxtCnt )
982         {
983             if ( bBody || bFootnote )
984             {
985                 while ( pNxtCnt )
986                 {
987                     // OD 02.04.2003 #108446# - check for endnote, only if found
988                     // next content isn't contained in a section, that collect its
989                     // endnotes at its end.
990                     bool bEndn = IsInSct() && !IsSctFrame() &&
991                                  ( !pNxtCnt->IsInSct() ||
992                                    !pNxtCnt->FindSctFrame()->IsEndnAtEnd()
993                                  );
994                     if ( ( bBody && pNxtCnt->IsInDocBody() ) ||
995                          ( pNxtCnt->IsInFootnote() &&
996                            ( bFootnote ||
997                              ( bEndn && pNxtCnt->FindFootnoteFrame()->GetAttr()->GetFootnote().IsEndNote() )
998                            )
999                          )
1000                        )
1001                     {
1002                         if (pNxtCnt->IsInTab())
1003                         {
1004                             if (!IsTabFrame() || !static_cast<SwLayoutFrame*>(this)->IsAnLower(pNxtCnt))
1005                             {
1006                                 pRet = pNxtCnt->FindTabFrame();
1007                                 break;
1008                             }
1009                         }
1010                         else
1011                         {
1012                             pRet = pNxtCnt;
1013                             break;
1014                         }
1015                     }
1016                     pNxtCnt = lcl_NextFrame( pNxtCnt );
1017                 }
1018             }
1019             else if ( pThis->IsInFly() )
1020             {
1021                 pRet = pNxtCnt->IsInTab() ? pNxtCnt->FindTabFrame()
1022                                             : pNxtCnt;
1023             }
1024             else    //footer-/or header section
1025             {
1026                 const SwFrame *pUp = pThis->GetUpper();
1027                 const SwFrame *pCntUp = pNxtCnt->GetUpper();
1028                 while ( pUp && pUp->GetUpper() &&
1029                         !pUp->IsHeaderFrame() && !pUp->IsFooterFrame() )
1030                     pUp = pUp->GetUpper();
1031                 while ( pCntUp && pCntUp->GetUpper() &&
1032                         !pCntUp->IsHeaderFrame() && !pCntUp->IsFooterFrame() )
1033                     pCntUp = pCntUp->GetUpper();
1034                 if ( pCntUp == pUp )
1035                 {
1036                     pRet = pNxtCnt->IsInTab() ? pNxtCnt->FindTabFrame()
1037                                                 : pNxtCnt;
1038                 }
1039             }
1040         }
1041     }
1042     if( pRet && pRet->IsInSct() )
1043     {
1044         SwSectionFrame* pSct = pRet->FindSctFrame();
1045         //Footnotes in frames with columns must not return the section which
1046         //contains the footnote
1047         if( !pSct->IsAnLower( this ) &&
1048             (!bFootnote || pSct->IsInFootnote() ) )
1049             return pSct;
1050     }
1051     return pRet == this ? nullptr : pRet;
1052 }
1053 
1054 // #i27138# - add parameter <_bInSameFootnote>
FindNextCnt_(const bool _bInSameFootnote)1055 SwContentFrame *SwFrame::FindNextCnt_( const bool _bInSameFootnote )
1056 {
1057     SwFrame *pThis = this;
1058 
1059     if ( IsTabFrame() )
1060     {
1061         if ( static_cast<SwTabFrame*>(this)->GetFollow() )
1062         {
1063             pThis = static_cast<SwTabFrame*>(this)->GetFollow()->ContainsContent();
1064             if( pThis )
1065                 return static_cast<SwContentFrame*>(pThis);
1066         }
1067         pThis = static_cast<SwTabFrame*>(this)->FindLastContentOrTable();
1068         if ( !pThis )
1069             return nullptr;
1070     }
1071     else if ( IsSctFrame() )
1072     {
1073         if ( static_cast<SwSectionFrame*>(this)->GetFollow() )
1074         {
1075             pThis = static_cast<SwSectionFrame*>(this)->GetFollow()->ContainsContent();
1076             if( pThis )
1077                 return static_cast<SwContentFrame*>(pThis);
1078         }
1079         pThis = static_cast<SwSectionFrame*>(this)->FindLastContent();
1080         if ( !pThis )
1081             return nullptr;
1082     }
1083     else if ( IsContentFrame() && static_cast<SwContentFrame*>(this)->GetFollow() )
1084         return static_cast<SwContentFrame*>(this)->GetFollow();
1085 
1086     if ( pThis->IsContentFrame() )
1087     {
1088         const bool bBody = pThis->IsInDocBody();
1089         const bool bFootnote  = pThis->IsInFootnote();
1090         SwContentFrame *pNxtCnt = static_cast<SwContentFrame*>(pThis)->GetNextContentFrame();
1091         if ( pNxtCnt )
1092         {
1093             // #i27138#
1094             if ( bBody || ( bFootnote && !_bInSameFootnote ) )
1095             {
1096                 // handling for environments 'footnotes' and 'document body frames':
1097                 while ( pNxtCnt )
1098                 {
1099                     if ( (bBody && pNxtCnt->IsInDocBody()) ||
1100                          (bFootnote  && pNxtCnt->IsInFootnote()) )
1101                         return pNxtCnt;
1102                     pNxtCnt = pNxtCnt->GetNextContentFrame();
1103                 }
1104             }
1105             // #i27138#
1106             else if ( bFootnote && _bInSameFootnote )
1107             {
1108                 // handling for environments 'each footnote':
1109                 // Assure that found next content frame belongs to the same footnotes
1110                 const SwFootnoteFrame* pFootnoteFrameOfNext( pNxtCnt->FindFootnoteFrame() );
1111                 SwFootnoteFrame* pFootnoteFrameOfCurr(pThis->FindFootnoteFrame());
1112                 OSL_ENSURE( pFootnoteFrameOfCurr,
1113                         "<SwFrame::FindNextCnt_() - unknown layout situation: current frame has to have an upper footnote frame." );
1114                 if ( pFootnoteFrameOfNext == pFootnoteFrameOfCurr )
1115                 {
1116                     return pNxtCnt;
1117                 }
1118                 else if ( pFootnoteFrameOfCurr->GetFollow() )
1119                 {
1120                     // next content frame has to be the first content frame
1121                     // in the follow footnote, which contains a content frame.
1122                     SwFootnoteFrame* pFollowFootnoteFrameOfCurr(pFootnoteFrameOfCurr);
1123                     pNxtCnt = nullptr;
1124                     do {
1125                         pFollowFootnoteFrameOfCurr = pFollowFootnoteFrameOfCurr->GetFollow();
1126                         pNxtCnt = pFollowFootnoteFrameOfCurr->ContainsContent();
1127                     } while ( !pNxtCnt && pFollowFootnoteFrameOfCurr->GetFollow() );
1128                     return pNxtCnt;
1129                 }
1130                 else
1131                 {
1132                     // current content frame is the last content frame in the
1133                     // footnote - no next content frame exists.
1134                     return nullptr;
1135                 }
1136             }
1137             else if ( pThis->IsInFly() )
1138                 // handling for environments 'unlinked fly frame' and
1139                 // 'group of linked fly frames':
1140                 return pNxtCnt;
1141             else
1142             {
1143                 // handling for environments 'page header' and 'page footer':
1144                 const SwFrame *pUp = pThis->GetUpper();
1145                 const SwFrame *pCntUp = pNxtCnt->GetUpper();
1146                 while ( pUp && pUp->GetUpper() &&
1147                         !pUp->IsHeaderFrame() && !pUp->IsFooterFrame() )
1148                     pUp = pUp->GetUpper();
1149                 while ( pCntUp && pCntUp->GetUpper() &&
1150                         !pCntUp->IsHeaderFrame() && !pCntUp->IsFooterFrame() )
1151                     pCntUp = pCntUp->GetUpper();
1152                 if ( pCntUp == pUp )
1153                     return pNxtCnt;
1154             }
1155         }
1156     }
1157     return nullptr;
1158 }
1159 
1160 /** method to determine previous content frame in the same environment
1161     for a flow frame (content frame, table frame, section frame)
1162 
1163     OD 2005-11-30 #i27138#
1164 */
FindPrevCnt_()1165 SwContentFrame* SwFrame::FindPrevCnt_()
1166 {
1167     if ( !IsFlowFrame() )
1168     {
1169         // nothing to do, if current frame isn't a flow frame.
1170         return nullptr;
1171     }
1172 
1173     SwContentFrame* pPrevContentFrame( nullptr );
1174 
1175     // Because method <SwContentFrame::GetPrevContentFrame()> is used to travel
1176     // through the layout, a content frame, at which the travel starts, is needed.
1177     SwContentFrame* pCurrContentFrame = dynamic_cast<SwContentFrame*>(this);
1178 
1179     // perform shortcut, if current frame is a follow, and
1180     // determine <pCurrContentFrame>, if current frame is a table or section frame
1181     if ( pCurrContentFrame && pCurrContentFrame->IsFollow() )
1182     {
1183         // previous content frame is its master content frame
1184         pPrevContentFrame = pCurrContentFrame->FindMaster();
1185     }
1186     else if ( IsTabFrame() )
1187     {
1188         SwTabFrame* pTabFrame( static_cast<SwTabFrame*>(this) );
1189         if ( pTabFrame->IsFollow() )
1190         {
1191             // previous content frame is the last content of its master table frame
1192             pPrevContentFrame = pTabFrame->FindMaster()->FindLastContent();
1193         }
1194         else
1195         {
1196             // start content frame for the search is the first content frame of
1197             // the table frame.
1198             pCurrContentFrame = pTabFrame->ContainsContent();
1199         }
1200     }
1201     else if ( IsSctFrame() )
1202     {
1203         SwSectionFrame* pSectFrame( static_cast<SwSectionFrame*>(this) );
1204         if ( pSectFrame->IsFollow() )
1205         {
1206             // previous content frame is the last content of its master section frame
1207             pPrevContentFrame = pSectFrame->FindMaster()->FindLastContent();
1208         }
1209         else
1210         {
1211             // start content frame for the search is the first content frame of
1212             // the section frame.
1213             pCurrContentFrame = pSectFrame->ContainsContent();
1214         }
1215     }
1216 
1217     // search for next content frame, depending on the environment, in which
1218     // the current frame is in.
1219     if ( !pPrevContentFrame && pCurrContentFrame )
1220     {
1221         pPrevContentFrame = pCurrContentFrame->GetPrevContentFrame();
1222         if ( pPrevContentFrame )
1223         {
1224             if ( pCurrContentFrame->IsInFly() )
1225             {
1226                 // handling for environments 'unlinked fly frame' and
1227                 // 'group of linked fly frames':
1228                 // Nothing to do, <pPrevContentFrame> is the one
1229             }
1230             else
1231             {
1232                 const bool bInDocBody = pCurrContentFrame->IsInDocBody();
1233                 const bool bInFootnote  = pCurrContentFrame->IsInFootnote();
1234                 if ( bInDocBody )
1235                 {
1236                     // handling for environments 'footnotes' and 'document body frames':
1237                     // Assure that found previous frame is also in one of these
1238                     // environments. Otherwise, travel further
1239                     while ( pPrevContentFrame )
1240                     {
1241                         if ( ( bInDocBody && pPrevContentFrame->IsInDocBody() ) ||
1242                              ( bInFootnote && pPrevContentFrame->IsInFootnote() ) )
1243                         {
1244                             break;
1245                         }
1246                         pPrevContentFrame = pPrevContentFrame->GetPrevContentFrame();
1247                     }
1248                 }
1249                 else if ( bInFootnote )
1250                 {
1251                     // handling for environments 'each footnote':
1252                     // Assure that found next content frame belongs to the same footnotes
1253                     const SwFootnoteFrame* pFootnoteFrameOfPrev( pPrevContentFrame->FindFootnoteFrame() );
1254                     SwFootnoteFrame* pFootnoteFrameOfCurr(pCurrContentFrame->FindFootnoteFrame());
1255                     if ( pFootnoteFrameOfPrev != pFootnoteFrameOfCurr )
1256                     {
1257                         if ( pFootnoteFrameOfCurr->GetMaster() )
1258                         {
1259                             SwFootnoteFrame* pMasterFootnoteFrameOfCurr(pFootnoteFrameOfCurr);
1260                             pPrevContentFrame = nullptr;
1261                             // correct wrong loop-condition
1262                             do {
1263                                 pMasterFootnoteFrameOfCurr = pMasterFootnoteFrameOfCurr->GetMaster();
1264                                 pPrevContentFrame = pMasterFootnoteFrameOfCurr->FindLastContent();
1265                             } while ( !pPrevContentFrame &&
1266                                       pMasterFootnoteFrameOfCurr->GetMaster() );
1267                         }
1268                         else
1269                         {
1270                             // current content frame is the first content in the
1271                             // footnote - no previous content exists.
1272                             pPrevContentFrame = nullptr;
1273                         }
1274                     }
1275                 }
1276                 else
1277                 {
1278                     // handling for environments 'page header' and 'page footer':
1279                     // Assure that found previous frame is also in the same
1280                     // page header respectively page footer as <pCurrContentFrame>
1281                     // Note: At this point it's clear that <pCurrContentFrame> has
1282                     //       to be inside a page header or page footer and that
1283                     //       neither <pCurrContentFrame> nor <pPrevContentFrame> are
1284                     //       inside a fly frame.
1285                     //       Thus, method <FindFooterOrHeader()> can be used.
1286                     OSL_ENSURE( pCurrContentFrame->FindFooterOrHeader(),
1287                             "<SwFrame::FindPrevCnt_()> - unknown layout situation: current frame should be in page header or page footer" );
1288                     OSL_ENSURE( !pPrevContentFrame->IsInFly(),
1289                             "<SwFrame::FindPrevCnt_()> - unknown layout situation: found previous frame should *not* be inside a fly frame." );
1290                     if ( pPrevContentFrame->FindFooterOrHeader() !=
1291                                             pCurrContentFrame->FindFooterOrHeader() )
1292                     {
1293                         pPrevContentFrame = nullptr;
1294                     }
1295                 }
1296             }
1297         }
1298     }
1299 
1300     return pPrevContentFrame;
1301 }
1302 
FindPrev_()1303 SwFrame *SwFrame::FindPrev_()
1304 {
1305     bool bIgnoreTab = false;
1306     SwFrame *pThis = this;
1307 
1308     if ( IsTabFrame() )
1309     {
1310         //The first Content of the table gets picked up and his predecessor is
1311         //returned. To be able to deactivate the special case for tables
1312         //(see below) bIgnoreTab will be set.
1313         if ( static_cast<SwTabFrame*>(this)->IsFollow() )
1314             return static_cast<SwTabFrame*>(this)->FindMaster();
1315         else
1316             pThis = static_cast<SwTabFrame*>(this)->ContainsContent();
1317         bIgnoreTab = true;
1318     }
1319 
1320     if ( pThis && pThis->IsContentFrame() )
1321     {
1322         SwContentFrame *pPrvCnt = static_cast<SwContentFrame*>(pThis)->GetPrevContentFrame();
1323         if( !pPrvCnt )
1324             return nullptr;
1325         if ( !bIgnoreTab && pThis->IsInTab() )
1326         {
1327             SwLayoutFrame *pUp = pThis->GetUpper();
1328             while (pUp && !pUp->IsCellFrame())
1329                 pUp = pUp->GetUpper();
1330             assert(pUp && "Content flag says it's in table but it's not in cell.");
1331             if (pUp && pUp->IsAnLower(pPrvCnt))
1332                 return pPrvCnt;
1333         }
1334         else
1335         {
1336             SwFrame* pRet;
1337             const bool bBody = pThis->IsInDocBody();
1338             const bool bFootnote  = !bBody && pThis->IsInFootnote();
1339             if ( bBody || bFootnote )
1340             {
1341                 while ( pPrvCnt )
1342                 {
1343                     if ( (bBody && pPrvCnt->IsInDocBody()) ||
1344                             (bFootnote   && pPrvCnt->IsInFootnote()) )
1345                     {
1346                         pRet = pPrvCnt->IsInTab() ? pPrvCnt->FindTabFrame()
1347                                                   : static_cast<SwFrame*>(pPrvCnt);
1348                         return pRet;
1349                     }
1350                     pPrvCnt = pPrvCnt->GetPrevContentFrame();
1351                 }
1352             }
1353             else if ( pThis->IsInFly() )
1354             {
1355                 pRet = pPrvCnt->IsInTab() ? pPrvCnt->FindTabFrame()
1356                                             : static_cast<SwFrame*>(pPrvCnt);
1357                 return pRet;
1358             }
1359             else // footer or header or Fly
1360             {
1361                 const SwFrame *pUp = pThis->GetUpper();
1362                 const SwFrame *pCntUp = pPrvCnt->GetUpper();
1363                 while ( pUp && pUp->GetUpper() &&
1364                         !pUp->IsHeaderFrame() && !pUp->IsFooterFrame() )
1365                     pUp = pUp->GetUpper();
1366                 while ( pCntUp && pCntUp->GetUpper() )
1367                     pCntUp = pCntUp->GetUpper();
1368                 if ( pCntUp == pUp )
1369                 {
1370                     pRet = pPrvCnt->IsInTab() ? pPrvCnt->FindTabFrame()
1371                                                 : static_cast<SwFrame*>(pPrvCnt);
1372                     return pRet;
1373                 }
1374             }
1375         }
1376     }
1377     return nullptr;
1378 }
1379 
ImplInvalidateNextPos(bool bNoFootnote)1380 void SwFrame::ImplInvalidateNextPos( bool bNoFootnote )
1381 {
1382     SwFrame *pFrame = FindNext_();
1383     if ( nullptr == pFrame )
1384         return;
1385 
1386     if( pFrame->IsSctFrame() )
1387     {
1388         while( pFrame && pFrame->IsSctFrame() )
1389         {
1390             if( static_cast<SwSectionFrame*>(pFrame)->GetSection() )
1391             {
1392                 SwFrame* pTmp = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
1393                 if( pTmp )
1394                     pTmp->InvalidatePos();
1395                 else if( !bNoFootnote )
1396                     static_cast<SwSectionFrame*>(pFrame)->InvalidateFootnotePos();
1397                 if( !IsInSct() || FindSctFrame()->GetFollow() != pFrame )
1398                     pFrame->InvalidatePos();
1399                 return;
1400             }
1401             pFrame = pFrame->FindNext();
1402         }
1403         if( pFrame )
1404         {
1405             if ( pFrame->IsSctFrame())
1406             {
1407                 // We need to invalidate the section's content so it gets
1408                 // the chance to flow to a different page.
1409                 SwFrame* pTmp = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
1410                 if( pTmp )
1411                     pTmp->InvalidatePos();
1412                 if( !IsInSct() || FindSctFrame()->GetFollow() != pFrame )
1413                     pFrame->InvalidatePos();
1414             }
1415             else
1416                 pFrame->InvalidatePos();
1417         }
1418     }
1419     else
1420         pFrame->InvalidatePos();
1421 }
1422 
1423 /** method to invalidate printing area of next frame
1424 
1425     OD 09.01.2004 #i11859#
1426 
1427     FME 2004-04-19 #i27145# Moved function from SwTextFrame to SwFrame
1428 */
InvalidateNextPrtArea()1429 void SwFrame::InvalidateNextPrtArea()
1430 {
1431     // determine next frame
1432     SwFrame* pNextFrame = FindNext();
1433     // skip empty section frames and hidden text frames
1434     {
1435         while (pNextFrame && pNextFrame->IsHiddenNow())
1436         {
1437             pNextFrame = pNextFrame->FindNext();
1438         }
1439     }
1440 
1441     // Invalidate printing area of found next frame
1442     if ( !pNextFrame )
1443         return;
1444 
1445     if ( pNextFrame->IsSctFrame() )
1446     {
1447         // Invalidate printing area of found section frame, if
1448         // (1) this text frame isn't in a section OR
1449         // (2) found section frame isn't a follow of the section frame this
1450         //     text frame is in.
1451         if ( !IsInSct() || FindSctFrame()->GetFollow() != pNextFrame )
1452         {
1453             pNextFrame->InvalidatePrt();
1454         }
1455 
1456         // Invalidate printing area of first content in found section.
1457         SwFrame* pFstContentOfSctFrame =
1458                 static_cast<SwSectionFrame*>(pNextFrame)->ContainsAny();
1459         if ( pFstContentOfSctFrame )
1460         {
1461             pFstContentOfSctFrame->InvalidatePrt();
1462         }
1463     }
1464     else
1465     {
1466         pNextFrame->InvalidatePrt();
1467     }
1468 }
1469 
1470 /// @returns true if the frame _directly_ sits in a section
1471 ///     but not if it sits in a table which itself sits in a section.
lcl_IsInSectionDirectly(const SwFrame * pUp)1472 static bool lcl_IsInSectionDirectly( const SwFrame *pUp )
1473 {
1474     bool bSeenColumn = false;
1475 
1476     while( pUp )
1477     {
1478         if( pUp->IsColumnFrame() )
1479             bSeenColumn = true;
1480         else if( pUp->IsSctFrame() )
1481         {
1482             auto pSection = static_cast<const SwSectionFrame*>(pUp);
1483             const SwFrame* pHeaderFooter = pSection->FindFooterOrHeader();
1484             // When the section frame is not in header/footer:
1485             // Allow move of frame in case our only column is not growable.
1486             // Also allow if there is a previous section frame (to move back).
1487             bool bAllowOutsideHeaderFooter = !pSection->Growable() || pSection->GetPrecede();
1488             return bSeenColumn || (!pHeaderFooter && bAllowOutsideHeaderFooter);
1489         }
1490         else if( pUp->IsTabFrame() )
1491             return false;
1492         pUp = pUp->GetUpper();
1493     }
1494     return false;
1495 }
1496 
1497 /** determine, if frame is moveable in given environment
1498 
1499     OD 08.08.2003 #110978#
1500     method replaced 'old' method <sal_Bool IsMoveable() const>.
1501     Determines, if frame is moveable in given environment. if no environment
1502     is given (parameter _pLayoutFrame == 0), the movability in the actual
1503     environment (<GetUpper()) is checked.
1504 */
IsMoveable(const SwLayoutFrame * _pLayoutFrame) const1505 bool SwFrame::IsMoveable( const SwLayoutFrame* _pLayoutFrame ) const
1506 {
1507     bool bRetVal = false;
1508 
1509     if ( !_pLayoutFrame )
1510     {
1511         _pLayoutFrame = GetUpper();
1512     }
1513 
1514     if ( _pLayoutFrame && IsFlowFrame() )
1515     {
1516         if ( _pLayoutFrame->IsInSct() && lcl_IsInSectionDirectly( _pLayoutFrame ) )
1517         {
1518             bRetVal = true;
1519         }
1520         else if ( _pLayoutFrame->IsInFly() ||
1521                   _pLayoutFrame->IsInDocBody() ||
1522                   _pLayoutFrame->IsInFootnote() )
1523         {
1524             // If IsMovable() is called before a MoveFwd() the method
1525             // may return false if there is no NextCellLeaf. If
1526             // IsMovable() is called before a MoveBwd() the method may
1527             // return false if there is no PrevCellLeaf.
1528             if ( _pLayoutFrame->IsInTab() && !IsTabFrame() &&
1529                  ( !IsContentFrame() || (!const_cast<SwFrame*>(this)->GetNextCellLeaf()
1530                                       && !const_cast<SwFrame*>(this)->GetPrevCellLeaf()) )
1531                 )
1532             {
1533                 bRetVal = false;
1534             }
1535             else
1536             {
1537                 if ( _pLayoutFrame->IsInFly() )
1538                 {
1539                     // if fly frame has a follow (next linked fly frame) or can split,
1540                     // frame is moveable.
1541                     const SwFlyFrame* pFlyFrame = _pLayoutFrame->FindFlyFrame();
1542                     if ( pFlyFrame->GetNextLink() || pFlyFrame->IsFlySplitAllowed() )
1543                     {
1544                         bRetVal = true;
1545                     }
1546                     else
1547                     {
1548                         // if environment is columned, frame is moveable, if
1549                         // it isn't in last column.
1550                         // search for column frame
1551                         const SwFrame* pCol = _pLayoutFrame;
1552                         while ( pCol && !pCol->IsColumnFrame() )
1553                         {
1554                             pCol = pCol->GetUpper();
1555                         }
1556                         // frame is moveable, if found column frame isn't last one.
1557                         if ( pCol && pCol->GetNext() )
1558                         {
1559                             bRetVal = true;
1560                         }
1561                     }
1562                 }
1563                 else if (!(_pLayoutFrame->IsInFootnote() && (IsTabFrame() || IsInTab())))
1564                 {
1565                     bRetVal = true;
1566                 }
1567             }
1568         }
1569     }
1570 
1571     return bRetVal;
1572 }
1573 
SetInfFlags()1574 void SwFrame::SetInfFlags()
1575 {
1576     if ( !IsFlyFrame() && !GetUpper() ) //not yet pasted, no information available
1577         return;
1578 
1579     mbInfInvalid = mbInfBody = mbInfTab = mbInfFly = mbInfFootnote = mbInfSct = false;
1580 
1581     SwFrame *pFrame = this;
1582     if( IsFootnoteContFrame() )
1583         mbInfFootnote = true;
1584     do
1585     {
1586         // mbInfBody is only set in the page body, but not in the column body
1587         if ( pFrame->IsBodyFrame() && !mbInfFootnote && pFrame->GetUpper()
1588              && pFrame->GetUpper()->IsPageFrame() )
1589             mbInfBody = true;
1590         else if ( pFrame->IsTabFrame() || pFrame->IsCellFrame() )
1591         {
1592             mbInfTab = true;
1593         }
1594         else if ( pFrame->IsFlyFrame() )
1595             mbInfFly = true;
1596         else if ( pFrame->IsSctFrame() )
1597             mbInfSct = true;
1598         else if ( pFrame->IsFootnoteFrame() )
1599             mbInfFootnote = true;
1600 
1601         pFrame = pFrame->GetUpper();
1602 
1603     } while ( pFrame && !pFrame->IsPageFrame() ); //there is nothing above the page
1604 }
1605 
1606 /** Updates the vertical or the righttoleft-flags.
1607  *
1608  * If the property is derived, it's from the upper or (for fly frames) from
1609  * the anchor. Otherwise we've to call a virtual method to check the property.
1610  */
SetDirFlags(bool bVert)1611 void SwFrame::SetDirFlags( bool bVert )
1612 {
1613     if( bVert )
1614     {
1615         // OD 2004-01-21 #114969# - if derived, valid vertical flag only if
1616         // vertical flag of upper/anchor is valid.
1617         if( mbDerivedVert )
1618         {
1619             const SwFrame* pAsk = IsFlyFrame() ?
1620                           static_cast<SwFlyFrame*>(this)->GetAnchorFrame() : GetUpper();
1621 
1622             OSL_ENSURE( pAsk != this, "Autsch! Stack overflow is about to happen" );
1623 
1624             if( pAsk )
1625             {
1626                 mbVertical = pAsk->IsVertical();
1627                 mbVertLR  = pAsk->IsVertLR();
1628                 mbVertLRBT = pAsk->IsVertLRBT();
1629 
1630                 if ( !pAsk->mbInvalidVert )
1631                     mbInvalidVert = false;
1632 
1633                 if ( IsCellFrame() )
1634                 {
1635                     SwCellFrame* pPrv = static_cast<SwCellFrame*>(this)->GetPreviousCell();
1636                     if ( pPrv && !mbVertical && pPrv->IsVertical() )
1637                     {
1638                         mbVertical = pPrv->IsVertical();
1639                         mbVertLR  = pPrv->IsVertLR();
1640                         mbVertLRBT = pPrv->IsVertLRBT();
1641                     }
1642                 }
1643             }
1644         }
1645         else
1646             CheckDirection( bVert );
1647     }
1648     else
1649     {
1650         bool bInv = false;
1651         if( !mbDerivedR2L ) // CheckDirection is able to set bDerivedR2L!
1652             CheckDirection( bVert );
1653         if( mbDerivedR2L )
1654         {
1655             const SwFrame* pAsk = IsFlyFrame() ?
1656                           static_cast<SwFlyFrame*>(this)->GetAnchorFrame() : GetUpper();
1657 
1658             OSL_ENSURE( pAsk != this, "Oops! Stack overflow is about to happen" );
1659 
1660             if( pAsk )
1661                 mbRightToLeft = pAsk->IsRightToLeft();
1662             if( !pAsk || pAsk->mbInvalidR2L )
1663                 bInv = mbInvalidR2L;
1664         }
1665         mbInvalidR2L = bInv;
1666     }
1667 }
1668 
GetNextCellLeaf()1669 SwLayoutFrame* SwFrame::GetNextCellLeaf()
1670 {
1671     SwFrame* pTmpFrame = this;
1672     while (pTmpFrame && !pTmpFrame->IsCellFrame())
1673         pTmpFrame = pTmpFrame->GetUpper();
1674 
1675     SAL_WARN_IF(!pTmpFrame, "sw.core", "SwFrame::GetNextCellLeaf() without cell");
1676     return pTmpFrame ? static_cast<SwCellFrame*>(pTmpFrame)->GetFollowCell() : nullptr;
1677 }
1678 
GetPrevCellLeaf()1679 SwLayoutFrame* SwFrame::GetPrevCellLeaf()
1680 {
1681     SwFrame* pTmpFrame = this;
1682     while (pTmpFrame && !pTmpFrame->IsCellFrame())
1683         pTmpFrame = pTmpFrame->GetUpper();
1684 
1685     SAL_WARN_IF(!pTmpFrame, "sw.core", "SwFrame::GetNextPreviousLeaf() without cell");
1686     return pTmpFrame ? static_cast<SwCellFrame*>(pTmpFrame)->GetPreviousCell() : nullptr;
1687 }
1688 
lcl_FindCorrespondingCellFrame(const SwRowFrame & rOrigRow,const SwCellFrame & rOrigCell,const SwRowFrame & rCorrRow,bool bInFollow)1689 static SwCellFrame* lcl_FindCorrespondingCellFrame( const SwRowFrame& rOrigRow,
1690                                          const SwCellFrame& rOrigCell,
1691                                          const SwRowFrame& rCorrRow,
1692                                          bool bInFollow )
1693 {
1694     SwCellFrame* pRet = nullptr;
1695     const SwCellFrame* pCell = static_cast<const SwCellFrame*>(rOrigRow.Lower());
1696     SwCellFrame* pCorrCell = const_cast<SwCellFrame*>(static_cast<const SwCellFrame*>(rCorrRow.Lower()));
1697 
1698     while ( pCell != &rOrigCell && !pCell->IsAnLower( &rOrigCell ) )
1699     {
1700         pCell = static_cast<const SwCellFrame*>(pCell->GetNext());
1701         pCorrCell = static_cast<SwCellFrame*>(pCorrCell->GetNext());
1702     }
1703 
1704     assert(pCell && pCorrCell && "lcl_FindCorrespondingCellFrame does not work");
1705 
1706     if ( pCell != &rOrigCell )
1707     {
1708         // rOrigCell must be a lower of pCell. We need to recurse into the rows:
1709         assert(pCell->Lower() && pCell->Lower()->IsRowFrame() &&
1710                "lcl_FindCorrespondingCellFrame does not work");
1711 
1712         const SwRowFrame* pRow = static_cast<const SwRowFrame*>(pCell->Lower());
1713         while ( !pRow->IsAnLower( &rOrigCell ) )
1714             pRow = static_cast<const SwRowFrame*>(pRow->GetNext());
1715 
1716         SwRowFrame* pCorrRow = nullptr;
1717         if ( bInFollow )
1718             pCorrRow = pRow->GetFollowRow();
1719         else
1720         {
1721             SwRowFrame* pTmpRow = static_cast<SwRowFrame*>(pCorrCell->GetLastLower());
1722 
1723             if ( pTmpRow && pTmpRow->GetFollowRow() == pRow )
1724                 pCorrRow = pTmpRow;
1725         }
1726 
1727         if ( pCorrRow )
1728             pRet = lcl_FindCorrespondingCellFrame( *pRow, rOrigCell, *pCorrRow, bInFollow );
1729     }
1730     else
1731         pRet = pCorrCell;
1732 
1733     return pRet;
1734 }
1735 
1736 // VERSION OF GetFollowCell() that assumes that we always have a follow flow line:
GetFollowCell() const1737 SwCellFrame* SwCellFrame::GetFollowCell() const
1738 {
1739     SwCellFrame* pRet = nullptr;
1740 
1741     // NEW TABLES
1742     // Covered cells do not have follow cells!
1743     const tools::Long nRowSpan = GetLayoutRowSpan();
1744     if ( nRowSpan < 1 )
1745         return nullptr;
1746 
1747     // find most upper row frame
1748     const SwFrame* pRow = GetUpper();
1749 
1750     while (pRow && (!pRow->IsRowFrame() || !pRow->GetUpper()->IsTabFrame()))
1751         pRow = pRow->GetUpper();
1752 
1753     if (!pRow)
1754         return nullptr;
1755 
1756     const SwTabFrame* pTabFrame = static_cast<const SwTabFrame*>(pRow->GetUpper());
1757     if (!pTabFrame || !pTabFrame->GetFollow() || !pTabFrame->HasFollowFlowLine())
1758         return nullptr;
1759 
1760     const SwCellFrame* pThisCell = this;
1761 
1762     // Get last cell of the current table frame that belongs to the rowspan:
1763     if ( nRowSpan > 1 )
1764     {
1765         // optimization: Will end of row span be in last row or exceed row?
1766         tools::Long nMax = 0;
1767         while ( pRow->GetNext() && ++nMax < nRowSpan )
1768             pRow = pRow->GetNext();
1769 
1770         if ( !pRow->GetNext() )
1771         {
1772             pThisCell = &pThisCell->FindStartEndOfRowSpanCell( false );
1773             pRow = pThisCell->GetUpper();
1774         }
1775     }
1776 
1777     const SwRowFrame* pFollowRow = nullptr;
1778     if ( !pRow->GetNext() &&
1779          nullptr != ( pFollowRow = pRow->IsInSplitTableRow() ) &&
1780          ( !pFollowRow->IsRowSpanLine() || nRowSpan > 1 ) )
1781          pRet = lcl_FindCorrespondingCellFrame( *static_cast<const SwRowFrame*>(pRow), *pThisCell, *pFollowRow, true );
1782 
1783     return pRet;
1784 }
1785 
1786 // VERSION OF GetPreviousCell() THAT ASSUMES THAT WE ALWAYS HAVE A FFL
GetPreviousCell() const1787 SwCellFrame* SwCellFrame::GetPreviousCell() const
1788 {
1789     SwCellFrame* pRet = nullptr;
1790 
1791     // NEW TABLES
1792     // Covered cells do not have previous cells!
1793     if ( GetLayoutRowSpan() < 1 )
1794         return nullptr;
1795 
1796     // find most upper row frame
1797     const SwFrame* pRow = GetUpper();
1798     while( !pRow->IsRowFrame() || (pRow->GetUpper() && !pRow->GetUpper()->IsTabFrame()) )
1799         pRow = pRow->GetUpper();
1800 
1801     OSL_ENSURE( pRow->GetUpper() && pRow->GetUpper()->IsTabFrame(), "GetPreviousCell without Table" );
1802 
1803     const SwTabFrame* pTab = static_cast<const SwTabFrame*>(pRow->GetUpper());
1804 
1805     if ( pTab && pTab->IsFollow() )
1806     {
1807         const SwFrame* pTmp = pTab->GetFirstNonHeadlineRow();
1808         const bool bIsInFirstLine = ( pTmp == pRow );
1809 
1810         if ( bIsInFirstLine )
1811         {
1812             SwTabFrame *pMaster = pTab->FindMaster();
1813             if ( pMaster && pMaster->HasFollowFlowLine() )
1814             {
1815                 SwRowFrame* pMasterRow = static_cast<SwRowFrame*>(pMaster->GetLastLower());
1816                 if ( pMasterRow )
1817                     pRet = lcl_FindCorrespondingCellFrame( *static_cast<const SwRowFrame*>(pRow), *this, *pMasterRow, false );
1818                 if ( pRet && pRet->GetTabBox()->getRowSpan() < 1 )
1819                     pRet = &const_cast<SwCellFrame&>(pRet->FindStartEndOfRowSpanCell( true ));
1820             }
1821         }
1822     }
1823 
1824     return pRet;
1825 }
1826 
1827 // --> NEW TABLES
FindStartEndOfRowSpanCell(bool bStart) const1828 const SwCellFrame& SwCellFrame::FindStartEndOfRowSpanCell( bool bStart ) const
1829 {
1830     const SwTabFrame* pTableFrame = dynamic_cast<const SwTabFrame*>(GetUpper()->GetUpper());
1831 
1832     if ( !bStart && pTableFrame && pTableFrame->IsFollow() && pTableFrame->IsInHeadline( *this ) )
1833         return *this;
1834 
1835     OSL_ENSURE( pTableFrame &&
1836             (  (bStart && GetTabBox()->getRowSpan() < 1) ||
1837               (!bStart && GetLayoutRowSpan() > 1) ),
1838             "SwCellFrame::FindStartRowSpanCell: No rowspan, no table, no cookies" );
1839 
1840     if ( pTableFrame )
1841     {
1842         const SwTable* pTable = pTableFrame->GetTable();
1843 
1844         sal_uInt16 nMax = USHRT_MAX;
1845         const SwFrame* pCurrentRow = GetUpper();
1846         const bool bDoNotEnterHeadline = bStart && pTableFrame->IsFollow() &&
1847                                         !pTableFrame->IsInHeadline( *pCurrentRow );
1848 
1849         // check how many rows we are allowed to go up or down until we reach the end of
1850         // the current table frame:
1851         nMax = 0;
1852         while ( bStart ? pCurrentRow->GetPrev() : pCurrentRow->GetNext() )
1853         {
1854             if ( bStart )
1855             {
1856                 // do not enter a repeated headline:
1857                 if ( bDoNotEnterHeadline && pTableFrame->IsFollow() &&
1858                      pTableFrame->IsInHeadline( *pCurrentRow->GetPrev() ) )
1859                     break;
1860 
1861                 pCurrentRow = pCurrentRow->GetPrev();
1862             }
1863             else
1864                pCurrentRow = pCurrentRow->GetNext();
1865 
1866             ++nMax;
1867         }
1868 
1869         // By passing the nMax value for Find*OfRowSpan (in case of bCurrentTableOnly
1870         // is set) we assure that we find a rMasterBox that has a SwCellFrame in
1871         // the current table frame:
1872         const SwTableBox& rMasterBox = bStart ?
1873                                        GetTabBox()->FindStartOfRowSpan( *pTable, nMax ) :
1874                                        GetTabBox()->FindEndOfRowSpan( *pTable, nMax );
1875 
1876         SwIterator<SwCellFrame,SwFormat> aIter( *rMasterBox.GetFrameFormat() );
1877 
1878         for ( SwCellFrame* pMasterCell = aIter.First(); pMasterCell; pMasterCell = aIter.Next() )
1879         {
1880             if ( pMasterCell->GetTabBox() == &rMasterBox )
1881             {
1882                 const SwTabFrame* pMasterTable = static_cast<const SwTabFrame*>(pMasterCell->GetUpper()->GetUpper());
1883 
1884                 if ( pMasterTable == pTableFrame )
1885                 {
1886                     return *pMasterCell;
1887                 }
1888             }
1889         }
1890     }
1891 
1892     SAL_WARN("sw.core", "SwCellFrame::FindStartRowSpanCell: No result");
1893 
1894     return *this;
1895 }
1896 
1897 // <-- NEW TABLES
1898 
IsInSplitTableRow() const1899 const SwRowFrame* SwFrame::IsInSplitTableRow() const
1900 {
1901     OSL_ENSURE( IsInTab(), "IsInSplitTableRow should only be called for frames in tables" );
1902 
1903     const SwFrame* pRow = this;
1904 
1905     // find most upper row frame
1906     while( pRow && ( !pRow->IsRowFrame() || !pRow->GetUpper()->IsTabFrame() ) )
1907         pRow = pRow->GetUpper();
1908 
1909     if ( !pRow ) return nullptr;
1910 
1911     OSL_ENSURE( pRow->GetUpper()->IsTabFrame(), "Confusion in table layout" );
1912 
1913     const SwTabFrame* pTab = static_cast<const SwTabFrame*>(pRow->GetUpper());
1914 
1915     // If most upper row frame is a headline row, the current frame
1916     // can't be in a split table row. Thus, add corresponding condition.
1917     if ( pRow->GetNext() ||
1918          pTab->GetTable()->IsHeadline(
1919                     *(static_cast<const SwRowFrame*>(pRow)->GetTabLine()) ) ||
1920          !pTab->HasFollowFlowLine() ||
1921          !pTab->GetFollow() )
1922         return nullptr;
1923 
1924     // skip headline
1925     const SwRowFrame* pFollowRow = pTab->GetFollow()->GetFirstNonHeadlineRow();
1926 
1927     OSL_ENSURE( pFollowRow, "SwFrame::IsInSplitTableRow() does not work" );
1928 
1929     return pFollowRow;
1930 }
1931 
IsInFollowFlowRow() const1932 const SwRowFrame* SwFrame::IsInFollowFlowRow() const
1933 {
1934     OSL_ENSURE( IsInTab(), "IsInSplitTableRow should only be called for frames in tables" );
1935 
1936     // find most upper row frame
1937     const SwFrame* pRow = this;
1938     while( pRow && ( !pRow->IsRowFrame() || !pRow->GetUpper()->IsTabFrame() ) )
1939         pRow = pRow->GetUpper();
1940 
1941     if ( !pRow ) return nullptr;
1942 
1943     OSL_ENSURE( pRow->GetUpper()->IsTabFrame(), "Confusion in table layout" );
1944 
1945     const SwTabFrame* pTab = static_cast<const SwTabFrame*>(pRow->GetUpper());
1946 
1947     const SwTabFrame* pMaster = pTab->IsFollow() ? pTab->FindMaster() : nullptr;
1948 
1949     if ( !pMaster || !pMaster->HasFollowFlowLine() )
1950         return nullptr;
1951 
1952     const SwFrame* pTmp = pTab->GetFirstNonHeadlineRow();
1953     const bool bIsInFirstLine = ( pTmp == pRow );
1954 
1955     if ( !bIsInFirstLine )
1956         return nullptr;
1957 
1958     const SwRowFrame* pMasterRow = static_cast<const SwRowFrame*>(pMaster->GetLastLower());
1959     return pMasterRow;
1960 }
1961 
IsInBalancedSection() const1962 bool SwFrame::IsInBalancedSection() const
1963 {
1964     bool bRet = false;
1965 
1966     if ( IsInSct() )
1967     {
1968         const SwSectionFrame* pSectionFrame = FindSctFrame();
1969         if ( pSectionFrame )
1970             bRet = pSectionFrame->IsBalancedSection();
1971     }
1972     return bRet;
1973 }
1974 
GetLastLower() const1975 const SwFrame* SwLayoutFrame::GetLastLower() const
1976 {
1977     const SwFrame* pRet = Lower();
1978     if ( !pRet )
1979         return nullptr;
1980     while ( pRet->GetNext() )
1981         pRet = pRet->GetNext();
1982     return pRet;
1983 }
1984 
DynCastTextFrame()1985 SwTextFrame* SwFrame::DynCastTextFrame()
1986 {
1987     return IsTextFrame() ? static_cast<SwTextFrame*>(this) : nullptr;
1988 }
1989 
DynCastTextFrame() const1990 const SwTextFrame* SwFrame::DynCastTextFrame() const
1991 {
1992     return IsTextFrame() ? static_cast<const SwTextFrame*>(this) : nullptr;
1993 }
1994 
DynCastPageFrame()1995 SwPageFrame* SwFrame::DynCastPageFrame()
1996 {
1997     return IsPageFrame() ? static_cast<SwPageFrame*>(this) : nullptr;
1998 }
1999 
DynCastPageFrame() const2000 const SwPageFrame* SwFrame::DynCastPageFrame() const
2001 {
2002     return IsPageFrame() ? static_cast<const SwPageFrame*>(this) : nullptr;
2003 }
2004 
DynCastColumnFrame()2005 SwColumnFrame* SwFrame::DynCastColumnFrame()
2006 {
2007     return IsColumnFrame() ? static_cast<SwColumnFrame*>(this) : nullptr;
2008 }
2009 
DynCastColumnFrame() const2010 const SwColumnFrame* SwFrame::DynCastColumnFrame() const
2011 {
2012     return IsColumnFrame() ? static_cast<const SwColumnFrame*>(this) : nullptr;
2013 }
2014 
2015 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2016