Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / oox / source / shape / ShapeContextHandler.cxx
blob7665022c56dfd91fc4237c19a5bbff6e9d689325
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 <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>
38 #include <memory>
39 #include <utility>
41 using namespace ::com::sun::star;
43 namespace oox::shape {
44 using namespace core;
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));
68 break;
69 default:
70 break;
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)
86 case XML_chart:
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));
92 break;
94 default:
95 break;
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))
117 case XML_wsp:
118 mxWpsContext.set(new WpsContext(
119 *rFragmentHandler,
120 xShape,
121 pMasterShape,
122 std::make_shared<oox::drawingml::Shape>(
123 "com.sun.star.drawing.CustomShape")));
124 break;
125 default:
126 break;
130 return mxWpsContext;
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))
141 case XML_wgp:
143 mxWpgContext.set(new WpgContext(*rFragmentHandler, oox::drawingml::ShapePtr()));
144 mxWpgContext->setFullWPGSupport(m_bFullWPGSUpport);
145 break;
147 default:
148 break;
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)
165 case XML_graphic:
166 mpShape = std::make_shared<Shape>("com.sun.star.drawing.GraphicObjectShape" );
167 mxGraphicShapeContext.set
168 (new GraphicalObjectFrameContext(*pFragmentHandler, pMasterShape, mpShape, true));
169 break;
170 case XML_pic:
171 mpShape = std::make_shared<Shape>("com.sun.star.drawing.GraphicObjectShape" );
172 mxGraphicShapeContext.set
173 (new GraphicShapeContext(*pFragmentHandler, pMasterShape, mpShape));
174 break;
175 default:
176 break;
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 ));
193 else
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 ))
230 case NMSP_doc:
231 case NMSP_vml:
232 xResult.set(getDrawingShapeContext());
233 break;
234 case NMSP_dmlDiagram:
235 xResult.set(getDiagramShapeContext());
236 break;
237 case NMSP_dmlLockedCanvas:
238 xResult.set(getLockedCanvasContext(nStartToken));
239 break;
240 case NMSP_dmlChart:
241 xResult.set(getChartShapeContext(nStartToken));
242 break;
243 case NMSP_wps:
244 xResult.set(getWpsContext(nStartToken, nElement));
245 break;
246 case NMSP_wpg:
247 xResult.set(getWpgContext(nStartToken));
248 break;
249 default:
250 xResult.set(getGraphicShapeContext(nStartToken));
251 break;
254 return xResult;
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))
331 return;
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();
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
367 (Element, Attribs));
369 return xResult;
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();
420 else
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();
450 mpShape.reset();
452 mxDiagramShapeContext.clear();
454 else if (mxLockedCanvasContext.is())
456 ShapePtr pShape = mxLockedCanvasContext->getShape();
457 if (pShape)
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();
481 if (pShape)
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();
494 if (pShape)
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();
504 else if (mpShape)
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( );
522 if (xResult)
523 popStartToken();
524 return xResult;
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)
569 maSize = 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: */