Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / oox / source / shape / ShapeContextHandler.cxx
blob1062589c91b6dc43ce646e5794779b86f69ea880
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <com/sun/star/beans/XPropertySet.hpp>
21 #include <com/sun/star/xml/dom/XDocument.hpp>
22 #include <com/sun/star/xml/sax/XFastSAXSerializable.hpp>
24 #include "ShapeContextHandler.hxx"
25 #include "ShapeDrawingFragmentHandler.hxx"
26 #include "LockedCanvasContext.hxx"
27 #include "WpsContext.hxx"
28 #include "WpgContext.hxx"
29 #include <basegfx/matrix/b2dhommatrix.hxx>
30 #include <oox/vml/vmldrawingfragment.hxx>
31 #include <oox/vml/vmlshape.hxx>
32 #include <oox/vml/vmlshapecontainer.hxx>
33 #include <oox/token/namespaces.hxx>
34 #include <oox/token/tokens.hxx>
35 #include <oox/drawingml/themefragmenthandler.hxx>
36 #include <cppuhelper/supportsservice.hxx>
37 #include <memory>
39 using namespace ::com::sun::star;
41 namespace oox { namespace shape {
42 using namespace core;
43 using namespace drawingml;
45 ShapeContextHandler::ShapeContextHandler(uno::Reference< uno::XComponentContext > const & context) :
46 mnStartToken(0)
48 try
50 mxFilterBase.set( new ShapeFilterBase(context) );
52 catch( uno::Exception& )
57 ShapeContextHandler::~ShapeContextHandler()
61 uno::Reference<xml::sax::XFastContextHandler> const & ShapeContextHandler::getLockedCanvasContext(sal_Int32 nElement)
63 if (!mxLockedCanvasContext.is())
65 FragmentHandler2Ref rFragmentHandler(new ShapeFragmentHandler(*mxFilterBase, msRelationFragmentPath));
66 ShapePtr pMasterShape;
68 switch (nElement & 0xffff)
70 case XML_lockedCanvas:
71 mxLockedCanvasContext.set(new LockedCanvasContext(*rFragmentHandler));
72 break;
73 default:
74 break;
78 return mxLockedCanvasContext;
82 * This method creates new ChartGraphicDataContext Object.
84 uno::Reference<xml::sax::XFastContextHandler> const & ShapeContextHandler::getChartShapeContext(sal_Int32 nElement)
86 if (!mxChartShapeContext.is())
88 switch (nElement & 0xffff)
90 case XML_chart:
92 std::unique_ptr<ContextHandler2Helper> pFragmentHandler(
93 new ShapeFragmentHandler(*mxFilterBase, msRelationFragmentPath));
94 mpShape.reset(new Shape("com.sun.star.drawing.OLE2Shape" ));
95 mxChartShapeContext.set(new ChartGraphicDataContext(*pFragmentHandler, mpShape, true));
96 break;
98 default:
99 break;
103 return mxChartShapeContext;
106 uno::Reference<xml::sax::XFastContextHandler> const & ShapeContextHandler::getWpsContext(sal_Int32 nStartElement, sal_Int32 nElement)
108 if (!mxWpsContext.is())
110 FragmentHandler2Ref rFragmentHandler(new ShapeFragmentHandler(*mxFilterBase, msRelationFragmentPath));
111 ShapePtr pMasterShape;
113 uno::Reference<drawing::XShape> xShape;
114 // No element happens in case of pretty-printed XML, bodyPr is the case when we are called again after <wps:txbx>.
115 if (!nElement || nElement == WPS_TOKEN(bodyPr))
116 // Assume that this is just a continuation of the previous shape.
117 xShape = mxSavedShape;
119 switch (getBaseToken(nStartElement))
121 case XML_wsp:
122 mxWpsContext.set(new WpsContext(
123 *rFragmentHandler,
124 xShape,
125 pMasterShape,
126 ShapePtr(
127 new oox::drawingml::Shape(
128 "com.sun.star.drawing.CustomShape"))));
129 break;
130 default:
131 break;
135 return mxWpsContext;
138 uno::Reference<xml::sax::XFastContextHandler> const & ShapeContextHandler::getWpgContext(sal_Int32 nElement)
140 if (!mxWpgContext.is())
142 FragmentHandler2Ref rFragmentHandler(new ShapeFragmentHandler(*mxFilterBase, msRelationFragmentPath));
143 ShapePtr pMasterShape;
145 switch (getBaseToken(nElement))
147 case XML_wgp:
148 mxWpgContext.set(new WpgContext(*rFragmentHandler));
149 break;
150 default:
151 break;
155 return mxWpgContext;
158 uno::Reference<xml::sax::XFastContextHandler> const &
159 ShapeContextHandler::getGraphicShapeContext(::sal_Int32 Element )
161 if (! mxGraphicShapeContext.is())
163 std::shared_ptr<ContextHandler2Helper> pFragmentHandler
164 (new ShapeFragmentHandler(*mxFilterBase, msRelationFragmentPath));
165 ShapePtr pMasterShape;
167 switch (Element & 0xffff)
169 case XML_graphic:
170 mpShape.reset(new Shape("com.sun.star.drawing.GraphicObjectShape" ));
171 mxGraphicShapeContext.set
172 (new GraphicalObjectFrameContext(*pFragmentHandler, pMasterShape, mpShape, true));
173 break;
174 case XML_pic:
175 mpShape.reset(new Shape("com.sun.star.drawing.GraphicObjectShape" ));
176 mxGraphicShapeContext.set
177 (new GraphicShapeContext(*pFragmentHandler, pMasterShape, mpShape));
178 break;
179 default:
180 break;
184 return mxGraphicShapeContext;
187 uno::Reference<xml::sax::XFastContextHandler> const &
188 ShapeContextHandler::getDrawingShapeContext()
190 if (!mxDrawingFragmentHandler.is())
192 mpDrawing.reset( new oox::vml::Drawing( *mxFilterBase, mxDrawPage, oox::vml::VMLDRAWING_WORD ) );
193 mxDrawingFragmentHandler.set
194 (static_cast<ContextHandler *>
195 (new oox::vml::DrawingFragment
196 ( *mxFilterBase, msRelationFragmentPath, *mpDrawing )));
198 else
200 // Reset the handler if fragment path has changed
201 OUString sHandlerFragmentPath = dynamic_cast<ContextHandler&>(*mxDrawingFragmentHandler).getFragmentPath();
202 if ( msRelationFragmentPath != sHandlerFragmentPath )
204 mxDrawingFragmentHandler.clear();
205 mxDrawingFragmentHandler.set
206 (static_cast<ContextHandler *>
207 (new oox::vml::DrawingFragment
208 ( *mxFilterBase, msRelationFragmentPath, *mpDrawing )));
211 return mxDrawingFragmentHandler;
214 uno::Reference<xml::sax::XFastContextHandler> const &
215 ShapeContextHandler::getDiagramShapeContext()
217 if (!mxDiagramShapeContext.is())
219 std::shared_ptr<ContextHandler2Helper> pFragmentHandler(new ShapeFragmentHandler(*mxFilterBase, msRelationFragmentPath));
220 mpShape.reset(new Shape());
221 mxDiagramShapeContext.set(new DiagramGraphicDataContext(*pFragmentHandler, mpShape));
224 return mxDiagramShapeContext;
227 uno::Reference<xml::sax::XFastContextHandler>
228 ShapeContextHandler::getContextHandler(sal_Int32 nElement)
230 uno::Reference<xml::sax::XFastContextHandler> xResult;
232 switch (getNamespace( mnStartToken ))
234 case NMSP_doc:
235 case NMSP_vml:
236 xResult.set(getDrawingShapeContext());
237 break;
238 case NMSP_dmlDiagram:
239 xResult.set(getDiagramShapeContext());
240 break;
241 case NMSP_dmlLockedCanvas:
242 xResult.set(getLockedCanvasContext(mnStartToken));
243 break;
244 case NMSP_dmlChart:
245 xResult.set(getChartShapeContext(mnStartToken));
246 break;
247 case NMSP_wps:
248 xResult.set(getWpsContext(mnStartToken, nElement));
249 break;
250 case NMSP_wpg:
251 xResult.set(getWpgContext(mnStartToken));
252 break;
253 default:
254 xResult.set(getGraphicShapeContext(mnStartToken));
255 break;
258 return xResult;
261 // css::xml::sax::XFastContextHandler:
262 void SAL_CALL ShapeContextHandler::startFastElement
263 (::sal_Int32 Element,
264 const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
266 mxFilterBase->filter(maMediaDescriptor);
268 mpThemePtr.reset(new Theme());
270 if (Element == DGM_TOKEN(relIds) || Element == LC_TOKEN(lockedCanvas) || Element == C_TOKEN(chart) ||
271 Element == WPS_TOKEN(wsp) || Element == WPG_TOKEN(wgp) || Element == OOX_TOKEN(dmlPicture, pic))
273 // Parse the theme relation, if available; the diagram won't have colors without it.
274 if (!msRelationFragmentPath.isEmpty())
276 // Get Target for Type = "officeDocument" from _rels/.rels file
277 // aOfficeDocumentFragmentPath is pointing to "word/document.xml" for docx & to "ppt/presentation.xml" for pptx
278 FragmentHandlerRef rFragmentHandlerRef(new ShapeFragmentHandler(*mxFilterBase, "/"));
279 OUString aOfficeDocumentFragmentPath = rFragmentHandlerRef->getFragmentPathFromFirstTypeFromOfficeDoc( "officeDocument" );
281 // Get the theme DO NOT use msRelationFragmentPath for getting theme as for a document there is a single theme in document.xml.rels
282 // and the same is used by header and footer as well.
283 FragmentHandlerRef rFragmentHandler(new ShapeFragmentHandler(*mxFilterBase, aOfficeDocumentFragmentPath));
284 OUString aThemeFragmentPath = rFragmentHandler->getFragmentPathFromFirstTypeFromOfficeDoc( "theme" );
286 if(!aThemeFragmentPath.isEmpty())
288 uno::Reference<xml::sax::XFastSAXSerializable> xDoc(mxFilterBase->importFragment(aThemeFragmentPath), uno::UNO_QUERY_THROW);
289 mxFilterBase->importFragment(new ThemeFragmentHandler(*mxFilterBase, aThemeFragmentPath, *mpThemePtr ), xDoc);
290 ShapeFilterBase* pShapeFilterBase(dynamic_cast<ShapeFilterBase*>(mxFilterBase.get()));
291 if (pShapeFilterBase)
292 pShapeFilterBase->setCurrentTheme(mpThemePtr);
296 createFastChildContext(Element, Attribs);
299 // Entering VML block (startFastElement() is called for the outermost tag),
300 // handle possible recursion.
301 if ( getContextHandler() == getDrawingShapeContext() )
302 mpDrawing->getShapes().pushMark();
304 uno::Reference<XFastContextHandler> xContextHandler(getContextHandler());
306 if (xContextHandler.is())
307 xContextHandler->startFastElement(Element, Attribs);
310 void SAL_CALL ShapeContextHandler::startUnknownElement
311 (const OUString & Namespace, const OUString & Name,
312 const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
314 if ( getContextHandler() == getDrawingShapeContext() )
315 mpDrawing->getShapes().pushMark();
317 uno::Reference<XFastContextHandler> xContextHandler(getContextHandler());
319 if (xContextHandler.is())
320 xContextHandler->startUnknownElement(Namespace, Name, Attribs);
323 void SAL_CALL ShapeContextHandler::endFastElement(::sal_Int32 Element)
325 uno::Reference<XFastContextHandler> xContextHandler(getContextHandler());
327 if (xContextHandler.is())
328 xContextHandler->endFastElement(Element);
329 // In case a textbox is sent, and later we get additional properties for
330 // the textbox, then the wps context is not cleared, so do that here.
331 if (Element == (NMSP_wps | XML_wsp))
333 uno::Reference<lang::XServiceInfo> xServiceInfo(mxSavedShape, uno::UNO_QUERY);
334 bool bTextFrame = xServiceInfo.is() && xServiceInfo->supportsService("com.sun.star.text.TextFrame");
335 bool bTextBox = false;
336 if (!bTextFrame)
338 uno::Reference<beans::XPropertySet> xPropertySet(mxSavedShape, uno::UNO_QUERY);
339 if (xPropertySet.is())
340 xPropertySet->getPropertyValue("TextBox") >>= bTextBox;
342 if (bTextFrame || bTextBox)
343 mxWpsContext.clear();
344 mxSavedShape.clear();
348 void SAL_CALL ShapeContextHandler::endUnknownElement
349 (const OUString & Namespace,
350 const OUString & Name)
352 uno::Reference<XFastContextHandler> xContextHandler(getContextHandler());
354 if (xContextHandler.is())
355 xContextHandler->endUnknownElement(Namespace, Name);
358 uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
359 ShapeContextHandler::createFastChildContext
360 (::sal_Int32 Element,
361 const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
363 uno::Reference< xml::sax::XFastContextHandler > xResult;
364 uno::Reference< xml::sax::XFastContextHandler > xContextHandler(getContextHandler(Element));
366 if (xContextHandler.is())
367 xResult.set(xContextHandler->createFastChildContext
368 (Element, Attribs));
370 return xResult;
373 uno::Reference< xml::sax::XFastContextHandler > SAL_CALL
374 ShapeContextHandler::createUnknownChildContext
375 (const OUString & Namespace,
376 const OUString & Name,
377 const uno::Reference< xml::sax::XFastAttributeList > & Attribs)
379 uno::Reference<XFastContextHandler> xContextHandler(getContextHandler());
381 if (xContextHandler.is())
382 return xContextHandler->createUnknownChildContext
383 (Namespace, Name, Attribs);
385 return uno::Reference< xml::sax::XFastContextHandler >();
388 void SAL_CALL ShapeContextHandler::characters(const OUString & aChars)
390 uno::Reference<XFastContextHandler> xContextHandler(getContextHandler());
392 if (xContextHandler.is())
393 xContextHandler->characters(aChars);
396 // css::xml::sax::XFastShapeContextHandler:
397 uno::Reference< drawing::XShape > SAL_CALL
398 ShapeContextHandler::getShape()
400 uno::Reference< drawing::XShape > xResult;
401 uno::Reference< drawing::XShapes > xShapes = mxDrawPage;
403 if (mxFilterBase.is() && xShapes.is())
405 if ( getContextHandler() == getDrawingShapeContext() )
407 mpDrawing->finalizeFragmentImport();
408 if( std::shared_ptr< vml::ShapeBase > pShape = mpDrawing->getShapes().takeLastShape() )
409 xResult = pShape->convertAndInsert( xShapes );
410 // Only now remove the recursion mark, because getShape() is called in writerfilter
411 // after endFastElement().
412 mpDrawing->getShapes().popMark();
414 else if (mxDiagramShapeContext.is())
416 basegfx::B2DHomMatrix aMatrix;
417 if (mpShape->getExtDrawings().empty())
419 mpShape->addShape( *mxFilterBase, mpThemePtr.get(), xShapes, aMatrix, mpShape->getFillProperties() );
420 xResult = mpShape->getXShape();
422 else
424 // Prerendered diagram output is available, then use that, and throw away the original result.
425 for (auto const& extDrawing : mpShape->getExtDrawings())
427 DiagramGraphicDataContext* pDiagramGraphicDataContext = dynamic_cast<DiagramGraphicDataContext*>(mxDiagramShapeContext.get());
428 if (!pDiagramGraphicDataContext)
429 break;
430 OUString aFragmentPath(pDiagramGraphicDataContext->getFragmentPathFromRelId(extDrawing));
431 oox::drawingml::ShapePtr pShapePtr( new Shape( "com.sun.star.drawing.GroupShape" ) );
432 pShapePtr->setDiagramType();
433 mxFilterBase->importFragment(new ShapeDrawingFragmentHandler(*mxFilterBase, aFragmentPath, pShapePtr));
434 pShapePtr->setDiagramDoms(mpShape->getDiagramDoms());
435 pShapePtr->keepDiagramDrawing(*mxFilterBase, aFragmentPath);
437 if (!mpShape->getChildren().empty())
439 // first child is diagram background - we want to keep it, as drawingML fallback doesn't contain it
440 auto& aChildren = pShapePtr->getChildren();
441 ShapePtr pBackground = mpShape->getChildren().front();
442 aChildren.insert(aChildren.begin(), pBackground);
445 pShapePtr->addShape( *mxFilterBase, mpThemePtr.get(), xShapes, aMatrix, pShapePtr->getFillProperties() );
446 xResult = pShapePtr->getXShape();
448 mpShape.reset();
450 mxDiagramShapeContext.clear();
452 else if (mxLockedCanvasContext.is())
454 ShapePtr pShape = dynamic_cast<LockedCanvasContext&>(*mxLockedCanvasContext).getShape();
455 if (pShape)
457 basegfx::B2DHomMatrix aMatrix;
458 pShape->addShape(*mxFilterBase, mpThemePtr.get(), xShapes, aMatrix, pShape->getFillProperties());
459 xResult = pShape->getXShape();
460 mxLockedCanvasContext.clear();
463 //NMSP_dmlChart == getNamespace( mnStartToken ) check is introduced to make sure that
464 //mnStartToken is set as NMSP_dmlChart in setStartToken.
465 //Only in case it is set then only the below block of code for ChartShapeContext should be executed.
466 else if (mxChartShapeContext.is() && (NMSP_dmlChart == getNamespace( mnStartToken )))
468 ChartGraphicDataContext* pChartGraphicDataContext = dynamic_cast<ChartGraphicDataContext*>(mxChartShapeContext.get());
469 if (pChartGraphicDataContext)
471 basegfx::B2DHomMatrix aMatrix;
472 oox::drawingml::ShapePtr xShapePtr( pChartGraphicDataContext->getShape());
473 // See SwXTextDocument::createInstance(), ODF import uses the same hack.
474 xShapePtr->setServiceName("com.sun.star.drawing.temporaryForXMLImportOLE2Shape");
475 xShapePtr->addShape( *mxFilterBase, mpThemePtr.get(), xShapes, aMatrix, xShapePtr->getFillProperties() );
476 xResult = xShapePtr->getXShape();
478 mxChartShapeContext.clear();
480 else if (mxWpsContext.is())
482 ShapePtr pShape = dynamic_cast<WpsContext&>(*mxWpsContext).getShape();
483 if (pShape)
485 basegfx::B2DHomMatrix aMatrix;
486 pShape->setPosition(maPosition);
487 pShape->addShape(*mxFilterBase, mpThemePtr.get(), xShapes, aMatrix, pShape->getFillProperties());
488 xResult = pShape->getXShape();
489 mxSavedShape = xResult;
490 mxWpsContext.clear();
493 else if (mxWpgContext.is())
495 ShapePtr pShape = dynamic_cast<WpgContext&>(*mxWpgContext).getShape();
496 if (pShape)
498 basegfx::B2DHomMatrix aMatrix;
499 pShape->setPosition(maPosition);
500 pShape->addShape(*mxFilterBase, mpThemePtr.get(), xShapes, aMatrix, pShape->getFillProperties());
501 xResult = pShape->getXShape();
502 mxSavedShape = xResult;
505 else if (mpShape.get() != nullptr)
507 basegfx::B2DHomMatrix aTransformation;
508 mpShape->addShape(*mxFilterBase, mpThemePtr.get(), xShapes, aTransformation, mpShape->getFillProperties() );
509 xResult.set(mpShape->getXShape());
510 mxGraphicShapeContext.clear( );
514 return xResult;
517 css::uno::Reference< css::drawing::XDrawPage > SAL_CALL
518 ShapeContextHandler::getDrawPage()
520 return mxDrawPage;
523 void SAL_CALL ShapeContextHandler::setDrawPage
524 (const css::uno::Reference< css::drawing::XDrawPage > & the_value)
526 mxDrawPage = the_value;
529 css::uno::Reference< css::frame::XModel > SAL_CALL
530 ShapeContextHandler::getModel()
532 if( !mxFilterBase.is() )
533 throw uno::RuntimeException();
534 return mxFilterBase->getModel();
537 void SAL_CALL ShapeContextHandler::setModel
538 (const css::uno::Reference< css::frame::XModel > & the_value)
540 if( !mxFilterBase.is() )
541 throw uno::RuntimeException();
542 uno::Reference<lang::XComponent> xComp(the_value, uno::UNO_QUERY_THROW);
543 mxFilterBase->setTargetDocument(xComp);
546 OUString SAL_CALL ShapeContextHandler::getRelationFragmentPath()
548 return msRelationFragmentPath;
551 void SAL_CALL ShapeContextHandler::setRelationFragmentPath(const OUString & the_value)
553 msRelationFragmentPath = the_value;
556 ::sal_Int32 SAL_CALL ShapeContextHandler::getStartToken()
558 return mnStartToken;
561 void SAL_CALL ShapeContextHandler::setStartToken( ::sal_Int32 _starttoken )
563 mnStartToken = _starttoken;
566 awt::Point SAL_CALL ShapeContextHandler::getPosition()
568 return maPosition;
571 void SAL_CALL ShapeContextHandler::setPosition(const awt::Point& rPosition)
573 maPosition = rPosition;
576 void SAL_CALL ShapeContextHandler::setDocumentProperties(const uno::Reference<document::XDocumentProperties>& xDocProps)
578 mxDocumentProperties = xDocProps;
579 mxFilterBase->checkDocumentProperties(mxDocumentProperties);
582 uno::Reference<document::XDocumentProperties> SAL_CALL ShapeContextHandler::getDocumentProperties()
584 return mxDocumentProperties;
587 uno::Sequence<beans::PropertyValue> SAL_CALL ShapeContextHandler::getMediaDescriptor()
589 return maMediaDescriptor;
592 void SAL_CALL ShapeContextHandler::setMediaDescriptor(const uno::Sequence<beans::PropertyValue>& rMediaDescriptor)
594 maMediaDescriptor = rMediaDescriptor;
597 OUString ShapeContextHandler::getImplementationName()
599 return "com.sun.star.comp.oox.ShapeContextHandler";
602 uno::Sequence< OUString > ShapeContextHandler::getSupportedServiceNames()
604 uno::Sequence< OUString > s { "com.sun.star.xml.sax.FastShapeContextHandler" };
605 return s;
608 sal_Bool SAL_CALL ShapeContextHandler::supportsService(const OUString & ServiceName)
610 return cppu::supportsService(this, ServiceName);
615 extern "C" SAL_DLLPUBLIC_EXPORT uno::XInterface*
616 com_sun_star_comp_oox_ShapeContextHandler_get_implementation(
617 uno::XComponentContext* pCtx, uno::Sequence<uno::Any> const& /*rSeq*/)
619 return cppu::acquire(new oox::shape::ShapeContextHandler(pCtx));
622 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */