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 <memory>
21 #include <hintids.hxx>
22 #include <editeng/lrspitem.hxx>
23 #include <svx/svdpage.hxx>
24 #include <svx/svditer.hxx>
25 #include <svx/svdogrp.hxx>
26 #include <svx/svdotext.hxx>
27 #include <svx/svdmodel.hxx>
28 #include <svx/svdviter.hxx>
29 #include <svx/svdview.hxx>
30 #include <svx/sdr/contact/displayinfo.hxx>
31 #include <svx/sdr/contact/objectcontact.hxx>
32 #include <drawdoc.hxx>
33 #include <fmtornt.hxx>
34 #include <viewimp.hxx>
35 #include <fmtsrnd.hxx>
36 #include <fmtanchr.hxx>
37 #include <node.hxx>
38 #include <fmtcntnt.hxx>
39 #include <fmtfsize.hxx>
40 #include <pam.hxx>
41 #include <pagefrm.hxx>
42 #include <rootfrm.hxx>
43 #include <frmtool.hxx>
44 #include <flyfrm.hxx>
45 #include <textboxhelper.hxx>
46 #include <frmfmt.hxx>
47 #include <fmtfollowtextflow.hxx>
48 #include <dflyobj.hxx>
49 #include <dcontact.hxx>
50 #include <unodraw.hxx>
51 #include <IDocumentDrawModelAccess.hxx>
52 #include <IDocumentLayoutAccess.hxx>
53 #include <doc.hxx>
54 #include <hints.hxx>
55 #include <txtfrm.hxx>
56 #include <docary.hxx>
57 #include <sortedobjs.hxx>
58 #include <basegfx/matrix/b2dhommatrix.hxx>
59 #include <basegfx/matrix/b2dhommatrixtools.hxx>
60 #include <svx/sdr/contact/viewcontactofvirtobj.hxx>
61 #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
62 #include <drawinglayer/geometry/viewinformation2d.hxx>
63 #include <svx/sdr/contact/viewobjectcontactofsdrobj.hxx>
64 #include <com/sun/star/text/WritingMode2.hpp>
65 #include <calbck.hxx>
66 #include <algorithm>
67 #include <txtfly.hxx>
68 #include <sal/log.hxx>
69 
70 using namespace ::com::sun::star;
71 
72 namespace
73 {
74     /** unary function used to find a 'virtual' drawing object anchored at a given frame */
75     struct VirtObjAnchoredAtFramePred
76     {
77         const SwFrame* m_pAnchorFrame;
78 
79         // #i26791# - compare with master frame
FindFrame__anon0a18b0040111::VirtObjAnchoredAtFramePred80         static const SwFrame* FindFrame(const SwFrame* pFrame)
81         {
82             if(!pFrame || !pFrame->IsContentFrame())
83                 return pFrame;
84             auto pContentFrame = static_cast<const SwContentFrame*>(pFrame);
85             while(pContentFrame->IsFollow())
86                 pContentFrame = pContentFrame->FindMaster();
87             return pContentFrame;
88         }
89 
VirtObjAnchoredAtFramePred__anon0a18b0040111::VirtObjAnchoredAtFramePred90         VirtObjAnchoredAtFramePred(const SwFrame* pAnchorFrame)
91         :   m_pAnchorFrame(FindFrame(pAnchorFrame))
92         {}
93 
operator ()__anon0a18b0040111::VirtObjAnchoredAtFramePred94         bool operator()(const SwDrawVirtObjPtr& rpDrawVirtObj)
95         {
96             return FindFrame(rpDrawVirtObj->GetAnchorFrame()) == m_pAnchorFrame;
97         }
98     };
99 }
100 
setContextWritingMode(SdrObject * pObj,SwFrame const * pAnchor)101 void setContextWritingMode(SdrObject* pObj, SwFrame const * pAnchor)
102 {
103     if(!pObj || !pAnchor)
104         return;
105     short nWritingDirection =
106             pAnchor->IsVertical()    ? text::WritingMode2::TB_RL :
107             pAnchor->IsRightToLeft() ? text::WritingMode2::RL_TB :
108                     text::WritingMode2::LR_TB;
109     pObj->SetContextWritingMode(nWritingDirection);
110 }
111 
112 
113 /** The Get reverse way: seeks the format to the specified object.
114  * If the object is a SwVirtFlyDrawObj then the format of this
115  * will be acquired.
116  * Otherwise it is just a simple drawing object. This has a
117  * UserCall and is the client of the searched format.
118 */
FindFrameFormat(SdrObject * pObj)119 SwFrameFormat *FindFrameFormat( SdrObject *pObj )
120 {
121     SwFrameFormat* pRetval = nullptr;
122 
123     if (SwVirtFlyDrawObj* pFlyDrawObj = dynamic_cast<SwVirtFlyDrawObj*>(pObj))
124     {
125        pRetval = pFlyDrawObj->GetFormat();
126     }
127     else
128     {
129         SwContact* pContact = GetUserCall(pObj);
130         if ( pContact )
131         {
132             pRetval = pContact->GetFormat();
133         }
134     }
135     return pRetval;
136 }
137 
HasWrap(const SdrObject * pObj)138 bool HasWrap( const SdrObject* pObj )
139 {
140     if ( pObj )
141     {
142         const SwFrameFormat* pFormat = ::FindFrameFormat( pObj );
143         if ( pFormat )
144         {
145             return css::text::WrapTextMode_THROUGH != pFormat->GetSurround().GetSurround();
146         }
147     }
148 
149     return false;
150 }
151 
152 /// returns the BoundRect _inclusive_ distance of the object.
GetBoundRectOfAnchoredObj(const SdrObject * pObj)153 SwRect GetBoundRectOfAnchoredObj( const SdrObject* pObj )
154 {
155     SwRect aRet( pObj->GetCurrentBoundRect() );
156     // #i68520# - call cache of <SwAnchoredObject>
157     SwContact* pContact( GetUserCall( pObj ) );
158     if ( pContact )
159     {
160         const SwAnchoredObject* pAnchoredObj( pContact->GetAnchoredObj( pObj ) );
161         if ( pAnchoredObj )
162         {
163             aRet = pAnchoredObj->GetObjRectWithSpaces();
164         }
165     }
166     return aRet;
167 }
168 
169 /// Returns the UserCall if applicable from the group object
GetUserCall(const SdrObject * pObj)170 SwContact* GetUserCall( const SdrObject* pObj )
171 {
172     SdrObject *pTmp;
173     while ( !pObj->GetUserCall() && nullptr != (pTmp = pObj->getParentSdrObjectFromSdrObject()) )
174         pObj = pTmp;
175     assert((!pObj->GetUserCall() || nullptr != dynamic_cast<const SwContact*>(pObj->GetUserCall())) &&
176             "<::GetUserCall(..)> - wrong type of found object user call." );
177     return static_cast<SwContact*>(pObj->GetUserCall());
178 }
179 
180 /// Returns true if the SrdObject is a Marquee-Object (scrolling text)
IsMarqueeTextObj(const SdrObject & rObj)181 bool IsMarqueeTextObj( const SdrObject& rObj )
182 {
183     SdrTextAniKind eTKind;
184     return SdrInventor::Default == rObj.GetObjInventor() &&
185         OBJ_TEXT == rObj.GetObjIdentifier() &&
186         ( SdrTextAniKind::Scroll == ( eTKind = static_cast<const SdrTextObj&>(rObj).GetTextAniKind())
187          || SdrTextAniKind::Alternate == eTKind || SdrTextAniKind::Slide == eTKind );
188 }
189 
SwContact(SwFrameFormat * pToRegisterIn)190 SwContact::SwContact( SwFrameFormat *pToRegisterIn ) :
191     SwClient( pToRegisterIn ),
192     mbInDTOR( false )
193 {}
194 
~SwContact()195 SwContact::~SwContact()
196 {
197     SetInDTOR();
198 }
199 
200 
SetInDTOR()201 void SwContact::SetInDTOR()
202 {
203     mbInDTOR = true;
204 }
205 
206 /// method to move drawing object to corresponding visible layer
MoveObjToVisibleLayer(SdrObject * _pDrawObj)207 void SwContact::MoveObjToVisibleLayer( SdrObject* _pDrawObj )
208 {
209     // #i46297# - notify background about the arriving of
210     // the object and invalidate its position.
211     const bool bNotify( !GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) );
212 
213     MoveObjToLayer( true, _pDrawObj );
214 
215     // #i46297#
216     if ( bNotify )
217     {
218         SwAnchoredObject* pAnchoredObj = GetAnchoredObj( _pDrawObj );
219         assert(pAnchoredObj);
220         ::setContextWritingMode( _pDrawObj, pAnchoredObj->GetAnchorFrameContainingAnchPos() );
221         // Note: as-character anchored objects aren't registered at a page frame and
222         //       a notification of its background isn't needed.
223         if ( pAnchoredObj->GetPageFrame() )
224         {
225             ::Notify_Background( _pDrawObj, pAnchoredObj->GetPageFrame(),
226                                  pAnchoredObj->GetObjRect(), PREP_FLY_ARRIVE, true );
227         }
228 
229         pAnchoredObj->InvalidateObjPos();
230     }
231 }
232 
233 /// method to move drawing object to corresponding invisible layer - #i18447#
MoveObjToInvisibleLayer(SdrObject * _pDrawObj)234 void SwContact::MoveObjToInvisibleLayer( SdrObject* _pDrawObj )
235 {
236     // #i46297# - notify background about the leaving of the object.
237     const bool bNotify( GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) );
238 
239     MoveObjToLayer( false, _pDrawObj );
240 
241     // #i46297#
242     if ( bNotify )
243     {
244         SwAnchoredObject* pAnchoredObj = GetAnchoredObj( _pDrawObj );
245         assert(pAnchoredObj);
246         // Note: as-character anchored objects aren't registered at a page frame and
247         //       a notification of its background isn't needed.
248         if (pAnchoredObj->GetPageFrame())
249         {
250             ::Notify_Background( _pDrawObj, pAnchoredObj->GetPageFrame(),
251                                  pAnchoredObj->GetObjRect(), PREP_FLY_LEAVE, true );
252         }
253     }
254 }
255 
256 /** method to move object to visible/invisible layer -  #i18447#
257 
258     implementation for the public method <MoveObjToVisibleLayer(..)>
259     and <MoveObjToInvisibleLayer(..)>
260 */
MoveObjToLayer(const bool _bToVisible,SdrObject * _pDrawObj)261 void SwContact::MoveObjToLayer( const bool _bToVisible,
262                                  SdrObject* _pDrawObj )
263 {
264     if ( !_pDrawObj )
265     {
266         OSL_FAIL( "SwDrawContact::MoveObjToLayer(..) - no drawing object!" );
267         return;
268     }
269 
270     if ( !GetRegisteredIn() )
271     {
272         OSL_FAIL( "SwDrawContact::MoveObjToLayer(..) - no drawing frame format!" );
273         return;
274     }
275 
276     const IDocumentDrawModelAccess& rIDDMA = static_cast<SwFrameFormat*>(GetRegisteredInNonConst())->getIDocumentDrawModelAccess();
277 
278     SdrLayerID nToHellLayerId =
279         _bToVisible ? rIDDMA.GetHellId() : rIDDMA.GetInvisibleHellId();
280     SdrLayerID nToHeavenLayerId =
281         _bToVisible ? rIDDMA.GetHeavenId() : rIDDMA.GetInvisibleHeavenId();
282     SdrLayerID nToControlLayerId =
283         _bToVisible ? rIDDMA.GetControlsId() : rIDDMA.GetInvisibleControlsId();
284     SdrLayerID nFromHellLayerId =
285         _bToVisible ? rIDDMA.GetInvisibleHellId() : rIDDMA.GetHellId();
286     SdrLayerID nFromHeavenLayerId =
287         _bToVisible ? rIDDMA.GetInvisibleHeavenId() : rIDDMA.GetHeavenId();
288     SdrLayerID nFromControlLayerId =
289         _bToVisible ? rIDDMA.GetInvisibleControlsId() : rIDDMA.GetControlsId();
290 
291     if ( dynamic_cast<const SdrObjGroup*>( _pDrawObj) !=  nullptr )
292     {
293         // determine layer for group object
294         {
295             // proposed layer of a group object is the hell layer
296             SdrLayerID nNewLayerId = nToHellLayerId;
297             if ( ::CheckControlLayer( _pDrawObj ) )
298             {
299                 // it has to be the control layer, if one of the member
300                 // is a control
301                 nNewLayerId = nToControlLayerId;
302             }
303             else if ( _pDrawObj->GetLayer() == rIDDMA.GetHeavenId() ||
304                       _pDrawObj->GetLayer() == rIDDMA.GetInvisibleHeavenId() )
305             {
306                 // it has to be the heaven layer, if method <GetLayer()> reveals
307                 // a heaven layer
308                 nNewLayerId = nToHeavenLayerId;
309             }
310             // set layer at group object, but do *not* broadcast and
311             // no propagation to the members.
312             // Thus, call <NbcSetLayer(..)> at super class
313             _pDrawObj->SdrObject::NbcSetLayer( nNewLayerId );
314         }
315 
316         // call method recursively for group object members
317         const SdrObjList* pLst =
318                 static_cast<SdrObjGroup*>(_pDrawObj)->GetSubList();
319         if ( pLst )
320         {
321             for ( size_t i = 0; i < pLst->GetObjCount(); ++i )
322             {
323                 MoveObjToLayer( _bToVisible, pLst->GetObj( i ) );
324             }
325         }
326     }
327     else
328     {
329         const SdrLayerID nLayerIdOfObj = _pDrawObj->GetLayer();
330         if ( nLayerIdOfObj == nFromHellLayerId )
331         {
332             _pDrawObj->SetLayer( nToHellLayerId );
333         }
334         else if ( nLayerIdOfObj == nFromHeavenLayerId )
335         {
336             _pDrawObj->SetLayer( nToHeavenLayerId );
337         }
338         else if ( nLayerIdOfObj == nFromControlLayerId )
339         {
340             _pDrawObj->SetLayer( nToControlLayerId );
341         }
342     }
343 }
344 
345 /// get minimum order number of anchored objects handled by with contact
GetMinOrdNum() const346 sal_uInt32 SwContact::GetMinOrdNum() const
347 {
348     sal_uInt32 nMinOrdNum( SAL_MAX_UINT32 );
349 
350     std::vector< SwAnchoredObject* > aObjs;
351     GetAnchoredObjs( aObjs );
352 
353     while ( !aObjs.empty() )
354     {
355         sal_uInt32 nTmpOrdNum = aObjs.back()->GetDrawObj()->GetOrdNum();
356 
357         if ( nTmpOrdNum < nMinOrdNum )
358         {
359             nMinOrdNum = nTmpOrdNum;
360         }
361 
362         aObjs.pop_back();
363     }
364 
365     OSL_ENSURE( nMinOrdNum != SAL_MAX_UINT32,
366             "<SwContact::GetMinOrdNum()> - no order number found." );
367     return nMinOrdNum;
368 }
369 
370 /// get maximum order number of anchored objects handled by with contact
GetMaxOrdNum() const371 sal_uInt32 SwContact::GetMaxOrdNum() const
372 {
373     sal_uInt32 nMaxOrdNum( 0 );
374 
375     std::vector< SwAnchoredObject* > aObjs;
376     GetAnchoredObjs( aObjs );
377 
378     while ( !aObjs.empty() )
379     {
380         sal_uInt32 nTmpOrdNum = aObjs.back()->GetDrawObj()->GetOrdNum();
381 
382         if ( nTmpOrdNum > nMaxOrdNum )
383         {
384             nMaxOrdNum = nTmpOrdNum;
385         }
386 
387         aObjs.pop_back();
388     }
389 
390     return nMaxOrdNum;
391 }
392 
393 namespace
394 {
lcl_GetWW8Pos(SwAnchoredObject const * pAnchoredObj,const bool bFollowTextFlow,sw::WW8AnchorConv & reConv)395     Point lcl_GetWW8Pos(SwAnchoredObject const * pAnchoredObj, const bool bFollowTextFlow, sw::WW8AnchorConv& reConv)
396     {
397         switch(reConv)
398         {
399             case sw::WW8AnchorConv::CONV2PG:
400             {
401                 bool bRelToTableCell(false);
402                 Point aPos(pAnchoredObj->GetRelPosToPageFrame(bFollowTextFlow, bRelToTableCell));
403                 if(bRelToTableCell)
404                     reConv = sw::WW8AnchorConv::RELTOTABLECELL;
405                 return aPos;
406             }
407             case sw::WW8AnchorConv::CONV2COL_OR_PARA:
408                 return pAnchoredObj->GetRelPosToAnchorFrame();
409             case sw::WW8AnchorConv::CONV2CHAR:
410                 return pAnchoredObj->GetRelPosToChar();
411             case sw::WW8AnchorConv::CONV2LINE:
412                 return pAnchoredObj->GetRelPosToLine();
413             default: ;
414         }
415         return Point();
416     }
417 }
SwClientNotify(const SwModify & rMod,const SfxHint & rHint)418 void SwContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
419 {
420     // this does not call SwClient::SwClientNotify and thus doesn't handle RES_OBJECTDYING as usual. Is this intentional?
421     if (auto pFindSdrObjectHint = dynamic_cast<const sw::FindSdrObjectHint*>(&rHint))
422     {
423         if(!pFindSdrObjectHint->m_rpObject)
424             pFindSdrObjectHint->m_rpObject = GetMaster();
425     }
426     else if (auto pWW8AnchorConvHint = dynamic_cast<const sw::WW8AnchorConvHint*>(&rHint))
427     {
428         // determine anchored object
429         SwAnchoredObject* pAnchoredObj(nullptr);
430         {
431             std::vector<SwAnchoredObject*> aAnchoredObjs;
432             GetAnchoredObjs(aAnchoredObjs);
433             if(!aAnchoredObjs.empty())
434                 pAnchoredObj = aAnchoredObjs.front();
435         }
436         // no anchored object found. Thus, the needed layout information can't
437         // be determined. --> no conversion
438         if(!pAnchoredObj)
439             return;
440         // no conversion for anchored drawing object, which aren't attached to an
441         // anchor frame.
442         // This is the case for drawing objects, which are anchored inside a page
443         // header/footer of an *unused* page style.
444         if(dynamic_cast<SwAnchoredDrawObject*>(pAnchoredObj) && !pAnchoredObj->GetAnchorFrame())
445             return;
446         const bool bFollowTextFlow = static_cast<const SwFrameFormat&>(rMod).GetFollowTextFlow().GetValue();
447         sw::WW8AnchorConvResult& rResult(pWW8AnchorConvHint->m_rResult);
448         // No distinction between layout directions, because of missing
449         // information about WW8 in vertical layout.
450         rResult.m_aPos.setX(lcl_GetWW8Pos(pAnchoredObj, bFollowTextFlow, rResult.m_eHoriConv).getX());
451         rResult.m_aPos.setY(lcl_GetWW8Pos(pAnchoredObj, bFollowTextFlow, rResult.m_eVertConv).getY());
452         rResult.m_bConverted = true;
453     }
454 }
455 
456 
SwFlyDrawContact(SwFlyFrameFormat * pToRegisterIn,SdrModel & rTargetModel)457 SwFlyDrawContact::SwFlyDrawContact(
458     SwFlyFrameFormat *pToRegisterIn,
459     SdrModel& rTargetModel)
460 :   SwContact(pToRegisterIn),
461     mpMasterObj(new SwFlyDrawObj(rTargetModel))
462 {
463     // #i26791# - class <SwFlyDrawContact> contains the 'master'
464     // drawing object of type <SwFlyDrawObj> on its own.
465     mpMasterObj->SetOrdNum( 0xFFFFFFFE );
466     mpMasterObj->SetUserCall( this );
467 }
468 
~SwFlyDrawContact()469 SwFlyDrawContact::~SwFlyDrawContact()
470 {
471     if ( mpMasterObj )
472     {
473         mpMasterObj->SetUserCall( nullptr );
474         if ( mpMasterObj->getSdrPageFromSdrObject() )
475             mpMasterObj->getSdrPageFromSdrObject()->RemoveObject( mpMasterObj->GetOrdNum() );
476     }
477 }
478 
GetOrdNumForNewRef(const SwFlyFrame * pFly)479 sal_uInt32 SwFlyDrawContact::GetOrdNumForNewRef(const SwFlyFrame* pFly)
480 {
481     // search for another Writer fly frame registered at same frame format
482     SwIterator<SwFlyFrame,SwFormat> aIter(*GetFormat());
483     const SwFlyFrame* pFlyFrame(nullptr);
484     for(pFlyFrame = aIter.First(); pFlyFrame; pFlyFrame = aIter.Next())
485     {
486         if(pFlyFrame != pFly)
487             break;
488     }
489 
490     if(pFlyFrame)
491     {
492         // another Writer fly frame found. Take its order number
493         return pFlyFrame->GetVirtDrawObj()->GetOrdNum();
494     }
495     // no other Writer fly frame found. Take order number of 'master' object
496     // #i35748# - use method <GetOrdNumDirect()> instead
497     // of method <GetOrdNum()> to avoid a recalculation of the order number,
498     // which isn't intended.
499     return GetMaster()->GetOrdNumDirect();
500 }
501 
CreateNewRef(SwFlyFrame * pFly,SwFlyFrameFormat * pFormat)502 SwVirtFlyDrawObj* SwFlyDrawContact::CreateNewRef(SwFlyFrame* pFly, SwFlyFrameFormat* pFormat)
503 {
504     // Find ContactObject from the Format. If there's already one, we just
505     // need to create a new Ref, else we create the Contact now.
506 
507     IDocumentDrawModelAccess& rIDDMA = pFormat->getIDocumentDrawModelAccess();
508     SwFlyDrawContact* pContact = pFormat->GetOrCreateContact();
509     SwVirtFlyDrawObj* pDrawObj(
510         new SwVirtFlyDrawObj(
511             pContact->GetMaster()->getSdrModelFromSdrObject(),
512             *pContact->GetMaster(),
513             pFly));
514     pDrawObj->SetUserCall(pContact);
515 
516     // The Reader creates the Masters and inserts them into the Page in
517     // order to transport the z-order.
518     // After creating the first Reference the Masters are removed from the
519     // List and are not important anymore.
520     SdrPage* pPg(nullptr);
521     if(nullptr != (pPg = pContact->GetMaster()->getSdrPageFromSdrObject()))
522     {
523         const size_t nOrdNum = pContact->GetMaster()->GetOrdNum();
524         pPg->ReplaceObject(pDrawObj, nOrdNum);
525     }
526     // #i27030# - insert new <SwVirtFlyDrawObj> instance
527     // into drawing page with correct order number
528     else
529         rIDDMA.GetDrawModel()->GetPage(0)->InsertObject(pDrawObj, pContact->GetOrdNumForNewRef(pFly));
530     // #i38889# - assure, that new <SwVirtFlyDrawObj> instance
531     // is in a visible layer.
532     pContact->MoveObjToVisibleLayer(pDrawObj);
533     return pDrawObj;
534 }
535 
536 // #i26791#
GetAnchoredObj(const SdrObject * pSdrObj) const537 const SwAnchoredObject* SwFlyDrawContact::GetAnchoredObj(const SdrObject* pSdrObj) const
538 {
539     assert(pSdrObj);
540     assert(dynamic_cast<const SwVirtFlyDrawObj*>(pSdrObj) != nullptr);
541     assert(GetUserCall(pSdrObj) == this &&
542         "<SwFlyDrawContact::GetAnchoredObj(..)> - provided object doesn't belong to this contact");
543 
544     const SwAnchoredObject *const pRetAnchoredObj =
545         static_cast<const SwVirtFlyDrawObj*>(pSdrObj)->GetFlyFrame();
546 
547     return pRetAnchoredObj;
548 }
549 
GetAnchoredObj(SdrObject * const pSdrObj)550 SwAnchoredObject* SwFlyDrawContact::GetAnchoredObj(SdrObject *const pSdrObj)
551 {
552     return const_cast<SwAnchoredObject *>(const_cast<SwFlyDrawContact const*>(this)->GetAnchoredObj(pSdrObj));
553 }
554 
GetMaster()555 SdrObject* SwFlyDrawContact::GetMaster()
556 {
557     return mpMasterObj.get();
558 }
559 
560 /**
561  * @note Overriding method to control Writer fly frames, which are linked, and
562  *       to assure that all objects anchored at/inside the Writer fly frame are
563  *       also made visible.
564  */
MoveObjToVisibleLayer(SdrObject * _pDrawObj)565 void SwFlyDrawContact::MoveObjToVisibleLayer( SdrObject* _pDrawObj )
566 {
567     assert(dynamic_cast<const SwVirtFlyDrawObj*>(_pDrawObj) != nullptr);
568 
569     if ( GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) )
570     {
571         // nothing to do
572         return;
573     }
574 
575     SwFlyFrame* pFlyFrame = static_cast<SwVirtFlyDrawObj*>(_pDrawObj)->GetFlyFrame();
576 
577     // #i44464# - consider, that Writer fly frame content
578     // already exists - (e.g. WW8 document is inserted into an existing document).
579     if ( !pFlyFrame->Lower() )
580     {
581         pFlyFrame->InsertColumns();
582         pFlyFrame->Chain( pFlyFrame->AnchorFrame() );
583         pFlyFrame->InsertCnt();
584     }
585     if ( pFlyFrame->GetDrawObjs() )
586     {
587         for (SwAnchoredObject* i : *pFlyFrame->GetDrawObjs())
588         {
589             // #i28701# - consider type of objects in sorted object list.
590             SdrObject* pObj = i->DrawObj();
591             SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
592             pContact->MoveObjToVisibleLayer( pObj );
593         }
594     }
595 
596     // make fly frame visible
597     SwContact::MoveObjToVisibleLayer( _pDrawObj );
598 }
599 
600 /**
601  * @note Override method to control Writer fly frames, which are linked, and
602  *       to assure that all objects anchored at/inside the Writer fly frame are
603  *       also made invisible.
604  */
MoveObjToInvisibleLayer(SdrObject * _pDrawObj)605 void SwFlyDrawContact::MoveObjToInvisibleLayer( SdrObject* _pDrawObj )
606 {
607     assert(dynamic_cast<const SwVirtFlyDrawObj*>(_pDrawObj) != nullptr);
608 
609     if ( !GetFormat()->getIDocumentDrawModelAccess().IsVisibleLayerId( _pDrawObj->GetLayer() ) )
610     {
611         // nothing to do
612         return;
613     }
614 
615     SwFlyFrame* pFlyFrame = static_cast<SwVirtFlyDrawObj*>(_pDrawObj)->GetFlyFrame();
616 
617     pFlyFrame->Unchain();
618     pFlyFrame->DeleteCnt();
619     if ( pFlyFrame->GetDrawObjs() )
620     {
621         for (SwAnchoredObject* i : *pFlyFrame->GetDrawObjs())
622         {
623             // #i28701# - consider type of objects in sorted object list.
624             SdrObject* pObj = i->DrawObj();
625             SwContact* pContact = static_cast<SwContact*>(pObj->GetUserCall());
626             pContact->MoveObjToInvisibleLayer( pObj );
627         }
628     }
629 
630     // make fly frame invisible
631     SwContact::MoveObjToInvisibleLayer( _pDrawObj );
632 }
633 
634 /// get data collection of anchored objects, handled by with contact
GetAnchoredObjs(std::vector<SwAnchoredObject * > & _roAnchoredObjs) const635 void SwFlyDrawContact::GetAnchoredObjs( std::vector<SwAnchoredObject*>& _roAnchoredObjs ) const
636 {
637     const SwFrameFormat* pFormat = GetFormat();
638     SwFlyFrame::GetAnchoredObjects( _roAnchoredObjs, *pFormat );
639 }
SwClientNotify(const SwModify & rMod,const SfxHint & rHint)640 void SwFlyDrawContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
641 {
642     SwContact::SwClientNotify(rMod, rHint);
643     if(auto pGetZOrdnerHint = dynamic_cast<const sw::GetZOrderHint*>(&rHint))
644     {
645         // #i11176#
646         // This also needs to work when no layout exists. Thus, for
647         // FlyFrames an alternative method is used now in that case.
648         auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod));
649         if (pFormat && pFormat->Which() == RES_FLYFRMFMT && !pFormat->getIDocumentLayoutAccess().GetCurrentViewShell())
650             pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
651     }
652 }
653 
654 // SwDrawContact
655 
CheckControlLayer(const SdrObject * pObj)656 bool CheckControlLayer( const SdrObject *pObj )
657 {
658     if ( SdrInventor::FmForm == pObj->GetObjInventor() )
659         return true;
660     if (const SdrObjGroup *pObjGroup = dynamic_cast<const SdrObjGroup*>(pObj))
661     {
662         const SdrObjList *pLst = pObjGroup->GetSubList();
663         for ( size_t i = 0; i < pLst->GetObjCount(); ++i )
664         {
665             if ( ::CheckControlLayer( pLst->GetObj( i ) ) )
666             {
667                 // #i18447# - return correct value ;-)
668                 return true;
669             }
670         }
671     }
672     return false;
673 }
674 
SwDrawContact(SwFrameFormat * pToRegisterIn,SdrObject * pObj)675 SwDrawContact::SwDrawContact( SwFrameFormat* pToRegisterIn, SdrObject* pObj ) :
676     SwContact( pToRegisterIn ),
677     maAnchoredDrawObj(),
678     mbMasterObjCleared( false ),
679     mbDisconnectInProgress( false ),
680     mbUserCallActive( false ),
681     // Note: value of <meEventTypeOfCurrentUserCall> isn't of relevance, because
682     //       <mbUserCallActive> is false.
683     meEventTypeOfCurrentUserCall( SdrUserCallType::MoveOnly )
684 {
685     // --> #i33909# - assure, that drawing object is inserted
686     // in the drawing page.
687     if ( !pObj->IsInserted() )
688     {
689         pToRegisterIn->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)->
690                                 InsertObject( pObj, pObj->GetOrdNumDirect() );
691     }
692 
693     // Controls have to be always in the Control-Layer. This is also true for
694     // group objects, if they contain controls.
695     if ( ::CheckControlLayer( pObj ) )
696     {
697         // set layer of object to corresponding invisible layer.
698         pObj->SetLayer( pToRegisterIn->getIDocumentDrawModelAccess().GetInvisibleControlsId() );
699     }
700 
701     // #i26791#
702     pObj->SetUserCall( this );
703     maAnchoredDrawObj.SetDrawObj( *pObj );
704 
705     // if there already exists an SwXShape for the object, ensure it knows about us, and the SdrObject
706     // #i99056#
707     SwXShape::AddExistingShapeToFormat( *pObj );
708 }
709 
~SwDrawContact()710 SwDrawContact::~SwDrawContact()
711 {
712     SetInDTOR();
713 
714     DisconnectFromLayout();
715 
716     // remove 'master' from drawing page
717     RemoveMasterFromDrawPage();
718 
719     // remove and destroy 'virtual' drawing objects.
720     RemoveAllVirtObjs();
721 
722     if ( !mbMasterObjCleared )
723     {
724         SdrObject* pObject = const_cast< SdrObject* >( maAnchoredDrawObj.GetDrawObj() );
725         SdrObject::Free( pObject );
726     }
727 }
728 
GetTextObjectsFromFormat(std::list<SdrTextObj * > & o_rTextObjects,SwDoc * pDoc)729 void SwDrawContact::GetTextObjectsFromFormat(std::list<SdrTextObj*>& o_rTextObjects, SwDoc* pDoc)
730 {
731     for(auto& rpFly : *pDoc->GetSpzFrameFormats())
732     {
733         if(dynamic_cast<const SwDrawFrameFormat*>(rpFly))
734             rpFly->CallSwClientNotify(sw::CollectTextObjectsHint(o_rTextObjects));
735     }
736 }
737 
738 // #i26791#
GetAnchoredObj(const SdrObject * pSdrObj) const739 const SwAnchoredObject* SwDrawContact::GetAnchoredObj(const SdrObject* pSdrObj ) const
740 {
741     // handle default parameter value
742     if (!pSdrObj)
743     {
744         pSdrObj = GetMaster();
745     }
746 
747     assert(pSdrObj);
748     assert(dynamic_cast<const SwDrawVirtObj*>(pSdrObj) != nullptr ||
749            dynamic_cast<const SdrVirtObj*>(pSdrObj) == nullptr);
750     assert((GetUserCall(pSdrObj) == this ||
751             pSdrObj == GetMaster()) &&
752             "<SwDrawContact::GetAnchoredObj(..)> - provided object doesn't belongs to this contact" );
753 
754     const SwAnchoredObject* pRetAnchoredObj = nullptr;
755 
756     if (auto pVirtObj = dynamic_cast<const SwDrawVirtObj*>(pSdrObj))
757     {
758         pRetAnchoredObj = &(pVirtObj->GetAnchoredObj());
759     }
760     else
761     {
762         assert(dynamic_cast<const SdrVirtObj*>(pSdrObj) == nullptr);
763         pRetAnchoredObj = &maAnchoredDrawObj;
764     }
765 
766     return pRetAnchoredObj;
767 }
768 
GetAnchoredObj(SdrObject * const pSdrObj)769 SwAnchoredObject* SwDrawContact::GetAnchoredObj(SdrObject *const pSdrObj)
770 {
771     return const_cast<SwAnchoredObject*>(const_cast<SwDrawContact const*>(this)->GetAnchoredObj(pSdrObj));
772 }
773 
GetMaster()774 SdrObject* SwDrawContact::GetMaster()
775 {
776     return !mbMasterObjCleared
777            ? maAnchoredDrawObj.DrawObj()
778            : nullptr;
779 }
780 
GetAnchorFrame(const SdrObject * _pDrawObj) const781 const SwFrame* SwDrawContact::GetAnchorFrame( const SdrObject* _pDrawObj ) const
782 {
783     const SwFrame* pAnchorFrame = nullptr;
784     if ( !_pDrawObj ||
785          _pDrawObj == GetMaster() ||
786          ( !_pDrawObj->GetUserCall() &&
787            GetUserCall( _pDrawObj ) == this ) )
788     {
789         pAnchorFrame = maAnchoredDrawObj.GetAnchorFrame();
790     }
791     else
792     {
793         assert(dynamic_cast<SwDrawVirtObj const*>(_pDrawObj) !=  nullptr);
794         pAnchorFrame = static_cast<const SwDrawVirtObj*>(_pDrawObj)->GetAnchorFrame();
795     }
796 
797     return pAnchorFrame;
798 }
799 
GetAnchorFrame(SdrObject const * const pDrawObj)800 SwFrame* SwDrawContact::GetAnchorFrame(SdrObject const *const pDrawObj)
801 {
802     return const_cast<SwFrame *>(const_cast<SwDrawContact const*>(this)->GetAnchorFrame(pDrawObj));
803 }
804 
805 /** add a 'virtual' drawing object to drawing page.
806  */
AddVirtObj()807 SwDrawVirtObj* SwDrawContact::AddVirtObj()
808 {
809     maDrawVirtObjs.push_back(
810         SwDrawVirtObjPtr(
811             new SwDrawVirtObj(
812                 GetMaster()->getSdrModelFromSdrObject(),
813                 *GetMaster(),
814                 *this)));
815     maDrawVirtObjs.back()->AddToDrawingPage();
816     return maDrawVirtObjs.back().get();
817 }
818 
819 /// remove 'virtual' drawing objects and destroy them.
RemoveAllVirtObjs()820 void SwDrawContact::RemoveAllVirtObjs()
821 {
822     for(auto& rpDrawVirtObj : maDrawVirtObjs)
823     {
824         // remove and destroy 'virtual object'
825         rpDrawVirtObj->RemoveFromWriterLayout();
826         rpDrawVirtObj->RemoveFromDrawingPage();
827     }
828     maDrawVirtObjs.clear();
829 }
830 
831 
832 /// get drawing object ('master' or 'virtual') by frame.
GetDrawObjectByAnchorFrame(const SwFrame & _rAnchorFrame)833 SdrObject* SwDrawContact::GetDrawObjectByAnchorFrame( const SwFrame& _rAnchorFrame )
834 {
835     SdrObject* pRetDrawObj = nullptr;
836 
837     // #i26791# - compare master frames instead of direct frames
838     const SwFrame* pProposedAnchorFrame = &_rAnchorFrame;
839     if ( pProposedAnchorFrame->IsContentFrame() )
840     {
841         const SwContentFrame* pTmpFrame =
842                             static_cast<const SwContentFrame*>( pProposedAnchorFrame );
843         while ( pTmpFrame->IsFollow() )
844         {
845             pTmpFrame = pTmpFrame->FindMaster();
846         }
847         pProposedAnchorFrame = pTmpFrame;
848     }
849 
850     const SwFrame* pMasterObjAnchorFrame = GetAnchorFrame();
851     if ( pMasterObjAnchorFrame && pMasterObjAnchorFrame->IsContentFrame() )
852     {
853         const SwContentFrame* pTmpFrame =
854                             static_cast<const SwContentFrame*>( pMasterObjAnchorFrame );
855         while ( pTmpFrame->IsFollow() )
856         {
857             pTmpFrame = pTmpFrame->FindMaster();
858         }
859         pMasterObjAnchorFrame = pTmpFrame;
860     }
861 
862     if ( pMasterObjAnchorFrame && pMasterObjAnchorFrame == pProposedAnchorFrame )
863     {
864         pRetDrawObj = GetMaster();
865     }
866     else
867     {
868         const auto ppFoundVirtObj(std::find_if(maDrawVirtObjs.begin(), maDrawVirtObjs.end(),
869                 VirtObjAnchoredAtFramePred(pProposedAnchorFrame)));
870         if(ppFoundVirtObj != maDrawVirtObjs.end())
871             pRetDrawObj = ppFoundVirtObj->get();
872     }
873 
874     return pRetDrawObj;
875 }
876 
NotifyBackgrdOfAllVirtObjs(const tools::Rectangle * pOldBoundRect)877 void SwDrawContact::NotifyBackgrdOfAllVirtObjs(const tools::Rectangle* pOldBoundRect)
878 {
879     for(const auto& rpDrawVirtObj : maDrawVirtObjs)
880     {
881         SwDrawVirtObj* pDrawVirtObj(rpDrawVirtObj.get());
882         if ( pDrawVirtObj->GetAnchorFrame() )
883         {
884             // #i34640# - determine correct page frame
885             SwPageFrame* pPage = pDrawVirtObj->AnchoredObj().FindPageFrameOfAnchor();
886             if( pOldBoundRect && pPage )
887             {
888                 SwRect aOldRect( *pOldBoundRect );
889                 aOldRect.Pos() += pDrawVirtObj->GetOffset();
890                 if( aOldRect.HasArea() )
891                     ::Notify_Background( pDrawVirtObj, pPage,
892                                          aOldRect, PREP_FLY_LEAVE,true);
893             }
894             // #i34640# - include spacing for wrapping
895             SwRect aRect( pDrawVirtObj->GetAnchoredObj().GetObjRectWithSpaces() );
896             if (aRect.HasArea() && pPage)
897             {
898                 SwPageFrame* pPg = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aRect, pPage )));
899                 if ( pPg )
900                     ::Notify_Background( pDrawVirtObj, pPg, aRect,
901                                          PREP_FLY_ARRIVE, true );
902             }
903             ::ClrContourCache( pDrawVirtObj );
904         }
905     }
906 }
907 
908 /// local method to notify the background for a drawing object - #i26791#
lcl_NotifyBackgroundOfObj(SwDrawContact const & _rDrawContact,const SdrObject & _rObj,const tools::Rectangle * _pOldObjRect)909 static void lcl_NotifyBackgroundOfObj( SwDrawContact const & _rDrawContact,
910                                 const SdrObject& _rObj,
911                                 const tools::Rectangle* _pOldObjRect )
912 {
913     // #i34640#
914     SwAnchoredObject* pAnchoredObj =
915         const_cast<SwAnchoredObject*>(_rDrawContact.GetAnchoredObj( &_rObj ));
916     if ( pAnchoredObj && pAnchoredObj->GetAnchorFrame() )
917     {
918         // #i34640# - determine correct page frame
919         SwPageFrame* pPageFrame = pAnchoredObj->FindPageFrameOfAnchor();
920         if( _pOldObjRect && pPageFrame )
921         {
922             SwRect aOldRect( *_pOldObjRect );
923             if( aOldRect.HasArea() )
924             {
925                 // #i34640# - determine correct page frame
926                 SwPageFrame* pOldPageFrame = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aOldRect, pPageFrame )));
927                 ::Notify_Background( &_rObj, pOldPageFrame, aOldRect,
928                                      PREP_FLY_LEAVE, true);
929             }
930         }
931         // #i34640# - include spacing for wrapping
932         SwRect aNewRect( pAnchoredObj->GetObjRectWithSpaces() );
933         if( aNewRect.HasArea() && pPageFrame )
934         {
935             pPageFrame = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( aNewRect, pPageFrame )));
936             ::Notify_Background( &_rObj, pPageFrame, aNewRect,
937                                  PREP_FLY_ARRIVE, true );
938         }
939         ClrContourCache( &_rObj );
940     }
941 }
942 
Changed(const SdrObject & rObj,SdrUserCallType eType,const tools::Rectangle & rOldBoundRect)943 void SwDrawContact::Changed( const SdrObject& rObj,
944                              SdrUserCallType eType,
945                              const tools::Rectangle& rOldBoundRect )
946 {
947     // #i26791# - no event handling, if existing <SwViewShell>
948     // is in construction
949     SwDoc* pDoc = GetFormat()->GetDoc();
950     if ( pDoc->getIDocumentLayoutAccess().GetCurrentViewShell() &&
951          pDoc->getIDocumentLayoutAccess().GetCurrentViewShell()->IsInConstructor() )
952     {
953         return;
954     }
955 
956     // #i44339#
957     // no event handling, if document is in destruction.
958     // Exception: It's the SdrUserCallType::Delete event
959     if ( pDoc->IsInDtor() && eType != SdrUserCallType::Delete )
960     {
961         return;
962     }
963 
964     //Put on Action, but not if presently anywhere an action runs.
965     bool bHasActions(true);
966     SwRootFrame *pTmpRoot = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
967     if ( pTmpRoot && pTmpRoot->IsCallbackActionEnabled() )
968     {
969         SwViewShell* const pSh = pDoc->getIDocumentLayoutAccess().GetCurrentViewShell();
970         if ( pSh )
971         {
972             for(SwViewShell& rShell : pSh->GetRingContainer() )
973             {
974                 if ( rShell.Imp()->IsAction() || rShell.Imp()->IsIdleAction() )
975                 {
976                     bHasActions = true;
977                     break;
978                 }
979                 bHasActions = false;
980             }
981         }
982         if(!bHasActions)
983             pTmpRoot->StartAllAction();
984     }
985     SdrObjUserCall::Changed( rObj, eType, rOldBoundRect );
986     Changed_( rObj, eType, &rOldBoundRect );    //Attention, possibly suicidal!
987 
988     if(!bHasActions)
989         pTmpRoot->EndAllAction();
990 }
991 
992 /// helper class for method <SwDrawContact::Changed_(..)> for handling nested
993 /// <SdrObjUserCall> events
994 class NestedUserCallHdl
995 {
996     private:
997         SwDrawContact* mpDrawContact;
998         bool const mbParentUserCallActive;
999         SdrUserCallType const meParentUserCallEventType;
1000 
1001     public:
NestedUserCallHdl(SwDrawContact * _pDrawContact,SdrUserCallType _eEventType)1002         NestedUserCallHdl( SwDrawContact* _pDrawContact,
1003                            SdrUserCallType _eEventType )
1004             : mpDrawContact( _pDrawContact ),
1005               mbParentUserCallActive( _pDrawContact->mbUserCallActive ),
1006               meParentUserCallEventType( _pDrawContact->meEventTypeOfCurrentUserCall )
1007         {
1008             mpDrawContact->mbUserCallActive = true;
1009             mpDrawContact->meEventTypeOfCurrentUserCall = _eEventType;
1010         }
1011 
~NestedUserCallHdl()1012         ~NestedUserCallHdl()
1013         {
1014             if ( mpDrawContact )
1015             {
1016                 mpDrawContact->mbUserCallActive = mbParentUserCallActive;
1017                 mpDrawContact->meEventTypeOfCurrentUserCall = meParentUserCallEventType;
1018             }
1019         }
1020 
DrawContactDeleted()1021         void DrawContactDeleted()
1022         {
1023             mpDrawContact = nullptr;
1024         }
1025 
IsNestedUserCall() const1026         bool IsNestedUserCall() const
1027         {
1028             return mbParentUserCallActive;
1029         }
1030 
AssertNestedUserCall()1031         void AssertNestedUserCall()
1032         {
1033             if ( IsNestedUserCall() )
1034             {
1035                 bool bTmpAssert( true );
1036                 // Currently its known, that a nested event SdrUserCallType::Resize
1037                 // could occur during parent user call SdrUserCallType::Inserted,
1038                 // SdrUserCallType::Delete and SdrUserCallType::Resize for edge objects.
1039                 // Also possible are nested SdrUserCallType::ChildResize events for
1040                 // edge objects
1041                 // Thus, assert all other combinations
1042                 if ( ( meParentUserCallEventType == SdrUserCallType::Inserted ||
1043                        meParentUserCallEventType == SdrUserCallType::Delete ||
1044                        meParentUserCallEventType == SdrUserCallType::Resize ) &&
1045                      mpDrawContact->meEventTypeOfCurrentUserCall == SdrUserCallType::Resize )
1046                 {
1047                     bTmpAssert = false;
1048                 }
1049                 else if ( meParentUserCallEventType == SdrUserCallType::ChildResize &&
1050                           mpDrawContact->meEventTypeOfCurrentUserCall == SdrUserCallType::ChildResize )
1051                 {
1052                     bTmpAssert = false;
1053                 }
1054 
1055                 if ( bTmpAssert )
1056                 {
1057                     OSL_FAIL( "<SwDrawContact::Changed_(..)> - unknown nested <UserCall> event. This is serious." );
1058                 }
1059             }
1060         }
1061 };
1062 
1063 /// Notify the format's textbox that it should reconsider its position / size.
lcl_textBoxSizeNotify(SwFrameFormat * pFormat)1064 static void lcl_textBoxSizeNotify(SwFrameFormat* pFormat)
1065 {
1066     if (SwTextBoxHelper::isTextBox(pFormat, RES_DRAWFRMFMT))
1067     {
1068         // Just notify the textbox that the size has changed, the actual object size is not interesting.
1069         SfxItemSet aResizeSet(pFormat->GetDoc()->GetAttrPool(), svl::Items<RES_FRM_SIZE, RES_FRM_SIZE>{});
1070         SwFormatFrameSize aSize;
1071         aResizeSet.Put(aSize);
1072         SwTextBoxHelper::syncFlyFrameAttr(*pFormat, aResizeSet);
1073     }
1074 }
1075 
1076 // !!!ATTENTION!!! The object may commit suicide!!!
1077 
Changed_(const SdrObject & rObj,SdrUserCallType eType,const tools::Rectangle * pOldBoundRect)1078 void SwDrawContact::Changed_( const SdrObject& rObj,
1079                               SdrUserCallType eType,
1080                               const tools::Rectangle* pOldBoundRect )
1081 {
1082     // suppress handling of nested <SdrObjUserCall> events
1083     NestedUserCallHdl aNestedUserCallHdl( this, eType );
1084     if ( aNestedUserCallHdl.IsNestedUserCall() )
1085     {
1086         aNestedUserCallHdl.AssertNestedUserCall();
1087         return;
1088     }
1089     // do *not* notify, if document is destructing
1090     // #i35912# - do *not* notify for as-character anchored
1091     // drawing objects.
1092     // #i35007#
1093     // improvement: determine as-character anchored object flag only once.
1094     const bool bAnchoredAsChar = ObjAnchoredAsChar();
1095     const bool bNotify = !(GetFormat()->GetDoc()->IsInDtor()) &&
1096                          ( css::text::WrapTextMode_THROUGH != GetFormat()->GetSurround().GetSurround() ) &&
1097                          !bAnchoredAsChar;
1098     switch( eType )
1099     {
1100         case SdrUserCallType::Delete:
1101             {
1102                 if ( bNotify )
1103                 {
1104                     lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1105                     // --> #i36181# - background of 'virtual'
1106                     // drawing objects have also been notified.
1107                     NotifyBackgrdOfAllVirtObjs( pOldBoundRect );
1108                 }
1109                 DisconnectFromLayout( false );
1110                 mbMasterObjCleared = true;
1111                 delete this;
1112                 // --> #i65784# Prevent memory corruption
1113                 aNestedUserCallHdl.DrawContactDeleted();
1114                 break;
1115             }
1116         case SdrUserCallType::Inserted:
1117             {
1118                 if ( mbDisconnectInProgress )
1119                 {
1120                     OSL_FAIL( "<SwDrawContact::Changed_(..)> - Insert event during disconnection from layout is invalid." );
1121                 }
1122                 else
1123                 {
1124                     ConnectToLayout();
1125                     if ( bNotify )
1126                     {
1127                         lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1128                     }
1129                 }
1130                 break;
1131             }
1132         case SdrUserCallType::Removed:
1133             {
1134                 if ( bNotify )
1135                 {
1136                     lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1137                 }
1138                 DisconnectFromLayout( false );
1139                 break;
1140             }
1141         case SdrUserCallType::ChildInserted :
1142         case SdrUserCallType::ChildRemoved :
1143         {
1144             // --> #i113730#
1145             // force layer of controls for group objects containing control objects
1146             if(dynamic_cast< SdrObjGroup* >(maAnchoredDrawObj.DrawObj()))
1147             {
1148                 if(::CheckControlLayer(maAnchoredDrawObj.DrawObj()))
1149                 {
1150                     const IDocumentDrawModelAccess& rIDDMA = static_cast<SwFrameFormat*>(GetRegisteredInNonConst())->getIDocumentDrawModelAccess();
1151                     const SdrLayerID aCurrentLayer(maAnchoredDrawObj.DrawObj()->GetLayer());
1152                     const SdrLayerID aControlLayerID(rIDDMA.GetControlsId());
1153                     const SdrLayerID aInvisibleControlLayerID(rIDDMA.GetInvisibleControlsId());
1154 
1155                     if(aCurrentLayer != aControlLayerID && aCurrentLayer != aInvisibleControlLayerID)
1156                     {
1157                         if ( aCurrentLayer == rIDDMA.GetInvisibleHellId() ||
1158                              aCurrentLayer == rIDDMA.GetInvisibleHeavenId() )
1159                         {
1160                             maAnchoredDrawObj.DrawObj()->SetLayer(aInvisibleControlLayerID);
1161                         }
1162                         else
1163                         {
1164                             maAnchoredDrawObj.DrawObj()->SetLayer(aControlLayerID);
1165                         }
1166                     }
1167                 }
1168             }
1169             [[fallthrough]];
1170         }
1171         case SdrUserCallType::MoveOnly:
1172         case SdrUserCallType::Resize:
1173         case SdrUserCallType::ChildMoveOnly :
1174         case SdrUserCallType::ChildResize :
1175         case SdrUserCallType::ChildChangeAttr :
1176         case SdrUserCallType::ChildDelete :
1177         {
1178             // #i31698# - improvement
1179             // get instance <SwAnchoredDrawObject> only once
1180             const SwAnchoredDrawObject* pAnchoredDrawObj =
1181                 static_cast<const SwAnchoredDrawObject*>( GetAnchoredObj( &rObj ) );
1182 
1183             /* protect against NULL pointer dereferencing */
1184             if(!pAnchoredDrawObj)
1185             {
1186                 break;
1187             }
1188 
1189             // #i26791# - adjust positioning and alignment attributes,
1190             // if positioning of drawing object isn't in progress.
1191             // #i53320# - no adjust of positioning attributes,
1192             // if drawing object isn't positioned.
1193             if ( !pAnchoredDrawObj->IsPositioningInProgress() &&
1194                  !pAnchoredDrawObj->NotYetPositioned() )
1195             {
1196                 // #i34748# - If no last object rectangle is
1197                 // provided by the anchored object, use parameter <pOldBoundRect>.
1198                 const tools::Rectangle& aOldObjRect = pAnchoredDrawObj->GetLastObjRect()
1199                                                ? *(pAnchoredDrawObj->GetLastObjRect())
1200                                                : *pOldBoundRect;
1201                 // #i79400#
1202                 // always invalidate object rectangle inclusive spaces
1203                 pAnchoredDrawObj->InvalidateObjRectWithSpaces();
1204                 // #i41324# - notify background before
1205                 // adjusting position
1206                 if ( bNotify )
1207                 {
1208                     // #i31573# - correction
1209                     // background of given drawing object.
1210                     lcl_NotifyBackgroundOfObj( *this, rObj, &aOldObjRect );
1211                 }
1212                 // #i31698# - determine layout direction
1213                 // via draw frame format.
1214                 SwFrameFormat::tLayoutDir eLayoutDir =
1215                                 pAnchoredDrawObj->GetFrameFormat().GetLayoutDir();
1216                 // use geometry of drawing object
1217                 SwRect aObjRect( rObj.GetSnapRect() );
1218                 // If drawing object is a member of a group, the adjustment
1219                 // of the positioning and the alignment attributes has to
1220                 // be done for the top group object.
1221                 if ( rObj.getParentSdrObjectFromSdrObject() )
1222                 {
1223                     const SdrObject* pGroupObj = rObj.getParentSdrObjectFromSdrObject();
1224                     while ( pGroupObj->getParentSdrObjectFromSdrObject() )
1225                     {
1226                         pGroupObj = pGroupObj->getParentSdrObjectFromSdrObject();
1227                     }
1228                     // use geometry of drawing object
1229                     aObjRect = pGroupObj->GetSnapRect();
1230                 }
1231                 SwTwips nXPosDiff(0);
1232                 SwTwips nYPosDiff(0);
1233                 switch ( eLayoutDir )
1234                 {
1235                     case SwFrameFormat::HORI_L2R:
1236                     {
1237                         nXPosDiff = aObjRect.Left() - aOldObjRect.Left();
1238                         nYPosDiff = aObjRect.Top() - aOldObjRect.Top();
1239                     }
1240                     break;
1241                     case SwFrameFormat::HORI_R2L:
1242                     {
1243                         nXPosDiff = aOldObjRect.Right() - aObjRect.Right();
1244                         nYPosDiff = aObjRect.Top() - aOldObjRect.Top();
1245                     }
1246                     break;
1247                     case SwFrameFormat::VERT_R2L:
1248                     {
1249                         nXPosDiff = aObjRect.Top() - aOldObjRect.Top();
1250                         nYPosDiff = aOldObjRect.Right() - aObjRect.Right();
1251                     }
1252                     break;
1253                     default:
1254                     {
1255                         assert(!"<SwDrawContact::Changed_(..)> - unsupported layout direction");
1256                     }
1257                 }
1258                 SfxItemSet aSet( GetFormat()->GetDoc()->GetAttrPool(),
1259                                  svl::Items<RES_VERT_ORIENT, RES_HORI_ORIENT>{} );
1260                 const SwFormatVertOrient& rVert = GetFormat()->GetVertOrient();
1261                 if ( nYPosDiff != 0 )
1262                 {
1263 
1264                     if ( rVert.GetRelationOrient() == text::RelOrientation::CHAR ||
1265                          rVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
1266                     {
1267                         nYPosDiff = -nYPosDiff;
1268                     }
1269                     aSet.Put( SwFormatVertOrient( rVert.GetPos()+nYPosDiff,
1270                                                text::VertOrientation::NONE,
1271                                                rVert.GetRelationOrient() ) );
1272                 }
1273 
1274                 const SwFormatHoriOrient& rHori = GetFormat()->GetHoriOrient();
1275                 if ( !bAnchoredAsChar && nXPosDiff != 0 )
1276                 {
1277                     aSet.Put( SwFormatHoriOrient( rHori.GetPos()+nXPosDiff,
1278                                                text::HoriOrientation::NONE,
1279                                                rHori.GetRelationOrient() ) );
1280                 }
1281 
1282                 if ( nYPosDiff ||
1283                      ( !bAnchoredAsChar && nXPosDiff != 0 ) )
1284                 {
1285                     GetFormat()->GetDoc()->SetFlyFrameAttr( *(GetFormat()), aSet );
1286                     // keep new object rectangle, to avoid multiple
1287                     // changes of the attributes by multiple event from
1288                     // the drawing layer - e.g. group objects and its members
1289                     // #i34748# - use new method
1290                     // <SwAnchoredDrawObject::SetLastObjRect(..)>.
1291                     const_cast<SwAnchoredDrawObject*>(pAnchoredDrawObj)
1292                                     ->SetLastObjRect( aObjRect.SVRect() );
1293                 }
1294                 else if ( aObjRect.SSize() != aOldObjRect.GetSize() )
1295                 {
1296                     InvalidateObjs_();
1297                     // #i35007# - notify anchor frame
1298                     // of as-character anchored object
1299                     if ( bAnchoredAsChar )
1300                     {
1301                         SwFrame* pAnchorFrame = const_cast<SwAnchoredDrawObject*>(pAnchoredDrawObj)->AnchorFrame();
1302                         if(pAnchorFrame)
1303                         {
1304                             pAnchorFrame->Prepare( PREP_FLY_ATTR_CHG, GetFormat() );
1305                         }
1306                     }
1307 
1308                     lcl_textBoxSizeNotify(GetFormat());
1309                 }
1310                 else if (eType == SdrUserCallType::Resize)
1311                     // Even if the bounding box of the shape didn't change,
1312                     // notify about the size change, as an adjustment change
1313                     // may affect the size of the underlying textbox.
1314                     lcl_textBoxSizeNotify(GetFormat());
1315             }
1316         }
1317         break;
1318         case SdrUserCallType::ChangeAttr:
1319             if ( bNotify )
1320             {
1321                 lcl_NotifyBackgroundOfObj( *this, rObj, pOldBoundRect );
1322             }
1323             break;
1324         default:
1325             break;
1326     }
1327 }
1328 
1329 namespace
1330 {
lcl_getAnchorFormat(const SfxPoolItem & _rItem)1331     const SwFormatAnchor* lcl_getAnchorFormat( const SfxPoolItem& _rItem )
1332     {
1333         sal_uInt16 nWhich = _rItem.Which();
1334         const SwFormatAnchor* pAnchorFormat = nullptr;
1335         if ( RES_ATTRSET_CHG == nWhich )
1336         {
1337             static_cast<const SwAttrSetChg&>(_rItem).GetChgSet()->
1338                 GetItemState( RES_ANCHOR, false, reinterpret_cast<const SfxPoolItem**>(&pAnchorFormat) );
1339         }
1340         else if ( RES_ANCHOR == nWhich )
1341         {
1342             pAnchorFormat = &static_cast<const SwFormatAnchor&>(_rItem);
1343         }
1344         return pAnchorFormat;
1345     }
1346 }
1347 
SwClientNotify(const SwModify & rMod,const SfxHint & rHint)1348 void SwDrawContact::SwClientNotify(const SwModify& rMod, const SfxHint& rHint)
1349 {
1350     SwClient::SwClientNotify(rMod, rHint); // needed as SwContact::SwClientNotify doesn't explicitly call SwClient::SwClientNotify
1351     SwContact::SwClientNotify(rMod, rHint);
1352     if (auto pLegacyHint = dynamic_cast<const sw::LegacyModifyHint*>(&rHint))
1353     {
1354         SAL_WARN_IF(mbDisconnectInProgress, "sw.core", "<SwDrawContact::Modify(..)> called during disconnection.");
1355 
1356         const SfxPoolItem* pNew = pLegacyHint->m_pNew;
1357         sal_uInt16 nWhich = pNew ? pNew->Which() : 0;
1358         if(const SwFormatAnchor* pNewAnchorFormat = pNew ? lcl_getAnchorFormat(*pNew) : nullptr)
1359         {
1360             // Do not respond to a Reset Anchor!
1361             if(GetFormat()->GetAttrSet().GetItemState(RES_ANCHOR, false) == SfxItemState::SET)
1362             {
1363                 // no connect to layout during disconnection
1364                 if(!mbDisconnectInProgress)
1365                 {
1366                     // determine old object rectangle of 'master' drawing object
1367                     // for notification
1368                     const tools::Rectangle* pOldRect = nullptr;
1369                     tools::Rectangle aOldRect;
1370                     if(GetAnchorFrame())
1371                     {
1372                         // --> #i36181# - include spacing in object
1373                         // rectangle for notification.
1374                         aOldRect = maAnchoredDrawObj.GetObjRectWithSpaces().SVRect();
1375                         pOldRect = &aOldRect;
1376                     }
1377                     // re-connect to layout due to anchor format change
1378                     ConnectToLayout(pNewAnchorFormat);
1379                     // notify background of drawing objects
1380                     lcl_NotifyBackgroundOfObj(*this, *GetMaster(), pOldRect);
1381                     NotifyBackgrdOfAllVirtObjs(pOldRect);
1382 
1383                     const SwFormatAnchor* pOldAnchorFormat = pLegacyHint->m_pOld ? lcl_getAnchorFormat(*pLegacyHint->m_pOld) : nullptr;
1384                     if(!pOldAnchorFormat || (pOldAnchorFormat->GetAnchorId() != pNewAnchorFormat->GetAnchorId()))
1385                     {
1386                         if(maAnchoredDrawObj.DrawObj())
1387                         {
1388                             // --> #i102752#
1389                             // assure that a ShapePropertyChangeNotifier exists
1390                             maAnchoredDrawObj.DrawObj()->notifyShapePropertyChange(svx::ShapeProperty::TextDocAnchor);
1391                         }
1392                         else
1393                             SAL_WARN("sw.core", "SwDrawContact::Modify: no draw object here?");
1394                     }
1395                 }
1396             }
1397             else
1398                 DisconnectFromLayout();
1399         }
1400         else if (nWhich == RES_REMOVE_UNO_OBJECT)
1401         {} // nothing to do
1402         // --> #i62875# - no further notification, if not connected to Writer layout
1403         else if ( maAnchoredDrawObj.GetAnchorFrame() &&
1404                   maAnchoredDrawObj.GetDrawObj()->GetUserCall() )
1405         {
1406             bool bUpdateSortedObjsList(false);
1407             switch(nWhich)
1408             {
1409                 case RES_UL_SPACE:
1410                 case RES_LR_SPACE:
1411                 case RES_HORI_ORIENT:
1412                 case RES_VERT_ORIENT:
1413                 case RES_FOLLOW_TEXT_FLOW: // #i28701# - add attribute 'Follow text flow'
1414                     break;
1415                 case RES_SURROUND:
1416                 case RES_OPAQUE:
1417                 case RES_WRAP_INFLUENCE_ON_OBJPOS:
1418                     // --> #i28701# - on change of wrapping style, hell|heaven layer,
1419                     // or wrapping style influence an update of the <SwSortedObjs> list,
1420                     // the drawing object is registered in, has to be performed. This is triggered
1421                     // by the 1st parameter of method call <InvalidateObjs_(..)>.
1422                     bUpdateSortedObjsList = true;
1423                     break;
1424                 case RES_ATTRSET_CHG: // #i35443#
1425                 {
1426                     auto pChgSet = static_cast<const SwAttrSetChg*>(pNew)->GetChgSet();
1427                     if(pChgSet->GetItemState(RES_SURROUND, false) == SfxItemState::SET ||
1428                             pChgSet->GetItemState(RES_OPAQUE, false) == SfxItemState::SET ||
1429                             pChgSet->GetItemState(RES_WRAP_INFLUENCE_ON_OBJPOS, false) == SfxItemState::SET)
1430                         bUpdateSortedObjsList = true;
1431                 }
1432                 break;
1433                 default:
1434                     assert(!"<SwDraw Contact::Modify(..)> - unhandled attribute?");
1435             }
1436             lcl_NotifyBackgroundOfObj(*this, *GetMaster(), nullptr);
1437             NotifyBackgrdOfAllVirtObjs(nullptr);
1438             InvalidateObjs_(bUpdateSortedObjsList);
1439         }
1440 
1441         // #i51474#
1442         GetAnchoredObj(nullptr)->ResetLayoutProcessBools();
1443     }
1444     else if (auto pDrawFrameFormatHint = dynamic_cast<const sw::DrawFrameFormatHint*>(&rHint))
1445     {
1446         switch(pDrawFrameFormatHint->m_eId)
1447         {
1448             case sw::DrawFrameFormatHintId::DYING:
1449                 delete this;
1450                 break;
1451             case sw::DrawFrameFormatHintId::PREPPASTING:
1452                 MoveObjToVisibleLayer(GetMaster());
1453                 break;
1454             case sw::DrawFrameFormatHintId::PREP_INSERT_FLY:
1455                 InsertMasterIntoDrawPage();
1456                 // #i40845# - follow-up of #i35635#
1457                 // move object to visible layer
1458                 MoveObjToVisibleLayer(GetMaster());
1459                 // tdf#135661 InsertMasterIntoDrawPage may have created a new
1460                 // SwXShape with null m_pFormat; fix that
1461                 SwXShape::AddExistingShapeToFormat(*GetMaster());
1462                 break;
1463             case sw::DrawFrameFormatHintId::PREP_DELETE_FLY:
1464                 RemoveMasterFromDrawPage();
1465                 break;
1466             case sw::DrawFrameFormatHintId::PAGE_OUT_OF_BOUNDS:
1467             case sw::DrawFrameFormatHintId::DELETE_FRAMES:
1468                 DisconnectFromLayout();
1469                 break;
1470             case sw::DrawFrameFormatHintId::MAKE_FRAMES:
1471                  ConnectToLayout();
1472                  break;
1473             case sw::DrawFrameFormatHintId::POST_RESTORE_FLY_ANCHOR:
1474                 GetAnchoredObj(GetMaster())->MakeObjPos();
1475                 break;
1476             default:
1477                 ;
1478         }
1479     }
1480     else if (auto pCheckDrawFrameFormatLayerHint = dynamic_cast<const sw::CheckDrawFrameFormatLayerHint*>(&rHint))
1481     {
1482         *(pCheckDrawFrameFormatLayerHint->m_bCheckControlLayer) |= (GetMaster() && CheckControlLayer(GetMaster()));
1483     }
1484     else if (auto pContactChangedHint = dynamic_cast<const sw::ContactChangedHint*>(&rHint))
1485     {
1486         if(!*pContactChangedHint->m_ppObject)
1487             *pContactChangedHint->m_ppObject = GetMaster();
1488         auto pObject = *pContactChangedHint->m_ppObject;
1489         Changed(*pObject, SdrUserCallType::Delete, pObject->GetLastBoundRect());
1490     }
1491     else if (auto pDrawFormatLayoutCopyHint = dynamic_cast<const sw::DrawFormatLayoutCopyHint*>(&rHint))
1492     {
1493         const SwDrawFrameFormat& rFormat = static_cast<const SwDrawFrameFormat&>(rMod);
1494         new SwDrawContact(
1495                 &pDrawFormatLayoutCopyHint->m_rDestFormat,
1496                 pDrawFormatLayoutCopyHint->m_rDestDoc.CloneSdrObj(
1497                         *GetMaster(),
1498                         pDrawFormatLayoutCopyHint->m_rDestDoc.IsCopyIsMove() && &pDrawFormatLayoutCopyHint->m_rDestDoc == rFormat.GetDoc()));
1499         // #i49730# - notify draw frame format that position attributes are
1500         // already set, if the position attributes are already set at the
1501         // source draw frame format.
1502         if(rFormat.IsPosAttrSet())
1503             pDrawFormatLayoutCopyHint->m_rDestFormat.PosAttrSet();
1504     }
1505     else if (auto pRestoreFlyAnchorHint = dynamic_cast<const sw::RestoreFlyAnchorHint*>(&rHint))
1506     {
1507         SdrObject* pObj = GetMaster();
1508         if(GetAnchorFrame() && !pObj->IsInserted())
1509         {
1510             auto pDrawModel = const_cast<SwDrawFrameFormat&>(static_cast<const SwDrawFrameFormat&>(rMod)).GetDoc()->getIDocumentDrawModelAccess().GetDrawModel();
1511             assert(pDrawModel);
1512             pDrawModel->GetPage(0)->InsertObject(pObj);
1513         }
1514         pObj->SetRelativePos(pRestoreFlyAnchorHint->m_aPos);
1515     }
1516     else if (auto pCreatePortionHint = dynamic_cast<const sw::CreatePortionHint*>(&rHint))
1517     {
1518         if(*pCreatePortionHint->m_ppContact)
1519             return;
1520         *pCreatePortionHint->m_ppContact = this; // This is kind of ridiculous: the FrameFormat doesn't even hold a pointer to the contact itself,  but here we are leaking it out randomly
1521         if(!GetAnchorFrame())
1522         {
1523             // No direct positioning needed any more
1524             ConnectToLayout();
1525             // Move object to visible layer
1526             MoveObjToVisibleLayer(GetMaster());
1527         }
1528     }
1529     else if (auto pCollectTextObjectsHint = dynamic_cast<const sw::CollectTextObjectsHint*>(&rHint))
1530     {
1531         auto pSdrO = GetMaster();
1532         if(!pSdrO)
1533             return;
1534         if(dynamic_cast<const SdrObjGroup*>(pSdrO))
1535         {
1536             SdrObjListIter aListIter(*pSdrO, SdrIterMode::DeepNoGroups);
1537             //iterate inside of a grouped object
1538             while(aListIter.IsMore())
1539             {
1540                 SdrObject* pSdrOElement = aListIter.Next();
1541                 auto pTextObj = const_cast<SdrTextObj*>(dynamic_cast<const SdrTextObj*>(pSdrOElement));
1542                 if(pTextObj && pTextObj->HasText())
1543                     pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
1544             }
1545         }
1546         else if(auto pTextObj = const_cast<SdrTextObj*>(dynamic_cast<const SdrTextObj*>(pSdrO)))
1547         {
1548             if(pTextObj->HasText())
1549                 pCollectTextObjectsHint->m_rTextObjects.push_back(pTextObj);
1550         }
1551     }
1552     else if (auto pGetZOrdnerHint = dynamic_cast<const sw::GetZOrderHint*>(&rHint))
1553     {
1554         auto pFormat(dynamic_cast<const SwFrameFormat*>(&rMod));
1555         if(pFormat->Which() == RES_DRAWFRMFMT)
1556             pGetZOrdnerHint->m_rnZOrder = GetMaster()->GetOrdNum();
1557     }
1558     else if (auto pConnectedHint = dynamic_cast<const sw::GetObjectConnectedHint*>(&rHint))
1559     {
1560         pConnectedHint->m_risConnected |= (GetAnchorFrame() != nullptr);
1561     }
1562 }
1563 
1564 // #i26791#
1565 // #i28701# - added parameter <_bUpdateSortedObjsList>
InvalidateObjs_(const bool _bUpdateSortedObjsList)1566 void SwDrawContact::InvalidateObjs_( const bool _bUpdateSortedObjsList )
1567 {
1568     for(const auto& rpDrawVirtObj : maDrawVirtObjs)
1569     // invalidate position of existing 'virtual' drawing objects
1570     {
1571         SwDrawVirtObj* pDrawVirtObj(rpDrawVirtObj.get());
1572         // #i33313# - invalidation only for connected
1573         // 'virtual' drawing objects
1574         if ( pDrawVirtObj->IsConnected() )
1575         {
1576             pDrawVirtObj->AnchoredObj().InvalidateObjPos();
1577             // #i28701#
1578             if ( _bUpdateSortedObjsList )
1579             {
1580                 pDrawVirtObj->AnchoredObj().UpdateObjInSortedList();
1581             }
1582         }
1583     }
1584 
1585     // invalidate position of 'master' drawing object
1586     SwAnchoredObject* pAnchoredObj = GetAnchoredObj( nullptr );
1587     pAnchoredObj->InvalidateObjPos();
1588     // #i28701#
1589     if ( _bUpdateSortedObjsList )
1590     {
1591         pAnchoredObj->UpdateObjInSortedList();
1592     }
1593 }
1594 
DisconnectFromLayout(bool _bMoveMasterToInvisibleLayer)1595 void SwDrawContact::DisconnectFromLayout( bool _bMoveMasterToInvisibleLayer )
1596 {
1597     mbDisconnectInProgress = true;
1598 
1599     // --> #i36181# - notify background of drawing object
1600     if ( _bMoveMasterToInvisibleLayer &&
1601          !(GetFormat()->GetDoc()->IsInDtor()) &&
1602          GetAnchorFrame() && !GetAnchorFrame()->IsInDtor() )
1603     {
1604         const tools::Rectangle aOldRect( maAnchoredDrawObj.GetObjRectWithSpaces().SVRect() );
1605         lcl_NotifyBackgroundOfObj( *this, *GetMaster(), &aOldRect );
1606         NotifyBackgrdOfAllVirtObjs( &aOldRect );
1607     }
1608 
1609     // remove 'virtual' drawing objects from writer
1610     // layout and from drawing page
1611     for(auto& rpVirtDrawObj : maDrawVirtObjs)
1612     {
1613         rpVirtDrawObj->RemoveFromWriterLayout();
1614         rpVirtDrawObj->RemoveFromDrawingPage();
1615     }
1616 
1617     if ( maAnchoredDrawObj.GetAnchorFrame() )
1618     {
1619         maAnchoredDrawObj.AnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
1620     }
1621 
1622     if ( _bMoveMasterToInvisibleLayer && GetMaster() && GetMaster()->IsInserted() )
1623     {
1624         SdrViewIter aIter( GetMaster() );
1625         for( SdrView* pView = aIter.FirstView(); pView;
1626                     pView = aIter.NextView() )
1627         {
1628             pView->MarkObj( GetMaster(), pView->GetSdrPageView(), true );
1629         }
1630 
1631         // Instead of removing 'master' object from drawing page, move the
1632         // 'master' drawing object into the corresponding invisible layer.
1633         {
1634             //static_cast<SwFrameFormat*>(GetRegisteredIn())->getIDocumentDrawModelAccess()->GetDrawModel()->GetPage(0)->
1635             //                            RemoveObject( GetMaster()->GetOrdNum() );
1636             // #i18447# - in order to consider group object correct
1637             // use new method <SwDrawContact::MoveObjToInvisibleLayer(..)>
1638             MoveObjToInvisibleLayer( GetMaster() );
1639         }
1640     }
1641 
1642     mbDisconnectInProgress = false;
1643 }
1644 
1645 /// method to remove 'master' drawing object from drawing page.
RemoveMasterFromDrawPage()1646 void SwDrawContact::RemoveMasterFromDrawPage()
1647 {
1648     if ( GetMaster() )
1649     {
1650         GetMaster()->SetUserCall( nullptr );
1651         if ( GetMaster()->IsInserted() )
1652         {
1653             static_cast<SwFrameFormat*>(GetRegisteredIn())->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)->
1654                                         RemoveObject( GetMaster()->GetOrdNum() );
1655         }
1656     }
1657 }
1658 
1659 // disconnect for a dedicated drawing object - could be 'master' or 'virtual'.
1660 // a 'master' drawing object will disconnect a 'virtual' drawing object
1661 // in order to take its place.
1662 // #i19919# - no special case, if drawing object isn't in
1663 // page header/footer, in order to get drawing objects in repeating table headers
1664 // also working.
DisconnectObjFromLayout(SdrObject * _pDrawObj)1665 void SwDrawContact::DisconnectObjFromLayout( SdrObject* _pDrawObj )
1666 {
1667     if ( dynamic_cast<const SwDrawVirtObj*>( _pDrawObj) !=  nullptr )
1668     {
1669         SwDrawVirtObj* pDrawVirtObj = static_cast<SwDrawVirtObj*>(_pDrawObj);
1670         pDrawVirtObj->RemoveFromWriterLayout();
1671         pDrawVirtObj->RemoveFromDrawingPage();
1672     }
1673     else
1674     {
1675         const auto ppVirtDrawObj(std::find_if(maDrawVirtObjs.begin(), maDrawVirtObjs.end(),
1676                 [] (const SwDrawVirtObjPtr& pObj) { return pObj->IsConnected(); }));
1677 
1678         if(ppVirtDrawObj != maDrawVirtObjs.end())
1679         {
1680             // replace found 'virtual' drawing object by 'master' drawing
1681             // object and disconnect the 'virtual' one
1682             SwDrawVirtObj* pDrawVirtObj(ppVirtDrawObj->get());
1683             SwFrame* pNewAnchorFrameOfMaster = pDrawVirtObj->AnchorFrame();
1684             // disconnect 'virtual' drawing object
1685             pDrawVirtObj->RemoveFromWriterLayout();
1686             pDrawVirtObj->RemoveFromDrawingPage();
1687             // disconnect 'master' drawing object from current frame
1688             GetAnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
1689             // re-connect 'master' drawing object to frame of found 'virtual'
1690             // drawing object.
1691             pNewAnchorFrameOfMaster->AppendDrawObj( maAnchoredDrawObj );
1692         }
1693         else
1694         {
1695             // no connected 'virtual' drawing object found. Thus, disconnect
1696             // completely from layout.
1697             DisconnectFromLayout();
1698         }
1699     }
1700 }
1701 
lcl_GetFlyInContentAnchor(SwTextFrame * _pProposedAnchorFrame,SwPosition const & rAnchorPos)1702 static SwTextFrame* lcl_GetFlyInContentAnchor( SwTextFrame* _pProposedAnchorFrame,
1703                                    SwPosition const& rAnchorPos)
1704 {
1705     SwTextFrame* pAct = _pProposedAnchorFrame;
1706     SwTextFrame* pTmp;
1707     TextFrameIndex const nTextOffset(_pProposedAnchorFrame->MapModelToViewPos(rAnchorPos));
1708     do
1709     {
1710         pTmp = pAct;
1711         pAct = pTmp->GetFollow();
1712     }
1713     while (pAct && nTextOffset >= pAct->GetOfst());
1714     return pTmp;
1715 }
1716 
ConnectToLayout(const SwFormatAnchor * pAnch)1717 void SwDrawContact::ConnectToLayout( const SwFormatAnchor* pAnch )
1718 {
1719     // *no* connect to layout during disconnection from layout.
1720     if ( mbDisconnectInProgress )
1721     {
1722         OSL_FAIL( "<SwDrawContact::ConnectToLayout(..)> called during disconnection.");
1723         return;
1724     }
1725 
1726     // --> #i33909# - *no* connect to layout, if 'master' drawing
1727     // object isn't inserted in the drawing page
1728     if ( !GetMaster()->IsInserted() )
1729     {
1730         OSL_FAIL( "<SwDrawContact::ConnectToLayout(..)> - master drawing object not inserted -> no connect to layout. Please inform od@openoffice.org" );
1731         return;
1732     }
1733 
1734     SwFrameFormat* pDrawFrameFormat = static_cast<SwFrameFormat*>(GetRegisteredIn());
1735 
1736     if( !pDrawFrameFormat->getIDocumentLayoutAccess().GetCurrentViewShell() )
1737         return;
1738 
1739     // remove 'virtual' drawing objects from writer
1740     // layout and from drawing page, and remove 'master' drawing object from
1741     // writer layout - 'master' object will remain in drawing page.
1742     DisconnectFromLayout( false );
1743 
1744     if ( !pAnch )
1745     {
1746         pAnch = &(pDrawFrameFormat->GetAnchor());
1747     }
1748 
1749     switch ( pAnch->GetAnchorId() )
1750     {
1751         case RndStdIds::FLY_AT_PAGE:
1752                 {
1753                 sal_uInt16 nPgNum = pAnch->GetPageNum();
1754                 SwViewShell *pShell = pDrawFrameFormat->getIDocumentLayoutAccess().GetCurrentViewShell();
1755                 if( !pShell )
1756                     break;
1757                 SwRootFrame* pRoot = pShell->GetLayout();
1758                 SwPageFrame *pPage = static_cast<SwPageFrame*>(pRoot->Lower());
1759 
1760                 for ( sal_uInt16 i = 1; i < nPgNum && pPage; ++i )
1761                 {
1762                     pPage = static_cast<SwPageFrame*>(pPage->GetNext());
1763                 }
1764 
1765                 if ( pPage )
1766                 {
1767                     pPage->AppendDrawObj( maAnchoredDrawObj );
1768                 }
1769                 else
1770                     //Looks stupid but is allowed (compare SwFEShell::SetPageObjsNewPage)
1771                     pRoot->SetAssertFlyPages();
1772                 }
1773                 break;
1774 
1775         case RndStdIds::FLY_AT_CHAR:
1776         case RndStdIds::FLY_AT_PARA:
1777         case RndStdIds::FLY_AT_FLY:
1778         case RndStdIds::FLY_AS_CHAR:
1779             {
1780                 if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1781                 {
1782                     ClrContourCache( GetMaster() );
1783                 }
1784                 // support drawing objects in header/footer,
1785                 // but not control objects:
1786                 // anchor at first found frame the 'master' object and
1787                 // at the following frames 'virtual' drawing objects.
1788                 // Note: method is similar to <SwFlyFrameFormat::MakeFrames(..)>
1789                 SwModify *pModify = nullptr;
1790                 if( pAnch->GetContentAnchor() )
1791                 {
1792                     if ( pAnch->GetAnchorId() == RndStdIds::FLY_AT_FLY )
1793                     {
1794                         SwNodeIndex aIdx( pAnch->GetContentAnchor()->nNode );
1795                         SwContentNode* pCNd = pDrawFrameFormat->GetDoc()->GetNodes().GoNext( &aIdx );
1796                         if (SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*pCNd).First())
1797                             pModify = pCNd;
1798                         else
1799                         {
1800                             const SwNodeIndex& rIdx = pAnch->GetContentAnchor()->nNode;
1801                             SwFrameFormats& rFormats = *(pDrawFrameFormat->GetDoc()->GetSpzFrameFormats());
1802                             for( auto pFlyFormat : rFormats )
1803                             {
1804                                 if( pFlyFormat->GetContent().GetContentIdx() &&
1805                                     rIdx == *(pFlyFormat->GetContent().GetContentIdx()) )
1806                                 {
1807                                     pModify = pFlyFormat;
1808                                     break;
1809                                 }
1810                             }
1811                         }
1812                     }
1813                     else
1814                     {
1815                         pModify = pAnch->GetContentAnchor()->nNode.GetNode().GetContentNode();
1816                     }
1817                 }
1818 
1819                 // #i29199# - It is possible, that
1820                 // the anchor doesn't exist - E.g., reordering the
1821                 // sub-documents in a master document.
1822                 // Note: The anchor will be inserted later.
1823                 if ( !pModify )
1824                 {
1825                     // break to end of the current switch case.
1826                     break;
1827                 }
1828 
1829                 SwIterator<SwFrame, SwModify, sw::IteratorMode::UnwrapMulti> aIter(*pModify);
1830                 SwFrame* pAnchorFrameOfMaster = nullptr;
1831                 for( SwFrame *pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
1832                 {
1833                     // append drawing object, if
1834                     // (1) proposed anchor frame isn't a follow and
1835                     // (2) drawing object isn't a control object to be anchored
1836                     //     in header/footer.
1837                     bool bAdd = ( !pFrame->IsContentFrame() ||
1838                                         !static_cast<SwContentFrame*>(pFrame)->IsFollow() ) &&
1839                                       ( !::CheckControlLayer( GetMaster() ) ||
1840                                         !pFrame->FindFooterOrHeader() );
1841 
1842                     if (bAdd && RndStdIds::FLY_AT_FLY != pAnch->GetAnchorId())
1843                     {
1844                         assert(pFrame->IsTextFrame());
1845                         bAdd = IsAnchoredObjShown(*static_cast<SwTextFrame*>(pFrame), *pAnch);
1846                     }
1847 
1848                     if( bAdd )
1849                     {
1850                         if ( RndStdIds::FLY_AT_FLY == pAnch->GetAnchorId() && !pFrame->IsFlyFrame() )
1851                         {
1852                             pFrame = pFrame->FindFlyFrame();
1853                             assert(pFrame);
1854                         }
1855 
1856                         // find correct follow for as character anchored objects
1857                         if ((pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR) &&
1858                              pFrame->IsTextFrame() )
1859                         {
1860                             pFrame = lcl_GetFlyInContentAnchor(
1861                                         static_cast<SwTextFrame*>(pFrame),
1862                                         *pAnch->GetContentAnchor());
1863                         }
1864 
1865                         if ( !pAnchorFrameOfMaster )
1866                         {
1867                             // append 'master' drawing object
1868                             pAnchorFrameOfMaster = pFrame;
1869                             pFrame->AppendDrawObj( maAnchoredDrawObj );
1870                         }
1871                         else
1872                         {
1873                             // append 'virtual' drawing object
1874                             SwDrawVirtObj* pDrawVirtObj = AddVirtObj();
1875                             if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1876                             {
1877                                 ClrContourCache( pDrawVirtObj );
1878                             }
1879                             pFrame->AppendDrawObj( pDrawVirtObj->AnchoredObj() );
1880 
1881                             pDrawVirtObj->ActionChanged();
1882                         }
1883 
1884                         if ( pAnch->GetAnchorId() == RndStdIds::FLY_AS_CHAR )
1885                         {
1886                             pFrame->InvalidatePrt();
1887                         }
1888                     }
1889                 }
1890             }
1891             break;
1892         default:
1893             assert(!"Unknown Anchor.");
1894             break;
1895     }
1896     if ( GetAnchorFrame() )
1897     {
1898         ::setContextWritingMode( maAnchoredDrawObj.DrawObj(), GetAnchorFrame() );
1899         // #i26791# - invalidate objects instead of direct positioning
1900         InvalidateObjs_();
1901     }
1902 }
1903 
1904 /// insert 'master' drawing object into drawing page
InsertMasterIntoDrawPage()1905 void SwDrawContact::InsertMasterIntoDrawPage()
1906 {
1907     if ( !GetMaster()->IsInserted() )
1908     {
1909         GetFormat()->getIDocumentDrawModelAccess().GetDrawModel()->GetPage(0)
1910                 ->InsertObject( GetMaster(), GetMaster()->GetOrdNumDirect() );
1911     }
1912     GetMaster()->SetUserCall( this );
1913 }
1914 
FindPage(const SwRect & rRect)1915 SwPageFrame* SwDrawContact::FindPage( const SwRect &rRect )
1916 {
1917     // --> #i28701# - use method <GetPageFrame()>
1918     SwPageFrame* pPg = GetPageFrame();
1919     if ( !pPg && GetAnchorFrame() )
1920         pPg = GetAnchorFrame()->FindPageFrame();
1921     if ( pPg )
1922         pPg = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(::FindPage( rRect, pPg )));
1923     return pPg;
1924 }
1925 
ChkPage()1926 void SwDrawContact::ChkPage()
1927 {
1928     if ( mbDisconnectInProgress )
1929     {
1930         OSL_FAIL( "<SwDrawContact::ChkPage()> called during disconnection." );
1931         return;
1932     }
1933 
1934     // --> #i28701#
1935     SwPageFrame* pPg = ( maAnchoredDrawObj.GetAnchorFrame() &&
1936                        maAnchoredDrawObj.GetAnchorFrame()->IsPageFrame() )
1937                      ? GetPageFrame()
1938                      : FindPage( GetMaster()->GetCurrentBoundRect() );
1939     if ( GetPageFrame() != pPg )
1940     {
1941         // if drawing object is anchor in header/footer a change of the page
1942         // is a dramatic change. Thus, completely re-connect to the layout
1943         if ( maAnchoredDrawObj.GetAnchorFrame() &&
1944              maAnchoredDrawObj.GetAnchorFrame()->FindFooterOrHeader() )
1945         {
1946             ConnectToLayout();
1947         }
1948         else
1949         {
1950             // --> #i28701# - use methods <GetPageFrame()> and <SetPageFrame>
1951             if ( GetPageFrame() )
1952                 GetPageFrame()->RemoveDrawObjFromPage( maAnchoredDrawObj );
1953             pPg->AppendDrawObjToPage( maAnchoredDrawObj );
1954             maAnchoredDrawObj.SetPageFrame( pPg );
1955         }
1956     }
1957 }
1958 
1959 // Important note:
1960 // method is called by method <SwDPage::ReplaceObject(..)>, which called its
1961 // corresponding superclass method <FmFormPage::ReplaceObject(..)>.
1962 // Note: 'master' drawing object *has* to be connected to layout triggered
1963 //       by the caller of this, if method is called.
ChangeMasterObject(SdrObject * pNewMaster)1964 void SwDrawContact::ChangeMasterObject(SdrObject* pNewMaster)
1965 {
1966     DisconnectFromLayout( false );
1967     // consider 'virtual' drawing objects
1968     RemoveAllVirtObjs();
1969 
1970     GetMaster()->SetUserCall( nullptr );
1971     if(pNewMaster)
1972         maAnchoredDrawObj.SetDrawObj(*pNewMaster);
1973     else
1974         mbMasterObjCleared = true;
1975     GetMaster()->SetUserCall( this );
1976 
1977     InvalidateObjs_();
1978 }
1979 
1980 /// get data collection of anchored objects, handled by with contact
GetAnchoredObjs(std::vector<SwAnchoredObject * > & o_rAnchoredObjs) const1981 void SwDrawContact::GetAnchoredObjs(std::vector<SwAnchoredObject*>& o_rAnchoredObjs) const
1982 {
1983     o_rAnchoredObjs.push_back(const_cast<SwAnchoredDrawObject*>(&maAnchoredDrawObj));
1984 
1985     for(auto& rpDrawVirtObj : maDrawVirtObjs)
1986         o_rAnchoredObjs.push_back(&rpDrawVirtObj->AnchoredObj());
1987 }
1988 
1989 // AW: own sdr::contact::ViewContact (VC) sdr::contact::ViewObjectContact (VOC) needed
1990 // since offset is defined different from SdrVirtObj's sdr::contact::ViewContactOfVirtObj.
1991 // For paint, that offset is used by setting at the OutputDevice; for primitives this is
1992 // not possible since we have no OutputDevice, but define the geometry itself.
1993 
1994 namespace sdr
1995 {
1996     namespace contact
1997     {
1998         class VOCOfDrawVirtObj : public ViewObjectContactOfSdrObj
1999         {
2000         protected:
2001             /**
2002              * This method is responsible for creating the graphical visualisation data which is
2003              * stored/cached in the local primitive. Default gets view-independent Primitive from
2004              * the ViewContact using ViewContact::getViewIndependentPrimitive2DContainer(), takes
2005              * care of visibility, handles glue and ghosted.
2006              *
2007              * This method will not handle included hierarchies and not check geometric visibility.
2008              */
2009             virtual drawinglayer::primitive2d::Primitive2DContainer createPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const override;
2010 
2011         public:
VOCOfDrawVirtObj(ObjectContact & rObjectContact,ViewContact & rViewContact)2012             VOCOfDrawVirtObj(ObjectContact& rObjectContact, ViewContact& rViewContact)
2013             :   ViewObjectContactOfSdrObj(rObjectContact, rViewContact)
2014             {
2015             }
2016         };
2017 
2018         class VCOfDrawVirtObj : public ViewContactOfVirtObj
2019         {
2020         protected:
2021             /** Create an Object-Specific ViewObjectContact, set ViewContact and ObjectContact.
2022              *
2023              * Always needs to return something. Default is to create a standard ViewObjectContact
2024              * containing the given ObjectContact and *this.
2025              */
2026             virtual ViewObjectContact& CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact) override;
2027 
2028         public:
2029             /// basic constructor, used from SdrObject.
VCOfDrawVirtObj(SwDrawVirtObj & rObj)2030             explicit VCOfDrawVirtObj(SwDrawVirtObj& rObj)
2031             :   ViewContactOfVirtObj(rObj)
2032             {
2033             }
2034 
2035             /// access to SwDrawVirtObj
GetSwDrawVirtObj() const2036             SwDrawVirtObj& GetSwDrawVirtObj() const
2037             {
2038                 return static_cast<SwDrawVirtObj&>(mrObject);
2039             }
2040         };
2041     } // end of namespace contact
2042 } // end of namespace sdr
2043 
2044 namespace sdr
2045 {
2046     namespace contact
2047     {
2048         /// recursively collect primitive data from given VOC with given offset
impAddPrimitivesFromGroup(const ViewObjectContact & rVOC,const basegfx::B2DHomMatrix & rOffsetMatrix,const DisplayInfo & rDisplayInfo,drawinglayer::primitive2d::Primitive2DContainer & rxTarget)2049         static void impAddPrimitivesFromGroup(const ViewObjectContact& rVOC, const basegfx::B2DHomMatrix& rOffsetMatrix, const DisplayInfo& rDisplayInfo, drawinglayer::primitive2d::Primitive2DContainer& rxTarget)
2050         {
2051             const sal_uInt32 nSubHierarchyCount(rVOC.GetViewContact().GetObjectCount());
2052 
2053             for(sal_uInt32 a(0); a < nSubHierarchyCount; a++)
2054             {
2055                 const ViewObjectContact& rCandidate(rVOC.GetViewContact().GetViewContact(a).GetViewObjectContact(rVOC.GetObjectContact()));
2056 
2057                 if(rCandidate.GetViewContact().GetObjectCount())
2058                 {
2059                     // is a group object itself, call recursively
2060                     impAddPrimitivesFromGroup(rCandidate, rOffsetMatrix, rDisplayInfo, rxTarget);
2061                 }
2062                 else
2063                 {
2064                     // single object, add primitives; check model-view visibility
2065                     if(rCandidate.isPrimitiveVisible(rDisplayInfo))
2066                     {
2067                         drawinglayer::primitive2d::Primitive2DContainer aNewSequence(rCandidate.getPrimitive2DSequence(rDisplayInfo));
2068 
2069                         if(!aNewSequence.empty())
2070                         {
2071                             // get ranges
2072                             const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(rCandidate.GetObjectContact().getViewInformation2D());
2073                             const basegfx::B2DRange aViewRange(rViewInformation2D.getViewport());
2074                             basegfx::B2DRange aObjectRange(rCandidate.getObjectRange());
2075 
2076                             // correct with virtual object's offset
2077                             aObjectRange.transform(rOffsetMatrix);
2078 
2079                             // check geometrical visibility (with offset)
2080                             if(!aViewRange.overlaps(aObjectRange))
2081                             {
2082                                 // not visible, release
2083                                 aNewSequence.clear();
2084                             }
2085                         }
2086 
2087                         if(!aNewSequence.empty())
2088                         {
2089                             rxTarget.append(aNewSequence);
2090                         }
2091                     }
2092                 }
2093             }
2094         }
2095 
createPrimitive2DSequence(const DisplayInfo & rDisplayInfo) const2096         drawinglayer::primitive2d::Primitive2DContainer VOCOfDrawVirtObj::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const
2097         {
2098             // tdf#91260 have already checked top-level one is on the right page
2099             assert(isPrimitiveVisible(rDisplayInfo));
2100             // nasty corner case: override to clear page frame to disable the
2101             // sub-objects' anchor check, because their anchor is always on
2102             // the first page that the page style is applied to
2103             DisplayInfo aDisplayInfo(rDisplayInfo);
2104             aDisplayInfo.SetWriterPageFrame(basegfx::B2IRectangle());
2105             const VCOfDrawVirtObj& rVC = static_cast< const VCOfDrawVirtObj& >(GetViewContact());
2106             const SdrObject& rReferencedObject = rVC.GetSwDrawVirtObj().GetReferencedObj();
2107             drawinglayer::primitive2d::Primitive2DContainer xRetval;
2108 
2109             // create offset transformation
2110             basegfx::B2DHomMatrix aOffsetMatrix;
2111             const Point aLocalOffset(rVC.GetSwDrawVirtObj().GetOffset());
2112 
2113             if(aLocalOffset.X() || aLocalOffset.Y())
2114             {
2115                 aOffsetMatrix.set(0, 2, aLocalOffset.X());
2116                 aOffsetMatrix.set(1, 2, aLocalOffset.Y());
2117             }
2118 
2119             if(dynamic_cast<const SdrObjGroup*>( &rReferencedObject) !=  nullptr)
2120             {
2121                 // group object. Since the VOC/OC/VC hierarchy does not represent the
2122                 // hierarchy virtual objects when they have group objects
2123                 // (ViewContactOfVirtObj::GetObjectCount() returns null for that purpose)
2124                 // to avoid multiple usages of VOCs (which would not work), the primitives
2125                 // for the sub-hierarchy need to be collected here
2126 
2127                 // Get the VOC of the referenced object (the Group) and fetch primitives from it
2128                 const ViewObjectContact& rVOCOfRefObj = rReferencedObject.GetViewContact().GetViewObjectContact(GetObjectContact());
2129                 impAddPrimitivesFromGroup(rVOCOfRefObj, aOffsetMatrix, aDisplayInfo, xRetval);
2130             }
2131             else
2132             {
2133                 // single object, use method from referenced object to get the Primitive2DSequence
2134                 xRetval = rReferencedObject.GetViewContact().getViewIndependentPrimitive2DContainer();
2135             }
2136 
2137             if(!xRetval.empty())
2138             {
2139                 // create transform primitive
2140                 const drawinglayer::primitive2d::Primitive2DReference xReference(new drawinglayer::primitive2d::TransformPrimitive2D(aOffsetMatrix, xRetval));
2141                 xRetval = drawinglayer::primitive2d::Primitive2DContainer { xReference };
2142             }
2143 
2144             return xRetval;
2145         }
2146 
CreateObjectSpecificViewObjectContact(ObjectContact & rObjectContact)2147         ViewObjectContact& VCOfDrawVirtObj::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
2148         {
2149             return *(new VOCOfDrawVirtObj(rObjectContact, *this));
2150         }
2151 
2152     } // end of namespace contact
2153 } // end of namespace sdr
2154 
2155 /// implementation of class <SwDrawVirtObj>
CreateObjectSpecificViewContact()2156 std::unique_ptr<sdr::contact::ViewContact> SwDrawVirtObj::CreateObjectSpecificViewContact()
2157 {
2158     return std::make_unique<sdr::contact::VCOfDrawVirtObj>(*this);
2159 }
2160 
SwDrawVirtObj(SdrModel & rSdrModel,SdrObject & _rNewObj,SwDrawContact & _rDrawContact)2161 SwDrawVirtObj::SwDrawVirtObj(
2162     SdrModel& rSdrModel,
2163     SdrObject& _rNewObj,
2164     SwDrawContact& _rDrawContact)
2165 :   SdrVirtObj(rSdrModel, _rNewObj ),
2166     maAnchoredDrawObj(),
2167     mrDrawContact(_rDrawContact)
2168 {
2169     // #i26791#
2170     maAnchoredDrawObj.SetDrawObj( *this );
2171 
2172     // #i35635# - set initial position out of sight
2173     NbcMove( Size( -16000, -16000 ) );
2174 }
2175 
~SwDrawVirtObj()2176 SwDrawVirtObj::~SwDrawVirtObj()
2177 {
2178 }
2179 
operator =(const SwDrawVirtObj & rObj)2180 SwDrawVirtObj& SwDrawVirtObj::operator=( const SwDrawVirtObj& rObj )
2181 {
2182     SdrVirtObj::operator=(rObj);
2183     // Note: Members <maAnchoredDrawObj> and <mrDrawContact>
2184     //       haven't to be considered.
2185     return *this;
2186 }
2187 
CloneSdrObject(SdrModel & rTargetModel) const2188 SwDrawVirtObj* SwDrawVirtObj::CloneSdrObject(SdrModel& rTargetModel) const
2189 {
2190     SwDrawVirtObj* pObj = new SwDrawVirtObj(
2191         rTargetModel,
2192         rRefObj,
2193         mrDrawContact);
2194 
2195     pObj->operator=( *this );
2196     // Note: Member <maAnchoredDrawObj> hasn't to be considered.
2197 
2198     return pObj;
2199 }
2200 
GetAnchorFrame() const2201 const SwFrame* SwDrawVirtObj::GetAnchorFrame() const
2202 {
2203     // #i26791# - use new member <maAnchoredDrawObj>
2204     return maAnchoredDrawObj.GetAnchorFrame();
2205 }
2206 
AnchorFrame()2207 SwFrame* SwDrawVirtObj::AnchorFrame()
2208 {
2209     // #i26791# - use new member <maAnchoredDrawObj>
2210     return maAnchoredDrawObj.AnchorFrame();
2211 }
2212 
RemoveFromWriterLayout()2213 void SwDrawVirtObj::RemoveFromWriterLayout()
2214 {
2215     // remove contact object from frame for 'virtual' drawing object
2216     // #i26791# - use new member <maAnchoredDrawObj>
2217     if ( maAnchoredDrawObj.GetAnchorFrame() )
2218     {
2219         maAnchoredDrawObj.AnchorFrame()->RemoveDrawObj( maAnchoredDrawObj );
2220     }
2221 }
2222 
AddToDrawingPage()2223 void SwDrawVirtObj::AddToDrawingPage()
2224 {
2225     // determine 'master'
2226     SdrObject* pOrgMasterSdrObj = mrDrawContact.GetMaster();
2227 
2228     // insert 'virtual' drawing object into page, set layer and user call.
2229     SdrPage* pDrawPg;
2230     // #i27030# - apply order number of referenced object
2231     if ( nullptr != ( pDrawPg = pOrgMasterSdrObj->getSdrPageFromSdrObject() ) )
2232     {
2233         // #i27030# - apply order number of referenced object
2234         pDrawPg->InsertObject( this, GetReferencedObj().GetOrdNum() );
2235     }
2236     else
2237     {
2238         pDrawPg = getSdrPageFromSdrObject();
2239         if ( pDrawPg )
2240         {
2241             pDrawPg->SetObjectOrdNum( GetOrdNumDirect(),
2242                                       GetReferencedObj().GetOrdNum() );
2243         }
2244         else
2245         {
2246             SetOrdNum( GetReferencedObj().GetOrdNum() );
2247         }
2248     }
2249     SetUserCall( &mrDrawContact );
2250 }
2251 
RemoveFromDrawingPage()2252 void SwDrawVirtObj::RemoveFromDrawingPage()
2253 {
2254     SetUserCall( nullptr );
2255     if ( getSdrPageFromSdrObject() )
2256     {
2257         getSdrPageFromSdrObject()->RemoveObject( GetOrdNum() );
2258     }
2259 }
2260 
2261 /// Is 'virtual' drawing object connected to writer layout and to drawing layer?
IsConnected() const2262 bool SwDrawVirtObj::IsConnected() const
2263 {
2264     bool bRetVal = GetAnchorFrame() &&
2265                    ( getSdrPageFromSdrObject() && GetUserCall() );
2266 
2267     return bRetVal;
2268 }
2269 
NbcSetAnchorPos(const Point & rPnt)2270 void SwDrawVirtObj::NbcSetAnchorPos(const Point& rPnt)
2271 {
2272     SdrObject::NbcSetAnchorPos( rPnt );
2273 }
2274 
2275 // #i97197#
2276 // the methods relevant for positioning
2277 
GetCurrentBoundRect() const2278 const tools::Rectangle& SwDrawVirtObj::GetCurrentBoundRect() const
2279 {
2280     if(aOutRect.IsEmpty())
2281     {
2282         const_cast<SwDrawVirtObj*>(this)->RecalcBoundRect();
2283     }
2284 
2285     return aOutRect;
2286 }
2287 
GetLastBoundRect() const2288 const tools::Rectangle& SwDrawVirtObj::GetLastBoundRect() const
2289 {
2290     return aOutRect;
2291 }
2292 
GetOffset() const2293 Point SwDrawVirtObj::GetOffset() const
2294 {
2295     // do NOT use IsEmpty() here, there is already a useful offset
2296     // in the position
2297     if(aOutRect == tools::Rectangle())
2298     {
2299         return Point();
2300     }
2301     else
2302     {
2303         return aOutRect.TopLeft() - GetReferencedObj().GetCurrentBoundRect().TopLeft();
2304     }
2305 }
2306 
SetBoundRectDirty()2307 void SwDrawVirtObj::SetBoundRectDirty()
2308 {
2309     // do nothing to not lose model information in aOutRect
2310 }
2311 
RecalcBoundRect()2312 void SwDrawVirtObj::RecalcBoundRect()
2313 {
2314     // #i26791# - switch order of calling <GetOffset()> and
2315     // <ReferencedObj().GetCurrentBoundRect()>, because <GetOffset()> calculates
2316     // its value by the 'BoundRect' of the referenced object.
2317 
2318     const Point aOffset(GetOffset());
2319     aOutRect = ReferencedObj().GetCurrentBoundRect() + aOffset;
2320 }
2321 
TakeXorPoly() const2322 basegfx::B2DPolyPolygon SwDrawVirtObj::TakeXorPoly() const
2323 {
2324     basegfx::B2DPolyPolygon aRetval(rRefObj.TakeXorPoly());
2325     aRetval.transform(basegfx::utils::createTranslateB2DHomMatrix(GetOffset().X(), GetOffset().Y()));
2326 
2327     return aRetval;
2328 }
2329 
TakeContour() const2330 basegfx::B2DPolyPolygon SwDrawVirtObj::TakeContour() const
2331 {
2332     basegfx::B2DPolyPolygon aRetval(rRefObj.TakeContour());
2333     aRetval.transform(basegfx::utils::createTranslateB2DHomMatrix(GetOffset().X(), GetOffset().Y()));
2334 
2335     return aRetval;
2336 }
2337 
AddToHdlList(SdrHdlList & rHdlList) const2338 void SwDrawVirtObj::AddToHdlList(SdrHdlList& rHdlList) const
2339 {
2340     SdrHdlList tmpList(nullptr);
2341     rRefObj.AddToHdlList(tmpList);
2342 
2343     size_t cnt = tmpList.GetHdlCount();
2344     for(size_t i=0; i < cnt; ++i)
2345     {
2346         SdrHdl* pHdl = tmpList.GetHdl(i);
2347         Point aP(pHdl->GetPos() + GetOffset());
2348         pHdl->SetPos(aP);
2349     }
2350     tmpList.MoveTo(rHdlList);
2351 }
2352 
NbcMove(const Size & rSiz)2353 void SwDrawVirtObj::NbcMove(const Size& rSiz)
2354 {
2355     SdrObject::NbcMove( rSiz );
2356 }
2357 
NbcResize(const Point & rRef,const Fraction & xFact,const Fraction & yFact)2358 void SwDrawVirtObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
2359 {
2360     rRefObj.NbcResize(rRef - GetOffset(), xFact, yFact);
2361     SetRectsDirty();
2362 }
2363 
NbcRotate(const Point & rRef,long nAngle,double sn,double cs)2364 void SwDrawVirtObj::NbcRotate(const Point& rRef, long nAngle, double sn, double cs)
2365 {
2366     rRefObj.NbcRotate(rRef - GetOffset(), nAngle, sn, cs);
2367     SetRectsDirty();
2368 }
2369 
NbcMirror(const Point & rRef1,const Point & rRef2)2370 void SwDrawVirtObj::NbcMirror(const Point& rRef1, const Point& rRef2)
2371 {
2372     rRefObj.NbcMirror(rRef1 - GetOffset(), rRef2 - GetOffset());
2373     SetRectsDirty();
2374 }
2375 
NbcShear(const Point & rRef,long nAngle,double tn,bool bVShear)2376 void SwDrawVirtObj::NbcShear(const Point& rRef, long nAngle, double tn, bool bVShear)
2377 {
2378     rRefObj.NbcShear(rRef - GetOffset(), nAngle, tn, bVShear);
2379     SetRectsDirty();
2380 }
2381 
Move(const Size & rSiz)2382 void SwDrawVirtObj::Move(const Size& rSiz)
2383 {
2384     SdrObject::Move( rSiz );
2385 }
2386 
Resize(const Point & rRef,const Fraction & xFact,const Fraction & yFact,bool bUnsetRelative)2387 void SwDrawVirtObj::Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative)
2388 {
2389     if(xFact.GetNumerator() != xFact.GetDenominator() || yFact.GetNumerator() != yFact.GetDenominator())
2390     {
2391         tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2392         rRefObj.Resize(rRef - GetOffset(), xFact, yFact, bUnsetRelative);
2393         SetRectsDirty();
2394         SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2395     }
2396 }
2397 
Rotate(const Point & rRef,long nAngle,double sn,double cs)2398 void SwDrawVirtObj::Rotate(const Point& rRef, long nAngle, double sn, double cs)
2399 {
2400     if(nAngle)
2401     {
2402         tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2403         rRefObj.Rotate(rRef - GetOffset(), nAngle, sn, cs);
2404         SetRectsDirty();
2405         SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2406     }
2407 }
2408 
Mirror(const Point & rRef1,const Point & rRef2)2409 void SwDrawVirtObj::Mirror(const Point& rRef1, const Point& rRef2)
2410 {
2411     tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2412     rRefObj.Mirror(rRef1 - GetOffset(), rRef2 - GetOffset());
2413     SetRectsDirty();
2414     SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2415 }
2416 
Shear(const Point & rRef,long nAngle,double tn,bool bVShear)2417 void SwDrawVirtObj::Shear(const Point& rRef, long nAngle, double tn, bool bVShear)
2418 {
2419     if(nAngle)
2420     {
2421         tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2422         rRefObj.Shear(rRef - GetOffset(), nAngle, tn, bVShear);
2423         SetRectsDirty();
2424         SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2425     }
2426 }
2427 
RecalcSnapRect()2428 void SwDrawVirtObj::RecalcSnapRect()
2429 {
2430     aSnapRect = rRefObj.GetSnapRect();
2431     aSnapRect += GetOffset();
2432 }
2433 
GetSnapRect() const2434 const tools::Rectangle& SwDrawVirtObj::GetSnapRect() const
2435 {
2436     const_cast<SwDrawVirtObj*>(this)->aSnapRect = rRefObj.GetSnapRect();
2437     const_cast<SwDrawVirtObj*>(this)->aSnapRect += GetOffset();
2438 
2439     return aSnapRect;
2440 }
2441 
SetSnapRect(const tools::Rectangle & rRect)2442 void SwDrawVirtObj::SetSnapRect(const tools::Rectangle& rRect)
2443 {
2444     tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2445     tools::Rectangle aR(rRect);
2446     aR -= GetOffset();
2447     rRefObj.SetSnapRect(aR);
2448     SetRectsDirty();
2449     SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2450 }
2451 
NbcSetSnapRect(const tools::Rectangle & rRect)2452 void SwDrawVirtObj::NbcSetSnapRect(const tools::Rectangle& rRect)
2453 {
2454     tools::Rectangle aR(rRect);
2455     aR -= GetOffset();
2456     SetRectsDirty();
2457     rRefObj.NbcSetSnapRect(aR);
2458 }
2459 
GetLogicRect() const2460 const tools::Rectangle& SwDrawVirtObj::GetLogicRect() const
2461 {
2462     const_cast<SwDrawVirtObj*>(this)->aSnapRect = rRefObj.GetLogicRect();
2463     const_cast<SwDrawVirtObj*>(this)->aSnapRect += GetOffset();
2464 
2465     return aSnapRect;
2466 }
2467 
SetLogicRect(const tools::Rectangle & rRect)2468 void SwDrawVirtObj::SetLogicRect(const tools::Rectangle& rRect)
2469 {
2470     tools::Rectangle aBoundRect0; if(pUserCall) aBoundRect0 = GetLastBoundRect();
2471     tools::Rectangle aR(rRect);
2472     aR -= GetOffset();
2473     rRefObj.SetLogicRect(aR);
2474     SetRectsDirty();
2475     SendUserCall(SdrUserCallType::Resize, aBoundRect0);
2476 }
2477 
NbcSetLogicRect(const tools::Rectangle & rRect)2478 void SwDrawVirtObj::NbcSetLogicRect(const tools::Rectangle& rRect)
2479 {
2480     tools::Rectangle aR(rRect);
2481     aR -= GetOffset();
2482     rRefObj.NbcSetLogicRect(aR);
2483     SetRectsDirty();
2484 }
2485 
GetSnapPoint(sal_uInt32 i) const2486 Point SwDrawVirtObj::GetSnapPoint(sal_uInt32 i) const
2487 {
2488     Point aP(rRefObj.GetSnapPoint(i));
2489     aP += GetOffset();
2490 
2491     return aP;
2492 }
2493 
GetPoint(sal_uInt32 i) const2494 Point SwDrawVirtObj::GetPoint(sal_uInt32 i) const
2495 {
2496     return rRefObj.GetPoint(i) + GetOffset();
2497 }
2498 
NbcSetPoint(const Point & rPnt,sal_uInt32 i)2499 void SwDrawVirtObj::NbcSetPoint(const Point& rPnt, sal_uInt32 i)
2500 {
2501     Point aP(rPnt);
2502     aP -= GetOffset();
2503     rRefObj.SetPoint(aP, i);
2504     SetRectsDirty();
2505 }
2506 
HasTextEdit() const2507 bool SwDrawVirtObj::HasTextEdit() const
2508 {
2509     return rRefObj.HasTextEdit();
2510 }
2511 
2512 // override 'layer' methods for 'virtual' drawing object to assure
2513 // that layer of 'virtual' object is the layer of the referenced object.
GetLayer() const2514 SdrLayerID SwDrawVirtObj::GetLayer() const
2515 {
2516     return GetReferencedObj().GetLayer();
2517 }
2518 
NbcSetLayer(SdrLayerID nLayer)2519 void SwDrawVirtObj::NbcSetLayer(SdrLayerID nLayer)
2520 {
2521     ReferencedObj().NbcSetLayer( nLayer );
2522     SdrVirtObj::NbcSetLayer( ReferencedObj().GetLayer() );
2523 }
2524 
SetLayer(SdrLayerID nLayer)2525 void SwDrawVirtObj::SetLayer(SdrLayerID nLayer)
2526 {
2527     ReferencedObj().SetLayer( nLayer );
2528     SdrVirtObj::NbcSetLayer( ReferencedObj().GetLayer() );
2529 }
2530 
2531 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2532