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 <oox/shape/ShapeContextHandler.hxx>
25 #include <oox/shape/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/shape/ShapeFilterBase.hxx>
34 #include <oox/token/namespaces.hxx>
35 #include <oox/token/tokens.hxx>
36 #include <oox/drawingml/theme.hxx>
37 #include <oox/drawingml/themefragmenthandler.hxx>
41 using namespace ::com::sun::star
;
43 namespace oox::shape
{
45 using namespace drawingml
;
47 ShapeContextHandler::ShapeContextHandler(rtl::Reference
<ShapeFilterBase
> xFilterBase
) :
48 m_bFullWPGSUpport(false),
49 mxShapeFilterBase(std::move(xFilterBase
))
54 ShapeContextHandler::~ShapeContextHandler()
58 uno::Reference
<xml::sax::XFastContextHandler
> ShapeContextHandler::getLockedCanvasContext(sal_Int32 nElement
)
60 if (!mxLockedCanvasContext
.is())
62 FragmentHandler2Ref
rFragmentHandler(new ShapeFragmentHandler(*mxShapeFilterBase
, msRelationFragmentPath
));
64 switch (nElement
& 0xffff)
66 case XML_lockedCanvas
:
67 mxLockedCanvasContext
.set(new LockedCanvasContext(*rFragmentHandler
));
74 return static_cast<ContextHandler
*>(mxLockedCanvasContext
.get());
78 * This method creates new ChartGraphicDataContext Object.
80 uno::Reference
<xml::sax::XFastContextHandler
> ShapeContextHandler::getChartShapeContext(sal_Int32 nElement
)
82 if (!mxChartShapeContext
.is())
84 switch (nElement
& 0xffff)
88 std::unique_ptr
<ContextHandler2Helper
> pFragmentHandler(
89 new ShapeFragmentHandler(*mxShapeFilterBase
, msRelationFragmentPath
));
90 mpShape
= std::make_shared
<Shape
>("com.sun.star.drawing.OLE2Shape" );
91 mxChartShapeContext
.set(new ChartGraphicDataContext(*pFragmentHandler
, mpShape
, true));
99 return mxChartShapeContext
;
102 uno::Reference
<xml::sax::XFastContextHandler
> ShapeContextHandler::getWpsContext(sal_Int32 nStartElement
, sal_Int32 nElement
)
104 if (!mxWpsContext
.is())
106 FragmentHandler2Ref
rFragmentHandler(new ShapeFragmentHandler(*mxShapeFilterBase
, msRelationFragmentPath
));
107 ShapePtr pMasterShape
;
109 uno::Reference
<drawing::XShape
> xShape
;
110 // No element happens in case of pretty-printed XML, bodyPr is the case when we are called again after <wps:txbx>.
111 if (!nElement
|| nElement
== WPS_TOKEN(bodyPr
))
112 // Assume that this is just a continuation of the previous shape.
113 xShape
= mxSavedShape
;
115 switch (getBaseToken(nStartElement
))
118 mxWpsContext
.set(new WpsContext(
122 std::make_shared
<oox::drawingml::Shape
>(
123 "com.sun.star.drawing.CustomShape")));
133 uno::Reference
<xml::sax::XFastContextHandler
> ShapeContextHandler::getWpgContext(sal_Int32 nElement
)
135 if (!mxWpgContext
.is())
137 FragmentHandler2Ref
rFragmentHandler(new ShapeFragmentHandler(*mxShapeFilterBase
, msRelationFragmentPath
));
139 switch (getBaseToken(nElement
))
143 mxWpgContext
.set(new WpgContext(*rFragmentHandler
, oox::drawingml::ShapePtr()));
144 mxWpgContext
->setFullWPGSupport(m_bFullWPGSUpport
);
152 return static_cast<ContextHandler
*>(mxWpgContext
.get());
155 uno::Reference
<xml::sax::XFastContextHandler
> const &
156 ShapeContextHandler::getGraphicShapeContext(::sal_Int32 Element
)
158 if (! mxGraphicShapeContext
.is())
160 auto pFragmentHandler
= std::make_shared
<ShapeFragmentHandler
>(*mxShapeFilterBase
, msRelationFragmentPath
);
161 ShapePtr pMasterShape
;
163 switch (Element
& 0xffff)
166 mpShape
= std::make_shared
<Shape
>("com.sun.star.drawing.GraphicObjectShape" );
167 mxGraphicShapeContext
.set
168 (new GraphicalObjectFrameContext(*pFragmentHandler
, pMasterShape
, mpShape
, true));
171 mpShape
= std::make_shared
<Shape
>("com.sun.star.drawing.GraphicObjectShape" );
172 mxGraphicShapeContext
.set
173 (new GraphicShapeContext(*pFragmentHandler
, pMasterShape
, mpShape
));
180 return mxGraphicShapeContext
;
183 uno::Reference
<xml::sax::XFastContextHandler
>
184 ShapeContextHandler::getDrawingShapeContext()
186 if (!mxDrawingFragmentHandler
.is())
188 mpDrawing
= std::make_shared
<oox::vml::Drawing
>( *mxShapeFilterBase
, mxDrawPage
, oox::vml::VMLDRAWING_WORD
);
189 mxDrawingFragmentHandler
.set
190 (new oox::vml::DrawingFragment
191 ( *mxShapeFilterBase
, msRelationFragmentPath
, *mpDrawing
));
195 // Reset the handler if fragment path has changed
196 OUString sHandlerFragmentPath
= mxDrawingFragmentHandler
->getFragmentPath();
197 if ( msRelationFragmentPath
!= sHandlerFragmentPath
)
199 mxDrawingFragmentHandler
.clear();
200 mxDrawingFragmentHandler
.set
201 (new oox::vml::DrawingFragment
202 ( *mxShapeFilterBase
, msRelationFragmentPath
, *mpDrawing
));
205 return static_cast<ContextHandler
*>(mxDrawingFragmentHandler
.get());
208 uno::Reference
<xml::sax::XFastContextHandler
>
209 ShapeContextHandler::getDiagramShapeContext()
211 if (!mxDiagramShapeContext
.is())
213 auto pFragmentHandler
= std::make_shared
<ShapeFragmentHandler
>(*mxShapeFilterBase
, msRelationFragmentPath
);
214 mpShape
= std::make_shared
<Shape
>();
215 mpShape
->setSize(maSize
);
216 mxDiagramShapeContext
.set(new DiagramGraphicDataContext(*pFragmentHandler
, mpShape
));
219 return mxDiagramShapeContext
;
222 uno::Reference
<xml::sax::XFastContextHandler
>
223 ShapeContextHandler::getContextHandler(sal_Int32 nElement
)
225 uno::Reference
<xml::sax::XFastContextHandler
> xResult
;
226 const sal_uInt32 nStartToken
= getStartToken();
228 switch (getNamespace( nStartToken
))
232 xResult
.set(getDrawingShapeContext());
234 case NMSP_dmlDiagram
:
235 xResult
.set(getDiagramShapeContext());
237 case NMSP_dmlLockedCanvas
:
238 xResult
.set(getLockedCanvasContext(nStartToken
));
241 xResult
.set(getChartShapeContext(nStartToken
));
244 xResult
.set(getWpsContext(nStartToken
, nElement
));
247 xResult
.set(getWpgContext(nStartToken
));
250 xResult
.set(getGraphicShapeContext(nStartToken
));
257 // css::xml::sax::XFastContextHandler:
258 void SAL_CALL
ShapeContextHandler::startFastElement
259 (::sal_Int32 Element
,
260 const uno::Reference
< xml::sax::XFastAttributeList
> & Attribs
)
262 mxShapeFilterBase
->filter(maMediaDescriptor
);
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 (!mpThemePtr
&& !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(*mxShapeFilterBase
, "/"));
273 OUString aOfficeDocumentFragmentPath
= rFragmentHandlerRef
->getFragmentPathFromFirstTypeFromOfficeDoc( u
"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(*mxShapeFilterBase
, aOfficeDocumentFragmentPath
));
278 OUString aThemeFragmentPath
= rFragmentHandler
->getFragmentPathFromFirstTypeFromOfficeDoc( u
"theme" );
280 if (!aThemeFragmentPath
.isEmpty())
282 mpThemePtr
= std::make_shared
<Theme
>();
283 auto pTheme
= std::make_shared
<model::Theme
>();
284 mpThemePtr
->setTheme(pTheme
);
285 uno::Reference
<xml::sax::XFastSAXSerializable
> xDoc(mxShapeFilterBase
->importFragment(aThemeFragmentPath
), uno::UNO_QUERY_THROW
);
286 mxShapeFilterBase
->importFragment(new ThemeFragmentHandler(*mxShapeFilterBase
, aThemeFragmentPath
, *mpThemePtr
, *pTheme
), xDoc
);
287 mxShapeFilterBase
->setCurrentTheme(mpThemePtr
);
290 else if (mpThemePtr
&& !mxShapeFilterBase
->getCurrentTheme())
292 mxShapeFilterBase
->setCurrentTheme(mpThemePtr
);
295 createFastChildContext(Element
, Attribs
);
298 // Entering VML block (startFastElement() is called for the outermost tag),
299 // handle possible recursion.
300 if ( getContextHandler() == getDrawingShapeContext() )
301 mpDrawing
->getShapes().pushMark();
303 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
305 if (xContextHandler
.is())
306 xContextHandler
->startFastElement(Element
, Attribs
);
309 void SAL_CALL
ShapeContextHandler::startUnknownElement
310 (const OUString
& Namespace
, const OUString
& Name
,
311 const uno::Reference
< xml::sax::XFastAttributeList
> & Attribs
)
313 if ( getContextHandler() == getDrawingShapeContext() )
314 mpDrawing
->getShapes().pushMark();
316 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
318 if (xContextHandler
.is())
319 xContextHandler
->startUnknownElement(Namespace
, Name
, Attribs
);
322 void SAL_CALL
ShapeContextHandler::endFastElement(::sal_Int32 Element
)
324 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
326 if (xContextHandler
.is())
327 xContextHandler
->endFastElement(Element
);
328 // In case a textbox is sent, and later we get additional properties for
329 // the textbox, then the wps context is not cleared, so do that here.
330 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();
347 void SAL_CALL
ShapeContextHandler::endUnknownElement
348 (const OUString
& Namespace
,
349 const OUString
& Name
)
351 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
353 if (xContextHandler
.is())
354 xContextHandler
->endUnknownElement(Namespace
, Name
);
357 uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
358 ShapeContextHandler::createFastChildContext
359 (::sal_Int32 Element
,
360 const uno::Reference
< xml::sax::XFastAttributeList
> & Attribs
)
362 uno::Reference
< xml::sax::XFastContextHandler
> xResult
;
363 uno::Reference
< xml::sax::XFastContextHandler
> xContextHandler(getContextHandler(Element
));
365 if (xContextHandler
.is())
366 xResult
.set(xContextHandler
->createFastChildContext
372 uno::Reference
< xml::sax::XFastContextHandler
> SAL_CALL
373 ShapeContextHandler::createUnknownChildContext
374 (const OUString
& Namespace
,
375 const OUString
& Name
,
376 const uno::Reference
< xml::sax::XFastAttributeList
> & Attribs
)
378 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
380 if (xContextHandler
.is())
381 return xContextHandler
->createUnknownChildContext
382 (Namespace
, Name
, Attribs
);
384 return uno::Reference
< xml::sax::XFastContextHandler
>();
387 void SAL_CALL
ShapeContextHandler::characters(const OUString
& aChars
)
389 uno::Reference
<XFastContextHandler
> xContextHandler(getContextHandler());
391 if (xContextHandler
.is())
392 xContextHandler
->characters(aChars
);
395 uno::Reference
< drawing::XShape
>
396 ShapeContextHandler::getShape()
398 uno::Reference
< drawing::XShape
> xResult
;
399 uno::Reference
< drawing::XShapes
> xShapes
= mxDrawPage
;
401 if (mxShapeFilterBase
&& xShapes
.is())
403 if ( getContextHandler() == getDrawingShapeContext() )
405 mpDrawing
->finalizeFragmentImport();
406 if( std::shared_ptr
< vml::ShapeBase
> pShape
= mpDrawing
->getShapes().takeLastShape() )
407 xResult
= pShape
->convertAndInsert( xShapes
);
408 // Only now remove the recursion mark, because getShape() is called in writerfilter
409 // after endFastElement().
410 mpDrawing
->getShapes().popMark();
412 else if (mxDiagramShapeContext
.is())
414 basegfx::B2DHomMatrix aMatrix
;
415 if (mpShape
->getExtDrawings().empty())
417 mpShape
->addShape( *mxShapeFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, mpShape
->getFillProperties() );
418 xResult
= mpShape
->getXShape();
422 // Prerendered diagram output is available, then use that, and throw away the original result.
423 for (auto const& extDrawing
: mpShape
->getExtDrawings())
425 OUString
aFragmentPath(mxDiagramShapeContext
->getFragmentPathFromRelId(extDrawing
));
426 oox::drawingml::ShapePtr pShapePtr
= std::make_shared
<Shape
>( "com.sun.star.drawing.GroupShape" );
427 pShapePtr
->setDiagramType();
428 mxShapeFilterBase
->importFragment(new ShapeDrawingFragmentHandler(*mxShapeFilterBase
, aFragmentPath
, pShapePtr
));
429 pShapePtr
->setDiagramDoms(mpShape
->getDiagramDoms());
430 pShapePtr
->keepDiagramDrawing(*mxShapeFilterBase
, aFragmentPath
);
432 if (mpShape
->getFontRefColorForNodes().isUsed())
433 applyFontRefColor(pShapePtr
, mpShape
->getFontRefColorForNodes());
435 // migrate IDiagramHelper to new oox::Shape (from mpShape which was loaded
436 // to pShapePtr where the geometry is now constructed)
437 mpShape
->migrateDiagramHelperToNewShape(pShapePtr
);
439 if (!mpShape
->getChildren().empty())
441 // first child is diagram background - we want to keep it, as drawingML fallback doesn't contain it
442 auto& aChildren
= pShapePtr
->getChildren();
443 ShapePtr pBackground
= mpShape
->getChildren().front();
444 aChildren
.insert(aChildren
.begin(), pBackground
);
447 pShapePtr
->addShape( *mxShapeFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, pShapePtr
->getFillProperties() );
448 xResult
= pShapePtr
->getXShape();
452 mxDiagramShapeContext
.clear();
454 else if (mxLockedCanvasContext
.is())
456 ShapePtr pShape
= mxLockedCanvasContext
->getShape();
459 basegfx::B2DHomMatrix aMatrix
;
460 pShape
->addShape(*mxShapeFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, pShape
->getFillProperties());
461 xResult
= pShape
->getXShape();
462 mxLockedCanvasContext
.clear();
465 //NMSP_dmlChart == getNamespace( mnStartToken ) check is introduced to make sure that
466 //mnStartToken is set as NMSP_dmlChart in setStartToken.
467 //Only in case it is set then only the below block of code for ChartShapeContext should be executed.
468 else if (mxChartShapeContext
.is() && (NMSP_dmlChart
== getNamespace( getStartToken() )))
470 basegfx::B2DHomMatrix aMatrix
;
471 oox::drawingml::ShapePtr
xShapePtr( mxChartShapeContext
->getShape());
472 // See SwXTextDocument::createInstance(), ODF import uses the same hack.
473 xShapePtr
->setServiceName("com.sun.star.drawing.temporaryForXMLImportOLE2Shape");
474 xShapePtr
->addShape( *mxShapeFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, xShapePtr
->getFillProperties() );
475 xResult
= xShapePtr
->getXShape();
476 mxChartShapeContext
.clear();
478 else if (mxWpsContext
.is())
480 ShapePtr pShape
= mxWpsContext
->getShape();
483 basegfx::B2DHomMatrix aMatrix
;
484 pShape
->setPosition(maPosition
);
485 pShape
->addShape(*mxShapeFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, pShape
->getFillProperties());
486 xResult
= pShape
->getXShape();
487 mxSavedShape
= xResult
;
488 mxWpsContext
.clear();
491 else if (mxWpgContext
.is())
493 ShapePtr pShape
= mxWpgContext
->getShape();
496 basegfx::B2DHomMatrix aMatrix
;
497 pShape
->setPosition(maPosition
);
498 pShape
->addShape(*mxShapeFilterBase
, mpThemePtr
.get(), xShapes
, aMatrix
, pShape
->getFillProperties());
499 xResult
= pShape
->getXShape();
500 mxSavedShape
= xResult
;
501 mxWpgContext
.clear();
506 basegfx::B2DHomMatrix aTransformation
;
508 if (maPosition
.X
!= 0 || maPosition
.Y
!= 0)
510 // We got a position from writerfilter/, store that in the shape, otherwise the
511 // position won't be set.
512 mpShape
->setWps(true);
513 mpShape
->setPosition(maPosition
);
516 mpShape
->addShape(*mxShapeFilterBase
, mpThemePtr
.get(), xShapes
, aTransformation
, mpShape
->getFillProperties() );
517 xResult
.set(mpShape
->getXShape());
518 mxGraphicShapeContext
.clear( );
527 void ShapeContextHandler::setDrawPage(const css::uno::Reference
< css::drawing::XDrawPage
> & the_value
)
529 mxDrawPage
= the_value
;
532 void ShapeContextHandler::setModel(const css::uno::Reference
< css::frame::XModel
> & the_value
)
534 if( !mxShapeFilterBase
.is() )
535 throw uno::RuntimeException();
536 uno::Reference
<lang::XComponent
> xComp(the_value
, uno::UNO_QUERY_THROW
);
537 mxShapeFilterBase
->setTargetDocument(xComp
);
540 void ShapeContextHandler::setRelationFragmentPath(const OUString
& the_value
)
542 msRelationFragmentPath
= the_value
;
545 sal_Int32
ShapeContextHandler::getStartToken() const
547 assert(mnStartTokenStack
.size() && "This stack must not be empty!");
548 return mnStartTokenStack
.top();
551 void ShapeContextHandler::popStartToken()
553 if (mnStartTokenStack
.size() > 1)
554 mnStartTokenStack
.pop();
557 void ShapeContextHandler::pushStartToken( sal_Int32 _starttoken
)
559 mnStartTokenStack
.push(_starttoken
);
562 void ShapeContextHandler::setPosition(const awt::Point
& rPosition
)
564 maPosition
= rPosition
;
567 void ShapeContextHandler::setSize(const awt::Size
& rSize
)
572 void ShapeContextHandler::setDocumentProperties(const uno::Reference
<document::XDocumentProperties
>& xDocProps
)
574 mxDocumentProperties
= xDocProps
;
575 mxShapeFilterBase
->checkDocumentProperties(mxDocumentProperties
);
578 void ShapeContextHandler::setMediaDescriptor(const uno::Sequence
<beans::PropertyValue
>& rMediaDescriptor
)
580 maMediaDescriptor
= rMediaDescriptor
;
583 void ShapeContextHandler::setGraphicMapper(css::uno::Reference
<css::graphic::XGraphicMapper
> const & rxGraphicMapper
)
585 mxShapeFilterBase
->setGraphicMapper(rxGraphicMapper
);
588 void ShapeContextHandler::applyFontRefColor(const oox::drawingml::ShapePtr
& pShape
,
589 const oox::drawingml::Color
& rFontRefColor
)
591 pShape
->getShapeStyleRefs()[XML_fontRef
].maPhClr
= rFontRefColor
;
592 std::vector
<oox::drawingml::ShapePtr
>& vChildren
= pShape
->getChildren();
593 for (auto const& child
: vChildren
)
595 applyFontRefColor(child
, rFontRefColor
);
600 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */