android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / objectpositioning / tocntntanchoredobjectposition.cxx
blob31802ee4c184399417b5d49851cca950436e5691
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 <tocntntanchoredobjectposition.hxx>
21 #include <anchoredobject.hxx>
22 #include <frame.hxx>
23 #include <txtfrm.hxx>
24 #include <pagefrm.hxx>
25 #include <sectfrm.hxx>
26 #include <tabfrm.hxx>
27 #include <rootfrm.hxx>
28 #include <viewopt.hxx>
29 #include <viewsh.hxx>
30 #include <frmfmt.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 <osl/diagnose.h>
39 #include <environmentofanchoredobject.hxx>
40 #include <frmatr.hxx>
41 #include <fmtwrapinfluenceonobjpos.hxx>
42 #include <sortedobjs.hxx>
43 #include <textboxhelper.hxx>
44 #include <flyfrms.hxx>
46 using namespace ::com::sun::star;
48 namespace objectpositioning
50 SwToContentAnchoredObjectPosition::SwToContentAnchoredObjectPosition( SdrObject& _rDrawObj )
51 : SwAnchoredObjectPosition ( _rDrawObj ),
52 mpVertPosOrientFrame( nullptr ),
53 mbAnchorToChar ( false ),
54 mpToCharOrientFrame( nullptr ),
55 mpToCharRect( nullptr ),
56 // #i22341#
57 mnToCharTopOfLine( 0 )
60 SwToContentAnchoredObjectPosition::~SwToContentAnchoredObjectPosition()
63 bool SwToContentAnchoredObjectPosition::IsAnchoredToChar() const
65 return mbAnchorToChar;
68 const SwFrame* SwToContentAnchoredObjectPosition::ToCharOrientFrame() const
70 return mpToCharOrientFrame;
73 const SwRect* SwToContentAnchoredObjectPosition::ToCharRect() const
75 return mpToCharRect;
78 // #i22341#
79 SwTwips SwToContentAnchoredObjectPosition::ToCharTopOfLine() const
81 return mnToCharTopOfLine;
84 SwTextFrame& SwToContentAnchoredObjectPosition::GetAnchorTextFrame() const
86 assert( dynamic_cast<const SwTextFrame*>( &GetAnchorFrame()) &&
87 "SwToContentAnchoredObjectPosition::GetAnchorTextFrame() - wrong anchor frame type" );
89 return static_cast<SwTextFrame&>(GetAnchorFrame());
92 // #i23512#
93 static bool lcl_DoesVertPosFits( const SwTwips _nRelPosY,
94 const SwTwips _nAvail,
95 const SwLayoutFrame* _pUpperOfOrientFrame,
96 const bool _bBrowse,
97 const bool _bGrowInTable,
98 SwLayoutFrame*& _orpLayoutFrameToGrow )
100 bool bVertPosFits = false;
102 if ( _nRelPosY <= _nAvail )
104 bVertPosFits = true;
106 else if ( _bBrowse )
108 if ( _pUpperOfOrientFrame->IsInSct() )
110 SwSectionFrame* pSctFrame =
111 const_cast<SwSectionFrame*>(_pUpperOfOrientFrame->FindSctFrame());
112 bVertPosFits = pSctFrame->GetUpper()->Grow( _nRelPosY - _nAvail, true ) > 0;
113 // Note: do not provide a layout frame for a grow.
115 else
117 bVertPosFits = const_cast<SwLayoutFrame*>(_pUpperOfOrientFrame)->
118 Grow( _nRelPosY - _nAvail, true ) > 0;
119 if ( bVertPosFits )
120 _orpLayoutFrameToGrow = const_cast<SwLayoutFrame*>(_pUpperOfOrientFrame);
123 else if ( _pUpperOfOrientFrame->IsInTab() && _bGrowInTable )
125 // #i45085# - check, if upper frame would grow the
126 // expected amount of twips.
127 const SwTwips nTwipsGrown = const_cast<SwLayoutFrame*>(_pUpperOfOrientFrame)->
128 Grow( _nRelPosY - _nAvail, true );
129 bVertPosFits = ( nTwipsGrown == ( _nRelPosY - _nAvail ) );
130 if ( bVertPosFits )
131 _orpLayoutFrameToGrow = const_cast<SwLayoutFrame*>(_pUpperOfOrientFrame);
134 return bVertPosFits;
137 void SwToContentAnchoredObjectPosition::CalcPosition()
139 // get format of object
140 const SwFrameFormat& rFrameFormat = GetFrameFormat();
142 // declare and set <pFooter> to footer frame, if object is anchored
143 // at a frame belonging to the footer.
144 const SwFrame* pFooter = GetAnchorFrame().FindFooterOrHeader();
145 if ( pFooter && !pFooter->IsFooterFrame() )
146 pFooter = nullptr;
148 // declare and set <bBrowse> to true, if document is in browser mode and
149 // object is anchored at the body, but not at frame belonging to a table.
150 bool bBrowse = GetAnchorFrame().IsInDocBody() && !GetAnchorFrame().IsInTab();
151 if( bBrowse )
153 const SwViewShell *pSh = GetAnchorFrame().getRootFrame()->GetCurrShell();
154 if( !pSh || !pSh->GetViewOptions()->getBrowseMode() )
155 bBrowse = false;
158 // determine left/right and its upper/lower spacing.
159 const SvxLRSpaceItem &rLR = rFrameFormat.GetLRSpace();
160 const SvxULSpaceItem &rUL = rFrameFormat.GetULSpace();
162 // determine, if object has no surrounding.
163 const SwFormatSurround& rSurround = rFrameFormat.GetSurround();
164 const bool bNoSurround = rSurround.GetSurround() == css::text::WrapTextMode_NONE;
165 const bool bWrapThrough = rSurround.GetSurround() == css::text::WrapTextMode_THROUGH;
167 // new class <SwEnvironmentOfAnchoredObject>
168 SwEnvironmentOfAnchoredObject aEnvOfObj( DoesObjFollowsTextFlow() );
170 // #i18732# - grow only, if object has to follow the text flow
171 const bool bGrow = DoesObjFollowsTextFlow() &&
172 ( !GetAnchorFrame().IsInTab() ||
173 !rFrameFormat.GetFrameSize().GetHeightPercent() );
175 // get text frame the object is anchored at
176 const SwTextFrame& rAnchorTextFrame = GetAnchorTextFrame();
177 SwRectFnSet aRectFnSet(&rAnchorTextFrame);
179 const SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() );
181 // local variable keeping the calculated relative position; initialized with
182 // current relative position.
183 // #i26791# - use new object instance of <SwAnchoredObject>
184 Point aRelPos( GetAnchoredObj().GetCurrRelPos() );
186 SwTwips nRelDiff = 0;
188 bool bMoveable = rAnchorTextFrame.IsMoveable();
190 // determine frame the object position has to be oriented at.
191 const SwTextFrame* pOrientFrame = &rAnchorTextFrame;
192 const SwTextFrame* pAnchorFrameForVertPos;
193 // If true, this means that the anchored object is a split fly frame and it's not a master but
194 // one of the follows.
195 bool bFollowSplitFly = false;
196 // The anchored object is a fly that is allowed to split.
197 bool bSplitFly = false;
199 // if object is at-character anchored, determine character-rectangle
200 // and frame, position has to be oriented at.
201 mbAnchorToChar = (RndStdIds::FLY_AT_CHAR == rFrameFormat.GetAnchor().GetAnchorId());
202 if ( mbAnchorToChar )
204 const SwFormatAnchor& rAnch = rFrameFormat.GetAnchor();
205 // #i26791# - use new object instance of <SwAnchoredObject>
206 // Due to table break algorithm the character
207 // rectangle can have no height. Thus, check also the width
208 if ( ( !GetAnchoredObj().GetLastCharRect().Height() &&
209 !GetAnchoredObj().GetLastCharRect().Width() ) ||
210 !GetAnchoredObj().GetLastTopOfLine() )
212 GetAnchoredObj().CheckCharRectAndTopOfLine( false );
213 // Due to table break algorithm the character
214 // rectangle can have no height. Thus, check also the width
215 if ( ( !GetAnchoredObj().GetLastCharRect().Height() &&
216 !GetAnchoredObj().GetLastCharRect().Width() ) ||
217 !GetAnchoredObj().GetLastTopOfLine() )
219 // Get default for <mpVertPosOrientFrame>, if it's not set.
220 if ( !mpVertPosOrientFrame )
222 mpVertPosOrientFrame = rAnchorTextFrame.GetUpper();
224 return;
227 mpToCharRect = &(GetAnchoredObj().GetLastCharRect());
228 // #i22341# - get top of line, in which the anchor character is.
229 mnToCharTopOfLine = GetAnchoredObj().GetLastTopOfLine();
230 pOrientFrame = &(const_cast<SwTextFrame&>(rAnchorTextFrame).GetFrameAtOfst(
231 rAnchorTextFrame.MapModelToViewPos(*rAnch.GetContentAnchor())));
232 mpToCharOrientFrame = pOrientFrame;
234 else if (SwFlyFrame* pFlyFrame = GetAnchoredObj().DynCastFlyFrame())
236 // See if this fly is split. If so, then the anchor is also split. All anchors are
237 // empty, except the last follow.
238 if (pFlyFrame->IsFlySplitAllowed())
240 auto pFlyAtContentFrame = static_cast<SwFlyAtContentFrame*>(pFlyFrame);
241 // Decrement pFly to point to the master; increment pAnchor to point to the correct
242 // follow anchor.
243 SwFlyAtContentFrame* pFly = pFlyAtContentFrame;
244 SwTextFrame* pAnchor = const_cast<SwTextFrame*>(&rAnchorTextFrame);
245 while (pFly->GetPrecede())
247 pFly = pFly->GetPrecede();
248 if (!pAnchor)
250 SAL_WARN("sw.core", "SwToContentAnchoredObjectPosition::CalcPosition: fly "
251 "chain length is longer then anchor chain length");
252 break;
254 pAnchor = pAnchor->GetFollow();
256 if (pAnchor && pAnchor->GetPrecede())
258 pOrientFrame = pAnchor;
259 // Anchored object has a precede, so it's a follow.
260 bFollowSplitFly = true;
262 bSplitFly = true;
266 aRectFnSet.Refresh(pOrientFrame);
268 // determine vertical position
271 // determine vertical positioning and alignment attributes
272 SwFormatVertOrient aVert( rFrameFormat.GetVertOrient() );
274 // #i18732# - determine layout frame for vertical
275 // positions aligned to 'page areas'.
276 const SwLayoutFrame& rPageAlignLayFrame =
277 aEnvOfObj.GetVertEnvironmentLayoutFrame( *pOrientFrame );
279 if ( aVert.GetVertOrient() != text::VertOrientation::NONE )
281 // #i18732# - adjustments for follow text flow or not
282 // AND vertical alignment at 'page areas'.
283 SwTwips nAlignAreaHeight;
284 SwTwips nAlignAreaOffset;
285 GetVertAlignmentValues( *pOrientFrame, rPageAlignLayFrame,
286 aVert.GetRelationOrient(),
287 nAlignAreaHeight, nAlignAreaOffset );
289 SwRect aHeaderRect;
290 const SwPageFrame* aPageFrame = pOrientFrame->FindPageFrame();
291 const SwHeaderFrame* pHeaderFrame = aPageFrame->GetHeaderFrame();
292 if (pHeaderFrame)
293 aHeaderRect = pHeaderFrame->GetPaintArea();
294 const SwTwips nTopMarginHeight = aPageFrame->GetTopMargin() + aHeaderRect.Height();
295 const SwTwips nHeightBetweenOffsetAndMargin = nAlignAreaOffset + nTopMarginHeight;
297 // determine relative vertical position
298 SwTwips nRelPosY = nAlignAreaOffset;
299 const SwTwips nObjHeight = aRectFnSet.GetHeight(aObjBoundRect);
300 const SwTwips nUpperSpace = aRectFnSet.IsVert()
301 ? ( aRectFnSet.IsVertL2R()
302 ? rLR.GetLeft()
303 : rLR.GetRight() )
304 : rUL.GetUpper();
305 // --> OD 2009-08-31 #monglianlayout#
306 const SwTwips nLowerSpace = aRectFnSet.IsVert()
307 ? ( aRectFnSet.IsVertL2R()
308 ? rLR.GetLeft()
309 : rLR.GetRight() )
310 : rUL.GetLower();
311 switch ( aVert.GetVertOrient() )
313 case text::VertOrientation::CHAR_BOTTOM:
315 if ( mbAnchorToChar )
317 // bottom (to character anchored)
318 nRelPosY += nAlignAreaHeight + nUpperSpace;
319 if ( aRectFnSet.IsVert() && !aRectFnSet.IsVertL2R() )
321 nRelPosY += nObjHeight;
323 break;
325 [[fallthrough]];
327 case text::VertOrientation::TOP:
329 // #i22341# - special case for vertical
330 // alignment at top of line
331 if ( mbAnchorToChar &&
332 aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
334 nRelPosY -= (nObjHeight + nLowerSpace);
336 else
338 nRelPosY += nUpperSpace;
341 break;
342 // #i22341#
343 case text::VertOrientation::LINE_TOP:
345 if ( mbAnchorToChar &&
346 aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
348 nRelPosY -= (nObjHeight + nLowerSpace);
350 else
352 OSL_FAIL( "<SwToContentAnchoredObjectPosition::CalcPosition()> - unknown combination of vertical position and vertical alignment." );
355 break;
356 case text::VertOrientation::CENTER:
358 if (aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA_TOP)
359 nRelPosY = (nAlignAreaOffset / 2) - (nObjHeight / 2) + (nHeightBetweenOffsetAndMargin / 2);
360 else
361 nRelPosY += (nAlignAreaHeight / 2) - (nObjHeight / 2);
363 break;
364 // #i22341#
365 case text::VertOrientation::LINE_CENTER:
367 if ( mbAnchorToChar &&
368 aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
370 nRelPosY += (nAlignAreaHeight / 2) - (nObjHeight / 2);
372 else
374 OSL_FAIL( "<SwToContentAnchoredObjectPosition::CalcPosition()> - unknown combination of vertical position and vertical alignment." );
377 break;
378 case text::VertOrientation::BOTTOM:
380 if ( ( aVert.GetRelationOrient() == text::RelOrientation::FRAME ||
381 aVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ) &&
382 bNoSurround )
384 // bottom (aligned to 'paragraph areas')
385 nRelPosY += nAlignAreaHeight + nUpperSpace;
387 else
389 // #i22341# - special case for vertical
390 // alignment at top of line
391 if ( mbAnchorToChar &&
392 aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
394 nRelPosY += nUpperSpace;
396 else
398 if (aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA_TOP)
399 nRelPosY = 0 - (nObjHeight + nLowerSpace) + nHeightBetweenOffsetAndMargin;
400 else
401 nRelPosY += nAlignAreaHeight - (nObjHeight + nLowerSpace);
405 break;
406 // #i22341#
407 case text::VertOrientation::LINE_BOTTOM:
409 if ( mbAnchorToChar &&
410 aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
412 nRelPosY += nUpperSpace;
414 else
416 OSL_FAIL( "<SwToContentAnchoredObjectPosition::CalcPosition()> - unknown combination of vertical position and vertical alignment." );
419 break;
420 default:
421 break;
424 // adjust relative position by distance between anchor frame and
425 // the frame, the object is oriented at.
426 // #i28701# - correction: adjust relative position,
427 // only if the floating screen object has to follow the text flow.
428 // Also don't do this for split flys: pOrientFrame already points to the follow anchor,
429 // so pOrientFrame is not the anchor text frame anymore, and that would lead to an
430 // additional, unwanted increase of nRelPosY.
431 if (DoesObjFollowsTextFlow() && pOrientFrame != &rAnchorTextFrame && !bFollowSplitFly)
433 // #i11860# - use new method <GetTopForObjPos>
434 // to get top of frame for object positioning.
435 const SwTwips nTopOfOrient = GetTopForObjPos( *pOrientFrame, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
436 nRelPosY += aRectFnSet.YDiff( nTopOfOrient,
437 GetTopForObjPos( rAnchorTextFrame, aRectFnSet.FnRect(), aRectFnSet.IsVert() ) );
440 // #i42124# - capture object inside vertical
441 // layout environment.
443 const SwTwips nTopOfAnch =
444 GetTopForObjPos( *pOrientFrame, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
445 const SwLayoutFrame& rVertEnvironLayFrame =
446 aEnvOfObj.GetVertEnvironmentLayoutFrame(
447 *(pOrientFrame->GetUpper()) );
448 const bool bCheckBottom = !DoesObjFollowsTextFlow();
449 nRelPosY = AdjustVertRelPos( nTopOfAnch, aRectFnSet.IsVert(), aRectFnSet.IsVertL2R(),
450 rVertEnvironLayFrame, nRelPosY,
451 DoesObjFollowsTextFlow(),
452 bCheckBottom );
455 // keep calculated relative vertical position - needed for filters
456 // (including the xml-filter)
458 // determine position
459 SwTwips nAttrRelPosY = nRelPosY - nAlignAreaOffset;
460 // set
461 if ( nAttrRelPosY != aVert.GetPos() )
463 aVert.SetPos( nAttrRelPosY );
464 const_cast<SwFrameFormat&>(rFrameFormat).LockModify();
465 const_cast<SwFrameFormat&>(rFrameFormat).SetFormatAttr( aVert );
466 const_cast<SwFrameFormat&>(rFrameFormat).UnlockModify();
470 // determine absolute 'vertical' position, depending on layout-direction
471 // #i26791# - determine offset to 'vertical' frame
472 // anchor position, depending on layout-direction
473 if ( aRectFnSet.IsVert() )
475 aRelPos.setX( nRelPosY );
476 maOffsetToFrameAnchorPos.setX( nAlignAreaOffset );
478 else
480 aRelPos.setY( nRelPosY );
481 maOffsetToFrameAnchorPos.setY( nAlignAreaOffset );
485 // Determine upper of frame vertical position is oriented at.
486 // #i28701# - determine 'virtual' anchor frame.
487 // This frame is used in the following instead of the 'real' anchor
488 // frame <rAnchorTextFrame> for the 'vertical' position in all cases.
489 const SwLayoutFrame* pUpperOfOrientFrame = nullptr;
491 // #i28701# - As long as the anchor frame is on the
492 // same page as <pOrientFrame> and the vertical position isn't aligned
493 // automatic at the anchor character or the top of the line of the
494 // anchor character, the anchor frame determines the vertical position.
495 // Split fly follows: always let the anchor char frame determine the vertical position.
496 // This gives us a vertical cut position between the master and the follow.
497 if ( &rAnchorTextFrame == pOrientFrame ||
498 ( rAnchorTextFrame.FindPageFrame() == pOrientFrame->FindPageFrame() &&
499 aVert.GetVertOrient() == text::VertOrientation::NONE &&
500 aVert.GetRelationOrient() != text::RelOrientation::CHAR &&
501 aVert.GetRelationOrient() != text::RelOrientation::TEXT_LINE && !bFollowSplitFly ) )
503 pUpperOfOrientFrame = rAnchorTextFrame.GetUpper();
504 pAnchorFrameForVertPos = &rAnchorTextFrame;
506 else
508 pUpperOfOrientFrame = pOrientFrame->GetUpper();
509 pAnchorFrameForVertPos = pOrientFrame;
513 // ignore one-column sections.
514 // #i23512# - correction: also ignore one-columned
515 // sections with footnotes/endnotes
516 if ( pUpperOfOrientFrame->IsInSct() )
518 const SwSectionFrame* pSctFrame = pUpperOfOrientFrame->FindSctFrame();
519 const bool bIgnoreSection = pUpperOfOrientFrame->IsSctFrame() ||
520 ( pSctFrame->Lower()->IsColumnFrame() &&
521 !pSctFrame->Lower()->GetNext() );
522 if ( bIgnoreSection )
523 pUpperOfOrientFrame = pSctFrame->GetUpper();
526 if ( aVert.GetVertOrient() == text::VertOrientation::NONE )
528 // local variable <nRelPosY> for calculation of relative vertical
529 // distance to anchor.
530 SwTwips nRelPosY = 0;
531 // #i26791# - local variable <nVertOffsetToFrameAnchorPos>
532 // for determination of the 'vertical' offset to the frame anchor
533 // position
534 SwTwips nVertOffsetToFrameAnchorPos( 0 );
535 // #i22341# - add special case for vertical alignment
536 // at top of line.
537 if ( mbAnchorToChar &&
538 ( aVert.GetRelationOrient() == text::RelOrientation::CHAR ||
539 aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE ) )
541 // #i11860# - use new method <GetTopForObjPos>
542 // to get top of frame for object positioning.
543 SwTwips nTopOfOrient = GetTopForObjPos( *pOrientFrame, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
544 if ( aVert.GetRelationOrient() == text::RelOrientation::CHAR )
546 nVertOffsetToFrameAnchorPos = aRectFnSet.YDiff(
547 aRectFnSet.GetBottom(*ToCharRect()),
548 nTopOfOrient );
550 else
552 nVertOffsetToFrameAnchorPos = aRectFnSet.YDiff( ToCharTopOfLine(),
553 nTopOfOrient );
555 nRelPosY = nVertOffsetToFrameAnchorPos - aVert.GetPos();
557 else
559 // #i28701# - correction: use <pAnchorFrameForVertPos>
560 // instead of <pOrientFrame> and do not adjust relative position
561 // to get correct vertical position.
562 nVertOffsetToFrameAnchorPos = 0;
563 // #i11860# - use new method <GetTopForObjPos>
564 // to get top of frame for object positioning.
565 const SwTwips nTopOfOrient =
566 GetTopForObjPos( *pAnchorFrameForVertPos, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
567 // Increase <nRelPosY> by margin height,
568 // if position is vertical aligned to "paragraph text area"
569 if ( aVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA )
571 // #i11860# - consider upper space amount of previous frame
572 SwTwips nTopMargin = aRectFnSet.GetTopMargin(*pAnchorFrameForVertPos);
573 if ( pAnchorFrameForVertPos->IsTextFrame() )
575 nTopMargin -= pAnchorFrameForVertPos->
576 GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid();
578 nVertOffsetToFrameAnchorPos += nTopMargin;
580 // #i18732# - adjust <nRelPosY> by difference
581 // between 'page area' and 'anchor' frame, if position is
582 // vertical aligned to 'page areas'
583 else if (aVert.GetRelationOrient() == text::RelOrientation::PAGE_FRAME
584 || aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA_TOP)
586 nVertOffsetToFrameAnchorPos += aRectFnSet.YDiff(
587 aRectFnSet.GetTop(rPageAlignLayFrame.getFrameArea()),
588 nTopOfOrient );
590 else if ( aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA )
592 SwRect aPgPrtRect( rPageAlignLayFrame.getFrameArea() );
593 if ( rPageAlignLayFrame.IsPageFrame() )
595 aPgPrtRect =
596 static_cast<const SwPageFrame&>(rPageAlignLayFrame).PrtWithoutHeaderAndFooter();
598 nVertOffsetToFrameAnchorPos += aRectFnSet.YDiff(
599 aRectFnSet.GetTop(aPgPrtRect),
600 nTopOfOrient );
602 else if (aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA_BOTTOM)
604 // The anchored object is relative from the bottom of the page's print area.
605 SwRect aPgPrtRect(rPageAlignLayFrame.getFrameArea());
606 if (rPageAlignLayFrame.IsPageFrame())
608 auto& rPageFrame = static_cast<const SwPageFrame&>(rPageAlignLayFrame);
609 aPgPrtRect = rPageFrame.PrtWithoutHeaderAndFooter();
611 SwTwips nPageBottom = aRectFnSet.GetBottom(aPgPrtRect);
612 nVertOffsetToFrameAnchorPos += aRectFnSet.YDiff(nPageBottom, nTopOfOrient);
614 nRelPosY = nVertOffsetToFrameAnchorPos + aVert.GetPos();
615 if (bFollowSplitFly)
617 // This is a follow of a split fly: shift it up to match the anchor position,
618 // because the vertical offset is meant to be handled only on the first page.
619 nRelPosY -= aVert.GetPos();
621 if (aVert.GetRelationOrient() == text::RelOrientation::PAGE_FRAME
622 && rPageAlignLayFrame.IsPageFrame())
624 // Master is positioned relative to the edge of the page, with an offset.
625 // Follow will have no offset, but is relative to the bottom of the header.
626 auto& rPageFrame = static_cast<const SwPageFrame&>(rPageAlignLayFrame);
627 const SwLayoutFrame* pBodyFrame = rPageFrame.FindBodyCont();
628 if (pBodyFrame)
630 SwTwips nDiff = pBodyFrame->getFrameArea().Top()
631 - rPageFrame.getFrameArea().Top();
632 nRelPosY += nDiff;
638 // <pUpperOfOrientFrame>: layout frame, at which the position has to
639 // is oriented at
640 // <nRelPosY>: rest of the relative distance in the current
641 // layout frame
642 // <nAvail>: space, which is available in the current
643 // layout frame
645 // #i26791# - determine offset to 'vertical'
646 // frame anchor position, depending on layout-direction
647 if ( aRectFnSet.IsVert() )
648 maOffsetToFrameAnchorPos.setX( nVertOffsetToFrameAnchorPos );
649 else
650 maOffsetToFrameAnchorPos.setY( nVertOffsetToFrameAnchorPos );
651 // #i11860# - use new method <GetTopForObjPos>
652 // to get top of frame for object positioning.
653 const SwTwips nTopOfAnch = GetTopForObjPos( *pAnchorFrameForVertPos, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
654 if( nRelPosY <= 0 )
656 // Allow negative position, but keep it
657 // inside environment layout frame.
658 const SwLayoutFrame& rVertEnvironLayFrame =
659 aEnvOfObj.GetVertEnvironmentLayoutFrame( *pUpperOfOrientFrame );
660 // #i31805# - do not check, if bottom of
661 // anchored object would fit into environment layout frame, if
662 // anchored object has to follow the text flow.
663 const bool bCheckBottom = !DoesObjFollowsTextFlow();
664 nRelPosY = AdjustVertRelPos( nTopOfAnch, aRectFnSet.IsVert(), aRectFnSet.IsVertL2R(),
665 rVertEnvironLayFrame, nRelPosY,
666 DoesObjFollowsTextFlow(),
667 bCheckBottom );
668 if ( aRectFnSet.IsVert() )
669 aRelPos.setX( nRelPosY );
670 else
671 aRelPos.setY( nRelPosY );
673 else
675 aRectFnSet.Refresh(pAnchorFrameForVertPos);
676 SwTwips nAvail =
677 aRectFnSet.YDiff( aRectFnSet.GetPrtBottom(*pUpperOfOrientFrame),
678 nTopOfAnch );
679 const bool bInFootnote = pAnchorFrameForVertPos->IsInFootnote();
680 while ( nRelPosY )
682 // #i23512# - correction:
683 // consider section frame for grow in online layout.
684 // use new local method <lcl_DoesVertPosFits(..)>
685 SwLayoutFrame* pLayoutFrameToGrow = nullptr;
686 const bool bDoesVertPosFits = lcl_DoesVertPosFits(
687 nRelPosY, nAvail, pUpperOfOrientFrame, bBrowse,
688 bGrow, pLayoutFrameToGrow );
690 if ( bDoesVertPosFits )
692 SwTwips nTmpRelPosY =
693 aRectFnSet.YDiff( aRectFnSet.GetPrtBottom(*pUpperOfOrientFrame),
694 nTopOfAnch ) -
695 nAvail + nRelPosY;
696 // #i28701# - adjust calculated
697 // relative vertical position to object's environment.
698 const SwFrame& rVertEnvironLayFrame =
699 aEnvOfObj.GetVertEnvironmentLayoutFrame( *pUpperOfOrientFrame );
700 // Do not check, if bottom of
701 // anchored object would fit into environment layout
702 // frame, if anchored object has to follow the text flow.
703 const bool bCheckBottom = !DoesObjFollowsTextFlow();
704 nTmpRelPosY = AdjustVertRelPos( nTopOfAnch, aRectFnSet.IsVert(), aRectFnSet.IsVertL2R(),
705 rVertEnvironLayFrame,
706 nTmpRelPosY,
707 DoesObjFollowsTextFlow(),
708 bCheckBottom );
709 if ( aRectFnSet.IsVert() )
710 aRelPos.setX( nTmpRelPosY );
711 else
712 aRelPos.setY( nTmpRelPosY );
714 // #i23512# - use local variable
715 // <pLayoutFrameToGrow> provided by new method
716 // <lcl_DoesVertPosFits(..)>.
717 if ( pLayoutFrameToGrow )
719 // No need to grow the anchor cell in case the follow-text-flow object
720 // is wrap-though.
721 if (!GetAnchorFrame().IsInTab() || !DoesObjFollowsTextFlow() || !bWrapThrough)
723 pLayoutFrameToGrow->Grow( nRelPosY - nAvail );
726 nRelPosY = 0;
728 else
730 // #i26495# - floating screen objects,
731 // which are anchored inside a table, doesn't follow
732 // the text flow.
733 if ( DoesObjFollowsTextFlow() &&
734 ( aVert.GetRelationOrient() != text::RelOrientation::PAGE_FRAME &&
735 aVert.GetRelationOrient() != text::RelOrientation::PAGE_PRINT_AREA ) &&
736 !GetAnchorFrame().IsInTab() )
738 if ( bMoveable )
740 // follow the text flow
741 nRelPosY -= nAvail;
742 MakePageType eMakePage = bInFootnote ? MAKEPAGE_NONE
743 : MAKEPAGE_APPEND;
744 const bool bInSct = pUpperOfOrientFrame->IsInSct();
745 if( bInSct )
746 eMakePage = MAKEPAGE_NOSECTION;
748 const SwLayoutFrame* pTmp =
749 pUpperOfOrientFrame->GetLeaf( eMakePage, true, &rAnchorTextFrame );
750 if ( pTmp &&
751 ( !bInSct ||
752 pUpperOfOrientFrame->FindSctFrame()->IsAnFollow( pTmp->FindSctFrame() ) ) )
754 pUpperOfOrientFrame = pTmp;
755 bMoveable = rAnchorTextFrame.IsMoveable( pUpperOfOrientFrame );
756 aRectFnSet.Refresh(pUpperOfOrientFrame);
757 nAvail = aRectFnSet.GetHeight(pUpperOfOrientFrame->getFramePrintArea());
759 else
761 // if there isn't enough space in the (columned)
762 // section, leave it and set available space <nAvail>
763 // to the space below the section.
764 // if the new available space isn't also enough,
765 // new pages can be created.
766 if( bInSct )
768 const SwFrame* pSct = pUpperOfOrientFrame->FindSctFrame();
769 pUpperOfOrientFrame = pSct->GetUpper();
770 nAvail = aRectFnSet.YDiff(
771 aRectFnSet.GetPrtBottom(*pUpperOfOrientFrame),
772 aRectFnSet.GetPrtBottom(*pSct) );
774 else
776 #if OSL_DEBUG_LEVEL > 1
777 OSL_FAIL( "<SwToContentAnchoredObjectPosition::CalcPosition()> - !bInSct" );
778 #endif
779 nRelDiff = nRelPosY;
780 nRelPosY = 0;
784 else
786 nRelPosY = 0;
789 else
791 // #i18732# - do not follow text flow respectively
792 // align at 'page areas', but stay inside given environment
793 const SwFrame& rVertEnvironLayFrame =
794 aEnvOfObj.GetVertEnvironmentLayoutFrame( *pUpperOfOrientFrame );
795 nRelPosY = AdjustVertRelPos( nTopOfAnch, aRectFnSet.IsVert(), aRectFnSet.IsVertL2R(),
796 rVertEnvironLayFrame,
797 nRelPosY,
798 DoesObjFollowsTextFlow() );
799 if( aRectFnSet.IsVert() )
800 aRelPos.setX( nRelPosY );
801 else
802 aRelPos.setY( nRelPosY );
803 nRelPosY = 0;
806 } // end of <while ( nRelPosY )>
807 } // end of else <nRelPosY <= 0>
808 } // end of <aVert.GetVertOrient() == text::VertOrientation::NONE>
810 // We need to calculate the part's absolute position, in order for
811 // it to be put onto the right page and to be pulled into the
812 // LayLeaf's PrtArea
813 const SwTwips nTopOfAnch = GetTopForObjPos( *pAnchorFrameForVertPos, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
814 if( aRectFnSet.IsVert() )
816 // --> OD 2009-08-31 #monglianlayout#
817 if ( !aRectFnSet.IsVertL2R() )
819 GetAnchoredObj().SetObjLeft( nTopOfAnch -
820 ( aRelPos.X() - nRelDiff ) -
821 aObjBoundRect.Width() );
823 else
825 GetAnchoredObj().SetObjLeft( nTopOfAnch +
826 ( aRelPos.X() - nRelDiff ) );
829 else
831 GetAnchoredObj().SetObjTop( nTopOfAnch +
832 ( aRelPos.Y() - nRelDiff ) );
835 // grow environment under certain conditions
836 // ignore one-column sections.
837 // #i23512# - correction: also ignore one-columned
838 // sections with footnotes/endnotes
839 if ( pUpperOfOrientFrame->IsInSct() )
841 const SwSectionFrame* pSctFrame = pUpperOfOrientFrame->FindSctFrame();
842 const bool bIgnoreSection = pUpperOfOrientFrame->IsSctFrame() ||
843 ( pSctFrame->Lower()->IsColumnFrame() &&
844 !pSctFrame->Lower()->GetNext() );
845 if ( bIgnoreSection )
846 pUpperOfOrientFrame = pSctFrame->GetUpper();
848 SwTwips nDist = aRectFnSet.BottomDist( GetAnchoredObj().GetObjRect(),
849 aRectFnSet.GetPrtBottom(*pUpperOfOrientFrame) );
850 if( nDist < 0 )
852 // #i23512# - correction:
853 // consider section frame for grow in online layout and
854 // consider page alignment for grow in table.
855 SwLayoutFrame* pLayoutFrameToGrow = nullptr;
856 if ( bBrowse && rAnchorTextFrame.IsMoveable() )
858 if ( pUpperOfOrientFrame->IsInSct() )
860 pLayoutFrameToGrow = const_cast<SwLayoutFrame*>(
861 pUpperOfOrientFrame->FindSctFrame()->GetUpper());
862 nDist = aRectFnSet.BottomDist( GetAnchoredObj().GetObjRect(),
863 aRectFnSet.GetPrtBottom(*pLayoutFrameToGrow) );
864 if ( nDist >= 0 )
866 pLayoutFrameToGrow = nullptr;
869 else
871 pLayoutFrameToGrow =
872 const_cast<SwLayoutFrame*>(pUpperOfOrientFrame);
875 else if ( rAnchorTextFrame.IsInTab() && bGrow )
877 pLayoutFrameToGrow = const_cast<SwLayoutFrame*>(pUpperOfOrientFrame);
879 if ( pLayoutFrameToGrow )
881 // No need to grow the anchor cell in case the follow-text-flow object
882 // is wrap-though.
883 if (!GetAnchorFrame().IsInTab() || !DoesObjFollowsTextFlow() || !bWrapThrough)
885 pLayoutFrameToGrow->Grow( -nDist );
890 if ( DoesObjFollowsTextFlow() &&
891 ( aVert.GetRelationOrient() != text::RelOrientation::PAGE_FRAME &&
892 aVert.GetRelationOrient() != text::RelOrientation::PAGE_PRINT_AREA ) )
895 nDist = aRectFnSet.BottomDist( GetAnchoredObj().GetObjRect(),
896 aRectFnSet.GetPrtBottom(*pUpperOfOrientFrame) );
897 // #i26945# - floating screen objects, which are
898 // anchored inside a table, doesn't follow the text flow. But, they
899 // have to stay inside its layout environment.
900 if ( nDist < 0 && pOrientFrame->IsInTab() )
902 // If the anchor frame is the first content of the table cell
903 // and has no follow, the table frame is notified,
904 // that the object doesn't fit into the table cell.
905 // Adjustment of position isn't needed in this case.
906 if ( pOrientFrame == &rAnchorTextFrame &&
907 !pOrientFrame->GetFollow() &&
908 !pOrientFrame->GetIndPrev() )
910 const_cast<SwTabFrame*>(pOrientFrame->FindTabFrame())
911 ->SetDoesObjsFit( false );
913 else
915 SwTwips nTmpRelPosY( 0 );
916 if ( aRectFnSet.IsVert() )
917 nTmpRelPosY = aRelPos.X() - nDist;
918 else
919 nTmpRelPosY = aRelPos.Y() + nDist;
920 const SwLayoutFrame& rVertEnvironLayFrame =
921 aEnvOfObj.GetVertEnvironmentLayoutFrame( *pUpperOfOrientFrame );
922 nTmpRelPosY = AdjustVertRelPos( nTopOfAnch, aRectFnSet.IsVert(), aRectFnSet.IsVertL2R(),
923 rVertEnvironLayFrame,
924 nTmpRelPosY,
925 DoesObjFollowsTextFlow(),
926 false );
927 if ( aRectFnSet.IsVert() )
929 aRelPos.setX( nTmpRelPosY );
930 // --> OD 2009-08-31 #mongolianlayout#
931 if ( !aRectFnSet.IsVertL2R() )
933 GetAnchoredObj().SetObjLeft( nTopOfAnch -
934 aRelPos.X() -
935 aObjBoundRect.Width() );
937 else
939 GetAnchoredObj().SetObjLeft( nTopOfAnch + aRelPos.X() );
942 else
944 aRelPos.setY( nTmpRelPosY );
945 GetAnchoredObj().SetObjTop( nTopOfAnch + aRelPos.Y() );
947 // If the anchor frame is the first content of the table cell
948 // and the object still doesn't fit, the table frame is notified,
949 // that the object doesn't fit into the table cell.
950 nDist = aRectFnSet.BottomDist( GetAnchoredObj().GetObjRect(),
951 aRectFnSet.GetPrtBottom(*pUpperOfOrientFrame) );
952 if ( nDist < 0 &&
953 pOrientFrame == &rAnchorTextFrame && !pOrientFrame->GetIndPrev() )
955 const_cast<SwTabFrame*>(pOrientFrame->FindTabFrame())
956 ->SetDoesObjsFit( false );
960 // Don't move split flys around for follow text flow purposes; if they don't fit their
961 // parent anymore, they will shrink and part of the content will move to the follow fly.
962 else if (!bSplitFly)
964 // follow text flow
965 const bool bInFootnote = rAnchorTextFrame.IsInFootnote();
966 while( bMoveable && nDist < 0 )
968 bool bInSct = pUpperOfOrientFrame->IsInSct();
969 if ( bInSct )
971 const SwLayoutFrame* pTmp = pUpperOfOrientFrame->FindSctFrame()->GetUpper();
972 nDist = aRectFnSet.BottomDist( GetAnchoredObj().GetObjRect(),
973 aRectFnSet.GetPrtBottom(*pTmp) );
974 // #i23129# - Try to flow into next
975 // section|section column. Thus, do *not* leave section
976 // area, if anchored object doesn't fit into upper of section.
977 // But the anchored object is allowed to overlap bottom
978 // section|section column.
979 if ( nDist >= 0 )
981 break;
984 if ( !bInSct &&
985 aRectFnSet.GetTop(GetAnchoredObj().GetObjRect()) ==
986 aRectFnSet.GetPrtTop(*pUpperOfOrientFrame) )
987 // It doesn't fit, moving it would not help either anymore
988 break;
990 const SwLayoutFrame* pNextLay = pUpperOfOrientFrame->GetLeaf(
991 ( bInSct
992 ? MAKEPAGE_NOSECTION
993 : ( bInFootnote ? MAKEPAGE_NONE : MAKEPAGE_APPEND ) ),
994 true, &rAnchorTextFrame );
995 // correction:
996 // If anchor is in footnote and proposed next layout environment
997 // isn't a footnote frame, object can't follow the text flow
998 if ( bInFootnote && pNextLay && !pNextLay->IsFootnoteFrame() )
1000 pNextLay = nullptr;
1002 if ( pNextLay )
1004 SwRectFnSet fnRectX(pNextLay);
1005 if ( !bInSct ||
1006 ( pUpperOfOrientFrame->FindSctFrame()->IsAnFollow( pNextLay->FindSctFrame() ) &&
1007 fnRectX.GetHeight(pNextLay->getFramePrintArea()) ) )
1009 SwTwips nTmpRelPosY =
1010 aRectFnSet.YDiff( aRectFnSet.GetPrtTop(*pNextLay),
1011 nTopOfAnch );
1012 if ( aRectFnSet.IsVert() )
1013 aRelPos.setX( nTmpRelPosY );
1014 else
1015 aRelPos.setY( nTmpRelPosY );
1016 pUpperOfOrientFrame = pNextLay;
1017 aRectFnSet.Refresh(pUpperOfOrientFrame);
1018 bMoveable = rAnchorTextFrame.IsMoveable( pUpperOfOrientFrame );
1019 if( fnRectX.IsVert() )
1021 // --> OD 2009-08-31 #mongolianlayout#
1022 if ( !aRectFnSet.IsVertL2R() )
1024 GetAnchoredObj().SetObjLeft( nTopOfAnch -
1025 aRelPos.X() -
1026 aObjBoundRect.Width() );
1028 else
1030 GetAnchoredObj().SetObjLeft( nTopOfAnch +
1031 aRelPos.X() );
1034 else
1035 GetAnchoredObj().SetObjTop( nTopOfAnch +
1036 aRelPos.Y() );
1037 nDist = aRectFnSet.BottomDist( GetAnchoredObj().GetObjRect(),
1038 aRectFnSet.GetPrtBottom(*pUpperOfOrientFrame) );
1040 // #i23129# - leave section area
1041 else if ( bInSct )
1043 const SwLayoutFrame* pTmp = pUpperOfOrientFrame->FindSctFrame()->GetUpper();
1044 nDist = aRectFnSet.BottomDist( GetAnchoredObj().GetObjRect(),
1045 aRectFnSet.GetPrtBottom(*pTmp) );
1046 if( nDist < 0 )
1047 pUpperOfOrientFrame = pTmp;
1048 else
1049 break;
1052 else if ( bInSct )
1054 // If we don't have enough room within the Area, we take a look at
1055 // the Page
1056 const SwLayoutFrame* pTmp = pUpperOfOrientFrame->FindSctFrame()->GetUpper();
1057 nDist = aRectFnSet.BottomDist( GetAnchoredObj().GetObjRect(),
1058 aRectFnSet.GetPrtBottom(*pTmp) );
1059 if( nDist < 0 )
1060 pUpperOfOrientFrame = pTmp;
1061 else
1062 break;
1064 else
1065 bMoveable = false;
1070 // keep layout frame vertical position is oriented at.
1071 mpVertPosOrientFrame = pUpperOfOrientFrame;
1073 // If it was requested to not overlap with already formatted objects, take care of that
1074 // here.
1075 CalcOverlap(pAnchorFrameForVertPos, aRelPos, nTopOfAnch);
1078 // determine 'horizontal' position
1080 // determine horizontal positioning and alignment attributes
1081 SwFormatHoriOrient aHori( rFrameFormat.GetHoriOrient() );
1083 // set calculated vertical position in order to determine correct
1084 // frame, the horizontal position is oriented at.
1085 const SwTwips nTopOfAnch = GetTopForObjPos( *pAnchorFrameForVertPos, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
1086 if( aRectFnSet.IsVert() )
1088 // --> OD 2009-08-31 #mongolianlayout#
1089 if ( !aRectFnSet.IsVertL2R() )
1091 GetAnchoredObj().SetObjLeft( nTopOfAnch -
1092 aRelPos.X() - aObjBoundRect.Width() );
1094 else
1096 GetAnchoredObj().SetObjLeft( nTopOfAnch + aRelPos.X() );
1099 else
1100 GetAnchoredObj().SetObjTop( nTopOfAnch + aRelPos.Y() );
1102 // determine frame, horizontal position is oriented at.
1103 // #i28701# - If floating screen object doesn't follow
1104 // the text flow, its horizontal position is oriented at <pOrientFrame>.
1105 const SwFrame* pHoriOrientFrame = DoesObjFollowsTextFlow()
1106 ? &GetHoriVirtualAnchor( *mpVertPosOrientFrame )
1107 : pOrientFrame;
1109 // #i26791# - get 'horizontal' offset to frame anchor position.
1110 SwTwips nHoriOffsetToFrameAnchorPos( 0 );
1111 SwTwips nRelPosX = CalcRelPosX( *pHoriOrientFrame, aEnvOfObj,
1112 aHori, rLR, rUL, bWrapThrough,
1113 ( aRectFnSet.IsVert() ? aRelPos.X() : aRelPos.Y() ),
1114 nHoriOffsetToFrameAnchorPos );
1116 // #i26791# - determine offset to 'horizontal' frame
1117 // anchor position, depending on layout-direction
1118 if ( aRectFnSet.IsVert() )
1120 aRelPos.setY( nRelPosX );
1121 maOffsetToFrameAnchorPos.setY( nHoriOffsetToFrameAnchorPos );
1123 else
1125 aRelPos.setX( nRelPosX );
1126 maOffsetToFrameAnchorPos.setX( nHoriOffsetToFrameAnchorPos );
1129 // save calculated horizontal position - needed for filters
1130 // (including the xml-filter)
1132 SwTwips nAttrRelPosX = nRelPosX - nHoriOffsetToFrameAnchorPos;
1133 if ( aHori.GetHoriOrient() != text::HoriOrientation::NONE &&
1134 aHori.GetPos() != nAttrRelPosX )
1136 aHori.SetPos( nAttrRelPosX );
1137 const_cast<SwFrameFormat&>(rFrameFormat).LockModify();
1138 const_cast<SwFrameFormat&>(rFrameFormat).SetFormatAttr( aHori );
1139 const_cast<SwFrameFormat&>(rFrameFormat).UnlockModify();
1144 // set absolute position at object
1145 const SwTwips nTopOfAnch = GetTopForObjPos( *pAnchorFrameForVertPos, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
1146 if( aRectFnSet.IsVert() )
1148 // --> OD 2009-08-31 #mongolianlayout#
1149 if ( !aRectFnSet.IsVertL2R() )
1151 GetAnchoredObj().SetObjLeft( nTopOfAnch -
1152 aRelPos.X() - aObjBoundRect.Width() );
1154 else
1156 GetAnchoredObj().SetObjLeft( nTopOfAnch + aRelPos.X() );
1158 GetAnchoredObj().SetObjTop( rAnchorTextFrame.getFrameArea().Top() +
1159 aRelPos.Y() );
1161 else
1163 GetAnchoredObj().SetObjLeft( rAnchorTextFrame.getFrameArea().Left() +
1164 aRelPos.X() );
1165 GetAnchoredObj().SetObjTop( nTopOfAnch + aRelPos.Y() );
1168 // set relative position at object
1169 GetAnchoredObj().SetCurrRelPos( aRelPos );
1172 void SwToContentAnchoredObjectPosition::CalcOverlap(const SwTextFrame* pAnchorFrameForVertPos,
1173 Point& rRelPos, const SwTwips nTopOfAnch)
1175 const SwFrameFormat& rFrameFormat = GetFrameFormat();
1176 bool bAllowOverlap = rFrameFormat.GetWrapInfluenceOnObjPos().GetAllowOverlap();
1177 if (bAllowOverlap)
1179 return;
1182 if (rFrameFormat.GetSurround().GetSurround() == css::text::WrapTextMode_THROUGH)
1184 // This is explicit wrap through: allowed to overlap.
1185 return;
1188 if (SwTextBoxHelper::isTextBox(&rFrameFormat, RES_FLYFRMFMT))
1190 // This is the frame part of a textbox, just take the offset from the textbox's shape part.
1191 SwFrameFormat* pShapeOfTextBox
1192 = SwTextBoxHelper::getOtherTextBoxFormat(&rFrameFormat, RES_FLYFRMFMT);
1193 if (pShapeOfTextBox)
1195 SwTwips nYDiff = pShapeOfTextBox->GetWrapInfluenceOnObjPos().GetOverlapVertOffset();
1196 if (nYDiff > 0)
1198 rRelPos.setY(rRelPos.getY() + nYDiff + 1);
1199 GetAnchoredObj().SetObjTop(nTopOfAnch + rRelPos.Y());
1202 return;
1205 // Get the list of objects.
1206 auto pSortedObjs = pAnchorFrameForVertPos->GetDrawObjs();
1207 const SwLayoutFrame* pAnchorUpper = pAnchorFrameForVertPos->GetUpper();
1209 bool bSplitFly = false;
1210 SwFlyFrame* pFlyFrame = GetAnchoredObj().DynCastFlyFrame();
1211 if (pFlyFrame && pFlyFrame->IsFlySplitAllowed())
1213 // At least for split flys we need to consider objects on the same page, but anchored in
1214 // different text frames.
1215 bSplitFly = true;
1217 SwFrame* pFlyFrameAnchor = pFlyFrame->GetAnchorFrameContainingAnchPos();
1218 if (pFlyFrameAnchor && pFlyFrameAnchor->IsInFly())
1220 // An inner fly overlapping with its outer fly is fine.
1221 return;
1224 const SwPageFrame* pPageFrame = pAnchorFrameForVertPos->FindPageFrame();
1225 if (pPageFrame)
1227 pSortedObjs = pPageFrame->GetSortedObjs();
1231 if (!pSortedObjs)
1233 return;
1236 for (const auto& pAnchoredObj : *pSortedObjs)
1238 if (pAnchoredObj == &GetAnchoredObj())
1240 // We found ourselves, stop iterating.
1241 break;
1244 if (SwTextBoxHelper::isTextBox(&pAnchoredObj->GetFrameFormat(), RES_FLYFRMFMT))
1246 // Overlapping with the frame of a textbox is fine.
1247 continue;
1250 SwFlyFrame* pAnchoredObjFly = pAnchoredObj->DynCastFlyFrame();
1251 if (bSplitFly)
1253 if (!pAnchoredObjFly)
1255 // This is a split fly, then overlap is only checked against other split flys.
1256 continue;
1259 if (pAnchoredObjFly->getRootFrame()->IsInFlyDelList(pAnchoredObjFly))
1261 // A fly overlapping with a to-be-deleted fly is fine.
1262 continue;
1265 SwFrame* pAnchoredObjFlyAnchor = pAnchoredObjFly->GetAnchorFrameContainingAnchPos();
1266 if (pAnchoredObjFlyAnchor && pAnchoredObjFlyAnchor->IsInFly())
1268 // An inner fly overlapping with its outer fly is fine.
1269 continue;
1272 if (pAnchoredObjFlyAnchor && pAnchoredObjFlyAnchor->GetUpper() != pAnchorUpper)
1274 // A fly overlapping with a fly from an other upper is fine.
1275 continue;
1279 css::text::WrapTextMode eWrap = pAnchoredObj->GetFrameFormat().GetSurround().GetSurround();
1280 if (eWrap == css::text::WrapTextMode_THROUGH)
1282 // The other object is wrap through: allowed to overlap.
1283 continue;
1286 if (!GetAnchoredObj().GetObjRect().Overlaps(pAnchoredObj->GetObjRect()))
1288 // Found an already positioned object, but it doesn't overlap, ignore.
1289 continue;
1292 // Already formatted, overlaps: resolve the conflict by shifting ourselves down.
1293 SwTwips nYDiff = pAnchoredObj->GetObjRect().Bottom() - GetAnchoredObj().GetObjRect().Top();
1294 rRelPos.setY(rRelPos.getY() + nYDiff + 1);
1295 GetAnchoredObj().SetObjTop(nTopOfAnch + rRelPos.Y());
1297 // Store our offset that avoids the overlap. If this is a shape of a textbox, then the frame
1298 // of the textbox will use it.
1299 SwFormatWrapInfluenceOnObjPos aInfluence(rFrameFormat.GetWrapInfluenceOnObjPos());
1300 aInfluence.SetOverlapVertOffset(nYDiff);
1301 const_cast<SwFrameFormat&>(rFrameFormat).LockModify();
1302 const_cast<SwFrameFormat&>(rFrameFormat).SetFormatAttr(aInfluence);
1303 const_cast<SwFrameFormat&>(rFrameFormat).UnlockModify();
1308 * Determine frame for horizontal position
1310 const SwFrame& SwToContentAnchoredObjectPosition::GetHoriVirtualAnchor(
1311 const SwLayoutFrame& _rProposedFrame ) const
1313 const SwFrame* pHoriVirtAnchFrame = &_rProposedFrame;
1315 // Search for first lower content frame, which is the anchor or a follow
1316 // of the anchor (Note: <Anchor.IsAnFollow( Anchor )> is true)
1317 // If none found, <_rProposedFrame> is returned.
1318 const SwFrame* pFrame = _rProposedFrame.Lower();
1319 while ( pFrame )
1321 if ( pFrame->IsContentFrame() &&
1322 GetAnchorTextFrame().IsAnFollow( static_cast<const SwContentFrame*>(pFrame) ) )
1324 pHoriVirtAnchFrame = pFrame;
1325 break;
1327 pFrame = pFrame->GetNext();
1330 return *pHoriVirtAnchFrame;
1335 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */