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