xref: /core/sw/source/core/layout/flylay.cxx (revision f2cd9c0c)
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 <rootfrm.hxx>
22 #include <cntfrm.hxx>
23 #include <dflyobj.hxx>
24 #include <dcontact.hxx>
25 #include <ftnfrm.hxx>
26 #include <frmtool.hxx>
27 #include <hints.hxx>
28 #include <sectfrm.hxx>
29 #include <notxtfrm.hxx>
30 #include <txtfly.hxx>
31 
32 #include <svx/svdpage.hxx>
33 #include <editeng/ulspitem.hxx>
34 #include <fmtornt.hxx>
35 #include <fmtfsize.hxx>
36 #include <ndole.hxx>
37 #include <tabfrm.hxx>
38 #include <flyfrms.hxx>
39 #include <fmtfollowtextflow.hxx>
40 #include <environmentofanchoredobject.hxx>
41 #include <sortedobjs.hxx>
42 #include <viewimp.hxx>
43 #include <IDocumentSettingAccess.hxx>
44 #include <IDocumentDrawModelAccess.hxx>
45 #include <pam.hxx>
46 #include <ndindex.hxx>
47 #include <basegfx/matrix/b2dhommatrixtools.hxx>
48 #include <svx/sdr/attribute/sdrallfillattributeshelper.hxx>
49 
50 using namespace ::com::sun::star;
51 
52 SwFlyFreeFrame::SwFlyFreeFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch )
53 :   SwFlyFrame( pFormat, pSib, pAnch ),
54     // #i34753#
55     mbNoMakePos( false ),
56     // #i37068#
57     mbNoMoveOnCheckClip( false ),
58     maUnclippedFrame(),
59     // RotateFlyFrame3
60     mpTransformableSwFrame()
61 {
62 }
63 
64 void SwFlyFreeFrame::DestroyImpl()
65 {
66     // #i28701# - use new method <GetPageFrame()>
67     if( GetPageFrame() )
68     {
69         if( GetFormat()->GetDoc()->IsInDtor() )
70         {
71             // #i29879# - remove also to-frame anchored Writer
72             // fly frame from page.
73             const bool bRemoveFromPage =
74                     GetPageFrame()->GetSortedObjs() &&
75                     ( IsFlyAtContentFrame() ||
76                       ( GetAnchorFrame() && GetAnchorFrame()->IsFlyFrame() ) );
77             if ( bRemoveFromPage )
78             {
79                 GetPageFrame()->GetSortedObjs()->Remove( *this );
80             }
81         }
82         else
83         {
84             SwRect aTmp( GetObjRectWithSpaces() );
85             SwFlyFreeFrame::NotifyBackground( GetPageFrame(), aTmp, PREP_FLY_LEAVE );
86         }
87     }
88 
89     SwFlyFrame::DestroyImpl();
90 }
91 
92 SwFlyFreeFrame::~SwFlyFreeFrame()
93 {
94 #if 0
95     // we are possibly in ContourCache, make sure we vanish
96     ::ClrContourCache(GetVirtDrawObj());
97 #endif
98 }
99 
100 // #i28701#
101 /** Notifies the background (all ContentFrames that currently are overlapping).
102  *
103  * Additionally, the window is also directly invalidated (especially where
104  * there are no overlapping ContentFrames).
105  * This also takes ContentFrames within other Flys into account.
106  */
107 void SwFlyFreeFrame::NotifyBackground( SwPageFrame *pPageFrame,
108                                      const SwRect& rRect, PrepareHint eHint )
109 {
110     ::Notify_Background( GetVirtDrawObj(), pPageFrame, rRect, eHint, true );
111 }
112 
113 void SwFlyFreeFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
114 {
115     if ( !GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId( GetVirtDrawObj()->GetLayer() ) )
116     {
117         return;
118     }
119 
120     if ( !GetAnchorFrame() || IsLocked() || IsColLocked() )
121     {
122         return;
123     }
124 
125     // #i28701# - use new method <GetPageFrame()>
126     if( !GetPageFrame() && GetAnchorFrame()->IsInFly() )
127     {
128         SwFlyFrame* pFly = AnchorFrame()->FindFlyFrame();
129         SwPageFrame *pPageFrame = pFly ? pFly->FindPageFrame() : nullptr;
130         if( pPageFrame )
131             pPageFrame->AppendFlyToPage( this );
132     }
133 
134     if( !GetPageFrame() )
135     {
136         return;
137     }
138 
139     Lock(); // The curtain drops
140 
141     // takes care of the notification in the dtor
142     const SwFlyNotify aNotify( this );
143 
144     if ( IsClipped() )
145     {
146         setFrameAreaSizeValid(false);
147         m_bHeightClipped = m_bWidthClipped = false;
148         // no invalidation of position,
149         // if anchored object is anchored inside a Writer fly frame,
150         // its position is already locked, and it follows the text flow.
151         // #i34753# - add condition:
152         // no invalidation of position, if no direct move is requested in <CheckClip(..)>
153         if ( !IsNoMoveOnCheckClip() &&
154              !( PositionLocked() &&
155                 GetAnchorFrame()->IsInFly() &&
156                 GetFrameFormat().GetFollowTextFlow().GetValue() ) )
157         {
158             setFrameAreaPositionValid(false);
159         }
160     }
161 
162     // #i81146# new loop control
163     int nLoopControlRuns = 0;
164     const int nLoopControlMax = 10;
165 
166     // RotateFlyFrame3 - outer frame
167     const double fRotation(getLocalFrameRotation());
168     const bool bRotated(!basegfx::fTools::equalZero(fRotation));
169 
170     if(bRotated)
171     {
172         // Re-layout may be partially (see all isFrameAreaDefinitionValid() flags),
173         // so resetting the local SwFrame(s) in the local SwFrameAreaDefinition is
174         // needed. Reset to BoundAreas will be done below automatically
175         if(isTransformableSwFrame())
176         {
177             getTransformableSwFrame()->restoreFrameAreas();
178         }
179     }
180 
181     while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() || m_bFormatHeightOnly || !m_bValidContentPos )
182     {
183         SwRectFnSet aRectFnSet(this);
184         const SwFormatFrameSize *pSz;
185         {   // Additional scope, so aAccess will be destroyed before the check!
186 
187             SwBorderAttrAccess aAccess( SwFrame::GetCache(), this );
188             const SwBorderAttrs &rAttrs = *aAccess.Get();
189             pSz = &rAttrs.GetAttrSet().GetFrameSize();
190 
191             // Only set when the flag is set!
192             if ( !isFrameAreaSizeValid() )
193             {
194                 setFramePrintAreaValid(false);
195             }
196 
197             if ( !isFramePrintAreaValid() )
198             {
199                 MakePrtArea( rAttrs );
200                 m_bValidContentPos = false;
201             }
202 
203             if ( !isFrameAreaSizeValid() || m_bFormatHeightOnly )
204             {
205                 setFrameAreaSizeValid(false);
206                 Format( getRootFrame()->GetCurrShell()->GetOut(), &rAttrs );
207                 m_bFormatHeightOnly = false;
208             }
209         }
210 
211         if ( !isFrameAreaPositionValid() )
212         {
213             const Point aOldPos( aRectFnSet.GetPos(getFrameArea()) );
214             // #i26791# - use new method <MakeObjPos()>
215             // #i34753# - no positioning, if requested.
216             if ( IsNoMakePos() )
217             {
218                 setFrameAreaPositionValid(true);
219             }
220             else
221                 // #i26791# - use new method <MakeObjPos()>
222                 MakeObjPos();
223             if( aOldPos == aRectFnSet.GetPos(getFrameArea()) )
224             {
225                 if( !isFrameAreaPositionValid() && GetAnchorFrame()->IsInSct() &&
226                     !GetAnchorFrame()->FindSctFrame()->isFrameAreaDefinitionValid() )
227                 {
228                     setFrameAreaPositionValid(true);
229                 }
230             }
231             else
232             {
233                 setFrameAreaSizeValid(false);
234             }
235         }
236 
237         if ( !m_bValidContentPos )
238         {
239             SwBorderAttrAccess aAccess( SwFrame::GetCache(), this );
240             const SwBorderAttrs &rAttrs = *aAccess.Get();
241             MakeContentPos( rAttrs );
242         }
243 
244         if ( isFrameAreaPositionValid() && isFrameAreaSizeValid() )
245         {
246             ++nLoopControlRuns;
247 
248             OSL_ENSURE( nLoopControlRuns < nLoopControlMax, "LoopControl in SwFlyFreeFrame::MakeAll" );
249 
250             if ( nLoopControlRuns < nLoopControlMax )
251                 CheckClip( *pSz );
252         }
253         else
254             nLoopControlRuns = 0;
255     }
256 
257     // RotateFlyFrame3 - outer frame
258     // Do not refresh transforms/Areas self here, this will be done
259     // when inner and outer frame are layouted, in SwNoTextFrame::MakeAll
260     if(bRotated)
261     {
262         // RotateFlyFrame3: Safe changes locally
263         // get center from outer frame (layout frame) to be on the safe side
264         const Point aCenter(getFrameArea().Center());
265         const basegfx::B2DPoint aB2DCenter(aCenter.X(), aCenter.Y());
266 
267         if(!mpTransformableSwFrame)
268         {
269             mpTransformableSwFrame.reset(new TransformableSwFrame(*this));
270         }
271 
272         getTransformableSwFrame()->createFrameAreaTransformations(
273             fRotation,
274             aB2DCenter);
275         getTransformableSwFrame()->adaptFrameAreasToTransformations();
276     }
277     else
278     {
279         // RotateFlyFrame3: Also need to clear ContourCache (if used),
280         // usually done in SwFlyFrame::NotifyDrawObj, but there relies on
281         // being in transform mode which is already resetted then
282         if(isTransformableSwFrame())
283         {
284             ::ClrContourCache(GetVirtDrawObj());
285         }
286 
287         // reset transformations to show that they are not used
288         mpTransformableSwFrame.reset();
289     }
290 
291     Unlock();
292 
293 #if OSL_DEBUG_LEVEL > 0
294     SwRectFnSet aRectFnSet(this);
295     OSL_ENSURE( m_bHeightClipped || ( aRectFnSet.GetHeight(getFrameArea()) > 0 &&
296             aRectFnSet.GetHeight(getFramePrintArea()) > 0),
297             "SwFlyFreeFrame::Format(), flipping Fly." );
298 
299 #endif
300 }
301 
302 bool SwFlyFreeFrame::supportsAutoContour() const
303 {
304     static bool bOverrideHandleContourToAlwaysOff(true);
305 
306     // RotateFlyFrameFix: For LO6.0 we need to deactivate the AutoContour feature again, it is simply
307     // not clear how/if to use and save/load it in ODF. This has to be discussed.
308     // The reason not to remove is that this may be used as-is now, using a new switch.
309     // Even when not, the detection if it is possible will be needed in any case later.
310     if(bOverrideHandleContourToAlwaysOff)
311     {
312         return false;
313     }
314 
315     if(!isTransformableSwFrame())
316     {
317         // support only when transformed, else there is no free space
318         return false;
319     }
320 
321     // Check for Borders. If we have Borders, do (currently) not support,
322     // since borders do not transform with the object.
323     // (Will need to be enhanced to take into account if we have Borders and if these
324     // transform with the object)
325     SwBorderAttrAccess aAccess(SwFrame::GetCache(), this);
326     const SwBorderAttrs &rAttrs(*aAccess.Get());
327 
328     if(rAttrs.IsLine())
329     {
330         return false;
331     }
332 
333     // Check for Padding. Do not support when padding is used, this will
334     // produce a covered space around the object (filled with fill defines)
335     const SfxPoolItem* pItem(nullptr);
336 
337     if(GetFormat() && SfxItemState::SET == GetFormat()->GetItemState(RES_BOX, false, &pItem))
338     {
339         const SvxBoxItem& rBox = *static_cast< const SvxBoxItem* >(pItem);
340 
341         if(rBox.HasBorder(/*bTreatPaddingAsBorder*/true))
342         {
343             return false;
344         }
345     }
346 
347     // check for Fill - if we have fill, it will fill the gaps and we will not
348     // support AutoContour
349     if(GetFormat() && GetFormat()->supportsFullDrawingLayerFillAttributeSet())
350     {
351         const drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes(GetFormat()->getSdrAllFillAttributesHelper());
352 
353         if(aFillAttributes.get() && aFillAttributes->isUsed())
354         {
355             return false;
356         }
357     }
358     else
359     {
360         const SvxBrushItem aBack(GetFormat()->makeBackgroundBrushItem());
361 
362         if(aBack.isUsed())
363         {
364             return false;
365         }
366     }
367 
368     // else, support
369     return true;
370 }
371 
372 // RotateFlyFrame3 - Support for Transformations - outer frame
373 basegfx::B2DHomMatrix SwFlyFreeFrame::getFrameAreaTransformation() const
374 {
375     if(isTransformableSwFrame())
376     {
377         // use pre-created transformation
378         return getTransformableSwFrame()->getLocalFrameAreaTransformation();
379     }
380 
381     // call parent
382     return SwFlyFrame::getFrameAreaTransformation();
383 }
384 
385 basegfx::B2DHomMatrix SwFlyFreeFrame::getFramePrintAreaTransformation() const
386 {
387     if(isTransformableSwFrame())
388     {
389         // use pre-created transformation
390         return getTransformableSwFrame()->getLocalFramePrintAreaTransformation();
391     }
392 
393     // call parent
394     return SwFlyFrame::getFramePrintAreaTransformation();
395 }
396 
397 // RotateFlyFrame3 - Support for Transformations
398 void SwFlyFreeFrame::transform_translate(const Point& rOffset)
399 {
400     // call parent - this will do the basic transform for SwRect(s)
401     // in the SwFrameAreaDefinition
402     SwFlyFrame::transform_translate(rOffset);
403 
404     // check if the Transformations need to be adapted
405     if(isTransformableSwFrame())
406     {
407         const basegfx::B2DHomMatrix aTransform(
408             basegfx::utils::createTranslateB2DHomMatrix(
409                 rOffset.X(), rOffset.Y()));
410 
411         // transform using TransformableSwFrame
412         getTransformableSwFrame()->transform(aTransform);
413     }
414 }
415 
416 // RotateFlyFrame3 - outer frame
417 double getLocalFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame)
418 {
419     return rNoTextFrame.getLocalFrameRotation();
420 }
421 
422 double SwFlyFreeFrame::getLocalFrameRotation() const
423 {
424     // SwLayoutFrame::Lower() != SwFrame::GetLower(), but SwFrame::GetLower()
425     // calls SwLayoutFrame::Lower() when it's a SwLayoutFrame - so use GetLower()
426     const SwNoTextFrame* pSwNoTextFrame(dynamic_cast< const SwNoTextFrame* >(GetLower()));
427 
428     if(nullptr != pSwNoTextFrame)
429     {
430         return getLocalFrameRotation_from_SwNoTextFrame(*pSwNoTextFrame);
431     }
432 
433     // no rotation
434     return 0.0;
435 }
436 
437 /** determines, if direct environment of fly frame has 'auto' size
438 
439     #i17297#
440     start with anchor frame and search via <GetUpper()> for a header, footer,
441     row or fly frame stopping at page frame.
442     return <true>, if such a frame is found and it has 'auto' size.
443     otherwise <false> is returned.
444 
445     @return boolean indicating, that direct environment has 'auto' size
446 */
447 bool SwFlyFreeFrame::HasEnvironmentAutoSize() const
448 {
449     bool bRetVal = false;
450 
451     const SwFrame* pToBeCheckedFrame = GetAnchorFrame();
452     while ( pToBeCheckedFrame &&
453             !pToBeCheckedFrame->IsPageFrame() )
454     {
455         if ( pToBeCheckedFrame->IsHeaderFrame() ||
456              pToBeCheckedFrame->IsFooterFrame() ||
457              pToBeCheckedFrame->IsRowFrame() ||
458              pToBeCheckedFrame->IsFlyFrame() )
459         {
460             bRetVal = ATT_FIX_SIZE !=
461                       pToBeCheckedFrame->GetAttrSet()->GetFrameSize().GetHeightSizeType();
462             break;
463         }
464         else
465         {
466             pToBeCheckedFrame = pToBeCheckedFrame->GetUpper();
467         }
468     }
469 
470     return bRetVal;
471 }
472 
473 void SwFlyFreeFrame::CheckClip( const SwFormatFrameSize &rSz )
474 {
475     // It's probably time now to take appropriate measures, if the Fly
476     // doesn't fit into its surrounding.
477     // First, the Fly gives up its position, then it's formatted.
478     // Only if it still doesn't fit after giving up its position, the
479     // width or height are given up as well. The frame will be squeezed
480     // as much as needed.
481 
482     const SwVirtFlyDrawObj *pObj = GetVirtDrawObj();
483     SwRect aClip, aTmpStretch;
484     ::CalcClipRect( pObj, aClip );
485     ::CalcClipRect( pObj, aTmpStretch, false );
486     aClip.Intersection_( aTmpStretch );
487 
488     const long nBot = getFrameArea().Top() + getFrameArea().Height();
489     const long nRig = getFrameArea().Left() + getFrameArea().Width();
490     const long nClipBot = aClip.Top() + aClip.Height();
491     const long nClipRig = aClip.Left() + aClip.Width();
492 
493     const bool bBot = nBot > nClipBot;
494     const bool bRig = nRig > nClipRig;
495     if ( bBot || bRig )
496     {
497         bool bAgain = false;
498         // #i37068# - no move, if it's requested
499         if ( bBot && !IsNoMoveOnCheckClip() &&
500              !GetDrawObjs() && !GetAnchorFrame()->IsInTab() )
501         {
502             SwFrame* pHeader = FindFooterOrHeader();
503             // In a header, correction of the position is no good idea.
504             // If the fly moves, some paragraphs have to be formatted, this
505             // could cause a change of the height of the headerframe,
506             // now the flyframe can change its position and so on ...
507             if ( !pHeader || !pHeader->IsHeaderFrame() )
508             {
509                 const long nOld = getFrameArea().Top();
510 
511                 // tdf#112443 disable positioning if content is completely off page
512                 bool bDisableOffPagePositioning = GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);
513                 if ( !bDisableOffPagePositioning || nOld <= nClipBot)
514                 {
515                     SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
516                     aFrm.Pos().setY( std::max( aClip.Top(), nClipBot - aFrm.Height() ) );
517                 }
518 
519                 if ( getFrameArea().Top() != nOld )
520                 {
521                     bAgain = true;
522                 }
523 
524                 m_bHeightClipped = true;
525             }
526         }
527         if ( bRig )
528         {
529             const long nOld = getFrameArea().Left();
530 
531             // tdf#112443 disable positioning if content is completely off page
532             bool bDisableOffPagePositioning = GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);
533             if ( !bDisableOffPagePositioning || nOld <= nClipRig )
534             {
535                 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
536                 aFrm.Pos().setX( std::max( aClip.Left(), nClipRig - aFrm.Width() ) );
537             }
538 
539             if ( getFrameArea().Left() != nOld )
540             {
541                 const SwFormatHoriOrient &rH = GetFormat()->GetHoriOrient();
542                 // Left-aligned ones may not be moved to the left when they
543                 // are avoiding another one.
544                 if( rH.GetHoriOrient() == text::HoriOrientation::LEFT )
545                 {
546                     SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
547                     aFrm.Pos().setX( nOld );
548                 }
549                 else
550                 {
551                     bAgain = true;
552                 }
553             }
554             m_bWidthClipped = true;
555         }
556         if ( bAgain )
557         {
558             setFrameAreaSizeValid(false);
559         }
560         else
561         {
562             // If we reach this branch, the Frame protrudes into forbidden
563             // areas, and correcting the position is not allowed or not
564             // possible or not required.
565 
566             // For Flys with OLE objects as lower, we make sure that
567             // we always resize proportionally
568             Size aOldSize( getFrameArea().SSize() );
569 
570             // First, setup the FrameRect, then transfer it to the Frame.
571             SwRect aFrameRect( getFrameArea() );
572 
573             if ( bBot )
574             {
575                 long nDiff = nClipBot;
576                 nDiff -= aFrameRect.Top(); // nDiff represents the available distance
577                 nDiff = aFrameRect.Height() - nDiff;
578                 aFrameRect.Height( aFrameRect.Height() - nDiff );
579                 m_bHeightClipped = true;
580             }
581             if ( bRig )
582             {
583                 long nDiff = nClipRig;
584                 nDiff -= aFrameRect.Left();// nDiff represents the available distance
585                 nDiff = aFrameRect.Width() - nDiff;
586                 aFrameRect.Width( aFrameRect.Width() - nDiff );
587                 m_bWidthClipped = true;
588             }
589 
590             // #i17297# - no proportional
591             // scaling of graphics in environments, which determines its size
592             // by its content ('auto' size). Otherwise layout loops can occur and
593             // layout sizes of the environment can be incorrect.
594             // Such environment are:
595             // (1) header and footer frames with 'auto' size
596             // (2) table row frames with 'auto' size
597             // (3) fly frames with 'auto' size
598             // Note: section frames seems to be not critical - didn't found
599             //       any critical layout situation so far.
600             if ( Lower() && Lower()->IsNoTextFrame() &&
601                  (static_cast<SwNoTextFrame*>(Lower())->GetNode()->GetOLENode() ||
602                    !HasEnvironmentAutoSize() ) )
603             {
604                 // If width and height got adjusted, then the bigger
605                 // change is relevant.
606                 if ( aFrameRect.Width() != aOldSize.Width() &&
607                      aFrameRect.Height()!= aOldSize.Height() )
608                 {
609                     if ( (aOldSize.Width() - aFrameRect.Width()) >
610                          (aOldSize.Height()- aFrameRect.Height()) )
611                         aFrameRect.Height( aOldSize.Height() );
612                     else
613                         aFrameRect.Width( aOldSize.Width() );
614                 }
615 
616                 // Adjusted the width? change height proportionally
617                 if( aFrameRect.Width() != aOldSize.Width() )
618                 {
619                     aFrameRect.Height( aFrameRect.Width() * aOldSize.Height() /
620                                      aOldSize.Width() );
621                     m_bHeightClipped = true;
622                 }
623                 // Adjusted the height? change width proportionally
624                 else if( aFrameRect.Height() != aOldSize.Height() )
625                 {
626                     aFrameRect.Width( aFrameRect.Height() * aOldSize.Width() /
627                                     aOldSize.Height() );
628                     m_bWidthClipped = true;
629                 }
630 
631                 // #i17297# - reactivate change
632                 // of size attribute for fly frames containing an ole object.
633 
634                 // Added the aFrameRect.HasArea() hack, because
635                 // the environment of the ole object does not have to be valid
636                 // at this moment, or even worse, it does not have to have a
637                 // reasonable size. In this case we do not want to change to
638                 // attributes permanently. Maybe one day somebody dares to remove
639                 // this code.
640                 if ( aFrameRect.HasArea() &&
641                      static_cast<SwNoTextFrame*>(Lower())->GetNode()->GetOLENode() &&
642                      ( m_bWidthClipped || m_bHeightClipped ) )
643                 {
644                     SwFlyFrameFormat *pFormat = GetFormat();
645                     pFormat->LockModify();
646                     SwFormatFrameSize aFrameSize( rSz );
647                     aFrameSize.SetWidth( aFrameRect.Width() );
648                     aFrameSize.SetHeight( aFrameRect.Height() );
649                     pFormat->SetFormatAttr( aFrameSize );
650                     pFormat->UnlockModify();
651                 }
652             }
653 
654             // Now change the Frame; for columns, we put the new values into the attributes,
655             // otherwise we'll end up with unwanted side-effects/oscillations
656             const long nPrtHeightDiff = getFrameArea().Height() - getFramePrintArea().Height();
657             const long nPrtWidthDiff  = getFrameArea().Width()  - getFramePrintArea().Width();
658             maUnclippedFrame = getFrameArea();
659 
660             {
661                 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
662                 aFrm.Height( aFrameRect.Height() );
663                 aFrm.Width ( std::max( long(MINLAY), aFrameRect.Width() ) );
664             }
665 
666             if ( Lower() && Lower()->IsColumnFrame() )
667             {
668                 ColLock();  //lock grow/shrink
669                 const Size aTmpOldSize( getFramePrintArea().SSize() );
670 
671                 {
672                     SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
673                     aPrt.Height( getFrameArea().Height() - nPrtHeightDiff );
674                     aPrt.Width ( getFrameArea().Width()  - nPrtWidthDiff );
675                 }
676 
677                 ChgLowersProp( aTmpOldSize );
678                 SwFrame *pLow = Lower();
679                 do
680                 {
681                     pLow->Calc(getRootFrame()->GetCurrShell()->GetOut());
682                     // also calculate the (Column)BodyFrame
683                     static_cast<SwLayoutFrame*>(pLow)->Lower()->Calc(getRootFrame()->GetCurrShell()->GetOut());
684                     pLow = pLow->GetNext();
685                 } while ( pLow );
686                 ::CalcContent( this );
687                 ColUnlock();
688 
689                 if ( !isFrameAreaSizeValid() && !m_bWidthClipped )
690                 {
691                     setFrameAreaSizeValid(true);
692                     m_bFormatHeightOnly = true;
693                 }
694             }
695             else
696             {
697                 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
698                 aPrt.Height( getFrameArea().Height() - nPrtHeightDiff );
699                 aPrt.Width ( getFrameArea().Width()  - nPrtWidthDiff );
700             }
701         }
702     }
703 
704     // #i26945#
705     OSL_ENSURE( getFrameArea().Height() >= 0,
706             "<SwFlyFreeFrame::CheckClip(..)> - fly frame has negative height now." );
707 }
708 
709 /** method to determine, if a <MakeAll()> on the Writer fly frame is possible
710     #i43771#
711 */
712 bool SwFlyFreeFrame::IsFormatPossible() const
713 {
714     return SwFlyFrame::IsFormatPossible() &&
715            ( GetPageFrame() ||
716              ( GetAnchorFrame() && GetAnchorFrame()->IsInFly() ) );
717 }
718 
719 SwFlyLayFrame::SwFlyLayFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch ) :
720     SwFlyFreeFrame( pFormat, pSib, pAnch )
721 {
722     m_bLayout = true;
723 }
724 
725 // #i28701#
726 
727 void SwFlyLayFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
728 {
729     const SwFormatAnchor *pAnch = nullptr;
730 
731     if (pNew)
732     {
733         const sal_uInt16 nWhich = pNew->Which();
734         if( RES_ATTRSET_CHG == nWhich && SfxItemState::SET ==
735             static_cast<const SwAttrSetChg*>(pNew)->GetChgSet()->GetItemState( RES_ANCHOR, false,
736                 reinterpret_cast<const SfxPoolItem**>(&pAnch) ))
737             ; // GetItemState sets the anchor pointer!
738 
739         else if( RES_ANCHOR == nWhich )
740         {
741             // Change of anchor. I'm attaching myself to the new place.
742             // It's not allowed to change the anchor type. This is only
743             // possible via SwFEShell.
744             pAnch = static_cast<const SwFormatAnchor*>(pNew);
745         }
746     }
747 
748     if( pAnch )
749     {
750         OSL_ENSURE( pAnch->GetAnchorId() ==
751                 GetFormat()->GetAnchor().GetAnchorId(),
752                 "8-) Invalid change of anchor type." );
753 
754         // Unregister, get hold of the page, attach to the corresponding LayoutFrame.
755         SwRect aOld( GetObjRectWithSpaces() );
756         // #i28701# - use new method <GetPageFrame()>
757         SwPageFrame *pOldPage = GetPageFrame();
758         AnchorFrame()->RemoveFly( this );
759 
760         if ( RndStdIds::FLY_AT_PAGE == pAnch->GetAnchorId() )
761         {
762             sal_uInt16 nPgNum = pAnch->GetPageNum();
763             SwRootFrame *pRoot = getRootFrame();
764             SwPageFrame *pTmpPage = static_cast<SwPageFrame*>(pRoot->Lower());
765             for ( sal_uInt16 i = 1; (i <= nPgNum) && pTmpPage; ++i,
766                                 pTmpPage = static_cast<SwPageFrame*>(pTmpPage->GetNext()) )
767             {
768                 if ( i == nPgNum )
769                 {
770                     // #i50432# - adjust synopsis of <PlaceFly(..)>
771                     pTmpPage->PlaceFly( this, nullptr );
772                 }
773             }
774             if( !pTmpPage )
775             {
776                 pRoot->SetAssertFlyPages();
777                 pRoot->AssertFlyPages();
778             }
779         }
780         else
781         {
782             SwNodeIndex aIdx( pAnch->GetContentAnchor()->nNode );
783             SwContentFrame *pContent = GetFormat()->GetDoc()->GetNodes().GoNext( &aIdx )->
784                 GetContentNode()->getLayoutFrame(getRootFrame(), nullptr, nullptr);
785             if( pContent )
786             {
787                 SwFlyFrame *pTmp = pContent->FindFlyFrame();
788                 if( pTmp )
789                     pTmp->AppendFly( this );
790             }
791         }
792         // #i28701# - use new method <GetPageFrame()>
793         if ( pOldPage && pOldPage != GetPageFrame() )
794             NotifyBackground( pOldPage, aOld, PREP_FLY_LEAVE );
795         SetCompletePaint();
796         InvalidateAll();
797         SetNotifyBack();
798     }
799     else
800         SwFlyFrame::Modify( pOld, pNew );
801 }
802 
803 void SwPageFrame::AppendFlyToPage( SwFlyFrame *pNew )
804 {
805     if ( !pNew->GetVirtDrawObj()->IsInserted() )
806         getRootFrame()->GetDrawPage()->InsertObject(
807                 static_cast<SdrObject*>(pNew->GetVirtDrawObj()),
808                 pNew->GetVirtDrawObj()->GetReferencedObj().GetOrdNumDirect() );
809 
810     InvalidateSpelling();
811     InvalidateSmartTags();
812     InvalidateAutoCompleteWords();
813     InvalidateWordCount();
814 
815     if ( GetUpper() )
816     {
817         static_cast<SwRootFrame*>(GetUpper())->SetIdleFlags();
818         static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth();
819     }
820 
821     SdrObject* pObj = pNew->GetVirtDrawObj();
822     OSL_ENSURE( pNew->GetAnchorFrame(), "Fly without Anchor" );
823     SwFlyFrame* pFly = const_cast<SwFlyFrame*>(pNew->GetAnchorFrame()->FindFlyFrame());
824     if ( pFly && pObj->GetOrdNum() < pFly->GetVirtDrawObj()->GetOrdNum() )
825     {
826         //#i119945# set pFly's OrdNum to _rNewObj's. So when pFly is removed by Undo, the original OrdNum will not be changed.
827         sal_uInt32 nNewNum = pObj->GetOrdNumDirect();
828         if ( pObj->getSdrPageFromSdrObject() )
829             pObj->getSdrPageFromSdrObject()->SetObjectOrdNum( pFly->GetVirtDrawObj()->GetOrdNumDirect(), nNewNum );
830         else
831             pFly->GetVirtDrawObj()->SetOrdNum( nNewNum );
832     }
833 
834     // Don't look further at Flys that sit inside the Content.
835     if ( pNew->IsFlyInContentFrame() )
836         InvalidateFlyInCnt();
837     else
838     {
839         InvalidateFlyContent();
840 
841         if ( !m_pSortedObjs )
842         {
843             m_pSortedObjs.reset(new SwSortedObjs());
844         }
845 
846         const bool bSuccessInserted = m_pSortedObjs->Insert( *pNew );
847         OSL_ENSURE( bSuccessInserted, "Fly not inserted in Sorted." );
848 
849         // #i87493#
850         OSL_ENSURE( pNew->GetPageFrame() == nullptr || pNew->GetPageFrame() == this,
851                 "<SwPageFrame::AppendFlyToPage(..)> - anchored fly frame seems to be registered at another page frame. Serious defect." );
852         // #i28701# - use new method <SetPageFrame(..)>
853         pNew->SetPageFrame( this );
854         pNew->InvalidatePage( this );
855         // #i28701#
856         pNew->UnlockPosition();
857 
858         // Notify accessible layout. That's required at this place for
859         // frames only where the anchor is moved. Creation of new frames
860         // is additionally handled by the SwFrameNotify class.
861         if( GetUpper() &&
862             static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
863              static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
864         {
865             static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
866                                       ->AddAccessibleFrame( pNew );
867         }
868     }
869 
870     // #i28701# - correction: consider also drawing objects
871     if ( pNew->GetDrawObjs() )
872     {
873         SwSortedObjs &rObjs = *pNew->GetDrawObjs();
874         for (SwAnchoredObject* pTmpObj : rObjs)
875         {
876             if ( dynamic_cast<const SwFlyFrame*>( pTmpObj) !=  nullptr )
877             {
878                 SwFlyFrame* pTmpFly = static_cast<SwFlyFrame*>(pTmpObj);
879                 // #i28701# - use new method <GetPageFrame()>
880                 if ( pTmpFly->IsFlyFreeFrame() && !pTmpFly->GetPageFrame() )
881                     AppendFlyToPage( pTmpFly );
882             }
883             else if ( dynamic_cast<const SwAnchoredDrawObject*>( pTmpObj) !=  nullptr )
884             {
885                 // #i87493#
886                 if ( pTmpObj->GetPageFrame() != this )
887                 {
888                     if ( pTmpObj->GetPageFrame() != nullptr )
889                     {
890                         pTmpObj->GetPageFrame()->RemoveDrawObjFromPage( *pTmpObj );
891                     }
892                     AppendDrawObjToPage( *pTmpObj );
893                 }
894             }
895         }
896     }
897 }
898 
899 void SwPageFrame::RemoveFlyFromPage( SwFlyFrame *pToRemove )
900 {
901     const sal_uInt32 nOrdNum = pToRemove->GetVirtDrawObj()->GetOrdNum();
902     getRootFrame()->GetDrawPage()->RemoveObject( nOrdNum );
903     pToRemove->GetVirtDrawObj()->ReferencedObj().SetOrdNum( nOrdNum );
904 
905     if ( GetUpper() )
906     {
907         if ( !pToRemove->IsFlyInContentFrame() )
908             static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous();
909         static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth();
910     }
911 
912     // Don't look further at Flys that sit inside the Content.
913     if ( pToRemove->IsFlyInContentFrame() )
914         return;
915 
916     // Don't delete collections just yet. This will happen at the end of the
917     // action in the RemoveSuperfluous of the page, kicked off by a method of
918     // the same name in the root.
919     // The FlyColl might be gone already, because the page's dtor is being
920     // executed.
921     // Remove it _before_ disposing accessible frames to avoid accesses to
922     // the Frame from event handlers.
923     if (m_pSortedObjs)
924     {
925         m_pSortedObjs->Remove(*pToRemove);
926         if (!m_pSortedObjs->size())
927         {
928             m_pSortedObjs.reset();
929         }
930     }
931 
932     // Notify accessible layout. That's required at this place for
933     // frames only where the anchor is moved. Creation of new frames
934     // is additionally handled by the SwFrameNotify class.
935     if( GetUpper() &&
936         static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
937         static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
938     {
939         static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
940                                   ->DisposeAccessibleFrame( pToRemove, true );
941     }
942 
943     // #i28701# - use new method <SetPageFrame(..)>
944     pToRemove->SetPageFrame( nullptr );
945 }
946 
947 void SwPageFrame::MoveFly( SwFlyFrame *pToMove, SwPageFrame *pDest )
948 {
949     // Invalidations
950     if ( GetUpper() )
951     {
952         static_cast<SwRootFrame*>(GetUpper())->SetIdleFlags();
953         if ( !pToMove->IsFlyInContentFrame() && pDest->GetPhyPageNum() < GetPhyPageNum() )
954             static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous();
955     }
956 
957     pDest->InvalidateSpelling();
958     pDest->InvalidateSmartTags();
959     pDest->InvalidateAutoCompleteWords();
960     pDest->InvalidateWordCount();
961 
962     if ( pToMove->IsFlyInContentFrame() )
963     {
964         pDest->InvalidateFlyInCnt();
965         return;
966     }
967 
968     // Notify accessible layout. That's required at this place for
969     // frames only where the anchor is moved. Creation of new frames
970     // is additionally handled by the SwFrameNotify class.
971     if( GetUpper() &&
972         static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
973         static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
974     {
975         static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
976                                   ->DisposeAccessibleFrame( pToMove, true );
977     }
978 
979     // The FlyColl might be gone already, because the page's dtor is being executed.
980     if ( m_pSortedObjs )
981     {
982         m_pSortedObjs->Remove( *pToMove );
983         if ( !m_pSortedObjs->size() )
984         {
985             m_pSortedObjs.reset();
986         }
987     }
988 
989     // Register
990     if ( !pDest->GetSortedObjs() )
991         pDest->m_pSortedObjs.reset(new SwSortedObjs());
992 
993     const bool bSuccessInserted = pDest->GetSortedObjs()->Insert( *pToMove );
994     OSL_ENSURE( bSuccessInserted, "Fly not inserted in Sorted." );
995 
996     // #i28701# - use new method <SetPageFrame(..)>
997     pToMove->SetPageFrame( pDest );
998     pToMove->InvalidatePage( pDest );
999     pToMove->SetNotifyBack();
1000     pDest->InvalidateFlyContent();
1001     // #i28701#
1002     pToMove->UnlockPosition();
1003 
1004     // Notify accessible layout. That's required at this place for
1005     // frames only where the anchor is moved. Creation of new frames
1006     // is additionally handled by the SwFrameNotify class.
1007     if( GetUpper() &&
1008         static_cast< SwRootFrame * >( GetUpper() )->IsAnyShellAccessible() &&
1009         static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell() )
1010     {
1011         static_cast< SwRootFrame * >( GetUpper() )->GetCurrShell()->Imp()
1012                                   ->AddAccessibleFrame( pToMove );
1013     }
1014 
1015     // #i28701# - correction: move lowers of Writer fly frame
1016     if ( pToMove->GetDrawObjs() )
1017     {
1018         SwSortedObjs &rObjs = *pToMove->GetDrawObjs();
1019         for (SwAnchoredObject* pObj : rObjs)
1020         {
1021             if ( dynamic_cast<const SwFlyFrame*>( pObj) !=  nullptr )
1022             {
1023                 SwFlyFrame* pFly = static_cast<SwFlyFrame*>(pObj);
1024                 if ( pFly->IsFlyFreeFrame() )
1025                 {
1026                     // #i28701# - use new method <GetPageFrame()>
1027                     SwPageFrame* pPageFrame = pFly->GetPageFrame();
1028                     if ( pPageFrame )
1029                         pPageFrame->MoveFly( pFly, pDest );
1030                     else
1031                         pDest->AppendFlyToPage( pFly );
1032                 }
1033             }
1034             else if ( dynamic_cast<const SwAnchoredDrawObject*>( pObj) !=  nullptr )
1035             {
1036                 RemoveDrawObjFromPage( *pObj );
1037                 pDest->AppendDrawObjToPage( *pObj );
1038             }
1039         }
1040     }
1041 }
1042 
1043 void SwPageFrame::AppendDrawObjToPage( SwAnchoredObject& _rNewObj )
1044 {
1045     if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rNewObj) ==  nullptr )
1046     {
1047         OSL_FAIL( "SwPageFrame::AppendDrawObjToPage(..) - anchored object of unexpected type -> object not appended" );
1048         return;
1049     }
1050 
1051     if ( GetUpper() )
1052     {
1053         static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth();
1054     }
1055 
1056     assert(_rNewObj.GetAnchorFrame());
1057     SwFlyFrame* pFlyFrame = const_cast<SwFlyFrame*>(_rNewObj.GetAnchorFrame()->FindFlyFrame());
1058     if ( pFlyFrame &&
1059          _rNewObj.GetDrawObj()->GetOrdNum() < pFlyFrame->GetVirtDrawObj()->GetOrdNum() )
1060     {
1061         //#i119945# set pFly's OrdNum to _rNewObj's. So when pFly is removed by Undo, the original OrdNum will not be changed.
1062         sal_uInt32 nNewNum = _rNewObj.GetDrawObj()->GetOrdNumDirect();
1063         if ( _rNewObj.GetDrawObj()->getSdrPageFromSdrObject() )
1064             _rNewObj.DrawObj()->getSdrPageFromSdrObject()->SetObjectOrdNum( pFlyFrame->GetVirtDrawObj()->GetOrdNumDirect(), nNewNum );
1065         else
1066             pFlyFrame->GetVirtDrawObj()->SetOrdNum( nNewNum );
1067     }
1068 
1069     if ( RndStdIds::FLY_AS_CHAR == _rNewObj.GetFrameFormat().GetAnchor().GetAnchorId() )
1070     {
1071         return;
1072     }
1073 
1074     if ( !m_pSortedObjs )
1075     {
1076         m_pSortedObjs.reset(new SwSortedObjs());
1077     }
1078     if ( !m_pSortedObjs->Insert( _rNewObj ) )
1079     {
1080         OSL_ENSURE( m_pSortedObjs->Contains( _rNewObj ),
1081                 "Drawing object not appended into list <pSortedObjs>." );
1082     }
1083     // #i87493#
1084     OSL_ENSURE( _rNewObj.GetPageFrame() == nullptr || _rNewObj.GetPageFrame() == this,
1085             "<SwPageFrame::AppendDrawObjToPage(..)> - anchored draw object seems to be registered at another page frame. Serious defect." );
1086     _rNewObj.SetPageFrame( this );
1087 
1088     // invalidate page in order to force a reformat of object layout of the page.
1089     InvalidateFlyLayout();
1090 }
1091 
1092 void SwPageFrame::RemoveDrawObjFromPage( SwAnchoredObject& _rToRemoveObj )
1093 {
1094     if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rToRemoveObj) ==  nullptr )
1095     {
1096         OSL_FAIL( "SwPageFrame::RemoveDrawObjFromPage(..) - anchored object of unexpected type -> object not removed" );
1097         return;
1098     }
1099 
1100     if ( m_pSortedObjs )
1101     {
1102         m_pSortedObjs->Remove( _rToRemoveObj );
1103         if ( !m_pSortedObjs->size() )
1104         {
1105             m_pSortedObjs.reset();
1106         }
1107         if ( GetUpper() )
1108         {
1109             if (RndStdIds::FLY_AS_CHAR !=
1110                     _rToRemoveObj.GetFrameFormat().GetAnchor().GetAnchorId())
1111             {
1112                 static_cast<SwRootFrame*>(GetUpper())->SetSuperfluous();
1113                 InvalidatePage();
1114             }
1115             static_cast<SwRootFrame*>(GetUpper())->InvalidateBrowseWidth();
1116         }
1117     }
1118     _rToRemoveObj.SetPageFrame( nullptr );
1119 }
1120 
1121 // #i50432# - adjust method description and synopsis.
1122 void SwPageFrame::PlaceFly( SwFlyFrame* pFly, SwFlyFrameFormat* pFormat )
1123 {
1124     // #i50432# - consider the case that page is an empty page:
1125     // In this case append the fly frame at the next page
1126     OSL_ENSURE( !IsEmptyPage() || GetNext(),
1127             "<SwPageFrame::PlaceFly(..)> - empty page with no next page! -> fly frame appended at empty page" );
1128     if ( IsEmptyPage() && GetNext() )
1129     {
1130         static_cast<SwPageFrame*>(GetNext())->PlaceFly( pFly, pFormat );
1131     }
1132     else
1133     {
1134         // If we received a Fly, we use that one. Otherwise, create a new
1135         // one using the Format.
1136         if ( pFly )
1137             AppendFly( pFly );
1138         else
1139         {
1140             OSL_ENSURE( pFormat, ":-( No Format given for Fly." );
1141             pFly = new SwFlyLayFrame( pFormat, this, this );
1142             AppendFly( pFly );
1143             ::RegistFlys( this, pFly );
1144         }
1145     }
1146 }
1147 
1148 // #i18732# - adjustments for following text flow or not
1149 // AND alignment at 'page areas' for to paragraph/to character anchored objects
1150 // #i22305# - adjustment for following text flow for to frame anchored objects
1151 // #i29778# - Because calculating the floating screen object's position
1152 // (Writer fly frame or drawing object) doesn't perform a calculation on its
1153 // upper frames and its anchor frame, a calculation of the upper frames in this
1154 // method is no longer sensible.
1155 // #i28701# - if document compatibility option 'Consider wrapping style influence
1156 // on object positioning' is ON, the clip area corresponds to the one as the
1157 // object doesn't follow the text flow.
1158 bool CalcClipRect( const SdrObject *pSdrObj, SwRect &rRect, bool bMove )
1159 {
1160     bool bRet = true;
1161     if ( auto pVirtFlyDrawObj = dynamic_cast<const SwVirtFlyDrawObj*>(pSdrObj) )
1162     {
1163         const SwFlyFrame* pFly = pVirtFlyDrawObj->GetFlyFrame();
1164         const bool bFollowTextFlow = pFly->GetFormat()->GetFollowTextFlow().GetValue();
1165         // #i28701#
1166         const bool bConsiderWrapOnObjPos =
1167                                 pFly->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION);
1168         const SwFormatVertOrient &rV = pFly->GetFormat()->GetVertOrient();
1169         if( pFly->IsFlyLayFrame() )
1170         {
1171             const SwFrame* pClip;
1172             // #i22305#
1173             // #i28701#
1174             if ( !bFollowTextFlow || bConsiderWrapOnObjPos )
1175             {
1176                 pClip = pFly->GetAnchorFrame()->FindPageFrame();
1177             }
1178             else
1179             {
1180                 pClip = pFly->GetAnchorFrame();
1181             }
1182 
1183             rRect = pClip->getFrameArea();
1184             SwRectFnSet aRectFnSet(pClip);
1185 
1186             // vertical clipping: Top and Bottom, also to PrtArea if necessary
1187             if( rV.GetVertOrient() != text::VertOrientation::NONE &&
1188                 rV.GetRelationOrient() == text::RelOrientation::PRINT_AREA )
1189             {
1190                 aRectFnSet.SetTop( rRect, aRectFnSet.GetPrtTop(*pClip) );
1191                 aRectFnSet.SetBottom( rRect, aRectFnSet.GetPrtBottom(*pClip) );
1192             }
1193             // horizontal clipping: Top and Bottom, also to PrtArea if necessary
1194             const SwFormatHoriOrient &rH = pFly->GetFormat()->GetHoriOrient();
1195             if( rH.GetHoriOrient() != text::HoriOrientation::NONE &&
1196                 rH.GetRelationOrient() == text::RelOrientation::PRINT_AREA )
1197             {
1198                 aRectFnSet.SetLeft( rRect, aRectFnSet.GetPrtLeft(*pClip) );
1199                 aRectFnSet.SetRight(rRect, aRectFnSet.GetPrtRight(*pClip));
1200             }
1201         }
1202         else if( pFly->IsFlyAtContentFrame() )
1203         {
1204             // #i18732# - consider following text flow or not
1205             // AND alignment at 'page areas'
1206             const SwFrame* pVertPosOrientFrame = pFly->GetVertPosOrientFrame();
1207             if ( !pVertPosOrientFrame )
1208             {
1209                 OSL_FAIL( "::CalcClipRect(..) - frame, vertical position is oriented at, is missing .");
1210                 pVertPosOrientFrame = pFly->GetAnchorFrame();
1211             }
1212 
1213             if ( !bFollowTextFlow || bConsiderWrapOnObjPos )
1214             {
1215                 const SwLayoutFrame* pClipFrame = pVertPosOrientFrame->FindPageFrame();
1216                 if (!pClipFrame)
1217                 {
1218                     OSL_FAIL("!pClipFrame: "
1219                             "if you can reproduce this please file a bug");
1220                     return false;
1221                 }
1222                 rRect = bMove ? pClipFrame->GetUpper()->getFrameArea()
1223                               : pClipFrame->getFrameArea();
1224                 // #i26945# - consider that a table, during
1225                 // its format, can exceed its upper printing area bottom.
1226                 // Thus, enlarge the clip rectangle, if such a case occurred
1227                 if ( pFly->GetAnchorFrame()->IsInTab() )
1228                 {
1229                     const SwTabFrame* pTabFrame = const_cast<SwFlyFrame*>(pFly)
1230                                 ->GetAnchorFrameContainingAnchPos()->FindTabFrame();
1231                     SwRect aTmp( pTabFrame->getFramePrintArea() );
1232                     aTmp += pTabFrame->getFrameArea().Pos();
1233                     rRect.Union( aTmp );
1234                     // #i43913# - consider also the cell frame
1235                     const SwFrame* pCellFrame = const_cast<SwFlyFrame*>(pFly)
1236                                 ->GetAnchorFrameContainingAnchPos()->GetUpper();
1237                     while ( pCellFrame && !pCellFrame->IsCellFrame() )
1238                     {
1239                         pCellFrame = pCellFrame->GetUpper();
1240                     }
1241                     if ( pCellFrame )
1242                     {
1243                         aTmp = pCellFrame->getFramePrintArea();
1244                         aTmp += pCellFrame->getFrameArea().Pos();
1245                         rRect.Union( aTmp );
1246                     }
1247                 }
1248             }
1249             else if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_FRAME ||
1250                       rV.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA )
1251             {
1252                 // new class <SwEnvironmentOfAnchoredObject>
1253                 objectpositioning::SwEnvironmentOfAnchoredObject
1254                                                 aEnvOfObj( bFollowTextFlow );
1255                 const SwLayoutFrame& rVertClipFrame =
1256                     aEnvOfObj.GetVertEnvironmentLayoutFrame( *pVertPosOrientFrame );
1257                 if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_FRAME )
1258                 {
1259                     rRect = rVertClipFrame.getFrameArea();
1260                 }
1261                 else if ( rV.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA )
1262                 {
1263                     if ( rVertClipFrame.IsPageFrame() )
1264                     {
1265                         rRect = static_cast<const SwPageFrame&>(rVertClipFrame).PrtWithoutHeaderAndFooter();
1266                     }
1267                     else
1268                     {
1269                         rRect = rVertClipFrame.getFrameArea();
1270                     }
1271                 }
1272                 const SwLayoutFrame* pHoriClipFrame =
1273                         pFly->GetAnchorFrame()->FindPageFrame()->GetUpper();
1274                 SwRectFnSet aRectFnSet(pFly->GetAnchorFrame());
1275                 aRectFnSet.SetLeft( rRect, aRectFnSet.GetLeft(pHoriClipFrame->getFrameArea()) );
1276                 aRectFnSet.SetRight(rRect, aRectFnSet.GetRight(pHoriClipFrame->getFrameArea()));
1277             }
1278             else
1279             {
1280                 // #i26945#
1281                 const SwFrame *pClip =
1282                         const_cast<SwFlyFrame*>(pFly)->GetAnchorFrameContainingAnchPos();
1283                 SwRectFnSet aRectFnSet(pClip);
1284                 const SwLayoutFrame *pUp = pClip->GetUpper();
1285                 const SwFrame *pCell = pUp->IsCellFrame() ? pUp : nullptr;
1286                 const SwFrameType nType = bMove
1287                                      ? SwFrameType::Root   | SwFrameType::Fly | SwFrameType::Header |
1288                                        SwFrameType::Footer | SwFrameType::Ftn
1289                                      : SwFrameType::Body   | SwFrameType::Fly | SwFrameType::Header |
1290                                        SwFrameType::Footer | SwFrameType::Cell| SwFrameType::Ftn;
1291 
1292                 while ( !(pUp->GetType() & nType) || pUp->IsColBodyFrame() )
1293                 {
1294                     pUp = pUp->GetUpper();
1295                     if ( !pCell && pUp->IsCellFrame() )
1296                         pCell = pUp;
1297                 }
1298                 if ( bMove && pUp->IsRootFrame() )
1299                 {
1300                     rRect  = pUp->getFramePrintArea();
1301                     rRect += pUp->getFrameArea().Pos();
1302                     pUp = nullptr;
1303                 }
1304                 if ( pUp )
1305                 {
1306                     if ( pUp->GetType() & SwFrameType::Body )
1307                     {
1308                         const SwPageFrame *pPg;
1309                         if ( pUp->GetUpper() != (pPg = pFly->FindPageFrame()) )
1310                             pUp = pPg->FindBodyCont();
1311                         if (pUp)
1312                         {
1313                             rRect = pUp->GetUpper()->getFrameArea();
1314                             aRectFnSet.SetTop( rRect, aRectFnSet.GetPrtTop(*pUp) );
1315                             aRectFnSet.SetBottom(rRect, aRectFnSet.GetPrtBottom(*pUp));
1316                         }
1317                     }
1318                     else
1319                     {
1320                         if( ( pUp->GetType() & (SwFrameType::Fly | SwFrameType::Ftn ) ) &&
1321                             !pUp->getFrameArea().IsInside( pFly->getFrameArea().Pos() ) )
1322                         {
1323                             if( pUp->IsFlyFrame() )
1324                             {
1325                                 const SwFlyFrame *pTmpFly = static_cast<const SwFlyFrame*>(pUp);
1326                                 while( pTmpFly->GetNextLink() )
1327                                 {
1328                                     pTmpFly = pTmpFly->GetNextLink();
1329                                     if( pTmpFly->getFrameArea().IsInside( pFly->getFrameArea().Pos() ) )
1330                                         break;
1331                                 }
1332                                 pUp = pTmpFly;
1333                             }
1334                             else if( pUp->IsInFootnote() )
1335                             {
1336                                 const SwFootnoteFrame *pTmp = pUp->FindFootnoteFrame();
1337                                 while( pTmp->GetFollow() )
1338                                 {
1339                                     pTmp = pTmp->GetFollow();
1340                                     if( pTmp->getFrameArea().IsInside( pFly->getFrameArea().Pos() ) )
1341                                         break;
1342                                 }
1343                                 pUp = pTmp;
1344                             }
1345                         }
1346                         rRect = pUp->getFramePrintArea();
1347                         rRect.Pos() += pUp->getFrameArea().Pos();
1348                         if ( pUp->GetType() & (SwFrameType::Header | SwFrameType::Footer) )
1349                         {
1350                             rRect.Left ( pUp->GetUpper()->getFrameArea().Left() );
1351                             rRect.Width( pUp->GetUpper()->getFrameArea().Width());
1352                         }
1353                         else if ( pUp->IsCellFrame() )                //MA_FLY_HEIGHT
1354                         {
1355                             const SwFrame *pTab = pUp->FindTabFrame();
1356                             aRectFnSet.SetBottom( rRect, aRectFnSet.GetPrtBottom(*pTab->GetUpper()) );
1357                             // expand to left and right cell border
1358                             rRect.Left ( pUp->getFrameArea().Left() );
1359                             rRect.Width( pUp->getFrameArea().Width() );
1360                         }
1361                     }
1362                 }
1363                 if ( pCell )
1364                 {
1365                     // CellFrames might also sit in unallowed areas. In this case,
1366                     // the Fly is allowed to do so as well
1367                     SwRect aTmp( pCell->getFramePrintArea() );
1368                     aTmp += pCell->getFrameArea().Pos();
1369                     rRect.Union( aTmp );
1370                 }
1371             }
1372         }
1373         else
1374         {
1375             const SwFrame *pUp = pFly->GetAnchorFrame()->GetUpper();
1376             SwRectFnSet aRectFnSet(pFly->GetAnchorFrame());
1377             while( pUp->IsColumnFrame() || pUp->IsSctFrame() || pUp->IsColBodyFrame())
1378                 pUp = pUp->GetUpper();
1379             rRect = pUp->getFrameArea();
1380             if( !pUp->IsBodyFrame() )
1381             {
1382                 rRect += pUp->getFramePrintArea().Pos();
1383                 rRect.SSize( pUp->getFramePrintArea().SSize() );
1384                 if ( pUp->IsCellFrame() )
1385                 {
1386                     const SwFrame *pTab = pUp->FindTabFrame();
1387                     aRectFnSet.SetBottom( rRect, aRectFnSet.GetPrtBottom(*pTab->GetUpper()) );
1388                 }
1389             }
1390             else if ( pUp->GetUpper()->IsPageFrame() )
1391             {
1392                 // Objects anchored as character may exceed right margin
1393                 // of body frame:
1394                 aRectFnSet.SetRight( rRect, aRectFnSet.GetRight(pUp->GetUpper()->getFrameArea()) );
1395             }
1396             long nHeight = (9*aRectFnSet.GetHeight(rRect))/10;
1397             long nTop;
1398             const SwFormat *pFormat = GetUserCall(pSdrObj)->GetFormat();
1399             const SvxULSpaceItem &rUL = pFormat->GetULSpace();
1400             if( bMove )
1401             {
1402                 nTop = aRectFnSet.IsVert() ? static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().X() :
1403                                static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().Y();
1404                 nTop = aRectFnSet.YInc( nTop, -nHeight );
1405                 long nWidth = aRectFnSet.GetWidth(pFly->getFrameArea());
1406                 aRectFnSet.SetLeftAndWidth( rRect, aRectFnSet.IsVert() ?
1407                             static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().Y() :
1408                             static_cast<const SwFlyInContentFrame*>(pFly)->GetRefPoint().X(), nWidth );
1409                 nHeight = 2*nHeight - rUL.GetLower() - rUL.GetUpper();
1410             }
1411             else
1412             {
1413                 nTop = aRectFnSet.YInc( aRectFnSet.GetBottom(pFly->getFrameArea()),
1414                                            rUL.GetLower() - nHeight );
1415                 nHeight = 2*nHeight - aRectFnSet.GetHeight(pFly->getFrameArea())
1416                           - rUL.GetLower() - rUL.GetUpper();
1417             }
1418             aRectFnSet.SetTopAndHeight( rRect, nTop, nHeight );
1419         }
1420     }
1421     else
1422     {
1423         const SwDrawContact *pC = static_cast<const SwDrawContact*>(GetUserCall(pSdrObj));
1424         const SwFrameFormat  *pFormat = pC->GetFormat();
1425         const SwFormatAnchor &rAnch = pFormat->GetAnchor();
1426         if ( RndStdIds::FLY_AS_CHAR == rAnch.GetAnchorId() )
1427         {
1428             const SwFrame* pAnchorFrame = pC->GetAnchorFrame( pSdrObj );
1429             if( !pAnchorFrame )
1430             {
1431                 OSL_FAIL( "<::CalcClipRect(..)> - missing anchor frame." );
1432                 const_cast<SwDrawContact*>(pC)->ConnectToLayout();
1433                 pAnchorFrame = pC->GetAnchorFrame();
1434             }
1435             const SwFrame* pUp = pAnchorFrame->GetUpper();
1436             rRect = pUp->getFramePrintArea();
1437             rRect += pUp->getFrameArea().Pos();
1438             SwRectFnSet aRectFnSet(pAnchorFrame);
1439             long nHeight = (9*aRectFnSet.GetHeight(rRect))/10;
1440             long nTop;
1441             const SvxULSpaceItem &rUL = pFormat->GetULSpace();
1442             SwRect aSnapRect( pSdrObj->GetSnapRect() );
1443             long nTmpH = 0;
1444             if( bMove )
1445             {
1446                 nTop = aRectFnSet.YInc( aRectFnSet.IsVert() ? pSdrObj->GetAnchorPos().X() :
1447                                        pSdrObj->GetAnchorPos().Y(), -nHeight );
1448                 long nWidth = aRectFnSet.GetWidth(aSnapRect);
1449                 aRectFnSet.SetLeftAndWidth( rRect, aRectFnSet.IsVert() ?
1450                             pSdrObj->GetAnchorPos().Y() :
1451                             pSdrObj->GetAnchorPos().X(), nWidth );
1452             }
1453             else
1454             {
1455                 // #i26791# - value of <nTmpH> is needed to
1456                 // calculate value of <nTop>.
1457                 nTmpH = aRectFnSet.IsVert() ? pSdrObj->GetCurrentBoundRect().GetWidth() :
1458                                        pSdrObj->GetCurrentBoundRect().GetHeight();
1459                 nTop = aRectFnSet.YInc( aRectFnSet.GetTop(aSnapRect),
1460                                           rUL.GetLower() + nTmpH - nHeight );
1461             }
1462             nHeight = 2*nHeight - nTmpH - rUL.GetLower() - rUL.GetUpper();
1463             aRectFnSet.SetTopAndHeight( rRect, nTop, nHeight );
1464         }
1465         else
1466         {
1467             // restrict clip rectangle for drawing
1468             // objects in header/footer to the page frame.
1469             // #i26791#
1470             const SwFrame* pAnchorFrame = pC->GetAnchorFrame( pSdrObj );
1471             if ( pAnchorFrame && pAnchorFrame->FindFooterOrHeader() )
1472             {
1473                 // clip frame is the page frame the header/footer is on.
1474                 const SwFrame* pClipFrame = pAnchorFrame->FindPageFrame();
1475                 rRect = pClipFrame->getFrameArea();
1476             }
1477             else
1478             {
1479                 bRet = false;
1480             }
1481         }
1482     }
1483     return bRet;
1484 }
1485 
1486 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
1487