1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20 #include <sal/config.h>
21
22 #include <string_view>
23
24 #include <oox/drawingml/graphicshapecontext.hxx>
25
26 #include <osl/diagnose.h>
27 #include <sal/log.hxx>
28
29 #include <drawingml/embeddedwavaudiofile.hxx>
30 #include <drawingml/misccontexts.hxx>
31 #include <drawingml/graphicproperties.hxx>
32 #include <drawingml/customshapeproperties.hxx>
33 #include <oox/drawingml/diagram/diagram.hxx>
34 #include <drawingml/table/tablecontext.hxx>
35 #include <oox/core/xmlfilterbase.hxx>
36 #include <oox/helper/attributelist.hxx>
37 #include <oox/vml/vmldrawing.hxx>
38 #include <drawingml/transform2dcontext.hxx>
39 #include <oox/ppt/pptshapegroupcontext.hxx>
40 #include <oox/token/namespaces.hxx>
41 #include <oox/token/tokens.hxx>
42
43 using namespace ::com::sun::star;
44 using namespace ::com::sun::star::io;
45 using namespace ::com::sun::star::uno;
46 using namespace ::com::sun::star::lang;
47 using namespace ::com::sun::star::beans;
48 using namespace ::com::sun::star::xml::sax;
49 using namespace ::oox::core;
50
51 static uno::Reference<io::XInputStream>
lcl_GetMediaStream(const OUString & rStream,const oox::core::XmlFilterBase & rFilter)52 lcl_GetMediaStream(const OUString& rStream, const oox::core::XmlFilterBase& rFilter)
53 {
54 if (rStream.isEmpty())
55 return nullptr;
56
57 Reference< XInputStream > xInStrm( rFilter.openInputStream(rStream), UNO_SET_THROW );
58 return xInStrm;
59 }
60
lcl_GetMediaReference(std::u16string_view rStream)61 static OUString lcl_GetMediaReference(std::u16string_view rStream)
62 {
63 return rStream.empty() ? OUString() : OUString::Concat("vnd.sun.star.Package:") + rStream;
64 }
65
66 namespace oox::drawingml {
67
68 // CT_Picture
69
GraphicShapeContext(ContextHandler2Helper const & rParent,const ShapePtr & pMasterShapePtr,const ShapePtr & pShapePtr)70 GraphicShapeContext::GraphicShapeContext( ContextHandler2Helper const & rParent, const ShapePtr& pMasterShapePtr, const ShapePtr& pShapePtr )
71 : ShapeContext( rParent, pMasterShapePtr, pShapePtr )
72 {
73 }
74
onCreateContext(sal_Int32 aElementToken,const AttributeList & rAttribs)75 ContextHandlerRef GraphicShapeContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
76 {
77 switch( getBaseToken( aElementToken ) )
78 {
79 // CT_ShapeProperties
80 case XML_xfrm:
81 return new Transform2DContext( *this, rAttribs, *mpShapePtr );
82 case XML_blipFill:
83 return new BlipFillContext( *this, rAttribs, mpShapePtr->getGraphicProperties().maBlipProps );
84 case XML_wavAudioFile:
85 {
86 OUString const path(getEmbeddedWAVAudioFile(getRelations(), rAttribs));
87 mpShapePtr->getGraphicProperties().m_xMediaStream =
88 lcl_GetMediaStream(path, getFilter());
89 mpShapePtr->getGraphicProperties().m_sMediaPackageURL =
90 lcl_GetMediaReference(path);
91 }
92 break;
93 case XML_audioFile:
94 case XML_videoFile:
95 {
96 OUString rPath = getRelations().getFragmentPathFromRelId(
97 rAttribs.getString(R_TOKEN(link)).get() );
98 mpShapePtr->getGraphicProperties().m_xMediaStream =
99 lcl_GetMediaStream(rPath, getFilter());
100 mpShapePtr->getGraphicProperties().m_sMediaPackageURL =
101 lcl_GetMediaReference(rPath);
102 }
103 break;
104 }
105
106 if ((getNamespace( aElementToken ) == NMSP_vml) && mpShapePtr)
107 {
108 mpShapePtr->setServiceName("com.sun.star.drawing.CustomShape");
109 CustomShapePropertiesPtr pCstmShpProps
110 (mpShapePtr->getCustomShapeProperties());
111
112 pCstmShpProps->setShapePresetType( getBaseToken( aElementToken ) );
113 }
114
115 return ShapeContext::onCreateContext( aElementToken, rAttribs );
116 }
117
118 // CT_GraphicalObjectFrameContext
119
GraphicalObjectFrameContext(ContextHandler2Helper & rParent,const ShapePtr & pMasterShapePtr,const ShapePtr & pShapePtr,bool bEmbedShapesInChart)120 GraphicalObjectFrameContext::GraphicalObjectFrameContext( ContextHandler2Helper& rParent, const ShapePtr& pMasterShapePtr, const ShapePtr& pShapePtr, bool bEmbedShapesInChart ) :
121 ShapeContext( rParent, pMasterShapePtr, pShapePtr ),
122 mbEmbedShapesInChart( bEmbedShapesInChart ),
123 mpParent(&rParent)
124 {
125 }
126
onCreateContext(sal_Int32 aElementToken,const AttributeList & rAttribs)127 ContextHandlerRef GraphicalObjectFrameContext::onCreateContext( sal_Int32 aElementToken, const AttributeList& rAttribs )
128 {
129 switch( getBaseToken( aElementToken ) )
130 {
131 // CT_ShapeProperties
132 case XML_nvGraphicFramePr: // CT_GraphicalObjectFrameNonVisual
133 break;
134 case XML_xfrm: // CT_Transform2D
135 return new Transform2DContext( *this, rAttribs, *mpShapePtr );
136 case XML_graphic: // CT_GraphicalObject
137 return this;
138
139 case XML_graphicData : // CT_GraphicalObjectData
140 {
141 OUString sUri( rAttribs.getString( XML_uri ).get() );
142 if ( sUri == "http://schemas.openxmlformats.org/presentationml/2006/ole" ||
143 sUri == "http://purl.oclc.org/ooxml/presentationml/ole" )
144 return new OleObjectGraphicDataContext( *this, mpShapePtr );
145 else if ( sUri == "http://schemas.openxmlformats.org/drawingml/2006/diagram" ||
146 sUri == "http://purl.oclc.org/ooxml/drawingml/diagram" )
147 return new DiagramGraphicDataContext( *this, mpShapePtr );
148 else if ( sUri == "http://schemas.openxmlformats.org/drawingml/2006/chart" ||
149 sUri == "http://purl.oclc.org/ooxml/drawingml/chart" )
150 return new ChartGraphicDataContext( *this, mpShapePtr, mbEmbedShapesInChart );
151 else if ( sUri == "http://schemas.openxmlformats.org/drawingml/2006/table" ||
152 sUri == "http://purl.oclc.org/ooxml/drawingml/table" )
153 return new table::TableContext( *this, mpShapePtr );
154 else
155 {
156 SAL_WARN("oox.drawingml", "OOX: Ignore graphicsData of :" << sUri );
157 return nullptr;
158 }
159 }
160 break;
161 }
162
163 return ShapeContext::onCreateContext( aElementToken, rAttribs );
164 }
165
onEndElement()166 void GraphicalObjectFrameContext::onEndElement()
167 {
168 if( getCurrentElement() == PPT_TOKEN( graphicFrame ) && mpParent )
169 {
170 oox::ppt::PPTShapeGroupContext* pParent = dynamic_cast<oox::ppt::PPTShapeGroupContext*>(mpParent);
171 if( pParent )
172 pParent->importExtDrawings();
173 }
174 }
175
OleObjectGraphicDataContext(ContextHandler2Helper const & rParent,const ShapePtr & xShape)176 OleObjectGraphicDataContext::OleObjectGraphicDataContext( ContextHandler2Helper const & rParent, const ShapePtr& xShape ) :
177 ShapeContext( rParent, ShapePtr(), xShape ),
178 mrOleObjectInfo( xShape->setOleObjectType() )
179 {
180 }
181
~OleObjectGraphicDataContext()182 OleObjectGraphicDataContext::~OleObjectGraphicDataContext()
183 {
184 /* Register the OLE shape at the VML drawing, this prevents that the
185 related VML shape converts the OLE object by itself. */
186 if( !mrOleObjectInfo.maShapeId.isEmpty() )
187 if( ::oox::vml::Drawing* pVmlDrawing = getFilter().getVmlDrawing() )
188 pVmlDrawing->registerOleObject( mrOleObjectInfo );
189 }
190
onCreateContext(sal_Int32 nElement,const AttributeList & rAttribs)191 ContextHandlerRef OleObjectGraphicDataContext::onCreateContext( sal_Int32 nElement, const AttributeList& rAttribs )
192 {
193 switch( nElement )
194 {
195 case PPT_TOKEN( oleObj ):
196 {
197 mrOleObjectInfo.maShapeId = rAttribs.getXString( XML_spid, OUString() );
198 const Relation* pRelation = getRelations().getRelationFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
199 OSL_ENSURE( pRelation, "OleObjectGraphicDataContext::createFastChildContext - missing relation for OLE object" );
200 if( pRelation )
201 {
202 mrOleObjectInfo.mbLinked = pRelation->mbExternal;
203 if( pRelation->mbExternal )
204 {
205 mrOleObjectInfo.maTargetLink = getFilter().getAbsoluteUrl( pRelation->maTarget );
206 }
207 else
208 {
209 OUString aFragmentPath = getFragmentPathFromRelation( *pRelation );
210 if( !aFragmentPath.isEmpty() )
211 getFilter().importBinaryData( mrOleObjectInfo.maEmbeddedData, aFragmentPath );
212 }
213 }
214 mrOleObjectInfo.maName = rAttribs.getXString( XML_name, OUString() );
215 mrOleObjectInfo.maProgId = rAttribs.getXString( XML_progId, OUString() );
216 mrOleObjectInfo.mbShowAsIcon = rAttribs.getBool( XML_showAsIcon, false );
217 return this;
218 }
219 break;
220
221 case PPT_TOKEN( embed ):
222 OSL_ENSURE( !mrOleObjectInfo.mbLinked, "OleObjectGraphicDataContext::createFastChildContext - unexpected child element" );
223 break;
224
225 case PPT_TOKEN( link ):
226 OSL_ENSURE( mrOleObjectInfo.mbLinked, "OleObjectGraphicDataContext::createFastChildContext - unexpected child element" );
227 mrOleObjectInfo.mbAutoUpdate = rAttribs.getBool( XML_updateAutomatic, false );
228 break;
229 case PPT_TOKEN( pic ):
230 return new GraphicShapeContext( *this, mpMasterShapePtr, mpShapePtr );
231 }
232 SAL_WARN("oox", "OleObjectGraphicDataContext::onCreateContext: unhandled element: "
233 << getBaseToken(nElement));
234 return nullptr;
235 }
236
DiagramGraphicDataContext(ContextHandler2Helper const & rParent,const ShapePtr & pShapePtr)237 DiagramGraphicDataContext::DiagramGraphicDataContext( ContextHandler2Helper const & rParent, const ShapePtr& pShapePtr )
238 : ShapeContext( rParent, ShapePtr(), pShapePtr )
239 {
240 pShapePtr->setDiagramType();
241 }
242
~DiagramGraphicDataContext()243 DiagramGraphicDataContext::~DiagramGraphicDataContext()
244 {
245 }
246
onCreateContext(::sal_Int32 aElementToken,const AttributeList & rAttribs)247 ContextHandlerRef DiagramGraphicDataContext::onCreateContext( ::sal_Int32 aElementToken, const AttributeList& rAttribs )
248 {
249 switch( aElementToken )
250 {
251 case DGM_TOKEN( relIds ):
252 {
253 msDm = rAttribs.getString( R_TOKEN( dm ) ).get();
254 msLo = rAttribs.getString( R_TOKEN( lo ) ).get();
255 msQs = rAttribs.getString( R_TOKEN( qs ) ).get();
256 msCs = rAttribs.getString( R_TOKEN( cs ) ).get();
257 loadDiagram(mpShapePtr,
258 getFilter(),
259 getFragmentPathFromRelId( msDm ),
260 getFragmentPathFromRelId( msLo ),
261 getFragmentPathFromRelId( msQs ),
262 getFragmentPathFromRelId( msCs ),
263 getRelations());
264 SAL_INFO("oox.drawingml", "DiagramGraphicDataContext::onCreateContext: added shape " << mpShapePtr->getName()
265 << " of type " << mpShapePtr->getServiceName()
266 << ", position: " << mpShapePtr->getPosition().X
267 << "," << mpShapePtr->getPosition().Y
268 << ", size: " << mpShapePtr->getSize().Width
269 << "x" << mpShapePtr->getSize().Height);
270
271 // No DrawingML fallback, need to warn the user at the end.
272 if (mpShapePtr->getExtDrawings().empty())
273 getFilter().setMissingExtDrawing();
274 else
275 {
276 for (const auto& rRelId : mpShapePtr->getExtDrawings())
277 {
278 // An invalid fallback reference is as bad as a missing one.
279 if (getFragmentPathFromRelId(rRelId).isEmpty())
280 {
281 getFilter().setMissingExtDrawing();
282 break;
283 }
284 }
285 }
286
287 break;
288 }
289 default:
290 break;
291 }
292
293 return ShapeContext::onCreateContext( aElementToken, rAttribs );
294 }
295
ChartGraphicDataContext(ContextHandler2Helper const & rParent,const ShapePtr & rxShape,bool bEmbedShapes)296 ChartGraphicDataContext::ChartGraphicDataContext( ContextHandler2Helper const & rParent, const ShapePtr& rxShape, bool bEmbedShapes ) :
297 ShapeContext( rParent, ShapePtr(), rxShape ),
298 mrChartShapeInfo( rxShape->setChartType( bEmbedShapes ) )
299 {
300 }
301
onCreateContext(::sal_Int32 nElement,const AttributeList & rAttribs)302 ContextHandlerRef ChartGraphicDataContext::onCreateContext( ::sal_Int32 nElement, const AttributeList& rAttribs )
303 {
304 if( nElement == C_TOKEN( chart ) )
305 {
306 mrChartShapeInfo.maFragmentPath = getFragmentPathFromRelId( rAttribs.getString( R_TOKEN( id ), OUString() ) );
307 }
308 return nullptr;
309 }
310
311 } // namespace oox::drawingml
312
313 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
314