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