tdf#154285 Check upper bound of arguments in SbRtl_Minute function
[LibreOffice.git] / xmloff / source / draw / shapeexport.cxx
blob9d9cb7506b14600c9b0628c4020256608f264bc8
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_wasm_strip.h>
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>
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>
85 #include <comphelper/classids.hxx>
86 #include <comphelper/processfactory.hxx>
87 #include <comphelper/propertyvalue.hxx>
88 #include <comphelper/sequenceashashmap.hxx>
89 #include <comphelper/storagehelper.hxx>
90 #include <officecfg/Office/Common.hxx>
92 #include <o3tl/any.hxx>
93 #include <o3tl/typed_flags_set.hxx>
94 #include <o3tl/string_view.hxx>
96 #include <rtl/math.hxx>
97 #include <rtl/ustrbuf.hxx>
98 #include <rtl/ustring.hxx>
99 #include <sal/log.hxx>
101 #include <sax/tools/converter.hxx>
103 #include <tools/debug.hxx>
104 #include <tools/globname.hxx>
105 #include <tools/helpers.hxx>
106 #include <comphelper/diagnose_ex.hxx>
107 #include <vcl/graph.hxx>
109 #include <xmloff/contextid.hxx>
110 #include <xmloff/families.hxx>
111 #include <xmloff/namespacemap.hxx>
112 #include <xmloff/shapeexport.hxx>
113 #include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
114 #include <xmloff/xmlexp.hxx>
115 #include <xmloff/xmlnamespace.hxx>
116 #include <xmloff/xmltoken.hxx>
117 #include <xmloff/xmluconv.hxx>
118 #include <xmloff/table/XMLTableExport.hxx>
119 #include <xmloff/ProgressBarHelper.hxx>
121 #include <anim.hxx>
122 #include <EnhancedCustomShapeToken.hxx>
123 #include "sdpropls.hxx"
124 #include <xexptran.hxx>
125 #include "ximpshap.hxx"
126 #include <XMLBase64Export.hxx>
127 #include <XMLImageMapExport.hxx>
128 #include <memory>
129 #include <algorithm>
131 using namespace ::com::sun::star;
132 using namespace ::xmloff::EnhancedCustomShapeToken;
133 using namespace ::xmloff::token;
135 constexpr OUStringLiteral XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE = u"vnd.sun.star.GraphicObject:";
137 namespace {
139 bool supportsText(XmlShapeType eShapeType)
141 return eShapeType != XmlShapeType::PresChartShape &&
142 eShapeType != XmlShapeType::PresOLE2Shape &&
143 eShapeType != XmlShapeType::DrawSheetShape &&
144 eShapeType != XmlShapeType::PresSheetShape &&
145 eShapeType != XmlShapeType::Draw3DSceneObject &&
146 eShapeType != XmlShapeType::Draw3DCubeObject &&
147 eShapeType != XmlShapeType::Draw3DSphereObject &&
148 eShapeType != XmlShapeType::Draw3DLatheObject &&
149 eShapeType != XmlShapeType::Draw3DExtrudeObject &&
150 eShapeType != XmlShapeType::DrawPageShape &&
151 eShapeType != XmlShapeType::PresPageShape &&
152 eShapeType != XmlShapeType::DrawGroupShape;
158 constexpr OUString gsZIndex( u"ZOrder"_ustr );
159 constexpr OUStringLiteral gsPrintable( u"Printable" );
160 constexpr OUStringLiteral gsVisible( u"Visible" );
161 constexpr OUString gsModel( u"Model"_ustr );
162 constexpr OUStringLiteral gsStartShape( u"StartShape" );
163 constexpr OUStringLiteral gsEndShape( u"EndShape" );
164 constexpr OUString gsOnClick( u"OnClick"_ustr );
165 constexpr OUStringLiteral gsEventType( u"EventType" );
166 constexpr OUStringLiteral gsPresentation( u"Presentation" );
167 constexpr OUStringLiteral gsMacroName( u"MacroName" );
168 constexpr OUString gsScript( u"Script"_ustr );
169 constexpr OUStringLiteral gsLibrary( u"Library" );
170 constexpr OUStringLiteral gsClickAction( u"ClickAction" );
171 constexpr OUString gsBookmark( u"Bookmark"_ustr );
172 constexpr OUStringLiteral gsEffect( u"Effect" );
173 constexpr OUStringLiteral gsPlayFull( u"PlayFull" );
174 constexpr OUStringLiteral gsVerb( u"Verb" );
175 constexpr OUStringLiteral gsSoundURL( u"SoundURL" );
176 constexpr OUStringLiteral gsSpeed( u"Speed" );
177 constexpr OUStringLiteral gsStarBasic( u"StarBasic" );
178 constexpr OUStringLiteral gsHyperlink( u"Hyperlink" );
180 XMLShapeExport::XMLShapeExport(SvXMLExport& rExp,
181 SvXMLExportPropertyMapper *pExtMapper )
182 : mrExport( rExp ),
183 maCurrentShapesIter(maShapesInfos.end()),
184 mbExportLayer( false ),
185 // #88546# init to sal_False
186 mbHandleProgressBar( false )
188 // construct PropertySetMapper
189 mxPropertySetMapper = CreateShapePropMapper( mrExport );
190 if( pExtMapper )
192 rtl::Reference < SvXMLExportPropertyMapper > xExtMapper( pExtMapper );
193 mxPropertySetMapper->ChainExportMapper( xExtMapper );
197 // chain text attributes
198 xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(rExp));
201 mrExport.GetAutoStylePool()->AddFamily(
202 XmlStyleFamily::SD_GRAPHICS_ID,
203 XML_STYLE_FAMILY_SD_GRAPHICS_NAME,
204 GetPropertySetMapper(),
205 XML_STYLE_FAMILY_SD_GRAPHICS_PREFIX);
206 mrExport.GetAutoStylePool()->AddFamily(
207 XmlStyleFamily::SD_PRESENTATION_ID,
208 XML_STYLE_FAMILY_SD_PRESENTATION_NAME,
209 GetPropertySetMapper(),
210 XML_STYLE_FAMILY_SD_PRESENTATION_PREFIX);
212 // create table export helper and let him add his families in time
213 GetShapeTableExport();
216 XMLShapeExport::~XMLShapeExport()
220 // sj: replacing CustomShapes with standard objects that are also supported in OpenOffice.org format
221 uno::Reference< drawing::XShape > XMLShapeExport::checkForCustomShapeReplacement( const uno::Reference< drawing::XShape >& xShape )
223 uno::Reference< drawing::XShape > xCustomShapeReplacement;
225 if( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) )
227 OUString aType( xShape->getShapeType() );
228 if( aType == "com.sun.star.drawing.CustomShape" )
230 uno::Reference< beans::XPropertySet > xSet( xShape, uno::UNO_QUERY );
231 if( xSet.is() )
233 OUString aEngine;
234 xSet->getPropertyValue(u"CustomShapeEngine"_ustr) >>= aEngine;
235 if ( aEngine.isEmpty() )
237 aEngine = "com.sun.star.drawing.EnhancedCustomShapeEngine";
239 const uno::Reference< uno::XComponentContext >& xContext( ::comphelper::getProcessComponentContext() );
241 if ( !aEngine.isEmpty() )
243 uno::Sequence< beans::PropertyValue > aPropValues{
244 comphelper::makePropertyValue(u"CustomShape"_ustr, xShape),
245 comphelper::makePropertyValue(u"ForceGroupWithText"_ustr, true)
247 uno::Sequence< uno::Any > aArgument = { uno::Any(aPropValues) };
248 uno::Reference< uno::XInterface > xInterface(
249 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aEngine, aArgument, xContext) );
250 if ( xInterface.is() )
252 uno::Reference< drawing::XCustomShapeEngine > xCustomShapeEngine(
253 uno::Reference< drawing::XCustomShapeEngine >( xInterface, uno::UNO_QUERY ) );
254 if ( xCustomShapeEngine.is() )
255 xCustomShapeReplacement = xCustomShapeEngine->render();
261 return xCustomShapeReplacement;
264 // This method collects all automatic styles for the given XShape
265 void XMLShapeExport::collectShapeAutoStyles(const uno::Reference< drawing::XShape >& xShape )
267 if( maCurrentShapesIter == maShapesInfos.end() )
269 OSL_FAIL( "XMLShapeExport::collectShapeAutoStyles(): no call to seekShapes()!" );
270 return;
272 sal_Int32 nZIndex = 0;
273 uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
274 if( xPropSet.is() )
275 xPropSet->getPropertyValue(gsZIndex) >>= nZIndex;
277 ImplXMLShapeExportInfoVector& aShapeInfoVector = (*maCurrentShapesIter).second;
279 if( static_cast<sal_Int32>(aShapeInfoVector.size()) <= nZIndex )
281 OSL_FAIL( "XMLShapeExport::collectShapeAutoStyles(): no shape info allocated for a given shape" );
282 return;
285 ImplXMLShapeExportInfo& aShapeInfo = aShapeInfoVector[nZIndex];
287 uno::Reference< drawing::XShape > xCustomShapeReplacement = checkForCustomShapeReplacement( xShape );
288 if ( xCustomShapeReplacement.is() )
289 aShapeInfo.xCustomShapeReplacement = std::move(xCustomShapeReplacement);
291 // first compute the shapes type
292 ImpCalcShapeType(xShape, aShapeInfo.meShapeType);
294 // #i118485# enabled XmlShapeType::DrawChartShape and XmlShapeType::DrawOLE2Shape
295 // to have text
296 const bool bObjSupportsText =
297 supportsText(aShapeInfo.meShapeType);
299 const bool bObjSupportsStyle =
300 aShapeInfo.meShapeType != XmlShapeType::DrawGroupShape;
302 bool bIsEmptyPresObj = false;
304 if ( aShapeInfo.xCustomShapeReplacement.is() )
305 xPropSet.clear();
307 // prep text styles
308 if( xPropSet.is() && bObjSupportsText )
310 uno::Reference< text::XText > xText(xShape, uno::UNO_QUERY);
311 if (xText.is())
315 // tdf#153161: it seems that the call to XTextRange::getString flushes the changes
316 // for some objects, that otherwise fail to get exported correctly. Maybe at some
317 // point it would make sense to find a better place for more targeted flush.
318 xText->getString();
320 catch (uno::RuntimeException const&)
322 // E.g., SwXTextFrame that contains only a table will throw; this is not an error
325 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
327 if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(u"IsEmptyPresentationObject"_ustr) )
329 uno::Any aAny = xPropSet->getPropertyValue(u"IsEmptyPresentationObject"_ustr);
330 aAny >>= bIsEmptyPresObj;
333 if(!bIsEmptyPresObj)
335 GetExport().GetTextParagraphExport()->collectTextAutoStyles( xText );
340 // compute the shape parent style
341 if( xPropSet.is() )
343 uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( xPropSet->getPropertySetInfo() );
345 OUString aParentName;
346 uno::Reference< style::XStyle > xStyle;
348 if( bObjSupportsStyle )
350 if( xPropertySetInfo.is() && xPropertySetInfo->hasPropertyByName(u"Style"_ustr) )
351 xPropSet->getPropertyValue(u"Style"_ustr) >>= xStyle;
353 if(xStyle.is())
355 // get family ID
356 uno::Reference< beans::XPropertySet > xStylePropSet(xStyle, uno::UNO_QUERY);
357 SAL_WARN_IF( !xStylePropSet.is(), "xmloff", "style without a XPropertySet?" );
360 if(xStylePropSet.is())
362 OUString aFamilyName;
363 xStylePropSet->getPropertyValue(u"Family"_ustr) >>= aFamilyName;
364 if( !aFamilyName.isEmpty() && aFamilyName != "graphics" )
365 aShapeInfo.mnFamily = XmlStyleFamily::SD_PRESENTATION_ID;
368 catch(const beans::UnknownPropertyException&)
370 // Ignored.
371 SAL_WARN( "xmloff",
372 "XMLShapeExport::collectShapeAutoStyles: style has no 'Family' property");
375 // get parent-style name
376 if(XmlStyleFamily::SD_PRESENTATION_ID == aShapeInfo.mnFamily)
378 aParentName = msPresentationStylePrefix;
381 aParentName += xStyle->getName();
385 if (aParentName.isEmpty() && xPropertySetInfo->hasPropertyByName(u"TextBox"_ustr) && xPropSet->getPropertyValue(u"TextBox"_ustr).hasValue() && xPropSet->getPropertyValue(u"TextBox"_ustr).get<bool>())
387 // Shapes with a Writer TextBox always have a parent style.
388 // If there would be none, then assign the default one.
389 aParentName = "Frame";
392 // filter propset
393 std::vector< XMLPropertyState > aPropStates;
395 sal_Int32 nCount = 0;
396 if( !bIsEmptyPresObj || (aShapeInfo.meShapeType != XmlShapeType::PresPageShape) )
398 aPropStates = GetPropertySetMapper()->Filter(mrExport, xPropSet);
400 if (XmlShapeType::DrawControlShape == aShapeInfo.meShapeType)
402 // for control shapes, we additionally need the number format style (if any)
403 uno::Reference< drawing::XControlShape > xControl(xShape, uno::UNO_QUERY);
404 DBG_ASSERT(xControl.is(), "XMLShapeExport::collectShapeAutoStyles: ShapeType control, but no XControlShape!");
405 if (xControl.is())
407 uno::Reference< beans::XPropertySet > xControlModel(xControl->getControl(), uno::UNO_QUERY);
408 DBG_ASSERT(xControlModel.is(), "XMLShapeExport::collectShapeAutoStyles: no control model on the control shape!");
410 OUString sNumberStyle = mrExport.GetFormExport()->getControlNumberStyle(xControlModel);
411 if (!sNumberStyle.isEmpty())
413 sal_Int32 nIndex = GetPropertySetMapper()->getPropertySetMapper()->FindEntryIndex(CTF_SD_CONTROL_SHAPE_DATA_STYLE);
414 // TODO : this retrieval of the index could be moved into the ctor, holding the index
415 // as member, thus saving time.
416 DBG_ASSERT(-1 != nIndex, "XMLShapeExport::collectShapeAutoStyles: could not obtain the index for our context id!");
418 XMLPropertyState aNewState(nIndex, uno::Any(sNumberStyle));
419 aPropStates.push_back(aNewState);
424 nCount = std::count_if(aPropStates.cbegin(), aPropStates.cend(),
425 [](const XMLPropertyState& rProp) { return rProp.mnIndex != -1; });
428 if(nCount == 0)
430 // no hard attributes, use parent style name for export
431 aShapeInfo.msStyleName = aParentName;
433 else
435 // there are filtered properties -> hard attributes
436 // try to find this style in AutoStylePool
437 aShapeInfo.msStyleName = mrExport.GetAutoStylePool()->Find(aShapeInfo.mnFamily, aParentName, aPropStates);
439 if(aShapeInfo.msStyleName.isEmpty())
441 // Style did not exist, add it to AutoStalePool
442 aShapeInfo.msStyleName = mrExport.GetAutoStylePool()->Add(aShapeInfo.mnFamily, aParentName, std::move(aPropStates));
446 // optionally generate auto style for text attributes
447 if( (!bIsEmptyPresObj || (aShapeInfo.meShapeType != XmlShapeType::PresPageShape)) && bObjSupportsText )
449 aPropStates = GetExport().GetTextParagraphExport()->GetParagraphPropertyMapper()->Filter(mrExport, xPropSet);
451 // yet more additionally, we need to care for the ParaAdjust property
452 if ( XmlShapeType::DrawControlShape == aShapeInfo.meShapeType )
454 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
455 uno::Reference< beans::XPropertyState > xPropState( xPropSet, uno::UNO_QUERY );
456 if ( xPropSetInfo.is() && xPropState.is() )
458 // this is because:
459 // * if controls shapes have a ParaAdjust property, then this is the Align property of the control model
460 // * control models are allowed to have an Align of "void"
461 // * the Default for control model's Align is TextAlign_LEFT
462 // * defaults for style properties are not written, but we need to write the "left",
463 // because we need to distinguish this "left" from the case where not align attribute
464 // is present which means "void"
465 if ( xPropSetInfo->hasPropertyByName( u"ParaAdjust"_ustr )
466 && ( beans::PropertyState_DEFAULT_VALUE == xPropState->getPropertyState( u"ParaAdjust"_ustr ) )
469 sal_Int32 nIndex = GetExport().GetTextParagraphExport()->GetParagraphPropertyMapper()->getPropertySetMapper()->FindEntryIndex( CTF_SD_SHAPE_PARA_ADJUST );
470 // TODO : this retrieval of the index should be moved into the ctor, holding the index
471 // as member, thus saving time.
472 DBG_ASSERT(-1 != nIndex, "XMLShapeExport::collectShapeAutoStyles: could not obtain the index for the ParaAdjust context id!");
474 XMLPropertyState aAlignDefaultState(nIndex, xPropSet->getPropertyValue(u"ParaAdjust"_ustr));
476 aPropStates.push_back( aAlignDefaultState );
481 nCount = std::count_if(aPropStates.cbegin(), aPropStates.cend(),
482 [](const XMLPropertyState& rProp) { return rProp.mnIndex != -1; });
484 if( nCount )
486 aShapeInfo.msTextStyleName = mrExport.GetAutoStylePool()->Find( XmlStyleFamily::TEXT_PARAGRAPH, u""_ustr, aPropStates );
487 if(aShapeInfo.msTextStyleName.isEmpty())
489 // Style did not exist, add it to AutoStalePool
490 aShapeInfo.msTextStyleName = mrExport.GetAutoStylePool()->Add(XmlStyleFamily::TEXT_PARAGRAPH, u""_ustr, std::move(aPropStates));
496 // prepare animation information if needed
497 if( mxAnimationsExporter.is() )
498 XMLAnimationsExporter::prepare( xShape );
500 // check for special shapes
502 switch( aShapeInfo.meShapeType )
504 case XmlShapeType::DrawConnectorShape:
506 uno::Reference< uno::XInterface > xConnection;
508 // create shape ids for export later
509 xPropSet->getPropertyValue( gsStartShape ) >>= xConnection;
510 if( xConnection.is() )
511 mrExport.getInterfaceToIdentifierMapper().registerReference( xConnection );
513 xPropSet->getPropertyValue( gsEndShape ) >>= xConnection;
514 if( xConnection.is() )
515 mrExport.getInterfaceToIdentifierMapper().registerReference( xConnection );
516 break;
518 case XmlShapeType::PresTableShape:
519 case XmlShapeType::DrawTableShape:
523 uno::Reference< table::XColumnRowRange > xRange( xPropSet->getPropertyValue( gsModel ), uno::UNO_QUERY_THROW );
524 GetShapeTableExport()->collectTableAutoStyles( xRange );
526 catch(const uno::Exception&)
528 DBG_UNHANDLED_EXCEPTION( "xmloff", "collecting auto styles for a table" );
530 break;
532 default:
533 break;
536 // check for shape collections (group shape or 3d scene)
537 // and collect contained shapes style infos
538 const uno::Reference< drawing::XShape >& xCollection = aShapeInfo.xCustomShapeReplacement.is()
539 ? aShapeInfo.xCustomShapeReplacement : xShape;
541 uno::Reference< drawing::XShapes > xShapes( xCollection, uno::UNO_QUERY );
542 if( xShapes.is() )
544 collectShapesAutoStyles( xShapes );
549 namespace
551 class NewTextListsHelper
553 public:
554 explicit NewTextListsHelper( SvXMLExport& rExp )
555 : mrExport( rExp )
557 mrExport.GetTextParagraphExport()->PushNewTextListsHelper();
560 ~NewTextListsHelper()
562 mrExport.GetTextParagraphExport()->PopTextListsHelper();
565 private:
566 SvXMLExport& mrExport;
569 // This method exports the given XShape
570 void XMLShapeExport::exportShape(const uno::Reference< drawing::XShape >& xShape,
571 XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */,
572 css::awt::Point* pRefPoint /* = NULL */,
573 comphelper::AttributeList* pAttrList /* = NULL */ )
575 SAL_INFO("xmloff", xShape->getShapeType());
576 if( maCurrentShapesIter == maShapesInfos.end() )
578 SAL_WARN( "xmloff", "XMLShapeExport::exportShape(): no auto styles where collected before export" );
579 return;
581 sal_Int32 nZIndex = 0;
582 uno::Reference< beans::XPropertySet > xSet( xShape, uno::UNO_QUERY );
583 OUString sHyperlink;
586 xSet->getPropertyValue(gsHyperlink) >>= sHyperlink;
588 catch (beans::UnknownPropertyException)
592 std::unique_ptr< SvXMLElementExport > pHyperlinkElement;
594 // Need to stash the attributes that are pre-loaded for the shape export
595 // (otherwise they will become attributes of the draw:a element)
596 uno::Reference<xml::sax::XAttributeList> xSaveAttribs(
597 new comphelper::AttributeList(GetExport().GetAttrList()));
598 GetExport().ClearAttrList();
599 if( xSet.is() && (GetExport().GetModelType() == SvtModuleOptions::EFactory::DRAW) )
601 // export hyperlinks with <a><shape/></a>. Currently only in draw since draw
602 // does not support document events
605 presentation::ClickAction eAction = presentation::ClickAction_NONE;
606 xSet->getPropertyValue(gsOnClick) >>= eAction;
608 if( (eAction == presentation::ClickAction_DOCUMENT) ||
609 (eAction == presentation::ClickAction_BOOKMARK) )
611 OUString sURL;
612 xSet->getPropertyValue(gsBookmark) >>= sURL;
614 if( !sURL.isEmpty() )
616 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sURL );
617 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
618 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
619 pHyperlinkElement.reset( new SvXMLElementExport(mrExport, XML_NAMESPACE_DRAW, XML_A, true, true) );
623 catch(const uno::Exception&)
625 TOOLS_WARN_EXCEPTION("xmloff", "XMLShapeExport::exportShape(): exception during hyperlink export");
628 else if (xSet.is() && !sHyperlink.isEmpty())
630 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sHyperlink );
631 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
632 pHyperlinkElement.reset( new SvXMLElementExport(mrExport, XML_NAMESPACE_DRAW, XML_A, true, true) );
634 // re-add stashed attributes
635 GetExport().AddAttributeList(xSaveAttribs);
637 if( xSet.is() )
638 xSet->getPropertyValue(gsZIndex) >>= nZIndex;
640 ImplXMLShapeExportInfoVector& aShapeInfoVector = (*maCurrentShapesIter).second;
642 if( static_cast<sal_Int32>(aShapeInfoVector.size()) <= nZIndex )
644 SAL_WARN( "xmloff", "XMLShapeExport::exportShape(): no shape info collected for a given shape" );
645 return;
648 NewTextListsHelper aNewTextListsHelper( mrExport );
650 const ImplXMLShapeExportInfo& aShapeInfo = aShapeInfoVector[nZIndex];
652 #ifdef DBG_UTIL
653 // check if this is the correct ShapesInfo
654 uno::Reference< container::XChild > xChild( xShape, uno::UNO_QUERY );
655 if( xChild.is() )
657 uno::Reference< drawing::XShapes > xParent( xChild->getParent(), uno::UNO_QUERY );
658 SAL_WARN_IF( !xParent.is() && xParent.get() == (*maCurrentShapesIter).first.get(), "xmloff", "XMLShapeExport::exportShape(): Wrong call to XMLShapeExport::seekShapes()" );
661 // first compute the shapes type
663 XmlShapeType eShapeType(XmlShapeType::NotYetSet);
664 ImpCalcShapeType(xShape, eShapeType);
666 SAL_WARN_IF( eShapeType != aShapeInfo.meShapeType, "xmloff", "exportShape callings do not correspond to collectShapeAutoStyles calls!: " << xShape->getShapeType() );
668 #endif
670 // collect animation information if needed
671 if( mxAnimationsExporter.is() )
672 mxAnimationsExporter->collect( xShape, mrExport );
674 /* Export shapes name if he has one (#i51726#)
675 Export of the shape name for text documents only if the OpenDocument
676 file format is written - exceptions are group shapes.
677 Note: Writer documents in OpenOffice.org file format doesn't contain
678 any names for shapes, except for group shapes.
681 if ( ( GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITER &&
682 GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITERWEB &&
683 GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITERGLOBAL ) ||
684 ( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) ||
685 aShapeInfo.meShapeType == XmlShapeType::DrawGroupShape ||
686 ( aShapeInfo.meShapeType == XmlShapeType::DrawCustomShape &&
687 aShapeInfo.xCustomShapeReplacement.is() ) )
689 uno::Reference< container::XNamed > xNamed( xShape, uno::UNO_QUERY );
690 if( xNamed.is() )
692 const OUString aName( xNamed->getName() );
693 if( !aName.isEmpty() )
694 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_NAME, aName );
699 // export style name
700 if( !aShapeInfo.msStyleName.isEmpty() )
702 if(XmlStyleFamily::SD_GRAPHICS_ID == aShapeInfo.mnFamily)
703 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_STYLE_NAME, mrExport.EncodeStyleName( aShapeInfo.msStyleName) );
704 else
705 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_STYLE_NAME, mrExport.EncodeStyleName( aShapeInfo.msStyleName) );
708 // export text style name
709 if( !aShapeInfo.msTextStyleName.isEmpty() )
711 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TEXT_STYLE_NAME, aShapeInfo.msTextStyleName );
714 // export shapes id if needed
716 uno::Reference< uno::XInterface > xRef( xShape, uno::UNO_QUERY );
717 const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRef );
718 if( !rShapeId.isEmpty() )
720 mrExport.AddAttributeIdLegacy(XML_NAMESPACE_DRAW, rShapeId);
724 // export layer information
725 if( mbExportLayer )
727 // check for group or scene shape and not export layer if this is one
728 uno::Reference< drawing::XShapes > xShapes( xShape, uno::UNO_QUERY );
729 if( !xShapes.is() )
733 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
734 OUString aLayerName;
735 xProps->getPropertyValue(u"LayerName"_ustr) >>= aLayerName;
736 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_LAYER, aLayerName );
739 catch(const uno::Exception&)
741 DBG_UNHANDLED_EXCEPTION( "xmloff", "exporting layer name for shape" );
746 // export draw:display (do not export in ODF 1.3 or older)
747 if (xSet.is() && (mrExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED))
749 if( aShapeInfo.meShapeType != XmlShapeType::DrawPageShape && aShapeInfo.meShapeType != XmlShapeType::PresPageShape &&
750 aShapeInfo.meShapeType != XmlShapeType::HandoutShape && aShapeInfo.meShapeType != XmlShapeType::DrawChartShape )
753 bool bVisible = true;
754 bool bPrintable = true;
756 xSet->getPropertyValue(gsVisible) >>= bVisible;
757 xSet->getPropertyValue(gsPrintable) >>= bPrintable;
759 XMLTokenEnum eDisplayToken = XML_TOKEN_INVALID;
760 const unsigned short nDisplay = (bVisible ? 2 : 0) | (bPrintable ? 1 : 0);
761 switch( nDisplay )
763 case 0: eDisplayToken = XML_NONE; break;
764 case 1: eDisplayToken = XML_PRINTER; break;
765 case 2: eDisplayToken = XML_SCREEN; break;
766 // case 3: eDisplayToken = XML_ALWAYS break; this is the default
769 if( eDisplayToken != XML_TOKEN_INVALID )
770 mrExport.AddAttribute(XML_NAMESPACE_DRAW_EXT, XML_DISPLAY, eDisplayToken );
772 catch(const uno::Exception&)
774 DBG_UNHANDLED_EXCEPTION("xmloff.draw");
778 // #82003# test export count
779 // #91587# ALWAYS increment since now ALL to be exported shapes are counted.
780 if(mrExport.GetShapeExport()->IsHandleProgressBarEnabled())
782 mrExport.GetProgressBarHelper()->Increment();
785 onExport( xShape );
787 // export shape element
788 switch(aShapeInfo.meShapeType)
790 case XmlShapeType::DrawRectangleShape:
792 ImpExportRectangleShape(xShape, nFeatures, pRefPoint );
793 break;
795 case XmlShapeType::DrawEllipseShape:
797 ImpExportEllipseShape(xShape, nFeatures, pRefPoint );
798 break;
800 case XmlShapeType::DrawLineShape:
802 ImpExportLineShape(xShape, nFeatures, pRefPoint );
803 break;
805 case XmlShapeType::DrawPolyPolygonShape: // closed PolyPolygon
806 case XmlShapeType::DrawPolyLineShape: // open PolyPolygon
807 case XmlShapeType::DrawClosedBezierShape: // closed tools::PolyPolygon containing curves
808 case XmlShapeType::DrawOpenBezierShape: // open tools::PolyPolygon containing curves
810 ImpExportPolygonShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
811 break;
814 case XmlShapeType::DrawTextShape:
815 case XmlShapeType::PresTitleTextShape:
816 case XmlShapeType::PresOutlinerShape:
817 case XmlShapeType::PresSubtitleShape:
818 case XmlShapeType::PresNotesShape:
819 case XmlShapeType::PresHeaderShape:
820 case XmlShapeType::PresFooterShape:
821 case XmlShapeType::PresSlideNumberShape:
822 case XmlShapeType::PresDateTimeShape:
824 ImpExportTextBoxShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
825 break;
828 case XmlShapeType::DrawGraphicObjectShape:
829 case XmlShapeType::PresGraphicObjectShape:
831 ImpExportGraphicObjectShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
832 break;
835 case XmlShapeType::DrawChartShape:
836 case XmlShapeType::PresChartShape:
838 ImpExportChartShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint, pAttrList );
839 break;
842 case XmlShapeType::DrawControlShape:
844 ImpExportControlShape(xShape, nFeatures, pRefPoint );
845 break;
848 case XmlShapeType::DrawConnectorShape:
850 ImpExportConnectorShape(xShape, nFeatures, pRefPoint );
851 break;
854 case XmlShapeType::DrawMeasureShape:
856 ImpExportMeasureShape(xShape, nFeatures, pRefPoint );
857 break;
860 case XmlShapeType::DrawOLE2Shape:
861 case XmlShapeType::PresOLE2Shape:
862 case XmlShapeType::DrawSheetShape:
863 case XmlShapeType::PresSheetShape:
865 ImpExportOLE2Shape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
866 break;
869 case XmlShapeType::PresTableShape:
870 case XmlShapeType::DrawTableShape:
872 ImpExportTableShape( xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
873 break;
876 case XmlShapeType::DrawPageShape:
877 case XmlShapeType::PresPageShape:
878 case XmlShapeType::HandoutShape:
880 ImpExportPageShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
881 break;
884 case XmlShapeType::DrawCaptionShape:
886 ImpExportCaptionShape(xShape, nFeatures, pRefPoint );
887 break;
890 case XmlShapeType::Draw3DCubeObject:
891 case XmlShapeType::Draw3DSphereObject:
892 case XmlShapeType::Draw3DLatheObject:
893 case XmlShapeType::Draw3DExtrudeObject:
895 ImpExport3DShape(xShape, aShapeInfo.meShapeType);
896 break;
899 case XmlShapeType::Draw3DSceneObject:
901 ImpExport3DSceneShape( xShape, nFeatures, pRefPoint );
902 break;
905 case XmlShapeType::DrawGroupShape:
907 // empty group
908 ImpExportGroupShape( xShape, nFeatures, pRefPoint );
909 break;
912 case XmlShapeType::DrawFrameShape:
914 ImpExportFrameShape(xShape, nFeatures, pRefPoint );
915 break;
918 case XmlShapeType::DrawAppletShape:
920 ImpExportAppletShape(xShape, nFeatures, pRefPoint );
921 break;
924 case XmlShapeType::DrawPluginShape:
926 ImpExportPluginShape(xShape, nFeatures, pRefPoint );
927 break;
930 case XmlShapeType::DrawCustomShape:
932 if ( aShapeInfo.xCustomShapeReplacement.is() )
933 ImpExportGroupShape( aShapeInfo.xCustomShapeReplacement, nFeatures, pRefPoint );
934 else
935 ImpExportCustomShape( xShape, nFeatures, pRefPoint );
936 break;
939 case XmlShapeType::PresMediaShape:
940 case XmlShapeType::DrawMediaShape:
942 ImpExportMediaShape( xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
943 break;
946 case XmlShapeType::PresOrgChartShape:
947 case XmlShapeType::Unknown:
948 case XmlShapeType::NotYetSet:
949 default:
951 // this should never happen and is an error
952 OSL_FAIL("XMLEXP: WriteShape: unknown or unexpected type of shape in export!");
953 break;
957 pHyperlinkElement.reset();
959 // #97489# #97111#
960 // if there was an error and no element for the shape was exported
961 // we need to clear the attribute list or the attributes will be
962 // set on the next exported element, which can result in corrupt
963 // xml files due to duplicate attributes
965 mrExport.CheckAttrList(); // asserts in non pro if we have attributes left
966 mrExport.ClearAttrList(); // clears the attributes
969 // This method collects all automatic styles for the shapes inside the given XShapes collection
970 void XMLShapeExport::collectShapesAutoStyles( const uno::Reference < drawing::XShapes >& xShapes )
972 ShapesInfos::iterator aOldCurrentShapesIter = maCurrentShapesIter;
973 seekShapes( xShapes );
975 uno::Reference< drawing::XShape > xShape;
976 const sal_Int32 nShapeCount(xShapes->getCount());
977 for(sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++)
979 xShapes->getByIndex(nShapeId) >>= xShape;
980 SAL_WARN_IF( !xShape.is(), "xmloff", "Shape without a XShape?" );
981 if(!xShape.is())
982 continue;
984 collectShapeAutoStyles( xShape );
987 maCurrentShapesIter = aOldCurrentShapesIter;
990 // This method exports all XShape inside the given XShapes collection
991 void XMLShapeExport::exportShapes( const uno::Reference < drawing::XShapes >& xShapes, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */ )
993 ShapesInfos::iterator aOldCurrentShapesIter = maCurrentShapesIter;
994 seekShapes( xShapes );
996 uno::Reference< drawing::XShape > xShape;
997 const sal_Int32 nShapeCount(xShapes->getCount());
998 for(sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++)
1000 xShapes->getByIndex(nShapeId) >>= xShape;
1001 SAL_WARN_IF( !xShape.is(), "xmloff", "Shape without a XShape?" );
1002 if(!xShape.is())
1003 continue;
1005 exportShape( xShape, nFeatures, pRefPoint );
1008 maCurrentShapesIter = aOldCurrentShapesIter;
1011 namespace xmloff {
1013 void FixZOrder(uno::Reference<drawing::XShapes> const& xShapes,
1014 std::function<unsigned int (uno::Reference<beans::XPropertySet> const&)> const& rGetLayer)
1016 uno::Reference<drawing::XShapes3> const xShapes3(xShapes, uno::UNO_QUERY);
1017 assert(xShapes3.is());
1018 if (!xShapes3.is())
1020 return; // only SvxDrawPage implements this
1022 struct Layer { std::vector<sal_Int32> shapes; sal_Int32 nMin = SAL_MAX_INT32; sal_Int32 nMax = 0; };
1023 std::vector<Layer> layers;
1024 // shapes are sorted by ZOrder
1025 sal_Int32 const nCount(xShapes->getCount());
1026 for (sal_Int32 i = 0; i < nCount; ++i)
1028 uno::Reference<beans::XPropertySet> const xShape(xShapes->getByIndex(i), uno::UNO_QUERY);
1029 if (!xShape.is())
1031 SAL_WARN("xmloff", "FixZOrder: null shape, cannot sort");
1032 return;
1034 unsigned int const nLayer(rGetLayer(xShape));
1035 if (layers.size() <= nLayer)
1037 layers.resize(nLayer + 1);
1039 layers[nLayer].shapes.emplace_back(i);
1040 if (i < layers[nLayer].nMin)
1042 layers[nLayer].nMin = i;
1044 if (layers[nLayer].nMax < i)
1046 layers[nLayer].nMax = i;
1049 std::erase_if(layers, [](Layer const& rLayer) { return rLayer.shapes.empty(); });
1050 bool isSorted(true);
1051 for (size_t i = 1; i < layers.size(); ++i)
1053 assert(layers[i].nMin != layers[i-1].nMax); // unique!
1054 if (layers[i].nMin < layers[i-1].nMax)
1056 isSorted = false;
1057 break;
1060 if (isSorted)
1062 return; // nothing to do
1064 uno::Sequence<sal_Int32> aNewOrder(nCount);
1065 auto iterInsert(aNewOrder.getArray());
1066 for (auto const& rLayer : layers)
1068 assert(rLayer.nMin <= rLayer.nMax); // empty layers have been removed
1069 iterInsert = std::copy(rLayer.shapes.begin(), rLayer.shapes.end(), iterInsert);
1073 xShapes3->sort(aNewOrder);
1075 catch (uno::Exception const&)
1077 SAL_WARN("xmloff", "FixZOrder: exception");
1081 } // namespace xmloff
1083 void XMLShapeExport::seekShapes( const uno::Reference< drawing::XShapes >& xShapes ) noexcept
1085 if( xShapes.is() )
1087 maCurrentShapesIter = maShapesInfos.find( xShapes );
1088 if( maCurrentShapesIter == maShapesInfos.end() )
1090 auto itPair = maShapesInfos.emplace( xShapes, ImplXMLShapeExportInfoVector( static_cast<ShapesInfos::size_type>(xShapes->getCount()) ) );
1092 maCurrentShapesIter = itPair.first;
1094 SAL_WARN_IF( maCurrentShapesIter == maShapesInfos.end(), "xmloff", "XMLShapeExport::seekShapes(): insert into stl::map failed" );
1097 SAL_WARN_IF( (*maCurrentShapesIter).second.size() != static_cast<ShapesInfos::size_type>(xShapes->getCount()), "xmloff", "XMLShapeExport::seekShapes(): XShapes size varied between calls" );
1100 else
1102 maCurrentShapesIter = maShapesInfos.end();
1106 void XMLShapeExport::exportAutoStyles()
1108 // export all autostyle infos
1110 // ...for graphic
1112 GetExport().GetAutoStylePool()->exportXML( XmlStyleFamily::SD_GRAPHICS_ID );
1115 // ...for presentation
1117 GetExport().GetAutoStylePool()->exportXML( XmlStyleFamily::SD_PRESENTATION_ID );
1120 if( mxShapeTableExport.is() )
1121 mxShapeTableExport->exportAutoStyles();
1124 /// returns the export property mapper for external chaining
1125 SvXMLExportPropertyMapper* XMLShapeExport::CreateShapePropMapper(
1126 SvXMLExport& rExport )
1128 rtl::Reference< XMLPropertyHandlerFactory > xFactory = new XMLSdPropHdlFactory( rExport.GetModel(), rExport );
1129 rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( xFactory, true );
1130 rExport.GetTextParagraphExport(); // get or create text paragraph export
1131 SvXMLExportPropertyMapper* pResult =
1132 new XMLShapeExportPropertyMapper( xMapper, rExport );
1133 // chain text attributes
1134 return pResult;
1137 void XMLShapeExport::ImpCalcShapeType(const uno::Reference< drawing::XShape >& xShape,
1138 XmlShapeType& eShapeType)
1140 // set in every case, so init here
1141 eShapeType = XmlShapeType::Unknown;
1143 if(!xShape.is())
1144 return;
1146 OUString aType(xShape->getShapeType());
1148 if(!aType.match("com.sun.star."))
1149 return;
1151 if(aType.match("drawing.", 13))
1153 // drawing shapes
1154 if (aType.match("Rectangle", 21)) { eShapeType = XmlShapeType::DrawRectangleShape; }
1156 // #i72177# Note: Correcting CustomShape, CustomShape->Custom, len from 9 (was wrong anyways) to 6.
1157 // As can be seen at the other compares, the appendix "Shape" is left out of the comparison.
1158 else if(aType.match("Custom", 21)) { eShapeType = XmlShapeType::DrawCustomShape; }
1160 else if(aType.match("Ellipse", 21)) { eShapeType = XmlShapeType::DrawEllipseShape; }
1161 else if(aType.match("Control", 21)) { eShapeType = XmlShapeType::DrawControlShape; }
1162 else if(aType.match("Connector", 21)) { eShapeType = XmlShapeType::DrawConnectorShape; }
1163 else if(aType.match("Measure", 21)) { eShapeType = XmlShapeType::DrawMeasureShape; }
1164 else if(aType.match("Line", 21)) { eShapeType = XmlShapeType::DrawLineShape; }
1166 // #i72177# Note: This covers two types by purpose, PolyPolygonShape and PolyPolygonPathShape
1167 else if(aType.match("PolyPolygon", 21)) { eShapeType = XmlShapeType::DrawPolyPolygonShape; }
1169 // #i72177# Note: This covers two types by purpose, PolyLineShape and PolyLinePathShape
1170 else if(aType.match("PolyLine", 21)) { eShapeType = XmlShapeType::DrawPolyLineShape; }
1172 else if(aType.match("OpenBezier", 21)) { eShapeType = XmlShapeType::DrawOpenBezierShape; }
1173 else if(aType.match("ClosedBezier", 21)) { eShapeType = XmlShapeType::DrawClosedBezierShape; }
1175 // #i72177# FreeHand (opened and closed) now supports the types OpenFreeHandShape and
1176 // ClosedFreeHandShape respectively. Represent them as bezier shapes
1177 else if(aType.match("OpenFreeHand", 21)) { eShapeType = XmlShapeType::DrawOpenBezierShape; }
1178 else if(aType.match("ClosedFreeHand", 21)) { eShapeType = XmlShapeType::DrawClosedBezierShape; }
1180 else if(aType.match("GraphicObject", 21)) { eShapeType = XmlShapeType::DrawGraphicObjectShape; }
1181 else if(aType.match("Group", 21)) { eShapeType = XmlShapeType::DrawGroupShape; }
1182 else if(aType.match("Text", 21)) { eShapeType = XmlShapeType::DrawTextShape; }
1183 else if(aType.match("OLE2", 21))
1185 eShapeType = XmlShapeType::DrawOLE2Shape;
1187 // get info about presentation shape
1188 uno::Reference <beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1190 if(xPropSet.is())
1192 OUString sCLSID;
1193 if(xPropSet->getPropertyValue(u"CLSID"_ustr) >>= sCLSID)
1195 #if !ENABLE_WASM_STRIP_CHART
1196 // WASM_CHART change
1197 // TODO: With Chart extracted this cannot really happen since
1198 // no Chart could've been added at all
1199 if (sCLSID == mrExport.GetChartExport()->getChartCLSID() ||
1200 #else
1202 #endif
1203 sCLSID == SvGlobalName( SO3_RPTCH_CLASSID ).GetHexName() )
1205 eShapeType = XmlShapeType::DrawChartShape;
1207 else if (sCLSID == SvGlobalName( SO3_SC_CLASSID ).GetHexName() )
1209 eShapeType = XmlShapeType::DrawSheetShape;
1211 else
1213 // general OLE2 Object
1218 else if(aType.match("Page", 21)) { eShapeType = XmlShapeType::DrawPageShape; }
1219 else if(aType.match("Frame", 21)) { eShapeType = XmlShapeType::DrawFrameShape; }
1220 else if(aType.match("Caption", 21)) { eShapeType = XmlShapeType::DrawCaptionShape; }
1221 else if(aType.match("Plugin", 21)) { eShapeType = XmlShapeType::DrawPluginShape; }
1222 else if(aType.match("Applet", 21)) { eShapeType = XmlShapeType::DrawAppletShape; }
1223 else if(aType.match("MediaShape", 21)) { eShapeType = XmlShapeType::DrawMediaShape; }
1224 else if(aType.match("TableShape", 21)) { eShapeType = XmlShapeType::DrawTableShape; }
1226 // 3D shapes
1227 else if(aType.match("Scene", 21 + 7)) { eShapeType = XmlShapeType::Draw3DSceneObject; }
1228 else if(aType.match("Cube", 21 + 7)) { eShapeType = XmlShapeType::Draw3DCubeObject; }
1229 else if(aType.match("Sphere", 21 + 7)) { eShapeType = XmlShapeType::Draw3DSphereObject; }
1230 else if(aType.match("Lathe", 21 + 7)) { eShapeType = XmlShapeType::Draw3DLatheObject; }
1231 else if(aType.match("Extrude", 21 + 7)) { eShapeType = XmlShapeType::Draw3DExtrudeObject; }
1233 else if(aType.match("presentation.", 13))
1235 // presentation shapes
1236 if (aType.match("TitleText", 26)) { eShapeType = XmlShapeType::PresTitleTextShape; }
1237 else if(aType.match("Outliner", 26)) { eShapeType = XmlShapeType::PresOutlinerShape; }
1238 else if(aType.match("Subtitle", 26)) { eShapeType = XmlShapeType::PresSubtitleShape; }
1239 else if(aType.match("GraphicObject", 26)) { eShapeType = XmlShapeType::PresGraphicObjectShape; }
1240 else if(aType.match("Page", 26)) { eShapeType = XmlShapeType::PresPageShape; }
1241 else if(aType.match("OLE2", 26))
1243 eShapeType = XmlShapeType::PresOLE2Shape;
1245 // get info about presentation shape
1246 uno::Reference <beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1248 if(xPropSet.is()) try
1250 OUString sCLSID;
1251 if(xPropSet->getPropertyValue(u"CLSID"_ustr) >>= sCLSID)
1253 if( sCLSID == SvGlobalName( SO3_SC_CLASSID ).GetHexName() )
1255 eShapeType = XmlShapeType::PresSheetShape;
1259 catch(const uno::Exception&)
1261 SAL_WARN( "xmloff", "XMLShapeExport::ImpCalcShapeType(), expected ole shape to have the CLSID property?" );
1264 else if(aType.match("Chart", 26)) { eShapeType = XmlShapeType::PresChartShape; }
1265 else if(aType.match("OrgChart", 26)) { eShapeType = XmlShapeType::PresOrgChartShape; }
1266 else if(aType.match("CalcShape", 26)) { eShapeType = XmlShapeType::PresSheetShape; }
1267 else if(aType.match("TableShape", 26)) { eShapeType = XmlShapeType::PresTableShape; }
1268 else if(aType.match("Notes", 26)) { eShapeType = XmlShapeType::PresNotesShape; }
1269 else if(aType.match("HandoutShape", 26)) { eShapeType = XmlShapeType::HandoutShape; }
1270 else if(aType.match("HeaderShape", 26)) { eShapeType = XmlShapeType::PresHeaderShape; }
1271 else if(aType.match("FooterShape", 26)) { eShapeType = XmlShapeType::PresFooterShape; }
1272 else if(aType.match("SlideNumberShape", 26)) { eShapeType = XmlShapeType::PresSlideNumberShape; }
1273 else if(aType.match("DateTimeShape", 26)) { eShapeType = XmlShapeType::PresDateTimeShape; }
1274 else if(aType.match("MediaShape", 26)) { eShapeType = XmlShapeType::PresMediaShape; }
1278 /** exports all user defined gluepoints */
1279 void XMLShapeExport::ImpExportGluePoints( const uno::Reference< drawing::XShape >& xShape )
1281 uno::Reference< drawing::XGluePointsSupplier > xSupplier( xShape, uno::UNO_QUERY );
1282 if( !xSupplier.is() )
1283 return;
1285 uno::Reference< container::XIdentifierAccess > xGluePoints( xSupplier->getGluePoints(), uno::UNO_QUERY );
1286 if( !xGluePoints.is() )
1287 return;
1289 drawing::GluePoint2 aGluePoint;
1291 const uno::Sequence< sal_Int32 > aIdSequence( xGluePoints->getIdentifiers() );
1293 for( const sal_Int32 nIdentifier : aIdSequence )
1295 if( (xGluePoints->getByIdentifier( nIdentifier ) >>= aGluePoint) && aGluePoint.IsUserDefined )
1297 // export only user defined gluepoints
1299 const OUString sId( OUString::number( nIdentifier ) );
1300 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_ID, sId );
1302 mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
1303 aGluePoint.Position.X);
1304 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, msBuffer.makeStringAndClear());
1306 mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
1307 aGluePoint.Position.Y);
1308 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, msBuffer.makeStringAndClear());
1310 if( !aGluePoint.IsRelative )
1312 SvXMLUnitConverter::convertEnum( msBuffer, aGluePoint.PositionAlignment, aXML_GlueAlignment_EnumMap );
1313 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ALIGN, msBuffer.makeStringAndClear() );
1316 if( aGluePoint.Escape != drawing::EscapeDirection_SMART )
1318 SvXMLUnitConverter::convertEnum( msBuffer, aGluePoint.Escape, aXML_GlueEscapeDirection_EnumMap );
1319 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ESCAPE_DIRECTION, msBuffer.makeStringAndClear() );
1322 SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_DRAW, XML_GLUE_POINT, true, true);
1327 void XMLShapeExport::ImpExportSignatureLine(const uno::Reference<drawing::XShape>& xShape)
1329 uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1331 bool bIsSignatureLine = false;
1332 xPropSet->getPropertyValue(u"IsSignatureLine"_ustr) >>= bIsSignatureLine;
1333 if (!bIsSignatureLine)
1334 return;
1336 OUString aSignatureLineId;
1337 xPropSet->getPropertyValue(u"SignatureLineId"_ustr) >>= aSignatureLineId;
1338 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_ID, aSignatureLineId);
1340 OUString aSuggestedSignerName;
1341 xPropSet->getPropertyValue(u"SignatureLineSuggestedSignerName"_ustr) >>= aSuggestedSignerName;
1342 if (!aSuggestedSignerName.isEmpty())
1343 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_NAME, aSuggestedSignerName);
1345 OUString aSuggestedSignerTitle;
1346 xPropSet->getPropertyValue(u"SignatureLineSuggestedSignerTitle"_ustr) >>= aSuggestedSignerTitle;
1347 if (!aSuggestedSignerTitle.isEmpty())
1348 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_TITLE, aSuggestedSignerTitle);
1350 OUString aSuggestedSignerEmail;
1351 xPropSet->getPropertyValue(u"SignatureLineSuggestedSignerEmail"_ustr) >>= aSuggestedSignerEmail;
1352 if (!aSuggestedSignerEmail.isEmpty())
1353 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_EMAIL, aSuggestedSignerEmail);
1355 OUString aSigningInstructions;
1356 xPropSet->getPropertyValue(u"SignatureLineSigningInstructions"_ustr) >>= aSigningInstructions;
1357 if (!aSigningInstructions.isEmpty())
1358 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SIGNING_INSTRUCTIONS, aSigningInstructions);
1360 bool bShowSignDate = false;
1361 xPropSet->getPropertyValue(u"SignatureLineShowSignDate"_ustr) >>= bShowSignDate;
1362 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SHOW_SIGN_DATE,
1363 bShowSignDate ? XML_TRUE : XML_FALSE);
1365 bool bCanAddComment = false;
1366 xPropSet->getPropertyValue(u"SignatureLineCanAddComment"_ustr) >>= bCanAddComment;
1367 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_CAN_ADD_COMMENT,
1368 bCanAddComment ? XML_TRUE : XML_FALSE);
1370 SvXMLElementExport aSignatureLineElement(mrExport, XML_NAMESPACE_LO_EXT, XML_SIGNATURELINE, true,
1371 true);
1374 void XMLShapeExport::ImpExportQRCode(const uno::Reference<drawing::XShape>& xShape)
1376 uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1378 uno::Any aAny = xPropSet->getPropertyValue(u"BarCodeProperties"_ustr);
1380 css::drawing::BarCode aBarCode;
1381 if(!(aAny >>= aBarCode))
1382 return;
1384 mrExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_STRING_VALUE, aBarCode.Payload);
1385 /* Export QR Code as per customised schema, @see OpenDocument-schema-v1.3+libreoffice */
1386 OUString temp;
1387 switch(aBarCode.ErrorCorrection){
1388 case css::drawing::BarCodeErrorCorrection::LOW :
1389 temp = "low";
1390 break;
1391 case css::drawing::BarCodeErrorCorrection::MEDIUM:
1392 temp = "medium";
1393 break;
1394 case css::drawing::BarCodeErrorCorrection::QUARTILE:
1395 temp = "quartile";
1396 break;
1397 case css::drawing::BarCodeErrorCorrection::HIGH:
1398 temp = "high";
1399 break;
1401 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_ERROR_CORRECTION, temp);
1402 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_BORDER, OUStringBuffer(20).append(aBarCode.Border).makeStringAndClear());
1403 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_TYPE, OUStringBuffer(20).append(aBarCode.Type).makeStringAndClear());
1405 SvXMLElementExport aBarCodeElement(mrExport, XML_NAMESPACE_LO_EXT, XML_QRCODE, true,
1406 true);
1409 void XMLShapeExport::ExportGraphicDefaults()
1411 rtl::Reference<XMLStyleExport> aStEx(new XMLStyleExport(mrExport, mrExport.GetAutoStylePool().get()));
1413 // construct PropertySetMapper
1414 rtl::Reference< SvXMLExportPropertyMapper > xPropertySetMapper( CreateShapePropMapper( mrExport ) );
1415 static_cast<XMLShapeExportPropertyMapper*>(xPropertySetMapper.get())->SetAutoStyles( false );
1417 // chain text attributes
1418 xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(mrExport));
1420 // chain special Writer/text frame default attributes
1421 xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaDefaultExtPropMapper(mrExport));
1423 // write graphic family default style
1424 uno::Reference< lang::XMultiServiceFactory > xFact( mrExport.GetModel(), uno::UNO_QUERY );
1425 if( !xFact.is() )
1426 return;
1430 uno::Reference< beans::XPropertySet > xDefaults( xFact->createInstance(u"com.sun.star.drawing.Defaults"_ustr), uno::UNO_QUERY );
1431 if( xDefaults.is() )
1433 aStEx->exportDefaultStyle( xDefaults, XML_STYLE_FAMILY_SD_GRAPHICS_NAME, xPropertySetMapper );
1435 // write graphic styles (family name differs depending on the module)
1436 aStEx->exportStyleFamily(u"graphics"_ustr, XML_STYLE_FAMILY_SD_GRAPHICS_NAME, xPropertySetMapper, false, XmlStyleFamily::SD_GRAPHICS_ID);
1437 aStEx->exportStyleFamily(u"GraphicStyles"_ustr, XML_STYLE_FAMILY_SD_GRAPHICS_NAME, xPropertySetMapper, false, XmlStyleFamily::SD_GRAPHICS_ID);
1440 catch(const lang::ServiceNotRegisteredException&)
1445 void XMLShapeExport::onExport( const css::uno::Reference < css::drawing::XShape >& )
1449 const rtl::Reference< XMLTableExport >& XMLShapeExport::GetShapeTableExport()
1451 if( !mxShapeTableExport.is() )
1453 rtl::Reference< XMLPropertyHandlerFactory > xFactory( new XMLSdPropHdlFactory( mrExport.GetModel(), mrExport ) );
1454 rtl::Reference < XMLPropertySetMapper > xMapper( new XMLShapePropertySetMapper( xFactory, true ) );
1455 mrExport.GetTextParagraphExport(); // get or create text paragraph export
1456 rtl::Reference< SvXMLExportPropertyMapper > xPropertySetMapper( new XMLShapeExportPropertyMapper( xMapper, mrExport ) );
1457 mxShapeTableExport = new XMLTableExport( mrExport, xPropertySetMapper, xFactory );
1460 return mxShapeTableExport;
1463 void XMLShapeExport::ImpExportNewTrans(const uno::Reference< beans::XPropertySet >& xPropSet,
1464 XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
1466 // get matrix
1467 ::basegfx::B2DHomMatrix aMatrix;
1468 ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
1470 // decompose and correct about pRefPoint
1471 ::basegfx::B2DTuple aTRScale;
1472 double fTRShear(0.0);
1473 double fTRRotate(0.0);
1474 ::basegfx::B2DTuple aTRTranslate;
1475 ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
1477 // use features and write
1478 ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures);
1481 void XMLShapeExport::ImpExportNewTrans_GetB2DHomMatrix(::basegfx::B2DHomMatrix& rMatrix,
1482 const uno::Reference< beans::XPropertySet >& xPropSet)
1484 /* Get <TransformationInHoriL2R>, if it exist
1485 and if the document is exported into the OpenOffice.org file format.
1486 This property only exists at service css::text::Shape - the
1487 Writer UNO service for shapes.
1488 This code is needed, because the positioning attributes in the
1489 OpenOffice.org file format are given in horizontal left-to-right layout
1490 regardless the layout direction the shape is in. In the OASIS Open Office
1491 file format the positioning attributes are correctly given in the layout
1492 direction the shape is in. Thus, this code provides the conversion from
1493 the OASIS Open Office file format to the OpenOffice.org file format. (#i28749#)
1495 uno::Any aAny;
1496 if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
1497 xPropSet->getPropertySetInfo()->hasPropertyByName(u"TransformationInHoriL2R"_ustr) )
1499 aAny = xPropSet->getPropertyValue(u"TransformationInHoriL2R"_ustr);
1501 else
1503 aAny = xPropSet->getPropertyValue(u"Transformation"_ustr);
1505 drawing::HomogenMatrix3 aMatrix;
1506 aAny >>= aMatrix;
1508 rMatrix.set(0, 0, aMatrix.Line1.Column1);
1509 rMatrix.set(0, 1, aMatrix.Line1.Column2);
1510 rMatrix.set(0, 2, aMatrix.Line1.Column3);
1511 rMatrix.set(1, 0, aMatrix.Line2.Column1);
1512 rMatrix.set(1, 1, aMatrix.Line2.Column2);
1513 rMatrix.set(1, 2, aMatrix.Line2.Column3);
1514 // For this to be a valid 2D transform matrix, the last row must be [0,0,1]
1515 assert( aMatrix.Line3.Column1 == 0 );
1516 assert( aMatrix.Line3.Column2 == 0 );
1517 assert( aMatrix.Line3.Column3 == 1 );
1520 void XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint(const ::basegfx::B2DHomMatrix& rMatrix, ::basegfx::B2DTuple& rTRScale,
1521 double& fTRShear, double& fTRRotate, ::basegfx::B2DTuple& rTRTranslate, css::awt::Point* pRefPoint)
1523 // decompose matrix
1524 rMatrix.decompose(rTRScale, rTRTranslate, fTRRotate, fTRShear);
1526 // correct translation about pRefPoint
1527 if(pRefPoint)
1529 rTRTranslate -= ::basegfx::B2DTuple(pRefPoint->X, pRefPoint->Y);
1533 void XMLShapeExport::ImpExportNewTrans_FeaturesAndWrite(::basegfx::B2DTuple const & rTRScale, double fTRShear,
1534 double fTRRotate, ::basegfx::B2DTuple const & rTRTranslate, const XMLShapeExportFlags nFeatures)
1536 // always write Size (rTRScale) since this statement carries the union
1537 // of the object
1538 OUString aStr;
1539 OUStringBuffer sStringBuffer;
1540 ::basegfx::B2DTuple aTRScale(rTRScale);
1542 // svg: width
1543 if(!(nFeatures & XMLShapeExportFlags::WIDTH))
1545 aTRScale.setX(1.0);
1547 else
1549 if( aTRScale.getX() > 0.0 )
1550 aTRScale.setX(aTRScale.getX() - 1.0);
1551 else if( aTRScale.getX() < 0.0 )
1552 aTRScale.setX(aTRScale.getX() + 1.0);
1555 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1556 basegfx::fround(aTRScale.getX()));
1557 aStr = sStringBuffer.makeStringAndClear();
1558 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, aStr);
1560 // svg: height
1561 if(!(nFeatures & XMLShapeExportFlags::HEIGHT))
1563 aTRScale.setY(1.0);
1565 else
1567 if( aTRScale.getY() > 0.0 )
1568 aTRScale.setY(aTRScale.getY() - 1.0);
1569 else if( aTRScale.getY() < 0.0 )
1570 aTRScale.setY(aTRScale.getY() + 1.0);
1573 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1574 basegfx::fround(aTRScale.getY()));
1575 aStr = sStringBuffer.makeStringAndClear();
1576 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, aStr);
1578 // decide if transformation is necessary
1579 bool bTransformationIsNecessary(fTRShear != 0.0 || fTRRotate != 0.0);
1581 if(bTransformationIsNecessary)
1583 // write transformation, but WITHOUT scale which is exported as size above
1584 SdXMLImExTransform2D aTransform;
1586 aTransform.AddSkewX(atan(fTRShear));
1588 // #i78696#
1589 // fTRRotate is mathematically correct, but due to the error
1590 // we export/import it mirrored. Since the API implementation is fixed and
1591 // uses the correctly oriented angle, it is necessary for compatibility to
1592 // mirror the angle here to stay at the old behaviour. There is a follow-up
1593 // task (#i78698#) to fix this in the next ODF FileFormat version
1594 aTransform.AddRotate(-fTRRotate);
1596 aTransform.AddTranslate(rTRTranslate);
1598 // does transformation need to be exported?
1599 if(aTransform.NeedsAction())
1600 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
1602 else
1604 // no shear, no rotate; just add object position to export and we are done
1605 if(nFeatures & XMLShapeExportFlags::X)
1607 // svg: x
1608 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1609 basegfx::fround(rTRTranslate.getX()));
1610 aStr = sStringBuffer.makeStringAndClear();
1611 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, aStr);
1614 if(nFeatures & XMLShapeExportFlags::Y)
1616 // svg: y
1617 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1618 basegfx::fround(rTRTranslate.getY()));
1619 aStr = sStringBuffer.makeStringAndClear();
1620 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, aStr);
1625 bool XMLShapeExport::ImpExportPresentationAttributes( const uno::Reference< beans::XPropertySet >& xPropSet, const OUString& rClass )
1627 bool bIsEmpty = false;
1629 // write presentation class entry
1630 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS, rClass);
1632 if( xPropSet.is() )
1634 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
1637 // is empty pres. shape?
1638 if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(u"IsEmptyPresentationObject"_ustr))
1640 xPropSet->getPropertyValue(u"IsEmptyPresentationObject"_ustr) >>= bIsEmpty;
1641 if( bIsEmpty )
1642 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PLACEHOLDER, XML_TRUE);
1645 // is user-transformed?
1646 if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(u"IsPlaceholderDependent"_ustr))
1648 bool bTemp = false;
1649 xPropSet->getPropertyValue(u"IsPlaceholderDependent"_ustr) >>= bTemp;
1650 if(!bTemp)
1651 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_USER_TRANSFORMED, XML_TRUE);
1655 return bIsEmpty;
1658 void XMLShapeExport::ImpExportText( const uno::Reference< drawing::XShape >& xShape, TextPNS eExtensionNS )
1660 if (eExtensionNS == TextPNS::EXTENSION)
1662 if ((mrExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
1664 return; // do not export to ODF 1.1/1.2/1.3
1667 uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY );
1668 if( xText.is() )
1670 uno::Reference< container::XEnumerationAccess > xEnumAccess( xShape, uno::UNO_QUERY );
1671 if( xEnumAccess.is() && xEnumAccess->hasElements() )
1672 mrExport.GetTextParagraphExport()->exportText( xText, false, true, eExtensionNS );
1676 namespace {
1678 enum class Found {
1679 NONE = 0x0000,
1680 CLICKACTION = 0x0001,
1681 BOOKMARK = 0x0002,
1682 EFFECT = 0x0004,
1683 PLAYFULL = 0x0008,
1684 VERB = 0x0010,
1685 SOUNDURL = 0x0020,
1686 SPEED = 0x0040,
1687 CLICKEVENTTYPE = 0x0080,
1688 MACRO = 0x0100,
1689 LIBRARY = 0x0200,
1694 namespace o3tl {
1695 template<> struct typed_flags<Found> : is_typed_flags<Found, 0x03ff> {};
1698 void XMLShapeExport::ImpExportEvents( const uno::Reference< drawing::XShape >& xShape )
1700 uno::Reference< document::XEventsSupplier > xEventsSupplier( xShape, uno::UNO_QUERY );
1701 if( !xEventsSupplier.is() )
1702 return;
1704 uno::Reference< container::XNameAccess > xEvents = xEventsSupplier->getEvents();
1705 SAL_WARN_IF( !xEvents.is(), "xmloff", "XEventsSupplier::getEvents() returned NULL" );
1706 if( !xEvents.is() )
1707 return;
1709 Found nFound = Found::NONE;
1711 OUString aClickEventType;
1712 presentation::ClickAction eClickAction = presentation::ClickAction_NONE;
1713 presentation::AnimationEffect eEffect = presentation::AnimationEffect_NONE;
1714 presentation::AnimationSpeed eSpeed = presentation::AnimationSpeed_SLOW;
1715 OUString aStrSoundURL;
1716 bool bPlayFull = false;
1717 sal_Int32 nVerb = 0;
1718 OUString aStrMacro;
1719 OUString aStrLibrary;
1720 OUString aStrBookmark;
1722 uno::Sequence< beans::PropertyValue > aClickProperties;
1723 if( xEvents->hasByName( gsOnClick ) && (xEvents->getByName( gsOnClick ) >>= aClickProperties) )
1725 for (const auto& rProperty : aClickProperties)
1727 if( !( nFound & Found::CLICKEVENTTYPE ) && rProperty.Name == gsEventType )
1729 if( rProperty.Value >>= aClickEventType )
1730 nFound |= Found::CLICKEVENTTYPE;
1732 else if( !( nFound & Found::CLICKACTION ) && rProperty.Name == gsClickAction )
1734 if( rProperty.Value >>= eClickAction )
1735 nFound |= Found::CLICKACTION;
1737 else if( !( nFound & Found::MACRO ) && ( rProperty.Name == gsMacroName || rProperty.Name == gsScript ) )
1739 if( rProperty.Value >>= aStrMacro )
1740 nFound |= Found::MACRO;
1742 else if( !( nFound & Found::LIBRARY ) && rProperty.Name == gsLibrary )
1744 if( rProperty.Value >>= aStrLibrary )
1745 nFound |= Found::LIBRARY;
1747 else if( !( nFound & Found::EFFECT ) && rProperty.Name == gsEffect )
1749 if( rProperty.Value >>= eEffect )
1750 nFound |= Found::EFFECT;
1752 else if( !( nFound & Found::BOOKMARK ) && rProperty.Name == gsBookmark )
1754 if( rProperty.Value >>= aStrBookmark )
1755 nFound |= Found::BOOKMARK;
1757 else if( !( nFound & Found::SPEED ) && rProperty.Name == gsSpeed )
1759 if( rProperty.Value >>= eSpeed )
1760 nFound |= Found::SPEED;
1762 else if( !( nFound & Found::SOUNDURL ) && rProperty.Name == gsSoundURL )
1764 if( rProperty.Value >>= aStrSoundURL )
1765 nFound |= Found::SOUNDURL;
1767 else if( !( nFound & Found::PLAYFULL ) && rProperty.Name == gsPlayFull )
1769 if( rProperty.Value >>= bPlayFull )
1770 nFound |= Found::PLAYFULL;
1772 else if( !( nFound & Found::VERB ) && rProperty.Name == gsVerb )
1774 if( rProperty.Value >>= nVerb )
1775 nFound |= Found::VERB;
1780 // create the XML elements
1782 if( aClickEventType == gsPresentation )
1784 if( !(nFound & Found::CLICKACTION) || (eClickAction == presentation::ClickAction_NONE) )
1785 return;
1787 SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
1789 enum XMLTokenEnum eStrAction;
1791 switch( eClickAction )
1793 case presentation::ClickAction_PREVPAGE: eStrAction = XML_PREVIOUS_PAGE; break;
1794 case presentation::ClickAction_NEXTPAGE: eStrAction = XML_NEXT_PAGE; break;
1795 case presentation::ClickAction_FIRSTPAGE: eStrAction = XML_FIRST_PAGE; break;
1796 case presentation::ClickAction_LASTPAGE: eStrAction = XML_LAST_PAGE; break;
1797 case presentation::ClickAction_INVISIBLE: eStrAction = XML_HIDE; break;
1798 case presentation::ClickAction_STOPPRESENTATION:eStrAction = XML_STOP; break;
1799 case presentation::ClickAction_PROGRAM: eStrAction = XML_EXECUTE; break;
1800 case presentation::ClickAction_BOOKMARK: eStrAction = XML_SHOW; break;
1801 case presentation::ClickAction_DOCUMENT: eStrAction = XML_SHOW; break;
1802 case presentation::ClickAction_MACRO: eStrAction = XML_EXECUTE_MACRO; break;
1803 case presentation::ClickAction_VERB: eStrAction = XML_VERB; break;
1804 case presentation::ClickAction_VANISH: eStrAction = XML_FADE_OUT; break;
1805 case presentation::ClickAction_SOUND: eStrAction = XML_SOUND; break;
1806 default:
1807 OSL_FAIL( "unknown presentation::ClickAction found!" );
1808 eStrAction = XML_UNKNOWN;
1811 OUString aEventQName(
1812 mrExport.GetNamespaceMap().GetQNameByKey(
1813 XML_NAMESPACE_DOM, u"click"_ustr ) );
1814 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
1815 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_ACTION, eStrAction );
1817 if( eClickAction == presentation::ClickAction_VANISH )
1819 if( nFound & Found::EFFECT )
1821 XMLEffect eKind;
1822 XMLEffectDirection eDirection;
1823 sal_Int16 nStartScale;
1824 bool bIn;
1826 SdXMLImplSetEffect( eEffect, eKind, eDirection, nStartScale, bIn );
1828 if( eKind != EK_none )
1830 SvXMLUnitConverter::convertEnum( msBuffer, eKind, aXML_AnimationEffect_EnumMap );
1831 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_EFFECT, msBuffer.makeStringAndClear() );
1834 if( eDirection != ED_none )
1836 SvXMLUnitConverter::convertEnum( msBuffer, eDirection, aXML_AnimationDirection_EnumMap );
1837 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_DIRECTION, msBuffer.makeStringAndClear() );
1840 if( nStartScale != -1 )
1842 ::sax::Converter::convertPercent( msBuffer, nStartScale );
1843 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_START_SCALE, msBuffer.makeStringAndClear() );
1847 if( nFound & Found::SPEED && eEffect != presentation::AnimationEffect_NONE )
1849 if( eSpeed != presentation::AnimationSpeed_MEDIUM )
1851 SvXMLUnitConverter::convertEnum( msBuffer, eSpeed, aXML_AnimationSpeed_EnumMap );
1852 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_SPEED, msBuffer.makeStringAndClear() );
1857 if( eClickAction == presentation::ClickAction_PROGRAM ||
1858 eClickAction == presentation::ClickAction_BOOKMARK ||
1859 eClickAction == presentation::ClickAction_DOCUMENT )
1861 if( eClickAction == presentation::ClickAction_BOOKMARK )
1862 msBuffer.append( '#' );
1864 msBuffer.append( aStrBookmark );
1865 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(msBuffer.makeStringAndClear()) );
1866 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
1867 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
1868 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST );
1871 if( ( nFound & Found::VERB ) && eClickAction == presentation::ClickAction_VERB )
1873 msBuffer.append( nVerb );
1874 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_VERB, msBuffer.makeStringAndClear());
1877 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_PRESENTATION, XML_EVENT_LISTENER, true, true);
1879 if( eClickAction == presentation::ClickAction_VANISH || eClickAction == presentation::ClickAction_SOUND )
1881 if( ( nFound & Found::SOUNDURL ) && !aStrSoundURL.isEmpty() )
1883 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStrSoundURL) );
1884 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
1885 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_NEW );
1886 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST );
1887 if( nFound & Found::PLAYFULL && bPlayFull )
1888 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PLAY_FULL, XML_TRUE );
1890 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_PRESENTATION, XML_SOUND, true, true );
1894 else if( aClickEventType == gsStarBasic )
1896 if( nFound & Found::MACRO )
1898 SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
1900 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE,
1901 mrExport.GetNamespaceMap().GetQNameByKey(
1902 XML_NAMESPACE_OOO,
1903 u"starbasic"_ustr ) );
1904 OUString aEventQName(
1905 mrExport.GetNamespaceMap().GetQNameByKey(
1906 XML_NAMESPACE_DOM, u"click"_ustr ) );
1907 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
1909 if( nFound & Found::LIBRARY )
1911 const OUString& sLocation( GetXMLToken(
1912 (aStrLibrary.equalsIgnoreAsciiCase("StarOffice") ||
1913 aStrLibrary.equalsIgnoreAsciiCase("application") ) ? XML_APPLICATION
1914 : XML_DOCUMENT ) );
1915 mrExport.AddAttribute(XML_NAMESPACE_SCRIPT, XML_MACRO_NAME,
1916 sLocation + ":" + aStrMacro);
1918 else
1920 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_MACRO_NAME, aStrMacro );
1923 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, true, true);
1926 else if( aClickEventType == gsScript )
1928 if( nFound & Found::MACRO )
1930 SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
1932 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE, mrExport.GetNamespaceMap().GetQNameByKey(
1933 XML_NAMESPACE_OOO, GetXMLToken(XML_SCRIPT) ) );
1934 OUString aEventQName(
1935 mrExport.GetNamespaceMap().GetQNameByKey(
1936 XML_NAMESPACE_DOM, u"click"_ustr ) );
1937 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
1938 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aStrMacro );
1939 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, u"simple"_ustr );
1941 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, true, true);
1946 /** #i68101# export shape Title and Description */
1947 void XMLShapeExport::ImpExportDescription( const uno::Reference< drawing::XShape >& xShape )
1951 OUString aTitle;
1952 OUString aDescription;
1954 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY_THROW );
1955 xProps->getPropertyValue(u"Title"_ustr) >>= aTitle;
1956 xProps->getPropertyValue(u"Description"_ustr) >>= aDescription;
1958 if(!aTitle.isEmpty())
1960 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_TITLE, true, false);
1961 mrExport.Characters( aTitle );
1964 if(!aDescription.isEmpty())
1966 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_DESC, true, false );
1967 mrExport.Characters( aDescription );
1970 catch( uno::Exception& )
1972 DBG_UNHANDLED_EXCEPTION( "xmloff", "exporting Title and/or Description for shape" );
1976 void XMLShapeExport::ImpExportGroupShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
1978 uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY);
1979 if(!(xShapes.is() && xShapes->getCount()))
1980 return;
1982 // write group shape
1983 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
1984 SvXMLElementExport aPGR(mrExport, XML_NAMESPACE_DRAW, XML_G, bCreateNewline, true);
1986 ImpExportDescription( xShape ); // #i68101#
1987 ImpExportEvents( xShape );
1988 ImpExportGluePoints( xShape );
1990 // #89764# if export of position is suppressed for group shape,
1991 // positions of contained objects should be written relative to
1992 // the upper left edge of the group.
1993 awt::Point aUpperLeft;
1995 if(!(nFeatures & XMLShapeExportFlags::POSITION))
1997 nFeatures |= XMLShapeExportFlags::POSITION;
1998 aUpperLeft = xShape->getPosition();
1999 pRefPoint = &aUpperLeft;
2002 // write members
2003 exportShapes( xShapes, nFeatures, pRefPoint );
2006 void XMLShapeExport::ImpExportTextBoxShape(
2007 const uno::Reference< drawing::XShape >& xShape,
2008 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2010 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2011 if(!xPropSet.is())
2012 return;
2014 // presentation attribute (if presentation)
2015 bool bIsPresShape(false);
2016 bool bIsEmptyPresObj(false);
2017 OUString aStr;
2019 switch(eShapeType)
2021 case XmlShapeType::PresSubtitleShape:
2023 aStr = GetXMLToken(XML_SUBTITLE);
2024 bIsPresShape = true;
2025 break;
2027 case XmlShapeType::PresTitleTextShape:
2029 aStr = GetXMLToken(XML_TITLE);
2030 bIsPresShape = true;
2031 break;
2033 case XmlShapeType::PresOutlinerShape:
2035 aStr = GetXMLToken(XML_PRESENTATION_OUTLINE);
2036 bIsPresShape = true;
2037 break;
2039 case XmlShapeType::PresNotesShape:
2041 aStr = GetXMLToken(XML_NOTES);
2042 bIsPresShape = true;
2043 break;
2045 case XmlShapeType::PresHeaderShape:
2047 aStr = GetXMLToken(XML_HEADER);
2048 bIsPresShape = true;
2049 break;
2051 case XmlShapeType::PresFooterShape:
2053 aStr = GetXMLToken(XML_FOOTER);
2054 bIsPresShape = true;
2055 break;
2057 case XmlShapeType::PresSlideNumberShape:
2059 aStr = GetXMLToken(XML_PAGE_NUMBER);
2060 bIsPresShape = true;
2061 break;
2063 case XmlShapeType::PresDateTimeShape:
2065 aStr = GetXMLToken(XML_DATE_TIME);
2066 bIsPresShape = true;
2067 break;
2069 default:
2070 break;
2073 // Transformation
2074 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2076 if(bIsPresShape)
2077 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, aStr );
2079 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2080 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
2081 XML_FRAME, bCreateNewline, true );
2083 // evtl. corner radius?
2084 sal_Int32 nCornerRadius(0);
2085 xPropSet->getPropertyValue(u"CornerRadius"_ustr) >>= nCornerRadius;
2086 if(nCornerRadius)
2088 OUStringBuffer sStringBuffer;
2089 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2090 nCornerRadius);
2091 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
2095 // write text-box
2096 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_TEXT_BOX, true, true);
2097 if(!bIsEmptyPresObj)
2098 ImpExportText( xShape );
2101 ImpExportDescription( xShape ); // #i68101#
2102 ImpExportEvents( xShape );
2103 ImpExportGluePoints( xShape );
2107 void XMLShapeExport::ImpExportRectangleShape(
2108 const uno::Reference< drawing::XShape >& xShape,
2109 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
2111 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2112 if(!xPropSet.is())
2113 return;
2115 // Transformation
2116 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2118 // evtl. corner radius?
2119 sal_Int32 nCornerRadius(0);
2120 xPropSet->getPropertyValue(u"CornerRadius"_ustr) >>= nCornerRadius;
2121 if(nCornerRadius)
2123 OUStringBuffer sStringBuffer;
2124 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2125 nCornerRadius);
2126 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
2129 // write rectangle
2130 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2131 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_RECT, bCreateNewline, true);
2133 ImpExportDescription( xShape ); // #i68101#
2134 ImpExportEvents( xShape );
2135 ImpExportGluePoints( xShape );
2136 ImpExportText( xShape );
2139 void XMLShapeExport::ImpExportLineShape(
2140 const uno::Reference< drawing::XShape >& xShape,
2141 XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2143 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2144 if(!xPropSet.is())
2145 return;
2147 OUString aStr;
2148 OUStringBuffer sStringBuffer;
2149 awt::Point aStart(0,0);
2150 awt::Point aEnd(1,1);
2152 // #85920# use 'Geometry' to get the points of the line
2153 // since this slot take anchor pos into account.
2155 // get matrix
2156 ::basegfx::B2DHomMatrix aMatrix;
2157 ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
2159 // decompose and correct about pRefPoint
2160 ::basegfx::B2DTuple aTRScale;
2161 double fTRShear(0.0);
2162 double fTRRotate(0.0);
2163 ::basegfx::B2DTuple aTRTranslate;
2164 ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
2166 // create base position
2167 awt::Point aBasePosition(basegfx::fround(aTRTranslate.getX()),
2168 basegfx::fround(aTRTranslate.getY()));
2170 if (xPropSet->getPropertySetInfo()->hasPropertyByName(u"Geometry"_ustr))
2172 // get the two points
2173 uno::Any aAny(xPropSet->getPropertyValue(u"Geometry"_ustr));
2174 if (auto pSourcePolyPolygon
2175 = o3tl::tryAccess<drawing::PointSequenceSequence>(aAny))
2177 if (pSourcePolyPolygon->getLength() > 0)
2179 const drawing::PointSequence& rInnerSequence = (*pSourcePolyPolygon)[0];
2180 if (rInnerSequence.hasElements())
2182 const awt::Point& rPoint = rInnerSequence[0];
2183 aStart = awt::Point(rPoint.X + aBasePosition.X, rPoint.Y + aBasePosition.Y);
2185 if (rInnerSequence.getLength() > 1)
2187 const awt::Point& rPoint = rInnerSequence[1];
2188 aEnd = awt::Point(rPoint.X + aBasePosition.X, rPoint.Y + aBasePosition.Y);
2194 if( nFeatures & XMLShapeExportFlags::X )
2196 // svg: x1
2197 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2198 aStart.X);
2199 aStr = sStringBuffer.makeStringAndClear();
2200 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
2202 else
2204 aEnd.X -= aStart.X;
2207 if( nFeatures & XMLShapeExportFlags::Y )
2209 // svg: y1
2210 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2211 aStart.Y);
2212 aStr = sStringBuffer.makeStringAndClear();
2213 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
2215 else
2217 aEnd.Y -= aStart.Y;
2220 // svg: x2
2221 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2222 aEnd.X);
2223 aStr = sStringBuffer.makeStringAndClear();
2224 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
2226 // svg: y2
2227 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2228 aEnd.Y);
2229 aStr = sStringBuffer.makeStringAndClear();
2230 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
2232 // write line
2233 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2234 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_LINE, bCreateNewline, true);
2236 ImpExportDescription( xShape ); // #i68101#
2237 ImpExportEvents( xShape );
2238 ImpExportGluePoints( xShape );
2239 ImpExportText( xShape );
2243 void XMLShapeExport::ImpExportEllipseShape(
2244 const uno::Reference< drawing::XShape >& xShape,
2245 XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2247 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2248 if(!xPropSet.is())
2249 return;
2251 // get size to decide between Circle and Ellipse
2252 awt::Size aSize = xShape->getSize();
2253 sal_Int32 nRx((aSize.Width + 1) / 2);
2254 sal_Int32 nRy((aSize.Height + 1) / 2);
2255 bool bCircle(nRx == nRy);
2257 // Transformation
2258 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2260 drawing::CircleKind eKind = drawing::CircleKind_FULL;
2261 xPropSet->getPropertyValue(u"CircleKind"_ustr) >>= eKind;
2262 if( eKind != drawing::CircleKind_FULL )
2264 OUStringBuffer sStringBuffer;
2265 sal_Int32 nStartAngle = 0;
2266 sal_Int32 nEndAngle = 0;
2267 xPropSet->getPropertyValue(u"CircleStartAngle"_ustr) >>= nStartAngle;
2268 xPropSet->getPropertyValue(u"CircleEndAngle"_ustr) >>= nEndAngle;
2270 const double dStartAngle = nStartAngle / 100.0;
2271 const double dEndAngle = nEndAngle / 100.0;
2273 // export circle kind
2274 SvXMLUnitConverter::convertEnum( sStringBuffer, eKind, aXML_CircleKind_EnumMap );
2275 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_KIND, sStringBuffer.makeStringAndClear() );
2277 // export start angle
2278 ::sax::Converter::convertDouble( sStringBuffer, dStartAngle );
2279 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_ANGLE, sStringBuffer.makeStringAndClear() );
2281 // export end angle
2282 ::sax::Converter::convertDouble( sStringBuffer, dEndAngle );
2283 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_ANGLE, sStringBuffer.makeStringAndClear() );
2286 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2288 // write ellipse or circle
2289 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW,
2290 bCircle ? XML_CIRCLE : XML_ELLIPSE,
2291 bCreateNewline, true);
2293 ImpExportDescription( xShape ); // #i68101#
2294 ImpExportEvents( xShape );
2295 ImpExportGluePoints( xShape );
2296 ImpExportText( xShape );
2300 void XMLShapeExport::ImpExportPolygonShape(
2301 const uno::Reference< drawing::XShape >& xShape,
2302 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2304 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2305 if(!xPropSet.is())
2306 return;
2308 bool bBezier(eShapeType == XmlShapeType::DrawClosedBezierShape
2309 || eShapeType == XmlShapeType::DrawOpenBezierShape);
2311 // get matrix
2312 ::basegfx::B2DHomMatrix aMatrix;
2313 ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
2315 // decompose and correct about pRefPoint
2316 ::basegfx::B2DTuple aTRScale;
2317 double fTRShear(0.0);
2318 double fTRRotate(0.0);
2319 ::basegfx::B2DTuple aTRTranslate;
2320 ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
2322 // use features and write
2323 ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures);
2325 // create and export ViewBox
2326 awt::Size aSize(basegfx::fround<tools::Long>(aTRScale.getX()),
2327 basegfx::fround<tools::Long>(aTRScale.getY()));
2328 SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height);
2329 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
2331 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2333 // prepare name (with most used)
2334 enum ::xmloff::token::XMLTokenEnum eName(XML_PATH);
2336 uno::Any aAny( xPropSet->getPropertyValue(u"Geometry"_ustr) );
2337 basegfx::B2DPolyPolygon aPolyPolygon;
2339 // tdf#145240 the Any can contain PolyPolygonBezierCoords or PointSequenceSequence
2340 // (see OWN_ATTR_BASE_GEOMETRY in SvxShapePolyPolygon::getPropertyValueImpl),
2341 // so be more flexible in interpreting it. Try to access bezier first:
2343 auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(aAny);
2345 if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength())
2347 aPolyPolygon = basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(*pSourcePolyPolygon);
2351 // if received no data, try to access point sequence second:
2352 if(0 == aPolyPolygon.count())
2354 auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PointSequenceSequence>(aAny);
2356 if(pSourcePolyPolygon)
2358 aPolyPolygon = basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(*pSourcePolyPolygon);
2362 if(aPolyPolygon.count())
2364 if(!bBezier && !aPolyPolygon.areControlPointsUsed() && 1 == aPolyPolygon.count())
2366 // simple polygon shape, can be written as svg:points sequence
2367 const basegfx::B2DPolygon& aPolygon(aPolyPolygon.getB2DPolygon(0));
2368 const OUString aPointString(basegfx::utils::exportToSvgPoints(aPolygon));
2370 // write point array
2371 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString);
2373 // set name
2374 eName = aPolygon.isClosed() ? XML_POLYGON : XML_POLYLINE;
2376 else
2378 // complex polygon shape, write as svg:d
2379 const OUString aPolygonString(
2380 basegfx::utils::exportToSvgD(
2381 aPolyPolygon,
2382 true, // bUseRelativeCoordinates
2383 false, // bDetectQuadraticBeziers: not used in old, but maybe activated now
2384 true)); // bHandleRelativeNextPointCompatible
2386 // write point array
2387 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
2391 // write object, but after attributes are added since this call will
2392 // consume all of these added attributes and the destructor will close the
2393 // scope. Also before text is added; this may add sub-scopes as needed
2394 SvXMLElementExport aOBJ(
2395 mrExport,
2396 XML_NAMESPACE_DRAW,
2397 eName,
2398 bCreateNewline,
2399 true);
2401 ImpExportDescription( xShape ); // #i68101#
2402 ImpExportEvents( xShape );
2403 ImpExportGluePoints( xShape );
2404 ImpExportText( xShape );
2408 namespace
2411 OUString getNameFromStreamURL(std::u16string_view rURL)
2413 static constexpr std::u16string_view sPackageURL(u"vnd.sun.star.Package:");
2415 OUString sResult;
2417 if (o3tl::starts_with(rURL, sPackageURL))
2419 std::u16string_view sRequestedName = rURL.substr(sPackageURL.size());
2420 size_t nLastIndex = sRequestedName.rfind('/');
2421 if (nLastIndex != std::u16string_view::npos && nLastIndex + 1 < sRequestedName.size())
2422 sRequestedName = sRequestedName.substr(nLastIndex + 1);
2423 nLastIndex = sRequestedName.rfind('.');
2424 if (nLastIndex != std::u16string_view::npos)
2425 sRequestedName = sRequestedName.substr(0, nLastIndex);
2426 if (!sRequestedName.empty())
2427 sResult = sRequestedName;
2430 return sResult;
2433 } // end anonymous namespace
2435 void XMLShapeExport::ImpExportGraphicObjectShape(
2436 const uno::Reference< drawing::XShape >& xShape,
2437 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2439 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2440 if(!xPropSet.is())
2441 return;
2443 bool bIsEmptyPresObj = false;
2445 // Transformation
2446 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2448 if(eShapeType == XmlShapeType::PresGraphicObjectShape)
2449 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_GRAPHIC) );
2451 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2452 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
2453 XML_FRAME, bCreateNewline, true );
2455 if (!bIsEmptyPresObj)
2457 uno::Reference<graphic::XGraphic> xGraphic;
2458 OUString sOutMimeType;
2461 OUString aStreamURL;
2462 xPropSet->getPropertyValue(u"GraphicStreamURL"_ustr) >>= aStreamURL;
2463 OUString sRequestedName = getNameFromStreamURL(aStreamURL);
2465 xPropSet->getPropertyValue(u"Graphic"_ustr) >>= xGraphic;
2467 OUString sInternalURL;
2469 if (xGraphic.is())
2470 sInternalURL = mrExport.AddEmbeddedXGraphic(xGraphic, sOutMimeType, sRequestedName);
2472 if (!sInternalURL.isEmpty())
2474 // apply possible changed stream URL to embedded image object
2475 if (!sRequestedName.isEmpty())
2477 OUString newStreamURL = u"vnd.sun.star.Package:"_ustr;
2478 if (sInternalURL[0] == '#')
2480 newStreamURL += sInternalURL.subView(1, sInternalURL.getLength() - 1);
2482 else
2484 newStreamURL += sInternalURL;
2487 if (newStreamURL != aStreamURL)
2489 xPropSet->setPropertyValue(u"GraphicStreamURL"_ustr, uno::Any(newStreamURL));
2493 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL);
2494 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
2495 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
2496 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
2501 if (GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
2503 if (sOutMimeType.isEmpty())
2505 GetExport().GetGraphicMimeTypeFromStream(xGraphic, sOutMimeType);
2507 if (!sOutMimeType.isEmpty())
2508 { // ODF 1.3 OFFICE-3943
2509 GetExport().AddAttribute(
2510 SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion()
2511 ? XML_NAMESPACE_DRAW
2512 : XML_NAMESPACE_LO_EXT,
2513 u"mime-type"_ustr, sOutMimeType);
2517 SvXMLElementExport aElement(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, true);
2519 // optional office:binary-data
2520 if (xGraphic.is())
2522 mrExport.AddEmbeddedXGraphicAsBase64(xGraphic);
2524 if (!bIsEmptyPresObj)
2525 ImpExportText(xShape);
2528 //Resolves: fdo#62461 put preferred image first above, followed by
2529 //fallback here
2530 if (!bIsEmptyPresObj
2531 && officecfg::Office::Common::Save::Graphic::AddReplacementImages::get())
2533 uno::Reference<graphic::XGraphic> xReplacementGraphic;
2534 xPropSet->getPropertyValue(u"ReplacementGraphic"_ustr) >>= xReplacementGraphic;
2536 // If there is no url, then the graphic is empty
2537 if (xReplacementGraphic.is())
2539 OUString aMimeType;
2540 const OUString aHref = mrExport.AddEmbeddedXGraphic(xReplacementGraphic, aMimeType);
2542 if (aMimeType.isEmpty())
2543 mrExport.GetGraphicMimeTypeFromStream(xReplacementGraphic, aMimeType);
2545 if (!aHref.isEmpty())
2547 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aHref);
2548 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
2549 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
2550 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
2553 if (!aMimeType.isEmpty() && GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
2554 { // ODF 1.3 OFFICE-3943
2555 mrExport.AddAttribute(
2556 SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion()
2557 ? XML_NAMESPACE_DRAW
2558 : XML_NAMESPACE_LO_EXT,
2559 u"mime-type"_ustr, aMimeType);
2562 SvXMLElementExport aElement(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, true);
2564 // optional office:binary-data
2565 mrExport.AddEmbeddedXGraphicAsBase64(xReplacementGraphic);
2570 ImpExportEvents( xShape );
2571 ImpExportGluePoints( xShape );
2573 // image map
2574 GetExport().GetImageMapExport().Export( xPropSet );
2575 ImpExportDescription( xShape ); // #i68101#
2577 // Signature Line, QR Code - needs to be after the images!
2578 if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
2580 ImpExportSignatureLine(xShape);
2581 ImpExportQRCode(xShape);
2585 void XMLShapeExport::ImpExportChartShape(
2586 const uno::Reference< drawing::XShape >& xShape,
2587 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint,
2588 comphelper::AttributeList* pAttrList )
2590 ImpExportOLE2Shape( xShape, eShapeType, nFeatures, pRefPoint, pAttrList );
2593 void XMLShapeExport::ImpExportControlShape(
2594 const uno::Reference< drawing::XShape >& xShape,
2595 XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2597 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2598 if(xPropSet.is())
2600 // Transformation
2601 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2604 uno::Reference< drawing::XControlShape > xControl( xShape, uno::UNO_QUERY );
2605 SAL_WARN_IF( !xControl.is(), "xmloff", "Control shape is not supporting XControlShape" );
2606 if( xControl.is() )
2608 uno::Reference< beans::XPropertySet > xControlModel( xControl->getControl(), uno::UNO_QUERY );
2609 SAL_WARN_IF( !xControlModel.is(), "xmloff", "Control shape has not XControlModel" );
2610 if( xControlModel.is() )
2612 OUString sControlId = mrExport.GetFormExport()->getControlId( xControlModel );
2613 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CONTROL, sControlId );
2617 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2618 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONTROL, bCreateNewline, true);
2620 ImpExportDescription( xShape ); // #i68101#
2623 void XMLShapeExport::ImpExportConnectorShape(
2624 const uno::Reference< drawing::XShape >& xShape,
2625 XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
2627 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
2629 OUString aStr;
2630 OUStringBuffer sStringBuffer;
2632 // export connection kind
2633 drawing::ConnectorType eType = drawing::ConnectorType_STANDARD;
2634 uno::Any aAny = xProps->getPropertyValue(u"EdgeKind"_ustr);
2635 aAny >>= eType;
2637 if( eType != drawing::ConnectorType_STANDARD )
2639 SvXMLUnitConverter::convertEnum( sStringBuffer, eType, aXML_ConnectionKind_EnumMap );
2640 aStr = sStringBuffer.makeStringAndClear();
2641 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TYPE, aStr);
2644 // export line skew
2645 sal_Int32 nDelta1 = 0, nDelta2 = 0, nDelta3 = 0;
2647 aAny = xProps->getPropertyValue(u"EdgeLine1Delta"_ustr);
2648 aAny >>= nDelta1;
2649 aAny = xProps->getPropertyValue(u"EdgeLine2Delta"_ustr);
2650 aAny >>= nDelta2;
2651 aAny = xProps->getPropertyValue(u"EdgeLine3Delta"_ustr);
2652 aAny >>= nDelta3;
2654 if( nDelta1 != 0 || nDelta2 != 0 || nDelta3 != 0 )
2656 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2657 nDelta1);
2658 if( nDelta2 != 0 || nDelta3 != 0 )
2660 sStringBuffer.append( ' ' );
2661 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2662 nDelta2);
2663 if( nDelta3 != 0 )
2665 sStringBuffer.append( ' ' );
2666 mrExport.GetMM100UnitConverter().convertMeasureToXML(
2667 sStringBuffer, nDelta3);
2671 aStr = sStringBuffer.makeStringAndClear();
2672 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_LINE_SKEW, aStr);
2675 // export start and end point
2676 awt::Point aStart(0,0);
2677 awt::Point aEnd(1,1);
2679 /* Get <StartPositionInHoriL2R> and
2680 <EndPositionInHoriL2R>, if they exist and if the document is exported
2681 into the OpenOffice.org file format.
2682 These properties only exist at service css::text::Shape - the
2683 Writer UNO service for shapes.
2684 This code is needed, because the positioning attributes in the
2685 OpenOffice.org file format are given in horizontal left-to-right layout
2686 regardless the layout direction the shape is in. In the OASIS Open Office
2687 file format the positioning attributes are correctly given in the layout
2688 direction the shape is in. Thus, this code provides the conversion from
2689 the OASIS Open Office file format to the OpenOffice.org file format. (#i36248#)
2691 if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
2692 xProps->getPropertySetInfo()->hasPropertyByName(u"StartPositionInHoriL2R"_ustr) &&
2693 xProps->getPropertySetInfo()->hasPropertyByName(u"EndPositionInHoriL2R"_ustr) )
2695 xProps->getPropertyValue(u"StartPositionInHoriL2R"_ustr) >>= aStart;
2696 xProps->getPropertyValue(u"EndPositionInHoriL2R"_ustr) >>= aEnd;
2698 else
2700 xProps->getPropertyValue(u"StartPosition"_ustr) >>= aStart;
2701 xProps->getPropertyValue(u"EndPosition"_ustr) >>= aEnd;
2704 if( pRefPoint )
2706 aStart.X -= pRefPoint->X;
2707 aStart.Y -= pRefPoint->Y;
2708 aEnd.X -= pRefPoint->X;
2709 aEnd.Y -= pRefPoint->Y;
2712 if( nFeatures & XMLShapeExportFlags::X )
2714 // svg: x1
2715 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2716 aStart.X);
2717 aStr = sStringBuffer.makeStringAndClear();
2718 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
2720 else
2722 aEnd.X -= aStart.X;
2725 if( nFeatures & XMLShapeExportFlags::Y )
2727 // svg: y1
2728 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2729 aStart.Y);
2730 aStr = sStringBuffer.makeStringAndClear();
2731 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
2733 else
2735 aEnd.Y -= aStart.Y;
2738 // svg: x2
2739 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.X);
2740 aStr = sStringBuffer.makeStringAndClear();
2741 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
2743 // svg: y2
2744 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.Y);
2745 aStr = sStringBuffer.makeStringAndClear();
2746 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
2748 // #i39320#
2749 uno::Reference< uno::XInterface > xRefS;
2750 uno::Reference< uno::XInterface > xRefE;
2752 // export start connection
2753 xProps->getPropertyValue(u"StartShape"_ustr) >>= xRefS;
2754 if( xRefS.is() )
2756 const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefS );
2757 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_SHAPE, rShapeId);
2759 aAny = xProps->getPropertyValue(u"StartGluePointIndex"_ustr);
2760 sal_Int32 nGluePointId = 0;
2761 if( aAny >>= nGluePointId )
2763 if( nGluePointId != -1 )
2765 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_GLUE_POINT, OUString::number( nGluePointId ));
2770 // export end connection
2771 xProps->getPropertyValue(u"EndShape"_ustr) >>= xRefE;
2772 if( xRefE.is() )
2774 const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefE );
2775 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_SHAPE, rShapeId);
2777 aAny = xProps->getPropertyValue(u"EndGluePointIndex"_ustr);
2778 sal_Int32 nGluePointId = 0;
2779 if( aAny >>= nGluePointId )
2781 if( nGluePointId != -1 )
2783 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_GLUE_POINT, OUString::number( nGluePointId ));
2788 // get PolygonBezier
2789 aAny = xProps->getPropertyValue(u"PolyPolygonBezier"_ustr);
2790 auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(aAny);
2791 if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength())
2793 const basegfx::B2DPolyPolygon aPolyPolygon(
2794 basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(
2795 *pSourcePolyPolygon));
2796 const OUString aPolygonString(
2797 basegfx::utils::exportToSvgD(
2798 aPolyPolygon,
2799 true, // bUseRelativeCoordinates
2800 false, // bDetectQuadraticBeziers: not used in old, but maybe activated now
2801 true)); // bHandleRelativeNextPointCompatible
2803 // write point array
2804 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
2807 // get matrix
2808 ::basegfx::B2DHomMatrix aMatrix;
2809 ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xProps);
2811 // decompose and correct about pRefPoint
2812 ::basegfx::B2DTuple aTRScale;
2813 double fTRShear(0.0);
2814 double fTRRotate(0.0);
2815 ::basegfx::B2DTuple aTRTranslate;
2816 ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear,
2817 fTRRotate, aTRTranslate, pRefPoint);
2819 // fdo#49678: create and export ViewBox
2820 awt::Size aSize(basegfx::fround<tools::Long>(aTRScale.getX()),
2821 basegfx::fround<tools::Long>(aTRScale.getY()));
2822 SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height);
2823 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
2825 // write connector shape. Add Export later.
2826 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2827 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONNECTOR, bCreateNewline, true);
2829 ImpExportDescription( xShape ); // #i68101#
2830 ImpExportEvents( xShape );
2831 ImpExportGluePoints( xShape );
2832 ImpExportText( xShape );
2835 void XMLShapeExport::ImpExportMeasureShape(
2836 const uno::Reference< drawing::XShape >& xShape,
2837 XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point const * pRefPoint /* = NULL */)
2839 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
2841 OUString aStr;
2842 OUStringBuffer sStringBuffer;
2844 // export start and end point
2845 awt::Point aStart(0,0);
2846 awt::Point aEnd(1,1);
2848 /* Get <StartPositionInHoriL2R> and
2849 <EndPositionInHoriL2R>, if they exist and if the document is exported
2850 into the OpenOffice.org file format.
2851 These properties only exist at service css::text::Shape - the
2852 Writer UNO service for shapes.
2853 This code is needed, because the positioning attributes in the
2854 OpenOffice.org file format are given in horizontal left-to-right layout
2855 regardless the layout direction the shape is in. In the OASIS Open Office
2856 file format the positioning attributes are correctly given in the layout
2857 direction the shape is in. Thus, this code provides the conversion from
2858 the OASIS Open Office file format to the OpenOffice.org file format. (#i36248#)
2860 if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
2861 xProps->getPropertySetInfo()->hasPropertyByName(u"StartPositionInHoriL2R"_ustr) &&
2862 xProps->getPropertySetInfo()->hasPropertyByName(u"EndPositionInHoriL2R"_ustr) )
2864 xProps->getPropertyValue(u"StartPositionInHoriL2R"_ustr) >>= aStart;
2865 xProps->getPropertyValue(u"EndPositionInHoriL2R"_ustr) >>= aEnd;
2867 else
2869 xProps->getPropertyValue(u"StartPosition"_ustr) >>= aStart;
2870 xProps->getPropertyValue(u"EndPosition"_ustr) >>= aEnd;
2873 if( pRefPoint )
2875 aStart.X -= pRefPoint->X;
2876 aStart.Y -= pRefPoint->Y;
2877 aEnd.X -= pRefPoint->X;
2878 aEnd.Y -= pRefPoint->Y;
2881 if( nFeatures & XMLShapeExportFlags::X )
2883 // svg: x1
2884 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2885 aStart.X);
2886 aStr = sStringBuffer.makeStringAndClear();
2887 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
2889 else
2891 aEnd.X -= aStart.X;
2894 if( nFeatures & XMLShapeExportFlags::Y )
2896 // svg: y1
2897 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2898 aStart.Y);
2899 aStr = sStringBuffer.makeStringAndClear();
2900 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
2902 else
2904 aEnd.Y -= aStart.Y;
2907 // svg: x2
2908 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.X);
2909 aStr = sStringBuffer.makeStringAndClear();
2910 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
2912 // svg: y2
2913 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.Y);
2914 aStr = sStringBuffer.makeStringAndClear();
2915 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
2917 // write measure shape
2918 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2919 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_MEASURE, bCreateNewline, true);
2921 ImpExportDescription( xShape ); // #i68101#
2922 ImpExportEvents( xShape );
2923 ImpExportGluePoints( xShape );
2925 uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY );
2926 if( xText.is() )
2927 mrExport.GetTextParagraphExport()->exportText( xText );
2930 void XMLShapeExport::ImpExportOLE2Shape(
2931 const uno::Reference< drawing::XShape >& xShape,
2932 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */,
2933 comphelper::AttributeList* pAttrList /* = NULL */ )
2935 uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2936 uno::Reference< container::XNamed > xNamed(xShape, uno::UNO_QUERY);
2938 SAL_WARN_IF( !xPropSet.is() || !xNamed.is(), "xmloff", "ole shape is not implementing needed interfaces");
2939 if(!(xPropSet.is() && xNamed.is()))
2940 return;
2942 // Transformation
2943 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2945 bool bIsEmptyPresObj = false;
2947 // presentation settings
2948 if(eShapeType == XmlShapeType::PresOLE2Shape)
2949 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_OBJECT) );
2950 else if(eShapeType == XmlShapeType::PresChartShape)
2951 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_CHART) );
2952 else if(eShapeType == XmlShapeType::PresSheetShape)
2953 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_TABLE) );
2955 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2956 bool bExportEmbedded(mrExport.getExportFlags() & SvXMLExportFlags::EMBEDDED);
2957 OUString sPersistName;
2958 SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
2959 XML_FRAME, bCreateNewline, true );
2961 if (!bIsEmptyPresObj)
2963 if (pAttrList)
2965 mrExport.AddAttributeList(pAttrList);
2968 OUString sClassId;
2969 OUString sURL;
2970 bool bInternal = false;
2971 xPropSet->getPropertyValue(u"IsInternal"_ustr) >>= bInternal;
2975 if ( bInternal )
2977 // OOo internal links have no storage persistence, URL is stored in the XML file
2978 // the result LinkURL is empty in case the object is not a link
2979 xPropSet->getPropertyValue(u"LinkURL"_ustr) >>= sURL;
2982 xPropSet->getPropertyValue(u"PersistName"_ustr) >>= sPersistName;
2983 if ( sURL.isEmpty() )
2985 if( !sPersistName.isEmpty() )
2987 sURL = "vnd.sun.star.EmbeddedObject:" + sPersistName;
2991 if( !bInternal )
2992 xPropSet->getPropertyValue(u"CLSID"_ustr) >>= sClassId;
2994 if( !sClassId.isEmpty() )
2995 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CLASS_ID, sClassId );
2997 if(!bExportEmbedded)
2999 // xlink:href
3000 if( !sURL.isEmpty() )
3002 // #96717# in theorie, if we don't have a URL we shouldn't even
3003 // export this OLE shape. But practically it's too risky right now
3004 // to change this so we better dispose this on load
3005 sURL = mrExport.AddEmbeddedObject( sURL );
3007 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL );
3008 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3009 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3010 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3012 else
3014 // tdf#153179 Export the preview graphic of the object if the object is missing.
3015 uno::Reference<graphic::XGraphic> xGraphic;
3016 xPropSet->getPropertyValue(u"Graphic"_ustr) >>= xGraphic;
3018 if (xGraphic.is())
3020 OUString aMimeType;
3021 const OUString aHref = mrExport.AddEmbeddedXGraphic(xGraphic, aMimeType);
3023 if (aMimeType.isEmpty())
3024 mrExport.GetGraphicMimeTypeFromStream(xGraphic, aMimeType);
3026 if (!aHref.isEmpty())
3028 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aHref);
3029 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
3030 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
3031 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
3034 if (!aMimeType.isEmpty()
3035 && GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
3036 { // ODF 1.3 OFFICE-3943
3037 mrExport.AddAttribute(SvtSaveOptions::ODFSVER_013
3038 <= GetExport().getSaneDefaultVersion()
3039 ? XML_NAMESPACE_DRAW
3040 : XML_NAMESPACE_LO_EXT,
3041 u"mime-type"_ustr, aMimeType);
3044 SvXMLElementExport aImageElem(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true,
3045 true);
3047 // optional office:binary-data
3048 mrExport.AddEmbeddedXGraphicAsBase64(xGraphic);
3050 ImpExportEvents(xShape);
3051 ImpExportGluePoints(xShape);
3052 ImpExportDescription(xShape);
3054 return;
3060 enum XMLTokenEnum eElem = sClassId.isEmpty() ? XML_OBJECT : XML_OBJECT_OLE ;
3061 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, eElem, true, true );
3063 // tdf#112547 export text as child of draw:object, where import expects it
3064 if (!bIsEmptyPresObj && supportsText(eShapeType))
3066 // #i118485# Add text export, the draw OLE shape allows text now
3067 ImpExportText( xShape, TextPNS::EXTENSION );
3070 if(bExportEmbedded && !bIsEmptyPresObj)
3072 if(bInternal)
3074 // embedded XML
3075 uno::Reference< lang::XComponent > xComp;
3076 xPropSet->getPropertyValue(u"Model"_ustr) >>= xComp;
3077 SAL_WARN_IF( !xComp.is(), "xmloff", "no xModel for own OLE format" );
3078 mrExport.ExportEmbeddedOwnObject( xComp );
3080 else
3082 // embed as Base64
3083 // this is an alien object ( currently MSOLE is the only supported type of such objects )
3084 // in case it is not an OASIS format the object should be asked to store replacement image if possible
3086 OUString sURLRequest( sURL );
3087 if ( !( mrExport.getExportFlags() & SvXMLExportFlags::OASIS ) )
3088 sURLRequest += "?oasis=false";
3089 mrExport.AddEmbeddedObjectAsBase64( sURLRequest );
3093 if( !bIsEmptyPresObj )
3095 OUString sURL = XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE + sPersistName;
3096 if( !bExportEmbedded )
3098 sURL = GetExport().AddEmbeddedObject( sURL );
3099 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL );
3100 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3101 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3102 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3105 SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW,
3106 XML_IMAGE, false, true );
3108 if( bExportEmbedded )
3109 GetExport().AddEmbeddedObjectAsBase64( sURL );
3112 ImpExportEvents( xShape );
3113 ImpExportGluePoints( xShape );
3114 ImpExportDescription( xShape ); // #i68101#
3118 void XMLShapeExport::ImpExportPageShape(
3119 const uno::Reference< drawing::XShape >& xShape,
3120 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
3122 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3123 if(!xPropSet.is())
3124 return;
3126 // #86163# Transformation
3127 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3129 // export page number used for this page
3130 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
3131 static constexpr OUString aPageNumberStr(u"PageNumber"_ustr);
3132 if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(aPageNumberStr))
3134 sal_Int32 nPageNumber = 0;
3135 xPropSet->getPropertyValue(aPageNumberStr) >>= nPageNumber;
3136 if( nPageNumber )
3137 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_PAGE_NUMBER, OUString::number(nPageNumber));
3140 // a presentation page shape, normally used on notes pages only. If
3141 // it is used not as presentation shape, it may have been created with
3142 // copy-paste exchange between draw and impress (this IS possible...)
3143 if(eShapeType == XmlShapeType::PresPageShape)
3145 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS,
3146 XML_PAGE);
3149 // write Page shape
3150 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3151 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PAGE_THUMBNAIL, bCreateNewline, true);
3154 void XMLShapeExport::ImpExportCaptionShape(
3155 const uno::Reference< drawing::XShape >& xShape,
3156 XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
3158 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3159 if(!xPropSet.is())
3160 return;
3162 // Transformation
3163 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3165 // evtl. corner radius?
3166 sal_Int32 nCornerRadius(0);
3167 xPropSet->getPropertyValue(u"CornerRadius"_ustr) >>= nCornerRadius;
3168 if(nCornerRadius)
3170 OUStringBuffer sStringBuffer;
3171 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
3172 nCornerRadius);
3173 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
3176 awt::Point aCaptionPoint;
3177 xPropSet->getPropertyValue(u"CaptionPoint"_ustr) >>= aCaptionPoint;
3179 mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
3180 aCaptionPoint.X);
3181 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_X, msBuffer.makeStringAndClear() );
3182 mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
3183 aCaptionPoint.Y);
3184 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_Y, msBuffer.makeStringAndClear() );
3186 // write Caption shape. Add export later.
3187 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3188 bool bAnnotation( (nFeatures & XMLShapeExportFlags::ANNOTATION) == XMLShapeExportFlags::ANNOTATION );
3190 SvXMLElementExport aObj( mrExport,
3191 (bAnnotation ? XML_NAMESPACE_OFFICE
3192 : XML_NAMESPACE_DRAW),
3193 (bAnnotation ? XML_ANNOTATION : XML_CAPTION),
3194 bCreateNewline, true );
3196 ImpExportDescription( xShape ); // #i68101#
3197 ImpExportEvents( xShape );
3198 ImpExportGluePoints( xShape );
3199 if( bAnnotation )
3200 mrExport.exportAnnotationMeta( xShape );
3201 ImpExportText( xShape );
3205 void XMLShapeExport::ImpExportFrameShape(
3206 const uno::Reference< drawing::XShape >& xShape,
3207 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3209 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3210 if(!xPropSet.is())
3211 return;
3213 // Transformation
3214 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3216 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3217 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
3218 XML_FRAME, bCreateNewline, true );
3220 // export frame url
3221 OUString aStr;
3222 xPropSet->getPropertyValue(u"FrameURL"_ustr) >>= aStr;
3223 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
3224 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3225 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3226 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3228 // export name
3229 xPropSet->getPropertyValue(u"FrameName"_ustr) >>= aStr;
3230 if( !aStr.isEmpty() )
3231 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FRAME_NAME, aStr );
3233 // write floating frame
3235 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_FLOATING_FRAME, true, true);
3238 ImpExportDescription(xShape);
3241 void XMLShapeExport::ImpExportAppletShape(
3242 const uno::Reference< drawing::XShape >& xShape,
3243 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3245 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3246 if(!xPropSet.is())
3247 return;
3249 // Transformation
3250 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3252 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3253 SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
3254 XML_FRAME, bCreateNewline, true );
3256 // export frame url
3257 OUString aStr;
3258 xPropSet->getPropertyValue(u"AppletCodeBase"_ustr) >>= aStr;
3259 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
3260 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3261 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3262 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3264 // export draw:applet-name
3265 xPropSet->getPropertyValue(u"AppletName"_ustr) >>= aStr;
3266 if( !aStr.isEmpty() )
3267 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_APPLET_NAME, aStr );
3269 // export draw:code
3270 xPropSet->getPropertyValue(u"AppletCode"_ustr) >>= aStr;
3271 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CODE, aStr );
3273 // export draw:may-script
3274 bool bIsScript = false;
3275 xPropSet->getPropertyValue(u"AppletIsScript"_ustr) >>= bIsScript;
3276 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MAY_SCRIPT, bIsScript ? XML_TRUE : XML_FALSE );
3279 // write applet
3280 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_APPLET, true, true);
3282 // export parameters
3283 uno::Sequence< beans::PropertyValue > aCommands;
3284 xPropSet->getPropertyValue(u"AppletCommands"_ustr) >>= aCommands;
3285 for (const auto& rCommand : aCommands)
3287 rCommand.Value >>= aStr;
3288 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rCommand.Name );
3289 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr );
3290 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3294 ImpExportDescription(xShape);
3297 void XMLShapeExport::ImpExportPluginShape(
3298 const uno::Reference< drawing::XShape >& xShape,
3299 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3301 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3302 if(!xPropSet.is())
3303 return;
3305 // Transformation
3306 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3308 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3309 SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
3310 XML_FRAME, bCreateNewline, true );
3312 // export plugin url
3313 OUString aStr;
3314 xPropSet->getPropertyValue(u"PluginURL"_ustr) >>= aStr;
3315 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
3316 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3317 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3318 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3320 // export mime-type
3321 xPropSet->getPropertyValue(u"PluginMimeType"_ustr) >>= aStr;
3322 if(!aStr.isEmpty())
3323 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, aStr );
3326 // write plugin
3327 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, true, true);
3329 // export parameters
3330 uno::Sequence< beans::PropertyValue > aCommands;
3331 xPropSet->getPropertyValue(u"PluginCommands"_ustr) >>= aCommands;
3332 for (const auto& rCommand : aCommands)
3334 rCommand.Value >>= aStr;
3335 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rCommand.Name );
3336 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr );
3337 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3341 ImpExportDescription(xShape);
3344 static void lcl_CopyStream(
3345 uno::Reference<io::XInputStream> const& xInStream,
3346 uno::Reference<embed::XStorage> const& xTarget,
3347 OUString const& rPath, const OUString& rMimeType)
3349 ::comphelper::LifecycleProxy proxy;
3350 uno::Reference<io::XStream> const xStream(
3351 ::comphelper::OStorageHelper::GetStreamAtPackageURL(xTarget, rPath,
3352 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE, proxy));
3353 uno::Reference<io::XOutputStream> const xOutStream(
3354 (xStream.is()) ? xStream->getOutputStream() : nullptr);
3355 if (!xOutStream.is())
3357 SAL_WARN("xmloff", "no output stream");
3358 throw uno::Exception(u"no output stream"_ustr,nullptr);
3360 uno::Reference< beans::XPropertySet > const xStreamProps(xStream,
3361 uno::UNO_QUERY);
3362 if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage
3363 xStreamProps->setPropertyValue(u"MediaType"_ustr,
3364 uno::Any(rMimeType));
3365 xStreamProps->setPropertyValue( // turn off compression
3366 u"Compressed"_ustr,
3367 uno::Any(false));
3369 ::comphelper::OStorageHelper::CopyInputToOutput(xInStream, xOutStream);
3370 xOutStream->closeOutput();
3371 proxy.commitStorages();
3374 static OUString
3375 lcl_StoreMediaAndGetURL(SvXMLExport & rExport,
3376 uno::Reference<beans::XPropertySet> const& xPropSet,
3377 OUString const& rURL, const OUString& rMimeType)
3379 OUString urlPath;
3380 if (rURL.startsWithIgnoreAsciiCase("vnd.sun.star.Package:", &urlPath))
3382 try // video is embedded
3384 uno::Reference<embed::XStorage> const xTarget(
3385 rExport.GetTargetStorage(), uno::UNO_SET_THROW);
3386 uno::Reference<io::XInputStream> xInStream;
3387 xPropSet->getPropertyValue(u"PrivateStream"_ustr)
3388 >>= xInStream;
3390 if (!xInStream.is())
3392 SAL_WARN("xmloff", "no input stream");
3393 return OUString();
3396 lcl_CopyStream(xInStream, xTarget, rURL, rMimeType);
3398 return urlPath;
3400 catch (uno::Exception const&)
3402 TOOLS_INFO_EXCEPTION("xmloff", "exception while storing embedded media");
3404 return OUString();
3406 else
3408 return rExport.GetRelativeReference(rURL); // linked
3412 namespace
3414 void ExportGraphicPreview(const uno::Reference<graphic::XGraphic>& xGraphic, SvXMLExport& rExport, std::u16string_view rPrefix, std::u16string_view rExtension, const OUString& rMimeType)
3416 const bool bExportEmbedded(rExport.getExportFlags() & SvXMLExportFlags::EMBEDDED);
3418 if( xGraphic.is() ) try
3420 uno::Reference< uno::XComponentContext > xContext = rExport.getComponentContext();
3422 uno::Reference< embed::XStorage > xPictureStorage;
3423 uno::Reference< embed::XStorage > xStorage;
3424 uno::Reference< io::XStream > xPictureStream;
3426 OUString sPictureName;
3427 if( bExportEmbedded )
3429 xPictureStream.set( xContext->getServiceManager()->createInstanceWithContext( u"com.sun.star.comp.MemoryStream"_ustr, xContext), uno::UNO_QUERY_THROW );
3431 else
3433 xStorage.set( rExport.GetTargetStorage(), uno::UNO_SET_THROW );
3435 xPictureStorage.set( xStorage->openStorageElement( u"Pictures"_ustr , ::embed::ElementModes::READWRITE ), uno::UNO_SET_THROW );
3437 sal_Int32 nIndex = 0;
3440 sPictureName = rPrefix + OUString::number( ++nIndex ) + rExtension;
3442 while( xPictureStorage->hasByName( sPictureName ) );
3444 xPictureStream.set( xPictureStorage->openStreamElement( sPictureName, ::embed::ElementModes::READWRITE ), uno::UNO_SET_THROW );
3447 uno::Reference< graphic::XGraphicProvider > xProvider( graphic::GraphicProvider::create(xContext) );
3448 uno::Sequence< beans::PropertyValue > aArgs{
3449 comphelper::makePropertyValue(u"MimeType"_ustr, rMimeType ),
3450 comphelper::makePropertyValue(u"OutputStream"_ustr, xPictureStream->getOutputStream())
3452 xProvider->storeGraphic( xGraphic, aArgs );
3454 if( xPictureStorage.is() )
3456 uno::Reference< embed::XTransactedObject > xTrans( xPictureStorage, uno::UNO_QUERY );
3457 if( xTrans.is() )
3458 xTrans->commit();
3461 if( !bExportEmbedded )
3463 OUString sURL = "Pictures/" + sPictureName;
3464 rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sURL );
3465 rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3466 rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3467 rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3470 SvXMLElementExport aElem( rExport, XML_NAMESPACE_DRAW, XML_IMAGE, false, true );
3472 if( bExportEmbedded )
3474 uno::Reference< io::XSeekableInputStream > xSeekable( xPictureStream, uno::UNO_QUERY_THROW );
3475 xSeekable->seek(0);
3477 XMLBase64Export aBase64Exp( rExport );
3478 aBase64Exp.exportOfficeBinaryDataElement( uno::Reference < io::XInputStream >( xPictureStream, uno::UNO_QUERY_THROW ) );
3481 catch( uno::Exception const & )
3483 DBG_UNHANDLED_EXCEPTION("xmloff.draw");
3488 void XMLShapeExport::ImpExportMediaShape(
3489 const uno::Reference< drawing::XShape >& xShape,
3490 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3492 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3493 if(!xPropSet.is())
3494 return;
3496 // Transformation
3497 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3499 if(eShapeType == XmlShapeType::PresMediaShape)
3501 (void)ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_OBJECT) );
3503 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3504 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
3505 XML_FRAME, bCreateNewline, true );
3507 // export media url
3508 OUString aMediaURL;
3509 xPropSet->getPropertyValue(u"MediaURL"_ustr) >>= aMediaURL;
3510 OUString sMimeType;
3511 xPropSet->getPropertyValue(u"MediaMimeType"_ustr) >>= sMimeType;
3513 OUString const persistentURL =
3514 lcl_StoreMediaAndGetURL(GetExport(), xPropSet, aMediaURL, sMimeType);
3516 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, persistentURL );
3517 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3518 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3519 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3521 // export mime-type
3522 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, sMimeType );
3524 // write plugin
3525 auto pPluginOBJ = std::make_unique<SvXMLElementExport>(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, !( nFeatures & XMLShapeExportFlags::NO_WS ), true);
3527 // export parameters
3528 static constexpr OUString aFalseStr( u"false"_ustr );
3529 static constexpr OUString aTrueStr( u"true"_ustr );
3531 bool bLoop = false;
3532 static constexpr OUString aLoopStr( u"Loop"_ustr );
3533 xPropSet->getPropertyValue( aLoopStr ) >>= bLoop;
3534 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aLoopStr );
3535 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, bLoop ? aTrueStr : aFalseStr );
3536 delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3538 bool bMute = false;
3539 static constexpr OUString aMuteStr( u"Mute"_ustr );
3540 xPropSet->getPropertyValue( aMuteStr ) >>= bMute;
3541 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aMuteStr );
3542 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, bMute ? aTrueStr : aFalseStr );
3543 delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3545 sal_Int16 nVolumeDB = 0;
3546 xPropSet->getPropertyValue(u"VolumeDB"_ustr) >>= nVolumeDB;
3547 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, u"VolumeDB"_ustr );
3548 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, OUString::number( nVolumeDB ) );
3549 delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3551 media::ZoomLevel eZoom;
3552 OUString aZoomValue;
3553 xPropSet->getPropertyValue(u"Zoom"_ustr) >>= eZoom;
3554 switch( eZoom )
3556 case media::ZoomLevel_ZOOM_1_TO_4 : aZoomValue = "25%"; break;
3557 case media::ZoomLevel_ZOOM_1_TO_2 : aZoomValue = "50%"; break;
3558 case media::ZoomLevel_ORIGINAL : aZoomValue = "100%"; break;
3559 case media::ZoomLevel_ZOOM_2_TO_1 : aZoomValue = "200%"; break;
3560 case media::ZoomLevel_ZOOM_4_TO_1 : aZoomValue = "400%"; break;
3561 case media::ZoomLevel_FIT_TO_WINDOW: aZoomValue = "fit"; break;
3562 case media::ZoomLevel_FIT_TO_WINDOW_FIXED_ASPECT: aZoomValue = "fixedfit"; break;
3563 case media::ZoomLevel_FULLSCREEN : aZoomValue = "fullscreen"; break;
3565 default:
3566 break;
3569 if( !aZoomValue.isEmpty() )
3571 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, u"Zoom"_ustr );
3572 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aZoomValue );
3573 delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3576 pPluginOBJ.reset();
3578 if (officecfg::Office::Common::Save::Graphic::AddReplacementImages::get())
3580 uno::Reference<graphic::XGraphic> xGraphic;
3581 xPropSet->getPropertyValue(u"Graphic"_ustr) >>= xGraphic;
3582 Graphic aGraphic(xGraphic);
3583 if (!aGraphic.IsNone())
3585 // The media has a preview, export it.
3586 ExportGraphicPreview(xGraphic, mrExport, u"MediaPreview", u".png", u"image/png"_ustr);
3590 ImpExportDescription(xShape);
3593 void XMLShapeExport::ImpExport3DSceneShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
3595 uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY);
3596 if(!(xShapes.is() && xShapes->getCount()))
3597 return;
3599 uno::Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
3600 SAL_WARN_IF( !xPropSet.is(), "xmloff", "XMLShapeExport::ImpExport3DSceneShape can't export a scene without a propertyset" );
3601 if( !xPropSet.is() )
3602 return;
3604 // Transformation
3605 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3607 // 3d attributes
3608 export3DSceneAttributes( xPropSet );
3610 // write 3DScene shape
3611 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3612 SvXMLElementExport aOBJ( mrExport, XML_NAMESPACE_DR3D, XML_SCENE, bCreateNewline, true);
3614 ImpExportDescription( xShape ); // #i68101#
3615 ImpExportEvents( xShape );
3617 // write 3DSceneLights
3618 export3DLamps( xPropSet );
3620 // #89764# if export of position is suppressed for group shape,
3621 // positions of contained objects should be written relative to
3622 // the upper left edge of the group.
3623 awt::Point aUpperLeft;
3625 if(!(nFeatures & XMLShapeExportFlags::POSITION))
3627 nFeatures |= XMLShapeExportFlags::POSITION;
3628 aUpperLeft = xShape->getPosition();
3629 pRefPoint = &aUpperLeft;
3632 // write members
3633 exportShapes( xShapes, nFeatures, pRefPoint );
3636 void XMLShapeExport::ImpExport3DShape(
3637 const uno::Reference< drawing::XShape >& xShape,
3638 XmlShapeType eShapeType)
3640 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3641 if(!xPropSet.is())
3642 return;
3644 OUString aStr;
3645 OUStringBuffer sStringBuffer;
3647 // transformation (UNO_NAME_3D_TRANSFORM_MATRIX == "D3DTransformMatrix")
3648 uno::Any aAny = xPropSet->getPropertyValue(u"D3DTransformMatrix"_ustr);
3649 drawing::HomogenMatrix aHomMat;
3650 aAny >>= aHomMat;
3651 SdXMLImExTransform3D aTransform;
3652 aTransform.AddHomogenMatrix(aHomMat);
3653 if(aTransform.NeedsAction())
3654 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
3656 switch(eShapeType)
3658 case XmlShapeType::Draw3DCubeObject:
3660 // minEdge
3661 aAny = xPropSet->getPropertyValue(u"D3DPosition"_ustr);
3662 drawing::Position3D aPosition3D;
3663 aAny >>= aPosition3D;
3664 ::basegfx::B3DVector aPos3D(aPosition3D.PositionX, aPosition3D.PositionY, aPosition3D.PositionZ);
3666 // maxEdge
3667 aAny = xPropSet->getPropertyValue(u"D3DSize"_ustr);
3668 drawing::Direction3D aDirection3D;
3669 aAny >>= aDirection3D;
3670 ::basegfx::B3DVector aDir3D(aDirection3D.DirectionX, aDirection3D.DirectionY, aDirection3D.DirectionZ);
3672 // transform maxEdge from distance to pos
3673 aDir3D = aPos3D + aDir3D;
3675 // write minEdge
3676 if(aPos3D != ::basegfx::B3DVector(-2500.0, -2500.0, -2500.0)) // write only when not default
3678 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aPos3D);
3679 aStr = sStringBuffer.makeStringAndClear();
3680 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_MIN_EDGE, aStr);
3683 // write maxEdge
3684 if(aDir3D != ::basegfx::B3DVector(2500.0, 2500.0, 2500.0)) // write only when not default
3686 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aDir3D);
3687 aStr = sStringBuffer.makeStringAndClear();
3688 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_MAX_EDGE, aStr);
3691 // write 3DCube shape
3692 // #i123542# Do this *after* the attributes are added, else these will be lost since opening
3693 // the scope will clear the global attribute list at the exporter
3694 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_CUBE, true, true);
3696 break;
3698 case XmlShapeType::Draw3DSphereObject:
3700 // Center
3701 aAny = xPropSet->getPropertyValue(u"D3DPosition"_ustr);
3702 drawing::Position3D aPosition3D;
3703 aAny >>= aPosition3D;
3704 ::basegfx::B3DVector aPos3D(aPosition3D.PositionX, aPosition3D.PositionY, aPosition3D.PositionZ);
3706 // Size
3707 aAny = xPropSet->getPropertyValue(u"D3DSize"_ustr);
3708 drawing::Direction3D aDirection3D;
3709 aAny >>= aDirection3D;
3710 ::basegfx::B3DVector aDir3D(aDirection3D.DirectionX, aDirection3D.DirectionY, aDirection3D.DirectionZ);
3712 // write Center
3713 if(aPos3D != ::basegfx::B3DVector(0.0, 0.0, 0.0)) // write only when not default
3715 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aPos3D);
3716 aStr = sStringBuffer.makeStringAndClear();
3717 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_CENTER, aStr);
3720 // write Size
3721 if(aDir3D != ::basegfx::B3DVector(5000.0, 5000.0, 5000.0)) // write only when not default
3723 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aDir3D);
3724 aStr = sStringBuffer.makeStringAndClear();
3725 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SIZE, aStr);
3728 // write 3DSphere shape
3729 // #i123542# Do this *after* the attributes are added, else these will be lost since opening
3730 // the scope will clear the global attribute list at the exporter
3731 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_SPHERE, true, true);
3733 break;
3735 case XmlShapeType::Draw3DLatheObject:
3736 case XmlShapeType::Draw3DExtrudeObject:
3738 // write special 3DLathe/3DExtrude attributes, get 3D tools::PolyPolygon as drawing::PolyPolygonShape3D
3739 aAny = xPropSet->getPropertyValue(u"D3DPolyPolygon3D"_ustr);
3740 drawing::PolyPolygonShape3D aUnoPolyPolygon3D;
3741 aAny >>= aUnoPolyPolygon3D;
3743 // convert to 3D PolyPolygon
3744 const basegfx::B3DPolyPolygon aPolyPolygon3D(
3745 basegfx::utils::UnoPolyPolygonShape3DToB3DPolyPolygon(
3746 aUnoPolyPolygon3D));
3748 // convert to 2D tools::PolyPolygon using identity 3D transformation (just grep X and Y)
3749 const basegfx::B3DHomMatrix aB3DHomMatrixFor2DConversion;
3750 const basegfx::B2DPolyPolygon aPolyPolygon(
3751 basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(
3752 aPolyPolygon3D,
3753 aB3DHomMatrixFor2DConversion));
3755 // get 2D range of it
3756 const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange());
3758 // export ViewBox
3759 SdXMLImExViewBox aViewBox(
3760 aPolyPolygonRange.getMinX(),
3761 aPolyPolygonRange.getMinY(),
3762 aPolyPolygonRange.getWidth(),
3763 aPolyPolygonRange.getHeight());
3765 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
3767 // prepare svg:d string
3768 const OUString aPolygonString(
3769 basegfx::utils::exportToSvgD(
3770 aPolyPolygon,
3771 true, // bUseRelativeCoordinates
3772 false, // bDetectQuadraticBeziers TTTT: not used in old, but maybe activated now
3773 true)); // bHandleRelativeNextPointCompatible
3775 // write point array
3776 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
3778 if(eShapeType == XmlShapeType::Draw3DLatheObject)
3780 // write 3DLathe shape
3781 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_ROTATE, true, true);
3783 else
3785 // write 3DExtrude shape
3786 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_EXTRUDE, true, true);
3788 break;
3790 default:
3791 break;
3795 /** helper for chart that adds all attributes of a 3d scene element to the export */
3796 void XMLShapeExport::export3DSceneAttributes( const css::uno::Reference< css::beans::XPropertySet >& xPropSet )
3798 OUString aStr;
3799 OUStringBuffer sStringBuffer;
3801 // world transformation (UNO_NAME_3D_TRANSFORM_MATRIX == "D3DTransformMatrix")
3802 uno::Any aAny = xPropSet->getPropertyValue(u"D3DTransformMatrix"_ustr);
3803 drawing::HomogenMatrix aHomMat;
3804 aAny >>= aHomMat;
3805 SdXMLImExTransform3D aTransform;
3806 aTransform.AddHomogenMatrix(aHomMat);
3807 if(aTransform.NeedsAction())
3808 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
3810 // VRP, VPN, VUP
3811 aAny = xPropSet->getPropertyValue(u"D3DCameraGeometry"_ustr);
3812 drawing::CameraGeometry aCamGeo;
3813 aAny >>= aCamGeo;
3815 ::basegfx::B3DVector aVRP(aCamGeo.vrp.PositionX, aCamGeo.vrp.PositionY, aCamGeo.vrp.PositionZ);
3816 if(aVRP != ::basegfx::B3DVector(0.0, 0.0, 1.0)) // write only when not default
3818 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVRP);
3819 aStr = sStringBuffer.makeStringAndClear();
3820 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VRP, aStr);
3823 ::basegfx::B3DVector aVPN(aCamGeo.vpn.DirectionX, aCamGeo.vpn.DirectionY, aCamGeo.vpn.DirectionZ);
3824 if(aVPN != ::basegfx::B3DVector(0.0, 0.0, 1.0)) // write only when not default
3826 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVPN);
3827 aStr = sStringBuffer.makeStringAndClear();
3828 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VPN, aStr);
3831 ::basegfx::B3DVector aVUP(aCamGeo.vup.DirectionX, aCamGeo.vup.DirectionY, aCamGeo.vup.DirectionZ);
3832 if(aVUP != ::basegfx::B3DVector(0.0, 1.0, 0.0)) // write only when not default
3834 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVUP);
3835 aStr = sStringBuffer.makeStringAndClear();
3836 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VUP, aStr);
3839 // projection "D3DScenePerspective" drawing::ProjectionMode
3840 aAny = xPropSet->getPropertyValue(u"D3DScenePerspective"_ustr);
3841 drawing::ProjectionMode aPrjMode;
3842 aAny >>= aPrjMode;
3843 if(aPrjMode == drawing::ProjectionMode_PARALLEL)
3844 aStr = GetXMLToken(XML_PARALLEL);
3845 else
3846 aStr = GetXMLToken(XML_PERSPECTIVE);
3847 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_PROJECTION, aStr);
3849 // distance
3850 aAny = xPropSet->getPropertyValue(u"D3DSceneDistance"_ustr);
3851 sal_Int32 nDistance = 0;
3852 aAny >>= nDistance;
3853 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
3854 nDistance);
3855 aStr = sStringBuffer.makeStringAndClear();
3856 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DISTANCE, aStr);
3858 // focalLength
3859 aAny = xPropSet->getPropertyValue(u"D3DSceneFocalLength"_ustr);
3860 sal_Int32 nFocalLength = 0;
3861 aAny >>= nFocalLength;
3862 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
3863 nFocalLength);
3864 aStr = sStringBuffer.makeStringAndClear();
3865 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_FOCAL_LENGTH, aStr);
3867 // shadowSlant
3868 aAny = xPropSet->getPropertyValue(u"D3DSceneShadowSlant"_ustr);
3869 sal_Int16 nShadowSlant = 0;
3870 aAny >>= nShadowSlant;
3871 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SHADOW_SLANT, OUString::number(static_cast<sal_Int32>(nShadowSlant)));
3873 // shadeMode
3874 aAny = xPropSet->getPropertyValue(u"D3DSceneShadeMode"_ustr);
3875 drawing::ShadeMode aShadeMode;
3876 if(aAny >>= aShadeMode)
3878 if(aShadeMode == drawing::ShadeMode_FLAT)
3879 aStr = GetXMLToken(XML_FLAT);
3880 else if(aShadeMode == drawing::ShadeMode_PHONG)
3881 aStr = GetXMLToken(XML_PHONG);
3882 else if(aShadeMode == drawing::ShadeMode_SMOOTH)
3883 aStr = GetXMLToken(XML_GOURAUD);
3884 else
3885 aStr = GetXMLToken(XML_DRAFT);
3887 else
3889 // ShadeMode enum not there, write default
3890 aStr = GetXMLToken(XML_GOURAUD);
3892 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SHADE_MODE, aStr);
3894 // ambientColor
3895 aAny = xPropSet->getPropertyValue(u"D3DSceneAmbientColor"_ustr);
3896 sal_Int32 nAmbientColor = 0;
3897 aAny >>= nAmbientColor;
3898 ::sax::Converter::convertColor(sStringBuffer, nAmbientColor);
3899 aStr = sStringBuffer.makeStringAndClear();
3900 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_AMBIENT_COLOR, aStr);
3902 // lightingMode
3903 aAny = xPropSet->getPropertyValue(u"D3DSceneTwoSidedLighting"_ustr);
3904 bool bTwoSidedLighting = false;
3905 aAny >>= bTwoSidedLighting;
3906 ::sax::Converter::convertBool(sStringBuffer, bTwoSidedLighting);
3907 aStr = sStringBuffer.makeStringAndClear();
3908 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_LIGHTING_MODE, aStr);
3911 /** helper for chart that exports all lamps from the propertyset */
3912 void XMLShapeExport::export3DLamps( const css::uno::Reference< css::beans::XPropertySet >& xPropSet )
3914 // write lamps 1..8 as content
3915 OUString aStr;
3916 OUStringBuffer sStringBuffer;
3918 static constexpr OUStringLiteral aColorPropName(u"D3DSceneLightColor");
3919 static constexpr OUStringLiteral aDirectionPropName(u"D3DSceneLightDirection");
3920 static constexpr OUStringLiteral aLightOnPropName(u"D3DSceneLightOn");
3922 ::basegfx::B3DVector aLightDirection;
3923 drawing::Direction3D aLightDir;
3924 bool bLightOnOff = false;
3925 for(sal_Int32 nLamp = 1; nLamp <= 8; nLamp++)
3927 OUString aIndexStr = OUString::number( nLamp );
3929 // lightcolor
3930 OUString aPropName = aColorPropName + aIndexStr;
3931 sal_Int32 nLightColor = 0;
3932 xPropSet->getPropertyValue( aPropName ) >>= nLightColor;
3933 ::sax::Converter::convertColor(sStringBuffer, nLightColor);
3934 aStr = sStringBuffer.makeStringAndClear();
3935 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DIFFUSE_COLOR, aStr);
3937 // lightdirection
3938 aPropName = aDirectionPropName + aIndexStr;
3939 xPropSet->getPropertyValue(aPropName) >>= aLightDir;
3940 aLightDirection = ::basegfx::B3DVector(aLightDir.DirectionX, aLightDir.DirectionY, aLightDir.DirectionZ);
3941 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aLightDirection);
3942 aStr = sStringBuffer.makeStringAndClear();
3943 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DIRECTION, aStr);
3945 // lighton
3946 aPropName = aLightOnPropName + aIndexStr;
3947 xPropSet->getPropertyValue(aPropName) >>= bLightOnOff;
3948 ::sax::Converter::convertBool(sStringBuffer, bLightOnOff);
3949 aStr = sStringBuffer.makeStringAndClear();
3950 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_ENABLED, aStr);
3952 // specular
3953 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SPECULAR,
3954 nLamp == 1 ? XML_TRUE : XML_FALSE);
3956 // write light entry
3957 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_LIGHT, true, true);
3962 // using namespace css::io;
3963 // using namespace ::xmloff::EnhancedCustomShapeToken;
3966 static void ExportParameter( OUStringBuffer& rStrBuffer, const css::drawing::EnhancedCustomShapeParameter& rParameter )
3968 if ( !rStrBuffer.isEmpty() )
3969 rStrBuffer.append( ' ' );
3970 if ( rParameter.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
3972 double fNumber = 0.0;
3973 rParameter.Value >>= fNumber;
3974 ::rtl::math::doubleToUStringBuffer( rStrBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true );
3976 else
3978 sal_Int32 nValue = 0;
3979 rParameter.Value >>= nValue;
3981 switch( rParameter.Type )
3983 case css::drawing::EnhancedCustomShapeParameterType::EQUATION :
3985 rStrBuffer.append( "?f" + OUString::number( nValue ) );
3987 break;
3989 case css::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT :
3991 rStrBuffer.append( '$' );
3992 rStrBuffer.append( nValue );
3994 break;
3996 case css::drawing::EnhancedCustomShapeParameterType::BOTTOM :
3997 rStrBuffer.append( GetXMLToken( XML_BOTTOM ) ); break;
3998 case css::drawing::EnhancedCustomShapeParameterType::RIGHT :
3999 rStrBuffer.append( GetXMLToken( XML_RIGHT ) ); break;
4000 case css::drawing::EnhancedCustomShapeParameterType::TOP :
4001 rStrBuffer.append( GetXMLToken( XML_TOP ) ); break;
4002 case css::drawing::EnhancedCustomShapeParameterType::LEFT :
4003 rStrBuffer.append( GetXMLToken( XML_LEFT ) ); break;
4004 case css::drawing::EnhancedCustomShapeParameterType::XSTRETCH :
4005 rStrBuffer.append( GetXMLToken( XML_XSTRETCH ) ); break;
4006 case css::drawing::EnhancedCustomShapeParameterType::YSTRETCH :
4007 rStrBuffer.append( GetXMLToken( XML_YSTRETCH ) ); break;
4008 case css::drawing::EnhancedCustomShapeParameterType::HASSTROKE :
4009 rStrBuffer.append( GetXMLToken( XML_HASSTROKE ) ); break;
4010 case css::drawing::EnhancedCustomShapeParameterType::HASFILL :
4011 rStrBuffer.append( GetXMLToken( XML_HASFILL ) ); break;
4012 case css::drawing::EnhancedCustomShapeParameterType::WIDTH :
4013 rStrBuffer.append( GetXMLToken( XML_WIDTH ) ); break;
4014 case css::drawing::EnhancedCustomShapeParameterType::HEIGHT :
4015 rStrBuffer.append( GetXMLToken( XML_HEIGHT ) ); break;
4016 case css::drawing::EnhancedCustomShapeParameterType::LOGWIDTH :
4017 rStrBuffer.append( GetXMLToken( XML_LOGWIDTH ) ); break;
4018 case css::drawing::EnhancedCustomShapeParameterType::LOGHEIGHT :
4019 rStrBuffer.append( GetXMLToken( XML_LOGHEIGHT ) ); break;
4020 default :
4021 rStrBuffer.append( nValue );
4026 static void ImpExportEquations( SvXMLExport& rExport, const uno::Sequence< OUString >& rEquations )
4028 sal_Int32 i;
4029 for ( i = 0; i < rEquations.getLength(); i++ )
4031 OUString aStr= "f" + OUString::number( i );
4032 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aStr );
4034 aStr = rEquations[ i ];
4035 sal_Int32 nIndex = 0;
4038 nIndex = aStr.indexOf( '?', nIndex );
4039 if ( nIndex != -1 )
4041 aStr = OUString::Concat(aStr.subView(0, nIndex + 1)) + "f"
4042 + aStr.subView(nIndex + 1, aStr.getLength() - nIndex - 1);
4043 nIndex++;
4045 } while( nIndex != -1 );
4046 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FORMULA, aStr );
4047 SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_EQUATION, true, true );
4051 static void ImpExportHandles( SvXMLExport& rExport, const uno::Sequence< beans::PropertyValues >& rHandles )
4053 if ( !rHandles.hasElements() )
4054 return;
4056 OUString aStr;
4057 OUStringBuffer aStrBuffer;
4059 for ( const uno::Sequence< beans::PropertyValue >& rPropSeq : rHandles )
4061 bool bPosition = false;
4062 for ( const beans::PropertyValue& rPropVal : rPropSeq )
4064 switch( EASGet( rPropVal.Name ) )
4066 case EAS_Position :
4068 css::drawing::EnhancedCustomShapeParameterPair aPosition;
4069 if ( rPropVal.Value >>= aPosition )
4071 ExportParameter( aStrBuffer, aPosition.First );
4072 ExportParameter( aStrBuffer, aPosition.Second );
4073 aStr = aStrBuffer.makeStringAndClear();
4075 // Keep it for backward compatibility
4076 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POSITION, aStr );
4078 SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion();
4079 if (eVersion >= SvtSaveOptions::ODFSVER_014)
4081 comphelper::SequenceAsHashMap aPropSeqMap(rPropSeq);
4082 if (aPropSeqMap.contains(u"Polar"_ustr))
4084 ExportParameter( aStrBuffer, aPosition.First );
4085 aStr = aStrBuffer.makeStringAndClear();
4086 rExport.AddAttribute(XML_NAMESPACE_DRAW, XML_HANDLE_POLAR_RADIUS, aStr);
4088 ExportParameter( aStrBuffer, aPosition.Second );
4089 aStr = aStrBuffer.makeStringAndClear();
4090 rExport.AddAttribute(XML_NAMESPACE_DRAW, XML_HANDLE_POLAR_ANGLE, aStr);
4092 else
4094 ExportParameter( aStrBuffer, aPosition.First );
4095 aStr = aStrBuffer.makeStringAndClear();
4096 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POSITION_X, aStr );
4098 ExportParameter( aStrBuffer, aPosition.Second );
4099 aStr = aStrBuffer.makeStringAndClear();
4100 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POSITION_Y, aStr );
4104 bPosition = true;
4107 break;
4108 case EAS_MirroredX :
4110 bool bMirroredX;
4111 if ( rPropVal.Value >>= bMirroredX )
4112 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_MIRROR_HORIZONTAL,
4113 bMirroredX ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4115 break;
4116 case EAS_MirroredY :
4118 bool bMirroredY;
4119 if ( rPropVal.Value >>= bMirroredY )
4120 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_MIRROR_VERTICAL,
4121 bMirroredY ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4123 break;
4124 case EAS_Switched :
4126 bool bSwitched;
4127 if ( rPropVal.Value >>= bSwitched )
4128 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_SWITCHED,
4129 bSwitched ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4131 break;
4132 case EAS_Polar :
4134 css::drawing::EnhancedCustomShapeParameterPair aPolar;
4135 if ( rPropVal.Value >>= aPolar )
4137 ExportParameter( aStrBuffer, aPolar.First );
4138 ExportParameter( aStrBuffer, aPolar.Second );
4139 aStr = aStrBuffer.makeStringAndClear();
4140 // Keep it for backward compatibility
4141 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POLAR, aStr );
4143 SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion();
4144 if (eVersion >= SvtSaveOptions::ODFSVER_014)
4146 ExportParameter( aStrBuffer, aPolar.First );
4147 aStr = aStrBuffer.makeStringAndClear();
4148 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POLAR_POLE_X, aStr );
4150 ExportParameter( aStrBuffer, aPolar.Second );
4151 aStr = aStrBuffer.makeStringAndClear();
4152 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POLAR_POLE_Y, aStr );
4156 break;
4157 case EAS_RadiusRangeMinimum :
4159 css::drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum;
4160 if ( rPropVal.Value >>= aRadiusRangeMinimum )
4162 ExportParameter( aStrBuffer, aRadiusRangeMinimum );
4163 aStr = aStrBuffer.makeStringAndClear();
4164 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RADIUS_RANGE_MINIMUM, aStr );
4167 break;
4168 case EAS_RadiusRangeMaximum :
4170 css::drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum;
4171 if ( rPropVal.Value >>= aRadiusRangeMaximum )
4173 ExportParameter( aStrBuffer, aRadiusRangeMaximum );
4174 aStr = aStrBuffer.makeStringAndClear();
4175 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RADIUS_RANGE_MAXIMUM, aStr );
4178 break;
4179 case EAS_RangeXMinimum :
4181 css::drawing::EnhancedCustomShapeParameter aXRangeMinimum;
4182 if ( rPropVal.Value >>= aXRangeMinimum )
4184 ExportParameter( aStrBuffer, aXRangeMinimum );
4185 aStr = aStrBuffer.makeStringAndClear();
4186 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_X_MINIMUM, aStr );
4189 break;
4190 case EAS_RangeXMaximum :
4192 css::drawing::EnhancedCustomShapeParameter aXRangeMaximum;
4193 if ( rPropVal.Value >>= aXRangeMaximum )
4195 ExportParameter( aStrBuffer, aXRangeMaximum );
4196 aStr = aStrBuffer.makeStringAndClear();
4197 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_X_MAXIMUM, aStr );
4200 break;
4201 case EAS_RangeYMinimum :
4203 css::drawing::EnhancedCustomShapeParameter aYRangeMinimum;
4204 if ( rPropVal.Value >>= aYRangeMinimum )
4206 ExportParameter( aStrBuffer, aYRangeMinimum );
4207 aStr = aStrBuffer.makeStringAndClear();
4208 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_Y_MINIMUM, aStr );
4211 break;
4212 case EAS_RangeYMaximum :
4214 css::drawing::EnhancedCustomShapeParameter aYRangeMaximum;
4215 if ( rPropVal.Value >>= aYRangeMaximum )
4217 ExportParameter( aStrBuffer, aYRangeMaximum );
4218 aStr = aStrBuffer.makeStringAndClear();
4219 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_Y_MAXIMUM, aStr );
4222 break;
4223 default:
4224 break;
4227 if ( bPosition )
4228 SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_HANDLE, true, true );
4229 else
4230 rExport.ClearAttrList();
4234 static void ImpExportEnhancedPath( SvXMLExport& rExport,
4235 const uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair >& rCoordinates,
4236 const uno::Sequence< css::drawing::EnhancedCustomShapeSegment >& rSegments,
4237 bool bExtended = false )
4240 OUString aStr;
4241 OUStringBuffer aStrBuffer;
4242 bool bNeedExtended = false;
4244 sal_Int32 i, j, k, l;
4246 sal_Int32 nCoords = rCoordinates.getLength();
4247 sal_Int32 nSegments = rSegments.getLength();
4248 bool bSimpleSegments = nSegments == 0;
4249 if ( bSimpleSegments )
4250 nSegments = 4;
4251 for ( j = i = 0; j < nSegments; j++ )
4253 css::drawing::EnhancedCustomShapeSegment aSegment;
4254 if ( bSimpleSegments )
4256 // if there are not enough segments we will default them
4257 switch( j )
4259 case 0 :
4261 aSegment.Count = 1;
4262 aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO;
4264 break;
4265 case 1 :
4267 aSegment.Count = static_cast<sal_Int16>(std::min( nCoords - 1, sal_Int32(32767) ));
4268 aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO;
4270 break;
4271 case 2 :
4273 aSegment.Count = 1;
4274 aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH;
4276 break;
4277 case 3 :
4279 aSegment.Count = 1;
4280 aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
4282 break;
4285 else
4286 aSegment = rSegments[ j ];
4288 if ( !aStrBuffer.isEmpty() )
4289 aStrBuffer.append( ' ' );
4291 sal_Int32 nParameter = 0;
4292 switch( aSegment.Command )
4294 case css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH :
4295 aStrBuffer.append( 'Z' ); break;
4296 case css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH :
4297 aStrBuffer.append( 'N' ); break;
4298 case css::drawing::EnhancedCustomShapeSegmentCommand::NOFILL :
4299 aStrBuffer.append( 'F' ); break;
4300 case css::drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE :
4301 aStrBuffer.append( 'S' ); break;
4303 case css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO :
4304 aStrBuffer.append( 'M' ); nParameter = 1; break;
4305 case css::drawing::EnhancedCustomShapeSegmentCommand::LINETO :
4306 aStrBuffer.append( 'L' ); nParameter = 1; break;
4307 case css::drawing::EnhancedCustomShapeSegmentCommand::CURVETO :
4308 aStrBuffer.append( 'C' ); nParameter = 3; break;
4309 case css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO :
4310 aStrBuffer.append( 'T' ); nParameter = 3; break;
4311 case css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE :
4312 aStrBuffer.append( 'U' ); nParameter = 3; break;
4313 case css::drawing::EnhancedCustomShapeSegmentCommand::ARCTO :
4314 aStrBuffer.append( 'A' ); nParameter = 4; break;
4315 case css::drawing::EnhancedCustomShapeSegmentCommand::ARC :
4316 aStrBuffer.append( 'B' ); nParameter = 4; break;
4317 case css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO :
4318 aStrBuffer.append( 'W' ); nParameter = 4; break;
4319 case css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC :
4320 aStrBuffer.append( 'V' ); nParameter = 4; break;
4321 case css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX :
4322 aStrBuffer.append( 'X' ); nParameter = 1; break;
4323 case css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY :
4324 aStrBuffer.append( 'Y' ); nParameter = 1; break;
4325 case css::drawing::EnhancedCustomShapeSegmentCommand::QUADRATICCURVETO :
4326 aStrBuffer.append( 'Q' ); nParameter = 2; break;
4327 case css::drawing::EnhancedCustomShapeSegmentCommand::ARCANGLETO :
4328 if ( bExtended ) {
4329 aStrBuffer.append( 'G' );
4330 nParameter = 2;
4331 } else {
4332 aStrBuffer.setLength( aStrBuffer.getLength() - 1);
4333 bNeedExtended = true;
4334 i += 2;
4336 break;
4337 case css::drawing::EnhancedCustomShapeSegmentCommand::DARKEN :
4338 if ( bExtended )
4339 aStrBuffer.append( 'H' );
4340 else
4341 bNeedExtended = true;
4342 break;
4343 case css::drawing::EnhancedCustomShapeSegmentCommand::DARKENLESS :
4344 if ( bExtended )
4345 aStrBuffer.append( 'I' );
4346 else
4347 bNeedExtended = true;
4348 break;
4349 case css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTEN :
4350 if ( bExtended )
4351 aStrBuffer.append( 'J' );
4352 else
4353 bNeedExtended = true;
4354 break;
4355 case css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTENLESS :
4356 if ( bExtended )
4357 aStrBuffer.append( 'K' );
4358 else
4359 bNeedExtended = true;
4360 break;
4361 default : // ups, seems to be something wrong
4363 aSegment.Count = 1;
4364 aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO;
4366 break;
4368 if ( nParameter )
4370 for ( k = 0; k < aSegment.Count; k++ )
4372 if ( ( i + nParameter ) <= nCoords )
4374 for ( l = 0; l < nParameter; l++ )
4376 ExportParameter( aStrBuffer, rCoordinates[ i ].First );
4377 ExportParameter( aStrBuffer, rCoordinates[ i++ ].Second );
4380 else
4382 j = nSegments; // error -> exiting
4383 break;
4388 aStr = aStrBuffer.makeStringAndClear();
4389 rExport.AddAttribute( bExtended ? XML_NAMESPACE_DRAW_EXT : XML_NAMESPACE_DRAW, XML_ENHANCED_PATH, aStr );
4390 if (!bExtended && bNeedExtended && (rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED))
4391 ImpExportEnhancedPath( rExport, rCoordinates, rSegments, true );
4394 static void ImpExportEnhancedGeometry( SvXMLExport& rExport, const uno::Reference< beans::XPropertySet >& xPropSet )
4396 bool bEquations = false;
4397 uno::Sequence< OUString > aEquations;
4399 bool bHandles = false;
4400 uno::Sequence< beans::PropertyValues > aHandles;
4402 uno::Sequence< css::drawing::EnhancedCustomShapeSegment > aSegments;
4403 uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates;
4405 uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentValues;
4407 OUString aStr;
4408 OUStringBuffer aStrBuffer;
4409 double fTextRotateAngle(0.0);
4410 double fTextPreRotateAngle(0.0); // will be consolidated with fTextRotateAngle at the end
4411 SvXMLUnitConverter& rUnitConverter = rExport.GetMM100UnitConverter();
4413 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
4415 // geometry
4416 static constexpr OUString sCustomShapeGeometry( u"CustomShapeGeometry"_ustr );
4417 if ( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName( sCustomShapeGeometry ) )
4419 uno::Any aGeoPropSet( xPropSet->getPropertyValue( sCustomShapeGeometry ) );
4420 uno::Sequence< beans::PropertyValue > aGeoPropSeq;
4422 if ( aGeoPropSet >>= aGeoPropSeq )
4424 bool bCoordinates = false;
4425 OUString aCustomShapeType( u"non-primitive"_ustr );
4427 for (const beans::PropertyValue& rGeoProp : aGeoPropSeq)
4429 switch( EASGet( rGeoProp.Name ) )
4431 case EAS_Type :
4433 rGeoProp.Value >>= aCustomShapeType;
4435 break;
4436 case EAS_MirroredX :
4438 bool bMirroredX;
4439 if ( rGeoProp.Value >>= bMirroredX )
4440 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIRROR_HORIZONTAL,
4441 bMirroredX ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4443 break;
4444 case EAS_MirroredY :
4446 bool bMirroredY;
4447 if ( rGeoProp.Value >>= bMirroredY )
4448 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIRROR_VERTICAL,
4449 bMirroredY ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4451 break;
4452 case EAS_ViewBox :
4454 awt::Rectangle aRect;
4455 if ( rGeoProp.Value >>= aRect )
4457 SdXMLImExViewBox aViewBox( aRect.X, aRect.Y, aRect.Width, aRect.Height );
4458 rExport.AddAttribute( XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString() );
4461 break;
4462 case EAS_TextPreRotateAngle :
4464 rGeoProp.Value >>= fTextPreRotateAngle;
4466 break;
4467 case EAS_TextRotateAngle :
4469 rGeoProp.Value >>= fTextRotateAngle;
4471 break;
4472 case EAS_Extrusion :
4474 uno::Sequence< beans::PropertyValue > aExtrusionPropSeq;
4475 if ( rGeoProp.Value >>= aExtrusionPropSeq )
4477 bool bSkewValuesProvided = false;
4478 for (const beans::PropertyValue& rProp : aExtrusionPropSeq)
4480 switch( EASGet( rProp.Name ) )
4482 case EAS_Extrusion :
4484 bool bExtrusionOn;
4485 if ( rProp.Value >>= bExtrusionOn )
4486 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION,
4487 bExtrusionOn ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4489 break;
4490 case EAS_Brightness :
4492 double fExtrusionBrightness = 0;
4493 if ( rProp.Value >>= fExtrusionBrightness )
4495 ::sax::Converter::convertDouble(
4496 aStrBuffer,
4497 fExtrusionBrightness,
4498 false,
4499 util::MeasureUnit::PERCENT,
4500 util::MeasureUnit::PERCENT);
4501 aStrBuffer.append( '%' );
4502 aStr = aStrBuffer.makeStringAndClear();
4503 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_BRIGHTNESS, aStr );
4506 break;
4507 case EAS_Depth :
4509 css::drawing::EnhancedCustomShapeParameterPair aDepthParaPair;
4510 if ( rProp.Value >>= aDepthParaPair )
4512 double fDepth = 0;
4513 if ( aDepthParaPair.First.Value >>= fDepth )
4515 rExport.GetMM100UnitConverter().convertDouble( aStrBuffer, fDepth );
4516 ExportParameter( aStrBuffer, aDepthParaPair.Second );
4517 aStr = aStrBuffer.makeStringAndClear();
4518 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_DEPTH, aStr );
4522 break;
4523 case EAS_Diffusion :
4525 double fExtrusionDiffusion = 0;
4526 if ( rProp.Value >>= fExtrusionDiffusion )
4528 ::sax::Converter::convertDouble(
4529 aStrBuffer,
4530 fExtrusionDiffusion,
4531 false,
4532 util::MeasureUnit::PERCENT,
4533 util::MeasureUnit::PERCENT);
4534 aStrBuffer.append( '%' );
4535 aStr = aStrBuffer.makeStringAndClear();
4536 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_DIFFUSION, aStr );
4539 break;
4540 case EAS_NumberOfLineSegments :
4542 sal_Int32 nExtrusionNumberOfLineSegments = 0;
4543 if ( rProp.Value >>= nExtrusionNumberOfLineSegments )
4544 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_NUMBER_OF_LINE_SEGMENTS, OUString::number( nExtrusionNumberOfLineSegments ) );
4546 break;
4547 case EAS_LightFace :
4549 bool bExtrusionLightFace;
4550 if ( rProp.Value >>= bExtrusionLightFace )
4551 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_LIGHT_FACE,
4552 bExtrusionLightFace ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4554 break;
4555 case EAS_FirstLightHarsh :
4557 bool bExtrusionFirstLightHarsh;
4558 if ( rProp.Value >>= bExtrusionFirstLightHarsh )
4559 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_HARSH,
4560 bExtrusionFirstLightHarsh ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4562 break;
4563 case EAS_SecondLightHarsh :
4565 bool bExtrusionSecondLightHarsh;
4566 if ( rProp.Value >>= bExtrusionSecondLightHarsh )
4567 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_HARSH,
4568 bExtrusionSecondLightHarsh ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4570 break;
4571 case EAS_FirstLightLevel :
4573 double fExtrusionFirstLightLevel = 0;
4574 if ( rProp.Value >>= fExtrusionFirstLightLevel )
4576 fExtrusionFirstLightLevel =
4577 std::clamp(fExtrusionFirstLightLevel, 0.0, 100.0);
4578 ::sax::Converter::convertDouble(
4579 aStrBuffer,
4580 fExtrusionFirstLightLevel,
4581 false,
4582 util::MeasureUnit::PERCENT,
4583 util::MeasureUnit::PERCENT);
4584 aStrBuffer.append( '%' );
4585 aStr = aStrBuffer.makeStringAndClear();
4586 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_LEVEL, aStr );
4589 break;
4590 case EAS_SecondLightLevel :
4592 double fExtrusionSecondLightLevel = 0;
4593 if ( rProp.Value >>= fExtrusionSecondLightLevel )
4595 fExtrusionSecondLightLevel =
4596 std::clamp(fExtrusionSecondLightLevel, 0.0, 100.0);
4597 ::sax::Converter::convertDouble(
4598 aStrBuffer,
4599 fExtrusionSecondLightLevel,
4600 false,
4601 util::MeasureUnit::PERCENT,
4602 util::MeasureUnit::PERCENT);
4603 aStrBuffer.append( '%' );
4604 aStr = aStrBuffer.makeStringAndClear();
4605 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_LEVEL, aStr );
4608 break;
4609 case EAS_FirstLightDirection :
4611 drawing::Direction3D aExtrusionFirstLightDirection;
4612 if ( rProp.Value >>= aExtrusionFirstLightDirection )
4614 ::basegfx::B3DVector aVec3D( aExtrusionFirstLightDirection.DirectionX, aExtrusionFirstLightDirection.DirectionY,
4615 aExtrusionFirstLightDirection.DirectionZ );
4616 SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D );
4617 aStr = aStrBuffer.makeStringAndClear();
4618 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_DIRECTION, aStr );
4621 break;
4622 case EAS_SecondLightDirection :
4624 drawing::Direction3D aExtrusionSecondLightDirection;
4625 if ( rProp.Value >>= aExtrusionSecondLightDirection )
4627 ::basegfx::B3DVector aVec3D( aExtrusionSecondLightDirection.DirectionX, aExtrusionSecondLightDirection.DirectionY,
4628 aExtrusionSecondLightDirection.DirectionZ );
4629 SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D );
4630 aStr = aStrBuffer.makeStringAndClear();
4631 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_DIRECTION, aStr );
4634 break;
4635 case EAS_Metal :
4637 bool bExtrusionMetal;
4638 if ( rProp.Value >>= bExtrusionMetal )
4639 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_METAL,
4640 bExtrusionMetal ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4642 break;
4643 case EAS_MetalType :
4645 // In ODF since ODF 1.4. Before 1.4, export only in extended.
4646 sal_Int16 eMetalType;
4647 if (rProp.Value >>= eMetalType)
4649 // LibreOffice had used the same values as later specified in ODF 1.4
4650 if (eMetalType == drawing::EnhancedCustomShapeMetalType::MetalMSCompatible)
4651 aStr = "loext:MetalMSCompatible";
4652 else
4653 aStr = "draw:MetalODF";
4655 SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion();
4656 if (eVersion >= SvtSaveOptions::ODFSVER_014)
4658 if (!(eVersion & SvtSaveOptions::ODFSVER_EXTENDED)
4659 && eMetalType == drawing::EnhancedCustomShapeMetalType::MetalMSCompatible)
4660 rExport.AddAttribute(XML_NAMESPACE_XMLNS, XML_NP_LO_EXT, XML_N_LO_EXT);
4661 rExport.AddAttribute(XML_NAMESPACE_DRAW, XML_EXTRUSION_METAL_TYPE, aStr);
4663 else if (eVersion & SvtSaveOptions::ODFSVER_EXTENDED)
4665 rExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_EXTRUSION_METAL_TYPE, aStr);
4669 break;
4670 case EAS_ShadeMode :
4672 // shadeMode
4673 drawing::ShadeMode eShadeMode;
4674 if( rProp.Value >>= eShadeMode )
4676 if( eShadeMode == drawing::ShadeMode_FLAT )
4677 aStr = GetXMLToken( XML_FLAT );
4678 else if( eShadeMode == drawing::ShadeMode_PHONG )
4679 aStr = GetXMLToken( XML_PHONG );
4680 else if( eShadeMode == drawing::ShadeMode_SMOOTH )
4681 aStr = GetXMLToken( XML_GOURAUD );
4682 else
4683 aStr = GetXMLToken( XML_DRAFT );
4685 else
4687 // ShadeMode enum not there, write default
4688 aStr = GetXMLToken( XML_FLAT);
4690 rExport.AddAttribute( XML_NAMESPACE_DR3D, XML_SHADE_MODE, aStr );
4692 break;
4693 case EAS_RotateAngle :
4695 css::drawing::EnhancedCustomShapeParameterPair aRotateAngleParaPair;
4696 if ( rProp.Value >>= aRotateAngleParaPair )
4698 ExportParameter( aStrBuffer, aRotateAngleParaPair.First );
4699 ExportParameter( aStrBuffer, aRotateAngleParaPair.Second );
4700 aStr = aStrBuffer.makeStringAndClear();
4701 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ROTATION_ANGLE, aStr );
4704 break;
4705 case EAS_RotationCenter :
4707 drawing::Direction3D aExtrusionRotationCenter;
4708 if ( rProp.Value >>= aExtrusionRotationCenter )
4710 ::basegfx::B3DVector aVec3D( aExtrusionRotationCenter.DirectionX, aExtrusionRotationCenter.DirectionY,
4711 aExtrusionRotationCenter.DirectionZ );
4712 SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D );
4713 aStr = aStrBuffer.makeStringAndClear();
4714 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ROTATION_CENTER, aStr );
4717 break;
4718 case EAS_Shininess :
4720 double fExtrusionShininess = 0;
4721 if ( rProp.Value >>= fExtrusionShininess )
4723 ::sax::Converter::convertDouble(
4724 aStrBuffer,
4725 fExtrusionShininess,
4726 false,
4727 util::MeasureUnit::PERCENT,
4728 util::MeasureUnit::PERCENT);
4729 aStrBuffer.append( '%' );
4730 aStr = aStrBuffer.makeStringAndClear();
4731 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SHININESS, aStr );
4734 break;
4735 case EAS_Skew :
4737 css::drawing::EnhancedCustomShapeParameterPair aSkewParaPair;
4738 if ( rProp.Value >>= aSkewParaPair )
4740 bSkewValuesProvided = true;
4741 ExportParameter( aStrBuffer, aSkewParaPair.First );
4742 ExportParameter( aStrBuffer, aSkewParaPair.Second );
4743 aStr = aStrBuffer.makeStringAndClear();
4744 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SKEW, aStr );
4747 break;
4748 case EAS_Specularity :
4750 double fExtrusionSpecularity = 0;
4751 if ( rProp.Value >>= fExtrusionSpecularity )
4753 // ODF 1.0/1.1 allow arbitrary percent, ODF 1.2/1.3 restrict it to 0%-100%,
4754 // ODF 1.4 restricts it to non negative percent.
4755 SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion();
4756 if (fExtrusionSpecularity > 100.0 && eVersion & SvtSaveOptions::ODFSVER_EXTENDED
4757 && eVersion >= SvtSaveOptions::ODFSVER_012 && eVersion < SvtSaveOptions::ODFSVER_014)
4759 // tdf#147580 write values > 100% in loext
4760 ::sax::Converter::convertDouble(
4761 aStrBuffer,
4762 fExtrusionSpecularity,
4763 false,
4764 util::MeasureUnit::PERCENT,
4765 util::MeasureUnit::PERCENT);
4766 aStrBuffer.append( '%' );
4767 aStr = aStrBuffer.makeStringAndClear();
4768 rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_EXTRUSION_SPECULARITY_LOEXT, aStr );
4770 // clamp fExtrusionSpecularity to allowed values
4771 if (eVersion >= SvtSaveOptions::ODFSVER_012 && eVersion < SvtSaveOptions::ODFSVER_014)
4772 fExtrusionSpecularity = std::clamp<double>(fExtrusionSpecularity, 0.0, 100.0);
4773 else if (eVersion >= SvtSaveOptions::ODFSVER_014)
4774 fExtrusionSpecularity = std::max<double>(0.0, fExtrusionSpecularity);
4775 // write percent
4776 ::sax::Converter::convertDouble(
4777 aStrBuffer,
4778 fExtrusionSpecularity,
4779 false,
4780 util::MeasureUnit::PERCENT,
4781 util::MeasureUnit::PERCENT);
4782 aStrBuffer.append( '%' );
4783 aStr = aStrBuffer.makeStringAndClear();
4784 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SPECULARITY, aStr );
4787 break;
4788 case EAS_ProjectionMode :
4790 drawing::ProjectionMode eProjectionMode;
4791 if ( rProp.Value >>= eProjectionMode )
4792 rExport.AddAttribute( XML_NAMESPACE_DR3D, XML_PROJECTION,
4793 eProjectionMode == drawing::ProjectionMode_PARALLEL ? GetXMLToken( XML_PARALLEL ) : GetXMLToken( XML_PERSPECTIVE ) );
4795 break;
4796 case EAS_ViewPoint :
4798 drawing::Position3D aExtrusionViewPoint;
4799 if ( rProp.Value >>= aExtrusionViewPoint )
4801 rUnitConverter.convertPosition3D( aStrBuffer, aExtrusionViewPoint );
4802 aStr = aStrBuffer.makeStringAndClear();
4803 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_VIEWPOINT, aStr );
4806 break;
4807 case EAS_Origin :
4809 css::drawing::EnhancedCustomShapeParameterPair aOriginParaPair;
4810 if ( rProp.Value >>= aOriginParaPair )
4812 ExportParameter( aStrBuffer, aOriginParaPair.First );
4813 ExportParameter( aStrBuffer, aOriginParaPair.Second );
4814 aStr = aStrBuffer.makeStringAndClear();
4815 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ORIGIN, aStr );
4818 break;
4819 case EAS_Color :
4821 bool bExtrusionColor;
4822 if ( rProp.Value >>= bExtrusionColor )
4824 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_COLOR,
4825 bExtrusionColor ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4828 break;
4829 default:
4830 break;
4833 // tdf#141301: no specific skew values provided
4834 if (!bSkewValuesProvided)
4836 // so we need to export default values explicitly
4837 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SKEW, u"50 -135"_ustr);
4841 break;
4842 case EAS_TextPath :
4844 uno::Sequence< beans::PropertyValue > aTextPathPropSeq;
4845 if ( rGeoProp.Value >>= aTextPathPropSeq )
4847 for (const beans::PropertyValue& rProp : aTextPathPropSeq)
4849 switch( EASGet( rProp.Name ) )
4851 case EAS_TextPath :
4853 bool bTextPathOn;
4854 if ( rProp.Value >>= bTextPathOn )
4855 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH,
4856 bTextPathOn ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4858 break;
4859 case EAS_TextPathMode :
4861 css::drawing::EnhancedCustomShapeTextPathMode eTextPathMode;
4862 if ( rProp.Value >>= eTextPathMode )
4864 switch ( eTextPathMode )
4866 case css::drawing::EnhancedCustomShapeTextPathMode_NORMAL: aStr = GetXMLToken( XML_NORMAL ); break;
4867 case css::drawing::EnhancedCustomShapeTextPathMode_PATH : aStr = GetXMLToken( XML_PATH ); break;
4868 case css::drawing::EnhancedCustomShapeTextPathMode_SHAPE : aStr = GetXMLToken( XML_SHAPE ); break;
4869 default:
4870 break;
4872 if ( !aStr.isEmpty() )
4873 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_MODE, aStr );
4876 break;
4877 case EAS_ScaleX :
4879 bool bScaleX;
4880 if ( rProp.Value >>= bScaleX )
4882 aStr = bScaleX ? GetXMLToken( XML_SHAPE ) : GetXMLToken( XML_PATH );
4883 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_SCALE, aStr );
4886 break;
4887 case EAS_SameLetterHeights :
4889 bool bSameLetterHeights;
4890 if ( rProp.Value >>= bSameLetterHeights )
4891 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_SAME_LETTER_HEIGHTS,
4892 bSameLetterHeights ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4894 break;
4895 default:
4896 break;
4901 break;
4902 case EAS_Path :
4904 uno::Sequence< beans::PropertyValue > aPathPropSeq;
4905 if ( rGeoProp.Value >>= aPathPropSeq )
4907 for (const beans::PropertyValue& rProp : aPathPropSeq)
4909 switch( EASGet( rProp.Name ) )
4911 case EAS_SubViewSize:
4913 // export draw:sub-view-size (do not export in ODF 1.3 or older)
4914 if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
4916 continue;
4918 uno::Sequence< awt::Size > aSubViewSizes;
4919 rProp.Value >>= aSubViewSizes;
4921 for ( int nIdx = 0; nIdx < aSubViewSizes.getLength(); nIdx++ )
4923 if ( nIdx )
4924 aStrBuffer.append(' ');
4925 aStrBuffer.append( aSubViewSizes[nIdx].Width );
4926 aStrBuffer.append(' ');
4927 aStrBuffer.append( aSubViewSizes[nIdx].Height );
4929 aStr = aStrBuffer.makeStringAndClear();
4930 rExport.AddAttribute( XML_NAMESPACE_DRAW_EXT, XML_SUB_VIEW_SIZE, aStr );
4932 break;
4933 case EAS_ExtrusionAllowed :
4935 bool bExtrusionAllowed;
4936 if ( rProp.Value >>= bExtrusionAllowed )
4937 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ALLOWED,
4938 bExtrusionAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4940 break;
4941 case EAS_ConcentricGradientFillAllowed :
4943 bool bConcentricGradientFillAllowed;
4944 if ( rProp.Value >>= bConcentricGradientFillAllowed )
4945 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CONCENTRIC_GRADIENT_FILL_ALLOWED,
4946 bConcentricGradientFillAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4948 break;
4949 case EAS_TextPathAllowed :
4951 bool bTextPathAllowed;
4952 if ( rProp.Value >>= bTextPathAllowed )
4953 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_ALLOWED,
4954 bTextPathAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4956 break;
4957 case EAS_GluePoints :
4959 css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> aGluePoints;
4960 if ( rProp.Value >>= aGluePoints )
4962 if ( aGluePoints.hasElements() )
4964 for (const auto& rGluePoint : aGluePoints)
4966 ExportParameter( aStrBuffer, rGluePoint.First );
4967 ExportParameter( aStrBuffer, rGluePoint.Second );
4969 aStr = aStrBuffer.makeStringAndClear();
4971 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GLUE_POINTS, aStr );
4974 break;
4975 case EAS_GluePointType :
4977 sal_Int16 nGluePointType = sal_Int16();
4978 if ( rProp.Value >>= nGluePointType )
4980 switch ( nGluePointType )
4982 case css::drawing::EnhancedCustomShapeGluePointType::NONE : aStr = GetXMLToken( XML_NONE ); break;
4983 case css::drawing::EnhancedCustomShapeGluePointType::SEGMENTS : aStr = GetXMLToken( XML_SEGMENTS ); break;
4984 case css::drawing::EnhancedCustomShapeGluePointType::RECT : aStr = GetXMLToken( XML_RECTANGLE ); break;
4986 if ( !aStr.isEmpty() )
4987 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GLUE_POINT_TYPE, aStr );
4990 break;
4991 case EAS_Coordinates :
4993 bCoordinates = ( rProp.Value >>= aCoordinates );
4995 break;
4996 case EAS_Segments :
4998 rProp.Value >>= aSegments;
5000 break;
5001 case EAS_StretchX :
5003 sal_Int32 nStretchPoint = 0;
5004 if ( rProp.Value >>= nStretchPoint )
5005 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PATH_STRETCHPOINT_X, OUString::number( nStretchPoint ) );
5007 break;
5008 case EAS_StretchY :
5010 sal_Int32 nStretchPoint = 0;
5011 if ( rProp.Value >>= nStretchPoint )
5012 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PATH_STRETCHPOINT_Y, OUString::number( nStretchPoint ) );
5014 break;
5015 case EAS_TextFrames :
5017 css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aPathTextFrames;
5018 if ( rProp.Value >>= aPathTextFrames )
5020 if ( aPathTextFrames.hasElements() )
5022 for (const auto& rPathTextFrame : aPathTextFrames)
5024 ExportParameter( aStrBuffer, rPathTextFrame.TopLeft.First );
5025 ExportParameter( aStrBuffer, rPathTextFrame.TopLeft.Second );
5026 ExportParameter( aStrBuffer, rPathTextFrame.BottomRight.First );
5027 ExportParameter( aStrBuffer, rPathTextFrame.BottomRight.Second );
5029 aStr = aStrBuffer.makeStringAndClear();
5031 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_AREAS, aStr );
5034 break;
5035 default:
5036 break;
5041 break;
5042 case EAS_Equations :
5044 bEquations = ( rGeoProp.Value >>= aEquations );
5046 break;
5047 case EAS_Handles :
5049 bHandles = ( rGeoProp.Value >>= aHandles );
5051 break;
5052 case EAS_AdjustmentValues :
5054 rGeoProp.Value >>= aAdjustmentValues;
5056 break;
5057 default:
5058 break;
5060 } // for
5062 // ToDo: Where is TextPreRotateAngle still used? We cannot save it in ODF.
5063 fTextRotateAngle += fTextPreRotateAngle;
5064 // Workaround for writing-mode bt-lr and tb-rl90 in ODF strict,
5065 // otherwise loext:writing-mode is used in style export.
5066 if (!(rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED))
5068 if (xPropSetInfo->hasPropertyByName(u"WritingMode"_ustr))
5070 sal_Int16 nDirection = -1;
5071 xPropSet->getPropertyValue(u"WritingMode"_ustr) >>= nDirection;
5072 if (nDirection == text::WritingMode2::TB_RL90)
5073 fTextRotateAngle -= 90;
5074 else if (nDirection == text::WritingMode2::BT_LR)
5075 fTextRotateAngle -= 270;
5078 if (fTextRotateAngle != 0)
5080 ::sax::Converter::convertDouble( aStrBuffer, fTextRotateAngle );
5081 aStr = aStrBuffer.makeStringAndClear();
5082 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_ROTATE_ANGLE, aStr );
5085 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TYPE, aCustomShapeType );
5087 // adjustments
5088 sal_Int32 nAdjustmentValues = aAdjustmentValues.getLength();
5089 if ( nAdjustmentValues )
5091 sal_Int32 i, nValue = 0;
5092 for ( i = 0; i < nAdjustmentValues; i++ )
5094 if ( i )
5095 aStrBuffer.append( ' ' );
5097 const css::drawing::EnhancedCustomShapeAdjustmentValue& rAdj = aAdjustmentValues[ i ];
5098 if ( rAdj.State == beans::PropertyState_DIRECT_VALUE )
5100 if ( rAdj.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
5102 double fValue = 0.0;
5103 rAdj.Value >>= fValue;
5104 ::sax::Converter::convertDouble(aStrBuffer, fValue);
5106 else
5108 rAdj.Value >>= nValue;
5109 aStrBuffer.append(nValue);
5112 else
5114 // this should not be, but better than setting nothing
5115 aStrBuffer.append("0");
5118 aStr = aStrBuffer.makeStringAndClear();
5119 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MODIFIERS, aStr );
5121 if ( bCoordinates )
5122 ImpExportEnhancedPath( rExport, aCoordinates, aSegments );
5125 SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_ENHANCED_GEOMETRY, true, true );
5126 if ( bEquations )
5127 ImpExportEquations( rExport, aEquations );
5128 if ( bHandles )
5129 ImpExportHandles( rExport, aHandles );
5132 void XMLShapeExport::ImpExportCustomShape(
5133 const uno::Reference< drawing::XShape >& xShape,
5134 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint )
5136 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
5137 if ( !xPropSet.is() )
5138 return;
5140 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
5142 // Transformation
5143 ImpExportNewTrans( xPropSet, nFeatures, pRefPoint );
5145 if ( xPropSetInfo.is() )
5147 OUString aStr;
5148 if ( xPropSetInfo->hasPropertyByName( u"CustomShapeEngine"_ustr ) )
5150 uno::Any aEngine( xPropSet->getPropertyValue( u"CustomShapeEngine"_ustr ) );
5151 if ( ( aEngine >>= aStr ) && !aStr.isEmpty() )
5152 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ENGINE, aStr );
5154 if ( xPropSetInfo->hasPropertyByName( u"CustomShapeData"_ustr ) )
5156 uno::Any aData( xPropSet->getPropertyValue( u"CustomShapeData"_ustr ) );
5157 if ( ( aData >>= aStr ) && !aStr.isEmpty() )
5158 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DATA, aStr );
5161 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
5162 SvXMLElementExport aOBJ( mrExport, XML_NAMESPACE_DRAW, XML_CUSTOM_SHAPE, bCreateNewline, true );
5163 ImpExportDescription( xShape ); // #i68101#
5164 ImpExportEvents( xShape );
5165 ImpExportGluePoints( xShape );
5166 ImpExportText( xShape );
5167 ImpExportEnhancedGeometry( mrExport, xPropSet );
5171 void XMLShapeExport::ImpExportTableShape( const uno::Reference< drawing::XShape >& xShape, XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint )
5173 uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
5174 uno::Reference< container::XNamed > xNamed(xShape, uno::UNO_QUERY);
5176 SAL_WARN_IF( !xPropSet.is() || !xNamed.is(), "xmloff", "xmloff::XMLShapeExport::ImpExportTableShape(), table shape is not implementing needed interfaces");
5177 if(!(xPropSet.is() && xNamed.is()))
5178 return;
5182 // Transformation
5183 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
5185 bool bIsEmptyPresObj = false;
5187 // presentation settings
5188 if(eShapeType == XmlShapeType::PresTableShape)
5189 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_TABLE) );
5191 const bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE );
5193 SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW, XML_FRAME, bCreateNewline, true );
5195 // do not export in ODF 1.1 or older
5196 if (mrExport.getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012)
5198 if( !bIsEmptyPresObj )
5200 uno::Reference< container::XNamed > xTemplate( xPropSet->getPropertyValue(u"TableTemplate"_ustr), uno::UNO_QUERY );
5201 if( xTemplate.is() )
5203 const OUString sTemplate( xTemplate->getName() );
5204 if( !sTemplate.isEmpty() )
5206 mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_TEMPLATE_NAME, sTemplate );
5208 for( const XMLPropertyMapEntry* pEntry = &aXMLTableShapeAttributes[0]; !pEntry->IsEnd(); pEntry++ )
5212 bool bBool = false;
5213 xPropSet->getPropertyValue( pEntry->getApiName() ) >>= bBool;
5214 if( bBool )
5215 mrExport.AddAttribute(pEntry->mnNameSpace, pEntry->meXMLName, XML_TRUE );
5217 catch( uno::Exception& )
5219 DBG_UNHANDLED_EXCEPTION("xmloff.draw");
5225 uno::Reference< table::XColumnRowRange > xRange( xPropSet->getPropertyValue( gsModel ), uno::UNO_QUERY_THROW );
5226 GetShapeTableExport()->exportTable( xRange );
5230 if (!bIsEmptyPresObj
5231 && officecfg::Office::Common::Save::Graphic::AddReplacementImages::get())
5233 uno::Reference< graphic::XGraphic > xGraphic( xPropSet->getPropertyValue(u"ReplacementGraphic"_ustr), uno::UNO_QUERY );
5234 ExportGraphicPreview(xGraphic, mrExport, u"TablePreview", u".svm", u"image/x-vclgraphic"_ustr);
5237 ImpExportEvents( xShape );
5238 ImpExportGluePoints( xShape );
5239 ImpExportDescription( xShape ); // #i68101#
5241 catch( uno::Exception const & )
5243 DBG_UNHANDLED_EXCEPTION("xmloff.draw");
5247 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */