1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <anchoredobjectposition.hxx>
21 #include <environmentofanchoredobject.hxx>
23 #include <flyfrms.hxx>
25 #include <pagefrm.hxx>
27 #include <frmtool.hxx>
28 #include <svx/svdobj.hxx>
29 #include <dflyobj.hxx>
30 #include <dcontact.hxx>
32 #include <fmtornt.hxx>
33 #include <fmtfollowtextflow.hxx>
34 #include <editeng/lrspitem.hxx>
35 #include <editeng/ulspitem.hxx>
37 #include <IDocumentSettingAccess.hxx>
38 #include <textboxhelper.hxx>
39 #include <fmtsrnd.hxx>
40 #include <osl/diagnose.h>
42 using namespace ::com::sun::star
;
44 namespace objectpositioning
47 SwAnchoredObjectPosition::SwAnchoredObjectPosition( SdrObject
& _rDrawObj
)
48 : mrDrawObj( _rDrawObj
),
49 mpAnchoredObj( nullptr ),
50 mpAnchorFrame( nullptr ),
54 mbFollowTextFlow( false ),
55 mbDoNotCaptureAnchoredObj( false )
57 #if OSL_DEBUG_LEVEL > 0
58 // assert, if object isn't of expected type
59 const bool bObjOfExceptedType
=
60 dynamic_cast<const SwVirtFlyDrawObj
*>( &mrDrawObj
) != nullptr || // object representing fly frame
61 dynamic_cast<const SwDrawVirtObj
*>( &mrDrawObj
) != nullptr || // 'virtual' drawing object
62 ( dynamic_cast<const SdrVirtObj
*>( &mrDrawObj
) == nullptr && // 'master' drawing object
63 dynamic_cast<const SwFlyDrawObj
*>( &mrDrawObj
) == nullptr ); // - indirectly checked
64 OSL_ENSURE( bObjOfExceptedType
,
65 "SwAnchoredObjectPosition(..) - object of unexpected type!" );
71 /** determine information about object
73 members <mbIsObjFly>, <mpFrameOfObj>, <mpAnchorFrame>, <mpContact>,
74 <mbFollowTextFlow> and <mbDoNotCaptureAnchoredObj> are set
76 void SwAnchoredObjectPosition::GetInfoAboutObj()
78 // determine, if object represents a fly frame
80 mbIsObjFly
= dynamic_cast<const SwVirtFlyDrawObj
*>( &mrDrawObj
) != nullptr;
83 // determine contact object
85 mpContact
= GetUserCall( &mrDrawObj
);
87 "SwAnchoredObjectPosition::GetInfoAboutObj() - missing SwContact-object.");
90 // determine anchored object, the object belongs to
93 mpAnchoredObj
= mpContact
->GetAnchoredObj( &mrDrawObj
);
94 assert(mpAnchoredObj
&&
95 "SwAnchoredObjectPosition::GetInfoAboutObj() - missing anchored object.");
98 // determine frame, the object is anchored at
101 mpAnchorFrame
= mpAnchoredObj
->AnchorFrame();
102 OSL_ENSURE( mpAnchorFrame
,
103 "SwAnchoredObjectPosition::GetInfoAboutObj() - missing anchor frame." );
106 // determine format the object belongs to
109 mpFrameFormat
= &mpAnchoredObj
->GetFrameFormat();
110 assert(mpFrameFormat
&&
111 "<SwAnchoredObjectPosition::GetInfoAboutObj() - missing frame format.");
114 // #i62875# - determine attribute value of <Follow-Text-Flow>
116 mbFollowTextFlow
= mpFrameFormat
->GetFollowTextFlow().GetValue();
119 // determine, if anchored object has not to be captured on the page.
120 // the following conditions must be hold to *not* capture it:
121 // - corresponding document compatibility flag is set
122 // - it's a drawing object or it's a non-textbox wrap-though fly frame
123 // - it doesn't follow the text flow
125 bool bTextBox
= SwTextBoxHelper::isTextBox(mpFrameFormat
, RES_FLYFRMFMT
);
126 bool bWrapThrough
= mpFrameFormat
->GetSurround().GetSurround() == css::text::WrapTextMode_THROUGH
;
127 mbDoNotCaptureAnchoredObj
= (!mbIsObjFly
|| (!bTextBox
&& bWrapThrough
)) && !mbFollowTextFlow
&&
128 mpFrameFormat
->getIDocumentSettingAccess().get(DocumentSettingId::DO_NOT_CAPTURE_DRAW_OBJS_ON_PAGE
);
132 SwAnchoredObjectPosition::~SwAnchoredObjectPosition()
135 bool SwAnchoredObjectPosition::IsAnchoredToChar() const
140 const SwFrame
* SwAnchoredObjectPosition::ToCharOrientFrame() const
145 const SwRect
* SwAnchoredObjectPosition::ToCharRect() const
151 SwTwips
SwAnchoredObjectPosition::ToCharTopOfLine() const
156 /** helper method to determine top of a frame for the vertical
161 SwTwips
SwAnchoredObjectPosition::GetTopForObjPos( const SwFrame
& _rFrame
,
162 const SwRectFn
& _fnRect
,
163 const bool _bVert
) const
165 SwTwips nTopOfFrameForObjPos
= (_rFrame
.getFrameArea().*_fnRect
->fnGetTop
)();
167 if ( _rFrame
.IsTextFrame() )
169 const SwTextFrame
& rTextFrame
= static_cast<const SwTextFrame
&>(_rFrame
);
172 nTopOfFrameForObjPos
-=
173 rTextFrame
.GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid();
177 nTopOfFrameForObjPos
+=
178 rTextFrame
.GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid();
180 const SwFormatSurround
& rSurround
= mpFrameFormat
->GetSurround();
181 bool bWrapThrough
= rSurround
.GetSurround() == css::text::WrapTextMode_THROUGH
;
182 // If the frame format is a TextBox of a draw shape, then use the
183 // surround of the original shape.
184 SwTextBoxHelper::getShapeWrapThrough(mpFrameFormat
, bWrapThrough
);
186 // Get the offset between the top of the text frame and the top of
187 // the first line inside the frame that has more than just fly
189 nTopOfFrameForObjPos
+= rTextFrame
.GetBaseVertOffsetForFly(!bWrapThrough
);
193 return nTopOfFrameForObjPos
;
196 void SwAnchoredObjectPosition::GetVertAlignmentValues(
197 const SwFrame
& _rVertOrientFrame
,
198 const SwFrame
& _rPageAlignLayFrame
,
199 const sal_Int16 _eRelOrient
,
200 SwTwips
& _orAlignAreaHeight
,
201 SwTwips
& _orAlignAreaOffset
) const
205 SwRectFnSet
aRectFnSet(&_rVertOrientFrame
);
206 // #i11860# - top of <_rVertOrientFrame> for object positioning
207 const SwTwips nVertOrientTop
= GetTopForObjPos( _rVertOrientFrame
, aRectFnSet
.FnRect(), aRectFnSet
.IsVert() );
208 // #i11860# - upper space amount of <_rVertOrientFrame> considered
209 // for previous frame
210 const SwTwips nVertOrientUpperSpaceForPrevFrameAndPageGrid
=
211 _rVertOrientFrame
.IsTextFrame()
212 ? static_cast<const SwTextFrame
&>(_rVertOrientFrame
).
213 GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid()
215 switch ( _eRelOrient
)
217 case text::RelOrientation::FRAME
:
219 // #i11860# - consider upper space of previous frame
220 nHeight
= aRectFnSet
.GetHeight(_rVertOrientFrame
.getFrameArea()) -
221 nVertOrientUpperSpaceForPrevFrameAndPageGrid
;
225 case text::RelOrientation::PRINT_AREA
:
227 nHeight
= aRectFnSet
.GetHeight(_rVertOrientFrame
.getFramePrintArea());
228 // #i11860# - consider upper space of previous frame
229 nOffset
= aRectFnSet
.GetTopMargin(_rVertOrientFrame
) -
230 nVertOrientUpperSpaceForPrevFrameAndPageGrid
;
231 // if aligned to page in horizontal layout, consider header and
232 // footer frame height appropriately.
233 if( _rVertOrientFrame
.IsPageFrame() && !aRectFnSet
.IsVert() )
235 const SwFrame
* pPrtFrame
=
236 static_cast<const SwPageFrame
&>(_rVertOrientFrame
).Lower();
239 if( pPrtFrame
->IsHeaderFrame() )
241 nHeight
-= pPrtFrame
->getFrameArea().Height();
242 nOffset
+= pPrtFrame
->getFrameArea().Height();
244 else if( pPrtFrame
->IsFooterFrame() )
246 nHeight
-= pPrtFrame
->getFrameArea().Height();
248 pPrtFrame
= pPrtFrame
->GetNext();
253 case text::RelOrientation::PAGE_FRAME
:
254 case text::RelOrientation::PAGE_PRINT_AREA_TOP
:
256 nHeight
= aRectFnSet
.GetHeight(_rPageAlignLayFrame
.getFrameArea());
257 nOffset
= aRectFnSet
.YDiff(
258 aRectFnSet
.GetTop(_rPageAlignLayFrame
.getFrameArea()),
262 case text::RelOrientation::PAGE_PRINT_AREA
:
264 nHeight
= aRectFnSet
.GetHeight(_rPageAlignLayFrame
.getFramePrintArea());
265 nOffset
= aRectFnSet
.GetTopMargin(_rPageAlignLayFrame
) +
267 aRectFnSet
.GetTop(_rPageAlignLayFrame
.getFrameArea()),
269 // if aligned to page in horizontal layout, consider header and
270 // footer frame height appropriately.
271 if( _rPageAlignLayFrame
.IsPageFrame() && !aRectFnSet
.IsVert() )
273 const SwFrame
* pPrtFrame
=
274 static_cast<const SwPageFrame
&>(_rPageAlignLayFrame
).Lower();
277 if( pPrtFrame
->IsHeaderFrame() )
279 nHeight
-= pPrtFrame
->getFrameArea().Height();
280 nOffset
+= pPrtFrame
->getFrameArea().Height();
282 else if( pPrtFrame
->IsFooterFrame() )
284 nHeight
-= pPrtFrame
->getFrameArea().Height();
286 pPrtFrame
= pPrtFrame
->GetNext();
291 case text::RelOrientation::PAGE_PRINT_AREA_BOTTOM
:
293 nHeight
= aRectFnSet
.GetBottomMargin(_rPageAlignLayFrame
);
294 nOffset
= aRectFnSet
.YDiff(
295 aRectFnSet
.GetPrtBottom(_rPageAlignLayFrame
),
298 if (_rPageAlignLayFrame
.IsPageFrame() && !aRectFnSet
.IsVert())
300 const SwFrame
* pPrtFrame
=
301 static_cast<const SwPageFrame
&>(_rPageAlignLayFrame
).Lower();
305 if (pPrtFrame
->IsFooterFrame())
307 nHeight
+= pPrtFrame
->getFrameArea().Height();
308 nOffset
-= pPrtFrame
->getFrameArea().Height();
310 pPrtFrame
= pPrtFrame
->GetNext();
316 // #i22341# - vertical alignment at top of line
317 case text::RelOrientation::TEXT_LINE
:
319 if ( IsAnchoredToChar() )
322 nOffset
= aRectFnSet
.YDiff( ToCharTopOfLine(), nVertOrientTop
);
326 OSL_FAIL( "<SwAnchoredObjectPosition::GetVertAlignmentValues(..)> - invalid relative alignment" );
330 case text::RelOrientation::CHAR
:
332 if ( IsAnchoredToChar() )
334 nHeight
= aRectFnSet
.GetHeight(*ToCharRect());
335 nOffset
= aRectFnSet
.YDiff( aRectFnSet
.GetTop(*ToCharRect()),
340 OSL_FAIL( "<SwAnchoredObjectPosition::GetVertAlignmentValues(..)> - invalid relative alignment" );
344 // no break here, because text::RelOrientation::CHAR is invalid, if !mbAnchorToChar
347 OSL_FAIL( "<SwAnchoredObjectPosition::GetVertAlignmentValues(..)> - invalid relative alignment" );
351 _orAlignAreaHeight
= nHeight
;
352 _orAlignAreaOffset
= nOffset
;
355 // #i26791# - add output parameter <_roVertOffsetToFrameAnchorPos>
356 SwTwips
SwAnchoredObjectPosition::GetVertRelPos(
357 const SwFrame
& _rVertOrientFrame
,
358 const SwFrame
& _rPageAlignLayFrame
,
359 const sal_Int16 _eVertOrient
,
360 const sal_Int16 _eRelOrient
,
361 const SwTwips _nVertPos
,
362 const SvxLRSpaceItem
& _rLRSpacing
,
363 const SvxULSpaceItem
& _rULSpacing
,
364 SwTwips
& _roVertOffsetToFrameAnchorPos
) const
366 SwTwips nRelPosY
= 0;
367 SwRectFnSet
aRectFnSet(&_rVertOrientFrame
);
369 SwTwips nAlignAreaHeight
;
370 SwTwips nAlignAreaOffset
;
371 GetVertAlignmentValues( _rVertOrientFrame
, _rPageAlignLayFrame
,
372 _eRelOrient
, nAlignAreaHeight
, nAlignAreaOffset
);
374 nRelPosY
= nAlignAreaOffset
;
375 const SwRect
aObjBoundRect( GetAnchoredObj().GetObjRect() );
376 const SwTwips nObjHeight
= aRectFnSet
.GetHeight(aObjBoundRect
);
378 switch ( _eVertOrient
)
380 case text::VertOrientation::NONE
:
382 // 'manual' vertical position
383 nRelPosY
+= _nVertPos
;
386 case text::VertOrientation::TOP
:
388 nRelPosY
+= aRectFnSet
.IsVert()
389 ? ( aRectFnSet
.IsVertL2R()
390 ? _rLRSpacing
.GetLeft()
391 : _rLRSpacing
.GetRight() )
392 : _rULSpacing
.GetUpper();
395 case text::VertOrientation::CENTER
:
397 nRelPosY
+= (nAlignAreaHeight
/ 2) - (nObjHeight
/ 2);
400 case text::VertOrientation::BOTTOM
:
402 nRelPosY
+= nAlignAreaHeight
-
403 ( nObjHeight
+ ( aRectFnSet
.IsVert()
404 ? ( aRectFnSet
.IsVertL2R()
405 ? _rLRSpacing
.GetRight()
406 : _rLRSpacing
.GetLeft() )
407 : _rULSpacing
.GetLower() ) );
412 OSL_FAIL( "<SwAnchoredObjectPosition::GetVertRelPos(..) - invalid vertical positioning" );
417 _roVertOffsetToFrameAnchorPos
= nAlignAreaOffset
;
422 /** adjust calculated vertical in order to keep object inside
423 'page' alignment layout frame.
425 #i28701# - parameter <_nTopOfAnch> and <_bVert> added
426 #i31805# - add parameter <_bCheckBottom>
427 #i26945# - add parameter <_bFollowTextFlow>
428 #i62875# - method now private and renamed.
429 OD 2009-09-01 #mongolianlayout# - add parameter <bVertL2R>
431 SwTwips
SwAnchoredObjectPosition::ImplAdjustVertRelPos( const SwTwips nTopOfAnch
,
434 const SwFrame
& rPageAlignLayFrame
,
435 const SwTwips nProposedRelPosY
,
436 const bool bFollowTextFlow
,
437 const bool bCheckBottom
) const
439 SwTwips nAdjustedRelPosY
= nProposedRelPosY
;
440 // TODO: Replace the following condition with the correction
441 // of the implementation of option FollowTextFlow.
442 if ( SwAnchoredObject::IsDraggingOffPageAllowed(FindFrameFormat(&mrDrawObj
)) &&
443 !(GetAnchorFrame().IsInTab() && DoesObjFollowsTextFlow()) )
445 return nAdjustedRelPosY
;
448 const Size
aObjSize(GetAnchoredObj().GetObjRect().SSize());
449 // determine the area of 'page' alignment frame, to which the vertical
450 // position is restricted.
451 // #i28701# - Extend restricted area for the vertical
452 // position to area of the page frame, if wrapping style influence is
453 // considered on object positioning. Needed to avoid layout loops in the
454 // object positioning algorithm considering the wrapping style influence
455 // caused by objects, which follow the text flow and thus are restricted
456 // to its environment (e.g. page header/footer).
459 // #i26945# - no extension of restricted area, if
460 // object's attribute follow text flow is set and its inside a table
461 if ( GetFrameFormat().getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION
) &&
462 ( !bFollowTextFlow
||
463 !GetAnchoredObj().GetAnchorFrame()->IsInTab() ) )
465 aPgAlignArea
= rPageAlignLayFrame
.FindPageFrame()->getFrameArea();
469 aPgAlignArea
= rPageAlignLayFrame
.getFrameArea();
475 // #i31805# - consider value of <_bCheckBottom>
479 nTopOfAnch
- nAdjustedRelPosY
- aObjSize
.Width() <
480 aPgAlignArea
.Left() )
482 nAdjustedRelPosY
= aPgAlignArea
.Left() +
486 // #i32964# - correction
487 if ( nTopOfAnch
- nAdjustedRelPosY
> aPgAlignArea
.Right() )
489 nAdjustedRelPosY
= nTopOfAnch
- aPgAlignArea
.Right();
494 // tdf#112443 if position is completely off-page
495 // return the proposed position and do not adjust it...
496 // tdf#120839 .. unless anchored to char (anchor can jump on other page)
497 const bool bDisablePositioning
= mpFrameFormat
->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING
);
498 if ( bDisablePositioning
&& !IsAnchoredToChar() && nTopOfAnch
+ nAdjustedRelPosY
> aPgAlignArea
.Right() )
500 return nProposedRelPosY
;
504 nTopOfAnch
+ nAdjustedRelPosY
+ aObjSize
.Width() >
505 aPgAlignArea
.Right() )
507 nAdjustedRelPosY
= aPgAlignArea
.Right() -
511 if ( nTopOfAnch
+ nAdjustedRelPosY
< aPgAlignArea
.Left() )
513 nAdjustedRelPosY
= aPgAlignArea
.Left() - nTopOfAnch
;
519 // tdf#112443 if position is completely off-page
520 // return the proposed position and do not adjust it...
521 const bool bDisablePositioning
= mpFrameFormat
->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING
);
523 // tdf#123002 disable the positioning in header and footer only
524 // we should limit this since anchors of body frames may appear on other pages
525 const bool bIsFooterOrHeader
= GetAnchorFrame().GetUpper()
526 && (GetAnchorFrame().GetUpper()->IsFooterFrame() || GetAnchorFrame().GetUpper()->IsHeaderFrame() );
528 if ( bDisablePositioning
&& bIsFooterOrHeader
&& nTopOfAnch
+ nAdjustedRelPosY
> aPgAlignArea
.Bottom() )
530 return nProposedRelPosY
;
533 // #i31805# - consider value of <bCheckBottom>
535 nTopOfAnch
+ nAdjustedRelPosY
+ aObjSize
.Height() >
536 aPgAlignArea
.Top() + aPgAlignArea
.Height() )
538 nAdjustedRelPosY
= aPgAlignArea
.Top() + aPgAlignArea
.Height() -
542 if ( nTopOfAnch
+ nAdjustedRelPosY
< aPgAlignArea
.Top() )
544 nAdjustedRelPosY
= aPgAlignArea
.Top() - nTopOfAnch
;
547 return nAdjustedRelPosY
;
550 /** adjust calculated horizontal in order to keep object inside
551 'page' alignment layout frame.
553 #i62875# - method now private and renamed.
555 SwTwips
SwAnchoredObjectPosition::ImplAdjustHoriRelPos(
556 const SwFrame
& _rPageAlignLayFrame
,
557 const SwTwips _nProposedRelPosX
) const
559 SwTwips nAdjustedRelPosX
= _nProposedRelPosX
;
561 if (SwAnchoredObject::IsDraggingOffPageAllowed(FindFrameFormat(&mrDrawObj
)))
562 return nAdjustedRelPosX
;
564 const SwFrame
& rAnchorFrame
= GetAnchorFrame();
565 const bool bVert
= rAnchorFrame
.IsVertical();
567 const Size
aObjSize( GetAnchoredObj().GetObjRect().SSize() );
571 if ( rAnchorFrame
.getFrameArea().Top() + nAdjustedRelPosX
+ aObjSize
.Height() >
572 _rPageAlignLayFrame
.getFrameArea().Bottom() )
574 nAdjustedRelPosX
= _rPageAlignLayFrame
.getFrameArea().Bottom() -
575 rAnchorFrame
.getFrameArea().Top() -
578 if ( rAnchorFrame
.getFrameArea().Top() + nAdjustedRelPosX
<
579 _rPageAlignLayFrame
.getFrameArea().Top() )
581 nAdjustedRelPosX
= _rPageAlignLayFrame
.getFrameArea().Top() -
582 rAnchorFrame
.getFrameArea().Top();
587 if ( rAnchorFrame
.getFrameArea().Left() + nAdjustedRelPosX
+ aObjSize
.Width() >
588 _rPageAlignLayFrame
.getFrameArea().Right() )
590 nAdjustedRelPosX
= _rPageAlignLayFrame
.getFrameArea().Right() -
591 rAnchorFrame
.getFrameArea().Left() -
594 if ( rAnchorFrame
.getFrameArea().Left() + nAdjustedRelPosX
<
595 _rPageAlignLayFrame
.getFrameArea().Left() )
597 nAdjustedRelPosX
= _rPageAlignLayFrame
.getFrameArea().Left() -
598 rAnchorFrame
.getFrameArea().Left();
602 return nAdjustedRelPosX
;
605 /** determine alignment value for horizontal position of object */
606 void SwAnchoredObjectPosition::GetHoriAlignmentValues( const SwFrame
& _rHoriOrientFrame
,
607 const SwFrame
& _rPageAlignLayFrame
,
608 const sal_Int16 _eRelOrient
,
609 const bool _bObjWrapThrough
,
610 SwTwips
& _orAlignAreaWidth
,
611 SwTwips
& _orAlignAreaOffset
,
612 bool& _obAlignedRelToPage
) const
616 SwRectFnSet
aRectFnSet(&_rHoriOrientFrame
);
617 switch ( _eRelOrient
)
619 case text::RelOrientation::PRINT_AREA
:
621 nWidth
= aRectFnSet
.GetWidth(_rHoriOrientFrame
.getFramePrintArea());
622 nOffset
= aRectFnSet
.GetLeftMargin(_rHoriOrientFrame
);
623 if ( _rHoriOrientFrame
.IsTextFrame() )
625 // consider movement of text frame left
626 nOffset
+= static_cast<const SwTextFrame
&>(_rHoriOrientFrame
).GetBaseOffsetForFly( !_bObjWrapThrough
);
628 else if ( _rHoriOrientFrame
.IsPageFrame() && aRectFnSet
.IsVert() )
630 // for to-page anchored objects, consider header/footer frame
631 // in vertical layout
632 const SwFrame
* pPrtFrame
=
633 static_cast<const SwPageFrame
&>(_rHoriOrientFrame
).Lower();
636 if( pPrtFrame
->IsHeaderFrame() )
638 nWidth
-= pPrtFrame
->getFrameArea().Height();
639 nOffset
+= pPrtFrame
->getFrameArea().Height();
641 else if( pPrtFrame
->IsFooterFrame() )
643 nWidth
-= pPrtFrame
->getFrameArea().Height();
645 pPrtFrame
= pPrtFrame
->GetNext();
650 case text::RelOrientation::PAGE_LEFT
:
652 // align at left border of page frame/fly frame/cell frame
653 nWidth
= aRectFnSet
.GetLeftMargin(_rPageAlignLayFrame
);
654 nOffset
= aRectFnSet
.XDiff(
655 aRectFnSet
.GetLeft(_rPageAlignLayFrame
.getFrameArea()),
656 aRectFnSet
.GetLeft(_rHoriOrientFrame
.getFrameArea()) );
657 _obAlignedRelToPage
= true;
660 case text::RelOrientation::PAGE_RIGHT
:
662 // align at right border of page frame/fly frame/cell frame
663 nWidth
= aRectFnSet
.GetRightMargin(_rPageAlignLayFrame
);
664 nOffset
= aRectFnSet
.XDiff(
665 aRectFnSet
.GetPrtRight(_rPageAlignLayFrame
),
666 aRectFnSet
.GetLeft(_rHoriOrientFrame
.getFrameArea()) );
667 _obAlignedRelToPage
= true;
670 case text::RelOrientation::FRAME_LEFT
:
672 // align at left border of anchor frame
673 nWidth
= aRectFnSet
.GetLeftMargin(_rHoriOrientFrame
);
677 case text::RelOrientation::FRAME_RIGHT
:
679 // align at right border of anchor frame
680 // Unify and simplify
681 nWidth
= aRectFnSet
.GetRightMargin(_rHoriOrientFrame
);
682 nOffset
= aRectFnSet
.GetRight(_rHoriOrientFrame
.getFramePrintArea());
685 case text::RelOrientation::CHAR
:
687 // alignment relative to character - assure, that corresponding
688 // character rectangle is set.
689 if ( IsAnchoredToChar() )
692 nOffset
= aRectFnSet
.XDiff(
693 aRectFnSet
.GetLeft(*ToCharRect()),
694 aRectFnSet
.GetLeft(ToCharOrientFrame()->getFrameArea()) );
699 case text::RelOrientation::PAGE_PRINT_AREA
:
701 nWidth
= aRectFnSet
.GetWidth(_rPageAlignLayFrame
.getFramePrintArea());
702 nOffset
= aRectFnSet
.XDiff(
703 aRectFnSet
.GetPrtLeft(_rPageAlignLayFrame
),
704 aRectFnSet
.GetLeft(_rHoriOrientFrame
.getFrameArea()) );
705 if ( _rHoriOrientFrame
.IsPageFrame() && aRectFnSet
.IsVert() )
707 // for to-page anchored objects, consider header/footer frame
708 // in vertical layout
709 const SwFrame
* pPrtFrame
=
710 static_cast<const SwPageFrame
&>(_rHoriOrientFrame
).Lower();
713 if( pPrtFrame
->IsHeaderFrame() )
715 nWidth
-= pPrtFrame
->getFrameArea().Height();
716 nOffset
+= pPrtFrame
->getFrameArea().Height();
718 else if( pPrtFrame
->IsFooterFrame() )
720 nWidth
-= pPrtFrame
->getFrameArea().Height();
722 pPrtFrame
= pPrtFrame
->GetNext();
725 _obAlignedRelToPage
= true;
728 case text::RelOrientation::PAGE_FRAME
:
730 nWidth
= aRectFnSet
.GetWidth(_rPageAlignLayFrame
.getFrameArea());
731 nOffset
= aRectFnSet
.XDiff(
732 aRectFnSet
.GetLeft(_rPageAlignLayFrame
.getFrameArea()),
733 aRectFnSet
.GetLeft(_rHoriOrientFrame
.getFrameArea()) );
734 _obAlignedRelToPage
= true;
739 nWidth
= aRectFnSet
.GetWidth(_rHoriOrientFrame
.getFrameArea());
741 bool bWrapThrough
= _bObjWrapThrough
;
742 // If the frame format is a TextBox of a draw shape, then use the
743 // surround of the original shape.
744 SwTextBoxHelper::getShapeWrapThrough(mpFrameFormat
, bWrapThrough
);
746 bool bIgnoreFlysAnchoredAtFrame
= !bWrapThrough
;
747 nOffset
= _rHoriOrientFrame
.IsTextFrame() ?
748 static_cast<const SwTextFrame
&>(_rHoriOrientFrame
).GetBaseOffsetForFly( bIgnoreFlysAnchoredAtFrame
) :
754 _orAlignAreaWidth
= nWidth
;
755 _orAlignAreaOffset
= nOffset
;
758 /** toggle given horizontal orientation and relative alignment */
759 void SwAnchoredObjectPosition::ToggleHoriOrientAndAlign(
760 const bool _bToggleLeftRight
,
761 sal_Int16
& _ioeHoriOrient
,
762 sal_Int16
& _iopeRelOrient
765 if( !_bToggleLeftRight
)
768 // toggle orientation
769 switch ( _ioeHoriOrient
)
771 case text::HoriOrientation::RIGHT
:
773 _ioeHoriOrient
= text::HoriOrientation::LEFT
;
776 case text::HoriOrientation::LEFT
:
778 _ioeHoriOrient
= text::HoriOrientation::RIGHT
;
785 // toggle relative alignment
786 switch ( _iopeRelOrient
)
788 case text::RelOrientation::PAGE_RIGHT
:
790 _iopeRelOrient
= text::RelOrientation::PAGE_LEFT
;
793 case text::RelOrientation::PAGE_LEFT
:
795 _iopeRelOrient
= text::RelOrientation::PAGE_RIGHT
;
798 case text::RelOrientation::FRAME_RIGHT
:
800 _iopeRelOrient
= text::RelOrientation::FRAME_LEFT
;
803 case text::RelOrientation::FRAME_LEFT
:
805 _iopeRelOrient
= text::RelOrientation::FRAME_RIGHT
;
813 /** calculate relative horizontal position */
814 SwTwips
SwAnchoredObjectPosition::CalcRelPosX(
815 const SwFrame
& _rHoriOrientFrame
,
816 const SwEnvironmentOfAnchoredObject
& _rEnvOfObj
,
817 const SwFormatHoriOrient
& _rHoriOrient
,
818 const SvxLRSpaceItem
& _rLRSpacing
,
819 const SvxULSpaceItem
& _rULSpacing
,
820 const bool _bObjWrapThrough
,
821 const SwTwips _nRelPosY
,
822 SwTwips
& _roHoriOffsetToFrameAnchorPos
825 // determine 'page' alignment layout frame
826 const SwFrame
& rPageAlignLayFrame
=
827 _rEnvOfObj
.GetHoriEnvironmentLayoutFrame( _rHoriOrientFrame
);
829 const bool bEvenPage
= !rPageAlignLayFrame
.OnRightPage();
830 const bool bToggle
= _rHoriOrient
.IsPosToggle() && bEvenPage
;
832 // determine orientation and relative alignment
833 sal_Int16 eHoriOrient
= _rHoriOrient
.GetHoriOrient();
834 sal_Int16 eRelOrient
= _rHoriOrient
.GetRelationOrient();
835 // toggle orientation and relative alignment
836 ToggleHoriOrientAndAlign( bToggle
, eHoriOrient
, eRelOrient
);
838 // determine alignment parameter
839 // <nWidth>: 'width' of alignment area
840 // <nOffset>: offset of alignment area, relative to 'left' of anchor frame
843 bool bAlignedRelToPage
= false;
844 GetHoriAlignmentValues( _rHoriOrientFrame
, rPageAlignLayFrame
,
845 eRelOrient
, _bObjWrapThrough
,
846 nWidth
, nOffset
, bAlignedRelToPage
);
848 const SwFrame
& rAnchorFrame
= GetAnchorFrame();
849 SwRectFnSet
aRectFnSet(&_rHoriOrientFrame
);
850 SwTwips nObjWidth
= aRectFnSet
.GetWidth(GetAnchoredObj().GetObjRect());
851 SwTwips nRelPosX
= nOffset
;
852 if ( _rHoriOrient
.GetHoriOrient() == text::HoriOrientation::NONE
)
854 // 'manual' horizontal position
855 const bool bR2L
= rAnchorFrame
.IsRightToLeft();
856 if( IsAnchoredToChar() && text::RelOrientation::CHAR
== eRelOrient
)
859 nRelPosX
-= _rHoriOrient
.GetPos();
861 nRelPosX
+= _rHoriOrient
.GetPos();
863 else if ( bToggle
|| ( !_rHoriOrient
.IsPosToggle() && bR2L
) )
865 // Correction: consider <nOffset> also for
866 // toggling from left to right.
867 nRelPosX
+= nWidth
- nObjWidth
- _rHoriOrient
.GetPos();
871 nRelPosX
+= _rHoriOrient
.GetPos();
874 else if ( text::HoriOrientation::CENTER
== eHoriOrient
)
875 nRelPosX
+= (nWidth
/ 2) - (nObjWidth
/ 2);
876 else if ( text::HoriOrientation::RIGHT
== eHoriOrient
)
879 ( aRectFnSet
.IsVert() ? _rULSpacing
.GetLower() : _rLRSpacing
.GetRight() ) );
881 nRelPosX
+= aRectFnSet
.IsVert() ? _rULSpacing
.GetUpper() : _rLRSpacing
.GetLeft();
883 // adjust relative position by distance between anchor frame and
884 // the frame, the object is oriented at.
885 if ( &rAnchorFrame
!= &_rHoriOrientFrame
)
887 SwTwips nLeftOrient
= aRectFnSet
.GetLeft(_rHoriOrientFrame
.getFrameArea());
888 SwTwips nLeftAnchor
= aRectFnSet
.GetLeft(rAnchorFrame
.getFrameArea());
889 nRelPosX
+= aRectFnSet
.XDiff( nLeftOrient
, nLeftAnchor
);
892 // adjust calculated relative horizontal position, in order to
893 // keep object inside 'page' alignment layout frame
894 const SwFrame
& rEnvironmentLayFrame
=
895 _rEnvOfObj
.GetHoriEnvironmentLayoutFrame( _rHoriOrientFrame
);
896 bool bFollowTextFlow
= GetFrameFormat().GetFollowTextFlow().GetValue();
897 bool bWrapThrough
= GetFrameFormat().GetSurround().GetSurround() != text::WrapTextMode_THROUGH
;
898 // Don't try to keep wrap-though objects inside the cell, even if they are following text flow.
899 if (!rEnvironmentLayFrame
.IsInTab() || !bFollowTextFlow
|| bWrapThrough
)
901 nRelPosX
= AdjustHoriRelPos( rEnvironmentLayFrame
, nRelPosX
);
904 // if object is a Writer fly frame and it's anchored to a content and
905 // it is horizontal positioned left or right, but not relative to character,
906 // it has to be drawn aside another object, which have the same horizontal
907 // position and lay below it.
908 if ( GetAnchoredObj().DynCastFlyFrame() &&
909 ( mpContact
->ObjAnchoredAtPara() || mpContact
->ObjAnchoredAtChar() ) &&
910 ( eHoriOrient
== text::HoriOrientation::LEFT
|| eHoriOrient
== text::HoriOrientation::RIGHT
) &&
911 eRelOrient
!= text::RelOrientation::CHAR
)
913 nRelPosX
= AdjustHoriRelPosForDrawAside( _rHoriOrientFrame
,
915 eHoriOrient
, eRelOrient
,
916 _rLRSpacing
, _rULSpacing
,
921 _roHoriOffsetToFrameAnchorPos
= nOffset
;
926 // method incl. helper methods for adjusting proposed horizontal position,
927 // if object has to draw aside another object.
928 /** adjust calculated horizontal position in order to draw object
929 aside other objects with same positioning
931 SwTwips
SwAnchoredObjectPosition::AdjustHoriRelPosForDrawAside(
932 const SwFrame
& _rHoriOrientFrame
,
933 const SwTwips _nProposedRelPosX
,
934 const SwTwips _nRelPosY
,
935 const sal_Int16 _eHoriOrient
,
936 const sal_Int16 _eRelOrient
,
937 const SvxLRSpaceItem
& _rLRSpacing
,
938 const SvxULSpaceItem
& _rULSpacing
,
939 const bool _bEvenPage
943 if ( GetAnchorFrame().DynCastTextFrame() == nullptr ||
944 dynamic_cast<const SwFlyAtContentFrame
*>( &GetAnchoredObj() ) == nullptr )
946 OSL_FAIL( "<SwAnchoredObjectPosition::AdjustHoriRelPosForDrawAside(..) - usage for wrong anchor type" );
947 return _nProposedRelPosX
;
950 const SwTextFrame
& rAnchorTextFrame
= static_cast<const SwTextFrame
&>(GetAnchorFrame());
952 const SwFlyAtContentFrame
& rFlyAtContentFrame
=
953 static_cast<const SwFlyAtContentFrame
&>(GetAnchoredObj());
954 const SwRect
aObjBoundRect( GetAnchoredObj().GetObjRect() );
955 SwRectFnSet
aRectFnSet(&_rHoriOrientFrame
);
957 SwTwips nAdjustedRelPosX
= _nProposedRelPosX
;
959 // determine proposed object bound rectangle
960 Point aTmpPos
= aRectFnSet
.GetPos(rAnchorTextFrame
.getFrameArea());
961 if( aRectFnSet
.IsVert() )
963 aTmpPos
.AdjustX( -(_nRelPosY
+ aObjBoundRect
.Width()) );
964 aTmpPos
.AdjustY(nAdjustedRelPosX
);
968 aTmpPos
.AdjustX(nAdjustedRelPosX
);
969 aTmpPos
.AdjustY(_nRelPosY
);
971 SwRect
aTmpObjRect( aTmpPos
, aObjBoundRect
.SSize() );
973 const sal_uInt32 nObjOrdNum
= GetObject().GetOrdNum();
974 const SwPageFrame
* pObjPage
= rFlyAtContentFrame
.FindPageFrame();
975 const SwFrame
* pObjContext
= ::FindContext( &rAnchorTextFrame
, SwFrameType::Column
);
976 SwNodeOffset nObjIndex
= rAnchorTextFrame
.GetTextNodeFirst()->GetIndex();
977 SwOrderIter
aIter( pObjPage
);
978 const SwFlyFrame
* pFly
= static_cast<const SwVirtFlyDrawObj
*>(aIter
.Bottom())->GetFlyFrame();
979 while ( pFly
&& nObjOrdNum
> pFly
->GetVirtDrawObj()->GetOrdNumDirect() )
981 if ( DrawAsideFly( pFly
, aTmpObjRect
, pObjContext
, nObjIndex
,
982 _bEvenPage
, _eHoriOrient
, _eRelOrient
) )
984 if( aRectFnSet
.IsVert() )
986 const SvxULSpaceItem
& rOtherUL
= pFly
->GetFormat()->GetULSpace();
987 const SwTwips nOtherTop
= pFly
->getFrameArea().Top() - rOtherUL
.GetUpper();
988 const SwTwips nOtherBot
= pFly
->getFrameArea().Bottom() + rOtherUL
.GetLower();
989 if ( nOtherTop
<= aTmpObjRect
.Bottom() + _rULSpacing
.GetLower() &&
990 nOtherBot
>= aTmpObjRect
.Top() - _rULSpacing
.GetUpper() )
992 if ( _eHoriOrient
== text::HoriOrientation::LEFT
)
994 SwTwips nTmp
= nOtherBot
+ 1 + _rULSpacing
.GetUpper() -
995 rAnchorTextFrame
.getFrameArea().Top();
996 if ( nTmp
> nAdjustedRelPosX
&&
997 rAnchorTextFrame
.getFrameArea().Top() + nTmp
+
998 aObjBoundRect
.Height() + _rULSpacing
.GetLower()
999 <= pObjPage
->getFrameArea().Height() + pObjPage
->getFrameArea().Top() )
1001 nAdjustedRelPosX
= nTmp
;
1004 else if ( _eHoriOrient
== text::HoriOrientation::RIGHT
)
1006 SwTwips nTmp
= nOtherTop
- 1 - _rULSpacing
.GetLower() -
1007 aObjBoundRect
.Height() -
1008 rAnchorTextFrame
.getFrameArea().Top();
1009 if ( nTmp
< nAdjustedRelPosX
&&
1010 rAnchorTextFrame
.getFrameArea().Top() + nTmp
- _rULSpacing
.GetUpper()
1011 >= pObjPage
->getFrameArea().Top() )
1013 nAdjustedRelPosX
= nTmp
;
1016 aTmpObjRect
.Pos().setY( rAnchorTextFrame
.getFrameArea().Top() +
1022 const SvxLRSpaceItem
& rOtherLR
= pFly
->GetFormat()->GetLRSpace();
1023 const SwTwips nOtherLeft
= pFly
->getFrameArea().Left() - rOtherLR
.GetLeft();
1024 const SwTwips nOtherRight
= pFly
->getFrameArea().Right() + rOtherLR
.GetRight();
1025 if( nOtherLeft
<= aTmpObjRect
.Right() + _rLRSpacing
.GetRight() &&
1026 nOtherRight
>= aTmpObjRect
.Left() - _rLRSpacing
.GetLeft() )
1028 if ( _eHoriOrient
== text::HoriOrientation::LEFT
)
1030 SwTwips nTmp
= nOtherRight
+ 1 + _rLRSpacing
.GetLeft() -
1031 rAnchorTextFrame
.getFrameArea().Left();
1032 if ( nTmp
> nAdjustedRelPosX
&&
1033 rAnchorTextFrame
.getFrameArea().Left() + nTmp
+
1034 aObjBoundRect
.Width() + _rLRSpacing
.GetRight()
1035 <= pObjPage
->getFrameArea().Width() + pObjPage
->getFrameArea().Left() )
1037 nAdjustedRelPosX
= nTmp
;
1040 else if ( _eHoriOrient
== text::HoriOrientation::RIGHT
)
1042 SwTwips nTmp
= nOtherLeft
- 1 - _rLRSpacing
.GetRight() -
1043 aObjBoundRect
.Width() -
1044 rAnchorTextFrame
.getFrameArea().Left();
1045 if ( nTmp
< nAdjustedRelPosX
&&
1046 rAnchorTextFrame
.getFrameArea().Left() + nTmp
- _rLRSpacing
.GetLeft()
1047 >= pObjPage
->getFrameArea().Left() )
1049 nAdjustedRelPosX
= nTmp
;
1052 aTmpObjRect
.Pos().setX( rAnchorTextFrame
.getFrameArea().Left() +
1055 } // end of <if (bVert)>
1056 } // end of <if DrawAsideFly(..)>
1058 pFly
= static_cast<const SwVirtFlyDrawObj
*>(aIter
.Next())->GetFlyFrame();
1059 } // end of <loop on fly frames
1061 return nAdjustedRelPosX
;
1064 /** determine, if object has to draw aside given fly frame
1066 method used by <AdjustHoriRelPosForDrawAside(..)>
1068 bool SwAnchoredObjectPosition::DrawAsideFly( const SwFlyFrame
* _pFly
,
1069 const SwRect
& _rObjRect
,
1070 const SwFrame
* _pObjContext
,
1071 const SwNodeOffset _nObjIndex
,
1072 const bool _bEvenPage
,
1073 const sal_Int16 _eHoriOrient
,
1074 const sal_Int16 _eRelOrient
1077 bool bRetVal
= false;
1079 SwRectFnSet
aRectFnSet(&GetAnchorFrame());
1081 if ( _pFly
->IsFlyAtContentFrame() &&
1082 aRectFnSet
.BottomDist( _pFly
->getFrameArea(), aRectFnSet
.GetTop(_rObjRect
) ) < 0 &&
1083 aRectFnSet
.BottomDist( _rObjRect
, aRectFnSet
.GetTop(_pFly
->getFrameArea()) ) < 0 &&
1084 ::FindContext( _pFly
->GetAnchorFrame(), SwFrameType::Column
) == _pObjContext
)
1086 SwNodeOffset nOtherIndex
=
1087 static_cast<const SwTextFrame
*>(_pFly
->GetAnchorFrame())->GetTextNodeFirst()->GetIndex();
1088 if (sw::FrameContainsNode(static_cast<SwTextFrame
const&>(*_pFly
->GetAnchorFrame()), _nObjIndex
)
1089 || nOtherIndex
< _nObjIndex
)
1091 const SwFormatHoriOrient
& rHori
= _pFly
->GetFormat()->GetHoriOrient();
1092 sal_Int16 eOtherRelOrient
= rHori
.GetRelationOrient();
1093 if( text::RelOrientation::CHAR
!= eOtherRelOrient
)
1095 sal_Int16 eOtherHoriOrient
= rHori
.GetHoriOrient();
1096 ToggleHoriOrientAndAlign( _bEvenPage
&& rHori
.IsPosToggle(),
1099 if ( eOtherHoriOrient
== _eHoriOrient
&&
1100 Minor_( _eRelOrient
, eOtherRelOrient
, text::HoriOrientation::LEFT
== _eHoriOrient
) )
1111 /** determine, if object has to draw aside another object
1113 the different alignments of the objects determines, if one has
1114 to draw aside another one. Thus, the given alignment are checked
1115 against each other, which one has to be drawn aside the other one.
1116 depending on parameter _bLeft check is done for left or right
1118 method used by <DrawAsideFly(..)>
1120 bool SwAnchoredObjectPosition::Minor_( sal_Int16 _eRelOrient1
,
1121 sal_Int16 _eRelOrient2
,
1126 // draw aside order for left horizontal position
1127 //! one array entry for each value in text::RelOrientation
1128 static sal_uInt16
const aLeft
[ 10 ] =
1129 { 5, 6, 0, 1, 8, 4, 7, 2, 3, 9 };
1130 // draw aside order for right horizontal position
1131 //! one array entry for each value in text::RelOrientation
1132 static sal_uInt16
const aRight
[ 10 ] =
1133 { 5, 6, 0, 8, 1, 7, 4, 2, 3, 9 };
1135 // decide depending on given order, which frame has to draw aside another frame
1137 bRetVal
= aLeft
[ _eRelOrient1
] >= aLeft
[ _eRelOrient2
];
1139 bRetVal
= aRight
[ _eRelOrient1
] >= aRight
[ _eRelOrient2
];
1146 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */