diff options
Diffstat (limited to 'xmloff/source/draw/ximpshap.cxx')
-rw-r--r-- | xmloff/source/draw/ximpshap.cxx | 4021 |
1 files changed, 4021 insertions, 0 deletions
diff --git a/xmloff/source/draw/ximpshap.cxx b/xmloff/source/draw/ximpshap.cxx new file mode 100644 index 0000000000..aaee9668fa --- /dev/null +++ b/xmloff/source/draw/ximpshap.cxx @@ -0,0 +1,4021 @@ +/* -*- 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 <cassert> + +#include <sal/log.hxx> +#include <com/sun/star/document/XEventsSupplier.hpp> +#include <com/sun/star/container/XNameReplace.hpp> +#include <com/sun/star/presentation/ClickAction.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <com/sun/star/drawing/LineStyle.hpp> +#include <utility> +#include <xmloff/unointerfacetouniqueidentifiermapper.hxx> +#include <com/sun/star/drawing/XGluePointsSupplier.hpp> +#include <com/sun/star/drawing/GluePoint2.hpp> +#include <com/sun/star/drawing/Alignment.hpp> +#include <com/sun/star/drawing/EscapeDirection.hpp> +#include <com/sun/star/media/ZoomLevel.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/style/XStyleFamiliesSupplier.hpp> +#include <com/sun/star/container/XNameAccess.hpp> +#include "ximpshap.hxx" +#include <xmloff/XMLBase64ImportContext.hxx> +#include <xmloff/XMLShapeStyleContext.hxx> +#include <xmloff/xmluconv.hxx> +#include <com/sun/star/container/XNamed.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/awt/XControlModel.hpp> +#include <com/sun/star/drawing/XControlShape.hpp> +#include <com/sun/star/drawing/PointSequenceSequence.hpp> +#include <com/sun/star/drawing/PointSequence.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/lang/XMultiServiceFactory.hpp> +#include <com/sun/star/util/XCloneable.hpp> +#include <com/sun/star/beans/XMultiPropertyStates.hpp> +#include <xexptran.hxx> +#include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/drawing/HomogenMatrix3.hpp> +#include <com/sun/star/graphic/XGraphic.hpp> +#include <com/sun/star/style/XStyle.hpp> + +#include <sax/tools/converter.hxx> +#include <comphelper/sequence.hxx> +#include <comphelper/diagnose_ex.hxx> +#include <comphelper/mediamimetype.hxx> + +#include <xmloff/families.hxx> +#include<xmloff/xmlnamespace.hxx> +#include <xmloff/xmltoken.hxx> +#include <EnhancedCustomShapeToken.hxx> +#include <XMLReplacementImageContext.hxx> +#include <XMLImageMapContext.hxx> +#include "sdpropls.hxx" +#include "eventimp.hxx" +#include "descriptionimp.hxx" +#include "SignatureLineContext.hxx" +#include "QRCodeContext.hxx" +#include "ximpcustomshape.hxx" +#include <XMLEmbeddedObjectImportContext.hxx> +#include <xmloff/xmlerror.hxx> +#include <xmloff/table/XMLTableImport.hxx> +#include <xmloff/ProgressBarHelper.hxx> +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <com/sun/star/drawing/XEnhancedCustomShapeDefaulter.hpp> +#include <com/sun/star/container/XChild.hpp> +#include <com/sun/star/text/XTextDocument.hpp> +#include <basegfx/matrix/b2dhommatrixtools.hxx> +#include <basegfx/point/b2dpoint.hxx> +#include <basegfx/polygon/b2dpolygon.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <basegfx/polygon/b2dpolypolygontools.hxx> +#include <basegfx/vector/b2dvector.hxx> +#include <tools/urlobj.hxx> +#include <o3tl/any.hxx> +#include <o3tl/safeint.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::style; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::document; +using namespace ::xmloff::token; +using namespace ::xmloff::EnhancedCustomShapeToken; + +SvXMLEnumMapEntry<drawing::Alignment> const aXML_GlueAlignment_EnumMap[] = +{ + { XML_TOP_LEFT, drawing::Alignment_TOP_LEFT }, + { XML_TOP, drawing::Alignment_TOP }, + { XML_TOP_RIGHT, drawing::Alignment_TOP_RIGHT }, + { XML_LEFT, drawing::Alignment_LEFT }, + { XML_CENTER, drawing::Alignment_CENTER }, + { XML_RIGHT, drawing::Alignment_RIGHT }, + { XML_BOTTOM_LEFT, drawing::Alignment_BOTTOM_LEFT }, + { XML_BOTTOM, drawing::Alignment_BOTTOM }, + { XML_BOTTOM_RIGHT, drawing::Alignment_BOTTOM_RIGHT }, + { XML_TOKEN_INVALID, drawing::Alignment(0) } +}; + +SvXMLEnumMapEntry<drawing::EscapeDirection> const aXML_GlueEscapeDirection_EnumMap[] = +{ + { XML_AUTO, drawing::EscapeDirection_SMART }, + { XML_LEFT, drawing::EscapeDirection_LEFT }, + { XML_RIGHT, drawing::EscapeDirection_RIGHT }, + { XML_UP, drawing::EscapeDirection_UP }, + { XML_DOWN, drawing::EscapeDirection_DOWN }, + { XML_HORIZONTAL, drawing::EscapeDirection_HORIZONTAL }, + { XML_VERTICAL, drawing::EscapeDirection_VERTICAL }, + { XML_TOKEN_INVALID, drawing::EscapeDirection(0) } +}; + +static bool ImpIsEmptyURL( std::u16string_view rURL ) +{ + if( rURL.empty() ) + return true; + + // #i13140# Also compare against 'toplevel' URLs. which also + // result in empty filename strings. + if( rURL == u"#./" ) + return true; + + return false; +} + + +SdXMLShapeContext::SdXMLShapeContext( + SvXMLImport& rImport, + css::uno::Reference< css::xml::sax::XFastAttributeList> xAttrList, + uno::Reference< drawing::XShapes > xShapes, + bool bTemporaryShape) + : SvXMLShapeContext( rImport, bTemporaryShape ) + , mxShapes(std::move( xShapes )) + , mxAttrList(std::move(xAttrList)) + , mbListContextPushed( false ) + , mnStyleFamily(XmlStyleFamily::SD_GRAPHICS_ID) + , mbIsPlaceholder(false) + , mbClearDefaultAttributes( true ) + , mbIsUserTransformed(false) + , mnZOrder(-1) + , maSize(1, 1) + , mnRelWidth(0) + , mnRelHeight(0) + , maPosition(0, 0) + , mbVisible(true) + , mbPrintable(true) + , mbHaveXmlId(false) + , mbTextBox(false) +{ +} + +SdXMLShapeContext::~SdXMLShapeContext() +{ +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + SvXMLImportContextRef xContext; + // #i68101# + if( nElement == XML_ELEMENT(SVG, XML_TITLE) || nElement == XML_ELEMENT(SVG, XML_DESC) + || nElement == XML_ELEMENT(SVG_COMPAT, XML_TITLE) || nElement == XML_ELEMENT(SVG_COMPAT, XML_DESC) ) + { + xContext = new SdXMLDescriptionContext( GetImport(), nElement, mxShape ); + } + else if( nElement == XML_ELEMENT(LO_EXT, XML_SIGNATURELINE) ) + { + xContext = new SignatureLineContext( GetImport(), nElement, xAttrList, mxShape ); + } + else if( nElement == XML_ELEMENT(LO_EXT, XML_QRCODE) ) + { + xContext = new QRCodeContext( GetImport(), nElement, xAttrList, mxShape ); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) ) + { + xContext = new SdXMLEventsContext( GetImport(), mxShape ); + } + else if( nElement == XML_ELEMENT(DRAW, XML_GLUE_POINT) ) + { + addGluePoint( xAttrList ); + } + else if( nElement == XML_ELEMENT(DRAW, XML_THUMBNAIL) ) + { + // search attributes for xlink:href + maThumbnailURL = xAttrList->getOptionalValue(XML_ELEMENT(XLINK, XML_HREF)); + } + else + { + // create text cursor on demand + if( !mxCursor.is() ) + { + uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY ); + if( xText.is() ) + { + rtl::Reference < XMLTextImportHelper > xTxtImport = + GetImport().GetTextImport(); + mxOldCursor = xTxtImport->GetCursor(); + mxCursor = xText->createTextCursor(); + if( mxCursor.is() ) + { + xTxtImport->SetCursor( mxCursor ); + } + + // remember old list item and block (#91964#) and reset them + // for the text frame + xTxtImport->PushListContext(); + mbListContextPushed = true; + } + } + + // if we have a text cursor, lets try to import some text + if( mxCursor.is() ) + { + xContext = GetImport().GetTextImport()->CreateTextChildContext( + GetImport(), nElement, xAttrList, + ( mbTextBox ? XMLTextType::TextBox : XMLTextType::Shape ) ); + } + } + + if (!xContext) + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return xContext; +} + +void SdXMLShapeContext::addGluePoint( const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + // get the gluepoints container for this shape if it's not already there + if( !mxGluePoints.is() ) + { + uno::Reference< drawing::XGluePointsSupplier > xSupplier( mxShape, uno::UNO_QUERY ); + if( !xSupplier.is() ) + return; + + mxGluePoints.set( xSupplier->getGluePoints(), UNO_QUERY ); + + if( !mxGluePoints.is() ) + return; + } + + drawing::GluePoint2 aGluePoint; + aGluePoint.IsUserDefined = true; + aGluePoint.Position.X = 0; + aGluePoint.Position.Y = 0; + aGluePoint.Escape = drawing::EscapeDirection_SMART; + aGluePoint.PositionAlignment = drawing::Alignment_CENTER; + aGluePoint.IsRelative = true; + + sal_Int32 nId = -1; + + // read attributes for the 3DScene + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + switch(aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aGluePoint.Position.X, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + aGluePoint.Position.Y, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_ID): + nId = aIter.toInt32(); + break; + case XML_ELEMENT(DRAW, XML_ALIGN): + { + drawing::Alignment eKind; + if( SvXMLUnitConverter::convertEnum( eKind, aIter.toView(), aXML_GlueAlignment_EnumMap ) ) + { + aGluePoint.PositionAlignment = eKind; + aGluePoint.IsRelative = false; + } + break; + } + case XML_ELEMENT(DRAW, XML_ESCAPE_DIRECTION): + { + SvXMLUnitConverter::convertEnum( aGluePoint.Escape, aIter.toView(), aXML_GlueEscapeDirection_EnumMap ); + break; + } + default: + XMLOFF_WARN_UNKNOWN("xmloff", aIter); + } + } + + if( nId != -1 ) + { + try + { + sal_Int32 nInternalId = mxGluePoints->insert( uno::Any( aGluePoint ) ); + GetImport().GetShapeImport()->addGluePointMapping( mxShape, nId, nInternalId ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "during setting of gluepoints"); + } + } +} + +void SdXMLShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); +} + +void SdXMLShapeContext::endFastElement(sal_Int32 ) +{ + if(mxCursor.is()) + { + // tdf#72776 force UpdateData in the EditSource so we will not override text in SdrOutliner + if( mxLockable.is() ) + { + mxLockable->removeActionLock(); + mxLockable->addActionLock(); + } + + // delete addition newline + mxCursor->gotoEnd( false ); + mxCursor->goLeft( 1, true ); + mxCursor->setString( "" ); + + // reset cursor + GetImport().GetTextImport()->ResetCursor(); + } + + if(mxOldCursor.is()) + GetImport().GetTextImport()->SetCursor( mxOldCursor ); + + // reinstall old list item (if necessary) #91964# + if (mbListContextPushed) { + GetImport().GetTextImport()->PopListContext(); + } + + if( !msHyperlink.isEmpty() ) try + { + uno::Reference< beans::XPropertySet > xProp( mxShape, uno::UNO_QUERY ); + + if ( xProp.is() && xProp->getPropertySetInfo()->hasPropertyByName( "Hyperlink" ) ) + xProp->setPropertyValue( "Hyperlink", uno::Any( msHyperlink ) ); + Reference< XEventsSupplier > xEventsSupplier( mxShape, UNO_QUERY ); + + if( xEventsSupplier.is() ) + { + Reference< XNameReplace > xEvents( xEventsSupplier->getEvents(), UNO_SET_THROW ); + + uno::Sequence< beans::PropertyValue > aProperties{ + { /* Name */ "EventType", + /* Handle */ -1, + /* Value */ uno::Any(OUString( "Presentation" )), + /* State */ beans::PropertyState_DIRECT_VALUE }, + + { /* Name */ "ClickAction", + /* Handle */ -1, + /* Value */ uno::Any(css::presentation::ClickAction_DOCUMENT), + /* State */ beans::PropertyState_DIRECT_VALUE }, + + { /* Name */ "Bookmark", + /* Handle */ -1, + /* Value */ uno::Any(msHyperlink), + /* State */ beans::PropertyState_DIRECT_VALUE } + }; + + xEvents->replaceByName( "OnClick", Any( aProperties ) ); + } + else + { + // in draw use the Bookmark property + Reference< beans::XPropertySet > xSet( mxShape, UNO_QUERY_THROW ); + xSet->setPropertyValue( "Bookmark", Any( msHyperlink ) ); + xSet->setPropertyValue("OnClick", Any( css::presentation::ClickAction_DOCUMENT ) ); + } + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff", "while setting hyperlink"); + } + + if( mxLockable.is() ) + mxLockable->removeActionLock(); +} + +void SdXMLShapeContext::AddShape(uno::Reference< drawing::XShape >& xShape) +{ + if(xShape.is()) + { + // set shape local + mxShape = xShape; + + if(!maShapeName.isEmpty()) + { + uno::Reference< container::XNamed > xNamed( mxShape, uno::UNO_QUERY ); + if( xNamed.is() ) + xNamed->setName( maShapeName ); + } + + rtl::Reference< XMLShapeImportHelper > xImp( GetImport().GetShapeImport() ); + xImp->addShape( xShape, mxAttrList, mxShapes ); + + if( mbClearDefaultAttributes ) + { + uno::Reference<beans::XMultiPropertyStates> xMultiPropertyStates(xShape, uno::UNO_QUERY ); + if (xMultiPropertyStates.is()) + xMultiPropertyStates->setAllPropertiesToDefault(); + } + + if( !mbVisible || !mbPrintable ) try + { + uno::Reference< beans::XPropertySet > xSet( xShape, uno::UNO_QUERY_THROW ); + if( !mbVisible ) + xSet->setPropertyValue("Visible", uno::Any( false ) ); + + if( !mbPrintable ) + xSet->setPropertyValue("Printable", uno::Any( false ) ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "while setting visible or printable" ); + } + + if(!mbTemporaryShape && (!GetImport().HasTextImport() + || !GetImport().GetTextImport()->IsInsideDeleteContext())) + { + xImp->shapeWithZIndexAdded( xShape, mnZOrder ); + } + + if (mnRelWidth || mnRelHeight) + { + uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY); + uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo(); + if (mnRelWidth && xPropertySetInfo->hasPropertyByName("RelativeWidth")) + xPropertySet->setPropertyValue("RelativeWidth", uno::Any(mnRelWidth)); + if (mnRelHeight && xPropertySetInfo->hasPropertyByName("RelativeHeight")) + xPropertySet->setPropertyValue("RelativeHeight", uno::Any(mnRelHeight)); + } + + if( !maShapeId.isEmpty() ) + { + uno::Reference< uno::XInterface > xRef( static_cast<uno::XInterface *>(xShape.get()) ); + GetImport().getInterfaceToIdentifierMapper().registerReference( maShapeId, xRef ); + } + + // #91065# count only if counting for shape import is enabled + if(GetImport().GetShapeImport()->IsHandleProgressBarEnabled()) + { + // #80365# increment progress bar at load once for each draw object + GetImport().GetProgressBarHelper()->Increment(); + } + } + + mxLockable.set( xShape, UNO_QUERY ); + + if( mxLockable.is() ) + mxLockable->addActionLock(); + +} + +void SdXMLShapeContext::AddShape(OUString const & serviceName) +{ + uno::Reference< lang::XMultiServiceFactory > xServiceFact(GetImport().GetModel(), uno::UNO_QUERY); + if(!xServiceFact.is()) + return; + + try + { + /* Since fix for issue i33294 the Writer model doesn't support + com.sun.star.drawing.OLE2Shape anymore. + To handle Draw OLE objects it's decided to import these + objects as com.sun.star.drawing.OLE2Shape and convert these + objects after the import into com.sun.star.drawing.GraphicObjectShape. + */ + uno::Reference< drawing::XShape > xShape; + if ( serviceName == "com.sun.star.drawing.OLE2Shape" && + uno::Reference< text::XTextDocument >(GetImport().GetModel(), uno::UNO_QUERY).is() ) + { + xShape.set(xServiceFact->createInstance("com.sun.star.drawing.temporaryForXMLImportOLE2Shape"), uno::UNO_QUERY); + } + else if (serviceName == "com.sun.star.drawing.GraphicObjectShape" + || serviceName == "com.sun.star.drawing.AppletShape" + || serviceName == "com.sun.star.drawing.FrameShape" + || serviceName == "com.sun.star.drawing.MediaShape" + || serviceName == "com.sun.star.drawing.OLE2Shape" + || serviceName == "com.sun.star.drawing.PluginShape" + || serviceName == "com.sun.star.presentation.MediaShape") + { + // On adding another entry to this list of service names to pass an argument via the WithArguments variant + // you may need to adjust the more obscure OReportDefinition::createInstanceWithArguments as well as the + // more obvious SvxUnoDrawMSFactory::createInstanceWithArguments + xShape.set( xServiceFact->createInstanceWithArguments(serviceName, { css::uno::Any(GetImport().GetDocumentBase()) }), + css::uno::UNO_QUERY); + } + else + { + xShape.set(xServiceFact->createInstance(serviceName), uno::UNO_QUERY); + } + if( xShape.is() ) + AddShape( xShape ); + } + catch(const uno::Exception& e) + { + TOOLS_WARN_EXCEPTION("xmloff", "AddShape " << serviceName); + uno::Sequence<OUString> aSeq { serviceName }; + GetImport().SetError( XMLERROR_FLAG_ERROR | XMLERROR_API, + aSeq, e.Message, nullptr ); + } +} + +void SdXMLShapeContext::SetTransformation() +{ + if(!mxShape.is()) + return; + + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(!xPropSet.is()) + return; + + maUsedTransformation.identity(); + + if(maSize.Width != 1 || maSize.Height != 1) + { + // take care there are no zeros used by error + if(0 == maSize.Width) + maSize.Width = 1; + if(0 == maSize.Height) + maSize.Height = 1; + + // set global size. This should always be used. + maUsedTransformation.scale(maSize.Width, maSize.Height); + } + + if(maPosition.X != 0 || maPosition.Y != 0) + { + // if global position is used, add it to transformation + maUsedTransformation.translate(maPosition.X, maPosition.Y); + } + + if(mnTransform.NeedsAction()) + { + // transformation is used, apply to object. + // NOTICE: The transformation is applied AFTER evtl. used + // global positioning and scaling is used, so any shear or + // rotate used herein is applied around the (0,0) position + // of the PAGE object !!! + ::basegfx::B2DHomMatrix aMat; + mnTransform.GetFullTransform(aMat); + + // now add to transformation + maUsedTransformation *= aMat; + } + + // now set transformation for this object + + // maUsedTransformtion contains the mathematical correct matrix, which if + // applied to a unit square would generate the transformed shape. But the property + // "Transformation" contains a matrix, which can be used in TRSetBaseGeometry + // and would be created by TRGetBaseGeometry. And those use a mathematically wrong + // sign for the shearing angle. So we need to adapt the matrix here. + basegfx::B2DTuple aScale; + basegfx::B2DTuple aTranslate; + double fRotate; + double fShearX; + maUsedTransformation.decompose(aScale, aTranslate, fRotate, fShearX); + basegfx::B2DHomMatrix aB2DHomMatrix; + aB2DHomMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix( + aScale, + basegfx::fTools::equalZero(fShearX) ? 0.0 : -fShearX, + basegfx::fTools::equalZero(fRotate) ? 0.0 : fRotate, + aTranslate); + drawing::HomogenMatrix3 aUnoMatrix; + + aUnoMatrix.Line1.Column1 = aB2DHomMatrix.get(0, 0); + aUnoMatrix.Line1.Column2 = aB2DHomMatrix.get(0, 1); + aUnoMatrix.Line1.Column3 = aB2DHomMatrix.get(0, 2); + + aUnoMatrix.Line2.Column1 = aB2DHomMatrix.get(1, 0); + aUnoMatrix.Line2.Column2 = aB2DHomMatrix.get(1, 1); + aUnoMatrix.Line2.Column3 = aB2DHomMatrix.get(1, 2); + + aUnoMatrix.Line3.Column1 = 0; + aUnoMatrix.Line3.Column2 = 0; + aUnoMatrix.Line3.Column3 = 1; + + xPropSet->setPropertyValue("Transformation", Any(aUnoMatrix)); +} + +void SdXMLShapeContext::SetStyle( bool bSupportsStyle /* = true */) +{ + try + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if( !xPropSet.is() ) + return; + + do + { + // set style on shape + if(maDrawStyleName.isEmpty()) + break; + + const SvXMLStyleContext* pStyle = nullptr; + bool bAutoStyle(false); + + if(GetImport().GetShapeImport()->GetAutoStylesContext()) + pStyle = GetImport().GetShapeImport()->GetAutoStylesContext()->FindStyleChildContext(mnStyleFamily, maDrawStyleName); + + if(pStyle) + bAutoStyle = true; + + if(!pStyle && GetImport().GetShapeImport()->GetStylesContext()) + pStyle = GetImport().GetShapeImport()->GetStylesContext()->FindStyleChildContext(mnStyleFamily, maDrawStyleName); + + OUString aStyleName = maDrawStyleName; + uno::Reference< style::XStyle > xStyle; + + XMLPropStyleContext* pDocStyle + = dynamic_cast<XMLShapeStyleContext*>(const_cast<SvXMLStyleContext*>(pStyle)); + if (pDocStyle) + { + if( pDocStyle->GetStyle().is() ) + { + xStyle = pDocStyle->GetStyle(); + } + else + { + aStyleName = pDocStyle->GetParentName(); + } + } + + if( !xStyle.is() && !aStyleName.isEmpty() ) + { + try + { + + uno::Reference< style::XStyleFamiliesSupplier > xFamiliesSupplier( GetImport().GetModel(), uno::UNO_QUERY ); + + if( xFamiliesSupplier.is() ) + { + uno::Reference< container::XNameAccess > xFamilies( xFamiliesSupplier->getStyleFamilies() ); + if( xFamilies.is() ) + { + + uno::Reference< container::XNameAccess > xFamily; + + if( XmlStyleFamily::SD_PRESENTATION_ID == mnStyleFamily ) + { + aStyleName = GetImport().GetStyleDisplayName( + XmlStyleFamily::SD_PRESENTATION_ID, + aStyleName ); + sal_Int32 nPos = aStyleName.lastIndexOf( '-' ); + if( -1 != nPos ) + { + OUString aFamily( aStyleName.copy( 0, nPos ) ); + + xFamilies->getByName( aFamily ) >>= xFamily; + aStyleName = aStyleName.copy( nPos + 1 ); + } + } + else + { + // get graphics family + if (xFamilies->hasByName("graphics")) + xFamilies->getByName("graphics") >>= xFamily; + else + xFamilies->getByName("GraphicStyles") >>= xFamily; + + aStyleName = GetImport().GetStyleDisplayName( + XmlStyleFamily::SD_GRAPHICS_ID, + aStyleName ); + } + + if( xFamily.is() ) + xFamily->getByName( aStyleName ) >>= xStyle; + } + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "finding style for shape" ); + } + } + + if( bSupportsStyle && xStyle.is() ) + { + try + { + // set style on object + xPropSet->setPropertyValue("Style", Any(xStyle)); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting style for shape" ); + } + } + + // Writer shapes: if this one has a TextBox, set it here. We need to do it before + // pDocStyle->FillPropertySet, because setting some properties depend on the format + // having RES_CNTNT attribute (e.g., UNO_NAME_TEXT_(LEFT|RIGHT|UPPER|LOWER)DIST; see + // SwTextBoxHelper::syncProperty, which indirectly calls SwTextBoxHelper::isTextBox) + uno::Reference<beans::XPropertySetInfo> xPropertySetInfo + = xPropSet->getPropertySetInfo(); + static constexpr OUString sTextBox = u"TextBox"_ustr; + if (xPropertySetInfo->hasPropertyByName(sTextBox)) + xPropSet->setPropertyValue(sTextBox, uno::Any(mbTextBox)); + + // if this is an auto style, set its properties + if(bAutoStyle && pDocStyle) + { + // set PropertySet on object + pDocStyle->FillPropertySet(xPropSet); + } + + } while(false); + + // try to set text auto style + do + { + // set style on shape + if( maTextStyleName.isEmpty() ) + break; + + if( nullptr == GetImport().GetShapeImport()->GetAutoStylesContext()) + break; + + const SvXMLStyleContext* pTempStyle = GetImport().GetShapeImport()->GetAutoStylesContext()->FindStyleChildContext(XmlStyleFamily::TEXT_PARAGRAPH, maTextStyleName); + XMLPropStyleContext* pStyle = const_cast<XMLPropStyleContext*>(dynamic_cast<const XMLPropStyleContext*>( pTempStyle ) ); // use temp var, PTR_CAST is a bad macro, FindStyleChildContext will be called twice + if( pStyle == nullptr ) + break; + + // set PropertySet on object + pStyle->FillPropertySet(xPropSet); + + } while(false); + } + catch(const uno::Exception&) + { + } +} + +void SdXMLShapeContext::SetLayer() +{ + if( maLayerName.isEmpty() ) + return; + + try + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is() ) + { + xPropSet->setPropertyValue("LayerName", Any(maLayerName)); + return; + } + } + catch(const uno::Exception&) + { + } +} + +void SdXMLShapeContext::SetThumbnail() +{ + if( maThumbnailURL.isEmpty() ) + return; + + try + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if( !xPropSet.is() ) + return; + + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName( "ThumbnailGraphic" ) ) + { + // load the thumbnail graphic and export it to a wmf stream so we can set + // it at the api + + uno::Reference<graphic::XGraphic> xGraphic = GetImport().loadGraphicByURL(maThumbnailURL); + xPropSet->setPropertyValue("ThumbnailGraphic", uno::Any(xGraphic)); + } + } + catch(const uno::Exception&) + { + } +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + sal_Int32 nTmp; + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_ZINDEX): + case XML_ELEMENT(DRAW_EXT, XML_ZINDEX): + mnZOrder = aIter.toInt32(); + break; + case XML_ELEMENT(DRAW, XML_ID): + case XML_ELEMENT(DRAW_EXT, XML_ID): + if (!mbHaveXmlId) { maShapeId = aIter.toString(); } + break; + case XML_ELEMENT(DRAW, XML_NAME): + case XML_ELEMENT(DRAW_EXT, XML_NAME): + maShapeName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_STYLE_NAME): + case XML_ELEMENT(DRAW_EXT, XML_STYLE_NAME): + maDrawStyleName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_TEXT_STYLE_NAME): + case XML_ELEMENT(DRAW_EXT, XML_TEXT_STYLE_NAME): + maTextStyleName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_LAYER): + case XML_ELEMENT(DRAW_EXT, XML_LAYER): + maLayerName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_TRANSFORM): + case XML_ELEMENT(DRAW_EXT, XML_TRANSFORM): + mnTransform.SetString(aIter.toString(), GetImport().GetMM100UnitConverter()); + break; + case XML_ELEMENT(DRAW, XML_DISPLAY): + case XML_ELEMENT(DRAW_EXT, XML_DISPLAY): + mbVisible = IsXMLToken( aIter, XML_ALWAYS ) || IsXMLToken( aIter, XML_SCREEN ); + mbPrintable = IsXMLToken( aIter, XML_ALWAYS ) || IsXMLToken( aIter, XML_PRINTER ); + break; + case XML_ELEMENT(PRESENTATION, XML_USER_TRANSFORMED): + mbIsUserTransformed = IsXMLToken( aIter, XML_TRUE ); + break; + case XML_ELEMENT(PRESENTATION, XML_PLACEHOLDER): + mbIsPlaceholder = IsXMLToken( aIter, XML_TRUE ); + if( mbIsPlaceholder ) + mbClearDefaultAttributes = false; + break; + case XML_ELEMENT(PRESENTATION, XML_CLASS): + maPresentationClass = aIter.toString(); + break; + case XML_ELEMENT(PRESENTATION, XML_STYLE_NAME): + maDrawStyleName = aIter.toString(); + mnStyleFamily = XmlStyleFamily::SD_PRESENTATION_ID; + break; + case XML_ELEMENT(SVG, XML_X): + case XML_ELEMENT(SVG_COMPAT, XML_X): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maPosition.X, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y): + case XML_ELEMENT(SVG_COMPAT, XML_Y): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maPosition.Y, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_WIDTH): + case XML_ELEMENT(SVG_COMPAT, XML_WIDTH): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maSize.Width, aIter.toView()); + if (maSize.Width > 0) + maSize.Width = o3tl::saturating_add<sal_Int32>(maSize.Width, 1); + else if (maSize.Width < 0) + maSize.Width = o3tl::saturating_add<sal_Int32>(maSize.Width, -1); + break; + case XML_ELEMENT(SVG, XML_HEIGHT): + case XML_ELEMENT(SVG_COMPAT, XML_HEIGHT): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maSize.Height, aIter.toView()); + if (maSize.Height > 0) + maSize.Height = o3tl::saturating_add<sal_Int32>(maSize.Height, 1); + else if (maSize.Height < 0) + maSize.Height = o3tl::saturating_add<sal_Int32>(maSize.Height, -1); + break; + case XML_ELEMENT(SVG, XML_TRANSFORM): + case XML_ELEMENT(SVG_COMPAT, XML_TRANSFORM): + // because of #85127# take svg:transform into account and handle like + // draw:transform for compatibility + mnTransform.SetString(aIter.toString(), GetImport().GetMM100UnitConverter()); + break; + case XML_ELEMENT(STYLE, XML_REL_WIDTH): + if (sax::Converter::convertPercent(nTmp, aIter.toView())) + mnRelWidth = static_cast<sal_Int16>(nTmp); + break; + case XML_ELEMENT(STYLE, XML_REL_HEIGHT): + if (sax::Converter::convertPercent(nTmp, aIter.toView())) + mnRelHeight = static_cast<sal_Int16>(nTmp); + break; + case XML_ELEMENT(NONE, XML_ID): + case XML_ELEMENT(XML, XML_ID): + maShapeId = aIter.toString(); + mbHaveXmlId = true; + break; + default: + return false; + } + return true; +} + +bool SdXMLShapeContext::isPresentationShape() const +{ + if( !maPresentationClass.isEmpty() && const_cast<SdXMLShapeContext*>(this)->GetImport().GetShapeImport()->IsPresentationShapesSupported() ) + { + if(XmlStyleFamily::SD_PRESENTATION_ID == mnStyleFamily) + { + return true; + } + + if( IsXMLToken( maPresentationClass, XML_HEADER ) || IsXMLToken( maPresentationClass, XML_FOOTER ) || + IsXMLToken( maPresentationClass, XML_PAGE_NUMBER ) || IsXMLToken( maPresentationClass, XML_DATE_TIME ) ) + { + return true; + } + } + + return false; +} + +SdXMLRectShapeContext::SdXMLRectShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + mnRadius( 0 ) +{ +} + +SdXMLRectShapeContext::~SdXMLRectShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLRectShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_CORNER_RADIUS): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRadius, aIter.toView()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLRectShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create rectangle shape + AddShape("com.sun.star.drawing.RectangleShape"); + if(!mxShape.is()) + return; + + // Add, set Style and properties from base shape + SetStyle(); + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + + if(mnRadius) + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + try + { + xPropSet->setPropertyValue("CornerRadius", uno::Any( mnRadius ) ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting corner radius"); + } + } + } + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLLineShapeContext::SdXMLLineShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + mnX1( 0 ), + mnY1( 0 ), + mnX2( 1 ), + mnY2( 1 ) +{ +} + +SdXMLLineShapeContext::~SdXMLLineShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLLineShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_X1): + case XML_ELEMENT(SVG_COMPAT, XML_X1): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnX1, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y1): + case XML_ELEMENT(SVG_COMPAT, XML_Y1): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnY1, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_X2): + case XML_ELEMENT(SVG_COMPAT, XML_X2): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnX2, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y2): + case XML_ELEMENT(SVG_COMPAT, XML_Y2): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnY2, aIter.toView()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLLineShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // #85920# use SetTransformation() to handle import of simple lines. + // This is necessary to take into account all anchor positions and + // other things. All shape imports use the same import schemata now. + // create necessary shape (Line Shape) + AddShape("com.sun.star.drawing.PolyLineShape"); + + if(!mxShape.is()) + return; + + // Add, set Style and properties from base shape + SetStyle(); + SetLayer(); + + // get sizes and offsets + awt::Point aTopLeft(mnX1, mnY1); + awt::Point aBottomRight(mnX2, mnY2); + + if(mnX1 > mnX2) + { + aTopLeft.X = mnX2; + aBottomRight.X = mnX1; + } + + if(mnY1 > mnY2) + { + aTopLeft.Y = mnY2; + aBottomRight.Y = mnY1; + } + + // set local parameters on shape + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + drawing::PointSequenceSequence aPolyPoly(1); + drawing::PointSequence* pOuterSequence = aPolyPoly.getArray(); + pOuterSequence->realloc(2); + awt::Point* pInnerSequence = pOuterSequence->getArray(); + + *pInnerSequence = awt::Point(o3tl::saturating_sub(mnX1, aTopLeft.X), o3tl::saturating_sub(mnY1, aTopLeft.Y)); + pInnerSequence++; + *pInnerSequence = awt::Point(o3tl::saturating_sub(mnX2, aTopLeft.X), o3tl::saturating_sub(mnY2, aTopLeft.Y)); + + xPropSet->setPropertyValue("Geometry", Any(aPolyPoly)); + } + + // Size is included in point coordinates + maSize.Width = 1; + maSize.Height = 1; + maPosition.X = aTopLeft.X; + maPosition.Y = aTopLeft.Y; + + // set pos, size, shear and rotate and get copy of matrix + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLEllipseShapeContext::SdXMLEllipseShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + mnCX( 0 ), + mnCY( 0 ), + mnRX( 1 ), + mnRY( 1 ), + meKind( drawing::CircleKind_FULL ), + mnStartAngle( 0 ), + mnEndAngle( 0 ) +{ +} + +SdXMLEllipseShapeContext::~SdXMLEllipseShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLEllipseShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_RX): + case XML_ELEMENT(SVG_COMPAT, XML_RX): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRX, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_RY): + case XML_ELEMENT(SVG_COMPAT, XML_RY): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRY, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_CX): + case XML_ELEMENT(SVG_COMPAT, XML_CX): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnCX, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_CY): + case XML_ELEMENT(SVG_COMPAT, XML_CY): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnCY, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_R): + case XML_ELEMENT(SVG_COMPAT, XML_R): + // single radius, it's a circle and both radii are the same + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRX, aIter.toView()); + mnRY = mnRX; + break; + case XML_ELEMENT(DRAW, XML_KIND): + SvXMLUnitConverter::convertEnum( meKind, aIter.toView(), aXML_CircleKind_EnumMap ); + break; + case XML_ELEMENT(DRAW, XML_START_ANGLE): + { + double dStartAngle; + if (::sax::Converter::convertDouble( dStartAngle, aIter.toView() )) + mnStartAngle = static_cast<sal_Int32>(dStartAngle * 100.0); + break; + } + case XML_ELEMENT(DRAW, XML_END_ANGLE): + { + double dEndAngle; + if (::sax::Converter::convertDouble( dEndAngle, aIter.toView() )) + mnEndAngle = static_cast<sal_Int32>(dEndAngle * 100.0); + break; + } + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLEllipseShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create rectangle shape + AddShape("com.sun.star.drawing.EllipseShape"); + if(!mxShape.is()) + return; + + // Add, set Style and properties from base shape + SetStyle(); + SetLayer(); + + if(mnCX != 0 || mnCY != 0 || mnRX != 1 || mnRY != 1) + { + // #i121972# center/radius is used, put to pos and size + maSize.Width = 2 * mnRX; + maSize.Height = 2 * mnRY; + maPosition.X = mnCX - mnRX; + maPosition.Y = mnCY - mnRY; + } + // set pos, size, shear and rotate + SetTransformation(); + + if( meKind != drawing::CircleKind_FULL ) + { + uno::Reference< beans::XPropertySet > xPropSet( mxShape, uno::UNO_QUERY ); + if( xPropSet.is() ) + { + // calculate the correct start and end angle + sal_Int32 mnOldStartAngle = mnStartAngle; + sal_Int32 mnOldEndAngle = mnEndAngle; + basegfx::B2DTuple aScale; + basegfx::B2DTuple aTranslate; + double fRotate; + double fShearX; + maUsedTransformation.decompose(aScale, aTranslate, fRotate, fShearX); + if (aScale.getX() < 0 || aScale.getY() < 0) + { + // The angle for a horizontal flip is the same as the angle for a + // vertical flip because a vertical flip is treated as a horizontal + // flip plus a rotation. + + // To perform the flip, the start and end angle are switched and we + // use the fact performing a horizontal flip on a shape will change + // the angle that a radius makes with the origin to 180 degrees + // minus that angle (we use 54000 hundredths of a degree to get the + // modulus operation to give a value between 0 and 36000). + + mnStartAngle = (54000 - mnOldEndAngle) % 36000; + mnEndAngle = (54000 - mnOldStartAngle) % 36000; + } + + xPropSet->setPropertyValue("CircleKind", Any( meKind) ); + xPropSet->setPropertyValue("CircleStartAngle", Any(mnStartAngle) ); + xPropSet->setPropertyValue("CircleEndAngle", Any(mnEndAngle) ); + } + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLPolygonShapeContext::SdXMLPolygonShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, bool bClosed, bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + mbClosed( bClosed ) +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLPolygonShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_VIEWBOX): + case XML_ELEMENT(SVG_COMPAT, XML_VIEWBOX): + maViewBox = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_POINTS): + maPoints = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute( aIter); + } + return true; +} + +SdXMLPolygonShapeContext::~SdXMLPolygonShapeContext() +{ +} + +void SdXMLPolygonShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // Add, set Style and properties from base shape + if(mbClosed) + AddShape("com.sun.star.drawing.PolyPolygonShape"); + else + AddShape("com.sun.star.drawing.PolyLineShape"); + + if( !mxShape.is() ) + return; + + SetStyle(); + SetLayer(); + + // set local parameters on shape + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + // set polygon + if(!maPoints.isEmpty() && !maViewBox.isEmpty()) + { + const SdXMLImExViewBox aViewBox(maViewBox, GetImport().GetMM100UnitConverter()); + basegfx::B2DVector aSize(aViewBox.GetWidth(), aViewBox.GetHeight()); + + // Is this correct? It overrides ViewBox stuff; OTOH it makes no + // sense to have the geometry content size different from object size + if(maSize.Width != 0 && maSize.Height != 0) + { + aSize = basegfx::B2DVector(maSize.Width, maSize.Height); + } + + basegfx::B2DPolygon aPolygon; + + if(basegfx::utils::importFromSvgPoints(aPolygon, maPoints)) + { + if(aPolygon.count()) + { + const basegfx::B2DRange aSourceRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aViewBox.GetWidth(), aViewBox.GetY() + aViewBox.GetHeight()); + const basegfx::B2DRange aTargetRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aSize.getX(), aViewBox.GetY() + aSize.getY()); + + if(!aSourceRange.equal(aTargetRange)) + { + aPolygon.transform( + basegfx::utils::createSourceRangeTargetRangeTransform( + aSourceRange, + aTargetRange)); + } + + css::drawing::PointSequenceSequence aPointSequenceSequence; + basegfx::utils::B2DPolyPolygonToUnoPointSequenceSequence(basegfx::B2DPolyPolygon(aPolygon), aPointSequenceSequence); + xPropSet->setPropertyValue("Geometry", Any(aPointSequenceSequence)); + // Size is now contained in the point coordinates, adapt maSize for + // to use the correct transformation matrix in SetTransformation() + maSize.Width = 1; + maSize.Height = 1; + } + } + } + } + + // set pos, size, shear and rotate and get copy of matrix + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLPathShapeContext::SdXMLPathShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ) +{ +} + +SdXMLPathShapeContext::~SdXMLPathShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLPathShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(SVG, XML_VIEWBOX): + case XML_ELEMENT(SVG_COMPAT, XML_VIEWBOX): + maViewBox = aIter.toString(); + break; + case XML_ELEMENT(SVG, XML_D): + case XML_ELEMENT(SVG_COMPAT, XML_D): + maD = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLPathShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create polygon shape + if(maD.isEmpty()) + return; + + const SdXMLImExViewBox aViewBox(maViewBox, GetImport().GetMM100UnitConverter()); + basegfx::B2DVector aSize(aViewBox.GetWidth(), aViewBox.GetHeight()); + + // Is this correct? It overrides ViewBox stuff; OTOH it makes no + // sense to have the geometry content size different from object size + if(maSize.Width != 0 && maSize.Height != 0) + { + aSize = basegfx::B2DVector(maSize.Width, maSize.Height); + } + + basegfx::B2DPolyPolygon aPolyPolygon; + + if(!basegfx::utils::importFromSvgD(aPolyPolygon, maD, GetImport().needFixPositionAfterZ(), nullptr)) + return; + + if(!aPolyPolygon.count()) + return; + + const basegfx::B2DRange aSourceRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aViewBox.GetWidth(), aViewBox.GetY() + aViewBox.GetHeight()); + const basegfx::B2DRange aTargetRange( + aViewBox.GetX(), aViewBox.GetY(), + aViewBox.GetX() + aSize.getX(), aViewBox.GetY() + aSize.getY()); + + if(!aSourceRange.equal(aTargetRange)) + { + aPolyPolygon.transform( + basegfx::utils::createSourceRangeTargetRangeTransform( + aSourceRange, + aTargetRange)); + } + + // create shape + OUString service; + + if(aPolyPolygon.areControlPointsUsed()) + { + if(aPolyPolygon.isClosed()) + { + service = "com.sun.star.drawing.ClosedBezierShape"; + } + else + { + service = "com.sun.star.drawing.OpenBezierShape"; + } + } + else + { + if(aPolyPolygon.isClosed()) + { + service = "com.sun.star.drawing.PolyPolygonShape"; + } + else + { + service = "com.sun.star.drawing.PolyLineShape"; + } + } + + // Add, set Style and properties from base shape + AddShape(service); + + // #89344# test for mxShape.is() and not for mxShapes.is() to support + // shape import helper classes WITHOUT XShapes (member mxShapes). This + // is used by the writer. + if( !mxShape.is() ) + return; + + SetStyle(); + SetLayer(); + + // set local parameters on shape + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + + if(xPropSet.is()) + { + uno::Any aAny; + + // set polygon data + if(aPolyPolygon.areControlPointsUsed()) + { + drawing::PolyPolygonBezierCoords aSourcePolyPolygon; + + basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( + aPolyPolygon, + aSourcePolyPolygon); + aAny <<= aSourcePolyPolygon; + } + else + { + drawing::PointSequenceSequence aSourcePolyPolygon; + + basegfx::utils::B2DPolyPolygonToUnoPointSequenceSequence( + aPolyPolygon, + aSourcePolyPolygon); + aAny <<= aSourcePolyPolygon; + } + + xPropSet->setPropertyValue("Geometry", aAny); + // Size is now contained in the point coordinates, adapt maSize for + // to use the correct transformation matrix in SetTransformation() + maSize.Width = 1; + maSize.Height = 1; + } + + // set pos, size, shear and rotate + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLTextBoxShapeContext::SdXMLTextBoxShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ), + mnRadius(0), + maChainNextName("") +{ +} + +SdXMLTextBoxShapeContext::~SdXMLTextBoxShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLTextBoxShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_CORNER_RADIUS): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRadius, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_CHAIN_NEXT_NAME): + maChainNextName = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLTextBoxShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create textbox shape + bool bIsPresShape = false; + bool bClearText = false; + + OUString service; + + if( isPresentationShape() ) + { + // check if the current document supports presentation shapes + if( GetImport().GetShapeImport()->IsPresentationShapesSupported() ) + { + if( IsXMLToken( maPresentationClass, XML_SUBTITLE )) + { + // XmlShapeType::PresSubtitleShape + service = "com.sun.star.presentation.SubtitleShape"; + } + else if( IsXMLToken( maPresentationClass, XML_PRESENTATION_OUTLINE ) ) + { + // XmlShapeType::PresOutlinerShape + service = "com.sun.star.presentation.OutlinerShape"; + } + else if( IsXMLToken( maPresentationClass, XML_NOTES ) ) + { + // XmlShapeType::PresNotesShape + service = "com.sun.star.presentation.NotesShape"; + } + else if( IsXMLToken( maPresentationClass, XML_HEADER ) ) + { + // XmlShapeType::PresHeaderShape + service = "com.sun.star.presentation.HeaderShape"; + bClearText = true; + } + else if( IsXMLToken( maPresentationClass, XML_FOOTER ) ) + { + // XmlShapeType::PresFooterShape + service = "com.sun.star.presentation.FooterShape"; + bClearText = true; + } + else if( IsXMLToken( maPresentationClass, XML_PAGE_NUMBER ) ) + { + // XmlShapeType::PresSlideNumberShape + service = "com.sun.star.presentation.SlideNumberShape"; + bClearText = true; + } + else if( IsXMLToken( maPresentationClass, XML_DATE_TIME ) ) + { + // XmlShapeType::PresDateTimeShape + service = "com.sun.star.presentation.DateTimeShape"; + bClearText = true; + } + else // IsXMLToken( maPresentationClass, XML_TITLE ) ) + { + // XmlShapeType::PresTitleTextShape + service = "com.sun.star.presentation.TitleTextShape"; + } + bIsPresShape = true; + } + } + + if( service.isEmpty() ) + { + // normal text shape + service = "com.sun.star.drawing.TextShape"; + } + + // Add, set Style and properties from base shape + AddShape(service); + + if( !mxShape.is() ) + return; + + SetStyle(); + SetLayer(); + + if(bIsPresShape) + { + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( !mbIsPlaceholder && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xProps->setPropertyValue("IsEmptyPresentationObject", css::uno::Any(false) ); + + if( mbIsUserTransformed && xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + } + + if( bClearText ) + { + uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY ); + xText->setString( "" ); + } + + // set parameters on shape +//A AW->CL: Eventually You need to strip scale and translate from the transformation +//A to reach the same goal again. +//A if(!bIsPresShape || mbIsUserTransformed) +//A { +//A // set pos and size on shape, this should remove binding +//A // to presentation object on masterpage +//A SetSizeAndPosition(); +//A } + + // set pos, size, shear and rotate + SetTransformation(); + + if(mnRadius) + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + try + { + xPropSet->setPropertyValue("CornerRadius", uno::Any( mnRadius ) ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting corner radius"); + } + } + } + + if(!maChainNextName.isEmpty()) + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + try + { + xPropSet->setPropertyValue("TextChainNextName", + uno::Any( maChainNextName ) ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting name of next chain link"); + } + } + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLControlShapeContext::SdXMLControlShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ) +{ +} + +SdXMLControlShapeContext::~SdXMLControlShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLControlShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_CONTROL): + maFormId = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLControlShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create Control shape + // add, set style and properties from base shape + AddShape("com.sun.star.drawing.ControlShape"); + if( !mxShape.is() ) + return; + + SAL_WARN_IF( !!maFormId.isEmpty(), "xmloff", "draw:control without a form:id attribute!" ); + if( !maFormId.isEmpty() ) + { + if( GetImport().IsFormsSupported() ) + { + uno::Reference< awt::XControlModel > xControlModel( GetImport().GetFormImport()->lookupControl( maFormId ), uno::UNO_QUERY ); + if( xControlModel.is() ) + { + uno::Reference< drawing::XControlShape > xControl( mxShape, uno::UNO_QUERY ); + if( xControl.is() ) + xControl->setControl( xControlModel ); + + } + } + } + + SetStyle(); + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLConnectorShapeContext::SdXMLConnectorShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + maStart(0,0), + maEnd(1,1), + mnType( drawing::ConnectorType_STANDARD ), + mnStartGlueId(-1), + mnEndGlueId(-1), + mnDelta1(0), + mnDelta2(0), + mnDelta3(0), + mbLikelyOOXMLCurve(true) +{ +} + +SdXMLConnectorShapeContext::~SdXMLConnectorShapeContext() +{ +} + +bool SvXMLImport::needFixPositionAfterZ() const +{ + bool bWrongPositionAfterZ( false ); + sal_Int32 nUPD( 0 ); + sal_Int32 nBuildId( 0 ); + if ( getBuildIds( nUPD, nBuildId ) && // test OOo and old versions of LibO and AOO + ( ( ( nUPD == 641 ) || ( nUPD == 645 ) || ( nUPD == 680 ) || ( nUPD == 300 ) || + ( nUPD == 310 ) || ( nUPD == 320 ) || ( nUPD == 330 ) || ( nUPD == 340 ) || + ( nUPD == 350 && nBuildId < 202 ) ) + || (getGeneratorVersion() == SvXMLImport::AOO_40x))) // test if AOO 4.0.x + // apparently bug was fixed in AOO by i#123433 f15874d8f976f3874bdbcb53429eeefa65c28841 + { + bWrongPositionAfterZ = true; + } + return bWrongPositionAfterZ; +} + +namespace +{ +bool lcl_IsLikelyOOXMLCurve(const basegfx::B2DPolygon& rPolygon) +{ + sal_uInt32 nCount = rPolygon.count(); + if (!rPolygon.areControlPointsUsed() or nCount < 2) + return false; // no curve at all + + basegfx::B2DVector aStartVec(rPolygon.getNextControlPoint(0) - rPolygon.getB2DPoint(0)); + basegfx::B2DVector aEndVec(rPolygon.getPrevControlPoint(nCount-1) - rPolygon.getB2DPoint(nCount - 1)); + // LibreOffice uses one point less than OOXML for the same underlying bentConnector or + // STANDARD connector, respectively. A deeper inspection is only needed in case of 2 resulting + // points. Those connector paths look like a quarter ellipse. + switch (nCount) + { + case 2: + { + // In case start and end direction are parallel, it cannot be OOXML because that case + // introduces a handle on the path and the curve has three points then. + if (basegfx::areParallel(aStartVec, aEndVec)) + return false; + // OOXML sets the control point at 1/2, LibreOffice at 2/3 of width or height. + // A tolerance is used because +-1 deviations due to integer arithmetic in many places. + basegfx::B2DRange aRect(rPolygon.getB2DPoint(0), rPolygon.getB2DPoint(1)); + if ((basegfx::fTools::equalZero(aStartVec.getX()) + && basegfx::fTools::equal(aStartVec.getLength() * 2.0, aRect.getHeight(), 2.0)) + || (basegfx::fTools::equalZero(aStartVec.getY()) + && basegfx::fTools::equal(aStartVec.getLength() * 2.0, aRect.getWidth(), 2.0))) + return true; + } + break; + case 3: + case 5: + return basegfx::areParallel(aStartVec, aEndVec); + break; + case 4: // start and end direction are orthogonal + return basegfx::fTools::equalZero(aStartVec.scalar( aEndVec)); + break; + default: + return false; + } + return false; +} +} // end namespace + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLConnectorShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_START_SHAPE): + maStartShapeId = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_START_GLUE_POINT): + mnStartGlueId = aIter.toInt32(); + break; + case XML_ELEMENT(DRAW, XML_END_SHAPE): + maEndShapeId = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_END_GLUE_POINT): + mnEndGlueId = aIter.toInt32(); + break; + case XML_ELEMENT(DRAW, XML_LINE_SKEW): + { + OUString sValue = aIter.toString(); + SvXMLTokenEnumerator aTokenEnum( sValue ); + std::u16string_view aToken; + if( aTokenEnum.getNextToken( aToken ) ) + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnDelta1, aToken); + if( aTokenEnum.getNextToken( aToken ) ) + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnDelta2, aToken); + if( aTokenEnum.getNextToken( aToken ) ) + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnDelta3, aToken); + } + } + } + break; + } + case XML_ELEMENT(DRAW, XML_TYPE): + { + (void)SvXMLUnitConverter::convertEnum( mnType, aIter.toView(), aXML_ConnectionKind_EnumMap ); + break; + } + // #121965# draw:transform may be used in ODF1.2, e.g. exports from MS seem to use these + case XML_ELEMENT(DRAW, XML_TRANSFORM): + mnTransform.SetString(aIter.toString(), GetImport().GetMM100UnitConverter()); + break; + + case XML_ELEMENT(SVG, XML_X1): + case XML_ELEMENT(SVG_COMPAT, XML_X1): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maStart.X, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y1): + case XML_ELEMENT(SVG_COMPAT, XML_Y1): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maStart.Y, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_X2): + case XML_ELEMENT(SVG_COMPAT, XML_X2): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maEnd.X, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_Y2): + case XML_ELEMENT(SVG_COMPAT, XML_Y2): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maEnd.Y, aIter.toView()); + break; + case XML_ELEMENT(SVG, XML_D): + case XML_ELEMENT(SVG_COMPAT, XML_D): + { + basegfx::B2DPolyPolygon aPolyPolygon; + + if(basegfx::utils::importFromSvgD(aPolyPolygon, aIter.toString(), GetImport().needFixPositionAfterZ(), nullptr)) + { + if(aPolyPolygon.count()) + { + drawing::PolyPolygonBezierCoords aSourcePolyPolygon; + + basegfx::utils::B2DPolyPolygonToUnoPolyPolygonBezierCoords( + aPolyPolygon, + aSourcePolyPolygon); + maPath <<= aSourcePolyPolygon; + + mbLikelyOOXMLCurve = lcl_IsLikelyOOXMLCurve(aPolyPolygon.getB2DPolygon(0)); + } + } + break; + } + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLConnectorShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // For security reasons, do not add empty connectors. There may have been an error in EA2 + // that created empty, far set off connectors (e.g. 63 meters below top of document). This + // is not guaranteed, but it's definitely safe to not add empty connectors. + bool bDoAdd(true); + + if( maStartShapeId.isEmpty() + && maEndShapeId.isEmpty() + && maStart.X == maEnd.X + && maStart.Y == maEnd.Y + && 0 == mnDelta1 + && 0 == mnDelta2 + && 0 == mnDelta3 + ) + { + bDoAdd = false; + } + + if(!bDoAdd) + return; + + // create Connector shape + // add, set style and properties from base shape + AddShape("com.sun.star.drawing.ConnectorShape"); + if(!mxShape.is()) + return; + + // #121965# if draw:transform is used, apply directly to the start + // and end positions before using these + if(mnTransform.NeedsAction()) + { + // transformation is used, apply to object. + ::basegfx::B2DHomMatrix aMat; + mnTransform.GetFullTransform(aMat); + + if(!aMat.isIdentity()) + { + basegfx::B2DPoint aStart(maStart.X, maStart.Y); + basegfx::B2DPoint aEnd(maEnd.X, maEnd.Y); + + aStart = aMat * aStart; + aEnd = aMat * aEnd; + + maStart.X = basegfx::fround(aStart.getX()); + maStart.Y = basegfx::fround(aStart.getY()); + maEnd.X = basegfx::fround(aEnd.getX()); + maEnd.Y = basegfx::fround(aEnd.getY()); + } + } + + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + if (xProps.is()) + xProps->setPropertyValue("EdgeOOXMLCurve", Any(mbLikelyOOXMLCurve)); + + // add connection ids + if( !maStartShapeId.isEmpty() ) + GetImport().GetShapeImport()->addShapeConnection( mxShape, true, maStartShapeId, mnStartGlueId ); + if( !maEndShapeId.isEmpty() ) + GetImport().GetShapeImport()->addShapeConnection( mxShape, false, maEndShapeId, mnEndGlueId ); + + if( xProps.is() ) + { + xProps->setPropertyValue("StartPosition", Any(maStart)); + xProps->setPropertyValue("EndPosition", Any(maEnd) ); + xProps->setPropertyValue("EdgeKind", Any(mnType) ); + xProps->setPropertyValue("EdgeLine1Delta", Any(mnDelta1) ); + xProps->setPropertyValue("EdgeLine2Delta", Any(mnDelta2) ); + xProps->setPropertyValue("EdgeLine3Delta", Any(mnDelta3) ); + } + SetStyle(); + SetLayer(); + + if ( maPath.hasValue() ) + { + // #i115492# + // Ignore svg:d attribute for text documents created by OpenOffice.org + // versions before OOo 3.3, because these OOo versions are storing + // svg:d values not using the correct unit. + bool bApplySVGD( true ); + if ( uno::Reference< text::XTextDocument >(GetImport().GetModel(), uno::UNO_QUERY).is() ) + { + sal_Int32 nUPD( 0 ); + sal_Int32 nBuild( 0 ); + const bool bBuildIdFound = GetImport().getBuildIds( nUPD, nBuild ); + if ( GetImport().IsTextDocInOOoFileFormat() || + ( bBuildIdFound && + ( ( nUPD == 641 ) || ( nUPD == 645 ) || // prior OOo 2.0 + ( nUPD == 680 ) || // OOo 2.x + ( nUPD == 300 ) || // OOo 3.0 - OOo 3.0.1 + ( nUPD == 310 ) || // OOo 3.1 - OOo 3.1.1 + ( nUPD == 320 ) ) ) ) // OOo 3.2 - OOo 3.2.1 + { + bApplySVGD = false; + } + } + + if ( bApplySVGD ) + { + // tdf#83360 use path data only when redundant data of start and end point coordinates of + // path start/end and connector start/end is equal. This is to avoid using erroneous + // or inconsistent path data at import of foreign formats. Office itself always + // writes out a consistent data set. Not using it when there is inconsistency + // is okay since the path data is redundant, buffered data just to avoid recalculation + // of the connector's layout at load time, no real information would be lost. + // A 'connected' end has prio to direct coordinate data in Start/EndPosition + // to the path data (which should have the start/end redundant in the path) + const drawing::PolyPolygonBezierCoords* pSource = static_cast< const drawing::PolyPolygonBezierCoords* >(maPath.getValue()); + const sal_uInt32 nSequenceCount(pSource->Coordinates.getLength()); + bool bStartEqual(false); + bool bEndEqual(false); + + if(nSequenceCount) + { + const drawing::PointSequence& rStartSeq = pSource->Coordinates[0]; + const sal_uInt32 nStartCount = rStartSeq.getLength(); + + if(nStartCount) + { + const awt::Point& rStartPoint = rStartSeq.getConstArray()[0]; + + if(rStartPoint.X == maStart.X && rStartPoint.Y == maStart.Y) + { + bStartEqual = true; + } + } + + const drawing::PointSequence& rEndSeq = pSource->Coordinates[nSequenceCount - 1]; + const sal_uInt32 nEndCount = rEndSeq.getLength(); + + if(nEndCount) + { + const awt::Point& rEndPoint = rEndSeq.getConstArray()[nEndCount - 1]; + + if(rEndPoint.X == maEnd.X && rEndPoint.Y == maEnd.Y) + { + bEndEqual = true; + } + } + } + + if(!bStartEqual || !bEndEqual) + { + bApplySVGD = false; + } + } + + if ( bApplySVGD ) + { + assert(maPath.getValueType() == cppu::UnoType<drawing::PolyPolygonBezierCoords>::get()); + xProps->setPropertyValue("PolyPolygonBezier", maPath); + } + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLMeasureShapeContext::SdXMLMeasureShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + maStart(0,0), + maEnd(1,1) +{ +} + +SdXMLMeasureShapeContext::~SdXMLMeasureShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLMeasureShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(SVG, XML_X1): + case XML_ELEMENT(SVG_COMPAT, XML_X1): + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maStart.X, aIter.toView()); + break; + } + case XML_ELEMENT(SVG, XML_Y1): + case XML_ELEMENT(SVG_COMPAT, XML_Y1): + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maStart.Y, aIter.toView()); + break; + } + case XML_ELEMENT(SVG, XML_X2): + case XML_ELEMENT(SVG_COMPAT, XML_X2): + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maEnd.X, aIter.toView()); + break; + } + case XML_ELEMENT(SVG, XML_Y2): + case XML_ELEMENT(SVG_COMPAT, XML_Y2): + { + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maEnd.Y, aIter.toView()); + break; + } + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLMeasureShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create Measure shape + // add, set style and properties from base shape + AddShape("com.sun.star.drawing.MeasureShape"); + if(!mxShape.is()) + return; + + SetStyle(); + SetLayer(); + + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + if( xProps.is() ) + { + xProps->setPropertyValue("StartPosition", Any(maStart)); + xProps->setPropertyValue("EndPosition", Any(maEnd) ); + } + + // delete pre created fields + uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY ); + if( xText.is() ) + { + xText->setString( " " ); + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + +void SdXMLMeasureShapeContext::endFastElement(sal_Int32 nElement) +{ + do + { + // delete pre created fields + uno::Reference< text::XText > xText( mxShape, uno::UNO_QUERY ); + if( !xText.is() ) + break; + + uno::Reference< text::XTextCursor > xCursor( xText->createTextCursor() ); + if( !xCursor.is() ) + break; + + xCursor->collapseToStart(); + xCursor->goRight( 1, true ); + xCursor->setString( "" ); + } + while(false); + + SdXMLShapeContext::endFastElement(nElement); +} + + +SdXMLPageShapeContext::SdXMLPageShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), mnPageNumber(0) +{ + mbClearDefaultAttributes = false; +} + +SdXMLPageShapeContext::~SdXMLPageShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLPageShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_PAGE_NUMBER) ) + mnPageNumber = aIter.toInt32(); + else + return SdXMLShapeContext::processAttribute( aIter ); + return true; +} + +void SdXMLPageShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create Page shape + // add, set style and properties from base shape + + // #86163# take into account which type of PageShape needs to + // be constructed. It's a presentation shape if presentation:XML_CLASS == XML_PAGE. + bool bIsPresentation = !maPresentationClass.isEmpty() && + GetImport().GetShapeImport()->IsPresentationShapesSupported(); + + uno::Reference< lang::XServiceInfo > xInfo( mxShapes, uno::UNO_QUERY ); + const bool bIsOnHandoutPage = xInfo.is() && xInfo->supportsService("com.sun.star.presentation.HandoutMasterPage"); + + if( bIsOnHandoutPage ) + { + AddShape("com.sun.star.presentation.HandoutShape"); + } + else + { + if(bIsPresentation && !IsXMLToken( maPresentationClass, XML_PAGE ) ) + { + bIsPresentation = false; + } + + if(bIsPresentation) + { + AddShape("com.sun.star.presentation.PageShape"); + } + else + { + AddShape("com.sun.star.drawing.PageShape"); + } + } + + if(!mxShape.is()) + return; + + SetStyle(); + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() ); + static constexpr OUString aPageNumberStr(u"PageNumber"_ustr); + if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(aPageNumberStr)) + xPropSet->setPropertyValue(aPageNumberStr, uno::Any( mnPageNumber )); + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + + +SdXMLCaptionShapeContext::SdXMLCaptionShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + // #86616# for correct edge rounding import mnRadius needs to be initialized + mnRadius( 0 ) +{ +} + +SdXMLCaptionShapeContext::~SdXMLCaptionShapeContext() +{ +} + +void SdXMLCaptionShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create Caption shape + // add, set style and properties from base shape + AddShape("com.sun.star.drawing.CaptionShape"); + if( !mxShape.is() ) + return; + + SetStyle(); + SetLayer(); + + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + + // SJ: If AutoGrowWidthItem is set, SetTransformation will lead to the wrong SnapRect + // because NbcAdjustTextFrameWidthAndHeight() is called (text is set later and center alignment + // is the default setting, so the top left reference point that is used by the caption point is + // no longer correct) There are two ways to solve this problem, temporarily disabling the + // autogrowwidth as we are doing here or to apply the CaptionPoint after setting text + bool bIsAutoGrowWidth = false; + if ( xProps.is() ) + { + uno::Any aAny( xProps->getPropertyValue("TextAutoGrowWidth") ); + aAny >>= bIsAutoGrowWidth; + + if ( bIsAutoGrowWidth ) + xProps->setPropertyValue("TextAutoGrowWidth", uno::Any( false ) ); + } + + // set pos, size, shear and rotate + SetTransformation(); + if( xProps.is() ) + xProps->setPropertyValue("CaptionPoint", uno::Any( maCaptionPoint ) ); + + if ( bIsAutoGrowWidth ) + xProps->setPropertyValue("TextAutoGrowWidth", uno::Any( true ) ); + + if(mnRadius) + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if(xPropSet.is()) + { + try + { + xPropSet->setPropertyValue("CornerRadius", uno::Any( mnRadius ) ); + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting corner radius"); + } + } + } + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLCaptionShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(DRAW, XML_CAPTION_POINT_X): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maCaptionPoint.X, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_CAPTION_POINT_Y): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + maCaptionPoint.Y, aIter.toView()); + break; + case XML_ELEMENT(DRAW, XML_CORNER_RADIUS): + GetImport().GetMM100UnitConverter().convertMeasureToCore( + mnRadius, aIter.toView()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + + +SdXMLGraphicObjectShapeContext::SdXMLGraphicObjectShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ) +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLGraphicObjectShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch (aIter.getToken()) + { + case XML_ELEMENT(XLINK, XML_HREF): + maURL = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_MIME_TYPE): + case XML_ELEMENT(LO_EXT, XML_MIME_TYPE): + msMimeType = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute(aIter); + } + return true; +} + +void SdXMLGraphicObjectShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create graphic object shape + OUString service; + + if( IsXMLToken( maPresentationClass, XML_GRAPHIC ) && GetImport().GetShapeImport()->IsPresentationShapesSupported() ) + { + service = "com.sun.star.presentation.GraphicObjectShape"; + } + else + { + service = "com.sun.star.drawing.GraphicObjectShape"; + } + + AddShape(service); + + if(!mxShape.is()) + return; + + SetStyle(); + SetLayer(); + + uno::Reference< beans::XPropertySet > xPropset(mxShape, uno::UNO_QUERY); + if(xPropset.is()) + { + // since OOo 1.x had no line or fill style for graphics, but may create + // documents with them, we have to override them here + sal_Int32 nUPD, nBuildId; + if( GetImport().getBuildIds( nUPD, nBuildId ) && (nUPD == 645) ) try + { + xPropset->setPropertyValue("FillStyle", Any( FillStyle_NONE ) ); + xPropset->setPropertyValue("LineStyle", Any( LineStyle_NONE ) ); + } + catch(const Exception&) + { + } + + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xPropset->getPropertySetInfo() ); + if( xPropsInfo.is() && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xPropset->setPropertyValue("IsEmptyPresentationObject", css::uno::Any( mbIsPlaceholder ) ); + + if( !mbIsPlaceholder ) + { + if( !maURL.isEmpty() ) + { + uno::Reference<graphic::XGraphic> xGraphic = GetImport().loadGraphicByURL(maURL); + if (xGraphic.is()) + { + xPropset->setPropertyValue("Graphic", uno::Any(xGraphic)); + } + } + } + } + + if(mbIsUserTransformed) + { + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + } + + // set pos, size, shear and rotate + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + +void SdXMLGraphicObjectShapeContext::endFastElement(sal_Int32 nElement) +{ + if (mxBase64Stream.is()) + { + uno::Reference<graphic::XGraphic> xGraphic(GetImport().loadGraphicFromBase64(mxBase64Stream)); + if (xGraphic.is()) + { + uno::Reference<beans::XPropertySet> xProperties(mxShape, uno::UNO_QUERY); + if (xProperties.is()) + { + xProperties->setPropertyValue("Graphic", uno::Any(xGraphic)); + } + } + } + + SdXMLShapeContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLGraphicObjectShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + css::uno::Reference< css::xml::sax::XFastContextHandler > xContext; + + if( nElement == XML_ELEMENT(OFFICE, XML_BINARY_DATA) ) + { + if( maURL.isEmpty() && !mxBase64Stream.is() ) + { + mxBase64Stream = GetImport().GetStreamForGraphicObjectURLFromBase64(); + if( mxBase64Stream.is() ) + xContext = new XMLBase64ImportContext( GetImport(), + mxBase64Stream ); + } + } + + // delegate to parent class if no context could be created + if (!xContext) + xContext = SdXMLShapeContext::createFastChildContext(nElement, + xAttrList); + + if (!xContext) + XMLOFF_WARN_UNKNOWN_ELEMENT("xmloff", nElement); + + return xContext; +} + +SdXMLGraphicObjectShapeContext::~SdXMLGraphicObjectShapeContext() +{ + +} + + +SdXMLChartShapeContext::SdXMLChartShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ) +{ +} + +void SdXMLChartShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + const bool bIsPresentation = isPresentationShape(); + + AddShape( + bIsPresentation + ? OUString("com.sun.star.presentation.ChartShape") + : OUString("com.sun.star.drawing.OLE2Shape")); + + if(!mxShape.is()) + return; + + SetStyle(); + SetLayer(); + + if( !mbIsPlaceholder ) + { + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xProps->setPropertyValue("IsEmptyPresentationObject", css::uno::Any(false) ); + + uno::Any aAny; + + xProps->setPropertyValue("CLSID", Any(OUString("12DCAE26-281F-416F-a234-c3086127382e")) ); + + aAny = xProps->getPropertyValue("Model"); + uno::Reference< frame::XModel > xChartModel; + if( aAny >>= xChartModel ) + { +#if !ENABLE_WASM_STRIP_CHART + // WASM_CHART change + // TODO: Maybe use SdXMLGraphicObjectShapeContext completely instead + // or try to create as mbIsPlaceholder object adding a Chart visualization + // that should be available somehow + mxChartContext.set( GetImport().GetChartImport()->CreateChartContext( GetImport(), xChartModel ) ); +#endif + } + } + } + + if(mbIsUserTransformed) + { + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + } + + // set pos, size, shear and rotate + SetTransformation(); + + SdXMLShapeContext::startFastElement(nElement, xAttrList); + + if( mxChartContext.is() ) + mxChartContext->startFastElement( nElement, xAttrList ); +} + +void SdXMLChartShapeContext::endFastElement(sal_Int32 nElement) +{ + if( mxChartContext.is() ) + mxChartContext->endFastElement(nElement); + + SdXMLShapeContext::endFastElement(nElement); +} + +void SdXMLChartShapeContext::characters( const OUString& rChars ) +{ + if( mxChartContext.is() ) + mxChartContext->characters( rChars ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLChartShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( mxChartContext.is() ) + return mxChartContext->createFastChildContext( nElement, xAttrList ); + + return nullptr; +} + + +SdXMLObjectShapeContext::SdXMLObjectShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ) +{ +} + +SdXMLObjectShapeContext::~SdXMLObjectShapeContext() +{ +} + +void SdXMLObjectShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + // #96717# in theorie, if we don't have a URL we shouldn't even + // export this OLE shape. But practically it's too risky right now + // to change this so we better dispose this on load + //if( !mbIsPlaceholder && ImpIsEmptyURL(maHref) ) + // return; + + // #100592# this BugFix prevents that a shape is created. CL + // is thinking about an alternative. + // #i13140# Check for more than empty string in maHref, there are + // other possibilities that maHref results in empty container + // storage names + if( !(GetImport().getImportFlags() & SvXMLImportFlags::EMBEDDED) && !mbIsPlaceholder && ImpIsEmptyURL(maHref) ) + return; + + OUString service("com.sun.star.drawing.OLE2Shape"); + + bool bIsPresShape = !maPresentationClass.isEmpty() && GetImport().GetShapeImport()->IsPresentationShapesSupported(); + + if( bIsPresShape ) + { + if( IsXMLToken( maPresentationClass, XML_CHART ) ) + { + service = "com.sun.star.presentation.ChartShape"; + } + else if( IsXMLToken( maPresentationClass, XML_TABLE ) ) + { + service = "com.sun.star.presentation.CalcShape"; + } + else if( IsXMLToken( maPresentationClass, XML_OBJECT ) ) + { + service = "com.sun.star.presentation.OLE2Shape"; + } + } + + AddShape(service); + + if( !mxShape.is() ) + return; + + SetLayer(); + + if(bIsPresShape) + { + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( !mbIsPlaceholder && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xProps->setPropertyValue("IsEmptyPresentationObject", css::uno::Any(false) ); + + if( mbIsUserTransformed && xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + } + + if( !mbIsPlaceholder && !maHref.isEmpty() ) + { + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + + if( xProps.is() ) + { + OUString aPersistName = GetImport().ResolveEmbeddedObjectURL( maHref, maCLSID ); + + if ( GetImport().IsPackageURL( maHref ) ) + { + static constexpr OUString sURL( u"vnd.sun.star.EmbeddedObject:"_ustr ); + + if ( aPersistName.startsWith( sURL ) ) + aPersistName = aPersistName.copy( sURL.getLength() ); + + xProps->setPropertyValue("PersistName", + uno::Any( aPersistName ) ); + } + else + { + // this is OOo link object + xProps->setPropertyValue("LinkURL", + uno::Any( aPersistName ) ); + } + } + } + + // set pos, size, shear and rotate + SetTransformation(); + + SetStyle(); + + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); +} + +void SdXMLObjectShapeContext::endFastElement(sal_Int32 nElement) +{ + if (GetImport().isGeneratorVersionOlderThan( + SvXMLImport::OOo_34x, SvXMLImport::LO_41x)) // < LO 4.0 + { + // #i118485# + // If it's an old file from us written before OOo3.4, we need to correct + // FillStyle and LineStyle for OLE2 objects. The error was that the old paint + // implementations just ignored added fill/linestyles completely, thus + // those objects need to be corrected to not show blue and hairline which + // always was the default, but would be shown now + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + + if( xProps.is() ) + { + xProps->setPropertyValue("FillStyle", uno::Any(drawing::FillStyle_NONE)); + xProps->setPropertyValue("LineStyle", uno::Any(drawing::LineStyle_NONE)); + } + } + + if( mxBase64Stream.is() ) + { + OUString aPersistName( GetImport().ResolveEmbeddedObjectURLFromBase64() ); + static constexpr OUStringLiteral sURL( u"vnd.sun.star.EmbeddedObject:" ); + + aPersistName = aPersistName.copy( sURL.getLength() ); + + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + if( xProps.is() ) + xProps->setPropertyValue("PersistName", uno::Any( aPersistName ) ); + } + + SdXMLShapeContext::endFastElement(nElement); +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLObjectShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_CLASS_ID): + maCLSID = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_HREF): + maHref = aIter.toString(); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLObjectShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if(nElement == XML_ELEMENT(OFFICE, XML_BINARY_DATA)) + { + mxBase64Stream = GetImport().GetStreamForEmbeddedObjectURLFromBase64(); + if( mxBase64Stream.is() ) + return new XMLBase64ImportContext( GetImport(), mxBase64Stream ); + } + else if( nElement == XML_ELEMENT(OFFICE, XML_DOCUMENT) || + nElement == XML_ELEMENT(MATH, XML_MATH) ) + { + rtl::Reference<XMLEmbeddedObjectImportContext> xEContext( + new XMLEmbeddedObjectImportContext(GetImport(), nElement, xAttrList)); + maCLSID = xEContext->GetFilterCLSID(); + if( !maCLSID.isEmpty() ) + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + if( xPropSet.is() ) + { + xPropSet->setPropertyValue("CLSID", uno::Any( maCLSID ) ); + + uno::Reference< lang::XComponent > xComp; + xPropSet->getPropertyValue("Model") >>= xComp; + SAL_WARN_IF( !xComp.is(), "xmloff", "no xModel for own OLE format" ); + xEContext->SetComponent(xComp); + } + } + return xEContext; + } + + // delegate to parent class if no context could be created + return SdXMLShapeContext::createFastChildContext(nElement, xAttrList); +} + +SdXMLAppletShapeContext::SdXMLAppletShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ), + mbIsScript( false ) +{ +} + +SdXMLAppletShapeContext::~SdXMLAppletShapeContext() +{ +} + +void SdXMLAppletShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + AddShape("com.sun.star.drawing.AppletShape"); + + if( mxShape.is() ) + { + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); + } +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLAppletShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_APPLET_NAME): + maAppletName = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_CODE): + maAppletCode = aIter.toString(); + break; + case XML_ELEMENT(DRAW, XML_MAY_SCRIPT): + mbIsScript = IsXMLToken( aIter, XML_TRUE ); + break; + case XML_ELEMENT(XLINK, XML_HREF): + maHref = GetImport().GetAbsoluteReference(aIter.toString()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLAppletShapeContext::endFastElement(sal_Int32 nElement) +{ + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + if( xProps.is() ) + { + if ( maSize.Width && maSize.Height ) + { + // the visual area for applet must be set on loading + awt::Rectangle aRect( 0, 0, maSize.Width, maSize.Height ); + xProps->setPropertyValue("VisibleArea", Any(aRect) ); + } + + if( maParams.hasElements() ) + { + xProps->setPropertyValue("AppletCommands", Any(maParams) ); + } + + if( !maHref.isEmpty() ) + { + xProps->setPropertyValue("AppletCodeBase", Any(maHref) ); + } + + if( !maAppletName.isEmpty() ) + { + xProps->setPropertyValue("AppletName", Any(maAppletName) ); + } + + if( mbIsScript ) + { + xProps->setPropertyValue("AppletIsScript", Any(mbIsScript) ); + + } + + if( !maAppletCode.isEmpty() ) + { + xProps->setPropertyValue("AppletCode", Any(maAppletCode) ); + } + + xProps->setPropertyValue("AppletDocBase", Any(GetImport().GetDocumentBase()) ); + + SetThumbnail(); + } + + SdXMLShapeContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLAppletShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(DRAW, XML_PARAM) ) + { + OUString aParamName, aParamValue; + // now parse the attribute list and look for draw:name and draw:value + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_NAME) ) + aParamName = aIter.toString(); + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_VALUE) ) + aParamValue = aIter.toString(); + } + + if( !aParamName.isEmpty() ) + { + sal_Int32 nIndex = maParams.getLength(); + maParams.realloc( nIndex + 1 ); + auto pParams = maParams.getArray(); + pParams[nIndex].Name = aParamName; + pParams[nIndex].Handle = -1; + pParams[nIndex].Value <<= aParamValue; + pParams[nIndex].State = beans::PropertyState_DIRECT_VALUE; + } + + return new SvXMLImportContext( GetImport() ); + } + + return SdXMLShapeContext::createFastChildContext( nElement, xAttrList ); +} + + +SdXMLPluginShapeContext::SdXMLPluginShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes) : +SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ), +mbMedia( false ) +{ +} + +SdXMLPluginShapeContext::~SdXMLPluginShapeContext() +{ +} + +void SdXMLPluginShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + + // watch for MimeType attribute to see if we have a media object + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_MIME_TYPE) ) + { + if (::comphelper::IsMediaMimeType(aIter.toView())) + mbMedia = true; + // leave this loop + break; + } + } + + OUString service; + + bool bIsPresShape = false; + + if( mbMedia ) + { + service = "com.sun.star.drawing.MediaShape"; + + bIsPresShape = !maPresentationClass.isEmpty() && GetImport().GetShapeImport()->IsPresentationShapesSupported(); + if( bIsPresShape ) + { + if( IsXMLToken( maPresentationClass, XML_OBJECT ) ) + { + service = "com.sun.star.presentation.MediaShape"; + } + } + } + else + service = "com.sun.star.drawing.PluginShape"; + + AddShape(service); + + if( !mxShape.is() ) + return; + + if (mbMedia) + { + // The media may have a crop, apply it. + SetStyle(/*bSupportsStyle=*/false); + } + + SetLayer(); + + if(bIsPresShape) + { + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + if(xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( !mbIsPlaceholder && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xProps->setPropertyValue("IsEmptyPresentationObject", css::uno::Any(false) ); + + if( mbIsUserTransformed && xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + } + + // set pos, size, shear and rotate + SetTransformation(); + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); +} + +static OUString +lcl_GetMediaReference(SvXMLImport const& rImport, OUString const& rURL) +{ + if (rImport.IsPackageURL(rURL)) + { + return "vnd.sun.star.Package:" + rURL; + } + else + { + return rImport.GetAbsoluteReference(rURL); + } +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLPluginShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_MIME_TYPE): + maMimeType = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_HREF): + maHref = lcl_GetMediaReference(GetImport(), aIter.toString()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLPluginShapeContext::endFastElement(sal_Int32 nElement) +{ + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + + if( xProps.is() ) + { + if ( maSize.Width && maSize.Height ) + { + static constexpr OUString sVisibleArea( u"VisibleArea"_ustr ); + uno::Reference< beans::XPropertySetInfo > aXPropSetInfo( xProps->getPropertySetInfo() ); + if ( !aXPropSetInfo.is() || aXPropSetInfo->hasPropertyByName( sVisibleArea ) ) + { + // the visual area for a plugin must be set on loading + awt::Rectangle aRect( 0, 0, maSize.Width, maSize.Height ); + xProps->setPropertyValue( sVisibleArea, Any(aRect) ); + } + } + + if( !mbMedia ) + { + // in case we have a plugin object + if( maParams.hasElements() ) + { + xProps->setPropertyValue("PluginCommands", Any(maParams) ); + } + + if( !maMimeType.isEmpty() ) + { + xProps->setPropertyValue("PluginMimeType", Any(maMimeType) ); + } + + if( !maHref.isEmpty() ) + { + xProps->setPropertyValue("PluginURL", Any(maHref) ); + } + } + else + { + // in case we have a media object + xProps->setPropertyValue( "MediaURL", uno::Any(maHref)); + + xProps->setPropertyValue("MediaMimeType", uno::Any(maMimeType) ); + + for( const auto& rParam : std::as_const(maParams) ) + { + const OUString& rName = rParam.Name; + + if( rName == "Loop" ) + { + OUString aValueStr; + rParam.Value >>= aValueStr; + xProps->setPropertyValue("Loop", + uno::Any( aValueStr == "true" ) ); + } + else if( rName == "Mute" ) + { + OUString aValueStr; + rParam.Value >>= aValueStr; + xProps->setPropertyValue("Mute", + uno::Any( aValueStr == "true" ) ); + } + else if( rName == "VolumeDB" ) + { + OUString aValueStr; + rParam.Value >>= aValueStr; + xProps->setPropertyValue("VolumeDB", + uno::Any( static_cast< sal_Int16 >( aValueStr.toInt32() ) ) ); + } + else if( rName == "Zoom" ) + { + OUString aZoomStr; + media::ZoomLevel eZoomLevel; + + rParam.Value >>= aZoomStr; + + if( aZoomStr == "25%" ) + eZoomLevel = media::ZoomLevel_ZOOM_1_TO_4; + else if( aZoomStr == "50%" ) + eZoomLevel = media::ZoomLevel_ZOOM_1_TO_2; + else if( aZoomStr == "100%" ) + eZoomLevel = media::ZoomLevel_ORIGINAL; + else if( aZoomStr == "200%" ) + eZoomLevel = media::ZoomLevel_ZOOM_2_TO_1; + else if( aZoomStr == "400%" ) + eZoomLevel = media::ZoomLevel_ZOOM_4_TO_1; + else if( aZoomStr == "fit" ) + eZoomLevel = media::ZoomLevel_FIT_TO_WINDOW; + else if( aZoomStr == "fixedfit" ) + eZoomLevel = media::ZoomLevel_FIT_TO_WINDOW_FIXED_ASPECT; + else if( aZoomStr == "fullscreen" ) + eZoomLevel = media::ZoomLevel_FULLSCREEN; + else + eZoomLevel = media::ZoomLevel_NOT_AVAILABLE; + + xProps->setPropertyValue("Zoom", uno::Any( eZoomLevel ) ); + } + } + } + + SetThumbnail(); + } + + SdXMLShapeContext::endFastElement(nElement); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLPluginShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( nElement == XML_ELEMENT(DRAW, XML_PARAM) ) + { + OUString aParamName, aParamValue; + // now parse the attribute list and look for draw:name and draw:value + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_NAME) ) + aParamName = aIter.toString(); + else if( aIter.getToken() == XML_ELEMENT(DRAW, XML_VALUE) ) + aParamValue = aIter.toString(); + } + + if( !aParamName.isEmpty() ) + { + sal_Int32 nIndex = maParams.getLength(); + maParams.realloc( nIndex + 1 ); + auto pParams = maParams.getArray(); + pParams[nIndex].Name = aParamName; + pParams[nIndex].Handle = -1; + pParams[nIndex].Value <<= aParamValue; + pParams[nIndex].State = beans::PropertyState_DIRECT_VALUE; + } + + return new SvXMLImportContext( GetImport() ); + } + + return SdXMLShapeContext::createFastChildContext( nElement, xAttrList ); +} + + +SdXMLFloatingFrameShapeContext::SdXMLFloatingFrameShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ) +{ +} + +SdXMLFloatingFrameShapeContext::~SdXMLFloatingFrameShapeContext() +{ +} + +uno::Reference<drawing::XShape> SdXMLFloatingFrameShapeContext::CreateFloatingFrameShape() const +{ + uno::Reference<lang::XMultiServiceFactory> xServiceFact(GetImport().GetModel(), uno::UNO_QUERY); + if (!xServiceFact.is()) + return nullptr; + uno::Reference<drawing::XShape> xShape( + xServiceFact->createInstance("com.sun.star.drawing.FrameShape"), uno::UNO_QUERY); + return xShape; +} + +void SdXMLFloatingFrameShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + uno::Reference<drawing::XShape> xShape(SdXMLFloatingFrameShapeContext::CreateFloatingFrameShape()); + + uno::Reference< beans::XPropertySet > xProps(xShape, uno::UNO_QUERY); + // set FrameURL before AddShape, we have to do it again later because it + // gets cleared when the SdrOle2Obj is attached to the XShape. But we want + // FrameURL to exist when AddShape triggers SetPersistName which itself + // triggers SdrOle2Obj::CheckFileLink_Impl and at that point we want to + // know what URL will end up being used. So bodge this by setting FrameURL + // to the temp pre-SdrOle2Obj attached properties and we can smuggle it + // eventually into SdrOle2Obj::SetPersistName at the right point after + // PersistName is set but before SdrOle2Obj::CheckFileLink_Impl is called + // in order to inform the link manager that this is an IFrame that links to + // a URL + if (xProps && !maHref.isEmpty()) + xProps->setPropertyValue("FrameURL", Any(maHref)); + + AddShape(xShape); + + if( !mxShape.is() ) + return; + + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + + if( xProps.is() ) + { + if( !maFrameName.isEmpty() ) + { + xProps->setPropertyValue("FrameName", Any(maFrameName) ); + } + + if( !maHref.isEmpty() ) + { + if (INetURLObject(maHref).IsExoticProtocol()) + GetImport().NotifyMacroEventRead(); + + xProps->setPropertyValue("FrameURL", Any(maHref) ); + } + } + + SetStyle(); + + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLFloatingFrameShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + switch( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_FRAME_NAME): + maFrameName = aIter.toString(); + break; + case XML_ELEMENT(XLINK, XML_HREF): + maHref = GetImport().GetAbsoluteReference(aIter.toString()); + break; + default: + return SdXMLShapeContext::processAttribute( aIter ); + } + return true; +} + +void SdXMLFloatingFrameShapeContext::endFastElement(sal_Int32 nElement) +{ + uno::Reference< beans::XPropertySet > xProps( mxShape, uno::UNO_QUERY ); + + if( xProps.is() ) + { + if ( maSize.Width && maSize.Height ) + { + // the visual area for a floating frame must be set on loading + awt::Rectangle aRect( 0, 0, maSize.Width, maSize.Height ); + xProps->setPropertyValue("VisibleArea", Any(aRect) ); + } + } + + SetThumbnail(); + SdXMLShapeContext::endFastElement(nElement); +} + + +SdXMLFrameShapeContext::SdXMLFrameShapeContext( SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + css::uno::Reference< css::drawing::XShapes > const & rShapes, + bool bTemporaryShape) +: SdXMLShapeContext( rImport, xAttrList, rShapes, bTemporaryShape ), + mbSupportsReplacement( false ) +{ + uno::Reference < util::XCloneable > xClone( xAttrList, uno::UNO_QUERY ); + if( xClone.is() ) + mxAttrList.set( xClone->createClone(), uno::UNO_QUERY ); + else + mxAttrList = new sax_fastparser::FastAttributeList(xAttrList); +} + +SdXMLFrameShapeContext::~SdXMLFrameShapeContext() +{ +} + +void SdXMLFrameShapeContext::removeGraphicFromImportContext(const SvXMLImportContext& rContext) +{ + const SdXMLGraphicObjectShapeContext* pSdXMLGraphicObjectShapeContext = dynamic_cast< const SdXMLGraphicObjectShapeContext* >(&rContext); + + if(!pSdXMLGraphicObjectShapeContext) + return; + + try + { + uno::Reference< container::XChild > xChild(pSdXMLGraphicObjectShapeContext->getShape(), uno::UNO_QUERY_THROW); + + uno::Reference< drawing::XShapes > xParent(xChild->getParent(), uno::UNO_QUERY_THROW); + + // remove from parent + xParent->remove(pSdXMLGraphicObjectShapeContext->getShape()); + + // dispose + uno::Reference< lang::XComponent > xComp(pSdXMLGraphicObjectShapeContext->getShape(), UNO_QUERY); + + if(xComp.is()) + { + xComp->dispose(); + } + } + catch( uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "Error in cleanup of multiple graphic object import." ); + } +} + +namespace +{ +uno::Reference<beans::XPropertySet> getGraphicPropertySetFromImportContext(const SvXMLImportContext& rContext) +{ + uno::Reference<beans::XPropertySet> aPropertySet; + const SdXMLGraphicObjectShapeContext* pSdXMLGraphicObjectShapeContext = dynamic_cast<const SdXMLGraphicObjectShapeContext*>(&rContext); + + if (pSdXMLGraphicObjectShapeContext) + aPropertySet.set(pSdXMLGraphicObjectShapeContext->getShape(), uno::UNO_QUERY); + + return aPropertySet; +} + +} // end anonymous namespace + +uno::Reference<graphic::XGraphic> SdXMLFrameShapeContext::getGraphicFromImportContext(const SvXMLImportContext& rContext) const +{ + uno::Reference<graphic::XGraphic> xGraphic; + try + { + const uno::Reference<beans::XPropertySet> xPropertySet = getGraphicPropertySetFromImportContext(rContext); + + if (xPropertySet.is()) + { + xPropertySet->getPropertyValue("Graphic") >>= xGraphic; + } + } + catch( uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION("xmloff", "Error in cleanup of multiple graphic object import."); + } + + return xGraphic; +} + +OUString SdXMLFrameShapeContext::getMimeTypeFromImportContext(const SvXMLImportContext& rContext) const +{ + OUString aMimeType; + const SdXMLGraphicObjectShapeContext* pSdXMLGraphicObjectShapeContext = dynamic_cast<const SdXMLGraphicObjectShapeContext*>(&rContext); + + if (pSdXMLGraphicObjectShapeContext) + aMimeType = pSdXMLGraphicObjectShapeContext->getMimeType(); + return aMimeType; +} + +OUString SdXMLFrameShapeContext::getGraphicPackageURLFromImportContext(const SvXMLImportContext& rContext) const +{ + OUString aRetval; + const SdXMLGraphicObjectShapeContext* pSdXMLGraphicObjectShapeContext = dynamic_cast< const SdXMLGraphicObjectShapeContext* >(&rContext); + + if(pSdXMLGraphicObjectShapeContext) + { + try + { + const uno::Reference< beans::XPropertySet > xPropSet(pSdXMLGraphicObjectShapeContext->getShape(), uno::UNO_QUERY_THROW); + + xPropSet->getPropertyValue("GraphicStreamURL") >>= aRetval; + } + catch( uno::Exception& ) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "Error in cleanup of multiple graphic object import." ); + } + } + + return aRetval; +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLFrameShapeContext::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + SvXMLImportContextRef xContext; + if( !mxImplContext.is() ) + { + SvXMLShapeContext* pShapeContext = XMLShapeImportHelper::CreateFrameChildContext( + GetImport(), nElement, xAttrList, mxShapes, mxAttrList ); + + xContext = pShapeContext; + + // propagate the hyperlink to child context + if ( !msHyperlink.isEmpty() ) + pShapeContext->setHyperlink( msHyperlink ); + + auto nToken = nElement & TOKEN_MASK; + bool bMedia = false; + // Ignore gltf model if necessary and so the fallback image will be imported + if( nToken == XML_PLUGIN ) + { + SdXMLPluginShapeContext* pPluginContext = dynamic_cast<SdXMLPluginShapeContext*>(pShapeContext); + if( pPluginContext && pPluginContext->getMimeType() == "model/vnd.gltf+json" ) + { + mxImplContext = nullptr; + return new SvXMLImportContext(GetImport()); + } + else if (pPluginContext && ::comphelper::IsMediaMimeType(pPluginContext->getMimeType())) + { + // The media may have a preview, import it. + bMedia = true; + } + } + + mxImplContext = xContext; + mbSupportsReplacement = (nToken == XML_OBJECT ) || (nToken == XML_OBJECT_OLE) || bMedia; + setSupportsMultipleContents(nToken == XML_IMAGE); + + if(getSupportsMultipleContents() && dynamic_cast< SdXMLGraphicObjectShapeContext* >(xContext.get())) + { + if ( !maShapeId.isEmpty() ) + GetImport().getInterfaceToIdentifierMapper().reserveIdentifier( maShapeId ); + + addContent(*mxImplContext); + } + } + else if(getSupportsMultipleContents() && nElement == XML_ELEMENT(DRAW, XML_IMAGE)) + { + // read another image + xContext = XMLShapeImportHelper::CreateFrameChildContext( + GetImport(), nElement, xAttrList, mxShapes, mxAttrList); + mxImplContext = xContext; + + if(dynamic_cast< SdXMLGraphicObjectShapeContext* >(xContext.get())) + { + addContent(*mxImplContext); + } + } + else if( mbSupportsReplacement && !mxReplImplContext.is() && + nElement == XML_ELEMENT(DRAW, XML_IMAGE) ) + { + // read replacement image + SvXMLImportContext *pImplContext = mxImplContext.get(); + SdXMLShapeContext *pSContext = + dynamic_cast<SdXMLShapeContext*>( pImplContext ); + if( pSContext ) + { + uno::Reference < beans::XPropertySet > xPropSet( + pSContext->getShape(), uno::UNO_QUERY ); + if( xPropSet.is() ) + { + xContext = new XMLReplacementImageContext( GetImport(), + nElement, xAttrList, xPropSet ); + mxReplImplContext = xContext; + } + } + } + else if( nElement == XML_ELEMENT(SVG, XML_TITLE) || // #i68101# + nElement == XML_ELEMENT(SVG_COMPAT, XML_TITLE) || + nElement == XML_ELEMENT(SVG, XML_DESC) || + nElement == XML_ELEMENT(SVG_COMPAT, XML_DESC) || + nElement == XML_ELEMENT(OFFICE, XML_EVENT_LISTENERS) || + nElement == XML_ELEMENT(DRAW, XML_GLUE_POINT) || + nElement == XML_ELEMENT(DRAW, XML_THUMBNAIL) ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + // note: no more draw:image can be added once we get here + mxImplContext = solveMultipleImages(); + } + SvXMLImportContext *pImplContext = mxImplContext.get(); + xContext = static_cast<SvXMLImportContext*>(dynamic_cast<SdXMLShapeContext&>(*pImplContext).createFastChildContext( nElement, + xAttrList ).get()); + } + else if ( nElement == XML_ELEMENT(DRAW, XML_IMAGE_MAP) ) + { + if (getSupportsMultipleContents()) + { // tdf#103567 ensure props are set on surviving shape + // note: no more draw:image can be added once we get here + mxImplContext = solveMultipleImages(); + } + SdXMLShapeContext *pSContext = dynamic_cast< SdXMLShapeContext* >( mxImplContext.get() ); + if( pSContext ) + { + uno::Reference < beans::XPropertySet > xPropSet( pSContext->getShape(), uno::UNO_QUERY ); + if (xPropSet.is()) + { + xContext = new XMLImageMapContext(GetImport(), xPropSet); + } + } + } + else if ( nElement == XML_ELEMENT(LO_EXT, XML_SIGNATURELINE) ) + { + SdXMLShapeContext* pSContext = dynamic_cast<SdXMLShapeContext*>(mxImplContext.get()); + if (pSContext) + { + uno::Reference<beans::XPropertySet> xPropSet(pSContext->getShape(), uno::UNO_QUERY); + if (xPropSet.is()) + { + xContext = new SignatureLineContext(GetImport(), nElement, xAttrList, + pSContext->getShape()); + } + } + } + else if ( nElement == XML_ELEMENT(LO_EXT, XML_QRCODE)) + { + SdXMLShapeContext* pSContext = dynamic_cast<SdXMLShapeContext*>(mxImplContext.get()); + if (pSContext) + { + uno::Reference<beans::XPropertySet> xPropSet(pSContext->getShape(), uno::UNO_QUERY); + if (xPropSet.is()) + { + xContext = new QRCodeContext(GetImport(), nElement, xAttrList, + pSContext->getShape()); + } + } + } + + return xContext; +} + +void SdXMLFrameShapeContext::startFastElement (sal_Int32 /*nElement*/, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& /*xAttrList*/) +{ + // ignore +} + +void SdXMLFrameShapeContext::endFastElement(sal_Int32 nElement) +{ + // solve if multiple image child contexts were imported + SvXMLImportContextRef const pSelectedContext(solveMultipleImages()); + const SdXMLGraphicObjectShapeContext* pShapeContext( + dynamic_cast<const SdXMLGraphicObjectShapeContext*>(pSelectedContext.get())); + if ( pShapeContext ) + { + assert( mxImplContext.is() ); + const uno::Reference< uno::XInterface > xShape( pShapeContext->getShape() ); + GetImport().getInterfaceToIdentifierMapper().registerReservedReference( maShapeId, xShape ); + } + + if( !mxImplContext.is() ) + { + // now check if this is an empty presentation object + for( auto& aIter : sax_fastparser::castToFastAttributeList(mxAttrList) ) + { + switch (aIter.getToken()) + { + case XML_ELEMENT(PRESENTATION, XML_PLACEHOLDER): + mbIsPlaceholder = IsXMLToken( aIter, XML_TRUE ); + break; + case XML_ELEMENT(PRESENTATION, XML_CLASS): + maPresentationClass = aIter.toString(); + break; + default:; + } + } + + if( (!maPresentationClass.isEmpty()) && mbIsPlaceholder ) + { + uno::Reference< xml::sax::XFastAttributeList> xEmpty; + + enum XMLTokenEnum eToken = XML_TEXT_BOX; + + if( IsXMLToken( maPresentationClass, XML_GRAPHIC ) ) + { + eToken = XML_IMAGE; + + } + else if( IsXMLToken( maPresentationClass, XML_PAGE ) ) + { + eToken = XML_PAGE_THUMBNAIL; + } + else if( IsXMLToken( maPresentationClass, XML_CHART ) || + IsXMLToken( maPresentationClass, XML_TABLE ) || + IsXMLToken( maPresentationClass, XML_OBJECT ) ) + { + eToken = XML_OBJECT; + } + + auto x = XML_ELEMENT(DRAW, eToken); + mxImplContext = XMLShapeImportHelper::CreateFrameChildContext( + GetImport(), x, mxAttrList, mxShapes, xEmpty ); + + if( mxImplContext.is() ) + { + mxImplContext->startFastElement( x, mxAttrList ); + mxImplContext->endFastElement(x); + } + } + } + + mxImplContext = nullptr; + SdXMLShapeContext::endFastElement(nElement); +} + +bool SdXMLFrameShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + bool bId( false ); + + switch ( aIter.getToken() ) + { + case XML_ELEMENT(DRAW, XML_ID): + case XML_ELEMENT(DRAW_EXT, XML_ID): + case XML_ELEMENT(NONE, XML_ID): + case XML_ELEMENT(XML, XML_ID) : + bId = true; + break; + default:; + } + + if ( bId ) + return SdXMLShapeContext::processAttribute( aIter ); + return true; // deliberately ignoring other attributes +} + + +SdXMLCustomShapeContext::SdXMLCustomShapeContext( + SvXMLImport& rImport, + const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, + uno::Reference< drawing::XShapes > const & rShapes) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false/*bTemporaryShape*/ ) +{ + // See the XMLTextFrameContext ctor, a frame has Writer content (and not + // editeng) if its autostyle has a parent style. Do the same for shapes as well. + for( auto& aIter : sax_fastparser::castToFastAttributeList(xAttrList) ) + { + if (aIter.getToken() == XML_ELEMENT(DRAW, XML_STYLE_NAME)) + { + OUString aStyleName = aIter.toString(); + if(!aStyleName.isEmpty()) + { + rtl::Reference<XMLTextImportHelper> xTxtImport = GetImport().GetTextImport(); + XMLPropStyleContext* pStyle = xTxtImport->FindAutoFrameStyle(aStyleName); + // Note that this an API name, so intentionally not localized. + // Also allow other Frame styles with the same prefix, we just want to reject + // Graphics after all. + if (pStyle && pStyle->GetParentName().startsWith("Frame")) + { + mbTextBox = true; + break; + } + } + } + } +} + +SdXMLCustomShapeContext::~SdXMLCustomShapeContext() +{ +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLCustomShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + if( aIter.getToken() == XML_ELEMENT(DRAW, XML_ENGINE) ) + { + maCustomShapeEngine = aIter.toString(); + } + else if (aIter.getToken() == XML_ELEMENT(DRAW, XML_DATA) ) + { + maCustomShapeData = aIter.toString(); + } + else + return SdXMLShapeContext::processAttribute( aIter ); + return true; +} + +void SdXMLCustomShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + // create rectangle shape + AddShape("com.sun.star.drawing.CustomShape"); + if ( !mxShape.is() ) + return; + + // Add, set Style and properties from base shape + SetStyle(); + SetLayer(); + + // set pos, size, shear and rotate + SetTransformation(); + + try + { + uno::Reference< beans::XPropertySet > xPropSet( mxShape, uno::UNO_QUERY ); + if( xPropSet.is() ) + { + if ( !maCustomShapeEngine.isEmpty() ) + { + xPropSet->setPropertyValue( EASGet( EAS_CustomShapeEngine ), Any(maCustomShapeEngine) ); + } + if ( !maCustomShapeData.isEmpty() ) + { + xPropSet->setPropertyValue( EASGet( EAS_CustomShapeData ), Any(maCustomShapeData) ); + } + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting enhanced customshape geometry" ); + } + SdXMLShapeContext::startFastElement(nElement, xAttrList); +} + +void SdXMLCustomShapeContext::endFastElement(sal_Int32 nElement) +{ + // Customshapes remember mirror state in its enhanced geometry. + // SetTransformation() in StartElement() may have applied mirroring, but that is not yet + // contained. Merge that information here before writing the property. + if(!maUsedTransformation.isIdentity()) + { + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + + maUsedTransformation.decompose(aScale, aTranslate, fRotate, fShearX); + + if (aScale.getX() < 0.0) + { + static constexpr OUString sName(u"MirroredX"_ustr); + //fdo#84043 Merge, if property exists, otherwise append it + auto aI = std::find_if(maCustomShapeGeometry.begin(), maCustomShapeGeometry.end(), + [](beans::PropertyValue& rValue) { return rValue.Name == sName; }); + if (aI != maCustomShapeGeometry.end()) + { + beans::PropertyValue& rItem = *aI; + bool bMirroredX = *o3tl::doAccess<bool>(rItem.Value); + rItem.Value <<= !bMirroredX; + rItem.Handle = -1; + rItem.State = beans::PropertyState_DIRECT_VALUE; + } + else + { + beans::PropertyValue* pItem; + maCustomShapeGeometry.emplace_back(); + pItem = &maCustomShapeGeometry.back(); + pItem->Name = sName; + pItem->Handle = -1; + pItem->Value <<= true; + pItem->State = beans::PropertyState_DIRECT_VALUE; + } + } + + if (aScale.getY() < 0.0) + { + static constexpr OUString sName(u"MirroredY"_ustr); + //fdo#84043 Merge, if property exists, otherwise append it + auto aI = std::find_if(maCustomShapeGeometry.begin(), maCustomShapeGeometry.end(), + [](beans::PropertyValue& rValue) { return rValue.Name == sName; }); + if (aI != maCustomShapeGeometry.end()) + { + beans::PropertyValue& rItem = *aI; + bool bMirroredY = *o3tl::doAccess<bool>(rItem.Value); + rItem.Value <<= !bMirroredY; + rItem.Handle = -1; + rItem.State = beans::PropertyState_DIRECT_VALUE; + } + else + { + beans::PropertyValue* pItem; + maCustomShapeGeometry.emplace_back(); + pItem = &maCustomShapeGeometry.back(); + pItem->Name = sName; + pItem->Handle = -1; + pItem->Value <<= true; + pItem->State = beans::PropertyState_DIRECT_VALUE; + } + } + } + + if ( !maCustomShapeGeometry.empty() ) + { + // converting the vector to a sequence + uno::Sequence< beans::PropertyValue > aSeq( comphelper::containerToSequence(maCustomShapeGeometry) ); + + try + { + uno::Reference< beans::XPropertySet > xPropSet( mxShape, uno::UNO_QUERY ); + if( xPropSet.is() ) + { + xPropSet->setPropertyValue( "CustomShapeGeometry", Any(aSeq) ); + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION( "xmloff", "setting enhanced customshape geometry" ); + } + + sal_Int32 nUPD; + sal_Int32 nBuild; + if (GetImport().getBuildIds(nUPD, nBuild)) + { + if( ((nUPD >= 640 && nUPD <= 645) || (nUPD == 680)) && (nBuild <= 9221) ) + { + Reference< drawing::XEnhancedCustomShapeDefaulter > xDefaulter( mxShape, UNO_QUERY ); + if( xDefaulter.is() ) + { + xDefaulter->createCustomShapeDefaults( "" ); + } + } + } + } + + SdXMLShapeContext::endFastElement(nElement); + + // tdf#98163 call a custom slot to be able to reset the UNO API + // implementations held on the SdrObjects of type + // SdrObjCustomShape - those tend to linger until the entire file + // is loaded. For large files with a lot of these, 32bit systems + // may crash due to being out of resources after ca. 4200 + // Outliners and VirtualDevices used there as RefDevice + try + { + uno::Reference< beans::XPropertySet > xPropSet(mxShape, uno::UNO_QUERY); + + if(xPropSet.is()) + { + xPropSet->setPropertyValue( + "FlushCustomShapeUnoApiObjects", css::uno::Any(true)); + } + } + catch(const uno::Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff", "flushing after load"); + } +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLCustomShapeContext::createFastChildContext( + sal_Int32 nElement, + const uno::Reference< xml::sax::XFastAttributeList>& xAttrList ) +{ + css::uno::Reference< css::xml::sax::XFastContextHandler > xContext; + if ( nElement == XML_ELEMENT(DRAW, XML_ENHANCED_GEOMETRY) ) + { + uno::Reference< beans::XPropertySet > xPropSet( mxShape,uno::UNO_QUERY ); + if ( xPropSet.is() ) + xContext = new XMLEnhancedCustomShapeContext( GetImport(), mxShape, maCustomShapeGeometry ); + } + // delegate to parent class if no context could be created + if (!xContext) + xContext = SdXMLShapeContext::createFastChildContext( nElement, + xAttrList); + return xContext; +} + +SdXMLTableShapeContext::SdXMLTableShapeContext( SvXMLImport& rImport, const css::uno::Reference< css::xml::sax::XFastAttributeList>& xAttrList, css::uno::Reference< css::drawing::XShapes > const & rShapes ) +: SdXMLShapeContext( rImport, xAttrList, rShapes, false ) +{ +} + +SdXMLTableShapeContext::~SdXMLTableShapeContext() +{ +} + +void SdXMLTableShapeContext::startFastElement (sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList) +{ + OUString service("com.sun.star.drawing.TableShape"); + + bool bIsPresShape = !maPresentationClass.isEmpty() && GetImport().GetShapeImport()->IsPresentationShapesSupported(); + if( bIsPresShape ) + { + if( IsXMLToken( maPresentationClass, XML_TABLE ) ) + { + service = "com.sun.star.presentation.TableShape"; + } + } + + AddShape(service); + + if( !mxShape.is() ) + return; + + SetLayer(); + + uno::Reference< beans::XPropertySet > xProps(mxShape, uno::UNO_QUERY); + + if(bIsPresShape && xProps.is()) + { + uno::Reference< beans::XPropertySetInfo > xPropsInfo( xProps->getPropertySetInfo() ); + if( xPropsInfo.is() ) + { + if( !mbIsPlaceholder && xPropsInfo->hasPropertyByName("IsEmptyPresentationObject")) + xProps->setPropertyValue("IsEmptyPresentationObject", css::uno::Any(false) ); + + if( mbIsUserTransformed && xPropsInfo->hasPropertyByName("IsPlaceholderDependent")) + xProps->setPropertyValue("IsPlaceholderDependent", css::uno::Any(false) ); + } + } + + SetStyle(); + + if( xProps.is() ) + { + if( !msTemplateStyleName.isEmpty() ) try + { + Reference< XStyleFamiliesSupplier > xFamiliesSupp( GetImport().GetModel(), UNO_QUERY_THROW ); + Reference< XNameAccess > xFamilies( xFamiliesSupp->getStyleFamilies() ); + Reference< XNameAccess > xTableFamily( xFamilies->getByName( "table" ), UNO_QUERY_THROW ); + Reference< XStyle > xTableStyle( xTableFamily->getByName( msTemplateStyleName ), UNO_QUERY_THROW ); + xProps->setPropertyValue("TableTemplate", Any( xTableStyle ) ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff.draw"); + } + + const XMLPropertyMapEntry* pEntry = &aXMLTableShapeAttributes[0]; + for( int i = 0; !pEntry->IsEnd() && (i < 6); i++, pEntry++ ) + { + try + { + xProps->setPropertyValue( pEntry->getApiName(), Any( maTemplateStylesUsed[i] ) ); + } + catch(const Exception&) + { + DBG_UNHANDLED_EXCEPTION("xmloff.draw"); + } + } + } + + GetImport().GetShapeImport()->finishShape( mxShape, mxAttrList, mxShapes ); + + const rtl::Reference< XMLTableImport >& xTableImport( GetImport().GetShapeImport()->GetShapeTableImport() ); + if( xTableImport.is() && xProps.is() ) + { + uno::Reference< table::XColumnRowRange > xColumnRowRange( + xProps->getPropertyValue("Model"), uno::UNO_QUERY ); + + if( xColumnRowRange.is() ) + mxTableImportContext = xTableImport->CreateTableContext( xColumnRowRange ); + + if( mxTableImportContext.is() ) + mxTableImportContext->startFastElement( nElement, xAttrList ); + } +} + +void SdXMLTableShapeContext::endFastElement(sal_Int32 nElement) +{ + if( mxTableImportContext.is() ) + mxTableImportContext->endFastElement(nElement); + + SdXMLShapeContext::endFastElement(nElement); + + if( mxShape.is() ) + { + // set pos, size, shear and rotate + SetTransformation(); + } +} + +// this is called from the parent group for each unparsed attribute in the attribute list +bool SdXMLTableShapeContext::processAttribute( const sax_fastparser::FastAttributeList::FastAttributeIter & aIter ) +{ + auto nElement = aIter.getToken(); + if( IsTokenInNamespace(nElement, XML_NAMESPACE_TABLE) ) + { + if( (nElement & TOKEN_MASK) == XML_TEMPLATE_NAME ) + { + msTemplateStyleName = aIter.toString(); + } + else + { + int i = 0; + const XMLPropertyMapEntry* pEntry = &aXMLTableShapeAttributes[0]; + while( !pEntry->IsEnd() && (i < 6) ) + { + if( (nElement & TOKEN_MASK) == pEntry->meXMLName ) + { + if( IsXMLToken( aIter, XML_TRUE ) ) + maTemplateStylesUsed[i] = true; + break; + } + pEntry++; + i++; + } + } + } + return SdXMLShapeContext::processAttribute( aIter ); +} + +css::uno::Reference< css::xml::sax::XFastContextHandler > SdXMLTableShapeContext::createFastChildContext( + sal_Int32 nElement, + const css::uno::Reference< css::xml::sax::XFastAttributeList >& xAttrList ) +{ + if( mxTableImportContext.is() && IsTokenInNamespace(nElement, XML_NAMESPACE_TABLE) ) + return mxTableImportContext->createFastChildContext(nElement, xAttrList); + return SdXMLShapeContext::createFastChildContext(nElement, xAttrList); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |