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 <basegfx/matrix/b2dhommatrix.hxx>
21 #include <basegfx/matrix/b3dhommatrix.hxx>
22 #include <basegfx/polygon/b2dpolypolygon.hxx>
23 #include <basegfx/polygon/b2dpolypolygontools.hxx>
24 #include <basegfx/polygon/b2dpolygontools.hxx>
25 #include <basegfx/polygon/b3dpolypolygon.hxx>
26 #include <basegfx/polygon/b3dpolypolygontools.hxx>
27 #include <basegfx/tuple/b2dtuple.hxx>
28 #include <basegfx/vector/b3dvector.hxx>
29 
30 #include <com/sun/star/beans/XPropertyState.hpp>
31 #include <com/sun/star/beans/PropertyValues.hpp>
32 #include <com/sun/star/container/XChild.hpp>
33 #include <com/sun/star/container/XEnumerationAccess.hpp>
34 #include <com/sun/star/container/XIdentifierAccess.hpp>
35 #include <com/sun/star/container/XNamed.hpp>
36 #include <com/sun/star/document/XEventsSupplier.hpp>
37 #include <com/sun/star/drawing/Alignment.hpp>
38 #include <com/sun/star/drawing/CameraGeometry.hpp>
39 #include <com/sun/star/drawing/CircleKind.hpp>
40 #include <com/sun/star/drawing/ConnectorType.hpp>
41 #include <com/sun/star/drawing/Direction3D.hpp>
42 #include <com/sun/star/drawing/EscapeDirection.hpp>
43 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
44 #include <com/sun/star/drawing/EnhancedCustomShapeGluePointType.hpp>
45 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
46 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
47 #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
48 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
49 #include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
50 #include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
51 #include <com/sun/star/drawing/GluePoint2.hpp>
52 #include <com/sun/star/drawing/HomogenMatrix.hpp>
53 #include <com/sun/star/drawing/HomogenMatrix3.hpp>
54 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
55 #include <com/sun/star/drawing/PolyPolygonShape3D.hpp>
56 #include <com/sun/star/drawing/Position3D.hpp>
57 #include <com/sun/star/drawing/ProjectionMode.hpp>
58 #include <com/sun/star/drawing/ShadeMode.hpp>
59 #include <com/sun/star/drawing/XControlShape.hpp>
60 #include <com/sun/star/drawing/XCustomShapeEngine.hpp>
61 #include <com/sun/star/drawing/XGluePointsSupplier.hpp>
62 #include <com/sun/star/drawing/QRCode.hpp>
63 #include <com/sun/star/drawing/QRCodeErrorCorrection.hpp>
64 #include <com/sun/star/embed/ElementModes.hpp>
65 #include <com/sun/star/embed/XStorage.hpp>
66 #include <com/sun/star/embed/XTransactedObject.hpp>
67 #include <com/sun/star/graphic/XGraphic.hpp>
68 #include <com/sun/star/graphic/GraphicProvider.hpp>
69 #include <com/sun/star/graphic/XGraphicProvider.hpp>
70 #include <com/sun/star/io/XSeekableInputStream.hpp>
71 #include <com/sun/star/io/XStream.hpp>
72 #include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
73 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
74 #include <com/sun/star/media/ZoomLevel.hpp>
75 #include <com/sun/star/presentation/AnimationSpeed.hpp>
76 #include <com/sun/star/presentation/ClickAction.hpp>
77 #include <com/sun/star/style/XStyle.hpp>
78 #include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
79 #include <com/sun/star/table/XColumnRowRange.hpp>
80 #include <com/sun/star/text/XText.hpp>
81 
82 #include <comphelper/classids.hxx>
83 #include <comphelper/processfactory.hxx>
84 #include <comphelper/storagehelper.hxx>
85 #include <officecfg/Office/Common.hxx>
86 
87 #include <o3tl/any.hxx>
88 #include <o3tl/typed_flags_set.hxx>
89 
90 #include <rtl/math.hxx>
91 #include <rtl/ustrbuf.hxx>
92 #include <rtl/ustring.hxx>
93 #include <sal/log.hxx>
94 
95 #include <sax/tools/converter.hxx>
96 
97 #include <tools/debug.hxx>
98 #include <tools/globname.hxx>
99 #include <tools/helpers.hxx>
100 #include <tools/diagnose_ex.h>
101 
102 #include <xmloff/contextid.hxx>
103 #include <xmloff/families.hxx>
104 #include <xmloff/nmspmap.hxx>
105 #include <xmloff/shapeexport.hxx>
106 #include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
107 #include <xmloff/xmlexp.hxx>
108 #include <xmloff/xmlnmspe.hxx>
109 #include <xmloff/xmltoken.hxx>
110 #include <xmloff/xmluconv.hxx>
111 #include <xmloff/table/XMLTableExport.hxx>
112 #include <xmloff/ProgressBarHelper.hxx>
113 
114 #include <anim.hxx>
115 #include <EnhancedCustomShapeToken.hxx>
116 #include "sdpropls.hxx"
117 #include <xexptran.hxx>
118 #include "ximpshap.hxx"
119 #include <XMLBase64Export.hxx>
120 #include <XMLImageMapExport.hxx>
121 #include <memory>
122 
123 using namespace ::com::sun::star;
124 using namespace ::xmloff::EnhancedCustomShapeToken;
125 using namespace ::xmloff::token;
126 
127 #define XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE "vnd.sun.star.GraphicObject:"
128 
129 namespace {
130 
supportsText(XmlShapeType eShapeType)131 bool supportsText(XmlShapeType eShapeType)
132 {
133         return eShapeType != XmlShapeTypePresChartShape &&
134         eShapeType != XmlShapeTypePresOLE2Shape &&
135         eShapeType != XmlShapeTypeDrawSheetShape &&
136         eShapeType != XmlShapeTypePresSheetShape &&
137         eShapeType != XmlShapeTypeDraw3DSceneObject &&
138         eShapeType != XmlShapeTypeDraw3DCubeObject &&
139         eShapeType != XmlShapeTypeDraw3DSphereObject &&
140         eShapeType != XmlShapeTypeDraw3DLatheObject &&
141         eShapeType != XmlShapeTypeDraw3DExtrudeObject &&
142         eShapeType != XmlShapeTypeDrawPageShape &&
143         eShapeType != XmlShapeTypePresPageShape &&
144         eShapeType != XmlShapeTypeDrawGroupShape;
145 
146 }
147 
148 }
149 
150 static const OUStringLiteral gsZIndex( "ZOrder" );
151 static const OUStringLiteral gsPrintable( "Printable" );
152 static const OUStringLiteral gsVisible( "Visible" );
153 static const OUStringLiteral gsModel( "Model" );
154 static const OUStringLiteral gsStartShape( "StartShape" );
155 static const OUStringLiteral gsEndShape( "EndShape" );
156 static const OUStringLiteral gsOnClick( "OnClick" );
157 static const OUStringLiteral gsEventType( "EventType" );
158 static const OUStringLiteral gsPresentation( "Presentation" );
159 static const OUStringLiteral gsMacroName( "MacroName" );
160 static const OUStringLiteral gsScript( "Script" );
161 static const OUStringLiteral gsLibrary( "Library" );
162 static const OUStringLiteral gsClickAction( "ClickAction" );
163 static const OUStringLiteral gsBookmark( "Bookmark" );
164 static const OUStringLiteral gsEffect( "Effect" );
165 static const OUStringLiteral gsPlayFull( "PlayFull" );
166 static const OUStringLiteral gsVerb( "Verb" );
167 static const OUStringLiteral gsSoundURL( "SoundURL" );
168 static const OUStringLiteral gsSpeed( "Speed" );
169 static const OUStringLiteral gsStarBasic( "StarBasic" );
170 
XMLShapeExport(SvXMLExport & rExp,SvXMLExportPropertyMapper * pExtMapper)171 XMLShapeExport::XMLShapeExport(SvXMLExport& rExp,
172                                 SvXMLExportPropertyMapper *pExtMapper )
173 :   mrExport( rExp ),
174     maShapesInfos(),
175     maCurrentShapesIter(maShapesInfos.end()),
176     mbExportLayer( false ),
177     // #88546# init to sal_False
178     mbHandleProgressBar( false )
179 {
180     // construct PropertySetMapper
181     mxPropertySetMapper = CreateShapePropMapper( mrExport );
182     if( pExtMapper )
183     {
184         rtl::Reference < SvXMLExportPropertyMapper > xExtMapper( pExtMapper );
185         mxPropertySetMapper->ChainExportMapper( xExtMapper );
186     }
187 
188 /*
189     // chain text attributes
190     xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(rExp));
191 */
192 
193     mrExport.GetAutoStylePool()->AddFamily(
194         XML_STYLE_FAMILY_SD_GRAPHICS_ID,
195         XML_STYLE_FAMILY_SD_GRAPHICS_NAME,
196         GetPropertySetMapper(),
197         XML_STYLE_FAMILY_SD_GRAPHICS_PREFIX);
198     mrExport.GetAutoStylePool()->AddFamily(
199         XML_STYLE_FAMILY_SD_PRESENTATION_ID,
200         XML_STYLE_FAMILY_SD_PRESENTATION_NAME,
201         GetPropertySetMapper(),
202         XML_STYLE_FAMILY_SD_PRESENTATION_PREFIX);
203 
204     // create table export helper and let him add his families in time
205     GetShapeTableExport();
206 }
207 
~XMLShapeExport()208 XMLShapeExport::~XMLShapeExport()
209 {
210 }
211 
212 // sj: replacing CustomShapes with standard objects that are also supported in OpenOffice.org format
checkForCustomShapeReplacement(const uno::Reference<drawing::XShape> & xShape)213 uno::Reference< drawing::XShape > XMLShapeExport::checkForCustomShapeReplacement( const uno::Reference< drawing::XShape >& xShape )
214 {
215     uno::Reference< drawing::XShape > xCustomShapeReplacement;
216 
217     if( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) )
218     {
219         OUString aType( xShape->getShapeType() );
220         if( aType == "com.sun.star.drawing.CustomShape" )
221         {
222             uno::Reference< beans::XPropertySet > xSet( xShape, uno::UNO_QUERY );
223             if( xSet.is() )
224             {
225                 OUString aEngine;
226                 xSet->getPropertyValue("CustomShapeEngine") >>= aEngine;
227                 if ( aEngine.isEmpty() )
228                 {
229                     aEngine = "com.sun.star.drawing.EnhancedCustomShapeEngine";
230                 }
231                 uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
232 
233                 if ( !aEngine.isEmpty() )
234                 {
235                     uno::Sequence< uno::Any > aArgument( 1 );
236                     uno::Sequence< beans::PropertyValue > aPropValues( 2 );
237                     aPropValues[ 0 ].Name = "CustomShape";
238                     aPropValues[ 0 ].Value <<= xShape;
239                     aPropValues[ 1 ].Name = "ForceGroupWithText";
240                     aPropValues[ 1 ].Value <<= true;
241                     aArgument[ 0 ] <<= aPropValues;
242                     uno::Reference< uno::XInterface > xInterface(
243                         xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aEngine, aArgument, xContext) );
244                     if ( xInterface.is() )
245                     {
246                         uno::Reference< drawing::XCustomShapeEngine > xCustomShapeEngine(
247                             uno::Reference< drawing::XCustomShapeEngine >( xInterface, uno::UNO_QUERY ) );
248                         if ( xCustomShapeEngine.is() )
249                             xCustomShapeReplacement = xCustomShapeEngine->render();
250                     }
251                 }
252             }
253         }
254     }
255     return xCustomShapeReplacement;
256 }
257 
258 // This method collects all automatic styles for the given XShape
collectShapeAutoStyles(const uno::Reference<drawing::XShape> & xShape)259 void XMLShapeExport::collectShapeAutoStyles(const uno::Reference< drawing::XShape >& xShape )
260 {
261     if( maCurrentShapesIter == maShapesInfos.end() )
262     {
263         OSL_FAIL( "XMLShapeExport::collectShapeAutoStyles(): no call to seekShapes()!" );
264         return;
265     }
266     sal_Int32 nZIndex = 0;
267     uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
268     if( xPropSet.is() )
269         xPropSet->getPropertyValue(gsZIndex) >>= nZIndex;
270 
271     ImplXMLShapeExportInfoVector& aShapeInfoVector = (*maCurrentShapesIter).second;
272 
273     if( static_cast<sal_Int32>(aShapeInfoVector.size()) <= nZIndex )
274     {
275         OSL_FAIL( "XMLShapeExport::collectShapeAutoStyles(): no shape info allocated for a given shape" );
276         return;
277     }
278 
279     ImplXMLShapeExportInfo& aShapeInfo = aShapeInfoVector[nZIndex];
280 
281     uno::Reference< drawing::XShape > xCustomShapeReplacement = checkForCustomShapeReplacement( xShape );
282     if ( xCustomShapeReplacement.is() )
283         aShapeInfo.xCustomShapeReplacement = xCustomShapeReplacement;
284 
285     // first compute the shapes type
286     ImpCalcShapeType(xShape, aShapeInfo.meShapeType);
287 
288     // #i118485# enabled XmlShapeTypeDrawChartShape and XmlShapeTypeDrawOLE2Shape
289     // to have text
290     const bool bObjSupportsText =
291         supportsText(aShapeInfo.meShapeType);
292 
293     const bool bObjSupportsStyle =
294         aShapeInfo.meShapeType != XmlShapeTypeDrawGroupShape;
295 
296     bool bIsEmptyPresObj = false;
297 
298     if ( aShapeInfo.xCustomShapeReplacement.is() )
299         xPropSet.clear();
300 
301     // prep text styles
302     if( xPropSet.is() && bObjSupportsText )
303     {
304         uno::Reference< text::XText > xText(xShape, uno::UNO_QUERY);
305         bool bSkip = false;
306         if (xText.is())
307         {
308             try
309             {
310                 bSkip = xText->getString().isEmpty();
311             }
312             catch (uno::RuntimeException const&)
313             {
314                 // tdf#102479: SwXTextFrame that contains only a table will
315                 // throw, but the table must be iterated so that
316                 // SwXMLExport::ExportTableLines() can find its auto styles
317                 // so do not skip it!
318             }
319         }
320         if (!bSkip)
321         {
322             uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
323 
324             if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsEmptyPresentationObject") )
325             {
326                 uno::Any aAny = xPropSet->getPropertyValue("IsEmptyPresentationObject");
327                 aAny >>= bIsEmptyPresObj;
328             }
329 
330             if(!bIsEmptyPresObj)
331             {
332                 GetExport().GetTextParagraphExport()->collectTextAutoStyles( xText );
333             }
334         }
335     }
336 
337     // compute the shape parent style
338     if( xPropSet.is() )
339     {
340         uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( xPropSet->getPropertySetInfo() );
341 
342         OUString aParentName;
343         uno::Reference< style::XStyle > xStyle;
344 
345         if( bObjSupportsStyle )
346         {
347             if( xPropertySetInfo.is() && xPropertySetInfo->hasPropertyByName("Style") )
348                 xPropSet->getPropertyValue("Style") >>= xStyle;
349 
350             if(xStyle.is())
351             {
352                 // get family ID
353                 uno::Reference< beans::XPropertySet > xStylePropSet(xStyle, uno::UNO_QUERY);
354                 SAL_WARN_IF( !xStylePropSet.is(), "xmloff", "style without a XPropertySet?" );
355                 try
356                 {
357                     if(xStylePropSet.is())
358                     {
359                         OUString aFamilyName;
360                         xStylePropSet->getPropertyValue("Family") >>= aFamilyName;
361                         if( !aFamilyName.isEmpty() && aFamilyName != "graphics" )
362                             aShapeInfo.mnFamily = XML_STYLE_FAMILY_SD_PRESENTATION_ID;
363                     }
364                 }
365                 catch(const beans::UnknownPropertyException&)
366                 {
367                     // Ignored.
368                     SAL_WARN( "xmloff",
369                         "XMLShapeExport::collectShapeAutoStyles: style has no 'Family' property");
370                 }
371 
372                 // get parent-style name
373                 if(XML_STYLE_FAMILY_SD_PRESENTATION_ID == aShapeInfo.mnFamily)
374                 {
375                     aParentName = msPresentationStylePrefix;
376                 }
377 
378                 aParentName += xStyle->getName();
379             }
380         }
381 
382         if (aParentName.isEmpty() && xPropertySetInfo->hasPropertyByName("TextBox") && xPropSet->getPropertyValue("TextBox").hasValue() && xPropSet->getPropertyValue("TextBox").get<bool>())
383         {
384             // Shapes with a Writer TextBox always have a parent style.
385             // If there would be none, then just assign the first available.
386             uno::Reference<style::XStyleFamiliesSupplier> xStyleFamiliesSupplier(GetExport().GetModel(), uno::UNO_QUERY);
387             if (xStyleFamiliesSupplier.is()) // tdf#108231
388             {
389                 uno::Reference<container::XNameAccess> xStyleFamilies = xStyleFamiliesSupplier->getStyleFamilies();
390                 uno::Reference<container::XNameAccess> xFrameStyles = xStyleFamilies->getByName("FrameStyles").get< uno::Reference<container::XNameAccess> >();
391                 uno::Sequence<OUString> aFrameStyles = xFrameStyles->getElementNames();
392                 if (aFrameStyles.hasElements())
393                 {
394                     aParentName = aFrameStyles[0];
395                 }
396             }
397         }
398 
399         // filter propset
400         std::vector< XMLPropertyState > aPropStates;
401 
402         sal_Int32 nCount = 0;
403         if( !bIsEmptyPresObj || (aShapeInfo.meShapeType != XmlShapeTypePresPageShape) )
404         {
405             aPropStates = GetPropertySetMapper()->Filter( xPropSet );
406 
407             if (XmlShapeTypeDrawControlShape == aShapeInfo.meShapeType)
408             {
409                 // for control shapes, we additionally need the number format style (if any)
410                 uno::Reference< drawing::XControlShape > xControl(xShape, uno::UNO_QUERY);
411                 DBG_ASSERT(xControl.is(), "XMLShapeExport::collectShapeAutoStyles: ShapeType control, but no XControlShape!");
412                 if (xControl.is())
413                 {
414                     uno::Reference< beans::XPropertySet > xControlModel(xControl->getControl(), uno::UNO_QUERY);
415                     DBG_ASSERT(xControlModel.is(), "XMLShapeExport::collectShapeAutoStyles: no control model on the control shape!");
416 
417                     OUString sNumberStyle = mrExport.GetFormExport()->getControlNumberStyle(xControlModel);
418                     if (!sNumberStyle.isEmpty())
419                     {
420                         sal_Int32 nIndex = GetPropertySetMapper()->getPropertySetMapper()->FindEntryIndex(CTF_SD_CONTROL_SHAPE_DATA_STYLE);
421                             // TODO : this retrieval of the index could be moved into the ctor, holding the index
422                             //          as member, thus saving time.
423                         DBG_ASSERT(-1 != nIndex, "XMLShapeExport::collectShapeAutoStyles: could not obtain the index for our context id!");
424 
425                         XMLPropertyState aNewState(nIndex, uno::makeAny(sNumberStyle));
426                         aPropStates.push_back(aNewState);
427                     }
428                 }
429             }
430 
431             nCount = std::count_if(aPropStates.cbegin(), aPropStates.cend(),
432                 [](const XMLPropertyState& rProp) { return rProp.mnIndex != -1; });
433         }
434 
435         if(nCount == 0)
436         {
437             // no hard attributes, use parent style name for export
438             aShapeInfo.msStyleName = aParentName;
439         }
440         else
441         {
442             // there are filtered properties -> hard attributes
443             // try to find this style in AutoStylePool
444             aShapeInfo.msStyleName = mrExport.GetAutoStylePool()->Find(aShapeInfo.mnFamily, aParentName, aPropStates);
445 
446             if(aShapeInfo.msStyleName.isEmpty())
447             {
448                 // Style did not exist, add it to AutoStalePool
449                 aShapeInfo.msStyleName = mrExport.GetAutoStylePool()->Add(aShapeInfo.mnFamily, aParentName, aPropStates);
450             }
451         }
452 
453         // optionally generate auto style for text attributes
454         if( (!bIsEmptyPresObj || (aShapeInfo.meShapeType != XmlShapeTypePresPageShape)) && bObjSupportsText )
455         {
456             aPropStates = GetExport().GetTextParagraphExport()->GetParagraphPropertyMapper()->Filter( xPropSet );
457 
458             // yet more additionally, we need to care for the ParaAdjust property
459             if ( XmlShapeTypeDrawControlShape == aShapeInfo.meShapeType )
460             {
461                 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
462                 uno::Reference< beans::XPropertyState > xPropState( xPropSet, uno::UNO_QUERY );
463                 if ( xPropSetInfo.is() && xPropState.is() )
464                 {
465                     // this is because:
466                     // * if controls shapes have a ParaAdjust property, then this is the Align property of the control model
467                     // * control models are allowed to have an Align of "void"
468                     // * the Default for control model's Align is TextAlign_LEFT
469                     // * defaults for style properties are not written, but we need to write the "left",
470                     //   because we need to distinguish this "left" from the case where not align attribute
471                     //   is present which means "void"
472                     if  (   xPropSetInfo->hasPropertyByName( "ParaAdjust" )
473                         &&  ( beans::PropertyState_DEFAULT_VALUE == xPropState->getPropertyState( "ParaAdjust" ) )
474                         )
475                     {
476                         sal_Int32 nIndex = GetExport().GetTextParagraphExport()->GetParagraphPropertyMapper()->getPropertySetMapper()->FindEntryIndex( CTF_SD_SHAPE_PARA_ADJUST );
477                             // TODO : this retrieval of the index should be moved into the ctor, holding the index
478                             //          as member, thus saving time.
479                         DBG_ASSERT(-1 != nIndex, "XMLShapeExport::collectShapeAutoStyles: could not obtain the index for the ParaAdjust context id!");
480 
481                         uno::Any aParaAdjustValue = xPropSet->getPropertyValue( "ParaAdjust" );
482                         XMLPropertyState aAlignDefaultState( nIndex, aParaAdjustValue );
483 
484                         aPropStates.push_back( aAlignDefaultState );
485                     }
486                 }
487             }
488 
489             nCount = std::count_if(aPropStates.cbegin(), aPropStates.cend(),
490                 [](const XMLPropertyState& rProp) { return rProp.mnIndex != -1; });
491 
492             if( nCount )
493             {
494                 aShapeInfo.msTextStyleName = mrExport.GetAutoStylePool()->Find( XML_STYLE_FAMILY_TEXT_PARAGRAPH, "", aPropStates );
495                 if(aShapeInfo.msTextStyleName.isEmpty())
496                 {
497                     // Style did not exist, add it to AutoStalePool
498                     aShapeInfo.msTextStyleName = mrExport.GetAutoStylePool()->Add(XML_STYLE_FAMILY_TEXT_PARAGRAPH, "", aPropStates);
499                 }
500             }
501         }
502     }
503 
504     // prepare animation information if needed
505     if( mxAnimationsExporter.is() )
506         XMLAnimationsExporter::prepare( xShape );
507 
508     // check for special shapes
509 
510     switch( aShapeInfo.meShapeType )
511     {
512         case XmlShapeTypeDrawConnectorShape:
513         {
514             uno::Reference< uno::XInterface > xConnection;
515 
516             // create shape ids for export later
517             xPropSet->getPropertyValue( gsStartShape ) >>= xConnection;
518             if( xConnection.is() )
519                 mrExport.getInterfaceToIdentifierMapper().registerReference( xConnection );
520 
521             xPropSet->getPropertyValue( gsEndShape ) >>= xConnection;
522             if( xConnection.is() )
523                 mrExport.getInterfaceToIdentifierMapper().registerReference( xConnection );
524             break;
525         }
526         case XmlShapeTypePresTableShape:
527         case XmlShapeTypeDrawTableShape:
528         {
529             try
530             {
531                 uno::Reference< table::XColumnRowRange > xRange( xPropSet->getPropertyValue( gsModel ), uno::UNO_QUERY_THROW );
532                 GetShapeTableExport()->collectTableAutoStyles( xRange );
533             }
534             catch(const uno::Exception&)
535             {
536                 DBG_UNHANDLED_EXCEPTION( "xmloff", "collecting auto styles for a table" );
537             }
538             break;
539         }
540         default:
541             break;
542     }
543 
544     // check for shape collections (group shape or 3d scene)
545     // and collect contained shapes style infos
546     const uno::Reference< drawing::XShape >& xCollection = aShapeInfo.xCustomShapeReplacement.is()
547                                                 ? aShapeInfo.xCustomShapeReplacement : xShape;
548     {
549         uno::Reference< drawing::XShapes > xShapes( xCollection, uno::UNO_QUERY );
550         if( xShapes.is() )
551         {
552             collectShapesAutoStyles( xShapes );
553         }
554     }
555 }
556 
557 namespace
558 {
559     class NewTextListsHelper
560     {
561         public:
NewTextListsHelper(SvXMLExport & rExp)562             explicit NewTextListsHelper( SvXMLExport& rExp )
563                 : mrExport( rExp )
564             {
565                 mrExport.GetTextParagraphExport()->PushNewTextListsHelper();
566             }
567 
~NewTextListsHelper()568             ~NewTextListsHelper()
569             {
570                 mrExport.GetTextParagraphExport()->PopTextListsHelper();
571             }
572 
573         private:
574             SvXMLExport& mrExport;
575     };
576 }
577 // This method exports the given XShape
exportShape(const uno::Reference<drawing::XShape> & xShape,XMLShapeExportFlags nFeatures,css::awt::Point * pRefPoint,SvXMLAttributeList * pAttrList)578 void XMLShapeExport::exportShape(const uno::Reference< drawing::XShape >& xShape,
579                                  XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */,
580                                  css::awt::Point* pRefPoint /* = NULL */,
581                                  SvXMLAttributeList* pAttrList /* = NULL */ )
582 {
583     SAL_INFO("xmloff", xShape->getShapeType());
584     if( maCurrentShapesIter == maShapesInfos.end() )
585     {
586         SAL_WARN( "xmloff", "XMLShapeExport::exportShape(): no auto styles where collected before export" );
587         return;
588     }
589     sal_Int32 nZIndex = 0;
590     uno::Reference< beans::XPropertySet > xSet( xShape, uno::UNO_QUERY );
591 
592     std::unique_ptr< SvXMLElementExport >  pHyperlinkElement;
593 
594     // export hyperlinks with <a><shape/></a>. Currently only in draw since draw
595     // does not support document events
596     if( xSet.is() && (GetExport().GetModelType() == SvtModuleOptions::EFactory::DRAW) ) try
597     {
598         presentation::ClickAction eAction = presentation::ClickAction_NONE;
599         xSet->getPropertyValue("OnClick") >>= eAction;
600 
601         if( (eAction == presentation::ClickAction_DOCUMENT) ||
602             (eAction == presentation::ClickAction_BOOKMARK) )
603         {
604             OUString sURL;
605             xSet->getPropertyValue(gsBookmark) >>= sURL;
606 
607             if( !sURL.isEmpty() )
608             {
609                 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sURL );
610                 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
611                 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
612                 pHyperlinkElement.reset( new SvXMLElementExport(mrExport, XML_NAMESPACE_DRAW, XML_A, true, true) );
613             }
614         }
615     }
616     catch(const uno::Exception&)
617     {
618         TOOLS_WARN_EXCEPTION("xmloff", "XMLShapeExport::exportShape(): exception during hyperlink export");
619     }
620 
621     if( xSet.is() )
622         xSet->getPropertyValue(gsZIndex) >>= nZIndex;
623 
624     ImplXMLShapeExportInfoVector& aShapeInfoVector = (*maCurrentShapesIter).second;
625 
626     if( static_cast<sal_Int32>(aShapeInfoVector.size()) <= nZIndex )
627     {
628         SAL_WARN( "xmloff", "XMLShapeExport::exportShape(): no shape info collected for a given shape" );
629         return;
630     }
631 
632     NewTextListsHelper aNewTextListsHelper( mrExport );
633 
634     const ImplXMLShapeExportInfo& aShapeInfo = aShapeInfoVector[nZIndex];
635 
636 #ifdef DBG_UTIL
637     // check if this is the correct ShapesInfo
638     uno::Reference< container::XChild > xChild( xShape, uno::UNO_QUERY );
639     if( xChild.is() )
640     {
641         uno::Reference< drawing::XShapes > xParent( xChild->getParent(), uno::UNO_QUERY );
642         SAL_WARN_IF( !xParent.is() && xParent.get() == (*maCurrentShapesIter).first.get(), "xmloff", "XMLShapeExport::exportShape(): Wrong call to XMLShapeExport::seekShapes()" );
643     }
644 
645     // first compute the shapes type
646     {
647         XmlShapeType eShapeType(XmlShapeTypeNotYetSet);
648         ImpCalcShapeType(xShape, eShapeType);
649 
650         SAL_WARN_IF( eShapeType != aShapeInfo.meShapeType, "xmloff", "exportShape callings do not correspond to collectShapeAutoStyles calls!: " << xShape->getShapeType() );
651     }
652 #endif
653 
654     // collect animation information if needed
655     if( mxAnimationsExporter.is() )
656         mxAnimationsExporter->collect( xShape, mrExport );
657 
658     /* Export shapes name if he has one (#i51726#)
659        Export of the shape name for text documents only if the OpenDocument
660        file format is written - exceptions are group shapes.
661        Note: Writer documents in OpenOffice.org file format doesn't contain
662              any names for shapes, except for group shapes.
663     */
664     {
665         if ( ( GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITER &&
666                GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITERWEB &&
667                GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITERGLOBAL ) ||
668              ( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) ||
669              aShapeInfo.meShapeType == XmlShapeTypeDrawGroupShape ||
670              ( aShapeInfo.meShapeType == XmlShapeTypeDrawCustomShape &&
671                aShapeInfo.xCustomShapeReplacement.is() ) )
672         {
673             uno::Reference< container::XNamed > xNamed( xShape, uno::UNO_QUERY );
674             if( xNamed.is() )
675             {
676                 const OUString aName( xNamed->getName() );
677                 if( !aName.isEmpty() )
678                     mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_NAME, aName );
679             }
680         }
681     }
682 
683     // export style name
684     if( !aShapeInfo.msStyleName.isEmpty() )
685     {
686         if(XML_STYLE_FAMILY_SD_GRAPHICS_ID == aShapeInfo.mnFamily)
687             mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_STYLE_NAME, mrExport.EncodeStyleName( aShapeInfo.msStyleName) );
688         else
689             mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_STYLE_NAME, mrExport.EncodeStyleName( aShapeInfo.msStyleName) );
690     }
691 
692     // export text style name
693     if( !aShapeInfo.msTextStyleName.isEmpty() )
694     {
695         mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TEXT_STYLE_NAME, aShapeInfo.msTextStyleName );
696     }
697 
698     // export shapes id if needed
699     {
700         uno::Reference< uno::XInterface > xRef( xShape, uno::UNO_QUERY );
701         const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRef );
702         if( !rShapeId.isEmpty() )
703         {
704             mrExport.AddAttributeIdLegacy(XML_NAMESPACE_DRAW, rShapeId);
705         }
706     }
707 
708     // export layer information
709     if( mbExportLayer )
710     {
711         // check for group or scene shape and not export layer if this is one
712         uno::Reference< drawing::XShapes > xShapes( xShape, uno::UNO_QUERY );
713         if( !xShapes.is() )
714         {
715             try
716             {
717                 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
718                 OUString aLayerName;
719                 xProps->getPropertyValue("LayerName") >>= aLayerName;
720                 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_LAYER, aLayerName );
721 
722             }
723             catch(const uno::Exception&)
724             {
725                 DBG_UNHANDLED_EXCEPTION( "xmloff", "exporting layer name for shape" );
726             }
727         }
728     }
729 
730     // export draw:display (do not export in ODF 1.2 or older)
731     if( xSet.is() && ( mrExport.getDefaultVersion() > SvtSaveOptions::ODFVER_012 ) )
732     {
733         if( aShapeInfo.meShapeType != XmlShapeTypeDrawPageShape && aShapeInfo.meShapeType != XmlShapeTypePresPageShape &&
734             aShapeInfo.meShapeType != XmlShapeTypeHandoutShape && aShapeInfo.meShapeType != XmlShapeTypeDrawChartShape )
735             try
736             {
737                 bool bVisible = true;
738                 bool bPrintable = true;
739 
740                 xSet->getPropertyValue(gsVisible) >>= bVisible;
741                 xSet->getPropertyValue(gsPrintable) >>= bPrintable;
742 
743                 XMLTokenEnum eDisplayToken = XML_TOKEN_INVALID;
744                 const unsigned short nDisplay = (bVisible ? 2 : 0) | (bPrintable ? 1 : 0);
745                 switch( nDisplay )
746                 {
747                 case 0: eDisplayToken = XML_NONE; break;
748                 case 1: eDisplayToken = XML_PRINTER; break;
749                 case 2: eDisplayToken = XML_SCREEN; break;
750                 // case 3: eDisplayToken = XML_ALWAYS break; this is the default
751                 }
752 
753                 if( eDisplayToken != XML_TOKEN_INVALID )
754                     mrExport.AddAttribute(XML_NAMESPACE_DRAW_EXT, XML_DISPLAY, eDisplayToken );
755             }
756             catch(const uno::Exception&)
757             {
758                 DBG_UNHANDLED_EXCEPTION("xmloff.draw");
759             }
760     }
761 
762     // #82003# test export count
763     // #91587# ALWAYS increment since now ALL to be exported shapes are counted.
764     if(mrExport.GetShapeExport()->IsHandleProgressBarEnabled())
765     {
766         mrExport.GetProgressBarHelper()->Increment();
767     }
768 
769     onExport( xShape );
770 
771     // export shape element
772     switch(aShapeInfo.meShapeType)
773     {
774         case XmlShapeTypeDrawRectangleShape:
775         {
776             ImpExportRectangleShape(xShape, nFeatures, pRefPoint );
777             break;
778         }
779         case XmlShapeTypeDrawEllipseShape:
780         {
781             ImpExportEllipseShape(xShape, nFeatures, pRefPoint );
782             break;
783         }
784         case XmlShapeTypeDrawLineShape:
785         {
786             ImpExportLineShape(xShape, nFeatures, pRefPoint );
787             break;
788         }
789         case XmlShapeTypeDrawPolyPolygonShape:  // closed PolyPolygon
790         case XmlShapeTypeDrawPolyLineShape:     // open PolyPolygon
791         case XmlShapeTypeDrawClosedBezierShape: // closed tools::PolyPolygon containing curves
792         case XmlShapeTypeDrawOpenBezierShape:   // open tools::PolyPolygon containing curves
793         {
794             ImpExportPolygonShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
795             break;
796         }
797 
798         case XmlShapeTypeDrawTextShape:
799         case XmlShapeTypePresTitleTextShape:
800         case XmlShapeTypePresOutlinerShape:
801         case XmlShapeTypePresSubtitleShape:
802         case XmlShapeTypePresNotesShape:
803         case XmlShapeTypePresHeaderShape:
804         case XmlShapeTypePresFooterShape:
805         case XmlShapeTypePresSlideNumberShape:
806         case XmlShapeTypePresDateTimeShape:
807         {
808             ImpExportTextBoxShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
809             break;
810         }
811 
812         case XmlShapeTypeDrawGraphicObjectShape:
813         case XmlShapeTypePresGraphicObjectShape:
814         {
815             ImpExportGraphicObjectShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
816             break;
817         }
818 
819         case XmlShapeTypeDrawChartShape:
820         case XmlShapeTypePresChartShape:
821         {
822             ImpExportChartShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint, pAttrList );
823             break;
824         }
825 
826         case XmlShapeTypeDrawControlShape:
827         {
828             ImpExportControlShape(xShape, nFeatures, pRefPoint );
829             break;
830         }
831 
832         case XmlShapeTypeDrawConnectorShape:
833         {
834             ImpExportConnectorShape(xShape, nFeatures, pRefPoint );
835             break;
836         }
837 
838         case XmlShapeTypeDrawMeasureShape:
839         {
840             ImpExportMeasureShape(xShape, nFeatures, pRefPoint );
841             break;
842         }
843 
844         case XmlShapeTypeDrawOLE2Shape:
845         case XmlShapeTypePresOLE2Shape:
846         case XmlShapeTypeDrawSheetShape:
847         case XmlShapeTypePresSheetShape:
848         {
849             ImpExportOLE2Shape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
850             break;
851         }
852 
853         case XmlShapeTypePresTableShape:
854         case XmlShapeTypeDrawTableShape:
855         {
856             ImpExportTableShape( xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
857             break;
858         }
859 
860         case XmlShapeTypeDrawPageShape:
861         case XmlShapeTypePresPageShape:
862         case XmlShapeTypeHandoutShape:
863         {
864             ImpExportPageShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
865             break;
866         }
867 
868         case XmlShapeTypeDrawCaptionShape:
869         {
870             ImpExportCaptionShape(xShape, nFeatures, pRefPoint );
871             break;
872         }
873 
874         case XmlShapeTypeDraw3DCubeObject:
875         case XmlShapeTypeDraw3DSphereObject:
876         case XmlShapeTypeDraw3DLatheObject:
877         case XmlShapeTypeDraw3DExtrudeObject:
878         {
879             ImpExport3DShape(xShape, aShapeInfo.meShapeType);
880             break;
881         }
882 
883         case XmlShapeTypeDraw3DSceneObject:
884         {
885             ImpExport3DSceneShape( xShape, nFeatures, pRefPoint );
886             break;
887         }
888 
889         case XmlShapeTypeDrawGroupShape:
890         {
891             // empty group
892             ImpExportGroupShape( xShape, nFeatures, pRefPoint );
893             break;
894         }
895 
896         case XmlShapeTypeDrawFrameShape:
897         {
898             ImpExportFrameShape(xShape, nFeatures, pRefPoint );
899             break;
900         }
901 
902         case XmlShapeTypeDrawAppletShape:
903         {
904             ImpExportAppletShape(xShape, nFeatures, pRefPoint );
905             break;
906         }
907 
908         case XmlShapeTypeDrawPluginShape:
909         {
910             ImpExportPluginShape(xShape, nFeatures, pRefPoint );
911             break;
912         }
913 
914         case XmlShapeTypeDrawCustomShape:
915         {
916             if ( aShapeInfo.xCustomShapeReplacement.is() )
917                 ImpExportGroupShape( aShapeInfo.xCustomShapeReplacement, nFeatures, pRefPoint );
918             else
919                 ImpExportCustomShape( xShape, nFeatures, pRefPoint );
920             break;
921         }
922 
923         case XmlShapeTypePresMediaShape:
924         case XmlShapeTypeDrawMediaShape:
925         {
926             ImpExportMediaShape( xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
927             break;
928         }
929 
930         case XmlShapeTypePresOrgChartShape:
931         case XmlShapeTypeUnknown:
932         case XmlShapeTypeNotYetSet:
933         default:
934         {
935             // this should never happen and is an error
936             OSL_FAIL("XMLEXP: WriteShape: unknown or unexpected type of shape in export!");
937             break;
938         }
939     }
940 
941     pHyperlinkElement.reset();
942 
943     // #97489# #97111#
944     // if there was an error and no element for the shape was exported
945     // we need to clear the attribute list or the attributes will be
946     // set on the next exported element, which can result in corrupt
947     // xml files due to duplicate attributes
948 
949     mrExport.CheckAttrList();   // asserts in non pro if we have attributes left
950     mrExport.ClearAttrList();   // clears the attributes
951 }
952 
953 // This method collects all automatic styles for the shapes inside the given XShapes collection
collectShapesAutoStyles(const uno::Reference<drawing::XShapes> & xShapes)954 void XMLShapeExport::collectShapesAutoStyles( const uno::Reference < drawing::XShapes >& xShapes )
955 {
956     ShapesInfos::iterator aOldCurrentShapesIter = maCurrentShapesIter;
957     seekShapes( xShapes );
958 
959     uno::Reference< drawing::XShape > xShape;
960     const sal_Int32 nShapeCount(xShapes->getCount());
961     for(sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++)
962     {
963         xShapes->getByIndex(nShapeId) >>= xShape;
964         SAL_WARN_IF( !xShape.is(), "xmloff", "Shape without a XShape?" );
965         if(!xShape.is())
966             continue;
967 
968         collectShapeAutoStyles( xShape );
969     }
970 
971     maCurrentShapesIter = aOldCurrentShapesIter;
972 }
973 
974 // This method exports all XShape inside the given XShapes collection
exportShapes(const uno::Reference<drawing::XShapes> & xShapes,XMLShapeExportFlags nFeatures,awt::Point * pRefPoint)975 void XMLShapeExport::exportShapes( const uno::Reference < drawing::XShapes >& xShapes, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */ )
976 {
977     ShapesInfos::iterator aOldCurrentShapesIter = maCurrentShapesIter;
978     seekShapes( xShapes );
979 
980     uno::Reference< drawing::XShape > xShape;
981     const sal_Int32 nShapeCount(xShapes->getCount());
982     for(sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++)
983     {
984         xShapes->getByIndex(nShapeId) >>= xShape;
985         SAL_WARN_IF( !xShape.is(), "xmloff", "Shape without a XShape?" );
986         if(!xShape.is())
987             continue;
988 
989         exportShape( xShape, nFeatures, pRefPoint );
990     }
991 
992     maCurrentShapesIter = aOldCurrentShapesIter;
993 }
994 
seekShapes(const uno::Reference<drawing::XShapes> & xShapes)995 void XMLShapeExport::seekShapes( const uno::Reference< drawing::XShapes >& xShapes ) throw()
996 {
997     if( xShapes.is() )
998     {
999         maCurrentShapesIter = maShapesInfos.find( xShapes );
1000         if( maCurrentShapesIter == maShapesInfos.end() )
1001         {
1002             ImplXMLShapeExportInfoVector aNewInfoVector;
1003             aNewInfoVector.resize( static_cast<ShapesInfos::size_type>(xShapes->getCount()) );
1004             maShapesInfos[ xShapes ] = aNewInfoVector;
1005 
1006             maCurrentShapesIter = maShapesInfos.find( xShapes );
1007 
1008             SAL_WARN_IF( maCurrentShapesIter == maShapesInfos.end(), "xmloff", "XMLShapeExport::seekShapes(): insert into stl::map failed" );
1009         }
1010 
1011         SAL_WARN_IF( (*maCurrentShapesIter).second.size() != static_cast<ShapesInfos::size_type>(xShapes->getCount()), "xmloff", "XMLShapeExport::seekShapes(): XShapes size varied between calls" );
1012 
1013     }
1014     else
1015     {
1016         maCurrentShapesIter = maShapesInfos.end();
1017     }
1018 }
1019 
exportAutoStyles()1020 void XMLShapeExport::exportAutoStyles()
1021 {
1022     // export all autostyle infos
1023 
1024     // ...for graphic
1025     {
1026         GetExport().GetAutoStylePool()->exportXML( XML_STYLE_FAMILY_SD_GRAPHICS_ID );
1027     }
1028 
1029     // ...for presentation
1030     {
1031         GetExport().GetAutoStylePool()->exportXML( XML_STYLE_FAMILY_SD_PRESENTATION_ID );
1032     }
1033 
1034     if( mxShapeTableExport.is() )
1035         mxShapeTableExport->exportAutoStyles();
1036 }
1037 
1038 /// returns the export property mapper for external chaining
CreateShapePropMapper(SvXMLExport & rExport)1039 SvXMLExportPropertyMapper* XMLShapeExport::CreateShapePropMapper(
1040     SvXMLExport& rExport )
1041 {
1042     rtl::Reference< XMLPropertyHandlerFactory > xFactory = new XMLSdPropHdlFactory( rExport.GetModel(), rExport );
1043     rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( xFactory, true );
1044     rExport.GetTextParagraphExport(); // get or create text paragraph export
1045     SvXMLExportPropertyMapper* pResult =
1046         new XMLShapeExportPropertyMapper( xMapper, rExport );
1047     // chain text attributes
1048     return pResult;
1049 }
1050 
ImpCalcShapeType(const uno::Reference<drawing::XShape> & xShape,XmlShapeType & eShapeType)1051 void XMLShapeExport::ImpCalcShapeType(const uno::Reference< drawing::XShape >& xShape,
1052     XmlShapeType& eShapeType)
1053 {
1054     // set in every case, so init here
1055     eShapeType = XmlShapeTypeUnknown;
1056 
1057     if(xShape.is())
1058     {
1059         OUString aType(xShape->getShapeType());
1060 
1061         if(aType.match("com.sun.star."))
1062         {
1063             if(aType.match("drawing.", 13))
1064             {
1065                 // drawing shapes
1066                 if     (aType.match("Rectangle", 21)) { eShapeType = XmlShapeTypeDrawRectangleShape; }
1067 
1068                 // #i72177# Note: Correcting CustomShape, CustomShape->Custom, len from 9 (was wrong anyways) to 6.
1069                 // As can be seen at the other compares, the appendix "Shape" is left out of the comparison.
1070                 else if(aType.match("Custom", 21)) { eShapeType = XmlShapeTypeDrawCustomShape; }
1071 
1072                 else if(aType.match("Ellipse", 21)) { eShapeType = XmlShapeTypeDrawEllipseShape; }
1073                 else if(aType.match("Control", 21)) { eShapeType = XmlShapeTypeDrawControlShape; }
1074                 else if(aType.match("Connector", 21)) { eShapeType = XmlShapeTypeDrawConnectorShape; }
1075                 else if(aType.match("Measure", 21)) { eShapeType = XmlShapeTypeDrawMeasureShape; }
1076                 else if(aType.match("Line", 21)) { eShapeType = XmlShapeTypeDrawLineShape; }
1077 
1078                 // #i72177# Note: This covers two types by purpose, PolyPolygonShape and PolyPolygonPathShape
1079                 else if(aType.match("PolyPolygon", 21)) { eShapeType = XmlShapeTypeDrawPolyPolygonShape; }
1080 
1081                 // #i72177# Note: This covers two types by purpose, PolyLineShape and PolyLinePathShape
1082                 else if(aType.match("PolyLine", 21)) { eShapeType = XmlShapeTypeDrawPolyLineShape; }
1083 
1084                 else if(aType.match("OpenBezier", 21)) { eShapeType = XmlShapeTypeDrawOpenBezierShape; }
1085                 else if(aType.match("ClosedBezier", 21)) { eShapeType = XmlShapeTypeDrawClosedBezierShape; }
1086 
1087                 // #i72177# FreeHand (opened and closed) now supports the types OpenFreeHandShape and
1088                 // ClosedFreeHandShape respectively. Represent them as bezier shapes
1089                 else if(aType.match("OpenFreeHand", 21)) { eShapeType = XmlShapeTypeDrawOpenBezierShape; }
1090                 else if(aType.match("ClosedFreeHand", 21)) { eShapeType = XmlShapeTypeDrawClosedBezierShape; }
1091 
1092                 else if(aType.match("GraphicObject", 21)) { eShapeType = XmlShapeTypeDrawGraphicObjectShape; }
1093                 else if(aType.match("Group", 21)) { eShapeType = XmlShapeTypeDrawGroupShape; }
1094                 else if(aType.match("Text", 21)) { eShapeType = XmlShapeTypeDrawTextShape; }
1095                 else if(aType.match("OLE2", 21))
1096                 {
1097                     eShapeType = XmlShapeTypeDrawOLE2Shape;
1098 
1099                     // get info about presentation shape
1100                     uno::Reference <beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1101 
1102                     if(xPropSet.is())
1103                     {
1104                         OUString sCLSID;
1105                         if(xPropSet->getPropertyValue("CLSID") >>= sCLSID)
1106                         {
1107                             if (sCLSID == mrExport.GetChartExport()->getChartCLSID() ||
1108                                 sCLSID == SvGlobalName( SO3_RPTCH_CLASSID ).GetHexName() )
1109                             {
1110                                 eShapeType = XmlShapeTypeDrawChartShape;
1111                             }
1112                             else if (sCLSID == SvGlobalName( SO3_SC_CLASSID ).GetHexName() )
1113                             {
1114                                 eShapeType = XmlShapeTypeDrawSheetShape;
1115                             }
1116                             else
1117                             {
1118                                 // general OLE2 Object
1119                             }
1120                         }
1121                     }
1122                 }
1123                 else if(aType.match("Page", 21)) { eShapeType = XmlShapeTypeDrawPageShape; }
1124                 else if(aType.match("Frame", 21)) { eShapeType = XmlShapeTypeDrawFrameShape; }
1125                 else if(aType.match("Caption", 21)) { eShapeType = XmlShapeTypeDrawCaptionShape; }
1126                 else if(aType.match("Plugin", 21)) { eShapeType = XmlShapeTypeDrawPluginShape; }
1127                 else if(aType.match("Applet", 21)) { eShapeType = XmlShapeTypeDrawAppletShape; }
1128                 else if(aType.match("MediaShape", 21)) { eShapeType = XmlShapeTypeDrawMediaShape; }
1129                 else if(aType.match("TableShape", 21)) { eShapeType = XmlShapeTypeDrawTableShape; }
1130 
1131                 // 3D shapes
1132                 else if(aType.match("Scene", 21 + 7)) { eShapeType = XmlShapeTypeDraw3DSceneObject; }
1133                 else if(aType.match("Cube", 21 + 7)) { eShapeType = XmlShapeTypeDraw3DCubeObject; }
1134                 else if(aType.match("Sphere", 21 + 7)) { eShapeType = XmlShapeTypeDraw3DSphereObject; }
1135                 else if(aType.match("Lathe", 21 + 7)) { eShapeType = XmlShapeTypeDraw3DLatheObject; }
1136                 else if(aType.match("Extrude", 21 + 7)) { eShapeType = XmlShapeTypeDraw3DExtrudeObject; }
1137             }
1138             else if(aType.match("presentation.", 13))
1139             {
1140                 // presentation shapes
1141                 if     (aType.match("TitleText", 26)) { eShapeType = XmlShapeTypePresTitleTextShape; }
1142                 else if(aType.match("Outliner", 26)) { eShapeType = XmlShapeTypePresOutlinerShape;  }
1143                 else if(aType.match("Subtitle", 26)) { eShapeType = XmlShapeTypePresSubtitleShape;  }
1144                 else if(aType.match("GraphicObject", 26)) { eShapeType = XmlShapeTypePresGraphicObjectShape;  }
1145                 else if(aType.match("Page", 26)) { eShapeType = XmlShapeTypePresPageShape;  }
1146                 else if(aType.match("OLE2", 26))
1147                 {
1148                     eShapeType = XmlShapeTypePresOLE2Shape;
1149 
1150                     // get info about presentation shape
1151                     uno::Reference <beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1152 
1153                     if(xPropSet.is()) try
1154                     {
1155                         OUString sCLSID;
1156                         if(xPropSet->getPropertyValue("CLSID") >>= sCLSID)
1157                         {
1158                             if( sCLSID == SvGlobalName( SO3_SC_CLASSID ).GetHexName() )
1159                             {
1160                                 eShapeType = XmlShapeTypePresSheetShape;
1161                             }
1162                         }
1163                     }
1164                     catch(const uno::Exception&)
1165                     {
1166                         SAL_WARN( "xmloff", "XMLShapeExport::ImpCalcShapeType(), expected ole shape to have the CLSID property?" );
1167                     }
1168                 }
1169                 else if(aType.match("Chart", 26)) { eShapeType = XmlShapeTypePresChartShape;  }
1170                 else if(aType.match("OrgChart", 26)) { eShapeType = XmlShapeTypePresOrgChartShape;  }
1171                 else if(aType.match("CalcShape", 26)) { eShapeType = XmlShapeTypePresSheetShape; }
1172                 else if(aType.match("TableShape", 26)) { eShapeType = XmlShapeTypePresTableShape; }
1173                 else if(aType.match("Notes", 26)) { eShapeType = XmlShapeTypePresNotesShape;  }
1174                 else if(aType.match("HandoutShape", 26)) { eShapeType = XmlShapeTypeHandoutShape; }
1175                 else if(aType.match("HeaderShape", 26)) { eShapeType = XmlShapeTypePresHeaderShape; }
1176                 else if(aType.match("FooterShape", 26)) { eShapeType = XmlShapeTypePresFooterShape; }
1177                 else if(aType.match("SlideNumberShape", 26)) { eShapeType = XmlShapeTypePresSlideNumberShape; }
1178                 else if(aType.match("DateTimeShape", 26)) { eShapeType = XmlShapeTypePresDateTimeShape; }
1179                 else if(aType.match("MediaShape", 26)) { eShapeType = XmlShapeTypePresMediaShape; }
1180             }
1181         }
1182     }
1183 }
1184 
1185 /** exports all user defined glue points */
ImpExportGluePoints(const uno::Reference<drawing::XShape> & xShape)1186 void XMLShapeExport::ImpExportGluePoints( const uno::Reference< drawing::XShape >& xShape )
1187 {
1188     uno::Reference< drawing::XGluePointsSupplier > xSupplier( xShape, uno::UNO_QUERY );
1189     if( !xSupplier.is() )
1190         return;
1191 
1192     uno::Reference< container::XIdentifierAccess > xGluePoints( xSupplier->getGluePoints(), uno::UNO_QUERY );
1193     if( !xGluePoints.is() )
1194         return;
1195 
1196     drawing::GluePoint2 aGluePoint;
1197 
1198     uno::Sequence< sal_Int32 > aIdSequence( xGluePoints->getIdentifiers() );
1199 
1200     for( const sal_Int32 nIdentifier : aIdSequence )
1201     {
1202         if( (xGluePoints->getByIdentifier( nIdentifier ) >>= aGluePoint) && aGluePoint.IsUserDefined )
1203         {
1204             // export only user defined glue points
1205 
1206             const OUString sId( OUString::number( nIdentifier ) );
1207             mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_ID, sId );
1208 
1209             mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
1210                     aGluePoint.Position.X);
1211             mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, msBuffer.makeStringAndClear());
1212 
1213             mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
1214                     aGluePoint.Position.Y);
1215             mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, msBuffer.makeStringAndClear());
1216 
1217             if( !aGluePoint.IsRelative )
1218             {
1219                 SvXMLUnitConverter::convertEnum( msBuffer, aGluePoint.PositionAlignment, aXML_GlueAlignment_EnumMap );
1220                 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ALIGN, msBuffer.makeStringAndClear() );
1221             }
1222 
1223             if( aGluePoint.Escape != drawing::EscapeDirection_SMART )
1224             {
1225                 SvXMLUnitConverter::convertEnum( msBuffer, aGluePoint.Escape, aXML_GlueEscapeDirection_EnumMap );
1226                 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ESCAPE_DIRECTION, msBuffer.makeStringAndClear() );
1227             }
1228 
1229             SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_DRAW, XML_GLUE_POINT, true, true);
1230         }
1231     }
1232 }
1233 
ImpExportSignatureLine(const uno::Reference<drawing::XShape> & xShape)1234 void XMLShapeExport::ImpExportSignatureLine(const uno::Reference<drawing::XShape>& xShape)
1235 {
1236     uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1237 
1238     bool bIsSignatureLine = false;
1239     xPropSet->getPropertyValue("IsSignatureLine") >>= bIsSignatureLine;
1240     if (!bIsSignatureLine)
1241         return;
1242 
1243     OUString aSignatureLineId;
1244     xPropSet->getPropertyValue("SignatureLineId") >>= aSignatureLineId;
1245     mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_ID, aSignatureLineId);
1246 
1247     OUString aSuggestedSignerName;
1248     xPropSet->getPropertyValue("SignatureLineSuggestedSignerName") >>= aSuggestedSignerName;
1249     if (!aSuggestedSignerName.isEmpty())
1250         mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_NAME, aSuggestedSignerName);
1251 
1252     OUString aSuggestedSignerTitle;
1253     xPropSet->getPropertyValue("SignatureLineSuggestedSignerTitle") >>= aSuggestedSignerTitle;
1254     if (!aSuggestedSignerTitle.isEmpty())
1255         mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_TITLE, aSuggestedSignerTitle);
1256 
1257     OUString aSuggestedSignerEmail;
1258     xPropSet->getPropertyValue("SignatureLineSuggestedSignerEmail") >>= aSuggestedSignerEmail;
1259     if (!aSuggestedSignerEmail.isEmpty())
1260         mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_EMAIL, aSuggestedSignerEmail);
1261 
1262     OUString aSigningInstructions;
1263     xPropSet->getPropertyValue("SignatureLineSigningInstructions") >>= aSigningInstructions;
1264     if (!aSigningInstructions.isEmpty())
1265         mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SIGNING_INSTRUCTIONS, aSigningInstructions);
1266 
1267     bool bShowSignDate = false;
1268     xPropSet->getPropertyValue("SignatureLineShowSignDate") >>= bShowSignDate;
1269     mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SHOW_SIGN_DATE,
1270                           bShowSignDate ? XML_TRUE : XML_FALSE);
1271 
1272     bool bCanAddComment = false;
1273     xPropSet->getPropertyValue("SignatureLineCanAddComment") >>= bCanAddComment;
1274     mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_CAN_ADD_COMMENT,
1275                           bCanAddComment ? XML_TRUE : XML_FALSE);
1276 
1277     SvXMLElementExport aSignatureLineElement(mrExport, XML_NAMESPACE_LO_EXT, XML_SIGNATURELINE, true,
1278                                              true);
1279 }
1280 
ImpExportQRCode(const uno::Reference<drawing::XShape> & xShape)1281 void XMLShapeExport::ImpExportQRCode(const uno::Reference<drawing::XShape>& xShape)
1282 {
1283     uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1284 
1285     uno::Any aAny = xPropSet->getPropertyValue("QRCodeProperties");
1286 
1287     css::drawing::QRCode aQRCode;
1288     if(aAny >>= aQRCode)
1289     {
1290         mrExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_STRING_VALUE, aQRCode.Payload);
1291         /* Export QR Code as per customised schema, @see OpenDocument-schema-v1.3+libreoffice */
1292         OUString temp;
1293         switch(aQRCode.ErrorCorrection){
1294             case css::drawing::QRCodeErrorCorrection::LOW :
1295                 temp = "low";
1296                 break;
1297             case css::drawing::QRCodeErrorCorrection::MEDIUM:
1298                 temp = "medium";
1299                 break;
1300             case css::drawing::QRCodeErrorCorrection::QUARTILE:
1301                 temp = "quartile";
1302                 break;
1303             case css::drawing::QRCodeErrorCorrection::HIGH:
1304                 temp = "high";
1305                 break;
1306         }
1307         mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_ERROR_CORRECTION, temp);
1308         mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_BORDER, OUStringBuffer(20).append(aQRCode.Border).makeStringAndClear());
1309 
1310         SvXMLElementExport aQRCodeElement(mrExport, XML_NAMESPACE_LO_EXT, XML_QRCODE, true,
1311                                                 true);
1312     }
1313 }
1314 
ExportGraphicDefaults()1315 void XMLShapeExport::ExportGraphicDefaults()
1316 {
1317     rtl::Reference<XMLStyleExport> aStEx(new XMLStyleExport(mrExport, mrExport.GetAutoStylePool().get()));
1318 
1319     // construct PropertySetMapper
1320     rtl::Reference< SvXMLExportPropertyMapper > xPropertySetMapper( CreateShapePropMapper( mrExport ) );
1321     static_cast<XMLShapeExportPropertyMapper*>(xPropertySetMapper.get())->SetAutoStyles( false );
1322 
1323     // chain text attributes
1324     xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(mrExport));
1325 
1326     // chain special Writer/text frame default attributes
1327     xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaDefaultExtPropMapper(mrExport));
1328 
1329     // write graphic family default style
1330     uno::Reference< lang::XMultiServiceFactory > xFact( mrExport.GetModel(), uno::UNO_QUERY );
1331     if( xFact.is() )
1332     {
1333         try
1334         {
1335             uno::Reference< beans::XPropertySet > xDefaults( xFact->createInstance("com.sun.star.drawing.Defaults"), uno::UNO_QUERY );
1336             if( xDefaults.is() )
1337             {
1338                 aStEx->exportDefaultStyle( xDefaults, XML_STYLE_FAMILY_SD_GRAPHICS_NAME, xPropertySetMapper );
1339 
1340                 // write graphic family styles
1341                 aStEx->exportStyleFamily("graphics", OUString(XML_STYLE_FAMILY_SD_GRAPHICS_NAME), xPropertySetMapper, false, XML_STYLE_FAMILY_SD_GRAPHICS_ID);
1342             }
1343         }
1344         catch(const lang::ServiceNotRegisteredException&)
1345         {
1346         }
1347     }
1348 }
1349 
onExport(const css::uno::Reference<css::drawing::XShape> &)1350 void XMLShapeExport::onExport( const css::uno::Reference < css::drawing::XShape >& )
1351 {
1352 }
1353 
GetShapeTableExport()1354 const rtl::Reference< XMLTableExport >& XMLShapeExport::GetShapeTableExport()
1355 {
1356     if( !mxShapeTableExport.is() )
1357     {
1358         rtl::Reference< XMLPropertyHandlerFactory > xFactory( new XMLSdPropHdlFactory( mrExport.GetModel(), mrExport ) );
1359         rtl::Reference < XMLPropertySetMapper > xMapper( new XMLShapePropertySetMapper( xFactory.get(), true ) );
1360         mrExport.GetTextParagraphExport(); // get or create text paragraph export
1361         rtl::Reference< SvXMLExportPropertyMapper > xPropertySetMapper( new XMLShapeExportPropertyMapper( xMapper, mrExport ) );
1362         mxShapeTableExport = new XMLTableExport( mrExport, xPropertySetMapper, xFactory );
1363     }
1364 
1365     return mxShapeTableExport;
1366 }
1367 
ImpExportNewTrans(const uno::Reference<beans::XPropertySet> & xPropSet,XMLShapeExportFlags nFeatures,awt::Point * pRefPoint)1368 void XMLShapeExport::ImpExportNewTrans(const uno::Reference< beans::XPropertySet >& xPropSet,
1369     XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
1370 {
1371     // get matrix
1372     ::basegfx::B2DHomMatrix aMatrix;
1373     ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
1374 
1375     // decompose and correct about pRefPoint
1376     ::basegfx::B2DTuple aTRScale;
1377     double fTRShear(0.0);
1378     double fTRRotate(0.0);
1379     ::basegfx::B2DTuple aTRTranslate;
1380     ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
1381 
1382     // use features and write
1383     ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures);
1384 }
1385 
ImpExportNewTrans_GetB2DHomMatrix(::basegfx::B2DHomMatrix & rMatrix,const uno::Reference<beans::XPropertySet> & xPropSet)1386 void XMLShapeExport::ImpExportNewTrans_GetB2DHomMatrix(::basegfx::B2DHomMatrix& rMatrix,
1387     const uno::Reference< beans::XPropertySet >& xPropSet)
1388 {
1389     /* Get <TransformationInHoriL2R>, if it exist
1390        and if the document is exported into the OpenOffice.org file format.
1391        This property only exists at service css::text::Shape - the
1392        Writer UNO service for shapes.
1393        This code is needed, because the positioning attributes in the
1394        OpenOffice.org file format are given in horizontal left-to-right layout
1395        regardless the layout direction the shape is in. In the OASIS Open Office
1396        file format the positioning attributes are correctly given in the layout
1397        direction the shape is in. Thus, this code provides the conversion from
1398        the OASIS Open Office file format to the OpenOffice.org file format. (#i28749#)
1399     */
1400     uno::Any aAny;
1401     if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
1402          xPropSet->getPropertySetInfo()->hasPropertyByName("TransformationInHoriL2R") )
1403     {
1404         aAny = xPropSet->getPropertyValue("TransformationInHoriL2R");
1405     }
1406     else
1407     {
1408         aAny = xPropSet->getPropertyValue("Transformation");
1409     }
1410     drawing::HomogenMatrix3 aMatrix;
1411     aAny >>= aMatrix;
1412 
1413     rMatrix.set(0, 0, aMatrix.Line1.Column1);
1414     rMatrix.set(0, 1, aMatrix.Line1.Column2);
1415     rMatrix.set(0, 2, aMatrix.Line1.Column3);
1416     rMatrix.set(1, 0, aMatrix.Line2.Column1);
1417     rMatrix.set(1, 1, aMatrix.Line2.Column2);
1418     rMatrix.set(1, 2, aMatrix.Line2.Column3);
1419     rMatrix.set(2, 0, aMatrix.Line3.Column1);
1420     rMatrix.set(2, 1, aMatrix.Line3.Column2);
1421     rMatrix.set(2, 2, aMatrix.Line3.Column3);
1422 }
1423 
ImpExportNewTrans_DecomposeAndRefPoint(const::basegfx::B2DHomMatrix & rMatrix,::basegfx::B2DTuple & rTRScale,double & fTRShear,double & fTRRotate,::basegfx::B2DTuple & rTRTranslate,css::awt::Point * pRefPoint)1424 void XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint(const ::basegfx::B2DHomMatrix& rMatrix, ::basegfx::B2DTuple& rTRScale,
1425     double& fTRShear, double& fTRRotate, ::basegfx::B2DTuple& rTRTranslate, css::awt::Point* pRefPoint)
1426 {
1427     // decompose matrix
1428     rMatrix.decompose(rTRScale, rTRTranslate, fTRRotate, fTRShear);
1429 
1430     // correct translation about pRefPoint
1431     if(pRefPoint)
1432     {
1433         rTRTranslate -= ::basegfx::B2DTuple(pRefPoint->X, pRefPoint->Y);
1434     }
1435 }
1436 
ImpExportNewTrans_FeaturesAndWrite(::basegfx::B2DTuple const & rTRScale,double fTRShear,double fTRRotate,::basegfx::B2DTuple const & rTRTranslate,const XMLShapeExportFlags nFeatures)1437 void XMLShapeExport::ImpExportNewTrans_FeaturesAndWrite(::basegfx::B2DTuple const & rTRScale, double fTRShear,
1438     double fTRRotate, ::basegfx::B2DTuple const & rTRTranslate, const XMLShapeExportFlags nFeatures)
1439 {
1440     // always write Size (rTRScale) since this statement carries the union
1441     // of the object
1442     OUString aStr;
1443     OUStringBuffer sStringBuffer;
1444     ::basegfx::B2DTuple aTRScale(rTRScale);
1445 
1446     // svg: width
1447     if(!(nFeatures & XMLShapeExportFlags::WIDTH))
1448     {
1449         aTRScale.setX(1.0);
1450     }
1451     else
1452     {
1453         if( aTRScale.getX() > 0.0 )
1454             aTRScale.setX(aTRScale.getX() - 1.0);
1455         else if( aTRScale.getX() < 0.0 )
1456             aTRScale.setX(aTRScale.getX() + 1.0);
1457     }
1458 
1459     mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1460             FRound(aTRScale.getX()));
1461     aStr = sStringBuffer.makeStringAndClear();
1462     mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, aStr);
1463 
1464     // svg: height
1465     if(!(nFeatures & XMLShapeExportFlags::HEIGHT))
1466     {
1467         aTRScale.setY(1.0);
1468     }
1469     else
1470     {
1471         if( aTRScale.getY() > 0.0 )
1472             aTRScale.setY(aTRScale.getY() - 1.0);
1473         else if( aTRScale.getY() < 0.0 )
1474             aTRScale.setY(aTRScale.getY() + 1.0);
1475     }
1476 
1477     mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1478             FRound(aTRScale.getY()));
1479     aStr = sStringBuffer.makeStringAndClear();
1480     mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, aStr);
1481 
1482     // decide if transformation is necessary
1483     bool bTransformationIsNecessary(fTRShear != 0.0 || fTRRotate != 0.0);
1484 
1485     if(bTransformationIsNecessary)
1486     {
1487         // write transformation, but WITHOUT scale which is exported as size above
1488         SdXMLImExTransform2D aTransform;
1489 
1490         aTransform.AddSkewX(atan(fTRShear));
1491 
1492         // #i78696#
1493         // fTRRotate is mathematically correct, but due to the error
1494         // we export/import it mirrored. Since the API implementation is fixed and
1495         // uses the correctly oriented angle, it is necessary for compatibility to
1496         // mirror the angle here to stay at the old behaviour. There is a follow-up
1497         // task (#i78698#) to fix this in the next ODF FileFormat version
1498         aTransform.AddRotate(-fTRRotate);
1499 
1500         aTransform.AddTranslate(rTRTranslate);
1501 
1502         // does transformation need to be exported?
1503         if(aTransform.NeedsAction())
1504             mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
1505     }
1506     else
1507     {
1508         // no shear, no rotate; just add object position to export and we are done
1509         if(nFeatures & XMLShapeExportFlags::X)
1510         {
1511             // svg: x
1512             mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1513                     FRound(rTRTranslate.getX()));
1514             aStr = sStringBuffer.makeStringAndClear();
1515             mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, aStr);
1516         }
1517 
1518         if(nFeatures & XMLShapeExportFlags::Y)
1519         {
1520             // svg: y
1521             mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1522                     FRound(rTRTranslate.getY()));
1523             aStr = sStringBuffer.makeStringAndClear();
1524             mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, aStr);
1525         }
1526     }
1527 }
1528 
ImpExportPresentationAttributes(const uno::Reference<beans::XPropertySet> & xPropSet,const OUString & rClass)1529 bool XMLShapeExport::ImpExportPresentationAttributes( const uno::Reference< beans::XPropertySet >& xPropSet, const OUString& rClass )
1530 {
1531     bool bIsEmpty = false;
1532 
1533     // write presentation class entry
1534     mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS, rClass);
1535 
1536     if( xPropSet.is() )
1537     {
1538         uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
1539 
1540 
1541         // is empty pres. shape?
1542         if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsEmptyPresentationObject"))
1543         {
1544             xPropSet->getPropertyValue("IsEmptyPresentationObject") >>= bIsEmpty;
1545             if( bIsEmpty )
1546                 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PLACEHOLDER, XML_TRUE);
1547         }
1548 
1549         // is user-transformed?
1550         if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsPlaceholderDependent"))
1551         {
1552             bool bTemp = false;
1553             xPropSet->getPropertyValue("IsPlaceholderDependent") >>= bTemp;
1554             if(!bTemp)
1555                 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_USER_TRANSFORMED, XML_TRUE);
1556         }
1557     }
1558 
1559     return bIsEmpty;
1560 }
1561 
ImpExportText(const uno::Reference<drawing::XShape> & xShape,TextPNS eExtensionNS)1562 void XMLShapeExport::ImpExportText( const uno::Reference< drawing::XShape >& xShape, TextPNS eExtensionNS )
1563 {
1564     if (eExtensionNS == TextPNS::EXTENSION)
1565     {
1566         if (mrExport.getDefaultVersion() <= SvtSaveOptions::ODFVER_012)
1567         {
1568             return; // do not export to ODF 1.1/1.2
1569         }
1570     }
1571     uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY );
1572     if( xText.is() )
1573     {
1574         uno::Reference< container::XEnumerationAccess > xEnumAccess( xShape, uno::UNO_QUERY );
1575         if( xEnumAccess.is() && xEnumAccess->hasElements() )
1576             mrExport.GetTextParagraphExport()->exportText( xText, false, true, eExtensionNS );
1577     }
1578 }
1579 
1580 
1581 enum class Found {
1582     NONE              = 0x0000,
1583     CLICKACTION       = 0x0001,
1584     BOOKMARK          = 0x0002,
1585     EFFECT            = 0x0004,
1586     PLAYFULL          = 0x0008,
1587     VERB              = 0x0010,
1588     SOUNDURL          = 0x0020,
1589     SPEED             = 0x0040,
1590     CLICKEVENTTYPE    = 0x0080,
1591     MACRO             = 0x0100,
1592     LIBRARY           = 0x0200,
1593 };
1594 namespace o3tl {
1595     template<> struct typed_flags<Found> : is_typed_flags<Found, 0x03ff> {};
1596 }
1597 
ImpExportEvents(const uno::Reference<drawing::XShape> & xShape)1598 void XMLShapeExport::ImpExportEvents( const uno::Reference< drawing::XShape >& xShape )
1599 {
1600     uno::Reference< document::XEventsSupplier > xEventsSupplier( xShape, uno::UNO_QUERY );
1601     if( !xEventsSupplier.is() )
1602         return;
1603 
1604     uno::Reference< container::XNameAccess > xEvents = xEventsSupplier->getEvents();
1605     SAL_WARN_IF( !xEvents.is(), "xmloff", "XEventsSupplier::getEvents() returned NULL" );
1606     if( !xEvents.is() )
1607         return;
1608 
1609     Found nFound = Found::NONE;
1610 
1611     OUString aClickEventType;
1612     presentation::ClickAction eClickAction = presentation::ClickAction_NONE;
1613     presentation::AnimationEffect eEffect = presentation::AnimationEffect_NONE;
1614     presentation::AnimationSpeed eSpeed = presentation::AnimationSpeed_SLOW;
1615     OUString aStrSoundURL;
1616     bool bPlayFull = false;
1617     sal_Int32 nVerb = 0;
1618     OUString aStrMacro;
1619     OUString aStrLibrary;
1620     OUString aStrBookmark;
1621 
1622     uno::Sequence< beans::PropertyValue > aClickProperties;
1623     if( xEvents->hasByName( gsOnClick ) && (xEvents->getByName( gsOnClick ) >>= aClickProperties) )
1624     {
1625         for( const auto& rProperty : std::as_const(aClickProperties) )
1626         {
1627             if( !( nFound & Found::CLICKEVENTTYPE ) && rProperty.Name == gsEventType )
1628             {
1629                 if( rProperty.Value >>= aClickEventType )
1630                     nFound |= Found::CLICKEVENTTYPE;
1631             }
1632             else if( !( nFound & Found::CLICKACTION ) && rProperty.Name == gsClickAction )
1633             {
1634                 if( rProperty.Value >>= eClickAction )
1635                     nFound |= Found::CLICKACTION;
1636             }
1637             else if( !( nFound & Found::MACRO ) && ( rProperty.Name == gsMacroName || rProperty.Name == gsScript ) )
1638             {
1639                 if( rProperty.Value >>= aStrMacro )
1640                     nFound |= Found::MACRO;
1641             }
1642             else if( !( nFound & Found::LIBRARY ) && rProperty.Name == gsLibrary )
1643             {
1644                 if( rProperty.Value >>= aStrLibrary )
1645                     nFound |= Found::LIBRARY;
1646             }
1647             else if( !( nFound & Found::EFFECT ) && rProperty.Name == gsEffect )
1648             {
1649                 if( rProperty.Value >>= eEffect )
1650                     nFound |= Found::EFFECT;
1651             }
1652             else if( !( nFound & Found::BOOKMARK ) && rProperty.Name == gsBookmark )
1653             {
1654                 if( rProperty.Value >>= aStrBookmark )
1655                     nFound |= Found::BOOKMARK;
1656             }
1657             else if( !( nFound & Found::SPEED ) && rProperty.Name == gsSpeed )
1658             {
1659                 if( rProperty.Value >>= eSpeed )
1660                     nFound |= Found::SPEED;
1661             }
1662             else if( !( nFound & Found::SOUNDURL ) && rProperty.Name == gsSoundURL )
1663             {
1664                 if( rProperty.Value >>= aStrSoundURL )
1665                     nFound |= Found::SOUNDURL;
1666             }
1667             else if( !( nFound & Found::PLAYFULL ) && rProperty.Name == gsPlayFull )
1668             {
1669                 if( rProperty.Value >>= bPlayFull )
1670                     nFound |= Found::PLAYFULL;
1671             }
1672             else if( !( nFound & Found::VERB ) && rProperty.Name == gsVerb )
1673             {
1674                 if( rProperty.Value >>= nVerb )
1675                     nFound |= Found::VERB;
1676             }
1677         }
1678     }
1679 
1680     // create the XML elements
1681 
1682     if( aClickEventType == gsPresentation )
1683     {
1684         if( !(nFound & Found::CLICKACTION) || (eClickAction == presentation::ClickAction_NONE) )
1685             return;
1686 
1687         SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
1688 
1689         enum XMLTokenEnum eStrAction;
1690 
1691         switch( eClickAction )
1692         {
1693             case presentation::ClickAction_PREVPAGE:        eStrAction = XML_PREVIOUS_PAGE; break;
1694             case presentation::ClickAction_NEXTPAGE:        eStrAction = XML_NEXT_PAGE; break;
1695             case presentation::ClickAction_FIRSTPAGE:       eStrAction = XML_FIRST_PAGE; break;
1696             case presentation::ClickAction_LASTPAGE:        eStrAction = XML_LAST_PAGE; break;
1697             case presentation::ClickAction_INVISIBLE:       eStrAction = XML_HIDE; break;
1698             case presentation::ClickAction_STOPPRESENTATION:eStrAction = XML_STOP; break;
1699             case presentation::ClickAction_PROGRAM:         eStrAction = XML_EXECUTE; break;
1700             case presentation::ClickAction_BOOKMARK:        eStrAction = XML_SHOW; break;
1701             case presentation::ClickAction_DOCUMENT:        eStrAction = XML_SHOW; break;
1702             case presentation::ClickAction_MACRO:           eStrAction = XML_EXECUTE_MACRO; break;
1703             case presentation::ClickAction_VERB:            eStrAction = XML_VERB; break;
1704             case presentation::ClickAction_VANISH:          eStrAction = XML_FADE_OUT; break;
1705             case presentation::ClickAction_SOUND:           eStrAction = XML_SOUND; break;
1706             default:
1707                 OSL_FAIL( "unknown presentation::ClickAction found!" );
1708                 eStrAction = XML_UNKNOWN;
1709         }
1710 
1711         OUString aEventQName(
1712             mrExport.GetNamespaceMap().GetQNameByKey(
1713                     XML_NAMESPACE_DOM, "click" ) );
1714         mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
1715         mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_ACTION, eStrAction );
1716 
1717         if( eClickAction == presentation::ClickAction_VANISH )
1718         {
1719             if( nFound & Found::EFFECT )
1720             {
1721                 XMLEffect eKind;
1722                 XMLEffectDirection eDirection;
1723                 sal_Int16 nStartScale;
1724                 bool bIn;
1725 
1726                 SdXMLImplSetEffect( eEffect, eKind, eDirection, nStartScale, bIn );
1727 
1728                 if( eKind != EK_none )
1729                 {
1730                     SvXMLUnitConverter::convertEnum( msBuffer, eKind, aXML_AnimationEffect_EnumMap );
1731                     mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_EFFECT, msBuffer.makeStringAndClear() );
1732                 }
1733 
1734                 if( eDirection != ED_none )
1735                 {
1736                     SvXMLUnitConverter::convertEnum( msBuffer, eDirection, aXML_AnimationDirection_EnumMap );
1737                     mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_DIRECTION, msBuffer.makeStringAndClear() );
1738                 }
1739 
1740                 if( nStartScale != -1 )
1741                 {
1742                     ::sax::Converter::convertPercent( msBuffer, nStartScale );
1743                     mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_START_SCALE, msBuffer.makeStringAndClear() );
1744                 }
1745             }
1746 
1747             if( nFound & Found::SPEED && eEffect != presentation::AnimationEffect_NONE )
1748             {
1749                  if( eSpeed != presentation::AnimationSpeed_MEDIUM )
1750                     {
1751                     SvXMLUnitConverter::convertEnum( msBuffer, eSpeed, aXML_AnimationSpeed_EnumMap );
1752                     mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_SPEED, msBuffer.makeStringAndClear() );
1753                 }
1754             }
1755         }
1756 
1757         if( eClickAction == presentation::ClickAction_PROGRAM ||
1758             eClickAction == presentation::ClickAction_BOOKMARK ||
1759             eClickAction == presentation::ClickAction_DOCUMENT )
1760         {
1761             if( eClickAction == presentation::ClickAction_BOOKMARK )
1762                 msBuffer.append( '#' );
1763 
1764             msBuffer.append( aStrBookmark );
1765             mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(msBuffer.makeStringAndClear()) );
1766             mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
1767             mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
1768             mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST );
1769         }
1770 
1771         if( ( nFound & Found::VERB ) && eClickAction == presentation::ClickAction_VERB )
1772         {
1773             msBuffer.append( nVerb );
1774             mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_VERB, msBuffer.makeStringAndClear());
1775         }
1776 
1777         SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_PRESENTATION, XML_EVENT_LISTENER, true, true);
1778 
1779         if( eClickAction == presentation::ClickAction_VANISH || eClickAction == presentation::ClickAction_SOUND )
1780         {
1781             if( ( nFound & Found::SOUNDURL ) && !aStrSoundURL.isEmpty() )
1782             {
1783                 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStrSoundURL) );
1784                 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
1785                 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_NEW );
1786                 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST );
1787                 if( nFound & Found::PLAYFULL && bPlayFull )
1788                     mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PLAY_FULL, XML_TRUE );
1789 
1790                 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_PRESENTATION, XML_SOUND, true, true );
1791             }
1792        }
1793     }
1794     else if( aClickEventType == gsStarBasic )
1795     {
1796         if( nFound & Found::MACRO )
1797         {
1798             SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
1799 
1800             mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE,
1801                         mrExport.GetNamespaceMap().GetQNameByKey(
1802                             XML_NAMESPACE_OOO,
1803                             "starbasic" ) );
1804             OUString aEventQName(
1805                 mrExport.GetNamespaceMap().GetQNameByKey(
1806                         XML_NAMESPACE_DOM, "click" ) );
1807             mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
1808 
1809             if( nFound & Found::LIBRARY )
1810             {
1811                 const OUString& sLocation( GetXMLToken(
1812                     (aStrLibrary.equalsIgnoreAsciiCase("StarOffice") ||
1813                      aStrLibrary.equalsIgnoreAsciiCase("application") ) ? XML_APPLICATION
1814                                                                        : XML_DOCUMENT ) );
1815                 mrExport.AddAttribute(XML_NAMESPACE_SCRIPT, XML_MACRO_NAME,
1816                     sLocation + ":" + aStrMacro);
1817             }
1818             else
1819             {
1820                 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_MACRO_NAME, aStrMacro );
1821             }
1822 
1823             SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, true, true);
1824         }
1825     }
1826     else if( aClickEventType == gsScript )
1827     {
1828         if( nFound & Found::MACRO )
1829         {
1830             SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
1831 
1832             mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE, mrExport.GetNamespaceMap().GetQNameByKey(
1833                      XML_NAMESPACE_OOO, GetXMLToken(XML_SCRIPT) ) );
1834             OUString aEventQName(
1835                 mrExport.GetNamespaceMap().GetQNameByKey(
1836                         XML_NAMESPACE_DOM, "click" ) );
1837             mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
1838             mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aStrMacro );
1839             mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, "simple" );
1840 
1841             SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, true, true);
1842         }
1843     }
1844 }
1845 
1846 /** #i68101# export shape Title and Description */
ImpExportDescription(const uno::Reference<drawing::XShape> & xShape)1847 void XMLShapeExport::ImpExportDescription( const uno::Reference< drawing::XShape >& xShape )
1848 {
1849     try
1850     {
1851         OUString aTitle;
1852         OUString aDescription;
1853 
1854         uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY_THROW );
1855         xProps->getPropertyValue("Title") >>= aTitle;
1856         xProps->getPropertyValue("Description") >>= aDescription;
1857 
1858         if(!aTitle.isEmpty())
1859         {
1860             SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_TITLE, true, false);
1861             mrExport.Characters( aTitle );
1862         }
1863 
1864         if(!aDescription.isEmpty())
1865         {
1866             SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_DESC, true, false );
1867             mrExport.Characters( aDescription );
1868         }
1869     }
1870     catch( uno::Exception& )
1871     {
1872         DBG_UNHANDLED_EXCEPTION( "xmloff", "exporting Title and/or Description for shape" );
1873     }
1874 }
1875 
ImpExportGroupShape(const uno::Reference<drawing::XShape> & xShape,XMLShapeExportFlags nFeatures,awt::Point * pRefPoint)1876 void XMLShapeExport::ImpExportGroupShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
1877 {
1878     uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY);
1879     if(xShapes.is() && xShapes->getCount())
1880     {
1881         // write group shape
1882         bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
1883         SvXMLElementExport aPGR(mrExport, XML_NAMESPACE_DRAW, XML_G, bCreateNewline, true);
1884 
1885         ImpExportDescription( xShape ); // #i68101#
1886         ImpExportEvents( xShape );
1887         ImpExportGluePoints( xShape );
1888 
1889         // #89764# if export of position is suppressed for group shape,
1890         // positions of contained objects should be written relative to
1891         // the upper left edge of the group.
1892         awt::Point aUpperLeft;
1893 
1894         if(!(nFeatures & XMLShapeExportFlags::POSITION))
1895         {
1896             nFeatures |= XMLShapeExportFlags::POSITION;
1897             aUpperLeft = xShape->getPosition();
1898             pRefPoint = &aUpperLeft;
1899         }
1900 
1901         // write members
1902         exportShapes( xShapes, nFeatures, pRefPoint );
1903     }
1904 }
1905 
ImpExportTextBoxShape(const uno::Reference<drawing::XShape> & xShape,XmlShapeType eShapeType,XMLShapeExportFlags nFeatures,awt::Point * pRefPoint)1906 void XMLShapeExport::ImpExportTextBoxShape(
1907     const uno::Reference< drawing::XShape >& xShape,
1908     XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
1909 {
1910     const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
1911     if(!xPropSet.is())
1912         return;
1913 
1914     // presentation attribute (if presentation)
1915     bool bIsPresShape(false);
1916     bool bIsEmptyPresObj(false);
1917     OUString aStr;
1918 
1919     switch(eShapeType)
1920     {
1921         case XmlShapeTypePresSubtitleShape:
1922         {
1923             aStr = GetXMLToken(XML_PRESENTATION_SUBTITLE);
1924             bIsPresShape = true;
1925             break;
1926         }
1927         case XmlShapeTypePresTitleTextShape:
1928         {
1929             aStr = GetXMLToken(XML_PRESENTATION_TITLE);
1930             bIsPresShape = true;
1931             break;
1932         }
1933         case XmlShapeTypePresOutlinerShape:
1934         {
1935             aStr = GetXMLToken(XML_PRESENTATION_OUTLINE);
1936             bIsPresShape = true;
1937             break;
1938         }
1939         case XmlShapeTypePresNotesShape:
1940         {
1941             aStr = GetXMLToken(XML_PRESENTATION_NOTES);
1942             bIsPresShape = true;
1943             break;
1944         }
1945         case XmlShapeTypePresHeaderShape:
1946         {
1947             aStr = GetXMLToken(XML_HEADER);
1948             bIsPresShape = true;
1949             break;
1950         }
1951         case XmlShapeTypePresFooterShape:
1952         {
1953             aStr = GetXMLToken(XML_FOOTER);
1954             bIsPresShape = true;
1955             break;
1956         }
1957         case XmlShapeTypePresSlideNumberShape:
1958         {
1959             aStr = GetXMLToken(XML_PAGE_NUMBER);
1960             bIsPresShape = true;
1961             break;
1962         }
1963         case XmlShapeTypePresDateTimeShape:
1964         {
1965             aStr = GetXMLToken(XML_DATE_TIME);
1966             bIsPresShape = true;
1967             break;
1968         }
1969         default:
1970             break;
1971     }
1972 
1973     // Transformation
1974     ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
1975 
1976     if(bIsPresShape)
1977         bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, aStr );
1978 
1979     bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
1980     SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
1981                               XML_FRAME, bCreateNewline, true );
1982 
1983     // evtl. corner radius?
1984     sal_Int32 nCornerRadius(0);
1985     xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius;
1986     if(nCornerRadius)
1987     {
1988         OUStringBuffer sStringBuffer;
1989         mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1990                 nCornerRadius);
1991         mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
1992     }
1993 
1994     {
1995         // write text-box
1996         SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_TEXT_BOX, true, true);
1997         if(!bIsEmptyPresObj)
1998             ImpExportText( xShape );
1999     }
2000 
2001     ImpExportDescription( xShape ); // #i68101#
2002     ImpExportEvents( xShape );
2003     ImpExportGluePoints( xShape );
2004 
2005 }
2006 
ImpExportRectangleShape(const uno::Reference<drawing::XShape> & xShape,XMLShapeExportFlags nFeatures,css::awt::Point * pRefPoint)2007 void XMLShapeExport::ImpExportRectangleShape(
2008     const uno::Reference< drawing::XShape >& xShape,
2009     XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
2010 {
2011     const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2012     if(xPropSet.is())
2013     {
2014         // Transformation
2015         ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2016 
2017         // evtl. corner radius?
2018         sal_Int32 nCornerRadius(0);
2019         xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius;
2020         if(nCornerRadius)
2021         {
2022             OUStringBuffer sStringBuffer;
2023             mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2024                     nCornerRadius);
2025             mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
2026         }
2027 
2028         // write rectangle
2029         bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2030         SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_RECT, bCreateNewline, true);
2031 
2032         ImpExportDescription( xShape ); // #i68101#
2033         ImpExportEvents( xShape );
2034         ImpExportGluePoints( xShape );
2035         ImpExportText( xShape );
2036     }
2037 }
2038 
ImpExportLineShape(const uno::Reference<drawing::XShape> & xShape,XMLShapeExportFlags nFeatures,awt::Point * pRefPoint)2039 void XMLShapeExport::ImpExportLineShape(
2040     const uno::Reference< drawing::XShape >& xShape,
2041     XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2042 {
2043     const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2044     if(!xPropSet.is())
2045         return;
2046 
2047     OUString aStr;
2048     OUStringBuffer sStringBuffer;
2049     awt::Point aStart(0,0);
2050     awt::Point aEnd(1,1);
2051 
2052     // #85920# use 'Geometry' to get the points of the line
2053     // since this slot take anchor pos into account.
2054 
2055     // get matrix
2056     ::basegfx::B2DHomMatrix aMatrix;
2057     ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
2058 
2059     // decompose and correct about pRefPoint
2060     ::basegfx::B2DTuple aTRScale;
2061     double fTRShear(0.0);
2062     double fTRRotate(0.0);
2063     ::basegfx::B2DTuple aTRTranslate;
2064     ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
2065 
2066     // create base position
2067     awt::Point aBasePosition(FRound(aTRTranslate.getX()), FRound(aTRTranslate.getY()));
2068 
2069     // get the two points
2070     uno::Any aAny(xPropSet->getPropertyValue("Geometry"));
2071     if (auto pSourcePolyPolygon
2072             = o3tl::tryAccess<drawing::PointSequenceSequence>(aAny))
2073     {
2074         if (pSourcePolyPolygon->getLength() > 0)
2075         {
2076             const drawing::PointSequence& rInnerSequence = (*pSourcePolyPolygon)[0];
2077             if (rInnerSequence.hasElements())
2078             {
2079                 const awt::Point& rPoint = rInnerSequence[0];
2080                 aStart = awt::Point(rPoint.X + aBasePosition.X, rPoint.Y + aBasePosition.Y);
2081             }
2082             if (rInnerSequence.getLength() > 1)
2083             {
2084                 const awt::Point& rPoint = rInnerSequence[1];
2085                 aEnd = awt::Point(rPoint.X + aBasePosition.X, rPoint.Y + aBasePosition.Y);
2086             }
2087         }
2088     }
2089 
2090     if( nFeatures & XMLShapeExportFlags::X )
2091     {
2092         // svg: x1
2093         mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2094                 aStart.X);
2095         aStr = sStringBuffer.makeStringAndClear();
2096         mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
2097     }
2098     else
2099     {
2100         aEnd.X -= aStart.X;
2101     }
2102 
2103     if( nFeatures & XMLShapeExportFlags::Y )
2104     {
2105         // svg: y1
2106         mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2107                 aStart.Y);
2108         aStr = sStringBuffer.makeStringAndClear();
2109         mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
2110     }
2111     else
2112     {
2113         aEnd.Y -= aStart.Y;
2114     }
2115 
2116     // svg: x2
2117     mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2118             aEnd.X);
2119     aStr = sStringBuffer.makeStringAndClear();
2120     mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
2121 
2122     // svg: y2
2123     mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2124             aEnd.Y);
2125     aStr = sStringBuffer.makeStringAndClear();
2126     mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
2127 
2128     // write line
2129     bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2130     SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_LINE, bCreateNewline, true);
2131 
2132     ImpExportDescription( xShape ); // #i68101#
2133     ImpExportEvents( xShape );
2134     ImpExportGluePoints( xShape );
2135     ImpExportText( xShape );
2136 
2137 }
2138 
ImpExportEllipseShape(const uno::Reference<drawing::XShape> & xShape,XMLShapeExportFlags nFeatures,awt::Point * pRefPoint)2139 void XMLShapeExport::ImpExportEllipseShape(
2140     const uno::Reference< drawing::XShape >& xShape,
2141     XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2142 {
2143     const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2144     if(!xPropSet.is())
2145         return;
2146 
2147     // get size to decide between Circle and Ellipse
2148     awt::Size aSize = xShape->getSize();
2149     sal_Int32 nRx((aSize.Width + 1) / 2);
2150     sal_Int32 nRy((aSize.Height + 1) / 2);
2151     bool bCircle(nRx == nRy);
2152 
2153     // Transformation
2154     ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2155 
2156     drawing::CircleKind eKind = drawing::CircleKind_FULL;
2157     xPropSet->getPropertyValue("CircleKind") >>= eKind;
2158     if( eKind != drawing::CircleKind_FULL )
2159     {
2160         OUStringBuffer sStringBuffer;
2161         sal_Int32 nStartAngle = 0;
2162         sal_Int32 nEndAngle = 0;
2163         xPropSet->getPropertyValue("CircleStartAngle") >>= nStartAngle;
2164         xPropSet->getPropertyValue("CircleEndAngle") >>= nEndAngle;
2165 
2166         const double dStartAngle = nStartAngle / 100.0;
2167         const double dEndAngle = nEndAngle / 100.0;
2168 
2169         // export circle kind
2170         SvXMLUnitConverter::convertEnum( sStringBuffer, eKind, aXML_CircleKind_EnumMap );
2171         mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_KIND, sStringBuffer.makeStringAndClear() );
2172 
2173         // export start angle
2174         ::sax::Converter::convertDouble( sStringBuffer, dStartAngle );
2175         mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_ANGLE, sStringBuffer.makeStringAndClear() );
2176 
2177         // export end angle
2178         ::sax::Converter::convertDouble( sStringBuffer, dEndAngle );
2179         mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_ANGLE, sStringBuffer.makeStringAndClear() );
2180     }
2181 
2182     bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2183 
2184     // write ellipse or circle
2185     SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW,
2186                             bCircle ? XML_CIRCLE : XML_ELLIPSE,
2187                             bCreateNewline, true);
2188 
2189     ImpExportDescription( xShape ); // #i68101#
2190     ImpExportEvents( xShape );
2191     ImpExportGluePoints( xShape );
2192     ImpExportText( xShape );
2193 
2194 }
2195 
ImpExportPolygonShape(const uno::Reference<drawing::XShape> & xShape,XmlShapeType eShapeType,XMLShapeExportFlags nFeatures,awt::Point * pRefPoint)2196 void XMLShapeExport::ImpExportPolygonShape(
2197     const uno::Reference< drawing::XShape >& xShape,
2198     XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2199 {
2200     const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2201     if(!xPropSet.is())
2202         return;
2203 
2204     bool bBezier(eShapeType == XmlShapeTypeDrawClosedBezierShape
2205         || eShapeType == XmlShapeTypeDrawOpenBezierShape);
2206 
2207     // get matrix
2208     ::basegfx::B2DHomMatrix aMatrix;
2209     ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
2210 
2211     // decompose and correct about pRefPoint
2212     ::basegfx::B2DTuple aTRScale;
2213     double fTRShear(0.0);
2214     double fTRRotate(0.0);
2215     ::basegfx::B2DTuple aTRTranslate;
2216     ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
2217 
2218     // use features and write
2219     ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures);
2220 
2221     // create and export ViewBox
2222     awt::Size aSize(FRound(aTRScale.getX()), FRound(aTRScale.getY()));
2223     SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height);
2224     mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
2225 
2226     bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2227 
2228     // prepare name (with most used)
2229     enum ::xmloff::token::XMLTokenEnum eName(XML_PATH);
2230 
2231     if(bBezier)
2232     {
2233         // get PolygonBezier
2234         uno::Any aAny( xPropSet->getPropertyValue("Geometry") );
2235         const basegfx::B2DPolyPolygon aPolyPolygon(
2236             basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(*o3tl::doAccess<drawing::PolyPolygonBezierCoords>(aAny)));
2237 
2238         if(aPolyPolygon.count())
2239         {
2240             // complex polygon shape, write as svg:d
2241             const OUString aPolygonString(
2242                 basegfx::utils::exportToSvgD(
2243                     aPolyPolygon,
2244                     true,       // bUseRelativeCoordinates
2245                     false,      // bDetectQuadraticBeziers: not used in old, but maybe activated now
2246                     true));     // bHandleRelativeNextPointCompatible
2247 
2248             // write point array
2249             mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
2250         }
2251     }
2252     else
2253     {
2254         // get non-bezier polygon
2255         uno::Any aAny( xPropSet->getPropertyValue("Geometry") );
2256         const basegfx::B2DPolyPolygon aPolyPolygon(
2257             basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(*o3tl::doAccess<drawing::PointSequenceSequence>(aAny)));
2258 
2259         if(!aPolyPolygon.areControlPointsUsed() && 1 == aPolyPolygon.count())
2260         {
2261             // simple polygon shape, can be written as svg:points sequence
2262             const basegfx::B2DPolygon& aPolygon(aPolyPolygon.getB2DPolygon(0));
2263             const OUString aPointString(basegfx::utils::exportToSvgPoints(aPolygon));
2264 
2265             // write point array
2266             mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString);
2267 
2268             // set name
2269             eName = aPolygon.isClosed() ? XML_POLYGON : XML_POLYLINE;
2270         }
2271         else
2272         {
2273             // complex polygon shape, write as svg:d
2274             const OUString aPolygonString(
2275                 basegfx::utils::exportToSvgD(
2276                     aPolyPolygon,
2277                     true,       // bUseRelativeCoordinates
2278                     false,      // bDetectQuadraticBeziers: not used in old, but maybe activated now
2279                     true));     // bHandleRelativeNextPointCompatible
2280 
2281             // write point array
2282             mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
2283         }
2284     }
2285 
2286     // write object, but after attributes are added since this call will
2287     // consume all of these added attributes and the destructor will close the
2288     // scope. Also before text is added; this may add sub-scopes as needed
2289     SvXMLElementExport aOBJ(
2290         mrExport,
2291         XML_NAMESPACE_DRAW,
2292         eName,
2293         bCreateNewline,
2294         true);
2295 
2296     ImpExportDescription( xShape ); // #i68101#
2297     ImpExportEvents( xShape );
2298     ImpExportGluePoints( xShape );
2299     ImpExportText( xShape );
2300 
2301 }
2302 
2303 namespace
2304 {
2305 
getNameFromStreamURL(OUString const & rURL)2306 OUString getNameFromStreamURL(OUString const & rURL)
2307 {
2308     const OUString sPackageURL("vnd.sun.star.Package:");
2309 
2310     OUString sResult;
2311 
2312     if (rURL.match(sPackageURL))
2313     {
2314         OUString sRequestedName = rURL.copy(sPackageURL.getLength());
2315         sal_Int32 nLastIndex = sRequestedName.lastIndexOf('/') + 1;
2316         if ((nLastIndex > 0) && (nLastIndex < sRequestedName.getLength()))
2317             sRequestedName = sRequestedName.copy(nLastIndex);
2318         nLastIndex = sRequestedName.lastIndexOf('.');
2319         if (nLastIndex >= 0)
2320             sRequestedName = sRequestedName.copy(0, nLastIndex);
2321         if (!sRequestedName.isEmpty())
2322             sResult = sRequestedName;
2323     }
2324 
2325     return sResult;
2326 }
2327 
2328 } // end anonymous namespace
2329 
ImpExportGraphicObjectShape(const uno::Reference<drawing::XShape> & xShape,XmlShapeType eShapeType,XMLShapeExportFlags nFeatures,awt::Point * pRefPoint)2330 void XMLShapeExport::ImpExportGraphicObjectShape(
2331     const uno::Reference< drawing::XShape >& xShape,
2332     XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2333 {
2334     const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2335     if(!xPropSet.is())
2336         return;
2337 
2338     bool bIsEmptyPresObj = false;
2339 
2340     // Transformation
2341     ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2342 
2343     if(eShapeType == XmlShapeTypePresGraphicObjectShape)
2344         bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_PRESENTATION_GRAPHIC) );
2345 
2346     bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2347     SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
2348                               XML_FRAME, bCreateNewline, true );
2349 
2350     const bool bSaveBackwardsCompatible = bool( mrExport.getExportFlags() & SvXMLExportFlags::SAVEBACKWARDCOMPATIBLE );
2351 
2352     if (!bIsEmptyPresObj || bSaveBackwardsCompatible)
2353     {
2354         uno::Reference<graphic::XGraphic> xGraphic;
2355         OUString sOutMimeType;
2356 
2357         if (!bIsEmptyPresObj)
2358         {
2359             OUString aStreamURL;
2360             xPropSet->getPropertyValue("GraphicStreamURL") >>= aStreamURL;
2361             OUString sRequestedName = getNameFromStreamURL(aStreamURL);
2362 
2363             xPropSet->getPropertyValue("Graphic") >>= xGraphic;
2364 
2365             OUString sInternalURL;
2366 
2367             if (xGraphic.is())
2368                 sInternalURL = mrExport.AddEmbeddedXGraphic(xGraphic, sOutMimeType, sRequestedName);
2369 
2370             if (!sInternalURL.isEmpty())
2371             {
2372                 // apply possible changed stream URL to embedded image object
2373                 if (!sRequestedName.isEmpty())
2374                 {
2375                     const OUString sPackageURL("vnd.sun.star.Package:");
2376                     OUString newStreamURL = sPackageURL;
2377                     if (sInternalURL[0] == '#')
2378                     {
2379                         newStreamURL += sInternalURL.copy(1, sInternalURL.getLength() - 1);
2380                     }
2381                     else
2382                     {
2383                         newStreamURL += sInternalURL;
2384                     }
2385 
2386                     if (newStreamURL != aStreamURL)
2387                     {
2388                         xPropSet->setPropertyValue("GraphicStreamURL", uno::Any(newStreamURL));
2389                     }
2390                 }
2391 
2392                 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL);
2393                 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
2394                 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
2395                 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
2396             }
2397         }
2398         else
2399         {
2400             mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, OUString());
2401             mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
2402             mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
2403             mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
2404         }
2405 
2406         {
2407             if (GetExport().getDefaultVersion() > SvtSaveOptions::ODFVER_012)
2408             {
2409                 if (sOutMimeType.isEmpty())
2410                 {
2411                     GetExport().GetGraphicMimeTypeFromStream(xGraphic, sOutMimeType);
2412                 }
2413                 if (!sOutMimeType.isEmpty())
2414                 {
2415                     GetExport().AddAttribute(XML_NAMESPACE_LO_EXT, "mime-type", sOutMimeType);
2416                 }
2417             }
2418 
2419             SvXMLElementExport aElement(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, true);
2420 
2421             // optional office:binary-data
2422             if (xGraphic.is())
2423             {
2424                 mrExport.AddEmbeddedXGraphicAsBase64(xGraphic);
2425             }
2426             if (!bIsEmptyPresObj)
2427                 ImpExportText(xShape);
2428         }
2429 
2430         //Resolves: fdo#62461 put preferred image first above, followed by
2431         //fallback here
2432         const bool bAddReplacementImages = officecfg::Office::Common::Save::Graphic::AddReplacementImages::get();
2433         if( !bIsEmptyPresObj && bAddReplacementImages)
2434         {
2435             uno::Reference<graphic::XGraphic> xReplacementGraphic;
2436             xPropSet->getPropertyValue("ReplacementGraphic") >>= xReplacementGraphic;
2437 
2438             // If there is no url, then the graphic is empty
2439             if (xReplacementGraphic.is())
2440             {
2441                 OUString aMimeType;
2442                 const OUString aHref = mrExport.AddEmbeddedXGraphic(xReplacementGraphic, aMimeType);
2443 
2444                 if (aMimeType.isEmpty())
2445                     mrExport.GetGraphicMimeTypeFromStream(xReplacementGraphic, aMimeType);
2446 
2447                 if (!aHref.isEmpty())
2448                 {
2449                     mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aHref);
2450                     mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
2451                     mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
2452                     mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
2453                 }
2454 
2455                 if (!aMimeType.isEmpty() && GetExport().getDefaultVersion() > SvtSaveOptions::ODFVER_012)
2456                     mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, "mime-type", aMimeType);
2457 
2458                 SvXMLElementExport aElement(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, true);
2459 
2460                 // optional office:binary-data
2461                 mrExport.AddEmbeddedXGraphicAsBase64(xReplacementGraphic);
2462             }
2463         }
2464     }
2465 
2466     ImpExportEvents( xShape );
2467     ImpExportGluePoints( xShape );
2468 
2469     // image map
2470     GetExport().GetImageMapExport().Export( xPropSet );
2471     ImpExportDescription( xShape ); // #i68101#
2472 
2473     // Signature Line, QR Code - needs to be after the images!
2474     if (GetExport().getDefaultVersion() > SvtSaveOptions::ODFVER_012)
2475     {
2476         ImpExportSignatureLine(xShape);
2477         ImpExportQRCode(xShape);
2478     }
2479 }
2480 
ImpExportChartShape(const uno::Reference<drawing::XShape> & xShape,XmlShapeType eShapeType,XMLShapeExportFlags nFeatures,awt::Point * pRefPoint,SvXMLAttributeList * pAttrList)2481 void XMLShapeExport::ImpExportChartShape(
2482     const uno::Reference< drawing::XShape >& xShape,
2483     XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint,
2484     SvXMLAttributeList* pAttrList )
2485 {
2486     ImpExportOLE2Shape( xShape, eShapeType, nFeatures, pRefPoint, pAttrList );
2487 }
2488 
ImpExportControlShape(const uno::Reference<drawing::XShape> & xShape,XMLShapeExportFlags nFeatures,awt::Point * pRefPoint)2489 void XMLShapeExport::ImpExportControlShape(
2490     const uno::Reference< drawing::XShape >& xShape,
2491     XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2492 {
2493     const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2494     if(xPropSet.is())
2495     {
2496         // Transformation
2497         ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2498     }
2499 
2500     uno::Reference< drawing::XControlShape > xControl( xShape, uno::UNO_QUERY );
2501     SAL_WARN_IF( !xControl.is(), "xmloff", "Control shape is not supporting XControlShape" );
2502     if( xControl.is() )
2503     {
2504         uno::Reference< beans::XPropertySet > xControlModel( xControl->getControl(), uno::UNO_QUERY );
2505         SAL_WARN_IF( !xControlModel.is(), "xmloff", "Control shape has not XControlModel" );
2506         if( xControlModel.is() )
2507         {
2508             mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CONTROL, mrExport.GetFormExport()->getControlId( xControlModel ) );
2509         }
2510     }
2511 
2512     bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2513     SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONTROL, bCreateNewline, true);
2514 
2515     ImpExportDescription( xShape ); // #i68101#
2516 }
2517 
ImpExportConnectorShape(const uno::Reference<drawing::XShape> & xShape,XMLShapeExportFlags nFeatures,awt::Point * pRefPoint)2518 void XMLShapeExport::ImpExportConnectorShape(
2519     const uno::Reference< drawing::XShape >& xShape,
2520     XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
2521 {
2522     uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
2523 
2524     OUString aStr;
2525     OUStringBuffer sStringBuffer;
2526 
2527     // export connection kind
2528     drawing::ConnectorType eType = drawing::ConnectorType_STANDARD;
2529     uno::Any aAny = xProps->getPropertyValue("EdgeKind");
2530     aAny >>= eType;
2531 
2532     if( eType != drawing::ConnectorType_STANDARD )
2533     {
2534         SvXMLUnitConverter::convertEnum( sStringBuffer, eType, aXML_ConnectionKind_EnumMap );
2535         aStr = sStringBuffer.makeStringAndClear();
2536         mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TYPE, aStr);
2537     }
2538 
2539     // export line skew
2540     sal_Int32 nDelta1 = 0, nDelta2 = 0, nDelta3 = 0;
2541 
2542     aAny = xProps->getPropertyValue("EdgeLine1Delta");
2543     aAny >>= nDelta1;
2544     aAny = xProps->getPropertyValue("EdgeLine2Delta");
2545     aAny >>= nDelta2;
2546     aAny = xProps->getPropertyValue("EdgeLine3Delta");
2547     aAny >>= nDelta3;
2548 
2549     if( nDelta1 != 0 || nDelta2 != 0 || nDelta3 != 0 )
2550     {
2551         mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2552                 nDelta1);
2553         if( nDelta2 != 0 || nDelta3 != 0 )
2554         {
2555             sStringBuffer.append( ' ' );
2556             mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2557                     nDelta2);
2558             if( nDelta3 != 0 )
2559             {
2560                 sStringBuffer.append( ' ' );
2561                 mrExport.GetMM100UnitConverter().convertMeasureToXML(
2562                         sStringBuffer, nDelta3);
2563             }
2564         }
2565 
2566         aStr = sStringBuffer.makeStringAndClear();
2567         mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_LINE_SKEW, aStr);
2568     }
2569 
2570     // export start and end point
2571     awt::Point aStart(0,0);
2572     awt::Point aEnd(1,1);
2573 
2574     /* Get <StartPositionInHoriL2R> and
2575        <EndPositionInHoriL2R>, if they exist and if the document is exported
2576        into the OpenOffice.org file format.
2577        These properties only exist at service css::text::Shape - the
2578        Writer UNO service for shapes.
2579        This code is needed, because the positioning attributes in the
2580        OpenOffice.org file format are given in horizontal left-to-right layout
2581        regardless the layout direction the shape is in. In the OASIS Open Office
2582        file format the positioning attributes are correctly given in the layout
2583        direction the shape is in. Thus, this code provides the conversion from
2584        the OASIS Open Office file format to the OpenOffice.org file format. (#i36248#)
2585     */
2586     if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
2587          xProps->getPropertySetInfo()->hasPropertyByName("StartPositionInHoriL2R") &&
2588          xProps->getPropertySetInfo()->hasPropertyByName("EndPositionInHoriL2R") )
2589     {
2590         xProps->getPropertyValue("StartPositionInHoriL2R") >>= aStart;
2591         xProps->getPropertyValue("EndPositionInHoriL2R") >>= aEnd;
2592     }
2593     else
2594     {
2595         xProps->getPropertyValue("StartPosition") >>= aStart;
2596         xProps->getPropertyValue("EndPosition") >>= aEnd;
2597     }
2598 
2599     if( pRefPoint )
2600     {
2601         aStart.X -= pRefPoint->X;
2602         aStart.Y -= pRefPoint->Y;
2603         aEnd.X -= pRefPoint->X;
2604         aEnd.Y -= pRefPoint->Y;
2605     }
2606 
2607     if( nFeatures & XMLShapeExportFlags::X )
2608     {
2609         // svg: x1
2610         mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2611                 aStart.X);
2612         aStr = sStringBuffer.makeStringAndClear();
2613         mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
2614     }
2615     else
2616     {
2617         aEnd.X -= aStart.X;
2618     }
2619 
2620     if( nFeatures & XMLShapeExportFlags::Y )
2621     {
2622         // svg: y1
2623         mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2624                 aStart.Y);
2625         aStr = sStringBuffer.makeStringAndClear();
2626         mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
2627     }
2628     else
2629     {
2630         aEnd.Y -= aStart.Y;
2631     }
2632 
2633     // svg: x2
2634     mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.X);
2635     aStr = sStringBuffer.makeStringAndClear();
2636     mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
2637 
2638     // svg: y2
2639     mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.Y);
2640     aStr = sStringBuffer.makeStringAndClear();
2641     mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
2642 
2643     // #i39320#
2644     uno::Reference< uno::XInterface > xRefS;
2645     uno::Reference< uno::XInterface > xRefE;
2646 
2647     // export start connection
2648     xProps->getPropertyValue("StartShape") >>= xRefS;
2649     if( xRefS.is() )
2650     {
2651         const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefS );
2652         mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_SHAPE, rShapeId);
2653 
2654         aAny = xProps->getPropertyValue("StartGluePointIndex");
2655         sal_Int32 nGluePointId = 0;
2656         if( aAny >>= nGluePointId )
2657         {
2658             if( nGluePointId != -1 )
2659             {
2660                 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_GLUE_POINT, OUString::number( nGluePointId ));
2661             }
2662         }
2663     }
2664 
2665     // export end connection
2666     xProps->getPropertyValue("EndShape") >>= xRefE;
2667     if( xRefE.is() )
2668     {
2669         const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefE );
2670         mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_SHAPE, rShapeId);
2671 
2672         aAny = xProps->getPropertyValue("EndGluePointIndex");
2673         sal_Int32 nGluePointId = 0;
2674         if( aAny >>= nGluePointId )
2675         {
2676             if( nGluePointId != -1 )
2677             {
2678                 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_GLUE_POINT, OUString::number( nGluePointId ));
2679             }
2680         }
2681     }
2682 
2683     // get PolygonBezier
2684     aAny = xProps->getPropertyValue("PolyPolygonBezier");
2685     auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(aAny);
2686     if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength())
2687     {
2688         const basegfx::B2DPolyPolygon aPolyPolygon(
2689             basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(
2690                 *pSourcePolyPolygon));
2691         const OUString aPolygonString(
2692             basegfx::utils::exportToSvgD(
2693                 aPolyPolygon,
2694                 true,           // bUseRelativeCoordinates
2695                 false,          // bDetectQuadraticBeziers: not used in old, but maybe activated now
2696                 true));         // bHandleRelativeNextPointCompatible
2697 
2698         // write point array
2699         mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
2700     }
2701 
2702     // get matrix
2703     ::basegfx::B2DHomMatrix aMatrix;
2704     ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xProps);
2705 
2706     // decompose and correct about pRefPoint
2707     ::basegfx::B2DTuple aTRScale;
2708     double fTRShear(0.0);
2709     double fTRRotate(0.0);
2710     ::basegfx::B2DTuple aTRTranslate;
2711     ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear,
2712             fTRRotate, aTRTranslate, pRefPoint);
2713 
2714     // fdo#49678: create and export ViewBox
2715     awt::Size aSize(FRound(aTRScale.getX()), FRound(aTRScale.getY()));
2716     SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height);
2717     mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
2718 
2719     // write connector shape. Add Export later.
2720     bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2721     SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONNECTOR, bCreateNewline, true);
2722 
2723     ImpExportDescription( xShape ); // #i68101#
2724     ImpExportEvents( xShape );
2725     ImpExportGluePoints( xShape );
2726     ImpExportText( xShape );
2727 }
2728 
ImpExportMeasureShape(const uno::Reference<drawing::XShape> & xShape,XMLShapeExportFlags nFeatures,awt::Point const * pRefPoint)2729 void XMLShapeExport::ImpExportMeasureShape(
2730     const uno::Reference< drawing::XShape >& xShape,
2731     XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point const * pRefPoint /* = NULL */)
2732 {
2733     uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
2734 
2735     OUString aStr;
2736     OUStringBuffer sStringBuffer;
2737 
2738     // export start and end point
2739     awt::Point aStart(0,0);
2740     awt::Point aEnd(1,1);
2741 
2742     /* Get <StartPositionInHoriL2R> and
2743        <EndPositionInHoriL2R>, if they exist and if the document is exported
2744        into the OpenOffice.org file format.
2745        These properties only exist at service css::text::Shape - the
2746        Writer UNO service for shapes.
2747        This code is needed, because the positioning attributes in the
2748        OpenOffice.org file format are given in horizontal left-to-right layout
2749        regardless the layout direction the shape is in. In the OASIS Open Office
2750        file format the positioning attributes are correctly given in the layout
2751        direction the shape is in. Thus, this code provides the conversion from
2752        the OASIS Open Office file format to the OpenOffice.org file format. (#i36248#)
2753     */
2754     if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
2755          xProps->getPropertySetInfo()->hasPropertyByName("StartPositionInHoriL2R") &&
2756          xProps->getPropertySetInfo()->hasPropertyByName("EndPositionInHoriL2R") )
2757     {
2758         xProps->getPropertyValue("StartPositionInHoriL2R") >>= aStart;
2759         xProps->getPropertyValue("EndPositionInHoriL2R") >>= aEnd;
2760     }
2761     else
2762     {
2763         xProps->getPropertyValue("StartPosition") >>= aStart;
2764         xProps->getPropertyValue("EndPosition") >>= aEnd;
2765     }
2766 
2767     if( pRefPoint )
2768     {
2769         aStart.X -= pRefPoint->X;
2770         aStart.Y -= pRefPoint->Y;
2771         aEnd.X -= pRefPoint->X;
2772         aEnd.Y -= pRefPoint->Y;
2773     }
2774 
2775     if( nFeatures & XMLShapeExportFlags::X )
2776     {
2777         // svg: x1
2778         mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2779                 aStart.X);
2780         aStr = sStringBuffer.makeStringAndClear();
2781         mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
2782     }
2783     else
2784     {
2785         aEnd.X -= aStart.X;
2786     }
2787 
2788     if( nFeatures & XMLShapeExportFlags::Y )
2789     {
2790         // svg: y1
2791         mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2792                 aStart.Y);
2793         aStr = sStringBuffer.makeStringAndClear();
2794         mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
2795     }
2796     else
2797     {
2798         aEnd.Y -= aStart.Y;
2799     }
2800 
2801     // svg: x2
2802     mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.X);
2803     aStr = sStringBuffer.makeStringAndClear();
2804     mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
2805 
2806     // svg: y2
2807     mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.Y);
2808     aStr = sStringBuffer.makeStringAndClear();
2809     mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
2810 
2811     // write measure shape
2812     bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2813     SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_MEASURE, bCreateNewline, true);
2814 
2815     ImpExportDescription( xShape ); // #i68101#
2816     ImpExportEvents( xShape );
2817     ImpExportGluePoints( xShape );
2818 
2819     uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY );
2820     if( xText.is() )
2821         mrExport.GetTextParagraphExport()->exportText( xText );
2822 }
2823 
ImpExportOLE2Shape(const uno::Reference<drawing::XShape> & xShape,XmlShapeType eShapeType,XMLShapeExportFlags nFeatures,awt::Point * pRefPoint,SvXMLAttributeList * pAttrList)2824 void XMLShapeExport::ImpExportOLE2Shape(
2825     const uno::Reference< drawing::XShape >& xShape,
2826     XmlShapeType eShapeType, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */,
2827     SvXMLAttributeList* pAttrList /* = NULL */ )
2828 {
2829     uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2830     uno::Reference< container::XNamed > xNamed(xShape, uno::UNO_QUERY);
2831 
2832     SAL_WARN_IF( !xPropSet.is() || !xNamed.is(), "xmloff", "ole shape is not implementing needed interfaces");
2833     if(!(xPropSet.is() && xNamed.is()))
2834         return;
2835 
2836     // Transformation
2837     ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2838 
2839     bool bIsEmptyPresObj = false;
2840 
2841     // presentation settings
2842     if(eShapeType == XmlShapeTypePresOLE2Shape)
2843         bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_PRESENTATION_OBJECT) );
2844     else if(eShapeType == XmlShapeTypePresChartShape)
2845         bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_PRESENTATION_CHART) );
2846     else if(eShapeType == XmlShapeTypePresSheetShape)
2847         bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_PRESENTATION_TABLE) );
2848 
2849     bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2850     bool bExportEmbedded(mrExport.getExportFlags() & SvXMLExportFlags::EMBEDDED);
2851     OUString sPersistName;
2852     SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
2853                               XML_FRAME, bCreateNewline, true );
2854 
2855     const bool bSaveBackwardsCompatible = bool( mrExport.getExportFlags() & SvXMLExportFlags::SAVEBACKWARDCOMPATIBLE );
2856 
2857     if( !bIsEmptyPresObj || bSaveBackwardsCompatible )
2858     {
2859         if (pAttrList)
2860         {
2861             mrExport.AddAttributeList(pAttrList);
2862         }
2863 
2864         OUString sClassId;
2865         OUString sURL;
2866         bool bInternal = false;
2867         xPropSet->getPropertyValue("IsInternal") >>= bInternal;
2868 
2869         if( !bIsEmptyPresObj )
2870         {
2871 
2872             if ( bInternal )
2873             {
2874                 // OOo internal links have no storage persistence, URL is stored in the XML file
2875                 // the result LinkURL is empty in case the object is not a link
2876                 xPropSet->getPropertyValue("LinkURL") >>= sURL;
2877             }
2878 
2879             xPropSet->getPropertyValue("PersistName") >>= sPersistName;
2880             if ( sURL.isEmpty() )
2881             {
2882                 if( !sPersistName.isEmpty() )
2883                 {
2884                     sURL = "vnd.sun.star.EmbeddedObject:" + sPersistName;
2885                 }
2886             }
2887 
2888             if( !bInternal )
2889                 xPropSet->getPropertyValue("CLSID") >>= sClassId;
2890 
2891             if( !sClassId.isEmpty() )
2892                 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CLASS_ID, sClassId );
2893 
2894             if(!bExportEmbedded)
2895             {
2896                 // xlink:href
2897                 if( !sURL.isEmpty() )
2898                 {
2899                     // #96717# in theorie, if we don't have a URL we shouldn't even
2900                     // export this OLE shape. But practically it's too risky right now
2901                     // to change this so we better dispose this on load
2902                     sURL = mrExport.AddEmbeddedObject( sURL );
2903 
2904                     mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL );
2905                     mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
2906                     mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
2907                     mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
2908                 }
2909             }
2910         }
2911         else
2912         {
2913             // export empty href for empty placeholders to be valid ODF
2914             mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, "" );
2915             mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
2916             mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
2917             mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
2918         }
2919 
2920         enum XMLTokenEnum eElem = sClassId.isEmpty() ? XML_OBJECT : XML_OBJECT_OLE ;
2921         SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, eElem, true, true );
2922 
2923         // tdf#112547 export text as child of draw:object, where import expects it
2924         if (!bIsEmptyPresObj && supportsText(eShapeType))
2925         {
2926             // #i118485# Add text export, the draw OLE shape allows text now
2927             ImpExportText( xShape, TextPNS::EXTENSION );
2928         }
2929 
2930         if(bExportEmbedded && !bIsEmptyPresObj)
2931         {
2932             if(bInternal)
2933             {
2934                 // embedded XML
2935                 uno::Reference< lang::XComponent > xComp;
2936                 xPropSet->getPropertyValue("Model") >>= xComp;
2937                 SAL_WARN_IF( !xComp.is(), "xmloff", "no xModel for own OLE format" );
2938                 mrExport.ExportEmbeddedOwnObject( xComp );
2939             }
2940             else
2941             {
2942                 // embed as Base64
2943                 // this is an alien object ( currently MSOLE is the only supported type of such objects )
2944                 // in case it is not an OASIS format the object should be asked to store replacement image if possible
2945 
2946                 OUString sURLRequest( sURL );
2947                 if ( !( mrExport.getExportFlags() & SvXMLExportFlags::OASIS ) )
2948                     sURLRequest +=  "?oasis=false";
2949                 mrExport.AddEmbeddedObjectAsBase64( sURLRequest );
2950             }
2951         }
2952     }
2953     if( !bIsEmptyPresObj )
2954     {
2955         OUString sURL = XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE + sPersistName;
2956         if( !bExportEmbedded )
2957         {
2958             sURL = GetExport().AddEmbeddedObject( sURL );
2959             mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL );
2960             mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
2961             mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
2962             mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
2963         }
2964 
2965         SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW,
2966                                   XML_IMAGE, false, true );
2967 
2968         if( bExportEmbedded )
2969             GetExport().AddEmbeddedObjectAsBase64( sURL );
2970     }
2971 
2972     ImpExportEvents( xShape );
2973     ImpExportGluePoints( xShape );
2974     ImpExportDescription( xShape ); // #i68101#
2975 
2976 }
2977 
ImpExportPageShape(const uno::Reference<drawing::XShape> & xShape,XmlShapeType eShapeType,XMLShapeExportFlags nFeatures,awt::Point * pRefPoint)2978 void XMLShapeExport::ImpExportPageShape(
2979     const uno::Reference< drawing::XShape >& xShape,
2980     XmlShapeType eShapeType, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
2981 {
2982     const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2983     if(xPropSet.is())
2984     {
2985         // #86163# Transformation
2986         ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2987 
2988         // export page number used for this page
2989         uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
2990         const OUString aPageNumberStr("PageNumber");
2991         if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(aPageNumberStr))
2992         {
2993             sal_Int32 nPageNumber = 0;
2994             xPropSet->getPropertyValue(aPageNumberStr) >>= nPageNumber;
2995             if( nPageNumber )
2996                 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_PAGE_NUMBER, OUString::number(nPageNumber));
2997         }
2998 
2999         // a presentation page shape, normally used on notes pages only. If
3000         // it is used not as presentation shape, it may have been created with
3001         // copy-paste exchange between draw and impress (this IS possible...)
3002         if(eShapeType == XmlShapeTypePresPageShape)
3003         {
3004             mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS,
3005                                  XML_PRESENTATION_PAGE);
3006         }
3007 
3008         // write Page shape
3009         bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3010         SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PAGE_THUMBNAIL, bCreateNewline, true);
3011     }
3012 }
3013 
ImpExportCaptionShape(const uno::Reference<drawing::XShape> & xShape,XMLShapeExportFlags nFeatures,awt::Point * pRefPoint)3014 void XMLShapeExport::ImpExportCaptionShape(
3015     const uno::Reference< drawing::XShape >& xShape,
3016     XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
3017 {
3018     const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3019     if(!xPropSet.is())
3020         return;
3021 
3022     // Transformation
3023     ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3024 
3025     // evtl. corner radius?
3026     sal_Int32 nCornerRadius(0);
3027     xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius;
3028     if(nCornerRadius)
3029     {
3030         OUStringBuffer sStringBuffer;
3031         mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
3032                 nCornerRadius);
3033         mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
3034     }
3035 
3036     awt::Point aCaptionPoint;
3037     xPropSet->getPropertyValue("CaptionPoint") >>= aCaptionPoint;
3038 
3039     mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
3040             aCaptionPoint.X);
3041     mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_X, msBuffer.makeStringAndClear() );
3042     mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
3043             aCaptionPoint.Y);
3044     mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_Y, msBuffer.makeStringAndClear() );
3045 
3046     // write Caption shape. Add export later.
3047     bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3048     bool bAnnotation( (nFeatures & XMLShapeExportFlags::ANNOTATION) == XMLShapeExportFlags::ANNOTATION );
3049 
3050     SvXMLElementExport aObj( mrExport,
3051                              (bAnnotation ? XML_NAMESPACE_OFFICE
3052                                            : XML_NAMESPACE_DRAW),
3053                              (bAnnotation ? XML_ANNOTATION : XML_CAPTION),
3054                              bCreateNewline, true );
3055 
3056     ImpExportDescription( xShape ); // #i68101#
3057     ImpExportEvents( xShape );
3058     ImpExportGluePoints( xShape );
3059     if( bAnnotation )
3060         mrExport.exportAnnotationMeta( xShape );
3061     ImpExportText( xShape );
3062 
3063 }
3064 
ImpExportFrameShape(const uno::Reference<drawing::XShape> & xShape,XMLShapeExportFlags nFeatures,css::awt::Point * pRefPoint)3065 void XMLShapeExport::ImpExportFrameShape(
3066     const uno::Reference< drawing::XShape >& xShape,
3067     XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3068 {
3069     const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3070     if(!xPropSet.is())
3071         return;
3072 
3073     // Transformation
3074     ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3075 
3076     bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3077     SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
3078                               XML_FRAME, bCreateNewline, true );
3079 
3080     // export frame url
3081     OUString aStr;
3082     xPropSet->getPropertyValue("FrameURL") >>= aStr;
3083     mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
3084     mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3085     mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3086     mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3087 
3088     // export name
3089     xPropSet->getPropertyValue("FrameName") >>= aStr;
3090     if( !aStr.isEmpty() )
3091         mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FRAME_NAME, aStr );
3092 
3093     // write floating frame
3094     {
3095         SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_FLOATING_FRAME, true, true);
3096     }
3097 
3098 }
3099 
ImpExportAppletShape(const uno::Reference<drawing::XShape> & xShape,XMLShapeExportFlags nFeatures,css::awt::Point * pRefPoint)3100 void XMLShapeExport::ImpExportAppletShape(
3101     const uno::Reference< drawing::XShape >& xShape,
3102     XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3103 {
3104     const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3105     if(!xPropSet.is())
3106         return;
3107 
3108     // Transformation
3109     ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3110 
3111     bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3112     SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
3113                               XML_FRAME, bCreateNewline, true );
3114 
3115     // export frame url
3116     OUString aStr;
3117     xPropSet->getPropertyValue("AppletCodeBase") >>= aStr;
3118     mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
3119     mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3120     mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3121     mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3122 
3123     // export draw:applet-name
3124     xPropSet->getPropertyValue("AppletName") >>= aStr;
3125     if( !aStr.isEmpty() )
3126         mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_APPLET_NAME, aStr );
3127 
3128     // export draw:code
3129     xPropSet->getPropertyValue("AppletCode") >>= aStr;
3130     mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CODE, aStr );
3131 
3132     // export draw:may-script
3133     bool bIsScript = false;
3134     xPropSet->getPropertyValue("AppletIsScript") >>= bIsScript;
3135     mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MAY_SCRIPT, bIsScript ? XML_TRUE : XML_FALSE );
3136 
3137     {
3138         // write applet
3139         SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_APPLET, true, true);
3140 
3141         // export parameters
3142         uno::Sequence< beans::PropertyValue > aCommands;
3143         xPropSet->getPropertyValue("AppletCommands") >>= aCommands;
3144         for( const auto& rCommand : std::as_const(aCommands) )
3145         {
3146             rCommand.Value >>= aStr;
3147             mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rCommand.Name );
3148             mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr );
3149             SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3150         }
3151     }
3152 
3153 }
3154 
ImpExportPluginShape(const uno::Reference<drawing::XShape> & xShape,XMLShapeExportFlags nFeatures,css::awt::Point * pRefPoint)3155 void XMLShapeExport::ImpExportPluginShape(
3156     const uno::Reference< drawing::XShape >& xShape,
3157     XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3158 {
3159     const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3160     if(!xPropSet.is())
3161         return;
3162 
3163     // Transformation
3164     ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3165 
3166     bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3167     SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
3168                               XML_FRAME, bCreateNewline, true );
3169 
3170     // export plugin url
3171     OUString aStr;
3172     xPropSet->getPropertyValue("PluginURL") >>= aStr;
3173     mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
3174     mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3175     mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3176     mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3177 
3178     // export mime-type
3179     xPropSet->getPropertyValue("PluginMimeType") >>= aStr;
3180     if(!aStr.isEmpty())
3181         mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, aStr );
3182 
3183     {
3184         // write plugin
3185         SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, true, true);
3186 
3187         // export parameters
3188         uno::Sequence< beans::PropertyValue > aCommands;
3189         xPropSet->getPropertyValue("PluginCommands") >>= aCommands;
3190         for( const auto& rCommand : std::as_const(aCommands) )
3191         {
3192             rCommand.Value >>= aStr;
3193             mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rCommand.Name );
3194             mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr );
3195             SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3196         }
3197     }
3198 
3199 }
3200 
lcl_CopyStream(uno::Reference<io::XInputStream> const & xInStream,uno::Reference<embed::XStorage> const & xTarget,OUString const & rPath,const OUString & rMimeType)3201 static void lcl_CopyStream(
3202         uno::Reference<io::XInputStream> const& xInStream,
3203         uno::Reference<embed::XStorage> const& xTarget,
3204         OUString const& rPath, const OUString& rMimeType)
3205 {
3206     ::comphelper::LifecycleProxy proxy;
3207     uno::Reference<io::XStream> const xStream(
3208         ::comphelper::OStorageHelper::GetStreamAtPackageURL(xTarget, rPath,
3209             embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE, proxy));
3210     uno::Reference<io::XOutputStream> const xOutStream(
3211             (xStream.is()) ? xStream->getOutputStream() : nullptr);
3212     if (!xOutStream.is())
3213     {
3214         SAL_WARN("xmloff", "no output stream");
3215         throw uno::Exception("no output stream",nullptr);
3216     }
3217     uno::Reference< beans::XPropertySet > const xStreamProps(xStream,
3218         uno::UNO_QUERY);
3219     if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage
3220         xStreamProps->setPropertyValue("MediaType",
3221             uno::makeAny(rMimeType));
3222         xStreamProps->setPropertyValue( // turn off compression
3223             "Compressed",
3224             uno::makeAny(false));
3225     }
3226     ::comphelper::OStorageHelper::CopyInputToOutput(xInStream, xOutStream);
3227     xOutStream->closeOutput();
3228     proxy.commitStorages();
3229 }
3230 
3231 static OUString
lcl_StoreMediaAndGetURL(SvXMLExport & rExport,uno::Reference<beans::XPropertySet> const & xPropSet,OUString const & rURL,const OUString & rMimeType)3232 lcl_StoreMediaAndGetURL(SvXMLExport & rExport,
3233     uno::Reference<beans::XPropertySet> const& xPropSet,
3234     OUString const& rURL, const OUString& rMimeType)
3235 {
3236     OUString urlPath;
3237     if (rURL.startsWithIgnoreAsciiCase("vnd.sun.star.Package:", &urlPath))
3238     {
3239         try // video is embedded
3240         {
3241             uno::Reference<embed::XStorage> const xTarget(
3242                     rExport.GetTargetStorage(), uno::UNO_SET_THROW);
3243             uno::Reference<io::XInputStream> xInStream;
3244             xPropSet->getPropertyValue("PrivateStream")
3245                     >>= xInStream;
3246 
3247             if (!xInStream.is())
3248             {
3249                 SAL_WARN("xmloff", "no input stream");
3250                 return OUString();
3251             }
3252 
3253             lcl_CopyStream(xInStream, xTarget, rURL, rMimeType);
3254 
3255             return urlPath;
3256         }
3257         catch (uno::Exception const&)
3258         {
3259             TOOLS_INFO_EXCEPTION("xmloff", "exception while storing embedded media");
3260         }
3261         return OUString();
3262     }
3263     else
3264     {
3265         return rExport.GetRelativeReference(rURL); // linked
3266     }
3267 }
3268 
ImpExportMediaShape(const uno::Reference<drawing::XShape> & xShape,XmlShapeType eShapeType,XMLShapeExportFlags nFeatures,css::awt::Point * pRefPoint)3269 void XMLShapeExport::ImpExportMediaShape(
3270     const uno::Reference< drawing::XShape >& xShape,
3271     XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3272 {
3273     const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3274     if(!xPropSet.is())
3275         return;
3276 
3277     // Transformation
3278     ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3279 
3280     if(eShapeType == XmlShapeTypePresMediaShape)
3281     {
3282         (void)ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_PRESENTATION_OBJECT) );
3283     }
3284     bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3285     SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
3286                               XML_FRAME, bCreateNewline, true );
3287 
3288     // export media url
3289     OUString aMediaURL;
3290     xPropSet->getPropertyValue("MediaURL") >>= aMediaURL;
3291     OUString sMimeType;
3292     xPropSet->getPropertyValue("MediaMimeType") >>= sMimeType;
3293 
3294     OUString const persistentURL =
3295         lcl_StoreMediaAndGetURL(GetExport(), xPropSet, aMediaURL, sMimeType);
3296 
3297     mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, persistentURL );
3298     mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3299     mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3300     mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3301 
3302     // export mime-type
3303     mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, sMimeType );
3304 
3305     // write plugin
3306     auto pPluginOBJ = std::make_unique<SvXMLElementExport>(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, !( nFeatures & XMLShapeExportFlags::NO_WS ), true);
3307 
3308     // export parameters
3309     const OUString aFalseStr(  "false"  ), aTrueStr(  "true"  );
3310 
3311     bool bLoop = false;
3312     const OUString aLoopStr(  "Loop"  );
3313     xPropSet->getPropertyValue( aLoopStr ) >>= bLoop;
3314     mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aLoopStr );
3315     mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, bLoop ? aTrueStr : aFalseStr );
3316     delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3317 
3318     bool bMute = false;
3319     const OUString aMuteStr(  "Mute"  );
3320     xPropSet->getPropertyValue( aMuteStr ) >>= bMute;
3321     mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aMuteStr );
3322     mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, bMute ? aTrueStr : aFalseStr );
3323     delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3324 
3325     sal_Int16 nVolumeDB = 0;
3326     const OUString aVolumeDBStr(  "VolumeDB"  );
3327     xPropSet->getPropertyValue("VolumeDB") >>= nVolumeDB;
3328     mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aVolumeDBStr );
3329     mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, OUString::number( nVolumeDB ) );
3330     delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3331 
3332     media::ZoomLevel eZoom;
3333     const OUString aZoomStr(  "Zoom"  );
3334     OUString aZoomValue;
3335     xPropSet->getPropertyValue("Zoom") >>= eZoom;
3336     switch( eZoom )
3337     {
3338         case media::ZoomLevel_ZOOM_1_TO_4  : aZoomValue = "25%"; break;
3339         case media::ZoomLevel_ZOOM_1_TO_2  : aZoomValue = "50%"; break;
3340         case media::ZoomLevel_ORIGINAL     : aZoomValue = "100%"; break;
3341         case media::ZoomLevel_ZOOM_2_TO_1  : aZoomValue = "200%"; break;
3342         case media::ZoomLevel_ZOOM_4_TO_1  : aZoomValue = "400%"; break;
3343         case media::ZoomLevel_FIT_TO_WINDOW: aZoomValue = "fit"; break;
3344         case media::ZoomLevel_FIT_TO_WINDOW_FIXED_ASPECT: aZoomValue = "fixedfit"; break;
3345         case media::ZoomLevel_FULLSCREEN   : aZoomValue = "fullscreen"; break;
3346 
3347         default:
3348         break;
3349     }
3350 
3351     if( !aZoomValue.isEmpty() )
3352     {
3353         mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aZoomStr );
3354         mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aZoomValue );
3355         delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3356     }
3357 
3358 }
3359 
ImpExport3DSceneShape(const uno::Reference<drawing::XShape> & xShape,XMLShapeExportFlags nFeatures,awt::Point * pRefPoint)3360 void XMLShapeExport::ImpExport3DSceneShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
3361 {
3362     uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY);
3363     if(xShapes.is() && xShapes->getCount())
3364     {
3365         uno::Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
3366         SAL_WARN_IF( !xPropSet.is(), "xmloff", "XMLShapeExport::ImpExport3DSceneShape can't export a scene without a propertyset" );
3367         if( xPropSet.is() )
3368         {
3369             // Transformation
3370             ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3371 
3372             // 3d attributes
3373             export3DSceneAttributes( xPropSet );
3374 
3375             // write 3DScene shape
3376             bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3377             SvXMLElementExport aOBJ( mrExport, XML_NAMESPACE_DR3D, XML_SCENE, bCreateNewline, true);
3378 
3379             ImpExportDescription( xShape ); // #i68101#
3380             ImpExportEvents( xShape );
3381 
3382             // write 3DSceneLights
3383             export3DLamps( xPropSet );
3384 
3385             // #89764# if export of position is suppressed for group shape,
3386             // positions of contained objects should be written relative to
3387             // the upper left edge of the group.
3388             awt::Point aUpperLeft;
3389 
3390             if(!(nFeatures & XMLShapeExportFlags::POSITION))
3391             {
3392                 nFeatures |= XMLShapeExportFlags::POSITION;
3393                 aUpperLeft = xShape->getPosition();
3394                 pRefPoint = &aUpperLeft;
3395             }
3396 
3397             // write members
3398             exportShapes( xShapes, nFeatures, pRefPoint );
3399         }
3400     }
3401 }
3402 
ImpExport3DShape(const uno::Reference<drawing::XShape> & xShape,XmlShapeType eShapeType)3403 void XMLShapeExport::ImpExport3DShape(
3404     const uno::Reference< drawing::XShape >& xShape,
3405     XmlShapeType eShapeType)
3406 {
3407     const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3408     if(xPropSet.is())
3409     {
3410         OUString aStr;
3411         OUStringBuffer sStringBuffer;
3412 
3413         // transformation (UNO_NAME_3D_TRANSFORM_MATRIX == "D3DTransformMatrix")
3414         uno::Any aAny = xPropSet->getPropertyValue("D3DTransformMatrix");
3415         drawing::HomogenMatrix aHomMat;
3416         aAny >>= aHomMat;
3417         SdXMLImExTransform3D aTransform;
3418         aTransform.AddHomogenMatrix(aHomMat);
3419         if(aTransform.NeedsAction())
3420             mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
3421 
3422         switch(eShapeType)
3423         {
3424             case XmlShapeTypeDraw3DCubeObject:
3425             {
3426                 // minEdge
3427                 aAny = xPropSet->getPropertyValue("D3DPosition");
3428                 drawing::Position3D aPosition3D;
3429                 aAny >>= aPosition3D;
3430                 ::basegfx::B3DVector aPos3D(aPosition3D.PositionX, aPosition3D.PositionY, aPosition3D.PositionZ);
3431 
3432                 // maxEdge
3433                 aAny = xPropSet->getPropertyValue("D3DSize");
3434                 drawing::Direction3D aDirection3D;
3435                 aAny >>= aDirection3D;
3436                 ::basegfx::B3DVector aDir3D(aDirection3D.DirectionX, aDirection3D.DirectionY, aDirection3D.DirectionZ);
3437 
3438                 // transform maxEdge from distance to pos
3439                 aDir3D = aPos3D + aDir3D;
3440 
3441                 // write minEdge
3442                 if(aPos3D != ::basegfx::B3DVector(-2500.0, -2500.0, -2500.0)) // write only when not default
3443                 {
3444                     SvXMLUnitConverter::convertB3DVector(sStringBuffer, aPos3D);
3445                     aStr = sStringBuffer.makeStringAndClear();
3446                     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_MIN_EDGE, aStr);
3447                 }
3448 
3449                 // write maxEdge
3450                 if(aDir3D != ::basegfx::B3DVector(2500.0, 2500.0, 2500.0)) // write only when not default
3451                 {
3452                     SvXMLUnitConverter::convertB3DVector(sStringBuffer, aDir3D);
3453                     aStr = sStringBuffer.makeStringAndClear();
3454                     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_MAX_EDGE, aStr);
3455                 }
3456 
3457                 // write 3DCube shape
3458                 // #i123542# Do this *after* the attributes are added, else these will be lost since opening
3459                 // the scope will clear the global attribute list at the exporter
3460                 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_CUBE, true, true);
3461 
3462                 break;
3463             }
3464             case XmlShapeTypeDraw3DSphereObject:
3465             {
3466                 // Center
3467                 aAny = xPropSet->getPropertyValue("D3DPosition");
3468                 drawing::Position3D aPosition3D;
3469                 aAny >>= aPosition3D;
3470                 ::basegfx::B3DVector aPos3D(aPosition3D.PositionX, aPosition3D.PositionY, aPosition3D.PositionZ);
3471 
3472                 // Size
3473                 aAny = xPropSet->getPropertyValue("D3DSize");
3474                 drawing::Direction3D aDirection3D;
3475                 aAny >>= aDirection3D;
3476                 ::basegfx::B3DVector aDir3D(aDirection3D.DirectionX, aDirection3D.DirectionY, aDirection3D.DirectionZ);
3477 
3478                 // write Center
3479                 if(aPos3D != ::basegfx::B3DVector(0.0, 0.0, 0.0)) // write only when not default
3480                 {
3481                     SvXMLUnitConverter::convertB3DVector(sStringBuffer, aPos3D);
3482                     aStr = sStringBuffer.makeStringAndClear();
3483                     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_CENTER, aStr);
3484                 }
3485 
3486                 // write Size
3487                 if(aDir3D != ::basegfx::B3DVector(5000.0, 5000.0, 5000.0)) // write only when not default
3488                 {
3489                     SvXMLUnitConverter::convertB3DVector(sStringBuffer, aDir3D);
3490                     aStr = sStringBuffer.makeStringAndClear();
3491                     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SIZE, aStr);
3492                 }
3493 
3494                 // write 3DSphere shape
3495                 // #i123542# Do this *after* the attributes are added, else these will be lost since opening
3496                 // the scope will clear the global attribute list at the exporter
3497                 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_SPHERE, true, true);
3498 
3499                 break;
3500             }
3501             case XmlShapeTypeDraw3DLatheObject:
3502             case XmlShapeTypeDraw3DExtrudeObject:
3503             {
3504                 // write special 3DLathe/3DExtrude attributes, get 3D tools::PolyPolygon as drawing::PolyPolygonShape3D
3505                 aAny = xPropSet->getPropertyValue("D3DPolyPolygon3D");
3506                 drawing::PolyPolygonShape3D aUnoPolyPolygon3D;
3507                 aAny >>= aUnoPolyPolygon3D;
3508 
3509                 // convert to 3D PolyPolygon
3510                 const basegfx::B3DPolyPolygon aPolyPolygon3D(
3511                     basegfx::utils::UnoPolyPolygonShape3DToB3DPolyPolygon(
3512                         aUnoPolyPolygon3D));
3513 
3514                 // convert to 2D tools::PolyPolygon using identity 3D transformation (just grep X and Y)
3515                 const basegfx::B3DHomMatrix aB3DHomMatrixFor2DConversion;
3516                 const basegfx::B2DPolyPolygon aPolyPolygon(
3517                     basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(
3518                         aPolyPolygon3D,
3519                         aB3DHomMatrixFor2DConversion));
3520 
3521                 // get 2D range of it
3522                 const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange());
3523 
3524                 // export ViewBox
3525                 SdXMLImExViewBox aViewBox(
3526                     aPolyPolygonRange.getMinX(),
3527                     aPolyPolygonRange.getMinY(),
3528                     aPolyPolygonRange.getWidth(),
3529                     aPolyPolygonRange.getHeight());
3530 
3531                 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
3532 
3533                 // prepare svg:d string
3534                 const OUString aPolygonString(
3535                     basegfx::utils::exportToSvgD(
3536                         aPolyPolygon,
3537                         true,           // bUseRelativeCoordinates
3538                         false,          // bDetectQuadraticBeziers TTTT: not used in old, but maybe activated now
3539                         true));         // bHandleRelativeNextPointCompatible
3540 
3541                 // write point array
3542                 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
3543 
3544                 if(eShapeType == XmlShapeTypeDraw3DLatheObject)
3545                 {
3546                     // write 3DLathe shape
3547                     SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_ROTATE, true, true);
3548                 }
3549                 else
3550                 {
3551                     // write 3DExtrude shape
3552                     SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_EXTRUDE, true, true);
3553                 }
3554                 break;
3555             }
3556             default:
3557                 break;
3558         }
3559     }
3560 }
3561 
3562 /** helper for chart that adds all attributes of a 3d scene element to the export */
export3DSceneAttributes(const css::uno::Reference<css::beans::XPropertySet> & xPropSet)3563 void XMLShapeExport::export3DSceneAttributes( const css::uno::Reference< css::beans::XPropertySet >& xPropSet )
3564 {
3565     OUString aStr;
3566     OUStringBuffer sStringBuffer;
3567 
3568     // world transformation (UNO_NAME_3D_TRANSFORM_MATRIX == "D3DTransformMatrix")
3569     uno::Any aAny = xPropSet->getPropertyValue("D3DTransformMatrix");
3570     drawing::HomogenMatrix aHomMat;
3571     aAny >>= aHomMat;
3572     SdXMLImExTransform3D aTransform;
3573     aTransform.AddHomogenMatrix(aHomMat);
3574     if(aTransform.NeedsAction())
3575         mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
3576 
3577     // VRP, VPN, VUP
3578     aAny = xPropSet->getPropertyValue("D3DCameraGeometry");
3579     drawing::CameraGeometry aCamGeo;
3580     aAny >>= aCamGeo;
3581 
3582     ::basegfx::B3DVector aVRP(aCamGeo.vrp.PositionX, aCamGeo.vrp.PositionY, aCamGeo.vrp.PositionZ);
3583     if(aVRP != ::basegfx::B3DVector(0.0, 0.0, 1.0)) // write only when not default
3584     {
3585         SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVRP);
3586         aStr = sStringBuffer.makeStringAndClear();
3587         mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VRP, aStr);
3588     }
3589 
3590     ::basegfx::B3DVector aVPN(aCamGeo.vpn.DirectionX, aCamGeo.vpn.DirectionY, aCamGeo.vpn.DirectionZ);
3591     if(aVPN != ::basegfx::B3DVector(0.0, 0.0, 1.0)) // write only when not default
3592     {
3593         SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVPN);
3594         aStr = sStringBuffer.makeStringAndClear();
3595         mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VPN, aStr);
3596     }
3597 
3598     ::basegfx::B3DVector aVUP(aCamGeo.vup.DirectionX, aCamGeo.vup.DirectionY, aCamGeo.vup.DirectionZ);
3599     if(aVUP != ::basegfx::B3DVector(0.0, 1.0, 0.0)) // write only when not default
3600     {
3601         SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVUP);
3602         aStr = sStringBuffer.makeStringAndClear();
3603         mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VUP, aStr);
3604     }
3605 
3606     // projection "D3DScenePerspective" drawing::ProjectionMode
3607     aAny = xPropSet->getPropertyValue("D3DScenePerspective");
3608     drawing::ProjectionMode aPrjMode;
3609     aAny >>= aPrjMode;
3610     if(aPrjMode == drawing::ProjectionMode_PARALLEL)
3611         aStr = GetXMLToken(XML_PARALLEL);
3612     else
3613         aStr = GetXMLToken(XML_PERSPECTIVE);
3614     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_PROJECTION, aStr);
3615 
3616     // distance
3617     aAny = xPropSet->getPropertyValue("D3DSceneDistance");
3618     sal_Int32 nDistance = 0;
3619     aAny >>= nDistance;
3620     mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
3621             nDistance);
3622     aStr = sStringBuffer.makeStringAndClear();
3623     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DISTANCE, aStr);
3624 
3625     // focalLength
3626     aAny = xPropSet->getPropertyValue("D3DSceneFocalLength");
3627     sal_Int32 nFocalLength = 0;
3628     aAny >>= nFocalLength;
3629     mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
3630             nFocalLength);
3631     aStr = sStringBuffer.makeStringAndClear();
3632     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_FOCAL_LENGTH, aStr);
3633 
3634     // shadowSlant
3635     aAny = xPropSet->getPropertyValue("D3DSceneShadowSlant");
3636     sal_Int16 nShadowSlant = 0;
3637     aAny >>= nShadowSlant;
3638     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SHADOW_SLANT, OUString::number(static_cast<sal_Int32>(nShadowSlant)));
3639 
3640     // shadeMode
3641     aAny = xPropSet->getPropertyValue("D3DSceneShadeMode");
3642     drawing::ShadeMode aShadeMode;
3643     if(aAny >>= aShadeMode)
3644     {
3645         if(aShadeMode == drawing::ShadeMode_FLAT)
3646             aStr = GetXMLToken(XML_FLAT);
3647         else if(aShadeMode == drawing::ShadeMode_PHONG)
3648             aStr = GetXMLToken(XML_PHONG);
3649         else if(aShadeMode == drawing::ShadeMode_SMOOTH)
3650             aStr = GetXMLToken(XML_GOURAUD);
3651         else
3652             aStr = GetXMLToken(XML_DRAFT);
3653     }
3654     else
3655     {
3656         // ShadeMode enum not there, write default
3657         aStr = GetXMLToken(XML_GOURAUD);
3658     }
3659     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SHADE_MODE, aStr);
3660 
3661     // ambientColor
3662     aAny = xPropSet->getPropertyValue("D3DSceneAmbientColor");
3663     sal_Int32 nAmbientColor = 0;
3664     aAny >>= nAmbientColor;
3665     ::sax::Converter::convertColor(sStringBuffer, nAmbientColor);
3666     aStr = sStringBuffer.makeStringAndClear();
3667     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_AMBIENT_COLOR, aStr);
3668 
3669     // lightingMode
3670     aAny = xPropSet->getPropertyValue("D3DSceneTwoSidedLighting");
3671     bool bTwoSidedLighting = false;
3672     aAny >>= bTwoSidedLighting;
3673     ::sax::Converter::convertBool(sStringBuffer, bTwoSidedLighting);
3674     aStr = sStringBuffer.makeStringAndClear();
3675     mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_LIGHTING_MODE, aStr);
3676 }
3677 
3678 /** helper for chart that exports all lamps from the propertyset */
export3DLamps(const css::uno::Reference<css::beans::XPropertySet> & xPropSet)3679 void XMLShapeExport::export3DLamps( const css::uno::Reference< css::beans::XPropertySet >& xPropSet )
3680 {
3681     // write lamps 1..8 as content
3682     OUString aStr;
3683     OUStringBuffer sStringBuffer;
3684 
3685     const OUString aColorPropName("D3DSceneLightColor");
3686     const OUString aDirectionPropName("D3DSceneLightDirection");
3687     const OUString aLightOnPropName("D3DSceneLightOn");
3688 
3689     ::basegfx::B3DVector aLightDirection;
3690     drawing::Direction3D aLightDir;
3691     bool bLightOnOff = false;
3692     for(sal_Int32 nLamp = 1; nLamp <= 8; nLamp++)
3693     {
3694         OUString aIndexStr = OUString::number( nLamp );
3695 
3696         // lightcolor
3697         OUString aPropName = aColorPropName + aIndexStr;
3698         sal_Int32 nLightColor = 0;
3699         xPropSet->getPropertyValue( aPropName ) >>= nLightColor;
3700         ::sax::Converter::convertColor(sStringBuffer, nLightColor);
3701         aStr = sStringBuffer.makeStringAndClear();
3702         mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DIFFUSE_COLOR, aStr);
3703 
3704         // lightdirection
3705         aPropName = aDirectionPropName + aIndexStr;
3706         xPropSet->getPropertyValue(aPropName) >>= aLightDir;
3707         aLightDirection = ::basegfx::B3DVector(aLightDir.DirectionX, aLightDir.DirectionY, aLightDir.DirectionZ);
3708         SvXMLUnitConverter::convertB3DVector(sStringBuffer, aLightDirection);
3709         aStr = sStringBuffer.makeStringAndClear();
3710         mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DIRECTION, aStr);
3711 
3712         // lighton
3713         aPropName = aLightOnPropName + aIndexStr;
3714         xPropSet->getPropertyValue(aPropName) >>= bLightOnOff;
3715         ::sax::Converter::convertBool(sStringBuffer, bLightOnOff);
3716         aStr = sStringBuffer.makeStringAndClear();
3717         mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_ENABLED, aStr);
3718 
3719         // specular
3720         mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SPECULAR,
3721             nLamp == 1 ? XML_TRUE : XML_FALSE);
3722 
3723         // write light entry
3724         SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_LIGHT, true, true);
3725     }
3726 }
3727 
3728 
3729 // using namespace css::io;
3730 // using namespace ::xmloff::EnhancedCustomShapeToken;
3731 
3732 
ExportParameter(OUStringBuffer & rStrBuffer,const css::drawing::EnhancedCustomShapeParameter & rParameter)3733 static void ExportParameter( OUStringBuffer& rStrBuffer, const css::drawing::EnhancedCustomShapeParameter& rParameter )
3734 {
3735     if ( !rStrBuffer.isEmpty() )
3736         rStrBuffer.append( ' ' );
3737     if ( rParameter.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
3738     {
3739         double fNumber = 0.0;
3740         rParameter.Value >>= fNumber;
3741         ::rtl::math::doubleToUStringBuffer( rStrBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true );
3742     }
3743     else
3744     {
3745         sal_Int32 nValue = 0;
3746         rParameter.Value >>= nValue;
3747 
3748         switch( rParameter.Type )
3749         {
3750             case css::drawing::EnhancedCustomShapeParameterType::EQUATION :
3751             {
3752                 rStrBuffer.append( "?f" ).append(OUString::number( nValue ) );
3753             }
3754             break;
3755 
3756             case css::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT :
3757             {
3758                 rStrBuffer.append( '$' );
3759                 rStrBuffer.append( OUString::number( nValue ) );
3760             }
3761             break;
3762 
3763             case css::drawing::EnhancedCustomShapeParameterType::BOTTOM :
3764                 rStrBuffer.append( GetXMLToken( XML_BOTTOM ) ); break;
3765             case css::drawing::EnhancedCustomShapeParameterType::RIGHT :
3766                 rStrBuffer.append( GetXMLToken( XML_RIGHT ) ); break;
3767             case css::drawing::EnhancedCustomShapeParameterType::TOP :
3768                 rStrBuffer.append( GetXMLToken( XML_TOP ) ); break;
3769             case css::drawing::EnhancedCustomShapeParameterType::LEFT :
3770                 rStrBuffer.append( GetXMLToken( XML_LEFT ) ); break;
3771             case css::drawing::EnhancedCustomShapeParameterType::XSTRETCH :
3772                 rStrBuffer.append( GetXMLToken( XML_XSTRETCH ) ); break;
3773             case css::drawing::EnhancedCustomShapeParameterType::YSTRETCH :
3774                 rStrBuffer.append( GetXMLToken( XML_YSTRETCH ) ); break;
3775             case css::drawing::EnhancedCustomShapeParameterType::HASSTROKE :
3776                 rStrBuffer.append( GetXMLToken( XML_HASSTROKE ) ); break;
3777             case css::drawing::EnhancedCustomShapeParameterType::HASFILL :
3778                 rStrBuffer.append( GetXMLToken( XML_HASFILL ) ); break;
3779             case css::drawing::EnhancedCustomShapeParameterType::WIDTH :
3780                 rStrBuffer.append( GetXMLToken( XML_WIDTH ) ); break;
3781             case css::drawing::EnhancedCustomShapeParameterType::HEIGHT :
3782                 rStrBuffer.append( GetXMLToken( XML_HEIGHT ) ); break;
3783             case css::drawing::EnhancedCustomShapeParameterType::LOGWIDTH :
3784                 rStrBuffer.append( GetXMLToken( XML_LOGWIDTH ) ); break;
3785             case css::drawing::EnhancedCustomShapeParameterType::LOGHEIGHT :
3786                 rStrBuffer.append( GetXMLToken( XML_LOGHEIGHT ) ); break;
3787             default :
3788                 rStrBuffer.append( OUString::number( nValue ) );
3789         }
3790     }
3791 }
3792 
ImpExportEquations(SvXMLExport & rExport,const uno::Sequence<OUString> & rEquations)3793 static void ImpExportEquations( SvXMLExport& rExport, const uno::Sequence< OUString >& rEquations )
3794 {
3795     sal_Int32 i;
3796     for ( i = 0; i < rEquations.getLength(); i++ )
3797     {
3798         OUString aStr= "f" + OUString::number( i );
3799         rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aStr );
3800 
3801         aStr = rEquations[ i ];
3802         sal_Int32 nIndex = 0;
3803         do
3804         {
3805             nIndex = aStr.indexOf( '?', nIndex );
3806             if ( nIndex != -1 )
3807             {
3808                 aStr = aStr.copy(0, nIndex + 1) + "f"
3809                     + aStr.copy(nIndex + 1, aStr.getLength() - nIndex - 1);
3810                 nIndex++;
3811             }
3812         } while( nIndex != -1 );
3813         rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FORMULA, aStr );
3814         SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_EQUATION, true, true );
3815     }
3816 }
3817 
ImpExportHandles(SvXMLExport & rExport,const uno::Sequence<beans::PropertyValues> & rHandles)3818 static void ImpExportHandles( SvXMLExport& rExport, const uno::Sequence< beans::PropertyValues >& rHandles )
3819 {
3820     if ( rHandles.hasElements() )
3821     {
3822         OUString       aStr;
3823         OUStringBuffer aStrBuffer;
3824 
3825         for ( const uno::Sequence< beans::PropertyValue >& rPropSeq : rHandles )
3826         {
3827             bool bPosition = false;
3828             for ( const beans::PropertyValue& rPropVal : rPropSeq )
3829             {
3830                 switch( EASGet( rPropVal.Name ) )
3831                 {
3832                     case EAS_Position :
3833                     {
3834                         css::drawing::EnhancedCustomShapeParameterPair aPosition;
3835                         if ( rPropVal.Value >>= aPosition )
3836                         {
3837                             ExportParameter( aStrBuffer, aPosition.First );
3838                             ExportParameter( aStrBuffer, aPosition.Second );
3839                             aStr = aStrBuffer.makeStringAndClear();
3840                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POSITION, aStr );
3841                             bPosition = true;
3842                         }
3843                     }
3844                     break;
3845                     case EAS_MirroredX :
3846                     {
3847                         bool bMirroredX;
3848                         if ( rPropVal.Value >>= bMirroredX )
3849                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_MIRROR_HORIZONTAL,
3850                                 bMirroredX ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
3851                     }
3852                     break;
3853                     case EAS_MirroredY :
3854                     {
3855                         bool bMirroredY;
3856                         if ( rPropVal.Value >>= bMirroredY )
3857                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_MIRROR_VERTICAL,
3858                                 bMirroredY ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
3859                     }
3860                     break;
3861                     case EAS_Switched :
3862                     {
3863                         bool bSwitched;
3864                         if ( rPropVal.Value >>= bSwitched )
3865                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_SWITCHED,
3866                                 bSwitched ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
3867                     }
3868                     break;
3869                     case EAS_Polar :
3870                     {
3871                         css::drawing::EnhancedCustomShapeParameterPair aPolar;
3872                         if ( rPropVal.Value >>= aPolar )
3873                         {
3874                             ExportParameter( aStrBuffer, aPolar.First );
3875                             ExportParameter( aStrBuffer, aPolar.Second );
3876                             aStr = aStrBuffer.makeStringAndClear();
3877                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POLAR, aStr );
3878                         }
3879                     }
3880                     break;
3881                     case EAS_RadiusRangeMinimum :
3882                     {
3883                         css::drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum;
3884                         if ( rPropVal.Value >>= aRadiusRangeMinimum )
3885                         {
3886                             ExportParameter( aStrBuffer, aRadiusRangeMinimum );
3887                             aStr = aStrBuffer.makeStringAndClear();
3888                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RADIUS_RANGE_MINIMUM, aStr );
3889                         }
3890                     }
3891                     break;
3892                     case EAS_RadiusRangeMaximum :
3893                     {
3894                         css::drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum;
3895                         if ( rPropVal.Value >>= aRadiusRangeMaximum )
3896                         {
3897                             ExportParameter( aStrBuffer, aRadiusRangeMaximum );
3898                             aStr = aStrBuffer.makeStringAndClear();
3899                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RADIUS_RANGE_MAXIMUM, aStr );
3900                         }
3901                     }
3902                     break;
3903                     case EAS_RangeXMinimum :
3904                     {
3905                         css::drawing::EnhancedCustomShapeParameter aXRangeMinimum;
3906                         if ( rPropVal.Value >>= aXRangeMinimum )
3907                         {
3908                             ExportParameter( aStrBuffer, aXRangeMinimum );
3909                             aStr = aStrBuffer.makeStringAndClear();
3910                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_X_MINIMUM, aStr );
3911                         }
3912                     }
3913                     break;
3914                     case EAS_RangeXMaximum :
3915                     {
3916                         css::drawing::EnhancedCustomShapeParameter aXRangeMaximum;
3917                         if ( rPropVal.Value >>= aXRangeMaximum )
3918                         {
3919                             ExportParameter( aStrBuffer, aXRangeMaximum );
3920                             aStr = aStrBuffer.makeStringAndClear();
3921                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_X_MAXIMUM, aStr );
3922                         }
3923                     }
3924                     break;
3925                     case EAS_RangeYMinimum :
3926                     {
3927                         css::drawing::EnhancedCustomShapeParameter aYRangeMinimum;
3928                         if ( rPropVal.Value >>= aYRangeMinimum )
3929                         {
3930                             ExportParameter( aStrBuffer, aYRangeMinimum );
3931                             aStr = aStrBuffer.makeStringAndClear();
3932                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_Y_MINIMUM, aStr );
3933                         }
3934                     }
3935                     break;
3936                     case EAS_RangeYMaximum :
3937                     {
3938                         css::drawing::EnhancedCustomShapeParameter aYRangeMaximum;
3939                         if ( rPropVal.Value >>= aYRangeMaximum )
3940                         {
3941                             ExportParameter( aStrBuffer, aYRangeMaximum );
3942                             aStr = aStrBuffer.makeStringAndClear();
3943                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_Y_MAXIMUM, aStr );
3944                         }
3945                     }
3946                     break;
3947                     default:
3948                         break;
3949                 }
3950             }
3951             if ( bPosition )
3952                 SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_HANDLE, true, true );
3953             else
3954                 rExport.ClearAttrList();
3955         }
3956     }
3957 }
3958 
ImpExportEnhancedPath(SvXMLExport & rExport,const uno::Sequence<css::drawing::EnhancedCustomShapeParameterPair> & rCoordinates,const uno::Sequence<css::drawing::EnhancedCustomShapeSegment> & rSegments,bool bExtended=false)3959 static void ImpExportEnhancedPath( SvXMLExport& rExport,
3960                             const uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair >& rCoordinates,
3961                             const uno::Sequence< css::drawing::EnhancedCustomShapeSegment >& rSegments,
3962                             bool bExtended = false )
3963 {
3964 
3965     OUString       aStr;
3966     OUStringBuffer aStrBuffer;
3967     bool bNeedExtended = false;
3968 
3969     sal_Int32 i, j, k, l;
3970 
3971     sal_Int32 nCoords = rCoordinates.getLength();
3972     sal_Int32 nSegments = rSegments.getLength();
3973     bool bSimpleSegments = nSegments == 0;
3974     if ( bSimpleSegments )
3975         nSegments = 4;
3976     for ( j = i = 0; j < nSegments; j++ )
3977     {
3978         css::drawing::EnhancedCustomShapeSegment aSegment;
3979         if ( bSimpleSegments )
3980         {
3981             // if there are not enough segments we will default them
3982             switch( j )
3983             {
3984                 case 0 :
3985                 {
3986                     aSegment.Count = 1;
3987                     aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO;
3988                 }
3989                 break;
3990                 case 1 :
3991                 {
3992                     aSegment.Count = static_cast<sal_Int16>(std::min( nCoords - 1, sal_Int32(32767) ));
3993                     aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO;
3994                 }
3995                 break;
3996                 case 2 :
3997                 {
3998                     aSegment.Count = 1;
3999                     aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH;
4000                 }
4001                 break;
4002                 case 3 :
4003                 {
4004                     aSegment.Count = 1;
4005                     aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
4006                 }
4007                 break;
4008             }
4009         }
4010         else
4011             aSegment = rSegments[ j ];
4012 
4013         if ( !aStrBuffer.isEmpty() )
4014             aStrBuffer.append( ' ' );
4015 
4016         sal_Int32 nParameter = 0;
4017         switch( aSegment.Command )
4018         {
4019             case css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH :
4020                 aStrBuffer.append( 'Z' ); break;
4021             case css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH :
4022                 aStrBuffer.append( 'N' ); break;
4023             case css::drawing::EnhancedCustomShapeSegmentCommand::NOFILL :
4024                 aStrBuffer.append( 'F' ); break;
4025             case css::drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE :
4026                 aStrBuffer.append( 'S' ); break;
4027 
4028             case css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO :
4029                 aStrBuffer.append( 'M' ); nParameter = 1; break;
4030             case css::drawing::EnhancedCustomShapeSegmentCommand::LINETO :
4031                 aStrBuffer.append( 'L' ); nParameter = 1; break;
4032             case css::drawing::EnhancedCustomShapeSegmentCommand::CURVETO :
4033                 aStrBuffer.append( 'C' ); nParameter = 3; break;
4034             case css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO :
4035                 aStrBuffer.append( 'T' ); nParameter = 3; break;
4036             case css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE :
4037                 aStrBuffer.append( 'U' ); nParameter = 3; break;
4038             case css::drawing::EnhancedCustomShapeSegmentCommand::ARCTO :
4039                 aStrBuffer.append( 'A' ); nParameter = 4; break;
4040             case css::drawing::EnhancedCustomShapeSegmentCommand::ARC :
4041                 aStrBuffer.append( 'B' ); nParameter = 4; break;
4042             case css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO :
4043                 aStrBuffer.append( 'W' ); nParameter = 4; break;
4044             case css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC :
4045                 aStrBuffer.append( 'V' ); nParameter = 4; break;
4046             case css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX :
4047                 aStrBuffer.append( 'X' ); nParameter = 1; break;
4048             case css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY :
4049                 aStrBuffer.append( 'Y' ); nParameter = 1; break;
4050             case css::drawing::EnhancedCustomShapeSegmentCommand::QUADRATICCURVETO :
4051                 aStrBuffer.append( 'Q' ); nParameter = 2; break;
4052             case css::drawing::EnhancedCustomShapeSegmentCommand::ARCANGLETO :
4053                 if ( bExtended ) {
4054                     aStrBuffer.append( 'G' );
4055                     nParameter = 2;
4056                 } else {
4057                     aStrBuffer.setLength( aStrBuffer.getLength() - 1);
4058                     bNeedExtended = true;
4059                     i += 2;
4060                 }
4061                 break;
4062             case css::drawing::EnhancedCustomShapeSegmentCommand::DARKEN :
4063                 if ( bExtended )
4064                     aStrBuffer.append( 'H' );
4065                 else
4066                     bNeedExtended = true;
4067                 break;
4068             case css::drawing::EnhancedCustomShapeSegmentCommand::DARKENLESS :
4069                 if ( bExtended )
4070                     aStrBuffer.append( 'I' );
4071                 else
4072                     bNeedExtended = true;
4073                 break;
4074             case css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTEN :
4075                 if ( bExtended )
4076                     aStrBuffer.append( 'J' );
4077                 else
4078                     bNeedExtended = true;
4079                 break;
4080             case css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTENLESS :
4081                 if ( bExtended )
4082                     aStrBuffer.append( 'K' );
4083                 else
4084                     bNeedExtended = true;
4085                 break;
4086             default : // ups, seems to be something wrong
4087             {
4088                 aSegment.Count = 1;
4089                 aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO;
4090             }
4091             break;
4092         }
4093         if ( nParameter )
4094         {
4095             for ( k = 0; k < aSegment.Count; k++ )
4096             {
4097                 if ( ( i + nParameter ) <= nCoords )
4098                 {
4099                     for ( l = 0; l < nParameter; l++ )
4100                     {
4101                         ExportParameter( aStrBuffer, rCoordinates[ i ].First );
4102                         ExportParameter( aStrBuffer, rCoordinates[ i++ ].Second );
4103                     }
4104                 }
4105                 else
4106                 {
4107                     j = nSegments;  // error -> exiting
4108                     break;
4109                 }
4110             }
4111         }
4112     }
4113     aStr = aStrBuffer.makeStringAndClear();
4114     rExport.AddAttribute( bExtended ? XML_NAMESPACE_DRAW_EXT : XML_NAMESPACE_DRAW, XML_ENHANCED_PATH, aStr );
4115     if ( !bExtended && bNeedExtended && (rExport.getDefaultVersion() > SvtSaveOptions::ODFVER_012) )
4116         ImpExportEnhancedPath( rExport, rCoordinates, rSegments, true );
4117 }
4118 
ImpExportEnhancedGeometry(SvXMLExport & rExport,const uno::Reference<beans::XPropertySet> & xPropSet)4119 static void ImpExportEnhancedGeometry( SvXMLExport& rExport, const uno::Reference< beans::XPropertySet >& xPropSet )
4120 {
4121     bool bEquations = false;
4122     uno::Sequence< OUString > aEquations;
4123 
4124     bool bHandles = false;
4125     uno::Sequence< beans::PropertyValues > aHandles;
4126 
4127     uno::Sequence< css::drawing::EnhancedCustomShapeSegment > aSegments;
4128     uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates;
4129 
4130     uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentValues;
4131 
4132     OUString       aStr;
4133     OUStringBuffer aStrBuffer;
4134     SvXMLUnitConverter& rUnitConverter = rExport.GetMM100UnitConverter();
4135 
4136     uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
4137 
4138     // geometry
4139     const OUString sCustomShapeGeometry( "CustomShapeGeometry" );
4140     if ( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName( sCustomShapeGeometry ) )
4141     {
4142         uno::Any aGeoPropSet( xPropSet->getPropertyValue( sCustomShapeGeometry ) );
4143         uno::Sequence< beans::PropertyValue > aGeoPropSeq;
4144 
4145         if ( aGeoPropSet >>= aGeoPropSeq )
4146         {
4147             bool bCoordinates = false;
4148             OUString aCustomShapeType( "non-primitive" );
4149 
4150             for ( const beans::PropertyValue& rGeoProp : std::as_const(aGeoPropSeq) )
4151             {
4152                 switch( EASGet( rGeoProp.Name ) )
4153                 {
4154                     case EAS_Type :
4155                     {
4156                         rGeoProp.Value >>= aCustomShapeType;
4157                     }
4158                     break;
4159                     case EAS_MirroredX :
4160                     {
4161                         bool bMirroredX;
4162                         if ( rGeoProp.Value >>= bMirroredX )
4163                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIRROR_HORIZONTAL,
4164                                 bMirroredX ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4165                     }
4166                     break;
4167                     case EAS_MirroredY :
4168                     {
4169                         bool bMirroredY;
4170                         if ( rGeoProp.Value >>= bMirroredY )
4171                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIRROR_VERTICAL,
4172                                 bMirroredY ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4173                     }
4174                     break;
4175                     case EAS_ViewBox :
4176                     {
4177                         awt::Rectangle aRect;
4178                         if ( rGeoProp.Value >>= aRect )
4179                         {
4180                             SdXMLImExViewBox aViewBox( aRect.X, aRect.Y, aRect.Width, aRect.Height );
4181                             rExport.AddAttribute( XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString() );
4182                         }
4183                     }
4184                     break;
4185                     case EAS_TextPreRotateAngle :
4186                     case EAS_TextRotateAngle :
4187                     {
4188                         double fTextRotateAngle = 0;
4189                         if ( ( rGeoProp.Value >>= fTextRotateAngle ) && fTextRotateAngle != 0 )
4190                         {
4191                             ::sax::Converter::convertDouble(
4192                                     aStrBuffer, fTextRotateAngle );
4193                             aStr = aStrBuffer.makeStringAndClear();
4194                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_ROTATE_ANGLE, aStr );
4195                         }
4196                     }
4197                     break;
4198                     case EAS_Extrusion :
4199                     {
4200                         uno::Sequence< beans::PropertyValue > aExtrusionPropSeq;
4201                         if ( rGeoProp.Value >>= aExtrusionPropSeq )
4202                         {
4203                             for ( const beans::PropertyValue& rProp : std::as_const(aExtrusionPropSeq) )
4204                             {
4205                                 switch( EASGet( rProp.Name ) )
4206                                 {
4207                                     case EAS_Extrusion :
4208                                     {
4209                                         bool bExtrusionOn;
4210                                         if ( rProp.Value >>= bExtrusionOn )
4211                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION,
4212                                                 bExtrusionOn ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4213                                     }
4214                                     break;
4215                                     case EAS_Brightness :
4216                                     {
4217                                         double fExtrusionBrightness = 0;
4218                                         if ( rProp.Value >>= fExtrusionBrightness )
4219                                         {
4220                                             ::sax::Converter::convertDouble(
4221                                                 aStrBuffer,
4222                                                 fExtrusionBrightness,
4223                                                 false,
4224                                                 util::MeasureUnit::PERCENT,
4225                                                 util::MeasureUnit::PERCENT);
4226                                             aStrBuffer.append( '%' );
4227                                             aStr = aStrBuffer.makeStringAndClear();
4228                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_BRIGHTNESS, aStr );
4229                                         }
4230                                     }
4231                                     break;
4232                                     case EAS_Depth :
4233                                     {
4234                                         css::drawing::EnhancedCustomShapeParameterPair aDepthParaPair;
4235                                         if ( rProp.Value >>= aDepthParaPair )
4236                                         {
4237                                             double fDepth = 0;
4238                                             if ( aDepthParaPair.First.Value >>= fDepth )
4239                                             {
4240                                                 rExport.GetMM100UnitConverter().convertDouble( aStrBuffer, fDepth );
4241                                                 ExportParameter( aStrBuffer, aDepthParaPair.Second );
4242                                                 aStr = aStrBuffer.makeStringAndClear();
4243                                                 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_DEPTH, aStr );
4244                                             }
4245                                         }
4246                                     }
4247                                     break;
4248                                     case EAS_Diffusion :
4249                                     {
4250                                         double fExtrusionDiffusion = 0;
4251                                         if ( rProp.Value >>= fExtrusionDiffusion )
4252                                         {
4253                                             ::sax::Converter::convertDouble(
4254                                                 aStrBuffer,
4255                                                 fExtrusionDiffusion,
4256                                                 false,
4257                                                 util::MeasureUnit::PERCENT,
4258                                                 util::MeasureUnit::PERCENT);
4259                                             aStrBuffer.append( '%' );
4260                                             aStr = aStrBuffer.makeStringAndClear();
4261                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_DIFFUSION, aStr );
4262                                         }
4263                                     }
4264                                     break;
4265                                     case EAS_NumberOfLineSegments :
4266                                     {
4267                                         sal_Int32 nExtrusionNumberOfLineSegments = 0;
4268                                         if ( rProp.Value >>= nExtrusionNumberOfLineSegments )
4269                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_NUMBER_OF_LINE_SEGMENTS, OUString::number( nExtrusionNumberOfLineSegments ) );
4270                                     }
4271                                     break;
4272                                     case EAS_LightFace :
4273                                     {
4274                                         bool bExtrusionLightFace;
4275                                         if ( rProp.Value >>= bExtrusionLightFace )
4276                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_LIGHT_FACE,
4277                                                 bExtrusionLightFace ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4278                                     }
4279                                     break;
4280                                     case EAS_FirstLightHarsh :
4281                                     {
4282                                         bool bExtrusionFirstLightHarsh;
4283                                         if ( rProp.Value >>= bExtrusionFirstLightHarsh )
4284                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_HARSH,
4285                                                 bExtrusionFirstLightHarsh ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4286                                     }
4287                                     break;
4288                                     case EAS_SecondLightHarsh :
4289                                     {
4290                                         bool bExtrusionSecondLightHarsh;
4291                                         if ( rProp.Value >>= bExtrusionSecondLightHarsh )
4292                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_HARSH,
4293                                                 bExtrusionSecondLightHarsh ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4294                                     }
4295                                     break;
4296                                     case EAS_FirstLightLevel :
4297                                     {
4298                                         double fExtrusionFirstLightLevel = 0;
4299                                         if ( rProp.Value >>= fExtrusionFirstLightLevel )
4300                                         {
4301                                             ::sax::Converter::convertDouble(
4302                                                 aStrBuffer,
4303                                                 fExtrusionFirstLightLevel,
4304                                                 false,
4305                                                 util::MeasureUnit::PERCENT,
4306                                                 util::MeasureUnit::PERCENT);
4307                                             aStrBuffer.append( '%' );
4308                                             aStr = aStrBuffer.makeStringAndClear();
4309                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_LEVEL, aStr );
4310                                         }
4311                                     }
4312                                     break;
4313                                     case EAS_SecondLightLevel :
4314                                     {
4315                                         double fExtrusionSecondLightLevel = 0;
4316                                         if ( rProp.Value >>= fExtrusionSecondLightLevel )
4317                                         {
4318                                             ::sax::Converter::convertDouble(
4319                                                 aStrBuffer,
4320                                                 fExtrusionSecondLightLevel,
4321                                                 false,
4322                                                 util::MeasureUnit::PERCENT,
4323                                                 util::MeasureUnit::PERCENT);
4324                                             aStrBuffer.append( '%' );
4325                                             aStr = aStrBuffer.makeStringAndClear();
4326                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_LEVEL, aStr );
4327                                         }
4328                                     }
4329                                     break;
4330                                     case EAS_FirstLightDirection :
4331                                     {
4332                                         drawing::Direction3D aExtrusionFirstLightDirection;
4333                                         if ( rProp.Value >>= aExtrusionFirstLightDirection )
4334                                         {
4335                                             ::basegfx::B3DVector aVec3D( aExtrusionFirstLightDirection.DirectionX, aExtrusionFirstLightDirection.DirectionY,
4336                                                 aExtrusionFirstLightDirection.DirectionZ );
4337                                             SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D );
4338                                             aStr = aStrBuffer.makeStringAndClear();
4339                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_DIRECTION, aStr );
4340                                         }
4341                                     }
4342                                     break;
4343                                     case EAS_SecondLightDirection :
4344                                     {
4345                                         drawing::Direction3D aExtrusionSecondLightDirection;
4346                                         if ( rProp.Value >>= aExtrusionSecondLightDirection )
4347                                         {
4348                                             ::basegfx::B3DVector aVec3D( aExtrusionSecondLightDirection.DirectionX, aExtrusionSecondLightDirection.DirectionY,
4349                                                 aExtrusionSecondLightDirection.DirectionZ );
4350                                             SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D );
4351                                             aStr = aStrBuffer.makeStringAndClear();
4352                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_DIRECTION, aStr );
4353                                         }
4354                                     }
4355                                     break;
4356                                     case EAS_Metal :
4357                                     {
4358                                         bool bExtrusionMetal;
4359                                         if ( rProp.Value >>= bExtrusionMetal )
4360                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_METAL,
4361                                                 bExtrusionMetal ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4362                                     }
4363                                     break;
4364                                     case EAS_ShadeMode :
4365                                     {
4366                                         // shadeMode
4367                                         drawing::ShadeMode eShadeMode;
4368                                         if( rProp.Value >>= eShadeMode )
4369                                         {
4370                                             if( eShadeMode == drawing::ShadeMode_FLAT )
4371                                                 aStr = GetXMLToken( XML_FLAT );
4372                                             else if( eShadeMode == drawing::ShadeMode_PHONG )
4373                                                 aStr = GetXMLToken( XML_PHONG );
4374                                             else if( eShadeMode == drawing::ShadeMode_SMOOTH )
4375                                                 aStr = GetXMLToken( XML_GOURAUD );
4376                                             else
4377                                                 aStr = GetXMLToken( XML_DRAFT );
4378                                         }
4379                                         else
4380                                         {
4381                                             // ShadeMode enum not there, write default
4382                                             aStr = GetXMLToken( XML_FLAT);
4383                                         }
4384                                         rExport.AddAttribute( XML_NAMESPACE_DR3D, XML_SHADE_MODE, aStr );
4385                                     }
4386                                     break;
4387                                     case EAS_RotateAngle :
4388                                     {
4389                                         css::drawing::EnhancedCustomShapeParameterPair aRotateAngleParaPair;
4390                                         if ( rProp.Value >>= aRotateAngleParaPair )
4391                                         {
4392                                             ExportParameter( aStrBuffer, aRotateAngleParaPair.First );
4393                                             ExportParameter( aStrBuffer, aRotateAngleParaPair.Second );
4394                                             aStr = aStrBuffer.makeStringAndClear();
4395                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ROTATION_ANGLE, aStr );
4396                                         }
4397                                     }
4398                                     break;
4399                                     case EAS_RotationCenter :
4400                                     {
4401                                         drawing::Direction3D aExtrusionRotationCenter;
4402                                         if ( rProp.Value >>= aExtrusionRotationCenter )
4403                                         {
4404                                             ::basegfx::B3DVector aVec3D( aExtrusionRotationCenter.DirectionX, aExtrusionRotationCenter.DirectionY,
4405                                                 aExtrusionRotationCenter.DirectionZ );
4406                                             SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D );
4407                                             aStr = aStrBuffer.makeStringAndClear();
4408                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ROTATION_CENTER, aStr );
4409                                         }
4410                                     }
4411                                     break;
4412                                     case EAS_Shininess :
4413                                     {
4414                                         double fExtrusionShininess = 0;
4415                                         if ( rProp.Value >>= fExtrusionShininess )
4416                                         {
4417                                             ::sax::Converter::convertDouble(
4418                                                 aStrBuffer,
4419                                                 fExtrusionShininess,
4420                                                 false,
4421                                                 util::MeasureUnit::PERCENT,
4422                                                 util::MeasureUnit::PERCENT);
4423                                             aStrBuffer.append( '%' );
4424                                             aStr = aStrBuffer.makeStringAndClear();
4425                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SHININESS, aStr );
4426                                         }
4427                                     }
4428                                     break;
4429                                     case EAS_Skew :
4430                                     {
4431                                         css::drawing::EnhancedCustomShapeParameterPair aSkewParaPair;
4432                                         if ( rProp.Value >>= aSkewParaPair )
4433                                         {
4434                                             ExportParameter( aStrBuffer, aSkewParaPair.First );
4435                                             ExportParameter( aStrBuffer, aSkewParaPair.Second );
4436                                             aStr = aStrBuffer.makeStringAndClear();
4437                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SKEW, aStr );
4438                                         }
4439                                     }
4440                                     break;
4441                                     case EAS_Specularity :
4442                                     {
4443                                         double fExtrusionSpecularity = 0;
4444                                         if ( rProp.Value >>= fExtrusionSpecularity )
4445                                         {
4446                                             ::sax::Converter::convertDouble(
4447                                                 aStrBuffer,
4448                                                 fExtrusionSpecularity,
4449                                                 false,
4450                                                 util::MeasureUnit::PERCENT,
4451                                                 util::MeasureUnit::PERCENT);
4452                                             aStrBuffer.append( '%' );
4453                                             aStr = aStrBuffer.makeStringAndClear();
4454                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SPECULARITY, aStr );
4455                                         }
4456                                     }
4457                                     break;
4458                                     case EAS_ProjectionMode :
4459                                     {
4460                                         drawing::ProjectionMode eProjectionMode;
4461                                         if ( rProp.Value >>= eProjectionMode )
4462                                             rExport.AddAttribute( XML_NAMESPACE_DR3D, XML_PROJECTION,
4463                                                 eProjectionMode == drawing::ProjectionMode_PARALLEL ? GetXMLToken( XML_PARALLEL ) : GetXMLToken( XML_PERSPECTIVE ) );
4464                                     }
4465                                     break;
4466                                     case EAS_ViewPoint :
4467                                     {
4468                                         drawing::Position3D aExtrusionViewPoint;
4469                                         if ( rProp.Value >>= aExtrusionViewPoint )
4470                                         {
4471                                             rUnitConverter.convertPosition3D( aStrBuffer, aExtrusionViewPoint );
4472                                             aStr = aStrBuffer.makeStringAndClear();
4473                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_VIEWPOINT, aStr );
4474                                         }
4475                                     }
4476                                     break;
4477                                     case EAS_Origin :
4478                                     {
4479                                         css::drawing::EnhancedCustomShapeParameterPair aOriginParaPair;
4480                                         if ( rProp.Value >>= aOriginParaPair )
4481                                         {
4482                                             ExportParameter( aStrBuffer, aOriginParaPair.First );
4483                                             ExportParameter( aStrBuffer, aOriginParaPair.Second );
4484                                             aStr = aStrBuffer.makeStringAndClear();
4485                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ORIGIN, aStr );
4486                                         }
4487                                     }
4488                                     break;
4489                                     case EAS_Color :
4490                                     {
4491                                         bool bExtrusionColor;
4492                                         if ( rProp.Value >>= bExtrusionColor )
4493                                         {
4494                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_COLOR,
4495                                                 bExtrusionColor ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4496                                         }
4497                                     }
4498                                     break;
4499                                     default:
4500                                         break;
4501                                 }
4502                             }
4503                         }
4504                     }
4505                     break;
4506                     case EAS_TextPath :
4507                     {
4508                         uno::Sequence< beans::PropertyValue > aTextPathPropSeq;
4509                         if ( rGeoProp.Value >>= aTextPathPropSeq )
4510                         {
4511                             for ( const beans::PropertyValue& rProp : std::as_const(aTextPathPropSeq) )
4512                             {
4513                                 switch( EASGet( rProp.Name ) )
4514                                 {
4515                                     case EAS_TextPath :
4516                                     {
4517                                         bool bTextPathOn;
4518                                         if ( rProp.Value >>= bTextPathOn )
4519                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH,
4520                                                 bTextPathOn ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4521                                     }
4522                                     break;
4523                                     case EAS_TextPathMode :
4524                                     {
4525                                         css::drawing::EnhancedCustomShapeTextPathMode eTextPathMode;
4526                                         if ( rProp.Value >>= eTextPathMode )
4527                                         {
4528                                             switch ( eTextPathMode )
4529                                             {
4530                                                 case css::drawing::EnhancedCustomShapeTextPathMode_NORMAL: aStr = GetXMLToken( XML_NORMAL ); break;
4531                                                 case css::drawing::EnhancedCustomShapeTextPathMode_PATH  : aStr = GetXMLToken( XML_PATH );   break;
4532                                                 case css::drawing::EnhancedCustomShapeTextPathMode_SHAPE : aStr = GetXMLToken( XML_SHAPE );  break;
4533                                                 default:
4534                                                     break;
4535                                             }
4536                                             if ( !aStr.isEmpty() )
4537                                                 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_MODE, aStr );
4538                                         }
4539                                     }
4540                                     break;
4541                                     case EAS_ScaleX :
4542                                     {
4543                                         bool bScaleX;
4544                                         if ( rProp.Value >>= bScaleX )
4545                                         {
4546                                             aStr = bScaleX ? GetXMLToken( XML_SHAPE ) : GetXMLToken( XML_PATH );
4547                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_SCALE, aStr );
4548                                         }
4549                                     }
4550                                     break;
4551                                     case EAS_SameLetterHeights :
4552                                     {
4553                                         bool bSameLetterHeights;
4554                                         if ( rProp.Value >>= bSameLetterHeights )
4555                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_SAME_LETTER_HEIGHTS,
4556                                                 bSameLetterHeights ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4557                                     }
4558                                     break;
4559                                     default:
4560                                         break;
4561                                 }
4562                             }
4563                         }
4564                     }
4565                     break;
4566                     case EAS_Path :
4567                     {
4568                         uno::Sequence< beans::PropertyValue > aPathPropSeq;
4569                         if ( rGeoProp.Value >>= aPathPropSeq )
4570                         {
4571                             for ( const beans::PropertyValue& rProp : std::as_const(aPathPropSeq) )
4572                             {
4573                                 switch( EASGet( rProp.Name ) )
4574                                 {
4575                                     case EAS_SubViewSize:
4576                                     {
4577                                         // export draw:sub-view-size (do not export in ODF 1.2 or older)
4578                                         if (rExport.getDefaultVersion() <= SvtSaveOptions::ODFVER_012)
4579                                         {
4580                                             continue;
4581                                         }
4582                                         uno::Sequence< awt::Size > aSubViewSizes;
4583                                         rProp.Value >>= aSubViewSizes;
4584 
4585                                         for ( int nIdx = 0; nIdx < aSubViewSizes.getLength(); nIdx++ )
4586                                         {
4587                                             if ( nIdx )
4588                                                 aStrBuffer.append(' ');
4589                                             aStrBuffer.append( aSubViewSizes[nIdx].Width );
4590                                             aStrBuffer.append(' ');
4591                                             aStrBuffer.append( aSubViewSizes[nIdx].Height );
4592                                         }
4593                                         aStr = aStrBuffer.makeStringAndClear();
4594                                         rExport.AddAttribute( XML_NAMESPACE_DRAW_EXT, XML_SUB_VIEW_SIZE, aStr );
4595                                     }
4596                                     break;
4597                                     case EAS_ExtrusionAllowed :
4598                                     {
4599                                         bool bExtrusionAllowed;
4600                                         if ( rProp.Value >>= bExtrusionAllowed )
4601                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ALLOWED,
4602                                                 bExtrusionAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4603                                     }
4604                                     break;
4605                                     case EAS_ConcentricGradientFillAllowed :
4606                                     {
4607                                         bool bConcentricGradientFillAllowed;
4608                                         if ( rProp.Value >>= bConcentricGradientFillAllowed )
4609                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CONCENTRIC_GRADIENT_FILL_ALLOWED,
4610                                                 bConcentricGradientFillAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4611                                     }
4612                                     break;
4613                                     case EAS_TextPathAllowed  :
4614                                     {
4615                                         bool bTextPathAllowed;
4616                                         if ( rProp.Value >>= bTextPathAllowed )
4617                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_ALLOWED,
4618                                                 bTextPathAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4619                                     }
4620                                     break;
4621                                     case EAS_GluePoints :
4622                                     {
4623                                         css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> aGluePoints;
4624                                         if ( rProp.Value >>= aGluePoints )
4625                                         {
4626                                             if ( aGluePoints.hasElements() )
4627                                             {
4628                                                 for( const auto& rGluePoint : std::as_const(aGluePoints) )
4629                                                 {
4630                                                     ExportParameter( aStrBuffer, rGluePoint.First );
4631                                                     ExportParameter( aStrBuffer, rGluePoint.Second );
4632                                                 }
4633                                                 aStr = aStrBuffer.makeStringAndClear();
4634                                             }
4635                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GLUE_POINTS, aStr );
4636                                         }
4637                                     }
4638                                     break;
4639                                     case EAS_GluePointType :
4640                                     {
4641                                         sal_Int16 nGluePointType = sal_Int16();
4642                                         if ( rProp.Value >>= nGluePointType )
4643                                         {
4644                                             switch ( nGluePointType )
4645                                             {
4646                                                 case css::drawing::EnhancedCustomShapeGluePointType::NONE     : aStr = GetXMLToken( XML_NONE );    break;
4647                                                 case css::drawing::EnhancedCustomShapeGluePointType::SEGMENTS : aStr = GetXMLToken( XML_SEGMENTS ); break;
4648                                                 case css::drawing::EnhancedCustomShapeGluePointType::RECT     : aStr = GetXMLToken( XML_RECTANGLE ); break;
4649                                             }
4650                                             if ( !aStr.isEmpty() )
4651                                                 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GLUE_POINT_TYPE, aStr );
4652                                         }
4653                                     }
4654                                     break;
4655                                     case EAS_Coordinates :
4656                                     {
4657                                         bCoordinates = ( rProp.Value >>= aCoordinates );
4658                                     }
4659                                     break;
4660                                     case EAS_Segments :
4661                                     {
4662                                         rProp.Value >>= aSegments;
4663                                     }
4664                                     break;
4665                                     case EAS_StretchX :
4666                                     {
4667                                         sal_Int32 nStretchPoint = 0;
4668                                         if ( rProp.Value >>= nStretchPoint )
4669                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PATH_STRETCHPOINT_X, OUString::number( nStretchPoint ) );
4670                                     }
4671                                     break;
4672                                     case EAS_StretchY :
4673                                     {
4674                                         sal_Int32 nStretchPoint = 0;
4675                                         if ( rProp.Value >>= nStretchPoint )
4676                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PATH_STRETCHPOINT_Y, OUString::number( nStretchPoint ) );
4677                                     }
4678                                     break;
4679                                     case EAS_TextFrames :
4680                                     {
4681                                         css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aPathTextFrames;
4682                                         if ( rProp.Value >>= aPathTextFrames )
4683                                         {
4684                                             if ( aPathTextFrames.hasElements() )
4685                                             {
4686                                                 for ( const auto& rPathTextFrame : std::as_const(aPathTextFrames) )
4687                                                 {
4688                                                     ExportParameter( aStrBuffer, rPathTextFrame.TopLeft.First );
4689                                                     ExportParameter( aStrBuffer, rPathTextFrame.TopLeft.Second );
4690                                                     ExportParameter( aStrBuffer, rPathTextFrame.BottomRight.First );
4691                                                     ExportParameter( aStrBuffer, rPathTextFrame.BottomRight.Second );
4692                                                 }
4693                                                 aStr = aStrBuffer.makeStringAndClear();
4694                                             }
4695                                             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_AREAS, aStr );
4696                                         }
4697                                     }
4698                                     break;
4699                                     default:
4700                                         break;
4701                                 }
4702                             }
4703                         }
4704                     }
4705                     break;
4706                     case EAS_Equations :
4707                     {
4708                         bEquations = ( rGeoProp.Value >>= aEquations );
4709                     }
4710                     break;
4711                     case EAS_Handles :
4712                     {
4713                         bHandles = ( rGeoProp.Value >>= aHandles );
4714                     }
4715                     break;
4716                     case EAS_AdjustmentValues :
4717                     {
4718                         rGeoProp.Value >>= aAdjustmentValues;
4719                     }
4720                     break;
4721                     default:
4722                         break;
4723                 }
4724             }   // for
4725             rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TYPE, aCustomShapeType );
4726 
4727             // adjustments
4728             sal_Int32 nAdjustmentValues = aAdjustmentValues.getLength();
4729             if ( nAdjustmentValues )
4730             {
4731                 sal_Int32 i, nValue = 0;
4732                 for ( i = 0; i < nAdjustmentValues; i++ )
4733                 {
4734                     if ( i )
4735                         aStrBuffer.append( ' ' );
4736 
4737                     const css::drawing::EnhancedCustomShapeAdjustmentValue& rAdj = aAdjustmentValues[ i ];
4738                     if ( rAdj.State == beans::PropertyState_DIRECT_VALUE )
4739                     {
4740                         if ( rAdj.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
4741                         {
4742                             double fValue = 0.0;
4743                             rAdj.Value >>= fValue;
4744                             ::sax::Converter::convertDouble(aStrBuffer, fValue);
4745                         }
4746                         else
4747                         {
4748                             rAdj.Value >>= nValue;
4749                             aStrBuffer.append(nValue);
4750                         }
4751                     }
4752                     else
4753                     {
4754                         // this should not be, but better than setting nothing
4755                         aStrBuffer.append("0");
4756                     }
4757                 }
4758                 aStr = aStrBuffer.makeStringAndClear();
4759                 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MODIFIERS, aStr );
4760             }
4761             if ( bCoordinates )
4762                 ImpExportEnhancedPath( rExport, aCoordinates, aSegments );
4763         }
4764     }
4765     SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_ENHANCED_GEOMETRY, true, true );
4766     if ( bEquations )
4767         ImpExportEquations( rExport, aEquations );
4768     if ( bHandles )
4769         ImpExportHandles( rExport, aHandles );
4770 }
4771 
ImpExportCustomShape(const uno::Reference<drawing::XShape> & xShape,XMLShapeExportFlags nFeatures,css::awt::Point * pRefPoint)4772 void XMLShapeExport::ImpExportCustomShape(
4773     const uno::Reference< drawing::XShape >& xShape,
4774     XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint )
4775 {
4776     const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
4777     if ( !xPropSet.is() )
4778         return;
4779 
4780     OUString aStr;
4781     uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
4782 
4783     // Transformation
4784     ImpExportNewTrans( xPropSet, nFeatures, pRefPoint );
4785 
4786     if ( xPropSetInfo.is() )
4787     {
4788         if ( xPropSetInfo->hasPropertyByName( "CustomShapeEngine" ) )
4789         {
4790             uno::Any aEngine( xPropSet->getPropertyValue( "CustomShapeEngine" ) );
4791             if ( ( aEngine >>= aStr ) && !aStr.isEmpty() )
4792                 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ENGINE, aStr );
4793         }
4794         if ( xPropSetInfo->hasPropertyByName( "CustomShapeData" ) )
4795         {
4796             uno::Any aData( xPropSet->getPropertyValue( "CustomShapeData" ) );
4797             if ( ( aData >>= aStr ) && !aStr.isEmpty() )
4798                 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DATA, aStr );
4799         }
4800     }
4801     bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
4802     SvXMLElementExport aOBJ( mrExport, XML_NAMESPACE_DRAW, XML_CUSTOM_SHAPE, bCreateNewline, true );
4803     ImpExportDescription( xShape ); // #i68101#
4804     ImpExportEvents( xShape );
4805     ImpExportGluePoints( xShape );
4806     ImpExportText( xShape );
4807     ImpExportEnhancedGeometry( mrExport, xPropSet );
4808 
4809 }
4810 
ImpExportTableShape(const uno::Reference<drawing::XShape> & xShape,XmlShapeType eShapeType,XMLShapeExportFlags nFeatures,css::awt::Point * pRefPoint)4811 void XMLShapeExport::ImpExportTableShape( const uno::Reference< drawing::XShape >& xShape, XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint )
4812 {
4813     uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
4814     uno::Reference< container::XNamed > xNamed(xShape, uno::UNO_QUERY);
4815 
4816     SAL_WARN_IF( !xPropSet.is() || !xNamed.is(), "xmloff", "xmloff::XMLShapeExport::ImpExportTableShape(), table shape is not implementing needed interfaces");
4817     if(xPropSet.is() && xNamed.is()) try
4818     {
4819         // Transformation
4820         ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
4821 
4822         bool bIsEmptyPresObj = false;
4823 
4824         // presentation settings
4825         if(eShapeType == XmlShapeTypePresTableShape)
4826             bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_PRESENTATION_TABLE) );
4827 
4828         const bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE );
4829         const bool bExportEmbedded(mrExport.getExportFlags() & SvXMLExportFlags::EMBEDDED);
4830 
4831         SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW, XML_FRAME, bCreateNewline, true );
4832 
4833         // do not export in ODF 1.1 or older
4834         if( mrExport.getDefaultVersion() >= SvtSaveOptions::ODFVER_012 )
4835         {
4836             if( !bIsEmptyPresObj )
4837             {
4838                 uno::Reference< container::XNamed > xTemplate( xPropSet->getPropertyValue("TableTemplate"), uno::UNO_QUERY );
4839                 if( xTemplate.is() )
4840                 {
4841                     const OUString sTemplate( xTemplate->getName() );
4842                     if( !sTemplate.isEmpty() )
4843                     {
4844                         mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_TEMPLATE_NAME, sTemplate );
4845 
4846                         for( const XMLPropertyMapEntry* pEntry = &aXMLTableShapeAttributes[0]; pEntry->msApiName; pEntry++ )
4847                         {
4848                             try
4849                             {
4850                                 bool bBool = false;
4851                                 const OUString sAPIPropertyName( pEntry->msApiName, pEntry->nApiNameLength, RTL_TEXTENCODING_ASCII_US );
4852 
4853                                 xPropSet->getPropertyValue( sAPIPropertyName ) >>= bBool;
4854                                 if( bBool )
4855                                     mrExport.AddAttribute(pEntry->mnNameSpace, pEntry->meXMLName, XML_TRUE );
4856                             }
4857                             catch( uno::Exception& )
4858                             {
4859                                 DBG_UNHANDLED_EXCEPTION("xmloff.draw");
4860                             }
4861                         }
4862                     }
4863                 }
4864 
4865                 uno::Reference< table::XColumnRowRange > xRange( xPropSet->getPropertyValue( gsModel ), uno::UNO_QUERY_THROW );
4866                 GetShapeTableExport()->exportTable( xRange );
4867             }
4868         }
4869 
4870         if( !bIsEmptyPresObj )
4871         {
4872             uno::Reference< graphic::XGraphic > xGraphic( xPropSet->getPropertyValue("ReplacementGraphic"), uno::UNO_QUERY );
4873             if( xGraphic.is() ) try
4874             {
4875                 uno::Reference< uno::XComponentContext > xContext = GetExport().getComponentContext();
4876 
4877                 uno::Reference< embed::XStorage > xPictureStorage;
4878                 uno::Reference< embed::XStorage > xStorage;
4879                 uno::Reference< io::XStream > xPictureStream;
4880 
4881                 OUString sPictureName;
4882                 if( bExportEmbedded )
4883                 {
4884                     xPictureStream.set( xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.comp.MemoryStream", xContext), uno::UNO_QUERY_THROW );
4885                 }
4886                 else
4887                 {
4888                     xStorage.set( GetExport().GetTargetStorage(), uno::UNO_SET_THROW );
4889 
4890                     xPictureStorage.set( xStorage->openStorageElement( "Pictures" , ::embed::ElementModes::READWRITE ), uno::UNO_SET_THROW );
4891 
4892                     sal_Int32 nIndex = 0;
4893                     do
4894                     {
4895                         sPictureName = "TablePreview" + OUString::number( ++nIndex ) + ".svm";
4896                     }
4897                     while( xPictureStorage->hasByName( sPictureName ) );
4898 
4899                     xPictureStream.set( xPictureStorage->openStreamElement( sPictureName, ::embed::ElementModes::READWRITE ), uno::UNO_SET_THROW );
4900                 }
4901 
4902                 uno::Reference< graphic::XGraphicProvider > xProvider( graphic::GraphicProvider::create(xContext) );
4903                 uno::Sequence< beans::PropertyValue > aArgs( 2 );
4904                 aArgs[ 0 ].Name = "MimeType";
4905                 aArgs[ 0 ].Value <<= OUString( "image/x-vclgraphic" );
4906                 aArgs[ 1 ].Name = "OutputStream";
4907                 aArgs[ 1 ].Value <<= xPictureStream->getOutputStream();
4908                 xProvider->storeGraphic( xGraphic, aArgs );
4909 
4910                 if( xPictureStorage.is() )
4911                 {
4912                     uno::Reference< embed::XTransactedObject > xTrans( xPictureStorage, uno::UNO_QUERY );
4913                     if( xTrans.is() )
4914                         xTrans->commit();
4915                 }
4916 
4917                 if( !bExportEmbedded )
4918                 {
4919                     OUString sURL = "Pictures/" + sPictureName;
4920                     mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sURL );
4921                     mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
4922                     mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
4923                     mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
4924                 }
4925 
4926                 SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW, XML_IMAGE, false, true );
4927 
4928                 if( bExportEmbedded )
4929                 {
4930                     uno::Reference< io::XSeekableInputStream > xSeekable( xPictureStream, uno::UNO_QUERY_THROW );
4931                     xSeekable->seek(0);
4932 
4933                     XMLBase64Export aBase64Exp( GetExport() );
4934                     aBase64Exp.exportOfficeBinaryDataElement( uno::Reference < io::XInputStream >( xPictureStream, uno::UNO_QUERY_THROW ) );
4935                 }
4936             }
4937             catch( uno::Exception const & )
4938             {
4939                 DBG_UNHANDLED_EXCEPTION("xmloff.draw");
4940             }
4941         }
4942 
4943         ImpExportEvents( xShape );
4944         ImpExportGluePoints( xShape );
4945         ImpExportDescription( xShape ); // #i68101#
4946     }
4947     catch( uno::Exception const & )
4948     {
4949         DBG_UNHANDLED_EXCEPTION("xmloff.draw");
4950     }
4951 }
4952 
4953 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
4954