diff options
Diffstat (limited to 'sw/source/core/objectpositioning/anchoredobjectposition.cxx')
-rw-r--r-- | sw/source/core/objectpositioning/anchoredobjectposition.cxx | 1129 |
1 files changed, 1129 insertions, 0 deletions
diff --git a/sw/source/core/objectpositioning/anchoredobjectposition.cxx b/sw/source/core/objectpositioning/anchoredobjectposition.cxx new file mode 100644 index 000000000000..78b9ba86e362 --- /dev/null +++ b/sw/source/core/objectpositioning/anchoredobjectposition.cxx @@ -0,0 +1,1129 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_sw.hxx" +#include <anchoredobjectposition.hxx> +#ifndef _ENVIRONMENTOFANCHOREDOBJECT +#include <environmentofanchoredobject.hxx> +#endif +#include <flyfrm.hxx> +#include <flyfrms.hxx> +#include <txtfrm.hxx> +#include <pagefrm.hxx> +#include <frmtool.hxx> +#include <svx/svdobj.hxx> +#include <dflyobj.hxx> +#include <dcontact.hxx> +#include <frmfmt.hxx> +#include <fmtornt.hxx> +// --> OD 2006-03-15 #i62875# +#include <fmtfollowtextflow.hxx> +// <-- +#include <editeng/lrspitem.hxx> +#include <editeng/ulspitem.hxx> +#include <ndtxt.hxx> +#include <IDocumentSettingAccess.hxx> + +using namespace ::com::sun::star; +using namespace objectpositioning; + +// ************************************************************************** +// constructor, destructor, initialization +// ************************************************************************** +SwAnchoredObjectPosition::SwAnchoredObjectPosition( SdrObject& _rDrawObj ) + : mrDrawObj( _rDrawObj ), + mbIsObjFly( false ), + mpAnchoredObj( 0 ), + mpAnchorFrm( 0 ), + mpContact( 0 ), + // --> OD 2006-03-15 #i62875# + mbFollowTextFlow( false ), + mbDoNotCaptureAnchoredObj( false ) + // <-- +{ +#if OSL_DEBUG_LEVEL > 1 + // assert, if object isn't of excepted type + const bool bObjOfExceptedType = + mrDrawObj.ISA(SwVirtFlyDrawObj) || // object representing fly frame + mrDrawObj.ISA(SwDrawVirtObj) || // 'virtual' drawing object + ( !mrDrawObj.ISA(SdrVirtObj) && // 'master' drawing object + !mrDrawObj.ISA(SwFlyDrawObj) ); // - indirectly checked + (void) bObjOfExceptedType; + OSL_ENSURE( bObjOfExceptedType, + "SwAnchoredObjectPosition(..) - object of unexcepted type!" ); +#endif + + _GetInfoAboutObj(); +} + +/** determine information about object + + OD 30.07.2003 #110978# + members <mbIsObjFly>, <mpFrmOfObj>, <mpAnchorFrm>, <mpContact>, + <mbFollowTextFlow> and <mbDoNotCaptureAnchoredObj> are set + + @author OD +*/ +void SwAnchoredObjectPosition::_GetInfoAboutObj() +{ + // determine, if object represents a fly frame + { + mbIsObjFly = mrDrawObj.ISA(SwVirtFlyDrawObj); + } + + // determine contact object + { + mpContact = static_cast<SwContact*>(GetUserCall( &mrDrawObj )); + OSL_ENSURE( mpContact, + "SwAnchoredObjectPosition::_GetInfoAboutObj() - missing SwContact-object." ); + } + + // determine anchored object, the object belongs to + { + // OD 2004-03-30 #i26791# + mpAnchoredObj = mpContact->GetAnchoredObj( &mrDrawObj ); + OSL_ENSURE( mpAnchoredObj, + "SwAnchoredObjectPosition::_GetInfoAboutObj() - missing anchored object." ); + } + + // determine frame, the object is anchored at + { + // OD 2004-03-23 #i26791# + mpAnchorFrm = mpAnchoredObj->AnchorFrm(); + OSL_ENSURE( mpAnchorFrm, + "SwAnchoredObjectPosition::_GetInfoAboutObj() - missing anchor frame." ); + } + + // determine format the object belongs to + { + // --> OD 2004-07-01 #i28701# + mpFrmFmt = &mpAnchoredObj->GetFrmFmt(); + OSL_ENSURE( mpFrmFmt, + "<SwAnchoredObjectPosition::_GetInfoAboutObj() - missing frame format." ); + } + + // --> OD 2006-03-15 #i62875# + // determine attribute value of <Follow-Text-Flow> + { + mbFollowTextFlow = mpFrmFmt->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 + // - it doesn't follow the text flow + { + mbDoNotCaptureAnchoredObj = !mbIsObjFly && !mbFollowTextFlow && + mpFrmFmt->getIDocumentSettingAccess()->get(IDocumentSettingAccess::DO_NOT_CAPTURE_DRAW_OBJS_ON_PAGE); + } + // <-- +} + +SwAnchoredObjectPosition::~SwAnchoredObjectPosition() +{} + +bool SwAnchoredObjectPosition::IsAnchoredToChar() const +{ + return false; +} + +const SwFrm* SwAnchoredObjectPosition::ToCharOrientFrm() const +{ + return NULL; +} + +const SwRect* SwAnchoredObjectPosition::ToCharRect() const +{ + return NULL; +} + +// OD 12.11.2003 #i22341# +SwTwips SwAnchoredObjectPosition::ToCharTopOfLine() const +{ + return 0L; +} + +/** helper method to determine top of a frame for the vertical + object positioning + + OD 2004-03-11 #i11860# + + @author OD +*/ +SwTwips SwAnchoredObjectPosition::_GetTopForObjPos( const SwFrm& _rFrm, + const SwRectFn& _fnRect, + const bool _bVert ) const +{ + SwTwips nTopOfFrmForObjPos = (_rFrm.Frm().*_fnRect->fnGetTop)(); + + if ( _rFrm.IsTxtFrm() ) + { + const SwTxtFrm& rTxtFrm = static_cast<const SwTxtFrm&>(_rFrm); + if ( _bVert ) + { + nTopOfFrmForObjPos -= + rTxtFrm.GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid(); + } + else + { + nTopOfFrmForObjPos += + rTxtFrm.GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid(); + } + } + + return nTopOfFrmForObjPos; +} + +void SwAnchoredObjectPosition::_GetVertAlignmentValues( + const SwFrm& _rVertOrientFrm, + const SwFrm& _rPageAlignLayFrm, + const sal_Int16 _eRelOrient, + SwTwips& _orAlignAreaHeight, + SwTwips& _orAlignAreaOffset ) const +{ + SwTwips nHeight = 0; + SwTwips nOffset = 0; + SWRECTFN( (&_rVertOrientFrm) ) + // OD 2004-03-11 #i11860# - top of <_rVertOrientFrm> for object positioning + const SwTwips nVertOrientTop = _GetTopForObjPos( _rVertOrientFrm, fnRect, bVert ); + // OD 2004-03-11 #i11860# - upper space amount of <_rVertOrientFrm> considered + // for previous frame + const SwTwips nVertOrientUpperSpaceForPrevFrmAndPageGrid = + _rVertOrientFrm.IsTxtFrm() + ? static_cast<const SwTxtFrm&>(_rVertOrientFrm). + GetUpperSpaceAmountConsideredForPrevFrmAndPageGrid() + : 0; + switch ( _eRelOrient ) + { + case text::RelOrientation::FRAME: + { + // OD 2004-03-11 #i11860# - consider upper space of previous frame + nHeight = (_rVertOrientFrm.Frm().*fnRect->fnGetHeight)() - + nVertOrientUpperSpaceForPrevFrmAndPageGrid; + nOffset = 0; + } + break; + case text::RelOrientation::PRINT_AREA: + { + nHeight = (_rVertOrientFrm.Prt().*fnRect->fnGetHeight)(); + // OD 2004-03-11 #i11860# - consider upper space of previous frame + nOffset = (_rVertOrientFrm.*fnRect->fnGetTopMargin)() - + nVertOrientUpperSpaceForPrevFrmAndPageGrid; + // if aligned to page in horizontal layout, consider header and + // footer frame height appropriately. + if( _rVertOrientFrm.IsPageFrm() && !bVert ) + { + const SwFrm* pPrtFrm = + static_cast<const SwPageFrm&>(_rVertOrientFrm).Lower(); + while( pPrtFrm ) + { + if( pPrtFrm->IsHeaderFrm() ) + { + nHeight -= pPrtFrm->Frm().Height(); + nOffset += pPrtFrm->Frm().Height(); + } + else if( pPrtFrm->IsFooterFrm() ) + { + nHeight -= pPrtFrm->Frm().Height(); + } + pPrtFrm = pPrtFrm->GetNext(); + } + } + } + break; + case text::RelOrientation::PAGE_FRAME: + { + nHeight = (_rPageAlignLayFrm.Frm().*fnRect->fnGetHeight)(); + nOffset = (*fnRect->fnYDiff)( + (_rPageAlignLayFrm.Frm().*fnRect->fnGetTop)(), + nVertOrientTop ); + } + break; + case text::RelOrientation::PAGE_PRINT_AREA: + { + nHeight = (_rPageAlignLayFrm.Prt().*fnRect->fnGetHeight)(); + nOffset = (_rPageAlignLayFrm.*fnRect->fnGetTopMargin)() + + (*fnRect->fnYDiff)( + (_rPageAlignLayFrm.Frm().*fnRect->fnGetTop)(), + nVertOrientTop ); + // if aligned to page in horizontal layout, consider header and + // footer frame height appropriately. + if( _rPageAlignLayFrm.IsPageFrm() && !bVert ) + { + const SwFrm* pPrtFrm = + static_cast<const SwPageFrm&>(_rPageAlignLayFrm).Lower(); + while( pPrtFrm ) + { + if( pPrtFrm->IsHeaderFrm() ) + { + nHeight -= pPrtFrm->Frm().Height(); + nOffset += pPrtFrm->Frm().Height(); + } + else if( pPrtFrm->IsFooterFrm() ) + { + nHeight -= pPrtFrm->Frm().Height(); + } + pPrtFrm = pPrtFrm->GetNext(); + } + } + } + break; + // OD 12.11.2003 #i22341# - vertical alignment at top of line + case text::RelOrientation::TEXT_LINE: + { + if ( IsAnchoredToChar() ) + { + nHeight = 0; + nOffset = (*fnRect->fnYDiff)( ToCharTopOfLine(), nVertOrientTop ); + } + else + { + OSL_ENSURE( false, + "<SwAnchoredObjectPosition::_GetVertAlignmentValues(..)> - invalid relative alignment" ); + } + } + break; + case text::RelOrientation::CHAR: + { + if ( IsAnchoredToChar() ) + { + nHeight = (ToCharRect()->*fnRect->fnGetHeight)(); + nOffset = (*fnRect->fnYDiff)( (ToCharRect()->*fnRect->fnGetTop)(), + nVertOrientTop ); + } + else + { + OSL_ENSURE( false, + "<SwAnchoredObjectPosition::_GetVertAlignmentValues(..)> - invalid relative alignment" ); + } + } + break; + // no break here, because text::RelOrientation::CHAR is invalid, if !mbAnchorToChar + default: + //case text::RelOrientation::PAGE_LEFT: not valid for vertical alignment + //case text::RelOrientation::PAGE_RIGHT: not valid for vertical alignment + //case text::RelOrientation::FRAME_LEFT: not valid for vertical alignment + //case text::RelOrientation::FRAME_RIGHT: not valid for vertical alignment + { + OSL_ENSURE( false, + "<SwAnchoredObjectPosition::_GetVertAlignmentValues(..)> - invalid relative alignment" ); + } + } + + _orAlignAreaHeight = nHeight; + _orAlignAreaOffset = nOffset; +} + +// --> OD 2004-06-17 #i26791# - add output parameter <_roVertOffsetToFrmAnchorPos> +SwTwips SwAnchoredObjectPosition::_GetVertRelPos( + const SwFrm& _rVertOrientFrm, + const SwFrm& _rPageAlignLayFrm, + const sal_Int16 _eVertOrient, + const sal_Int16 _eRelOrient, + const SwTwips _nVertPos, + const SvxLRSpaceItem& _rLRSpacing, + const SvxULSpaceItem& _rULSpacing, + SwTwips& _roVertOffsetToFrmAnchorPos ) const +{ + SwTwips nRelPosY = 0; + SWRECTFN( (&_rVertOrientFrm) ); + + SwTwips nAlignAreaHeight; + SwTwips nAlignAreaOffset; + _GetVertAlignmentValues( _rVertOrientFrm, _rPageAlignLayFrm, + _eRelOrient, nAlignAreaHeight, nAlignAreaOffset ); + + nRelPosY = nAlignAreaOffset; + const SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() ); + const SwTwips nObjHeight = (aObjBoundRect.*fnRect->fnGetHeight)(); + + switch ( _eVertOrient ) + { + case text::VertOrientation::NONE: + { + // 'manual' vertical position + nRelPosY += _nVertPos; + } + break; + case text::VertOrientation::TOP: + { + nRelPosY += bVert ? _rLRSpacing.GetRight() : _rULSpacing.GetUpper(); + } + break; + case text::VertOrientation::CENTER: + { + nRelPosY += (nAlignAreaHeight / 2) - (nObjHeight / 2); + } + break; + case text::VertOrientation::BOTTOM: + { + nRelPosY += nAlignAreaHeight - + ( nObjHeight + ( bVert ? _rLRSpacing.GetLeft() : _rULSpacing.GetLower() ) ); + } + break; + default: + { + OSL_ENSURE( false, + "<SwAnchoredObjectPosition::_GetVertRelPos(..) - invalid vertical positioning" ); + } + } + + // --> OD 2004-06-17 #i26791# + _roVertOffsetToFrmAnchorPos = nAlignAreaOffset; + + return nRelPosY; +} + +/** adjust calculated vertical in order to keep object inside + 'page' alignment layout frame. + + OD 2004-07-01 #i28701# - parameter <_nTopOfAnch> and <_bVert> added + OD 2004-07-22 #i31805# - add parameter <_bCheckBottom> + OD 2004-10-08 #i26945# - add parameter <_bFollowTextFlow> + OD 2006-03-15 #i62875# - method now private and renamed. + + @author OD +*/ +SwTwips SwAnchoredObjectPosition::_ImplAdjustVertRelPos( const SwTwips _nTopOfAnch, + const bool _bVert, + const SwFrm& _rPageAlignLayFrm, + const SwTwips _nProposedRelPosY, + const bool _bFollowTextFlow, + const bool _bCheckBottom ) const +{ + SwTwips nAdjustedRelPosY = _nProposedRelPosY; + + const Size aObjSize( GetAnchoredObj().GetObjRect().SSize() ); + + // determine the area of 'page' alignment frame, to which the vertical + // position is restricted. + // --> OD 2004-07-06 #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; + { + // --> OD 2004-10-08 #i26945# - no extension of restricted area, if + // object's attribute follow text flow is set and its inside a table + if ( GetFrmFmt().getIDocumentSettingAccess()->get(IDocumentSettingAccess::CONSIDER_WRAP_ON_OBJECT_POSITION) && + ( !_bFollowTextFlow || + !GetAnchoredObj().GetAnchorFrm()->IsInTab() ) ) + { + aPgAlignArea = _rPageAlignLayFrm.FindPageFrm()->Frm(); + } + else + { + aPgAlignArea = _rPageAlignLayFrm.Frm(); + } + } + + if ( _bVert ) + { + // OD 2004-07-22 #i31805# - consider value of <_bCheckBottom> + if ( _bCheckBottom && + _nTopOfAnch - nAdjustedRelPosY - aObjSize.Width() < + aPgAlignArea.Left() ) + { + nAdjustedRelPosY = aPgAlignArea.Left() + + _nTopOfAnch - + aObjSize.Width(); + } + // --> OD 2004-08-13 #i32964# - correction + if ( _nTopOfAnch - nAdjustedRelPosY > aPgAlignArea.Right() ) + { + nAdjustedRelPosY = _nTopOfAnch - aPgAlignArea.Right(); + } + // <-- + } + else + { + // OD 2004-07-22 #i31805# - consider value of <_bCheckBottom> + if ( _bCheckBottom && + _nTopOfAnch + nAdjustedRelPosY + aObjSize.Height() > + // --> OD 2006-01-13 #129959# + // Do not mix usage of <top + height> and <bottom> +// aPgAlignArea.Bottom() ) + aPgAlignArea.Top() + aPgAlignArea.Height() ) + // <-- + { + // --> OD 2006-01-13 #129959# + // Do not mix usage of <top + height> and <bottom> +// nAdjustedRelPosY = aPgAlignArea.Bottom() - + 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. + + OD 2006-03-15 #i62875# - method now private and renamed. + + @author OD +*/ +SwTwips SwAnchoredObjectPosition::_ImplAdjustHoriRelPos( + const SwFrm& _rPageAlignLayFrm, + const SwTwips _nProposedRelPosX ) const +{ + SwTwips nAdjustedRelPosX = _nProposedRelPosX; + + const SwFrm& rAnchorFrm = GetAnchorFrm(); + const bool bVert = rAnchorFrm.IsVertical(); + + const Size aObjSize( GetAnchoredObj().GetObjRect().SSize() ); + + if( bVert ) + { + if ( rAnchorFrm.Frm().Top() + nAdjustedRelPosX + aObjSize.Height() > + _rPageAlignLayFrm.Frm().Bottom() ) + { + nAdjustedRelPosX = _rPageAlignLayFrm.Frm().Bottom() - + rAnchorFrm.Frm().Top() - + aObjSize.Height(); + } + if ( rAnchorFrm.Frm().Top() + nAdjustedRelPosX < + _rPageAlignLayFrm.Frm().Top() ) + { + nAdjustedRelPosX = _rPageAlignLayFrm.Frm().Top() - + rAnchorFrm.Frm().Top(); + } + } + else + { + if ( rAnchorFrm.Frm().Left() + nAdjustedRelPosX + aObjSize.Width() > + _rPageAlignLayFrm.Frm().Right() ) + { + nAdjustedRelPosX = _rPageAlignLayFrm.Frm().Right() - + rAnchorFrm.Frm().Left() - + aObjSize.Width(); + } + if ( rAnchorFrm.Frm().Left() + nAdjustedRelPosX < + _rPageAlignLayFrm.Frm().Left() ) + { + nAdjustedRelPosX = _rPageAlignLayFrm.Frm().Left() - + rAnchorFrm.Frm().Left(); + } + } + + return nAdjustedRelPosX; +} + +/** determine alignment value for horizontal position of object + + @author OD +*/ +void SwAnchoredObjectPosition::_GetHoriAlignmentValues( const SwFrm& _rHoriOrientFrm, + const SwFrm& _rPageAlignLayFrm, + const sal_Int16 _eRelOrient, + const bool _bObjWrapThrough, + SwTwips& _orAlignAreaWidth, + SwTwips& _orAlignAreaOffset, + bool& _obAlignedRelToPage ) const +{ + SwTwips nWidth = 0; + SwTwips nOffset = 0; + SWRECTFN( (&_rHoriOrientFrm) ) + switch ( _eRelOrient ) + { + case text::RelOrientation::PRINT_AREA: + { + nWidth = (_rHoriOrientFrm.Prt().*fnRect->fnGetWidth)(); + nOffset = (_rHoriOrientFrm.*fnRect->fnGetLeftMargin)(); + if ( _rHoriOrientFrm.IsTxtFrm() ) + { + // consider movement of text frame left + nOffset += static_cast<const SwTxtFrm&>(_rHoriOrientFrm).GetBaseOfstForFly( !_bObjWrapThrough ); + } + else if ( _rHoriOrientFrm.IsPageFrm() && bVert ) + { + // for to-page anchored objects, consider header/footer frame + // in vertical layout + const SwFrm* pPrtFrm = + static_cast<const SwPageFrm&>(_rHoriOrientFrm).Lower(); + while( pPrtFrm ) + { + if( pPrtFrm->IsHeaderFrm() ) + { + nWidth -= pPrtFrm->Frm().Height(); + nOffset += pPrtFrm->Frm().Height(); + } + else if( pPrtFrm->IsFooterFrm() ) + { + nWidth -= pPrtFrm->Frm().Height(); + } + pPrtFrm = pPrtFrm->GetNext(); + } + } + break; + } + case text::RelOrientation::PAGE_LEFT: + { + // align at left border of page frame/fly frame/cell frame + nWidth = (_rPageAlignLayFrm.*fnRect->fnGetLeftMargin)(); + nOffset = (*fnRect->fnXDiff)( + (_rPageAlignLayFrm.Frm().*fnRect->fnGetLeft)(), + (_rHoriOrientFrm.Frm().*fnRect->fnGetLeft)() ); + _obAlignedRelToPage = true; + } + break; + case text::RelOrientation::PAGE_RIGHT: + { + // align at right border of page frame/fly frame/cell frame + nWidth = (_rPageAlignLayFrm.*fnRect->fnGetRightMargin)(); + nOffset = (*fnRect->fnXDiff)( + (_rPageAlignLayFrm.*fnRect->fnGetPrtRight)(), + (_rHoriOrientFrm.Frm().*fnRect->fnGetLeft)() ); + _obAlignedRelToPage = true; + } + break; + case text::RelOrientation::FRAME_LEFT: + { + // align at left border of anchor frame + nWidth = (_rHoriOrientFrm.*fnRect->fnGetLeftMargin)(); + nOffset = 0; + } + break; + case text::RelOrientation::FRAME_RIGHT: + { + // align at right border of anchor frame + // OD 19.08.2003 #110978# - unify and simplify + nWidth = (_rHoriOrientFrm.*fnRect->fnGetRightMargin)(); + //nOffset = (_rHoriOrientFrm.Frm().*fnRect->fnGetWidth)() - + // nWidth; + nOffset = (_rHoriOrientFrm.Prt().*fnRect->fnGetRight)(); + } + break; + case text::RelOrientation::CHAR: + { + // alignment relative to character - assure, that corresponding + // character rectangle is set. + if ( IsAnchoredToChar() ) + { + nWidth = 0; + nOffset = (*fnRect->fnXDiff)( + (ToCharRect()->*fnRect->fnGetLeft)(), + (ToCharOrientFrm()->Frm().*fnRect->fnGetLeft)() ); + break; + } + // no break! + } + case text::RelOrientation::PAGE_PRINT_AREA: + { + nWidth = (_rPageAlignLayFrm.Prt().*fnRect->fnGetWidth)(); + nOffset = (*fnRect->fnXDiff)( + (_rPageAlignLayFrm.*fnRect->fnGetPrtLeft)(), + (_rHoriOrientFrm.Frm().*fnRect->fnGetLeft)() ); + if ( _rHoriOrientFrm.IsPageFrm() && bVert ) + { + // for to-page anchored objects, consider header/footer frame + // in vertical layout + const SwFrm* pPrtFrm = + static_cast<const SwPageFrm&>(_rHoriOrientFrm).Lower(); + while( pPrtFrm ) + { + if( pPrtFrm->IsHeaderFrm() ) + { + nWidth -= pPrtFrm->Frm().Height(); + nOffset += pPrtFrm->Frm().Height(); + } + else if( pPrtFrm->IsFooterFrm() ) + { + nWidth -= pPrtFrm->Frm().Height(); + } + pPrtFrm = pPrtFrm->GetNext(); + } + } + _obAlignedRelToPage = true; + break; + } + case text::RelOrientation::PAGE_FRAME: + { + nWidth = (_rPageAlignLayFrm.Frm().*fnRect->fnGetWidth)(); + nOffset = (*fnRect->fnXDiff)( + (_rPageAlignLayFrm.Frm().*fnRect->fnGetLeft)(), + (_rHoriOrientFrm.Frm().*fnRect->fnGetLeft)() ); + _obAlignedRelToPage = true; + break; + } + default: + // case text::RelOrientation::FRAME: + { + nWidth = (_rHoriOrientFrm.Frm().*fnRect->fnGetWidth)(); + nOffset = _rHoriOrientFrm.IsTxtFrm() ? + static_cast<const SwTxtFrm&>(_rHoriOrientFrm).GetBaseOfstForFly( !_bObjWrapThrough ) : + 0; + break; + } + } + + _orAlignAreaWidth = nWidth; + _orAlignAreaOffset = nOffset; +} + +/** toggle given horizontal orientation and relative alignment + + @author OD +*/ +void SwAnchoredObjectPosition::_ToggleHoriOrientAndAlign( + const bool _bToggleLeftRight, + sal_Int16& _ioeHoriOrient, + sal_Int16& _iopeRelOrient + ) const +{ + if( _bToggleLeftRight ) + { + // 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 + + @author OD +*/ +SwTwips SwAnchoredObjectPosition::_CalcRelPosX( + const SwFrm& _rHoriOrientFrm, + const SwEnvironmentOfAnchoredObject& _rEnvOfObj, + const SwFmtHoriOrient& _rHoriOrient, + const SvxLRSpaceItem& _rLRSpacing, + const SvxULSpaceItem& _rULSpacing, + const bool _bObjWrapThrough, + const SwTwips _nRelPosY, + SwTwips& _roHoriOffsetToFrmAnchorPos + ) const +{ + // determine 'page' alignment layout frame + const SwFrm& rPageAlignLayFrm = + _rEnvOfObj.GetHoriEnvironmentLayoutFrm( _rHoriOrientFrm ); + + const bool bEvenPage = !rPageAlignLayFrm.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( _rHoriOrientFrm, rPageAlignLayFrm, + eRelOrient, _bObjWrapThrough, + nWidth, nOffset, bAlignedRelToPage ); + + const SwFrm& rAnchorFrm = GetAnchorFrm(); + SWRECTFN( (&_rHoriOrientFrm) ) + SwTwips nObjWidth = (GetAnchoredObj().GetObjRect().*fnRect->fnGetWidth)(); + SwTwips nRelPosX = nOffset; + if ( _rHoriOrient.GetHoriOrient() == text::HoriOrientation::NONE ) + { + // 'manual' horizonal position + const bool bR2L = rAnchorFrm.IsRightToLeft(); + if( IsAnchoredToChar() && text::RelOrientation::CHAR == eRelOrient ) + { + if( bR2L ) + nRelPosX -= _rHoriOrient.GetPos(); + else + nRelPosX += _rHoriOrient.GetPos(); + } + else if ( bToggle || ( !_rHoriOrient.IsPosToggle() && bR2L ) ) + { + // OD 04.08.2003 #110978# - 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 + + ( bVert ? _rULSpacing.GetLower() : _rLRSpacing.GetRight() ) ); + else + nRelPosX += bVert ? _rULSpacing.GetUpper() : _rLRSpacing.GetLeft(); + + // adjust relative position by distance between anchor frame and + // the frame, the object is oriented at. + if ( &rAnchorFrm != &_rHoriOrientFrm ) + { + SwTwips nLeftOrient = (_rHoriOrientFrm.Frm().*fnRect->fnGetLeft)(); + SwTwips nLeftAnchor = (rAnchorFrm.Frm().*fnRect->fnGetLeft)(); + nRelPosX += (*fnRect->fnXDiff)( nLeftOrient, nLeftAnchor ); + } + + // OD 2004-05-21 #i28701# - deactivate follow code +// // adjust relative horizontal position, if object is manual horizontal +// // positioned (not 'page' aligned) and orients not at the anchor frame, +// // but it overlaps anchor frame. +// if ( _rHoriOrient.GetHoriOrient() == text::HoriOrientation::NONE && !bAlignedRelToPage && +// &rAnchorFrm != &_rHoriOrientFrm ) +// { +// // E.g.: consider a columned page/section with an horizontal +// // negative positioned object. +// // OD 2004-03-23 #i26791# +// const SwRect& rObjRect = GetAnchoredObj().GetObjRect(); +// if( bVert ) +// { +// if( _rHoriOrientFrm.Frm().Top() > rAnchorFrm.Frm().Bottom() && +// rObjRect.Right() > rAnchorFrm.Frm().Left() ) +// { +// const SwTwips nProposedPosX = nRelPosX + rAnchorFrm.Frm().Top(); +// if ( nProposedPosX < rAnchorFrm.Frm().Bottom() ) +// nRelPosX = rAnchorFrm.Frm().Height() + 1; +// } +// } +// else +// { +// if( _rHoriOrientFrm.Frm().Left() > rAnchorFrm.Frm().Right() && +// rObjRect.Top() < rAnchorFrm.Frm().Bottom() ) +// { +// // OD 04.08.2003 #110978# - correction: use <nRelPosX> +// // instead of <aRelPos.X()> +// const SwTwips nProposedPosX = nRelPosX + rAnchorFrm.Frm().Left(); +// if ( nProposedPosX < rAnchorFrm.Frm().Right() ) +// nRelPosX = rAnchorFrm.Frm().Width() + 1; +// } +// } +// } + // adjust calculated relative horizontal position, in order to + // keep object inside 'page' alignment layout frame + const SwFrm& rEnvironmentLayFrm = + _rEnvOfObj.GetHoriEnvironmentLayoutFrm( _rHoriOrientFrm ); + nRelPosX = _AdjustHoriRelPos( rEnvironmentLayFrm, 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().ISA(SwFlyFrm) && + ( GetContact().ObjAnchoredAtPara() || GetContact().ObjAnchoredAtChar() ) && + ( eHoriOrient == text::HoriOrientation::LEFT || eHoriOrient == text::HoriOrientation::RIGHT ) && + eRelOrient != text::RelOrientation::CHAR ) + { + nRelPosX = _AdjustHoriRelPosForDrawAside( _rHoriOrientFrm, + nRelPosX, _nRelPosY, + eHoriOrient, eRelOrient, + _rLRSpacing, _rULSpacing, + bEvenPage ); + } + + // --> OD 2004-06-17 #i26791# + _roHoriOffsetToFrmAnchorPos = 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 + + @author OD +*/ +SwTwips SwAnchoredObjectPosition::_AdjustHoriRelPosForDrawAside( + const SwFrm& _rHoriOrientFrm, + const SwTwips _nProposedRelPosX, + const SwTwips _nRelPosY, + const sal_Int16 _eHoriOrient, + const sal_Int16 _eRelOrient, + const SvxLRSpaceItem& _rLRSpacing, + const SvxULSpaceItem& _rULSpacing, + const bool _bEvenPage + ) const +{ + // OD 2004-03-23 #i26791# + if ( !GetAnchorFrm().ISA(SwTxtFrm) || + !GetAnchoredObj().ISA(SwFlyAtCntFrm) ) + { + OSL_ENSURE( false, + "<SwAnchoredObjectPosition::_AdjustHoriRelPosForDrawAside(..) - usage for wrong anchor type" ); + return _nProposedRelPosX; + } + + const SwTxtFrm& rAnchorTxtFrm = static_cast<const SwTxtFrm&>(GetAnchorFrm()); + // OD 2004-03-23 #i26791# + const SwFlyAtCntFrm& rFlyAtCntFrm = + static_cast<const SwFlyAtCntFrm&>(GetAnchoredObj()); + const SwRect aObjBoundRect( GetAnchoredObj().GetObjRect() ); + SWRECTFN( (&_rHoriOrientFrm) ) + + SwTwips nAdjustedRelPosX = _nProposedRelPosX; + + // determine proposed object bound rectangle + Point aTmpPos = (rAnchorTxtFrm.Frm().*fnRect->fnGetPos)(); + if( bVert ) + { + aTmpPos.X() -= _nRelPosY + aObjBoundRect.Width(); + aTmpPos.Y() += nAdjustedRelPosX; + } + else + { + aTmpPos.X() += nAdjustedRelPosX; + aTmpPos.Y() += _nRelPosY; + } + SwRect aTmpObjRect( aTmpPos, aObjBoundRect.SSize() ); + + const UINT32 nObjOrdNum = GetObject().GetOrdNum(); + const SwPageFrm* pObjPage = rFlyAtCntFrm.FindPageFrm(); + const SwFrm* pObjContext = ::FindKontext( &rAnchorTxtFrm, FRM_COLUMN ); + ULONG nObjIndex = rAnchorTxtFrm.GetTxtNode()->GetIndex(); + SwOrderIter aIter( pObjPage, TRUE ); + const SwFlyFrm* pFly = ((SwVirtFlyDrawObj*)aIter.Bottom())->GetFlyFrm(); + while ( pFly && nObjOrdNum > pFly->GetVirtDrawObj()->GetOrdNumDirect() ) + { + if ( _DrawAsideFly( pFly, aTmpObjRect, pObjContext, nObjIndex, + _bEvenPage, _eHoriOrient, _eRelOrient ) ) + { + if( bVert ) + { + const SvxULSpaceItem& rOtherUL = pFly->GetFmt()->GetULSpace(); + const SwTwips nOtherTop = pFly->Frm().Top() - rOtherUL.GetUpper(); + const SwTwips nOtherBot = pFly->Frm().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() - + rAnchorTxtFrm.Frm().Top(); + if ( nTmp > nAdjustedRelPosX && + rAnchorTxtFrm.Frm().Top() + nTmp + + aObjBoundRect.Height() + _rULSpacing.GetLower() + <= pObjPage->Frm().Height() + pObjPage->Frm().Top() ) + { + nAdjustedRelPosX = nTmp; + } + } + else if ( _eHoriOrient == text::HoriOrientation::RIGHT ) + { + SwTwips nTmp = nOtherTop - 1 - _rULSpacing.GetLower() - + aObjBoundRect.Height() - + rAnchorTxtFrm.Frm().Top(); + if ( nTmp < nAdjustedRelPosX && + rAnchorTxtFrm.Frm().Top() + nTmp - _rULSpacing.GetUpper() + >= pObjPage->Frm().Top() ) + { + nAdjustedRelPosX = nTmp; + } + } + aTmpObjRect.Pos().Y() = rAnchorTxtFrm.Frm().Top() + + nAdjustedRelPosX; + } + } + else + { + const SvxLRSpaceItem& rOtherLR = pFly->GetFmt()->GetLRSpace(); + const SwTwips nOtherLeft = pFly->Frm().Left() - rOtherLR.GetLeft(); + const SwTwips nOtherRight = pFly->Frm().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() - + rAnchorTxtFrm.Frm().Left(); + if ( nTmp > nAdjustedRelPosX && + rAnchorTxtFrm.Frm().Left() + nTmp + + aObjBoundRect.Width() + _rLRSpacing.GetRight() + <= pObjPage->Frm().Width() + pObjPage->Frm().Left() ) + { + nAdjustedRelPosX = nTmp; + } + } + else if ( _eHoriOrient == text::HoriOrientation::RIGHT ) + { + SwTwips nTmp = nOtherLeft - 1 - _rLRSpacing.GetRight() - + aObjBoundRect.Width() - + rAnchorTxtFrm.Frm().Left(); + if ( nTmp < nAdjustedRelPosX && + rAnchorTxtFrm.Frm().Left() + nTmp - _rLRSpacing.GetLeft() + >= pObjPage->Frm().Left() ) + { + nAdjustedRelPosX = nTmp; + } + } + aTmpObjRect.Pos().X() = rAnchorTxtFrm.Frm().Left() + + nAdjustedRelPosX; + } + } // end of <if (bVert)> + } // end of <if _DrawAsideFly(..)> + + pFly = ((SwVirtFlyDrawObj*)aIter.Next())->GetFlyFrm(); + } // end of <loop on fly frames + + return nAdjustedRelPosX; +} + +/** detemine, if object has to draw aside given fly frame + + method used by <_AdjustHoriRelPosForDrawAside(..)> + + @author OD +*/ +bool SwAnchoredObjectPosition::_DrawAsideFly( const SwFlyFrm* _pFly, + const SwRect& _rObjRect, + const SwFrm* _pObjContext, + const ULONG _nObjIndex, + const bool _bEvenPage, + const sal_Int16 _eHoriOrient, + const sal_Int16 _eRelOrient + ) const +{ + bool bRetVal = false; + + SWRECTFN( (&GetAnchorFrm()) ) + + if ( _pFly->IsFlyAtCntFrm() && + (_pFly->Frm().*fnRect->fnBottomDist)( (_rObjRect.*fnRect->fnGetTop)() ) < 0 && + (_rObjRect.*fnRect->fnBottomDist)( (_pFly->Frm().*fnRect->fnGetTop)() ) < 0 && + ::FindKontext( _pFly->GetAnchorFrm(), FRM_COLUMN ) == _pObjContext ) + { + ULONG nOtherIndex = + static_cast<const SwTxtFrm*>(_pFly->GetAnchorFrm())->GetTxtNode()->GetIndex(); + if( _nObjIndex >= nOtherIndex ) + { + const SwFmtHoriOrient& rHori = _pFly->GetFmt()->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(..)> + + @author OD +*/ +bool SwAnchoredObjectPosition::_Minor( sal_Int16 _eRelOrient1, + sal_Int16 _eRelOrient2, + bool _bLeft ) const +{ + bool bRetVal; + + // draw aside order for left horizontal position + //! one array entry for each value in text::RelOrientation + static USHORT __READONLY_DATA 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 USHORT __READONLY_DATA 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: */ |