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 <tocntntanchoredobjectposition.hxx>
21 #include <anchoredobject.hxx>
24 #include <pagefrm.hxx>
25 #include <sectfrm.hxx>
27 #include <rootfrm.hxx>
28 #include <viewopt.hxx>
31 #include <fmtsrnd.hxx>
32 #include <fmtfsize.hxx>
33 #include <fmtanchr.hxx>
34 #include <fmtornt.hxx>
35 #include <editeng/lrspitem.hxx>
36 #include <editeng/ulspitem.hxx>
37 #include <svx/svdobj.hxx>
38 #include <environmentofanchoredobject.hxx>
40 #include <fmtwrapinfluenceonobjpos.hxx>
41 #include <sortedobjs.hxx>
42 #include <textboxhelper.hxx>
44 using namespace objectpositioning
;
45 using namespace ::com::sun::star
;
47 SwToContentAnchoredObjectPosition::SwToContentAnchoredObjectPosition( SdrObject
& _rDrawObj
)
48 : SwAnchoredObjectPosition ( _rDrawObj
),
49 mpVertPosOrientFrame( nullptr ),
51 maOffsetToFrameAnchorPos( Point() ),
52 mbAnchorToChar ( false ),
53 mpToCharOrientFrame( nullptr ),
54 mpToCharRect( nullptr ),
56 mnToCharTopOfLine( 0 )
59 SwToContentAnchoredObjectPosition::~SwToContentAnchoredObjectPosition()
62 bool SwToContentAnchoredObjectPosition::IsAnchoredToChar() const
64 return mbAnchorToChar
;
67 const SwFrame
* SwToContentAnchoredObjectPosition::ToCharOrientFrame() const
69 return mpToCharOrientFrame
;
72 const SwRect
* SwToContentAnchoredObjectPosition::ToCharRect() const
78 SwTwips
SwToContentAnchoredObjectPosition::ToCharTopOfLine() const
80 return mnToCharTopOfLine
;
83 SwTextFrame
& SwToContentAnchoredObjectPosition::GetAnchorTextFrame() const
85 OSL_ENSURE( dynamic_cast<const SwTextFrame
*>( &GetAnchorFrame()) != nullptr ,
86 "SwToContentAnchoredObjectPosition::GetAnchorTextFrame() - wrong anchor frame type" );
88 return static_cast<SwTextFrame
&>(GetAnchorFrame());
92 static bool lcl_DoesVertPosFits( const SwTwips _nRelPosY
,
93 const SwTwips _nAvail
,
94 const SwLayoutFrame
* _pUpperOfOrientFrame
,
96 const bool _bGrowInTable
,
97 SwLayoutFrame
*& _orpLayoutFrameToGrow
)
99 bool bVertPosFits
= false;
101 if ( _nRelPosY
<= _nAvail
)
107 if ( _pUpperOfOrientFrame
->IsInSct() )
109 SwSectionFrame
* pSctFrame
=
110 const_cast<SwSectionFrame
*>(_pUpperOfOrientFrame
->FindSctFrame());
111 bVertPosFits
= pSctFrame
->GetUpper()->Grow( _nRelPosY
- _nAvail
, true ) > 0;
112 // Note: do not provide a layout frame for a grow.
116 bVertPosFits
= const_cast<SwLayoutFrame
*>(_pUpperOfOrientFrame
)->
117 Grow( _nRelPosY
- _nAvail
, true ) > 0;
119 _orpLayoutFrameToGrow
= const_cast<SwLayoutFrame
*>(_pUpperOfOrientFrame
);
122 else if ( _pUpperOfOrientFrame
->IsInTab() && _bGrowInTable
)
124 // #i45085# - check, if upper frame would grow the
125 // expected amount of twips.
126 const SwTwips nTwipsGrown
= const_cast<SwLayoutFrame
*>(_pUpperOfOrientFrame
)->
127 Grow( _nRelPosY
- _nAvail
, true );
128 bVertPosFits
= ( nTwipsGrown
== ( _nRelPosY
- _nAvail
) );
130 _orpLayoutFrameToGrow
= const_cast<SwLayoutFrame
*>(_pUpperOfOrientFrame
);
136 void SwToContentAnchoredObjectPosition::CalcPosition()
138 // get format of object
139 const SwFrameFormat
& rFrameFormat
= GetFrameFormat();
141 // declare and set <pFooter> to footer frame, if object is anchored
142 // at a frame belonging to the footer.
143 const SwFrame
* pFooter
= GetAnchorFrame().FindFooterOrHeader();
144 if ( pFooter
&& !pFooter
->IsFooterFrame() )
147 // declare and set <bBrowse> to true, if document is in browser mode and
148 // object is anchored at the body, but not at frame belonging to a table.
149 bool bBrowse
= GetAnchorFrame().IsInDocBody() && !GetAnchorFrame().IsInTab();
152 const SwViewShell
*pSh
= GetAnchorFrame().getRootFrame()->GetCurrShell();
153 if( !pSh
|| !pSh
->GetViewOptions()->getBrowseMode() )
157 // determine left/right and its upper/lower spacing.
158 const SvxLRSpaceItem
&rLR
= rFrameFormat
.GetLRSpace();
159 const SvxULSpaceItem
&rUL
= rFrameFormat
.GetULSpace();
161 // determine, if object has no surrounding.
162 const SwFormatSurround
& rSurround
= rFrameFormat
.GetSurround();
163 const bool bNoSurround
= rSurround
.GetSurround() == css::text::WrapTextMode_NONE
;
164 const bool bWrapThrough
= rSurround
.GetSurround() == css::text::WrapTextMode_THROUGH
;
166 // new class <SwEnvironmentOfAnchoredObject>
167 SwEnvironmentOfAnchoredObject
aEnvOfObj( DoesObjFollowsTextFlow() );
169 // #i18732# - grow only, if object has to follow the text flow
170 const bool bGrow
= DoesObjFollowsTextFlow() &&
171 ( !GetAnchorFrame().IsInTab() ||
172 !rFrameFormat
.GetFrameSize().GetHeightPercent() );
174 // get text frame the object is anchored at
175 const SwTextFrame
& rAnchorTextFrame
= GetAnchorTextFrame();
176 SwRectFnSet
aRectFnSet(&rAnchorTextFrame
);
178 const SwRect
aObjBoundRect( GetAnchoredObj().GetObjRect() );
180 // local variable keeping the calculated relative position; initialized with
181 // current relative position.
182 // #i26791# - use new object instance of <SwAnchoredObject>
183 Point
aRelPos( GetAnchoredObj().GetCurrRelPos() );
185 SwTwips nRelDiff
= 0;
187 bool bMoveable
= rAnchorTextFrame
.IsMoveable();
189 // determine frame the object position has to be oriented at.
190 const SwTextFrame
* pOrientFrame
= &rAnchorTextFrame
;
191 const SwTextFrame
* pAnchorFrameForVertPos
;
193 // if object is at-character anchored, determine character-rectangle
194 // and frame, position has to be oriented at.
195 mbAnchorToChar
= (RndStdIds::FLY_AT_CHAR
== rFrameFormat
.GetAnchor().GetAnchorId());
196 if ( mbAnchorToChar
)
198 const SwFormatAnchor
& rAnch
= rFrameFormat
.GetAnchor();
199 // #i26791# - use new object instance of <SwAnchoredObject>
200 // Due to table break algorithm the character
201 // rectangle can have no height. Thus, check also the width
202 if ( ( !GetAnchoredObj().GetLastCharRect().Height() &&
203 !GetAnchoredObj().GetLastCharRect().Width() ) ||
204 !GetAnchoredObj().GetLastTopOfLine() )
206 GetAnchoredObj().CheckCharRectAndTopOfLine( false );
207 // Due to table break algorithm the character
208 // rectangle can have no height. Thus, check also the width
209 if ( ( !GetAnchoredObj().GetLastCharRect().Height() &&
210 !GetAnchoredObj().GetLastCharRect().Width() ) ||
211 !GetAnchoredObj().GetLastTopOfLine() )
213 // Get default for <mpVertPosOrientFrame>, if it's not set.
214 if ( !mpVertPosOrientFrame
)
216 mpVertPosOrientFrame
= rAnchorTextFrame
.GetUpper();
221 mpToCharRect
= &(GetAnchoredObj().GetLastCharRect());
222 // #i22341# - get top of line, in which the anchor character is.
223 mnToCharTopOfLine
= GetAnchoredObj().GetLastTopOfLine();
224 pOrientFrame
= &(const_cast<SwTextFrame
&>(rAnchorTextFrame
).GetFrameAtOfst(
225 rAnchorTextFrame
.MapModelToViewPos(*rAnch
.GetContentAnchor())));
226 mpToCharOrientFrame
= pOrientFrame
;
229 aRectFnSet
.Refresh(pOrientFrame
);
231 // determine vertical position
234 // determine vertical positioning and alignment attributes
235 SwFormatVertOrient
aVert( rFrameFormat
.GetVertOrient() );
237 // #i18732# - determine layout frame for vertical
238 // positions aligned to 'page areas'.
239 const SwLayoutFrame
& rPageAlignLayFrame
=
240 aEnvOfObj
.GetVertEnvironmentLayoutFrame( *pOrientFrame
);
242 if ( aVert
.GetVertOrient() != text::VertOrientation::NONE
)
244 // #i18732# - adjustments for follow text flow or not
245 // AND vertical alignment at 'page areas'.
246 SwTwips nAlignAreaHeight
;
247 SwTwips nAlignAreaOffset
;
248 GetVertAlignmentValues( *pOrientFrame
, rPageAlignLayFrame
,
249 aVert
.GetRelationOrient(),
250 nAlignAreaHeight
, nAlignAreaOffset
);
253 const SwPageFrame
* aPageFrame
= pOrientFrame
->FindPageFrame();
254 const SwHeaderFrame
* pHeaderFrame
= aPageFrame
->GetHeaderFrame();
256 aHeaderRect
= pHeaderFrame
->GetPaintArea();
257 const SwTwips nTopMarginHeight
= aPageFrame
->GetTopMargin() + aHeaderRect
.Height();
258 const SwTwips nHeightBetweenOffsetAndMargin
= nAlignAreaOffset
+ nTopMarginHeight
;
260 // determine relative vertical position
261 SwTwips nRelPosY
= nAlignAreaOffset
;
262 const SwTwips nObjHeight
= aRectFnSet
.GetHeight(aObjBoundRect
);
263 const SwTwips nUpperSpace
= aRectFnSet
.IsVert()
264 ? ( aRectFnSet
.IsVertL2R()
268 // --> OD 2009-08-31 #monglianlayout#
269 const SwTwips nLowerSpace
= aRectFnSet
.IsVert()
270 ? ( aRectFnSet
.IsVertL2R()
274 switch ( aVert
.GetVertOrient() )
276 case text::VertOrientation::CHAR_BOTTOM
:
278 if ( mbAnchorToChar
)
280 // bottom (to character anchored)
281 nRelPosY
+= nAlignAreaHeight
+ nUpperSpace
;
282 if ( aRectFnSet
.IsVert() && !aRectFnSet
.IsVertL2R() )
284 nRelPosY
+= nObjHeight
;
290 case text::VertOrientation::TOP
:
292 // #i22341# - special case for vertical
293 // alignment at top of line
294 if ( mbAnchorToChar
&&
295 aVert
.GetRelationOrient() == text::RelOrientation::TEXT_LINE
)
297 nRelPosY
-= (nObjHeight
+ nLowerSpace
);
301 nRelPosY
+= nUpperSpace
;
306 case text::VertOrientation::LINE_TOP
:
308 if ( mbAnchorToChar
&&
309 aVert
.GetRelationOrient() == text::RelOrientation::TEXT_LINE
)
311 nRelPosY
-= (nObjHeight
+ nLowerSpace
);
315 OSL_FAIL( "<SwToContentAnchoredObjectPosition::CalcPosition()> - unknown combination of vertical position and vertical alignment." );
319 case text::VertOrientation::CENTER
:
321 if (aVert
.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA_TOP
)
322 nRelPosY
= (nAlignAreaOffset
/ 2) - (nObjHeight
/ 2) + (nHeightBetweenOffsetAndMargin
/ 2);
324 nRelPosY
+= (nAlignAreaHeight
/ 2) - (nObjHeight
/ 2);
328 case text::VertOrientation::LINE_CENTER
:
330 if ( mbAnchorToChar
&&
331 aVert
.GetRelationOrient() == text::RelOrientation::TEXT_LINE
)
333 nRelPosY
+= (nAlignAreaHeight
/ 2) - (nObjHeight
/ 2);
337 OSL_FAIL( "<SwToContentAnchoredObjectPosition::CalcPosition()> - unknown combination of vertical position and vertical alignment." );
341 case text::VertOrientation::BOTTOM
:
343 if ( ( aVert
.GetRelationOrient() == text::RelOrientation::FRAME
||
344 aVert
.GetRelationOrient() == text::RelOrientation::PRINT_AREA
) &&
347 // bottom (aligned to 'paragraph areas')
348 nRelPosY
+= nAlignAreaHeight
+ nUpperSpace
;
352 // #i22341# - special case for vertical
353 // alignment at top of line
354 if ( mbAnchorToChar
&&
355 aVert
.GetRelationOrient() == text::RelOrientation::TEXT_LINE
)
357 nRelPosY
+= nUpperSpace
;
361 if (aVert
.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA_TOP
)
362 nRelPosY
= 0 - (nObjHeight
+ nLowerSpace
) + nHeightBetweenOffsetAndMargin
;
364 nRelPosY
+= nAlignAreaHeight
- (nObjHeight
+ nLowerSpace
);
370 case text::VertOrientation::LINE_BOTTOM
:
372 if ( mbAnchorToChar
&&
373 aVert
.GetRelationOrient() == text::RelOrientation::TEXT_LINE
)
375 nRelPosY
+= nUpperSpace
;
379 OSL_FAIL( "<SwToContentAnchoredObjectPosition::CalcPosition()> - unknown combination of vertical position and vertical alignment." );
387 // adjust relative position by distance between anchor frame and
388 // the frame, the object is oriented at.
389 // #i28701# - correction: adjust relative position,
390 // only if the floating screen object has to follow the text flow.
391 if ( DoesObjFollowsTextFlow() && pOrientFrame
!= &rAnchorTextFrame
)
393 // #i11860# - use new method <GetTopForObjPos>
394 // to get top of frame for object positioning.
395 const SwTwips nTopOfOrient
= GetTopForObjPos( *pOrientFrame
, aRectFnSet
.FnRect(), aRectFnSet
.IsVert() );
396 nRelPosY
+= aRectFnSet
.YDiff( nTopOfOrient
,
397 GetTopForObjPos( rAnchorTextFrame
, aRectFnSet
.FnRect(), aRectFnSet
.IsVert() ) );
400 // #i42124# - capture object inside vertical
401 // layout environment.
403 const SwTwips nTopOfAnch
=
404 GetTopForObjPos( *pOrientFrame
, aRectFnSet
.FnRect(), aRectFnSet
.IsVert() );
405 const SwLayoutFrame
& rVertEnvironLayFrame
=
406 aEnvOfObj
.GetVertEnvironmentLayoutFrame(
407 *(pOrientFrame
->GetUpper()) );
408 const bool bCheckBottom
= !DoesObjFollowsTextFlow();
409 nRelPosY
= AdjustVertRelPos( nTopOfAnch
, aRectFnSet
.IsVert(), aRectFnSet
.IsVertL2R(),
410 rVertEnvironLayFrame
, nRelPosY
,
411 DoesObjFollowsTextFlow(),
415 // keep calculated relative vertical position - needed for filters
416 // (including the xml-filter)
418 // determine position
419 SwTwips nAttrRelPosY
= nRelPosY
- nAlignAreaOffset
;
421 if ( nAttrRelPosY
!= aVert
.GetPos() )
423 aVert
.SetPos( nAttrRelPosY
);
424 const_cast<SwFrameFormat
&>(rFrameFormat
).LockModify();
425 const_cast<SwFrameFormat
&>(rFrameFormat
).SetFormatAttr( aVert
);
426 const_cast<SwFrameFormat
&>(rFrameFormat
).UnlockModify();
430 // determine absolute 'vertical' position, depending on layout-direction
431 // #i26791# - determine offset to 'vertical' frame
432 // anchor position, depending on layout-direction
433 if ( aRectFnSet
.IsVert() )
435 aRelPos
.setX( nRelPosY
);
436 maOffsetToFrameAnchorPos
.setX( nAlignAreaOffset
);
440 aRelPos
.setY( nRelPosY
);
441 maOffsetToFrameAnchorPos
.setY( nAlignAreaOffset
);
445 // Determine upper of frame vertical position is oriented at.
446 // #i28701# - determine 'virtual' anchor frame.
447 // This frame is used in the following instead of the 'real' anchor
448 // frame <rAnchorTextFrame> for the 'vertical' position in all cases.
449 const SwLayoutFrame
* pUpperOfOrientFrame
= nullptr;
451 // #i28701# - As long as the anchor frame is on the
452 // same page as <pOrientFrame> and the vertical position isn't aligned
453 // automatic at the anchor character or the top of the line of the
454 // anchor character, the anchor frame determines the vertical position.
455 if ( &rAnchorTextFrame
== pOrientFrame
||
456 ( rAnchorTextFrame
.FindPageFrame() == pOrientFrame
->FindPageFrame() &&
457 aVert
.GetVertOrient() == text::VertOrientation::NONE
&&
458 aVert
.GetRelationOrient() != text::RelOrientation::CHAR
&&
459 aVert
.GetRelationOrient() != text::RelOrientation::TEXT_LINE
) )
461 pUpperOfOrientFrame
= rAnchorTextFrame
.GetUpper();
462 pAnchorFrameForVertPos
= &rAnchorTextFrame
;
466 pUpperOfOrientFrame
= pOrientFrame
->GetUpper();
467 pAnchorFrameForVertPos
= pOrientFrame
;
471 // ignore one-column sections.
472 // #i23512# - correction: also ignore one-columned
473 // sections with footnotes/endnotes
474 if ( pUpperOfOrientFrame
->IsInSct() )
476 const SwSectionFrame
* pSctFrame
= pUpperOfOrientFrame
->FindSctFrame();
477 const bool bIgnoreSection
= pUpperOfOrientFrame
->IsSctFrame() ||
478 ( pSctFrame
->Lower()->IsColumnFrame() &&
479 !pSctFrame
->Lower()->GetNext() );
480 if ( bIgnoreSection
)
481 pUpperOfOrientFrame
= pSctFrame
->GetUpper();
484 if ( aVert
.GetVertOrient() == text::VertOrientation::NONE
)
486 // local variable <nRelPosY> for calculation of relative vertical
487 // distance to anchor.
488 SwTwips nRelPosY
= 0;
489 // #i26791# - local variable <nVertOffsetToFrameAnchorPos>
490 // for determination of the 'vertical' offset to the frame anchor
492 SwTwips
nVertOffsetToFrameAnchorPos( 0 );
493 // #i22341# - add special case for vertical alignment
495 if ( mbAnchorToChar
&&
496 ( aVert
.GetRelationOrient() == text::RelOrientation::CHAR
||
497 aVert
.GetRelationOrient() == text::RelOrientation::TEXT_LINE
) )
499 // #i11860# - use new method <GetTopForObjPos>
500 // to get top of frame for object positioning.
501 SwTwips nTopOfOrient
= GetTopForObjPos( *pOrientFrame
, aRectFnSet
.FnRect(), aRectFnSet
.IsVert() );
502 if ( aVert
.GetRelationOrient() == text::RelOrientation::CHAR
)
504 nVertOffsetToFrameAnchorPos
= aRectFnSet
.YDiff(
505 aRectFnSet
.GetBottom(*ToCharRect()),
510 nVertOffsetToFrameAnchorPos
= aRectFnSet
.YDiff( ToCharTopOfLine(),
513 nRelPosY
= nVertOffsetToFrameAnchorPos
- aVert
.GetPos();
517 // #i28701# - correction: use <pAnchorFrameForVertPos>
518 // instead of <pOrientFrame> and do not adjust relative position
519 // to get correct vertical position.
520 nVertOffsetToFrameAnchorPos
= 0;
521 // #i11860# - use new method <GetTopForObjPos>
522 // to get top of frame for object positioning.
523 const SwTwips nTopOfOrient
=
524 GetTopForObjPos( *pAnchorFrameForVertPos
, aRectFnSet
.FnRect(), aRectFnSet
.IsVert() );
525 // Increase <nRelPosY> by margin height,
526 // if position is vertical aligned to "paragraph text area"
527 if ( aVert
.GetRelationOrient() == text::RelOrientation::PRINT_AREA
)
529 // #i11860# - consider upper space amount of previous frame
530 SwTwips nTopMargin
= aRectFnSet
.GetTopMargin(*pAnchorFrameForVertPos
);
531 if ( pAnchorFrameForVertPos
->IsTextFrame() )
533 nTopMargin
-= pAnchorFrameForVertPos
->
534 GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid();
536 nVertOffsetToFrameAnchorPos
+= nTopMargin
;
538 // #i18732# - adjust <nRelPosY> by difference
539 // between 'page area' and 'anchor' frame, if position is
540 // vertical aligned to 'page areas'
541 else if (aVert
.GetRelationOrient() == text::RelOrientation::PAGE_FRAME
542 || aVert
.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA_TOP
)
544 nVertOffsetToFrameAnchorPos
+= aRectFnSet
.YDiff(
545 aRectFnSet
.GetTop(rPageAlignLayFrame
.getFrameArea()),
548 else if ( aVert
.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA
)
550 SwRect
aPgPrtRect( rPageAlignLayFrame
.getFrameArea() );
551 if ( rPageAlignLayFrame
.IsPageFrame() )
554 static_cast<const SwPageFrame
&>(rPageAlignLayFrame
).PrtWithoutHeaderAndFooter();
556 nVertOffsetToFrameAnchorPos
+= aRectFnSet
.YDiff(
557 aRectFnSet
.GetTop(aPgPrtRect
),
560 else if (aVert
.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA_BOTTOM
)
562 // The anchored object is relative from the bottom of the page's print area.
563 SwRect
aPgPrtRect(rPageAlignLayFrame
.getFrameArea());
564 if (rPageAlignLayFrame
.IsPageFrame())
566 auto& rPageFrame
= static_cast<const SwPageFrame
&>(rPageAlignLayFrame
);
567 aPgPrtRect
= rPageFrame
.PrtWithoutHeaderAndFooter();
569 SwTwips nPageBottom
= aRectFnSet
.GetBottom(aPgPrtRect
);
570 nVertOffsetToFrameAnchorPos
+= aRectFnSet
.YDiff(nPageBottom
, nTopOfOrient
);
572 nRelPosY
= nVertOffsetToFrameAnchorPos
+ aVert
.GetPos();
575 // <pUpperOfOrientFrame>: layout frame, at which the position has to
577 // <nRelPosY>: rest of the relative distance in the current
579 // <nAvail>: space, which is available in the current
582 // #i26791# - determine offset to 'vertical'
583 // frame anchor position, depending on layout-direction
584 if ( aRectFnSet
.IsVert() )
585 maOffsetToFrameAnchorPos
.setX( nVertOffsetToFrameAnchorPos
);
587 maOffsetToFrameAnchorPos
.setY( nVertOffsetToFrameAnchorPos
);
588 // #i11860# - use new method <GetTopForObjPos>
589 // to get top of frame for object positioning.
590 const SwTwips nTopOfAnch
= GetTopForObjPos( *pAnchorFrameForVertPos
, aRectFnSet
.FnRect(), aRectFnSet
.IsVert() );
593 // Allow negative position, but keep it
594 // inside environment layout frame.
595 const SwLayoutFrame
& rVertEnvironLayFrame
=
596 aEnvOfObj
.GetVertEnvironmentLayoutFrame( *pUpperOfOrientFrame
);
597 // #i31805# - do not check, if bottom of
598 // anchored object would fit into environment layout frame, if
599 // anchored object has to follow the text flow.
600 const bool bCheckBottom
= !DoesObjFollowsTextFlow();
601 nRelPosY
= AdjustVertRelPos( nTopOfAnch
, aRectFnSet
.IsVert(), aRectFnSet
.IsVertL2R(),
602 rVertEnvironLayFrame
, nRelPosY
,
603 DoesObjFollowsTextFlow(),
605 if ( aRectFnSet
.IsVert() )
606 aRelPos
.setX( nRelPosY
);
608 aRelPos
.setY( nRelPosY
);
612 aRectFnSet
.Refresh(pAnchorFrameForVertPos
);
614 aRectFnSet
.YDiff( aRectFnSet
.GetPrtBottom(*pUpperOfOrientFrame
),
616 const bool bInFootnote
= pAnchorFrameForVertPos
->IsInFootnote();
619 // #i23512# - correction:
620 // consider section frame for grow in online layout.
621 // use new local method <lcl_DoesVertPosFits(..)>
622 SwLayoutFrame
* pLayoutFrameToGrow
= nullptr;
623 const bool bDoesVertPosFits
= lcl_DoesVertPosFits(
624 nRelPosY
, nAvail
, pUpperOfOrientFrame
, bBrowse
,
625 bGrow
, pLayoutFrameToGrow
);
627 if ( bDoesVertPosFits
)
629 SwTwips nTmpRelPosY
=
630 aRectFnSet
.YDiff( aRectFnSet
.GetPrtBottom(*pUpperOfOrientFrame
),
633 // #i28701# - adjust calculated
634 // relative vertical position to object's environment.
635 const SwFrame
& rVertEnvironLayFrame
=
636 aEnvOfObj
.GetVertEnvironmentLayoutFrame( *pUpperOfOrientFrame
);
637 // Do not check, if bottom of
638 // anchored object would fit into environment layout
639 // frame, if anchored object has to follow the text flow.
640 const bool bCheckBottom
= !DoesObjFollowsTextFlow();
641 nTmpRelPosY
= AdjustVertRelPos( nTopOfAnch
, aRectFnSet
.IsVert(), aRectFnSet
.IsVertL2R(),
642 rVertEnvironLayFrame
,
644 DoesObjFollowsTextFlow(),
646 if ( aRectFnSet
.IsVert() )
647 aRelPos
.setX( nTmpRelPosY
);
649 aRelPos
.setY( nTmpRelPosY
);
651 // #i23512# - use local variable
652 // <pLayoutFrameToGrow> provided by new method
653 // <lcl_DoesVertPosFits(..)>.
654 if ( pLayoutFrameToGrow
)
656 // No need to grow the anchor cell in case the follow-text-flow object
658 if (!GetAnchorFrame().IsInTab() || !DoesObjFollowsTextFlow() || !bWrapThrough
)
660 pLayoutFrameToGrow
->Grow( nRelPosY
- nAvail
);
667 // #i26495# - floating screen objects,
668 // which are anchored inside a table, doesn't follow
670 if ( DoesObjFollowsTextFlow() &&
671 ( aVert
.GetRelationOrient() != text::RelOrientation::PAGE_FRAME
&&
672 aVert
.GetRelationOrient() != text::RelOrientation::PAGE_PRINT_AREA
) &&
673 !GetAnchorFrame().IsInTab() )
677 // follow the text flow
679 MakePageType eMakePage
= bInFootnote
? MAKEPAGE_NONE
681 const bool bInSct
= pUpperOfOrientFrame
->IsInSct();
683 eMakePage
= MAKEPAGE_NOSECTION
;
685 const SwLayoutFrame
* pTmp
=
686 pUpperOfOrientFrame
->GetLeaf( eMakePage
, true, &rAnchorTextFrame
);
689 pUpperOfOrientFrame
->FindSctFrame()->IsAnFollow( pTmp
->FindSctFrame() ) ) )
691 pUpperOfOrientFrame
= pTmp
;
692 bMoveable
= rAnchorTextFrame
.IsMoveable( pUpperOfOrientFrame
);
693 aRectFnSet
.Refresh(pUpperOfOrientFrame
);
694 nAvail
= aRectFnSet
.GetHeight(pUpperOfOrientFrame
->getFramePrintArea());
698 // if there isn't enough space in the (columned)
699 // section, leave it and set available space <nAvail>
700 // to the space below the section.
701 // if the new available space isn't also enough,
702 // new pages can be created.
705 const SwFrame
* pSct
= pUpperOfOrientFrame
->FindSctFrame();
706 pUpperOfOrientFrame
= pSct
->GetUpper();
707 nAvail
= aRectFnSet
.YDiff(
708 aRectFnSet
.GetPrtBottom(*pUpperOfOrientFrame
),
709 aRectFnSet
.GetPrtBottom(*pSct
) );
713 #if OSL_DEBUG_LEVEL > 1
714 OSL_FAIL( "<SwToContentAnchoredObjectPosition::CalcPosition()> - !bInSct" );
728 // #i18732# - do not follow text flow respectively
729 // align at 'page areas', but stay inside given environment
730 const SwFrame
& rVertEnvironLayFrame
=
731 aEnvOfObj
.GetVertEnvironmentLayoutFrame( *pUpperOfOrientFrame
);
732 nRelPosY
= AdjustVertRelPos( nTopOfAnch
, aRectFnSet
.IsVert(), aRectFnSet
.IsVertL2R(),
733 rVertEnvironLayFrame
,
735 DoesObjFollowsTextFlow() );
736 if( aRectFnSet
.IsVert() )
737 aRelPos
.setX( nRelPosY
);
739 aRelPos
.setY( nRelPosY
);
743 } // end of <while ( nRelPosY )>
744 } // end of else <nRelPosY <= 0>
745 } // end of <aVert.GetVertOrient() == text::VertOrientation::NONE>
747 // We need to calculate the part's absolute position, in order for
748 // it to be put onto the right page and to be pulled into the
750 const SwTwips nTopOfAnch
= GetTopForObjPos( *pAnchorFrameForVertPos
, aRectFnSet
.FnRect(), aRectFnSet
.IsVert() );
751 if( aRectFnSet
.IsVert() )
753 // --> OD 2009-08-31 #monglianlayout#
754 if ( !aRectFnSet
.IsVertL2R() )
756 GetAnchoredObj().SetObjLeft( nTopOfAnch
-
757 ( aRelPos
.X() - nRelDiff
) -
758 aObjBoundRect
.Width() );
762 GetAnchoredObj().SetObjLeft( nTopOfAnch
+
763 ( aRelPos
.X() - nRelDiff
) );
768 GetAnchoredObj().SetObjTop( nTopOfAnch
+
769 ( aRelPos
.Y() - nRelDiff
) );
772 // grow environment under certain conditions
773 // ignore one-column sections.
774 // #i23512# - correction: also ignore one-columned
775 // sections with footnotes/endnotes
776 if ( pUpperOfOrientFrame
->IsInSct() )
778 const SwSectionFrame
* pSctFrame
= pUpperOfOrientFrame
->FindSctFrame();
779 const bool bIgnoreSection
= pUpperOfOrientFrame
->IsSctFrame() ||
780 ( pSctFrame
->Lower()->IsColumnFrame() &&
781 !pSctFrame
->Lower()->GetNext() );
782 if ( bIgnoreSection
)
783 pUpperOfOrientFrame
= pSctFrame
->GetUpper();
785 SwTwips nDist
= aRectFnSet
.BottomDist( GetAnchoredObj().GetObjRect(),
786 aRectFnSet
.GetPrtBottom(*pUpperOfOrientFrame
) );
789 // #i23512# - correction:
790 // consider section frame for grow in online layout and
791 // consider page alignment for grow in table.
792 SwLayoutFrame
* pLayoutFrameToGrow
= nullptr;
793 if ( bBrowse
&& rAnchorTextFrame
.IsMoveable() )
795 if ( pUpperOfOrientFrame
->IsInSct() )
797 pLayoutFrameToGrow
= const_cast<SwLayoutFrame
*>(
798 pUpperOfOrientFrame
->FindSctFrame()->GetUpper());
799 nDist
= aRectFnSet
.BottomDist( GetAnchoredObj().GetObjRect(),
800 aRectFnSet
.GetPrtBottom(*pLayoutFrameToGrow
) );
803 pLayoutFrameToGrow
= nullptr;
809 const_cast<SwLayoutFrame
*>(pUpperOfOrientFrame
);
812 else if ( rAnchorTextFrame
.IsInTab() && bGrow
)
814 pLayoutFrameToGrow
= const_cast<SwLayoutFrame
*>(pUpperOfOrientFrame
);
816 if ( pLayoutFrameToGrow
)
818 // No need to grow the anchor cell in case the follow-text-flow object
820 if (!GetAnchorFrame().IsInTab() || !DoesObjFollowsTextFlow() || !bWrapThrough
)
822 pLayoutFrameToGrow
->Grow( -nDist
);
827 if ( DoesObjFollowsTextFlow() &&
828 ( aVert
.GetRelationOrient() != text::RelOrientation::PAGE_FRAME
&&
829 aVert
.GetRelationOrient() != text::RelOrientation::PAGE_PRINT_AREA
) )
832 nDist
= aRectFnSet
.BottomDist( GetAnchoredObj().GetObjRect(),
833 aRectFnSet
.GetPrtBottom(*pUpperOfOrientFrame
) );
834 // #i26945# - floating screen objects, which are
835 // anchored inside a table, doesn't follow the text flow. But, they
836 // have to stay inside its layout environment.
837 if ( nDist
< 0 && pOrientFrame
->IsInTab() )
839 // If the anchor frame is the first content of the table cell
840 // and has no follow, the table frame is notified,
841 // that the object doesn't fit into the table cell.
842 // Adjustment of position isn't needed in this case.
843 if ( pOrientFrame
== &rAnchorTextFrame
&&
844 !pOrientFrame
->GetFollow() &&
845 !pOrientFrame
->GetIndPrev() )
847 const_cast<SwTabFrame
*>(pOrientFrame
->FindTabFrame())
848 ->SetDoesObjsFit( false );
852 SwTwips
nTmpRelPosY( 0 );
853 if ( aRectFnSet
.IsVert() )
854 nTmpRelPosY
= aRelPos
.X() - nDist
;
856 nTmpRelPosY
= aRelPos
.Y() + nDist
;
857 const SwLayoutFrame
& rVertEnvironLayFrame
=
858 aEnvOfObj
.GetVertEnvironmentLayoutFrame( *pUpperOfOrientFrame
);
859 nTmpRelPosY
= AdjustVertRelPos( nTopOfAnch
, aRectFnSet
.IsVert(), aRectFnSet
.IsVertL2R(),
860 rVertEnvironLayFrame
,
862 DoesObjFollowsTextFlow(),
864 if ( aRectFnSet
.IsVert() )
866 aRelPos
.setX( nTmpRelPosY
);
867 // --> OD 2009-08-31 #mongolianlayout#
868 if ( !aRectFnSet
.IsVertL2R() )
870 GetAnchoredObj().SetObjLeft( nTopOfAnch
-
872 aObjBoundRect
.Width() );
876 GetAnchoredObj().SetObjLeft( nTopOfAnch
+ aRelPos
.X() );
881 aRelPos
.setY( nTmpRelPosY
);
882 GetAnchoredObj().SetObjTop( nTopOfAnch
+ aRelPos
.Y() );
884 // If the anchor frame is the first content of the table cell
885 // and the object still doesn't fit, the table frame is notified,
886 // that the object doesn't fit into the table cell.
887 nDist
= aRectFnSet
.BottomDist( GetAnchoredObj().GetObjRect(),
888 aRectFnSet
.GetPrtBottom(*pUpperOfOrientFrame
) );
890 pOrientFrame
== &rAnchorTextFrame
&& !pOrientFrame
->GetIndPrev() )
892 const_cast<SwTabFrame
*>(pOrientFrame
->FindTabFrame())
893 ->SetDoesObjsFit( false );
900 const bool bInFootnote
= rAnchorTextFrame
.IsInFootnote();
901 while( bMoveable
&& nDist
< 0 )
903 bool bInSct
= pUpperOfOrientFrame
->IsInSct();
906 const SwLayoutFrame
* pTmp
= pUpperOfOrientFrame
->FindSctFrame()->GetUpper();
907 nDist
= aRectFnSet
.BottomDist( GetAnchoredObj().GetObjRect(),
908 aRectFnSet
.GetPrtBottom(*pTmp
) );
909 // #i23129# - Try to flow into next
910 // section|section column. Thus, do *not* leave section
911 // area, if anchored object doesn't fit into upper of section.
912 // But the anchored object is allowed to overlap bottom
913 // section|section column.
920 aRectFnSet
.GetTop(GetAnchoredObj().GetObjRect()) ==
921 aRectFnSet
.GetPrtTop(*pUpperOfOrientFrame
) )
922 // It doesn't fit, moving it would not help either anymore
925 const SwLayoutFrame
* pNextLay
= pUpperOfOrientFrame
->GetLeaf(
928 : ( bInFootnote
? MAKEPAGE_NONE
: MAKEPAGE_APPEND
) ),
929 true, &rAnchorTextFrame
);
931 // If anchor is in footnote and proposed next layout environment
932 // isn't a footnote frame, object can't follow the text flow
933 if ( bInFootnote
&& pNextLay
&& !pNextLay
->IsFootnoteFrame() )
939 SwRectFnSet
fnRectX(pNextLay
);
941 ( pUpperOfOrientFrame
->FindSctFrame()->IsAnFollow( pNextLay
->FindSctFrame() ) &&
942 fnRectX
.GetHeight(pNextLay
->getFramePrintArea()) ) )
944 SwTwips nTmpRelPosY
=
945 aRectFnSet
.YDiff( aRectFnSet
.GetPrtTop(*pNextLay
),
947 if ( aRectFnSet
.IsVert() )
948 aRelPos
.setX( nTmpRelPosY
);
950 aRelPos
.setY( nTmpRelPosY
);
951 pUpperOfOrientFrame
= pNextLay
;
952 aRectFnSet
.Refresh(pUpperOfOrientFrame
);
953 bMoveable
= rAnchorTextFrame
.IsMoveable( pUpperOfOrientFrame
);
954 if( fnRectX
.IsVert() )
956 // --> OD 2009-08-31 #mongolianlayout#
957 if ( !aRectFnSet
.IsVertL2R() )
959 GetAnchoredObj().SetObjLeft( nTopOfAnch
-
961 aObjBoundRect
.Width() );
965 GetAnchoredObj().SetObjLeft( nTopOfAnch
+
970 GetAnchoredObj().SetObjTop( nTopOfAnch
+
972 nDist
= aRectFnSet
.BottomDist( GetAnchoredObj().GetObjRect(),
973 aRectFnSet
.GetPrtBottom(*pUpperOfOrientFrame
) );
975 // #i23129# - leave section area
978 const SwLayoutFrame
* pTmp
= pUpperOfOrientFrame
->FindSctFrame()->GetUpper();
979 nDist
= aRectFnSet
.BottomDist( GetAnchoredObj().GetObjRect(),
980 aRectFnSet
.GetPrtBottom(*pTmp
) );
982 pUpperOfOrientFrame
= pTmp
;
989 // If we don't have enough room within the Area, we take a look at
991 const SwLayoutFrame
* pTmp
= pUpperOfOrientFrame
->FindSctFrame()->GetUpper();
992 nDist
= aRectFnSet
.BottomDist( GetAnchoredObj().GetObjRect(),
993 aRectFnSet
.GetPrtBottom(*pTmp
) );
995 pUpperOfOrientFrame
= pTmp
;
1005 // keep layout frame vertical position is oriented at.
1006 mpVertPosOrientFrame
= pUpperOfOrientFrame
;
1008 // If it was requested to not overlap with already formatted objects, take care of that
1010 CalcOverlap(pAnchorFrameForVertPos
, aRelPos
, nTopOfAnch
);
1013 // determine 'horizontal' position
1015 // determine horizontal positioning and alignment attributes
1016 SwFormatHoriOrient
aHori( rFrameFormat
.GetHoriOrient() );
1018 // set calculated vertical position in order to determine correct
1019 // frame, the horizontal position is oriented at.
1020 const SwTwips nTopOfAnch
= GetTopForObjPos( *pAnchorFrameForVertPos
, aRectFnSet
.FnRect(), aRectFnSet
.IsVert() );
1021 if( aRectFnSet
.IsVert() )
1023 // --> OD 2009-08-31 #mongolianlayout#
1024 if ( !aRectFnSet
.IsVertL2R() )
1026 GetAnchoredObj().SetObjLeft( nTopOfAnch
-
1027 aRelPos
.X() - aObjBoundRect
.Width() );
1031 GetAnchoredObj().SetObjLeft( nTopOfAnch
+ aRelPos
.X() );
1035 GetAnchoredObj().SetObjTop( nTopOfAnch
+ aRelPos
.Y() );
1037 // determine frame, horizontal position is oriented at.
1038 // #i28701# - If floating screen object doesn't follow
1039 // the text flow, its horizontal position is oriented at <pOrientFrame>.
1040 const SwFrame
* pHoriOrientFrame
= DoesObjFollowsTextFlow()
1041 ? &GetHoriVirtualAnchor( *mpVertPosOrientFrame
)
1044 // #i26791# - get 'horizontal' offset to frame anchor position.
1045 SwTwips
nHoriOffsetToFrameAnchorPos( 0 );
1046 SwTwips nRelPosX
= CalcRelPosX( *pHoriOrientFrame
, aEnvOfObj
,
1047 aHori
, rLR
, rUL
, bWrapThrough
,
1048 ( aRectFnSet
.IsVert() ? aRelPos
.X() : aRelPos
.Y() ),
1049 nHoriOffsetToFrameAnchorPos
);
1051 // #i26791# - determine offset to 'horizontal' frame
1052 // anchor position, depending on layout-direction
1053 if ( aRectFnSet
.IsVert() )
1055 aRelPos
.setY( nRelPosX
);
1056 maOffsetToFrameAnchorPos
.setY( nHoriOffsetToFrameAnchorPos
);
1060 aRelPos
.setX( nRelPosX
);
1061 maOffsetToFrameAnchorPos
.setX( nHoriOffsetToFrameAnchorPos
);
1064 // save calculated horizontal position - needed for filters
1065 // (including the xml-filter)
1067 SwTwips nAttrRelPosX
= nRelPosX
- nHoriOffsetToFrameAnchorPos
;
1068 if ( aHori
.GetHoriOrient() != text::HoriOrientation::NONE
&&
1069 aHori
.GetPos() != nAttrRelPosX
)
1071 aHori
.SetPos( nAttrRelPosX
);
1072 const_cast<SwFrameFormat
&>(rFrameFormat
).LockModify();
1073 const_cast<SwFrameFormat
&>(rFrameFormat
).SetFormatAttr( aHori
);
1074 const_cast<SwFrameFormat
&>(rFrameFormat
).UnlockModify();
1079 // set absolute position at object
1080 const SwTwips nTopOfAnch
= GetTopForObjPos( *pAnchorFrameForVertPos
, aRectFnSet
.FnRect(), aRectFnSet
.IsVert() );
1081 if( aRectFnSet
.IsVert() )
1083 // --> OD 2009-08-31 #mongolianlayout#
1084 if ( !aRectFnSet
.IsVertL2R() )
1086 GetAnchoredObj().SetObjLeft( nTopOfAnch
-
1087 aRelPos
.X() - aObjBoundRect
.Width() );
1091 GetAnchoredObj().SetObjLeft( nTopOfAnch
+ aRelPos
.X() );
1093 GetAnchoredObj().SetObjTop( rAnchorTextFrame
.getFrameArea().Top() +
1098 GetAnchoredObj().SetObjLeft( rAnchorTextFrame
.getFrameArea().Left() +
1100 GetAnchoredObj().SetObjTop( nTopOfAnch
+ aRelPos
.Y() );
1103 // set relative position at object
1104 GetAnchoredObj().SetCurrRelPos( aRelPos
);
1107 void SwToContentAnchoredObjectPosition::CalcOverlap(const SwTextFrame
* pAnchorFrameForVertPos
,
1108 Point
& rRelPos
, const SwTwips nTopOfAnch
)
1110 const SwFrameFormat
& rFrameFormat
= GetFrameFormat();
1111 bool bAllowOverlap
= rFrameFormat
.GetWrapInfluenceOnObjPos().GetAllowOverlap();
1117 if (rFrameFormat
.GetSurround().GetSurround() == css::text::WrapTextMode_THROUGH
)
1119 // This is explicit wrap through: allowed to overlap.
1123 if (SwTextBoxHelper::isTextBox(&rFrameFormat
, RES_FLYFRMFMT
))
1125 // This is the frame part of a textbox, just take the offset from the textbox's shape part.
1126 SwFrameFormat
* pShapeOfTextBox
1127 = SwTextBoxHelper::getOtherTextBoxFormat(&rFrameFormat
, RES_FLYFRMFMT
);
1128 if (pShapeOfTextBox
)
1130 SwTwips nYDiff
= pShapeOfTextBox
->GetWrapInfluenceOnObjPos().GetOverlapVertOffset();
1133 rRelPos
.setY(rRelPos
.getY() + nYDiff
+ 1);
1134 GetAnchoredObj().SetObjTop(nTopOfAnch
+ rRelPos
.Y());
1140 // Get the list of objects.
1141 auto pSortedObjs
= pAnchorFrameForVertPos
->GetDrawObjs();
1147 for (const auto& pAnchoredObj
: *pSortedObjs
)
1149 if (pAnchoredObj
== &GetAnchoredObj())
1151 // We found ourselves, stop iterating.
1155 if (SwTextBoxHelper::isTextBox(&pAnchoredObj
->GetFrameFormat(), RES_FLYFRMFMT
))
1157 // Overlapping with the frame of a textbox is fine.
1161 css::text::WrapTextMode eWrap
= pAnchoredObj
->GetFrameFormat().GetSurround().GetSurround();
1162 if (eWrap
== css::text::WrapTextMode_THROUGH
)
1164 // The other object is wrap through: allowed to overlap.
1168 if (!GetAnchoredObj().GetObjRect().IsOver(pAnchoredObj
->GetObjRect()))
1170 // Found an already positioned object, but it doesn't overlap, ignore.
1174 // Already formatted, overlaps: resolve the conflict by shifting ourselves down.
1175 SwTwips nYDiff
= pAnchoredObj
->GetObjRect().Bottom() - GetAnchoredObj().GetObjRect().Top();
1176 rRelPos
.setY(rRelPos
.getY() + nYDiff
+ 1);
1177 GetAnchoredObj().SetObjTop(nTopOfAnch
+ rRelPos
.Y());
1179 // Store our offset that avoids the overlap. If this is a shape of a textbox, then the frame
1180 // of the textbox will use it.
1181 SwFormatWrapInfluenceOnObjPos
aInfluence(rFrameFormat
.GetWrapInfluenceOnObjPos());
1182 aInfluence
.SetOverlapVertOffset(nYDiff
);
1183 const_cast<SwFrameFormat
&>(rFrameFormat
).LockModify();
1184 const_cast<SwFrameFormat
&>(rFrameFormat
).SetFormatAttr(aInfluence
);
1185 const_cast<SwFrameFormat
&>(rFrameFormat
).UnlockModify();
1190 * Determine frame for horizontal position
1192 const SwFrame
& SwToContentAnchoredObjectPosition::GetHoriVirtualAnchor(
1193 const SwLayoutFrame
& _rProposedFrame
) const
1195 const SwFrame
* pHoriVirtAnchFrame
= &_rProposedFrame
;
1197 // Search for first lower content frame, which is the anchor or a follow
1198 // of the anchor (Note: <Anchor.IsAnFollow( Anchor )> is true)
1199 // If none found, <_rProposedFrame> is returned.
1200 const SwFrame
* pFrame
= _rProposedFrame
.Lower();
1203 if ( pFrame
->IsContentFrame() &&
1204 GetAnchorTextFrame().IsAnFollow( static_cast<const SwContentFrame
*>(pFrame
) ) )
1206 pHoriVirtAnchFrame
= pFrame
;
1209 pFrame
= pFrame
->GetNext();
1212 return *pHoriVirtAnchFrame
;
1216 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */