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