/**************************************************************
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 *
 *************************************************************/



// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_xmloff.hxx"
#include "unointerfacetouniqueidentifiermapper.hxx"
#include <com/sun/star/text/XText.hpp>
#include <com/sun/star/container/XNamed.hpp>
#include <com/sun/star/container/XEnumerationAccess.hpp>
#include <com/sun/star/drawing/CircleKind.hpp>
#include <com/sun/star/drawing/ConnectorType.hpp>
#include <com/sun/star/drawing/XControlShape.hpp>
#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
#include <com/sun/star/document/XEventsSupplier.hpp>
#include <com/sun/star/drawing/HomogenMatrix3.hpp>
#include <com/sun/star/media/ZoomLevel.hpp>
#include "anim.hxx"

#ifndef _XMLOFF_SHAPEEXPORT_HXX
#include <xmloff/shapeexport.hxx>
#endif
#include "sdpropls.hxx"
#include <tools/debug.hxx>
#include <tools/urlobj.hxx>
#include <rtl/ustrbuf.hxx>
#include <xmloff/xmlexp.hxx>
#include <xmloff/xmluconv.hxx>
#include "XMLImageMapExport.hxx"
#include "xexptran.hxx"
#include <tools/gen.hxx>        // FRound
#include <xmloff/xmltoken.hxx>
#include <xmloff/nmspmap.hxx>

#include "xmloff/xmlnmspe.hxx"
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <basegfx/tuple/b2dtuple.hxx>

using ::rtl::OUString;
using ::rtl::OUStringBuffer;

using namespace ::com::sun::star;
using namespace ::xmloff::token;


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

void XMLShapeExport::ImpExportNewTrans(const uno::Reference< beans::XPropertySet >& xPropSet,
    sal_Int32 nFeatures, awt::Point* pRefPoint)
{
    // get matrix
    ::basegfx::B2DHomMatrix aMatrix;
    ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);

    // decompose and correct abour pRefPoint
    ::basegfx::B2DTuple aTRScale;
    double fTRShear(0.0);
    double fTRRotate(0.0);
    ::basegfx::B2DTuple aTRTranslate;
    ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);

    // use features and write
    ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures);
}

void XMLShapeExport::ImpExportNewTrans_GetB2DHomMatrix(::basegfx::B2DHomMatrix& rMatrix,
    const uno::Reference< beans::XPropertySet >& xPropSet)
{
    // --> OD 2004-08-09 #i28749# - Get <TransformationInHoriL2R>, if it exist
    // and if the document is exported into the OpenOffice.org file format.
    // This property only exists at service com::sun::star::text::Shape - the
    // Writer UNO service for shapes.
    // This code is needed, because the positioning attributes in the
    // OpenOffice.org file format are given in horizontal left-to-right layout
    // regardless the layout direction the shape is in. In the OASIS Open Office
    // file format the positioning attributes are correctly given in the layout
    // direction the shape is in. Thus, this code provides the conversion from
    // the OASIS Open Office file format to the OpenOffice.org file format.
    uno::Any aAny;
    if ( ( GetExport().getExportFlags() & EXPORT_OASIS ) == 0 &&
         xPropSet->getPropertySetInfo()->hasPropertyByName(
            OUString(RTL_CONSTASCII_USTRINGPARAM("TransformationInHoriL2R"))) )
    {
        aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("TransformationInHoriL2R")));
    }
    else
    {
        aAny = xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("Transformation")));
    }
    // <--
    drawing::HomogenMatrix3 aMatrix;
    aAny >>= aMatrix;

    rMatrix.set(0, 0, aMatrix.Line1.Column1);
    rMatrix.set(0, 1, aMatrix.Line1.Column2);
    rMatrix.set(0, 2, aMatrix.Line1.Column3);
    rMatrix.set(1, 0, aMatrix.Line2.Column1);
    rMatrix.set(1, 1, aMatrix.Line2.Column2);
    rMatrix.set(1, 2, aMatrix.Line2.Column3);
    rMatrix.set(2, 0, aMatrix.Line3.Column1);
    rMatrix.set(2, 1, aMatrix.Line3.Column2);
    rMatrix.set(2, 2, aMatrix.Line3.Column3);
}

void XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint(const ::basegfx::B2DHomMatrix& rMatrix, ::basegfx::B2DTuple& rTRScale,
    double& fTRShear, double& fTRRotate, ::basegfx::B2DTuple& rTRTranslate, com::sun::star::awt::Point* pRefPoint)
{
    // decompose matrix
    rMatrix.decompose(rTRScale, rTRTranslate, fTRRotate, fTRShear);

    // correct translation about pRefPoint
    if(pRefPoint)
    {
        rTRTranslate -= ::basegfx::B2DTuple(pRefPoint->X, pRefPoint->Y);
    }
}

void XMLShapeExport::ImpExportNewTrans_FeaturesAndWrite(::basegfx::B2DTuple& rTRScale, double fTRShear,
    double fTRRotate, ::basegfx::B2DTuple& rTRTranslate, const sal_Int32 nFeatures)
{
    // allways write Size (rTRScale) since this statement carries the union
    // of the object
    OUString aStr;
    OUStringBuffer sStringBuffer;
    ::basegfx::B2DTuple aTRScale(rTRScale);

    // svg: width
    if(!(nFeatures & SEF_EXPORT_WIDTH))
    {
        aTRScale.setX(1.0);
    }
    else
    {
        if( aTRScale.getX() > 0.0 )
            aTRScale.setX(aTRScale.getX() - 1.0);
        else if( aTRScale.getX() < 0.0 )
            aTRScale.setX(aTRScale.getX() + 1.0);
    }

    mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, FRound(aTRScale.getX()));
    aStr = sStringBuffer.makeStringAndClear();
    mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, aStr);

    // svg: height
    if(!(nFeatures & SEF_EXPORT_HEIGHT))
    {
        aTRScale.setY(1.0);
    }
    else
    {
        if( aTRScale.getY() > 0.0 )
            aTRScale.setY(aTRScale.getY() - 1.0);
        else if( aTRScale.getY() < 0.0 )
            aTRScale.setY(aTRScale.getY() + 1.0);
    }

    mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, FRound(aTRScale.getY()));
    aStr = sStringBuffer.makeStringAndClear();
    mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, aStr);

    // decide if transformation is neccessary
    sal_Bool bTransformationIsNeccessary(fTRShear != 0.0 || fTRRotate != 0.0);

    if(bTransformationIsNeccessary)
    {
        // write transformation, but WITHOUT scale which is exported as size above
        SdXMLImExTransform2D aTransform;

        aTransform.AddSkewX(atan(fTRShear));

        // #i78696#
        // fTRRotate is mathematically correct, but due to the error
        // we export/import it mirrored. Since the API implementation is fixed and
        // uses the correctly oriented angle, it is necessary for compatibility to
        // mirror the angle here to stay at the old behaviour. There is a follow-up
        // task (#i78698#) to fix this in the next ODF FileFormat version
        aTransform.AddRotate(-fTRRotate);

        aTransform.AddTranslate(rTRTranslate);

        // does transformation need to be exported?
        if(aTransform.NeedsAction())
            mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
    }
    else
    {
        // no shear, no rotate; just add object position to export and we are done
        if(nFeatures & SEF_EXPORT_X)
        {
            // svg: x
            mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, FRound(rTRTranslate.getX()));
            aStr = sStringBuffer.makeStringAndClear();
            mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, aStr);
        }

        if(nFeatures & SEF_EXPORT_Y)
        {
            // svg: y
            mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, FRound(rTRTranslate.getY()));
            aStr = sStringBuffer.makeStringAndClear();
            mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, aStr);
        }
    }
}

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

sal_Bool XMLShapeExport::ImpExportPresentationAttributes( const uno::Reference< beans::XPropertySet >& xPropSet, const rtl::OUString& rClass )
{
    sal_Bool bIsEmpty = sal_False;

    OUStringBuffer sStringBuffer;

    // write presentation class entry
    mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS, rClass);

    if( xPropSet.is() )
    {
        uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );

        sal_Bool bTemp = false;

        // is empty pes shape?
        if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(OUString(RTL_CONSTASCII_USTRINGPARAM("IsEmptyPresentationObject"))))
        {
            xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("IsEmptyPresentationObject"))) >>= bIsEmpty;
            if( bIsEmpty )
                mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PLACEHOLDER, XML_TRUE);
        }

        // is user-transformed?
        if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(OUString(RTL_CONSTASCII_USTRINGPARAM("IsPlaceholderDependent"))))
        {
            xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("IsPlaceholderDependent"))) >>= bTemp;
            if(!bTemp)
                mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_USER_TRANSFORMED, XML_TRUE);
        }
    }

    return bIsEmpty;
}

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

void XMLShapeExport::ImpExportText( const uno::Reference< drawing::XShape >& xShape )
{
    uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY );
    if( xText.is() )
    {
        uno::Reference< container::XEnumerationAccess > xEnumAccess( xShape, uno::UNO_QUERY );
        if( xEnumAccess.is() && xEnumAccess->hasElements() )
            mrExport.GetTextParagraphExport()->exportText( xText );
    }
}

//////////////////////////////////////////////////////////////////////////////
#include <com/sun/star/presentation/ClickAction.hpp>
#include <com/sun/star/presentation/AnimationSpeed.hpp>

namespace {

const sal_Int32 FOUND_CLICKACTION       = 0x00000001;
const sal_Int32 FOUND_BOOKMARK          = 0x00000002;
const sal_Int32 FOUND_EFFECT            = 0x00000004;
const sal_Int32 FOUND_PLAYFULL          = 0x00000008;
const sal_Int32 FOUND_VERB              = 0x00000010;
const sal_Int32 FOUND_SOUNDURL          = 0x00000020;
const sal_Int32 FOUND_SPEED             = 0x00000040;
const sal_Int32 FOUND_CLICKEVENTTYPE    = 0x00000080;
const sal_Int32 FOUND_MACRO             = 0x00000100;
const sal_Int32 FOUND_LIBRARY           = 0x00000200;
const sal_Int32 FOUND_ACTIONEVENTTYPE   = 0x00000400;
#ifdef ISSUE66550_HLINK_FOR_SHAPES
const sal_Int32 FOUND_URL               = 0x00000800;
#endif

} // namespace

void XMLShapeExport::ImpExportEvents( const uno::Reference< drawing::XShape >& xShape )
{
    uno::Reference< document::XEventsSupplier > xEventsSupplier( xShape, uno::UNO_QUERY );
    if( !xEventsSupplier.is() )
        return;

    uno::Reference< container::XNameAccess > xEvents( xEventsSupplier->getEvents(), uno::UNO_QUERY );
    DBG_ASSERT( xEvents.is(), "XEventsSupplier::getEvents() returned NULL" );
    if( !xEvents.is() )
        return;

    sal_Int32 nFound = 0;

    // extract properties from "OnClick" event --------------------------------

    OUString aClickEventType;
    presentation::ClickAction eClickAction = presentation::ClickAction_NONE;
    presentation::AnimationEffect eEffect = presentation::AnimationEffect_NONE;
    presentation::AnimationSpeed eSpeed = presentation::AnimationSpeed_SLOW;
    OUString aStrSoundURL;
    sal_Bool bPlayFull = false;
    sal_Int32 nVerb = 0;
    OUString aStrMacro;
    OUString aStrLibrary;
    OUString aStrBookmark;

    uno::Sequence< beans::PropertyValue > aClickProperties;
    if( xEvents->hasByName( msOnClick ) && (xEvents->getByName( msOnClick ) >>= aClickProperties) )
    {
        const beans::PropertyValue* pProperty = aClickProperties.getConstArray();
        const beans::PropertyValue* pPropertyEnd = pProperty + aClickProperties.getLength();
        for( ; pProperty != pPropertyEnd; ++pProperty )
        {
            if( ( ( nFound & FOUND_CLICKEVENTTYPE ) == 0 ) && pProperty->Name == msEventType )
            {
                if( pProperty->Value >>= aClickEventType )
                    nFound |= FOUND_CLICKEVENTTYPE;
            }
            else if( ( ( nFound & FOUND_CLICKACTION ) == 0 ) && pProperty->Name == msClickAction )
            {
                if( pProperty->Value >>= eClickAction )
                    nFound |= FOUND_CLICKACTION;
            }
            else if( ( ( nFound & FOUND_MACRO ) == 0 ) && ( pProperty->Name == msMacroName || pProperty->Name == msScript ) )
            {
                if( pProperty->Value >>= aStrMacro )
                    nFound |= FOUND_MACRO;
            }
            else if( ( ( nFound & FOUND_LIBRARY ) == 0 ) && pProperty->Name == msLibrary )
            {
                if( pProperty->Value >>= aStrLibrary )
                    nFound |= FOUND_LIBRARY;
            }
            else if( ( ( nFound & FOUND_EFFECT ) == 0 ) && pProperty->Name == msEffect )
            {
                if( pProperty->Value >>= eEffect )
                    nFound |= FOUND_EFFECT;
            }
            else if( ( ( nFound & FOUND_BOOKMARK ) == 0 ) && pProperty->Name == msBookmark )
            {
                if( pProperty->Value >>= aStrBookmark )
                    nFound |= FOUND_BOOKMARK;
            }
            else if( ( ( nFound & FOUND_SPEED ) == 0 ) && pProperty->Name == msSpeed )
            {
                if( pProperty->Value >>= eSpeed )
                    nFound |= FOUND_SPEED;
            }
            else if( ( ( nFound & FOUND_SOUNDURL ) == 0 ) && pProperty->Name == msSoundURL )
            {
                if( pProperty->Value >>= aStrSoundURL )
                    nFound |= FOUND_SOUNDURL;
            }
            else if( ( ( nFound & FOUND_PLAYFULL ) == 0 ) && pProperty->Name == msPlayFull )
            {
                if( pProperty->Value >>= bPlayFull )
                    nFound |= FOUND_PLAYFULL;
            }
            else if( ( ( nFound & FOUND_VERB ) == 0 ) && pProperty->Name == msVerb )
            {
                if( pProperty->Value >>= nVerb )
                    nFound |= FOUND_VERB;
            }
        }
    }

#ifdef ISSUE66550_HLINK_FOR_SHAPES
    // extract properties from "OnAction" event -------------------------------

    OUString aActionEventType;
    OUString aHyperURL;

    uno::Sequence< beans::PropertyValue > aActionProperties;
    if( xEvents->hasByName( msOnAction ) && (xEvents->getByName( msOnAction ) >>= aActionProperties) )
    {
        const beans::PropertyValue* pProperty = aActionProperties.getConstArray();
        const beans::PropertyValue* pPropertyEnd = pProperty + aActionProperties.getLength();
        for( ; pProperty != pPropertyEnd; ++pProperty )
        {
            if( ( ( nFound & FOUND_ACTIONEVENTTYPE ) == 0 ) && pProperty->Name == msEventType )
            {
                if( pProperty->Value >>= aActionEventType )
                    nFound |= FOUND_ACTIONEVENTTYPE;
            }
            else if( ( ( nFound & FOUND_URL ) == 0 ) && ( pProperty->Name == msURL  ) )
            {
                if( pProperty->Value >>= aHyperURL )
                    nFound |= FOUND_URL;
            }
        }
    }
#endif

    // create the XML elements

    if( aClickEventType == msPresentation )
    {
        if( ((nFound & FOUND_CLICKACTION) == 0) || (eClickAction == presentation::ClickAction_NONE) )
            return;

        SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, sal_True, sal_True);

        enum XMLTokenEnum eStrAction;

        switch( eClickAction )
        {
            case presentation::ClickAction_PREVPAGE:        eStrAction = XML_PREVIOUS_PAGE; break;
            case presentation::ClickAction_NEXTPAGE:        eStrAction = XML_NEXT_PAGE; break;
            case presentation::ClickAction_FIRSTPAGE:       eStrAction = XML_FIRST_PAGE; break;
            case presentation::ClickAction_LASTPAGE:        eStrAction = XML_LAST_PAGE; break;
            case presentation::ClickAction_INVISIBLE:       eStrAction = XML_HIDE; break;
            case presentation::ClickAction_STOPPRESENTATION:eStrAction = XML_STOP; break;
            case presentation::ClickAction_PROGRAM:         eStrAction = XML_EXECUTE; break;
            case presentation::ClickAction_BOOKMARK:        eStrAction = XML_SHOW; break;
            case presentation::ClickAction_DOCUMENT:        eStrAction = XML_SHOW; break;
            case presentation::ClickAction_MACRO:           eStrAction = XML_EXECUTE_MACRO; break;
            case presentation::ClickAction_VERB:            eStrAction = XML_VERB; break;
            case presentation::ClickAction_VANISH:          eStrAction = XML_FADE_OUT; break;
            case presentation::ClickAction_SOUND:           eStrAction = XML_SOUND; break;
            default:
                DBG_ERROR( "unknown presentation::ClickAction found!" );
                eStrAction = XML_UNKNOWN;
        }

        OUString aEventQName(
            mrExport.GetNamespaceMap().GetQNameByKey(
                    XML_NAMESPACE_DOM, OUString( RTL_CONSTASCII_USTRINGPARAM( "click" ) ) ) );
        mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
        mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_ACTION, eStrAction );

        if( eClickAction == presentation::ClickAction_VANISH )
        {
            if( nFound & FOUND_EFFECT )
            {
                XMLEffect eKind;
                XMLEffectDirection eDirection;
                sal_Int16 nStartScale;
                sal_Bool bIn;

                SdXMLImplSetEffect( eEffect, eKind, eDirection, nStartScale, bIn );

                if( eKind != EK_none )
                {
                    SvXMLUnitConverter::convertEnum( msBuffer, eKind, aXML_AnimationEffect_EnumMap );
                    mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_EFFECT, msBuffer.makeStringAndClear() );
                }

                if( eDirection != ED_none )
                {
                    SvXMLUnitConverter::convertEnum( msBuffer, eDirection, aXML_AnimationDirection_EnumMap );
                    mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_DIRECTION, msBuffer.makeStringAndClear() );
                }

                if( nStartScale != -1 )
                {
                    SvXMLUnitConverter::convertPercent( msBuffer, nStartScale );
                    mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_START_SCALE, msBuffer.makeStringAndClear() );
                }
            }

            if( nFound & FOUND_SPEED && eEffect != presentation::AnimationEffect_NONE )
            {
                 if( eSpeed != presentation::AnimationSpeed_MEDIUM )
                    {
                    SvXMLUnitConverter::convertEnum( msBuffer, eSpeed, aXML_AnimationSpeed_EnumMap );
                    mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_SPEED, msBuffer.makeStringAndClear() );
                }
            }
        }

        if( eClickAction == presentation::ClickAction_PROGRAM ||
            eClickAction == presentation::ClickAction_BOOKMARK ||
            eClickAction == presentation::ClickAction_DOCUMENT )
        {
            if( eClickAction == presentation::ClickAction_BOOKMARK )
                msBuffer.append( sal_Unicode('#') );

            msBuffer.append( aStrBookmark );
            mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(msBuffer.makeStringAndClear()) );
            mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
            mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
            mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST );
        }

        if( ( nFound & FOUND_VERB ) && eClickAction == presentation::ClickAction_VERB )
        {
            msBuffer.append( nVerb );
            mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_VERB, msBuffer.makeStringAndClear());
        }

        SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_PRESENTATION, XML_EVENT_LISTENER, sal_True, sal_True);

        if( eClickAction == presentation::ClickAction_VANISH || eClickAction == presentation::ClickAction_SOUND )
        {
            if( ( nFound & FOUND_SOUNDURL ) && aStrSoundURL.getLength() != 0 )
            {
                mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStrSoundURL) );
                mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
                mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_NEW );
                mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST );
                if( nFound & FOUND_PLAYFULL && bPlayFull )
                    mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PLAY_FULL, XML_TRUE );

                SvXMLElementExport aElem( mrExport, XML_NAMESPACE_PRESENTATION, XML_SOUND, sal_True, sal_True );
            }
       }
    }
    else if( aClickEventType == msStarBasic )
    {
        if( nFound & FOUND_MACRO )
        {
            SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, sal_True, sal_True);

            mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE,
                        mrExport.GetNamespaceMap().GetQNameByKey(
                            XML_NAMESPACE_OOO,
                            OUString( RTL_CONSTASCII_USTRINGPARAM(
                                            "starbasic" ) ) ) );
            OUString aEventQName(
                mrExport.GetNamespaceMap().GetQNameByKey(
                        XML_NAMESPACE_DOM, OUString( RTL_CONSTASCII_USTRINGPARAM( "click" ) ) ) );
            mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );

            if( nFound & FOUND_LIBRARY )
            {
                OUString sLocation( GetXMLToken(
                    (aStrLibrary.equalsIgnoreAsciiCaseAscii("StarOffice") ||
                     aStrLibrary.equalsIgnoreAsciiCaseAscii("application") ) ? XML_APPLICATION
                                                                       : XML_DOCUMENT ) );
                OUStringBuffer sTmp( sLocation.getLength() + aStrMacro.getLength() + 1 );
                sTmp = sLocation;
                sTmp.append( sal_Unicode( ':' ) );
                sTmp.append( aStrMacro );
                mrExport.AddAttribute(XML_NAMESPACE_SCRIPT, XML_MACRO_NAME,
                                     sTmp.makeStringAndClear());
            }
            else
            {
                mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_MACRO_NAME, aStrMacro );
            }

            SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, sal_True, sal_True);
        }
    }
#ifdef ISSUE66550_HLINK_FOR_SHAPES
    else if( aClickEventType == msScript || aActionEventType == msAction )
    {
        if( nFound & ( FOUND_MACRO | FOUND_URL ) )
#else
    else if( aClickEventType == msScript )
    {
        if( nFound & FOUND_MACRO )
#endif
        {
            SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, sal_True, sal_True);
            if ( nFound & FOUND_MACRO )
            {
                mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE, mrExport.GetNamespaceMap().GetQNameByKey(
                         XML_NAMESPACE_OOO, GetXMLToken(XML_SCRIPT) ) );
                OUString aEventQName(
                    mrExport.GetNamespaceMap().GetQNameByKey(
                            XML_NAMESPACE_DOM, OUString( RTL_CONSTASCII_USTRINGPARAM( "click" ) ) ) );
                mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
                mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aStrMacro );

                SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, sal_True, sal_True);
            }
#ifdef ISSUE66550_HLINK_FOR_SHAPES
            if ( nFound & FOUND_URL )
            {
                OUString aEventQName(
                    mrExport.GetNamespaceMap().GetQNameByKey(
                            XML_NAMESPACE_DOM, OUString( RTL_CONSTASCII_USTRINGPARAM( "action" ) ) ) );
                mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
                mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aHyperURL );

                SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_PRESENTATION, XML_EVENT_LISTENER, sal_True, sal_True);
            }
#endif
        }
    }
}

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

/** #i68101# export shape Title and Description */
void XMLShapeExport::ImpExportDescription( const uno::Reference< drawing::XShape >& xShape )
{
    try
    {
        OUString aTitle;
        OUString aDescription;

        uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY_THROW );
        xProps->getPropertyValue( OUString::createFromAscii( "Title" ) ) >>= aTitle;
        xProps->getPropertyValue( OUString::createFromAscii( "Description" ) ) >>= aDescription;

        if(aTitle.getLength())
        {
            SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_TITLE, sal_True, sal_False);
            mrExport.Characters( aTitle );
        }

        if(aDescription.getLength())
        {
            SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_DESC, sal_True, sal_False );
            mrExport.Characters( aDescription );
        }
    }
    catch( uno::Exception& )
    {
        DBG_ERROR( "could not export Title and/or Description for shape!" );
    }
}

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

void XMLShapeExport::ImpExportGroupShape( const uno::Reference< drawing::XShape >& xShape, XmlShapeType, sal_Int32 nFeatures, awt::Point* pRefPoint)
{
    uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY);
    if(xShapes.is() && xShapes->getCount())
    {
        // write group shape
        sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#
        SvXMLElementExport aPGR(mrExport, XML_NAMESPACE_DRAW, XML_G, bCreateNewline, sal_True);

        ImpExportDescription( xShape ); // #i68101#
        ImpExportEvents( xShape );
        ImpExportGluePoints( xShape );

        // #89764# if export of position is supressed for group shape,
        // positions of contained objects should be written relative to
        // the upper left edge of the group.
        awt::Point aUpperLeft;

        if(!(nFeatures & SEF_EXPORT_POSITION))
        {
            nFeatures |= SEF_EXPORT_POSITION;
            aUpperLeft = xShape->getPosition();
            pRefPoint = &aUpperLeft;
        }

        // write members
        exportShapes( xShapes, nFeatures, pRefPoint );
    }
}

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

void XMLShapeExport::ImpExportTextBoxShape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType eShapeType, sal_Int32 nFeatures, awt::Point* pRefPoint)
{
    const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
    if(xPropSet.is())
    {
        uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );

        // presentation attribute (if presentation)
        sal_Bool bIsPresShape(sal_False);
        sal_Bool bIsEmptyPresObj(sal_False);
        OUString aStr;

        switch(eShapeType)
        {
            case XmlShapeTypePresSubtitleShape:
            {
                aStr = GetXMLToken(XML_PRESENTATION_SUBTITLE);
                bIsPresShape = sal_True;
                break;
            }
            case XmlShapeTypePresTitleTextShape:
            {
                aStr = GetXMLToken(XML_PRESENTATION_TITLE);
                bIsPresShape = sal_True;
                break;
            }
            case XmlShapeTypePresOutlinerShape:
            {
                aStr = GetXMLToken(XML_PRESENTATION_OUTLINE);
                bIsPresShape = sal_True;
                break;
            }
            case XmlShapeTypePresNotesShape:
            {
                aStr = GetXMLToken(XML_PRESENTATION_NOTES);
                bIsPresShape = sal_True;
                break;
            }
            case XmlShapeTypePresHeaderShape:
            {
                aStr = GetXMLToken(XML_HEADER);
                bIsPresShape = sal_True;
                break;
            }
            case XmlShapeTypePresFooterShape:
            {
                aStr = GetXMLToken(XML_FOOTER);
                bIsPresShape = sal_True;
                break;
            }
            case XmlShapeTypePresSlideNumberShape:
            {
                aStr = GetXMLToken(XML_PAGE_NUMBER);
                bIsPresShape = sal_True;
                break;
            }
            case XmlShapeTypePresDateTimeShape:
            {
                aStr = GetXMLToken(XML_DATE_TIME);
                bIsPresShape = sal_True;
                break;
            }
            default:
                break;
        }

        // Transformation
        ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);

        if(bIsPresShape)
            bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, aStr );


        sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#
        SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
                                  XML_FRAME, bCreateNewline, sal_True );

        // evtl. corner radius?
        sal_Int32 nCornerRadius(0L);
        xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("CornerRadius"))) >>= nCornerRadius;
        if(nCornerRadius)
        {
            OUStringBuffer sStringBuffer;
            mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, nCornerRadius);
            mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
        }

        {
            // write text-box
            SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_TEXT_BOX, sal_True, sal_True);
            if(!bIsEmptyPresObj)
                ImpExportText( xShape );
        }

        ImpExportDescription( xShape ); // #i68101#
        ImpExportEvents( xShape );
        ImpExportGluePoints( xShape );
    }
}

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

void XMLShapeExport::ImpExportRectangleShape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType, sal_Int32 nFeatures, com::sun::star::awt::Point* pRefPoint)
{
    const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
    if(xPropSet.is())
    {
        // Transformation
        ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);

        // evtl. corner radius?
        sal_Int32 nCornerRadius(0L);
        xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("CornerRadius"))) >>= nCornerRadius;
        if(nCornerRadius)
        {
            OUStringBuffer sStringBuffer;
            mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, nCornerRadius);
            mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
        }

        // write rectangle
        sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#
        SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_RECT, bCreateNewline, sal_True);

        ImpExportDescription( xShape ); // #i68101#
        ImpExportEvents( xShape );
        ImpExportGluePoints( xShape );
        ImpExportText( xShape );
    }
}

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

void XMLShapeExport::ImpExportLineShape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType, sal_Int32 nFeatures, awt::Point* pRefPoint)
{
    const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
    if(xPropSet.is())
    {
        OUString aStr;
        OUStringBuffer sStringBuffer;
        awt::Point aStart(0,0);
        awt::Point aEnd(1,1);

        // #85920# use 'Geometry' to get the points of the line
        // since this slot take anchor pos into account.

        // get matrix
        ::basegfx::B2DHomMatrix aMatrix;
        ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);

        // decompose and correct about pRefPoint
        ::basegfx::B2DTuple aTRScale;
        double fTRShear(0.0);
        double fTRRotate(0.0);
        ::basegfx::B2DTuple aTRTranslate;
        ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);

        // create base position
        awt::Point aBasePosition(FRound(aTRTranslate.getX()), FRound(aTRTranslate.getY()));

        // get the two points
        uno::Any aAny(xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("Geometry"))));
        drawing::PointSequenceSequence* pSourcePolyPolygon = (drawing::PointSequenceSequence*)aAny.getValue();

        if(pSourcePolyPolygon)
        {
            drawing::PointSequence* pOuterSequence = pSourcePolyPolygon->getArray();
            if(pOuterSequence)
            {
                drawing::PointSequence* pInnerSequence = pOuterSequence++;
                if(pInnerSequence)
                {
                    awt::Point* pArray = pInnerSequence->getArray();
                    if(pArray)
                    {
                        if(pInnerSequence->getLength() > 0)
                        {
                            aStart = awt::Point(
                                pArray->X + aBasePosition.X,
                                pArray->Y + aBasePosition.Y);
                            pArray++;
                        }

                        if(pInnerSequence->getLength() > 1)
                        {
                            aEnd = awt::Point(
                                pArray->X + aBasePosition.X,
                                pArray->Y + aBasePosition.Y);
                        }
                    }
                }
            }
        }

        if( nFeatures & SEF_EXPORT_X )
        {
            // svg: x1
            mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, aStart.X);
            aStr = sStringBuffer.makeStringAndClear();
            mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
        }
        else
        {
            aEnd.X -= aStart.X;
        }

        if( nFeatures & SEF_EXPORT_Y )
        {
            // svg: y1
            mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, aStart.Y);
            aStr = sStringBuffer.makeStringAndClear();
            mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
        }
        else
        {
            aEnd.Y -= aStart.Y;
        }

        // svg: x2
        mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, aEnd.X);
        aStr = sStringBuffer.makeStringAndClear();
        mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);

        // svg: y2
        mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, aEnd.Y);
        aStr = sStringBuffer.makeStringAndClear();
        mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);

        // write line
        sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#
        SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_LINE, bCreateNewline, sal_True);

        ImpExportDescription( xShape ); // #i68101#
        ImpExportEvents( xShape );
        ImpExportGluePoints( xShape );
        ImpExportText( xShape );
    }
}

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

void XMLShapeExport::ImpExportEllipseShape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType, sal_Int32 nFeatures, awt::Point* pRefPoint)
{
    const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
    if(xPropSet.is())
    {
        // get size to decide between Circle and Ellipse
        awt::Size aSize = xShape->getSize();
        sal_Int32 nRx((aSize.Width + 1) / 2);
        sal_Int32 nRy((aSize.Height + 1) / 2);
        sal_Bool bCircle(nRx == nRy);

        // Transformation
        ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);

        drawing::CircleKind eKind = drawing::CircleKind_FULL;
        xPropSet->getPropertyValue( OUString(RTL_CONSTASCII_USTRINGPARAM("CircleKind")) ) >>= eKind;
        if( eKind != drawing::CircleKind_FULL )
        {
            OUStringBuffer sStringBuffer;
            sal_Int32 nStartAngle = 0;
            sal_Int32 nEndAngle = 0;
            xPropSet->getPropertyValue( OUString(RTL_CONSTASCII_USTRINGPARAM("CircleStartAngle")) ) >>= nStartAngle;
            xPropSet->getPropertyValue( OUString(RTL_CONSTASCII_USTRINGPARAM("CircleEndAngle")) ) >>= nEndAngle;

            const double dStartAngle = nStartAngle / 100.0;
            const double dEndAngle = nEndAngle / 100.0;

            // export circle kind
            SvXMLUnitConverter::convertEnum( sStringBuffer, (sal_uInt16)eKind, aXML_CircleKind_EnumMap );
            mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_KIND, sStringBuffer.makeStringAndClear() );

            // export start angle
            SvXMLUnitConverter::convertDouble( sStringBuffer, dStartAngle );
            mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_ANGLE, sStringBuffer.makeStringAndClear() );

            // export end angle
            SvXMLUnitConverter::convertDouble( sStringBuffer, dEndAngle );
            mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_ANGLE, sStringBuffer.makeStringAndClear() );
        }

        sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#

        if(bCircle)
        {
            // write circle
            SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CIRCLE, bCreateNewline, sal_True);

            ImpExportDescription( xShape ); // #i68101#
            ImpExportEvents( xShape );
            ImpExportGluePoints( xShape );
            ImpExportText( xShape );
        }
        else
        {
            // write ellipse
            SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_ELLIPSE, bCreateNewline, sal_True);

            ImpExportDescription( xShape ); // #i68101#
            ImpExportEvents( xShape );
            ImpExportGluePoints( xShape );
            ImpExportText( xShape );
        }
    }
}

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

void XMLShapeExport::ImpExportPolygonShape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType eShapeType, sal_Int32 nFeatures, awt::Point* pRefPoint)
{
    const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
    if(xPropSet.is())
    {
        sal_Bool bClosed(eShapeType == XmlShapeTypeDrawPolyPolygonShape
            || eShapeType == XmlShapeTypeDrawClosedBezierShape);
        sal_Bool bBezier(eShapeType == XmlShapeTypeDrawClosedBezierShape
            || eShapeType == XmlShapeTypeDrawOpenBezierShape);

        // get matrix
        ::basegfx::B2DHomMatrix aMatrix;
        ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);

        // decompose and correct abour pRefPoint
        ::basegfx::B2DTuple aTRScale;
        double fTRShear(0.0);
        double fTRRotate(0.0);
        ::basegfx::B2DTuple aTRTranslate;
        ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);

        // use features and write
        ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures);

        // create and export ViewBox
        awt::Point aPoint(0, 0);
        awt::Size aSize(FRound(aTRScale.getX()), FRound(aTRScale.getY()));
        SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height);
        mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());

        sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#

        if(bBezier)
        {
            // get PolygonBezier
            uno::Any aAny( xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("Geometry"))) );
            drawing::PolyPolygonBezierCoords* pSourcePolyPolygon =
                (drawing::PolyPolygonBezierCoords*)aAny.getValue();

            if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength())
            {
                sal_Int32 nOuterCnt(pSourcePolyPolygon->Coordinates.getLength());
                drawing::PointSequence* pOuterSequence = pSourcePolyPolygon->Coordinates.getArray();
                drawing::FlagSequence*  pOuterFlags = pSourcePolyPolygon->Flags.getArray();

                if(pOuterSequence && pOuterFlags)
                {
                    // prepare svx:d element export
                    SdXMLImExSvgDElement aSvgDElement(aViewBox);

                    for(sal_Int32 a(0L); a < nOuterCnt; a++)
                    {
                        drawing::PointSequence* pSequence = pOuterSequence++;
                        drawing::FlagSequence* pFlags = pOuterFlags++;

                        if(pSequence && pFlags)
                        {
                            aSvgDElement.AddPolygon(pSequence, pFlags,
                                aPoint, aSize, bClosed);
                        }
                    }

                    // write point array
                    mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aSvgDElement.GetExportString());
                }

                // write object now
                SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PATH, bCreateNewline, sal_True);

                ImpExportDescription( xShape ); // #i68101#
                ImpExportEvents( xShape );
                ImpExportGluePoints( xShape );
                ImpExportText( xShape );
            }
        }
        else
        {
            // get non-bezier polygon
            uno::Any aAny( xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("Geometry"))) );
            drawing::PointSequenceSequence* pSourcePolyPolygon = (drawing::PointSequenceSequence*)aAny.getValue();

            if(pSourcePolyPolygon && pSourcePolyPolygon->getLength())
            {
                sal_Int32 nOuterCnt(pSourcePolyPolygon->getLength());

                if(1L == nOuterCnt && !bBezier)
                {
                    // simple polygon shape, can be written as svg:points sequence
                    drawing::PointSequence* pSequence = pSourcePolyPolygon->getArray();
                    if(pSequence)
                    {
                        SdXMLImExPointsElement aPoints(pSequence, aViewBox, aPoint, aSize,
                            // #96328#
                            bClosed);

                        // write point array
                        mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPoints.GetExportString());
                    }

                    // write object now
                    SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW,
                        bClosed ? XML_POLYGON : XML_POLYLINE , bCreateNewline, sal_True);

                    ImpExportDescription( xShape ); // #i68101#
                    ImpExportEvents( xShape );
                    ImpExportGluePoints( xShape );
                    ImpExportText( xShape );
                }
                else
                {
                    // polypolygon or bezier, needs to be written as a svg:path sequence
                    drawing::PointSequence* pOuterSequence = pSourcePolyPolygon->getArray();
                    if(pOuterSequence)
                    {
                        // prepare svx:d element export
                        SdXMLImExSvgDElement aSvgDElement(aViewBox);

                        for(sal_Int32 a(0L); a < nOuterCnt; a++)
                        {
                            drawing::PointSequence* pSequence = pOuterSequence++;
                            if(pSequence)
                            {
                                aSvgDElement.AddPolygon(pSequence, 0L, aPoint,
                                    aSize, bClosed);
                            }
                        }

                        // write point array
                        mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aSvgDElement.GetExportString());
                    }

                    // write object now
                    SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PATH, bCreateNewline, sal_True);

                    ImpExportDescription( xShape ); // #i68101#
                    ImpExportEvents( xShape );
                    ImpExportGluePoints( xShape );
                    ImpExportText( xShape );
                }
            }
        }
    }
}

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

void XMLShapeExport::ImpExportGraphicObjectShape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType eShapeType, sal_Int32 nFeatures, awt::Point* pRefPoint)
{
    const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
    if(xPropSet.is())
    {
        sal_Bool bIsEmptyPresObj = sal_False;
        uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );

        // Transformation
        ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);

        OUString sImageURL;

        if(eShapeType == XmlShapeTypePresGraphicObjectShape)
            bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_PRESENTATION_GRAPHIC) );

        sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#
        SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
                                  XML_FRAME, bCreateNewline, sal_True );

        const bool bSaveBackwardsCompatible = ( mrExport.getExportFlags() & EXPORT_SAVEBACKWARDCOMPATIBLE );

        if( !bIsEmptyPresObj || bSaveBackwardsCompatible )
        {
            if( !bIsEmptyPresObj )
            {
                OUString aReplacementUrl;
                xPropSet->getPropertyValue( OUString(RTL_CONSTASCII_USTRINGPARAM("ReplacementGraphicURL"))) >>= aReplacementUrl;

                // If there is no url, then then graphic is empty
                if(aReplacementUrl.getLength())
                {
                    const OUString aStr = mrExport.AddEmbeddedGraphicObject(aReplacementUrl);

                    if(aStr.getLength())
                    {
                        mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aStr);
                        mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
                        mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
                        mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );

                        // xlink:href for replacement, only written for Svg content
                        SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, sal_True, sal_True);

                        // optional office:binary-data
                        mrExport.AddEmbeddedGraphicObjectAsBase64(aReplacementUrl);
                    }
                }

                OUString aStreamURL;
                OUString aStr;

                xPropSet->getPropertyValue( OUString(RTL_CONSTASCII_USTRINGPARAM("GraphicStreamURL"))) >>= aStreamURL;
                xPropSet->getPropertyValue( OUString(RTL_CONSTASCII_USTRINGPARAM("GraphicURL"))) >>= sImageURL;

                OUString aResolveURL( sImageURL );
                const rtl::OUString sPackageURL( RTL_CONSTASCII_USTRINGPARAM("vnd.sun.star.Package:") );

                    // sj: trying to preserve the filename
                if ( aStreamURL.match( sPackageURL, 0 ) )
                {
                    rtl::OUString sRequestedName( aStreamURL.copy( sPackageURL.getLength(), aStreamURL.getLength() - sPackageURL.getLength() ) );
                    sal_Int32 nLastIndex = sRequestedName.lastIndexOf( '/' ) + 1;
                    if ( ( nLastIndex > 0 ) && ( nLastIndex < sRequestedName.getLength() ) )
                        sRequestedName = sRequestedName.copy( nLastIndex, sRequestedName.getLength() - nLastIndex );
                    nLastIndex = sRequestedName.lastIndexOf( '.' );
                    if ( nLastIndex >= 0 )
                        sRequestedName = sRequestedName.copy( 0, nLastIndex );
                    if ( sRequestedName.getLength() )
                    {
                        aResolveURL = aResolveURL.concat( OUString(RTL_CONSTASCII_USTRINGPARAM("?requestedName=")));
                        aResolveURL = aResolveURL.concat( sRequestedName );
                    }
                }

                aStr = mrExport.AddEmbeddedGraphicObject( aResolveURL );
                mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aStr );

                if( aStr.getLength() )
                {
                    if( aStr[ 0 ] == '#' )
                    {
                        aStreamURL = sPackageURL;
                        aStreamURL = aStreamURL.concat( aStr.copy( 1, aStr.getLength() - 1 ) );
                    }

                    // update stream URL for load on demand
                    uno::Any aAny;
                    aAny <<= aStreamURL;
                    xPropSet->setPropertyValue( OUString(RTL_CONSTASCII_USTRINGPARAM("GraphicStreamURL")), aAny );

                    mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
                    mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
                    mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
                }
            }
            else
            {
                OUString aStr;
                mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aStr );
                mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
                mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
                mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
            }

            {
                SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, sal_True, sal_True);

                if( sImageURL.getLength() )
                {
                    // optional office:binary-data
                    mrExport.AddEmbeddedGraphicObjectAsBase64( sImageURL );
                }
                if( !bIsEmptyPresObj )
                    ImpExportText( xShape );
            }
        }

        ImpExportEvents( xShape );
        ImpExportGluePoints( xShape );

        // image map
        GetExport().GetImageMapExport().Export( xPropSet );
        ImpExportDescription( xShape ); // #i68101#
    }
}

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

void XMLShapeExport::ImpExportChartShape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType eShapeType, sal_Int32 nFeatures, awt::Point* pRefPoint,
    SvXMLAttributeList* pAttrList )
{
    ImpExportOLE2Shape( xShape, eShapeType, nFeatures, pRefPoint, pAttrList );
}

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

void XMLShapeExport::ImpExportControlShape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType, sal_Int32 nFeatures, awt::Point* pRefPoint)
{
    const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
    if(xPropSet.is())
    {
        // Transformation
        ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
    }

    uno::Reference< drawing::XControlShape > xControl( xShape, uno::UNO_QUERY );
    DBG_ASSERT( xControl.is(), "Control shape is not supporting XControlShape" );
    if( xControl.is() )
    {
        uno::Reference< beans::XPropertySet > xControlModel( xControl->getControl(), uno::UNO_QUERY );
        DBG_ASSERT( xControlModel.is(), "Control shape has not XControlModel" );
        if( xControlModel.is() )
        {
            mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CONTROL, mrExport.GetFormExport()->getControlId( xControlModel ) );
        }
    }

    sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#
    SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONTROL, bCreateNewline, sal_True);

    ImpExportDescription( xShape ); // #i68101#
}

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

void XMLShapeExport::ImpExportConnectorShape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType, sal_Int32 nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
{
    uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );

    OUString aStr;
    OUStringBuffer sStringBuffer;

    // export connection kind
    drawing::ConnectorType eType = drawing::ConnectorType_STANDARD;
    uno::Any aAny = xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("EdgeKind")));
    aAny >>= eType;

    if( eType != drawing::ConnectorType_STANDARD )
    {
        SvXMLUnitConverter::convertEnum( sStringBuffer, (sal_uInt16)eType, aXML_ConnectionKind_EnumMap );
        aStr = sStringBuffer.makeStringAndClear();
        mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TYPE, aStr);
    }

    // export line skew
    sal_Int32 nDelta1 = 0, nDelta2 = 0, nDelta3 = 0;

    aAny = xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("EdgeLine1Delta")));
    aAny >>= nDelta1;
    aAny = xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("EdgeLine2Delta")));
    aAny >>= nDelta2;
    aAny = xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("EdgeLine3Delta")));
    aAny >>= nDelta3;

    if( nDelta1 != 0 || nDelta2 != 0 || nDelta3 != 0 )
    {
        mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, nDelta1);
        if( nDelta2 != 0 || nDelta3 != 0 )
        {
            const char aSpace = ' ';
            sStringBuffer.appendAscii( &aSpace, 1 );
            mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, nDelta2);
            if( nDelta3 != 0 )
            {
                sStringBuffer.appendAscii( &aSpace, 1 );
                mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, nDelta3);
            }
        }

        aStr = sStringBuffer.makeStringAndClear();
        mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_LINE_SKEW, aStr);
    }

    // export start and end point
    awt::Point aStart(0,0);
    awt::Point aEnd(1,1);

    // --> OD 2004-08-09 #i36248# - Get <StartPositionInHoriL2R> and
    // <EndPositionInHoriL2R>, if they exist and if the document is exported
    // into the OpenOffice.org file format.
    // These properties only exist at service com::sun::star::text::Shape - the
    // Writer UNO service for shapes.
    // This code is needed, because the positioning attributes in the
    // OpenOffice.org file format are given in horizontal left-to-right layout
    // regardless the layout direction the shape is in. In the OASIS Open Office
    // file format the positioning attributes are correctly given in the layout
    // direction the shape is in. Thus, this code provides the conversion from
    // the OASIS Open Office file format to the OpenOffice.org file format.
    if ( ( GetExport().getExportFlags() & EXPORT_OASIS ) == 0 &&
         xProps->getPropertySetInfo()->hasPropertyByName(
            OUString(RTL_CONSTASCII_USTRINGPARAM("StartPositionInHoriL2R"))) &&
         xProps->getPropertySetInfo()->hasPropertyByName(
            OUString(RTL_CONSTASCII_USTRINGPARAM("EndPositionInHoriL2R"))) )
    {
        xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("StartPositionInHoriL2R"))) >>= aStart;
        xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("EndPositionInHoriL2R"))) >>= aEnd;
    }
    else
    {
        xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("StartPosition"))) >>= aStart;
        xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("EndPosition"))) >>= aEnd;
    }
    // <--

    if( pRefPoint )
    {
        aStart.X -= pRefPoint->X;
        aStart.Y -= pRefPoint->Y;
        aEnd.X -= pRefPoint->X;
        aEnd.Y -= pRefPoint->Y;
    }

    if( nFeatures & SEF_EXPORT_X )
    {
        // svg: x1
        mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, aStart.X);
        aStr = sStringBuffer.makeStringAndClear();
        mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
    }
    else
    {
        aEnd.X -= aStart.X;
    }

    if( nFeatures & SEF_EXPORT_Y )
    {
        // svg: y1
        mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, aStart.Y);
        aStr = sStringBuffer.makeStringAndClear();
        mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
    }
    else
    {
        aEnd.Y -= aStart.Y;
    }

    // svg: x2
    mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, aEnd.X);
    aStr = sStringBuffer.makeStringAndClear();
    mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);

    // svg: y2
    mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, aEnd.Y);
    aStr = sStringBuffer.makeStringAndClear();
    mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);

    // #i39320#
    uno::Reference< uno::XInterface > xRefS;
    uno::Reference< uno::XInterface > xRefE;

    // export start connection
    xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("StartShape") ) ) >>= xRefS;
    if( xRefS.is() )
    {
        const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefS );
        mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_SHAPE, rShapeId);

        aAny = xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("StartGluePointIndex")) );
        sal_Int32 nGluePointId = 0;
        if( aAny >>= nGluePointId )
        {
            if( nGluePointId != -1 )
            {
                mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_GLUE_POINT, OUString::valueOf( nGluePointId ));
            }
        }
    }

    // export end connection
    xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("EndShape")) ) >>= xRefE;
    if( xRefE.is() )
    {
        const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefE );
        mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_SHAPE, rShapeId);

        aAny = xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("EndGluePointIndex")) );
        sal_Int32 nGluePointId = 0;
        if( aAny >>= nGluePointId )
        {
            if( nGluePointId != -1 )
            {
                mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_GLUE_POINT, OUString::valueOf( nGluePointId ));
            }
        }
    }

    if( xProps->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM("PolyPolygonBezier") ) ) >>= aAny )
    {
        // get PolygonBezier
        drawing::PolyPolygonBezierCoords* pSourcePolyPolygon =
            (drawing::PolyPolygonBezierCoords*)aAny.getValue();

        if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength())
        {
            sal_Int32 nOuterCnt(pSourcePolyPolygon->Coordinates.getLength());
            drawing::PointSequence* pOuterSequence = pSourcePolyPolygon->Coordinates.getArray();
            drawing::FlagSequence*  pOuterFlags = pSourcePolyPolygon->Flags.getArray();

            if(pOuterSequence && pOuterFlags)
            {
                // prepare svx:d element export
                awt::Point aPoint( 0, 0 );
                awt::Size aSize( 1, 1 );
                SdXMLImExViewBox aViewBox( 0, 0, 1, 1 );
                SdXMLImExSvgDElement aSvgDElement(aViewBox);

                for(sal_Int32 a(0L); a < nOuterCnt; a++)
                {
                    drawing::PointSequence* pSequence = pOuterSequence++;
                    drawing::FlagSequence* pFlags = pOuterFlags++;

                    if(pSequence && pFlags)
                    {
                        aSvgDElement.AddPolygon(pSequence, pFlags,
                            aPoint, aSize, sal_False );
                    }
                }

                // write point array
                mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aSvgDElement.GetExportString());
            }
        }
    }

    // write connector shape. Add Export later.
    sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#
    SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONNECTOR, bCreateNewline, sal_True);

    ImpExportDescription( xShape ); // #i68101#
    ImpExportEvents( xShape );
    ImpExportGluePoints( xShape );
    ImpExportText( xShape );
}

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

void XMLShapeExport::ImpExportMeasureShape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType, sal_Int32 nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
{
    uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );

    OUString aStr;
    OUStringBuffer sStringBuffer;

    // export start and end point
    awt::Point aStart(0,0);
    awt::Point aEnd(1,1);

    // --> OD 2004-08-09 #i36248# - Get <StartPositionInHoriL2R> and
    // <EndPositionInHoriL2R>, if they exist and if the document is exported
    // into the OpenOffice.org file format.
    // These properties only exist at service com::sun::star::text::Shape - the
    // Writer UNO service for shapes.
    // This code is needed, because the positioning attributes in the
    // OpenOffice.org file format are given in horizontal left-to-right layout
    // regardless the layout direction the shape is in. In the OASIS Open Office
    // file format the positioning attributes are correctly given in the layout
    // direction the shape is in. Thus, this code provides the conversion from
    // the OASIS Open Office file format to the OpenOffice.org file format.
    if ( ( GetExport().getExportFlags() & EXPORT_OASIS ) == 0 &&
         xProps->getPropertySetInfo()->hasPropertyByName(
            OUString(RTL_CONSTASCII_USTRINGPARAM("StartPositionInHoriL2R"))) &&
         xProps->getPropertySetInfo()->hasPropertyByName(
            OUString(RTL_CONSTASCII_USTRINGPARAM("EndPositionInHoriL2R"))) )
    {
        xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("StartPositionInHoriL2R"))) >>= aStart;
        xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("EndPositionInHoriL2R"))) >>= aEnd;
    }
    else
    {
        xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("StartPosition"))) >>= aStart;
        xProps->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("EndPosition"))) >>= aEnd;
    }
    // <--

    if( pRefPoint )
    {
        aStart.X -= pRefPoint->X;
        aStart.Y -= pRefPoint->Y;
        aEnd.X -= pRefPoint->X;
        aEnd.Y -= pRefPoint->Y;
    }

    if( nFeatures & SEF_EXPORT_X )
    {
        // svg: x1
        mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, aStart.X);
        aStr = sStringBuffer.makeStringAndClear();
        mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
    }
    else
    {
        aEnd.X -= aStart.X;
    }

    if( nFeatures & SEF_EXPORT_Y )
    {
        // svg: y1
        mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, aStart.Y);
        aStr = sStringBuffer.makeStringAndClear();
        mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
    }
    else
    {
        aEnd.Y -= aStart.Y;
    }

    // svg: x2
    mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, aEnd.X);
    aStr = sStringBuffer.makeStringAndClear();
    mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);

    // svg: y2
    mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, aEnd.Y);
    aStr = sStringBuffer.makeStringAndClear();
    mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);

    // write measure shape
    sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#
    SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_MEASURE, bCreateNewline, sal_True);

    ImpExportDescription( xShape ); // #i68101#
    ImpExportEvents( xShape );
    ImpExportGluePoints( xShape );

    uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY );
    if( xText.is() )
        mrExport.GetTextParagraphExport()->exportText( xText );
}

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

void XMLShapeExport::ImpExportOLE2Shape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType eShapeType, sal_Int32 nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */,
    SvXMLAttributeList* pAttrList /* = NULL */ )
{
    uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
    uno::Reference< container::XNamed > xNamed(xShape, uno::UNO_QUERY);

    DBG_ASSERT( xPropSet.is() && xNamed.is(), "ole shape is not implementing needed interfaces");
    if(xPropSet.is() && xNamed.is())
    {
        // Transformation
        ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);

        sal_Bool bIsEmptyPresObj = sal_False;

        // presentation settings
        if(eShapeType == XmlShapeTypePresOLE2Shape)
            bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_PRESENTATION_OBJECT) );
        else if(eShapeType == XmlShapeTypePresChartShape)
            bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_PRESENTATION_CHART) );
        else if(eShapeType == XmlShapeTypePresSheetShape)
            bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_PRESENTATION_TABLE) );

        sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#
        sal_Bool bExportEmbedded(0 != (mrExport.getExportFlags() & EXPORT_EMBEDDED));
        OUString sPersistName;
        SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
                                  XML_FRAME, bCreateNewline, sal_True );

        const bool bSaveBackwardsCompatible = ( mrExport.getExportFlags() & EXPORT_SAVEBACKWARDCOMPATIBLE );

        if( !bIsEmptyPresObj || bSaveBackwardsCompatible )
        {
            if (pAttrList)
            {
                mrExport.AddAttributeList(pAttrList);
            }

            OUString sClassId;
            OUString sURL;
            sal_Bool bInternal = false;
            xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("IsInternal"))) >>= bInternal;

            if( !bIsEmptyPresObj )
            {

                if ( bInternal )
                {
                    // OOo internal links have no storage persistance, URL is stored in the XML file
                    // the result LinkURL is empty in case the object is not a link
                    xPropSet->getPropertyValue( OUString::createFromAscii( "LinkURL" ) ) >>= sURL;
                }

                xPropSet->getPropertyValue( OUString(RTL_CONSTASCII_USTRINGPARAM( "PersistName" ) ) ) >>= sPersistName;
                if ( !sURL.getLength() )
                {
                    if( sPersistName.getLength() )
                    {
                        sURL = OUString( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.EmbeddedObject:" ) );
                        sURL += sPersistName;
                    }
                }

                if( !bInternal )
                    xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("CLSID"))) >>= sClassId;

                if( sClassId.getLength() )
                    mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CLASS_ID, sClassId );
                if(!bExportEmbedded)
                {
                    // xlink:href
                    if( sURL.getLength() )
                    {
                        // #96717# in theorie, if we don't have a url we shouldn't even
                        // export this ole shape. But practical its to risky right now
                        // to change this so we better dispose this on load
                        sURL = mrExport.AddEmbeddedObject( sURL );

                        mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL );
                        mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
                        mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
                        mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
                    }
                }
            }
            else
            {
                // export empty href for empty placeholders to be valid odf
                OUString sEmptyURL;

                mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sEmptyURL );
                mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
                mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
                mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
            }

            enum XMLTokenEnum eElem = sClassId.getLength() ? XML_OBJECT_OLE : XML_OBJECT;
            SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, eElem, sal_True, sal_True );

            // #i118485# Add text export, the draw OLE shape allows text now
            ImpExportText( xShape );

            if(bExportEmbedded && !bIsEmptyPresObj)
            {
                // #100592#
                if(bInternal)
                {
                    // embedded XML
                    uno::Reference< lang::XComponent > xComp;
                    xPropSet->getPropertyValue( OUString(RTL_CONSTASCII_USTRINGPARAM("Model") ) ) >>= xComp;
                    DBG_ASSERT( xComp.is(), "no xModel for own OLE format" );
                    mrExport.ExportEmbeddedOwnObject( xComp );
                }
                else
                {
                    // embed as Base64
                    // this is an alien object ( currently MSOLE is the only supported type of such objects )
                    // in case it is not an OASIS format the object should be asked to store replacement image if possible

                    ::rtl::OUString sURLRequest( sURL );
                    if ( ( mrExport.getExportFlags() & EXPORT_OASIS ) == 0 )
                        sURLRequest += ::rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "?oasis=false" ) );
                    mrExport.AddEmbeddedObjectAsBase64( sURLRequest );
                }
            }
        }
        if( !bIsEmptyPresObj )
        {
            OUString sURL( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.GraphicObject:" ) );
            sURL += sPersistName;
            if( !bExportEmbedded )
            {
                sURL = GetExport().AddEmbeddedObject( sURL );
                mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL );
                mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
                mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
                mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
            }

            SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW,
                                      XML_IMAGE, sal_False, sal_True );

            if( bExportEmbedded )
                GetExport().AddEmbeddedObjectAsBase64( sURL );
        }

        ImpExportEvents( xShape );
        ImpExportGluePoints( xShape );
        ImpExportDescription( xShape ); // #i68101#
    }
}

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

void XMLShapeExport::ImpExportPageShape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType eShapeType, sal_Int32 nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
{
    const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
    if(xPropSet.is())
    {
        // #86163# Transformation
        ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);

        // export page number used for this page
        uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
        const OUString aPageNumberStr(RTL_CONSTASCII_USTRINGPARAM("PageNumber"));
        if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(aPageNumberStr))
        {
            sal_Int32 nPageNumber = 0;
            xPropSet->getPropertyValue(aPageNumberStr) >>= nPageNumber;
            if( nPageNumber )
                mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_PAGE_NUMBER, OUString::valueOf(nPageNumber));
        }

        // a presentation page shape, normally used on notes pages only. If
        // it is used not as presentation shape, it may have been created with
        // copy-paste exchange between draw and impress (this IS possible...)
        if(eShapeType == XmlShapeTypePresPageShape)
        {
            mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS,
                                 XML_PRESENTATION_PAGE);
        }

        // write Page shape
        sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#
        SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PAGE_THUMBNAIL, bCreateNewline, sal_True);
    }
}

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

void XMLShapeExport::ImpExportCaptionShape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType, sal_Int32 nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
{
    const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
    if(xPropSet.is())
    {
        // Transformation
        ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);

        // evtl. corner radius?
        sal_Int32 nCornerRadius(0L);
        xPropSet->getPropertyValue(OUString(RTL_CONSTASCII_USTRINGPARAM("CornerRadius"))) >>= nCornerRadius;
        if(nCornerRadius)
        {
            OUStringBuffer sStringBuffer;
            mrExport.GetMM100UnitConverter().convertMeasure(sStringBuffer, nCornerRadius);
            mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
        }

        awt::Point aCaptionPoint;
        xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "CaptionPoint" ) ) ) >>= aCaptionPoint;

        mrExport.GetMM100UnitConverter().convertMeasure(msBuffer, aCaptionPoint.X);
        mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_X, msBuffer.makeStringAndClear() );
        mrExport.GetMM100UnitConverter().convertMeasure(msBuffer, aCaptionPoint.Y);
        mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_Y, msBuffer.makeStringAndClear() );

        // write Caption shape. Add export later.
        sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#
        sal_Bool bAnnotation( (nFeatures & SEF_EXPORT_ANNOTATION) == SEF_EXPORT_ANNOTATION );

        SvXMLElementExport aObj( mrExport,
                                 (bAnnotation ? XML_NAMESPACE_OFFICE
                                               : XML_NAMESPACE_DRAW),
                                 (bAnnotation ? XML_ANNOTATION : XML_CAPTION),
                                 bCreateNewline, sal_True );

        ImpExportDescription( xShape ); // #i68101#
        ImpExportEvents( xShape );
        ImpExportGluePoints( xShape );
        if( bAnnotation )
            mrExport.exportAnnotationMeta( xShape );
        ImpExportText( xShape );
    }
}

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

void XMLShapeExport::ImpExportFrameShape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType, sal_Int32 nFeatures, com::sun::star::awt::Point* pRefPoint)
{
    const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
    if(xPropSet.is())
    {
        // Transformation
        ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);

        sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#
        SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
                                  XML_FRAME, bCreateNewline, sal_True );

        // export frame url
        OUString aStr;
        xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "FrameURL" ) ) ) >>= aStr;
        mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
        mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
        mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
        mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );

        // export name
        xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "FrameName" ) ) ) >>= aStr;
        if( aStr.getLength() )
            mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FRAME_NAME, aStr );

        // write floating frame
        {
            SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_FLOATING_FRAME, sal_True, sal_True);
        }
    }
}

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

void XMLShapeExport::ImpExportAppletShape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType, sal_Int32 nFeatures, com::sun::star::awt::Point* pRefPoint)
{
    const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
    if(xPropSet.is())
    {
        // Transformation
        ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);

        sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#
        SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
                                  XML_FRAME, bCreateNewline, sal_True );

        // export frame url
        OUString aStr;
        xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "AppletCodeBase" ) ) ) >>= aStr;
        mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
        mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
        mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
        mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );

        // export draw:applet-name
        xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "AppletName" ) ) ) >>= aStr;
        if( aStr.getLength() )
            mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_APPLET_NAME, aStr );

        // export draw:code
        xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "AppletCode" ) ) ) >>= aStr;
        mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CODE, aStr );

        // export draw:may-script
        sal_Bool bIsScript = false;
        xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "AppletIsScript" ) ) ) >>= bIsScript;
        mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MAY_SCRIPT, bIsScript ? XML_TRUE : XML_FALSE );

        {
            // write applet
            SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_APPLET, sal_True, sal_True);

            // export parameters
            uno::Sequence< beans::PropertyValue > aCommands;
            xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "AppletCommands" ) ) ) >>= aCommands;
            const sal_Int32 nCount = aCommands.getLength();
            for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
            {
                aCommands[nIndex].Value >>= aStr;
                mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aCommands[nIndex].Name );
                mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr );
                SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, sal_False, sal_True );
            }
        }
    }
}

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

void XMLShapeExport::ImpExportPluginShape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType, sal_Int32 nFeatures, com::sun::star::awt::Point* pRefPoint)
{
    const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
    if(xPropSet.is())
    {
        // Transformation
        ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);

        sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#
        SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
                                  XML_FRAME, bCreateNewline, sal_True );

        // export plugin url
        OUString aStr;
        xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "PluginURL" ) ) ) >>= aStr;
        mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
        mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
        mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
        mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );


        // export mime-type
        xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "PluginMimeType" ) ) ) >>= aStr;
        if(aStr.getLength())
            mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, aStr );

        {
            // write plugin
            SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, sal_True, sal_True);

            // export parameters
            uno::Sequence< beans::PropertyValue > aCommands;
            xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "PluginCommands" ) ) ) >>= aCommands;
            const sal_Int32 nCount = aCommands.getLength();
            for( sal_Int32 nIndex = 0; nIndex < nCount; nIndex++ )
            {
                aCommands[nIndex].Value >>= aStr;
                mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aCommands[nIndex].Name );
                mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr );
                SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, sal_False, sal_True );
            }
        }
    }
}

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

void XMLShapeExport::ImpExportMediaShape(
    const uno::Reference< drawing::XShape >& xShape,
    XmlShapeType eShapeType, sal_Int32 nFeatures, com::sun::star::awt::Point* pRefPoint)
{
    const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
    if(xPropSet.is())
    {
        // Transformation
        ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);

        if(eShapeType == XmlShapeTypePresMediaShape)
            ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_PRESENTATION_OBJECT) );

        sal_Bool bCreateNewline( (nFeatures & SEF_EXPORT_NO_WS) == 0 ); // #86116#/#92210#
        SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
                                  XML_FRAME, bCreateNewline, sal_True );

        // export media url
        OUString aMediaURL;
        xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "MediaURL" ) ) ) >>= aMediaURL;
        mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference( aMediaURL ) );
        mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
        mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
        mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );

        // export mime-type
        mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, OUString( RTL_CONSTASCII_USTRINGPARAM( "application/vnd.sun.star.media" ) ) );

        // write plugin
        SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, !( nFeatures & SEF_EXPORT_NO_WS ), sal_True);

        // export parameters
        const OUString aFalseStr( RTL_CONSTASCII_USTRINGPARAM( "false" ) ), aTrueStr( RTL_CONSTASCII_USTRINGPARAM( "true" ) );

        sal_Bool bLoop = false;
        const OUString aLoopStr( RTL_CONSTASCII_USTRINGPARAM( "Loop" ) );
        xPropSet->getPropertyValue( aLoopStr ) >>= bLoop;
        mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aLoopStr );
        mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, bLoop ? aTrueStr : aFalseStr );
        delete( new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, sal_False, sal_True ) );

        sal_Bool bMute = false;
        const OUString aMuteStr( RTL_CONSTASCII_USTRINGPARAM( "Mute" ) );
        xPropSet->getPropertyValue( aMuteStr ) >>= bMute;
        mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aMuteStr );
        mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, bMute ? aTrueStr : aFalseStr );
        delete( new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, sal_False, sal_True ) );

        sal_Int16 nVolumeDB = 0;
        const OUString aVolumeDBStr( RTL_CONSTASCII_USTRINGPARAM( "VolumeDB" ) );
        xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "VolumeDB" ) ) ) >>= nVolumeDB;
        mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aVolumeDBStr );
        mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, OUString::valueOf( static_cast< sal_Int32 >( nVolumeDB ) ) );
        delete( new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, sal_False, sal_True ) );

        media::ZoomLevel eZoom;
        const OUString aZoomStr( RTL_CONSTASCII_USTRINGPARAM( "Zoom" ) );
        OUString aZoomValue;
        xPropSet->getPropertyValue( OUString( RTL_CONSTASCII_USTRINGPARAM( "Zoom" ) ) ) >>= eZoom;
        switch( eZoom )
        {
            case( media::ZoomLevel_ZOOM_1_TO_4 ): aZoomValue = OUString( RTL_CONSTASCII_USTRINGPARAM( "25%" ) ); break;
            case( media::ZoomLevel_ZOOM_1_TO_2 ): aZoomValue = OUString( RTL_CONSTASCII_USTRINGPARAM( "50%" ) ); break;
            case( media::ZoomLevel_ORIGINAL ): aZoomValue = OUString( RTL_CONSTASCII_USTRINGPARAM( "100%" ) ); break;
            case( media::ZoomLevel_ZOOM_2_TO_1 ): aZoomValue = OUString( RTL_CONSTASCII_USTRINGPARAM( "200%" ) ); break;
            case( media::ZoomLevel_ZOOM_4_TO_1 ): aZoomValue = OUString( RTL_CONSTASCII_USTRINGPARAM( "400%" ) ); break;
            case( media::ZoomLevel_FIT_TO_WINDOW ): aZoomValue = OUString( RTL_CONSTASCII_USTRINGPARAM( "fit" ) ); break;
            case( media::ZoomLevel_FIT_TO_WINDOW_FIXED_ASPECT ): aZoomValue = OUString( RTL_CONSTASCII_USTRINGPARAM( "fixedfit" ) ); break;
            case( media::ZoomLevel_FULLSCREEN ): aZoomValue = OUString( RTL_CONSTASCII_USTRINGPARAM( "fullscreen" ) ); break;

            default:
            break;
        }

        if( aZoomValue.getLength() )
        {
            mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aZoomStr );
            mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aZoomValue );
            delete( new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, sal_False, sal_True ) );
        }
    }
}