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