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(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(
127 new oox::drawingml::Shape(
128 "com.sun.star.drawing.CustomShape"))));
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
))
148 mxWpgContext
.set(new WpgContext(*rFragmentHandler
));
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)
170 mpShape
.reset(new Shape("com.sun.star.drawing.GraphicObjectShape" ));
171 mxGraphicShapeContext
.set
172 (new GraphicalObjectFrameContext(*pFragmentHandler
, pMasterShape
, mpShape
, true));
175 mpShape
.reset(new Shape("com.sun.star.drawing.GraphicObjectShape" ));
176 mxGraphicShapeContext
.set
177 (new GraphicShapeContext(*pFragmentHandler
, pMasterShape
, mpShape
));
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
)));
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
))
236 xResult
.set(getDrawingShapeContext());
238 case NMSP_dmlDiagram
:
239 xResult
.set(getDiagramShapeContext());
241 case NMSP_dmlLockedCanvas
:
242 xResult
.set(getLockedCanvasContext(mnStartToken
));
245 xResult
.set(getChartShapeContext(mnStartToken
));
248 xResult
.set(getWpsContext(mnStartToken
, nElement
));
251 xResult
.set(getWpgContext(mnStartToken
));
254 xResult
.set(getGraphicShapeContext(mnStartToken
));
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;
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
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();
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
)
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();
450 mxDiagramShapeContext
.clear();
452 else if (mxLockedCanvasContext
.is())
454 ShapePtr pShape
= dynamic_cast<LockedCanvasContext
&>(*mxLockedCanvasContext
).getShape();
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();
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();
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( );
517 css::uno::Reference
< css::drawing::XDrawPage
> SAL_CALL
518 ShapeContextHandler::getDrawPage()
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()
561 void SAL_CALL
ShapeContextHandler::setStartToken( ::sal_Int32 _starttoken
)
563 mnStartToken
= _starttoken
;
566 awt::Point SAL_CALL
ShapeContextHandler::getPosition()
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" };
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: */