/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 * 
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: svdoashp.cxx,v $
 * $Revision: 1.51.52.2 $
 *
 * 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_svx.hxx"
#include <svx/svdoashp.hxx>
#include "unoapi.hxx"
#include <svx/unoshape.hxx>
#include <ucbhelper/content.hxx>
#include <ucbhelper/contentbroker.hxx>
#include <unotools/datetime.hxx>
#include <sfx2/lnkbase.hxx>
#include <tools/urlobj.hxx>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/drawing/XShape.hpp>
#include <com/sun/star/drawing/XCustomShapeEngine.hpp>
#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
#include <com/sun/star/beans/PropertyValue.hpp>
#include <com/sun/star/awt/Rectangle.hpp>
#include "unopolyhelper.hxx"
#include <comphelper/processfactory.hxx>
#include <svtools/urihelper.hxx>
#include <com/sun/star/uno/Sequence.h>
#include <svx/svdogrp.hxx>
#include <vcl/salbtype.hxx>		// FRound
#include <svx/svddrag.hxx>
#include <svx/xpool.hxx>
#include <svx/xpoly.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdpage.hxx>
#include "svditer.hxx"
#include <svx/svdobj.hxx>
#include <svx/svdtrans.hxx>
#include <svx/svdetc.hxx>
#include <svx/svdattrx.hxx>  // NotPersistItems
#include <svx/svdoedge.hxx>  // #32383# Die Verbinder nach Move nochmal anbroadcasten
#include "svdglob.hxx"   // StringCache
#include "svdstr.hrc"    // Objektname
#include <svx/eeitem.hxx>
#include "editstat.hxx"
#include <svx/svdoutl.hxx>
#include <svx/outlobj.hxx>
#include <svx/sdtfchim.hxx>
#include "../customshapes/EnhancedCustomShapeGeometry.hxx"
#include "../customshapes/EnhancedCustomShapeTypeNames.hxx"
#include "../customshapes/EnhancedCustomShape2d.hxx"
#include <com/sun/star/beans/PropertyValues.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
#include <svx/writingmodeitem.hxx>
#include <svx/xlnclit.hxx>
#include <svx/svxids.hrc>
#include <svtools/whiter.hxx>
#include <svx/sdr/properties/customshapeproperties.hxx>
#include <svx/sdr/contact/viewcontactofsdrobjcustomshape.hxx>
#include <svx/xlnclit.hxx>
#include <svx/xlntrit.hxx>
#include <svx/xfltrit.hxx>
#include <svx/xflclit.hxx>
#include <svx/xflgrit.hxx>
#include <svx/xflhtit.hxx>
#include <svx/xbtmpit.hxx>
#include <vcl/bmpacc.hxx>
#include <svx/svdview.hxx>
#include <basegfx/polygon/b2dpolypolygontools.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>

// #104018# replace macros above with type-safe methods
inline double ImplTwipsToMM(double fVal) { return (fVal * (127.0 / 72.0)); }
inline double ImplMMToTwips(double fVal) { return (fVal * (72.0 / 127.0)); }

using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::drawing;

static MSO_SPT ImpGetCustomShapeType( const SdrObjCustomShape& rCustoShape )
{
	MSO_SPT eRetValue = mso_sptNil;

	rtl::OUString aEngine( ( (SdrCustomShapeEngineItem&)rCustoShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_ENGINE ) ).GetValue() );
	if ( !aEngine.getLength() || aEngine.equalsAscii( "com.sun.star.drawing.EnhancedCustomShapeEngine" ) )
	{
		rtl::OUString sShapeType;
		const rtl::OUString	sType( RTL_CONSTASCII_USTRINGPARAM ( "Type" ) );
		SdrCustomShapeGeometryItem& rGeometryItem( (SdrCustomShapeGeometryItem&)rCustoShape.GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
		Any* pAny = rGeometryItem.GetPropertyValueByName( sType );
		if ( pAny && ( *pAny >>= sShapeType ) )
			eRetValue = EnhancedCustomShapeTypeNames::Get( sShapeType );
	}
	return eRetValue;
};

static sal_Bool ImpVerticalSwitch( const SdrObjCustomShape& rCustoShape )
{
	sal_Bool bRet = sal_False;
	MSO_SPT eShapeType( ImpGetCustomShapeType( rCustoShape ) );
	switch( eShapeType )
	{
		case mso_sptAccentBorderCallout90 :		// 2 ortho
		case mso_sptBorderCallout1 :			// 2 diag
		case mso_sptBorderCallout2 :			// 3
		{
			bRet = sal_True;
		}
		break;
/*
		case mso_sptCallout1 :
		case mso_sptAccentCallout1 :
		case mso_sptAccentBorderCallout1 :
		case mso_sptBorderCallout90 :
		case mso_sptCallout90 :
		case mso_sptAccentCallout90 :
		case mso_sptCallout2 :
		case mso_sptCallout3 :
		case mso_sptAccentCallout2 :
		case mso_sptAccentCallout3 :
		case mso_sptBorderCallout3 :
		case mso_sptAccentBorderCallout2 :
		case mso_sptAccentBorderCallout3 :
*/
		default: break;
	}
	return bRet;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// #i37011# create a clone with all attributes changed to shadow attributes
// and translation executed, too.
SdrObject* ImpCreateShadowObjectClone(const SdrObject& rOriginal, const SfxItemSet& rOriginalSet)
{
	SdrObject* pRetval = 0L;
	const sal_Bool bShadow(((SdrShadowItem&)rOriginalSet.Get(SDRATTR_SHADOW)).GetValue());

	if(bShadow)
	{
		// create a shadow representing object
		const sal_Int32 nXDist(((SdrShadowXDistItem&)(rOriginalSet.Get(SDRATTR_SHADOWXDIST))).GetValue());
		const sal_Int32 nYDist(((SdrShadowYDistItem&)(rOriginalSet.Get(SDRATTR_SHADOWYDIST))).GetValue());
		const ::Color aShadowColor(((SdrShadowColorItem&)(rOriginalSet.Get(SDRATTR_SHADOWCOLOR))).GetColorValue());
		const sal_uInt16 nShadowTransparence(((SdrShadowTransparenceItem&)(rOriginalSet.Get(SDRATTR_SHADOWTRANSPARENCE))).GetValue());
		pRetval = rOriginal.Clone();
		DBG_ASSERT(pRetval, "ImpCreateShadowObjectClone: Could not clone object (!)");

		// look for used stuff
		SdrObjListIter aIterator(rOriginal);
		sal_Bool bLineUsed(sal_False);
		sal_Bool bAllFillUsed(sal_False);
		sal_Bool bSolidFillUsed(sal_False);
		sal_Bool bGradientFillUsed(sal_False);
		sal_Bool bHatchFillUsed(sal_False);
		sal_Bool bBitmapFillUsed(sal_False);

		while(aIterator.IsMore())
		{
			SdrObject* pObj = aIterator.Next();
			XFillStyle eFillStyle = ((XFillStyleItem&)(pObj->GetMergedItem(XATTR_FILLSTYLE))).GetValue();

			if(!bLineUsed)
			{
				XLineStyle eLineStyle = ((XLineStyleItem&)(pObj->GetMergedItem(XATTR_LINESTYLE))).GetValue();

				if(XLINE_NONE != eLineStyle)
				{
					bLineUsed = sal_True;
				}
			}

			if(!bAllFillUsed)
			{
				if(!bSolidFillUsed && XFILL_SOLID == eFillStyle)
				{
					bSolidFillUsed = sal_True;
					bAllFillUsed = (bSolidFillUsed || bGradientFillUsed || bHatchFillUsed || bBitmapFillUsed);
				}
				if(!bGradientFillUsed && XFILL_GRADIENT == eFillStyle)
				{
					bGradientFillUsed = sal_True;
					bAllFillUsed = (bSolidFillUsed || bGradientFillUsed || bHatchFillUsed || bBitmapFillUsed);
				}
				if(!bHatchFillUsed && XFILL_HATCH == eFillStyle)
				{
					bHatchFillUsed = sal_True;
					bAllFillUsed = (bSolidFillUsed || bGradientFillUsed || bHatchFillUsed || bBitmapFillUsed);
				}
				if(!bBitmapFillUsed && XFILL_BITMAP == eFillStyle)
				{
					bBitmapFillUsed = sal_True;
					bAllFillUsed = (bSolidFillUsed || bGradientFillUsed || bHatchFillUsed || bBitmapFillUsed);
				}
			}
		}

		// translate to shadow coordinates
		pRetval->NbcMove(Size(nXDist, nYDist));

		// set items as needed
		SfxItemSet aTempSet(rOriginalSet);

		// SJ: #40108# :-(  if a SvxWritingModeItem (Top->Bottom) is set the text object
		// is creating a paraobject, but paraobjects can not be created without model. So
		// we are preventing the crash by setting the writing mode always left to right,
		// this is not bad since our shadow geometry does not contain text.
        aTempSet.Put( SvxWritingModeItem( com::sun::star::text::WritingMode_LR_TB, SDRATTR_TEXTDIRECTION ) );

		// no shadow
		aTempSet.Put(SdrShadowItem(sal_False));
		aTempSet.Put(SdrShadowXDistItem(0L));
		aTempSet.Put(SdrShadowYDistItem(0L));

		// line color and transparence like shadow
		if(bLineUsed)
		{
			aTempSet.Put(XLineColorItem(String(), aShadowColor));
			aTempSet.Put(XLineTransparenceItem(nShadowTransparence));
		}

		// fill color and transparence like shadow
		if(bSolidFillUsed)
		{
			aTempSet.Put(XFillColorItem(String(), aShadowColor));
			aTempSet.Put(XFillTransparenceItem(nShadowTransparence));
		}

		// gradient and transparence like shadow
		if(bGradientFillUsed)
		{
			XGradient aGradient(((XFillGradientItem&)(rOriginalSet.Get(XATTR_FILLGRADIENT))).GetGradientValue());
			sal_uInt8 nStartLuminance(aGradient.GetStartColor().GetLuminance());
			sal_uInt8 nEndLuminance(aGradient.GetEndColor().GetLuminance());

			if(aGradient.GetStartIntens() != 100)
			{
				nStartLuminance = (sal_uInt8)(nStartLuminance * ((double)aGradient.GetStartIntens() / 100.0));
			}

			if(aGradient.GetEndIntens() != 100)
			{
				nEndLuminance = (sal_uInt8)(nEndLuminance * ((double)aGradient.GetEndIntens() / 100.0));
			}

            ::Color aStartColor(
				(sal_uInt8)((nStartLuminance * aShadowColor.GetRed()) / 256),
				(sal_uInt8)((nStartLuminance * aShadowColor.GetGreen()) / 256),
				(sal_uInt8)((nStartLuminance * aShadowColor.GetBlue()) / 256));

            ::Color aEndColor(
				(sal_uInt8)((nEndLuminance * aShadowColor.GetRed()) / 256),
				(sal_uInt8)((nEndLuminance * aShadowColor.GetGreen()) / 256),
				(sal_uInt8)((nEndLuminance * aShadowColor.GetBlue()) / 256));

			aGradient.SetStartColor(aStartColor);
			aGradient.SetEndColor(aEndColor);
			aTempSet.Put(XFillGradientItem(aTempSet.GetPool(), aGradient));
			aTempSet.Put(XFillTransparenceItem(nShadowTransparence));
		}

		// hatch and transparence like shadow
		if(bHatchFillUsed)
		{
			XHatch aHatch(((XFillHatchItem&)(rOriginalSet.Get(XATTR_FILLHATCH))).GetHatchValue());
			aHatch.SetColor(aShadowColor);
			aTempSet.Put(XFillHatchItem(aTempSet.GetPool(), aHatch));
			aTempSet.Put(XFillTransparenceItem(nShadowTransparence));
		}

		// bitmap and transparence like shadow
		if(bBitmapFillUsed)
		{
			XOBitmap aFillBitmap(((XFillBitmapItem&)(rOriginalSet.Get(XATTR_FILLBITMAP))).GetBitmapValue());
			Bitmap aSourceBitmap(aFillBitmap.GetBitmap());
			BitmapReadAccess* pReadAccess = aSourceBitmap.AcquireReadAccess();

			if(!aSourceBitmap.IsEmpty())
			{
				if(pReadAccess)
				{
					Bitmap aDestBitmap(aSourceBitmap.GetSizePixel(), 24L);
					BitmapWriteAccess* pWriteAccess = aDestBitmap.AcquireWriteAccess();

					if(pWriteAccess)
					{
						for(sal_Int32 y(0L); y < pReadAccess->Height(); y++)
						{
							for(sal_Int32 x(0L); x < pReadAccess->Width(); x++)
							{
								sal_uInt16 nLuminance((sal_uInt16)pReadAccess->GetLuminance(y, x) + 1);
								const BitmapColor aDestColor(
									(sal_uInt8)((nLuminance * (sal_uInt16)aShadowColor.GetRed()) >> 8L),
									(sal_uInt8)((nLuminance * (sal_uInt16)aShadowColor.GetGreen()) >> 8L),
									(sal_uInt8)((nLuminance * (sal_uInt16)aShadowColor.GetBlue()) >> 8L));
								pWriteAccess->SetPixel(y, x, aDestColor);
							}
						}

						aDestBitmap.ReleaseAccess(pWriteAccess);
						aFillBitmap.SetBitmap(aDestBitmap);
					}

					aSourceBitmap.ReleaseAccess(pReadAccess);
				}
			}

			aTempSet.Put(XFillBitmapItem(aTempSet.GetPool(), aFillBitmap));
			aTempSet.Put(XFillTransparenceItem(nShadowTransparence));
		}

		// set attributes and paint shadow object
		pRetval->SetMergedItemSet( aTempSet );
	}
	return pRetval;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

Reference< XCustomShapeEngine > SdrObjCustomShape::GetCustomShapeEngine( const SdrObjCustomShape* pCustomShape )
{
	Reference< XCustomShapeEngine > xCustomShapeEngine;
	String aEngine(((SdrCustomShapeEngineItem&)pCustomShape->GetMergedItem( SDRATTR_CUSTOMSHAPE_ENGINE )).GetValue());
	if ( !aEngine.Len() )
		aEngine = String( RTL_CONSTASCII_USTRINGPARAM ( "com.sun.star.drawing.EnhancedCustomShapeEngine" ) );

	Reference< XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );

	Reference< XShape > aXShape = GetXShapeForSdrObject( (SdrObjCustomShape*)pCustomShape );
	if ( aXShape.is() )
	{
		if ( aEngine.Len() && xFactory.is() )
		{
			Sequence< Any > aArgument( 1 );
			Sequence< PropertyValue > aPropValues( 1 );
			aPropValues[ 0 ].Name = rtl::OUString::createFromAscii( "CustomShape" );
			aPropValues[ 0 ].Value <<= aXShape;
			aArgument[ 0 ] <<= aPropValues;
			Reference< XInterface > xInterface( xFactory->createInstanceWithArguments( aEngine, aArgument ) );
			if ( xInterface.is() )
				xCustomShapeEngine = Reference< XCustomShapeEngine >( xInterface, UNO_QUERY );
		}
	}
	return xCustomShapeEngine;
}
const SdrObject* SdrObjCustomShape::GetSdrObjectFromCustomShape() const
{
	if ( !mXRenderedCustomShape.is() )
	{
		Reference< XCustomShapeEngine > xCustomShapeEngine( GetCustomShapeEngine( this ) );
		if ( xCustomShapeEngine.is() )
			((SdrObjCustomShape*)this)->mXRenderedCustomShape = xCustomShapeEngine->render();
	}
	SdrObject* pRenderedCustomShape = mXRenderedCustomShape.is()
				? GetSdrObjectFromXShape( mXRenderedCustomShape )
				: NULL;
	return pRenderedCustomShape;
}

// #i37011# Shadow geometry creation
const SdrObject* SdrObjCustomShape::GetSdrObjectShadowFromCustomShape() const
{
	if(!mpLastShadowGeometry)
	{
		const SdrObject* pSdrObject = GetSdrObjectFromCustomShape();
		if(pSdrObject)
		{
			const SfxItemSet& rOriginalSet = GetObjectItemSet();
			const sal_Bool bShadow(((SdrShadowItem&)rOriginalSet.Get( SDRATTR_SHADOW )).GetValue());

			if(bShadow)
			{
				// create a clone with all attributes changed to shadow attributes
				// and translation executed, too.
				((SdrObjCustomShape*)this)->mpLastShadowGeometry = ImpCreateShadowObjectClone(*pSdrObject, rOriginalSet);
			}
		}
	}

	return mpLastShadowGeometry;
}

sal_Bool SdrObjCustomShape::IsTextPath() const
{
	const rtl::OUString	sTextPath( RTL_CONSTASCII_USTRINGPARAM ( "TextPath" ) );
	sal_Bool bTextPathOn = sal_False;
	SdrCustomShapeGeometryItem& rGeometryItem = (SdrCustomShapeGeometryItem&)GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
	Any* pAny = rGeometryItem.GetPropertyValueByName( sTextPath, sTextPath );
	if ( pAny )
		*pAny >>= bTextPathOn;
	return bTextPathOn;
}

sal_Bool SdrObjCustomShape::UseNoFillStyle() const
{
	sal_Bool bRet = sal_False;
	rtl::OUString sShapeType;
	const rtl::OUString	sType( RTL_CONSTASCII_USTRINGPARAM ( "Type" ) );
	SdrCustomShapeGeometryItem& rGeometryItem( (SdrCustomShapeGeometryItem&)GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
	Any* pAny = rGeometryItem.GetPropertyValueByName( sType );
	if ( pAny )
		*pAny >>= sShapeType;
	bRet = IsCustomShapeFilledByDefault( EnhancedCustomShapeTypeNames::Get( sType ) ) == 0;

	return bRet;
}

sal_Bool SdrObjCustomShape::IsMirroredX() const
{
	sal_Bool bMirroredX = sal_False;
	SdrCustomShapeGeometryItem aGeometryItem( (SdrCustomShapeGeometryItem&)GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
	const rtl::OUString	sMirroredX( RTL_CONSTASCII_USTRINGPARAM ( "MirroredX" ) );
	com::sun::star::uno::Any* pAny = aGeometryItem.GetPropertyValueByName( sMirroredX );
	if ( pAny )
		*pAny >>= bMirroredX;
	return bMirroredX;
}
sal_Bool SdrObjCustomShape::IsMirroredY() const
{
	sal_Bool bMirroredY = sal_False;
	SdrCustomShapeGeometryItem aGeometryItem( (SdrCustomShapeGeometryItem&)GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
	const rtl::OUString	sMirroredY( RTL_CONSTASCII_USTRINGPARAM ( "MirroredY" ) );
	com::sun::star::uno::Any* pAny = aGeometryItem.GetPropertyValueByName( sMirroredY );
	if ( pAny )
		*pAny >>= bMirroredY;
	return bMirroredY;
}
void SdrObjCustomShape::SetMirroredX( const sal_Bool bMirrorX )
{
	SdrCustomShapeGeometryItem aGeometryItem( (SdrCustomShapeGeometryItem&)GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
	const rtl::OUString	sMirroredX( RTL_CONSTASCII_USTRINGPARAM ( "MirroredX" ) );
	//com::sun::star::uno::Any* pAny = aGeometryItem.GetPropertyValueByName( sMirroredX );
	PropertyValue aPropVal;
	aPropVal.Name = sMirroredX;
	aPropVal.Value <<= bMirrorX;
	aGeometryItem.SetPropertyValue( aPropVal );
	SetMergedItem( aGeometryItem );
}
void SdrObjCustomShape::SetMirroredY( const sal_Bool bMirrorY )
{
	SdrCustomShapeGeometryItem aGeometryItem( (SdrCustomShapeGeometryItem&)GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
	const rtl::OUString	sMirroredY( RTL_CONSTASCII_USTRINGPARAM ( "MirroredY" ) );
	//com::sun::star::uno::Any* pAny = aGeometryItem.GetPropertyValueByName( sMirroredY );
	PropertyValue aPropVal;
	aPropVal.Name = sMirroredY;
	aPropVal.Value <<= bMirrorY;
	aGeometryItem.SetPropertyValue( aPropVal );
	SetMergedItem( aGeometryItem );
}

double SdrObjCustomShape::GetObjectRotation() const
{
	return fObjectRotation;
}

double SdrObjCustomShape::GetExtraTextRotation() const
{
	const com::sun::star::uno::Any* pAny;
	SdrCustomShapeGeometryItem& rGeometryItem = (SdrCustomShapeGeometryItem&)GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
	const rtl::OUString sTextRotateAngle( RTL_CONSTASCII_USTRINGPARAM ( "TextRotateAngle" ) );
	pAny = rGeometryItem.GetPropertyValueByName( sTextRotateAngle );
	double fExtraTextRotateAngle = 0.0;
	if ( pAny )
		*pAny >>= fExtraTextRotateAngle;
	return fExtraTextRotateAngle;
}
sal_Bool SdrObjCustomShape::GetTextBounds( Rectangle& rTextBound ) const
{
	sal_Bool bRet = sal_False;
	Reference< XCustomShapeEngine > xCustomShapeEngine( GetCustomShapeEngine( this ) );	// a candidate for being cached
	if ( xCustomShapeEngine.is() )
	{
		awt::Rectangle aR( xCustomShapeEngine->getTextBounds() );
		if ( aR.Width || aR.Height )
		{
			rTextBound = Rectangle( Point( aR.X, aR.Y ), Size( aR.Width, aR.Height ) );
			bRet = sal_True;
		}
	}
	return bRet;
}
basegfx::B2DPolyPolygon SdrObjCustomShape::GetLineGeometry( const SdrObjCustomShape* pCustomShape, const sal_Bool bBezierAllowed )
{
	basegfx::B2DPolyPolygon aRetval;
	sal_Bool bRet = sal_False;
	Reference< XCustomShapeEngine > xCustomShapeEngine( GetCustomShapeEngine( pCustomShape ) );
	if ( xCustomShapeEngine.is() )
	{
		com::sun::star::drawing::PolyPolygonBezierCoords aBezierCoords = xCustomShapeEngine->getLineGeometry();
		try
		{
			aRetval = SvxConvertPolyPolygonBezierToB2DPolyPolygon( &aBezierCoords );
			if ( !bBezierAllowed && aRetval.areControlPointsUsed())
			{
				aRetval = basegfx::tools::adaptiveSubdivideByAngle(aRetval);
			}
			bRet = sal_True;
		}
		catch ( const com::sun::star::lang::IllegalArgumentException )
		{
		}
	}
	return aRetval;
}

std::vector< SdrCustomShapeInteraction > SdrObjCustomShape::GetInteractionHandles( const SdrObjCustomShape* pCustomShape ) const
{
	std::vector< SdrCustomShapeInteraction > xRet;
	try
	{
		Reference< XCustomShapeEngine > xCustomShapeEngine( GetCustomShapeEngine( pCustomShape ) );
		if ( xCustomShapeEngine.is() )
		{
			int i;
			Sequence< Reference< XCustomShapeHandle > > xInteractionHandles( xCustomShapeEngine->getInteraction() );
			for ( i = 0; i < xInteractionHandles.getLength(); i++ )
			{
				if ( xInteractionHandles[ i ].is() )
				{
					SdrCustomShapeInteraction aSdrCustomShapeInteraction;
					aSdrCustomShapeInteraction.xInteraction = xInteractionHandles[ i ];
					aSdrCustomShapeInteraction.aPosition = xInteractionHandles[ i ]->getPosition();

					sal_Int32 nMode = 0;
					switch( ImpGetCustomShapeType( *this ) )
					{
						case mso_sptAccentBorderCallout90 :		// 2 ortho
						{
							if ( !i )
								nMode |= CUSTOMSHAPE_HANDLE_RESIZE_FIXED | CUSTOMSHAPE_HANDLE_CREATE_FIXED;
							else if ( i == 1)
								nMode |= CUSTOMSHAPE_HANDLE_RESIZE_ABSOLUTE_X | CUSTOMSHAPE_HANDLE_RESIZE_ABSOLUTE_Y | CUSTOMSHAPE_HANDLE_MOVE_SHAPE | CUSTOMSHAPE_HANDLE_ORTHO4;
						}
						break;

						case mso_sptWedgeRectCallout :
						case mso_sptWedgeRRectCallout :
						case mso_sptCloudCallout :
						case mso_sptWedgeEllipseCallout :
						{
							if ( !i )
								nMode |= CUSTOMSHAPE_HANDLE_RESIZE_FIXED;
						}
						break;

						case mso_sptBorderCallout1 :			// 2 diag
						{
							if ( !i )
								nMode |= CUSTOMSHAPE_HANDLE_RESIZE_FIXED | CUSTOMSHAPE_HANDLE_CREATE_FIXED;
							else if ( i == 1 )
								nMode |= CUSTOMSHAPE_HANDLE_RESIZE_ABSOLUTE_X | CUSTOMSHAPE_HANDLE_RESIZE_ABSOLUTE_Y | CUSTOMSHAPE_HANDLE_MOVE_SHAPE;
						}
						break;
						case mso_sptBorderCallout2 :			// 3
						{
							if ( !i )
								nMode |= CUSTOMSHAPE_HANDLE_RESIZE_FIXED | CUSTOMSHAPE_HANDLE_CREATE_FIXED;
							else if ( i == 2 )
								nMode |= CUSTOMSHAPE_HANDLE_RESIZE_ABSOLUTE_X | CUSTOMSHAPE_HANDLE_RESIZE_ABSOLUTE_Y | CUSTOMSHAPE_HANDLE_MOVE_SHAPE;
						}
						break;
						case mso_sptCallout90 :
						case mso_sptAccentCallout90 :
						case mso_sptBorderCallout90 :
						case mso_sptCallout1 :
						case mso_sptCallout2 :
						case mso_sptCallout3 :
						case mso_sptAccentCallout1 :
						case mso_sptAccentCallout2 :
						case mso_sptAccentCallout3 :
						case mso_sptBorderCallout3 :
						case mso_sptAccentBorderCallout1 :
						case mso_sptAccentBorderCallout2 :
						case mso_sptAccentBorderCallout3 :
						{
							if ( !i )
								nMode |= CUSTOMSHAPE_HANDLE_RESIZE_FIXED | CUSTOMSHAPE_HANDLE_CREATE_FIXED;
						}
						break;
						default: break;
					}
					aSdrCustomShapeInteraction.nMode = nMode;
					xRet.push_back( aSdrCustomShapeInteraction );
				}
			}
		}
	}
	catch( const uno::RuntimeException& )
	{
	}
	return xRet;
}

//////////////////////////////////////////////////////////////////////////////
// BaseProperties section
#define	DEFAULT_MINIMUM_SIGNED_COMPARE	((sal_Int32)0x80000000)
#define	DEFAULT_MAXIMUM_SIGNED_COMPARE	((sal_Int32)0x7fffffff)

sdr::properties::BaseProperties* SdrObjCustomShape::CreateObjectSpecificProperties()
{
	return new sdr::properties::CustomShapeProperties(*this);
}

TYPEINIT1(SdrObjCustomShape,SdrTextObj);
SdrObjCustomShape::SdrObjCustomShape() :
	SdrTextObj(),
	fObjectRotation( 0.0 ),
	mpLastShadowGeometry(0L)
{
	bTextFrame = TRUE;
}

SdrObjCustomShape::~SdrObjCustomShape()
{
	// delete buffered display geometry
	InvalidateRenderGeometry();
}

void SdrObjCustomShape::MergeDefaultAttributes( const rtl::OUString* pType )
{
	PropertyValue aPropVal;
	rtl::OUString sShapeType;
	const rtl::OUString	sType( RTL_CONSTASCII_USTRINGPARAM ( "Type" ) );
	SdrCustomShapeGeometryItem aGeometryItem( (SdrCustomShapeGeometryItem&)GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );
	if ( pType && pType->getLength() )
	{
		sal_Int32 nType = pType->toInt32();
		if ( nType )
			sShapeType = EnhancedCustomShapeTypeNames::Get( static_cast< MSO_SPT >( nType ) );
		else
			sShapeType = *pType;

		aPropVal.Name = sType;
		aPropVal.Value <<= sShapeType;
		aGeometryItem.SetPropertyValue( aPropVal );
	}
	else
	{
		Any *pAny = aGeometryItem.GetPropertyValueByName( sType );
		if ( pAny )
			*pAny >>= sShapeType;
	}
	MSO_SPT eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType );

	const sal_Int32* pDefData = NULL;
	const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( eSpType );
	if ( pDefCustomShape )
		pDefData = pDefCustomShape->pDefData;

	com::sun::star::uno::Sequence< com::sun::star::drawing::EnhancedCustomShapeAdjustmentValue > seqAdjustmentValues;

	//////////////////////
	// AdjustmentValues //
	//////////////////////
	const rtl::OUString	sAdjustmentValues( RTL_CONSTASCII_USTRINGPARAM ( "AdjustmentValues" ) );
	const Any* pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sAdjustmentValues );
	if ( pAny )
		*pAny >>= seqAdjustmentValues;
	if ( pDefCustomShape && pDefData )	// now check if we have to default some adjustment values
	{
		// first check if there are adjustment values are to be appended
		sal_Int32 i, nAdjustmentValues = seqAdjustmentValues.getLength();
		sal_Int32 nAdjustmentDefaults = *pDefData++;
		if ( nAdjustmentDefaults > nAdjustmentValues )
		{
			seqAdjustmentValues.realloc( nAdjustmentDefaults );
			for ( i = nAdjustmentValues; i < nAdjustmentDefaults; i++ )
			{
				seqAdjustmentValues[ i ].Value <<= pDefData[ i ];
				seqAdjustmentValues[ i ].State = com::sun::star::beans::PropertyState_DIRECT_VALUE;	// com::sun::star::beans::PropertyState_DEFAULT_VALUE;
			}
		}
		// check if there are defaulted adjustment values that should be filled the hard coded defaults (pDefValue)
		sal_Int32 nCount = nAdjustmentValues > nAdjustmentDefaults ? nAdjustmentDefaults : nAdjustmentValues;
		for ( i = 0; i < nCount; i++ )
		{
			if ( seqAdjustmentValues[ i ].State != com::sun::star::beans::PropertyState_DIRECT_VALUE )
				seqAdjustmentValues[ i ].Value <<= pDefData[ i ];
		}
	}
	aPropVal.Name = sAdjustmentValues;
	aPropVal.Value <<= seqAdjustmentValues;
	aGeometryItem.SetPropertyValue( aPropVal );

	///////////////
	// Coordsize //
	///////////////
	const rtl::OUString	sViewBox( RTL_CONSTASCII_USTRINGPARAM ( "ViewBox" ) );
	const Any* pViewBox = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sViewBox );
	com::sun::star::awt::Rectangle aViewBox;
	if ( !pViewBox || !(*pViewBox >>= aViewBox ) )
	{
		if ( pDefCustomShape )
		{
			aViewBox.X = 0;
			aViewBox.Y = 0;
			aViewBox.Width = pDefCustomShape->nCoordWidth;
			aViewBox.Height= pDefCustomShape->nCoordHeight;
			aPropVal.Name = sViewBox;
			aPropVal.Value <<= aViewBox;
			aGeometryItem.SetPropertyValue( aPropVal );
		}
	}

	const rtl::OUString	sPath( RTL_CONSTASCII_USTRINGPARAM ( "Path" ) );

	//////////////////////
	// Path/Coordinates //
	//////////////////////
	const rtl::OUString	sCoordinates( RTL_CONSTASCII_USTRINGPARAM ( "Coordinates" ) );
	pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sPath, sCoordinates );
	if ( !pAny && pDefCustomShape && pDefCustomShape->nVertices && pDefCustomShape->pVertices )
	{
		com::sun::star::uno::Sequence< com::sun::star::drawing::EnhancedCustomShapeParameterPair> seqCoordinates;

		sal_Int32 i, nCount = pDefCustomShape->nVertices;
		seqCoordinates.realloc( nCount );
		for ( i = 0; i < nCount; i++ )
		{
			EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqCoordinates[ i ].First, pDefCustomShape->pVertices[ i ].nValA );
			EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqCoordinates[ i ].Second, pDefCustomShape->pVertices[ i ].nValB );
		}
		aPropVal.Name = sCoordinates;
		aPropVal.Value <<= seqCoordinates;
		aGeometryItem.SetPropertyValue( sPath, aPropVal );
	}

	/////////////////////
	// Path/GluePoints //
	/////////////////////
	const rtl::OUString	sGluePoints( RTL_CONSTASCII_USTRINGPARAM ( "GluePoints" ) );
	pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sPath, sGluePoints );
	if ( !pAny && pDefCustomShape && pDefCustomShape->nGluePoints && pDefCustomShape->pGluePoints )
	{
		com::sun::star::uno::Sequence< com::sun::star::drawing::EnhancedCustomShapeParameterPair> seqGluePoints;
		sal_Int32 i, nCount = pDefCustomShape->nGluePoints;
		seqGluePoints.realloc( nCount );
		for ( i = 0; i < nCount; i++ )
		{
			EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqGluePoints[ i ].First, pDefCustomShape->pGluePoints[ i ].nValA );
			EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqGluePoints[ i ].Second, pDefCustomShape->pGluePoints[ i ].nValB );
		}
		aPropVal.Name = sGluePoints;
		aPropVal.Value <<= seqGluePoints;
		aGeometryItem.SetPropertyValue( sPath, aPropVal );
	}

	///////////////////
	// Path/Segments //
	///////////////////
	const rtl::OUString	sSegments( RTL_CONSTASCII_USTRINGPARAM ( "Segments" ) );
	pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sPath, sSegments );
	if ( !pAny && pDefCustomShape && pDefCustomShape->nElements && pDefCustomShape->pElements )
	{
		com::sun::star::uno::Sequence< com::sun::star::drawing::EnhancedCustomShapeSegment > seqSegments;

		sal_Int32 i, nCount = pDefCustomShape->nElements;
		seqSegments.realloc( nCount );
		for ( i = 0; i < nCount; i++ )
		{
			EnhancedCustomShapeSegment& rSegInfo = seqSegments[ i ];
			sal_uInt16 nSDat = pDefCustomShape->pElements[ i ];
			switch( nSDat >> 8 )
			{
				case 0x00 :
				{
					rSegInfo.Command = EnhancedCustomShapeSegmentCommand::LINETO;
					rSegInfo.Count   = nSDat & 0xff;
					if ( !rSegInfo.Count )
						rSegInfo.Count = 1;
				}
				break;
				case 0x20 :
				{
					rSegInfo.Command = EnhancedCustomShapeSegmentCommand::CURVETO;
					rSegInfo.Count   = nSDat & 0xff;
					if ( !rSegInfo.Count )
						rSegInfo.Count = 1;
				}
				break;
				case 0x40 :
				{
					rSegInfo.Command = EnhancedCustomShapeSegmentCommand::MOVETO;
					rSegInfo.Count   = nSDat & 0xff;
					if ( !rSegInfo.Count )
						rSegInfo.Count = 1;
				}
				break;
				case 0x60 :
				{
					rSegInfo.Command = EnhancedCustomShapeSegmentCommand::CLOSESUBPATH;
					rSegInfo.Count   = 0;
				}
				break;
				case 0x80 :
				{
					rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
					rSegInfo.Count   = 0;
				}
				break;
				case 0xa1 :
				{
					rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO;
					rSegInfo.Count   = ( nSDat & 0xff ) / 3;
				}
				break;
				case 0xa2 :
				{
					rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE;
					rSegInfo.Count   = ( nSDat & 0xff ) / 3;
				}
				break;
				case 0xa3 :
				{
					rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ARCTO;
					rSegInfo.Count   = ( nSDat & 0xff ) >> 2;
				}
				break;
				case 0xa4 :
				{
					rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ARC;
					rSegInfo.Count   = ( nSDat & 0xff ) >> 2;
				}
				break;
				case 0xa5 :
				{
					rSegInfo.Command = EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO;
					rSegInfo.Count   = ( nSDat & 0xff ) >> 2;
				}
				break;
				case 0xa6 :
				{
					rSegInfo.Command = EnhancedCustomShapeSegmentCommand::CLOCKWISEARC;
					rSegInfo.Count   = ( nSDat & 0xff ) >> 2;
				}
				break;
				case 0xa7 :
				{
					rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX;
					rSegInfo.Count   = nSDat & 0xff;
				}
				break;
				case 0xa8 :
				{
					rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY;
					rSegInfo.Count   = nSDat & 0xff;
				}
				break;
				case 0xaa :
				{
					rSegInfo.Command = EnhancedCustomShapeSegmentCommand::NOFILL;
					rSegInfo.Count   = 0;
				}
				break;
				case 0xab :
				{
					rSegInfo.Command = EnhancedCustomShapeSegmentCommand::NOSTROKE;
					rSegInfo.Count   = 0;
				}
				break;
				default:
				case 0xf8 :
				{
					rSegInfo.Command = EnhancedCustomShapeSegmentCommand::UNKNOWN;
					rSegInfo.Count   = nSDat;
				}
				break;
			}
		}
		aPropVal.Name = sSegments;
		aPropVal.Value <<= seqSegments;
		aGeometryItem.SetPropertyValue( sPath, aPropVal );
	}

	///////////////////
	// Path/StretchX //
	///////////////////
	const rtl::OUString	sStretchX( RTL_CONSTASCII_USTRINGPARAM ( "StretchX" ) );
	pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sPath, sStretchX );
	if ( !pAny && pDefCustomShape )
	{
		sal_Int32 nXRef = pDefCustomShape->nXRef;
		if ( ( nXRef != DEFAULT_MINIMUM_SIGNED_COMPARE ) )
		{
			aPropVal.Name = sStretchX;
			aPropVal.Value <<= nXRef;
			aGeometryItem.SetPropertyValue( sPath, aPropVal );
		}
	}

	///////////////////
	// Path/StretchY //
	///////////////////
	const rtl::OUString	sStretchY( RTL_CONSTASCII_USTRINGPARAM ( "StretchY" ) );
	pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sPath, sStretchY );
	if ( !pAny && pDefCustomShape )
	{
		sal_Int32 nYRef = pDefCustomShape->nYRef;
		if ( ( nYRef != DEFAULT_MINIMUM_SIGNED_COMPARE ) )
		{
			aPropVal.Name = sStretchY;
			aPropVal.Value <<= nYRef;
			aGeometryItem.SetPropertyValue( sPath, aPropVal );
		}
	}

	/////////////////////
	// Path/TextFrames //
	/////////////////////
	const rtl::OUString	sTextFrames( RTL_CONSTASCII_USTRINGPARAM ( "TextFrames" ) );
	pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sPath, sTextFrames );
	if ( !pAny && pDefCustomShape && pDefCustomShape->nTextRect && pDefCustomShape->pTextRect )
	{
		com::sun::star::uno::Sequence< com::sun::star::drawing::EnhancedCustomShapeTextFrame > seqTextFrames;

		sal_Int32 i, nCount = pDefCustomShape->nTextRect;
		seqTextFrames.realloc( nCount );
		const SvxMSDffTextRectangles* pRectangles = pDefCustomShape->pTextRect;
		for ( i = 0; i < nCount; i++, pRectangles++ )
		{
			EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqTextFrames[ i ].TopLeft.First,	  pRectangles->nPairA.nValA );
			EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqTextFrames[ i ].TopLeft.Second,	  pRectangles->nPairA.nValB );
			EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqTextFrames[ i ].BottomRight.First,  pRectangles->nPairB.nValA );
			EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqTextFrames[ i ].BottomRight.Second, pRectangles->nPairB.nValB );
		}
		aPropVal.Name = sTextFrames;
		aPropVal.Value <<= seqTextFrames;
		aGeometryItem.SetPropertyValue( sPath, aPropVal );
	}

	///////////////
	// Equations //
	///////////////
	const rtl::OUString	sEquations( RTL_CONSTASCII_USTRINGPARAM( "Equations" ) );
	pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sEquations );
	if ( !pAny && pDefCustomShape && pDefCustomShape->nCalculation && pDefCustomShape->pCalculation )
	{
		com::sun::star::uno::Sequence< rtl::OUString > seqEquations;

		sal_Int32 i, nCount = pDefCustomShape->nCalculation;
		seqEquations.realloc( nCount );
		const SvxMSDffCalculationData* pData = pDefCustomShape->pCalculation;
		for ( i = 0; i < nCount; i++, pData++ )
			seqEquations[ i ] = EnhancedCustomShape2d::GetEquation( pData->nFlags, pData->nVal[ 0 ], pData->nVal[ 1 ], pData->nVal[ 2 ] );
		aPropVal.Name = sEquations;
		aPropVal.Value <<= seqEquations;
		aGeometryItem.SetPropertyValue( aPropVal );
	}

	/////////////
	// Handles //
	/////////////
	const rtl::OUString	sHandles( RTL_CONSTASCII_USTRINGPARAM( "Handles" ) );
	pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sHandles );
	if ( !pAny && pDefCustomShape && pDefCustomShape->nHandles && pDefCustomShape->pHandles )
	{
		com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValues > seqHandles;

		sal_Int32 i, n, nCount = pDefCustomShape->nHandles;
		const SvxMSDffHandle* pData = pDefCustomShape->pHandles;
		seqHandles.realloc( nCount );
		for ( i = 0; i < nCount; i++, pData++ )
		{
			sal_Int32 nPropertiesNeeded = 1;	// position is always needed
			sal_Int32 nFlags = pData->nFlags;
			if ( nFlags & MSDFF_HANDLE_FLAGS_MIRRORED_X )
				nPropertiesNeeded++;
			if ( nFlags & MSDFF_HANDLE_FLAGS_MIRRORED_Y )
				nPropertiesNeeded++;
			if ( nFlags & MSDFF_HANDLE_FLAGS_SWITCHED )
				nPropertiesNeeded++;
			if ( nFlags & MSDFF_HANDLE_FLAGS_POLAR )
			{
				nPropertiesNeeded++;
				if ( nFlags & MSDFF_HANDLE_FLAGS_RADIUS_RANGE )
				{
					if ( pData->nRangeXMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
						nPropertiesNeeded++;
					if ( pData->nRangeXMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
						nPropertiesNeeded++;
				}
			}
			else if ( nFlags & MSDFF_HANDLE_FLAGS_RANGE )
			{
				if ( pData->nRangeXMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
					nPropertiesNeeded++;
				if ( pData->nRangeXMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
					nPropertiesNeeded++;
				if ( pData->nRangeYMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
					nPropertiesNeeded++;
				if ( pData->nRangeYMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
					nPropertiesNeeded++;
			}

			n = 0;
			com::sun::star::beans::PropertyValues& rPropValues = seqHandles[ i ];
			rPropValues.realloc( nPropertiesNeeded );

			// POSITION
			{
				const rtl::OUString	sPosition( RTL_CONSTASCII_USTRINGPARAM ( "Position" ) );
				::com::sun::star::drawing::EnhancedCustomShapeParameterPair aPosition;
				EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.First, pData->nPositionX, sal_True, sal_True );
				EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.Second, pData->nPositionY, sal_True, sal_False );
				rPropValues[ n ].Name = sPosition;
				rPropValues[ n++ ].Value <<= aPosition;
			}
			if ( nFlags & MSDFF_HANDLE_FLAGS_MIRRORED_X )
			{
				const rtl::OUString	sMirroredX( RTL_CONSTASCII_USTRINGPARAM ( "MirroredX" ) );
				sal_Bool bMirroredX = sal_True;
				rPropValues[ n ].Name = sMirroredX;
				rPropValues[ n++ ].Value <<= bMirroredX;
			}
			if ( nFlags & MSDFF_HANDLE_FLAGS_MIRRORED_Y )
			{
				const rtl::OUString	sMirroredY( RTL_CONSTASCII_USTRINGPARAM ( "MirroredY" ) );
				sal_Bool bMirroredY = sal_True;
				rPropValues[ n ].Name = sMirroredY;
				rPropValues[ n++ ].Value <<= bMirroredY;
			}
			if ( nFlags & MSDFF_HANDLE_FLAGS_SWITCHED )
			{
				const rtl::OUString	sSwitched( RTL_CONSTASCII_USTRINGPARAM ( "Switched" ) );
				sal_Bool bSwitched = sal_True;
				rPropValues[ n ].Name = sSwitched;
				rPropValues[ n++ ].Value <<= bSwitched;
			}
			if ( nFlags & MSDFF_HANDLE_FLAGS_POLAR )
			{
				const rtl::OUString	sPolar( RTL_CONSTASCII_USTRINGPARAM ( "Polar" ) );
				::com::sun::star::drawing::EnhancedCustomShapeParameterPair aCenter;
				EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aCenter.First,  pData->nCenterX,
					( nFlags & MSDFF_HANDLE_FLAGS_CENTER_X_IS_SPECIAL ) != 0, sal_True  );
				EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aCenter.Second, pData->nCenterY,
					( nFlags & MSDFF_HANDLE_FLAGS_CENTER_Y_IS_SPECIAL ) != 0, sal_False );
				rPropValues[ n ].Name = sPolar;
				rPropValues[ n++ ].Value <<= aCenter;
				if ( nFlags & MSDFF_HANDLE_FLAGS_RADIUS_RANGE )
				{
					if ( pData->nRangeXMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
					{
						const rtl::OUString	sRadiusRangeMinimum( RTL_CONSTASCII_USTRINGPARAM ( "RadiusRangeMinimum" ) );
						::com::sun::star::drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum;
						EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMinimum, pData->nRangeXMin,
							( nFlags & MSDFF_HANDLE_FLAGS_RANGE_X_MIN_IS_SPECIAL ) != 0, sal_True  );
						rPropValues[ n ].Name = sRadiusRangeMinimum;
						rPropValues[ n++ ].Value <<= aRadiusRangeMinimum;
					}
					if ( pData->nRangeXMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
					{
						const rtl::OUString	sRadiusRangeMaximum( RTL_CONSTASCII_USTRINGPARAM ( "RadiusRangeMaximum" ) );
						::com::sun::star::drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum;
						EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMaximum, pData->nRangeXMax,
							( nFlags & MSDFF_HANDLE_FLAGS_RANGE_X_MAX_IS_SPECIAL ) != 0, sal_False );
						rPropValues[ n ].Name = sRadiusRangeMaximum;
						rPropValues[ n++ ].Value <<= aRadiusRangeMaximum;
					}
				}
			}
			else if ( nFlags & MSDFF_HANDLE_FLAGS_RANGE )
			{
				if ( pData->nRangeXMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
				{
					const rtl::OUString	sRangeXMinimum( RTL_CONSTASCII_USTRINGPARAM ( "RangeXMinimum" ) );
					::com::sun::star::drawing::EnhancedCustomShapeParameter aRangeXMinimum;
					EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMinimum, pData->nRangeXMin,
						( nFlags & MSDFF_HANDLE_FLAGS_RANGE_X_MIN_IS_SPECIAL ) != 0, sal_True  );
					rPropValues[ n ].Name = sRangeXMinimum;
					rPropValues[ n++ ].Value <<= aRangeXMinimum;
				}
				if ( pData->nRangeXMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
				{
					const rtl::OUString	sRangeXMaximum( RTL_CONSTASCII_USTRINGPARAM ( "RangeXMaximum" ) );
					::com::sun::star::drawing::EnhancedCustomShapeParameter aRangeXMaximum;
					EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMaximum, pData->nRangeXMax,
						( nFlags & MSDFF_HANDLE_FLAGS_RANGE_X_MAX_IS_SPECIAL ) != 0, sal_False );
					rPropValues[ n ].Name = sRangeXMaximum;
					rPropValues[ n++ ].Value <<= aRangeXMaximum;
				}
				if ( pData->nRangeYMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
				{
					const rtl::OUString	sRangeYMinimum( RTL_CONSTASCII_USTRINGPARAM ( "RangeYMinimum" ) );
					::com::sun::star::drawing::EnhancedCustomShapeParameter aRangeYMinimum;
					EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMinimum, pData->nRangeYMin,
						( nFlags & MSDFF_HANDLE_FLAGS_RANGE_Y_MIN_IS_SPECIAL ) != 0, sal_True );
					rPropValues[ n ].Name = sRangeYMinimum;
					rPropValues[ n++ ].Value <<= aRangeYMinimum;
				}
				if ( pData->nRangeYMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
				{
					const rtl::OUString	sRangeYMaximum( RTL_CONSTASCII_USTRINGPARAM ( "RangeYMaximum" ) );
					::com::sun::star::drawing::EnhancedCustomShapeParameter aRangeYMaximum;
					EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMaximum, pData->nRangeYMax,
						( nFlags & MSDFF_HANDLE_FLAGS_RANGE_Y_MAX_IS_SPECIAL ) != 0, sal_False );
					rPropValues[ n ].Name = sRangeYMaximum;
					rPropValues[ n++ ].Value <<= aRangeYMaximum;
				}
			}
		}
		aPropVal.Name = sHandles;
		aPropVal.Value <<= seqHandles;
		aGeometryItem.SetPropertyValue( aPropVal );
	}
	SetMergedItem( aGeometryItem );
}

sal_Bool SdrObjCustomShape::IsDefaultGeometry( const DefaultType eDefaultType ) const
{
	sal_Bool bIsDefaultGeometry = sal_False;

	PropertyValue aPropVal;
	rtl::OUString sShapeType;
	const rtl::OUString	sType( RTL_CONSTASCII_USTRINGPARAM ( "Type" ) );
	SdrCustomShapeGeometryItem aGeometryItem( (SdrCustomShapeGeometryItem&)GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );

	Any *pAny = aGeometryItem.GetPropertyValueByName( sType );
	if ( pAny )
		*pAny >>= sShapeType;

	MSO_SPT eSpType = EnhancedCustomShapeTypeNames::Get( sShapeType );

	const mso_CustomShape* pDefCustomShape = GetCustomShapeContent( eSpType );
	const rtl::OUString	sPath( RTL_CONSTASCII_USTRINGPARAM ( "Path" ) );
	switch( eDefaultType )
	{
		case DEFAULT_VIEWBOX :
		{
			const rtl::OUString	sViewBox( RTL_CONSTASCII_USTRINGPARAM ( "ViewBox" ) );
			const Any* pViewBox = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sViewBox );
			com::sun::star::awt::Rectangle aViewBox;
			if ( pViewBox && ( *pViewBox >>= aViewBox ) )
			{
				if ( ( aViewBox.Width == pDefCustomShape->nCoordWidth )
					&& ( aViewBox.Height == pDefCustomShape->nCoordHeight ) )
					bIsDefaultGeometry = sal_True;
			}
		}
		break;

		case DEFAULT_PATH :
		{
			const rtl::OUString	sCoordinates( RTL_CONSTASCII_USTRINGPARAM ( "Coordinates" ) );
			pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sPath, sCoordinates );
			if ( pAny && pDefCustomShape && pDefCustomShape->nVertices && pDefCustomShape->pVertices )
			{
				com::sun::star::uno::Sequence< com::sun::star::drawing::EnhancedCustomShapeParameterPair> seqCoordinates1, seqCoordinates2;
				if ( *pAny >>= seqCoordinates1 )
				{
					sal_Int32 i, nCount = pDefCustomShape->nVertices;
					seqCoordinates2.realloc( nCount );
					for ( i = 0; i < nCount; i++ )
					{
						EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqCoordinates2[ i ].First, pDefCustomShape->pVertices[ i ].nValA );
						EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqCoordinates2[ i ].Second, pDefCustomShape->pVertices[ i ].nValB );
					}
					if ( seqCoordinates1 == seqCoordinates2 )
						bIsDefaultGeometry = sal_True;
				}
			}
			else if ( pDefCustomShape && ( ( pDefCustomShape->nVertices == 0 ) || ( pDefCustomShape->pVertices == 0 ) ) )
				bIsDefaultGeometry = sal_True;
		}
		break;

		case DEFAULT_GLUEPOINTS :
		{
			const rtl::OUString	sGluePoints( RTL_CONSTASCII_USTRINGPARAM ( "GluePoints" ) );
			pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sPath, sGluePoints );
			if ( pAny && pDefCustomShape && pDefCustomShape->nGluePoints && pDefCustomShape->pGluePoints )
			{
				com::sun::star::uno::Sequence< com::sun::star::drawing::EnhancedCustomShapeParameterPair> seqGluePoints1, seqGluePoints2;
				if ( *pAny >>= seqGluePoints1 )
				{
					sal_Int32 i, nCount = pDefCustomShape->nGluePoints;
					seqGluePoints2.realloc( nCount );
					for ( i = 0; i < nCount; i++ )
					{
						EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqGluePoints2[ i ].First, pDefCustomShape->pGluePoints[ i ].nValA );
						EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqGluePoints2[ i ].Second, pDefCustomShape->pGluePoints[ i ].nValB );
					}
					if ( seqGluePoints1 == seqGluePoints2 )
						bIsDefaultGeometry = sal_True;
				}
			}
			else if ( pDefCustomShape && ( pDefCustomShape->nGluePoints == 0 ) )
				bIsDefaultGeometry = sal_True;
		}
		break;

		case DEFAULT_SEGMENTS :
		{
			///////////////////
			// Path/Segments //
			///////////////////
			const rtl::OUString	sSegments( RTL_CONSTASCII_USTRINGPARAM ( "Segments" ) );
			pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sPath, sSegments );
			if ( pAny )
			{
				com::sun::star::uno::Sequence< com::sun::star::drawing::EnhancedCustomShapeSegment > seqSegments1, seqSegments2;
				if ( *pAny >>= seqSegments1 )
				{
					if ( pDefCustomShape && pDefCustomShape->nElements && pDefCustomShape->pElements )
					{
						sal_Int32 i, nCount = pDefCustomShape->nElements;
						if ( nCount )
						{
							seqSegments2.realloc( nCount );
							for ( i = 0; i < nCount; i++ )
							{
								EnhancedCustomShapeSegment& rSegInfo = seqSegments2[ i ];
								sal_uInt16 nSDat = pDefCustomShape->pElements[ i ];
								switch( nSDat >> 8 )
								{
									case 0x00 :
									{
										rSegInfo.Command = EnhancedCustomShapeSegmentCommand::LINETO;
										rSegInfo.Count   = nSDat & 0xff;
										if ( !rSegInfo.Count )
											rSegInfo.Count = 1;
									}
									break;
									case 0x20 :
									{
										rSegInfo.Command = EnhancedCustomShapeSegmentCommand::CURVETO;
										rSegInfo.Count   = nSDat & 0xff;
										if ( !rSegInfo.Count )
											rSegInfo.Count = 1;
									}
									break;
									case 0x40 :
									{
										rSegInfo.Command = EnhancedCustomShapeSegmentCommand::MOVETO;
										rSegInfo.Count   = nSDat & 0xff;
										if ( !rSegInfo.Count )
											rSegInfo.Count = 1;
									}
									break;
									case 0x60 :
									{
										rSegInfo.Command = EnhancedCustomShapeSegmentCommand::CLOSESUBPATH;
										rSegInfo.Count   = 0;
									}
									break;
									case 0x80 :
									{
										rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
										rSegInfo.Count   = 0;
									}
									break;
									case 0xa1 :
									{
										rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO;
										rSegInfo.Count   = ( nSDat & 0xff ) / 3;
									}
									break;
									case 0xa2 :
									{
										rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE;
										rSegInfo.Count   = ( nSDat & 0xff ) / 3;
									}
									break;
									case 0xa3 :
									{
										rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ARCTO;
										rSegInfo.Count   = ( nSDat & 0xff ) >> 2;
									}
									break;
									case 0xa4 :
									{
										rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ARC;
										rSegInfo.Count   = ( nSDat & 0xff ) >> 2;
									}
									break;
									case 0xa5 :
									{
										rSegInfo.Command = EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO;
										rSegInfo.Count   = ( nSDat & 0xff ) >> 2;
									}
									break;
									case 0xa6 :
									{
										rSegInfo.Command = EnhancedCustomShapeSegmentCommand::CLOCKWISEARC;
										rSegInfo.Count   = ( nSDat & 0xff ) >> 2;
									}
									break;
									case 0xa7 :
									{
										rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX;
										rSegInfo.Count   = nSDat & 0xff;
									}
									break;
									case 0xa8 :
									{
										rSegInfo.Command = EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY;
										rSegInfo.Count   = nSDat & 0xff;
									}
									break;
									case 0xaa :
									{
										rSegInfo.Command = EnhancedCustomShapeSegmentCommand::NOFILL;
										rSegInfo.Count   = 0;
									}
									break;
									case 0xab :
									{
										rSegInfo.Command = EnhancedCustomShapeSegmentCommand::NOSTROKE;
										rSegInfo.Count   = 0;
									}
									break;
									default:
									case 0xf8 :
									{
										rSegInfo.Command = EnhancedCustomShapeSegmentCommand::UNKNOWN;
										rSegInfo.Count   = nSDat;
									}
									break;
								}
							}
							if ( seqSegments1 == seqSegments2 )
								bIsDefaultGeometry = sal_True;
						}
					}
					else
					{
						// check if its the default segment description	( M L Z N )
						if ( seqSegments1.getLength() == 4 )
						{
							if ( ( seqSegments1[ 0 ].Command == EnhancedCustomShapeSegmentCommand::MOVETO )
								&& ( seqSegments1[ 1 ].Command == EnhancedCustomShapeSegmentCommand::LINETO )
								&& ( seqSegments1[ 2 ].Command == EnhancedCustomShapeSegmentCommand::CLOSESUBPATH )
								&& ( seqSegments1[ 3 ].Command == EnhancedCustomShapeSegmentCommand::ENDSUBPATH ) )
								bIsDefaultGeometry = sal_True;
						}
					}
				}
			}
			else if ( pDefCustomShape && ( ( pDefCustomShape->nElements == 0 ) || ( pDefCustomShape->pElements == 0 ) ) )
				bIsDefaultGeometry = sal_True;
		}
		break;

		case DEFAULT_STRETCHX :
		{
			const rtl::OUString	sStretchX( RTL_CONSTASCII_USTRINGPARAM ( "StretchX" ) );
			pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sPath, sStretchX );
			if ( pAny && pDefCustomShape )
			{
				sal_Int32 nStretchX = 0;
				if ( *pAny >>= nStretchX )
				{
					if ( pDefCustomShape->nXRef == nStretchX )
						bIsDefaultGeometry = sal_True;
				}
			}
			else if ( pDefCustomShape && ( pDefCustomShape->nXRef == DEFAULT_MINIMUM_SIGNED_COMPARE ) )
				bIsDefaultGeometry = sal_True;
		}
		break;

		case DEFAULT_STRETCHY :
		{
			const rtl::OUString	sStretchY( RTL_CONSTASCII_USTRINGPARAM ( "StretchY" ) );
			pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sPath, sStretchY );
			if ( pAny && pDefCustomShape )
			{
				sal_Int32 nStretchY = 0;
				if ( *pAny >>= nStretchY )
				{
					if ( pDefCustomShape->nYRef == nStretchY )
						bIsDefaultGeometry = sal_True;
				}
			}
			else if ( pDefCustomShape && ( pDefCustomShape->nYRef == DEFAULT_MINIMUM_SIGNED_COMPARE ) )
				bIsDefaultGeometry = sal_True;
		}
		break;

		case DEFAULT_EQUATIONS :
		{
			const rtl::OUString	sEquations( RTL_CONSTASCII_USTRINGPARAM( "Equations" ) );
			pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sEquations );
			if ( pAny && pDefCustomShape && pDefCustomShape->nCalculation && pDefCustomShape->pCalculation )
			{
				com::sun::star::uno::Sequence< rtl::OUString > seqEquations1, seqEquations2;
				if ( *pAny >>= seqEquations1 )
				{
					sal_Int32 i, nCount = pDefCustomShape->nCalculation;
					seqEquations2.realloc( nCount );

					const SvxMSDffCalculationData* pData = pDefCustomShape->pCalculation;
					for ( i = 0; i < nCount; i++, pData++ )
						seqEquations2[ i ] = EnhancedCustomShape2d::GetEquation( pData->nFlags, pData->nVal[ 0 ], pData->nVal[ 1 ], pData->nVal[ 2 ] );

					if ( seqEquations1 == seqEquations2 )
						bIsDefaultGeometry = sal_True;
				}
			}
			else if ( pDefCustomShape && ( ( pDefCustomShape->nCalculation == 0 ) || ( pDefCustomShape->pCalculation == 0 ) ) )
				bIsDefaultGeometry = sal_True;
		}
		break;

		case DEFAULT_TEXTFRAMES :
		{
			const rtl::OUString	sTextFrames( RTL_CONSTASCII_USTRINGPARAM( "TextFrames" ) );
			pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sPath, sTextFrames );
			if ( pAny && pDefCustomShape && pDefCustomShape->nTextRect && pDefCustomShape->pTextRect )
			{
				com::sun::star::uno::Sequence< com::sun::star::drawing::EnhancedCustomShapeTextFrame > seqTextFrames1, seqTextFrames2;
				if ( *pAny >>= seqTextFrames1 )
				{
					sal_Int32 i, nCount = pDefCustomShape->nTextRect;
					seqTextFrames2.realloc( nCount );
					const SvxMSDffTextRectangles* pRectangles = pDefCustomShape->pTextRect;
					for ( i = 0; i < nCount; i++, pRectangles++ )
					{
						EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqTextFrames2[ i ].TopLeft.First,	  pRectangles->nPairA.nValA );
						EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqTextFrames2[ i ].TopLeft.Second,	  pRectangles->nPairA.nValB );
						EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqTextFrames2[ i ].BottomRight.First,  pRectangles->nPairB.nValA );
						EnhancedCustomShape2d::SetEnhancedCustomShapeParameter( seqTextFrames2[ i ].BottomRight.Second, pRectangles->nPairB.nValB );
					}
					if ( seqTextFrames1 == seqTextFrames2 )
						bIsDefaultGeometry = sal_True;
				}
			}
			else if ( pDefCustomShape && ( ( pDefCustomShape->nTextRect == 0 ) || ( pDefCustomShape->pTextRect == 0 ) ) )
				bIsDefaultGeometry = sal_True;
		}
		break;

		case DEFAULT_HANDLES :
		{
			const rtl::OUString	sHandles( RTL_CONSTASCII_USTRINGPARAM( "Handles" ) );
			pAny = ((SdrCustomShapeGeometryItem&)aGeometryItem).GetPropertyValueByName( sHandles );
			if ( pAny && pDefCustomShape && pDefCustomShape->nHandles && pDefCustomShape->pHandles )
			{
				com::sun::star::uno::Sequence< com::sun::star::beans::PropertyValues > seqHandles1, seqHandles2;
				if ( *pAny >>= seqHandles1 )
				{
					sal_Int32 i, n, nCount = pDefCustomShape->nHandles;
					const SvxMSDffHandle* pData = pDefCustomShape->pHandles;
					seqHandles2.realloc( nCount );
					for ( i = 0; i < nCount; i++, pData++ )
					{
						sal_Int32 nPropertiesNeeded = 1;	// position is always needed
						sal_Int32 nFlags = pData->nFlags;
						if ( nFlags & MSDFF_HANDLE_FLAGS_MIRRORED_X )
							nPropertiesNeeded++;
						if ( nFlags & MSDFF_HANDLE_FLAGS_MIRRORED_Y )
							nPropertiesNeeded++;
						if ( nFlags & MSDFF_HANDLE_FLAGS_SWITCHED )
							nPropertiesNeeded++;
						if ( nFlags & MSDFF_HANDLE_FLAGS_POLAR )
						{
							nPropertiesNeeded++;
							if ( nFlags & MSDFF_HANDLE_FLAGS_RADIUS_RANGE )
							{
								if ( pData->nRangeXMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
									nPropertiesNeeded++;
								if ( pData->nRangeXMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
									nPropertiesNeeded++;
							}
						}
						else if ( nFlags & MSDFF_HANDLE_FLAGS_RANGE )
						{
							if ( pData->nRangeXMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
								nPropertiesNeeded++;
							if ( pData->nRangeXMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
								nPropertiesNeeded++;
							if ( pData->nRangeYMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
								nPropertiesNeeded++;
							if ( pData->nRangeYMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
								nPropertiesNeeded++;
						}

						n = 0;
						com::sun::star::beans::PropertyValues& rPropValues = seqHandles2[ i ];
						rPropValues.realloc( nPropertiesNeeded );

						// POSITION
						{
							const rtl::OUString	sPosition( RTL_CONSTASCII_USTRINGPARAM ( "Position" ) );
							::com::sun::star::drawing::EnhancedCustomShapeParameterPair aPosition;
							EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.First, pData->nPositionX, sal_True, sal_True );
							EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aPosition.Second, pData->nPositionY, sal_True, sal_False );
							rPropValues[ n ].Name = sPosition;
							rPropValues[ n++ ].Value <<= aPosition;
						}
						if ( nFlags & MSDFF_HANDLE_FLAGS_MIRRORED_X )
						{
							const rtl::OUString	sMirroredX( RTL_CONSTASCII_USTRINGPARAM ( "MirroredX" ) );
							sal_Bool bMirroredX = sal_True;
							rPropValues[ n ].Name = sMirroredX;
							rPropValues[ n++ ].Value <<= bMirroredX;
						}
						if ( nFlags & MSDFF_HANDLE_FLAGS_MIRRORED_Y )
						{
							const rtl::OUString	sMirroredY( RTL_CONSTASCII_USTRINGPARAM ( "MirroredY" ) );
							sal_Bool bMirroredY = sal_True;
							rPropValues[ n ].Name = sMirroredY;
							rPropValues[ n++ ].Value <<= bMirroredY;
						}
						if ( nFlags & MSDFF_HANDLE_FLAGS_SWITCHED )
						{
							const rtl::OUString	sSwitched( RTL_CONSTASCII_USTRINGPARAM ( "Switched" ) );
							sal_Bool bSwitched = sal_True;
							rPropValues[ n ].Name = sSwitched;
							rPropValues[ n++ ].Value <<= bSwitched;
						}
						if ( nFlags & MSDFF_HANDLE_FLAGS_POLAR )
						{
							const rtl::OUString	sPolar( RTL_CONSTASCII_USTRINGPARAM ( "Polar" ) );
							::com::sun::star::drawing::EnhancedCustomShapeParameterPair aCenter;
							EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aCenter.First,  pData->nCenterX,
								( nFlags & MSDFF_HANDLE_FLAGS_CENTER_X_IS_SPECIAL ) != 0, sal_True  );
							EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aCenter.Second, pData->nCenterY,
								( nFlags & MSDFF_HANDLE_FLAGS_CENTER_Y_IS_SPECIAL ) != 0, sal_False );
							rPropValues[ n ].Name = sPolar;
							rPropValues[ n++ ].Value <<= aCenter;
							if ( nFlags & MSDFF_HANDLE_FLAGS_RADIUS_RANGE )
							{
								if ( pData->nRangeXMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
								{
									const rtl::OUString	sRadiusRangeMinimum( RTL_CONSTASCII_USTRINGPARAM ( "RadiusRangeMinimum" ) );
									::com::sun::star::drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum;
									EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMinimum, pData->nRangeXMin,
										( nFlags & MSDFF_HANDLE_FLAGS_RANGE_X_MIN_IS_SPECIAL ) != 0, sal_True  );
									rPropValues[ n ].Name = sRadiusRangeMinimum;
									rPropValues[ n++ ].Value <<= aRadiusRangeMinimum;
								}
								if ( pData->nRangeXMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
								{
									const rtl::OUString	sRadiusRangeMaximum( RTL_CONSTASCII_USTRINGPARAM ( "RadiusRangeMaximum" ) );
									::com::sun::star::drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum;
									EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRadiusRangeMaximum, pData->nRangeXMax,
										( nFlags & MSDFF_HANDLE_FLAGS_RANGE_X_MAX_IS_SPECIAL ) != 0, sal_False );
									rPropValues[ n ].Name = sRadiusRangeMaximum;
									rPropValues[ n++ ].Value <<= aRadiusRangeMaximum;
								}
							}
						}
						else if ( nFlags & MSDFF_HANDLE_FLAGS_RANGE )
						{
							if ( pData->nRangeXMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
							{
								const rtl::OUString	sRangeXMinimum( RTL_CONSTASCII_USTRINGPARAM ( "RangeXMinimum" ) );
								::com::sun::star::drawing::EnhancedCustomShapeParameter aRangeXMinimum;
								EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMinimum, pData->nRangeXMin,
									( nFlags & MSDFF_HANDLE_FLAGS_RANGE_X_MIN_IS_SPECIAL ) != 0, sal_True  );
								rPropValues[ n ].Name = sRangeXMinimum;
								rPropValues[ n++ ].Value <<= aRangeXMinimum;
							}
							if ( pData->nRangeXMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
							{
								const rtl::OUString	sRangeXMaximum( RTL_CONSTASCII_USTRINGPARAM ( "RangeXMaximum" ) );
								::com::sun::star::drawing::EnhancedCustomShapeParameter aRangeXMaximum;
								EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeXMaximum, pData->nRangeXMax,
									( nFlags & MSDFF_HANDLE_FLAGS_RANGE_X_MAX_IS_SPECIAL ) != 0, sal_False );
								rPropValues[ n ].Name = sRangeXMaximum;
								rPropValues[ n++ ].Value <<= aRangeXMaximum;
							}
							if ( pData->nRangeYMin != DEFAULT_MINIMUM_SIGNED_COMPARE )
							{
								const rtl::OUString	sRangeYMinimum( RTL_CONSTASCII_USTRINGPARAM ( "RangeYMinimum" ) );
								::com::sun::star::drawing::EnhancedCustomShapeParameter aRangeYMinimum;
								EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMinimum, pData->nRangeYMin,
									( nFlags & MSDFF_HANDLE_FLAGS_RANGE_Y_MIN_IS_SPECIAL ) != 0, sal_True );
								rPropValues[ n ].Name = sRangeYMinimum;
								rPropValues[ n++ ].Value <<= aRangeYMinimum;
							}
							if ( pData->nRangeYMax != DEFAULT_MAXIMUM_SIGNED_COMPARE )
							{
								const rtl::OUString	sRangeYMaximum( RTL_CONSTASCII_USTRINGPARAM ( "RangeYMaximum" ) );
								::com::sun::star::drawing::EnhancedCustomShapeParameter aRangeYMaximum;
								EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter( aRangeYMaximum, pData->nRangeYMax,
									( nFlags & MSDFF_HANDLE_FLAGS_RANGE_Y_MAX_IS_SPECIAL ) != 0, sal_False );
								rPropValues[ n ].Name = sRangeYMaximum;
								rPropValues[ n++ ].Value <<= aRangeYMaximum;
							}
						}
					}
					if ( seqHandles1 == seqHandles2 )
						bIsDefaultGeometry = sal_True;
				}
			}
			else if ( pDefCustomShape && ( ( pDefCustomShape->nHandles == 0 ) || ( pDefCustomShape->pHandles == 0 ) ) )
				bIsDefaultGeometry = sal_True;
		}
		break;
	}
	return bIsDefaultGeometry;
}

void SdrObjCustomShape::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
{
	rInfo.bResizeFreeAllowed=fObjectRotation == 0.0;
	rInfo.bResizePropAllowed=TRUE;
	rInfo.bRotateFreeAllowed=TRUE;
	rInfo.bRotate90Allowed  =TRUE;
	rInfo.bMirrorFreeAllowed=TRUE;
	rInfo.bMirror45Allowed  =TRUE;
	rInfo.bMirror90Allowed  =TRUE;
	rInfo.bTransparenceAllowed = FALSE;
	rInfo.bGradientAllowed = FALSE;
	rInfo.bShearAllowed     =FALSE;
	rInfo.bEdgeRadiusAllowed=FALSE;
	rInfo.bNoContortion     =TRUE;

	// #i37011#
	if ( mXRenderedCustomShape.is() )
	{
		const SdrObject* pRenderedCustomShape = GetSdrObjectFromXShape( mXRenderedCustomShape );
		if ( pRenderedCustomShape )
		{
			// #i37262#
			// Iterate self over the contained objects, since there are combinations of
			// polygon and curve objects. In that case, aInfo.bCanConvToPath and
			// aInfo.bCanConvToPoly would be false. What is needed here is an or, not an and.
			SdrObjListIter aIterator(*pRenderedCustomShape);
			while(aIterator.IsMore())
			{
				SdrObject* pCandidate = aIterator.Next();
				SdrObjTransformInfoRec aInfo;
				pCandidate->TakeObjInfo(aInfo);

				// set path and poly conversion if one is possible since
				// this object will first be broken
				const sal_Bool bCanConvToPathOrPoly(aInfo.bCanConvToPath || aInfo.bCanConvToPoly);
				if(rInfo.bCanConvToPath != bCanConvToPathOrPoly)
				{
					rInfo.bCanConvToPath = bCanConvToPathOrPoly;
				}

				if(rInfo.bCanConvToPoly != bCanConvToPathOrPoly)
				{
					rInfo.bCanConvToPoly = bCanConvToPathOrPoly;
				}

				if(rInfo.bCanConvToContour != aInfo.bCanConvToContour)
				{
					rInfo.bCanConvToContour = aInfo.bCanConvToContour;
				}
			}
		}
	}
}

UINT16 SdrObjCustomShape::GetObjIdentifier() const
{
	return UINT16(OBJ_CUSTOMSHAPE);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void SdrObjCustomShape::RecalcSnapRect()
{
	SdrTextObj::RecalcSnapRect();
}
const Rectangle& SdrObjCustomShape::GetSnapRect() const
{
	return SdrTextObj::GetSnapRect();
}
const Rectangle& SdrObjCustomShape::GetCurrentBoundRect() const
{
	return SdrTextObj::GetCurrentBoundRect();
}
const Rectangle& SdrObjCustomShape::GetLogicRect() const
{
	return SdrTextObj::GetLogicRect();
}
void SdrObjCustomShape::NbcSetSnapRect( const Rectangle& rRect )
{
	aRect=rRect;
	ImpJustifyRect(aRect);
	InvalidateRenderGeometry();
	Rectangle aTextBound( aRect );
	if ( GetTextBounds( aTextBound ) )
	{
		if ( pModel==NULL || !pModel->IsPasteResize() )
		{
			long nHDist=GetTextLeftDistance()+GetTextRightDistance();
			long nVDist=GetTextUpperDistance()+GetTextLowerDistance();
			long nTWdt=aTextBound.GetWidth ()-1-nHDist; if (nTWdt<0) nTWdt=0;
			long nTHgt=aTextBound.GetHeight()-1-nVDist; if (nTHgt<0) nTHgt=0;
			if ( IsAutoGrowWidth() )
				NbcSetMinTextFrameWidth( nTWdt );
			if ( IsAutoGrowHeight() )
				NbcSetMinTextFrameHeight( nTHgt );
			NbcAdjustTextFrameWidthAndHeight();
		}
	}
	ImpCheckShear();
	SetRectsDirty();
	SetChanged();
}
void SdrObjCustomShape::SetSnapRect( const Rectangle& rRect )
{
	Rectangle aBoundRect0;
	if ( pUserCall )
		aBoundRect0 = GetLastBoundRect();
	NbcSetSnapRect( rRect );
	BroadcastObjectChange();
	SendUserCall(SDRUSERCALL_RESIZE,aBoundRect0);
}
void SdrObjCustomShape::NbcSetLogicRect( const Rectangle& rRect )
{
	aRect = rRect;
	ImpJustifyRect( aRect );
	InvalidateRenderGeometry();
	Rectangle aTextBound( aRect );
	if ( GetTextBounds( aTextBound ) )
	{
		long nHDist=GetTextLeftDistance()+GetTextRightDistance();
		long nVDist=GetTextUpperDistance()+GetTextLowerDistance();

		long nTWdt=aTextBound.GetWidth()-1-nHDist; if (nTWdt<0) nTWdt=0;
		long nTHgt=aTextBound.GetHeight()-1-nVDist; if (nTHgt<0) nTHgt=0;
		if ( IsAutoGrowWidth() )
			NbcSetMinTextFrameWidth( nTWdt );
		if ( IsAutoGrowHeight() )
			NbcSetMinTextFrameHeight( nTHgt );
		NbcAdjustTextFrameWidthAndHeight();
	}
	SetRectsDirty();
	SetChanged();
}
void SdrObjCustomShape::SetLogicRect( const Rectangle& rRect )
{
	Rectangle aBoundRect0;
	if ( pUserCall )
		aBoundRect0 = GetLastBoundRect();
	NbcSetLogicRect(rRect);
	BroadcastObjectChange();
	SendUserCall(SDRUSERCALL_RESIZE,aBoundRect0);
}
void SdrObjCustomShape::Move( const Size& rSiz )
{
	if ( rSiz.Width() || rSiz.Height() )
	{
		Rectangle aBoundRect0;
		if ( pUserCall )
			aBoundRect0 = GetLastBoundRect();
		// #110094#-14 SendRepaintBroadcast();
		NbcMove(rSiz);
		SetChanged();
		BroadcastObjectChange();
		SendUserCall(SDRUSERCALL_MOVEONLY,aBoundRect0);
	}
}
void SdrObjCustomShape::NbcMove( const Size& rSiz )
{
	SdrTextObj::NbcMove( rSiz );
	if ( mXRenderedCustomShape.is() )
	{
		SdrObject* pRenderedCustomShape = GetSdrObjectFromXShape( mXRenderedCustomShape );
		if ( pRenderedCustomShape )
        {
            // #i97149# the visualisation shape needs to be informed
            // about change, too
            pRenderedCustomShape->ActionChanged();
			pRenderedCustomShape->NbcMove( rSiz );
        }
	}

	// #i37011# adapt geometry shadow
	if(mpLastShadowGeometry)
	{
		mpLastShadowGeometry->NbcMove( rSiz );
	}
}
void SdrObjCustomShape::Resize( const Point& rRef, const Fraction& xFact, const Fraction& yFact )
{
	SdrTextObj::Resize( rRef, xFact, yFact );
}

void SdrObjCustomShape::NbcResize( const Point& rRef, const Fraction& rxFact, const Fraction& ryFact )
{
	Fraction xFact( rxFact );
	Fraction yFact( ryFact );

	// taking care of handles that should not been changed
	Rectangle aOld( aRect );
	std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles( this ) );

	SdrTextObj::NbcResize( rRef, xFact, yFact );

	if ( ( xFact.GetNumerator() != xFact.GetDenominator() )
		|| ( yFact.GetNumerator()!= yFact.GetDenominator() ) )
	{
		if ( ( ( xFact.GetNumerator() < 0 ) && ( xFact.GetDenominator() > 0 ) ) ||
			( ( xFact.GetNumerator() > 0 ) && ( xFact.GetDenominator() < 0 ) ) )
		{
			SetMirroredX( IsMirroredX() == sal_False );
		}
		if ( ( ( yFact.GetNumerator() < 0 ) && ( yFact.GetDenominator() > 0 ) ) ||
			( ( yFact.GetNumerator() > 0 ) && ( yFact.GetDenominator() < 0 ) ) )
		{
			SetMirroredY( IsMirroredY() == sal_False );	
		}
	}

	std::vector< SdrCustomShapeInteraction >::iterator aIter( aInteractionHandles.begin() );
	while ( aIter != aInteractionHandles.end() )
	{
		try
		{
			if ( aIter->nMode & CUSTOMSHAPE_HANDLE_RESIZE_FIXED )
				aIter->xInteraction->setControllerPosition( aIter->aPosition );
			if ( aIter->nMode & CUSTOMSHAPE_HANDLE_RESIZE_ABSOLUTE_X )
			{
				sal_Int32 nX = ( aIter->aPosition.X - aOld.Left() ) + aRect.Left();
				aIter->xInteraction->setControllerPosition( com::sun::star::awt::Point( nX, aIter->xInteraction->getPosition().Y ) );
			}
			if ( aIter->nMode & CUSTOMSHAPE_HANDLE_RESIZE_ABSOLUTE_Y )
			{
				sal_Int32 nY = ( aIter->aPosition.Y - aOld.Top() ) + aRect.Top();
				aIter->xInteraction->setControllerPosition( com::sun::star::awt::Point( aIter->xInteraction->getPosition().X, nY ) );
			}
		}
		catch ( const uno::RuntimeException& )
		{
		}
		aIter++;
	}
	InvalidateRenderGeometry();
}
void SdrObjCustomShape::NbcRotate( const Point& rRef, long nWink, double sn, double cs )
{
	sal_Bool bMirroredX = IsMirroredX();
	sal_Bool bMirroredY = IsMirroredY();

	fObjectRotation = fmod( fObjectRotation, 360.0 );
	if ( fObjectRotation < 0 )
		fObjectRotation = 360 + fObjectRotation;

	// the rotation angle for ashapes is stored in fObjectRotation, this rotation
	// has to be applied to the text object (which is internally using aGeo.nWink).
	SdrTextObj::NbcRotate( aRect.TopLeft(), -aGeo.nDrehWink,		// retrieving the unrotated text object
							sin( (-aGeo.nDrehWink) * F_PI18000 ),
							cos( (-aGeo.nDrehWink) * F_PI18000 ) );
	aGeo.nDrehWink = 0;												// resetting aGeo data
	aGeo.RecalcSinCos();

	long nW = (long)( fObjectRotation * 100 );						// applying our object rotation
	if ( bMirroredX )
		nW = 36000 - nW;
	if ( bMirroredY )
		nW = 18000 - nW;
	nW = nW % 36000;
	if ( nW < 0 )
		nW = 36000 + nW;
	SdrTextObj::NbcRotate( aRect.TopLeft(), nW,						// applying text rotation
							sin( nW * F_PI18000 ),
							cos( nW * F_PI18000 ) );

	int nSwap = 0;
	if ( bMirroredX )
		nSwap ^= 1;
	if ( bMirroredY )
		nSwap ^= 1;

	double fWink = nWink;													// updating to our new object rotation
	fWink /= 100.0;
	fObjectRotation = fmod( nSwap ? fObjectRotation - fWink : fObjectRotation + fWink, 360.0 );
	if ( fObjectRotation < 0 )
		fObjectRotation = 360 + fObjectRotation;

	SdrTextObj::NbcRotate( rRef, nWink, sn, cs );							// applying text rotation
	InvalidateRenderGeometry();
}

void SdrObjCustomShape::NbcMirror( const Point& rRef1, const Point& rRef2 )
{
	// storing horizontal and vertical flipping without modifying the rotate angle

	sal_Bool bHorz = sal_False;
	sal_Bool bVert = sal_False;
	if ( rRef1.X() == rRef2.X() )
		bHorz = sal_True;
	if ( rRef1.Y() == rRef2.Y() )
		bVert = sal_True;
	if ( !bHorz && !bVert )
		bHorz = bVert = sal_True;

	if ( bHorz || bVert )
	{
		SdrCustomShapeGeometryItem aGeometryItem( (SdrCustomShapeGeometryItem&)GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) );

		/////////////////
		// "MirroredX" //
		/////////////////
		if ( bHorz )
		{
			const rtl::OUString	sMirroredX( RTL_CONSTASCII_USTRINGPARAM ( "MirroredX" ) );
			com::sun::star::uno::Any* pAny = aGeometryItem.GetPropertyValueByName( sMirroredX );
			if ( pAny )
			{
				sal_Bool bFlip = sal_Bool();
				if ( *pAny >>= bFlip )
				{
					if ( bFlip )
						bHorz = sal_False;
				}
			}
			PropertyValue aPropVal;
			aPropVal.Name = sMirroredX;
			aPropVal.Value <<= bHorz;
			aGeometryItem.SetPropertyValue( aPropVal );
		}

		/////////////////
		// "MirroredY" //
		/////////////////
		if ( bVert )
		{
			const rtl::OUString	sMirroredY( RTL_CONSTASCII_USTRINGPARAM ( "MirroredY" ) );
			com::sun::star::uno::Any* pAny = aGeometryItem.GetPropertyValueByName( sMirroredY );
			if ( pAny )
			{
				sal_Bool bFlip = sal_Bool();
				if ( *pAny >>= bFlip )
				{
					if ( bFlip )
						bVert = sal_False;
				}
			}
			PropertyValue aPropVal;
			aPropVal.Name = sMirroredY;
			aPropVal.Value <<= bVert;
			aGeometryItem.SetPropertyValue( aPropVal );
		}
		SetMergedItem( aGeometryItem );
	}
	SdrTextObj::NbcMirror( rRef1, rRef2 );
	InvalidateRenderGeometry();
}

void SdrObjCustomShape::Shear( const Point& /*rRef*/, long /*nWink*/, double /*tn*/, FASTBOOL /*bVShear*/)
{
/*
	SdrTextObj::Shear( rRef, nWink, tn, bVShear );
	InvalidateRenderGeometry();
*/
}
void SdrObjCustomShape::NbcShear( const Point& /*rRef*/, long /*nWink*/, double /*tn*/, FASTBOOL /*bVShear*/)
{
/*
	SdrTextObj::NbcShear(rRef,nWink,tn,bVShear);
	InvalidateRenderGeometry();
*/
}

////////////////////////////////////////////////////////////////////////////////////////////////////

// #i38892#
void SdrObjCustomShape::ImpCheckCustomGluePointsAreAdded()
{
	const SdrObject* pSdrObject = GetSdrObjectFromCustomShape();

	if(pSdrObject)
	{
		const SdrGluePointList* pSource = pSdrObject->GetGluePointList();

		if(pSource && pSource->GetCount())
		{
			if(!SdrTextObj::GetGluePointList())
			{
				SdrTextObj::ForceGluePointList();
			}

			const SdrGluePointList* pList = SdrTextObj::GetGluePointList();

			if(pList)
			{
				SdrGluePointList aNewList;
				sal_uInt16 a;

				for(a = 0; a < pSource->GetCount(); a++)
				{
					SdrGluePoint aCopy((*pSource)[a]);
					aCopy.SetUserDefined(FALSE);
					aNewList.Insert(aCopy);
				}

				for(a = 0; a < pList->GetCount(); a++)
				{
					const SdrGluePoint& rCandidate = (*pList)[a];

					if(rCandidate.IsUserDefined())
					{
						aNewList.Insert(rCandidate);
					}
				}

				// copy new list to local. This is NOT very convenient behaviour, the local
				// GluePointList should not be set, but be delivered by using GetGluePointList(),
				// maybe on demand. Since the local object is changed here, this is assumed to
				// be a result of GetGluePointList and thus the list is copied
				if(pPlusData)
				{
					*pPlusData->pGluePoints = aNewList;
				}
			}
		}
	}
}

// #i38892#
const SdrGluePointList* SdrObjCustomShape::GetGluePointList() const
{
	((SdrObjCustomShape*)this)->ImpCheckCustomGluePointsAreAdded();
	return SdrTextObj::GetGluePointList();
}

// #i38892#
//SdrGluePointList* SdrObjCustomShape::GetGluePointList()
//{
//	ImpCheckCustomGluePointsAreAdded();
//	return SdrTextObj::GetGluePointList();
//}

// #i38892#
SdrGluePointList* SdrObjCustomShape::ForceGluePointList()
{
	if(SdrTextObj::ForceGluePointList())
	{
		ImpCheckCustomGluePointsAreAdded();
		return SdrTextObj::ForceGluePointList();
	}
	else
	{
		return 0L;
	}
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

sal_uInt32 SdrObjCustomShape::GetHdlCount() const
{
	const sal_uInt32 nBasicHdlCount(SdrTextObj::GetHdlCount());
	std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles( this ) );
	return ( aInteractionHandles.size() + nBasicHdlCount );
}

SdrHdl* SdrObjCustomShape::GetHdl( sal_uInt32 nHdlNum ) const
{
	SdrHdl* pH = NULL;
	const sal_uInt32 nBasicHdlCount(SdrTextObj::GetHdlCount());

	if ( nHdlNum < nBasicHdlCount )
		pH = SdrTextObj::GetHdl( nHdlNum );
	else
	{
		std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles( this ) );
		const sal_uInt32 nCustomShapeHdlNum(nHdlNum - nBasicHdlCount);

		if ( nCustomShapeHdlNum < aInteractionHandles.size() )
		{
			if ( aInteractionHandles[ nCustomShapeHdlNum ].xInteraction.is() )
			{
				try
				{
					com::sun::star::awt::Point aPosition( aInteractionHandles[ nCustomShapeHdlNum ].xInteraction->getPosition() );
					pH = new SdrHdl( Point( aPosition.X, aPosition.Y ), HDL_CUSTOMSHAPE1 );
					pH->SetPointNum( nCustomShapeHdlNum );
					pH->SetObj( (SdrObject*)this );
				}
				catch ( const uno::RuntimeException& )
				{
				}
			}
		}
	}
	return pH;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

bool SdrObjCustomShape::hasSpecialDrag() const
{
	return true;
}

bool SdrObjCustomShape::beginSpecialDrag(SdrDragStat& rDrag) const
{
	const SdrHdl* pHdl = rDrag.GetHdl();

    if(pHdl && HDL_CUSTOMSHAPE1 == pHdl->GetKind())
	{
		rDrag.SetEndDragChangesAttributes(true);
		rDrag.SetNoSnap(true);
	}
	else
	{
		const SdrHdl* pHdl2 = rDrag.GetHdl();
		const SdrHdlKind eHdl((pHdl2 == NULL) ? HDL_MOVE : pHdl2->GetKind());

        switch( eHdl )
		{
			case HDL_UPLFT :
			case HDL_UPPER :
			case HDL_UPRGT :
			case HDL_LEFT  :
			case HDL_RIGHT :
			case HDL_LWLFT :
			case HDL_LOWER :
			case HDL_LWRGT :
			case HDL_MOVE  :
			{
    			break;
			}
			default:
            {
				return false;
            }
		}
	}

    return true;
}

void SdrObjCustomShape::DragResizeCustomShape( const Rectangle& rNewRect, SdrObjCustomShape* pObj ) const
{
	Rectangle	aOld( pObj->aRect );
	sal_Bool	bOldMirroredX( pObj->IsMirroredX() );
	sal_Bool	bOldMirroredY( pObj->IsMirroredY() );

	Rectangle aNewRect( rNewRect );
	aNewRect.Justify();

	std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles( pObj ) );

	if ( aNewRect.TopLeft()!= pObj->aRect.TopLeft() &&
		( pObj->aGeo.nDrehWink || pObj->aGeo.nShearWink ) )
	{
		Point aNewPos( aNewRect.TopLeft() );
		if ( pObj->aGeo.nShearWink ) ShearPoint( aNewPos, aOld.TopLeft(), pObj->aGeo.nTan );
		if ( pObj->aGeo.nDrehWink )  RotatePoint(aNewPos, aOld.TopLeft(), pObj->aGeo.nSin, pObj->aGeo.nCos );
		aNewRect.SetPos( aNewPos );
	}
	if ( aNewRect != pObj->aRect )
	{
		pObj->SetLogicRect( aNewRect );
		pObj->InvalidateRenderGeometry();

		if ( rNewRect.Left() > rNewRect.Right() )
		{
			Point aTop( ( pObj->GetSnapRect().Left() + pObj->GetSnapRect().Right() ) >> 1, pObj->GetSnapRect().Top() );
			Point aBottom( aTop.X(), aTop.Y() + 1000 );
			pObj->NbcMirror( aTop, aBottom );

		}
		if ( rNewRect.Top() > rNewRect.Bottom() )
		{
			Point aLeft( pObj->GetSnapRect().Left(), ( pObj->GetSnapRect().Top() + pObj->GetSnapRect().Bottom() ) >> 1 );
			Point aRight( aLeft.X() + 1000, aLeft.Y() );
			pObj->NbcMirror( aLeft, aRight );
		}
		std::vector< SdrCustomShapeInteraction >::iterator aIter( aInteractionHandles.begin() );
		while ( aIter != aInteractionHandles.end() )
		{
			try
			{
				if ( aIter->nMode & CUSTOMSHAPE_HANDLE_RESIZE_FIXED )
					aIter->xInteraction->setControllerPosition( aIter->aPosition );
				if ( aIter->nMode & CUSTOMSHAPE_HANDLE_RESIZE_ABSOLUTE_X )
				{
					sal_Int32 nX;
					if ( bOldMirroredX )
					{
						nX = ( aIter->aPosition.X - aOld.Right() );
						if ( rNewRect.Left() > rNewRect.Right() )
							nX = pObj->aRect.Left() - nX;
						else
							nX += pObj->aRect.Right();
					}
					else
					{
						nX = ( aIter->aPosition.X - aOld.Left() );
						if ( rNewRect.Left() > rNewRect.Right() )
							nX = pObj->aRect.Right() - nX;
						else
							nX += pObj->aRect.Left();
					}
					aIter->xInteraction->setControllerPosition( com::sun::star::awt::Point( nX, aIter->xInteraction->getPosition().Y ) );
				}
				if ( aIter->nMode & CUSTOMSHAPE_HANDLE_RESIZE_ABSOLUTE_Y )
				{
					sal_Int32 nY;
					if ( bOldMirroredY )
					{
						nY = ( aIter->aPosition.Y - aOld.Bottom() );
						if ( rNewRect.Top() > rNewRect.Bottom() )
							nY = pObj->aRect.Top() - nY;
						else
							nY += pObj->aRect.Bottom();
					}
					else
					{
						nY = ( aIter->aPosition.Y - aOld.Top() );
						if ( rNewRect.Top() > rNewRect.Bottom() )
							nY = pObj->aRect.Bottom() - nY;
						else
							nY += pObj->aRect.Top();
					}
					aIter->xInteraction->setControllerPosition( com::sun::star::awt::Point( aIter->xInteraction->getPosition().X, nY ) );
				}
			}
			catch ( const uno::RuntimeException& )
			{
			}
			aIter++;
		}
	}
}

void SdrObjCustomShape::DragMoveCustomShapeHdl( const Point aDestination, const sal_uInt16 nCustomShapeHdlNum, SdrObjCustomShape* pObj ) const
{
	std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles( pObj ) );
	if ( nCustomShapeHdlNum < aInteractionHandles.size() )
	{
		SdrCustomShapeInteraction aInteractionHandle( aInteractionHandles[ nCustomShapeHdlNum ] );
		if ( aInteractionHandle.xInteraction.is() )
		{
			try
			{
				com::sun::star::awt::Point aPt( aDestination.X(), aDestination.Y() );
				if ( aInteractionHandle.nMode & CUSTOMSHAPE_HANDLE_MOVE_SHAPE )
				{
					sal_Int32 nXDiff = aPt.X - aInteractionHandle.aPosition.X;
					sal_Int32 nYDiff = aPt.Y - aInteractionHandle.aPosition.Y;

					pObj->aRect.Move( nXDiff, nYDiff );
					pObj->aOutRect.Move( nXDiff, nYDiff );
					pObj->maSnapRect.Move( nXDiff, nYDiff );
					pObj->SetRectsDirty(sal_True);
					pObj->InvalidateRenderGeometry();

					std::vector< SdrCustomShapeInteraction >::iterator aIter( aInteractionHandles.begin() );
					while ( aIter != aInteractionHandles.end() )
					{
						if ( aIter->nMode & CUSTOMSHAPE_HANDLE_RESIZE_FIXED )
						{
							if ( aIter->xInteraction.is() )
								aIter->xInteraction->setControllerPosition( aIter->aPosition );
						}
						aIter++;
					}
				}
				aInteractionHandle.xInteraction->setControllerPosition( aPt );
			}
			catch ( const uno::RuntimeException& )
			{
			}
		}
	}
}

bool SdrObjCustomShape::applySpecialDrag(SdrDragStat& rDrag)
{
	const SdrHdl* pHdl = rDrag.GetHdl();
	const SdrHdlKind eHdl((pHdl == NULL) ? HDL_MOVE : pHdl->GetKind());

    switch(eHdl)
	{
		case HDL_CUSTOMSHAPE1 :
		{
			rDrag.SetEndDragChangesGeoAndAttributes(true);
		    DragMoveCustomShapeHdl( rDrag.GetNow(), (sal_uInt16)pHdl->GetPointNum(), this );
		    SetRectsDirty();
		    InvalidateRenderGeometry();
		    SetChanged();
            break;
		}

		case HDL_UPLFT :
		case HDL_UPPER :
		case HDL_UPRGT :
		case HDL_LEFT  :
		case HDL_RIGHT :
		case HDL_LWLFT :
		case HDL_LOWER :
		case HDL_LWRGT :
		{
			DragResizeCustomShape(ImpDragCalcRect(rDrag), this);
			break;
		}
		case HDL_MOVE :
		{
			Move(Size(rDrag.GetDX(), rDrag.GetDY()));
			break;
		}
		default: break;
	}

    return true;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

void SdrObjCustomShape::DragCreateObject( SdrDragStat& rStat )
{
	Rectangle aRect1;
	rStat.TakeCreateRect( aRect1 );

	std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles( this ) );

	sal_uInt32 nDefaultObjectSizeWidth = 3000;		// default width from SDOptions ?
	sal_uInt32 nDefaultObjectSizeHeight= 3000;

	if ( ImpVerticalSwitch( *this ) )
	{
		SetMirroredX( aRect1.Left() > aRect1.Right() );

		aRect1 = Rectangle( rStat.GetNow(), Size( nDefaultObjectSizeWidth, nDefaultObjectSizeHeight ) );
		// subtracting the horizontal difference of the latest handle from shape position
		if ( aInteractionHandles.size() )
		{
			sal_Int32 nHandlePos = aInteractionHandles[ aInteractionHandles.size() - 1 ].xInteraction->getPosition().X;
			aRect1.Move( aRect.Left() - nHandlePos, 0 );
		}
	}
	ImpJustifyRect( aRect1 );
	rStat.SetActionRect( aRect1 );
	aRect = aRect1;
	SetRectsDirty();

	std::vector< SdrCustomShapeInteraction >::iterator aIter( aInteractionHandles.begin() );
	while ( aIter != aInteractionHandles.end() )
	{
		try
		{
			if ( aIter->nMode & CUSTOMSHAPE_HANDLE_CREATE_FIXED )
				aIter->xInteraction->setControllerPosition( awt::Point( rStat.GetStart().X(), rStat.GetStart().Y() ) );
		}
		catch ( const uno::RuntimeException& )
		{
		}
		aIter++;
	}

	SetBoundRectDirty();
	bSnapRectDirty=TRUE;
}

FASTBOOL SdrObjCustomShape::BegCreate( SdrDragStat& rDrag )
{
	return SdrTextObj::BegCreate( rDrag );
}

FASTBOOL SdrObjCustomShape::MovCreate(SdrDragStat& rStat)
{
	SdrView* pView = rStat.GetView();		// #i37448#
	if( pView && pView->IsSolidDragging() )
	{
		InvalidateRenderGeometry();
	}
	DragCreateObject( rStat );
	SetRectsDirty();
	return TRUE;
}

FASTBOOL SdrObjCustomShape::EndCreate( SdrDragStat& rStat, SdrCreateCmd eCmd )
{
	DragCreateObject( rStat );

	if ( bTextFrame )
	{
		if ( IsAutoGrowHeight() )
		{
			// MinTextHeight
			long nHgt=aRect.GetHeight()-1;
			if (nHgt==1) nHgt=0;
			NbcSetMinTextFrameHeight( nHgt );
		}
		if ( IsAutoGrowWidth() )
		{
			// MinTextWidth
			long nWdt=aRect.GetWidth()-1;
			if (nWdt==1) nWdt=0;
			NbcSetMinTextFrameWidth( nWdt );
		}
		// Textrahmen neu berechnen
		NbcAdjustTextFrameWidthAndHeight();
	}
	SetRectsDirty();
	return ( eCmd == SDRCREATE_FORCEEND || rStat.GetPointAnz() >= 2 );
}

basegfx::B2DPolyPolygon SdrObjCustomShape::TakeCreatePoly(const SdrDragStat& /*rDrag*/) const
{
	return GetLineGeometry( this, sal_False );
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

// in context with the SdrObjCustomShape the SdrTextAutoGrowHeightItem == true -> Resize Shape to fit text,
//									   the SdrTextAutoGrowWidthItem  == true -> Word wrap text in Shape
FASTBOOL SdrObjCustomShape::IsAutoGrowHeight() const
{
	const SfxItemSet& rSet = GetMergedItemSet();
	FASTBOOL bIsAutoGrowHeight = ((SdrTextAutoGrowHeightItem&)(rSet.Get(SDRATTR_TEXT_AUTOGROWHEIGHT))).GetValue();
	if ( bIsAutoGrowHeight && IsVerticalWriting() )
		bIsAutoGrowHeight = ((SdrTextWordWrapItem&)(rSet.Get(SDRATTR_TEXT_WORDWRAP))).GetValue() == FALSE;
	return bIsAutoGrowHeight;
}
FASTBOOL SdrObjCustomShape::IsAutoGrowWidth() const
{
	const SfxItemSet& rSet = GetMergedItemSet();
	FASTBOOL bIsAutoGrowWidth = ((SdrTextAutoGrowHeightItem&)(rSet.Get(SDRATTR_TEXT_AUTOGROWHEIGHT))).GetValue();
	if ( bIsAutoGrowWidth && !IsVerticalWriting() )
		bIsAutoGrowWidth = ((SdrTextWordWrapItem&)(rSet.Get(SDRATTR_TEXT_WORDWRAP))).GetValue() == FALSE;
	return bIsAutoGrowWidth;
}

/* The following method is identical to the SdrTextObj::SetVerticalWriting method, the only difference
   is that the SdrAutoGrowWidthItem and SdrAutoGrowHeightItem are not exchanged if the vertical writing
   mode has been changed */

void SdrObjCustomShape::SetVerticalWriting( sal_Bool bVertical )
{
	ForceOutlinerParaObject();

	OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject();

	DBG_ASSERT( pOutlinerParaObject, "SdrTextObj::SetVerticalWriting() without OutlinerParaObject!" );

	if( pOutlinerParaObject )
	{
		if(pOutlinerParaObject->IsVertical() != (bool)bVertical)
		{
			// get item settings
			const SfxItemSet& rSet = GetObjectItemSet();

			// #103516# Also exchange hor/ver adjust items
			SdrTextHorzAdjust eHorz = ((SdrTextHorzAdjustItem&)(rSet.Get(SDRATTR_TEXT_HORZADJUST))).GetValue();
			SdrTextVertAdjust eVert = ((SdrTextVertAdjustItem&)(rSet.Get(SDRATTR_TEXT_VERTADJUST))).GetValue();

			// rescue object size
			Rectangle aObjectRect = GetSnapRect();

			// prepare ItemSet to set exchanged width and height items
			SfxItemSet aNewSet(*rSet.GetPool(),
				SDRATTR_TEXT_AUTOGROWHEIGHT, SDRATTR_TEXT_AUTOGROWHEIGHT,
				// #103516# Expanded item ranges to also support hor and ver adjust.
				SDRATTR_TEXT_VERTADJUST, SDRATTR_TEXT_VERTADJUST,
				SDRATTR_TEXT_AUTOGROWWIDTH, SDRATTR_TEXT_HORZADJUST,
				0, 0);

			aNewSet.Put(rSet);

			// #103516# Exchange horz and vert adjusts
			switch(eVert)
			{
				case SDRTEXTVERTADJUST_TOP: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_RIGHT)); break;
				case SDRTEXTVERTADJUST_CENTER: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_CENTER)); break;
				case SDRTEXTVERTADJUST_BOTTOM: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_LEFT)); break;
				case SDRTEXTVERTADJUST_BLOCK: aNewSet.Put(SdrTextHorzAdjustItem(SDRTEXTHORZADJUST_BLOCK)); break;
			}
			switch(eHorz)
			{
				case SDRTEXTHORZADJUST_LEFT: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BOTTOM)); break;
				case SDRTEXTHORZADJUST_CENTER: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_CENTER)); break;
				case SDRTEXTHORZADJUST_RIGHT: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_TOP)); break;
				case SDRTEXTHORZADJUST_BLOCK: aNewSet.Put(SdrTextVertAdjustItem(SDRTEXTVERTADJUST_BLOCK)); break;
			}

			SetObjectItemSet( aNewSet );
			pOutlinerParaObject = GetOutlinerParaObject();
			if ( pOutlinerParaObject )
				pOutlinerParaObject->SetVertical(bVertical);
	
			// restore object size
			SetSnapRect(aObjectRect);
		}
	}
}
FASTBOOL SdrObjCustomShape::AdjustTextFrameWidthAndHeight(Rectangle& rR, FASTBOOL bHgt, FASTBOOL bWdt) const
{
 	if ( pModel && HasText() && !rR.IsEmpty() )
	{
		FASTBOOL bWdtGrow=bWdt && IsAutoGrowWidth();
		FASTBOOL bHgtGrow=bHgt && IsAutoGrowHeight();
		if ( bWdtGrow || bHgtGrow )
		{
			Rectangle aR0(rR);
			long nHgt=0,nMinHgt=0,nMaxHgt=0;
			long nWdt=0,nMinWdt=0,nMaxWdt=0;
			Size aSiz(rR.GetSize()); aSiz.Width()--; aSiz.Height()--;
			Size aMaxSiz(100000,100000);
			Size aTmpSiz(pModel->GetMaxObjSize());
			if (aTmpSiz.Width()!=0) aMaxSiz.Width()=aTmpSiz.Width();
			if (aTmpSiz.Height()!=0) aMaxSiz.Height()=aTmpSiz.Height();
			if (bWdtGrow)
			{
				nMinWdt=GetMinTextFrameWidth();
				nMaxWdt=GetMaxTextFrameWidth();
				if (nMaxWdt==0 || nMaxWdt>aMaxSiz.Width()) nMaxWdt=aMaxSiz.Width();
				if (nMinWdt<=0) nMinWdt=1;
				aSiz.Width()=nMaxWdt;
			}
			if (bHgtGrow)
			{
				nMinHgt=GetMinTextFrameHeight();
				nMaxHgt=GetMaxTextFrameHeight();
				if (nMaxHgt==0 || nMaxHgt>aMaxSiz.Height()) nMaxHgt=aMaxSiz.Height();
				if (nMinHgt<=0) nMinHgt=1;
				aSiz.Height()=nMaxHgt;
			}
			long nHDist=GetTextLeftDistance()+GetTextRightDistance();
			long nVDist=GetTextUpperDistance()+GetTextLowerDistance();
			aSiz.Width()-=nHDist;
			aSiz.Height()-=nVDist;
			if ( aSiz.Width() < 2 )
				aSiz.Width() = 2;   // Mindestgroesse 2
			if ( aSiz.Height() < 2 )
				aSiz.Height() = 2; // Mindestgroesse 2

			if(pEdtOutl)
			{
				pEdtOutl->SetMaxAutoPaperSize( aSiz );
				if (bWdtGrow)
				{
					Size aSiz2(pEdtOutl->CalcTextSize());
					nWdt=aSiz2.Width()+1; // lieber etwas Tolleranz
					if (bHgtGrow) nHgt=aSiz2.Height()+1; // lieber etwas Tolleranz
				} else
				{
					nHgt=pEdtOutl->GetTextHeight()+1; // lieber etwas Tolleranz
				}
			}
			else
			{
				Outliner& rOutliner=ImpGetDrawOutliner();
				rOutliner.SetPaperSize(aSiz);
				rOutliner.SetUpdateMode(TRUE);
				// !!! hier sollte ich wohl auch noch mal die Optimierung mit
				// bPortionInfoChecked usw einbauen
				OutlinerParaObject* pOutlinerParaObject = GetOutlinerParaObject();
				if( pOutlinerParaObject != NULL )
				{
					rOutliner.SetText(*pOutlinerParaObject);
					rOutliner.SetFixedCellHeight(((const SdrTextFixedCellHeightItem&)GetMergedItem(SDRATTR_TEXT_USEFIXEDCELLHEIGHT)).GetValue());
				}
				if ( bWdtGrow )
				{
					Size aSiz2(rOutliner.CalcTextSize());
					nWdt=aSiz2.Width()+1; // lieber etwas Tolleranz
					if ( bHgtGrow )
						nHgt=aSiz2.Height()+1; // lieber etwas Tolleranz
				}
				else
					nHgt = rOutliner.GetTextHeight()+1; // lieber etwas Tolleranz
				rOutliner.Clear();
			}
			if ( nWdt < nMinWdt )
				nWdt = nMinWdt;
			if ( nWdt > nMaxWdt )
				nWdt = nMaxWdt;
			nWdt += nHDist;
			if ( nWdt < 1 )
				nWdt = 1; // nHDist kann auch negativ sein
			if ( nHgt < nMinHgt )
				nHgt = nMinHgt;
			if ( nHgt > nMaxHgt )
				nHgt = nMaxHgt;
			nHgt+=nVDist;
			if ( nHgt < 1 )
				nHgt = 1; // nVDist kann auch negativ sein
			long nWdtGrow = nWdt-(rR.Right()-rR.Left());
			long nHgtGrow = nHgt-(rR.Bottom()-rR.Top());
			if ( nWdtGrow == 0 )
				bWdtGrow = FALSE;
			if ( nHgtGrow == 0 )
				bHgtGrow=FALSE;
			if ( bWdtGrow || bHgtGrow )
			{
				if ( bWdtGrow )
				{
					SdrTextHorzAdjust eHAdj=GetTextHorizontalAdjust();
					if ( eHAdj == SDRTEXTHORZADJUST_LEFT )
						rR.Right()+=nWdtGrow;
					else if ( eHAdj == SDRTEXTHORZADJUST_RIGHT )
						rR.Left()-=nWdtGrow;
					else
					{
						long nWdtGrow2=nWdtGrow/2;
						rR.Left()-=nWdtGrow2;
						rR.Right()=rR.Left()+nWdt;
					}
				}
				if ( bHgtGrow )
				{
					SdrTextVertAdjust eVAdj=GetTextVerticalAdjust();
					if ( eVAdj == SDRTEXTVERTADJUST_TOP )
						rR.Bottom()+=nHgtGrow;
					else if ( eVAdj == SDRTEXTVERTADJUST_BOTTOM )
						rR.Top()-=nHgtGrow;
					else
					{
						long nHgtGrow2=nHgtGrow/2;
						rR.Top()-=nHgtGrow2;
						rR.Bottom()=rR.Top()+nHgt;
					}
				}
				if ( aGeo.nDrehWink )
				{
					Point aD1(rR.TopLeft());
					aD1-=aR0.TopLeft();
					Point aD2(aD1);
					RotatePoint(aD2,Point(),aGeo.nSin,aGeo.nCos);
					aD2-=aD1;
					rR.Move(aD2.X(),aD2.Y());
				}
				return TRUE;
			}
		}
	}
	return FALSE;
}

Rectangle SdrObjCustomShape::ImpCalculateTextFrame( const FASTBOOL bHgt, const FASTBOOL bWdt )
{
	Rectangle aReturnValue;

	Rectangle aOldTextRect( aRect );		// <- initial text rectangle

	Rectangle aNewTextRect( aRect );		// <- new text rectangle returned from the custom shape renderer,
	GetTextBounds( aNewTextRect );			//    it depends to the current logical shape size

	Rectangle aAdjustedTextRect( aNewTextRect );							// <- new text rectangle is being tested by AdjustTextFrameWidthAndHeight to ensure
	if ( AdjustTextFrameWidthAndHeight( aAdjustedTextRect, bHgt, bWdt ) )	//    that the new text rectangle is matching the current text size from the outliner
	{
		if ( ( aAdjustedTextRect != aNewTextRect ) && ( aOldTextRect != aAdjustedTextRect ) )
		{
			aReturnValue = aRect;
			double fXScale = (double)aOldTextRect.GetWidth() / (double)aNewTextRect.GetWidth();
			double fYScale = (double)aOldTextRect.GetHeight() / (double)aNewTextRect.GetHeight();
			double fRightDiff = (double)( aAdjustedTextRect.Right() - aNewTextRect.Right() ) * fXScale;
			double fLeftDiff  = (double)( aAdjustedTextRect.Left()  - aNewTextRect.Left()  ) * fXScale;
			double fTopDiff   = (double)( aAdjustedTextRect.Top()   - aNewTextRect.Top()   ) * fYScale;
			double fBottomDiff= (double)( aAdjustedTextRect.Bottom()- aNewTextRect.Bottom()) * fYScale;
			aReturnValue.Left() += (sal_Int32)fLeftDiff;
			aReturnValue.Right() += (sal_Int32)fRightDiff;
			aReturnValue.Top() += (sal_Int32)fTopDiff;
			aReturnValue.Bottom() += (sal_Int32)fBottomDiff;
		}
	}
	return aReturnValue;
}

FASTBOOL SdrObjCustomShape::NbcAdjustTextFrameWidthAndHeight(FASTBOOL bHgt, FASTBOOL bWdt)
{
	Rectangle aNewTextRect = ImpCalculateTextFrame( bHgt, bWdt );
	sal_Bool bRet = !aNewTextRect.IsEmpty() && ( aNewTextRect != aRect );
	if ( bRet )
	{
		// taking care of handles that should not been changed
		std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles( this ) );

		aRect = aNewTextRect;
		SetRectsDirty();
		SetChanged();

		std::vector< SdrCustomShapeInteraction >::iterator aIter( aInteractionHandles.begin() );
		while ( aIter != aInteractionHandles.end() )
		{
			try
			{
				if ( aIter->nMode & CUSTOMSHAPE_HANDLE_RESIZE_FIXED )
					aIter->xInteraction->setControllerPosition( aIter->aPosition );
			}
			catch ( const uno::RuntimeException& )
			{
			}
			aIter++;
		}
		InvalidateRenderGeometry();
	}
	return bRet;
}
FASTBOOL SdrObjCustomShape::AdjustTextFrameWidthAndHeight(FASTBOOL bHgt, FASTBOOL bWdt)
{
	Rectangle aNewTextRect = ImpCalculateTextFrame( bHgt, bWdt );
	sal_Bool bRet = !aNewTextRect.IsEmpty() && ( aNewTextRect != aRect );
	if ( bRet )
	{
		Rectangle aBoundRect0;
		if ( pUserCall )
			aBoundRect0 = GetCurrentBoundRect();

		// taking care of handles that should not been changed
		std::vector< SdrCustomShapeInteraction > aInteractionHandles( GetInteractionHandles( this ) );
	
//		SendRepaintBroadcast();
		aRect = aNewTextRect;
		SetRectsDirty();

		std::vector< SdrCustomShapeInteraction >::iterator aIter( aInteractionHandles.begin() );
		while ( aIter != aInteractionHandles.end() )
		{
			try
			{
				if ( aIter->nMode & CUSTOMSHAPE_HANDLE_RESIZE_FIXED )
					aIter->xInteraction->setControllerPosition( aIter->aPosition );
			}
			catch ( const uno::RuntimeException& )
			{
			}
			aIter++;
		}

		InvalidateRenderGeometry();
		SetChanged();
//		SendRepaintBroadcast();
		BroadcastObjectChange();
		SendUserCall(SDRUSERCALL_RESIZE,aBoundRect0);
	}
	return bRet;
}
sal_Bool SdrObjCustomShape::BegTextEdit( SdrOutliner& rOutl )
{
	return SdrTextObj::BegTextEdit( rOutl );
}
void SdrObjCustomShape::TakeTextEditArea(Size* pPaperMin, Size* pPaperMax, Rectangle* pViewInit, Rectangle* pViewMin) const
{
	Size aPaperMin,aPaperMax;
	Rectangle aViewInit;
	TakeTextAnchorRect( aViewInit );
	if ( aGeo.nDrehWink )
	{
		Point aCenter(aViewInit.Center());
		aCenter-=aViewInit.TopLeft();
		Point aCenter0(aCenter);
		RotatePoint(aCenter,Point(),aGeo.nSin,aGeo.nCos);
		aCenter-=aCenter0;
		aViewInit.Move(aCenter.X(),aCenter.Y());
	}
	Size aAnkSiz(aViewInit.GetSize());
	aAnkSiz.Width()--; aAnkSiz.Height()--; // weil GetSize() ein draufaddiert
	Size aMaxSiz(1000000,1000000);
	if (pModel!=NULL) {
		Size aTmpSiz(pModel->GetMaxObjSize());
		if (aTmpSiz.Width()!=0) aMaxSiz.Width()=aTmpSiz.Width();
		if (aTmpSiz.Height()!=0) aMaxSiz.Height()=aTmpSiz.Height();
	}
	SdrTextHorzAdjust eHAdj(GetTextHorizontalAdjust());
	SdrTextVertAdjust eVAdj(GetTextVerticalAdjust());

	long nMinWdt = GetMinTextFrameWidth();
	long nMinHgt = GetMinTextFrameHeight();
	long nMaxWdt = GetMaxTextFrameWidth();
	long nMaxHgt = GetMaxTextFrameHeight();
	if (nMinWdt<1) nMinWdt=1;
	if (nMinHgt<1) nMinHgt=1;
	if ( nMaxWdt == 0 || nMaxWdt > aMaxSiz.Width() )
		nMaxWdt = aMaxSiz.Width();
	if ( nMaxHgt == 0 || nMaxHgt > aMaxSiz.Height() )
		nMaxHgt=aMaxSiz.Height();

	if (((SdrTextWordWrapItem&)(GetMergedItem(SDRATTR_TEXT_WORDWRAP))).GetValue())
	{
		if ( IsVerticalWriting() )
		{
			nMaxHgt = aAnkSiz.Height();
			nMinHgt = nMaxHgt;
		}
		else
		{
			nMaxWdt = aAnkSiz.Width();
			nMinWdt = nMaxWdt;
		}
	}
	aPaperMax.Width()=nMaxWdt;
	aPaperMax.Height()=nMaxHgt;

	aPaperMin.Width()=nMinWdt;
	aPaperMin.Height()=nMinHgt;

	if ( pViewMin )
	{
		*pViewMin = aViewInit;

		long nXFree = aAnkSiz.Width() - aPaperMin.Width();
		if ( eHAdj == SDRTEXTHORZADJUST_LEFT )
			pViewMin->Right() -= nXFree;
		else if ( eHAdj == SDRTEXTHORZADJUST_RIGHT )
			pViewMin->Left() += nXFree;
		else { pViewMin->Left() += nXFree / 2; pViewMin->Right() = pViewMin->Left() + aPaperMin.Width(); }

		long nYFree = aAnkSiz.Height() - aPaperMin.Height();
		if ( eVAdj == SDRTEXTVERTADJUST_TOP )
			pViewMin->Bottom() -= nYFree;
		else if ( eVAdj == SDRTEXTVERTADJUST_BOTTOM )
			pViewMin->Top() += nYFree;
		else { pViewMin->Top() += nYFree / 2; pViewMin->Bottom() = pViewMin->Top() + aPaperMin.Height(); }
	}

	if( IsVerticalWriting() )
		aPaperMin.Width() = 0;
	else
		aPaperMin.Height() = 0; // #33102#

	if( eHAdj != SDRTEXTHORZADJUST_BLOCK )
		aPaperMin.Width()=0;

	// #103516# For complete ver adjust support, set paper min height to 0, here.
	if(SDRTEXTVERTADJUST_BLOCK != eVAdj )
		aPaperMin.Height() = 0;

	if (pPaperMin!=NULL) *pPaperMin=aPaperMin;
	if (pPaperMax!=NULL) *pPaperMax=aPaperMax;
	if (pViewInit!=NULL) *pViewInit=aViewInit;
}
void SdrObjCustomShape::EndTextEdit( SdrOutliner& rOutl )
{
	SdrTextObj::EndTextEdit( rOutl );
	InvalidateRenderGeometry();
}
void SdrObjCustomShape::TakeTextAnchorRect( Rectangle& rAnchorRect ) const
{
	if ( GetTextBounds( rAnchorRect ) )
	{
		Point aRotateRef( maSnapRect.Center() );
		rAnchorRect.Left()   += GetTextLeftDistance();
		rAnchorRect.Top()    += GetTextUpperDistance();
		rAnchorRect.Right()  -= GetTextRightDistance();
		rAnchorRect.Bottom() -= GetTextLowerDistance();
		ImpJustifyRect( rAnchorRect );

		if ( rAnchorRect.GetWidth() < 2 )
			rAnchorRect.Right() = rAnchorRect.Left() + 1;	// minimal width is 2
		if ( rAnchorRect.GetHeight() < 2 )
			rAnchorRect.Bottom() = rAnchorRect.Top() + 1;	// minimal height is 2
		if ( aGeo.nDrehWink )
		{
			Point aP( rAnchorRect.TopLeft() );
			RotatePoint( aP, aRotateRef, aGeo.nSin, aGeo. nCos );
			rAnchorRect.SetPos( aP );
		}
	}
	else
		SdrTextObj::TakeTextAnchorRect( rAnchorRect );
}
void SdrObjCustomShape::TakeTextRect( SdrOutliner& rOutliner, Rectangle& rTextRect, FASTBOOL bNoEditText,
	                           Rectangle* pAnchorRect, BOOL /*bLineWidth*/) const
{
	Rectangle aAnkRect; // Rect innerhalb dem geankert wird
	TakeTextAnchorRect(aAnkRect);
	SdrTextVertAdjust eVAdj=GetTextVerticalAdjust();
	SdrTextHorzAdjust eHAdj=GetTextHorizontalAdjust();
	ULONG nStat0=rOutliner.GetControlWord();
	Size aNullSize;

	rOutliner.SetControlWord(nStat0|EE_CNTRL_AUTOPAGESIZE);
	rOutliner.SetMinAutoPaperSize(aNullSize);
	sal_Int32 nMaxAutoPaperWidth = 1000000;
	sal_Int32 nMaxAutoPaperHeight= 1000000;

	long nAnkWdt=aAnkRect.GetWidth();
	long nAnkHgt=aAnkRect.GetHeight();

	if (((SdrTextWordWrapItem&)(GetMergedItem(SDRATTR_TEXT_WORDWRAP))).GetValue())
	{
		if ( IsVerticalWriting() )
			nMaxAutoPaperHeight = nAnkHgt;
		else
			nMaxAutoPaperWidth = nAnkWdt;
	}
	if(SDRTEXTHORZADJUST_BLOCK == eHAdj && !IsVerticalWriting())
	{
		rOutliner.SetMinAutoPaperSize(Size(nAnkWdt, 0));
	}

	if(SDRTEXTVERTADJUST_BLOCK == eVAdj && IsVerticalWriting())
	{
		rOutliner.SetMinAutoPaperSize(Size(0, nAnkHgt));
	}
	rOutliner.SetMaxAutoPaperSize( Size( nMaxAutoPaperWidth, nMaxAutoPaperHeight ) );
	rOutliner.SetPaperSize( aNullSize );

	// Text in den Outliner stecken - ggf. den aus dem EditOutliner
	OutlinerParaObject* pPara= GetOutlinerParaObject();
	if (pEdtOutl && !bNoEditText)
		pPara=pEdtOutl->CreateParaObject();

	if (pPara)
	{
		BOOL bHitTest = FALSE;
		if( pModel )
			bHitTest = &pModel->GetHitTestOutliner() == &rOutliner;

		const SdrTextObj* pTestObj = rOutliner.GetTextObj();
		if( !pTestObj || !bHitTest || pTestObj != this ||
		    pTestObj->GetOutlinerParaObject() != GetOutlinerParaObject() )
		{
			if( bHitTest )
				rOutliner.SetTextObj( this );

			rOutliner.SetUpdateMode(TRUE);
			rOutliner.SetText(*pPara);
		}
	}
	else
	{
		rOutliner.SetTextObj( NULL );
	}
	if (pEdtOutl && !bNoEditText && pPara)
		delete pPara;

	rOutliner.SetUpdateMode(TRUE);
	rOutliner.SetControlWord(nStat0);

	SdrText* pText = getActiveText();
	if( pText )
		pText->CheckPortionInfo( rOutliner );

	Point aTextPos(aAnkRect.TopLeft());
	Size aTextSiz(rOutliner.GetPaperSize()); // GetPaperSize() hat etwas Toleranz drauf, oder?

	// #106653#
	// For draw objects containing text correct hor/ver alignment if text is bigger
	// than the object itself. Without that correction, the text would always be
		// formatted to the left edge (or top edge when vertical) of the draw object.

	if( !IsTextFrame() )
	{
		if(aAnkRect.GetWidth() < aTextSiz.Width() && !IsVerticalWriting())
		{
			// #110129#
			// Horizontal case here. Correct only if eHAdj == SDRTEXTHORZADJUST_BLOCK,
			// else the alignment is wanted.
			if(SDRTEXTHORZADJUST_BLOCK == eHAdj)
			{
				eHAdj = SDRTEXTHORZADJUST_CENTER;
			}
		}

		if(aAnkRect.GetHeight() < aTextSiz.Height() && IsVerticalWriting())
		{
			// #110129#
			// Vertical case here. Correct only if eHAdj == SDRTEXTVERTADJUST_BLOCK,
			// else the alignment is wanted.
			if(SDRTEXTVERTADJUST_BLOCK == eVAdj)
			{
				eVAdj = SDRTEXTVERTADJUST_CENTER;
			}
		}
	}

	if (eHAdj==SDRTEXTHORZADJUST_CENTER || eHAdj==SDRTEXTHORZADJUST_RIGHT)
	{
		long nFreeWdt=aAnkRect.GetWidth()-aTextSiz.Width();
		if (eHAdj==SDRTEXTHORZADJUST_CENTER)
			aTextPos.X()+=nFreeWdt/2;
		if (eHAdj==SDRTEXTHORZADJUST_RIGHT)
			aTextPos.X()+=nFreeWdt;
	}
	if (eVAdj==SDRTEXTVERTADJUST_CENTER || eVAdj==SDRTEXTVERTADJUST_BOTTOM)
	{
		long nFreeHgt=aAnkRect.GetHeight()-aTextSiz.Height();
		if (eVAdj==SDRTEXTVERTADJUST_CENTER)
			aTextPos.Y()+=nFreeHgt/2;
		if (eVAdj==SDRTEXTVERTADJUST_BOTTOM)
			aTextPos.Y()+=nFreeHgt;
	}
	if (aGeo.nDrehWink!=0)
		RotatePoint(aTextPos,aAnkRect.TopLeft(),aGeo.nSin,aGeo.nCos);

	if (pAnchorRect)
		*pAnchorRect=aAnkRect;

	// rTextRect ist bei ContourFrame in einigen Faellen nicht korrekt
	rTextRect=Rectangle(aTextPos,aTextSiz);
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

void SdrObjCustomShape::NbcSetOutlinerParaObject(OutlinerParaObject* pTextObject)
{
	SdrTextObj::NbcSetOutlinerParaObject( pTextObject );
	SetBoundRectDirty();
	SetRectsDirty(TRUE);
	InvalidateRenderGeometry();
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

SdrObject* SdrObjCustomShape::CheckHit(const Point& rPnt, USHORT nTol, const SetOfByte* pVisiLayer) const
{
	SdrObject* pHitObj = NULL;
	const SdrObject* pSdrObject = GetSdrObjectFromCustomShape();
	if ( pSdrObject )
	{
		SdrObjList* pOL = pSdrObject->GetSubList();
		if ( pOL )
		{
			ULONG nObjNum = pOL->GetObjCount();
			while ( ( pHitObj == NULL ) && nObjNum )
			{
				nObjNum--;
				SdrObject* pObj = pOL->GetObj( nObjNum );
				if ( pObj->CheckHit( rPnt, nTol, pVisiLayer ) )
					pHitObj = (SdrObject*)this;
			}
		}
		else if ( pSdrObject->CheckHit( rPnt, nTol, pVisiLayer ) )
			pHitObj = (SdrObject*)this;
	}

	if ( !pHitObj && HasText() )
	{
		// paint text over object
		double fTextRotation = GetExtraTextRotation();
		if ( fTextRotation != 0.0 )
		{
			GeoStat aOldGeoStat( aGeo );
			Rectangle aOldRect( aRect );
			Rectangle aTextBound( aRect );
			GetTextBounds( aTextBound );

			// determining the correct refpoint
			Point aRef( aTextBound.Center() );
			Rectangle aUnrotatedSnapRect( aOutRect );
			RotatePoint( aRef, aUnrotatedSnapRect.Center(), -aGeo.nSin, -aGeo.nCos );

			long dx = aRect.Right()-aRect.Left();
			long dy = aRect.Bottom()-aRect.Top();
			Point aP( aRect.TopLeft() );
			double sn = sin( F_PI180 * fTextRotation );
			double cs = cos( F_PI180 * fTextRotation );
			RotatePoint( aP, aRef, sn, cs );
			((SdrObjCustomShape*)this)->aRect.Left()=aP.X();
			((SdrObjCustomShape*)this)->aRect.Top()=aP.Y();
			((SdrObjCustomShape*)this)->aRect.Right()=aRect.Left()+dx;
			((SdrObjCustomShape*)this)->aRect.Bottom()=aRect.Top()+dy;
			if ( aGeo.nDrehWink == 0 )
			{
				((SdrObjCustomShape*)this)->aGeo.nDrehWink=NormAngle360( (sal_Int32)( fTextRotation * 100.0 ) );
				((SdrObjCustomShape*)this)->aGeo.nSin = sn;
				((SdrObjCustomShape*)this)->aGeo.nCos = cs;
			}
			else
			{
				((SdrObjCustomShape*)this)->aGeo.nDrehWink=NormAngle360( aGeo.nDrehWink + (sal_Int32)( fTextRotation * 100.0 ) );
				((SdrObjCustomShape*)this)->aGeo.RecalcSinCos();
			}
			pHitObj = SdrTextObj::CheckHit( rPnt, nTol, pVisiLayer );
			((SdrObjCustomShape*)this)->aGeo = aOldGeoStat;
			((SdrObjCustomShape*)this)->aRect = aOldRect;

		}
		else
			pHitObj = SdrTextObj::CheckHit( rPnt, nTol, pVisiLayer );
	}

	return pHitObj;
}

void SdrObjCustomShape::operator=(const SdrObject& rObj)
{
	SdrTextObj::operator=( rObj );
	aName =((SdrObjCustomShape&)rObj).aName;
	fObjectRotation = ((SdrObjCustomShape&)rObj).fObjectRotation;
	InvalidateRenderGeometry();
}


void SdrObjCustomShape::TakeObjNameSingul(XubString& rName) const
{
	rName = ImpGetResStr(STR_ObjNameSingulCUSTOMSHAPE);
	String aNm( GetName() );
	if( aNm.Len() )
	{
		rName += sal_Unicode(' ');
		rName += sal_Unicode('\'');
		rName += aNm;
		rName += sal_Unicode('\'');
	}
}

void SdrObjCustomShape::TakeObjNamePlural(XubString& rName) const
{
	rName=ImpGetResStr(STR_ObjNamePluralCUSTOMSHAPE);
}

basegfx::B2DPolyPolygon SdrObjCustomShape::TakeXorPoly() const
{
	return GetLineGeometry( (SdrObjCustomShape*)this, sal_False );
}

basegfx::B2DPolyPolygon SdrObjCustomShape::TakeContour() const
{
	const SdrObject* pSdrObject = GetSdrObjectFromCustomShape();
	if ( pSdrObject )
		return pSdrObject->TakeContour();
	return basegfx::B2DPolyPolygon();
}

SdrObject* SdrObjCustomShape::DoConvertToPolyObj(BOOL bBezier) const
{
	// #i37011#
	SdrObject* pRetval = 0L;
	SdrObject* pRenderedCustomShape = 0L;

	if ( !mXRenderedCustomShape.is() )
	{
		// force CustomShape
		((SdrObjCustomShape*)this)->GetSdrObjectFromCustomShape();
	}

	if ( mXRenderedCustomShape.is() )
	{
		pRenderedCustomShape = GetSdrObjectFromXShape( mXRenderedCustomShape );
	}

	if ( pRenderedCustomShape )
	{
		SdrObject* pCandidate = pRenderedCustomShape->Clone();
		DBG_ASSERT(pCandidate, "SdrObjCustomShape::DoConvertToPolyObj: Could not clone SdrObject (!)");
		pCandidate->SetModel(GetModel());
		pRetval = pCandidate->DoConvertToPolyObj(bBezier);
		SdrObject::Free( pCandidate );

		if(pRetval)
		{
			const sal_Bool bShadow(((SdrShadowItem&)GetMergedItem(SDRATTR_SHADOW)).GetValue());
			if(bShadow)
			{
				pRetval->SetMergedItem(SdrShadowItem(sal_True));
			}
		}

		if(HasText() && !IsTextPath())
		{
			pRetval = ImpConvertAddText(pRetval, bBezier);
		}
	}

	return pRetval;
}

void SdrObjCustomShape::NbcSetStyleSheet( SfxStyleSheet* pNewStyleSheet, sal_Bool bDontRemoveHardAttr )
{
	// #i40944#
	InvalidateRenderGeometry();
	SdrObject::NbcSetStyleSheet( pNewStyleSheet, bDontRemoveHardAttr );
}

void SdrObjCustomShape::SetPage( SdrPage* pNewPage )
{
	SdrTextObj::SetPage( pNewPage );

	if( pNewPage )
	{
		// invalidating rectangles by SetRectsDirty is not sufficient,
		// AdjustTextFrameWidthAndHeight() also has to be made, both
		// actions are done by NbcSetSnapRect
		Rectangle aTmp( aRect );	//creating temporary rectangle #i61108#
		NbcSetSnapRect( aTmp );
	}
}

SdrObjGeoData* SdrObjCustomShape::NewGeoData() const
{
	return new SdrAShapeObjGeoData;
}

void SdrObjCustomShape::SaveGeoData(SdrObjGeoData& rGeo) const
{
	SdrTextObj::SaveGeoData( rGeo );
	SdrAShapeObjGeoData& rAGeo=(SdrAShapeObjGeoData&)rGeo;
	rAGeo.fObjectRotation = fObjectRotation;
	rAGeo.bMirroredX = IsMirroredX();
	rAGeo.bMirroredY = IsMirroredY();

	const rtl::OUString	sAdjustmentValues( RTL_CONSTASCII_USTRINGPARAM ( "AdjustmentValues" ) );
	Any* pAny( ( (SdrCustomShapeGeometryItem&)GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY ) ).GetPropertyValueByName( sAdjustmentValues ) );
	if ( pAny )
		*pAny >>= rAGeo.aAdjustmentSeq;
}

void SdrObjCustomShape::RestGeoData(const SdrObjGeoData& rGeo)
{
	SdrTextObj::RestGeoData( rGeo );
	SdrAShapeObjGeoData& rAGeo=(SdrAShapeObjGeoData&)rGeo;
	fObjectRotation = rAGeo.fObjectRotation;
	SetMirroredX( rAGeo.bMirroredX );
	SetMirroredY( rAGeo.bMirroredY );

	SdrCustomShapeGeometryItem rGeometryItem = (SdrCustomShapeGeometryItem&)GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
	const rtl::OUString	sAdjustmentValues( RTL_CONSTASCII_USTRINGPARAM ( "AdjustmentValues" ) );
	PropertyValue aPropVal;
	aPropVal.Name = sAdjustmentValues;
	aPropVal.Value <<= rAGeo.aAdjustmentSeq;
	rGeometryItem.SetPropertyValue( aPropVal );
	SetMergedItem( rGeometryItem );

	InvalidateRenderGeometry();
}

void SdrObjCustomShape::TRSetBaseGeometry(const basegfx::B2DHomMatrix& rMatrix, const basegfx::B2DPolyPolygon& /*rPolyPolygon*/)
{
	// break up matrix
	basegfx::B2DTuple aScale;
	basegfx::B2DTuple aTranslate;
	double fRotate, fShearX;
	rMatrix.decompose(aScale, aTranslate, fRotate, fShearX);

	// #i75086# Old DrawingLayer (GeoStat and geometry) does not support holding negative scalings
	// in X and Y which equal a 180 degree rotation. Recognize it and react accordingly
	if(basegfx::fTools::less(aScale.getX(), 0.0) && basegfx::fTools::less(aScale.getY(), 0.0))
	{
		aScale.setX(fabs(aScale.getX()));
		aScale.setY(fabs(aScale.getY()));
		fRotate = fmod(fRotate + F_PI, F_2PI);
	}

	// reset object shear and rotations
	aGeo.nDrehWink = 0;
	aGeo.RecalcSinCos();
	aGeo.nShearWink = 0;
	aGeo.RecalcTan();

	// force metric to pool metric
	SfxMapUnit eMapUnit = GetObjectItemSet().GetPool()->GetMetric(0);
	if(eMapUnit != SFX_MAPUNIT_100TH_MM)
	{
		switch(eMapUnit)
		{
			case SFX_MAPUNIT_TWIP :
			{
				// position
				aTranslate.setX(ImplMMToTwips(aTranslate.getX()));
				aTranslate.setY(ImplMMToTwips(aTranslate.getY()));

				// size
				aScale.setX(ImplMMToTwips(aScale.getX()));
				aScale.setY(ImplMMToTwips(aScale.getY()));

				break;
			}
			default:
			{
				DBG_ERROR("TRSetBaseGeometry: Missing unit translation to PoolMetric!");
			}
		}
	}

	// if anchor is used, make position relative to it
	if( pModel && pModel->IsWriter() )
	{
		if(GetAnchorPos().X() || GetAnchorPos().Y())
		{
			aTranslate += basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
		}
	}

	// build and set BaseRect (use scale)
	Point aPoint = Point();
	Size aSize(FRound(aScale.getX()), FRound(aScale.getY()));
	Rectangle aBaseRect(aPoint, aSize);
	SetSnapRect(aBaseRect);

	// shear?
//  if(!basegfx::fTools::equalZero(fShearX))
//	{
//		GeoStat aGeoStat;
//		aGeoStat.nShearWink = FRound((atan(fShearX) / F_PI180) * 100.0);
//		aGeoStat.RecalcTan();
//		Shear(Point(), aGeoStat.nShearWink, aGeoStat.nTan, FALSE);
//	}

	// rotation?
    if(!basegfx::fTools::equalZero(fRotate))
	{
		GeoStat aGeoStat;

        // #i78696# 
        // fRotate is mathematically correct, but aGeoStat.nDrehWink is
        // mirrored -> mirror value here
		aGeoStat.nDrehWink = NormAngle360(FRound(-fRotate / F_PI18000));
		aGeoStat.RecalcSinCos();
		Rotate(Point(), aGeoStat.nDrehWink, aGeoStat.nSin, aGeoStat.nCos);
	}

	// translate?
    if(!aTranslate.equalZero())
	{
		Move(Size(FRound(aTranslate.getX()), FRound(aTranslate.getY())));
	}
}

// taking fObjectRotation instead of aGeo.nWink
sal_Bool SdrObjCustomShape::TRGetBaseGeometry(basegfx::B2DHomMatrix& rMatrix, basegfx::B2DPolyPolygon& /*rPolyPolygon*/) const
{
	// get turn and shear
//	double fRotate = (aGeo.nDrehWink / 100.0) * F_PI180;
	double fRotate = fObjectRotation * F_PI180;
	double fShearX = (aGeo.nShearWink / 100.0) * F_PI180;

	// get aRect, this is the unrotated snaprect
	Rectangle aRectangle(aRect);

	sal_Bool bMirroredX = IsMirroredX();
	sal_Bool bMirroredY = IsMirroredY();
	if ( bMirroredX || bMirroredY )
	{	// we have to retrieve the unmirrored rect

		GeoStat aNewGeo( aGeo );

		if ( bMirroredX )
		{
			Polygon aPol( Rect2Poly( aRect, aNewGeo ) );
			Rectangle aBoundRect( aPol.GetBoundRect() );

			Point aRef1( ( aBoundRect.Left() + aBoundRect.Right() ) >> 1, aBoundRect.Top() );
			Point aRef2( aRef1.X(), aRef1.Y() + 1000 );
			USHORT i;
			USHORT nPntAnz=aPol.GetSize();
			for (i=0; i<nPntAnz; i++)
			{
				MirrorPoint(aPol[i],aRef1,aRef2);
			}
			// Polygon wenden und etwas schieben
			Polygon aPol0(aPol);
			aPol[0]=aPol0[1];
			aPol[1]=aPol0[0];
			aPol[2]=aPol0[3];
			aPol[3]=aPol0[2];
			aPol[4]=aPol0[1];
			Poly2Rect(aPol,aRectangle,aNewGeo);
		}
		if ( bMirroredY )
		{
			Polygon aPol( Rect2Poly( aRectangle, aNewGeo ) );
			Rectangle aBoundRect( aPol.GetBoundRect() );

			Point aRef1( aBoundRect.Left(), ( aBoundRect.Top() + aBoundRect.Bottom() ) >> 1 );
			Point aRef2( aRef1.X() + 1000, aRef1.Y() );
			USHORT i;
			USHORT nPntAnz=aPol.GetSize();
			for (i=0; i<nPntAnz; i++)
			{
				MirrorPoint(aPol[i],aRef1,aRef2);
			}
			// Polygon wenden und etwas schieben
			Polygon aPol0(aPol);
			aPol[0]=aPol0[1];
			aPol[1]=aPol0[0];
			aPol[2]=aPol0[3];
			aPol[3]=aPol0[2];
			aPol[4]=aPol0[1];
			Poly2Rect(aPol,aRectangle,aNewGeo);
		}
	}

	// fill other values
	basegfx::B2DTuple aScale(aRectangle.GetWidth(), aRectangle.GetHeight());
	basegfx::B2DTuple aTranslate(aRectangle.Left(), aRectangle.Top());

	// position maybe relative to anchorpos, convert
	if( pModel && pModel->IsWriter() )
	{
		if(GetAnchorPos().X() || GetAnchorPos().Y())
		{
			aTranslate -= basegfx::B2DTuple(GetAnchorPos().X(), GetAnchorPos().Y());
		}
	}

	// force MapUnit to 100th mm
	SfxMapUnit eMapUnit = GetObjectItemSet().GetPool()->GetMetric(0);
	if(eMapUnit != SFX_MAPUNIT_100TH_MM)
	{
		switch(eMapUnit)
		{
			case SFX_MAPUNIT_TWIP :
			{
				// postion
				aTranslate.setX(ImplTwipsToMM(aTranslate.getX()));
				aTranslate.setY(ImplTwipsToMM(aTranslate.getY()));

				// size
				aScale.setX(ImplTwipsToMM(aScale.getX()));
				aScale.setY(ImplTwipsToMM(aScale.getY()));

				break;
			}
			default:
			{
				DBG_ERROR("TRGetBaseGeometry: Missing unit translation to 100th mm!");
			}
		}
	}

	// build matrix
	rMatrix.identity();
	
    if(!basegfx::fTools::equal(aScale.getX(), 1.0) || !basegfx::fTools::equal(aScale.getY(), 1.0))
	{
		rMatrix.scale(aScale.getX(), aScale.getY());
	}

    if(!basegfx::fTools::equalZero(fShearX))
	{
		rMatrix.shearX(tan(fShearX));
	}

    if(!basegfx::fTools::equalZero(fRotate))
	{
        // #i78696#
        // fRotate is from the old GeoStat struct and thus mathematically wrong orientated. For 
        // the linear combination of matrices it needed to be fixed in the API, so it needs to
        // be mirrored here
		rMatrix.rotate(-fRotate);
	}

    if(!aTranslate.equalZero())
	{
		rMatrix.translate(aTranslate.getX(), aTranslate.getY());
	}

	return sal_False;
}

sdr::contact::ViewContact* SdrObjCustomShape::CreateObjectSpecificViewContact()
{
	return new sdr::contact::ViewContactOfSdrObjCustomShape(*this);
}

// #i33136#
bool SdrObjCustomShape::doConstructOrthogonal(const ::rtl::OUString& rName)
{
	bool bRetval(false);
	static ::rtl::OUString Imps_sNameASOrtho_quadrat( RTL_CONSTASCII_USTRINGPARAM( "quadrat" ) );
	static ::rtl::OUString Imps_sNameASOrtho_round_quadrat( RTL_CONSTASCII_USTRINGPARAM( "round-quadrat" ) );
	static ::rtl::OUString Imps_sNameASOrtho_circle( RTL_CONSTASCII_USTRINGPARAM( "circle" ) );
	static ::rtl::OUString Imps_sNameASOrtho_circle_pie( RTL_CONSTASCII_USTRINGPARAM( "circle-pie" ) );
	static ::rtl::OUString Imps_sNameASOrtho_ring( RTL_CONSTASCII_USTRINGPARAM( "ring" ) );

	if(Imps_sNameASOrtho_quadrat.equalsIgnoreAsciiCase(rName))
	{
		bRetval = true;
	}
	else if(Imps_sNameASOrtho_round_quadrat.equalsIgnoreAsciiCase(rName))
	{
		bRetval = true;
	}
	else if(Imps_sNameASOrtho_circle.equalsIgnoreAsciiCase(rName))
	{
		bRetval = true;
	}
	else if(Imps_sNameASOrtho_circle_pie.equalsIgnoreAsciiCase(rName))
	{
		bRetval = true;
	}
	else if(Imps_sNameASOrtho_ring.equalsIgnoreAsciiCase(rName))
	{
		bRetval = true;
	}

	return bRetval;
}

// #i37011# centralize throw-away of render geometry
void SdrObjCustomShape::InvalidateRenderGeometry()
{
	mXRenderedCustomShape = 0L;
    SdrObject::Free( mpLastShadowGeometry );
	mpLastShadowGeometry = 0L;
}

// eof
