Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sw / source / core / layout / anchoreddrawobject.cxx
blob6dc6cac5d1b2a5251a420b04a18b7c789d93923d
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_wasm_strip.h>
22 #include <dcontact.hxx>
23 #include <rootfrm.hxx>
24 #include <pagefrm.hxx>
25 #include <tocntntanchoredobjectposition.hxx>
26 #include <tolayoutanchoredobjectposition.hxx>
27 #include <frmtool.hxx>
28 #include <fmtornt.hxx>
29 #include <txtfrm.hxx>
30 #include <vector>
31 #include <svx/svdogrp.hxx>
32 #include <tools/fract.hxx>
33 #include <DocumentSettingManager.hxx>
34 #include <IDocumentState.hxx>
35 #include <IDocumentLayoutAccess.hxx>
36 #include <txtfly.hxx>
37 #include <viewimp.hxx>
38 #include <textboxhelper.hxx>
39 #include <unomid.h>
40 #include <svx/svdoashp.hxx>
41 #include <osl/diagnose.h>
43 using namespace ::com::sun::star;
45 namespace {
47 /// helper class for correct notification due to the positioning of
48 /// the anchored drawing object
49 class SwPosNotify
51 private:
52 SwAnchoredDrawObject* mpAnchoredDrawObj;
53 SwRect maOldObjRect;
54 SwPageFrame* mpOldPageFrame;
56 public:
57 explicit SwPosNotify( SwAnchoredDrawObject* _pAnchoredDrawObj );
58 ~SwPosNotify() COVERITY_NOEXCEPT_FALSE;
59 // #i32795#
60 Point const & LastObjPos() const;
65 SwPosNotify::SwPosNotify( SwAnchoredDrawObject* _pAnchoredDrawObj ) :
66 mpAnchoredDrawObj( _pAnchoredDrawObj )
68 maOldObjRect = mpAnchoredDrawObj->GetObjRect();
69 // --> #i35640# - determine correct page frame
70 mpOldPageFrame = mpAnchoredDrawObj->GetPageFrame();
73 SwPosNotify::~SwPosNotify() COVERITY_NOEXCEPT_FALSE
75 if ( maOldObjRect != mpAnchoredDrawObj->GetObjRect() )
77 if( maOldObjRect.HasArea() && mpOldPageFrame )
79 mpAnchoredDrawObj->NotifyBackground( mpOldPageFrame, maOldObjRect,
80 PrepareHint::FlyFrameLeave );
82 SwRect aNewObjRect( mpAnchoredDrawObj->GetObjRect() );
83 if( aNewObjRect.HasArea() )
85 // --> #i35640# - determine correct page frame
86 SwPageFrame* pNewPageFrame = mpAnchoredDrawObj->GetPageFrame();
87 if( pNewPageFrame )
88 mpAnchoredDrawObj->NotifyBackground( pNewPageFrame, aNewObjRect,
89 PrepareHint::FlyFrameArrive );
92 ::ClrContourCache( mpAnchoredDrawObj->GetDrawObj() );
94 // --> #i35640# - additional notify anchor text frame
95 // Needed for negative positioned drawing objects
96 // --> #i43255# - refine condition to avoid unneeded
97 // invalidations: anchored object had to be on the page of its anchor
98 // text frame.
99 if ( mpAnchoredDrawObj->GetAnchorFrame()->IsTextFrame() &&
100 mpOldPageFrame == mpAnchoredDrawObj->GetAnchorFrame()->FindPageFrame() )
102 mpAnchoredDrawObj->AnchorFrame()->Prepare( PrepareHint::FlyFrameLeave );
105 // indicate a restart of the layout process
106 mpAnchoredDrawObj->SetRestartLayoutProcess( true );
108 else
110 // lock position
111 mpAnchoredDrawObj->LockPosition();
113 if ( !mpAnchoredDrawObj->ConsiderForTextWrap() )
115 // indicate that object has to be considered for text wrap
116 mpAnchoredDrawObj->SetConsiderForTextWrap( true );
117 // invalidate 'background' in order to allow its 'background'
118 // to wrap around it.
119 mpAnchoredDrawObj->NotifyBackground( mpAnchoredDrawObj->GetPageFrame(),
120 mpAnchoredDrawObj->GetObjRectWithSpaces(),
121 PrepareHint::FlyFrameArrive );
122 // invalidate position of anchor frame in order to force
123 // a re-format of the anchor frame, which also causes a
124 // re-format of the invalid previous frames of the anchor frame.
125 mpAnchoredDrawObj->AnchorFrame()->InvalidatePos();
128 // tdf#101464 notify SwAccessibleMap about new drawing object position
129 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
130 if (mpOldPageFrame && mpOldPageFrame->getRootFrame()->IsAnyShellAccessible())
132 mpOldPageFrame->getRootFrame()->GetCurrShell()->Imp()->MoveAccessible(
133 nullptr, mpAnchoredDrawObj->GetDrawObj(), maOldObjRect);
135 #endif
138 // --> #i32795#
139 Point const & SwPosNotify::LastObjPos() const
141 return maOldObjRect.Pos();
144 namespace {
146 // #i32795#
147 /// helper class for oscillation control on object positioning
148 class SwObjPosOscillationControl
150 private:
151 const SwAnchoredDrawObject* mpAnchoredDrawObj;
153 std::vector<Point> maObjPositions;
155 public:
156 explicit SwObjPosOscillationControl( const SwAnchoredDrawObject& _rAnchoredDrawObj );
158 bool OscillationDetected();
163 SwObjPosOscillationControl::SwObjPosOscillationControl(
164 const SwAnchoredDrawObject& _rAnchoredDrawObj )
165 : mpAnchoredDrawObj( &_rAnchoredDrawObj )
169 bool SwObjPosOscillationControl::OscillationDetected()
171 bool bOscillationDetected = false;
173 if ( maObjPositions.size() == 20 )
175 // position stack is full -> oscillation
176 bOscillationDetected = true;
178 else
180 Point aNewObjPos = mpAnchoredDrawObj->GetObjRect().Pos();
181 for ( auto const & pt : maObjPositions )
183 if ( aNewObjPos == pt )
185 // position already occurred -> oscillation
186 bOscillationDetected = true;
187 break;
190 if ( !bOscillationDetected )
192 maObjPositions.push_back( aNewObjPos );
196 return bOscillationDetected;
200 SwAnchoredDrawObject::SwAnchoredDrawObject() :
201 mbValidPos( false ),
202 mbNotYetAttachedToAnchorFrame( true ),
203 // --> #i28749#
204 mbNotYetPositioned( true ),
205 // --> #i62875#
206 mbCaptureAfterLayoutDirChange( false )
210 SwAnchoredDrawObject::~SwAnchoredDrawObject()
214 // --> #i62875#
215 void SwAnchoredDrawObject::UpdateLayoutDir()
217 SwFrameFormat::tLayoutDir nOldLayoutDir( GetFrameFormat().GetLayoutDir() );
219 SwAnchoredObject::UpdateLayoutDir();
221 if ( !NotYetPositioned() &&
222 GetFrameFormat().GetLayoutDir() != nOldLayoutDir &&
223 GetFrameFormat().GetDoc()->GetDocumentSettingManager().get(DocumentSettingId::DO_NOT_CAPTURE_DRAW_OBJS_ON_PAGE) &&
224 !IsOutsidePage() )
226 mbCaptureAfterLayoutDirChange = true;
230 // --> #i62875#
231 bool SwAnchoredDrawObject::IsOutsidePage() const
233 bool bOutsidePage( false );
235 if ( !NotYetPositioned() && GetPageFrame() )
237 SwRect aTmpRect( GetObjRect() );
238 bOutsidePage =
239 ( aTmpRect.Intersection( GetPageFrame()->getFrameArea() ) != GetObjRect() );
242 return bOutsidePage;
245 void SwAnchoredDrawObject::MakeObjPos()
247 if ( IsPositioningInProgress() )
249 // nothing to do - positioning already in progress
250 return;
253 if ( mbValidPos )
255 // nothing to do - position is valid
256 return;
259 // --> #i28749# - anchored drawing object has to be attached
260 // to anchor frame
261 if ( mbNotYetAttachedToAnchorFrame )
263 OSL_FAIL( "<SwAnchoredDrawObject::MakeObjPos() - drawing object not yet attached to anchor frame -> no positioning" );
264 return;
267 SwDrawContact* pDrawContact =
268 static_cast<SwDrawContact*>(::GetUserCall( GetDrawObj() ));
270 // --> #i28749# - if anchored drawing object hasn't been yet
271 // positioned, convert its positioning attributes, if its positioning
272 // attributes are given in horizontal left-to-right layout.
273 // --> #i36010# - Note: horizontal left-to-right layout is made
274 // the default layout direction for <SwDrawFrameFormat> instances. Thus, it has
275 // to be adjusted manually, if no adjustment of the positioning attributes
276 // have to be performed here.
277 // --> #i35635# - additionally move drawing object to the visible layer.
278 if ( mbNotYetPositioned )
280 // --> #i35635#
281 pDrawContact->MoveObjToVisibleLayer( DrawObj() );
282 // --> perform conversion of positioning
283 // attributes only for 'master' drawing objects
284 // #i44334#, #i44681# - check, if positioning
285 // attributes already have been set.
286 if ( dynamic_cast< const SwDrawVirtObj* >(GetDrawObj()) == nullptr &&
287 !static_cast<SwDrawFrameFormat&>(GetFrameFormat()).IsPosAttrSet() )
289 SetPositioningAttr();
291 // -->
292 // - reset internal flag after all needed actions are performed to
293 // avoid callbacks from drawing layer
294 mbNotYetPositioned = false;
297 // indicate that positioning is in progress
299 SwObjPositioningInProgress aObjPosInProgress( *this );
301 // determine relative position of drawing object and set it
302 switch ( pDrawContact->GetAnchorId() )
304 case RndStdIds::FLY_AS_CHAR:
306 // indicate that position will be valid after positioning is performed
307 mbValidPos = true;
308 // nothing to do, because as-character anchored objects are positioned
309 // during the format of its anchor frame - see <SwFlyCntPortion::SetBase(..)>
311 break;
312 case RndStdIds::FLY_AT_PARA:
313 case RndStdIds::FLY_AT_CHAR:
315 // --> #i32795# - move intrinsic positioning to
316 // helper method <MakeObjPosAnchoredAtPara()>
317 MakeObjPosAnchoredAtPara();
319 break;
320 case RndStdIds::FLY_AT_PAGE:
321 case RndStdIds::FLY_AT_FLY:
323 // --> #i32795# - move intrinsic positioning to
324 // helper method <MakeObjPosAnchoredAtLayout()>
325 MakeObjPosAnchoredAtLayout();
327 break;
328 default:
330 assert(!"<SwAnchoredDrawObject::MakeObjPos()> - unknown anchor type.");
334 // keep, current object rectangle
335 // --> #i34748# - use new method <SetLastObjRect(..)>
336 SetLastObjRect( GetObjRect().SVRect() );
338 // Assure for 'master' drawing object, that it's registered at the correct page.
339 // Perform check not for as-character anchored drawing objects and only if
340 // the anchor frame is valid.
341 if ( dynamic_cast< const SwDrawVirtObj* >(GetDrawObj()) == nullptr &&
342 !pDrawContact->ObjAnchoredAsChar() &&
343 GetAnchorFrame()->isFrameAreaDefinitionValid() )
345 pDrawContact->ChkPage();
349 // --> #i62875#
350 if ( !(mbCaptureAfterLayoutDirChange &&
351 GetPageFrame()) )
352 return;
354 SwRect aPageRect( GetPageFrame()->getFrameArea() );
355 SwRect aObjRect( GetObjRect() );
356 if ( aObjRect.Right() >= aPageRect.Right() + 10 )
358 Size aSize( aPageRect.Right() - aObjRect.Right(), 0 );
359 DrawObj()->Move( aSize );
360 aObjRect = GetObjRect();
363 if ( aObjRect.Left() + 10 <= aPageRect.Left() )
365 Size aSize( aPageRect.Left() - aObjRect.Left(), 0 );
366 DrawObj()->Move( aSize );
369 mbCaptureAfterLayoutDirChange = false;
372 /** method for the intrinsic positioning of an at-paragraph|at-character
373 anchored drawing object
375 #i32795# - helper method for method <MakeObjPos>
377 void SwAnchoredDrawObject::MakeObjPosAnchoredAtPara()
379 // --> #i32795# - adopt positioning algorithm from Writer
380 // fly frames, which are anchored at paragraph|at character
382 // Determine, if anchor frame can/has to be formatted.
383 // If yes, after each object positioning the anchor frame is formatted.
384 // If after the anchor frame format the object position isn't valid, the
385 // object is positioned again.
386 // --> #i43255# - refine condition: anchor frame format not
387 // allowed, if another anchored object, has to be consider its wrap influence
388 // --> #i50356# - format anchor frame containing the anchor
389 // position. E.g., for at-character anchored object this can be the follow
390 // frame of the anchor frame, which contains the anchor character.
391 bool bJoinLocked
392 = static_cast<const SwTextFrame*>(GetAnchorFrameContainingAnchPos())->IsAnyJoinLocked();
393 const bool bFormatAnchor = !bJoinLocked && !ConsiderObjWrapInfluenceOnObjPos()
394 && !ConsiderObjWrapInfluenceOfOtherObjs();
396 // Format of anchor is needed for (vertical) fly offsets, otherwise the
397 // lack of fly portions will result in an incorrect 0 offset.
398 bool bAddVerticalFlyOffsets = GetFrameFormat().getIDocumentSettingAccess().get(
399 DocumentSettingId::ADD_VERTICAL_FLY_OFFSETS);
400 bool bFormatAnchorOnce = !bJoinLocked && bAddVerticalFlyOffsets;
402 if (bFormatAnchor || bFormatAnchorOnce)
404 // --> #i50356#
405 GetAnchorFrameContainingAnchPos()->Calc(GetAnchorFrameContainingAnchPos()->getRootFrame()->GetCurrShell()->GetOut());
408 bool bOscillationDetected = false;
409 SwObjPosOscillationControl aObjPosOscCtrl( *this );
410 // --> #i3317# - boolean, to apply temporarily the
411 // 'straightforward positioning process' for the frame due to its
412 // overlapping with a previous column.
413 bool bConsiderWrapInfluenceDueToOverlapPrevCol( false );
414 do {
415 // indicate that position will be valid after positioning is performed
416 mbValidPos = true;
418 // --> #i35640# - correct scope for <SwPosNotify> instance
420 // create instance of <SwPosNotify> for correct notification
421 SwPosNotify aPosNotify( this );
423 // determine and set position
424 objectpositioning::SwToContentAnchoredObjectPosition
425 aObjPositioning( *DrawObj() );
426 aObjPositioning.CalcPosition();
428 // get further needed results of the positioning algorithm
429 SetVertPosOrientFrame ( aObjPositioning.GetVertPosOrientFrame() );
430 SetDrawObjAnchor();
432 // check for object position oscillation, if position has changed.
433 if ( GetObjRect().Pos() != aPosNotify.LastObjPos() )
435 bOscillationDetected = aObjPosOscCtrl.OscillationDetected();
438 // format anchor frame, if requested.
439 // Note: the format of the anchor frame can cause the object position
440 // to be invalid.
441 if ( bFormatAnchor )
443 // --> #i50356#
444 GetAnchorFrameContainingAnchPos()->Calc(GetAnchorFrameContainingAnchPos()->getRootFrame()->GetCurrShell()->GetOut());
447 // --> #i3317#
448 if ( !ConsiderObjWrapInfluenceOnObjPos() &&
449 OverlapsPrevColumn() )
451 bConsiderWrapInfluenceDueToOverlapPrevCol = true;
453 } while ( !mbValidPos && !bOscillationDetected &&
454 !bConsiderWrapInfluenceDueToOverlapPrevCol );
456 // --> #i3317# - consider a detected oscillation and overlapping
457 // with previous column.
458 // temporarily consider the anchored objects wrapping style influence
459 if ( bOscillationDetected || bConsiderWrapInfluenceDueToOverlapPrevCol )
461 SetTmpConsiderWrapInfluence( true );
462 SetRestartLayoutProcess( true );
466 /** method for the intrinsic positioning of an at-page|at-frame anchored
467 drawing object
469 #i32795# - helper method for method <MakeObjPos>
471 void SwAnchoredDrawObject::MakeObjPosAnchoredAtLayout()
473 // indicate that position will be valid after positioning is performed
474 mbValidPos = true;
476 // create instance of <SwPosNotify> for correct notification
477 SwPosNotify aPosNotify( this );
479 // determine position
480 objectpositioning::SwToLayoutAnchoredObjectPosition
481 aObjPositioning( *DrawObj() );
482 aObjPositioning.CalcPosition();
484 // set position
486 // --> #i31698#
487 // --> #i34995# - setting anchor position needed for filters,
488 // especially for the xml-filter to the OpenOffice.org file format
490 const Point aNewAnchorPos =
491 GetAnchorFrame()->GetFrameAnchorPos( ::HasWrap( GetDrawObj() ) );
492 DrawObj()->SetAnchorPos( aNewAnchorPos );
493 // --> #i70122# - missing invalidation
494 InvalidateObjRectWithSpaces();
496 SetCurrRelPos( aObjPositioning.GetRelPos() );
497 const SwFrame* pAnchorFrame = GetAnchorFrame();
498 SwRectFnSet aRectFnSet(pAnchorFrame);
499 const Point aAnchPos( aRectFnSet.GetPos(pAnchorFrame->getFrameArea()) );
500 SetObjLeft( aAnchPos.X() + GetCurrRelPos().X() );
501 SetObjTop( aAnchPos.Y() + GetCurrRelPos().Y() );
504 void SwAnchoredDrawObject::SetDrawObjAnchor()
506 // new anchor position
507 // --> #i31698# -
508 Point aNewAnchorPos =
509 GetAnchorFrame()->GetFrameAnchorPos( ::HasWrap( GetDrawObj() ) );
510 Point aCurrAnchorPos = GetDrawObj()->GetAnchorPos();
511 if ( aNewAnchorPos != aCurrAnchorPos )
513 // determine movement to be applied after setting the new anchor position
514 Size aMove( aCurrAnchorPos.getX() - aNewAnchorPos.getX(),
515 aCurrAnchorPos.getY() - aNewAnchorPos.getY() );
516 // set new anchor position
517 DrawObj()->SetAnchorPos( aNewAnchorPos );
518 // correct object position, caused by setting new anchor position
519 DrawObj()->Move( aMove );
520 // Sync textbox if it wasn't done at move
521 if ( SwTextBoxHelper::isTextBox(&GetFrameFormat(), RES_DRAWFRMFMT) && GetFrameFormat().GetDoc() &&
522 GetFrameFormat().GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell() &&
523 GetFrameFormat().GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell()->IsInConstructor())
525 SwTextBoxHelper::changeAnchor(&GetFrameFormat(), GetFrameFormat().FindRealSdrObject());
527 // --> #i70122# - missing invalidation
528 InvalidateObjRectWithSpaces();
532 /** method to invalidate the given page frame
534 #i28701#
536 void SwAnchoredDrawObject::InvalidatePage_( SwPageFrame* _pPageFrame )
538 if ( !_pPageFrame || _pPageFrame->GetFormat()->GetDoc()->IsInDtor() )
539 return;
541 if ( !_pPageFrame->GetUpper() )
542 return;
544 // --> #i35007# - correct invalidation for as-character
545 // anchored objects.
546 if ( GetFrameFormat().GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR )
548 _pPageFrame->InvalidateFlyInCnt();
550 else
552 _pPageFrame->InvalidateFlyLayout();
555 SwRootFrame* pRootFrame = static_cast<SwRootFrame*>(_pPageFrame->GetUpper());
556 pRootFrame->DisallowTurbo();
557 if ( pRootFrame->GetTurbo() )
559 const SwContentFrame* pTmpFrame = pRootFrame->GetTurbo();
560 pRootFrame->ResetTurbo();
561 pTmpFrame->InvalidatePage();
563 pRootFrame->SetIdleFlags();
566 void SwAnchoredDrawObject::InvalidateObjPos()
568 // --> #i28701# - check, if invalidation is allowed
569 if ( !(mbValidPos &&
570 InvalidationOfPosAllowed()) )
571 return;
573 mbValidPos = false;
574 // --> #i68520#
575 InvalidateObjRectWithSpaces();
577 // --> #i44339# - check, if anchor frame exists.
578 if ( !GetAnchorFrame() )
579 return;
581 // --> #118547# - notify anchor frame of as-character
582 // anchored object, because its positioned by the format of its anchor frame.
583 // --> #i44559# - assure, that text hint is already
584 // existing in the text frame
585 if ( GetAnchorFrame()->DynCastTextFrame() != nullptr &&
586 (GetFrameFormat().GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR) )
588 SwTextFrame* pAnchorTextFrame( static_cast<SwTextFrame*>(AnchorFrame()) );
589 if (pAnchorTextFrame->CalcFlyPos(&GetFrameFormat()) != TextFrameIndex(COMPLETE_STRING))
591 AnchorFrame()->Prepare( PrepareHint::FlyFrameAttributesChanged, &GetFrameFormat() );
595 SwPageFrame* pPageFrame = AnchorFrame()->FindPageFrame();
596 InvalidatePage_( pPageFrame );
598 // --> #i32270# - also invalidate page frame, at which the
599 // drawing object is registered at.
600 SwPageFrame* pPageFrameRegisteredAt = GetPageFrame();
601 if ( pPageFrameRegisteredAt &&
602 pPageFrameRegisteredAt != pPageFrame )
604 InvalidatePage_( pPageFrameRegisteredAt );
606 // #i33751#, #i34060# - method <GetPageFrameOfAnchor()>
607 // is replaced by method <FindPageFrameOfAnchor()>. It's return value
608 // have to be checked.
609 SwPageFrame* pPageFrameOfAnchor = FindPageFrameOfAnchor();
610 if ( pPageFrameOfAnchor &&
611 pPageFrameOfAnchor != pPageFrame &&
612 pPageFrameOfAnchor != pPageFrameRegisteredAt )
614 InvalidatePage_( pPageFrameOfAnchor );
618 SwFrameFormat& SwAnchoredDrawObject::GetFrameFormat()
620 assert(static_cast<SwDrawContact*>(GetUserCall(GetDrawObj()))->GetFormat());
621 return *(static_cast<SwDrawContact*>(GetUserCall(GetDrawObj()))->GetFormat());
623 const SwFrameFormat& SwAnchoredDrawObject::GetFrameFormat() const
625 assert(static_cast<SwDrawContact*>(GetUserCall(GetDrawObj()))->GetFormat());
626 return *(static_cast<SwDrawContact*>(GetUserCall(GetDrawObj()))->GetFormat());
629 SwRect SwAnchoredDrawObject::GetObjRect() const
631 // use geometry of drawing object
632 //return GetDrawObj()->GetCurrentBoundRect();
633 return SwRect(GetDrawObj()->GetSnapRect());
636 namespace
638 // Imagine an open book, inside margin is the one that is at the inner side of the pages, at the center of the book,
639 // outside margin is at the two opposite edges of the book.
640 // outside --text-- inside | inside --text-- outside
641 // With mirrored margins, when relating the size of an object from the inside margin for example, on the
642 // first page we calculate the new size of the object using the size of the right margin,
643 // on second page the left margin, third page right margin, etc.
644 tools::Long getInsideOutsideRelativeWidth(bool isOutside, const SwPageFrame* const pPageFrame)
646 // Alternating between the only two possible cases: inside and outside.
647 // Inside = false, Outside = true.
648 auto nPageNum = pPageFrame->GetPhyPageNum();
649 if (nPageNum % 2 == (isOutside ? 0 : 1))
650 return pPageFrame->GetRightMargin();
651 else
652 return pPageFrame->GetLeftMargin();
656 // --> #i70122#
657 SwRect SwAnchoredDrawObject::GetObjBoundRect() const
659 bool bGroupShape = dynamic_cast<const SdrObjGroup*>( GetDrawObj() );
660 // Resize objects with relative width or height
661 if ( !bGroupShape && GetPageFrame( ) && ( GetDrawObj( )->GetRelativeWidth( ) || GetDrawObj()->GetRelativeHeight( ) ) )
663 tools::Rectangle aCurrObjRect = GetDrawObj()->GetCurrentBoundRect();
665 tools::Long nTargetWidth = aCurrObjRect.GetWidth( );
666 if ( GetDrawObj( )->GetRelativeWidth( ) )
668 tools::Long nWidth = 0;
669 if (GetDrawObj()->GetRelativeWidthRelation() == text::RelOrientation::FRAME)
670 // Exclude margins.
671 nWidth = GetPageFrame()->getFramePrintArea().SVRect().GetWidth();
672 // Here we handle the relative size of the width of some shape.
673 // The size of the shape's width is going to be relative to the size of the left margin.
674 // E.g.: (left margin = 8 && relative size = 150%) -> width of some shape = 12.
675 else if (GetDrawObj()->GetRelativeWidthRelation() == text::RelOrientation::PAGE_LEFT)
677 if (GetPageFrame()->GetPageDesc()->GetUseOn() == UseOnPage::Mirror)
678 // We want to get the width of whatever is going through here using the size of the
679 // outside margin.
680 nWidth = getInsideOutsideRelativeWidth(true, GetPageFrame());
681 else
682 nWidth = GetPageFrame()->GetLeftMargin();
684 // Same as the left margin above.
685 else if (GetDrawObj()->GetRelativeWidthRelation() == text::RelOrientation::PAGE_RIGHT)
686 if (GetPageFrame()->GetPageDesc()->GetUseOn() == UseOnPage::Mirror)
687 // We want to get the width of whatever is going through here using the size of the
688 // inside margin.
689 nWidth = getInsideOutsideRelativeWidth(false, GetPageFrame());
690 else
691 nWidth = GetPageFrame()->GetRightMargin();
692 else
693 nWidth = GetPageFrame( )->GetBoundRect( GetPageFrame()->getRootFrame()->GetCurrShell()->GetOut() ).SVRect().GetWidth();
694 nTargetWidth = nWidth * (*GetDrawObj( )->GetRelativeWidth());
697 bool bCheck = GetDrawObj()->GetRelativeHeight();
698 if (bCheck)
700 auto pObjCustomShape = dynamic_cast<const SdrObjCustomShape*>(GetDrawObj());
701 bCheck = !pObjCustomShape || !pObjCustomShape->IsAutoGrowHeight();
704 tools::Long nTargetHeight = aCurrObjRect.GetHeight();
705 if (bCheck)
707 tools::Long nHeight = 0;
708 if (GetDrawObj()->GetRelativeHeightRelation() == text::RelOrientation::FRAME)
709 // Exclude margins.
710 nHeight = GetPageFrame()->getFramePrintArea().SVRect().GetHeight();
711 else if (GetDrawObj()->GetRelativeHeightRelation() == text::RelOrientation::PAGE_PRINT_AREA)
713 // count required height: print area top = top margin + header
714 SwRect aHeaderRect;
715 const SwHeaderFrame* pHeaderFrame = GetPageFrame()->GetHeaderFrame();
716 if (pHeaderFrame)
717 aHeaderRect = pHeaderFrame->GetPaintArea();
718 nHeight = GetPageFrame()->GetTopMargin() + aHeaderRect.Height();
720 else if (GetDrawObj()->GetRelativeHeightRelation() == text::RelOrientation::PAGE_PRINT_AREA_BOTTOM)
722 // count required height: print area bottom = bottom margin + footer
723 SwRect aFooterRect;
724 auto pFooterFrame = GetPageFrame()->GetFooterFrame();
725 if (pFooterFrame)
726 aFooterRect = pFooterFrame->GetPaintArea();
727 nHeight = GetPageFrame()->GetBottomMargin() + aFooterRect.Height();
729 else
730 nHeight = GetPageFrame( )->GetBoundRect( GetPageFrame()->getRootFrame()->GetCurrShell()->GetOut() ).SVRect().GetHeight();
731 nTargetHeight = nHeight * (*GetDrawObj()->GetRelativeHeight());
734 if ( nTargetWidth != aCurrObjRect.GetWidth( ) || nTargetHeight != aCurrObjRect.GetHeight( ) )
736 SwDoc* pDoc = const_cast<SwDoc*>(GetPageFrame()->GetFormat()->GetDoc());
738 bool bEnableSetModified = pDoc->getIDocumentState().IsEnableSetModified();
739 pDoc->getIDocumentState().SetEnableSetModified(false);
740 auto pObject = const_cast<SdrObject*>(GetDrawObj());
741 pObject->Resize( aCurrObjRect.TopLeft(),
742 Fraction( nTargetWidth, aCurrObjRect.GetWidth() ),
743 Fraction( nTargetHeight, aCurrObjRect.GetHeight() ), false );
745 if (SwFrameFormat* pFrameFormat = FindFrameFormat(pObject))
747 if (SwTextBoxHelper::isTextBox(pFrameFormat, RES_DRAWFRMFMT))
749 // Shape has relative size and also a textbox, update its text area as well.
750 uno::Reference<drawing::XShape> xShape(pObject->getUnoShape(), uno::UNO_QUERY);
751 SwTextBoxHelper::syncProperty(pFrameFormat, RES_FRM_SIZE, MID_FRMSIZE_SIZE,
752 uno::Any(xShape->getSize()));
756 pDoc->getIDocumentState().SetEnableSetModified(bEnableSetModified);
759 return SwRect(GetDrawObj()->GetCurrentBoundRect());
762 // --> #i68520#
763 bool SwAnchoredDrawObject::SetObjTop_( const SwTwips _nTop )
765 SwTwips nDiff = _nTop - GetObjRect().Top();
766 DrawObj()->Move( Size( 0, nDiff ) );
768 return nDiff != 0;
770 bool SwAnchoredDrawObject::SetObjLeft_( const SwTwips _nLeft )
772 SwTwips nDiff = _nLeft - GetObjRect().Left();
773 DrawObj()->Move( Size( nDiff, 0 ) );
775 return nDiff != 0;
778 /** adjust positioning and alignment attributes for new anchor frame
780 #i33313# - add second optional parameter <_pNewObjRect>
782 void SwAnchoredDrawObject::AdjustPositioningAttr( const SwFrame* _pNewAnchorFrame,
783 const SwRect* _pNewObjRect )
785 SwTwips nHoriRelPos = 0;
786 SwTwips nVertRelPos = 0;
787 const Point aAnchorPos = _pNewAnchorFrame->GetFrameAnchorPos( ::HasWrap( GetDrawObj() ) );
788 // --> #i33313#
789 const SwRect aObjRect( _pNewObjRect ? *_pNewObjRect : GetObjRect() );
790 const bool bVert = _pNewAnchorFrame->IsVertical();
791 const bool bR2L = _pNewAnchorFrame->IsRightToLeft();
792 if ( bVert )
794 nHoriRelPos = aObjRect.Top() - aAnchorPos.Y();
795 nVertRelPos = aAnchorPos.X() - aObjRect.Right();
797 else if ( bR2L )
799 nHoriRelPos = aAnchorPos.X() - aObjRect.Right();
800 nVertRelPos = aObjRect.Top() - aAnchorPos.Y();
802 else
804 nHoriRelPos = aObjRect.Left() - aAnchorPos.X();
805 nVertRelPos = aObjRect.Top() - aAnchorPos.Y();
808 SwFormatHoriOrient hori(nHoriRelPos, text::HoriOrientation::NONE, text::RelOrientation::FRAME);
809 SwFormatVertOrient vert(nVertRelPos, text::VertOrientation::NONE, text::RelOrientation::FRAME);
810 SfxItemSetFixed<RES_VERT_ORIENT, RES_HORI_ORIENT> items(GetFrameFormat().GetDoc()->GetAttrPool());
811 items.Put(hori);
812 items.Put(vert);
813 GetFrameFormat().GetDoc()->SetAttr(items, GetFrameFormat());
816 // --> #i34748# - change return type.
817 // If member <mpLastObjRect> is NULL, create one.
818 void SwAnchoredDrawObject::SetLastObjRect( const tools::Rectangle& _rNewLastRect )
820 maLastObjRect = _rNewLastRect;
823 void SwAnchoredDrawObject::ObjectAttachedToAnchorFrame()
825 // --> #i31698#
826 SwAnchoredObject::ObjectAttachedToAnchorFrame();
828 if ( mbNotYetAttachedToAnchorFrame )
830 mbNotYetAttachedToAnchorFrame = false;
834 /** method to set positioning attributes
836 #i35798#
837 During load the positioning attributes aren't set.
838 Thus, the positioning attributes are set by the current object geometry.
839 This method is also used for the conversion for drawing objects
840 (not anchored as-character) imported from OpenOffice.org file format
841 once and directly before the first positioning.
843 void SwAnchoredDrawObject::SetPositioningAttr()
845 SwDrawContact* pDrawContact =
846 static_cast<SwDrawContact*>(GetUserCall( GetDrawObj() ));
848 if ( !pDrawContact->ObjAnchoredAsChar() )
850 SwRect aObjRect( GetObjRect() );
852 SwTwips nHoriPos = aObjRect.Left();
853 SwTwips nVertPos = aObjRect.Top();
854 // #i44334#, #i44681#
855 // perform conversion only if position is in horizontal-left-to-right-layout.
856 if ( GetFrameFormat().GetPositionLayoutDir() ==
857 text::PositionLayoutDir::PositionInHoriL2R )
859 SwFrameFormat::tLayoutDir eLayoutDir = GetFrameFormat().GetLayoutDir();
860 switch ( eLayoutDir )
862 case SwFrameFormat::HORI_L2R:
864 // nothing to do
866 break;
867 case SwFrameFormat::HORI_R2L:
869 nHoriPos = -aObjRect.Left() - aObjRect.Width();
871 break;
872 case SwFrameFormat::VERT_R2L:
874 nHoriPos = aObjRect.Top();
875 nVertPos = -aObjRect.Left() - aObjRect.Width();
877 break;
878 default:
880 assert(!"<SwAnchoredDrawObject::SetPositioningAttr()> - unsupported layout direction");
885 // --> #i71182#
886 // only change position - do not lose other attributes
888 SwFormatHoriOrient aHori( GetFrameFormat().GetHoriOrient() );
889 if (nHoriPos != aHori.GetPos()) {
890 aHori.SetPos( nHoriPos );
891 InvalidateObjRectWithSpaces();
892 GetFrameFormat().SetFormatAttr( aHori );
895 SwFormatVertOrient aVert( GetFrameFormat().GetVertOrient() );
896 if (nVertPos != aVert.GetPos()) {
897 aVert.SetPos( nVertPos );
898 InvalidateObjRectWithSpaces();
899 GetFrameFormat().SetFormatAttr( aVert );
902 // --> #i36010# - set layout direction of the position
903 GetFrameFormat().SetPositionLayoutDir(
904 text::PositionLayoutDir::PositionInLayoutDirOfAnchor );
906 // --> #i65798# - also for as-character anchored objects
907 // --> #i45952# - indicate that position
908 // attributes are set now.
909 static_cast<SwDrawFrameFormat&>(GetFrameFormat()).PosAttrSet();
912 void SwAnchoredDrawObject::NotifyBackground( SwPageFrame* _pPageFrame,
913 const SwRect& _rRect,
914 PrepareHint _eHint )
916 ::Notify_Background( GetDrawObj(), _pPageFrame, _rRect, _eHint, true );
919 /** method to assure that anchored object is registered at the correct
920 page frame
922 #i28701#
924 void SwAnchoredDrawObject::RegisterAtCorrectPage()
926 SwPageFrame* pPageFrame( nullptr );
927 if ( GetVertPosOrientFrame() )
929 pPageFrame = const_cast<SwPageFrame*>(GetVertPosOrientFrame()->FindPageFrame());
931 if ( pPageFrame && GetPageFrame() != pPageFrame )
933 RegisterAtPage(*pPageFrame);
937 void SwAnchoredDrawObject::RegisterAtPage(SwPageFrame & rPageFrame)
939 assert(GetPageFrame() != &rPageFrame);
940 if (GetPageFrame())
942 GetPageFrame()->RemoveDrawObjFromPage( *this );
944 rPageFrame.AppendDrawObjToPage( *this );
947 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */