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