Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/oox/source/drawingml/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 128 kB image not shown  

Quelle  shape.cxx   Sprache: C

 
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
 * This file is part of the LibreOffice project.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <config_wasm_strip.h>

#include <oox/drawingml/shape.hxx>
#include <drawingml/customshapeproperties.hxx>
#include <oox/drawingml/theme.hxx>
#include <drawingml/fillproperties.hxx>
#include <drawingml/fontworkhelpers.hxx>
#include <drawingml/graphicproperties.hxx>
#include <drawingml/lineproperties.hxx>
#include <drawingml/presetgeometrynames.hxx>
#include <drawingml/shape3dproperties.hxx>
#include <drawingml/scene3dhelper.hxx>
#include <oox/drawingml/effectproperties.hxx>
#include <oox/drawingml/shapepropertymap.hxx>
#include <drawingml/textbody.hxx>
#include <drawingml/textparagraph.hxx>
#include <drawingml/ThemeOverrideFragmentHandler.hxx>
#include <drawingml/table/tableproperties.hxx>
#include <oox/drawingml/chart/chartconverter.hxx>
#include <drawingml/chart/chartspacefragment.hxx>
#include <drawingml/chart/chartspacemodel.hxx>
#include <o3tl/safeint.hxx>
#include <o3tl/unit_conversion.hxx>
#include <oox/ppt/pptimport.hxx>
#include <oox/vml/vmldrawing.hxx>
#include <oox/vml/vmlshape.hxx>
#include <oox/vml/vmlshapecontainer.hxx>
#include <oox/core/xmlfilterbase.hxx>
#include <oox/helper/graphichelper.hxx>
#include <oox/helper/propertyset.hxx>
#include <oox/helper/modelobjecthelper.hxx>
#include <oox/mathml/imexport.hxx>
#include <oox/mathml/importutils.hxx>
#include <oox/token/properties.hxx>
#include "diagram/datamodel.hxx"
#include "diagram/diagramhelper.hxx"

#include <comphelper/classids.hxx>
#include <comphelper/propertysequence.hxx>
#include <comphelper/propertyvalue.hxx>
#include <comphelper/sequence.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <tools/gen.hxx>
#include <tools/globname.hxx>
#include <tools/mapunit.hxx>
#include <editeng/unoprnms.hxx>
#include <com/sun/star/awt/FontSlant.hpp>
#include <com/sun/star/awt/Size.hpp>
#include <com/sun/star/awt/XBitmap.hpp>
#include <com/sun/star/awt/FontWeight.hpp>
#include <com/sun/star/graphic/XGraphic.hpp>
#include <com/sun/star/container/XNamed.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/xml/dom/XDocument.hpp>
#include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/HomogenMatrix3.hpp>
#include <com/sun/star/drawing/TextVerticalAdjust.hpp>
#include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
#include <com/sun/star/drawing/GraphicExportFilter.hpp>
#include <com/sun/star/drawing/XShapes.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp>
#include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
#include <com/sun/star/drawing/ConnectorType.hpp>
#include <com/sun/star/embed/XEmbeddedObject.hpp>
#include <com/sun/star/text/XText.hpp>
#include <com/sun/star/table/BorderLine2.hpp>
#include <com/sun/star/table/ShadowFormat.hpp>
#include <com/sun/star/chart2/XChartDocument.hpp>
#include <com/sun/star/style/ParagraphAdjust.hpp>
#include <com/sun/star/io/XOutputStream.hpp>
#include <com/sun/star/lang/Locale.hpp>
#include <com/sun/star/i18n/ScriptType.hpp>
#include <com/sun/star/text/WritingMode2.hpp>

#include <basegfx/point/b2dpoint.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <com/sun/star/document/XActionLockable.hpp>
#include <com/sun/star/chart2/data/XDataReceiver.hpp>
#include <officecfg/Office/Common.hxx>
#include <svx/svdobj.hxx>
#include <svx/svdotable.hxx>
#include <svx/svdtrans.hxx>
#include <tools/stream.hxx>
#include <unotools/streamwrap.hxx>
#include <unotools/mediadescriptor.hxx>
#include <vcl/graph.hxx>
#include <vcl/graphicfilter.hxx>
#include <vcl/svapp.hxx>
#include <vcl/wmfexternal.hxx>
#include <sal/log.hxx>
#include <svx/sdtaitm.hxx>
#include <oox/drawingml/diagram/diagram.hxx>
#include <docmodel/theme/Theme.hxx>
#include <i18nlangtag/languagetag.hxx>
#include <i18nlangtag/mslangid.hxx>

using namespace ::oox::core;
using namespace ::com::sun::star;
using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::beans;
using namespace ::com::sun::star::frame;
using namespace ::com::sun::star::text;
using namespace ::com::sun::star::drawing;
using namespace ::com::sun::star::style;

namespace oox::drawingml {

Shape::Shape()
: mpLinePropertiesPtr( std::make_shared<LineProperties>() )
, mpShapeRefLinePropPtr( std::make_shared<LineProperties>() )
, mpFillPropertiesPtr( std::make_shared<FillProperties>() )
, mpShapeRefFillPropPtr( std::make_shared<FillProperties>() )
, mpGraphicPropertiesPtr( std::make_shared<GraphicProperties>() )
, mpCustomShapePropertiesPtr( std::make_shared<CustomShapeProperties>() )
, mp3DPropertiesPtr( std::make_shared<Shape3DProperties>() )
, mpEffectPropertiesPtr( std::make_shared<EffectProperties>() )
, mpShapeRefEffectPropPtr( std::make_shared<EffectProperties>() )
, mpMasterTextListStyle( std::make_shared<TextListStyle>() )
, mnSubType( 0 )
, meFrameType( FRAMETYPE_GENERIC )
, mnRotation( 0 )
, mnDiagramRotation( 0 )
, mbFlipH( false )
, mbFlipV( false )
, mbHidden( false )
, mbHiddenMasterShape( false )
, mbLocked( false )
, mbWPGChild(false)
, mbLockedCanvas( false )
, mbWordprocessingCanvas(false)
, mbWps( false )
, mbTextBox( false )
, mbHasLinkedTxbx( false )
, maDiagramDoms( 0 )
, mpDiagramHelper( nullptr )
{
    setDefaults(/*bDefaultHeight*/true);
}


Shape::Shape( const OUString& rServiceName, bool bDefaultHeight )
: mpLinePropertiesPtr( std::make_shared<LineProperties>() )
, mpShapeRefLinePropPtr( std::make_shared<LineProperties>() )
, mpFillPropertiesPtr( std::make_shared<FillProperties>() )
, mpShapeRefFillPropPtr( std::make_shared<FillProperties>() )
, mpGraphicPropertiesPtr( std::make_shared<GraphicProperties>() )
, mpCustomShapePropertiesPtr( std::make_shared<CustomShapeProperties>() )
, mp3DPropertiesPtr( std::make_shared<Shape3DProperties>() )
, mpEffectPropertiesPtr( std::make_shared<EffectProperties>() )
, mpShapeRefEffectPropPtr( std::make_shared<EffectProperties>() )
, mpMasterTextListStyle( std::make_shared<TextListStyle>() )
, mnSubType( 0 )
, meFrameType( FRAMETYPE_GENERIC )
, mnRotation( 0 )
, mnDiagramRotation( 0 )
, mbFlipH( false )
, mbFlipV( false )
, mbHidden( false )
, mbHiddenMasterShape( false )
, mbLocked( false )
, mbWPGChild(false)
, mbLockedCanvas( false )
, mbWordprocessingCanvas(false)
, mbWps( false )
, mbTextBox( false )
, mbHasLinkedTxbx( false )
, maDiagramDoms( 0 )
, mpDiagramHelper( nullptr )
{
    msServiceName = rServiceName;
    setDefaults(bDefaultHeight);
}

Shape::Shape( const ShapePtr& pSourceShape )
: mpTextBody(pSourceShape->mpTextBody)
, mpLinePropertiesPtr( pSourceShape->mpLinePropertiesPtr )
, mpShapeRefLinePropPtr( pSourceShape->mpShapeRefLinePropPtr )
, mpFillPropertiesPtr( pSourceShape->mpFillPropertiesPtr )
, mpShapeRefFillPropPtr( pSourceShape->mpShapeRefFillPropPtr )
, mpGraphicPropertiesPtr( pSourceShape->mpGraphicPropertiesPtr )
, mpCustomShapePropertiesPtr( pSourceShape->mpCustomShapePropertiesPtr )
, mpTablePropertiesPtr( pSourceShape->mpTablePropertiesPtr )
, mp3DPropertiesPtr( pSourceShape->mp3DPropertiesPtr )
, mpEffectPropertiesPtr (pSourceShape->mpEffectPropertiesPtr)
, mpShapeRefEffectPropPtr(pSourceShape->mpShapeRefEffectPropPtr)
, maShapeProperties( pSourceShape->maShapeProperties )
, mpMasterTextListStyle( pSourceShape->mpMasterTextListStyle )
, msServiceName( pSourceShape->msServiceName )
, msName( pSourceShape->msName )
, msInternalName( pSourceShape->msInternalName )
, msId( pSourceShape->msId )
, mnSubType( pSourceShape->mnSubType )
, moSubTypeIndex( pSourceShape->moSubTypeIndex )
, maShapeStyleRefs( pSourceShape->maShapeStyleRefs )
, maSize( pSourceShape->maSize )
, maPosition( pSourceShape->maPosition )
, meFrameType( pSourceShape->meFrameType )
, mnRotation( pSourceShape->mnRotation )
, mnDiagramRotation( pSourceShape->mnDiagramRotation )
, mbFlipH( pSourceShape->mbFlipH )
, mbFlipV( pSourceShape->mbFlipV )
, mbHidden( pSourceShape->mbHidden )
, mbHiddenMasterShape( pSourceShape->mbHiddenMasterShape )
, mbLocked( pSourceShape->mbLocked )
, mbWPGChild( pSourceShape->mbWPGChild )
, mbLockedCanvas( pSourceShape->mbLockedCanvas )
, mbWordprocessingCanvas(pSourceShape->mbWordprocessingCanvas)
, mbWps( pSourceShape->mbWps )
, mbTextBox( pSourceShape->mbTextBox )
, mbHasLinkedTxbx(false)
, maDiagramDoms( pSourceShape->maDiagramDoms )
, mnZOrder(pSourceShape->mnZOrder)
, mnZOrderOff(pSourceShape->mnZOrderOff)
, mnDataNodeType(pSourceShape->mnDataNodeType)
, mfAspectRatio(pSourceShape->mfAspectRatio)
, mpDiagramHelper( nullptr )
, msDiagramDataModelID(pSourceShape->msDiagramDataModelID)
{}

Shape::~Shape()
{
    // DiagramHelper should not be set here anymore, see
    // propagateDiagramHelper below (maybe assert..?)
    delete mpDiagramHelper;
}

void Shape::prepareDiagramHelper(
    const std::shared_ptr< Diagram >& rDiagramPtr,
    const std::shared_ptr<::oox::drawingml::Theme>& rTheme,
    bool bSelfCreated)
{
    // Prepare Diagram data collecting for this Shape
    if( nullptr == mpDiagramHelper && FRAMETYPE_DIAGRAM == meFrameType )
    {
        mpDiagramHelper = new AdvancedDiagramHelper(
            rDiagramPtr,
            rTheme,
            getSize(),
            bSelfCreated);
    }
}

void Shape::propagateDiagramHelper()
{
    // Propagate collected Diagram data to data holder
    if (FRAMETYPE_DIAGRAM == meFrameType && nullptr != mpDiagramHelper)
    {
        SdrObjGroup* pAnchorObj = dynamic_cast<SdrObjGroup*>(SdrObject::getSdrObjectFromXShape(mxShape));

        if(pAnchorObj)
        {
            mpDiagramHelper->doAnchor(*pAnchorObj, *this);
            mpDiagramHelper = nullptr;
        }
    }

    // If propagation failed, delete/cleanup here. Since the DiagramHelper
    // holds a Diagram and that this Shape it is necessary - the destructor
    // will not be called and will be too late
    if (nullptr != mpDiagramHelper)
    {
        delete mpDiagramHelper;
        mpDiagramHelper = nullptr;
    }
}

void Shape::migrateDiagramHelperToNewShape(const ShapePtr& pTarget)
{
    if(!mpDiagramHelper)
    {
        return;
    }

    if(!pTarget)
    {
        // no migrate target, but cleanup helper
        delete mpDiagramHelper;
        mpDiagramHelper = nullptr;
        return;
    }

    if(pTarget->mpDiagramHelper)
    {
        // this should no happen, but if there is already a helper, clean it up
        delete pTarget->mpDiagramHelper;
        pTarget->mpDiagramHelper = nullptr;
    }

    // exchange and reset to nullptr
    pTarget->mpDiagramHelper = mpDiagramHelper;
    mpDiagramHelper = nullptr;
}

table::TablePropertiesPtr const & Shape::getTableProperties()
{
    if ( !mpTablePropertiesPtr )
        mpTablePropertiesPtr = std::make_shared<table::TableProperties>();
    return mpTablePropertiesPtr;
}

void Shape::setDefaults(bool bHeight)
{
    maDefaultShapeProperties.setProperty(PROP_TextAutoGrowHeight, false);
    maDefaultShapeProperties.setProperty(PROP_TextWordWrap, true);
    maDefaultShapeProperties.setProperty(PROP_TextLeftDistance, static_cast< sal_Int32 >( 250 ));
    maDefaultShapeProperties.setProperty(PROP_TextUpperDistance, static_cast< sal_Int32 >( 125 ));
    maDefaultShapeProperties.setProperty(PROP_TextRightDistance, static_cast< sal_Int32 >( 250 ));
    maDefaultShapeProperties.setProperty(PROP_TextLowerDistance, static_cast< sal_Int32 >( 125 ));
    if (bHeight)
        maDefaultShapeProperties.setProperty(PROP_CharHeight, static_castfloat >( 18.0 ));
    maDefaultShapeProperties.setProperty(PROP_TextVerticalAdjust, TextVerticalAdjust_TOP);
    maDefaultShapeProperties.setProperty(PROP_ParaAdjust,
                                         static_cast<sal_Int16>(ParagraphAdjust_LEFT));
}

::oox::vml::OleObjectInfo& Shape::setOleObjectType()
{
    OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setOleObjectType - multiple frame types" );
    meFrameType = FRAMETYPE_OLEOBJECT;
    mxOleObjectInfo = std::make_shared<::oox::vml::OleObjectInfo>( true );
    return *mxOleObjectInfo;
}

ChartShapeInfo& Shape::setChartType( bool bEmbedShapes )
{
    OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setChartType - multiple frame types" );
    meFrameType = FRAMETYPE_CHART;
    if (mbWps)
        msServiceName = u"com.sun.star.drawing.temporaryForXMLImportOLE2Shape"_ustr;
    else
        msServiceName = u"com.sun.star.drawing.OLE2Shape"_ustr;
    mxChartShapeInfo = std::make_shared<ChartShapeInfo>( bEmbedShapes );
    return *mxChartShapeInfo;
}

void Shape::setDiagramType()
{
    OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setDiagramType - multiple frame types" );
    meFrameType = FRAMETYPE_DIAGRAM;
    msServiceName = u"com.sun.star.drawing.GroupShape"_ustr;
    mnSubType = 0;
}

void Shape::setTableType()
{
    OSL_ENSURE( meFrameType == FRAMETYPE_GENERIC, "Shape::setTableType - multiple frame types" );
    meFrameType = FRAMETYPE_TABLE;
    msServiceName = u"com.sun.star.drawing.TableShape"_ustr;
    mnSubType = 0;
}

const ShapeStyleRef* Shape::getShapeStyleRef( sal_Int32 nRefType ) const
{
    ShapeStyleRefMap::const_iterator aIt = maShapeStyleRefs.find( nRefType );
    return (aIt == maShapeStyleRefs.end()) ? nullptr : &aIt->second;
}

void Shape::addShape(
        ::oox::core::XmlFilterBase& rFilterBase,
        const Theme* pTheme,
        const Reference< XShapes >& rxShapes,
        const basegfx::B2DHomMatrix& aTransformation,
        const FillProperties& rShapeOrParentShapeFillProps,
        ShapeIdMap* pShapeMap,
        const oox::drawingml::ShapePtr& pParentGroupShape)
{
    SAL_INFO("oox.drawingml""Shape::addShape: id='" << msId << "'");

    try
    {
        OUString sServiceName( msServiceName );
        if( !sServiceName.isEmpty() )
        {
            basegfx::B2DHomMatrix aMatrix( aTransformation );
            Reference< XShape > xShape( createAndInsert( rFilterBase, sServiceName, pTheme, rxShapes, falsefalse, aMatrix, rShapeOrParentShapeFillProps, pParentGroupShape) );

            if( pShapeMap && !msId.isEmpty() )
            {
                (*pShapeMap)[ msId ] = shared_from_this();
            }

            // if this is a group shape, we have to add also each child shape
            Reference< XShapes > xShapes( xShape, UNO_QUERY );
            if ( xShapes.is() )
                addChildren( rFilterBase, *this, pTheme, xShapes, pShapeMap, aMatrix );

            if (mbWordprocessingCanvas && !mbWPGChild)
            {
                // This is a drawing canvas. In case the canvas has no fill and no stroke, Word does
                // not render shadow or glow, even if it is set for the canvas. Thus we disable shadow
                // and glow in this case for the ersatz background shape of the drawing canvas.
                try
                {
                    oox::drawingml::ShapePtr pBgShape = getChildren().front();
                    const Reference<css::drawing::XShape>& xBgShape = pBgShape->getXShape();
                    Reference<XPropertySet> xBgProps(xBgShape, uno::UNO_QUERY);
                    drawing::FillStyle eFillStyle = drawing::FillStyle_NONE;
                    xBgProps->getPropertyValue(u"FillStyle"_ustr) >>= eFillStyle;
                    drawing::LineStyle eLineStyle = drawing::LineStyle_NONE;
                    xBgProps->getPropertyValue(u"LineStyle"_ustr) >>= eLineStyle;
                    if (eFillStyle == drawing::FillStyle_NONE
                        && eLineStyle == drawing::LineStyle_NONE)
                    {
                        xBgProps->setPropertyValue(UNO_NAME_SHADOW, uno::Any(false));
                        xBgProps->setPropertyValue(u"GlowEffectRadius"_ustr, uno::Any(sal_Int32(0)));
                    }
                }
                catch (const Exception&)
                {
                    TOOLS_WARN_EXCEPTION("oox.drawingml""Shape::addShape mbWordprocessingCanvas");
                }
            }

            if (isWPGChild() && xShape)
            {
                // This is a wps shape and it is the child of the WPG, now copy the
                // the text body properties to the xshape.
                Reference<XPropertySet> xChildWPSProperties(xShape, uno::UNO_QUERY);

                if (getTextBody() && xChildWPSProperties)
                {
                    xChildWPSProperties->setPropertyValue(
                        UNO_NAME_TEXT_VERTADJUST,
                        uno::Any(getTextBody()->getTextProperties().meVA));

                    xChildWPSProperties->setPropertyValue(
                        UNO_NAME_TEXT_LEFTDIST,
                        uno::Any(getTextBody()->getTextProperties().moInsets[0].has_value()
                                     ? *getTextBody()->getTextProperties().moInsets[0]
                                     : 0));
                    xChildWPSProperties->setPropertyValue(
                        UNO_NAME_TEXT_UPPERDIST,
                        uno::Any(getTextBody()->getTextProperties().moInsets[1].has_value()
                                     ? *getTextBody()->getTextProperties().moInsets[1]
                                     : 0));
                    xChildWPSProperties->setPropertyValue(
                        UNO_NAME_TEXT_RIGHTDIST,
                        uno::Any(getTextBody()->getTextProperties().moInsets[2].has_value()
                                     ? *getTextBody()->getTextProperties().moInsets[2]
                                     : 0));
                    xChildWPSProperties->setPropertyValue(
                        UNO_NAME_TEXT_LOWERDIST,
                        uno::Any(getTextBody()->getTextProperties().moInsets[3].has_value()
                                     ? *getTextBody()->getTextProperties().moInsets[3]
                                     : 0));
                }

                // tdf#145147 Set the Hyperlink property to the child wps shape.
                if (getShapeProperties().hasProperty(PROP_URL)) try
                {
                    uno::Any aAny = getShapeProperties().getProperty(PROP_URL);
                    OUString sUrl = aAny.get<OUString>();
                    if (!sUrl.isEmpty())
                        xChildWPSProperties->setPropertyValue(UNO_NAME_HYPERLINK, aAny);
                }
                catch (const Exception&)
                {
                }
            }

            if( meFrameType == FRAMETYPE_DIAGRAM )
            {
                keepDiagramCompatibilityInfo();

                // set DiagramHelper at SdrObjGroup
                propagateDiagramHelper();

                // Check if this is the PPTX import, so far converting SmartArt to a non-editable
                // metafile is only implemented for DOCX.
                bool bPowerPoint = dynamic_cast<oox::ppt::PowerPointImport*>(&rFilterBase) != nullptr;

                if (!officecfg::Office::Common::Filter::Microsoft::Import::SmartArtToShapes::get() && !bPowerPoint)
                    convertSmartArtToMetafile( rFilterBase );
            }

            NamedShapePairs* pNamedShapePairs = rFilterBase.getDiagramFontHeights();
            if (xShape.is() && pNamedShapePairs)
            {
                auto itPairs = pNamedShapePairs->find(getInternalName());
                if (itPairs != pNamedShapePairs->end())
                {
                    auto it = itPairs->second.find(shared_from_this());
                    if (it != itPairs->second.end())
                    {
                        // Our drawingml::Shape is in the list of an internal name, remember the now
                        // inserted XShape.
                        it->second = std::move(xShape);
                    }
                }
            }
        }
    }
    catchconst Exception& )
    {
        TOOLS_WARN_EXCEPTION( "oox.drawingml""Shape::addShape" );
    }
}

void Shape::setLockedCanvas(bool bLockedCanvas)
{
    mbLockedCanvas = bLockedCanvas;
}

void Shape::setWordprocessingCanvas(bool bWordprocessingCanvas)
{
    mbWordprocessingCanvas = bWordprocessingCanvas;
}

void Shape::setWPGChild(bool bWPG)
{
    mbWPGChild = bWPG;
}

void Shape::setWps(bool bWps)
{
    mbWps = bWps;
}

void Shape::setTextBox(bool bTextBox)
{
    mbTextBox = bTextBox;
}

void Shape::applyShapeReference( const Shape& rReferencedShape, bool bUseText )
{
    SAL_INFO("oox.drawingml""Shape::applyShapeReference: apply '" << rReferencedShape.msId << "' to '" << msId << "'");

    if ( rReferencedShape.mpTextBody && bUseText )
        mpTextBody = std::make_shared<TextBody>( *rReferencedShape.mpTextBody );
    else
        mpTextBody.reset();
    maShapeProperties = rReferencedShape.maShapeProperties;
    mpShapeRefLinePropPtr = std::make_shared<LineProperties>( rReferencedShape.getActualLineProperties(nullptr) );
    mpShapeRefFillPropPtr = std::make_shared<FillProperties>( rReferencedShape.getActualFillProperties(nullptr, nullptr) );
    mpCustomShapePropertiesPtr = std::make_shared<CustomShapeProperties>( *rReferencedShape.mpCustomShapePropertiesPtr );
    mpTablePropertiesPtr = rReferencedShape.mpTablePropertiesPtr ? std::make_shared<table::TableProperties>( *rReferencedShape.mpTablePropertiesPtr ) : nullptr;
    mpShapeRefEffectPropPtr = std::make_shared<EffectProperties>( rReferencedShape.getActualEffectProperties(nullptr) );
    mpMasterTextListStyle = std::make_shared<TextListStyle>( *rReferencedShape.mpMasterTextListStyle );
    maSize = rReferencedShape.maSize;
    maPosition = rReferencedShape.maPosition;
    mnRotation = rReferencedShape.mnRotation;
    mbFlipH = rReferencedShape.mbFlipH;
    mbFlipV = rReferencedShape.mbFlipV;
    mbHidden = rReferencedShape.mbHidden;
    mbLocked = rReferencedShape.mbLocked;
}

namespace {

struct ActionLockGuard
{
    explicit ActionLockGuard(Reference<drawing::XShape> const& xShape)
        : m_xLockable(xShape, UNO_QUERY)
    {
        if (m_xLockable.is()) {
            m_xLockable->addActionLock();
        }
    }
    ~ActionLockGuard()
    {
        if (m_xLockable.is()) {
            m_xLockable->removeActionLock();
        }
    }
private:
    Reference<document::XActionLockable> m_xLockable;
};

}

// for group shapes, the following method is also adding each child
void Shape::addChildren(
        XmlFilterBase& rFilterBase,
        Shape& rMaster,
        const Theme* pTheme,
        const Reference< XShapes >& rxShapes,
        ShapeIdMap* pShapeMap,
        const basegfx::B2DHomMatrix& aTransformation )
{
    for (auto const& child : rMaster.maChildren)
    {
        child->setMasterTextListStyle( mpMasterTextListStyle );
        child->addShape( rFilterBase, pTheme, rxShapes, aTransformation, getFillProperties(), pShapeMap, rMaster.shared_from_this());
    }
}

static SdrTextHorzAdjust lcl_convertAdjust( ParagraphAdjust eAdjust )
{
    if (eAdjust == ParagraphAdjust_LEFT)
        return SDRTEXTHORZADJUST_LEFT;
    else if (eAdjust == ParagraphAdjust_RIGHT)
        return SDRTEXTHORZADJUST_RIGHT;
    else if (eAdjust == ParagraphAdjust_CENTER)
        return SDRTEXTHORZADJUST_CENTER;
    return SDRTEXTHORZADJUST_LEFT;
}

static TextHorizontalAdjust lcl_convertTextAdjust(ParagraphAdjust eAdjust)
{
    if (eAdjust == ParagraphAdjust_LEFT)
        return drawing::TextHorizontalAdjust_LEFT;
    else if (eAdjust == ParagraphAdjust_RIGHT)
        return drawing::TextHorizontalAdjust_RIGHT;
    else
        return drawing::TextHorizontalAdjust_BLOCK;
}

// LO does not interpret properties in styles belonging to the text content of a FontWork shape,
// but only those in the shape style. This method copies properties from the text content styles to
// the shape style.
static void lcl_copyCharPropsToShape(const uno::Reference<drawing::XShape>& xShape,
                                     const TextBodyPtr& pTextBody,
                                     const ::oox::core::XmlFilterBase& rFilter)
{
    if (!xShape.is() || !pTextBody)
        return;

    Reference<XPropertySet> xSet(xShape, UNO_QUERY);
    if (!xSet.is())
        return;

    // Content stretches or scales to given width and height, thus disable autogrow.
    xSet->setPropertyValue(UNO_NAME_TEXT_AUTOGROWHEIGHT, uno::Any(false));
    xSet->setPropertyValue(UNO_NAME_TEXT_AUTOGROWWIDTH, uno::Any(false));

    // LibreOffice is not able (as of Nov 2022) to use different styles for the paragraphs or
    // characters in FontWork, since that was not allowed in old binary WordArt. We use the
    // properties of the first non empty paragraph for now.
    const TextParagraphVector& rParagraphs = pTextBody->getParagraphs();
    auto aParaIt = std::find_if_not(rParagraphs.cbegin(), rParagraphs.cend(),
                                    [](const std::shared_ptr<TextParagraph> pParagraph) {
                                        return pParagraph->getRuns().empty();
                                    });
    if (aParaIt != rParagraphs.cend())
    {
        const std::shared_ptr<TextParagraph>& pParagraph = *aParaIt;
        const TextRunVector& rRuns = pParagraph->getRuns();
        auto aRunIt = std::find_if_not(rRuns.cbegin(), rRuns.cend(),
                                       [](const std::shared_ptr<TextRun> pRun)
                                       {
                                           return pRun->getText().isEmpty()
                                                  || pRun->getText() == " "
                                                  || pRun->getText().toChar() == 0xA0; // NBSP
                                       });
        if (aRunIt != rRuns.cend())
        {
            const std::shared_ptr<TextRun>& pRun = *aRunIt;
            TextCharacterProperties& rCharProps = pRun->getTextCharacterProperties();

            // set language
            if (rCharProps.moLang.has_value() && !rCharProps.moLang.value().isEmpty())
            {
                LanguageTag aTag(rCharProps.moLang.value());
                const css::lang::Locale& aLocale(aTag.getLocale(false));
                switch (MsLangId::getScriptType(aTag.getLanguageType()))
                {
                    case css::i18n::ScriptType::LATIN:
                        xSet->setPropertyValue(u"CharLocale"_ustr, uno::Any(aLocale));
                        break;
                    case css::i18n::ScriptType::ASIAN:
                        xSet->setPropertyValue(u"CharLocaleAsian"_ustr, uno::Any(aLocale));
                        break;
                    case css::i18n::ScriptType::COMPLEX:
                        xSet->setPropertyValue(u"CharLocaleComplex"_ustr, uno::Any(aLocale));
                        break;
                    default:;
                }
            }

            // Font Weight, Posture, Height
            if (rCharProps.moBold.has_value() && rCharProps.moBold.value())
            {
                xSet->setPropertyValue(UNO_NAME_CHAR_WEIGHT, uno::Any(css::awt::FontWeight::BOLD));
            }
            if (rCharProps.moItalic.has_value() && rCharProps.moItalic.value())
            {
                xSet->setPropertyValue(UNO_NAME_CHAR_POSTURE,
                                       uno::Any(css::awt::FontSlant::FontSlant_ITALIC));
            }
            if (rCharProps.moHeight.has_value())
            {
                sal_Int32 nHeight = rCharProps.moHeight.value() / 100;
                xSet->setPropertyValue(UNO_NAME_CHAR_HEIGHT, uno::Any(nHeight));
            }

            // Put theme fonts into shape properties
            OUString sFontName;
            sal_Int16 nFontPitch = 0;
            sal_Int16 nFontFamily = 0;
            bool bRet(false);
            if (const Theme* pTheme = rFilter.getCurrentTheme())
            {
                // minor Latin
                if (const TextFont* pFont = pTheme->resolveFont(u"+mn-lt"))
                {
                    bRet = pFont->getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter);
                    if (bRet)
                    {
                        xSet->setPropertyValue(u"CharFontName"_ustr, uno::Any(sFontName));
                        xSet->setPropertyValue(u"CharFontPitch"_ustr, uno::Any(nFontPitch));
                        xSet->setPropertyValue(u"CharFontFamily"_ustr, uno::Any(nFontFamily));
                    }
                }
                // minor Asian
                if (const TextFont* pFont = pTheme->resolveFont(u"+mn-ea"))
                {
                    bRet = pFont->getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter);
                    if (bRet)
                    {
                        xSet->setPropertyValue(u"CharFontNameAsian"_ustr, uno::Any(sFontName));
                        xSet->setPropertyValue(u"CharFontPitchAsian"_ustr, uno::Any(nFontPitch));
                        xSet->setPropertyValue(u"CharFontFamilyAsian"_ustr, uno::Any(nFontFamily));
                    }
                }
                // minor Complex
                if (const TextFont* pFont = pTheme->resolveFont(u"+mn-cs"))
                {
                    bRet = pFont->getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter);
                    if (bRet)
                    {
                        xSet->setPropertyValue(u"CharFontNameComplex"_ustr, uno::Any(sFontName));
                        xSet->setPropertyValue(u"CharFontPitchComplex"_ustr, uno::Any(nFontPitch));
                        xSet->setPropertyValue(u"CharFontFamilyComplex"_ustr, uno::Any(nFontFamily));
                    }
                }
            }

            // Replace theme fonts with formatting at run if any. ToDo: Inspect paragraph too?
            // Latin
            bRet = rCharProps.maLatinFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter);
            if (!bRet)
                // In case there is no direct font, try to look it up as a theme reference.
                bRet = rCharProps.maLatinThemeFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr,
                                                               rFilter);

            if (bRet)
            {
                xSet->setPropertyValue(u"CharFontName"_ustr, uno::Any(sFontName));
                xSet->setPropertyValue(u"CharFontPitch"_ustr, uno::Any(nFontPitch));
                xSet->setPropertyValue(u"CharFontFamily"_ustr, uno::Any(nFontFamily));
            }
            // Asian
            bRet = rCharProps.maAsianFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter);
            if (!bRet)
                // In case there is no direct font, try to look it up as a theme reference.
                bRet = rCharProps.maAsianThemeFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr,
                                                               rFilter);
            if (bRet)
            {
                xSet->setPropertyValue(u"CharFontNameAsian"_ustr, uno::Any(sFontName));
                xSet->setPropertyValue(u"CharFontPitchAsian"_ustr, uno::Any(nFontPitch));
                xSet->setPropertyValue(u"CharFontFamilyAsian"_ustr, uno::Any(nFontFamily));
            }
            // Complex
            bRet
                = rCharProps.maComplexFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr, rFilter);
            if (!bRet)
                // In case there is no direct font, try to look it up as a theme reference.
                bRet = rCharProps.maComplexThemeFont.getFontData(sFontName, nFontPitch, nFontFamily, nullptr,
                                                                 rFilter);
            if (bRet)
            {
                xSet->setPropertyValue(u"CharFontNameComplex"_ustr, uno::Any(sFontName));
                xSet->setPropertyValue(u"CharFontPitchComplex"_ustr, uno::Any(nFontPitch));
                xSet->setPropertyValue(u"CharFontFamilyComplex"_ustr, uno::Any(nFontFamily));
            }

            // LO uses shape properties, MS Office character properties. Copy them from char to shape.
            // Outline
            if (rCharProps.moTextOutlineProperties.has_value())
            {
                oox::drawingml::ShapePropertyMap aStrokeShapeProps(rFilter.getModelObjectHelper());
                rCharProps.moTextOutlineProperties.value().pushToPropMap(
                    aStrokeShapeProps, rFilter.getGraphicHelper());
                for (const auto& rProp : aStrokeShapeProps.makePropertyValueSequence())
                {
                    xSet->setPropertyValue(rProp.Name, rProp.Value);
                }
            }
            else
            {
                xSet->setPropertyValue(UNO_NAME_LINESTYLE, uno::Any(drawing::LineStyle_NONE));
            }

            // Fill
            // ToDo: Replace flip and rotate constants in parameters with actual values.
            // tdf#155327 If color is not explicitly set, MS Office uses scheme color 'tx1'.
            oox::drawingml::ShapePropertyMap aFillShapeProps(rFilter.getModelObjectHelper());
            if (!rCharProps.maFillProperties.moFillType.has_value())
                rCharProps.maFillProperties.moFillType = XML_solidFill;
            if (!rCharProps.maFillProperties.maFillColor.isUsed())
                rCharProps.maFillProperties.maFillColor.setSchemeClr(XML_tx1);
            rCharProps.maFillProperties.pushToPropMap(aFillShapeProps, rFilter.getGraphicHelper(),
                                                      /*nShapeRotation*/ 0,
                                                      /*nPhClr*/ API_RGB_TRANSPARENT,
                                                      /*aShapeSize*/ css::awt::Size(0, 0),
                                                      /*nPhClrTheme*/ -1,
                                                      /*bFlipH*/ false, /*bFlipV*/ false,
                                                      /*bIsCustomShape*/ true);
            for (const auto& rProp : aFillShapeProps.makePropertyValueSequence())
            {
                xSet->setPropertyValue(rProp.Name, rProp.Value);
            }

            // ToDo: Import WordArt glow and simple shadow effects. They are available in LO.
        }

        // LO does not evaluate paragraph alignment in text path mode. Use text area anchor instead.
        {
            ParagraphAdjust eAdjust = ParagraphAdjust_LEFT;
            if (pParagraph->getProperties().getParaAdjust())
                eAdjust = *pParagraph->getProperties().getParaAdjust();
            xSet->setPropertyValue(u"ParaAdjust"_ustr, uno::Any(eAdjust));
            SdrObject* pShape = SdrObject::getSdrObjectFromXShape(xShape);
            assert(pShape);
            SdrTextHorzAdjust eHorzAdjust = lcl_convertAdjust(eAdjust);
            pShape->SetMergedItem(SdrTextHorzAdjustItem(eHorzAdjust));
        }
    }

    // Vertical adjustment is only meaningful for OOXML WordArt shapes of 'Follow Path' kinds. We set
    // it so, that text position is approximately same as in MS Office.
    const OUString sMSPresetType = pTextBody->getTextProperties().msPrst;
    const OUString sFontworkType = PresetGeometryTypeNames::GetFontworkType(sMSPresetType);
    SdrObject* pShape = SdrObject::getSdrObjectFromXShape(xShape);
    assert(pShape);
    if (sFontworkType == "fontwork-arch-up-curve" || sFontworkType == "fontwork-circle-curve")
        pShape->SetMergedItem(SdrTextVertAdjustItem(SdrTextVertAdjust::SDRTEXTVERTADJUST_BOTTOM));
    else if (sFontworkType == "fontwork-arch-down-curve")
        pShape->SetMergedItem(SdrTextVertAdjustItem(SdrTextVertAdjust::SDRTEXTVERTADJUST_TOP));
    else
        pShape->SetMergedItem(SdrTextVertAdjustItem(SdrTextVertAdjust::SDRTEXTVERTADJUST_CENTER));
}

// Some helper methods for createAndInsert
namespace
{
// mirrors aTransformation at its center axis
// only valid if neither rotation or shear included
void lcl_mirrorAtCenter(basegfx::B2DHomMatrix& aTransformation, bool bFlipH, bool bFlipV)
{
    if (!bFlipH && !bFlipV)
        return;
    basegfx::B2DPoint aCenter(0.5, 0.5);
    aCenter *= aTransformation;
    aTransformation.translate(-aCenter);
    aTransformation.scale(bFlipH ? -1.0 : 1.0, bFlipV ? -1.0 : 1.0);
    aTransformation.translate(aCenter);
    return;
}

// only valid if neither rotation or shear included
void lcl_doSpecialMSOWidthHeightToggle(basegfx::B2DHomMatrix& aTransformation)
{
    // The values are directly set at the matrix without any matrix multiplication.
    // That way it is valid for lines too. Those have zero width or height.
    const double fSx(aTransformation.get(0, 0));
    const double fSy(aTransformation.get(1, 1));
    const double fTx(aTransformation.get(0, 2));
    const double fTy(aTransformation.get(1, 2));
    aTransformation.set(0, 0, fSy);
    aTransformation.set(1, 1, fSx);
    aTransformation.set(0, 2, fTx + 0.5 * (fSx - fSy));
    aTransformation.set(1, 2, fTy + 0.5 * (fSy - fSx));
    return;
}

void lcl_RotateAtCenter(basegfx::B2DHomMatrix& aTransformation, sal_Int32 nMSORotationAngle)
{
    if (nMSORotationAngle == 0)
        return;
    double fRad = basegfx::deg2rad<60000>(nMSORotationAngle);
    basegfx::B2DPoint aCenter(0.5, 0.5);
    aCenter *= aTransformation;
    aTransformation.translate(-aCenter);
    aTransformation.rotate(fRad);
    aTransformation.translate(aCenter);
    return;
}

Degree100 lcl_MSORotateAngleToAPIAngle(const sal_Int32 nMSORotationAngle)
{
    // Converts a shape rotation angle from MSO to angle for API property RotateAngle
    // from unit 1/60000 deg to unit 1/100 deg
    Degree100 nAngle(nMSORotationAngle / 600);
    // API RotateAngle has opposite direction than nMSORotationAngle, thus 'minus'.
    return NormAngle36000(-nAngle);
}
}

Reference< XShape > const & Shape::createAndInsert(
        ::oox::core::XmlFilterBase& rFilterBase,
        const OUString& rServiceName,
        const Theme* pTheme,
        const css::uno::Reference< css::drawing::XShapes >& rxShapes,
        bool bClearText,
        bool bDoNotInsertEmptyTextBody,
        basegfx::B2DHomMatrix& aParentTransformation,
        const FillProperties& rShapeOrParentShapeFillProps,
        const oox::drawingml::ShapePtr& pParentGroupShape)
{
    bool bIsEmbMedia = false;
    SAL_INFO("oox.drawingml""Shape::createAndInsert: id='" << msId << "' service='" << rServiceName << "'");

    formulaimport::XmlStreamBuilder * pMathXml(nullptr);
    if (mpTextBody)
    {
        for (auto const& it : mpTextBody->getParagraphs())
        {
            if (it->HasMathXml())
            {
                if (!mpTextBody->isEmpty() || pMathXml != nullptr)
                {
                    SAL_WARN("oox.drawingml""losing a Math object...");
                }
                else
                {
                    pMathXml = &it->GetMathXml();
                }
            }
        }
    }

    // tdf#90403 PowerPoint ignores a:ext cx and cy values of p:xfrm, and uses real table width and height
    if ( mpTablePropertiesPtr && rServiceName == "com.sun.star.drawing.TableShape" )
    {
        maSize.Width = 0;
        for (auto const& elem : mpTablePropertiesPtr->getTableGrid())
        {
            maSize.Width = o3tl::saturating_add(maSize.Width, static_cast<sal_Int32>(elem));
        }
        maSize.Height = 0;
        for (auto const& elem : mpTablePropertiesPtr->getTableRows())
        {
            // WARN: If some rows can't fit the content, this is not the final height
            maSize.Height = o3tl::saturating_add(maSize.Height, elem.getHeight());
        }
    }

    awt::Rectangle aShapeRectHmm(
        o3tl::convert(maPosition.X, o3tl::Length::emu, o3tl::Length::mm100),
        o3tl::convert(maPosition.Y, o3tl::Length::emu, o3tl::Length::mm100),
        o3tl::convert(maSize.Width, o3tl::Length::emu, o3tl::Length::mm100),
        o3tl::convert(maSize.Height, o3tl::Length::emu, o3tl::Length::mm100));

    OUString aServiceName;
    if (pMathXml)
    {
        // convert this shape to OLE
        aServiceName = u"com.sun.star.drawing.OLE2Shape"_ustr;
        msServiceName = aServiceName;
        meFrameType = FRAMETYPE_GENERIC; // not OLEOBJECT, no stream in package
        mnSubType = 0;
    }
    else if (rServiceName == "com.sun.star.drawing.GraphicObjectShape" &&
        mpGraphicPropertiesPtr && !mpGraphicPropertiesPtr->m_sMediaPackageURL.isEmpty())
    {
        aServiceName = finalizeServiceName( rFilterBase, u"com.sun.star.presentation.MediaShape"_ustr, aShapeRectHmm );
        bIsEmbMedia = true;
    }
    else
    {
        aServiceName = finalizeServiceName( rFilterBase, rServiceName, aShapeRectHmm );
    }
    // Use custom shape instead of GraphicObjectShape if the image is cropped to
    // shape. Except rectangle, which does not require further cropping
    bool bIsCroppedGraphic = (aServiceName == "com.sun.star.drawing.GraphicObjectShape" &&
                              !mpCustomShapePropertiesPtr->representsDefaultShape());

    bool bIsCustomShape = (aServiceName == "com.sun.star.drawing.CustomShape" || bIsCroppedGraphic);
    bool bIsConnectorShape = (aServiceName == "com.sun.star.drawing.ConnectorShape");

    // Look for 3D. Its z-rotation and extrusion color become shape properties. We consider a
    // z-rotation of an image even we currently do not extrude an image to 3D-scene.
    bool bBlockExtrusion = !bIsCustomShape && mp3DPropertiesPtr->mnPreset.has_value();
    double fShapeRotateInclCamera = 0.0; // unit rad; same orientation as shape property RotateAngle
    Color aExtrusionColor;
    Scene3DHelper aScene3DHelper;
    bool bHas3DEffect = aScene3DHelper.setExtrusionProperties(
        mp3DPropertiesPtr, mnRotation, getCustomShapeProperties()->getExtrusionPropertyMap(),
        fShapeRotateInclCamera, aExtrusionColor, bBlockExtrusion);
    // Currently the other places use unit 1/60000deg and MSO shape rotate orientation.
    sal_Int32 nShapeRotateInclCamera = -basegfx::rad2deg<60000>(fShapeRotateInclCamera);
    bool bIs3DGraphic = aServiceName == "com.sun.star.drawing.GraphicObjectShape" && bHas3DEffect;
    bIsCustomShape |= bIs3DGraphic;

    // The extrusion color does not belong to the extrusion properties but is secondary color in
    // the style of the shape, FillColor2 in API. The case that no extrusion color was set is handled
    // further down when FillProperties and LineProperties are handled.
    if (aExtrusionColor.isUsed())
    {
        // FillColor2 is not yet transformed to ComplexColor.
        ::Color aColor = aExtrusionColor.getColor(rFilterBase.getGraphicHelper());
        maShapeProperties.setProperty(PROP_FillColor2, aColor);
    }

    if (bHas3DEffect)
    {
        aScene3DHelper.setLightingProperties(mp3DPropertiesPtr, fShapeRotateInclCamera,
                                             getCustomShapeProperties()->getExtrusionPropertyMap());
        oox::Scene3DHelper::setMaterialProperties(
            mp3DPropertiesPtr, getCustomShapeProperties()->getExtrusionPropertyMap());
    }

    if (bIsCroppedGraphic || bIs3DGraphic)
    {
        aServiceName = "com.sun.star.drawing.CustomShape";
        mpGraphicPropertiesPtr->mbIsCustomShape = true;
        mpGraphicPropertiesPtr->mbIsExtruded = bIs3DGraphic;
    }
    bool bUseRotationTransform = ( !mbWps ||
            aServiceName == "com.sun.star.drawing.LineShape" ||
            aServiceName == "com.sun.star.drawing.GroupShape" ||
            mbFlipH ||
            mbFlipV );

    basegfx::B2DHomMatrix aTransformation; // will be cumulative transformation of this object

    // Special for SmartArt import. Rotate diagram's shape around object's center before sizing.
    if (bUseRotationTransform && mnDiagramRotation != 0)
    {
        aTransformation.translate(-0.5, -0.5);
        aTransformation.rotate(basegfx::deg2rad<60000>(mnDiagramRotation));
        aTransformation.translate(0.5, 0.5);
    }

    bool bLineShape = aServiceName == "com.sun.star.drawing.LineShape";
    bool bTopWriterLine = !pParentGroupShape && mbWps && bLineShape;
    // Build object matrix from shape size and position; corresponds to MSO ext and off
    // Only LineShape and ConnectorShape may have zero width or height.
    if (bLineShape || aServiceName == "com.sun.star.drawing.ConnectorShape")
    {
        // For toplevel Writer lines, size is included in the point coordinates.
        if (!bTopWriterLine)
        {
            aTransformation.scale(maSize.Width, maSize.Height);
        }
    }
    else
    {
        aTransformation.scale(maSize.Width ? maSize.Width : 1.0,
                              maSize.Height ? maSize.Height : 1.0);
    }

    // Evaluate object flip. Other shapes than custom shapes have no attribute for flip but use
    // negative scale. Flip in MSO is at object center.
    if (!bIsCustomShape && (mbFlipH || mbFlipV))
        lcl_mirrorAtCenter(aTransformation, mbFlipH, mbFlipV);

    // Evaluate parent flip.
    // A CustomShape has mirror not as negative scale, but as attributes.
    basegfx::B2DVector aParentScale(1.0, 1.0);
    basegfx::B2DVector aParentTranslate(0.0, 0.0);
    double fParentRotate(0.0);
    double fParentShearX(0.0);
    if (pParentGroupShape)
    {
        aParentTransformation.decompose(aParentScale, aParentTranslate, fParentRotate, fParentShearX);
        if (bIsCustomShape)
        {
            lcl_mirrorAtCenter(aTransformation, aParentScale.getX() < 0, aParentScale.getY() < 0);
            if(aParentScale.getX() < 0)
                mbFlipH = !mbFlipH;
            if(aParentScale.getY() < 0)
                mbFlipV = !mbFlipV;
        }
    }

    if (maPosition.X != 0 || maPosition.Y != 0)
    {
        // if global position is used, add it to transformation
        if (mbWps && pParentGroupShape == nullptr)
            aTransformation.translate(
                o3tl::convert(maPosition.X, o3tl::Length::mm100, o3tl::Length::emu),
                o3tl::convert(maPosition.Y, o3tl::Length::mm100, o3tl::Length::emu));
        else
            aTransformation.translate(maPosition.X, maPosition.Y);
    }

    // Apply further parent transformations. First scale object then rotate. Other way round would
    // introduce shearing.

    // The attributes chExt and chOff of the group in oox file contain the values on which the size
    // and position of the child is based on. If they differ from the actual size of the group as
    // given in its ext and off attributes, the child has to be transformed according the new values.
    if (pParentGroupShape)
    {
        // ToDo: A diagram in a group might need special handling because it cannot flip and only
        // resize uniformly. But currently it is imported with zero size, see tdf#139575. That needs
        // to be fixed beforehand.

        // Scaling is done from left/top edges of the group. So these need to become coordinate axes.
        aTransformation.translate(-pParentGroupShape->maChPosition.X,
                                  -pParentGroupShape->maChPosition.Y);

        // oox allows zero or missing attribute chExt. In that case the scaling factor is 1.
        // Transform2DContext::onCreateContext has set maChSize to maSize for groups in oox file in
        // such cases. For own made groups (e.g. diagrams) that is missing.
        // The factors cumulate on the way through the parent groups, so we do not use maSize of the
        // direct parent group but the cumulated value from aParentScale.
        double fFactorX = 1.0;
        double fFactorY = 1.0;
        if (pParentGroupShape->maChSize.Width != 0)
            fFactorX = aParentScale.getX() / pParentGroupShape->maChSize.Width;
        if (pParentGroupShape->maChSize.Height != 0)
            fFactorY = aParentScale.getY() / pParentGroupShape->maChSize.Height;
        if (fFactorX != 1 || fFactorY != 1)
        {
            // It depends on the object rotation angle whether scaling is applied to switched
            // width and height. MSO acts strange in that case (as of May 2021).
            const sal_Int32 nDeg(mnRotation / 60000);
            const bool bNeedsMSOWidthHeightToggle
                = (nDeg >= 45 && nDeg < 135) || (nDeg >= 225 && nDeg < 315);
            if (bNeedsMSOWidthHeightToggle)
                lcl_doSpecialMSOWidthHeightToggle(aTransformation);

            aTransformation.scale(fFactorX, fFactorY);

            if (bNeedsMSOWidthHeightToggle)
            {
                lcl_doSpecialMSOWidthHeightToggle(aTransformation);
                // In case of flip the special case needs an additional 180deg rotation.
                if ((aParentScale.getX() < 0) != (aParentScale.getY() < 0))
                    lcl_RotateAtCenter(aTransformation, 10800000);
            }
        }
    }

    // Apply object rotation at current object center
    // The flip contained in aParentScale will affect orientation of object rotation angle.
    sal_Int16 nOrientation = ((aParentScale.getX() < 0) != (aParentScale.getY() < 0)) ? -1 : 1;
    // ToDo: Not sure about the restrictions given by bUseRotationTransform.
    if (bUseRotationTransform && nShapeRotateInclCamera != 0)
    {
        lcl_RotateAtCenter(aTransformation, nOrientation * nShapeRotateInclCamera);
    }

    if (fParentRotate != 0.0)
        aTransformation.rotate(fParentRotate);
    if (!aParentTranslate.equalZero())
        aTransformation.translate(aParentTranslate);

    aParentTransformation = aTransformation;

    constexpr double fEmuToMm100 = o3tl::convert(1.0, o3tl::Length::emu, o3tl::Length::mm100);
    if (!bTopWriterLine)
    {
        aTransformation.scale(fEmuToMm100, fEmuToMm100);
    }

    // OOXML flips shapes before rotating them, so the rotation needs to be inverted
    if( bIsCustomShape && mbFlipH != mbFlipV )
    {
        basegfx::B2DVector aScale, aTranslate;
        double fRotate, fShearX;
        aTransformation.decompose(aScale, aTranslate, fRotate, fShearX);

        if(fRotate != 0)
        {
            basegfx::B2DPoint aCenter(0.5, 0.5);
            aCenter *= aTransformation;
            aTransformation.translate( -aCenter.getX(), -aCenter.getY() );
            aTransformation.rotate( fRotate * -2.0 );
            aTransformation.translate( aCenter.getX(), aCenter.getY() );
        }
    }

    // special for lineshape
    uno::Sequence< uno::Sequence< awt::Point > > aPolyPolySequence( 1 );
    if (bLineShape)
    {
        ::basegfx::B2DPolygon aPoly;
        aPoly.insert( 0, ::basegfx::B2DPoint( 0, 0 ) );
        if (bTopWriterLine)
        {
            // No transform of individual points, everything apart from size is part of the
            // transform matrix.
            sal_Int32 nMM100Width = o3tl::convert(maSize.Width, o3tl::Length::emu, o3tl::Length::mm100);
            sal_Int32 nMM100Height = o3tl::convert(maSize.Height, o3tl::Length::emu, o3tl::Length::mm100);
            aPoly.insert(1, ::basegfx::B2DPoint(nMM100Width, nMM100Height));
        }
        else
        {
            aPoly.insert( 1, ::basegfx::B2DPoint( maSize.Width ? 1 : 0, maSize.Height ? 1 : 0 ) );
            aPoly.transform( aTransformation );
        }

        // now creating the corresponding PolyPolygon
        sal_Int32 i, nNumPoints = aPoly.count();
        uno::Sequence< awt::Point > aPointSequence( nNumPoints );
        awt::Point* pPoints = aPointSequence.getArray();
        for( i = 0; i < nNumPoints; ++i )
        {
            basegfx::B2DPoint aPoint( aPoly.getB2DPoint( i ) );

            // Guard against zero width or height.
            if (i)
            {
                const basegfx::B2DPoint& rPreviousPoint = aPoly.getB2DPoint(i - 1);
                if (aPoint.getX() - rPreviousPoint.getX() == 0)
                    aPoint.setX(aPoint.getX() + 1);
                if (aPoint.getY() - rPreviousPoint.getY() == 0)
                    aPoint.setY(aPoint.getY() + 1);
            }

            pPoints[i] = awt::Point(static_cast<sal_Int32>(aPoint.getX()), static_cast<sal_Int32>(aPoint.getY()));
        }
        aPolyPolySequence.getArray()[ 0 ] = std::move(aPointSequence);

        if (!(bTopWriterLine && !maSize.Width))
        {
            maShapeProperties.setProperty(PROP_PolyPolygon, aPolyPolySequence);
        }
    }
    HomogenMatrix3 aMatrix;
    tools::Rectangle aOrigSize;
    if ( aServiceName == "com.sun.star.drawing.ConnectorShape" )
    {
        ::basegfx::B2DPolygon aPoly;
        aPoly.insert( 0, ::basegfx::B2DPoint( 0, 0 ) );
        aPoly.insert( 1, ::basegfx::B2DPoint( maSize.Width ? 1 : 0, maSize.Height ? 1 : 0 ) );
        aPoly.transform( aTransformation );

        basegfx::B2DPoint aStartPosition( aPoly.getB2DPoint( 0 ) );
        basegfx::B2DPoint aEndPosition( aPoly.getB2DPoint( 1 ) );
        awt::Point aAWTStartPosition( static_cast< sal_Int32 >( aStartPosition.getX() ), static_cast< sal_Int32 >( aStartPosition.getY() ) );
        awt::Point aAWTEndPosition( static_cast< sal_Int32 >( aEndPosition.getX() ), static_cast< sal_Int32 >( aEndPosition.getY() ) );

        maShapeProperties.setProperty(PROP_StartPosition, aAWTStartPosition);
        maShapeProperties.setProperty(PROP_EndPosition, aAWTEndPosition);
    }
    else if (!bLineShape || bTopWriterLine)
    {
        // now set transformation for this object

        aMatrix.Line1.Column1 = aTransformation.get(0,0);
        aMatrix.Line1.Column2 = aTransformation.get(0,1);
        aMatrix.Line1.Column3 = aTransformation.get(0,2);

        aMatrix.Line2.Column1 = aTransformation.get(1,0);
        aMatrix.Line2.Column2 = aTransformation.get(1,1);
        aMatrix.Line2.Column3 = aTransformation.get(1,2);

        aMatrix.Line3.Column1 = 0;
        aMatrix.Line3.Column2 = 0;
        aMatrix.Line3.Column3 = 1;

        if (!(bTopWriterLine && !maSize.Width))
        {
            maShapeProperties.setProperty(PROP_Transformation, aMatrix);
        }
    }

    Reference< lang::XMultiServiceFactory > xServiceFact( rFilterBase.getModel(), UNO_QUERY_THROW );
    if ( !mxShape.is() )
    {
        mxShape.set( xServiceFact->createInstance( aServiceName ), UNO_QUERY_THROW );
    }

    Reference< XPropertySet > xSet( mxShape, UNO_QUERY );
    if (xSet.is())
    {
        if (bTopWriterLine && !maSize.Width)
        {
            // Entirely vertical line, set the points and the transform separately to match the ODF
            // import.
            xSet->setPropertyValue(u"PolyPolygon"_ustr, Any(aPolyPolySequence));
            xSet->setPropertyValue(u"Transformation"_ustr, Any(aMatrix));
        }

        if( !msName.isEmpty() )
        {
            Reference< container::XNamed > xNamed( mxShape, UNO_QUERY );
            if( xNamed.is() )
                xNamed->setName( msName );
        }
        if( !msDescription.isEmpty() )
        {
            xSet->setPropertyValue( u"Description"_ustr, Any( msDescription ) );
        }
        if (m_isDecorative)
        {
            xSet->setPropertyValue(u"Decorative"_ustr, Any(m_isDecorative));
        }
        if (!msMacro.isEmpty())
        {
            putPropertyToGrabBag(u"mso-sp-macro"_ustr, Any(msMacro));
        }
        if (!msTextLink.isEmpty())
        {
            putPropertyToGrabBag(u"mso-sp-textlink"_ustr, Any(msTextLink));
        }
        if (!mbFLocksText) // set only if "false", otherwise it will use "true" by default
        {
            putPropertyToGrabBag(u"mso-sp-fLocksText"_ustr, Any(mbFLocksText));
        }
        if (mbFPublished)
        {
            putPropertyToGrabBag(u"mso-sp-fPublished"_ustr, Any(mbFPublished));
        }
        if (!msTitle.isEmpty())
        {
            xSet->setPropertyValue(u"Title"_ustr, Any(msTitle));
        }

        // get tooltip attribute of <hlinkClick>
        OUString sTooltip;
        getShapeProperties().getProperty(PROP_Representation) >>= sTooltip;
        if (!sTooltip.isEmpty())
            putPropertyToGrabBag(u"mso-hlinkClick-tooltip"_ustr, Any(sTooltip));

        // Placeholder uses the height set on the slide instead of the height from the master slide,
        // if it has the "TextAutoGrowHeight" property
        if (getTextBody() && mxShape->getShapeType().startsWith("com.sun.star.presentation."))
        {
            bool bAutoGrowHeight = getTextBody()
                                       ->getTextProperties()
                                       .maPropertyMap.getProperty(PROP_TextAutoGrowHeight)
                                       .get<bool>();
            if (bAutoGrowHeight)
            {
                ppt::PowerPointImport* pPPT = dynamic_cast<ppt::PowerPointImport*>(&rFilterBase);
                if (!pPPT->getActualSlidePersist()->isMasterPage())
                {
                    sal_Int32 nUpper = 0;
                    sal_Int32 nLower = 0;
                    sal_Int32 nHeight = maSize.Height / 360;
                    if (getTextBody()->getTextProperties().moInsets[1].has_value()
                        && getTextBody()->getTextProperties().moInsets[3].has_value())
                    {
                        nUpper = *getTextBody()->getTextProperties().moInsets[1];
                        nLower = *getTextBody()->getTextProperties().moInsets[3];
                    }
                    else
                    {
                        maDefaultShapeProperties.getProperty(PROP_TextUpperDistance) >>= nUpper;
                        maDefaultShapeProperties.getProperty(PROP_TextLowerDistance) >>= nLower;
                    }
                    nHeight -= (nUpper + nLower);
                    mxShape->setSize(awt::Size(0, nHeight));
                }
            }
            else // the placeholder uses the height set on the master slide
                mxShape->setSize(awt::Size(0, 0));
        }

        if (aServiceName != "com.sun.star.text.TextFrame")
            rxShapes->add( mxShape );

        if ( mbHidden || mbHiddenMasterShape )
        {
            SAL_INFO("oox.drawingml""Shape::createAndInsert: invisible shape with id='" << msId << "'");
            xSet->setPropertyValue( u"Visible"_ustr, Any( false ) );
            // In Excel hidden means not printed, let's use visibility for now until that's handled separately
            xSet->setPropertyValue( u"Printable"_ustr, Any( false ) );
        }

        if (mbLocked)
        {
            xSet->setPropertyValue(u"MoveProtect"_ustr, Any(true));
            xSet->setPropertyValue(u"SizeProtect"_ustr, Any(true));
        }

        ActionLockGuard const alg(mxShape);

        // sj: removing default text of placeholder objects such as SlideNumberShape or HeaderShape
        if ( bClearText )
        {
            uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY );
            if ( xText.is() )
            {
                xText->setString( u""_ustr );
            }
        }

        if (pMathXml)
        {
            // the "EmbeddedObject" property is read-only, so we have to create
            // the shape first, and it can be read only after the shape is
            // inserted into the document, so delay the actual import until here
            SvGlobalName name(SO3_SM_CLASSID);
            xSet->setPropertyValue(u"CLSID"_ustr, uno::Any(name.GetHexName()));
            uno::Reference<embed::XEmbeddedObject> const xObj(
                xSet->getPropertyValue(u"EmbeddedObject"_ustr), uno::UNO_QUERY);
            if (xObj.is())
            {
                uno::Reference<uno::XInterface> const xMathModel(xObj->getComponent());
                oox::FormulaImExportBase *const pMagic(
                        dynamic_cast<oox::FormulaImExportBase*>(xMathModel.get()));
                assert(pMagic);
                pMagic->readFormulaOoxml(*pMathXml);
            }
        }

        const GraphicHelper& rGraphicHelper = rFilterBase.getGraphicHelper();

        ::Color nLinePhClr(ColorTransparency, 0xffffffff);
        ::Color nFillPhClr(ColorTransparency, 0xffffffff);
        sal_Int16 nFillPhClrTheme = -1;
        sal_Int16 nLinePhClrTheme = -1;
        // TODO: use ph color when applying effect properties
        //sal_Int32 nEffectPhClr = -1;

        // dmapper needs the original rotation angle for calculating square wrap. This angle is not
        // available as property there, so store it in InteropGrabBag.
        putPropertyToGrabBag(u"mso-rotation-angle"_ustr, Any(mnRotation));

        if( pTheme )
        {
            ifconst ShapeStyleRef* pLineRef = getShapeStyleRef( XML_lnRef ) )
            {
                LineProperties aLineProperties;
                aLineProperties.maLineFill.moFillType = XML_noFill;
                ifconst LineProperties* pLineProps = pTheme->getLineStyle( pLineRef->mnThemedIdx ) )
                    aLineProperties.assignUsed( *pLineProps );
                nLinePhClr = pLineRef->maPhClr.getColor( rGraphicHelper );
                nLinePhClrTheme = pLineRef->maPhClr.getSchemeColorIndex();

                // Store style-related properties to InteropGrabBag to be able to export them back
                uno::Sequence<beans::PropertyValue> aProperties = comphelper::InitPropertySequence(
                {
                    {"SchemeClr", uno::Any(pLineRef->maPhClr.getSchemeColorName())},
                    {"Idx", uno::Any(pLineRef->mnThemedIdx)},
                    {"Color", uno::Any(nLinePhClr)},
                    {"LineStyle", uno::Any(aLineProperties.getLineStyle())},
                    {"LineCap", uno::Any(aLineProperties.getLineCap())},
                    {"LineJoint", uno::Any(aLineProperties.getLineJoint())},
                    {"LineWidth", uno::Any(aLineProperties.getLineWidth())},
                    {"Transformations", uno::Any(pLineRef->maPhClr.getTransformations())}
                });
                putPropertyToGrabBag( u"StyleLnRef"_ustr, Any( aProperties ) );
            }
            ifconst ShapeStyleRef* pFillRef = getShapeStyleRef( XML_fillRef ) )
            {
                if (!getFillProperties().moUseBgFill.value_or(false))
                {
                    nFillPhClr = pFillRef->maPhClr.getColor(rGraphicHelper);
                    nFillPhClrTheme = pFillRef->maPhClr.getSchemeColorIndex();
                }

                OUString sColorScheme = pFillRef->maPhClr.getSchemeColorName();
                if( !sColorScheme.isEmpty() )
                {
                    uno::Sequence<beans::PropertyValue> aProperties = comphelper::InitPropertySequence(
                    {
                        {"SchemeClr", uno::Any(sColorScheme)},
                        {"Idx", uno::Any(pFillRef->mnThemedIdx)},
                        {"Color", uno::Any(nFillPhClr)},
                        {"Transformations", uno::Any(pFillRef->maPhClr.getTransformations())}
                    });

                    putPropertyToGrabBag( u"StyleFillRef"_ustr, Any( aProperties ) );
                }
            }
            ifconst ShapeStyleRef* pEffectRef = getShapeStyleRef( XML_effectRef ) )
            {
                // TODO: use ph color when applying effect properties
                // nEffectPhClr = pEffectRef->maPhClr.getColor( rGraphicHelper );

                // Store style-related properties to InteropGrabBag to be able to export them back
                uno::Sequence<beans::PropertyValue> aProperties = comphelper::InitPropertySequence(
                {
                    {"SchemeClr", uno::Any(pEffectRef->maPhClr.getSchemeColorName())},
                    {"Idx", uno::Any(pEffectRef->mnThemedIdx)},
                    {"Transformations", uno::Any(pEffectRef->maPhClr.getTransformations())}
                });
                putPropertyToGrabBag( u"StyleEffectRef"_ustr, Any( aProperties ) );
            }
        }
        ShapePropertyMap aShapeProps( rFilterBase.getModelObjectHelper() );

        // add properties from textbody to shape properties
        if( mpTextBody )
        {
            // tdf#67347: In case of Stacked, PP calculates in the vertical direction with the
            // horizontal alignment.
            // In LO, we simulate it by setting TextVerticalAdjust based on the ParagraphAdjust
            // of the 1. paragraph
            // It is not perfect, because we have 1 TextVerticalAdjust / 1 shape, and it
            // does not support justified, while we can have many ParagraphAdjust / 1 shape
            // (if the shape have more paragraphs)
            if (mpTextBody->getTextProperties().maPropertyMap.hasProperty(PROP_WritingMode)
                && mpTextBody->getTextProperties().maPropertyMap.getProperty(PROP_WritingMode)
                       == uno::Any(text::WritingMode2::STACKED)
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=91 H=90 G=90

¤ Dauer der Verarbeitung: 0.19 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.