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 <svl/itemiter.hxx>
21 #include <vcl/imap.hxx>
22 #include <tools/helpers.hxx>
23 #include <editeng/protitem.hxx>
24 #include <editeng/opaqitem.hxx>
25 #include <editeng/ulspitem.hxx>
26 #include <editeng/frmdiritem.hxx>
27 #include <editeng/outlobj.hxx>
28 #include <fmtfsize.hxx>
29 #include <fmtclds.hxx>
30 #include <fmtcntnt.hxx>
31 #include <fmturl.hxx>
32 #include <fmtsrnd.hxx>
33 #include <fmtornt.hxx>
34 #include <fmtcnct.hxx>
35 #include <ndgrf.hxx>
36 #include <tolayoutanchoredobjectposition.hxx>
37 #include <fmtfollowtextflow.hxx>
38 #include <sortedobjs.hxx>
39 #include <objectformatter.hxx>
40 #include <ndole.hxx>
41 #include <swtable.hxx>
42 #include <svx/svdoashp.hxx>
43 #include <layouter.hxx>
44 #include <pagefrm.hxx>
45 #include <rootfrm.hxx>
46 #include <viewimp.hxx>
47 #include <viewopt.hxx>
48 #include <dcontact.hxx>
49 #include <dflyobj.hxx>
50 #include <dview.hxx>
51 #include <frmatr.hxx>
52 #include <frmtool.hxx>
53 #include <hints.hxx>
54 #include <tabfrm.hxx>
55 #include <txtfrm.hxx>
56 #include <notxtfrm.hxx>
57 #include <flyfrms.hxx>
58 #include <sectfrm.hxx>
59 #include <vcl/svapp.hxx>
60 #include <calbck.hxx>
61 #include <IDocumentDrawModelAccess.hxx>
62 #include <IDocumentSettingAccess.hxx>
63 #include <IDocumentLayoutAccess.hxx>
64 #include <textboxhelper.hxx>
65 #include <txtfly.hxx>
66 #include <ndindex.hxx>
67 #include <basegfx/matrix/b2dhommatrixtools.hxx>
68 #include <osl/diagnose.h>
69 
70 #include <wrtsh.hxx>
71 #include <view.hxx>
72 #include <edtwin.hxx>
73 #include <bodyfrm.hxx>
74 #include <FrameControlsManager.hxx>
75 #include <ndtxt.hxx>
76 
77 using namespace ::com::sun::star;
78 
79 static SwTwips lcl_CalcAutoWidth( const SwLayoutFrame& rFrame );
80 
SwFlyFrame(SwFlyFrameFormat * pFormat,SwFrame * pSib,SwFrame * pAnch)81 SwFlyFrame::SwFlyFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch ) :
82     SwLayoutFrame( pFormat, pSib ),
83     SwAnchoredObject(), // #i26791#
84     m_pPrevLink( nullptr ),
85     m_pNextLink( nullptr ),
86     m_bInCnt( false ),
87     m_bAtCnt( false ),
88     m_bLayout( false ),
89     m_bAutoPosition( false ),
90     m_bDeleted( false ),
91     m_nAuthor( std::string::npos ),
92     m_bValidContentPos( false )
93 {
94     mnFrameType = SwFrameType::Fly;
95 
96     m_bInvalid = m_bNotifyBack = true;
97     m_bLocked  = m_bMinHeight =
98     m_bHeightClipped = m_bWidthClipped = m_bFormatHeightOnly = false;
99 
100     // Size setting: Fixed size is always the width
101     const SwFormatFrameSize &rFrameSize = pFormat->GetFrameSize();
102     const SvxFrameDirection nDir = pFormat->GetFormatAttr( RES_FRAMEDIR ).GetValue();
103     if( SvxFrameDirection::Environment == nDir )
104     {
105         mbDerivedVert = true;
106         mbDerivedR2L = true;
107     }
108     else
109     {
110         mbInvalidVert = false;
111         mbDerivedVert = false;
112         mbDerivedR2L = false;
113         if( SvxFrameDirection::Horizontal_LR_TB == nDir || SvxFrameDirection::Horizontal_RL_TB == nDir )
114         {
115             mbVertLR = false;
116             mbVertical = false;
117         }
118         else
119         {
120             const SwViewShell *pSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
121             if( pSh && pSh->GetViewOptions()->getBrowseMode() )
122             {
123                 mbVertLR = false;
124                 mbVertical = false;
125             }
126             else
127             {
128                 mbVertical = true;
129 
130                 if ( SvxFrameDirection::Vertical_LR_TB == nDir )
131                     mbVertLR = true;
132                 else if (nDir == SvxFrameDirection::Vertical_LR_BT)
133                 {
134                     mbVertLR = true;
135                     mbVertLRBT = true;
136                 }
137                 else
138                     mbVertLR = false;
139             }
140         }
141 
142         mbInvalidR2L = false;
143         if( SvxFrameDirection::Horizontal_RL_TB == nDir )
144             mbRightToLeft = true;
145         else
146             mbRightToLeft = false;
147     }
148 
149     {
150         SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
151         aFrm.Width( rFrameSize.GetWidth() );
152         aFrm.Height( rFrameSize.GetHeightSizeType() == SwFrameSize::Variable ? MINFLY : rFrameSize.GetHeight() );
153     }
154 
155     // Fixed or variable Height?
156     if ( rFrameSize.GetHeightSizeType() == SwFrameSize::Minimum )
157         m_bMinHeight = true;
158     else if ( rFrameSize.GetHeightSizeType() == SwFrameSize::Fixed )
159         mbFixSize = true;
160 
161     // insert columns, if necessary
162     InsertColumns();
163 
164     // First the Init, then the Content:
165     // This is due to the fact that the Content may have Objects/Frames,
166     // which are then registered
167     InitDrawObj(*pAnch);
168 
169     Chain( pAnch );
170 
171     InsertCnt();
172 
173     // Put it somewhere outside so that out document is not formatted unnecessarily often
174     SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
175     aFrm.Pos().setX(FAR_AWAY);
176     aFrm.Pos().setY(FAR_AWAY);
177 }
178 
Chain(SwFrame * _pAnch)179 void SwFlyFrame::Chain( SwFrame* _pAnch )
180 {
181     // Connect to chain neighbours.
182     // No problem, if a neighbor doesn't exist - the construction of the
183     // neighbor will make the connection
184     const SwFormatChain& rChain = GetFormat()->GetChain();
185     if ( !(rChain.GetPrev() || rChain.GetNext()) )
186         return;
187 
188     if ( rChain.GetNext() )
189     {
190         SwFlyFrame* pFollow = FindChainNeighbour( *rChain.GetNext(), _pAnch );
191         if ( pFollow )
192         {
193             OSL_ENSURE( !pFollow->GetPrevLink(), "wrong chain detected" );
194             if ( !pFollow->GetPrevLink() )
195                 SwFlyFrame::ChainFrames( this, pFollow );
196         }
197     }
198     if ( rChain.GetPrev() )
199     {
200         SwFlyFrame *pMaster = FindChainNeighbour( *rChain.GetPrev(), _pAnch );
201         if ( pMaster )
202         {
203             OSL_ENSURE( !pMaster->GetNextLink(), "wrong chain detected" );
204             if ( !pMaster->GetNextLink() )
205                 SwFlyFrame::ChainFrames( pMaster, this );
206         }
207     }
208 }
209 
InsertCnt()210 void SwFlyFrame::InsertCnt()
211 {
212     if ( GetPrevLink() )
213         return;
214 
215     const SwFormatContent& rContent = GetFormat()->GetContent();
216     OSL_ENSURE( rContent.GetContentIdx(), ":-( no content prepared." );
217     sal_uLong nIndex = rContent.GetContentIdx()->GetIndex();
218     // Lower() means SwColumnFrame; the Content then needs to be inserted into the (Column)BodyFrame
219     ::InsertCnt_( Lower() ? static_cast<SwLayoutFrame*>(static_cast<SwLayoutFrame*>(Lower())->Lower()) : static_cast<SwLayoutFrame*>(this),
220                   GetFormat()->GetDoc(), nIndex );
221 
222     // NoText always have a fixed height.
223     if ( Lower() && Lower()->IsNoTextFrame() )
224     {
225         mbFixSize = true;
226         m_bMinHeight = false;
227     }
228 }
229 
InsertColumns()230 void SwFlyFrame::InsertColumns()
231 {
232     // #i97379#
233     // Check, if column are allowed.
234     // Columns are not allowed for fly frames, which represent graphics or embedded objects.
235     const SwFormatContent& rContent = GetFormat()->GetContent();
236     OSL_ENSURE( rContent.GetContentIdx(), "<SwFlyFrame::InsertColumns()> - no content prepared." );
237     SwNodeIndex aFirstContent( *(rContent.GetContentIdx()), 1 );
238     if ( aFirstContent.GetNode().IsNoTextNode() )
239     {
240         return;
241     }
242 
243     const SwFormatCol &rCol = GetFormat()->GetCol();
244     if ( rCol.GetNumCols() <= 1 )
245         return;
246 
247     // Start off PrtArea to be as large as Frame, so that we can put in the columns
248     // properly. It'll adjust later on.
249     {
250         SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
251         aPrt.Width( getFrameArea().Width() );
252         aPrt.Height( getFrameArea().Height() );
253     }
254 
255     const SwFormatCol aOld; // ChgColumns() also needs an old value passed
256     ChgColumns( aOld, rCol );
257 }
258 
DestroyImpl()259 void SwFlyFrame::DestroyImpl()
260 {
261     // Accessible objects for fly frames will be destroyed in this destructor.
262     // For frames bound as char or frames that don't have an anchor we have
263     // to do that ourselves. For any other frame the call RemoveFly at the
264     // anchor will do that.
265     if( IsAccessibleFrame() && GetFormat() && (IsFlyInContentFrame() || !GetAnchorFrame()) )
266     {
267         SwRootFrame *pRootFrame = getRootFrame();
268         if( pRootFrame && pRootFrame->IsAnyShellAccessible() )
269         {
270             SwViewShell *pVSh = pRootFrame->GetCurrShell();
271             if( pVSh && pVSh->Imp() )
272             {
273                 // Lowers aren't disposed already, so we have to do a recursive
274                 // dispose
275                 pVSh->Imp()->DisposeAccessibleFrame( this, true );
276             }
277         }
278     }
279 
280     if( GetFormat() && !GetFormat()->GetDoc()->IsInDtor() )
281     {
282         ClearTmpConsiderWrapInfluence(); // remove this from SwLayouter
283 
284         Unchain();
285 
286         DeleteCnt();
287 
288         if ( GetAnchorFrame() )
289             AnchorFrame()->RemoveFly( this );
290     }
291 
292     FinitDrawObj();
293 
294     SwLayoutFrame::DestroyImpl();
295 
296     SwWrtShell* pWrtSh = dynamic_cast<SwWrtShell*>(getRootFrame()->GetCurrShell());
297     UpdateUnfloatButton(pWrtSh, false);
298 }
299 
~SwFlyFrame()300 SwFlyFrame::~SwFlyFrame()
301 {
302 }
303 
getIDocumentDrawModelAccess()304 const IDocumentDrawModelAccess& SwFlyFrame::getIDocumentDrawModelAccess()
305 {
306     return GetFormat()->getIDocumentDrawModelAccess();
307 }
308 
Unchain()309 void SwFlyFrame::Unchain()
310 {
311     if ( GetPrevLink() )
312         UnchainFrames( GetPrevLink(), this );
313     if ( GetNextLink() )
314         UnchainFrames( this, GetNextLink() );
315 }
316 
DeleteCnt()317 void SwFlyFrame::DeleteCnt()
318 {
319     SwFrame* pFrame = m_pLower;
320     while ( pFrame )
321     {
322         while ( pFrame->GetDrawObjs() && pFrame->GetDrawObjs()->size() )
323         {
324             SwAnchoredObject *pAnchoredObj = (*pFrame->GetDrawObjs())[0];
325             if ( auto pFlyFrame = dynamic_cast<SwFlyFrame*>( pAnchoredObj) )
326             {
327                 SwFrame::DestroyFrame(pFlyFrame);
328             }
329             else if ( dynamic_cast<const SwAnchoredDrawObject*>( pAnchoredObj) !=  nullptr )
330             {
331                 // consider 'virtual' drawing objects
332                 SdrObject* pObj = pAnchoredObj->DrawObj();
333                 if ( auto pDrawVirtObj = dynamic_cast<SwDrawVirtObj*>( pObj) )
334                 {
335                     pDrawVirtObj->RemoveFromWriterLayout();
336                     pDrawVirtObj->RemoveFromDrawingPage();
337                 }
338                 else
339                 {
340                     SwDrawContact* pContact =
341                             static_cast<SwDrawContact*>(::GetUserCall( pObj ));
342                     if ( pContact )
343                     {
344                         pContact->DisconnectFromLayout();
345                     }
346                 }
347             }
348         }
349 
350         pFrame->RemoveFromLayout();
351         SwFrame::DestroyFrame(pFrame);
352         pFrame = m_pLower;
353     }
354 
355     InvalidatePage();
356 }
357 
InitDrawObj(SwFrame const & rAnchorFrame)358 void SwFlyFrame::InitDrawObj(SwFrame const& rAnchorFrame)
359 {
360     SetDrawObj(*SwFlyDrawContact::CreateNewRef(this, GetFormat(), rAnchorFrame));
361 
362     // Set the right Layer
363     IDocumentDrawModelAccess& rIDDMA = GetFormat()->getIDocumentDrawModelAccess();
364     SdrLayerID nHeavenId = rIDDMA.GetHeavenId();
365     SdrLayerID nHellId = rIDDMA.GetHellId();
366     GetVirtDrawObj()->SetLayer( GetFormat()->GetOpaque().GetValue()
367                                 ? nHeavenId
368                                 : nHellId );
369 }
370 
ResolveFlyAnchor(SwFrameFormat const & rFlyFrame)371 static SwPosition ResolveFlyAnchor(SwFrameFormat const& rFlyFrame)
372 {
373     SwFormatAnchor const& rAnch(rFlyFrame.GetAnchor());
374     if (rAnch.GetAnchorId() == RndStdIds::FLY_AT_PAGE)
375     {   // arbitrarily pick last node
376         return SwPosition(SwNodeIndex(rFlyFrame.GetDoc()->GetNodes().GetEndOfContent(), -1));
377     }
378     else
379     {
380         SwPosition const*const pPos(rAnch.GetContentAnchor());
381         assert(pPos);
382         if (SwFrameFormat const*const pParent = pPos->nNode.GetNode().GetFlyFormat())
383         {
384             return ResolveFlyAnchor(*pParent);
385         }
386         else if (pPos->nContent.GetIdxReg())
387         {
388             return *pPos;
389         }
390         else
391         {
392             return SwPosition(*pPos->nNode.GetNode().GetContentNode(), 0);
393         }
394     }
395 }
396 
FinitDrawObj()397 void SwFlyFrame::FinitDrawObj()
398 {
399     if(!GetVirtDrawObj() )
400         return;
401     SwFormat* pFormat = GetFormat();
402     // Deregister from SdrPageViews if the Objects is still selected there.
403     if(!pFormat->GetDoc()->IsInDtor())
404     {
405         SwViewShell* p1St = getRootFrame()->GetCurrShell();
406         if(p1St)
407         {
408             for(SwViewShell& rCurrentShell : p1St->GetRingContainer())
409             {   // At the moment the Drawing can do just do an Unmark on everything,
410                 // as the Object was already removed
411                 if (rCurrentShell.HasDrawView() &&
412                     rCurrentShell.Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount())
413                 {
414                     SwFlyFrame const*const pOldSelFly = ::GetFlyFromMarked(nullptr, &rCurrentShell);
415                     if (pOldSelFly == this)
416                     {
417                         assert(rCurrentShell.Imp()->GetDrawView()->GetMarkedObjectList().GetMarkCount() == 1);
418                         if (SwFEShell *const pFEShell = dynamic_cast<SwFEShell*>(&rCurrentShell))
419                         {   // tdf#131679 move any cursor out of fly
420                             rCurrentShell.Imp()->GetDrawView()->UnmarkAll();
421                             if (pOldSelFly)
422                             {
423                                 SwPosition const pos(ResolveFlyAnchor(*pOldSelFly->GetFormat()));
424                                 SwPaM const temp(pos);
425                                 pFEShell->SetSelection(temp);
426                                 // could also call SetCursor() like SwFEShell::SelectObj()
427                                 // does, but that would access layout a bit much...
428                             }
429                         }
430                         else
431                         {
432                             rCurrentShell.Imp()->GetDrawView()->UnmarkAll();
433                         }
434                     }
435                 }
436             }
437         }
438     }
439 
440     // Else calls delete of the ContactObj
441     GetVirtDrawObj()->SetUserCall(nullptr);
442 
443     // Deregisters itself at the Master
444     // always use SdrObject::Free(...) for SdrObjects (!)
445     SdrObject* pTemp(GetVirtDrawObj());
446     SdrObject::Free(pTemp);
447 }
448 
ChainFrames(SwFlyFrame * pMaster,SwFlyFrame * pFollow)449 void SwFlyFrame::ChainFrames( SwFlyFrame *pMaster, SwFlyFrame *pFollow )
450 {
451     OSL_ENSURE( pMaster && pFollow, "incomplete chain" );
452     OSL_ENSURE( !pMaster->GetNextLink(), "link can not be changed" );
453     OSL_ENSURE( !pFollow->GetPrevLink(), "link can not be changed" );
454 
455     pMaster->m_pNextLink = pFollow;
456     pFollow->m_pPrevLink = pMaster;
457 
458     if ( pMaster->ContainsContent() )
459     {
460         // To get a text flow we need to invalidate
461         SwFrame *pInva = pMaster->FindLastLower();
462         SwRectFnSet aRectFnSet(pMaster);
463         const tools::Long nBottom = aRectFnSet.GetPrtBottom(*pMaster);
464         while ( pInva )
465         {
466             if( aRectFnSet.BottomDist( pInva->getFrameArea(), nBottom ) <= 0 )
467             {
468                 pInva->InvalidateSize();
469                 pInva->Prepare();
470                 pInva = pInva->FindPrev();
471             }
472             else
473                 pInva = nullptr;
474         }
475     }
476 
477     if ( pFollow->ContainsContent() )
478     {
479         // There's only the content from the Masters left; the content from the Follow
480         // does not have any Frames left (should always be exactly one empty TextNode).
481         SwFrame *pFrame = pFollow->ContainsContent();
482         OSL_ENSURE( !pFrame->IsTabFrame() && !pFrame->FindNext(), "follow in chain contains content" );
483         pFrame->Cut();
484         SwFrame::DestroyFrame(pFrame);
485     }
486 
487     // invalidate accessible relation set (accessibility wrapper)
488     SwViewShell* pSh = pMaster->getRootFrame()->GetCurrShell();
489     if( pSh )
490     {
491         SwRootFrame* pLayout = pMaster->getRootFrame();
492         if( pLayout && pLayout->IsAnyShellAccessible() )
493             pSh->Imp()->InvalidateAccessibleRelationSet( pMaster, pFollow );
494     }
495 }
496 
UnchainFrames(SwFlyFrame * pMaster,SwFlyFrame * pFollow)497 void SwFlyFrame::UnchainFrames( SwFlyFrame *pMaster, SwFlyFrame *pFollow )
498 {
499     pMaster->m_pNextLink = nullptr;
500     pFollow->m_pPrevLink = nullptr;
501 
502     if ( pFollow->ContainsContent() )
503     {
504         // The Master sucks up the content of the Follow
505         SwLayoutFrame *pUpper = pMaster;
506         if ( pUpper->Lower()->IsColumnFrame() )
507         {
508             pUpper = static_cast<SwLayoutFrame*>(pUpper->GetLastLower());
509             pUpper = static_cast<SwLayoutFrame*>(pUpper->Lower()); // The (Column)BodyFrame
510             OSL_ENSURE( pUpper && pUpper->IsColBodyFrame(), "Missing ColumnBody" );
511         }
512         SwFlyFrame *pFoll = pFollow;
513         while ( pFoll )
514         {
515             SwFrame *pTmp = ::SaveContent( pFoll );
516             if ( pTmp )
517                 ::RestoreContent( pTmp, pUpper, pMaster->FindLastLower() );
518             pFoll->SetCompletePaint();
519             pFoll->InvalidateSize();
520             pFoll = pFoll->GetNextLink();
521         }
522     }
523 
524     // The Follow needs his own content to be served
525     const SwFormatContent &rContent = pFollow->GetFormat()->GetContent();
526     OSL_ENSURE( rContent.GetContentIdx(), ":-( No content prepared." );
527     sal_uLong nIndex = rContent.GetContentIdx()->GetIndex();
528     // Lower() means SwColumnFrame: this one contains another SwBodyFrame
529     ::InsertCnt_( pFollow->Lower() ? const_cast<SwLayoutFrame*>(static_cast<const SwLayoutFrame*>(static_cast<const SwLayoutFrame*>(pFollow->Lower())->Lower()))
530                                    : static_cast<SwLayoutFrame*>(pFollow),
531                   pFollow->GetFormat()->GetDoc(), ++nIndex );
532 
533     // invalidate accessible relation set (accessibility wrapper)
534     SwViewShell* pSh = pMaster->getRootFrame()->GetCurrShell();
535     if( pSh )
536     {
537         SwRootFrame* pLayout = pMaster->getRootFrame();
538         if( pLayout && pLayout->IsAnyShellAccessible() )
539             pSh->Imp()->InvalidateAccessibleRelationSet( pMaster, pFollow );
540     }
541 }
542 
FindChainNeighbour(SwFrameFormat const & rChain,SwFrame * pAnch)543 SwFlyFrame *SwFlyFrame::FindChainNeighbour( SwFrameFormat const &rChain, SwFrame *pAnch )
544 {
545     // We look for the Fly that's in the same Area.
546     // Areas can for now only be Head/Footer or Flys.
547 
548     if ( !pAnch ) // If an Anchor was passed along, that one counts (ctor!)
549         pAnch = AnchorFrame();
550 
551     SwLayoutFrame *pLay;
552     if ( pAnch->IsInFly() )
553         pLay = pAnch->FindFlyFrame();
554     else
555     {
556         // FindFooterOrHeader is not appropriate here, as we may not have a
557         // connection to the Anchor yet.
558         pLay = pAnch->GetUpper();
559         while ( pLay && !(pLay->GetType() & (SwFrameType::Header|SwFrameType::Footer)) )
560             pLay = pLay->GetUpper();
561     }
562 
563     SwIterator<SwFlyFrame,SwFormat> aIter( rChain );
564     SwFlyFrame *pFly = aIter.First();
565     if ( pLay )
566     {
567         while ( pFly )
568         {
569             if ( pFly->GetAnchorFrame() )
570             {
571                 if ( pFly->GetAnchorFrame()->IsInFly() )
572                 {
573                     if ( pFly->AnchorFrame()->FindFlyFrame() == pLay )
574                         break;
575                 }
576                 else if ( pLay == pFly->FindFooterOrHeader() )
577                     break;
578             }
579             pFly = aIter.Next();
580         }
581     }
582     else if ( pFly )
583     {
584         OSL_ENSURE( !aIter.Next(), "chain with more than one instance" );
585     }
586     return pFly;
587 }
588 
FindLastLower()589 SwFrame *SwFlyFrame::FindLastLower()
590 {
591     SwFrame *pRet = ContainsAny();
592     if ( pRet && pRet->IsInTab() )
593         pRet = pRet->FindTabFrame();
594     SwFrame *pNxt = pRet;
595     while ( pNxt && IsAnLower( pNxt ) )
596     {   pRet = pNxt;
597         pNxt = pNxt->FindNext();
598     }
599     return pRet;
600 }
601 
FrameSizeChg(const SwFormatFrameSize & rFrameSize)602 bool SwFlyFrame::FrameSizeChg( const SwFormatFrameSize &rFrameSize )
603 {
604     bool bRet = false;
605     SwTwips nDiffHeight = getFrameArea().Height();
606     if ( rFrameSize.GetHeightSizeType() == SwFrameSize::Variable )
607         mbFixSize = m_bMinHeight = false;
608     else
609     {
610         if ( rFrameSize.GetHeightSizeType() == SwFrameSize::Fixed )
611         {
612             mbFixSize = true;
613             m_bMinHeight = false;
614         }
615         else if ( rFrameSize.GetHeightSizeType() == SwFrameSize::Minimum )
616         {
617             mbFixSize = false;
618             m_bMinHeight = true;
619         }
620         nDiffHeight -= rFrameSize.GetHeight();
621     }
622     // If the Fly contains columns, we already need to set the Fly
623     // and the Columns to the required value or else we run into problems.
624     if ( Lower() )
625     {
626         if ( Lower()->IsColumnFrame() )
627         {
628             const SwRect aOld( GetObjRectWithSpaces() );
629             const Size   aOldSz( getFramePrintArea().SSize() );
630             const SwTwips nDiffWidth = getFrameArea().Width() - rFrameSize.GetWidth();
631 
632             {
633                 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
634                 aFrm.Height( aFrm.Height() - nDiffHeight );
635                 aFrm.Width ( aFrm.Width()  - nDiffWidth  );
636             }
637 
638             // #i68520#
639             InvalidateObjRectWithSpaces();
640 
641             {
642                 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
643                 aPrt.Height( aPrt.Height() - nDiffHeight );
644                 aPrt.Width ( aPrt.Width()  - nDiffWidth  );
645             }
646 
647             ChgLowersProp( aOldSz );
648             ::Notify( this, FindPageFrame(), aOld );
649             setFrameAreaPositionValid(false);
650             bRet = true;
651         }
652         else if ( Lower()->IsNoTextFrame() )
653         {
654             mbFixSize = true;
655             m_bMinHeight = false;
656         }
657     }
658     return bRet;
659 }
660 
SwClientNotify(const SwModify & rMod,const SfxHint & rHint)661 void SwFlyFrame::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
662 {
663     if (rHint.GetId() == SfxHintId::SwLegacyModify)
664     {
665         auto pLegacy = static_cast<const sw::LegacyModifyHint*>(&rHint);
666         SwFlyFrameInvFlags eInvFlags = SwFlyFrameInvFlags::NONE;
667         if(pLegacy->m_pNew && pLegacy->m_pOld && RES_ATTRSET_CHG == pLegacy->m_pNew->Which())
668         {
669             SfxItemIter aNIter(*static_cast<const SwAttrSetChg*>(pLegacy->m_pNew)->GetChgSet());
670             SfxItemIter aOIter(*static_cast<const SwAttrSetChg*>(pLegacy->m_pOld)->GetChgSet());
671             const SfxPoolItem* pNItem = aNIter.GetCurItem();
672             const SfxPoolItem* pOItem = aOIter.GetCurItem();
673             SwAttrSetChg aOldSet(*static_cast<const SwAttrSetChg*>(pLegacy->m_pOld));
674             SwAttrSetChg aNewSet(*static_cast<const SwAttrSetChg*>(pLegacy->m_pNew));
675             do
676             {
677                 UpdateAttr_(pOItem, pNItem, eInvFlags, &aOldSet, &aNewSet);
678                 pNItem = aNIter.NextItem();
679                 pOItem = aOIter.NextItem();
680             } while(pNItem);
681             if(aOldSet.Count() || aNewSet.Count())
682                 SwLayoutFrame::SwClientNotify(rMod, sw::LegacyModifyHint(&aOldSet, &aNewSet));
683         }
684         else
685             UpdateAttr_(pLegacy->m_pOld, pLegacy->m_pNew, eInvFlags);
686 
687         if(eInvFlags == SwFlyFrameInvFlags::NONE)
688             return;
689 
690         Invalidate_();
691         if(eInvFlags & SwFlyFrameInvFlags::InvalidatePos)
692         {
693             InvalidatePos_();
694             // #i68520#
695             InvalidateObjRectWithSpaces();
696         }
697         if(eInvFlags & SwFlyFrameInvFlags::InvalidateSize)
698         {
699             InvalidateSize_();
700             // #i68520#
701             InvalidateObjRectWithSpaces();
702         }
703         if(eInvFlags & SwFlyFrameInvFlags::InvalidatePrt)
704             InvalidatePrt_();
705         if(eInvFlags & SwFlyFrameInvFlags::SetNotifyBack)
706             SetNotifyBack();
707         if(eInvFlags & SwFlyFrameInvFlags::SetCompletePaint)
708             SetCompletePaint();
709         if((eInvFlags & SwFlyFrameInvFlags::ClearContourCache) && Lower() && Lower()->IsNoTextFrame())
710             ClrContourCache( GetVirtDrawObj() );
711         SwRootFrame *pRoot;
712         if(eInvFlags & SwFlyFrameInvFlags::InvalidateBrowseWidth && nullptr != (pRoot = getRootFrame()))
713             pRoot->InvalidateBrowseWidth();
714         // #i28701#
715         if(eInvFlags & SwFlyFrameInvFlags::UpdateObjInSortedList)
716         {
717             // update sorted object lists, the Writer fly frame is registered at.
718             UpdateObjInSortedList();
719         }
720 
721         // #i87645# - reset flags for the layout process (only if something has been invalidated)
722         ResetLayoutProcessBools();
723     }
724     else if (auto pGetZOrdnerHint = dynamic_cast<const sw::GetZOrderHint*>(&rHint))
725     {
726         const auto& rFormat(dynamic_cast<const SwFrameFormat&>(rMod));
727         if (rFormat.Which() == RES_FLYFRMFMT && rFormat.getIDocumentLayoutAccess().GetCurrentViewShell()) // #i11176#
728             pGetZOrdnerHint->m_rnZOrder = GetVirtDrawObj()->GetOrdNum();
729     }
730     else if (auto pConnectedHint = dynamic_cast<const sw::GetObjectConnectedHint*>(&rHint))
731     {
732         const auto& rFormat(dynamic_cast<const SwFrameFormat&>(rMod));
733         if (!pConnectedHint->m_risConnected && rFormat.Which() == RES_FLYFRMFMT && (!pConnectedHint->m_pRoot || pConnectedHint->m_pRoot == getRootFrame()))
734             pConnectedHint->m_risConnected = true;
735     }
736 }
737 
UpdateAttr_(const SfxPoolItem * pOld,const SfxPoolItem * pNew,SwFlyFrameInvFlags & rInvFlags,SwAttrSetChg * pOldSet,SwAttrSetChg * pNewSet)738 void SwFlyFrame::UpdateAttr_( const SfxPoolItem *pOld, const SfxPoolItem *pNew,
739                             SwFlyFrameInvFlags &rInvFlags,
740                             SwAttrSetChg *pOldSet, SwAttrSetChg *pNewSet )
741 {
742     bool bClear = true;
743     const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
744     SwViewShell *pSh = getRootFrame()->GetCurrShell();
745     switch( nWhich )
746     {
747         case RES_VERT_ORIENT:
748         case RES_HORI_ORIENT:
749         //  #i18732# - consider new option 'follow text flow'
750         case RES_FOLLOW_TEXT_FLOW:
751         {
752             // ATTENTION: Always also change Action in ChgRePos()!
753             rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::SetNotifyBack;
754         }
755         break;
756         // #i28701# - consider new option 'wrap influence on position'
757         case RES_WRAP_INFLUENCE_ON_OBJPOS:
758         {
759             rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::SetNotifyBack
760                          | SwFlyFrameInvFlags::UpdateObjInSortedList;
761         }
762         break;
763         case RES_SURROUND:
764         {
765             //#i28701# - invalidate position on change of
766             // wrapping style.
767             rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::ClearContourCache;
768             // The background needs to be messaged and invalidated
769             const SwRect aTmp( GetObjRectWithSpaces() );
770             NotifyBackground( FindPageFrame(), aTmp, PrepareHint::FlyFrameAttributesChanged );
771 
772             // By changing the flow of frame-bound Frames, a vertical alignment
773             // can be activated/deactivated => MakeFlyPos
774             if( RndStdIds::FLY_AT_FLY == GetFormat()->GetAnchor().GetAnchorId() )
775                 rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::SetNotifyBack;
776 
777             // Delete contour in the Node if necessary
778             if ( Lower() && Lower()->IsNoTextFrame() &&
779                  !GetFormat()->GetSurround().IsContour() )
780             {
781                 SwNoTextNode *pNd = static_cast<SwNoTextNode*>(static_cast<SwNoTextFrame*>(Lower())->GetNode());
782                 if ( pNd->HasContour() )
783                     pNd->SetContour( nullptr );
784             }
785             // #i28701# - perform reorder of object lists
786             // at anchor frame and at page frame.
787             rInvFlags |= SwFlyFrameInvFlags::UpdateObjInSortedList;
788         }
789         break;
790 
791         case RES_PROTECT:
792             if (pNew)
793             {
794                 const SvxProtectItem *pP = static_cast<const SvxProtectItem*>(pNew);
795                 GetVirtDrawObj()->SetMoveProtect( pP->IsPosProtected()   );
796                 GetVirtDrawObj()->SetResizeProtect( pP->IsSizeProtected() );
797                 if( pSh )
798                 {
799                     SwRootFrame* pLayout = getRootFrame();
800                     if( pLayout && pLayout->IsAnyShellAccessible() )
801                         pSh->Imp()->InvalidateAccessibleEditableState( true, this );
802                 }
803             }
804             break;
805         case RES_COL:
806             if (pOld && pNew)
807             {
808                 ChgColumns( *static_cast<const SwFormatCol*>(pOld), *static_cast<const SwFormatCol*>(pNew) );
809                 const SwFormatFrameSize &rNew = GetFormat()->GetFrameSize();
810                 if ( FrameSizeChg( rNew ) )
811                     NotifyDrawObj();
812                 rInvFlags |= SwFlyFrameInvFlags::InvalidateSize | SwFlyFrameInvFlags::SetNotifyBack
813                              | SwFlyFrameInvFlags::SetCompletePaint;
814             }
815             break;
816 
817         case RES_FRM_SIZE:
818         case RES_FMT_CHG:
819         {
820             const SwFormatFrameSize &rNew = GetFormat()->GetFrameSize();
821             if ( FrameSizeChg( rNew ) )
822                 NotifyDrawObj();
823             rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::InvalidateSize
824                          | SwFlyFrameInvFlags::InvalidatePrt | SwFlyFrameInvFlags::SetNotifyBack
825                          | SwFlyFrameInvFlags::SetCompletePaint
826                          | SwFlyFrameInvFlags::InvalidateBrowseWidth
827                          | SwFlyFrameInvFlags::ClearContourCache;
828             if (pOld && RES_FMT_CHG == nWhich)
829             {
830                 SwRect aNew( GetObjRectWithSpaces() );
831                 SwRect aOld( getFrameArea() );
832                 const SvxULSpaceItem &rUL = static_cast<const SwFormatChg*>(pOld)->pChangedFormat->GetULSpace();
833                 aOld.Top( std::max( aOld.Top() - tools::Long(rUL.GetUpper()), tools::Long(0) ) );
834                 aOld.AddHeight(rUL.GetLower() );
835                 const SvxLRSpaceItem &rLR = static_cast<const SwFormatChg*>(pOld)->pChangedFormat->GetLRSpace();
836                 aOld.Left  ( std::max( aOld.Left() - rLR.GetLeft(), tools::Long(0) ) );
837                 aOld.AddWidth(rLR.GetRight() );
838                 aNew.Union( aOld );
839                 NotifyBackground( FindPageFrame(), aNew, PrepareHint::Clear );
840 
841                 // Special case:
842                 // When assigning a template we cannot rely on the old column
843                 // attribute. As there need to be at least enough for ChgColumns,
844                 // we need to create a temporary attribute.
845                 SwFormatCol aCol;
846                 if ( Lower() && Lower()->IsColumnFrame() )
847                 {
848                     sal_uInt16 nCol = 0;
849                     SwFrame *pTmp = Lower();
850                     do
851                     {   ++nCol;
852                         pTmp = pTmp->GetNext();
853                     } while ( pTmp );
854                     aCol.Init( nCol, 0, 1000 );
855                 }
856                 ChgColumns( aCol, GetFormat()->GetCol() );
857             }
858 
859             SwFormatURL aURL( GetFormat()->GetURL() );
860 
861             SwFormatFrameSize *pNewFormatFrameSize = nullptr;
862             SwFormatChg *pOldFormatChg = nullptr;
863             if (nWhich == RES_FRM_SIZE)
864                 pNewFormatFrameSize = const_cast<SwFormatFrameSize*>(static_cast<const SwFormatFrameSize*>(pNew));
865             else
866                 pOldFormatChg = const_cast<SwFormatChg*>(static_cast<const SwFormatChg*>(pOld));
867 
868             if (aURL.GetMap() && (pNewFormatFrameSize || pOldFormatChg))
869             {
870                 const SwFormatFrameSize &rOld = pNewFormatFrameSize ?
871                                 *pNewFormatFrameSize :
872                                 pOldFormatChg->pChangedFormat->GetFrameSize();
873                 //#35091# Can be "times zero", when loading the template
874                 if ( rOld.GetWidth() && rOld.GetHeight() )
875                 {
876 
877                     Fraction aScaleX( rOld.GetWidth(), rNew.GetWidth() );
878                     Fraction aScaleY( rOld.GetHeight(), rOld.GetHeight() );
879                     aURL.GetMap()->Scale( aScaleX, aScaleY );
880                     SwFrameFormat *pFormat = GetFormat();
881                     pFormat->LockModify();
882                     pFormat->SetFormatAttr( aURL );
883                     pFormat->UnlockModify();
884                 }
885             }
886             const SvxProtectItem &rP = GetFormat()->GetProtect();
887             GetVirtDrawObj()->SetMoveProtect( rP.IsPosProtected()    );
888             GetVirtDrawObj()->SetResizeProtect( rP.IsSizeProtected() );
889 
890             if ( pSh )
891                 pSh->InvalidateWindows( getFrameArea() );
892             const IDocumentDrawModelAccess& rIDDMA = GetFormat()->getIDocumentDrawModelAccess();
893             const SdrLayerID nId = GetFormat()->GetOpaque().GetValue() ?
894                              rIDDMA.GetHeavenId() :
895                              rIDDMA.GetHellId();
896             GetVirtDrawObj()->SetLayer( nId );
897 
898             if ( Lower() )
899             {
900                 // Delete contour in the Node if necessary
901                 if( Lower()->IsNoTextFrame() &&
902                      !GetFormat()->GetSurround().IsContour() )
903                 {
904                     SwNoTextNode *pNd = static_cast<SwNoTextNode*>(static_cast<SwNoTextFrame*>(Lower())->GetNode());
905                     if ( pNd->HasContour() )
906                         pNd->SetContour( nullptr );
907                 }
908                 else if( !Lower()->IsColumnFrame() )
909                 {
910                     SwFrame* pFrame = GetLastLower();
911                     if( pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsUndersized() )
912                         pFrame->Prepare( PrepareHint::AdjustSizeWithoutFormatting );
913                 }
914             }
915 
916             // #i28701# - perform reorder of object lists
917             // at anchor frame and at page frame.
918             rInvFlags |= SwFlyFrameInvFlags::UpdateObjInSortedList;
919 
920             break;
921         }
922         case RES_UL_SPACE:
923         case RES_LR_SPACE:
924         {
925             rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::ClearContourCache;
926             if( pSh && pSh->GetViewOptions()->getBrowseMode() )
927                 getRootFrame()->InvalidateBrowseWidth();
928             SwRect aNew( GetObjRectWithSpaces() );
929             SwRect aOld( getFrameArea() );
930             if (pNew)
931             {
932                 if ( RES_UL_SPACE == nWhich )
933                 {
934                     const SvxULSpaceItem &rUL = *static_cast<const SvxULSpaceItem*>(pNew);
935                     aOld.Top( std::max( aOld.Top() - tools::Long(rUL.GetUpper()), tools::Long(0) ) );
936                     aOld.AddHeight(rUL.GetLower() );
937                 }
938                 else
939                 {
940                     const SvxLRSpaceItem &rLR = *static_cast<const SvxLRSpaceItem*>(pNew);
941                     aOld.Left  ( std::max( aOld.Left() - rLR.GetLeft(), tools::Long(0) ) );
942                     aOld.AddWidth(rLR.GetRight() );
943                 }
944             }
945             aNew.Union( aOld );
946             NotifyBackground( FindPageFrame(), aNew, PrepareHint::Clear );
947         }
948         break;
949 
950         case RES_TEXT_VERT_ADJUST:
951         {
952             InvalidateContentPos();
953             rInvFlags |= SwFlyFrameInvFlags::SetCompletePaint;
954         }
955         break;
956 
957         case RES_BOX:
958         case RES_SHADOW:
959             rInvFlags |= SwFlyFrameInvFlags::InvalidatePos | SwFlyFrameInvFlags::InvalidateSize
960                          | SwFlyFrameInvFlags::InvalidatePrt | SwFlyFrameInvFlags::SetCompletePaint;
961             break;
962 
963         case RES_FRAMEDIR :
964             SetDerivedVert( false );
965             SetDerivedR2L( false );
966             CheckDirChange();
967             break;
968 
969         case RES_OPAQUE:
970             if (pNew)
971             {
972                 if ( pSh )
973                     pSh->InvalidateWindows( getFrameArea() );
974 
975                 const IDocumentDrawModelAccess& rIDDMA = GetFormat()->getIDocumentDrawModelAccess();
976                 const SdrLayerID nId = static_cast<const SvxOpaqueItem*>(pNew)->GetValue() ?
977                                     rIDDMA.GetHeavenId() :
978                                     rIDDMA.GetHellId();
979                 GetVirtDrawObj()->SetLayer( nId );
980                 if( pSh )
981                 {
982                     SwRootFrame* pLayout = getRootFrame();
983                     if( pLayout && pLayout->IsAnyShellAccessible() )
984                 {
985                     pSh->Imp()->DisposeAccessibleFrame( this );
986                     pSh->Imp()->AddAccessibleFrame( this );
987                 }
988                 }
989                 // #i28701# - perform reorder of object lists
990                 // at anchor frame and at page frame.
991                 rInvFlags |= SwFlyFrameInvFlags::UpdateObjInSortedList;
992             }
993             break;
994 
995         case RES_URL:
996             // The interface changes the frame size when interacting with text frames,
997             // the Map, however, needs to be relative to FrameSize().
998             if ( (!Lower() || !Lower()->IsNoTextFrame()) && pNew && pOld &&
999                  static_cast<const SwFormatURL*>(pNew)->GetMap() && static_cast<const SwFormatURL*>(pOld)->GetMap() )
1000             {
1001                 const SwFormatFrameSize &rSz = GetFormat()->GetFrameSize();
1002                 if ( rSz.GetHeight() != getFrameArea().Height() ||
1003                      rSz.GetWidth()  != getFrameArea().Width() )
1004                 {
1005                     SwFormatURL aURL( GetFormat()->GetURL() );
1006                     Fraction aScaleX( getFrameArea().Width(),  rSz.GetWidth() );
1007                     Fraction aScaleY( getFrameArea().Height(), rSz.GetHeight() );
1008                     aURL.GetMap()->Scale( aScaleX, aScaleY );
1009                     SwFrameFormat *pFormat = GetFormat();
1010                     pFormat->LockModify();
1011                     pFormat->SetFormatAttr( aURL );
1012                     pFormat->UnlockModify();
1013                 }
1014             }
1015             // No invalidation necessary
1016             break;
1017 
1018         case RES_CHAIN:
1019             if (pNew)
1020             {
1021                 const SwFormatChain *pChain = static_cast<const SwFormatChain*>(pNew);
1022                 if ( pChain->GetNext() )
1023                 {
1024                     SwFlyFrame *pFollow = FindChainNeighbour( *pChain->GetNext() );
1025                     if ( GetNextLink() && pFollow != GetNextLink() )
1026                         SwFlyFrame::UnchainFrames( this, GetNextLink());
1027                     if ( pFollow )
1028                     {
1029                         if ( pFollow->GetPrevLink() &&
1030                              pFollow->GetPrevLink() != this )
1031                             SwFlyFrame::UnchainFrames( pFollow->GetPrevLink(),
1032                                                      pFollow );
1033                         if ( !GetNextLink() )
1034                             SwFlyFrame::ChainFrames( this, pFollow );
1035                     }
1036                 }
1037                 else if ( GetNextLink() )
1038                     SwFlyFrame::UnchainFrames( this, GetNextLink() );
1039                 if ( pChain->GetPrev() )
1040                 {
1041                     SwFlyFrame *pMaster = FindChainNeighbour( *pChain->GetPrev() );
1042                     if ( GetPrevLink() && pMaster != GetPrevLink() )
1043                         SwFlyFrame::UnchainFrames( GetPrevLink(), this );
1044                     if ( pMaster )
1045                     {
1046                         if ( pMaster->GetNextLink() &&
1047                              pMaster->GetNextLink() != this )
1048                             SwFlyFrame::UnchainFrames( pMaster,
1049                                                      pMaster->GetNextLink() );
1050                         if ( !GetPrevLink() )
1051                             SwFlyFrame::ChainFrames( pMaster, this );
1052                     }
1053                 }
1054                 else if ( GetPrevLink() )
1055                     SwFlyFrame::UnchainFrames( GetPrevLink(), this );
1056             }
1057             [[fallthrough]];
1058         default:
1059             bClear = false;
1060     }
1061     if ( !bClear )
1062         return;
1063 
1064     if ( pOldSet || pNewSet )
1065     {
1066         if ( pOldSet )
1067             pOldSet->ClearItem( nWhich );
1068         if ( pNewSet )
1069             pNewSet->ClearItem( nWhich );
1070     }
1071     else
1072     {
1073         SwModify aMod;
1074         SwLayoutFrame::SwClientNotify(aMod, sw::LegacyModifyHint(pOld, pNew));
1075     }
1076 }
1077 
1078 /// Gets information from the Modify
GetInfo(SfxPoolItem & rInfo) const1079 bool SwFlyFrame::GetInfo( SfxPoolItem & rInfo ) const
1080 {
1081     if( RES_AUTOFMT_DOCNODE == rInfo.Which() )
1082         return false;   // There's a FlyFrame, so use it
1083     return true;        // Continue searching
1084 }
1085 
Invalidate_(SwPageFrame const * pPage)1086 void SwFlyFrame::Invalidate_( SwPageFrame const *pPage )
1087 {
1088     InvalidatePage( pPage );
1089     m_bNotifyBack = m_bInvalid = true;
1090 
1091     SwFlyFrame *pFrame;
1092     if ( GetAnchorFrame() && nullptr != (pFrame = AnchorFrame()->FindFlyFrame()) )
1093     {
1094         // Very bad case: If the Fly is bound within another Fly which
1095         // contains columns, the Format should be from that one.
1096         if ( !pFrame->IsLocked() && !pFrame->IsColLocked() &&
1097              pFrame->Lower() && pFrame->Lower()->IsColumnFrame() )
1098             pFrame->InvalidateSize();
1099     }
1100 
1101     // #i85216#
1102     // if vertical position is oriented at a layout frame inside a ghost section,
1103     // assure that the position is invalidated and that the information about
1104     // the vertical position oriented frame is cleared
1105     if ( GetVertPosOrientFrame() && GetVertPosOrientFrame()->IsLayoutFrame() )
1106     {
1107         const SwSectionFrame* pSectFrame( GetVertPosOrientFrame()->FindSctFrame() );
1108         if ( pSectFrame && pSectFrame->GetSection() == nullptr )
1109         {
1110             InvalidatePos();
1111             ClearVertPosOrientFrame();
1112         }
1113     }
1114 }
1115 
1116 /** Change the relative position
1117  *
1118  * The position will be Fix automatically and the attribute is changed accordingly.
1119  */
ChgRelPos(const Point & rNewPos)1120 void SwFlyFrame::ChgRelPos( const Point &rNewPos )
1121 {
1122     if ( GetCurrRelPos() == rNewPos )
1123         return;
1124 
1125     SwFrameFormat *pFormat = GetFormat();
1126     const bool bVert = GetAnchorFrame()->IsVertical();
1127     const SwTwips nNewY = bVert ? rNewPos.X() : rNewPos.Y();
1128     SwTwips nTmpY = nNewY == LONG_MAX ? 0 : nNewY;
1129     if( bVert )
1130         nTmpY = -nTmpY;
1131     SfxItemSet aSet( pFormat->GetDoc()->GetAttrPool(),
1132                      svl::Items<RES_VERT_ORIENT, RES_HORI_ORIENT>{});
1133 
1134     SwFormatVertOrient aVert( pFormat->GetVertOrient() );
1135     const SwTextFrame *pAutoFrame = nullptr;
1136     // #i34948# - handle also at-page and at-fly anchored
1137     // Writer fly frames
1138     const RndStdIds eAnchorType = GetFrameFormat().GetAnchor().GetAnchorId();
1139     if ( eAnchorType == RndStdIds::FLY_AT_PAGE )
1140     {
1141         aVert.SetVertOrient( text::VertOrientation::NONE );
1142         aVert.SetRelationOrient( text::RelOrientation::PAGE_FRAME );
1143     }
1144     else if ( eAnchorType == RndStdIds::FLY_AT_FLY )
1145     {
1146         aVert.SetVertOrient( text::VertOrientation::NONE );
1147         aVert.SetRelationOrient( text::RelOrientation::FRAME );
1148     }
1149     else if ( IsFlyAtContentFrame() || text::VertOrientation::NONE != aVert.GetVertOrient() )
1150     {
1151         if( text::RelOrientation::CHAR == aVert.GetRelationOrient() && IsAutoPos() )
1152         {
1153             if( LONG_MAX != nNewY )
1154             {
1155                 aVert.SetVertOrient( text::VertOrientation::NONE );
1156                 assert(GetAnchorFrame()->IsTextFrame());
1157                 pAutoFrame = static_cast<const SwTextFrame*>(GetAnchorFrame());
1158                 TextFrameIndex const nOfs(pAutoFrame->MapModelToViewPos(
1159                             *pFormat->GetAnchor().GetContentAnchor()));
1160                 while( pAutoFrame->GetFollow() &&
1161                        pAutoFrame->GetFollow()->GetOffset() <= nOfs )
1162                 {
1163                     if( pAutoFrame == GetAnchorFrame() )
1164                         nTmpY += pAutoFrame->GetRelPos().Y();
1165                     nTmpY -= pAutoFrame->GetUpper()->getFramePrintArea().Height();
1166                     pAutoFrame = pAutoFrame->GetFollow();
1167                 }
1168                 nTmpY = static_cast<SwFlyAtContentFrame*>(this)->GetRelCharY(pAutoFrame)-nTmpY;
1169             }
1170             else
1171                 aVert.SetVertOrient( text::VertOrientation::CHAR_BOTTOM );
1172         }
1173         else
1174         {
1175             aVert.SetVertOrient( text::VertOrientation::NONE );
1176             aVert.SetRelationOrient( text::RelOrientation::FRAME );
1177         }
1178     }
1179     aVert.SetPos( nTmpY );
1180     aSet.Put( aVert );
1181 
1182     // For Flys in the Cnt, the horizontal orientation is of no interest,
1183     // as it's always 0
1184     if ( !IsFlyInContentFrame() )
1185     {
1186         const SwTwips nNewX = bVert ? rNewPos.Y() : rNewPos.X();
1187         SwTwips nTmpX = nNewX == LONG_MAX ? 0 : nNewX;
1188         SwFormatHoriOrient aHori( pFormat->GetHoriOrient() );
1189         // #i34948# - handle also at-page and at-fly anchored
1190         // Writer fly frames
1191         if ( eAnchorType == RndStdIds::FLY_AT_PAGE )
1192         {
1193             aHori.SetHoriOrient( text::HoriOrientation::NONE );
1194             aHori.SetRelationOrient( text::RelOrientation::PAGE_FRAME );
1195             aHori.SetPosToggle( false );
1196         }
1197         else if ( eAnchorType == RndStdIds::FLY_AT_FLY )
1198         {
1199             aHori.SetHoriOrient( text::HoriOrientation::NONE );
1200             aHori.SetRelationOrient( text::RelOrientation::FRAME );
1201             aHori.SetPosToggle( false );
1202         }
1203         else if ( IsFlyAtContentFrame() || text::HoriOrientation::NONE != aHori.GetHoriOrient() )
1204         {
1205             aHori.SetHoriOrient( text::HoriOrientation::NONE );
1206             if( text::RelOrientation::CHAR == aHori.GetRelationOrient() && IsAutoPos() )
1207             {
1208                 if( LONG_MAX != nNewX )
1209                 {
1210                     if( !pAutoFrame )
1211                     {
1212                         assert(GetAnchorFrame()->IsTextFrame());
1213                         pAutoFrame = static_cast<const SwTextFrame*>(GetAnchorFrame());
1214                         TextFrameIndex const nOfs(pAutoFrame->MapModelToViewPos(
1215                                     *pFormat->GetAnchor().GetContentAnchor()));
1216                         while( pAutoFrame->GetFollow() &&
1217                                pAutoFrame->GetFollow()->GetOffset() <= nOfs )
1218                             pAutoFrame = pAutoFrame->GetFollow();
1219                     }
1220                     nTmpX -= static_cast<SwFlyAtContentFrame*>(this)->GetRelCharX(pAutoFrame);
1221                 }
1222             }
1223             else
1224                 aHori.SetRelationOrient( text::RelOrientation::FRAME );
1225             aHori.SetPosToggle( false );
1226         }
1227         aHori.SetPos( nTmpX );
1228         aSet.Put( aHori );
1229     }
1230     SetCurrRelPos( rNewPos );
1231     pFormat->GetDoc()->SetAttr( aSet, *pFormat );
1232 
1233 }
1234 
1235 /** "Formats" the Frame; Frame and PrtArea.
1236  *
1237  * The FixSize is not inserted here.
1238  */
Format(vcl::RenderContext *,const SwBorderAttrs * pAttrs)1239 void SwFlyFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderAttrs *pAttrs )
1240 {
1241     OSL_ENSURE( pAttrs, "FlyFrame::Format, pAttrs is 0." );
1242 
1243     ColLock();
1244 
1245     if ( !isFrameAreaSizeValid() )
1246     {
1247         if ( getFrameArea().Top() == FAR_AWAY && getFrameArea().Left() == FAR_AWAY )
1248         {
1249             // Remove safety switch (see SwFrame::CTor)
1250             {
1251                 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
1252                 aFrm.Pos().setX(0);
1253                 aFrm.Pos().setY(0);
1254             }
1255 
1256             // #i68520#
1257             InvalidateObjRectWithSpaces();
1258         }
1259 
1260         // Check column width and set it if needed
1261         if ( Lower() && Lower()->IsColumnFrame() )
1262             AdjustColumns( nullptr, false );
1263 
1264         setFrameAreaSizeValid(true);
1265 
1266         const SwTwips nUL = pAttrs->CalcTopLine()  + pAttrs->CalcBottomLine();
1267         const SwTwips nLR = pAttrs->CalcLeftLine() + pAttrs->CalcRightLine();
1268         const SwFormatFrameSize &rFrameSz = GetFormat()->GetFrameSize();
1269         Size aRelSize( CalcRel( rFrameSz ) );
1270 
1271         OSL_ENSURE( pAttrs->GetSize().Height() != 0 || rFrameSz.GetHeightPercent(), "FrameAttr height is 0." );
1272         OSL_ENSURE( pAttrs->GetSize().Width()  != 0 || rFrameSz.GetWidthPercent(), "FrameAttr width is 0." );
1273 
1274         SwRectFnSet aRectFnSet(this);
1275         if( !HasFixSize() )
1276         {
1277             tools::Long nMinHeight = 0;
1278             if( IsMinHeight() )
1279                 nMinHeight = aRectFnSet.IsVert() ? aRelSize.Width() : aRelSize.Height();
1280 
1281             SwTwips nRemaining = CalcContentHeight(pAttrs, nMinHeight, nUL);
1282             if( IsMinHeight() && (nRemaining + nUL) < nMinHeight )
1283                 nRemaining = nMinHeight - nUL;
1284             // Because the Grow/Shrink of the Flys does not directly
1285             // set the size - only indirectly by triggering a Format()
1286             // via Invalidate() - the sizes need to be set here.
1287             // Notification is running along already.
1288             // As we already got a lot of zeros per attribute, we block them
1289             // from now on.
1290 
1291             if ( nRemaining < MINFLY )
1292                 nRemaining = MINFLY;
1293 
1294             {
1295                 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
1296                 aRectFnSet.SetHeight( aPrt, nRemaining );
1297             }
1298 
1299             nRemaining -= aRectFnSet.GetHeight(getFrameArea());
1300 
1301             {
1302                 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
1303                 aRectFnSet.AddBottom( aFrm, nRemaining + nUL );
1304             }
1305 
1306             // #i68520#
1307             if ( nRemaining + nUL != 0 )
1308             {
1309                 InvalidateObjRectWithSpaces();
1310             }
1311 
1312             setFrameAreaSizeValid(true);
1313 
1314             if (SwFrameFormat* pShapeFormat = SwTextBoxHelper::getOtherTextBoxFormat(GetFormat(), RES_FLYFRMFMT))
1315             {
1316                 // This fly is a textbox of a draw shape.
1317                 SdrObject* pShape = pShapeFormat->FindSdrObject();
1318                 if (SdrObjCustomShape* pCustomShape = dynamic_cast<SdrObjCustomShape*>( pShape) )
1319                 {
1320                     // The shape is a customshape: then inform it about the calculated fly size.
1321                     Size aSize(getFrameArea().Width(), getFrameArea().Height());
1322                     pCustomShape->SuggestTextFrameSize(aSize);
1323                     // Do the calculations normally done after touching editeng text of the shape.
1324                     pCustomShape->NbcSetOutlinerParaObjectForText(nullptr, nullptr);
1325                 }
1326             }
1327         }
1328         else
1329         {
1330             // Fixed Frames do not Format itself
1331             setFrameAreaSizeValid(true);
1332 
1333             // Flys set their size using the attr
1334             SwTwips nNewSize = aRectFnSet.IsVert() ? aRelSize.Width() : aRelSize.Height();
1335             nNewSize -= nUL;
1336             if( nNewSize < MINFLY )
1337                 nNewSize = MINFLY;
1338 
1339             {
1340                 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
1341                 aRectFnSet.SetHeight( aPrt, nNewSize );
1342             }
1343 
1344             nNewSize += nUL - aRectFnSet.GetHeight(getFrameArea());
1345 
1346             {
1347                 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
1348                 aRectFnSet.AddBottom( aFrm, nNewSize );
1349             }
1350 
1351             // #i68520#
1352             if ( nNewSize != 0 )
1353             {
1354                 InvalidateObjRectWithSpaces();
1355             }
1356         }
1357 
1358         if ( !m_bFormatHeightOnly )
1359         {
1360             OSL_ENSURE( aRelSize == CalcRel( rFrameSz ), "SwFlyFrame::Format CalcRel problem" );
1361             SwTwips nNewSize = aRectFnSet.IsVert() ? aRelSize.Height() : aRelSize.Width();
1362 
1363             if ( rFrameSz.GetWidthSizeType() != SwFrameSize::Fixed )
1364             {
1365                 // #i9046# Autowidth for fly frames
1366                 const SwTwips nAutoWidth = lcl_CalcAutoWidth( *this );
1367                 if ( nAutoWidth )
1368                 {
1369                     if( SwFrameSize::Minimum == rFrameSz.GetWidthSizeType() )
1370                         nNewSize = std::max( nNewSize - nLR, nAutoWidth );
1371                     else
1372                         nNewSize = nAutoWidth;
1373                 }
1374             }
1375             else
1376                 nNewSize -= nLR;
1377 
1378             if( nNewSize < MINFLY )
1379                 nNewSize = MINFLY;
1380 
1381             {
1382                 SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
1383                 aRectFnSet.SetWidth( aPrt, nNewSize );
1384             }
1385 
1386             nNewSize += nLR - aRectFnSet.GetWidth(getFrameArea());
1387 
1388             {
1389                 SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
1390                 aRectFnSet.AddRight( aFrm, nNewSize );
1391             }
1392 
1393             // #i68520#
1394             if ( nNewSize != 0 )
1395             {
1396                 InvalidateObjRectWithSpaces();
1397             }
1398         }
1399     }
1400     ColUnlock();
1401 }
1402 
1403 // #i11760# - change parameter <bNoColl>: type <bool>;
1404 //   add new parameter <bNoCalcFollow> with
1405 //  new parameter <bNoCalcFollow> was used by method
1406 //                          <FormatWidthCols(..)> to avoid follow formatting
1407 //                          for text frames. But, unformatted follows causes
1408 //                          problems in method <SwContentFrame::WouldFit_(..)>,
1409 //                          which assumes that the follows are formatted.
1410 //                          Thus, <bNoCalcFollow> no longer used by <FormatWidthCols(..)>.
CalcContent(SwLayoutFrame * pLay,bool bNoColl)1411 void CalcContent( SwLayoutFrame *pLay, bool bNoColl )
1412 {
1413     vcl::RenderContext* pRenderContext = pLay->getRootFrame()->GetCurrShell()->GetOut();
1414     SwSectionFrame* pSect;
1415     bool bCollect = false;
1416     if( pLay->IsSctFrame() )
1417     {
1418         pSect = static_cast<SwSectionFrame*>(pLay);
1419         if( pSect->IsEndnAtEnd() && !bNoColl )
1420         {
1421             bCollect = true;
1422             SwLayouter::CollectEndnotes( pLay->GetFormat()->GetDoc(), pSect );
1423         }
1424         pSect->CalcFootnoteContent();
1425     }
1426     else
1427         pSect = nullptr;
1428     SwFrame *pFrame = pLay->ContainsAny();
1429     if ( !pFrame )
1430     {
1431         if( pSect )
1432         {
1433             if( pSect->HasFollow() )
1434                 pFrame = pSect->GetFollow()->ContainsAny();
1435             if( !pFrame )
1436             {
1437                 if( pSect->IsEndnAtEnd() )
1438                 {
1439                     if( bCollect )
1440                         pLay->GetFormat()->GetDoc()->getIDocumentLayoutAccess().GetLayouter()->
1441                             InsertEndnotes( pSect );
1442                     bool bLock = pSect->IsFootnoteLock();
1443                     pSect->SetFootnoteLock( true );
1444                     pSect->CalcFootnoteContent();
1445                     pSect->CalcFootnoteContent();
1446                     pSect->SetFootnoteLock( bLock );
1447                 }
1448                 return;
1449             }
1450             pFrame->InvalidatePos_();
1451         }
1452         else
1453             return;
1454     }
1455     pFrame->InvalidatePage();
1456 
1457     do
1458     {
1459         // local variables to avoid loops caused by anchored object positioning
1460         SwAnchoredObject* pAgainObj1 = nullptr;
1461         SwAnchoredObject* pAgainObj2 = nullptr;
1462 
1463         // FME 2007-08-30 #i81146# new loop control
1464         int nLoopControlRuns = 0;
1465         const int nLoopControlMax = 20;
1466         const SwFrame* pLoopControlCond = nullptr;
1467 
1468         SwFrame* pLast;
1469         do
1470         {
1471             pLast = pFrame;
1472             bool const wasFrameLowerOfLay(pLay->IsAnLower(pFrame));
1473             if( pFrame->IsVertical() ?
1474                 ( pFrame->GetUpper()->getFramePrintArea().Height() != pFrame->getFrameArea().Height() )
1475                 : ( pFrame->GetUpper()->getFramePrintArea().Width() != pFrame->getFrameArea().Width() ) )
1476             {
1477                 pFrame->Prepare( PrepareHint::FixSizeChanged );
1478                 pFrame->InvalidateSize_();
1479             }
1480 
1481             if ( pFrame->IsTabFrame() )
1482             {
1483                 static_cast<SwTabFrame*>(pFrame)->m_bCalcLowers = true;
1484                 // #i18103# - lock move backward of follow table,
1485                 // if no section content is formatted or follow table belongs
1486                 // to the section, which content is formatted.
1487                 if ( static_cast<SwTabFrame*>(pFrame)->IsFollow() &&
1488                      ( !pSect || pSect == pFrame->FindSctFrame() ) )
1489                 {
1490                     static_cast<SwTabFrame*>(pFrame)->m_bLockBackMove = true;
1491                 }
1492             }
1493 
1494             {
1495                 SwFrameDeleteGuard aDeletePageGuard(pSect ? pSect->FindPageFrame() : nullptr);
1496                 SwFrameDeleteGuard aDeleteGuard(pSect);
1497                 pFrame->Calc(pRenderContext);
1498             }
1499 
1500             // #i11760# - reset control flag for follow format.
1501             if ( pFrame->IsTextFrame() )
1502             {
1503                 static_cast<SwTextFrame*>(pFrame)->AllowFollowFormat();
1504             }
1505 
1506             // The keep-attribute can cause the position
1507             // of the prev to be invalid:
1508             // Do not consider invalid previous frame
1509             // due to its keep-attribute, if current frame is a follow or is locked.
1510             // #i44049# - do not consider invalid previous
1511             // frame due to its keep-attribute, if it can't move forward.
1512             // #i57765# - do not consider invalid previous
1513             // frame, if current frame has a column/page break before attribute.
1514             SwFrame* pTmpPrev = pFrame->FindPrev();
1515             SwFlowFrame* pTmpPrevFlowFrame = pTmpPrev && pTmpPrev->IsFlowFrame() ? SwFlowFrame::CastFlowFrame(pTmpPrev) : nullptr;
1516             SwFlowFrame* pTmpFlowFrame     = pFrame->IsFlowFrame() ? SwFlowFrame::CastFlowFrame(pFrame) : nullptr;
1517 
1518             bool bPrevInvalid = pTmpPrevFlowFrame && pTmpFlowFrame &&
1519                                !pTmpFlowFrame->IsFollow() &&
1520                                !StackHack::IsLocked() && // #i76382#
1521                                !pTmpFlowFrame->IsJoinLocked() &&
1522                                !pTmpPrev->isFrameAreaPositionValid() &&
1523                                 pLay->IsAnLower( pTmpPrev ) &&
1524                                 pTmpPrevFlowFrame->IsKeep(pTmpPrev->GetAttrSet()->GetKeep(), pTmpPrev->GetBreakItem()) &&
1525                                 pTmpPrevFlowFrame->IsKeepFwdMoveAllowed();
1526 
1527             // format floating screen objects anchored to the frame.
1528             if ( !bPrevInvalid && pFrame->GetDrawObjs() && pLay->IsAnLower( pFrame ) )
1529             {
1530                 bool bAgain = false;
1531                 bool bRestartLayoutProcess = false;
1532                 SwPageFrame* pPageFrame = pFrame->FindPageFrame();
1533                 size_t nCnt = pFrame->GetDrawObjs()->size();
1534                 size_t i = 0;
1535                 while ( i < nCnt )
1536                 {
1537                     // #i28701#
1538                     SwAnchoredObject* pAnchoredObj = (*pFrame->GetDrawObjs())[i];
1539                     assert(pAnchoredObj);
1540 
1541                     // determine if anchored object has to be
1542                     // formatted and, in case, format it
1543                     if ( !pAnchoredObj->PositionLocked() && pAnchoredObj->IsFormatPossible() )
1544                     {
1545                         // #i43737# - no invalidation of
1546                         // anchored object needed - causes loops for as-character
1547                         // anchored objects.
1548                         //pAnchoredObj->InvalidateObjPos();
1549                         SwRect aRect( pAnchoredObj->GetObjRect() );
1550                         if ( !SwObjectFormatter::FormatObj( *pAnchoredObj, pFrame, pPageFrame ) )
1551                         {
1552                             bRestartLayoutProcess = true;
1553                             break;
1554                         }
1555                         // #i3317# - restart layout process,
1556                         // if the position of the anchored object is locked now.
1557                         if ( pAnchoredObj->PositionLocked() )
1558                         {
1559                             bRestartLayoutProcess = true;
1560                             break;
1561                         }
1562 
1563                         if ( aRect != pAnchoredObj->GetObjRect() )
1564                         {
1565                             bAgain = true;
1566                             if ( pAgainObj2 == pAnchoredObj )
1567                             {
1568                                 OSL_FAIL( "::CalcContent(..) - loop detected, perform attribute changes to avoid the loop" );
1569                                 // Prevent oscillation
1570                                 SwFrameFormat& rFormat = pAnchoredObj->GetFrameFormat();
1571                                 SwFormatSurround aAttr( rFormat.GetSurround() );
1572                                 if( css::text::WrapTextMode_THROUGH != aAttr.GetSurround() )
1573                                 {
1574                                     // When on auto position, we can only set it to
1575                                     // flow through
1576                                     if ((rFormat.GetAnchor().GetAnchorId() ==
1577                                             RndStdIds::FLY_AT_CHAR) &&
1578                                         (css::text::WrapTextMode_PARALLEL ==
1579                                             aAttr.GetSurround()))
1580                                     {
1581                                         aAttr.SetSurround( css::text::WrapTextMode_THROUGH );
1582                                     }
1583                                     else
1584                                     {
1585                                         aAttr.SetSurround( css::text::WrapTextMode_PARALLEL );
1586                                     }
1587                                     rFormat.LockModify();
1588                                     rFormat.SetFormatAttr( aAttr );
1589                                     rFormat.UnlockModify();
1590                                 }
1591                             }
1592                             else
1593                             {
1594                                 if ( pAgainObj1 == pAnchoredObj )
1595                                     pAgainObj2 = pAnchoredObj;
1596                                 pAgainObj1 = pAnchoredObj;
1597                             }
1598                         }
1599 
1600                         if ( !pFrame->GetDrawObjs() )
1601                             break;
1602                         if ( pFrame->GetDrawObjs()->size() < nCnt )
1603                         {
1604                             --nCnt;
1605                             // Do not increment index, in this case
1606                             continue;
1607                         }
1608                     }
1609                     ++i;
1610                 }
1611 
1612                 // #i28701# - restart layout process, if
1613                 // requested by floating screen object formatting
1614                 if (bRestartLayoutProcess
1615                     // tdf#142080 if it was already on next page, and still is,
1616                     // ignore restart, as restart could cause infinite loop
1617                     && (wasFrameLowerOfLay || pLay->IsAnLower(pFrame)))
1618                 {
1619                     pFrame = pLay->ContainsAny();
1620                     pAgainObj1 = nullptr;
1621                     pAgainObj2 = nullptr;
1622                     continue;
1623                 }
1624 
1625                 // #i28701# - format anchor frame after its objects
1626                 // are formatted, if the wrapping style influence has to be considered.
1627                 if ( pLay->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) )
1628                 {
1629                     pFrame->Calc(pRenderContext);
1630                 }
1631 
1632                 if ( bAgain )
1633                 {
1634                     pFrame = pLay->ContainsContent();
1635                     if ( pFrame && pFrame->IsInTab() )
1636                         pFrame = pFrame->FindTabFrame();
1637                     if( pFrame && pFrame->IsInSct() )
1638                     {
1639                         SwSectionFrame* pTmp = pFrame->FindSctFrame();
1640                         if( pTmp != pLay && pLay->IsAnLower( pTmp ) )
1641                             pFrame = pTmp;
1642                     }
1643 
1644                     if ( pFrame == pLoopControlCond )
1645                         ++nLoopControlRuns;
1646                     else
1647                     {
1648                         nLoopControlRuns = 0;
1649                         pLoopControlCond = pFrame;
1650                     }
1651 
1652                     if ( nLoopControlRuns < nLoopControlMax )
1653                         continue;
1654 
1655                     OSL_FAIL( "LoopControl in CalcContent" );
1656                 }
1657             }
1658             if ( pFrame->IsTabFrame() )
1659             {
1660                 if ( static_cast<SwTabFrame*>(pFrame)->IsFollow() )
1661                     static_cast<SwTabFrame*>(pFrame)->m_bLockBackMove = false;
1662             }
1663 
1664             pFrame = bPrevInvalid ? pTmpPrev : pFrame->FindNext();
1665             if( !bPrevInvalid && pFrame && pFrame->IsSctFrame() && pSect )
1666             {
1667                 // Empty SectionFrames could be present here
1668                 while( pFrame && pFrame->IsSctFrame() && !static_cast<SwSectionFrame*>(pFrame)->GetSection() )
1669                     pFrame = pFrame->FindNext();
1670 
1671                 // If FindNext returns the Follow of the original Area, we want to
1672                 // continue with this content as long as it flows back.
1673                 if( pFrame && pFrame->IsSctFrame() && ( pFrame == pSect->GetFollow() ||
1674                     static_cast<SwSectionFrame*>(pFrame)->IsAnFollow( pSect ) ) )
1675                 {
1676                     pFrame = static_cast<SwSectionFrame*>(pFrame)->ContainsAny();
1677                     if( pFrame )
1678                         pFrame->InvalidatePos_();
1679                 }
1680             }
1681           // Stay in the pLay.
1682           // Except for SectionFrames with Follow: the first ContentFrame of the
1683           // Follow will be formatted, so that it gets a chance to move back
1684           // into the pLay.  Continue as long as these Frames land in pLay.
1685         } while ( pFrame &&
1686                   ( pLay->IsAnLower( pFrame ) ||
1687                     ( pSect &&
1688                       ( ( pSect->HasFollow() &&
1689                           ( pLay->IsAnLower( pLast ) ||
1690                             ( pLast->IsInSct() &&
1691                               pLast->FindSctFrame()->IsAnFollow(pSect) ) ) &&
1692                           pSect->GetFollow()->IsAnLower( pFrame )  ) ||
1693                         ( pFrame->IsInSct() &&
1694                           pFrame->FindSctFrame()->IsAnFollow( pSect ) ) ) ) ) );
1695         if( pSect )
1696         {
1697             if( bCollect )
1698             {
1699                 pLay->GetFormat()->GetDoc()->getIDocumentLayoutAccess().GetLayouter()->InsertEndnotes(pSect);
1700                 pSect->CalcFootnoteContent();
1701             }
1702             if( pSect->HasFollow() )
1703             {
1704                 SwSectionFrame* pNxt = pSect->GetFollow();
1705                 while( pNxt && !pNxt->ContainsContent() )
1706                     pNxt = pNxt->GetFollow();
1707                 if( pNxt )
1708                     pNxt->CalcFootnoteContent();
1709             }
1710             if( bCollect )
1711             {
1712                 pFrame = pLay->ContainsAny();
1713                 bCollect = false;
1714                 if( pFrame )
1715                     continue;
1716             }
1717         }
1718         break;
1719     }
1720     while( true );
1721 }
1722 
MakeObjPos()1723 void SwFlyFrame::MakeObjPos()
1724 {
1725     if ( isFrameAreaPositionValid() )
1726         return;
1727 
1728     vcl::RenderContext* pRenderContext = getRootFrame()->GetCurrShell()->GetOut();
1729     setFrameAreaPositionValid(true);
1730 
1731     // use new class to position object
1732     GetAnchorFrame()->Calc(pRenderContext);
1733     objectpositioning::SwToLayoutAnchoredObjectPosition
1734             aObjPositioning( *GetVirtDrawObj() );
1735     aObjPositioning.CalcPosition();
1736 
1737     // #i58280#
1738     // update relative position
1739     SetCurrRelPos( aObjPositioning.GetRelPos() );
1740 
1741     {
1742         SwRectFnSet aRectFnSet(GetAnchorFrame());
1743         SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
1744         aFrm.Pos( aObjPositioning.GetRelPos() );
1745         aFrm.Pos() += aRectFnSet.GetPos(GetAnchorFrame()->getFrameArea());
1746     }
1747 
1748     // #i69335#
1749     InvalidateObjRectWithSpaces();
1750 }
1751 
MakePrtArea(const SwBorderAttrs & rAttrs)1752 void SwFlyFrame::MakePrtArea( const SwBorderAttrs &rAttrs )
1753 {
1754     if ( !isFramePrintAreaValid() )
1755     {
1756         setFramePrintAreaValid(true);
1757 
1758         // consider vertical layout
1759         SwRectFnSet aRectFnSet(this);
1760         aRectFnSet.SetXMargins( *this, rAttrs.CalcLeftLine(),
1761                                         rAttrs.CalcRightLine() );
1762         aRectFnSet.SetYMargins( *this, rAttrs.CalcTopLine(),
1763                                         rAttrs.CalcBottomLine() );
1764     }
1765 }
1766 
MakeContentPos(const SwBorderAttrs & rAttrs)1767 void SwFlyFrame::MakeContentPos( const SwBorderAttrs &rAttrs )
1768 {
1769     if ( m_bValidContentPos )
1770         return;
1771 
1772     m_bValidContentPos = true;
1773 
1774     const SwTwips nUL = rAttrs.CalcTopLine()  + rAttrs.CalcBottomLine();
1775     Size aRelSize( CalcRel( GetFormat()->GetFrameSize() ) );
1776 
1777     SwRectFnSet aRectFnSet(this);
1778     tools::Long nMinHeight = 0;
1779     if( IsMinHeight() )
1780         nMinHeight = aRectFnSet.IsVert() ? aRelSize.Width() : aRelSize.Height();
1781 
1782     Point aNewContentPos = getFramePrintArea().Pos();
1783     const SdrTextVertAdjust nAdjust = GetFormat()->GetTextVertAdjust().GetValue();
1784 
1785     if( nAdjust != SDRTEXTVERTADJUST_TOP )
1786     {
1787         const SwTwips nContentHeight = CalcContentHeight(&rAttrs, nMinHeight, nUL);
1788         SwTwips nDiff = 0;
1789 
1790         if( nContentHeight != 0)
1791             nDiff = aRectFnSet.GetHeight(getFramePrintArea()) - nContentHeight;
1792 
1793         if( nDiff > 0 )
1794         {
1795             if( nAdjust == SDRTEXTVERTADJUST_CENTER )
1796             {
1797                 if( aRectFnSet.IsVertL2R() )
1798                     aNewContentPos.setX(aNewContentPos.getX() + nDiff/2);
1799                 else if( aRectFnSet.IsVert() )
1800                     aNewContentPos.setX(aNewContentPos.getX() - nDiff/2);
1801                 else
1802                     aNewContentPos.setY(aNewContentPos.getY() + nDiff/2);
1803             }
1804             else if( nAdjust == SDRTEXTVERTADJUST_BOTTOM )
1805             {
1806                 if( aRectFnSet.IsVertL2R() )
1807                     aNewContentPos.setX(aNewContentPos.getX() + nDiff);
1808                 else if( aRectFnSet.IsVert() )
1809                     aNewContentPos.setX(aNewContentPos.getX() - nDiff);
1810                 else
1811                     aNewContentPos.setY(aNewContentPos.getY() + nDiff);
1812             }
1813         }
1814     }
1815     if( aNewContentPos != ContentPos() )
1816     {
1817         ContentPos() = aNewContentPos;
1818         for( SwFrame *pFrame = Lower(); pFrame; pFrame = pFrame->GetNext())
1819         {
1820             pFrame->InvalidatePos();
1821         }
1822     }
1823 
1824 }
1825 
InvalidateContentPos()1826 void SwFlyFrame::InvalidateContentPos()
1827 {
1828     m_bValidContentPos = false;
1829     Invalidate_();
1830 }
1831 
SelectionHasChanged(SwFEShell * pShell)1832 void SwFlyFrame::SelectionHasChanged(SwFEShell* pShell)
1833 {
1834     SwWrtShell* pWrtSh = dynamic_cast< SwWrtShell* >(pShell);
1835     if (pWrtSh == nullptr)
1836         return;
1837 
1838     UpdateUnfloatButton(pWrtSh, IsShowUnfloatButton(pWrtSh));
1839 }
1840 
IsShowUnfloatButton(SwWrtShell * pWrtSh) const1841 bool SwFlyFrame::IsShowUnfloatButton(SwWrtShell* pWrtSh) const
1842 {
1843     if (pWrtSh == nullptr)
1844         return false;
1845 
1846     // In read only mode we don't allow unfloat operation
1847     if (pWrtSh->GetViewOptions()->IsReadonly())
1848         return false;
1849 
1850     const SdrObject *pObj = GetFrameFormat().FindRealSdrObject();
1851     if (pObj == nullptr)
1852         return false;
1853 
1854     // SwFlyFrame itself can mean images, ole objects, etc, but we interested in actual text frames
1855     if (SwFEShell::GetObjCntType(*pObj) != OBJCNT_FLY)
1856         return false;
1857 
1858     // We show the button only for the selected text frame
1859     SwDrawView *pView = pWrtSh->Imp()->GetDrawView();
1860     if (pView == nullptr)
1861         return false;
1862 
1863     // Fly frame can be selected only alone
1864     if (pView->GetMarkedObjectList().GetMarkCount() != 1)
1865         return false;
1866 
1867     if(!pView->IsObjMarked(pObj))
1868         return false;
1869 
1870     // A frame is a floating table if there is only one table (and maybe some whitespaces) inside it
1871     int nTableCount = 0;
1872     const SwFrame* pLower = GetLower();
1873     const SwTabFrame* pTable = nullptr;
1874     while (pLower)
1875     {
1876         if (pLower->IsTabFrame())
1877         {
1878             pTable = static_cast<const SwTabFrame*>(pLower);
1879             ++nTableCount;
1880             if (nTableCount > 1 || pTable == nullptr)
1881                 return false;
1882         }
1883 
1884         if (pLower->IsTextFrame())
1885         {
1886             const SwTextFrame* pTextFrame = static_cast<const SwTextFrame*>(pLower);
1887             if (!pTextFrame->GetText().trim().isEmpty())
1888                 return false;
1889         }
1890         pLower = pLower->GetNext();
1891     }
1892 
1893     if (nTableCount != 1 || pTable == nullptr)
1894         return false;
1895 
1896     // Show the unfold button only for multipage tables
1897     const SwBodyFrame *pBody = GetAnchorFrame()->FindBodyFrame();
1898     if (pBody == nullptr)
1899         return false;
1900 
1901     tools::Long nBodyHeight = pBody->getFrameArea().Height();
1902     tools::Long nTableHeight = pTable->getFrameArea().Height();
1903     tools::Long nFrameOffset = std::abs(GetAnchorFrame()->getFrameArea().Top() - pBody->getFrameArea().Top());
1904 
1905     return nBodyHeight < nTableHeight + nFrameOffset;
1906 }
1907 
ActiveUnfloatButton(SwWrtShell * pWrtSh)1908 void SwFlyFrame::ActiveUnfloatButton(SwWrtShell* pWrtSh)
1909 {
1910     SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
1911     SwFrameControlsManager& rMngr = rEditWin.GetFrameControlsManager();
1912     SwFrameControlPtr pControl = rMngr.GetControl(FrameControlType::FloatingTable, this);
1913     if (pControl && pControl->GetWindow())
1914     {
1915         pControl->GetWindow()->MouseButtonDown(MouseEvent());
1916     }
1917 }
1918 
UpdateUnfloatButton(SwWrtShell * pWrtSh,bool bShow) const1919 void SwFlyFrame::UpdateUnfloatButton(SwWrtShell* pWrtSh, bool bShow) const
1920 {
1921     if (pWrtSh == nullptr)
1922         return;
1923 
1924     SwEditWin& rEditWin = pWrtSh->GetView().GetEditWin();
1925     SwFrameControlsManager& rMngr = rEditWin.GetFrameControlsManager();
1926     Point aTopRightPixel = rEditWin.LogicToPixel( getFrameArea().TopRight() );
1927     rMngr.SetUnfloatTableButton(this, bShow,  aTopRightPixel);
1928 }
1929 
Grow_(SwTwips nDist,bool bTst)1930 SwTwips SwFlyFrame::Grow_( SwTwips nDist, bool bTst )
1931 {
1932     SwRectFnSet aRectFnSet(this);
1933     if ( Lower() && !IsColLocked() && !HasFixSize() )
1934     {
1935         SwTwips nSize = aRectFnSet.GetHeight(getFrameArea());
1936         if( nSize > 0 && nDist > ( LONG_MAX - nSize ) )
1937             nDist = LONG_MAX - nSize;
1938 
1939         if ( nDist <= 0 )
1940             return 0;
1941 
1942         if ( Lower()->IsColumnFrame() )
1943         {   // If it's a Column Frame, the Format takes control of the
1944             // resizing (due to the adjustment).
1945             if ( !bTst )
1946             {
1947                 // #i28701# - unlock position of Writer fly frame
1948                 UnlockPosition();
1949                 InvalidatePos_();
1950                 InvalidateSize();
1951             }
1952             return 0;
1953         }
1954 
1955         if ( !bTst )
1956         {
1957             const SwRect aOld( GetObjRectWithSpaces() );
1958             InvalidateSize_();
1959             const bool bOldLock = m_bLocked;
1960             Unlock();
1961             if ( IsFlyFreeFrame() )
1962             {
1963                 // #i37068# - no format of position here
1964                 // and prevent move in method <CheckClip(..)>.
1965                 // This is needed to prevent layout loop caused by nested
1966                 // Writer fly frames - inner Writer fly frames format its
1967                 // anchor, which grows/shrinks the outer Writer fly frame.
1968                 // Note: position will be invalidated below.
1969                 setFrameAreaPositionValid(true);
1970 
1971                 // #i55416#
1972                 // Suppress format of width for autowidth frame, because the
1973                 // format of the width would call <SwTextFrame::CalcFitToContent()>
1974                 // for the lower frame, which initiated this grow.
1975                 const bool bOldFormatHeightOnly = m_bFormatHeightOnly;
1976                 const SwFormatFrameSize& rFrameSz = GetFormat()->GetFrameSize();
1977                 if ( rFrameSz.GetWidthSizeType() != SwFrameSize::Fixed )
1978                 {
1979                     m_bFormatHeightOnly = true;
1980                 }
1981                 SwViewShell* pSh = getRootFrame()->GetCurrShell();
1982                 if (pSh)
1983                 {
1984                     static_cast<SwFlyFreeFrame*>(this)->SetNoMoveOnCheckClip( true );
1985                     static_cast<SwFlyFreeFrame*>(this)->SwFlyFreeFrame::MakeAll(pSh->GetOut());
1986                     static_cast<SwFlyFreeFrame*>(this)->SetNoMoveOnCheckClip( false );
1987                 }
1988                 // #i55416#
1989                 if ( rFrameSz.GetWidthSizeType() != SwFrameSize::Fixed )
1990                 {
1991                     m_bFormatHeightOnly = bOldFormatHeightOnly;
1992                 }
1993             }
1994             else
1995                 MakeAll(getRootFrame()->GetCurrShell()->GetOut());
1996             InvalidateSize_();
1997             InvalidatePos();
1998             if ( bOldLock )
1999                 Lock();
2000             const SwRect aNew( GetObjRectWithSpaces() );
2001             if ( aOld != aNew )
2002                 ::Notify( this, FindPageFrame(), aOld );
2003             return aRectFnSet.GetHeight(aNew)-aRectFnSet.GetHeight(aOld);
2004         }
2005         return nDist;
2006     }
2007     return 0;
2008 }
2009 
Shrink_(SwTwips nDist,bool bTst)2010 SwTwips SwFlyFrame::Shrink_( SwTwips nDist, bool bTst )
2011 {
2012     if( Lower() && !IsColLocked() && !HasFixSize() )
2013     {
2014         SwRectFnSet aRectFnSet(this);
2015         SwTwips nHeight = aRectFnSet.GetHeight(getFrameArea());
2016         if ( nDist > nHeight )
2017             nDist = nHeight;
2018 
2019         SwTwips nVal = nDist;
2020         if ( IsMinHeight() )
2021         {
2022             const SwFormatFrameSize& rFormatSize = GetFormat()->GetFrameSize();
2023             SwTwips nFormatHeight = aRectFnSet.IsVert() ? rFormatSize.GetWidth() : rFormatSize.GetHeight();
2024 
2025             nVal = std::min( nDist, nHeight - nFormatHeight );
2026         }
2027 
2028         if ( nVal <= 0 )
2029             return 0;
2030 
2031         if ( Lower()->IsColumnFrame() )
2032         {   // If it's a Column Frame, the Format takes control of the
2033             // resizing (due to the adjustment).
2034             if ( !bTst )
2035             {
2036                 SwRect aOld( GetObjRectWithSpaces() );
2037 
2038                 {
2039                     SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
2040                     aRectFnSet.SetHeight( aFrm, nHeight - nVal );
2041                 }
2042 
2043                 // #i68520#
2044                 if ( nHeight - nVal != 0 )
2045                 {
2046                     InvalidateObjRectWithSpaces();
2047                 }
2048 
2049                 nHeight = aRectFnSet.GetHeight(getFramePrintArea());
2050 
2051                 {
2052                     SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(*this);
2053                     aRectFnSet.SetHeight( aPrt, nHeight - nVal );
2054                 }
2055 
2056                 InvalidatePos_();
2057                 InvalidateSize();
2058                 ::Notify( this, FindPageFrame(), aOld );
2059                 NotifyDrawObj();
2060                 if ( GetAnchorFrame()->IsInFly() )
2061                     AnchorFrame()->FindFlyFrame()->Shrink( nDist, bTst );
2062             }
2063             return 0;
2064         }
2065 
2066         if ( !bTst )
2067         {
2068             const SwRect aOld( GetObjRectWithSpaces() );
2069             InvalidateSize_();
2070             const bool bOldLocked = m_bLocked;
2071             Unlock();
2072             if ( IsFlyFreeFrame() )
2073             {
2074                 // #i37068# - no format of position here
2075                 // and prevent move in method <CheckClip(..)>.
2076                 // This is needed to prevent layout loop caused by nested
2077                 // Writer fly frames - inner Writer fly frames format its
2078                 // anchor, which grows/shrinks the outer Writer fly frame.
2079                 // Note: position will be invalidated below.
2080                 setFrameAreaPositionValid(true);
2081 
2082                 // #i55416#
2083                 // Suppress format of width for autowidth frame, because the
2084                 // format of the width would call <SwTextFrame::CalcFitToContent()>
2085                 // for the lower frame, which initiated this shrink.
2086                 const bool bOldFormatHeightOnly = m_bFormatHeightOnly;
2087                 const SwFormatFrameSize& rFrameSz = GetFormat()->GetFrameSize();
2088                 if ( rFrameSz.GetWidthSizeType() != SwFrameSize::Fixed )
2089                 {
2090                     m_bFormatHeightOnly = true;
2091                 }
2092                 static_cast<SwFlyFreeFrame*>(this)->SetNoMoveOnCheckClip( true );
2093                 static_cast<SwFlyFreeFrame*>(this)->SwFlyFreeFrame::MakeAll(getRootFrame()->GetCurrShell()->GetOut());
2094                 static_cast<SwFlyFreeFrame*>(this)->SetNoMoveOnCheckClip( false );
2095                 // #i55416#
2096                 if ( rFrameSz.GetWidthSizeType() != SwFrameSize::Fixed )
2097                 {
2098                     m_bFormatHeightOnly = bOldFormatHeightOnly;
2099                 }
2100             }
2101             else
2102                 MakeAll(getRootFrame()->GetCurrShell()->GetOut());
2103             InvalidateSize_();
2104             InvalidatePos();
2105             if ( bOldLocked )
2106                 Lock();
2107             const SwRect aNew( GetObjRectWithSpaces() );
2108             if ( aOld != aNew )
2109             {
2110                 ::Notify( this, FindPageFrame(), aOld );
2111                 if ( GetAnchorFrame()->IsInFly() )
2112                     AnchorFrame()->FindFlyFrame()->Shrink( nDist, bTst );
2113             }
2114             return aRectFnSet.GetHeight(aOld) -
2115                    aRectFnSet.GetHeight(aNew);
2116         }
2117         return nVal;
2118     }
2119     return 0;
2120 }
2121 
ChgSize(const Size & aNewSize)2122 Size SwFlyFrame::ChgSize( const Size& aNewSize )
2123 {
2124     // #i53298#
2125     // If the fly frame anchored at-paragraph or at-character contains an OLE
2126     // object, assure that the new size fits into the current clipping area
2127     // of the fly frame
2128     Size aAdjustedNewSize( aNewSize );
2129     {
2130         if ( dynamic_cast<SwFlyAtContentFrame*>(this) &&
2131              Lower() && dynamic_cast<SwNoTextFrame*>(Lower()) &&
2132              static_cast<SwNoTextFrame*>(Lower())->GetNode()->GetOLENode() )
2133         {
2134             SwRect aClipRect;
2135             ::CalcClipRect( GetVirtDrawObj(), aClipRect, false );
2136             if ( aAdjustedNewSize.Width() > aClipRect.Width() )
2137             {
2138                 aAdjustedNewSize.setWidth( aClipRect.Width() );
2139             }
2140             if ( aAdjustedNewSize.Height() > aClipRect.Height() )
2141             {
2142                 aAdjustedNewSize.setWidth( aClipRect.Height() );
2143             }
2144         }
2145     }
2146 
2147     if ( aAdjustedNewSize != getFrameArea().SSize() )
2148     {
2149         SwFrameFormat *pFormat = GetFormat();
2150         SwFormatFrameSize aSz( pFormat->GetFrameSize() );
2151         aSz.SetWidth( aAdjustedNewSize.Width() );
2152         aSz.SetHeight( aAdjustedNewSize.Height() );
2153         // go via the Doc for UNDO
2154         pFormat->GetDoc()->SetAttr( aSz, *pFormat );
2155         return aSz.GetSize();
2156     }
2157     else
2158         return getFrameArea().SSize();
2159 }
2160 
IsLowerOf(const SwLayoutFrame * pUpperFrame) const2161 bool SwFlyFrame::IsLowerOf( const SwLayoutFrame* pUpperFrame ) const
2162 {
2163     OSL_ENSURE( GetAnchorFrame(), "8-( Fly is lost in Space." );
2164     const SwFrame* pFrame = GetAnchorFrame();
2165     do
2166     {
2167         if ( pFrame == pUpperFrame )
2168             return true;
2169         pFrame = pFrame->IsFlyFrame()
2170                ? static_cast<const SwFlyFrame*>(pFrame)->GetAnchorFrame()
2171                : pFrame->GetUpper();
2172     } while ( pFrame );
2173     return false;
2174 }
2175 
Cut()2176 void SwFlyFrame::Cut()
2177 {
2178 }
2179 
AppendFly(SwFlyFrame * pNew)2180 void SwFrame::AppendFly( SwFlyFrame *pNew )
2181 {
2182     if (!m_pDrawObjs)
2183     {
2184         m_pDrawObjs.reset(new SwSortedObjs());
2185     }
2186     m_pDrawObjs->Insert( *pNew );
2187     pNew->ChgAnchorFrame( this );
2188 
2189     // Register at the page
2190     // If there's none present, register via SwPageFrame::PreparePage
2191     SwPageFrame* pPage = FindPageFrame();
2192     if ( pPage != nullptr )
2193     {
2194         pPage->AppendFlyToPage( pNew );
2195     }
2196 }
2197 
RemoveFly(SwFlyFrame * pToRemove)2198 void SwFrame::RemoveFly( SwFlyFrame *pToRemove )
2199 {
2200     // Deregister from the page
2201     // Could already have happened, if the page was already destructed
2202     SwPageFrame *pPage = pToRemove->FindPageFrame();
2203     if ( pPage && pPage->GetSortedObjs() )
2204     {
2205         pPage->RemoveFlyFromPage( pToRemove );
2206     }
2207     // #i73201#
2208     else
2209     {
2210         if ( pToRemove->IsAccessibleFrame() &&
2211              pToRemove->GetFormat() &&
2212              !pToRemove->IsFlyInContentFrame() )
2213         {
2214             SwRootFrame *pRootFrame = getRootFrame();
2215             if( pRootFrame && pRootFrame->IsAnyShellAccessible() )
2216             {
2217                 SwViewShell *pVSh = pRootFrame->GetCurrShell();
2218                 if( pVSh && pVSh->Imp() )
2219                 {
2220                     pVSh->Imp()->DisposeAccessibleFrame( pToRemove );
2221                 }
2222             }
2223         }
2224     }
2225 
2226     m_pDrawObjs->Remove(*pToRemove);
2227     if (!m_pDrawObjs->size())
2228     {
2229         m_pDrawObjs.reset();
2230     }
2231 
2232     pToRemove->ChgAnchorFrame( nullptr );
2233 
2234     if ( !pToRemove->IsFlyInContentFrame() && GetUpper() && IsInTab() )//MA_FLY_HEIGHT
2235         GetUpper()->InvalidateSize();
2236 }
2237 
AppendDrawObj(SwAnchoredObject & _rNewObj)2238 void SwFrame::AppendDrawObj( SwAnchoredObject& _rNewObj )
2239 {
2240     assert(!m_pDrawObjs || m_pDrawObjs->is_sorted());
2241 
2242     if ( dynamic_cast<const SwAnchoredDrawObject*>( &_rNewObj) ==  nullptr )
2243     {
2244         OSL_FAIL( "SwFrame::AppendDrawObj(..) - anchored object of unexpected type -> object not appended" );
2245         return;
2246     }
2247 
2248     if ( dynamic_cast<const SwDrawVirtObj*>(_rNewObj.GetDrawObj()) ==  nullptr &&
2249          _rNewObj.GetAnchorFrame() && _rNewObj.GetAnchorFrame() != this )
2250     {
2251         assert(!m_pDrawObjs || m_pDrawObjs->is_sorted());
2252         // perform disconnect from layout, if 'master' drawing object is appended
2253         // to a new frame.
2254         static_cast<SwDrawContact*>(::GetUserCall( _rNewObj.GetDrawObj() ))->
2255                                                 DisconnectFromLayout( false );
2256         assert(!m_pDrawObjs || m_pDrawObjs->is_sorted());
2257     }
2258 
2259     if ( _rNewObj.GetAnchorFrame() != this )
2260     {
2261         if (!m_pDrawObjs)
2262         {
2263             m_pDrawObjs.reset(new SwSortedObjs());
2264         }
2265         m_pDrawObjs->Insert(_rNewObj);
2266         _rNewObj.ChgAnchorFrame( this );
2267     }
2268 
2269     // #i113730#
2270     // Assure the control objects and group objects containing controls are on the control layer
2271     if ( ::CheckControlLayer( _rNewObj.DrawObj() ) )
2272     {
2273         const IDocumentDrawModelAccess& rIDDMA = getIDocumentDrawModelAccess();
2274         const SdrLayerID aCurrentLayer(_rNewObj.DrawObj()->GetLayer());
2275         const SdrLayerID aControlLayerID(rIDDMA.GetControlsId());
2276         const SdrLayerID aInvisibleControlLayerID(rIDDMA.GetInvisibleControlsId());
2277 
2278         if(aCurrentLayer != aControlLayerID && aCurrentLayer != aInvisibleControlLayerID)
2279         {
2280             if ( aCurrentLayer == rIDDMA.GetInvisibleHellId() ||
2281                  aCurrentLayer == rIDDMA.GetInvisibleHeavenId() )
2282             {
2283                 _rNewObj.DrawObj()->SetLayer(aInvisibleControlLayerID);
2284             }
2285             else
2286             {
2287                 _rNewObj.DrawObj()->SetLayer(aControlLayerID);
2288             }
2289             //The layer is part of the key used to sort the obj, so update
2290             //its position if the layer changed.
2291             m_pDrawObjs->Update(_rNewObj);
2292         }
2293     }
2294 
2295     // no direct positioning needed, but invalidate the drawing object position
2296     _rNewObj.InvalidateObjPos();
2297 
2298     // register at page frame
2299     SwPageFrame* pPage = FindPageFrame();
2300     if ( pPage )
2301     {
2302         pPage->AppendDrawObjToPage( _rNewObj );
2303     }
2304 
2305     // Notify accessible layout.
2306     SwViewShell* pSh = getRootFrame()->GetCurrShell();
2307     if( pSh )
2308     {
2309         SwRootFrame* pLayout = getRootFrame();
2310         if( pLayout && pLayout->IsAnyShellAccessible() )
2311         {
2312             pSh->Imp()->AddAccessibleObj( _rNewObj.GetDrawObj() );
2313         }
2314     }
2315 
2316     assert(!m_pDrawObjs || m_pDrawObjs->is_sorted());
2317 }
2318 
RemoveDrawObj(SwAnchoredObject & _rToRemoveObj)2319 void SwFrame::RemoveDrawObj( SwAnchoredObject& _rToRemoveObj )
2320 {
2321     // Notify accessible layout.
2322     SwViewShell* pSh = getRootFrame()->GetCurrShell();
2323     if( pSh )
2324     {
2325         SwRootFrame* pLayout = getRootFrame();
2326         if (pLayout && pLayout->IsAnyShellAccessible())
2327             pSh->Imp()->DisposeAccessibleObj(_rToRemoveObj.GetDrawObj(), false);
2328     }
2329 
2330     // deregister from page frame
2331     SwPageFrame* pPage = _rToRemoveObj.GetPageFrame();
2332     if ( pPage && pPage->GetSortedObjs() )
2333         pPage->RemoveDrawObjFromPage( _rToRemoveObj );
2334 
2335     m_pDrawObjs->Remove(_rToRemoveObj);
2336     if (!m_pDrawObjs->size())
2337     {
2338         m_pDrawObjs.reset();
2339     }
2340     _rToRemoveObj.ChgAnchorFrame( nullptr );
2341 
2342     assert(!m_pDrawObjs || m_pDrawObjs->is_sorted());
2343 }
2344 
InvalidateObjs(const bool _bNoInvaOfAsCharAnchoredObjs)2345 void SwFrame::InvalidateObjs( const bool _bNoInvaOfAsCharAnchoredObjs )
2346 {
2347     if ( !GetDrawObjs() )
2348         return;
2349 
2350     // #i26945# - determine page the frame is on,
2351     // in order to check, if anchored object is registered at the same
2352     // page.
2353     const SwPageFrame* pPageFrame = FindPageFrame();
2354     // #i28701# - re-factoring
2355     for (SwAnchoredObject* pAnchoredObj : *GetDrawObjs())
2356     {
2357         if ( _bNoInvaOfAsCharAnchoredObjs &&
2358              (pAnchoredObj->GetFrameFormat().GetAnchor().GetAnchorId()
2359                 == RndStdIds::FLY_AS_CHAR) )
2360         {
2361             continue;
2362         }
2363         // #i26945# - no invalidation, if anchored object
2364         // isn't registered at the same page and instead is registered at
2365         // the page, where its anchor character text frame is on.
2366         if ( pAnchoredObj->GetPageFrame() &&
2367              pAnchoredObj->GetPageFrame() != pPageFrame )
2368         {
2369             SwTextFrame* pAnchorCharFrame = pAnchoredObj->FindAnchorCharFrame();
2370             if ( pAnchorCharFrame &&
2371                  pAnchoredObj->GetPageFrame() == pAnchorCharFrame->FindPageFrame() )
2372             {
2373                 continue;
2374             }
2375             // #115759# - unlock its position, if anchored
2376             // object isn't registered at the page, where its anchor
2377             // character text frame is on, respectively if it has no
2378             // anchor character text frame.
2379             else
2380             {
2381                 pAnchoredObj->UnlockPosition();
2382             }
2383         }
2384         // #i51474# - reset flag, that anchored object
2385         // has cleared environment, and unlock its position, if the anchored
2386         // object is registered at the same page as the anchor frame is on.
2387         if ( pAnchoredObj->ClearedEnvironment() &&
2388              pAnchoredObj->GetPageFrame() &&
2389              pAnchoredObj->GetPageFrame() == pPageFrame )
2390         {
2391             pAnchoredObj->UnlockPosition();
2392             pAnchoredObj->SetClearedEnvironment( false );
2393         }
2394         // distinguish between writer fly frames and drawing objects
2395         if ( auto pFly = dynamic_cast<SwFlyFrame*>( pAnchoredObj) )
2396         {
2397             pFly->Invalidate_();
2398             pFly->InvalidatePos_();
2399         }
2400         else
2401         {
2402             pAnchoredObj->InvalidateObjPos();
2403         }
2404     } // end of loop on objects, which are connected to the frame
2405 }
2406 
2407 // #i26945# - correct check, if anchored object is a lower
2408 // of the layout frame. E.g., anchor character text frame can be a follow text
2409 // frame.
2410 // #i44016# - add parameter <_bUnlockPosOfObjs> to
2411 // force an unlockposition call for the lower objects.
NotifyLowerObjs(const bool _bUnlockPosOfObjs)2412 void SwLayoutFrame::NotifyLowerObjs( const bool _bUnlockPosOfObjs )
2413 {
2414     // invalidate lower floating screen objects
2415     SwPageFrame* pPageFrame = FindPageFrame();
2416     if ( !(pPageFrame && pPageFrame->GetSortedObjs()) )
2417         return;
2418 
2419     SwSortedObjs& rObjs = *(pPageFrame->GetSortedObjs());
2420     for (SwAnchoredObject* pObj : rObjs)
2421     {
2422         // #i26945# - check, if anchored object is a lower
2423         // of the layout frame is changed to check, if its anchor frame
2424         // is a lower of the layout frame.
2425         // determine the anchor frame - usually it's the anchor frame,
2426         // for at-character/as-character anchored objects the anchor character
2427         // text frame is taken.
2428         const SwFrame* pAnchorFrame = pObj->GetAnchorFrameContainingAnchPos();
2429         if ( auto pFly = dynamic_cast<SwFlyFrame*>( pObj) )
2430         {
2431             if ( pFly->getFrameArea().Left() == FAR_AWAY )
2432                 continue;
2433 
2434             if ( pFly->IsAnLower( this ) )
2435                 continue;
2436 
2437             // #i26945# - use <pAnchorFrame> to check, if
2438             // fly frame is lower of layout frame resp. if fly frame is
2439             // at a different page registered as its anchor frame is on.
2440             const bool bLow = IsAnLower( pAnchorFrame );
2441             if ( bLow || pAnchorFrame->FindPageFrame() != pPageFrame )
2442             {
2443                 pFly->Invalidate_( pPageFrame );
2444                 if ( !bLow || pFly->IsFlyAtContentFrame() )
2445                 {
2446                     // #i44016#
2447                     if ( _bUnlockPosOfObjs )
2448                     {
2449                         pFly->UnlockPosition();
2450                     }
2451                     pFly->InvalidatePos_();
2452                 }
2453                 else
2454                     pFly->InvalidatePrt_();
2455             }
2456         }
2457         else
2458         {
2459             OSL_ENSURE( dynamic_cast<const SwAnchoredDrawObject*>( pObj) !=  nullptr,
2460                     "<SwLayoutFrame::NotifyFlys() - anchored object of unexpected type" );
2461             // #i26945# - use <pAnchorFrame> to check, if
2462             // fly frame is lower of layout frame resp. if fly frame is
2463             // at a different page registered as its anchor frame is on.
2464             if ( IsAnLower( pAnchorFrame ) ||
2465                  pAnchorFrame->FindPageFrame() != pPageFrame )
2466             {
2467                 // #i44016#
2468                 if ( _bUnlockPosOfObjs )
2469                 {
2470                     pObj->UnlockPosition();
2471                 }
2472                 pObj->InvalidateObjPos();
2473             }
2474         }
2475     }
2476 }
2477 
NotifyDrawObj()2478 void SwFlyFrame::NotifyDrawObj()
2479 {
2480     SwVirtFlyDrawObj* pObj = GetVirtDrawObj();
2481     pObj->SetRect();
2482     pObj->SetRectsDirty();
2483     pObj->SetChanged();
2484     pObj->BroadcastObjectChange();
2485 
2486     if ( GetFormat()->GetSurround().IsContour() )
2487     {
2488         ClrContourCache( pObj );
2489     }
2490     else if(IsFlyFreeFrame() && static_cast< const SwFlyFreeFrame* >(this)->supportsAutoContour())
2491     {
2492         // RotateFlyFrame3: Also need to clear when changes happen
2493         // Caution: isTransformableSwFrame is already reset when resetting rotation, so
2494         // *additionally* reset in SwFlyFreeFrame::MakeAll when no more rotation
2495         ClrContourCache( pObj );
2496     }
2497 }
2498 
CalcRel(const SwFormatFrameSize & rSz) const2499 Size SwFlyFrame::CalcRel( const SwFormatFrameSize &rSz ) const
2500 {
2501     Size aRet( rSz.GetSize() );
2502 
2503     const SwFrame *pRel = IsFlyLayFrame() ? GetAnchorFrame() : GetAnchorFrame()->GetUpper();
2504     if( pRel ) // LAYER_IMPL
2505     {
2506         tools::Long nRelWidth = LONG_MAX, nRelHeight = LONG_MAX;
2507         const SwViewShell *pSh = getRootFrame()->GetCurrShell();
2508         if ( ( pRel->IsBodyFrame() || pRel->IsPageFrame() ) &&
2509              pSh && pSh->GetViewOptions()->getBrowseMode() &&
2510              pSh->VisArea().HasArea() )
2511         {
2512             nRelWidth  = pSh->GetBrowseWidth();
2513             nRelHeight = pSh->VisArea().Height();
2514             Size aBorder = pSh->GetOut()->PixelToLogic( pSh->GetBrowseBorder() );
2515             nRelWidth  = std::min( nRelWidth,  pRel->getFramePrintArea().Width() );
2516             nRelHeight -= 2*aBorder.Height();
2517             nRelHeight = std::min( nRelHeight, pRel->getFramePrintArea().Height() );
2518         }
2519 
2520         // At the moment only the "== PAGE_FRAME" and "!= PAGE_FRAME" cases are handled.
2521         // When size is a relative to page size, ignore size of SwBodyFrame.
2522         if (rSz.GetWidthPercentRelation() != text::RelOrientation::PAGE_FRAME)
2523             nRelWidth  = std::min( nRelWidth,  pRel->getFramePrintArea().Width() );
2524         else if ( pRel->IsPageFrame() )
2525             nRelWidth  = std::min( nRelWidth,  pRel->getFrameArea().Width() );
2526 
2527         if (rSz.GetHeightPercentRelation() != text::RelOrientation::PAGE_FRAME)
2528             nRelHeight = std::min( nRelHeight, pRel->getFramePrintArea().Height() );
2529         else if ( pRel->IsPageFrame() )
2530             nRelHeight = std::min( nRelHeight, pRel->getFrameArea().Height() );
2531 
2532         if( !pRel->IsPageFrame() )
2533         {
2534             const SwPageFrame* pPage = FindPageFrame();
2535             if( pPage )
2536             {
2537                 if (rSz.GetWidthPercentRelation() == text::RelOrientation::PAGE_FRAME)
2538                     // Ignore margins of pPage.
2539                     nRelWidth  = std::min( nRelWidth,  pPage->getFrameArea().Width() );
2540                 else
2541                     nRelWidth  = std::min( nRelWidth,  pPage->getFramePrintArea().Width() );
2542                 if (rSz.GetHeightPercentRelation() == text::RelOrientation::PAGE_FRAME)
2543                     // Ignore margins of pPage.
2544                     nRelHeight = std::min( nRelHeight, pPage->getFrameArea().Height() );
2545                 else
2546                     nRelHeight = std::min( nRelHeight, pPage->getFramePrintArea().Height() );
2547             }
2548         }
2549 
2550         if ( rSz.GetWidthPercent() && rSz.GetWidthPercent() != SwFormatFrameSize::SYNCED )
2551             aRet.setWidth( nRelWidth * rSz.GetWidthPercent() / 100 );
2552         if ( rSz.GetHeightPercent() && rSz.GetHeightPercent() != SwFormatFrameSize::SYNCED )
2553             aRet.setHeight( nRelHeight * rSz.GetHeightPercent() / 100 );
2554 
2555         if ( rSz.GetWidthPercent() == SwFormatFrameSize::SYNCED )
2556         {
2557             aRet.setWidth( aRet.Width() * ( aRet.Height()) );
2558             aRet.setWidth( aRet.Width() / ( rSz.GetHeight()) );
2559         }
2560         else if ( rSz.GetHeightPercent() == SwFormatFrameSize::SYNCED )
2561         {
2562             aRet.setHeight( aRet.Height() * ( aRet.Width()) );
2563             aRet.setHeight( aRet.Height() / ( rSz.GetWidth()) );
2564         }
2565     }
2566     return aRet;
2567 }
2568 
lcl_CalcAutoWidth(const SwLayoutFrame & rFrame)2569 static SwTwips lcl_CalcAutoWidth( const SwLayoutFrame& rFrame )
2570 {
2571     SwTwips nRet = 0;
2572     SwTwips nMin = 0;
2573     const SwFrame* pFrame = rFrame.Lower();
2574 
2575     // No autowidth defined for columned frames
2576     if ( !pFrame || pFrame->IsColumnFrame() )
2577         return nRet;
2578 
2579     int nParagraphCount = 0;
2580     while ( pFrame )
2581     {
2582         nParagraphCount++;
2583         if ( pFrame->IsSctFrame() )
2584         {
2585             nMin = lcl_CalcAutoWidth( *static_cast<const SwSectionFrame*>(pFrame) );
2586         }
2587         if ( pFrame->IsTextFrame() )
2588         {
2589             nMin = const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pFrame))->CalcFitToContent();
2590             const SvxLRSpaceItem &rSpace =
2591                 static_cast<const SwTextFrame*>(pFrame)->GetTextNodeForParaProps()->GetSwAttrSet().GetLRSpace();
2592             if (!static_cast<const SwTextFrame*>(pFrame)->IsLocked())
2593                 nMin += rSpace.GetRight() + rSpace.GetTextLeft() + rSpace.GetTextFirstLineOffset();
2594         }
2595         else if ( pFrame->IsTabFrame() )
2596         {
2597             const SwFormatFrameSize& rTableFormatSz = static_cast<const SwTabFrame*>(pFrame)->GetTable()->GetFrameFormat()->GetFrameSize();
2598             if ( USHRT_MAX == rTableFormatSz.GetSize().Width() ||
2599                  text::HoriOrientation::NONE == static_cast<const SwTabFrame*>(pFrame)->GetFormat()->GetHoriOrient().GetHoriOrient() )
2600             {
2601                 const SwPageFrame* pPage = rFrame.FindPageFrame();
2602                 // auto width table
2603                 nMin = pFrame->GetUpper()->IsVertical() ?
2604                     pPage->getFramePrintArea().Height() :
2605                     pPage->getFramePrintArea().Width();
2606             }
2607             else
2608             {
2609                 nMin = rTableFormatSz.GetSize().Width();
2610             }
2611         }
2612 
2613         if ( nMin > nRet )
2614             nRet = nMin;
2615 
2616         pFrame = pFrame->GetNext();
2617     }
2618 
2619     // tdf#124423 In Microsoft compatibility mode: widen the frame to max (PrintArea of the frame it anchored to) if it contains at least 2 paragraphs,
2620     // or 1 paragraph wider than its parent area.
2621     if (rFrame.GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::FRAME_AUTOWIDTH_WITH_MORE_PARA))
2622     {
2623         const SwFrame* pFrameRect = rFrame.IsFlyFrame() ? static_cast<const SwFlyFrame*>(&rFrame)->GetAnchorFrame() : rFrame.Lower()->FindPageFrame();
2624         SwTwips nParentWidth = rFrame.IsVertical() ? pFrameRect->getFramePrintArea().Height() : pFrameRect->getFramePrintArea().Width();
2625         if (nParagraphCount > 1 || nRet > nParentWidth)
2626         {
2627             return nParentWidth;
2628         }
2629     }
2630 
2631     return nRet;
2632 }
2633 
2634 ///  #i13147# -  If called for paint and the <SwNoTextFrame> contains
2635 /// a graphic, load of intrinsic graphic has to be avoided.
GetContour(tools::PolyPolygon & rContour,const bool _bForPaint) const2636 bool SwFlyFrame::GetContour( tools::PolyPolygon&   rContour,
2637                            const bool _bForPaint ) const
2638 {
2639     vcl::RenderContext* pRenderContext = getRootFrame()->GetCurrShell()->GetOut();
2640     bool bRet = false;
2641     const bool bIsCandidate(Lower() && Lower()->IsNoTextFrame());
2642 
2643     if(bIsCandidate)
2644     {
2645         if(GetFormat()->GetSurround().IsContour())
2646         {
2647             SwNoTextNode *pNd = const_cast<SwNoTextNode*>(static_cast<const SwNoTextNode*>(static_cast<const SwNoTextFrame*>(Lower())->GetNode()));
2648             // #i13147# - determine <GraphicObject> instead of <Graphic>
2649             // in order to avoid load of graphic, if <SwNoTextNode> contains a graphic
2650             // node and method is called for paint.
2651             std::unique_ptr<GraphicObject> xTmpGrfObj;
2652             const GraphicObject* pGrfObj = nullptr;
2653             const SwGrfNode* pGrfNd = pNd->GetGrfNode();
2654             if ( pGrfNd && _bForPaint )
2655             {
2656                 pGrfObj = &(pGrfNd->GetGrfObj());
2657             }
2658             else
2659             {
2660                 xTmpGrfObj.reset(new GraphicObject(pNd->GetGraphic()));
2661                 pGrfObj = xTmpGrfObj.get();
2662             }
2663             assert(pGrfObj && "SwFlyFrame::GetContour() - No Graphic/GraphicObject found at <SwNoTextNode>.");
2664             if (pGrfObj->GetType() != GraphicType::NONE)
2665             {
2666                 if( !pNd->HasContour() )
2667                 {
2668                     //#i13147# - no <CreateContour> for a graphic
2669                     // during paint. Thus, return (value of <bRet> should be <false>).
2670                     if ( pGrfNd && _bForPaint )
2671                     {
2672                         OSL_FAIL( "SwFlyFrame::GetContour() - No Contour found at <SwNoTextNode> during paint." );
2673                         return bRet;
2674                     }
2675                     pNd->CreateContour();
2676                 }
2677                 pNd->GetContour( rContour );
2678                 // The Node holds the Polygon matching the original size of the graphic
2679                 // We need to include the scaling here
2680                 SwRect aClip;
2681                 SwRect aOrig;
2682                 Lower()->Calc(pRenderContext);
2683                 static_cast<const SwNoTextFrame*>(Lower())->GetGrfArea( aClip, &aOrig );
2684                 // #i13147# - copy method code <SvxContourDlg::ScaleContour(..)>
2685                 // in order to avoid that graphic has to be loaded for contour scale.
2686                 //SvxContourDlg::ScaleContour( rContour, aGrf, MapUnit::MapTwip, aOrig.SSize() );
2687                 {
2688                     OutputDevice*   pOutDev = Application::GetDefaultDevice();
2689                     const MapMode   aDispMap( MapUnit::MapTwip );
2690                     const MapMode   aGrfMap( pGrfObj->GetPrefMapMode() );
2691                     const Size      aGrfSize( pGrfObj->GetPrefSize() );
2692                     Size            aOrgSize;
2693                     Point           aNewPoint;
2694                     bool            bPixelMap = aGrfMap.GetMapUnit() == MapUnit::MapPixel;
2695 
2696                     if ( bPixelMap )
2697                         aOrgSize = pOutDev->PixelToLogic( aGrfSize, aDispMap );
2698                     else
2699                         aOrgSize = OutputDevice::LogicToLogic( aGrfSize, aGrfMap, aDispMap );
2700 
2701                     if ( aOrgSize.Width() && aOrgSize.Height() )
2702                     {
2703                         double fScaleX = static_cast<double>(aOrig.Width()) / aOrgSize.Width();
2704                         double fScaleY = static_cast<double>(aOrig.Height()) / aOrgSize.Height();
2705 
2706                         for ( sal_uInt16 j = 0, nPolyCount = rContour.Count(); j < nPolyCount; j++ )
2707                         {
2708                             tools::Polygon& rPoly = rContour[ j ];
2709 
2710                             for ( sal_uInt16 i = 0, nCount = rPoly.GetSize(); i < nCount; i++ )
2711                             {
2712                                 if ( bPixelMap )
2713                                     aNewPoint = pOutDev->PixelToLogic( rPoly[ i ], aDispMap  );
2714                                 else
2715                                     aNewPoint = OutputDevice::LogicToLogic( rPoly[ i ], aGrfMap, aDispMap  );
2716 
2717                                 rPoly[ i ] = Point( FRound( aNewPoint.getX() * fScaleX ), FRound( aNewPoint.getY() * fScaleY ) );
2718                             }
2719                         }
2720                     }
2721                 }
2722                 // destroy created <GraphicObject>.
2723                 xTmpGrfObj.reset();
2724                 rContour.Move( aOrig.Left(), aOrig.Top() );
2725                 if( !aClip.Width() )
2726                     aClip.Width( 1 );
2727                 if( !aClip.Height() )
2728                     aClip.Height( 1 );
2729                 rContour.Clip( aClip.SVRect() );
2730                 rContour.Optimize(PolyOptimizeFlags::CLOSE);
2731                 bRet = true;
2732             }
2733         }
2734         else
2735         {
2736             const SwFlyFreeFrame* pSwFlyFreeFrame(dynamic_cast< const SwFlyFreeFrame* >(this));
2737 
2738             if(nullptr != pSwFlyFreeFrame &&
2739                 pSwFlyFreeFrame->supportsAutoContour() &&
2740                 // isTransformableSwFrame already used in supportsAutoContour(), but
2741                 // better check twice when it may get changed there...
2742                 pSwFlyFreeFrame->isTransformableSwFrame())
2743             {
2744                 // RotateFlyFrame: use untransformed SwFrame to allow text floating around.
2745                 // Will be transformed below
2746                 const TransformableSwFrame* pTransformableSwFrame(pSwFlyFreeFrame->getTransformableSwFrame());
2747                 const SwRect aFrameArea(pTransformableSwFrame->getUntransformedFrameArea());
2748                 rContour = tools::PolyPolygon(tools::Polygon(aFrameArea.SVRect()));
2749                 bRet = (0 != rContour.Count());
2750             }
2751         }
2752 
2753         if(bRet && 0 != rContour.Count())
2754         {
2755             const SwFlyFreeFrame* pSwFlyFreeFrame(dynamic_cast< const SwFlyFreeFrame* >(this));
2756 
2757             if(nullptr != pSwFlyFreeFrame && pSwFlyFreeFrame->isTransformableSwFrame())
2758             {
2759                 // Need to adapt contour to transformation
2760                 basegfx::B2DVector aScale, aTranslate;
2761                 double fRotate, fShearX;
2762                 getFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
2763 
2764                 if(!basegfx::fTools::equalZero(fRotate))
2765                 {
2766                     basegfx::B2DPolyPolygon aSource(rContour.getB2DPolyPolygon());
2767                     const basegfx::B2DPoint aCenter(getFrameAreaTransformation() * basegfx::B2DPoint(0.5, 0.5));
2768                     const basegfx::B2DHomMatrix aRotateAroundCenter(
2769                         basegfx::utils::createRotateAroundPoint(
2770                             aCenter.getX(),
2771                             aCenter.getY(),
2772                             fRotate));
2773                     aSource.transform(aRotateAroundCenter);
2774                     rContour = tools::PolyPolygon(aSource);
2775                 }
2776             }
2777         }
2778     }
2779 
2780     return bRet;
2781 }
2782 
2783 
GetVirtDrawObj() const2784 const SwVirtFlyDrawObj* SwFlyFrame::GetVirtDrawObj() const
2785 {
2786     return static_cast<const SwVirtFlyDrawObj*>(GetDrawObj());
2787 }
GetVirtDrawObj()2788 SwVirtFlyDrawObj* SwFlyFrame::GetVirtDrawObj()
2789 {
2790     return static_cast<SwVirtFlyDrawObj*>(DrawObj());
2791 }
2792 
2793 // implementation of pure virtual method declared in
2794 // base class <SwAnchoredObject>
2795 
InvalidateObjPos()2796 void SwFlyFrame::InvalidateObjPos()
2797 {
2798     InvalidatePos();
2799     // #i68520#
2800     InvalidateObjRectWithSpaces();
2801 }
2802 
GetFrameFormat()2803 SwFrameFormat& SwFlyFrame::GetFrameFormat()
2804 {
2805     OSL_ENSURE( GetFormat(),
2806             "<SwFlyFrame::GetFrameFormat()> - missing frame format -> crash." );
2807     return *GetFormat();
2808 }
GetFrameFormat() const2809 const SwFrameFormat& SwFlyFrame::GetFrameFormat() const
2810 {
2811     OSL_ENSURE( GetFormat(),
2812             "<SwFlyFrame::GetFrameFormat()> - missing frame format -> crash." );
2813     return *GetFormat();
2814 }
2815 
GetObjRect() const2816 SwRect SwFlyFrame::GetObjRect() const
2817 {
2818     return getFrameArea();
2819 }
2820 
2821 // #i70122#
2822 // for Writer fly frames the bounding rectangle equals the object rectangles
GetObjBoundRect() const2823 SwRect SwFlyFrame::GetObjBoundRect() const
2824 {
2825     return GetObjRect();
2826 }
2827 
2828 // #i68520#
SetObjTop_(const SwTwips _nTop)2829 bool SwFlyFrame::SetObjTop_( const SwTwips _nTop )
2830 {
2831     const bool bChanged( getFrameArea().Pos().getY() != _nTop );
2832     SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
2833     aFrm.Pos().setY(_nTop);
2834 
2835     return bChanged;
2836 }
SetObjLeft_(const SwTwips _nLeft)2837 bool SwFlyFrame::SetObjLeft_( const SwTwips _nLeft )
2838 {
2839     const bool bChanged( getFrameArea().Pos().getX() != _nLeft );
2840     SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
2841     aFrm.Pos().setX(_nLeft);
2842 
2843     return bChanged;
2844 }
2845 
2846 /** method to assure that anchored object is registered at the correct
2847     page frame
2848 
2849     OD 2004-07-02 #i28701#
2850 */
RegisterAtCorrectPage()2851 void SwFlyFrame::RegisterAtCorrectPage()
2852 {
2853     // default behaviour is to do nothing.
2854 }
2855 
RegisterAtPage(SwPageFrame &)2856 void SwFlyFrame::RegisterAtPage(SwPageFrame &)
2857 {
2858     // default behaviour is to do nothing.
2859 }
2860 
2861 /** method to determine, if a <MakeAll()> on the Writer fly frame is possible
2862 
2863     OD 2004-05-11 #i28701#
2864 */
IsFormatPossible() const2865 bool SwFlyFrame::IsFormatPossible() const
2866 {
2867     return SwAnchoredObject::IsFormatPossible() &&
2868            !IsLocked() && !IsColLocked();
2869 }
2870 
GetAnchoredObjects(std::vector<SwAnchoredObject * > & aVector,const SwFormat & rFormat)2871 void SwFlyFrame::GetAnchoredObjects( std::vector<SwAnchoredObject*>& aVector, const SwFormat& rFormat )
2872 {
2873     SwIterator<SwFlyFrame,SwFormat> aIter( rFormat );
2874     for( SwFlyFrame* pFlyFrame = aIter.First(); pFlyFrame; pFlyFrame = aIter.Next() )
2875         aVector.push_back( pFlyFrame );
2876 }
2877 
GetFormat() const2878 const SwFlyFrameFormat * SwFlyFrame::GetFormat() const
2879 {
2880     return static_cast< const SwFlyFrameFormat * >( GetDep() );
2881 }
2882 
GetFormat()2883 SwFlyFrameFormat * SwFlyFrame::GetFormat()
2884 {
2885     return static_cast< SwFlyFrameFormat * >( GetDep() );
2886 }
2887 
Calc(vcl::RenderContext * pRenderContext) const2888 void SwFlyFrame::Calc(vcl::RenderContext* pRenderContext) const
2889 {
2890     if ( !m_bValidContentPos )
2891         const_cast<SwFlyFrame*>(this)->PrepareMake(pRenderContext);
2892     else
2893         SwLayoutFrame::Calc(pRenderContext);
2894 }
2895 
CalcContentHeight(const SwBorderAttrs * pAttrs,const SwTwips nMinHeight,const SwTwips nUL)2896 SwTwips SwFlyFrame::CalcContentHeight(const SwBorderAttrs *pAttrs, const SwTwips nMinHeight, const SwTwips nUL)
2897 {
2898     SwRectFnSet aRectFnSet(this);
2899     SwTwips nHeight = 0;
2900     if ( Lower() )
2901     {
2902         if ( Lower()->IsColumnFrame() )
2903         {
2904             FormatWidthCols( *pAttrs, nUL, nMinHeight );
2905             nHeight = aRectFnSet.GetHeight(Lower()->getFrameArea());
2906         }
2907         else
2908         {
2909             SwFrame *pFrame = Lower();
2910             while ( pFrame )
2911             {
2912                 nHeight += aRectFnSet.GetHeight(pFrame->getFrameArea());
2913                 if( pFrame->IsTextFrame() && static_cast<SwTextFrame*>(pFrame)->IsUndersized() )
2914                 // This TextFrame would like to be a bit larger
2915                     nHeight += static_cast<SwTextFrame*>(pFrame)->GetParHeight()
2916                             - aRectFnSet.GetHeight(pFrame->getFramePrintArea());
2917                 else if( pFrame->IsSctFrame() && static_cast<SwSectionFrame*>(pFrame)->IsUndersized() )
2918                     nHeight += static_cast<SwSectionFrame*>(pFrame)->Undersize();
2919                 pFrame = pFrame->GetNext();
2920             }
2921         }
2922         if ( GetDrawObjs() )
2923         {
2924             const size_t nCnt = GetDrawObjs()->size();
2925             SwTwips nTop = aRectFnSet.GetTop(getFrameArea());
2926             SwTwips nBorder = aRectFnSet.GetHeight(getFrameArea()) -
2927             aRectFnSet.GetHeight(getFramePrintArea());
2928             for ( size_t i = 0; i < nCnt; ++i )
2929             {
2930                 SwAnchoredObject* pAnchoredObj = (*GetDrawObjs())[i];
2931                 if ( auto pFly = dynamic_cast<SwFlyFrame*>( pAnchoredObj) )
2932                 {
2933                     // consider only Writer fly frames, which follow the text flow.
2934                     if ( pFly->IsFlyLayFrame() &&
2935                         pFly->getFrameArea().Top() != FAR_AWAY &&
2936                         pFly->GetFormat()->GetFollowTextFlow().GetValue() )
2937                     {
2938                         SwTwips nDist = -aRectFnSet.BottomDist( pFly->getFrameArea(), nTop );
2939                         if( nDist > nBorder + nHeight )
2940                             nHeight = nDist - nBorder;
2941                     }
2942                 }
2943             }
2944         }
2945     }
2946     return nHeight;
2947 }
2948 
GetAnchorFromPoolItem(const SfxPoolItem & rItem)2949 const SwFormatAnchor* SwFlyFrame::GetAnchorFromPoolItem(const SfxPoolItem& rItem)
2950 {
2951     switch(rItem.Which())
2952     {
2953         case RES_ATTRSET_CHG:
2954             return static_cast<const SwAttrSetChg*>(&rItem)->GetChgSet()->GetItem(RES_ANCHOR, false);
2955         case RES_ANCHOR:
2956             return static_cast<const SwFormatAnchor*>(&rItem);
2957         default:
2958             return nullptr;
2959     }
2960 }
2961 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2962