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