1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
39 using namespace ::com::sun::star
;
41 namespace oox
{ namespace shape
{
43 using namespace drawingml
;
45 ShapeContextHandler::ShapeContextHandler(uno::Reference
< uno::XComponentContext
> const & context
) :
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(static_cast<oox::core::ContextHandler
*>(new LockedCanvasContext(*rFragmentHandler
)));
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)
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));
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
))
122 mxWpsContext
.set(new WpsContext(*rFragmentHandler
, xShape
));
132 uno::Reference
<xml::sax::XFastContextHandler
> const & ShapeContextHandler::getWpgContext(sal_Int32 nElement
)
134 if (!mxWpgContext
.is())
136 FragmentHandler2Ref
rFragmentHandler(new ShapeFragmentHandler(*mxFilterBase
, msRelationFragmentPath
));
137 ShapePtr pMasterShape
;
139 switch (getBaseToken(nElement
))
142 mxWpgContext
.set(static_cast<oox::core::ContextHandler
*>(new WpgContext(*rFragmentHandler
)));
152 uno::Reference
<xml::sax::XFastContextHandler
> const &
153 ShapeContextHandler::getGraphicShapeContext(::sal_Int32 Element
)
155 if (! mxGraphicShapeContext
.is())
157 std::shared_ptr
<ContextHandler2Helper
> pFragmentHandler
158 (new ShapeFragmentHandler(*mxFilterBase
, msRelationFragmentPath
));
159 ShapePtr pMasterShape
;
161 switch (Element
& 0xffff)
164 mpShape
.reset(new Shape("com.sun.star.drawing.GraphicObjectShape" ));
165 mxGraphicShapeContext
.set
166 (new GraphicalObjectFrameContext(*pFragmentHandler
, pMasterShape
, mpShape
, true));
169 mpShape
.reset(new Shape("com.sun.star.drawing.GraphicObjectShape" ));
170 mxGraphicShapeContext
.set
171 (new GraphicShapeContext(*pFragmentHandler
, pMasterShape
, mpShape
));
178 return mxGraphicShapeContext
;
181 uno::Reference
<xml::sax::XFastContextHandler
> const &
182 ShapeContextHandler::getDrawingShapeContext()
184 if (!mxDrawingFragmentHandler
.is())
186 mpDrawing
.reset( new oox::vml::Drawing( *mxFilterBase
, mxDrawPage
, oox::vml::VMLDRAWING_WORD
) );
187 mxDrawingFragmentHandler
.set
188 (dynamic_cast<ContextHandler
*>
189 (new oox::vml::DrawingFragment
190 ( *mxFilterBase
, msRelationFragmentPath
, *mpDrawing
)));
194 // Reset the handler if fragment path has changed
195 OUString sHandlerFragmentPath
= dynamic_cast<ContextHandler
&>(*mxDrawingFragmentHandler
.get()).getFragmentPath();
196 if ( msRelationFragmentPath
!= sHandlerFragmentPath
)
198 mxDrawingFragmentHandler
.clear();
199 mxDrawingFragmentHandler
.set
200 (dynamic_cast<ContextHandler
*>
201 (new oox::vml::DrawingFragment
202 ( *mxFilterBase
, msRelationFragmentPath
, *mpDrawing
)));
205 return mxDrawingFragmentHandler
;
208 uno::Reference
<xml::sax::XFastContextHandler
> const &
209 ShapeContextHandler::getDiagramShapeContext()
211 if (!mxDiagramShapeContext
.is())
213 std::shared_ptr
<ContextHandler2Helper
> pFragmentHandler(new ShapeFragmentHandler(*mxFilterBase
, msRelationFragmentPath
));
214 mpShape
.reset(new Shape());
215 mxDiagramShapeContext
.set(new DiagramGraphicDataContext(*pFragmentHandler
, mpShape
));
218 return mxDiagramShapeContext
;
221 uno::Reference
<xml::sax::XFastContextHandler
>
222 ShapeContextHandler::getContextHandler(sal_Int32 nElement
)
224 uno::Reference
<xml::sax::XFastContextHandler
> xResult
;
226 switch (getNamespace( mnStartToken
))
230 xResult
.set(getDrawingShapeContext());
232 case NMSP_dmlDiagram
:
233 xResult
.set(getDiagramShapeContext());
235 case NMSP_dmlLockedCanvas
:
236 xResult
.set(getLockedCanvasContext(mnStartToken
));
239 xResult
.set(getChartShapeContext(mnStartToken
));
242 xResult
.set(getWpsContext(mnStartToken
, nElement
));
245 xResult
.set(getWpgContext(mnStartToken
));
248 xResult
.set(getGraphicShapeContext(mnStartToken
));
255 // css::xml::sax::XFastContextHandler:
256 void SAL_CALL
ShapeContextHandler::startFastElement
257 (::sal_Int32 Element
,
258 const uno::Reference
< xml::sax::XFastAttributeList
> & Attribs
)
260 mxFilterBase
->filter(maMediaDescriptor
);
262 mpThemePtr
.reset(new Theme());
264 if (Element
== DGM_TOKEN(relIds
) || Element
== LC_TOKEN(lockedCanvas
) || Element
== C_TOKEN(chart
) ||
265 Element
== WPS_TOKEN(wsp
) || Element
== WPG_TOKEN(wgp
) || Element
== OOX_TOKEN(dmlPicture
, pic
))
267 // Parse the theme relation, if available; the diagram won't have colors without it.
268 if (!msRelationFragmentPath
.isEmpty())
270 // Get Target for Type = "officeDocument" from _rels/.rels file
271 // aOfficeDocumentFragmentPath is pointing to "word/document.xml" for docx & to "ppt/presentation.xml" for pptx
272 FragmentHandlerRef
rFragmentHandlerRef(new ShapeFragmentHandler(*mxFilterBase
, "/"));
273 OUString aOfficeDocumentFragmentPath
= rFragmentHandlerRef
->getFragmentPathFromFirstTypeFromOfficeDoc( "officeDocument" );
275 // Get the theme DO NOT use msRelationFragmentPath for getting theme as for a document there is a single theme in document.xml.rels
276 // and the same is used by header and footer as well.
277 FragmentHandlerRef
rFragmentHandler(new ShapeFragmentHandler(*mxFilterBase
, aOfficeDocumentFragmentPath
));
278 OUString aThemeFragmentPath
= rFragmentHandler
->getFragmentPathFromFirstTypeFromOfficeDoc( "theme" );
280 if(!aThemeFragmentPath
.isEmpty())
282 uno::Reference
<xml::sax::XFastSAXSerializable
> xDoc(mxFilterBase
->importFragment(aThemeFragmentPath
), uno::UNO_QUERY_THROW
);
283 mxFilterBase
->importFragment(new ThemeFragmentHandler(*mxFilterBase
, aThemeFragmentPath
, *mpThemePtr
), xDoc
);
284 ShapeFilterBase
* pShapeFilterBase(dynamic_cast<ShapeFilterBase
*>(mxFilterBase
.get()));
285 if (pShapeFilterBase
)
286 pShapeFilterBase
->setCurrentTheme(mpThemePtr
);
290 createFastChildContext(Element
, Attribs
);
293 // Entering VML block (startFastElement() is called for the outermost tag),
294 // handle possible recursion.
295 if ( getContextHandler() == getDrawingShapeContext() )
296 mpDrawing
->getShapes().pushMark();
298 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
300 if (xContextHandler
.is())
301 xContextHandler
->startFastElement(Element
, Attribs
);
304 void SAL_CALL
ShapeContextHandler::startUnknownElement
305 (const OUString
& Namespace
, const OUString
& Name
,
306 const uno::Reference
< xml::sax::XFastAttributeList
> & Attribs
)
308 if ( getContextHandler() == getDrawingShapeContext() )
309 mpDrawing
->getShapes().pushMark();
311 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
313 if (xContextHandler
.is())
314 xContextHandler
->startUnknownElement(Namespace
, Name
, Attribs
);
317 void SAL_CALL
ShapeContextHandler::endFastElement(::sal_Int32 Element
)
319 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
321 if (xContextHandler
.is())
322 xContextHandler
->endFastElement(Element
);
323 // In case a textbox is sent, and later we get additional properties for
324 // the textbox, then the wps context is not cleared, so do that here.
325 if (Element
== (NMSP_wps
| XML_wsp
))
327 uno::Reference
<lang::XServiceInfo
> xServiceInfo(mxSavedShape
, uno::UNO_QUERY
);
328 bool bTextFrame
= xServiceInfo
.is() && xServiceInfo
->supportsService("com.sun.star.text.TextFrame");
329 bool bTextBox
= false;
332 uno::Reference
<beans::XPropertySet
> xPropertySet(mxSavedShape
, uno::UNO_QUERY
);
333 if (xPropertySet
.is())
334 xPropertySet
->getPropertyValue("TextBox") >>= bTextBox
;
336 if (bTextFrame
|| bTextBox
)
337 mxWpsContext
.clear();
338 mxSavedShape
.clear();
342 void SAL_CALL
ShapeContextHandler::endUnknownElement
343 (const OUString
& Namespace
,
344 const OUString
& Name
)
346 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
348 if (xContextHandler
.is())
349 xContextHandler
->endUnknownElement(Namespace
, Name
);
352 uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
353 ShapeContextHandler::createFastChildContext
354 (::sal_Int32 Element
,
355 const uno::Reference
< xml::sax::XFastAttributeList
> & Attribs
)
357 uno::Reference
< xml::sax::XFastContextHandler
> xResult
;
358 uno::Reference
< xml::sax::XFastContextHandler
> xContextHandler(getContextHandler(Element
));
360 if (xContextHandler
.is())
361 xResult
.set(xContextHandler
->createFastChildContext
367 uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
368 ShapeContextHandler::createUnknownChildContext
369 (const OUString
& Namespace
,
370 const OUString
& Name
,
371 const uno::Reference
< xml::sax::XFastAttributeList
> & Attribs
)
373 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
375 if (xContextHandler
.is())
376 return xContextHandler
->createUnknownChildContext
377 (Namespace
, Name
, Attribs
);
379 return uno::Reference
< xml::sax::XFastContextHandler
>();
382 void SAL_CALL
ShapeContextHandler::characters(const OUString
& aChars
)
384 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
386 if (xContextHandler
.is())
387 xContextHandler
->characters(aChars
);
390 // css::xml::sax::XFastShapeContextHandler:
391 uno::Reference
< drawing::XShape
> SAL_CALL
392 ShapeContextHandler::getShape()
394 uno::Reference
< drawing::XShape
> xResult
;
395 uno::Reference
< drawing::XShapes
> xShapes( mxDrawPage
, uno::UNO_QUERY
);
397 if (mxFilterBase
.is() && xShapes
.is())
399 if ( getContextHandler() == getDrawingShapeContext() )
401 mpDrawing
->finalizeFragmentImport();
402 if( std::shared_ptr
< vml::ShapeBase
> pShape
= mpDrawing
->getShapes().takeLastShape() )
403 xResult
= pShape
->convertAndInsert( xShapes
);
404 // Only now remove the recursion mark, because getShape() is called in writerfilter
405 // after endFastElement().
406 mpDrawing
->getShapes().popMark();
408 else if (mxDiagramShapeContext
.is())
410 basegfx::B2DHomMatrix aMatrix
;
411 if (mpShape
->getExtDrawings().empty())
413 mpShape
->addShape( *mxFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, mpShape
->getFillProperties() );
414 xResult
= mpShape
->getXShape();
418 // Prerendered diagram output is available, then use that, and throw away the original result.
419 for (auto const& extDrawing
: mpShape
->getExtDrawings())
421 DiagramGraphicDataContext
* pDiagramGraphicDataContext
= dynamic_cast<DiagramGraphicDataContext
*>(mxDiagramShapeContext
.get());
422 if (!pDiagramGraphicDataContext
)
424 OUString
aFragmentPath(pDiagramGraphicDataContext
->getFragmentPathFromRelId(extDrawing
));
425 oox::drawingml::ShapePtr
pShapePtr( new Shape( "com.sun.star.drawing.GroupShape" ) );
426 pShapePtr
->setDiagramType();
427 mxFilterBase
->importFragment(new ShapeDrawingFragmentHandler(*mxFilterBase
, aFragmentPath
, pShapePtr
));
428 pShapePtr
->setDiagramDoms(mpShape
->getDiagramDoms());
429 pShapePtr
->keepDiagramDrawing(*mxFilterBase
, aFragmentPath
);
431 if (!mpShape
->getChildren().empty())
433 // first child is diagram background - we want to keep it, as drawingML fallback doesn't contain it
434 auto& aChildren
= pShapePtr
->getChildren();
435 ShapePtr pBackground
= mpShape
->getChildren().front();
436 aChildren
.insert(aChildren
.begin(), pBackground
);
439 pShapePtr
->addShape( *mxFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, pShapePtr
->getFillProperties() );
440 xResult
= pShapePtr
->getXShape();
444 mxDiagramShapeContext
.clear();
446 else if (mxLockedCanvasContext
.is())
448 ShapePtr pShape
= dynamic_cast<LockedCanvasContext
&>(*mxLockedCanvasContext
.get()).getShape();
451 basegfx::B2DHomMatrix aMatrix
;
452 pShape
->addShape(*mxFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, pShape
->getFillProperties());
453 xResult
= pShape
->getXShape();
454 mxLockedCanvasContext
.clear();
457 //NMSP_dmlChart == getNamespace( mnStartToken ) check is introduced to make sure that
458 //mnStartToken is set as NMSP_dmlChart in setStartToken.
459 //Only in case it is set then only the below block of code for ChartShapeContext should be executed.
460 else if (mxChartShapeContext
.is() && (NMSP_dmlChart
== getNamespace( mnStartToken
)))
462 ChartGraphicDataContext
* pChartGraphicDataContext
= dynamic_cast<ChartGraphicDataContext
*>(mxChartShapeContext
.get());
463 if (pChartGraphicDataContext
)
465 basegfx::B2DHomMatrix aMatrix
;
466 oox::drawingml::ShapePtr
xShapePtr( pChartGraphicDataContext
->getShape());
467 // See SwXTextDocument::createInstance(), ODF import uses the same hack.
468 xShapePtr
->setServiceName("com.sun.star.drawing.temporaryForXMLImportOLE2Shape");
469 xShapePtr
->addShape( *mxFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, xShapePtr
->getFillProperties() );
470 xResult
= xShapePtr
->getXShape();
472 mxChartShapeContext
.clear();
474 else if (mxWpsContext
.is())
476 ShapePtr pShape
= dynamic_cast<WpsContext
&>(*mxWpsContext
.get()).getShape();
479 basegfx::B2DHomMatrix aMatrix
;
480 pShape
->setPosition(maPosition
);
481 pShape
->addShape(*mxFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, pShape
->getFillProperties());
482 xResult
= pShape
->getXShape();
483 mxSavedShape
= xResult
;
484 mxWpsContext
.clear();
487 else if (mxWpgContext
.is())
489 ShapePtr pShape
= dynamic_cast<WpgContext
&>(*mxWpgContext
.get()).getShape();
492 basegfx::B2DHomMatrix aMatrix
;
493 pShape
->setPosition(maPosition
);
494 pShape
->addShape(*mxFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, pShape
->getFillProperties());
495 xResult
= pShape
->getXShape();
496 mxWpgContext
.clear();
499 else if (mpShape
.get() != nullptr)
501 basegfx::B2DHomMatrix aTransformation
;
502 mpShape
->addShape(*mxFilterBase
, mpThemePtr
.get(), xShapes
, aTransformation
, mpShape
->getFillProperties() );
503 xResult
.set(mpShape
->getXShape());
504 mxGraphicShapeContext
.clear( );
511 css::uno::Reference
< css::drawing::XDrawPage
> SAL_CALL
512 ShapeContextHandler::getDrawPage()
517 void SAL_CALL
ShapeContextHandler::setDrawPage
518 (const css::uno::Reference
< css::drawing::XDrawPage
> & the_value
)
520 mxDrawPage
= the_value
;
523 css::uno::Reference
< css::frame::XModel
> SAL_CALL
524 ShapeContextHandler::getModel()
526 if( !mxFilterBase
.is() )
527 throw uno::RuntimeException();
528 return mxFilterBase
->getModel();
531 void SAL_CALL
ShapeContextHandler::setModel
532 (const css::uno::Reference
< css::frame::XModel
> & the_value
)
534 if( !mxFilterBase
.is() )
535 throw uno::RuntimeException();
536 uno::Reference
<lang::XComponent
> xComp(the_value
, uno::UNO_QUERY_THROW
);
537 mxFilterBase
->setTargetDocument(xComp
);
540 OUString SAL_CALL
ShapeContextHandler::getRelationFragmentPath()
542 return msRelationFragmentPath
;
545 void SAL_CALL
ShapeContextHandler::setRelationFragmentPath(const OUString
& the_value
)
547 msRelationFragmentPath
= the_value
;
550 ::sal_Int32 SAL_CALL
ShapeContextHandler::getStartToken()
555 void SAL_CALL
ShapeContextHandler::setStartToken( ::sal_Int32 _starttoken
)
557 mnStartToken
= _starttoken
;
560 awt::Point SAL_CALL
ShapeContextHandler::getPosition()
565 void SAL_CALL
ShapeContextHandler::setPosition(const awt::Point
& rPosition
)
567 maPosition
= rPosition
;
570 void SAL_CALL
ShapeContextHandler::setDocumentProperties(const uno::Reference
<document::XDocumentProperties
>& xDocProps
)
572 mxDocumentProperties
= xDocProps
;
573 mxFilterBase
->checkDocumentProperties(mxDocumentProperties
);
576 uno::Reference
<document::XDocumentProperties
> SAL_CALL
ShapeContextHandler::getDocumentProperties()
578 return mxDocumentProperties
;
581 uno::Sequence
<beans::PropertyValue
> SAL_CALL
ShapeContextHandler::getMediaDescriptor()
583 return maMediaDescriptor
;
586 void SAL_CALL
ShapeContextHandler::setMediaDescriptor(const uno::Sequence
<beans::PropertyValue
>& rMediaDescriptor
)
588 maMediaDescriptor
= rMediaDescriptor
;
591 OUString
ShapeContextHandler::getImplementationName()
593 return OUString( "com.sun.star.comp.oox.ShapeContextHandler" );
596 uno::Sequence
< OUString
> ShapeContextHandler::getSupportedServiceNames()
598 uno::Sequence
< OUString
> s
{ "com.sun.star.xml.sax.FastShapeContextHandler" };
602 sal_Bool SAL_CALL
ShapeContextHandler::supportsService(const OUString
& ServiceName
)
604 return cppu::supportsService(this, ServiceName
);
609 extern "C" SAL_DLLPUBLIC_EXPORT
uno::XInterface
*
610 com_sun_star_comp_oox_ShapeContextHandler_get_implementation(
611 uno::XComponentContext
* pCtx
, uno::Sequence
<uno::Any
> const& /*rSeq*/)
613 return cppu::acquire(new oox::shape::ShapeContextHandler(pCtx
));
616 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */