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