summaryrefslogtreecommitdiffstats
path: root/sw/source/core/objectpositioning
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 05:54:39 +0000
commit267c6f2ac71f92999e969232431ba04678e7437e (patch)
tree358c9467650e1d0a1d7227a21dac2e3d08b622b2 /sw/source/core/objectpositioning
parentInitial commit. (diff)
downloadlibreoffice-267c6f2ac71f92999e969232431ba04678e7437e.tar.xz
libreoffice-267c6f2ac71f92999e969232431ba04678e7437e.zip
Adding upstream version 4:24.2.0.upstream/4%24.2.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'sw/source/core/objectpositioning')
-rw-r--r--sw/source/core/objectpositioning/anchoredobjectposition.cxx1146
-rw-r--r--sw/source/core/objectpositioning/ascharanchoredobjectposition.cxx398
-rw-r--r--sw/source/core/objectpositioning/environmentofanchoredobject.cxx99
-rw-r--r--sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx1335
-rw-r--r--sw/source/core/objectpositioning/tolayoutanchoredobjectposition.cxx226
5 files changed, 3204 insertions, 0 deletions
diff --git a/sw/source/core/objectpositioning/anchoredobjectposition.cxx b/sw/source/core/objectpositioning/anchoredobjectposition.cxx
new file mode 100644
index 0000000000..e530e36df3
--- /dev/null
+++ b/sw/source/core/objectpositioning/anchoredobjectposition.cxx
@@ -0,0 +1,1146 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <anchoredobjectposition.hxx>
+#include <environmentofanchoredobject.hxx>
+#include <flyfrm.hxx>
+#include <flyfrms.hxx>
+#include <txtfrm.hxx>
+#include <pagefrm.hxx>
+#include <frmatr.hxx>
+#include <frmtool.hxx>
+#include <svx/svdobj.hxx>
+#include <dflyobj.hxx>
+#include <dcontact.hxx>
+#include <frmfmt.hxx>
+#include <fmtornt.hxx>
+#include <fmtfollowtextflow.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <ndtxt.hxx>
+#include <IDocumentSettingAccess.hxx>
+#include <textboxhelper.hxx>
+#include <fmtsrnd.hxx>
+#include <osl/diagnose.h>
+
+using namespace ::com::sun::star;
+
+namespace objectpositioning
+{
+
+SwAnchoredObjectPosition::SwAnchoredObjectPosition( SdrObject& _rDrawObj )
+ : mrDrawObj( _rDrawObj ),
+ mpAnchoredObj( nullptr ),
+ mpAnchorFrame( nullptr ),
+ mpContact( nullptr ),
+ mbIsObjFly( false ),
+ // #i62875#
+ mbFollowTextFlow( false ),
+ mbDoNotCaptureAnchoredObj( false )
+{
+#if OSL_DEBUG_LEVEL > 0
+ // assert, if object isn't of expected type
+ const bool bObjOfExceptedType =
+ dynamic_cast<const SwVirtFlyDrawObj*>( &mrDrawObj) != nullptr || // object representing fly frame
+ dynamic_cast<const SwDrawVirtObj*>( &mrDrawObj) != nullptr || // 'virtual' drawing object
+ ( dynamic_cast<const SdrVirtObj*>( &mrDrawObj) == nullptr && // 'master' drawing object
+ dynamic_cast<const SwFlyDrawObj*>( &mrDrawObj) == nullptr ); // - indirectly checked
+ OSL_ENSURE( bObjOfExceptedType,
+ "SwAnchoredObjectPosition(..) - object of unexpected type!" );
+#endif
+
+ GetInfoAboutObj();
+}
+
+/** determine information about object
+
+ members <mbIsObjFly>, <mpFrameOfObj>, <mpAnchorFrame>, <mpContact>,
+ <mbFollowTextFlow> and <mbDoNotCaptureAnchoredObj> are set
+*/
+void SwAnchoredObjectPosition::GetInfoAboutObj()
+{
+ // determine, if object represents a fly frame
+ {
+ mbIsObjFly = dynamic_cast<const SwVirtFlyDrawObj*>( &mrDrawObj) != nullptr;
+ }
+
+ // determine contact object
+ {
+ mpContact = GetUserCall( &mrDrawObj );
+ assert(mpContact &&
+ "SwAnchoredObjectPosition::GetInfoAboutObj() - missing SwContact-object.");
+ }
+
+ // determine anchored object, the object belongs to
+ {
+ // #i26791#
+ mpAnchoredObj = mpContact->GetAnchoredObj( &mrDrawObj );
+ assert(mpAnchoredObj &&
+ "SwAnchoredObjectPosition::GetInfoAboutObj() - missing anchored object.");
+ }
+
+ // determine frame, the object is anchored at
+ {
+ // #i26791#
+ mpAnchorFrame = mpAnchoredObj->AnchorFrame();
+ OSL_ENSURE( mpAnchorFrame,
+ "SwAnchoredObjectPosition::GetInfoAboutObj() - missing anchor frame." );
+ }
+
+ // determine format the object belongs to
+ {
+ // #i28701#
+ mpFrameFormat = &mpAnchoredObj->GetFrameFormat();
+ assert(mpFrameFormat &&
+ "<SwAnchoredObjectPosition::GetInfoAboutObj() - missing frame format.");
+ }
+
+ // #i62875# - determine attribute value of <Follow-Text-Flow>
+ {
+ mbFollowTextFlow = mpFrameFormat->GetFollowTextFlow().GetValue();
+ }
+
+ // determine, if anchored object has not to be captured on the page.
+ // the following conditions must be hold to *not* capture it:
+ // - corresponding document compatibility flag is set
+ // - it's a drawing object or it's a non-textbox wrap-though fly frame
+ // - it doesn't follow the text flow
+ {
+ bool bTextBox = SwTextBoxHelper::isTextBox(mpFrameFormat, RES_FLYFRMFMT);
+ bool bWrapThrough = mpFrameFormat->GetSurround().GetSurround() == css::text::WrapTextMode_THROUGH;
+ mbDoNotCaptureAnchoredObj = (!mbIsObjFly || (!bTextBox && bWrapThrough)) && !mbFollowTextFlow &&
+ mpFrameFormat->getIDocumentSettingAccess().get(DocumentSettingId::DO_NOT_CAPTURE_DRAW_OBJS_ON_PAGE);
+ }
+}
+
+SwAnchoredObjectPosition::~SwAnchoredObjectPosition()
+{}
+
+bool SwAnchoredObjectPosition::IsAnchoredToChar() const
+{
+ return false;
+}
+
+const SwFrame* SwAnchoredObjectPosition::ToCharOrientFrame() const
+{
+ return nullptr;
+}
+
+const SwRect* SwAnchoredObjectPosition::ToCharRect() const
+{
+ return nullptr;
+}
+
+// #i22341#
+SwTwips SwAnchoredObjectPosition::ToCharTopOfLine() const
+{
+ return 0;
+}
+
+/** helper method to determine top of a frame for the vertical
+ object positioning
+
+ #i11860#
+*/
+SwTwips SwAnchoredObjectPosition::GetTopForObjPos( const SwFrame& _rFrame,
+ const SwRectFn& _fnRect,
+ const bool _bVert ) const
+{
+ SwTwips nTopOfFrameForObjPos = (_rFrame.getFrameArea().*_fnRect->fnGetTop)();
+
+ if ( _rFrame.IsTextFrame() )
+ {
+ const SwTextFrame& rTextFrame = static_cast<const SwTextFrame&>(_rFrame);
+ if ( _bVert )
+ {
+ nTopOfFrameForObjPos -=
+ rTextFrame.GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid();
+ }
+ else
+ {
+ nTopOfFrameForObjPos +=
+ rTextFrame.GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid();
+
+ const SwFormatSurround& rSurround = mpFrameFormat->GetSurround();
+ bool bWrapThrough = rSurround.GetSurround() == css::text::WrapTextMode_THROUGH;
+ // If the frame format is a TextBox of a draw shape, then use the
+ // surround of the original shape.
+ SwTextBoxHelper::getShapeWrapThrough(mpFrameFormat, bWrapThrough);
+
+ // Get the offset between the top of the text frame and the top of
+ // the first line inside the frame that has more than just fly
+ // portions.
+ nTopOfFrameForObjPos += rTextFrame.GetBaseVertOffsetForFly(!bWrapThrough);
+ }
+ }
+
+ return nTopOfFrameForObjPos;
+}
+
+void SwAnchoredObjectPosition::GetVertAlignmentValues(
+ const SwFrame& _rVertOrientFrame,
+ const SwFrame& _rPageAlignLayFrame,
+ const sal_Int16 _eRelOrient,
+ SwTwips& _orAlignAreaHeight,
+ SwTwips& _orAlignAreaOffset ) const
+{
+ SwTwips nHeight = 0;
+ SwTwips nOffset = 0;
+ SwRectFnSet aRectFnSet(&_rVertOrientFrame);
+ // #i11860# - top of <_rVertOrientFrame> for object positioning
+ const SwTwips nVertOrientTop = GetTopForObjPos( _rVertOrientFrame, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
+ // #i11860# - upper space amount of <_rVertOrientFrame> considered
+ // for previous frame
+ const SwTwips nVertOrientUpperSpaceForPrevFrameAndPageGrid =
+ _rVertOrientFrame.IsTextFrame()
+ ? static_cast<const SwTextFrame&>(_rVertOrientFrame).
+ GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid()
+ : 0;
+ switch ( _eRelOrient )
+ {
+ case text::RelOrientation::FRAME:
+ {
+ // #i11860# - consider upper space of previous frame
+ nHeight = aRectFnSet.GetHeight(_rVertOrientFrame.getFrameArea()) -
+ nVertOrientUpperSpaceForPrevFrameAndPageGrid;
+ nOffset = 0;
+ }
+ break;
+ case text::RelOrientation::PRINT_AREA:
+ {
+ nHeight = aRectFnSet.GetHeight(_rVertOrientFrame.getFramePrintArea());
+ // #i11860# - consider upper space of previous frame
+ nOffset = aRectFnSet.GetTopMargin(_rVertOrientFrame) -
+ nVertOrientUpperSpaceForPrevFrameAndPageGrid;
+ // if aligned to page in horizontal layout, consider header and
+ // footer frame height appropriately.
+ if( _rVertOrientFrame.IsPageFrame() && !aRectFnSet.IsVert() )
+ {
+ const SwFrame* pPrtFrame =
+ static_cast<const SwPageFrame&>(_rVertOrientFrame).Lower();
+ while( pPrtFrame )
+ {
+ if( pPrtFrame->IsHeaderFrame() )
+ {
+ nHeight -= pPrtFrame->getFrameArea().Height();
+ nOffset += pPrtFrame->getFrameArea().Height();
+ }
+ else if( pPrtFrame->IsFooterFrame() )
+ {
+ nHeight -= pPrtFrame->getFrameArea().Height();
+ }
+ pPrtFrame = pPrtFrame->GetNext();
+ }
+ }
+ }
+ break;
+ case text::RelOrientation::PAGE_FRAME:
+ case text::RelOrientation::PAGE_PRINT_AREA_TOP:
+ {
+ nHeight = aRectFnSet.GetHeight(_rPageAlignLayFrame.getFrameArea());
+ nOffset = aRectFnSet.YDiff(
+ aRectFnSet.GetTop(_rPageAlignLayFrame.getFrameArea()),
+ nVertOrientTop );
+ }
+ break;
+ case text::RelOrientation::PAGE_PRINT_AREA:
+ {
+ nHeight = aRectFnSet.GetHeight(_rPageAlignLayFrame.getFramePrintArea());
+ nOffset = aRectFnSet.GetTopMargin(_rPageAlignLayFrame) +
+ aRectFnSet.YDiff(
+ aRectFnSet.GetTop(_rPageAlignLayFrame.getFrameArea()),
+ nVertOrientTop );
+ // if aligned to page in horizontal layout, consider header and
+ // footer frame height appropriately.
+ if( _rPageAlignLayFrame.IsPageFrame() && !aRectFnSet.IsVert() )
+ {
+ const SwFrame* pPrtFrame =
+ static_cast<const SwPageFrame&>(_rPageAlignLayFrame).Lower();
+ while( pPrtFrame )
+ {
+ if( pPrtFrame->IsHeaderFrame() )
+ {
+ nHeight -= pPrtFrame->getFrameArea().Height();
+ nOffset += pPrtFrame->getFrameArea().Height();
+ }
+ else if( pPrtFrame->IsFooterFrame() )
+ {
+ nHeight -= pPrtFrame->getFrameArea().Height();
+ }
+ pPrtFrame = pPrtFrame->GetNext();
+ }
+ }
+ }
+ break;
+ case text::RelOrientation::PAGE_PRINT_AREA_BOTTOM:
+ {
+ nHeight = aRectFnSet.GetBottomMargin(_rPageAlignLayFrame);
+ nOffset = aRectFnSet.YDiff(
+ aRectFnSet.GetPrtBottom(_rPageAlignLayFrame),
+ nVertOrientTop);
+
+ if (_rPageAlignLayFrame.IsPageFrame() && !aRectFnSet.IsVert())
+ {
+ const SwFrame* pPrtFrame =
+ static_cast<const SwPageFrame&>(_rPageAlignLayFrame).Lower();
+
+ while (pPrtFrame)
+ {
+ if (pPrtFrame->IsFooterFrame())
+ {
+ nHeight += pPrtFrame->getFrameArea().Height();
+ nOffset -= pPrtFrame->getFrameArea().Height();
+ }
+ pPrtFrame = pPrtFrame->GetNext();
+ }
+ }
+
+ }
+ break;
+ // #i22341# - vertical alignment at top of line
+ case text::RelOrientation::TEXT_LINE:
+ {
+ if ( IsAnchoredToChar() )
+ {
+ nHeight = 0;
+ nOffset = aRectFnSet.YDiff( ToCharTopOfLine(), nVertOrientTop );
+ }
+ else
+ {
+ OSL_FAIL( "<SwAnchoredObjectPosition::GetVertAlignmentValues(..)> - invalid relative alignment" );
+ }
+ }
+ break;
+ case text::RelOrientation::CHAR:
+ {
+ if ( IsAnchoredToChar() )
+ {
+ nHeight = aRectFnSet.GetHeight(*ToCharRect());
+ nOffset = aRectFnSet.YDiff( aRectFnSet.GetTop(*ToCharRect()),
+ nVertOrientTop );
+ }
+ else
+ {
+ OSL_FAIL( "<SwAnchoredObjectPosition::GetVertAlignmentValues(..)> - invalid relative alignment" );
+ }
+ }
+ break;
+ // no break here, because text::RelOrientation::CHAR is invalid, if !mbAnchorToChar
+ default:
+ {
+ OSL_FAIL( "<SwAnchoredObjectPosition::GetVertAlignmentValues(..)> - invalid relative alignment" );
+ }
+ }
+
+ _orAlignAreaHeight = nHeight;
+ _orAlignAreaOffset = nOffset;
+}
+
+// #i26791# - add output parameter <_roVertOffsetToFrameAnchorPos>
+SwTwips SwAnchoredObjectPosition::GetVertRelPos(
+ const SwFrame& _rVertOrientFrame,
+ const SwFrame& _rPageAlignLayFrame,
+ const sal_Int16 _eVertOrient,
+ const sal_Int16 _eRelOrient,
+ const SwTwips _nVertPos,
+ const SvxLRSpaceItem& _rLRSpacing,
+ const SvxULSpaceItem& _rULSpacing,
+ SwTwips& _roVertOffsetToFrameAnchorPos ) const
+{
+ SwTwips nRelPosY = 0;
+ SwRectFnSet aRectFnSet(&_rVertOrientFrame);
+
+ SwTwips nAlignAreaHeight;
+ SwTwips nAlignAreaOffset;
+ GetVertAlignmentValues( _rVertOrientFrame, _rPageAlignLayFrame,
+ _eRelOrient, nAlignAreaHeight, nAlignAreaOffset );
+
+ nRelPosY = nAlignAreaOffset;
+ const SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() );
+ const SwTwips nObjHeight = aRectFnSet.GetHeight(aObjBoundRect);
+
+ switch ( _eVertOrient )
+ {
+ case text::VertOrientation::NONE:
+ {
+ // 'manual' vertical position
+ nRelPosY += _nVertPos;
+ }
+ break;
+ case text::VertOrientation::TOP:
+ {
+ nRelPosY += aRectFnSet.IsVert()
+ ? ( aRectFnSet.IsVertL2R()
+ ? _rLRSpacing.GetLeft()
+ : _rLRSpacing.GetRight() )
+ : _rULSpacing.GetUpper();
+ }
+ break;
+ case text::VertOrientation::CENTER:
+ {
+ nRelPosY += (nAlignAreaHeight / 2) - (nObjHeight / 2);
+ }
+ break;
+ case text::VertOrientation::BOTTOM:
+ {
+ nRelPosY += nAlignAreaHeight -
+ ( nObjHeight + ( aRectFnSet.IsVert()
+ ? ( aRectFnSet.IsVertL2R()
+ ? _rLRSpacing.GetRight()
+ : _rLRSpacing.GetLeft() )
+ : _rULSpacing.GetLower() ) );
+ }
+ break;
+ default:
+ {
+ OSL_FAIL( "<SwAnchoredObjectPosition::GetVertRelPos(..) - invalid vertical positioning" );
+ }
+ }
+
+ // #i26791#
+ _roVertOffsetToFrameAnchorPos = nAlignAreaOffset;
+
+ return nRelPosY;
+}
+
+/** adjust calculated vertical in order to keep object inside
+ 'page' alignment layout frame.
+
+ #i28701# - parameter <_nTopOfAnch> and <_bVert> added
+ #i31805# - add parameter <_bCheckBottom>
+ #i26945# - add parameter <_bFollowTextFlow>
+ #i62875# - method now private and renamed.
+ OD 2009-09-01 #mongolianlayout# - add parameter <bVertL2R>
+*/
+SwTwips SwAnchoredObjectPosition::ImplAdjustVertRelPos( const SwTwips nTopOfAnch,
+ const bool bVert,
+ const bool bVertL2R,
+ const SwFrame& rPageAlignLayFrame,
+ const SwTwips nProposedRelPosY,
+ const bool bFollowTextFlow,
+ const bool bCheckBottom ) const
+{
+ SwTwips nAdjustedRelPosY = nProposedRelPosY;
+ // TODO: Replace the following condition with the correction
+ // of the implementation of option FollowTextFlow.
+ if ( SwAnchoredObject::IsDraggingOffPageAllowed(FindFrameFormat(&mrDrawObj)) &&
+ !(GetAnchorFrame().IsInTab() && DoesObjFollowsTextFlow()) )
+ {
+ return nAdjustedRelPosY;
+ }
+
+ const Size aObjSize(GetAnchoredObj().GetObjRect().SSize());
+ // determine the area of 'page' alignment frame, to which the vertical
+ // position is restricted.
+ // #i28701# - Extend restricted area for the vertical
+ // position to area of the page frame, if wrapping style influence is
+ // considered on object positioning. Needed to avoid layout loops in the
+ // object positioning algorithm considering the wrapping style influence
+ // caused by objects, which follow the text flow and thus are restricted
+ // to its environment (e.g. page header/footer).
+ SwRect aPgAlignArea;
+ {
+ // #i26945# - no extension of restricted area, if
+ // object's attribute follow text flow is set and its inside a table
+ if ( GetFrameFormat().getIDocumentSettingAccess().get(DocumentSettingId::CONSIDER_WRAP_ON_OBJECT_POSITION) &&
+ ( !bFollowTextFlow ||
+ !GetAnchoredObj().GetAnchorFrame()->IsInTab() ) )
+ {
+ aPgAlignArea = rPageAlignLayFrame.FindPageFrame()->getFrameArea();
+ }
+ else
+ {
+ aPgAlignArea = rPageAlignLayFrame.getFrameArea();
+ }
+ }
+
+ if ( bVert )
+ {
+ // #i31805# - consider value of <_bCheckBottom>
+ if ( !bVertL2R )
+ {
+ if ( bCheckBottom &&
+ nTopOfAnch - nAdjustedRelPosY - aObjSize.Width() <
+ aPgAlignArea.Left() )
+ {
+ nAdjustedRelPosY = aPgAlignArea.Left() +
+ nTopOfAnch -
+ aObjSize.Width();
+ }
+ // #i32964# - correction
+ if ( nTopOfAnch - nAdjustedRelPosY > aPgAlignArea.Right() )
+ {
+ nAdjustedRelPosY = nTopOfAnch - aPgAlignArea.Right();
+ }
+ }
+ else
+ {
+ // tdf#112443 if position is completely off-page
+ // return the proposed position and do not adjust it...
+ // tdf#120839 .. unless anchored to char (anchor can jump on other page)
+ const bool bDisablePositioning = mpFrameFormat->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);
+ if ( bDisablePositioning && !IsAnchoredToChar() && nTopOfAnch + nAdjustedRelPosY > aPgAlignArea.Right() )
+ {
+ return nProposedRelPosY;
+ }
+
+ if ( bCheckBottom &&
+ nTopOfAnch + nAdjustedRelPosY + aObjSize.Width() >
+ aPgAlignArea.Right() )
+ {
+ nAdjustedRelPosY = aPgAlignArea.Right() -
+ nTopOfAnch -
+ aObjSize.Width();
+ }
+ if ( nTopOfAnch + nAdjustedRelPosY < aPgAlignArea.Left() )
+ {
+ nAdjustedRelPosY = aPgAlignArea.Left() - nTopOfAnch;
+ }
+ }
+ }
+ else
+ {
+ // tdf#112443 if position is completely off-page
+ // return the proposed position and do not adjust it...
+ const bool bDisablePositioning = mpFrameFormat->getIDocumentSettingAccess().get(DocumentSettingId::DISABLE_OFF_PAGE_POSITIONING);
+
+ // tdf#123002 disable the positioning in header and footer only
+ // we should limit this since anchors of body frames may appear on other pages
+ const bool bIsFooterOrHeader = GetAnchorFrame().GetUpper()
+ && (GetAnchorFrame().GetUpper()->IsFooterFrame() || GetAnchorFrame().GetUpper()->IsHeaderFrame() );
+
+ if ( bDisablePositioning && bIsFooterOrHeader && nTopOfAnch + nAdjustedRelPosY > aPgAlignArea.Bottom() )
+ {
+ return nProposedRelPosY;
+ }
+
+ // #i31805# - consider value of <bCheckBottom>
+ if ( bCheckBottom &&
+ nTopOfAnch + nAdjustedRelPosY + aObjSize.Height() >
+ aPgAlignArea.Top() + aPgAlignArea.Height() )
+ {
+ nAdjustedRelPosY = aPgAlignArea.Top() + aPgAlignArea.Height() -
+ nTopOfAnch -
+ aObjSize.Height();
+ }
+ if ( nTopOfAnch + nAdjustedRelPosY < aPgAlignArea.Top() )
+ {
+ nAdjustedRelPosY = aPgAlignArea.Top() - nTopOfAnch;
+ }
+ }
+ return nAdjustedRelPosY;
+}
+
+/** adjust calculated horizontal in order to keep object inside
+ 'page' alignment layout frame.
+
+ #i62875# - method now private and renamed.
+*/
+SwTwips SwAnchoredObjectPosition::ImplAdjustHoriRelPos(
+ const SwFrame& _rPageAlignLayFrame,
+ const SwTwips _nProposedRelPosX ) const
+{
+ SwTwips nAdjustedRelPosX = _nProposedRelPosX;
+
+ if (SwAnchoredObject::IsDraggingOffPageAllowed(FindFrameFormat(&mrDrawObj)))
+ return nAdjustedRelPosX;
+
+ const SwFrame& rAnchorFrame = GetAnchorFrame();
+ const bool bVert = rAnchorFrame.IsVertical();
+
+ const Size aObjSize( GetAnchoredObj().GetObjRect().SSize() );
+
+ if( bVert )
+ {
+ if ( rAnchorFrame.getFrameArea().Top() + nAdjustedRelPosX + aObjSize.Height() >
+ _rPageAlignLayFrame.getFrameArea().Bottom() )
+ {
+ nAdjustedRelPosX = _rPageAlignLayFrame.getFrameArea().Bottom() -
+ rAnchorFrame.getFrameArea().Top() -
+ aObjSize.Height();
+ }
+ if ( rAnchorFrame.getFrameArea().Top() + nAdjustedRelPosX <
+ _rPageAlignLayFrame.getFrameArea().Top() )
+ {
+ nAdjustedRelPosX = _rPageAlignLayFrame.getFrameArea().Top() -
+ rAnchorFrame.getFrameArea().Top();
+ }
+ }
+ else
+ {
+ if ( rAnchorFrame.getFrameArea().Left() + nAdjustedRelPosX + aObjSize.Width() >
+ _rPageAlignLayFrame.getFrameArea().Right() )
+ {
+ nAdjustedRelPosX = _rPageAlignLayFrame.getFrameArea().Right() -
+ rAnchorFrame.getFrameArea().Left() -
+ aObjSize.Width();
+ }
+ if ( rAnchorFrame.getFrameArea().Left() + nAdjustedRelPosX <
+ _rPageAlignLayFrame.getFrameArea().Left() )
+ {
+ nAdjustedRelPosX = _rPageAlignLayFrame.getFrameArea().Left() -
+ rAnchorFrame.getFrameArea().Left();
+ }
+ }
+
+ return nAdjustedRelPosX;
+}
+
+/** determine alignment value for horizontal position of object */
+void SwAnchoredObjectPosition::GetHoriAlignmentValues( const SwFrame& _rHoriOrientFrame,
+ const SwFrame& _rPageAlignLayFrame,
+ const sal_Int16 _eRelOrient,
+ const bool _bObjWrapThrough,
+ SwTwips& _orAlignAreaWidth,
+ SwTwips& _orAlignAreaOffset,
+ bool& _obAlignedRelToPage ) const
+{
+ SwTwips nWidth = 0;
+ SwTwips nOffset = 0;
+ SwRectFnSet aRectFnSet(&_rHoriOrientFrame);
+ switch ( _eRelOrient )
+ {
+ case text::RelOrientation::PRINT_AREA:
+ {
+ nWidth = aRectFnSet.GetWidth(_rHoriOrientFrame.getFramePrintArea());
+ nOffset = aRectFnSet.GetLeftMargin(_rHoriOrientFrame);
+ if ( _rHoriOrientFrame.IsTextFrame() )
+ {
+ // consider movement of text frame left
+ nOffset += static_cast<const SwTextFrame&>(_rHoriOrientFrame).GetBaseOffsetForFly( !_bObjWrapThrough );
+ }
+ else if ( _rHoriOrientFrame.IsPageFrame() && aRectFnSet.IsVert() )
+ {
+ // for to-page anchored objects, consider header/footer frame
+ // in vertical layout
+ const SwFrame* pPrtFrame =
+ static_cast<const SwPageFrame&>(_rHoriOrientFrame).Lower();
+ while( pPrtFrame )
+ {
+ if( pPrtFrame->IsHeaderFrame() )
+ {
+ nWidth -= pPrtFrame->getFrameArea().Height();
+ nOffset += pPrtFrame->getFrameArea().Height();
+ }
+ else if( pPrtFrame->IsFooterFrame() )
+ {
+ nWidth -= pPrtFrame->getFrameArea().Height();
+ }
+ pPrtFrame = pPrtFrame->GetNext();
+ }
+ }
+ break;
+ }
+ case text::RelOrientation::PAGE_LEFT:
+ {
+ // align at left border of page frame/fly frame/cell frame
+ nWidth = aRectFnSet.GetLeftMargin(_rPageAlignLayFrame);
+ nOffset = aRectFnSet.XDiff(
+ aRectFnSet.GetLeft(_rPageAlignLayFrame.getFrameArea()),
+ aRectFnSet.GetLeft(_rHoriOrientFrame.getFrameArea()) );
+ _obAlignedRelToPage = true;
+ }
+ break;
+ case text::RelOrientation::PAGE_RIGHT:
+ {
+ // align at right border of page frame/fly frame/cell frame
+ nWidth = aRectFnSet.GetRightMargin(_rPageAlignLayFrame);
+ nOffset = aRectFnSet.XDiff(
+ aRectFnSet.GetPrtRight(_rPageAlignLayFrame),
+ aRectFnSet.GetLeft(_rHoriOrientFrame.getFrameArea()) );
+ _obAlignedRelToPage = true;
+ }
+ break;
+ case text::RelOrientation::FRAME_LEFT:
+ {
+ // align at left border of anchor frame
+ nWidth = aRectFnSet.GetLeftMargin(_rHoriOrientFrame);
+ nOffset = 0;
+ }
+ break;
+ case text::RelOrientation::FRAME_RIGHT:
+ {
+ // align at right border of anchor frame
+ // Unify and simplify
+ nWidth = aRectFnSet.GetRightMargin(_rHoriOrientFrame);
+ nOffset = aRectFnSet.GetRight(_rHoriOrientFrame.getFramePrintArea());
+ }
+ break;
+ case text::RelOrientation::CHAR:
+ {
+ // alignment relative to character - assure, that corresponding
+ // character rectangle is set.
+ if ( IsAnchoredToChar() )
+ {
+ nWidth = 0;
+ nOffset = aRectFnSet.XDiff(
+ aRectFnSet.GetLeft(*ToCharRect()),
+ aRectFnSet.GetLeft(ToCharOrientFrame()->getFrameArea()) );
+ break;
+ }
+ [[fallthrough]];
+ }
+ case text::RelOrientation::PAGE_PRINT_AREA:
+ {
+ nWidth = aRectFnSet.GetWidth(_rPageAlignLayFrame.getFramePrintArea());
+ nOffset = aRectFnSet.XDiff(
+ aRectFnSet.GetPrtLeft(_rPageAlignLayFrame),
+ aRectFnSet.GetLeft(_rHoriOrientFrame.getFrameArea()) );
+ if ( _rHoriOrientFrame.IsPageFrame() && aRectFnSet.IsVert() )
+ {
+ // for to-page anchored objects, consider header/footer frame
+ // in vertical layout
+ const SwFrame* pPrtFrame =
+ static_cast<const SwPageFrame&>(_rHoriOrientFrame).Lower();
+ while( pPrtFrame )
+ {
+ if( pPrtFrame->IsHeaderFrame() )
+ {
+ nWidth -= pPrtFrame->getFrameArea().Height();
+ nOffset += pPrtFrame->getFrameArea().Height();
+ }
+ else if( pPrtFrame->IsFooterFrame() )
+ {
+ nWidth -= pPrtFrame->getFrameArea().Height();
+ }
+ pPrtFrame = pPrtFrame->GetNext();
+ }
+ }
+ _obAlignedRelToPage = true;
+ break;
+ }
+ case text::RelOrientation::PAGE_FRAME:
+ {
+ nWidth = aRectFnSet.GetWidth(_rPageAlignLayFrame.getFrameArea());
+ nOffset = aRectFnSet.XDiff(
+ aRectFnSet.GetLeft(_rPageAlignLayFrame.getFrameArea()),
+ aRectFnSet.GetLeft(_rHoriOrientFrame.getFrameArea()) );
+ _obAlignedRelToPage = true;
+ break;
+ }
+ default:
+ {
+ nWidth = aRectFnSet.GetWidth(_rHoriOrientFrame.getFrameArea());
+
+ bool bWrapThrough = _bObjWrapThrough;
+ // If the frame format is a TextBox of a draw shape, then use the
+ // surround of the original shape.
+ SwTextBoxHelper::getShapeWrapThrough(mpFrameFormat, bWrapThrough);
+
+ bool bIgnoreFlysAnchoredAtFrame = !bWrapThrough;
+ nOffset = _rHoriOrientFrame.IsTextFrame() ?
+ static_cast<const SwTextFrame&>(_rHoriOrientFrame).GetBaseOffsetForFly( bIgnoreFlysAnchoredAtFrame ) :
+ 0;
+ break;
+ }
+ }
+
+ _orAlignAreaWidth = nWidth;
+ _orAlignAreaOffset = nOffset;
+}
+
+/** toggle given horizontal orientation and relative alignment */
+void SwAnchoredObjectPosition::ToggleHoriOrientAndAlign(
+ const bool _bToggleLeftRight,
+ sal_Int16& _ioeHoriOrient,
+ sal_Int16& _iopeRelOrient
+ )
+{
+ if( !_bToggleLeftRight )
+ return;
+
+ // toggle orientation
+ switch ( _ioeHoriOrient )
+ {
+ case text::HoriOrientation::RIGHT :
+ {
+ _ioeHoriOrient = text::HoriOrientation::LEFT;
+ }
+ break;
+ case text::HoriOrientation::LEFT :
+ {
+ _ioeHoriOrient = text::HoriOrientation::RIGHT;
+ }
+ break;
+ default:
+ break;
+ }
+
+ // toggle relative alignment
+ switch ( _iopeRelOrient )
+ {
+ case text::RelOrientation::PAGE_RIGHT :
+ {
+ _iopeRelOrient = text::RelOrientation::PAGE_LEFT;
+ }
+ break;
+ case text::RelOrientation::PAGE_LEFT :
+ {
+ _iopeRelOrient = text::RelOrientation::PAGE_RIGHT;
+ }
+ break;
+ case text::RelOrientation::FRAME_RIGHT :
+ {
+ _iopeRelOrient = text::RelOrientation::FRAME_LEFT;
+ }
+ break;
+ case text::RelOrientation::FRAME_LEFT :
+ {
+ _iopeRelOrient = text::RelOrientation::FRAME_RIGHT;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/** calculate relative horizontal position */
+SwTwips SwAnchoredObjectPosition::CalcRelPosX(
+ const SwFrame& _rHoriOrientFrame,
+ const SwEnvironmentOfAnchoredObject& _rEnvOfObj,
+ const SwFormatHoriOrient& _rHoriOrient,
+ const SvxLRSpaceItem& _rLRSpacing,
+ const SvxULSpaceItem& _rULSpacing,
+ const bool _bObjWrapThrough,
+ const SwTwips _nRelPosY,
+ SwTwips& _roHoriOffsetToFrameAnchorPos
+ ) const
+{
+ // determine 'page' alignment layout frame
+ const SwFrame& rPageAlignLayFrame =
+ _rEnvOfObj.GetHoriEnvironmentLayoutFrame( _rHoriOrientFrame );
+
+ const bool bEvenPage = !rPageAlignLayFrame.OnRightPage();
+ const bool bToggle = _rHoriOrient.IsPosToggle() && bEvenPage;
+
+ // determine orientation and relative alignment
+ sal_Int16 eHoriOrient = _rHoriOrient.GetHoriOrient();
+ sal_Int16 eRelOrient = _rHoriOrient.GetRelationOrient();
+ // toggle orientation and relative alignment
+ ToggleHoriOrientAndAlign( bToggle, eHoriOrient, eRelOrient );
+
+ // determine alignment parameter
+ // <nWidth>: 'width' of alignment area
+ // <nOffset>: offset of alignment area, relative to 'left' of anchor frame
+ SwTwips nWidth = 0;
+ SwTwips nOffset = 0;
+ bool bAlignedRelToPage = false;
+ GetHoriAlignmentValues( _rHoriOrientFrame, rPageAlignLayFrame,
+ eRelOrient, _bObjWrapThrough,
+ nWidth, nOffset, bAlignedRelToPage );
+
+ const SwFrame& rAnchorFrame = GetAnchorFrame();
+ SwRectFnSet aRectFnSet(&_rHoriOrientFrame);
+ SwTwips nObjWidth = aRectFnSet.GetWidth(GetAnchoredObj().GetObjRect());
+ SwTwips nRelPosX = nOffset;
+ if ( _rHoriOrient.GetHoriOrient() == text::HoriOrientation::NONE )
+ {
+ // 'manual' horizontal position
+ const bool bR2L = rAnchorFrame.IsRightToLeft();
+ if( IsAnchoredToChar() && text::RelOrientation::CHAR == eRelOrient )
+ {
+ if( bR2L )
+ nRelPosX -= _rHoriOrient.GetPos();
+ else
+ nRelPosX += _rHoriOrient.GetPos();
+ }
+ else if ( bToggle || ( !_rHoriOrient.IsPosToggle() && bR2L ) )
+ {
+ // Correction: consider <nOffset> also for
+ // toggling from left to right.
+ nRelPosX += nWidth - nObjWidth - _rHoriOrient.GetPos();
+ }
+ else
+ {
+ nRelPosX += _rHoriOrient.GetPos();
+ }
+ }
+ else if ( text::HoriOrientation::CENTER == eHoriOrient )
+ nRelPosX += (nWidth / 2) - (nObjWidth / 2);
+ else if ( text::HoriOrientation::RIGHT == eHoriOrient )
+ nRelPosX += nWidth -
+ ( nObjWidth +
+ ( aRectFnSet.IsVert() ? _rULSpacing.GetLower() : _rLRSpacing.GetRight() ) );
+ else
+ nRelPosX += aRectFnSet.IsVert() ? _rULSpacing.GetUpper() : _rLRSpacing.GetLeft();
+
+ // adjust relative position by distance between anchor frame and
+ // the frame, the object is oriented at.
+ if ( &rAnchorFrame != &_rHoriOrientFrame )
+ {
+ SwTwips nLeftOrient = aRectFnSet.GetLeft(_rHoriOrientFrame.getFrameArea());
+ SwTwips nLeftAnchor = aRectFnSet.GetLeft(rAnchorFrame.getFrameArea());
+ nRelPosX += aRectFnSet.XDiff( nLeftOrient, nLeftAnchor );
+ }
+
+ // adjust calculated relative horizontal position, in order to
+ // keep object inside 'page' alignment layout frame
+ const SwFrame& rEnvironmentLayFrame =
+ _rEnvOfObj.GetHoriEnvironmentLayoutFrame( _rHoriOrientFrame );
+ bool bFollowTextFlow = GetFrameFormat().GetFollowTextFlow().GetValue();
+ bool bWrapThrough = GetFrameFormat().GetSurround().GetSurround() != text::WrapTextMode_THROUGH;
+ // Don't try to keep wrap-though objects inside the cell, even if they are following text flow.
+ if (!rEnvironmentLayFrame.IsInTab() || !bFollowTextFlow || bWrapThrough)
+ {
+ nRelPosX = AdjustHoriRelPos( rEnvironmentLayFrame, nRelPosX );
+ }
+
+ // if object is a Writer fly frame and it's anchored to a content and
+ // it is horizontal positioned left or right, but not relative to character,
+ // it has to be drawn aside another object, which have the same horizontal
+ // position and lay below it.
+ if ( GetAnchoredObj().DynCastFlyFrame() &&
+ ( mpContact->ObjAnchoredAtPara() || mpContact->ObjAnchoredAtChar() ) &&
+ ( eHoriOrient == text::HoriOrientation::LEFT || eHoriOrient == text::HoriOrientation::RIGHT ) &&
+ eRelOrient != text::RelOrientation::CHAR )
+ {
+ nRelPosX = AdjustHoriRelPosForDrawAside( _rHoriOrientFrame,
+ nRelPosX, _nRelPosY,
+ eHoriOrient, eRelOrient,
+ _rLRSpacing, _rULSpacing,
+ bEvenPage );
+ }
+
+ // #i26791#
+ _roHoriOffsetToFrameAnchorPos = nOffset;
+
+ return nRelPosX;
+}
+
+// method incl. helper methods for adjusting proposed horizontal position,
+// if object has to draw aside another object.
+/** adjust calculated horizontal position in order to draw object
+ aside other objects with same positioning
+*/
+SwTwips SwAnchoredObjectPosition::AdjustHoriRelPosForDrawAside(
+ const SwFrame& _rHoriOrientFrame,
+ const SwTwips _nProposedRelPosX,
+ const SwTwips _nRelPosY,
+ const sal_Int16 _eHoriOrient,
+ const sal_Int16 _eRelOrient,
+ const SvxLRSpaceItem& _rLRSpacing,
+ const SvxULSpaceItem& _rULSpacing,
+ const bool _bEvenPage
+ ) const
+{
+ // #i26791#
+ if ( GetAnchorFrame().DynCastTextFrame() == nullptr ||
+ dynamic_cast<const SwFlyAtContentFrame*>( &GetAnchoredObj() ) == nullptr )
+ {
+ OSL_FAIL( "<SwAnchoredObjectPosition::AdjustHoriRelPosForDrawAside(..) - usage for wrong anchor type" );
+ return _nProposedRelPosX;
+ }
+
+ const SwTextFrame& rAnchorTextFrame = static_cast<const SwTextFrame&>(GetAnchorFrame());
+ // #i26791#
+ const SwFlyAtContentFrame& rFlyAtContentFrame =
+ static_cast<const SwFlyAtContentFrame&>(GetAnchoredObj());
+ const SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() );
+ SwRectFnSet aRectFnSet(&_rHoriOrientFrame);
+
+ SwTwips nAdjustedRelPosX = _nProposedRelPosX;
+
+ // determine proposed object bound rectangle
+ Point aTmpPos = aRectFnSet.GetPos(rAnchorTextFrame.getFrameArea());
+ if( aRectFnSet.IsVert() )
+ {
+ aTmpPos.AdjustX( -(_nRelPosY + aObjBoundRect.Width()) );
+ aTmpPos.AdjustY(nAdjustedRelPosX );
+ }
+ else
+ {
+ aTmpPos.AdjustX(nAdjustedRelPosX );
+ aTmpPos.AdjustY(_nRelPosY );
+ }
+ SwRect aTmpObjRect( aTmpPos, aObjBoundRect.SSize() );
+
+ const sal_uInt32 nObjOrdNum = GetObject().GetOrdNum();
+ const SwPageFrame* pObjPage = rFlyAtContentFrame.FindPageFrame();
+ const SwFrame* pObjContext = ::FindContext( &rAnchorTextFrame, SwFrameType::Column );
+ SwNodeOffset nObjIndex = rAnchorTextFrame.GetTextNodeFirst()->GetIndex();
+ SwOrderIter aIter( pObjPage );
+ const SwFlyFrame* pFly = static_cast<const SwVirtFlyDrawObj*>(aIter.Bottom())->GetFlyFrame();
+ while ( pFly && nObjOrdNum > pFly->GetVirtDrawObj()->GetOrdNumDirect() )
+ {
+ if ( DrawAsideFly( pFly, aTmpObjRect, pObjContext, nObjIndex,
+ _bEvenPage, _eHoriOrient, _eRelOrient ) )
+ {
+ if( aRectFnSet.IsVert() )
+ {
+ const SvxULSpaceItem& rOtherUL = pFly->GetFormat()->GetULSpace();
+ const SwTwips nOtherTop = pFly->getFrameArea().Top() - rOtherUL.GetUpper();
+ const SwTwips nOtherBot = pFly->getFrameArea().Bottom() + rOtherUL.GetLower();
+ if ( nOtherTop <= aTmpObjRect.Bottom() + _rULSpacing.GetLower() &&
+ nOtherBot >= aTmpObjRect.Top() - _rULSpacing.GetUpper() )
+ {
+ if ( _eHoriOrient == text::HoriOrientation::LEFT )
+ {
+ SwTwips nTmp = nOtherBot + 1 + _rULSpacing.GetUpper() -
+ rAnchorTextFrame.getFrameArea().Top();
+ if ( nTmp > nAdjustedRelPosX &&
+ rAnchorTextFrame.getFrameArea().Top() + nTmp +
+ aObjBoundRect.Height() + _rULSpacing.GetLower()
+ <= pObjPage->getFrameArea().Height() + pObjPage->getFrameArea().Top() )
+ {
+ nAdjustedRelPosX = nTmp;
+ }
+ }
+ else if ( _eHoriOrient == text::HoriOrientation::RIGHT )
+ {
+ SwTwips nTmp = nOtherTop - 1 - _rULSpacing.GetLower() -
+ aObjBoundRect.Height() -
+ rAnchorTextFrame.getFrameArea().Top();
+ if ( nTmp < nAdjustedRelPosX &&
+ rAnchorTextFrame.getFrameArea().Top() + nTmp - _rULSpacing.GetUpper()
+ >= pObjPage->getFrameArea().Top() )
+ {
+ nAdjustedRelPosX = nTmp;
+ }
+ }
+ aTmpObjRect.Pos().setY( rAnchorTextFrame.getFrameArea().Top() +
+ nAdjustedRelPosX );
+ }
+ }
+ else
+ {
+ const SvxLRSpaceItem& rOtherLR = pFly->GetFormat()->GetLRSpace();
+ const SwTwips nOtherLeft = pFly->getFrameArea().Left() - rOtherLR.GetLeft();
+ const SwTwips nOtherRight = pFly->getFrameArea().Right() + rOtherLR.GetRight();
+ if( nOtherLeft <= aTmpObjRect.Right() + _rLRSpacing.GetRight() &&
+ nOtherRight >= aTmpObjRect.Left() - _rLRSpacing.GetLeft() )
+ {
+ if ( _eHoriOrient == text::HoriOrientation::LEFT )
+ {
+ SwTwips nTmp = nOtherRight + 1 + _rLRSpacing.GetLeft() -
+ rAnchorTextFrame.getFrameArea().Left();
+ if ( nTmp > nAdjustedRelPosX &&
+ rAnchorTextFrame.getFrameArea().Left() + nTmp +
+ aObjBoundRect.Width() + _rLRSpacing.GetRight()
+ <= pObjPage->getFrameArea().Width() + pObjPage->getFrameArea().Left() )
+ {
+ nAdjustedRelPosX = nTmp;
+ }
+ }
+ else if ( _eHoriOrient == text::HoriOrientation::RIGHT )
+ {
+ SwTwips nTmp = nOtherLeft - 1 - _rLRSpacing.GetRight() -
+ aObjBoundRect.Width() -
+ rAnchorTextFrame.getFrameArea().Left();
+ if ( nTmp < nAdjustedRelPosX &&
+ rAnchorTextFrame.getFrameArea().Left() + nTmp - _rLRSpacing.GetLeft()
+ >= pObjPage->getFrameArea().Left() )
+ {
+ nAdjustedRelPosX = nTmp;
+ }
+ }
+ aTmpObjRect.Pos().setX( rAnchorTextFrame.getFrameArea().Left() +
+ nAdjustedRelPosX );
+ }
+ } // end of <if (bVert)>
+ } // end of <if DrawAsideFly(..)>
+
+ pFly = static_cast<const SwVirtFlyDrawObj*>(aIter.Next())->GetFlyFrame();
+ } // end of <loop on fly frames
+
+ return nAdjustedRelPosX;
+}
+
+/** determine, if object has to draw aside given fly frame
+
+ method used by <AdjustHoriRelPosForDrawAside(..)>
+*/
+bool SwAnchoredObjectPosition::DrawAsideFly( const SwFlyFrame* _pFly,
+ const SwRect& _rObjRect,
+ const SwFrame* _pObjContext,
+ const SwNodeOffset _nObjIndex,
+ const bool _bEvenPage,
+ const sal_Int16 _eHoriOrient,
+ const sal_Int16 _eRelOrient
+ ) const
+{
+ bool bRetVal = false;
+
+ SwRectFnSet aRectFnSet(&GetAnchorFrame());
+
+ if ( _pFly->IsFlyAtContentFrame() &&
+ aRectFnSet.BottomDist( _pFly->getFrameArea(), aRectFnSet.GetTop(_rObjRect) ) < 0 &&
+ aRectFnSet.BottomDist( _rObjRect, aRectFnSet.GetTop(_pFly->getFrameArea()) ) < 0 &&
+ ::FindContext( _pFly->GetAnchorFrame(), SwFrameType::Column ) == _pObjContext )
+ {
+ SwNodeOffset nOtherIndex =
+ static_cast<const SwTextFrame*>(_pFly->GetAnchorFrame())->GetTextNodeFirst()->GetIndex();
+ if (sw::FrameContainsNode(static_cast<SwTextFrame const&>(*_pFly->GetAnchorFrame()), _nObjIndex)
+ || nOtherIndex < _nObjIndex)
+ {
+ const SwFormatHoriOrient& rHori = _pFly->GetFormat()->GetHoriOrient();
+ sal_Int16 eOtherRelOrient = rHori.GetRelationOrient();
+ if( text::RelOrientation::CHAR != eOtherRelOrient )
+ {
+ sal_Int16 eOtherHoriOrient = rHori.GetHoriOrient();
+ ToggleHoriOrientAndAlign( _bEvenPage && rHori.IsPosToggle(),
+ eOtherHoriOrient,
+ eOtherRelOrient );
+ if ( eOtherHoriOrient == _eHoriOrient &&
+ Minor_( _eRelOrient, eOtherRelOrient, text::HoriOrientation::LEFT == _eHoriOrient ) )
+ {
+ bRetVal = true;
+ }
+ }
+ }
+ }
+
+ return bRetVal;
+}
+
+/** determine, if object has to draw aside another object
+
+ the different alignments of the objects determines, if one has
+ to draw aside another one. Thus, the given alignment are checked
+ against each other, which one has to be drawn aside the other one.
+ depending on parameter _bLeft check is done for left or right
+ positioning.
+ method used by <DrawAsideFly(..)>
+*/
+bool SwAnchoredObjectPosition::Minor_( sal_Int16 _eRelOrient1,
+ sal_Int16 _eRelOrient2,
+ bool _bLeft )
+{
+ bool bRetVal;
+
+ // draw aside order for left horizontal position
+ //! one array entry for each value in text::RelOrientation
+ static sal_uInt16 const aLeft[ 10 ] =
+ { 5, 6, 0, 1, 8, 4, 7, 2, 3, 9 };
+ // draw aside order for right horizontal position
+ //! one array entry for each value in text::RelOrientation
+ static sal_uInt16 const aRight[ 10 ] =
+ { 5, 6, 0, 8, 1, 7, 4, 2, 3, 9 };
+
+ // decide depending on given order, which frame has to draw aside another frame
+ if( _bLeft )
+ bRetVal = aLeft[ _eRelOrient1 ] >= aLeft[ _eRelOrient2 ];
+ else
+ bRetVal = aRight[ _eRelOrient1 ] >= aRight[ _eRelOrient2 ];
+
+ return bRetVal;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/objectpositioning/ascharanchoredobjectposition.cxx b/sw/source/core/objectpositioning/ascharanchoredobjectposition.cxx
new file mode 100644
index 0000000000..e82659ccd5
--- /dev/null
+++ b/sw/source/core/objectpositioning/ascharanchoredobjectposition.cxx
@@ -0,0 +1,398 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <anchoreddrawobject.hxx>
+#include <ascharanchoredobjectposition.hxx>
+#include <frame.hxx>
+#include <txtfrm.hxx>
+#include <flyfrms.hxx>
+#include <svx/svdobj.hxx>
+#include <frmfmt.hxx>
+#include <frmatr.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <osl/diagnose.h>
+#include <fmtornt.hxx>
+
+
+using namespace ::com::sun::star;
+
+namespace objectpositioning
+{
+
+/** constructor */
+SwAsCharAnchoredObjectPosition::SwAsCharAnchoredObjectPosition(
+ SdrObject& _rDrawObj,
+ const Point& _rProposedAnchorPos,
+ const AsCharFlags _nFlags,
+ const SwTwips _nLineAscent,
+ const SwTwips _nLineDescent,
+ const SwTwips _nLineAscentInclObjs,
+ const SwTwips _nLineDescentInclObjs )
+ : SwAnchoredObjectPosition( _rDrawObj ),
+ mrProposedAnchorPos( _rProposedAnchorPos ),
+ mnFlags( _nFlags ),
+ mnLineAscent( _nLineAscent ),
+ mnLineDescent( _nLineDescent ),
+ mnLineAscentInclObjs( _nLineAscentInclObjs ),
+ mnLineDescentInclObjs( _nLineDescentInclObjs ),
+ mnRelPos ( 0 ),
+ mnLineAlignment ( sw::LineAlign::NONE )
+{}
+
+/** destructor */
+SwAsCharAnchoredObjectPosition::~SwAsCharAnchoredObjectPosition()
+{}
+
+/** method to cast <SwAnchoredObjectPosition::GetAnchorFrame()> to needed type */
+const SwTextFrame& SwAsCharAnchoredObjectPosition::GetAnchorTextFrame() const
+{
+ assert( dynamic_cast<const SwTextFrame*>( &GetAnchorFrame() ) &&
+ "SwAsCharAnchoredObjectPosition::GetAnchorTextFrame() - wrong anchor frame type" );
+
+ return static_cast<const SwTextFrame&>(GetAnchorFrame());
+}
+
+/** calculate position for object
+
+ OD 30.07.2003 #110978#
+ members <maAnchorPos>, <mnRelPos>, <maObjBoundRect> and
+ <mnLineAlignment> are calculated.
+ calculated position is set at the given object.
+*/
+void SwAsCharAnchoredObjectPosition::CalcPosition()
+{
+ const SwTextFrame& rAnchorFrame = GetAnchorTextFrame();
+ // swap anchor frame, if swapped. Note: destructor takes care of the 'undo'
+ SwFrameSwapper aFrameSwapper( &rAnchorFrame, false );
+
+ SwRectFnSet aRectFnSet(&rAnchorFrame);
+
+ Point aAnchorPos( mrProposedAnchorPos );
+
+ const SwFrameFormat& rFrameFormat = GetFrameFormat();
+
+ SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() );
+ SwTwips nObjWidth = aRectFnSet.GetWidth(aObjBoundRect);
+
+ // determine spacing values considering layout-/text-direction
+ const SvxLRSpaceItem& rLRSpace = rFrameFormat.GetLRSpace();
+ const SvxULSpaceItem& rULSpace = rFrameFormat.GetULSpace();
+ SwTwips nLRSpaceLeft, nLRSpaceRight, nULSpaceUpper, nULSpaceLower;
+ {
+ if ( rAnchorFrame.IsVertical() )
+ {
+ // Seems to be easier to do it all the horizontal way
+ // So, from now on think horizontal.
+ rAnchorFrame.SwitchVerticalToHorizontal( aObjBoundRect );
+ rAnchorFrame.SwitchVerticalToHorizontal( aAnchorPos );
+
+ // convert the spacing values
+ nLRSpaceLeft = rULSpace.GetUpper();
+ nLRSpaceRight = rULSpace.GetLower();
+ nULSpaceUpper = rLRSpace.GetRight();
+ nULSpaceLower = rLRSpace.GetLeft();
+ }
+ else
+ {
+ if ( rAnchorFrame.IsRightToLeft() )
+ {
+ nLRSpaceLeft = rLRSpace.GetRight();
+ nLRSpaceRight = rLRSpace.GetLeft();
+ }
+ else
+ {
+ nLRSpaceLeft = rLRSpace.GetLeft();
+ nLRSpaceRight = rLRSpace.GetRight();
+ }
+
+ nULSpaceUpper = rULSpace.GetUpper();
+ nULSpaceLower = rULSpace.GetLower();
+ }
+ }
+
+ // consider left and upper spacing by adjusting anchor position.
+ // left spacing is only considered, if requested.
+ if( mnFlags & AsCharFlags::UlSpace )
+ {
+ aAnchorPos.AdjustX(nLRSpaceLeft );
+ }
+ aAnchorPos.AdjustY(nULSpaceUpper );
+
+ // for drawing objects: consider difference between its bounding rectangle
+ // and its snapping rectangle by adjusting anchor position.
+ // left difference is only considered, if requested.
+ if( !IsObjFly() )
+ {
+ SwRect aSnapRect(GetObject().GetSnapRect());
+ if ( rAnchorFrame.IsVertical() )
+ {
+ rAnchorFrame.SwitchVerticalToHorizontal( aSnapRect );
+ }
+
+ if( mnFlags & AsCharFlags::UlSpace )
+ {
+ aAnchorPos.AdjustX(aSnapRect.Left() - aObjBoundRect.Left() );
+ }
+ aAnchorPos.AdjustY(aSnapRect.Top() - aObjBoundRect.Top() );
+ }
+
+ // enlarge bounding rectangle of object by its spacing.
+ aObjBoundRect.AddLeft( - nLRSpaceLeft );
+ aObjBoundRect.AddWidth( nLRSpaceRight );
+ aObjBoundRect.AddTop( - nULSpaceUpper );
+ aObjBoundRect.AddHeight( nULSpaceLower );
+
+ // calculate relative position to given base line.
+ const SwFormatVertOrient& rVert = rFrameFormat.GetVertOrient();
+ const SwTwips nObjBoundHeight = ( mnFlags & AsCharFlags::Rotate )
+ ? aObjBoundRect.Width()
+ : aObjBoundRect.Height();
+ const SwTwips nRelPos = GetRelPosToBase( nObjBoundHeight, rVert );
+
+ // for initial positioning:
+ // adjust the proposed anchor position by difference between
+ // calculated relative position to base line and current maximal line ascent.
+ // Note: In the following line formatting the base line will be adjusted
+ // by the same difference.
+ if( mnFlags & AsCharFlags::Init && nRelPos < 0 && mnLineAscentInclObjs < -nRelPos )
+ {
+ if( mnFlags & AsCharFlags::Rotate )
+ aAnchorPos.AdjustX( -(mnLineAscentInclObjs + nRelPos) );
+ else
+ aAnchorPos.AdjustY( -(mnLineAscentInclObjs + nRelPos) );
+ }
+
+ // consider BIDI-multiportion by adjusting proposed anchor position
+ if( mnFlags & AsCharFlags::Bidi )
+ aAnchorPos.AdjustX( -(aObjBoundRect.Width()) );
+
+ // calculate relative position considering rotation and inside rotation
+ // reverse direction.
+ Point aRelPos;
+ {
+ if( mnFlags & AsCharFlags::Rotate )
+ {
+ if( mnFlags & AsCharFlags::Reverse )
+ aRelPos.setX( -nRelPos - aObjBoundRect.Width() );
+ else
+ {
+ aRelPos.setX( nRelPos );
+ aRelPos.setY( -aObjBoundRect.Height() );
+ }
+ }
+ else
+ aRelPos.setY( nRelPos );
+ }
+
+ if( !IsObjFly() )
+ {
+ if( !( mnFlags & AsCharFlags::Quick ) )
+ {
+ // save calculated Y-position value for 'automatic' vertical positioning,
+ // in order to avoid a switch to 'manual' vertical positioning in
+ // <SwDrawContact::Changed_(..)>.
+ const sal_Int16 eVertOrient = rVert.GetVertOrient();
+ if( rVert.GetPos() != nRelPos && eVertOrient != text::VertOrientation::NONE )
+ {
+ SwFormatVertOrient aVert( rVert );
+ aVert.SetPos( nRelPos );
+ const_cast<SwFrameFormat&>(rFrameFormat).LockModify();
+ const_cast<SwFrameFormat&>(rFrameFormat).SetFormatAttr( aVert );
+ const_cast<SwFrameFormat&>(rFrameFormat).UnlockModify();
+ }
+
+ // determine absolute anchor position considering layout directions.
+ // Note: Use copy of <aAnchorPos>, because it's needed for
+ // setting relative position.
+ Point aAbsAnchorPos( aAnchorPos );
+ if ( rAnchorFrame.IsRightToLeft() )
+ {
+ rAnchorFrame.SwitchLTRtoRTL( aAbsAnchorPos );
+ aAbsAnchorPos.AdjustX( -nObjWidth );
+ }
+ if ( rAnchorFrame.IsVertical() )
+ rAnchorFrame.SwitchHorizontalToVertical( aAbsAnchorPos );
+
+ // set proposed anchor position at the drawing object.
+ // OD 2004-04-06 #i26791# - distinction between 'master' drawing
+ // object and 'virtual' drawing object no longer needed.
+ GetObject().SetAnchorPos( aAbsAnchorPos );
+
+ // move drawing object to set its correct relative position.
+ {
+ SwRect aSnapRect(GetObject().GetSnapRect());
+ if ( rAnchorFrame.IsVertical() )
+ rAnchorFrame.SwitchVerticalToHorizontal( aSnapRect );
+
+ Point aDiff;
+ if ( rAnchorFrame.IsRightToLeft() )
+ aDiff = aRelPos + aAbsAnchorPos - aSnapRect.TopLeft();
+ else
+ aDiff = aRelPos + aAnchorPos - aSnapRect.TopLeft();
+
+ if ( rAnchorFrame.IsVertical() )
+ aDiff = Point( -aDiff.Y(), aDiff.X() );
+
+ // OD 2004-04-06 #i26791# - distinction between 'master' drawing
+ // object and 'virtual' drawing object no longer needed.
+ GetObject().Move( Size( aDiff.X(), aDiff.Y() ) );
+ }
+ }
+
+ // switch horizontal, LTR anchor position to absolute values.
+ if ( rAnchorFrame.IsRightToLeft() )
+ {
+ rAnchorFrame.SwitchLTRtoRTL( aAnchorPos );
+ aAnchorPos.AdjustX( -nObjWidth );
+ }
+ if ( rAnchorFrame.IsVertical() )
+ rAnchorFrame.SwitchHorizontalToVertical( aAnchorPos );
+
+ // #i44347# - keep last object rectangle at anchored object
+ assert( dynamic_cast<const SwAnchoredDrawObject*>( &GetAnchoredObj() ) &&
+ "<SwAsCharAnchoredObjectPosition::CalcPosition()> - wrong type of anchored object." );
+ SwAnchoredDrawObject& rAnchoredDrawObj =
+ static_cast<SwAnchoredDrawObject&>( GetAnchoredObj() );
+ rAnchoredDrawObj.SetLastObjRect( rAnchoredDrawObj.GetObjRect().SVRect() );
+ }
+ else
+ {
+ // determine absolute anchor position and calculate corresponding
+ // relative position and its relative position attribute.
+ // Note: The relative position contains the spacing values.
+ Point aRelAttr;
+ if ( rAnchorFrame.IsRightToLeft() )
+ {
+ rAnchorFrame.SwitchLTRtoRTL( aAnchorPos );
+ aAnchorPos.AdjustX( -nObjWidth );
+ }
+ if ( rAnchorFrame.IsVertical() )
+ {
+ rAnchorFrame.SwitchHorizontalToVertical( aAnchorPos );
+ aRelAttr = Point( -nRelPos, 0 );
+ aRelPos = Point( -aRelPos.Y(), aRelPos.X() );
+ }
+ else
+ aRelAttr = Point( 0, nRelPos );
+
+ // OD 2004-03-23 #i26791#
+ assert( dynamic_cast<const SwFlyInContentFrame*>( &GetAnchoredObj()) &&
+ "<SwAsCharAnchoredObjectPosition::CalcPosition()> - wrong anchored object." );
+ const SwFlyInContentFrame& rFlyInContentFrame =
+ static_cast<const SwFlyInContentFrame&>(GetAnchoredObj());
+ if ( !(mnFlags & AsCharFlags::Quick) &&
+ ( aAnchorPos != rFlyInContentFrame.GetRefPoint() ||
+ aRelAttr != rFlyInContentFrame.GetCurrRelPos() ) )
+ {
+ // set new anchor position and relative position
+ SwFlyInContentFrame* pFlyInContentFrame = &const_cast<SwFlyInContentFrame&>(rFlyInContentFrame);
+ pFlyInContentFrame->SetRefPoint( aAnchorPos, aRelAttr, aRelPos );
+ if( nObjWidth != aRectFnSet.GetWidth(pFlyInContentFrame->getFrameArea()) )
+ {
+ // recalculate object bound rectangle, if object width has changed.
+ aObjBoundRect = GetAnchoredObj().GetObjRect();
+ aObjBoundRect.AddLeft( - rLRSpace.GetLeft() );
+ aObjBoundRect.AddWidth( rLRSpace.GetRight() );
+ aObjBoundRect.AddTop( - rULSpace.GetUpper() );
+ aObjBoundRect.AddHeight( rULSpace.GetLower() );
+ }
+ }
+ OSL_ENSURE( aRectFnSet.GetHeight(rFlyInContentFrame.getFrameArea()),
+ "SwAnchoredObjectPosition::CalcPosition(..) - fly frame has an invalid height" );
+ }
+
+ // keep calculated values
+ maAnchorPos = aAnchorPos;
+ mnRelPos = nRelPos;
+ maObjBoundRect = aObjBoundRect;
+}
+
+/** determine the relative position to base line for object position type AS_CHAR
+
+ OD 29.07.2003 #110978#
+ Note about values set at member <mnLineAlignment> -
+ value gives feedback for the line formatting.
+ 0 - no feedback; 1|2|3 - proposed formatting of characters
+ at top|at center|at bottom of line.
+*/
+SwTwips SwAsCharAnchoredObjectPosition::GetRelPosToBase(
+ const SwTwips _nObjBoundHeight,
+ const SwFormatVertOrient& _rVert )
+{
+ SwTwips nRelPosToBase = 0;
+
+ mnLineAlignment = sw::LineAlign::NONE;
+
+ const sal_Int16 eVertOrient = _rVert.GetVertOrient();
+
+ if ( eVertOrient == text::VertOrientation::NONE )
+ nRelPosToBase = _rVert.GetPos();
+ else
+ {
+ if ( eVertOrient == text::VertOrientation::CENTER )
+ nRelPosToBase -= _nObjBoundHeight / 2;
+ else if ( eVertOrient == text::VertOrientation::TOP )
+ nRelPosToBase -= _nObjBoundHeight;
+ else if ( eVertOrient == text::VertOrientation::BOTTOM )
+ nRelPosToBase = 0;
+ else if ( eVertOrient == text::VertOrientation::CHAR_CENTER )
+ nRelPosToBase -= ( _nObjBoundHeight + mnLineAscent - mnLineDescent ) / 2;
+ else if ( eVertOrient == text::VertOrientation::CHAR_TOP )
+ nRelPosToBase -= mnLineAscent;
+ else if ( eVertOrient == text::VertOrientation::CHAR_BOTTOM )
+ nRelPosToBase += mnLineDescent - _nObjBoundHeight;
+ else
+ {
+ if( _nObjBoundHeight >= mnLineAscentInclObjs + mnLineDescentInclObjs )
+ {
+ // object is at least as high as the line. Thus, no more is
+ // positioning necessary. Also, the max. ascent isn't changed.
+ nRelPosToBase -= mnLineAscentInclObjs;
+ if ( eVertOrient == text::VertOrientation::LINE_CENTER )
+ mnLineAlignment = sw::LineAlign::CENTER;
+ else if ( eVertOrient == text::VertOrientation::LINE_TOP )
+ mnLineAlignment = sw::LineAlign::TOP;
+ else if ( eVertOrient == text::VertOrientation::LINE_BOTTOM )
+ mnLineAlignment = sw::LineAlign::BOTTOM;
+ }
+ else if ( eVertOrient == text::VertOrientation::LINE_CENTER )
+ {
+ nRelPosToBase -= ( _nObjBoundHeight + mnLineAscentInclObjs - mnLineDescentInclObjs ) / 2;
+ mnLineAlignment = sw::LineAlign::CENTER;
+ }
+ else if ( eVertOrient == text::VertOrientation::LINE_TOP )
+ {
+ nRelPosToBase -= mnLineAscentInclObjs;
+ mnLineAlignment = sw::LineAlign::TOP;
+ }
+ else if ( eVertOrient == text::VertOrientation::LINE_BOTTOM )
+ {
+ nRelPosToBase += mnLineDescentInclObjs - _nObjBoundHeight;
+ mnLineAlignment = sw::LineAlign::BOTTOM;
+ }
+ }
+ }
+
+ return nRelPosToBase;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/objectpositioning/environmentofanchoredobject.cxx b/sw/source/core/objectpositioning/environmentofanchoredobject.cxx
new file mode 100644
index 0000000000..e6529be386
--- /dev/null
+++ b/sw/source/core/objectpositioning/environmentofanchoredobject.cxx
@@ -0,0 +1,99 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <environmentofanchoredobject.hxx>
+#include <frame.hxx>
+#include <pagefrm.hxx>
+#include <osl/diagnose.h>
+
+namespace objectpositioning
+{
+
+SwEnvironmentOfAnchoredObject::SwEnvironmentOfAnchoredObject(
+ const bool _bFollowTextFlow )
+ : mbFollowTextFlow( _bFollowTextFlow )
+{}
+
+/** determine environment layout frame for possible horizontal object positions */
+const SwLayoutFrame& SwEnvironmentOfAnchoredObject::GetHoriEnvironmentLayoutFrame(
+ const SwFrame& _rHoriOrientFrame ) const
+{
+ const SwFrame* pHoriEnvironmentLayFrame = &_rHoriOrientFrame;
+
+ if ( !mbFollowTextFlow )
+ {
+ // No exception any more for page alignment.
+ // the page frame determines the horizontal layout environment.
+ pHoriEnvironmentLayFrame = _rHoriOrientFrame.FindPageFrame();
+ }
+ else
+ {
+ while ( !pHoriEnvironmentLayFrame->IsCellFrame() &&
+ !pHoriEnvironmentLayFrame->IsFlyFrame() &&
+ !pHoriEnvironmentLayFrame->IsPageFrame() )
+ {
+ pHoriEnvironmentLayFrame = pHoriEnvironmentLayFrame->GetUpper();
+ OSL_ENSURE( pHoriEnvironmentLayFrame,
+ "SwEnvironmentOfAnchoredObject::GetHoriEnvironmentLayoutFrame(..) - no page|fly|cell frame found" );
+ }
+ }
+
+ assert( dynamic_cast< const SwLayoutFrame *>( pHoriEnvironmentLayFrame ) &&
+ "SwEnvironmentOfAnchoredObject::GetHoriEnvironmentLayoutFrame(..) - found frame isn't a layout frame" );
+
+ return static_cast<const SwLayoutFrame&>(*pHoriEnvironmentLayFrame);
+}
+
+/** determine environment layout frame for possible vertical object positions */
+const SwLayoutFrame& SwEnvironmentOfAnchoredObject::GetVertEnvironmentLayoutFrame(
+ const SwFrame& _rVertOrientFrame ) const
+{
+ const SwFrame* pVertEnvironmentLayFrame = &_rVertOrientFrame;
+
+ if ( !mbFollowTextFlow )
+ {
+ // No exception any more for page alignment.
+ // the page frame determines the vertical layout environment.
+ pVertEnvironmentLayFrame = _rVertOrientFrame.FindPageFrame();
+ }
+ else
+ {
+ while ( !pVertEnvironmentLayFrame->IsCellFrame() &&
+ !pVertEnvironmentLayFrame->IsFlyFrame() &&
+ !pVertEnvironmentLayFrame->IsHeaderFrame() &&
+ !pVertEnvironmentLayFrame->IsFooterFrame() &&
+ !pVertEnvironmentLayFrame->IsFootnoteFrame() &&
+ !pVertEnvironmentLayFrame->IsPageBodyFrame() &&
+ !pVertEnvironmentLayFrame->IsPageFrame() )
+ {
+ pVertEnvironmentLayFrame = pVertEnvironmentLayFrame->GetUpper();
+ OSL_ENSURE( pVertEnvironmentLayFrame,
+ "SwEnvironmentOfAnchoredObject::GetVertEnvironmentLayoutFrame(..) - proposed frame not found" );
+ }
+ }
+
+ assert( dynamic_cast< const SwLayoutFrame *>( pVertEnvironmentLayFrame ) &&
+ "SwEnvironmentOfAnchoredObject::GetVertEnvironmentLayoutFrame(..) - found frame isn't a layout frame" );
+
+ return static_cast<const SwLayoutFrame&>(*pVertEnvironmentLayFrame);
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
new file mode 100644
index 0000000000..8e4af98b71
--- /dev/null
+++ b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
@@ -0,0 +1,1335 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tocntntanchoredobjectposition.hxx>
+#include <anchoredobject.hxx>
+#include <frame.hxx>
+#include <txtfrm.hxx>
+#include <pagefrm.hxx>
+#include <sectfrm.hxx>
+#include <tabfrm.hxx>
+#include <rootfrm.hxx>
+#include <viewopt.hxx>
+#include <viewsh.hxx>
+#include <frmfmt.hxx>
+#include <fmtsrnd.hxx>
+#include <fmtfsize.hxx>
+#include <fmtanchr.hxx>
+#include <fmtornt.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+#include <svx/svdobj.hxx>
+#include <osl/diagnose.h>
+#include <environmentofanchoredobject.hxx>
+#include <frmatr.hxx>
+#include <fmtwrapinfluenceonobjpos.hxx>
+#include <sortedobjs.hxx>
+#include <textboxhelper.hxx>
+#include <flyfrms.hxx>
+
+using namespace ::com::sun::star;
+
+namespace objectpositioning
+{
+SwToContentAnchoredObjectPosition::SwToContentAnchoredObjectPosition( SdrObject& _rDrawObj )
+ : SwAnchoredObjectPosition ( _rDrawObj ),
+ mpVertPosOrientFrame( nullptr ),
+ mbAnchorToChar ( false ),
+ mpToCharOrientFrame( nullptr ),
+ mpToCharRect( nullptr ),
+ // #i22341#
+ mnToCharTopOfLine( 0 )
+{}
+
+SwToContentAnchoredObjectPosition::~SwToContentAnchoredObjectPosition()
+{}
+
+bool SwToContentAnchoredObjectPosition::IsAnchoredToChar() const
+{
+ return mbAnchorToChar;
+}
+
+const SwFrame* SwToContentAnchoredObjectPosition::ToCharOrientFrame() const
+{
+ return mpToCharOrientFrame;
+}
+
+const SwRect* SwToContentAnchoredObjectPosition::ToCharRect() const
+{
+ return mpToCharRect;
+}
+
+// #i22341#
+SwTwips SwToContentAnchoredObjectPosition::ToCharTopOfLine() const
+{
+ return mnToCharTopOfLine;
+}
+
+SwTextFrame& SwToContentAnchoredObjectPosition::GetAnchorTextFrame() const
+{
+ assert( dynamic_cast<const SwTextFrame*>( &GetAnchorFrame()) &&
+ "SwToContentAnchoredObjectPosition::GetAnchorTextFrame() - wrong anchor frame type" );
+
+ return static_cast<SwTextFrame&>(GetAnchorFrame());
+}
+
+// #i23512#
+static bool lcl_DoesVertPosFits( const SwTwips _nRelPosY,
+ const SwTwips _nAvail,
+ const SwLayoutFrame* _pUpperOfOrientFrame,
+ const bool _bBrowse,
+ const bool _bGrowInTable,
+ SwLayoutFrame*& _orpLayoutFrameToGrow )
+{
+ bool bVertPosFits = false;
+
+ if ( _nRelPosY <= _nAvail )
+ {
+ bVertPosFits = true;
+ }
+ else if ( _bBrowse )
+ {
+ if ( _pUpperOfOrientFrame->IsInSct() )
+ {
+ SwSectionFrame* pSctFrame =
+ const_cast<SwSectionFrame*>(_pUpperOfOrientFrame->FindSctFrame());
+ bVertPosFits = pSctFrame->GetUpper()->Grow( _nRelPosY - _nAvail, true ) > 0;
+ // Note: do not provide a layout frame for a grow.
+ }
+ else
+ {
+ bVertPosFits = const_cast<SwLayoutFrame*>(_pUpperOfOrientFrame)->
+ Grow( _nRelPosY - _nAvail, true ) > 0;
+ if ( bVertPosFits )
+ _orpLayoutFrameToGrow = const_cast<SwLayoutFrame*>(_pUpperOfOrientFrame);
+ }
+ }
+ else if ( _pUpperOfOrientFrame->IsInTab() && _bGrowInTable )
+ {
+ // #i45085# - check, if upper frame would grow the
+ // expected amount of twips.
+ const SwTwips nTwipsGrown = const_cast<SwLayoutFrame*>(_pUpperOfOrientFrame)->
+ Grow( _nRelPosY - _nAvail, true );
+ bVertPosFits = ( nTwipsGrown == ( _nRelPosY - _nAvail ) );
+ if ( bVertPosFits )
+ _orpLayoutFrameToGrow = const_cast<SwLayoutFrame*>(_pUpperOfOrientFrame);
+ }
+
+ return bVertPosFits;
+}
+
+void SwToContentAnchoredObjectPosition::CalcPosition()
+{
+ // get format of object
+ const SwFrameFormat& rFrameFormat = GetFrameFormat();
+
+ // declare and set <pFooter> to footer frame, if object is anchored
+ // at a frame belonging to the footer.
+ const SwFrame* pFooter = GetAnchorFrame().FindFooterOrHeader();
+ if ( pFooter && !pFooter->IsFooterFrame() )
+ pFooter = nullptr;
+
+ // declare and set <bBrowse> to true, if document is in browser mode and
+ // object is anchored at the body, but not at frame belonging to a table.
+ bool bBrowse = GetAnchorFrame().IsInDocBody() && !GetAnchorFrame().IsInTab();
+ if( bBrowse )
+ {
+ const SwViewShell *pSh = GetAnchorFrame().getRootFrame()->GetCurrShell();
+ if( !pSh || !pSh->GetViewOptions()->getBrowseMode() )
+ bBrowse = false;
+ }
+
+ // determine left/right and its upper/lower spacing.
+ const SvxLRSpaceItem &rLR = rFrameFormat.GetLRSpace();
+ const SvxULSpaceItem &rUL = rFrameFormat.GetULSpace();
+
+ // determine, if object has no surrounding.
+ const SwFormatSurround& rSurround = rFrameFormat.GetSurround();
+ const bool bNoSurround = rSurround.GetSurround() == css::text::WrapTextMode_NONE;
+ const bool bWrapThrough = rSurround.GetSurround() == css::text::WrapTextMode_THROUGH;
+
+ // new class <SwEnvironmentOfAnchoredObject>
+ SwEnvironmentOfAnchoredObject aEnvOfObj( DoesObjFollowsTextFlow() );
+
+ // #i18732# - grow only, if object has to follow the text flow
+ const bool bGrow = DoesObjFollowsTextFlow() &&
+ ( !GetAnchorFrame().IsInTab() ||
+ !rFrameFormat.GetFrameSize().GetHeightPercent() );
+
+ // get text frame the object is anchored at
+ const SwTextFrame& rAnchorTextFrame = GetAnchorTextFrame();
+ SwRectFnSet aRectFnSet(&rAnchorTextFrame);
+
+ const SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() );
+
+ // local variable keeping the calculated relative position; initialized with
+ // current relative position.
+ // #i26791# - use new object instance of <SwAnchoredObject>
+ Point aRelPos( GetAnchoredObj().GetCurrRelPos() );
+
+ SwTwips nRelDiff = 0;
+
+ bool bMoveable = rAnchorTextFrame.IsMoveable();
+
+ // determine frame the object position has to be oriented at.
+ const SwTextFrame* pOrientFrame = &rAnchorTextFrame;
+ const SwTextFrame* pAnchorFrameForVertPos;
+ // If true, this means that the anchored object is a split fly frame and it's not a master but
+ // one of the follows.
+ bool bFollowSplitFly = false;
+ // The anchored object is a fly that is allowed to split.
+ bool bSplitFly = false;
+ {
+ // if object is at-character anchored, determine character-rectangle
+ // and frame, position has to be oriented at.
+ mbAnchorToChar = (RndStdIds::FLY_AT_CHAR == rFrameFormat.GetAnchor().GetAnchorId());
+ if ( mbAnchorToChar )
+ {
+ const SwFormatAnchor& rAnch = rFrameFormat.GetAnchor();
+ // #i26791# - use new object instance of <SwAnchoredObject>
+ // Due to table break algorithm the character
+ // rectangle can have no height. Thus, check also the width
+ if ( ( !GetAnchoredObj().GetLastCharRect().Height() &&
+ !GetAnchoredObj().GetLastCharRect().Width() ) ||
+ !GetAnchoredObj().GetLastTopOfLine() )
+ {
+ GetAnchoredObj().CheckCharRectAndTopOfLine( false );
+ // Due to table break algorithm the character
+ // rectangle can have no height. Thus, check also the width
+ if ( ( !GetAnchoredObj().GetLastCharRect().Height() &&
+ !GetAnchoredObj().GetLastCharRect().Width() ) ||
+ !GetAnchoredObj().GetLastTopOfLine() )
+ {
+ // Get default for <mpVertPosOrientFrame>, if it's not set.
+ if ( !mpVertPosOrientFrame )
+ {
+ mpVertPosOrientFrame = rAnchorTextFrame.GetUpper();
+ }
+ return;
+ }
+ }
+ mpToCharRect = &(GetAnchoredObj().GetLastCharRect());
+ // #i22341# - get top of line, in which the anchor character is.
+ mnToCharTopOfLine = GetAnchoredObj().GetLastTopOfLine();
+ pOrientFrame = &(const_cast<SwTextFrame&>(rAnchorTextFrame).GetFrameAtOfst(
+ rAnchorTextFrame.MapModelToViewPos(*rAnch.GetContentAnchor())));
+ mpToCharOrientFrame = pOrientFrame;
+ }
+ else if (SwFlyFrame* pFlyFrame = GetAnchoredObj().DynCastFlyFrame())
+ {
+ // See if this fly is split. If so, then the anchor is also split. All anchors are
+ // empty, except the last follow.
+ if (pFlyFrame->IsFlySplitAllowed())
+ {
+ auto pFlyAtContentFrame = static_cast<SwFlyAtContentFrame*>(pFlyFrame);
+ // Decrement pFly to point to the master; increment pAnchor to point to the correct
+ // follow anchor.
+ SwFlyAtContentFrame* pFly = pFlyAtContentFrame;
+ SwTextFrame* pAnchor = const_cast<SwTextFrame*>(&rAnchorTextFrame);
+ while (pFly->GetPrecede())
+ {
+ pFly = pFly->GetPrecede();
+ if (!pAnchor)
+ {
+ SAL_WARN("sw.core", "SwToContentAnchoredObjectPosition::CalcPosition: fly "
+ "chain length is longer then anchor chain length");
+ break;
+ }
+ pAnchor = pAnchor->GetFollow();
+ }
+ if (pAnchor && pAnchor->GetPrecede())
+ {
+ pOrientFrame = pAnchor;
+ // Anchored object has a precede, so it's a follow.
+ bFollowSplitFly = true;
+ }
+ bSplitFly = true;
+ }
+ }
+ }
+ aRectFnSet.Refresh(pOrientFrame);
+
+ // determine vertical position
+ {
+
+ // determine vertical positioning and alignment attributes
+ SwFormatVertOrient aVert( rFrameFormat.GetVertOrient() );
+
+ // #i18732# - determine layout frame for vertical
+ // positions aligned to 'page areas'.
+ const SwLayoutFrame& rPageAlignLayFrame =
+ aEnvOfObj.GetVertEnvironmentLayoutFrame( *pOrientFrame );
+
+ if ( aVert.GetVertOrient() != text::VertOrientation::NONE )
+ {
+ // #i18732# - adjustments for follow text flow or not
+ // AND vertical alignment at 'page areas'.
+ SwTwips nAlignAreaHeight;
+ SwTwips nAlignAreaOffset;
+ GetVertAlignmentValues( *pOrientFrame, rPageAlignLayFrame,
+ aVert.GetRelationOrient(),
+ nAlignAreaHeight, nAlignAreaOffset );
+
+ SwRect aHeaderRect;
+ const SwPageFrame* aPageFrame = pOrientFrame->FindPageFrame();
+ const SwHeaderFrame* pHeaderFrame = aPageFrame->GetHeaderFrame();
+ if (pHeaderFrame)
+ aHeaderRect = pHeaderFrame->GetPaintArea();
+ const SwTwips nTopMarginHeight = aPageFrame->GetTopMargin() + aHeaderRect.Height();
+ const SwTwips nHeightBetweenOffsetAndMargin = nAlignAreaOffset + nTopMarginHeight;
+
+ // determine relative vertical position
+ SwTwips nRelPosY = nAlignAreaOffset;
+ const SwTwips nObjHeight = aRectFnSet.GetHeight(aObjBoundRect);
+ const SwTwips nUpperSpace = aRectFnSet.IsVert()
+ ? ( aRectFnSet.IsVertL2R()
+ ? rLR.GetLeft()
+ : rLR.GetRight() )
+ : rUL.GetUpper();
+ // --> OD 2009-08-31 #monglianlayout#
+ const SwTwips nLowerSpace = aRectFnSet.IsVert()
+ ? ( aRectFnSet.IsVertL2R()
+ ? rLR.GetLeft()
+ : rLR.GetRight() )
+ : rUL.GetLower();
+ switch ( aVert.GetVertOrient() )
+ {
+ case text::VertOrientation::CHAR_BOTTOM:
+ {
+ if ( mbAnchorToChar )
+ {
+ // bottom (to character anchored)
+ nRelPosY += nAlignAreaHeight + nUpperSpace;
+ if ( aRectFnSet.IsVert() && !aRectFnSet.IsVertL2R() )
+ {
+ nRelPosY += nObjHeight;
+ }
+ break;
+ }
+ [[fallthrough]];
+ }
+ case text::VertOrientation::TOP:
+ {
+ // #i22341# - special case for vertical
+ // alignment at top of line
+ if ( mbAnchorToChar &&
+ aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
+ {
+ nRelPosY -= (nObjHeight + nLowerSpace);
+ }
+ else
+ {
+ nRelPosY += nUpperSpace;
+ }
+ }
+ break;
+ // #i22341#
+ case text::VertOrientation::LINE_TOP:
+ {
+ if ( mbAnchorToChar &&
+ aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
+ {
+ nRelPosY -= (nObjHeight + nLowerSpace);
+ }
+ else
+ {
+ OSL_FAIL( "<SwToContentAnchoredObjectPosition::CalcPosition()> - unknown combination of vertical position and vertical alignment." );
+ }
+ }
+ break;
+ case text::VertOrientation::CENTER:
+ {
+ if (aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA_TOP)
+ nRelPosY = (nAlignAreaOffset / 2) - (nObjHeight / 2) + (nHeightBetweenOffsetAndMargin / 2);
+ else
+ nRelPosY += (nAlignAreaHeight / 2) - (nObjHeight / 2);
+ }
+ break;
+ // #i22341#
+ case text::VertOrientation::LINE_CENTER:
+ {
+ if ( mbAnchorToChar &&
+ aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
+ {
+ nRelPosY += (nAlignAreaHeight / 2) - (nObjHeight / 2);
+ }
+ else
+ {
+ OSL_FAIL( "<SwToContentAnchoredObjectPosition::CalcPosition()> - unknown combination of vertical position and vertical alignment." );
+ }
+ }
+ break;
+ case text::VertOrientation::BOTTOM:
+ {
+ if ( ( aVert.GetRelationOrient() == text::RelOrientation::FRAME ||
+ aVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ) &&
+ bNoSurround )
+ {
+ // bottom (aligned to 'paragraph areas')
+ nRelPosY += nAlignAreaHeight + nUpperSpace;
+ }
+ else
+ {
+ // #i22341# - special case for vertical
+ // alignment at top of line
+ if ( mbAnchorToChar &&
+ aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
+ {
+ nRelPosY += nUpperSpace;
+ }
+ else
+ {
+ if (aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA_TOP)
+ nRelPosY = 0 - (nObjHeight + nLowerSpace) + nHeightBetweenOffsetAndMargin;
+ else
+ nRelPosY += nAlignAreaHeight - (nObjHeight + nLowerSpace);
+ }
+ }
+ }
+ break;
+ // #i22341#
+ case text::VertOrientation::LINE_BOTTOM:
+ {
+ if ( mbAnchorToChar &&
+ aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE )
+ {
+ nRelPosY += nUpperSpace;
+ }
+ else
+ {
+ OSL_FAIL( "<SwToContentAnchoredObjectPosition::CalcPosition()> - unknown combination of vertical position and vertical alignment." );
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ // adjust relative position by distance between anchor frame and
+ // the frame, the object is oriented at.
+ // #i28701# - correction: adjust relative position,
+ // only if the floating screen object has to follow the text flow.
+ // Also don't do this for split flys: pOrientFrame already points to the follow anchor,
+ // so pOrientFrame is not the anchor text frame anymore, and that would lead to an
+ // additional, unwanted increase of nRelPosY.
+ if (DoesObjFollowsTextFlow() && pOrientFrame != &rAnchorTextFrame && !bFollowSplitFly)
+ {
+ // #i11860# - use new method <GetTopForObjPos>
+ // to get top of frame for object positioning.
+ const SwTwips nTopOfOrient = GetTopForObjPos( *pOrientFrame, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
+ nRelPosY += aRectFnSet.YDiff( nTopOfOrient,
+ GetTopForObjPos( rAnchorTextFrame, aRectFnSet.FnRect(), aRectFnSet.IsVert() ) );
+ }
+
+ // #i42124# - capture object inside vertical
+ // layout environment.
+ {
+ const SwTwips nTopOfAnch =
+ GetTopForObjPos( *pOrientFrame, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
+ const SwLayoutFrame& rVertEnvironLayFrame =
+ aEnvOfObj.GetVertEnvironmentLayoutFrame(
+ *(pOrientFrame->GetUpper()) );
+ const bool bCheckBottom = !DoesObjFollowsTextFlow();
+ nRelPosY = AdjustVertRelPos( nTopOfAnch, aRectFnSet.IsVert(), aRectFnSet.IsVertL2R(),
+ rVertEnvironLayFrame, nRelPosY,
+ DoesObjFollowsTextFlow(),
+ bCheckBottom );
+ }
+
+ // keep calculated relative vertical position - needed for filters
+ // (including the xml-filter)
+ {
+ // determine position
+ SwTwips nAttrRelPosY = nRelPosY - nAlignAreaOffset;
+ // set
+ if ( nAttrRelPosY != aVert.GetPos() )
+ {
+ aVert.SetPos( nAttrRelPosY );
+ const_cast<SwFrameFormat&>(rFrameFormat).LockModify();
+ const_cast<SwFrameFormat&>(rFrameFormat).SetFormatAttr( aVert );
+ const_cast<SwFrameFormat&>(rFrameFormat).UnlockModify();
+ }
+ }
+
+ // determine absolute 'vertical' position, depending on layout-direction
+ // #i26791# - determine offset to 'vertical' frame
+ // anchor position, depending on layout-direction
+ if ( aRectFnSet.IsVert() )
+ {
+ aRelPos.setX( nRelPosY );
+ maOffsetToFrameAnchorPos.setX( nAlignAreaOffset );
+ }
+ else
+ {
+ aRelPos.setY( nRelPosY );
+ maOffsetToFrameAnchorPos.setY( nAlignAreaOffset );
+ }
+ }
+
+ // Determine upper of frame vertical position is oriented at.
+ // #i28701# - determine 'virtual' anchor frame.
+ // This frame is used in the following instead of the 'real' anchor
+ // frame <rAnchorTextFrame> for the 'vertical' position in all cases.
+ const SwLayoutFrame* pUpperOfOrientFrame = nullptr;
+ {
+ // #i28701# - As long as the anchor frame is on the
+ // same page as <pOrientFrame> and the vertical position isn't aligned
+ // automatic at the anchor character or the top of the line of the
+ // anchor character, the anchor frame determines the vertical position.
+ // Split fly follows: always let the anchor char frame determine the vertical position.
+ // This gives us a vertical cut position between the master and the follow.
+ if ( &rAnchorTextFrame == pOrientFrame ||
+ ( rAnchorTextFrame.FindPageFrame() == pOrientFrame->FindPageFrame() &&
+ aVert.GetVertOrient() == text::VertOrientation::NONE &&
+ aVert.GetRelationOrient() != text::RelOrientation::CHAR &&
+ aVert.GetRelationOrient() != text::RelOrientation::TEXT_LINE && !bFollowSplitFly ) )
+ {
+ pUpperOfOrientFrame = rAnchorTextFrame.GetUpper();
+ pAnchorFrameForVertPos = &rAnchorTextFrame;
+ }
+ else
+ {
+ pUpperOfOrientFrame = pOrientFrame->GetUpper();
+ pAnchorFrameForVertPos = pOrientFrame;
+ }
+ }
+
+ // ignore one-column sections.
+ // #i23512# - correction: also ignore one-columned
+ // sections with footnotes/endnotes
+ if ( pUpperOfOrientFrame->IsInSct() )
+ {
+ const SwSectionFrame* pSctFrame = pUpperOfOrientFrame->FindSctFrame();
+ const bool bIgnoreSection = pUpperOfOrientFrame->IsSctFrame() ||
+ ( pSctFrame->Lower()->IsColumnFrame() &&
+ !pSctFrame->Lower()->GetNext() );
+ if ( bIgnoreSection )
+ pUpperOfOrientFrame = pSctFrame->GetUpper();
+ }
+
+ if ( aVert.GetVertOrient() == text::VertOrientation::NONE )
+ {
+ // local variable <nRelPosY> for calculation of relative vertical
+ // distance to anchor.
+ SwTwips nRelPosY = 0;
+ // #i26791# - local variable <nVertOffsetToFrameAnchorPos>
+ // for determination of the 'vertical' offset to the frame anchor
+ // position
+ SwTwips nVertOffsetToFrameAnchorPos( 0 );
+ // #i22341# - add special case for vertical alignment
+ // at top of line.
+ if ( mbAnchorToChar &&
+ ( aVert.GetRelationOrient() == text::RelOrientation::CHAR ||
+ aVert.GetRelationOrient() == text::RelOrientation::TEXT_LINE ) )
+ {
+ // #i11860# - use new method <GetTopForObjPos>
+ // to get top of frame for object positioning.
+ SwTwips nTopOfOrient = GetTopForObjPos( *pOrientFrame, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
+ if ( aVert.GetRelationOrient() == text::RelOrientation::CHAR )
+ {
+ nVertOffsetToFrameAnchorPos = aRectFnSet.YDiff(
+ aRectFnSet.GetBottom(*ToCharRect()),
+ nTopOfOrient );
+ }
+ else
+ {
+ nVertOffsetToFrameAnchorPos = aRectFnSet.YDiff( ToCharTopOfLine(),
+ nTopOfOrient );
+ }
+ nRelPosY = nVertOffsetToFrameAnchorPos - aVert.GetPos();
+ }
+ else
+ {
+ // #i28701# - correction: use <pAnchorFrameForVertPos>
+ // instead of <pOrientFrame> and do not adjust relative position
+ // to get correct vertical position.
+ nVertOffsetToFrameAnchorPos = 0;
+ // #i11860# - use new method <GetTopForObjPos>
+ // to get top of frame for object positioning.
+ const SwTwips nTopOfOrient =
+ GetTopForObjPos( *pAnchorFrameForVertPos, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
+ // Increase <nRelPosY> by margin height,
+ // if position is vertical aligned to "paragraph text area"
+ if ( aVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA )
+ {
+ // #i11860# - consider upper space amount of previous frame
+ SwTwips nTopMargin = aRectFnSet.GetTopMargin(*pAnchorFrameForVertPos);
+ if ( pAnchorFrameForVertPos->IsTextFrame() )
+ {
+ nTopMargin -= pAnchorFrameForVertPos->
+ GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid();
+ }
+ nVertOffsetToFrameAnchorPos += nTopMargin;
+ }
+ // #i18732# - adjust <nRelPosY> by difference
+ // between 'page area' and 'anchor' frame, if position is
+ // vertical aligned to 'page areas'
+ else if (aVert.GetRelationOrient() == text::RelOrientation::PAGE_FRAME
+ || aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA_TOP)
+ {
+ nVertOffsetToFrameAnchorPos += aRectFnSet.YDiff(
+ aRectFnSet.GetTop(rPageAlignLayFrame.getFrameArea()),
+ nTopOfOrient );
+ }
+ else if ( aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA )
+ {
+ SwRect aPgPrtRect( rPageAlignLayFrame.getFrameArea() );
+ if ( rPageAlignLayFrame.IsPageFrame() )
+ {
+ aPgPrtRect =
+ static_cast<const SwPageFrame&>(rPageAlignLayFrame).PrtWithoutHeaderAndFooter();
+ }
+ nVertOffsetToFrameAnchorPos += aRectFnSet.YDiff(
+ aRectFnSet.GetTop(aPgPrtRect),
+ nTopOfOrient );
+ }
+ else if (aVert.GetRelationOrient() == text::RelOrientation::PAGE_PRINT_AREA_BOTTOM)
+ {
+ // The anchored object is relative from the bottom of the page's print area.
+ SwRect aPgPrtRect(rPageAlignLayFrame.getFrameArea());
+ if (rPageAlignLayFrame.IsPageFrame())
+ {
+ auto& rPageFrame = static_cast<const SwPageFrame&>(rPageAlignLayFrame);
+ aPgPrtRect = rPageFrame.PrtWithoutHeaderAndFooter();
+ }
+ SwTwips nPageBottom = aRectFnSet.GetBottom(aPgPrtRect);
+ nVertOffsetToFrameAnchorPos += aRectFnSet.YDiff(nPageBottom, nTopOfOrient);
+ }
+ nRelPosY = nVertOffsetToFrameAnchorPos + aVert.GetPos();
+ if (bFollowSplitFly)
+ {
+ // This is a follow of a split fly: shift it up to match the anchor position,
+ // because the vertical offset is meant to be handled only on the first page.
+ nRelPosY -= aVert.GetPos();
+
+ if (aVert.GetRelationOrient() == text::RelOrientation::PAGE_FRAME
+ && rPageAlignLayFrame.IsPageFrame())
+ {
+ // Master is positioned relative to the edge of the page, with an offset.
+ // Follow will have no offset, but is relative to the bottom of the header.
+ auto& rPageFrame = static_cast<const SwPageFrame&>(rPageAlignLayFrame);
+ const SwLayoutFrame* pBodyFrame = rPageFrame.FindBodyCont();
+ if (pBodyFrame)
+ {
+ SwTwips nDiff = pBodyFrame->getFrameArea().Top()
+ - rPageFrame.getFrameArea().Top();
+ nRelPosY += nDiff;
+ }
+ }
+ }
+ }
+
+ // <pUpperOfOrientFrame>: layout frame, at which the position has to
+ // is oriented at
+ // <nRelPosY>: rest of the relative distance in the current
+ // layout frame
+ // <nAvail>: space, which is available in the current
+ // layout frame
+
+ // #i26791# - determine offset to 'vertical'
+ // frame anchor position, depending on layout-direction
+ if ( aRectFnSet.IsVert() )
+ maOffsetToFrameAnchorPos.setX( nVertOffsetToFrameAnchorPos );
+ else
+ maOffsetToFrameAnchorPos.setY( nVertOffsetToFrameAnchorPos );
+ // #i11860# - use new method <GetTopForObjPos>
+ // to get top of frame for object positioning.
+ const SwTwips nTopOfAnch = GetTopForObjPos( *pAnchorFrameForVertPos, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
+ if( nRelPosY <= 0 )
+ {
+ // Allow negative position, but keep it
+ // inside environment layout frame.
+ const SwLayoutFrame& rVertEnvironLayFrame =
+ aEnvOfObj.GetVertEnvironmentLayoutFrame( *pUpperOfOrientFrame );
+ // #i31805# - do not check, if bottom of
+ // anchored object would fit into environment layout frame, if
+ // anchored object has to follow the text flow.
+ const bool bCheckBottom = !DoesObjFollowsTextFlow();
+ nRelPosY = AdjustVertRelPos( nTopOfAnch, aRectFnSet.IsVert(), aRectFnSet.IsVertL2R(),
+ rVertEnvironLayFrame, nRelPosY,
+ DoesObjFollowsTextFlow(),
+ bCheckBottom );
+ if ( aRectFnSet.IsVert() )
+ aRelPos.setX( nRelPosY );
+ else
+ aRelPos.setY( nRelPosY );
+ }
+ else
+ {
+ aRectFnSet.Refresh(pAnchorFrameForVertPos);
+ SwTwips nAvail =
+ aRectFnSet.YDiff( aRectFnSet.GetPrtBottom(*pUpperOfOrientFrame),
+ nTopOfAnch );
+ const bool bInFootnote = pAnchorFrameForVertPos->IsInFootnote();
+ while ( nRelPosY )
+ {
+ // #i23512# - correction:
+ // consider section frame for grow in online layout.
+ // use new local method <lcl_DoesVertPosFits(..)>
+ SwLayoutFrame* pLayoutFrameToGrow = nullptr;
+ const bool bDoesVertPosFits = lcl_DoesVertPosFits(
+ nRelPosY, nAvail, pUpperOfOrientFrame, bBrowse,
+ bGrow, pLayoutFrameToGrow );
+
+ if ( bDoesVertPosFits )
+ {
+ SwTwips nTmpRelPosY =
+ aRectFnSet.YDiff( aRectFnSet.GetPrtBottom(*pUpperOfOrientFrame),
+ nTopOfAnch ) -
+ nAvail + nRelPosY;
+ // #i28701# - adjust calculated
+ // relative vertical position to object's environment.
+ const SwFrame& rVertEnvironLayFrame =
+ aEnvOfObj.GetVertEnvironmentLayoutFrame( *pUpperOfOrientFrame );
+ // Do not check, if bottom of
+ // anchored object would fit into environment layout
+ // frame, if anchored object has to follow the text flow.
+ const bool bCheckBottom = !DoesObjFollowsTextFlow();
+ nTmpRelPosY = AdjustVertRelPos( nTopOfAnch, aRectFnSet.IsVert(), aRectFnSet.IsVertL2R(),
+ rVertEnvironLayFrame,
+ nTmpRelPosY,
+ DoesObjFollowsTextFlow(),
+ bCheckBottom );
+ if ( aRectFnSet.IsVert() )
+ aRelPos.setX( nTmpRelPosY );
+ else
+ aRelPos.setY( nTmpRelPosY );
+
+ // #i23512# - use local variable
+ // <pLayoutFrameToGrow> provided by new method
+ // <lcl_DoesVertPosFits(..)>.
+ if ( pLayoutFrameToGrow )
+ {
+ // No need to grow the anchor cell in case the follow-text-flow object
+ // is wrap-though.
+ if (!GetAnchorFrame().IsInTab() || !DoesObjFollowsTextFlow() || !bWrapThrough)
+ {
+ pLayoutFrameToGrow->Grow( nRelPosY - nAvail );
+ }
+ }
+ nRelPosY = 0;
+ }
+ else
+ {
+ // #i26495# - floating screen objects,
+ // which are anchored inside a table, doesn't follow
+ // the text flow.
+ if ( DoesObjFollowsTextFlow() &&
+ ( aVert.GetRelationOrient() != text::RelOrientation::PAGE_FRAME &&
+ aVert.GetRelationOrient() != text::RelOrientation::PAGE_PRINT_AREA ) &&
+ !GetAnchorFrame().IsInTab() )
+ {
+ if ( bMoveable )
+ {
+ // follow the text flow
+ nRelPosY -= nAvail;
+ MakePageType eMakePage = bInFootnote ? MAKEPAGE_NONE
+ : MAKEPAGE_APPEND;
+ const bool bInSct = pUpperOfOrientFrame->IsInSct();
+ if( bInSct )
+ eMakePage = MAKEPAGE_NOSECTION;
+
+ const SwLayoutFrame* pTmp =
+ pUpperOfOrientFrame->GetLeaf( eMakePage, true, &rAnchorTextFrame );
+ if ( pTmp &&
+ ( !bInSct ||
+ pUpperOfOrientFrame->FindSctFrame()->IsAnFollow( pTmp->FindSctFrame() ) ) )
+ {
+ pUpperOfOrientFrame = pTmp;
+ bMoveable = rAnchorTextFrame.IsMoveable( pUpperOfOrientFrame );
+ aRectFnSet.Refresh(pUpperOfOrientFrame);
+ nAvail = aRectFnSet.GetHeight(pUpperOfOrientFrame->getFramePrintArea());
+ }
+ else
+ {
+ // if there isn't enough space in the (columned)
+ // section, leave it and set available space <nAvail>
+ // to the space below the section.
+ // if the new available space isn't also enough,
+ // new pages can be created.
+ if( bInSct )
+ {
+ const SwFrame* pSct = pUpperOfOrientFrame->FindSctFrame();
+ pUpperOfOrientFrame = pSct->GetUpper();
+ nAvail = aRectFnSet.YDiff(
+ aRectFnSet.GetPrtBottom(*pUpperOfOrientFrame),
+ aRectFnSet.GetPrtBottom(*pSct) );
+ }
+ else
+ {
+#if OSL_DEBUG_LEVEL > 1
+ OSL_FAIL( "<SwToContentAnchoredObjectPosition::CalcPosition()> - !bInSct" );
+#endif
+ nRelDiff = nRelPosY;
+ nRelPosY = 0;
+ }
+ }
+ }
+ else
+ {
+ nRelPosY = 0;
+ }
+ }
+ else
+ {
+ // #i18732# - do not follow text flow respectively
+ // align at 'page areas', but stay inside given environment
+ const SwFrame& rVertEnvironLayFrame =
+ aEnvOfObj.GetVertEnvironmentLayoutFrame( *pUpperOfOrientFrame );
+ nRelPosY = AdjustVertRelPos( nTopOfAnch, aRectFnSet.IsVert(), aRectFnSet.IsVertL2R(),
+ rVertEnvironLayFrame,
+ nRelPosY,
+ DoesObjFollowsTextFlow() );
+ if( aRectFnSet.IsVert() )
+ aRelPos.setX( nRelPosY );
+ else
+ aRelPos.setY( nRelPosY );
+ nRelPosY = 0;
+ }
+ }
+ } // end of <while ( nRelPosY )>
+ } // end of else <nRelPosY <= 0>
+ } // end of <aVert.GetVertOrient() == text::VertOrientation::NONE>
+
+ // We need to calculate the part's absolute position, in order for
+ // it to be put onto the right page and to be pulled into the
+ // LayLeaf's PrtArea
+ const SwTwips nTopOfAnch = GetTopForObjPos( *pAnchorFrameForVertPos, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
+ if( aRectFnSet.IsVert() )
+ {
+ // --> OD 2009-08-31 #monglianlayout#
+ if ( !aRectFnSet.IsVertL2R() )
+ {
+ GetAnchoredObj().SetObjLeft( nTopOfAnch -
+ ( aRelPos.X() - nRelDiff ) -
+ aObjBoundRect.Width() );
+ }
+ else
+ {
+ GetAnchoredObj().SetObjLeft( nTopOfAnch +
+ ( aRelPos.X() - nRelDiff ) );
+ }
+ }
+ else
+ {
+ GetAnchoredObj().SetObjTop( nTopOfAnch +
+ ( aRelPos.Y() - nRelDiff ) );
+ }
+
+ // grow environment under certain conditions
+ // ignore one-column sections.
+ // #i23512# - correction: also ignore one-columned
+ // sections with footnotes/endnotes
+ if ( pUpperOfOrientFrame->IsInSct() )
+ {
+ const SwSectionFrame* pSctFrame = pUpperOfOrientFrame->FindSctFrame();
+ const bool bIgnoreSection = pUpperOfOrientFrame->IsSctFrame() ||
+ ( pSctFrame->Lower()->IsColumnFrame() &&
+ !pSctFrame->Lower()->GetNext() );
+ if ( bIgnoreSection )
+ pUpperOfOrientFrame = pSctFrame->GetUpper();
+ }
+ SwTwips nDist = aRectFnSet.BottomDist( GetAnchoredObj().GetObjRect(),
+ aRectFnSet.GetPrtBottom(*pUpperOfOrientFrame) );
+ if( nDist < 0 )
+ {
+ // #i23512# - correction:
+ // consider section frame for grow in online layout and
+ // consider page alignment for grow in table.
+ SwLayoutFrame* pLayoutFrameToGrow = nullptr;
+ if ( bBrowse && rAnchorTextFrame.IsMoveable() )
+ {
+ if ( pUpperOfOrientFrame->IsInSct() )
+ {
+ pLayoutFrameToGrow = const_cast<SwLayoutFrame*>(
+ pUpperOfOrientFrame->FindSctFrame()->GetUpper());
+ nDist = aRectFnSet.BottomDist( GetAnchoredObj().GetObjRect(),
+ aRectFnSet.GetPrtBottom(*pLayoutFrameToGrow) );
+ if ( nDist >= 0 )
+ {
+ pLayoutFrameToGrow = nullptr;
+ }
+ }
+ else
+ {
+ pLayoutFrameToGrow =
+ const_cast<SwLayoutFrame*>(pUpperOfOrientFrame);
+ }
+ }
+ else if ( rAnchorTextFrame.IsInTab() && bGrow )
+ {
+ pLayoutFrameToGrow = const_cast<SwLayoutFrame*>(pUpperOfOrientFrame);
+ }
+ if ( pLayoutFrameToGrow )
+ {
+ // No need to grow the anchor cell in case the follow-text-flow object
+ // is wrap-though.
+ if (!GetAnchorFrame().IsInTab() || !DoesObjFollowsTextFlow() || !bWrapThrough)
+ {
+ pLayoutFrameToGrow->Grow( -nDist );
+ }
+ }
+ }
+
+ if ( DoesObjFollowsTextFlow() &&
+ ( aVert.GetRelationOrient() != text::RelOrientation::PAGE_FRAME &&
+ aVert.GetRelationOrient() != text::RelOrientation::PAGE_PRINT_AREA ) )
+ {
+
+ nDist = aRectFnSet.BottomDist( GetAnchoredObj().GetObjRect(),
+ aRectFnSet.GetPrtBottom(*pUpperOfOrientFrame) );
+ // #i26945# - floating screen objects, which are
+ // anchored inside a table, doesn't follow the text flow. But, they
+ // have to stay inside its layout environment.
+ if ( nDist < 0 && pOrientFrame->IsInTab() )
+ {
+ // If the anchor frame is the first content of the table cell
+ // and has no follow, the table frame is notified,
+ // that the object doesn't fit into the table cell.
+ // Adjustment of position isn't needed in this case.
+ if ( pOrientFrame == &rAnchorTextFrame &&
+ !pOrientFrame->GetFollow() &&
+ !pOrientFrame->GetIndPrev() )
+ {
+ const_cast<SwTabFrame*>(pOrientFrame->FindTabFrame())
+ ->SetDoesObjsFit( false );
+ }
+ else
+ {
+ SwTwips nTmpRelPosY( 0 );
+ if ( aRectFnSet.IsVert() )
+ nTmpRelPosY = aRelPos.X() - nDist;
+ else
+ nTmpRelPosY = aRelPos.Y() + nDist;
+ const SwLayoutFrame& rVertEnvironLayFrame =
+ aEnvOfObj.GetVertEnvironmentLayoutFrame( *pUpperOfOrientFrame );
+ nTmpRelPosY = AdjustVertRelPos( nTopOfAnch, aRectFnSet.IsVert(), aRectFnSet.IsVertL2R(),
+ rVertEnvironLayFrame,
+ nTmpRelPosY,
+ DoesObjFollowsTextFlow(),
+ false );
+ if ( aRectFnSet.IsVert() )
+ {
+ aRelPos.setX( nTmpRelPosY );
+ // --> OD 2009-08-31 #mongolianlayout#
+ if ( !aRectFnSet.IsVertL2R() )
+ {
+ GetAnchoredObj().SetObjLeft( nTopOfAnch -
+ aRelPos.X() -
+ aObjBoundRect.Width() );
+ }
+ else
+ {
+ GetAnchoredObj().SetObjLeft( nTopOfAnch + aRelPos.X() );
+ }
+ }
+ else
+ {
+ aRelPos.setY( nTmpRelPosY );
+ GetAnchoredObj().SetObjTop( nTopOfAnch + aRelPos.Y() );
+ }
+ // If the anchor frame is the first content of the table cell
+ // and the object still doesn't fit, the table frame is notified,
+ // that the object doesn't fit into the table cell.
+ nDist = aRectFnSet.BottomDist( GetAnchoredObj().GetObjRect(),
+ aRectFnSet.GetPrtBottom(*pUpperOfOrientFrame) );
+ if ( nDist < 0 &&
+ pOrientFrame == &rAnchorTextFrame && !pOrientFrame->GetIndPrev() )
+ {
+ const_cast<SwTabFrame*>(pOrientFrame->FindTabFrame())
+ ->SetDoesObjsFit( false );
+ }
+ }
+ }
+ // Don't move split flys around for follow text flow purposes; if they don't fit their
+ // parent anymore, they will shrink and part of the content will move to the follow fly.
+ else if (!bSplitFly)
+ {
+ // follow text flow
+ const bool bInFootnote = rAnchorTextFrame.IsInFootnote();
+ while( bMoveable && nDist < 0 )
+ {
+ bool bInSct = pUpperOfOrientFrame->IsInSct();
+ if ( bInSct )
+ {
+ const SwLayoutFrame* pTmp = pUpperOfOrientFrame->FindSctFrame()->GetUpper();
+ nDist = aRectFnSet.BottomDist( GetAnchoredObj().GetObjRect(),
+ aRectFnSet.GetPrtBottom(*pTmp) );
+ // #i23129# - Try to flow into next
+ // section|section column. Thus, do *not* leave section
+ // area, if anchored object doesn't fit into upper of section.
+ // But the anchored object is allowed to overlap bottom
+ // section|section column.
+ if ( nDist >= 0 )
+ {
+ break;
+ }
+ }
+ if ( !bInSct &&
+ aRectFnSet.GetTop(GetAnchoredObj().GetObjRect()) ==
+ aRectFnSet.GetPrtTop(*pUpperOfOrientFrame) )
+ // It doesn't fit, moving it would not help either anymore
+ break;
+
+ const SwLayoutFrame* pNextLay = pUpperOfOrientFrame->GetLeaf(
+ ( bInSct
+ ? MAKEPAGE_NOSECTION
+ : ( bInFootnote ? MAKEPAGE_NONE : MAKEPAGE_APPEND ) ),
+ true, &rAnchorTextFrame );
+ // correction:
+ // If anchor is in footnote and proposed next layout environment
+ // isn't a footnote frame, object can't follow the text flow
+ if ( bInFootnote && pNextLay && !pNextLay->IsFootnoteFrame() )
+ {
+ pNextLay = nullptr;
+ }
+ if ( pNextLay )
+ {
+ SwRectFnSet fnRectX(pNextLay);
+ if ( !bInSct ||
+ ( pUpperOfOrientFrame->FindSctFrame()->IsAnFollow( pNextLay->FindSctFrame() ) &&
+ fnRectX.GetHeight(pNextLay->getFramePrintArea()) ) )
+ {
+ SwTwips nTmpRelPosY =
+ aRectFnSet.YDiff( aRectFnSet.GetPrtTop(*pNextLay),
+ nTopOfAnch );
+ if ( aRectFnSet.IsVert() )
+ aRelPos.setX( nTmpRelPosY );
+ else
+ aRelPos.setY( nTmpRelPosY );
+ pUpperOfOrientFrame = pNextLay;
+ aRectFnSet.Refresh(pUpperOfOrientFrame);
+ bMoveable = rAnchorTextFrame.IsMoveable( pUpperOfOrientFrame );
+ if( fnRectX.IsVert() )
+ {
+ // --> OD 2009-08-31 #mongolianlayout#
+ if ( !aRectFnSet.IsVertL2R() )
+ {
+ GetAnchoredObj().SetObjLeft( nTopOfAnch -
+ aRelPos.X() -
+ aObjBoundRect.Width() );
+ }
+ else
+ {
+ GetAnchoredObj().SetObjLeft( nTopOfAnch +
+ aRelPos.X() );
+ }
+ }
+ else
+ GetAnchoredObj().SetObjTop( nTopOfAnch +
+ aRelPos.Y() );
+ nDist = aRectFnSet.BottomDist( GetAnchoredObj().GetObjRect(),
+ aRectFnSet.GetPrtBottom(*pUpperOfOrientFrame) );
+ }
+ // #i23129# - leave section area
+ else if ( bInSct )
+ {
+ const SwLayoutFrame* pTmp = pUpperOfOrientFrame->FindSctFrame()->GetUpper();
+ nDist = aRectFnSet.BottomDist( GetAnchoredObj().GetObjRect(),
+ aRectFnSet.GetPrtBottom(*pTmp) );
+ if( nDist < 0 )
+ pUpperOfOrientFrame = pTmp;
+ else
+ break;
+ }
+ }
+ else if ( bInSct )
+ {
+ // If we don't have enough room within the Area, we take a look at
+ // the Page
+ const SwLayoutFrame* pTmp = pUpperOfOrientFrame->FindSctFrame()->GetUpper();
+ nDist = aRectFnSet.BottomDist( GetAnchoredObj().GetObjRect(),
+ aRectFnSet.GetPrtBottom(*pTmp) );
+ if( nDist < 0 )
+ pUpperOfOrientFrame = pTmp;
+ else
+ break;
+ }
+ else
+ bMoveable = false;
+ }
+ }
+ }
+
+ // keep layout frame vertical position is oriented at.
+ mpVertPosOrientFrame = pUpperOfOrientFrame;
+
+ // If it was requested to not overlap with already formatted objects, take care of that
+ // here.
+ CalcOverlap(pAnchorFrameForVertPos, aRelPos, nTopOfAnch);
+ }
+
+ // determine 'horizontal' position
+ {
+ // determine horizontal positioning and alignment attributes
+ SwFormatHoriOrient aHori( rFrameFormat.GetHoriOrient() );
+
+ // set calculated vertical position in order to determine correct
+ // frame, the horizontal position is oriented at.
+ const SwTwips nTopOfAnch = GetTopForObjPos( *pAnchorFrameForVertPos, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
+ if( aRectFnSet.IsVert() )
+ {
+ // --> OD 2009-08-31 #mongolianlayout#
+ if ( !aRectFnSet.IsVertL2R() )
+ {
+ GetAnchoredObj().SetObjLeft( nTopOfAnch -
+ aRelPos.X() - aObjBoundRect.Width() );
+ }
+ else
+ {
+ GetAnchoredObj().SetObjLeft( nTopOfAnch + aRelPos.X() );
+ }
+ }
+ else
+ GetAnchoredObj().SetObjTop( nTopOfAnch + aRelPos.Y() );
+
+ // determine frame, horizontal position is oriented at.
+ // #i28701# - If floating screen object doesn't follow
+ // the text flow, its horizontal position is oriented at <pOrientFrame>.
+ const SwFrame* pHoriOrientFrame = DoesObjFollowsTextFlow()
+ ? &GetHoriVirtualAnchor( *mpVertPosOrientFrame )
+ : pOrientFrame;
+
+ // #i26791# - get 'horizontal' offset to frame anchor position.
+ SwTwips nHoriOffsetToFrameAnchorPos( 0 );
+ SwTwips nRelPosX = CalcRelPosX( *pHoriOrientFrame, aEnvOfObj,
+ aHori, rLR, rUL, bWrapThrough,
+ ( aRectFnSet.IsVert() ? aRelPos.X() : aRelPos.Y() ),
+ nHoriOffsetToFrameAnchorPos );
+
+ // #i26791# - determine offset to 'horizontal' frame
+ // anchor position, depending on layout-direction
+ if ( aRectFnSet.IsVert() )
+ {
+ aRelPos.setY( nRelPosX );
+ maOffsetToFrameAnchorPos.setY( nHoriOffsetToFrameAnchorPos );
+ }
+ else
+ {
+ aRelPos.setX( nRelPosX );
+ maOffsetToFrameAnchorPos.setX( nHoriOffsetToFrameAnchorPos );
+ }
+
+ // save calculated horizontal position - needed for filters
+ // (including the xml-filter)
+ {
+ SwTwips nAttrRelPosX = nRelPosX - nHoriOffsetToFrameAnchorPos;
+ if ( aHori.GetHoriOrient() != text::HoriOrientation::NONE &&
+ aHori.GetPos() != nAttrRelPosX )
+ {
+ aHori.SetPos( nAttrRelPosX );
+ const_cast<SwFrameFormat&>(rFrameFormat).LockModify();
+ const_cast<SwFrameFormat&>(rFrameFormat).SetFormatAttr( aHori );
+ const_cast<SwFrameFormat&>(rFrameFormat).UnlockModify();
+ }
+ }
+ }
+
+ // set absolute position at object
+ const SwTwips nTopOfAnch = GetTopForObjPos( *pAnchorFrameForVertPos, aRectFnSet.FnRect(), aRectFnSet.IsVert() );
+ if( aRectFnSet.IsVert() )
+ {
+ // --> OD 2009-08-31 #mongolianlayout#
+ if ( !aRectFnSet.IsVertL2R() )
+ {
+ GetAnchoredObj().SetObjLeft( nTopOfAnch -
+ aRelPos.X() - aObjBoundRect.Width() );
+ }
+ else
+ {
+ GetAnchoredObj().SetObjLeft( nTopOfAnch + aRelPos.X() );
+ }
+ GetAnchoredObj().SetObjTop( rAnchorTextFrame.getFrameArea().Top() +
+ aRelPos.Y() );
+ }
+ else
+ {
+ GetAnchoredObj().SetObjLeft( rAnchorTextFrame.getFrameArea().Left() +
+ aRelPos.X() );
+ GetAnchoredObj().SetObjTop( nTopOfAnch + aRelPos.Y() );
+ }
+
+ // set relative position at object
+ GetAnchoredObj().SetCurrRelPos( aRelPos );
+}
+
+void SwToContentAnchoredObjectPosition::CalcOverlap(const SwTextFrame* pAnchorFrameForVertPos,
+ Point& rRelPos, const SwTwips nTopOfAnch)
+{
+ const SwFrameFormat& rFrameFormat = GetFrameFormat();
+ bool bAllowOverlap = rFrameFormat.GetWrapInfluenceOnObjPos().GetAllowOverlap();
+ if (bAllowOverlap)
+ {
+ return;
+ }
+
+ if (rFrameFormat.GetSurround().GetSurround() == css::text::WrapTextMode_THROUGH)
+ {
+ // This is explicit wrap through: allowed to overlap.
+ return;
+ }
+
+ if (SwTextBoxHelper::isTextBox(&rFrameFormat, RES_FLYFRMFMT))
+ {
+ // This is the frame part of a textbox, just take the offset from the textbox's shape part.
+ SwFrameFormat* pShapeOfTextBox
+ = SwTextBoxHelper::getOtherTextBoxFormat(&rFrameFormat, RES_FLYFRMFMT);
+ if (pShapeOfTextBox)
+ {
+ SwTwips nYDiff = pShapeOfTextBox->GetWrapInfluenceOnObjPos().GetOverlapVertOffset();
+ if (nYDiff > 0)
+ {
+ rRelPos.setY(rRelPos.getY() + nYDiff + 1);
+ GetAnchoredObj().SetObjTop(nTopOfAnch + rRelPos.Y());
+ }
+ }
+ return;
+ }
+
+ // Get the list of objects.
+ auto pSortedObjs = pAnchorFrameForVertPos->GetDrawObjs();
+ const SwLayoutFrame* pAnchorUpper = pAnchorFrameForVertPos->GetUpper();
+
+ bool bSplitFly = false;
+ SwFlyFrame* pFlyFrame = GetAnchoredObj().DynCastFlyFrame();
+ if (pFlyFrame && pFlyFrame->IsFlySplitAllowed())
+ {
+ // At least for split flys we need to consider objects on the same page, but anchored in
+ // different text frames.
+ bSplitFly = true;
+
+ SwFrame* pFlyFrameAnchor = pFlyFrame->GetAnchorFrameContainingAnchPos();
+ if (pFlyFrameAnchor && pFlyFrameAnchor->IsInFly())
+ {
+ // An inner fly overlapping with its outer fly is fine.
+ return;
+ }
+
+ const SwPageFrame* pPageFrame = pAnchorFrameForVertPos->FindPageFrame();
+ if (pPageFrame)
+ {
+ pSortedObjs = pPageFrame->GetSortedObjs();
+ }
+ }
+
+ if (!pSortedObjs)
+ {
+ return;
+ }
+
+ for (const auto& pAnchoredObj : *pSortedObjs)
+ {
+ if (pAnchoredObj == &GetAnchoredObj())
+ {
+ // We found ourselves, stop iterating.
+ break;
+ }
+
+ if (SwTextBoxHelper::isTextBox(&pAnchoredObj->GetFrameFormat(), RES_FLYFRMFMT))
+ {
+ // Overlapping with the frame of a textbox is fine.
+ continue;
+ }
+
+ SwFlyFrame* pAnchoredObjFly = pAnchoredObj->DynCastFlyFrame();
+ if (bSplitFly)
+ {
+ if (!pAnchoredObjFly)
+ {
+ // This is a split fly, then overlap is only checked against other split flys.
+ continue;
+ }
+
+ if (pAnchoredObjFly->getRootFrame()->IsInFlyDelList(pAnchoredObjFly))
+ {
+ // A fly overlapping with a to-be-deleted fly is fine.
+ continue;
+ }
+
+ SwFrame* pAnchoredObjFlyAnchor = pAnchoredObjFly->GetAnchorFrameContainingAnchPos();
+ if (pAnchoredObjFlyAnchor && pAnchoredObjFlyAnchor->IsInFly())
+ {
+ // An inner fly overlapping with its outer fly is fine.
+ continue;
+ }
+
+ if (pAnchoredObjFlyAnchor && pAnchoredObjFlyAnchor->GetUpper() != pAnchorUpper)
+ {
+ // A fly overlapping with a fly from another upper is fine.
+ continue;
+ }
+ }
+
+ css::text::WrapTextMode eWrap = pAnchoredObj->GetFrameFormat().GetSurround().GetSurround();
+ if (eWrap == css::text::WrapTextMode_THROUGH)
+ {
+ // The other object is wrap through: allowed to overlap.
+ continue;
+ }
+
+ if (!GetAnchoredObj().GetObjRect().Overlaps(pAnchoredObj->GetObjRect()))
+ {
+ // Found an already positioned object, but it doesn't overlap, ignore.
+ continue;
+ }
+
+ // Already formatted, overlaps: resolve the conflict by shifting ourselves down.
+ SwTwips nYDiff = pAnchoredObj->GetObjRect().Bottom() - GetAnchoredObj().GetObjRect().Top();
+ rRelPos.setY(rRelPos.getY() + nYDiff + 1);
+ GetAnchoredObj().SetObjTop(nTopOfAnch + rRelPos.Y());
+
+ // Store our offset that avoids the overlap. If this is a shape of a textbox, then the frame
+ // of the textbox will use it.
+ SwFormatWrapInfluenceOnObjPos aInfluence(rFrameFormat.GetWrapInfluenceOnObjPos());
+ aInfluence.SetOverlapVertOffset(nYDiff);
+ const_cast<SwFrameFormat&>(rFrameFormat).LockModify();
+ const_cast<SwFrameFormat&>(rFrameFormat).SetFormatAttr(aInfluence);
+ const_cast<SwFrameFormat&>(rFrameFormat).UnlockModify();
+ }
+}
+
+/**
+ * Determine frame for horizontal position
+ */
+const SwFrame& SwToContentAnchoredObjectPosition::GetHoriVirtualAnchor(
+ const SwLayoutFrame& _rProposedFrame ) const
+{
+ const SwFrame* pHoriVirtAnchFrame = &_rProposedFrame;
+
+ // Search for first lower content frame, which is the anchor or a follow
+ // of the anchor (Note: <Anchor.IsAnFollow( Anchor )> is true)
+ // If none found, <_rProposedFrame> is returned.
+ const SwFrame* pFrame = _rProposedFrame.Lower();
+ while ( pFrame )
+ {
+ if ( pFrame->IsContentFrame() &&
+ GetAnchorTextFrame().IsAnFollow( static_cast<const SwContentFrame*>(pFrame) ) )
+ {
+ pHoriVirtAnchFrame = pFrame;
+ break;
+ }
+ pFrame = pFrame->GetNext();
+ }
+
+ return *pHoriVirtAnchFrame;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/objectpositioning/tolayoutanchoredobjectposition.cxx b/sw/source/core/objectpositioning/tolayoutanchoredobjectposition.cxx
new file mode 100644
index 0000000000..3e7d98bf7a
--- /dev/null
+++ b/sw/source/core/objectpositioning/tolayoutanchoredobjectposition.cxx
@@ -0,0 +1,226 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <tolayoutanchoredobjectposition.hxx>
+#include <anchoredobject.hxx>
+#include <frame.hxx>
+#include <pagefrm.hxx>
+#include <svx/svdobj.hxx>
+#include <frmfmt.hxx>
+#include <fmtanchr.hxx>
+#include <fmtornt.hxx>
+#include <fmtsrnd.hxx>
+#include <frmatr.hxx>
+#include <viewsh.hxx>
+#include <viewopt.hxx>
+#include <rootfrm.hxx>
+#include <editeng/lrspitem.hxx>
+#include <editeng/ulspitem.hxx>
+
+using namespace ::com::sun::star;
+
+namespace objectpositioning
+{
+SwToLayoutAnchoredObjectPosition::SwToLayoutAnchoredObjectPosition( SdrObject& _rDrawObj )
+ : SwAnchoredObjectPosition( _rDrawObj )
+{}
+
+SwToLayoutAnchoredObjectPosition::~SwToLayoutAnchoredObjectPosition()
+{}
+
+/** calculate position for object position type TO_LAYOUT */
+void SwToLayoutAnchoredObjectPosition::CalcPosition()
+{
+ const SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() );
+
+ SwRectFnSet aRectFnSet(&GetAnchorFrame());
+
+ const SwFrameFormat& rFrameFormat = GetFrameFormat();
+ const SvxLRSpaceItem &rLR = rFrameFormat.GetLRSpace();
+ const SvxULSpaceItem &rUL = rFrameFormat.GetULSpace();
+
+ const bool bFlyAtFly = RndStdIds::FLY_AT_FLY == rFrameFormat.GetAnchor().GetAnchorId();
+
+ // determine position.
+ // 'vertical' and 'horizontal' position are calculated separately
+ Point aRelPos;
+
+ // calculate 'vertical' position
+ SwFormatVertOrient aVert( rFrameFormat.GetVertOrient() );
+ {
+ // to-frame anchored objects are *only* vertical positioned centered or
+ // bottom, if its wrap mode is 'through' and its anchor frame has fixed
+ // size. Otherwise, it's positioned top.
+ sal_Int16 eVertOrient = aVert.GetVertOrient();
+ if ( bFlyAtFly &&
+ ( eVertOrient == text::VertOrientation::CENTER ||
+ eVertOrient == text::VertOrientation::BOTTOM ) &&
+ css::text::WrapTextMode_THROUGH != rFrameFormat.GetSurround().GetSurround() &&
+ !GetAnchorFrame().HasFixSize() )
+ {
+ eVertOrient = text::VertOrientation::TOP;
+ }
+ // #i26791# - get vertical offset to frame anchor position.
+ SwTwips nVertOffsetToFrameAnchorPos( 0 );
+ SwTwips nRelPosY =
+ GetVertRelPos( GetAnchorFrame(), GetAnchorFrame(), eVertOrient,
+ aVert.GetRelationOrient(), aVert.GetPos(),
+ rLR, rUL, nVertOffsetToFrameAnchorPos );
+
+ // keep the calculated relative vertical position - needed for filters
+ // (including the xml-filter)
+ {
+ SwTwips nAttrRelPosY = nRelPosY - nVertOffsetToFrameAnchorPos;
+ if ( aVert.GetVertOrient() != text::VertOrientation::NONE &&
+ aVert.GetPos() != nAttrRelPosY )
+ {
+ aVert.SetPos( nAttrRelPosY );
+ const_cast<SwFrameFormat&>(rFrameFormat).LockModify();
+ const_cast<SwFrameFormat&>(rFrameFormat).SetFormatAttr( aVert );
+ const_cast<SwFrameFormat&>(rFrameFormat).UnlockModify();
+ }
+ }
+
+ // determine absolute 'vertical' position, depending on layout-direction
+ // #i26791# - determine offset to 'vertical' frame
+ // anchor position, depending on layout-direction
+ if( aRectFnSet.IsVert() )
+ {
+ if ( aRectFnSet.IsVertL2R() )
+ aRelPos.setX( nRelPosY );
+ else
+ aRelPos.setX( -nRelPosY - aObjBoundRect.Width() );
+ maOffsetToFrameAnchorPos.setX( nVertOffsetToFrameAnchorPos );
+ }
+ else
+ {
+ aRelPos.setY( nRelPosY );
+ maOffsetToFrameAnchorPos.setY( nVertOffsetToFrameAnchorPos );
+ }
+
+ // if in online-layout the bottom of to-page anchored object is beyond
+ // the page bottom, the page frame has to grow by growing its body frame.
+ const SwViewShell *pSh = GetAnchorFrame().getRootFrame()->GetCurrShell();
+ if ( !bFlyAtFly && GetAnchorFrame().IsPageFrame() &&
+ pSh && pSh->GetViewOptions()->getBrowseMode() )
+ {
+ const tools::Long nAnchorBottom = GetAnchorFrame().getFrameArea().Bottom();
+ const tools::Long nBottom = GetAnchorFrame().getFrameArea().Top() +
+ aRelPos.Y() + aObjBoundRect.Height();
+ if ( nAnchorBottom < nBottom )
+ {
+ static_cast<SwPageFrame&>(GetAnchorFrame()).
+ FindBodyCont()->Grow( nBottom - nAnchorBottom );
+ }
+ }
+ } // end of determination of vertical position
+
+ // calculate 'horizontal' position
+ SwFormatHoriOrient aHori( rFrameFormat.GetHoriOrient() );
+ {
+ // consider toggle of horizontal position for even pages.
+ const bool bToggle = aHori.IsPosToggle() &&
+ !GetAnchorFrame().FindPageFrame()->OnRightPage();
+ sal_Int16 eHoriOrient = aHori.GetHoriOrient();
+ sal_Int16 eRelOrient = aHori.GetRelationOrient();
+ // toggle orientation
+ ToggleHoriOrientAndAlign( bToggle, eHoriOrient, eRelOrient );
+
+ // determine alignment values:
+ // <nWidth>: 'width' of the alignment area
+ // <nOffset>: offset of alignment area, relative to 'left' of
+ // frame anchor position
+ SwTwips nWidth, nOffset;
+ {
+ bool bDummy; // in this context irrelevant output parameter
+ GetHoriAlignmentValues( GetAnchorFrame(), GetAnchorFrame(),
+ eRelOrient, false,
+ nWidth, nOffset, bDummy );
+ }
+
+ SwTwips nObjWidth = aRectFnSet.GetWidth(aObjBoundRect);
+
+ // determine relative horizontal position
+ SwTwips nRelPosX;
+ if ( text::HoriOrientation::NONE == eHoriOrient )
+ {
+ if( bToggle ||
+ ( !aHori.IsPosToggle() && GetAnchorFrame().IsRightToLeft() ) )
+ {
+ nRelPosX = nWidth - nObjWidth - aHori.GetPos();
+ }
+ else
+ {
+ nRelPosX = aHori.GetPos();
+ }
+ }
+ else if ( text::HoriOrientation::CENTER == eHoriOrient )
+ nRelPosX = (nWidth / 2) - (nObjWidth / 2);
+ else if ( text::HoriOrientation::RIGHT == eHoriOrient )
+ nRelPosX = nWidth - ( nObjWidth +
+ ( aRectFnSet.IsVert() ? rUL.GetLower() : rLR.GetRight() ) );
+ else
+ nRelPosX = aRectFnSet.IsVert() ? rUL.GetUpper() : rLR.GetLeft();
+ nRelPosX += nOffset;
+
+ // no 'negative' relative horizontal position
+ // OD 06.11.2003 #FollowTextFlowAtFrame# - negative positions allow for
+ // to frame anchored objects.
+ if ( !bFlyAtFly && nRelPosX < 0 )
+ {
+ nRelPosX = 0;
+ }
+
+ // determine absolute 'horizontal' position, depending on layout-direction
+ // #i26791# - determine offset to 'horizontal' frame
+ // anchor position, depending on layout-direction
+ if( aRectFnSet.IsVert() || aRectFnSet.IsVertL2R() )
+ {
+
+ aRelPos.setY( nRelPosX );
+ maOffsetToFrameAnchorPos.setY( nOffset );
+ }
+ else
+ {
+ aRelPos.setX( nRelPosX );
+ maOffsetToFrameAnchorPos.setX( nOffset );
+ }
+
+ // keep the calculated relative horizontal position - needed for filters
+ // (including the xml-filter)
+ {
+ SwTwips nAttrRelPosX = nRelPosX - nOffset;
+ if ( text::HoriOrientation::NONE != aHori.GetHoriOrient() &&
+ aHori.GetPos() != nAttrRelPosX )
+ {
+ aHori.SetPos( nAttrRelPosX );
+ const_cast<SwFrameFormat&>(rFrameFormat).LockModify();
+ const_cast<SwFrameFormat&>(rFrameFormat).SetFormatAttr( aHori );
+ const_cast<SwFrameFormat&>(rFrameFormat).UnlockModify();
+ }
+ }
+ } // end of determination of horizontal position
+
+ // keep calculate relative position
+ maRelPos = aRelPos;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */