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 "services.hxx"
30 #include <basegfx/matrix/b2dhommatrix.hxx>
31 #include "oox/vml/vmldrawingfragment.hxx"
32 #include "oox/vml/vmlshape.hxx"
33 #include <oox/vml/vmlshapecontainer.hxx>
34 #include <oox/token/namespaces.hxx>
35 #include <oox/token/tokens.hxx>
36 #include "oox/drawingml/themefragmenthandler.hxx"
37 #include <cppuhelper/supportsservice.hxx>
40 namespace oox
{ namespace shape
{
42 using namespace ::com::sun::star
;
44 using namespace drawingml
;
46 OUString SAL_CALL
ShapeContextHandler_getImplementationName()
48 return OUString( "com.sun.star.comp.oox.ShapeContextHandler" );
51 uno::Sequence
< OUString
> SAL_CALL
52 ShapeContextHandler_getSupportedServiceNames()
54 uno::Sequence
< OUString
> s
{ "com.sun.star.xml.sax.FastShapeContextHandler" };
58 uno::Reference
< uno::XInterface
> SAL_CALL
59 ShapeContextHandler_createInstance( const uno::Reference
< uno::XComponentContext
> & context
)
61 return static_cast< ::cppu::OWeakObject
* >( new ShapeContextHandler(context
) );
64 ShapeContextHandler::ShapeContextHandler(uno::Reference
< uno::XComponentContext
> const & context
) :
69 mxFilterBase
.set( new ShapeFilterBase(context
) );
71 catch( uno::Exception
& )
76 ShapeContextHandler::~ShapeContextHandler()
80 uno::Reference
<xml::sax::XFastContextHandler
> const & ShapeContextHandler::getLockedCanvasContext(sal_Int32 nElement
)
82 if (!mxLockedCanvasContext
.is())
84 FragmentHandler2Ref
rFragmentHandler(new ShapeFragmentHandler(*mxFilterBase
, msRelationFragmentPath
));
85 ShapePtr pMasterShape
;
87 switch (nElement
& 0xffff)
89 case XML_lockedCanvas
:
90 mxLockedCanvasContext
.set(new LockedCanvasContext(*rFragmentHandler
));
97 return mxLockedCanvasContext
;
101 * This method creates new ChartGraphicDataContext Object.
103 uno::Reference
<xml::sax::XFastContextHandler
> const & ShapeContextHandler::getChartShapeContext(sal_Int32 nElement
)
105 if (!mxChartShapeContext
.is())
107 switch (nElement
& 0xffff)
111 std::unique_ptr
<ContextHandler2Helper
> pFragmentHandler(
112 new ShapeFragmentHandler(*mxFilterBase
, msRelationFragmentPath
));
113 mpShape
.reset(new Shape("com.sun.star.drawing.OLE2Shape" ));
114 mxChartShapeContext
.set(new ChartGraphicDataContext(*pFragmentHandler
, mpShape
, true));
122 return mxChartShapeContext
;
125 uno::Reference
<xml::sax::XFastContextHandler
> const & ShapeContextHandler::getWpsContext(sal_Int32 nStartElement
, sal_Int32 nElement
)
127 if (!mxWpsContext
.is())
129 FragmentHandler2Ref
rFragmentHandler(new ShapeFragmentHandler(*mxFilterBase
, msRelationFragmentPath
));
130 ShapePtr pMasterShape
;
132 uno::Reference
<drawing::XShape
> xShape
;
133 // No element happens in case of pretty-printed XML, bodyPr is the case when we are called again after <wps:txbx>.
134 if (!nElement
|| nElement
== WPS_TOKEN(bodyPr
))
135 // Assume that this is just a continuation of the previous shape.
136 xShape
= mxSavedShape
;
138 switch (getBaseToken(nStartElement
))
141 mxWpsContext
.set(new WpsContext(*rFragmentHandler
, xShape
));
151 uno::Reference
<xml::sax::XFastContextHandler
> const & ShapeContextHandler::getWpgContext(sal_Int32 nElement
)
153 if (!mxWpgContext
.is())
155 FragmentHandler2Ref
rFragmentHandler(new ShapeFragmentHandler(*mxFilterBase
, msRelationFragmentPath
));
156 ShapePtr pMasterShape
;
158 switch (getBaseToken(nElement
))
161 mxWpgContext
.set(new WpgContext(*rFragmentHandler
));
171 uno::Reference
<xml::sax::XFastContextHandler
> const &
172 ShapeContextHandler::getGraphicShapeContext(::sal_Int32 Element
)
174 if (! mxGraphicShapeContext
.is())
176 std::shared_ptr
<ContextHandler2Helper
> pFragmentHandler
177 (new ShapeFragmentHandler(*mxFilterBase
, msRelationFragmentPath
));
178 ShapePtr pMasterShape
;
180 switch (Element
& 0xffff)
183 mpShape
.reset(new Shape("com.sun.star.drawing.GraphicObjectShape" ));
184 mxGraphicShapeContext
.set
185 (new GraphicalObjectFrameContext(*pFragmentHandler
, pMasterShape
, mpShape
, true));
188 mpShape
.reset(new Shape("com.sun.star.drawing.GraphicObjectShape" ));
189 mxGraphicShapeContext
.set
190 (new GraphicShapeContext(*pFragmentHandler
, pMasterShape
, mpShape
));
197 return mxGraphicShapeContext
;
200 uno::Reference
<xml::sax::XFastContextHandler
> const &
201 ShapeContextHandler::getDrawingShapeContext()
203 if (!mxDrawingFragmentHandler
.is())
205 mpDrawing
.reset( new oox::vml::Drawing( *mxFilterBase
, mxDrawPage
, oox::vml::VMLDRAWING_WORD
) );
206 mxDrawingFragmentHandler
.set
207 (dynamic_cast<ContextHandler
*>
208 (new oox::vml::DrawingFragment
209 ( *mxFilterBase
, msRelationFragmentPath
, *mpDrawing
)));
213 // Reset the handler if fragment path has changed
214 OUString sHandlerFragmentPath
= dynamic_cast<ContextHandler
&>(*mxDrawingFragmentHandler
.get()).getFragmentPath();
215 if ( !msRelationFragmentPath
.equals(sHandlerFragmentPath
) )
217 mxDrawingFragmentHandler
.clear();
218 mxDrawingFragmentHandler
.set
219 (dynamic_cast<ContextHandler
*>
220 (new oox::vml::DrawingFragment
221 ( *mxFilterBase
, msRelationFragmentPath
, *mpDrawing
)));
224 return mxDrawingFragmentHandler
;
227 uno::Reference
<xml::sax::XFastContextHandler
> const &
228 ShapeContextHandler::getDiagramShapeContext()
230 if (!mxDiagramShapeContext
.is())
232 std::shared_ptr
<ContextHandler2Helper
> pFragmentHandler(new ShapeFragmentHandler(*mxFilterBase
, msRelationFragmentPath
));
233 mpShape
.reset(new Shape());
234 mxDiagramShapeContext
.set(new DiagramGraphicDataContext(*pFragmentHandler
, mpShape
));
237 return mxDiagramShapeContext
;
240 uno::Reference
<xml::sax::XFastContextHandler
>
241 ShapeContextHandler::getContextHandler(sal_Int32 nElement
)
243 uno::Reference
<xml::sax::XFastContextHandler
> xResult
;
245 switch (getNamespace( mnStartToken
))
249 xResult
.set(getDrawingShapeContext());
251 case NMSP_dmlDiagram
:
252 xResult
.set(getDiagramShapeContext());
254 case NMSP_dmlLockedCanvas
:
255 xResult
.set(getLockedCanvasContext(mnStartToken
));
258 xResult
.set(getChartShapeContext(mnStartToken
));
261 xResult
.set(getWpsContext(mnStartToken
, nElement
));
264 xResult
.set(getWpgContext(mnStartToken
));
267 xResult
.set(getGraphicShapeContext(mnStartToken
));
274 // css::xml::sax::XFastContextHandler:
275 void SAL_CALL
ShapeContextHandler::startFastElement
276 (::sal_Int32 Element
,
277 const uno::Reference
< xml::sax::XFastAttributeList
> & Attribs
)
279 mxFilterBase
->filter(maMediaDescriptor
);
281 mpThemePtr
.reset(new Theme());
283 if (Element
== DGM_TOKEN(relIds
) || Element
== LC_TOKEN(lockedCanvas
) || Element
== C_TOKEN(chart
) ||
284 Element
== WPS_TOKEN(wsp
) || Element
== WPG_TOKEN(wgp
) || Element
== OOX_TOKEN(dmlPicture
, pic
))
286 // Parse the theme relation, if available; the diagram won't have colors without it.
287 if (!msRelationFragmentPath
.isEmpty())
289 // Get Target for Type = "officeDocument" from _rels/.rels file
290 // aOfficeDocumentFragmentPath is pointing to "word/document.xml" for docx & to "ppt/presentation.xml" for pptx
291 FragmentHandlerRef
rFragmentHandlerRef(new ShapeFragmentHandler(*mxFilterBase
, "/"));
292 OUString aOfficeDocumentFragmentPath
= rFragmentHandlerRef
->getFragmentPathFromFirstTypeFromOfficeDoc( "officeDocument" );
294 // Get the theme DO NOT use msRelationFragmentPath for getting theme as for a document there is a single theme in document.xml.rels
295 // and the same is used by header and footer as well.
296 FragmentHandlerRef
rFragmentHandler(new ShapeFragmentHandler(*mxFilterBase
, aOfficeDocumentFragmentPath
));
297 OUString aThemeFragmentPath
= rFragmentHandler
->getFragmentPathFromFirstTypeFromOfficeDoc( "theme" );
299 if(!aThemeFragmentPath
.isEmpty())
301 uno::Reference
<xml::sax::XFastSAXSerializable
> xDoc(mxFilterBase
->importFragment(aThemeFragmentPath
), uno::UNO_QUERY_THROW
);
302 mxFilterBase
->importFragment(new ThemeFragmentHandler(*mxFilterBase
, aThemeFragmentPath
, *mpThemePtr
), xDoc
);
303 ShapeFilterBase
* pShapeFilterBase(dynamic_cast<ShapeFilterBase
*>(mxFilterBase
.get()));
304 if (pShapeFilterBase
)
305 pShapeFilterBase
->setCurrentTheme(mpThemePtr
);
309 createFastChildContext(Element
, Attribs
);
312 // Entering VML block (startFastElement() is called for the outermost tag),
313 // handle possible recursion.
314 if ( getContextHandler() == getDrawingShapeContext() )
315 mpDrawing
->getShapes().pushMark();
317 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
319 if (xContextHandler
.is())
320 xContextHandler
->startFastElement(Element
, Attribs
);
323 void SAL_CALL
ShapeContextHandler::startUnknownElement
324 (const OUString
& Namespace
, const OUString
& Name
,
325 const uno::Reference
< xml::sax::XFastAttributeList
> & Attribs
)
327 if ( getContextHandler() == getDrawingShapeContext() )
328 mpDrawing
->getShapes().pushMark();
330 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
332 if (xContextHandler
.is())
333 xContextHandler
->startUnknownElement(Namespace
, Name
, Attribs
);
336 void SAL_CALL
ShapeContextHandler::endFastElement(::sal_Int32 Element
)
338 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
340 if (xContextHandler
.is())
341 xContextHandler
->endFastElement(Element
);
342 // In case a textbox is sent, and later we get additional properties for
343 // the textbox, then the wps context is not cleared, so do that here.
344 if (Element
== (NMSP_wps
| XML_wsp
))
346 uno::Reference
<lang::XServiceInfo
> xServiceInfo(mxSavedShape
, uno::UNO_QUERY
);
347 bool bTextFrame
= xServiceInfo
.is() && xServiceInfo
->supportsService("com.sun.star.text.TextFrame");
348 bool bTextBox
= false;
351 uno::Reference
<beans::XPropertySet
> xPropertySet(mxSavedShape
, uno::UNO_QUERY
);
352 if (xPropertySet
.is())
353 xPropertySet
->getPropertyValue("TextBox") >>= bTextBox
;
355 if (bTextFrame
|| bTextBox
)
356 mxWpsContext
.clear();
357 mxSavedShape
.clear();
361 void SAL_CALL
ShapeContextHandler::endUnknownElement
362 (const OUString
& Namespace
,
363 const OUString
& Name
)
365 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
367 if (xContextHandler
.is())
368 xContextHandler
->endUnknownElement(Namespace
, Name
);
371 uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
372 ShapeContextHandler::createFastChildContext
373 (::sal_Int32 Element
,
374 const uno::Reference
< xml::sax::XFastAttributeList
> & Attribs
)
376 uno::Reference
< xml::sax::XFastContextHandler
> xResult
;
377 uno::Reference
< xml::sax::XFastContextHandler
> xContextHandler(getContextHandler(Element
));
379 if (xContextHandler
.is())
380 xResult
.set(xContextHandler
->createFastChildContext
386 uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
387 ShapeContextHandler::createUnknownChildContext
388 (const OUString
& Namespace
,
389 const OUString
& Name
,
390 const uno::Reference
< xml::sax::XFastAttributeList
> & Attribs
)
392 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
394 if (xContextHandler
.is())
395 return xContextHandler
->createUnknownChildContext
396 (Namespace
, Name
, Attribs
);
398 return uno::Reference
< xml::sax::XFastContextHandler
>();
401 void SAL_CALL
ShapeContextHandler::characters(const OUString
& aChars
)
403 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
405 if (xContextHandler
.is())
406 xContextHandler
->characters(aChars
);
409 // css::xml::sax::XFastShapeContextHandler:
410 uno::Reference
< drawing::XShape
> SAL_CALL
411 ShapeContextHandler::getShape()
413 uno::Reference
< drawing::XShape
> xResult
;
414 uno::Reference
< drawing::XShapes
> xShapes( mxDrawPage
, uno::UNO_QUERY
);
416 if (mxFilterBase
.is() && xShapes
.is())
418 if ( getContextHandler() == getDrawingShapeContext() )
420 mpDrawing
->finalizeFragmentImport();
421 if( std::shared_ptr
< vml::ShapeBase
> pShape
= mpDrawing
->getShapes().takeLastShape() )
422 xResult
= pShape
->convertAndInsert( xShapes
);
423 // Only now remove the recursion mark, because getShape() is called in writerfilter
424 // after endFastElement().
425 mpDrawing
->getShapes().popMark();
427 else if (mxDiagramShapeContext
.is())
429 basegfx::B2DHomMatrix aMatrix
;
430 if (mpShape
->getExtDrawings().empty())
432 mpShape
->addShape( *mxFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, mpShape
->getFillProperties() );
433 xResult
= mpShape
->getXShape();
437 // Prerendered diagram output is available, then use that, and throw away the original result.
438 for (std::vector
<OUString
>::const_iterator aIt
= mpShape
->getExtDrawings().begin(); aIt
!= mpShape
->getExtDrawings().end(); ++aIt
)
440 DiagramGraphicDataContext
* pDiagramGraphicDataContext
= dynamic_cast<DiagramGraphicDataContext
*>(mxDiagramShapeContext
.get());
441 if (!pDiagramGraphicDataContext
)
443 OUString
aFragmentPath(pDiagramGraphicDataContext
->getFragmentPathFromRelId(*aIt
));
444 oox::drawingml::ShapePtr
pShapePtr( new Shape( "com.sun.star.drawing.GroupShape" ) );
445 pShapePtr
->setDiagramType();
446 mxFilterBase
->importFragment(new ShapeDrawingFragmentHandler(*mxFilterBase
, aFragmentPath
, pShapePtr
));
448 uno::Sequence
<beans::PropertyValue
> aValue(mpShape
->getDiagramDoms());
449 uno::Sequence
< uno::Any
> diagramDrawing(2);
450 // drawingValue[0] => dom, drawingValue[1] => Sequence of associated relationships
452 sal_Int32 length
= aValue
.getLength();
453 aValue
.realloc(length
+1);
455 diagramDrawing
[0] <<= mxFilterBase
->importFragment( aFragmentPath
);
456 diagramDrawing
[1] <<= pShapePtr
->resolveRelationshipsOfTypeFromOfficeDoc(
457 *mxFilterBase
, aFragmentPath
, "image" );
459 beans::PropertyValue
* pValue
= aValue
.getArray();
460 pValue
[length
].Name
= "OOXDrawing";
461 pValue
[length
].Value
<<= diagramDrawing
;
463 pShapePtr
->setDiagramDoms( aValue
);
465 pShapePtr
->addShape( *mxFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, pShapePtr
->getFillProperties() );
466 xResult
= pShapePtr
->getXShape();
470 mxDiagramShapeContext
.clear();
472 else if (mxLockedCanvasContext
.is())
474 ShapePtr pShape
= dynamic_cast<LockedCanvasContext
&>(*mxLockedCanvasContext
.get()).getShape();
477 basegfx::B2DHomMatrix aMatrix
;
478 pShape
->addShape(*mxFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, pShape
->getFillProperties());
479 xResult
= pShape
->getXShape();
480 mxLockedCanvasContext
.clear();
483 //NMSP_dmlChart == getNamespace( mnStartToken ) check is introduced to make sure that
484 //mnStartToken is set as NMSP_dmlChart in setStartToken.
485 //Only in case it is set then only the below block of code for ChartShapeContext should be executed.
486 else if (mxChartShapeContext
.is() && (NMSP_dmlChart
== getNamespace( mnStartToken
)))
488 ChartGraphicDataContext
* pChartGraphicDataContext
= dynamic_cast<ChartGraphicDataContext
*>(mxChartShapeContext
.get());
489 if (pChartGraphicDataContext
)
491 basegfx::B2DHomMatrix aMatrix
;
492 oox::drawingml::ShapePtr
xShapePtr( pChartGraphicDataContext
->getShape());
493 // See SwXTextDocument::createInstance(), ODF import uses the same hack.
494 xShapePtr
->setServiceName("com.sun.star.drawing.temporaryForXMLImportOLE2Shape");
495 xShapePtr
->addShape( *mxFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, xShapePtr
->getFillProperties() );
496 xResult
= xShapePtr
->getXShape();
498 mxChartShapeContext
.clear();
500 else if (mxWpsContext
.is())
502 ShapePtr pShape
= dynamic_cast<WpsContext
&>(*mxWpsContext
.get()).getShape();
505 basegfx::B2DHomMatrix aMatrix
;
506 pShape
->setPosition(maPosition
);
507 pShape
->addShape(*mxFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, pShape
->getFillProperties());
508 xResult
= pShape
->getXShape();
509 mxSavedShape
= xResult
;
510 mxWpsContext
.clear();
513 else if (mxWpgContext
.is())
515 ShapePtr pShape
= dynamic_cast<WpgContext
&>(*mxWpgContext
.get()).getShape();
518 basegfx::B2DHomMatrix aMatrix
;
519 pShape
->setPosition(maPosition
);
520 pShape
->addShape(*mxFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, pShape
->getFillProperties());
521 xResult
= pShape
->getXShape();
522 mxWpgContext
.clear();
525 else if (mpShape
.get() != nullptr)
527 basegfx::B2DHomMatrix aTransformation
;
528 mpShape
->addShape(*mxFilterBase
, mpThemePtr
.get(), xShapes
, aTransformation
, mpShape
->getFillProperties() );
529 xResult
.set(mpShape
->getXShape());
530 mxGraphicShapeContext
.clear( );
537 css::uno::Reference
< css::drawing::XDrawPage
> SAL_CALL
538 ShapeContextHandler::getDrawPage()
543 void SAL_CALL
ShapeContextHandler::setDrawPage
544 (const css::uno::Reference
< css::drawing::XDrawPage
> & the_value
)
546 mxDrawPage
= the_value
;
549 css::uno::Reference
< css::frame::XModel
> SAL_CALL
550 ShapeContextHandler::getModel()
552 if( !mxFilterBase
.is() )
553 throw uno::RuntimeException();
554 return mxFilterBase
->getModel();
557 void SAL_CALL
ShapeContextHandler::setModel
558 (const css::uno::Reference
< css::frame::XModel
> & the_value
)
560 if( !mxFilterBase
.is() )
561 throw uno::RuntimeException();
562 uno::Reference
<lang::XComponent
> xComp(the_value
, uno::UNO_QUERY_THROW
);
563 mxFilterBase
->setTargetDocument(xComp
);
566 OUString SAL_CALL
ShapeContextHandler::getRelationFragmentPath()
568 return msRelationFragmentPath
;
571 void SAL_CALL
ShapeContextHandler::setRelationFragmentPath(const OUString
& the_value
)
573 msRelationFragmentPath
= the_value
;
576 ::sal_Int32 SAL_CALL
ShapeContextHandler::getStartToken()
581 void SAL_CALL
ShapeContextHandler::setStartToken( ::sal_Int32 _starttoken
)
583 mnStartToken
= _starttoken
;
586 awt::Point SAL_CALL
ShapeContextHandler::getPosition()
591 void SAL_CALL
ShapeContextHandler::setPosition(const awt::Point
& rPosition
)
593 maPosition
= rPosition
;
596 void SAL_CALL
ShapeContextHandler::setDocumentProperties(const uno::Reference
<document::XDocumentProperties
>& xDocProps
)
598 mxDocumentProperties
= xDocProps
;
599 mxFilterBase
->checkDocumentProperties(mxDocumentProperties
);
602 uno::Reference
<document::XDocumentProperties
> SAL_CALL
ShapeContextHandler::getDocumentProperties()
604 return mxDocumentProperties
;
607 uno::Sequence
<beans::PropertyValue
> SAL_CALL
ShapeContextHandler::getMediaDescriptor()
609 return maMediaDescriptor
;
612 void SAL_CALL
ShapeContextHandler::setMediaDescriptor(const uno::Sequence
<beans::PropertyValue
>& rMediaDescriptor
)
614 maMediaDescriptor
= rMediaDescriptor
;
617 OUString
ShapeContextHandler::getImplementationName()
619 return ShapeContextHandler_getImplementationName();
622 uno::Sequence
< OUString
> ShapeContextHandler::getSupportedServiceNames()
624 return ShapeContextHandler_getSupportedServiceNames();
627 sal_Bool SAL_CALL
ShapeContextHandler::supportsService(const OUString
& ServiceName
)
629 return cppu::supportsService(this, ServiceName
);
634 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */