diff options
Diffstat (limited to 'oox/source/shape')
-rw-r--r-- | oox/source/shape/LockedCanvasContext.cxx | 97 | ||||
-rw-r--r-- | oox/source/shape/LockedCanvasContext.hxx | 37 | ||||
-rw-r--r-- | oox/source/shape/ShapeContextHandler.cxx | 584 | ||||
-rw-r--r-- | oox/source/shape/ShapeDrawingFragmentHandler.cxx | 48 | ||||
-rw-r--r-- | oox/source/shape/ShapeDrawingFragmentHandler.hxx | 35 | ||||
-rw-r--r-- | oox/source/shape/ShapeFilterBase.cxx | 137 | ||||
-rw-r--r-- | oox/source/shape/WpgContext.cxx | 99 | ||||
-rw-r--r-- | oox/source/shape/WpgContext.hxx | 43 | ||||
-rw-r--r-- | oox/source/shape/WpsContext.cxx | 338 | ||||
-rw-r--r-- | oox/source/shape/WpsContext.hxx | 45 |
10 files changed, 1463 insertions, 0 deletions
diff --git a/oox/source/shape/LockedCanvasContext.cxx b/oox/source/shape/LockedCanvasContext.cxx new file mode 100644 index 000000000..19267954c --- /dev/null +++ b/oox/source/shape/LockedCanvasContext.cxx @@ -0,0 +1,97 @@ +/* -*- 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/. + */ + +#include "LockedCanvasContext.hxx" +#include <sal/log.hxx> +#include <drawingml/shapepropertiescontext.hxx> +#include <oox/drawingml/connectorshapecontext.hxx> +#include <oox/drawingml/graphicshapecontext.hxx> +#include <oox/drawingml/shape.hxx> +#include <oox/drawingml/shapecontext.hxx> +#include <oox/drawingml/shapegroupcontext.hxx> +#include <oox/helper/attributelist.hxx> +#include <oox/token/namespaces.hxx> +#include <oox/token/tokens.hxx> + +using namespace com::sun::star; + +namespace oox::shape +{ +LockedCanvasContext::LockedCanvasContext(FragmentHandler2 const& rParent) + : FragmentHandler2(rParent) +{ + mpShapePtr = std::make_shared<oox::drawingml::Shape>("com.sun.star.drawing.GroupShape"); + mpShapePtr->setLockedCanvas(true); // will be "LockedCanvas" in InteropGrabBag +} + +LockedCanvasContext::~LockedCanvasContext() = default; + +::oox::core::ContextHandlerRef +LockedCanvasContext::onCreateContext(sal_Int32 nElementToken, const ::oox::AttributeList& rAttribs) +{ + switch (getBaseToken(nElementToken)) + { + case XML_nvGrpSpPr: // CT_GvmlGroupShapeNonVisual, child see at end + return this; + case XML_grpSpPr: // CT_GroupShapeProperties + return new oox::drawingml::ShapePropertiesContext(*this, *mpShapePtr); + case XML_txSp: // CT_GvmlTextShape + break; + case XML_sp: // CT_GvmlShape + { + return new oox::drawingml::ShapeContext( + *this, mpShapePtr, + std::make_shared<oox::drawingml::Shape>("com.sun.star.drawing.CustomShape", true)); + } + case XML_cxnSp: // CT_GvmlConnector + { + oox::drawingml::ShapePtr pShape + = std::make_shared<oox::drawingml::Shape>("com.sun.star.drawing.ConnectorShape"); + return new oox::drawingml::ConnectorShapeContext(*this, mpShapePtr, pShape, + pShape->getConnectorShapeProperties()); + } + case XML_pic: // CT_GvmlPicture + { + return new oox::drawingml::GraphicShapeContext( + *this, mpShapePtr, + std::make_shared<oox::drawingml::Shape>("com.sun.star.drawing.GraphicObjectShape")); + } + case XML_graphicFrame: // CT_GvmlGraphicObjectFrame + { + return new oox::drawingml::GraphicalObjectFrameContext( + *this, mpShapePtr, + std::make_shared<oox::drawingml::Shape>("com.sun.star.drawing.GraphicObjectShape"), + true); + } + case XML_grpSp: // CT_GvmlGroupShape + { + return new oox::drawingml::ShapeGroupContext( + *this, mpShapePtr, + std::make_shared<oox::drawingml::Shape>("com.sun.star.drawing.GroupShape")); + } + // mandatory child elements of CT_GvmlGroupShapeNonVisual + case XML_cNvPr: // CT_NonVisualDrawingProps + { + mpShapePtr->setHidden(rAttribs.getBool(XML_hidden, false)); + mpShapePtr->setId(rAttribs.getString(XML_id).get()); + mpShapePtr->setName(rAttribs.getString(XML_name).get()); + break; + } + case XML_cNvGrpSpPr: // CT_NonVisualGroupDrawingShapeProps + break; + default: + SAL_WARN("oox", "LockedCanvasContext::createFastChildContext: unhandled element:" + << getBaseToken(nElementToken)); + break; + } + return nullptr; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/shape/LockedCanvasContext.hxx b/oox/source/shape/LockedCanvasContext.hxx new file mode 100644 index 000000000..076931d09 --- /dev/null +++ b/oox/source/shape/LockedCanvasContext.hxx @@ -0,0 +1,37 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_OOX_SOURCE_SHAPE_LOCKEDCANVASCONTEXT_HXX +#define INCLUDED_OOX_SOURCE_SHAPE_LOCKEDCANVASCONTEXT_HXX + +#include <oox/core/fragmenthandler2.hxx> +#include <oox/drawingml/drawingmltypes.hxx> + +namespace oox::shape +{ +/// Locked canvas is kind of a container for drawingml shapes: it can even contain group shapes. +class LockedCanvasContext final : public oox::core::FragmentHandler2 +{ +public: + explicit LockedCanvasContext(oox::core::FragmentHandler2 const& rParent); + ~LockedCanvasContext() override; + + oox::core::ContextHandlerRef onCreateContext(sal_Int32 nElementToken, + const ::oox::AttributeList& rAttribs) override; + + const oox::drawingml::ShapePtr& getShape() const { return mpShapePtr; } + +private: + oox::drawingml::ShapePtr mpShapePtr; +}; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/shape/ShapeContextHandler.cxx b/oox/source/shape/ShapeContextHandler.cxx new file mode 100644 index 000000000..e88637fc4 --- /dev/null +++ b/oox/source/shape/ShapeContextHandler.cxx @@ -0,0 +1,584 @@ +/* -*- 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 <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/xml/dom/XDocument.hpp> +#include <com/sun/star/xml/sax/XFastSAXSerializable.hpp> + +#include <oox/shape/ShapeContextHandler.hxx> +#include "ShapeDrawingFragmentHandler.hxx" +#include "LockedCanvasContext.hxx" +#include "WpsContext.hxx" +#include "WpgContext.hxx" +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <oox/vml/vmldrawingfragment.hxx> +#include <oox/vml/vmlshape.hxx> +#include <oox/vml/vmlshapecontainer.hxx> +#include <oox/shape/ShapeFilterBase.hxx> +#include <oox/token/namespaces.hxx> +#include <oox/token/tokens.hxx> +#include <oox/drawingml/theme.hxx> +#include <oox/drawingml/themefragmenthandler.hxx> +#include <memory> + +using namespace ::com::sun::star; + +namespace oox::shape { +using namespace core; +using namespace drawingml; + +ShapeContextHandler::ShapeContextHandler(const rtl::Reference<ShapeFilterBase>& xFilterBase) : + m_bFullWPGSUpport(false), + mxShapeFilterBase(xFilterBase) + +{ +} + +ShapeContextHandler::~ShapeContextHandler() +{ +} + +uno::Reference<xml::sax::XFastContextHandler> const & ShapeContextHandler::getLockedCanvasContext(sal_Int32 nElement) +{ + if (!mxLockedCanvasContext.is()) + { + FragmentHandler2Ref rFragmentHandler(new ShapeFragmentHandler(*mxShapeFilterBase, msRelationFragmentPath)); + + switch (nElement & 0xffff) + { + case XML_lockedCanvas: + mxLockedCanvasContext.set(static_cast<oox::core::ContextHandler*>(new LockedCanvasContext(*rFragmentHandler))); + break; + default: + break; + } + } + + return mxLockedCanvasContext; +} + +/* + * This method creates new ChartGraphicDataContext Object. + */ +uno::Reference<xml::sax::XFastContextHandler> const & ShapeContextHandler::getChartShapeContext(sal_Int32 nElement) +{ + if (!mxChartShapeContext.is()) + { + switch (nElement & 0xffff) + { + case XML_chart: + { + std::unique_ptr<ContextHandler2Helper> pFragmentHandler( + new ShapeFragmentHandler(*mxShapeFilterBase, msRelationFragmentPath)); + mpShape = std::make_shared<Shape>("com.sun.star.drawing.OLE2Shape" ); + mxChartShapeContext.set(new ChartGraphicDataContext(*pFragmentHandler, mpShape, true)); + break; + } + default: + break; + } + } + + return mxChartShapeContext; +} + +uno::Reference<xml::sax::XFastContextHandler> const & ShapeContextHandler::getWpsContext(sal_Int32 nStartElement, sal_Int32 nElement) +{ + if (!mxWpsContext.is()) + { + FragmentHandler2Ref rFragmentHandler(new ShapeFragmentHandler(*mxShapeFilterBase, msRelationFragmentPath)); + ShapePtr pMasterShape; + + uno::Reference<drawing::XShape> xShape; + // No element happens in case of pretty-printed XML, bodyPr is the case when we are called again after <wps:txbx>. + if (!nElement || nElement == WPS_TOKEN(bodyPr)) + // Assume that this is just a continuation of the previous shape. + xShape = mxSavedShape; + + switch (getBaseToken(nStartElement)) + { + case XML_wsp: + mxWpsContext.set(new WpsContext( + *rFragmentHandler, + xShape, + pMasterShape, + std::make_shared<oox::drawingml::Shape>( + "com.sun.star.drawing.CustomShape"))); + break; + default: + break; + } + } + + return mxWpsContext; +} + +uno::Reference<xml::sax::XFastContextHandler> const & ShapeContextHandler::getWpgContext(sal_Int32 nElement) +{ + if (!mxWpgContext.is()) + { + FragmentHandler2Ref rFragmentHandler(new ShapeFragmentHandler(*mxShapeFilterBase, msRelationFragmentPath)); + + switch (getBaseToken(nElement)) + { + case XML_wgp: + { + rtl::Reference<WpgContext> rContext = new WpgContext(*rFragmentHandler, oox::drawingml::ShapePtr()); + rContext->setFullWPGSupport(m_bFullWPGSUpport); + mxWpgContext.set(static_cast<oox::core::ContextHandler*>(rContext.get())); + break; + } + default: + break; + } + } + + return mxWpgContext; +} + +uno::Reference<xml::sax::XFastContextHandler> const & +ShapeContextHandler::getGraphicShapeContext(::sal_Int32 Element ) +{ + if (! mxGraphicShapeContext.is()) + { + auto pFragmentHandler = std::make_shared<ShapeFragmentHandler>(*mxShapeFilterBase, msRelationFragmentPath); + ShapePtr pMasterShape; + + switch (Element & 0xffff) + { + case XML_graphic: + mpShape = std::make_shared<Shape>("com.sun.star.drawing.GraphicObjectShape" ); + mxGraphicShapeContext.set + (new GraphicalObjectFrameContext(*pFragmentHandler, pMasterShape, mpShape, true)); + break; + case XML_pic: + mpShape = std::make_shared<Shape>("com.sun.star.drawing.GraphicObjectShape" ); + mxGraphicShapeContext.set + (new GraphicShapeContext(*pFragmentHandler, pMasterShape, mpShape)); + break; + default: + break; + } + } + + return mxGraphicShapeContext; +} + +uno::Reference<xml::sax::XFastContextHandler> const & +ShapeContextHandler::getDrawingShapeContext() +{ + if (!mxDrawingFragmentHandler.is()) + { + mpDrawing = std::make_shared<oox::vml::Drawing>( *mxShapeFilterBase, mxDrawPage, oox::vml::VMLDRAWING_WORD ); + mxDrawingFragmentHandler.set + (static_cast<ContextHandler *> + (new oox::vml::DrawingFragment + ( *mxShapeFilterBase, msRelationFragmentPath, *mpDrawing ))); + } + else + { + // Reset the handler if fragment path has changed + OUString sHandlerFragmentPath = dynamic_cast<ContextHandler&>(*mxDrawingFragmentHandler).getFragmentPath(); + if ( msRelationFragmentPath != sHandlerFragmentPath ) + { + mxDrawingFragmentHandler.clear(); + mxDrawingFragmentHandler.set + (static_cast<ContextHandler *> + (new oox::vml::DrawingFragment + ( *mxShapeFilterBase, msRelationFragmentPath, *mpDrawing ))); + } + } + return mxDrawingFragmentHandler; +} + +uno::Reference<xml::sax::XFastContextHandler> const & +ShapeContextHandler::getDiagramShapeContext() +{ + if (!mxDiagramShapeContext.is()) + { + auto pFragmentHandler = std::make_shared<ShapeFragmentHandler>(*mxShapeFilterBase, msRelationFragmentPath); + mpShape = std::make_shared<Shape>(); + mxDiagramShapeContext.set(new DiagramGraphicDataContext(*pFragmentHandler, mpShape)); + } + + return mxDiagramShapeContext; +} + +uno::Reference<xml::sax::XFastContextHandler> +ShapeContextHandler::getContextHandler(sal_Int32 nElement) +{ + uno::Reference<xml::sax::XFastContextHandler> xResult; + const sal_uInt32 nStartToken = getStartToken(); + + switch (getNamespace( nStartToken )) + { + case NMSP_doc: + case NMSP_vml: + xResult.set(getDrawingShapeContext()); + break; + case NMSP_dmlDiagram: + xResult.set(getDiagramShapeContext()); + break; + case NMSP_dmlLockedCanvas: + xResult.set(getLockedCanvasContext(nStartToken)); + break; + case NMSP_dmlChart: + xResult.set(getChartShapeContext(nStartToken)); + break; + case NMSP_wps: + xResult.set(getWpsContext(nStartToken, nElement)); + break; + case NMSP_wpg: + xResult.set(getWpgContext(nStartToken)); + break; + default: + xResult.set(getGraphicShapeContext(nStartToken)); + break; + } + + return xResult; +} + +// css::xml::sax::XFastContextHandler: +void SAL_CALL ShapeContextHandler::startFastElement +(::sal_Int32 Element, + const uno::Reference< xml::sax::XFastAttributeList > & Attribs) +{ + mxShapeFilterBase->filter(maMediaDescriptor); + + if (Element == DGM_TOKEN(relIds) || Element == LC_TOKEN(lockedCanvas) || Element == C_TOKEN(chart) || + Element == WPS_TOKEN(wsp) || Element == WPG_TOKEN(wgp) || Element == OOX_TOKEN(dmlPicture, pic)) + { + // Parse the theme relation, if available; the diagram won't have colors without it. + if (!mpThemePtr && !msRelationFragmentPath.isEmpty()) + { + mpThemePtr = std::make_shared<Theme>(); + // Get Target for Type = "officeDocument" from _rels/.rels file + // aOfficeDocumentFragmentPath is pointing to "word/document.xml" for docx & to "ppt/presentation.xml" for pptx + FragmentHandlerRef rFragmentHandlerRef(new ShapeFragmentHandler(*mxShapeFilterBase, "/")); + OUString aOfficeDocumentFragmentPath = rFragmentHandlerRef->getFragmentPathFromFirstTypeFromOfficeDoc( u"officeDocument" ); + + // Get the theme DO NOT use msRelationFragmentPath for getting theme as for a document there is a single theme in document.xml.rels + // and the same is used by header and footer as well. + FragmentHandlerRef rFragmentHandler(new ShapeFragmentHandler(*mxShapeFilterBase, aOfficeDocumentFragmentPath)); + OUString aThemeFragmentPath = rFragmentHandler->getFragmentPathFromFirstTypeFromOfficeDoc( u"theme" ); + + if(!aThemeFragmentPath.isEmpty()) + { + uno::Reference<xml::sax::XFastSAXSerializable> xDoc(mxShapeFilterBase->importFragment(aThemeFragmentPath), uno::UNO_QUERY_THROW); + mxShapeFilterBase->importFragment(new ThemeFragmentHandler(*mxShapeFilterBase, aThemeFragmentPath, *mpThemePtr ), xDoc); + mxShapeFilterBase->setCurrentTheme(mpThemePtr); + } + } + + createFastChildContext(Element, Attribs); + } + + // Entering VML block (startFastElement() is called for the outermost tag), + // handle possible recursion. + if ( getContextHandler() == getDrawingShapeContext() ) + mpDrawing->getShapes().pushMark(); + + uno::Reference<XFastContextHandler> xContextHandler(getContextHandler()); + + if (xContextHandler.is()) + xContextHandler->startFastElement(Element, Attribs); +} + +void SAL_CALL ShapeContextHandler::startUnknownElement +(const OUString & Namespace, const OUString & Name, + const uno::Reference< xml::sax::XFastAttributeList > & Attribs) +{ + if ( getContextHandler() == getDrawingShapeContext() ) + mpDrawing->getShapes().pushMark(); + + uno::Reference<XFastContextHandler> xContextHandler(getContextHandler()); + + if (xContextHandler.is()) + xContextHandler->startUnknownElement(Namespace, Name, Attribs); +} + +void SAL_CALL ShapeContextHandler::endFastElement(::sal_Int32 Element) +{ + uno::Reference<XFastContextHandler> xContextHandler(getContextHandler()); + + if (xContextHandler.is()) + xContextHandler->endFastElement(Element); + // In case a textbox is sent, and later we get additional properties for + // the textbox, then the wps context is not cleared, so do that here. + if (Element != (NMSP_wps | XML_wsp)) + return; + + uno::Reference<lang::XServiceInfo> xServiceInfo(mxSavedShape, uno::UNO_QUERY); + bool bTextFrame = xServiceInfo.is() && xServiceInfo->supportsService("com.sun.star.text.TextFrame"); + bool bTextBox = false; + if (!bTextFrame) + { + uno::Reference<beans::XPropertySet> xPropertySet(mxSavedShape, uno::UNO_QUERY); + if (xPropertySet.is()) + xPropertySet->getPropertyValue("TextBox") >>= bTextBox; + } + if (bTextFrame || bTextBox) + mxWpsContext.clear(); + mxSavedShape.clear(); +} + +void SAL_CALL ShapeContextHandler::endUnknownElement +(const OUString & Namespace, + const OUString & Name) +{ + uno::Reference<XFastContextHandler> xContextHandler(getContextHandler()); + + if (xContextHandler.is()) + xContextHandler->endUnknownElement(Namespace, Name); +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL +ShapeContextHandler::createFastChildContext +(::sal_Int32 Element, + const uno::Reference< xml::sax::XFastAttributeList > & Attribs) +{ + uno::Reference< xml::sax::XFastContextHandler > xResult; + uno::Reference< xml::sax::XFastContextHandler > xContextHandler(getContextHandler(Element)); + + if (xContextHandler.is()) + xResult.set(xContextHandler->createFastChildContext + (Element, Attribs)); + + return xResult; +} + +uno::Reference< xml::sax::XFastContextHandler > SAL_CALL +ShapeContextHandler::createUnknownChildContext +(const OUString & Namespace, + const OUString & Name, + const uno::Reference< xml::sax::XFastAttributeList > & Attribs) +{ + uno::Reference<XFastContextHandler> xContextHandler(getContextHandler()); + + if (xContextHandler.is()) + return xContextHandler->createUnknownChildContext + (Namespace, Name, Attribs); + + return uno::Reference< xml::sax::XFastContextHandler >(); +} + +void SAL_CALL ShapeContextHandler::characters(const OUString & aChars) +{ + uno::Reference<XFastContextHandler> xContextHandler(getContextHandler()); + + if (xContextHandler.is()) + xContextHandler->characters(aChars); +} + +uno::Reference< drawing::XShape > +ShapeContextHandler::getShape() +{ + uno::Reference< drawing::XShape > xResult; + uno::Reference< drawing::XShapes > xShapes = mxDrawPage; + + if (mxShapeFilterBase && xShapes.is()) + { + if ( getContextHandler() == getDrawingShapeContext() ) + { + mpDrawing->finalizeFragmentImport(); + if( std::shared_ptr< vml::ShapeBase > pShape = mpDrawing->getShapes().takeLastShape() ) + xResult = pShape->convertAndInsert( xShapes ); + // Only now remove the recursion mark, because getShape() is called in writerfilter + // after endFastElement(). + mpDrawing->getShapes().popMark(); + } + else if (mxDiagramShapeContext.is()) + { + basegfx::B2DHomMatrix aMatrix; + if (mpShape->getExtDrawings().empty()) + { + mpShape->addShape( *mxShapeFilterBase, mpThemePtr.get(), xShapes, aMatrix, mpShape->getFillProperties() ); + xResult = mpShape->getXShape(); + } + else + { + // Prerendered diagram output is available, then use that, and throw away the original result. + for (auto const& extDrawing : mpShape->getExtDrawings()) + { + DiagramGraphicDataContext* pDiagramGraphicDataContext = dynamic_cast<DiagramGraphicDataContext*>(mxDiagramShapeContext.get()); + if (!pDiagramGraphicDataContext) + break; + OUString aFragmentPath(pDiagramGraphicDataContext->getFragmentPathFromRelId(extDrawing)); + oox::drawingml::ShapePtr pShapePtr = std::make_shared<Shape>( "com.sun.star.drawing.GroupShape" ); + pShapePtr->setDiagramType(); + mxShapeFilterBase->importFragment(new ShapeDrawingFragmentHandler(*mxShapeFilterBase, aFragmentPath, pShapePtr)); + pShapePtr->setDiagramDoms(mpShape->getDiagramDoms()); + pShapePtr->keepDiagramDrawing(*mxShapeFilterBase, aFragmentPath); + + // migrate IDiagramHelper to new oox::Shape (from mpShape which was loaded + // to pShapePtr where the geometry is now constructed) + mpShape->migrateDiagramHelperToNewShape(pShapePtr); + + if (!mpShape->getChildren().empty()) + { + // first child is diagram background - we want to keep it, as drawingML fallback doesn't contain it + auto& aChildren = pShapePtr->getChildren(); + ShapePtr pBackground = mpShape->getChildren().front(); + aChildren.insert(aChildren.begin(), pBackground); + } + + pShapePtr->addShape( *mxShapeFilterBase, mpThemePtr.get(), xShapes, aMatrix, pShapePtr->getFillProperties() ); + xResult = pShapePtr->getXShape(); + } + mpShape.reset(); + } + mxDiagramShapeContext.clear(); + } + else if (mxLockedCanvasContext.is()) + { + ShapePtr pShape = dynamic_cast<LockedCanvasContext&>(*mxLockedCanvasContext).getShape(); + if (pShape) + { + basegfx::B2DHomMatrix aMatrix; + pShape->addShape(*mxShapeFilterBase, mpThemePtr.get(), xShapes, aMatrix, pShape->getFillProperties()); + xResult = pShape->getXShape(); + mxLockedCanvasContext.clear(); + } + } + //NMSP_dmlChart == getNamespace( mnStartToken ) check is introduced to make sure that + //mnStartToken is set as NMSP_dmlChart in setStartToken. + //Only in case it is set then only the below block of code for ChartShapeContext should be executed. + else if (mxChartShapeContext.is() && (NMSP_dmlChart == getNamespace( getStartToken() ))) + { + ChartGraphicDataContext* pChartGraphicDataContext = dynamic_cast<ChartGraphicDataContext*>(mxChartShapeContext.get()); + if (pChartGraphicDataContext) + { + basegfx::B2DHomMatrix aMatrix; + oox::drawingml::ShapePtr xShapePtr( pChartGraphicDataContext->getShape()); + // See SwXTextDocument::createInstance(), ODF import uses the same hack. + xShapePtr->setServiceName("com.sun.star.drawing.temporaryForXMLImportOLE2Shape"); + xShapePtr->addShape( *mxShapeFilterBase, mpThemePtr.get(), xShapes, aMatrix, xShapePtr->getFillProperties() ); + xResult = xShapePtr->getXShape(); + } + mxChartShapeContext.clear(); + } + else if (mxWpsContext.is()) + { + ShapePtr pShape = dynamic_cast<WpsContext&>(*mxWpsContext).getShape(); + if (pShape) + { + basegfx::B2DHomMatrix aMatrix; + pShape->setPosition(maPosition); + pShape->addShape(*mxShapeFilterBase, mpThemePtr.get(), xShapes, aMatrix, pShape->getFillProperties()); + xResult = pShape->getXShape(); + mxSavedShape = xResult; + mxWpsContext.clear(); + } + } + else if (mxWpgContext.is()) + { + ShapePtr pShape = dynamic_cast<WpgContext&>(*mxWpgContext).getShape(); + if (pShape) + { + basegfx::B2DHomMatrix aMatrix; + pShape->setPosition(maPosition); + pShape->addShape(*mxShapeFilterBase, mpThemePtr.get(), xShapes, aMatrix, pShape->getFillProperties()); + xResult = pShape->getXShape(); + mxSavedShape = xResult; + mxWpgContext.clear(); + } + } + else if (mpShape) + { + basegfx::B2DHomMatrix aTransformation; + + if (maPosition.X != 0 || maPosition.Y != 0) + { + // We got a position from writerfilter/, store that in the shape, otherwise the + // position won't be set. + mpShape->setWps(true); + mpShape->setPosition(maPosition); + } + + mpShape->addShape(*mxShapeFilterBase, mpThemePtr.get(), xShapes, aTransformation, mpShape->getFillProperties() ); + xResult.set(mpShape->getXShape()); + mxGraphicShapeContext.clear( ); + } + } + + if (xResult) + popStartToken(); + return xResult; +} + +void ShapeContextHandler::setDrawPage(const css::uno::Reference< css::drawing::XDrawPage > & the_value) +{ + mxDrawPage = the_value; +} + +void ShapeContextHandler::setModel(const css::uno::Reference< css::frame::XModel > & the_value) +{ + if( !mxShapeFilterBase.is() ) + throw uno::RuntimeException(); + uno::Reference<lang::XComponent> xComp(the_value, uno::UNO_QUERY_THROW); + mxShapeFilterBase->setTargetDocument(xComp); +} + +void ShapeContextHandler::setRelationFragmentPath(const OUString & the_value) +{ + msRelationFragmentPath = the_value; +} + +sal_Int32 ShapeContextHandler::getStartToken() const +{ + assert(mnStartTokenStack.size() && "This stack must not be empty!"); + return mnStartTokenStack.top(); +} + +void ShapeContextHandler::popStartToken() +{ + if (mnStartTokenStack.size() > 1) + mnStartTokenStack.pop(); +} + +void ShapeContextHandler::pushStartToken( sal_Int32 _starttoken ) +{ + mnStartTokenStack.push(_starttoken); +} + +void ShapeContextHandler::setPosition(const awt::Point& rPosition) +{ + maPosition = rPosition; +} + +void ShapeContextHandler::setDocumentProperties(const uno::Reference<document::XDocumentProperties>& xDocProps) +{ + mxDocumentProperties = xDocProps; + mxShapeFilterBase->checkDocumentProperties(mxDocumentProperties); +} + +void ShapeContextHandler::setMediaDescriptor(const uno::Sequence<beans::PropertyValue>& rMediaDescriptor) +{ + maMediaDescriptor = rMediaDescriptor; +} + +void ShapeContextHandler::setGraphicMapper(css::uno::Reference<css::graphic::XGraphicMapper> const & rxGraphicMapper) +{ + mxShapeFilterBase->setGraphicMapper(rxGraphicMapper); +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/shape/ShapeDrawingFragmentHandler.cxx b/oox/source/shape/ShapeDrawingFragmentHandler.cxx new file mode 100644 index 000000000..aafe004fa --- /dev/null +++ b/oox/source/shape/ShapeDrawingFragmentHandler.cxx @@ -0,0 +1,48 @@ +/* -*- 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/. + */ + +#include "ShapeDrawingFragmentHandler.hxx" + +#include <oox/drawingml/shapegroupcontext.hxx> +#include <oox/token/namespaces.hxx> + +using namespace com::sun::star; + +namespace oox::shape { + +ShapeDrawingFragmentHandler::ShapeDrawingFragmentHandler(oox::core::XmlFilterBase& rFilter, const OUString& rFragmentPath, oox::drawingml::ShapePtr const & pGroupShapePtr) + : FragmentHandler2(rFilter, rFragmentPath) + , mpGroupShapePtr(pGroupShapePtr) +{ +} + +ShapeDrawingFragmentHandler::~ShapeDrawingFragmentHandler() noexcept +{ +} + +void SAL_CALL ShapeDrawingFragmentHandler::endDocument() +{ +} + +::oox::core::ContextHandlerRef ShapeDrawingFragmentHandler::onCreateContext(sal_Int32 Element, const AttributeList& /*Attribs*/ ) +{ + switch( Element ) + { + case DSP_TOKEN( spTree ): + return new oox::drawingml::ShapeGroupContext(*this, oox::drawingml::ShapePtr(nullptr), mpGroupShapePtr); + default: + break; + } + + return this; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/shape/ShapeDrawingFragmentHandler.hxx b/oox/source/shape/ShapeDrawingFragmentHandler.hxx new file mode 100644 index 000000000..68b27f949 --- /dev/null +++ b/oox/source/shape/ShapeDrawingFragmentHandler.hxx @@ -0,0 +1,35 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_OOX_SOURCE_SHAPE_SHAPEDRAWINGFRAGMENTHANDLER_HXX +#define INCLUDED_OOX_SOURCE_SHAPE_SHAPEDRAWINGFRAGMENTHANDLER_HXX + +#include <oox/core/fragmenthandler2.hxx> +#include <oox/drawingml/drawingmltypes.hxx> + +namespace oox::shape { + +/// Generic (i.e. not specific to PPTX) handler for the prerendered diagram parsing. +class ShapeDrawingFragmentHandler : public oox::core::FragmentHandler2 +{ +public: + ShapeDrawingFragmentHandler(oox::core::XmlFilterBase& rFilter, const OUString& rFragmentPath, oox::drawingml::ShapePtr const & pGroupShapePtr); + virtual ~ShapeDrawingFragmentHandler() noexcept override; + virtual void SAL_CALL endDocument() override; + virtual ::oox::core::ContextHandlerRef onCreateContext(sal_Int32 Element, const AttributeList& rAttribs ) override; + +private: + oox::drawingml::ShapePtr mpGroupShapePtr; +}; + +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/shape/ShapeFilterBase.cxx b/oox/source/shape/ShapeFilterBase.cxx new file mode 100644 index 000000000..ad10c4fe6 --- /dev/null +++ b/oox/source/shape/ShapeFilterBase.cxx @@ -0,0 +1,137 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <config_wasm_strip.h> + +#include <oox/shape/ShapeFilterBase.hxx> +#include <oox/drawingml/chart/chartconverter.hxx> +#include <oox/drawingml/themefragmenthandler.hxx> +#include <oox/helper/graphichelper.hxx> +#include <oox/ole/vbaproject.hxx> +#include <oox/drawingml/theme.hxx> + +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/frame/XModel.hpp> +#include <com/sun/star/xml/sax/XFastSAXSerializable.hpp> + +namespace oox::shape { + +using namespace ::com::sun::star; + +ShapeFilterBase::ShapeFilterBase( const uno::Reference< uno::XComponentContext >& rxContext ) : + XmlFilterBase( rxContext ), +#if ENABLE_WASM_STRIP_CHART + // WASM_CHART change + mxChartConv( ) +#else + mxChartConv( std::make_shared<::oox::drawingml::chart::ChartConverter>() ) +#endif +{ +} + +ShapeFilterBase::~ShapeFilterBase() +{ +} + +const ::oox::drawingml::Theme* ShapeFilterBase::getCurrentTheme() const +{ + return mpTheme.get(); +} + +std::shared_ptr<::oox::drawingml::Theme> ShapeFilterBase::getCurrentThemePtr() const +{ + return mpTheme; +} + +void ShapeFilterBase::setCurrentTheme(const ::oox::drawingml::ThemePtr& pTheme) +{ + mpTheme = pTheme; +} + +::oox::vml::Drawing* ShapeFilterBase::getVmlDrawing() +{ + return nullptr; +} + +::oox::drawingml::table::TableStyleListPtr ShapeFilterBase::getTableStyles() +{ + return ::oox::drawingml::table::TableStyleListPtr(); +} + +::oox::drawingml::chart::ChartConverter* ShapeFilterBase::getChartConverter() +{ + return mxChartConv.get(); +} + +::oox::ole::VbaProject* ShapeFilterBase::implCreateVbaProject() const +{ + return new ::oox::ole::VbaProject( getComponentContext(), getModel(), u"Writer" ); +} + +OUString ShapeFilterBase::getImplementationName() +{ + return OUString(); +} + +namespace { + +/// Graphic helper for shapes, that can manage color schemes. +class ShapeGraphicHelper : public GraphicHelper +{ +public: + explicit ShapeGraphicHelper( const ShapeFilterBase& rFilter ); + virtual ::Color getSchemeColor( sal_Int32 nToken ) const override; +private: + const ShapeFilterBase& mrFilter; +}; + +} + +ShapeGraphicHelper::ShapeGraphicHelper( const ShapeFilterBase& rFilter ) : + GraphicHelper( rFilter.getComponentContext(), rFilter.getTargetFrame(), rFilter.getStorage() ), + mrFilter( rFilter ) +{ +} + +::Color ShapeGraphicHelper::getSchemeColor( sal_Int32 nToken ) const +{ + return mrFilter.getSchemeColor( nToken ); +} + +GraphicHelper* ShapeFilterBase::implCreateGraphicHelper() const +{ + GraphicHelper* pGraphicHelper = new ShapeGraphicHelper(*this); + if (mxGraphicMapper.is()) + pGraphicHelper->setGraphicMapper(mxGraphicMapper); + return pGraphicHelper; +} + +::Color ShapeFilterBase::getSchemeColor( sal_Int32 nToken ) const +{ + ::Color nColor; + + if (mpTheme) + mpTheme->getClrScheme().getColor( nToken, nColor ); + + return nColor; +} + +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/shape/WpgContext.cxx b/oox/source/shape/WpgContext.cxx new file mode 100644 index 000000000..cf65491e0 --- /dev/null +++ b/oox/source/shape/WpgContext.cxx @@ -0,0 +1,99 @@ +/* -*- 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/. + */ + +#include "WpgContext.hxx" +#include "WpsContext.hxx" +#include <sal/log.hxx> +#include <drawingml/shapepropertiescontext.hxx> +#include <oox/drawingml/shapegroupcontext.hxx> +#include <oox/drawingml/graphicshapecontext.hxx> +#include <oox/token/namespaces.hxx> +#include <oox/token/tokens.hxx> + +using namespace com::sun::star; + +namespace oox::shape +{ +WpgContext::WpgContext(FragmentHandler2 const& rParent, oox::drawingml::ShapePtr pMaster) + : FragmentHandler2(rParent) + , m_bFullWPGSupport(false) +{ + mpShape = std::make_shared<oox::drawingml::Shape>("com.sun.star.drawing.GroupShape"); + mpShape->setWps(true); + if (pMaster) + pMaster->addChild(mpShape); +} + +WpgContext::~WpgContext() = default; + +oox::core::ContextHandlerRef WpgContext::onCreateContext(sal_Int32 nElementToken, + const oox::AttributeList& /*rAttribs*/) +{ + switch (getBaseToken(nElementToken)) + { + case XML_wgp: + case XML_cNvGrpSpPr: + case XML_grpSpPr: + return new oox::drawingml::ShapePropertiesContext(*this, *mpShape); + case XML_wsp: + { + if (m_bFullWPGSupport) + { + oox::drawingml::ShapePtr pShape = std::make_shared<oox::drawingml::Shape>( + "com.sun.star.drawing.CustomShape", /*bDefaultHeight=*/false); + return new oox::shape::WpsContext(*this, uno::Reference<drawing::XShape>(), mpShape, + pShape); + } + else + { + // Don't set default character height, Writer has its own way to set + // the default, and if we don't set it here, editeng properly inherits + // it. + oox::drawingml::ShapePtr pShape = std::make_shared<oox::drawingml::Shape>( + "com.sun.star.drawing.CustomShape", /*bDefaultHeight=*/false); + return new oox::drawingml::ShapeContext(*this, mpShape, pShape); + } + } + case XML_pic: + return new oox::drawingml::GraphicShapeContext( + *this, mpShape, + std::make_shared<oox::drawingml::Shape>("com.sun.star.drawing.GraphicObjectShape")); + case XML_grpSp: + { + if (m_bFullWPGSupport) + { + rtl::Reference<WpgContext> pWPGShape = new oox::shape::WpgContext(*this, mpShape); + pWPGShape->setFullWPGSupport(m_bFullWPGSupport); + return pWPGShape; + } + else + { + return new oox::drawingml::ShapeGroupContext( + *this, mpShape, + std::make_shared<oox::drawingml::Shape>("com.sun.star.drawing.GroupShape")); + } + } + case XML_graphicFrame: + { + auto pShape = std::make_shared<oox::drawingml::Shape>( + "com.sun.star.drawing.GraphicObjectShape"); + pShape->setWps(true); + return new oox::drawingml::GraphicalObjectFrameContext(*this, mpShape, pShape, + /*bEmbedShapesInChart=*/true); + } + default: + SAL_WARN("oox", "WpgContext::createFastChildContext: unhandled element: " + << getBaseToken(nElementToken)); + break; + } + return nullptr; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/shape/WpgContext.hxx b/oox/source/shape/WpgContext.hxx new file mode 100644 index 000000000..643a2a493 --- /dev/null +++ b/oox/source/shape/WpgContext.hxx @@ -0,0 +1,43 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_OOX_SOURCE_SHAPE_WPGCONTEXT_HXX +#define INCLUDED_OOX_SOURCE_SHAPE_WPGCONTEXT_HXX + +#include <oox/core/fragmenthandler2.hxx> +#include <oox/drawingml/drawingmltypes.hxx> + +namespace oox::shape +{ +/// Wpg is the drawingML equivalent of v:group. +class WpgContext final : public oox::core::FragmentHandler2 +{ +public: + explicit WpgContext(oox::core::FragmentHandler2 const& rParent, + oox::drawingml::ShapePtr pMaster); + ~WpgContext() override; + + oox::core::ContextHandlerRef onCreateContext(sal_Int32 nElementToken, + const oox::AttributeList& rAttribs) override; + + const oox::drawingml::ShapePtr& getShape() const { return mpShape; } + + const bool& isFullWPGSupport() const { return m_bFullWPGSupport; }; + void setFullWPGSupport(bool bUse) { m_bFullWPGSupport = bUse; }; + +private: + oox::drawingml::ShapePtr mpShape; + + bool m_bFullWPGSupport; +}; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/shape/WpsContext.cxx b/oox/source/shape/WpsContext.cxx new file mode 100644 index 000000000..176ad569e --- /dev/null +++ b/oox/source/shape/WpsContext.cxx @@ -0,0 +1,338 @@ +/* -*- 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/. + */ + +#include "WpsContext.hxx" +#include "WpgContext.hxx" +#include <basegfx/matrix/b2dhommatrix.hxx> +#include <basegfx/tuple/b2dtuple.hxx> +#include <comphelper/sequenceashashmap.hxx> +#include <drawingml/customshapeproperties.hxx> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertyState.hpp> +#include <com/sun/star/container/XEnumerationAccess.hpp> +#include <com/sun/star/drawing/HomogenMatrix3.hpp> +#include <com/sun/star/lang/XServiceInfo.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/text/XTextCursor.hpp> +#include <com/sun/star/text/WritingMode.hpp> +#include <svx/svdtrans.hxx> +#include <oox/helper/attributelist.hxx> +#include <oox/token/namespaces.hxx> +#include <oox/token/tokens.hxx> +#include <oox/drawingml/shape.hxx> +#include <oox/drawingml/drawingmltypes.hxx> +#include <drawingml/textbody.hxx> +#include <drawingml/textbodyproperties.hxx> + +#include <optional> + +using namespace com::sun::star; + +namespace oox::shape +{ +WpsContext::WpsContext(ContextHandler2Helper const& rParent, uno::Reference<drawing::XShape> xShape, + const drawingml::ShapePtr& pMasterShapePtr, + const drawingml::ShapePtr& pShapePtr) + : ShapeContext(rParent, pMasterShapePtr, pShapePtr) + , mxShape(std::move(xShape)) +{ + if (mpShapePtr) + mpShapePtr->setWps(true); + + if (const auto pParent = dynamic_cast<const WpgContext*>(&rParent)) + m_bHasWPGParent = pParent->isFullWPGSupport(); + else + m_bHasWPGParent = false; +} + +WpsContext::~WpsContext() = default; + +oox::core::ContextHandlerRef WpsContext::onCreateContext(sal_Int32 nElementToken, + const oox::AttributeList& rAttribs) +{ + switch (getBaseToken(nElementToken)) + { + case XML_wsp: + case XML_cNvCnPr: + break; + case XML_bodyPr: + if (mxShape.is()) + { + uno::Reference<lang::XServiceInfo> xServiceInfo(mxShape, uno::UNO_QUERY); + uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY); + sal_Int32 nVert = rAttribs.getToken(XML_vert, XML_horz); + if (nVert == XML_eaVert) + { + xPropertySet->setPropertyValue("TextWritingMode", + uno::Any(text::WritingMode_TB_RL)); + } + else if (nVert != XML_horz) + { + // Get the existing rotation of the shape. + drawing::HomogenMatrix3 aMatrix; + xPropertySet->getPropertyValue("Transformation") >>= aMatrix; + basegfx::B2DHomMatrix aTransformation; + aTransformation.set(0, 0, aMatrix.Line1.Column1); + aTransformation.set(0, 1, aMatrix.Line1.Column2); + aTransformation.set(0, 2, aMatrix.Line1.Column3); + aTransformation.set(1, 0, aMatrix.Line1.Column1); + aTransformation.set(1, 1, aMatrix.Line2.Column2); + aTransformation.set(1, 2, aMatrix.Line3.Column3); + aTransformation.set(2, 0, aMatrix.Line1.Column1); + aTransformation.set(2, 1, aMatrix.Line2.Column2); + aTransformation.set(2, 2, aMatrix.Line3.Column3); + basegfx::B2DTuple aScale; + basegfx::B2DTuple aTranslate; + double fRotate = 0; + double fShearX = 0; + aTransformation.decompose(aScale, aTranslate, fRotate, fShearX); + + // If the text is not rotated the way the shape wants it already, set the angle. + const sal_Int32 nRotation = nVert == XML_vert270 ? -270 : -90; + if (static_cast<sal_Int32>(basegfx::rad2deg(fRotate)) + != NormAngle36000(Degree100(nRotation * 100)).get() / 100) + { + comphelper::SequenceAsHashMap aCustomShapeGeometry( + xPropertySet->getPropertyValue("CustomShapeGeometry")); + aCustomShapeGeometry["TextPreRotateAngle"] <<= nRotation; + xPropertySet->setPropertyValue( + "CustomShapeGeometry", + uno::Any(aCustomShapeGeometry.getAsConstPropertyValueList())); + } + } + + if (bool bUpright = rAttribs.getBool(XML_upright, false)) + { + uno::Sequence<beans::PropertyValue> aGrabBag; + xPropertySet->getPropertyValue("InteropGrabBag") >>= aGrabBag; + sal_Int32 length = aGrabBag.getLength(); + aGrabBag.realloc(length + 1); + auto pGrabBag = aGrabBag.getArray(); + pGrabBag[length].Name = "Upright"; + pGrabBag[length].Value <<= bUpright; + xPropertySet->setPropertyValue("InteropGrabBag", uno::Any(aGrabBag)); + } + + if (xServiceInfo.is()) + { + // Handle inset attributes for Writer textframes. + sal_Int32 aInsets[] = { XML_lIns, XML_tIns, XML_rIns, XML_bIns }; + std::optional<sal_Int32> oInsets[4]; + for (std::size_t i = 0; i < SAL_N_ELEMENTS(aInsets); ++i) + { + OptValue<OUString> oValue = rAttribs.getString(aInsets[i]); + if (oValue.has()) + oInsets[i] = oox::drawingml::GetCoordinate(oValue.get()); + else + // Defaults from the spec: left/right: 91440 EMU, top/bottom: 45720 EMU + oInsets[i] + = (aInsets[i] == XML_lIns || aInsets[i] == XML_rIns) ? 254 : 127; + } + const OUString aShapeProps[] + = { OUString("TextLeftDistance"), OUString("TextUpperDistance"), + OUString("TextRightDistance"), OUString("TextLowerDistance") }; + for (std::size_t i = 0; i < SAL_N_ELEMENTS(aShapeProps); ++i) + if (oInsets[i]) + xPropertySet->setPropertyValue(aShapeProps[i], uno::Any(*oInsets[i])); + } + + // Handle text vertical adjustment inside a text frame + if (rAttribs.hasAttribute(XML_anchor)) + { + drawing::TextVerticalAdjust eAdjust + = drawingml::GetTextVerticalAdjust(rAttribs.getToken(XML_anchor, XML_t)); + xPropertySet->setPropertyValue("TextVerticalAdjust", uno::Any(eAdjust)); + } + + // Apply character color of the shape to the shape's textbox. + uno::Reference<text::XText> xText(mxShape, uno::UNO_QUERY); + uno::Reference<text::XTextCursor> xTextCursor = xText->createTextCursor(); + xTextCursor->gotoStart(false); + xTextCursor->gotoEnd(true); + uno::Reference<beans::XPropertySet> xTextBoxPropertySet(xTextCursor, + uno::UNO_QUERY); + uno::Any xCharColor = xPropertySet->getPropertyValue("CharColor"); + Color aColor = COL_AUTO; + if ((xCharColor >>= aColor) && aColor != COL_AUTO) + { + const uno::Reference<beans::XPropertyState> xPropertyState(xTextCursor, + uno::UNO_QUERY); + const beans::PropertyState ePropertyState + = xPropertyState->getPropertyState("CharColor"); + if (ePropertyState == beans::PropertyState_DEFAULT_VALUE) + { + xTextBoxPropertySet->setPropertyValue("CharColor", xCharColor); + } + else + { + // tdf#135923 Apply character color of the shape to the textrun + // when the character color of the textrun is default. + uno::Reference<container::XEnumerationAccess> paraEnumAccess( + xText, uno::UNO_QUERY); + if (paraEnumAccess.is()) + { + uno::Reference<container::XEnumeration> paraEnum( + paraEnumAccess->createEnumeration()); + + while (paraEnum->hasMoreElements()) + { + uno::Reference<text::XTextRange> xParagraph(paraEnum->nextElement(), + uno::UNO_QUERY); + uno::Reference<container::XEnumerationAccess> runEnumAccess( + xParagraph, uno::UNO_QUERY); + if (!runEnumAccess.is()) + continue; + + uno::Reference<container::XEnumeration> runEnum + = runEnumAccess->createEnumeration(); + + while (runEnum->hasMoreElements()) + { + uno::Reference<text::XTextRange> xRun(runEnum->nextElement(), + uno::UNO_QUERY); + const uno::Reference<beans::XPropertyState> xRunState( + xRun, uno::UNO_QUERY); + if (xRunState->getPropertyState("CharColor") + == beans::PropertyState_DEFAULT_VALUE) + { + uno::Reference<beans::XPropertySet> xRunPropSet( + xRun, uno::UNO_QUERY); + xRunPropSet->setPropertyValue("CharColor", xCharColor); + } + } + } + } + } + } + + auto nWrappingType = rAttribs.getToken(XML_wrap, XML_square); + xPropertySet->setPropertyValue("TextWordWrap", + uno::Any(nWrappingType == XML_square)); + + return this; + } + else if (m_bHasWPGParent && mpShapePtr) + { + // this WPS context has to be inside a WPG shape, so the <BodyPr> element + // cannot be applied to mxShape member, use mpShape instead, and after the + // the parent shape finished, apply it for its children. + mpShapePtr->setWPGChild(true); + oox::drawingml::TextBodyPtr pTextBody; + pTextBody.reset(new oox::drawingml::TextBody()); + + if (rAttribs.hasAttribute(XML_anchor)) + { + drawing::TextVerticalAdjust eAdjust + = drawingml::GetTextVerticalAdjust(rAttribs.getToken(XML_anchor, XML_t)); + pTextBody->getTextProperties().meVA = eAdjust; + } + + sal_Int32 aInsets[] = { XML_lIns, XML_tIns, XML_rIns, XML_bIns }; + for (int i = 0; i < 4; ++i) + { + if (rAttribs.hasAttribute(XML_lIns)) + { + OptValue<OUString> oValue = rAttribs.getString(aInsets[i]); + if (oValue.has()) + pTextBody->getTextProperties().moInsets[i] + = oox::drawingml::GetCoordinate(oValue.get()); + else + // Defaults from the spec: left/right: 91440 EMU, top/bottom: 45720 EMU + pTextBody->getTextProperties().moInsets[i] + = (aInsets[i] == XML_lIns || aInsets[i] == XML_rIns) ? 254 : 127; + } + } + + mpShapePtr->setTextBody(pTextBody); + } + break; + case XML_noAutofit: + case XML_spAutoFit: + { + uno::Reference<lang::XServiceInfo> xServiceInfo(mxShape, uno::UNO_QUERY); + // We can't use oox::drawingml::TextBodyPropertiesContext here, as this + // is a child context of bodyPr, so the shape is already sent: we need + // to alter the XShape directly. + uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY); + if (xPropertySet.is()) + { + if (xServiceInfo->supportsService("com.sun.star.text.TextFrame")) + xPropertySet->setPropertyValue( + "FrameIsAutomaticHeight", + uno::Any(getBaseToken(nElementToken) == XML_spAutoFit)); + else + xPropertySet->setPropertyValue( + "TextAutoGrowHeight", + uno::Any(getBaseToken(nElementToken) == XML_spAutoFit)); + } + } + break; + case XML_prstTxWarp: + if (rAttribs.hasAttribute(XML_prst)) + { + uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY); + if (xPropertySet.is()) + { + oox::OptValue<OUString> presetShapeName = rAttribs.getString(XML_prst); + const OUString& preset = presetShapeName.get(); + comphelper::SequenceAsHashMap aCustomShapeGeometry( + xPropertySet->getPropertyValue("CustomShapeGeometry")); + aCustomShapeGeometry["PresetTextWarp"] <<= preset; + xPropertySet->setPropertyValue( + "CustomShapeGeometry", + uno::Any(aCustomShapeGeometry.getAsConstPropertyValueList())); + } + } + break; + case XML_txbx: + { + mpShapePtr->getCustomShapeProperties()->setShapeTypeOverride(true); + mpShapePtr->setTextBox(true); + //in case if the textbox is linked, save the attributes + //for further processing. + if (rAttribs.hasAttribute(XML_id)) + { + OptValue<OUString> id = rAttribs.getString(XML_id); + if (id.has()) + { + oox::drawingml::LinkedTxbxAttr linkedTxtBoxAttr; + linkedTxtBoxAttr.id = id.get().toInt32(); + mpShapePtr->setTxbxHasLinkedTxtBox(true); + mpShapePtr->setLinkedTxbxAttributes(linkedTxtBoxAttr); + } + } + return this; + } + break; + case XML_linkedTxbx: + { + //in case if the textbox is linked, save the attributes + //for further processing. + mpShapePtr->getCustomShapeProperties()->setShapeTypeOverride(true); + mpShapePtr->setTextBox(true); + OptValue<OUString> id = rAttribs.getString(XML_id); + OptValue<OUString> seq = rAttribs.getString(XML_seq); + if (id.has() && seq.has()) + { + oox::drawingml::LinkedTxbxAttr linkedTxtBoxAttr; + linkedTxtBoxAttr.id = id.get().toInt32(); + linkedTxtBoxAttr.seq = seq.get().toInt32(); + mpShapePtr->setTxbxHasLinkedTxtBox(true); + mpShapePtr->setLinkedTxbxAttributes(linkedTxtBoxAttr); + } + } + break; + default: + return ShapeContext::onCreateContext(nElementToken, rAttribs); + } + return nullptr; +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/shape/WpsContext.hxx b/oox/source/shape/WpsContext.hxx new file mode 100644 index 000000000..29110b6fb --- /dev/null +++ b/oox/source/shape/WpsContext.hxx @@ -0,0 +1,45 @@ +/* -*- 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/. + */ + +#ifndef INCLUDED_OOX_SOURCE_SHAPE_WPSCONTEXT_HXX +#define INCLUDED_OOX_SOURCE_SHAPE_WPSCONTEXT_HXX + +#include <oox/core/contexthandler2.hxx> +#include <oox/drawingml/shapecontext.hxx> +#include <oox/drawingml/drawingmltypes.hxx> + +namespace com::sun::star::drawing +{ +class XShape; +} + +namespace oox::shape +{ +/// Wps is the drawingML equivalent of v:shape. +class WpsContext final : public oox::drawingml::ShapeContext +{ +public: + WpsContext(oox::core::ContextHandler2Helper const& rParent, + css::uno::Reference<css::drawing::XShape> xShape, + oox::drawingml::ShapePtr const& pMasterShapePtr, + oox::drawingml::ShapePtr const& pShapePtr); + ~WpsContext() override; + + oox::core::ContextHandlerRef onCreateContext(sal_Int32 nElementToken, + const oox::AttributeList& rAttribs) override; + +private: + css::uno::Reference<css::drawing::XShape> mxShape; + bool m_bHasWPGParent; +}; +} + +#endif + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |