fix brain malfunction
[LibreOffice.git] / xmloff / source / draw / shapeexport.cxx
blob7f19e7fe368871a8b85ab836974ee1057ab22acf
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/Alignment.hpp>
40 #include <com/sun/star/drawing/CameraGeometry.hpp>
41 #include <com/sun/star/drawing/CircleKind.hpp>
42 #include <com/sun/star/drawing/ConnectorType.hpp>
43 #include <com/sun/star/drawing/Direction3D.hpp>
44 #include <com/sun/star/drawing/EscapeDirection.hpp>
45 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
46 #include <com/sun/star/drawing/EnhancedCustomShapeGluePointType.hpp>
47 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
48 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
49 #include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp>
50 #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
51 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
52 #include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
53 #include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
54 #include <com/sun/star/drawing/GluePoint2.hpp>
55 #include <com/sun/star/drawing/HomogenMatrix.hpp>
56 #include <com/sun/star/drawing/HomogenMatrix3.hpp>
57 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
58 #include <com/sun/star/drawing/PolyPolygonShape3D.hpp>
59 #include <com/sun/star/drawing/Position3D.hpp>
60 #include <com/sun/star/drawing/ProjectionMode.hpp>
61 #include <com/sun/star/drawing/ShadeMode.hpp>
62 #include <com/sun/star/drawing/XControlShape.hpp>
63 #include <com/sun/star/drawing/XCustomShapeEngine.hpp>
64 #include <com/sun/star/drawing/XGluePointsSupplier.hpp>
65 #include <com/sun/star/drawing/BarCode.hpp>
66 #include <com/sun/star/drawing/BarCodeErrorCorrection.hpp>
67 #include <com/sun/star/drawing/XShapes3.hpp>
68 #include <com/sun/star/embed/ElementModes.hpp>
69 #include <com/sun/star/embed/XStorage.hpp>
70 #include <com/sun/star/embed/XTransactedObject.hpp>
71 #include <com/sun/star/graphic/XGraphic.hpp>
72 #include <com/sun/star/graphic/GraphicProvider.hpp>
73 #include <com/sun/star/graphic/XGraphicProvider.hpp>
74 #include <com/sun/star/io/XSeekableInputStream.hpp>
75 #include <com/sun/star/io/XStream.hpp>
76 #include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
77 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
78 #include <com/sun/star/media/ZoomLevel.hpp>
79 #include <com/sun/star/presentation/AnimationSpeed.hpp>
80 #include <com/sun/star/presentation/ClickAction.hpp>
81 #include <com/sun/star/style/XStyle.hpp>
82 #include <com/sun/star/table/XColumnRowRange.hpp>
83 #include <com/sun/star/text/WritingMode2.hpp>
84 #include <com/sun/star/text/XText.hpp>
86 #include <comphelper/classids.hxx>
87 #include <comphelper/processfactory.hxx>
88 #include <comphelper/propertyvalue.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>
130 using namespace ::com::sun::star;
131 using namespace ::xmloff::EnhancedCustomShapeToken;
132 using namespace ::xmloff::token;
134 constexpr OUStringLiteral XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE = u"vnd.sun.star.GraphicObject:";
136 namespace {
138 bool supportsText(XmlShapeType eShapeType)
140 return eShapeType != XmlShapeType::PresChartShape &&
141 eShapeType != XmlShapeType::PresOLE2Shape &&
142 eShapeType != XmlShapeType::DrawSheetShape &&
143 eShapeType != XmlShapeType::PresSheetShape &&
144 eShapeType != XmlShapeType::Draw3DSceneObject &&
145 eShapeType != XmlShapeType::Draw3DCubeObject &&
146 eShapeType != XmlShapeType::Draw3DSphereObject &&
147 eShapeType != XmlShapeType::Draw3DLatheObject &&
148 eShapeType != XmlShapeType::Draw3DExtrudeObject &&
149 eShapeType != XmlShapeType::DrawPageShape &&
150 eShapeType != XmlShapeType::PresPageShape &&
151 eShapeType != XmlShapeType::DrawGroupShape;
157 constexpr OUStringLiteral gsZIndex( u"ZOrder" );
158 constexpr OUStringLiteral gsPrintable( u"Printable" );
159 constexpr OUStringLiteral gsVisible( u"Visible" );
160 constexpr OUStringLiteral gsModel( u"Model" );
161 constexpr OUStringLiteral gsStartShape( u"StartShape" );
162 constexpr OUStringLiteral gsEndShape( u"EndShape" );
163 constexpr OUStringLiteral gsOnClick( u"OnClick" );
164 constexpr OUStringLiteral gsEventType( u"EventType" );
165 constexpr OUStringLiteral gsPresentation( u"Presentation" );
166 constexpr OUStringLiteral gsMacroName( u"MacroName" );
167 constexpr OUStringLiteral gsScript( u"Script" );
168 constexpr OUStringLiteral gsLibrary( u"Library" );
169 constexpr OUStringLiteral gsClickAction( u"ClickAction" );
170 constexpr OUStringLiteral gsBookmark( u"Bookmark" );
171 constexpr OUStringLiteral gsEffect( u"Effect" );
172 constexpr OUStringLiteral gsPlayFull( u"PlayFull" );
173 constexpr OUStringLiteral gsVerb( u"Verb" );
174 constexpr OUStringLiteral gsSoundURL( u"SoundURL" );
175 constexpr OUStringLiteral gsSpeed( u"Speed" );
176 constexpr OUStringLiteral gsStarBasic( u"StarBasic" );
177 constexpr OUStringLiteral gsHyperlink( u"Hyperlink" );
179 XMLShapeExport::XMLShapeExport(SvXMLExport& rExp,
180 SvXMLExportPropertyMapper *pExtMapper )
181 : mrExport( rExp ),
182 maCurrentShapesIter(maShapesInfos.end()),
183 mbExportLayer( false ),
184 // #88546# init to sal_False
185 mbHandleProgressBar( false )
187 // construct PropertySetMapper
188 mxPropertySetMapper = CreateShapePropMapper( mrExport );
189 if( pExtMapper )
191 rtl::Reference < SvXMLExportPropertyMapper > xExtMapper( pExtMapper );
192 mxPropertySetMapper->ChainExportMapper( xExtMapper );
196 // chain text attributes
197 xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(rExp));
200 mrExport.GetAutoStylePool()->AddFamily(
201 XmlStyleFamily::SD_GRAPHICS_ID,
202 XML_STYLE_FAMILY_SD_GRAPHICS_NAME,
203 GetPropertySetMapper(),
204 XML_STYLE_FAMILY_SD_GRAPHICS_PREFIX);
205 mrExport.GetAutoStylePool()->AddFamily(
206 XmlStyleFamily::SD_PRESENTATION_ID,
207 XML_STYLE_FAMILY_SD_PRESENTATION_NAME,
208 GetPropertySetMapper(),
209 XML_STYLE_FAMILY_SD_PRESENTATION_PREFIX);
211 // create table export helper and let him add his families in time
212 GetShapeTableExport();
215 XMLShapeExport::~XMLShapeExport()
219 // sj: replacing CustomShapes with standard objects that are also supported in OpenOffice.org format
220 uno::Reference< drawing::XShape > XMLShapeExport::checkForCustomShapeReplacement( const uno::Reference< drawing::XShape >& xShape )
222 uno::Reference< drawing::XShape > xCustomShapeReplacement;
224 if( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) )
226 OUString aType( xShape->getShapeType() );
227 if( aType == "com.sun.star.drawing.CustomShape" )
229 uno::Reference< beans::XPropertySet > xSet( xShape, uno::UNO_QUERY );
230 if( xSet.is() )
232 OUString aEngine;
233 xSet->getPropertyValue("CustomShapeEngine") >>= aEngine;
234 if ( aEngine.isEmpty() )
236 aEngine = "com.sun.star.drawing.EnhancedCustomShapeEngine";
238 uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
240 if ( !aEngine.isEmpty() )
242 uno::Sequence< beans::PropertyValue > aPropValues{
243 comphelper::makePropertyValue("CustomShape", xShape),
244 comphelper::makePropertyValue("ForceGroupWithText", true)
246 uno::Sequence< uno::Any > aArgument = { uno::Any(aPropValues) };
247 uno::Reference< uno::XInterface > xInterface(
248 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aEngine, aArgument, xContext) );
249 if ( xInterface.is() )
251 uno::Reference< drawing::XCustomShapeEngine > xCustomShapeEngine(
252 uno::Reference< drawing::XCustomShapeEngine >( xInterface, uno::UNO_QUERY ) );
253 if ( xCustomShapeEngine.is() )
254 xCustomShapeReplacement = xCustomShapeEngine->render();
260 return xCustomShapeReplacement;
263 // This method collects all automatic styles for the given XShape
264 void XMLShapeExport::collectShapeAutoStyles(const uno::Reference< drawing::XShape >& xShape )
266 if( maCurrentShapesIter == maShapesInfos.end() )
268 OSL_FAIL( "XMLShapeExport::collectShapeAutoStyles(): no call to seekShapes()!" );
269 return;
271 sal_Int32 nZIndex = 0;
272 uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
273 if( xPropSet.is() )
274 xPropSet->getPropertyValue(gsZIndex) >>= nZIndex;
276 ImplXMLShapeExportInfoVector& aShapeInfoVector = (*maCurrentShapesIter).second;
278 if( static_cast<sal_Int32>(aShapeInfoVector.size()) <= nZIndex )
280 OSL_FAIL( "XMLShapeExport::collectShapeAutoStyles(): no shape info allocated for a given shape" );
281 return;
284 ImplXMLShapeExportInfo& aShapeInfo = aShapeInfoVector[nZIndex];
286 uno::Reference< drawing::XShape > xCustomShapeReplacement = checkForCustomShapeReplacement( xShape );
287 if ( xCustomShapeReplacement.is() )
288 aShapeInfo.xCustomShapeReplacement = xCustomShapeReplacement;
290 // first compute the shapes type
291 ImpCalcShapeType(xShape, aShapeInfo.meShapeType);
293 // #i118485# enabled XmlShapeType::DrawChartShape and XmlShapeType::DrawOLE2Shape
294 // to have text
295 const bool bObjSupportsText =
296 supportsText(aShapeInfo.meShapeType);
298 const bool bObjSupportsStyle =
299 aShapeInfo.meShapeType != XmlShapeType::DrawGroupShape;
301 bool bIsEmptyPresObj = false;
303 if ( aShapeInfo.xCustomShapeReplacement.is() )
304 xPropSet.clear();
306 // prep text styles
307 if( xPropSet.is() && bObjSupportsText )
309 uno::Reference< text::XText > xText(xShape, uno::UNO_QUERY);
310 if (xText.is())
314 // tdf#153161: it seems that the call to XTextRange::getString flushes the changes
315 // for some objects, that otherwise fail to get exported correctly. Maybe at some
316 // point it would make sense to find a better place for more targeted flush.
317 xText->getString();
319 catch (uno::RuntimeException const&)
321 // E.g., SwXTextFrame that contains only a table will throw; this is not an error
324 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
326 if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsEmptyPresentationObject") )
328 uno::Any aAny = xPropSet->getPropertyValue("IsEmptyPresentationObject");
329 aAny >>= bIsEmptyPresObj;
332 if(!bIsEmptyPresObj)
334 GetExport().GetTextParagraphExport()->collectTextAutoStyles( xText );
339 // compute the shape parent style
340 if( xPropSet.is() )
342 uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( xPropSet->getPropertySetInfo() );
344 OUString aParentName;
345 uno::Reference< style::XStyle > xStyle;
347 if( bObjSupportsStyle )
349 if( xPropertySetInfo.is() && xPropertySetInfo->hasPropertyByName("Style") )
350 xPropSet->getPropertyValue("Style") >>= xStyle;
352 if(xStyle.is())
354 // get family ID
355 uno::Reference< beans::XPropertySet > xStylePropSet(xStyle, uno::UNO_QUERY);
356 SAL_WARN_IF( !xStylePropSet.is(), "xmloff", "style without a XPropertySet?" );
359 if(xStylePropSet.is())
361 OUString aFamilyName;
362 xStylePropSet->getPropertyValue("Family") >>= aFamilyName;
363 if( !aFamilyName.isEmpty() && aFamilyName != "graphics" )
364 aShapeInfo.mnFamily = XmlStyleFamily::SD_PRESENTATION_ID;
367 catch(const beans::UnknownPropertyException&)
369 // Ignored.
370 SAL_WARN( "xmloff",
371 "XMLShapeExport::collectShapeAutoStyles: style has no 'Family' property");
374 // get parent-style name
375 if(XmlStyleFamily::SD_PRESENTATION_ID == aShapeInfo.mnFamily)
377 aParentName = msPresentationStylePrefix;
380 aParentName += xStyle->getName();
384 if (aParentName.isEmpty() && xPropertySetInfo->hasPropertyByName("TextBox") && xPropSet->getPropertyValue("TextBox").hasValue() && xPropSet->getPropertyValue("TextBox").get<bool>())
386 // Shapes with a Writer TextBox always have a parent style.
387 // If there would be none, then assign the default one.
388 aParentName = "Frame";
391 // filter propset
392 std::vector< XMLPropertyState > aPropStates;
394 sal_Int32 nCount = 0;
395 if( !bIsEmptyPresObj || (aShapeInfo.meShapeType != XmlShapeType::PresPageShape) )
397 aPropStates = GetPropertySetMapper()->Filter(mrExport, xPropSet);
399 if (XmlShapeType::DrawControlShape == aShapeInfo.meShapeType)
401 // for control shapes, we additionally need the number format style (if any)
402 uno::Reference< drawing::XControlShape > xControl(xShape, uno::UNO_QUERY);
403 DBG_ASSERT(xControl.is(), "XMLShapeExport::collectShapeAutoStyles: ShapeType control, but no XControlShape!");
404 if (xControl.is())
406 uno::Reference< beans::XPropertySet > xControlModel(xControl->getControl(), uno::UNO_QUERY);
407 DBG_ASSERT(xControlModel.is(), "XMLShapeExport::collectShapeAutoStyles: no control model on the control shape!");
409 OUString sNumberStyle = mrExport.GetFormExport()->getControlNumberStyle(xControlModel);
410 if (!sNumberStyle.isEmpty())
412 sal_Int32 nIndex = GetPropertySetMapper()->getPropertySetMapper()->FindEntryIndex(CTF_SD_CONTROL_SHAPE_DATA_STYLE);
413 // TODO : this retrieval of the index could be moved into the ctor, holding the index
414 // as member, thus saving time.
415 DBG_ASSERT(-1 != nIndex, "XMLShapeExport::collectShapeAutoStyles: could not obtain the index for our context id!");
417 XMLPropertyState aNewState(nIndex, uno::Any(sNumberStyle));
418 aPropStates.push_back(aNewState);
423 nCount = std::count_if(aPropStates.cbegin(), aPropStates.cend(),
424 [](const XMLPropertyState& rProp) { return rProp.mnIndex != -1; });
427 if(nCount == 0)
429 // no hard attributes, use parent style name for export
430 aShapeInfo.msStyleName = aParentName;
432 else
434 // there are filtered properties -> hard attributes
435 // try to find this style in AutoStylePool
436 aShapeInfo.msStyleName = mrExport.GetAutoStylePool()->Find(aShapeInfo.mnFamily, aParentName, aPropStates);
438 if(aShapeInfo.msStyleName.isEmpty())
440 // Style did not exist, add it to AutoStalePool
441 aShapeInfo.msStyleName = mrExport.GetAutoStylePool()->Add(aShapeInfo.mnFamily, aParentName, std::move(aPropStates));
445 // optionally generate auto style for text attributes
446 if( (!bIsEmptyPresObj || (aShapeInfo.meShapeType != XmlShapeType::PresPageShape)) && bObjSupportsText )
448 aPropStates = GetExport().GetTextParagraphExport()->GetParagraphPropertyMapper()->Filter(mrExport, xPropSet);
450 // yet more additionally, we need to care for the ParaAdjust property
451 if ( XmlShapeType::DrawControlShape == aShapeInfo.meShapeType )
453 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
454 uno::Reference< beans::XPropertyState > xPropState( xPropSet, uno::UNO_QUERY );
455 if ( xPropSetInfo.is() && xPropState.is() )
457 // this is because:
458 // * if controls shapes have a ParaAdjust property, then this is the Align property of the control model
459 // * control models are allowed to have an Align of "void"
460 // * the Default for control model's Align is TextAlign_LEFT
461 // * defaults for style properties are not written, but we need to write the "left",
462 // because we need to distinguish this "left" from the case where not align attribute
463 // is present which means "void"
464 if ( xPropSetInfo->hasPropertyByName( "ParaAdjust" )
465 && ( beans::PropertyState_DEFAULT_VALUE == xPropState->getPropertyState( "ParaAdjust" ) )
468 sal_Int32 nIndex = GetExport().GetTextParagraphExport()->GetParagraphPropertyMapper()->getPropertySetMapper()->FindEntryIndex( CTF_SD_SHAPE_PARA_ADJUST );
469 // TODO : this retrieval of the index should be moved into the ctor, holding the index
470 // as member, thus saving time.
471 DBG_ASSERT(-1 != nIndex, "XMLShapeExport::collectShapeAutoStyles: could not obtain the index for the ParaAdjust context id!");
473 uno::Any aParaAdjustValue = xPropSet->getPropertyValue( "ParaAdjust" );
474 XMLPropertyState aAlignDefaultState( nIndex, aParaAdjustValue );
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, "", aPropStates );
487 if(aShapeInfo.msTextStyleName.isEmpty())
489 // Style did not exist, add it to AutoStalePool
490 aShapeInfo.msTextStyleName = mrExport.GetAutoStylePool()->Add(XmlStyleFamily::TEXT_PARAGRAPH, "", 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("LayerName") >>= 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 layers.erase(std::remove_if(layers.begin(), layers.end(),
1050 [](Layer const& rLayer) { return rLayer.shapes.empty(); }),
1051 layers.end());
1052 bool isSorted(true);
1053 for (size_t i = 1; i < layers.size(); ++i)
1055 assert(layers[i].nMin != layers[i-1].nMax); // unique!
1056 if (layers[i].nMin < layers[i-1].nMax)
1058 isSorted = false;
1059 break;
1062 if (isSorted)
1064 return; // nothing to do
1066 uno::Sequence<sal_Int32> aNewOrder(nCount);
1067 auto iterInsert(aNewOrder.getArray());
1068 for (auto const& rLayer : layers)
1070 assert(rLayer.nMin <= rLayer.nMax); // empty layers have been removed
1071 iterInsert = std::copy(rLayer.shapes.begin(), rLayer.shapes.end(), iterInsert);
1075 xShapes3->sort(aNewOrder);
1077 catch (uno::Exception const&)
1079 SAL_WARN("xmloff", "FixZOrder: exception");
1083 } // namespace xmloff
1085 void XMLShapeExport::seekShapes( const uno::Reference< drawing::XShapes >& xShapes ) noexcept
1087 if( xShapes.is() )
1089 maCurrentShapesIter = maShapesInfos.find( xShapes );
1090 if( maCurrentShapesIter == maShapesInfos.end() )
1092 auto itPair = maShapesInfos.emplace( xShapes, ImplXMLShapeExportInfoVector( static_cast<ShapesInfos::size_type>(xShapes->getCount()) ) );
1094 maCurrentShapesIter = itPair.first;
1096 SAL_WARN_IF( maCurrentShapesIter == maShapesInfos.end(), "xmloff", "XMLShapeExport::seekShapes(): insert into stl::map failed" );
1099 SAL_WARN_IF( (*maCurrentShapesIter).second.size() != static_cast<ShapesInfos::size_type>(xShapes->getCount()), "xmloff", "XMLShapeExport::seekShapes(): XShapes size varied between calls" );
1102 else
1104 maCurrentShapesIter = maShapesInfos.end();
1108 void XMLShapeExport::exportAutoStyles()
1110 // export all autostyle infos
1112 // ...for graphic
1114 GetExport().GetAutoStylePool()->exportXML( XmlStyleFamily::SD_GRAPHICS_ID );
1117 // ...for presentation
1119 GetExport().GetAutoStylePool()->exportXML( XmlStyleFamily::SD_PRESENTATION_ID );
1122 if( mxShapeTableExport.is() )
1123 mxShapeTableExport->exportAutoStyles();
1126 /// returns the export property mapper for external chaining
1127 SvXMLExportPropertyMapper* XMLShapeExport::CreateShapePropMapper(
1128 SvXMLExport& rExport )
1130 rtl::Reference< XMLPropertyHandlerFactory > xFactory = new XMLSdPropHdlFactory( rExport.GetModel(), rExport );
1131 rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( xFactory, true );
1132 rExport.GetTextParagraphExport(); // get or create text paragraph export
1133 SvXMLExportPropertyMapper* pResult =
1134 new XMLShapeExportPropertyMapper( xMapper, rExport );
1135 // chain text attributes
1136 return pResult;
1139 void XMLShapeExport::ImpCalcShapeType(const uno::Reference< drawing::XShape >& xShape,
1140 XmlShapeType& eShapeType)
1142 // set in every case, so init here
1143 eShapeType = XmlShapeType::Unknown;
1145 if(!xShape.is())
1146 return;
1148 OUString aType(xShape->getShapeType());
1150 if(!aType.match("com.sun.star."))
1151 return;
1153 if(aType.match("drawing.", 13))
1155 // drawing shapes
1156 if (aType.match("Rectangle", 21)) { eShapeType = XmlShapeType::DrawRectangleShape; }
1158 // #i72177# Note: Correcting CustomShape, CustomShape->Custom, len from 9 (was wrong anyways) to 6.
1159 // As can be seen at the other compares, the appendix "Shape" is left out of the comparison.
1160 else if(aType.match("Custom", 21)) { eShapeType = XmlShapeType::DrawCustomShape; }
1162 else if(aType.match("Ellipse", 21)) { eShapeType = XmlShapeType::DrawEllipseShape; }
1163 else if(aType.match("Control", 21)) { eShapeType = XmlShapeType::DrawControlShape; }
1164 else if(aType.match("Connector", 21)) { eShapeType = XmlShapeType::DrawConnectorShape; }
1165 else if(aType.match("Measure", 21)) { eShapeType = XmlShapeType::DrawMeasureShape; }
1166 else if(aType.match("Line", 21)) { eShapeType = XmlShapeType::DrawLineShape; }
1168 // #i72177# Note: This covers two types by purpose, PolyPolygonShape and PolyPolygonPathShape
1169 else if(aType.match("PolyPolygon", 21)) { eShapeType = XmlShapeType::DrawPolyPolygonShape; }
1171 // #i72177# Note: This covers two types by purpose, PolyLineShape and PolyLinePathShape
1172 else if(aType.match("PolyLine", 21)) { eShapeType = XmlShapeType::DrawPolyLineShape; }
1174 else if(aType.match("OpenBezier", 21)) { eShapeType = XmlShapeType::DrawOpenBezierShape; }
1175 else if(aType.match("ClosedBezier", 21)) { eShapeType = XmlShapeType::DrawClosedBezierShape; }
1177 // #i72177# FreeHand (opened and closed) now supports the types OpenFreeHandShape and
1178 // ClosedFreeHandShape respectively. Represent them as bezier shapes
1179 else if(aType.match("OpenFreeHand", 21)) { eShapeType = XmlShapeType::DrawOpenBezierShape; }
1180 else if(aType.match("ClosedFreeHand", 21)) { eShapeType = XmlShapeType::DrawClosedBezierShape; }
1182 else if(aType.match("GraphicObject", 21)) { eShapeType = XmlShapeType::DrawGraphicObjectShape; }
1183 else if(aType.match("Group", 21)) { eShapeType = XmlShapeType::DrawGroupShape; }
1184 else if(aType.match("Text", 21)) { eShapeType = XmlShapeType::DrawTextShape; }
1185 else if(aType.match("OLE2", 21))
1187 eShapeType = XmlShapeType::DrawOLE2Shape;
1189 // get info about presentation shape
1190 uno::Reference <beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1192 if(xPropSet.is())
1194 OUString sCLSID;
1195 if(xPropSet->getPropertyValue("CLSID") >>= sCLSID)
1197 #if !ENABLE_WASM_STRIP_CHART
1198 // WASM_CHART change
1199 // TODO: With Chart extracted this cannot really happen since
1200 // no Chart could've been added at all
1201 if (sCLSID == mrExport.GetChartExport()->getChartCLSID() ||
1202 #else
1204 #endif
1205 sCLSID == SvGlobalName( SO3_RPTCH_CLASSID ).GetHexName() )
1207 eShapeType = XmlShapeType::DrawChartShape;
1209 else if (sCLSID == SvGlobalName( SO3_SC_CLASSID ).GetHexName() )
1211 eShapeType = XmlShapeType::DrawSheetShape;
1213 else
1215 // general OLE2 Object
1220 else if(aType.match("Page", 21)) { eShapeType = XmlShapeType::DrawPageShape; }
1221 else if(aType.match("Frame", 21)) { eShapeType = XmlShapeType::DrawFrameShape; }
1222 else if(aType.match("Caption", 21)) { eShapeType = XmlShapeType::DrawCaptionShape; }
1223 else if(aType.match("Plugin", 21)) { eShapeType = XmlShapeType::DrawPluginShape; }
1224 else if(aType.match("Applet", 21)) { eShapeType = XmlShapeType::DrawAppletShape; }
1225 else if(aType.match("MediaShape", 21)) { eShapeType = XmlShapeType::DrawMediaShape; }
1226 else if(aType.match("TableShape", 21)) { eShapeType = XmlShapeType::DrawTableShape; }
1228 // 3D shapes
1229 else if(aType.match("Scene", 21 + 7)) { eShapeType = XmlShapeType::Draw3DSceneObject; }
1230 else if(aType.match("Cube", 21 + 7)) { eShapeType = XmlShapeType::Draw3DCubeObject; }
1231 else if(aType.match("Sphere", 21 + 7)) { eShapeType = XmlShapeType::Draw3DSphereObject; }
1232 else if(aType.match("Lathe", 21 + 7)) { eShapeType = XmlShapeType::Draw3DLatheObject; }
1233 else if(aType.match("Extrude", 21 + 7)) { eShapeType = XmlShapeType::Draw3DExtrudeObject; }
1235 else if(aType.match("presentation.", 13))
1237 // presentation shapes
1238 if (aType.match("TitleText", 26)) { eShapeType = XmlShapeType::PresTitleTextShape; }
1239 else if(aType.match("Outliner", 26)) { eShapeType = XmlShapeType::PresOutlinerShape; }
1240 else if(aType.match("Subtitle", 26)) { eShapeType = XmlShapeType::PresSubtitleShape; }
1241 else if(aType.match("GraphicObject", 26)) { eShapeType = XmlShapeType::PresGraphicObjectShape; }
1242 else if(aType.match("Page", 26)) { eShapeType = XmlShapeType::PresPageShape; }
1243 else if(aType.match("OLE2", 26))
1245 eShapeType = XmlShapeType::PresOLE2Shape;
1247 // get info about presentation shape
1248 uno::Reference <beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1250 if(xPropSet.is()) try
1252 OUString sCLSID;
1253 if(xPropSet->getPropertyValue("CLSID") >>= sCLSID)
1255 if( sCLSID == SvGlobalName( SO3_SC_CLASSID ).GetHexName() )
1257 eShapeType = XmlShapeType::PresSheetShape;
1261 catch(const uno::Exception&)
1263 SAL_WARN( "xmloff", "XMLShapeExport::ImpCalcShapeType(), expected ole shape to have the CLSID property?" );
1266 else if(aType.match("Chart", 26)) { eShapeType = XmlShapeType::PresChartShape; }
1267 else if(aType.match("OrgChart", 26)) { eShapeType = XmlShapeType::PresOrgChartShape; }
1268 else if(aType.match("CalcShape", 26)) { eShapeType = XmlShapeType::PresSheetShape; }
1269 else if(aType.match("TableShape", 26)) { eShapeType = XmlShapeType::PresTableShape; }
1270 else if(aType.match("Notes", 26)) { eShapeType = XmlShapeType::PresNotesShape; }
1271 else if(aType.match("HandoutShape", 26)) { eShapeType = XmlShapeType::HandoutShape; }
1272 else if(aType.match("HeaderShape", 26)) { eShapeType = XmlShapeType::PresHeaderShape; }
1273 else if(aType.match("FooterShape", 26)) { eShapeType = XmlShapeType::PresFooterShape; }
1274 else if(aType.match("SlideNumberShape", 26)) { eShapeType = XmlShapeType::PresSlideNumberShape; }
1275 else if(aType.match("DateTimeShape", 26)) { eShapeType = XmlShapeType::PresDateTimeShape; }
1276 else if(aType.match("MediaShape", 26)) { eShapeType = XmlShapeType::PresMediaShape; }
1280 /** exports all user defined gluepoints */
1281 void XMLShapeExport::ImpExportGluePoints( const uno::Reference< drawing::XShape >& xShape )
1283 uno::Reference< drawing::XGluePointsSupplier > xSupplier( xShape, uno::UNO_QUERY );
1284 if( !xSupplier.is() )
1285 return;
1287 uno::Reference< container::XIdentifierAccess > xGluePoints( xSupplier->getGluePoints(), uno::UNO_QUERY );
1288 if( !xGluePoints.is() )
1289 return;
1291 drawing::GluePoint2 aGluePoint;
1293 const uno::Sequence< sal_Int32 > aIdSequence( xGluePoints->getIdentifiers() );
1295 for( const sal_Int32 nIdentifier : aIdSequence )
1297 if( (xGluePoints->getByIdentifier( nIdentifier ) >>= aGluePoint) && aGluePoint.IsUserDefined )
1299 // export only user defined gluepoints
1301 const OUString sId( OUString::number( nIdentifier ) );
1302 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_ID, sId );
1304 mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
1305 aGluePoint.Position.X);
1306 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, msBuffer.makeStringAndClear());
1308 mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
1309 aGluePoint.Position.Y);
1310 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, msBuffer.makeStringAndClear());
1312 if( !aGluePoint.IsRelative )
1314 SvXMLUnitConverter::convertEnum( msBuffer, aGluePoint.PositionAlignment, aXML_GlueAlignment_EnumMap );
1315 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ALIGN, msBuffer.makeStringAndClear() );
1318 if( aGluePoint.Escape != drawing::EscapeDirection_SMART )
1320 SvXMLUnitConverter::convertEnum( msBuffer, aGluePoint.Escape, aXML_GlueEscapeDirection_EnumMap );
1321 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ESCAPE_DIRECTION, msBuffer.makeStringAndClear() );
1324 SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_DRAW, XML_GLUE_POINT, true, true);
1329 void XMLShapeExport::ImpExportSignatureLine(const uno::Reference<drawing::XShape>& xShape)
1331 uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1333 bool bIsSignatureLine = false;
1334 xPropSet->getPropertyValue("IsSignatureLine") >>= bIsSignatureLine;
1335 if (!bIsSignatureLine)
1336 return;
1338 OUString aSignatureLineId;
1339 xPropSet->getPropertyValue("SignatureLineId") >>= aSignatureLineId;
1340 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_ID, aSignatureLineId);
1342 OUString aSuggestedSignerName;
1343 xPropSet->getPropertyValue("SignatureLineSuggestedSignerName") >>= aSuggestedSignerName;
1344 if (!aSuggestedSignerName.isEmpty())
1345 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_NAME, aSuggestedSignerName);
1347 OUString aSuggestedSignerTitle;
1348 xPropSet->getPropertyValue("SignatureLineSuggestedSignerTitle") >>= aSuggestedSignerTitle;
1349 if (!aSuggestedSignerTitle.isEmpty())
1350 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_TITLE, aSuggestedSignerTitle);
1352 OUString aSuggestedSignerEmail;
1353 xPropSet->getPropertyValue("SignatureLineSuggestedSignerEmail") >>= aSuggestedSignerEmail;
1354 if (!aSuggestedSignerEmail.isEmpty())
1355 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_EMAIL, aSuggestedSignerEmail);
1357 OUString aSigningInstructions;
1358 xPropSet->getPropertyValue("SignatureLineSigningInstructions") >>= aSigningInstructions;
1359 if (!aSigningInstructions.isEmpty())
1360 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SIGNING_INSTRUCTIONS, aSigningInstructions);
1362 bool bShowSignDate = false;
1363 xPropSet->getPropertyValue("SignatureLineShowSignDate") >>= bShowSignDate;
1364 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SHOW_SIGN_DATE,
1365 bShowSignDate ? XML_TRUE : XML_FALSE);
1367 bool bCanAddComment = false;
1368 xPropSet->getPropertyValue("SignatureLineCanAddComment") >>= bCanAddComment;
1369 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_CAN_ADD_COMMENT,
1370 bCanAddComment ? XML_TRUE : XML_FALSE);
1372 SvXMLElementExport aSignatureLineElement(mrExport, XML_NAMESPACE_LO_EXT, XML_SIGNATURELINE, true,
1373 true);
1376 void XMLShapeExport::ImpExportQRCode(const uno::Reference<drawing::XShape>& xShape)
1378 uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1380 uno::Any aAny = xPropSet->getPropertyValue("BarCodeProperties");
1382 css::drawing::BarCode aBarCode;
1383 if(!(aAny >>= aBarCode))
1384 return;
1386 mrExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_STRING_VALUE, aBarCode.Payload);
1387 /* Export QR Code as per customised schema, @see OpenDocument-schema-v1.3+libreoffice */
1388 OUString temp;
1389 switch(aBarCode.ErrorCorrection){
1390 case css::drawing::BarCodeErrorCorrection::LOW :
1391 temp = "low";
1392 break;
1393 case css::drawing::BarCodeErrorCorrection::MEDIUM:
1394 temp = "medium";
1395 break;
1396 case css::drawing::BarCodeErrorCorrection::QUARTILE:
1397 temp = "quartile";
1398 break;
1399 case css::drawing::BarCodeErrorCorrection::HIGH:
1400 temp = "high";
1401 break;
1403 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_ERROR_CORRECTION, temp);
1404 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_BORDER, OUStringBuffer(20).append(aBarCode.Border).makeStringAndClear());
1405 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_TYPE, OUStringBuffer(20).append(aBarCode.Type).makeStringAndClear());
1407 SvXMLElementExport aBarCodeElement(mrExport, XML_NAMESPACE_LO_EXT, XML_QRCODE, true,
1408 true);
1411 void XMLShapeExport::ExportGraphicDefaults()
1413 rtl::Reference<XMLStyleExport> aStEx(new XMLStyleExport(mrExport, mrExport.GetAutoStylePool().get()));
1415 // construct PropertySetMapper
1416 rtl::Reference< SvXMLExportPropertyMapper > xPropertySetMapper( CreateShapePropMapper( mrExport ) );
1417 static_cast<XMLShapeExportPropertyMapper*>(xPropertySetMapper.get())->SetAutoStyles( false );
1419 // chain text attributes
1420 xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(mrExport));
1422 // chain special Writer/text frame default attributes
1423 xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaDefaultExtPropMapper(mrExport));
1425 // write graphic family default style
1426 uno::Reference< lang::XMultiServiceFactory > xFact( mrExport.GetModel(), uno::UNO_QUERY );
1427 if( !xFact.is() )
1428 return;
1432 uno::Reference< beans::XPropertySet > xDefaults( xFact->createInstance("com.sun.star.drawing.Defaults"), uno::UNO_QUERY );
1433 if( xDefaults.is() )
1435 aStEx->exportDefaultStyle( xDefaults, XML_STYLE_FAMILY_SD_GRAPHICS_NAME, xPropertySetMapper );
1437 // write graphic styles (family name differs depending on the module)
1438 aStEx->exportStyleFamily("graphics", OUString(XML_STYLE_FAMILY_SD_GRAPHICS_NAME), xPropertySetMapper, false, XmlStyleFamily::SD_GRAPHICS_ID);
1439 aStEx->exportStyleFamily("GraphicStyles", OUString(XML_STYLE_FAMILY_SD_GRAPHICS_NAME), xPropertySetMapper, false, XmlStyleFamily::SD_GRAPHICS_ID);
1442 catch(const lang::ServiceNotRegisteredException&)
1447 void XMLShapeExport::onExport( const css::uno::Reference < css::drawing::XShape >& )
1451 const rtl::Reference< XMLTableExport >& XMLShapeExport::GetShapeTableExport()
1453 if( !mxShapeTableExport.is() )
1455 rtl::Reference< XMLPropertyHandlerFactory > xFactory( new XMLSdPropHdlFactory( mrExport.GetModel(), mrExport ) );
1456 rtl::Reference < XMLPropertySetMapper > xMapper( new XMLShapePropertySetMapper( xFactory, true ) );
1457 mrExport.GetTextParagraphExport(); // get or create text paragraph export
1458 rtl::Reference< SvXMLExportPropertyMapper > xPropertySetMapper( new XMLShapeExportPropertyMapper( xMapper, mrExport ) );
1459 mxShapeTableExport = new XMLTableExport( mrExport, xPropertySetMapper, xFactory );
1462 return mxShapeTableExport;
1465 void XMLShapeExport::ImpExportNewTrans(const uno::Reference< beans::XPropertySet >& xPropSet,
1466 XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
1468 // get matrix
1469 ::basegfx::B2DHomMatrix aMatrix;
1470 ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
1472 // decompose and correct about pRefPoint
1473 ::basegfx::B2DTuple aTRScale;
1474 double fTRShear(0.0);
1475 double fTRRotate(0.0);
1476 ::basegfx::B2DTuple aTRTranslate;
1477 ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
1479 // use features and write
1480 ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures);
1483 void XMLShapeExport::ImpExportNewTrans_GetB2DHomMatrix(::basegfx::B2DHomMatrix& rMatrix,
1484 const uno::Reference< beans::XPropertySet >& xPropSet)
1486 /* Get <TransformationInHoriL2R>, if it exist
1487 and if the document is exported into the OpenOffice.org file format.
1488 This property only exists at service css::text::Shape - the
1489 Writer UNO service for shapes.
1490 This code is needed, because the positioning attributes in the
1491 OpenOffice.org file format are given in horizontal left-to-right layout
1492 regardless the layout direction the shape is in. In the OASIS Open Office
1493 file format the positioning attributes are correctly given in the layout
1494 direction the shape is in. Thus, this code provides the conversion from
1495 the OASIS Open Office file format to the OpenOffice.org file format. (#i28749#)
1497 uno::Any aAny;
1498 if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
1499 xPropSet->getPropertySetInfo()->hasPropertyByName("TransformationInHoriL2R") )
1501 aAny = xPropSet->getPropertyValue("TransformationInHoriL2R");
1503 else
1505 aAny = xPropSet->getPropertyValue("Transformation");
1507 drawing::HomogenMatrix3 aMatrix;
1508 aAny >>= aMatrix;
1510 rMatrix.set(0, 0, aMatrix.Line1.Column1);
1511 rMatrix.set(0, 1, aMatrix.Line1.Column2);
1512 rMatrix.set(0, 2, aMatrix.Line1.Column3);
1513 rMatrix.set(1, 0, aMatrix.Line2.Column1);
1514 rMatrix.set(1, 1, aMatrix.Line2.Column2);
1515 rMatrix.set(1, 2, aMatrix.Line2.Column3);
1516 rMatrix.set(2, 0, aMatrix.Line3.Column1);
1517 rMatrix.set(2, 1, aMatrix.Line3.Column2);
1518 rMatrix.set(2, 2, aMatrix.Line3.Column3);
1521 void XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint(const ::basegfx::B2DHomMatrix& rMatrix, ::basegfx::B2DTuple& rTRScale,
1522 double& fTRShear, double& fTRRotate, ::basegfx::B2DTuple& rTRTranslate, css::awt::Point* pRefPoint)
1524 // decompose matrix
1525 rMatrix.decompose(rTRScale, rTRTranslate, fTRRotate, fTRShear);
1527 // correct translation about pRefPoint
1528 if(pRefPoint)
1530 rTRTranslate -= ::basegfx::B2DTuple(pRefPoint->X, pRefPoint->Y);
1534 void XMLShapeExport::ImpExportNewTrans_FeaturesAndWrite(::basegfx::B2DTuple const & rTRScale, double fTRShear,
1535 double fTRRotate, ::basegfx::B2DTuple const & rTRTranslate, const XMLShapeExportFlags nFeatures)
1537 // always write Size (rTRScale) since this statement carries the union
1538 // of the object
1539 OUString aStr;
1540 OUStringBuffer sStringBuffer;
1541 ::basegfx::B2DTuple aTRScale(rTRScale);
1543 // svg: width
1544 if(!(nFeatures & XMLShapeExportFlags::WIDTH))
1546 aTRScale.setX(1.0);
1548 else
1550 if( aTRScale.getX() > 0.0 )
1551 aTRScale.setX(aTRScale.getX() - 1.0);
1552 else if( aTRScale.getX() < 0.0 )
1553 aTRScale.setX(aTRScale.getX() + 1.0);
1556 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1557 FRound(aTRScale.getX()));
1558 aStr = sStringBuffer.makeStringAndClear();
1559 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, aStr);
1561 // svg: height
1562 if(!(nFeatures & XMLShapeExportFlags::HEIGHT))
1564 aTRScale.setY(1.0);
1566 else
1568 if( aTRScale.getY() > 0.0 )
1569 aTRScale.setY(aTRScale.getY() - 1.0);
1570 else if( aTRScale.getY() < 0.0 )
1571 aTRScale.setY(aTRScale.getY() + 1.0);
1574 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1575 FRound(aTRScale.getY()));
1576 aStr = sStringBuffer.makeStringAndClear();
1577 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, aStr);
1579 // decide if transformation is necessary
1580 bool bTransformationIsNecessary(fTRShear != 0.0 || fTRRotate != 0.0);
1582 if(bTransformationIsNecessary)
1584 // write transformation, but WITHOUT scale which is exported as size above
1585 SdXMLImExTransform2D aTransform;
1587 aTransform.AddSkewX(atan(fTRShear));
1589 // #i78696#
1590 // fTRRotate is mathematically correct, but due to the error
1591 // we export/import it mirrored. Since the API implementation is fixed and
1592 // uses the correctly oriented angle, it is necessary for compatibility to
1593 // mirror the angle here to stay at the old behaviour. There is a follow-up
1594 // task (#i78698#) to fix this in the next ODF FileFormat version
1595 aTransform.AddRotate(-fTRRotate);
1597 aTransform.AddTranslate(rTRTranslate);
1599 // does transformation need to be exported?
1600 if(aTransform.NeedsAction())
1601 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
1603 else
1605 // no shear, no rotate; just add object position to export and we are done
1606 if(nFeatures & XMLShapeExportFlags::X)
1608 // svg: x
1609 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1610 FRound(rTRTranslate.getX()));
1611 aStr = sStringBuffer.makeStringAndClear();
1612 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, aStr);
1615 if(nFeatures & XMLShapeExportFlags::Y)
1617 // svg: y
1618 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1619 FRound(rTRTranslate.getY()));
1620 aStr = sStringBuffer.makeStringAndClear();
1621 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, aStr);
1626 bool XMLShapeExport::ImpExportPresentationAttributes( const uno::Reference< beans::XPropertySet >& xPropSet, const OUString& rClass )
1628 bool bIsEmpty = false;
1630 // write presentation class entry
1631 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS, rClass);
1633 if( xPropSet.is() )
1635 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
1638 // is empty pres. shape?
1639 if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsEmptyPresentationObject"))
1641 xPropSet->getPropertyValue("IsEmptyPresentationObject") >>= bIsEmpty;
1642 if( bIsEmpty )
1643 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PLACEHOLDER, XML_TRUE);
1646 // is user-transformed?
1647 if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsPlaceholderDependent"))
1649 bool bTemp = false;
1650 xPropSet->getPropertyValue("IsPlaceholderDependent") >>= bTemp;
1651 if(!bTemp)
1652 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_USER_TRANSFORMED, XML_TRUE);
1656 return bIsEmpty;
1659 void XMLShapeExport::ImpExportText( const uno::Reference< drawing::XShape >& xShape, TextPNS eExtensionNS )
1661 if (eExtensionNS == TextPNS::EXTENSION)
1663 if ((mrExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
1665 return; // do not export to ODF 1.1/1.2/1.3
1668 uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY );
1669 if( xText.is() )
1671 uno::Reference< container::XEnumerationAccess > xEnumAccess( xShape, uno::UNO_QUERY );
1672 if( xEnumAccess.is() && xEnumAccess->hasElements() )
1673 mrExport.GetTextParagraphExport()->exportText( xText, false, true, eExtensionNS );
1677 namespace {
1679 enum class Found {
1680 NONE = 0x0000,
1681 CLICKACTION = 0x0001,
1682 BOOKMARK = 0x0002,
1683 EFFECT = 0x0004,
1684 PLAYFULL = 0x0008,
1685 VERB = 0x0010,
1686 SOUNDURL = 0x0020,
1687 SPEED = 0x0040,
1688 CLICKEVENTTYPE = 0x0080,
1689 MACRO = 0x0100,
1690 LIBRARY = 0x0200,
1695 namespace o3tl {
1696 template<> struct typed_flags<Found> : is_typed_flags<Found, 0x03ff> {};
1699 void XMLShapeExport::ImpExportEvents( const uno::Reference< drawing::XShape >& xShape )
1701 uno::Reference< document::XEventsSupplier > xEventsSupplier( xShape, uno::UNO_QUERY );
1702 if( !xEventsSupplier.is() )
1703 return;
1705 uno::Reference< container::XNameAccess > xEvents = xEventsSupplier->getEvents();
1706 SAL_WARN_IF( !xEvents.is(), "xmloff", "XEventsSupplier::getEvents() returned NULL" );
1707 if( !xEvents.is() )
1708 return;
1710 Found nFound = Found::NONE;
1712 OUString aClickEventType;
1713 presentation::ClickAction eClickAction = presentation::ClickAction_NONE;
1714 presentation::AnimationEffect eEffect = presentation::AnimationEffect_NONE;
1715 presentation::AnimationSpeed eSpeed = presentation::AnimationSpeed_SLOW;
1716 OUString aStrSoundURL;
1717 bool bPlayFull = false;
1718 sal_Int32 nVerb = 0;
1719 OUString aStrMacro;
1720 OUString aStrLibrary;
1721 OUString aStrBookmark;
1723 uno::Sequence< beans::PropertyValue > aClickProperties;
1724 if( xEvents->hasByName( gsOnClick ) && (xEvents->getByName( gsOnClick ) >>= aClickProperties) )
1726 for( const auto& rProperty : std::as_const(aClickProperties) )
1728 if( !( nFound & Found::CLICKEVENTTYPE ) && rProperty.Name == gsEventType )
1730 if( rProperty.Value >>= aClickEventType )
1731 nFound |= Found::CLICKEVENTTYPE;
1733 else if( !( nFound & Found::CLICKACTION ) && rProperty.Name == gsClickAction )
1735 if( rProperty.Value >>= eClickAction )
1736 nFound |= Found::CLICKACTION;
1738 else if( !( nFound & Found::MACRO ) && ( rProperty.Name == gsMacroName || rProperty.Name == gsScript ) )
1740 if( rProperty.Value >>= aStrMacro )
1741 nFound |= Found::MACRO;
1743 else if( !( nFound & Found::LIBRARY ) && rProperty.Name == gsLibrary )
1745 if( rProperty.Value >>= aStrLibrary )
1746 nFound |= Found::LIBRARY;
1748 else if( !( nFound & Found::EFFECT ) && rProperty.Name == gsEffect )
1750 if( rProperty.Value >>= eEffect )
1751 nFound |= Found::EFFECT;
1753 else if( !( nFound & Found::BOOKMARK ) && rProperty.Name == gsBookmark )
1755 if( rProperty.Value >>= aStrBookmark )
1756 nFound |= Found::BOOKMARK;
1758 else if( !( nFound & Found::SPEED ) && rProperty.Name == gsSpeed )
1760 if( rProperty.Value >>= eSpeed )
1761 nFound |= Found::SPEED;
1763 else if( !( nFound & Found::SOUNDURL ) && rProperty.Name == gsSoundURL )
1765 if( rProperty.Value >>= aStrSoundURL )
1766 nFound |= Found::SOUNDURL;
1768 else if( !( nFound & Found::PLAYFULL ) && rProperty.Name == gsPlayFull )
1770 if( rProperty.Value >>= bPlayFull )
1771 nFound |= Found::PLAYFULL;
1773 else if( !( nFound & Found::VERB ) && rProperty.Name == gsVerb )
1775 if( rProperty.Value >>= nVerb )
1776 nFound |= Found::VERB;
1781 // create the XML elements
1783 if( aClickEventType == gsPresentation )
1785 if( !(nFound & Found::CLICKACTION) || (eClickAction == presentation::ClickAction_NONE) )
1786 return;
1788 SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
1790 enum XMLTokenEnum eStrAction;
1792 switch( eClickAction )
1794 case presentation::ClickAction_PREVPAGE: eStrAction = XML_PREVIOUS_PAGE; break;
1795 case presentation::ClickAction_NEXTPAGE: eStrAction = XML_NEXT_PAGE; break;
1796 case presentation::ClickAction_FIRSTPAGE: eStrAction = XML_FIRST_PAGE; break;
1797 case presentation::ClickAction_LASTPAGE: eStrAction = XML_LAST_PAGE; break;
1798 case presentation::ClickAction_INVISIBLE: eStrAction = XML_HIDE; break;
1799 case presentation::ClickAction_STOPPRESENTATION:eStrAction = XML_STOP; break;
1800 case presentation::ClickAction_PROGRAM: eStrAction = XML_EXECUTE; break;
1801 case presentation::ClickAction_BOOKMARK: eStrAction = XML_SHOW; break;
1802 case presentation::ClickAction_DOCUMENT: eStrAction = XML_SHOW; break;
1803 case presentation::ClickAction_MACRO: eStrAction = XML_EXECUTE_MACRO; break;
1804 case presentation::ClickAction_VERB: eStrAction = XML_VERB; break;
1805 case presentation::ClickAction_VANISH: eStrAction = XML_FADE_OUT; break;
1806 case presentation::ClickAction_SOUND: eStrAction = XML_SOUND; break;
1807 default:
1808 OSL_FAIL( "unknown presentation::ClickAction found!" );
1809 eStrAction = XML_UNKNOWN;
1812 OUString aEventQName(
1813 mrExport.GetNamespaceMap().GetQNameByKey(
1814 XML_NAMESPACE_DOM, "click" ) );
1815 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
1816 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_ACTION, eStrAction );
1818 if( eClickAction == presentation::ClickAction_VANISH )
1820 if( nFound & Found::EFFECT )
1822 XMLEffect eKind;
1823 XMLEffectDirection eDirection;
1824 sal_Int16 nStartScale;
1825 bool bIn;
1827 SdXMLImplSetEffect( eEffect, eKind, eDirection, nStartScale, bIn );
1829 if( eKind != EK_none )
1831 SvXMLUnitConverter::convertEnum( msBuffer, eKind, aXML_AnimationEffect_EnumMap );
1832 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_EFFECT, msBuffer.makeStringAndClear() );
1835 if( eDirection != ED_none )
1837 SvXMLUnitConverter::convertEnum( msBuffer, eDirection, aXML_AnimationDirection_EnumMap );
1838 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_DIRECTION, msBuffer.makeStringAndClear() );
1841 if( nStartScale != -1 )
1843 ::sax::Converter::convertPercent( msBuffer, nStartScale );
1844 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_START_SCALE, msBuffer.makeStringAndClear() );
1848 if( nFound & Found::SPEED && eEffect != presentation::AnimationEffect_NONE )
1850 if( eSpeed != presentation::AnimationSpeed_MEDIUM )
1852 SvXMLUnitConverter::convertEnum( msBuffer, eSpeed, aXML_AnimationSpeed_EnumMap );
1853 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_SPEED, msBuffer.makeStringAndClear() );
1858 if( eClickAction == presentation::ClickAction_PROGRAM ||
1859 eClickAction == presentation::ClickAction_BOOKMARK ||
1860 eClickAction == presentation::ClickAction_DOCUMENT )
1862 if( eClickAction == presentation::ClickAction_BOOKMARK )
1863 msBuffer.append( '#' );
1865 msBuffer.append( aStrBookmark );
1866 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(msBuffer.makeStringAndClear()) );
1867 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
1868 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
1869 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST );
1872 if( ( nFound & Found::VERB ) && eClickAction == presentation::ClickAction_VERB )
1874 msBuffer.append( nVerb );
1875 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_VERB, msBuffer.makeStringAndClear());
1878 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_PRESENTATION, XML_EVENT_LISTENER, true, true);
1880 if( eClickAction == presentation::ClickAction_VANISH || eClickAction == presentation::ClickAction_SOUND )
1882 if( ( nFound & Found::SOUNDURL ) && !aStrSoundURL.isEmpty() )
1884 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStrSoundURL) );
1885 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
1886 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_NEW );
1887 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST );
1888 if( nFound & Found::PLAYFULL && bPlayFull )
1889 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PLAY_FULL, XML_TRUE );
1891 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_PRESENTATION, XML_SOUND, true, true );
1895 else if( aClickEventType == gsStarBasic )
1897 if( nFound & Found::MACRO )
1899 SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
1901 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE,
1902 mrExport.GetNamespaceMap().GetQNameByKey(
1903 XML_NAMESPACE_OOO,
1904 "starbasic" ) );
1905 OUString aEventQName(
1906 mrExport.GetNamespaceMap().GetQNameByKey(
1907 XML_NAMESPACE_DOM, "click" ) );
1908 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
1910 if( nFound & Found::LIBRARY )
1912 const OUString& sLocation( GetXMLToken(
1913 (aStrLibrary.equalsIgnoreAsciiCase("StarOffice") ||
1914 aStrLibrary.equalsIgnoreAsciiCase("application") ) ? XML_APPLICATION
1915 : XML_DOCUMENT ) );
1916 mrExport.AddAttribute(XML_NAMESPACE_SCRIPT, XML_MACRO_NAME,
1917 sLocation + ":" + aStrMacro);
1919 else
1921 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_MACRO_NAME, aStrMacro );
1924 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, true, true);
1927 else if( aClickEventType == gsScript )
1929 if( nFound & Found::MACRO )
1931 SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
1933 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE, mrExport.GetNamespaceMap().GetQNameByKey(
1934 XML_NAMESPACE_OOO, GetXMLToken(XML_SCRIPT) ) );
1935 OUString aEventQName(
1936 mrExport.GetNamespaceMap().GetQNameByKey(
1937 XML_NAMESPACE_DOM, "click" ) );
1938 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
1939 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aStrMacro );
1940 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, "simple" );
1942 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, true, true);
1947 /** #i68101# export shape Title and Description */
1948 void XMLShapeExport::ImpExportDescription( const uno::Reference< drawing::XShape >& xShape )
1952 OUString aTitle;
1953 OUString aDescription;
1955 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY_THROW );
1956 xProps->getPropertyValue("Title") >>= aTitle;
1957 xProps->getPropertyValue("Description") >>= aDescription;
1959 if(!aTitle.isEmpty())
1961 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_TITLE, true, false);
1962 mrExport.Characters( aTitle );
1965 if(!aDescription.isEmpty())
1967 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_DESC, true, false );
1968 mrExport.Characters( aDescription );
1971 catch( uno::Exception& )
1973 DBG_UNHANDLED_EXCEPTION( "xmloff", "exporting Title and/or Description for shape" );
1977 void XMLShapeExport::ImpExportGroupShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
1979 uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY);
1980 if(!(xShapes.is() && xShapes->getCount()))
1981 return;
1983 // write group shape
1984 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
1985 SvXMLElementExport aPGR(mrExport, XML_NAMESPACE_DRAW, XML_G, bCreateNewline, true);
1987 ImpExportDescription( xShape ); // #i68101#
1988 ImpExportEvents( xShape );
1989 ImpExportGluePoints( xShape );
1991 // #89764# if export of position is suppressed for group shape,
1992 // positions of contained objects should be written relative to
1993 // the upper left edge of the group.
1994 awt::Point aUpperLeft;
1996 if(!(nFeatures & XMLShapeExportFlags::POSITION))
1998 nFeatures |= XMLShapeExportFlags::POSITION;
1999 aUpperLeft = xShape->getPosition();
2000 pRefPoint = &aUpperLeft;
2003 // write members
2004 exportShapes( xShapes, nFeatures, pRefPoint );
2007 void XMLShapeExport::ImpExportTextBoxShape(
2008 const uno::Reference< drawing::XShape >& xShape,
2009 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2011 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2012 if(!xPropSet.is())
2013 return;
2015 // presentation attribute (if presentation)
2016 bool bIsPresShape(false);
2017 bool bIsEmptyPresObj(false);
2018 OUString aStr;
2020 switch(eShapeType)
2022 case XmlShapeType::PresSubtitleShape:
2024 aStr = GetXMLToken(XML_SUBTITLE);
2025 bIsPresShape = true;
2026 break;
2028 case XmlShapeType::PresTitleTextShape:
2030 aStr = GetXMLToken(XML_TITLE);
2031 bIsPresShape = true;
2032 break;
2034 case XmlShapeType::PresOutlinerShape:
2036 aStr = GetXMLToken(XML_PRESENTATION_OUTLINE);
2037 bIsPresShape = true;
2038 break;
2040 case XmlShapeType::PresNotesShape:
2042 aStr = GetXMLToken(XML_NOTES);
2043 bIsPresShape = true;
2044 break;
2046 case XmlShapeType::PresHeaderShape:
2048 aStr = GetXMLToken(XML_HEADER);
2049 bIsPresShape = true;
2050 break;
2052 case XmlShapeType::PresFooterShape:
2054 aStr = GetXMLToken(XML_FOOTER);
2055 bIsPresShape = true;
2056 break;
2058 case XmlShapeType::PresSlideNumberShape:
2060 aStr = GetXMLToken(XML_PAGE_NUMBER);
2061 bIsPresShape = true;
2062 break;
2064 case XmlShapeType::PresDateTimeShape:
2066 aStr = GetXMLToken(XML_DATE_TIME);
2067 bIsPresShape = true;
2068 break;
2070 default:
2071 break;
2074 // Transformation
2075 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2077 if(bIsPresShape)
2078 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, aStr );
2080 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2081 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
2082 XML_FRAME, bCreateNewline, true );
2084 // evtl. corner radius?
2085 sal_Int32 nCornerRadius(0);
2086 xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius;
2087 if(nCornerRadius)
2089 OUStringBuffer sStringBuffer;
2090 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2091 nCornerRadius);
2092 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
2096 // write text-box
2097 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_TEXT_BOX, true, true);
2098 if(!bIsEmptyPresObj)
2099 ImpExportText( xShape );
2102 ImpExportDescription( xShape ); // #i68101#
2103 ImpExportEvents( xShape );
2104 ImpExportGluePoints( xShape );
2108 void XMLShapeExport::ImpExportRectangleShape(
2109 const uno::Reference< drawing::XShape >& xShape,
2110 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
2112 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2113 if(!xPropSet.is())
2114 return;
2116 // Transformation
2117 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2119 // evtl. corner radius?
2120 sal_Int32 nCornerRadius(0);
2121 xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius;
2122 if(nCornerRadius)
2124 OUStringBuffer sStringBuffer;
2125 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2126 nCornerRadius);
2127 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
2130 // write rectangle
2131 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2132 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_RECT, bCreateNewline, true);
2134 ImpExportDescription( xShape ); // #i68101#
2135 ImpExportEvents( xShape );
2136 ImpExportGluePoints( xShape );
2137 ImpExportText( xShape );
2140 void XMLShapeExport::ImpExportLineShape(
2141 const uno::Reference< drawing::XShape >& xShape,
2142 XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2144 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2145 if(!xPropSet.is())
2146 return;
2148 OUString aStr;
2149 OUStringBuffer sStringBuffer;
2150 awt::Point aStart(0,0);
2151 awt::Point aEnd(1,1);
2153 // #85920# use 'Geometry' to get the points of the line
2154 // since this slot take anchor pos into account.
2156 // get matrix
2157 ::basegfx::B2DHomMatrix aMatrix;
2158 ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
2160 // decompose and correct about pRefPoint
2161 ::basegfx::B2DTuple aTRScale;
2162 double fTRShear(0.0);
2163 double fTRRotate(0.0);
2164 ::basegfx::B2DTuple aTRTranslate;
2165 ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
2167 // create base position
2168 awt::Point aBasePosition(FRound(aTRTranslate.getX()), FRound(aTRTranslate.getY()));
2170 if (xPropSet->getPropertySetInfo()->hasPropertyByName("Geometry"))
2172 // get the two points
2173 uno::Any aAny(xPropSet->getPropertyValue("Geometry"));
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("CircleKind") >>= eKind;
2262 if( eKind != drawing::CircleKind_FULL )
2264 OUStringBuffer sStringBuffer;
2265 sal_Int32 nStartAngle = 0;
2266 sal_Int32 nEndAngle = 0;
2267 xPropSet->getPropertyValue("CircleStartAngle") >>= nStartAngle;
2268 xPropSet->getPropertyValue("CircleEndAngle") >>= 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(FRound(aTRScale.getX()), FRound(aTRScale.getY()));
2327 SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height);
2328 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
2330 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2332 // prepare name (with most used)
2333 enum ::xmloff::token::XMLTokenEnum eName(XML_PATH);
2335 uno::Any aAny( xPropSet->getPropertyValue("Geometry") );
2336 basegfx::B2DPolyPolygon aPolyPolygon;
2338 // tdf#145240 the Any can contain PolyPolygonBezierCoords or PointSequenceSequence
2339 // (see OWN_ATTR_BASE_GEOMETRY in SvxShapePolyPolygon::getPropertyValueImpl),
2340 // so be more flexible in interpreting it. Try to access bezier first:
2342 auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(aAny);
2344 if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength())
2346 aPolyPolygon = basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(*pSourcePolyPolygon);
2350 // if received no data, try to access point sequence second:
2351 if(0 == aPolyPolygon.count())
2353 auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PointSequenceSequence>(aAny);
2355 if(pSourcePolyPolygon)
2357 aPolyPolygon = basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(*pSourcePolyPolygon);
2361 if(aPolyPolygon.count())
2363 if(!bBezier && !aPolyPolygon.areControlPointsUsed() && 1 == aPolyPolygon.count())
2365 // simple polygon shape, can be written as svg:points sequence
2366 const basegfx::B2DPolygon& aPolygon(aPolyPolygon.getB2DPolygon(0));
2367 const OUString aPointString(basegfx::utils::exportToSvgPoints(aPolygon));
2369 // write point array
2370 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString);
2372 // set name
2373 eName = aPolygon.isClosed() ? XML_POLYGON : XML_POLYLINE;
2375 else
2377 // complex polygon shape, write as svg:d
2378 const OUString aPolygonString(
2379 basegfx::utils::exportToSvgD(
2380 aPolyPolygon,
2381 true, // bUseRelativeCoordinates
2382 false, // bDetectQuadraticBeziers: not used in old, but maybe activated now
2383 true)); // bHandleRelativeNextPointCompatible
2385 // write point array
2386 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
2390 // write object, but after attributes are added since this call will
2391 // consume all of these added attributes and the destructor will close the
2392 // scope. Also before text is added; this may add sub-scopes as needed
2393 SvXMLElementExport aOBJ(
2394 mrExport,
2395 XML_NAMESPACE_DRAW,
2396 eName,
2397 bCreateNewline,
2398 true);
2400 ImpExportDescription( xShape ); // #i68101#
2401 ImpExportEvents( xShape );
2402 ImpExportGluePoints( xShape );
2403 ImpExportText( xShape );
2407 namespace
2410 OUString getNameFromStreamURL(std::u16string_view rURL)
2412 static constexpr std::u16string_view sPackageURL(u"vnd.sun.star.Package:");
2414 OUString sResult;
2416 if (o3tl::starts_with(rURL, sPackageURL))
2418 std::u16string_view sRequestedName = rURL.substr(sPackageURL.size());
2419 size_t nLastIndex = sRequestedName.rfind('/') + 1;
2420 if ((nLastIndex > 0) && (nLastIndex < sRequestedName.size()))
2421 sRequestedName = sRequestedName.substr(nLastIndex);
2422 nLastIndex = sRequestedName.rfind('.');
2423 if (nLastIndex != std::u16string_view::npos)
2424 sRequestedName = sRequestedName.substr(0, nLastIndex);
2425 if (!sRequestedName.empty())
2426 sResult = sRequestedName;
2429 return sResult;
2432 } // end anonymous namespace
2434 void XMLShapeExport::ImpExportGraphicObjectShape(
2435 const uno::Reference< drawing::XShape >& xShape,
2436 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2438 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2439 if(!xPropSet.is())
2440 return;
2442 bool bIsEmptyPresObj = false;
2444 // Transformation
2445 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2447 if(eShapeType == XmlShapeType::PresGraphicObjectShape)
2448 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_GRAPHIC) );
2450 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2451 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
2452 XML_FRAME, bCreateNewline, true );
2454 if (!bIsEmptyPresObj)
2456 uno::Reference<graphic::XGraphic> xGraphic;
2457 OUString sOutMimeType;
2460 OUString aStreamURL;
2461 xPropSet->getPropertyValue("GraphicStreamURL") >>= aStreamURL;
2462 OUString sRequestedName = getNameFromStreamURL(aStreamURL);
2464 xPropSet->getPropertyValue("Graphic") >>= xGraphic;
2466 OUString sInternalURL;
2468 if (xGraphic.is())
2469 sInternalURL = mrExport.AddEmbeddedXGraphic(xGraphic, sOutMimeType, sRequestedName);
2471 if (!sInternalURL.isEmpty())
2473 // apply possible changed stream URL to embedded image object
2474 if (!sRequestedName.isEmpty())
2476 OUString newStreamURL = "vnd.sun.star.Package:";
2477 if (sInternalURL[0] == '#')
2479 newStreamURL += sInternalURL.subView(1, sInternalURL.getLength() - 1);
2481 else
2483 newStreamURL += sInternalURL;
2486 if (newStreamURL != aStreamURL)
2488 xPropSet->setPropertyValue("GraphicStreamURL", uno::Any(newStreamURL));
2492 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL);
2493 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
2494 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
2495 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
2500 if (GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
2502 if (sOutMimeType.isEmpty())
2504 GetExport().GetGraphicMimeTypeFromStream(xGraphic, sOutMimeType);
2506 if (!sOutMimeType.isEmpty())
2507 { // ODF 1.3 OFFICE-3943
2508 GetExport().AddAttribute(
2509 SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion()
2510 ? XML_NAMESPACE_DRAW
2511 : XML_NAMESPACE_LO_EXT,
2512 "mime-type", sOutMimeType);
2516 SvXMLElementExport aElement(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, true);
2518 // optional office:binary-data
2519 if (xGraphic.is())
2521 mrExport.AddEmbeddedXGraphicAsBase64(xGraphic);
2523 if (!bIsEmptyPresObj)
2524 ImpExportText(xShape);
2527 //Resolves: fdo#62461 put preferred image first above, followed by
2528 //fallback here
2529 const bool bAddReplacementImages = officecfg::Office::Common::Save::Graphic::AddReplacementImages::get();
2530 if( !bIsEmptyPresObj && bAddReplacementImages)
2532 uno::Reference<graphic::XGraphic> xReplacementGraphic;
2533 xPropSet->getPropertyValue("ReplacementGraphic") >>= xReplacementGraphic;
2535 // If there is no url, then the graphic is empty
2536 if (xReplacementGraphic.is())
2538 OUString aMimeType;
2539 const OUString aHref = mrExport.AddEmbeddedXGraphic(xReplacementGraphic, aMimeType);
2541 if (aMimeType.isEmpty())
2542 mrExport.GetGraphicMimeTypeFromStream(xReplacementGraphic, aMimeType);
2544 if (!aHref.isEmpty())
2546 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aHref);
2547 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
2548 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
2549 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
2552 if (!aMimeType.isEmpty() && GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
2553 { // ODF 1.3 OFFICE-3943
2554 mrExport.AddAttribute(
2555 SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion()
2556 ? XML_NAMESPACE_DRAW
2557 : XML_NAMESPACE_LO_EXT,
2558 "mime-type", aMimeType);
2561 SvXMLElementExport aElement(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, true);
2563 // optional office:binary-data
2564 mrExport.AddEmbeddedXGraphicAsBase64(xReplacementGraphic);
2569 ImpExportEvents( xShape );
2570 ImpExportGluePoints( xShape );
2572 // image map
2573 GetExport().GetImageMapExport().Export( xPropSet );
2574 ImpExportDescription( xShape ); // #i68101#
2576 // Signature Line, QR Code - needs to be after the images!
2577 if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
2579 ImpExportSignatureLine(xShape);
2580 ImpExportQRCode(xShape);
2584 void XMLShapeExport::ImpExportChartShape(
2585 const uno::Reference< drawing::XShape >& xShape,
2586 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint,
2587 comphelper::AttributeList* pAttrList )
2589 ImpExportOLE2Shape( xShape, eShapeType, nFeatures, pRefPoint, pAttrList );
2592 void XMLShapeExport::ImpExportControlShape(
2593 const uno::Reference< drawing::XShape >& xShape,
2594 XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2596 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2597 if(xPropSet.is())
2599 // Transformation
2600 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2603 uno::Reference< drawing::XControlShape > xControl( xShape, uno::UNO_QUERY );
2604 SAL_WARN_IF( !xControl.is(), "xmloff", "Control shape is not supporting XControlShape" );
2605 if( xControl.is() )
2607 uno::Reference< beans::XPropertySet > xControlModel( xControl->getControl(), uno::UNO_QUERY );
2608 SAL_WARN_IF( !xControlModel.is(), "xmloff", "Control shape has not XControlModel" );
2609 if( xControlModel.is() )
2611 OUString sControlId = mrExport.GetFormExport()->getControlId( xControlModel );
2612 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CONTROL, sControlId );
2616 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2617 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONTROL, bCreateNewline, true);
2619 ImpExportDescription( xShape ); // #i68101#
2622 void XMLShapeExport::ImpExportConnectorShape(
2623 const uno::Reference< drawing::XShape >& xShape,
2624 XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
2626 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
2628 OUString aStr;
2629 OUStringBuffer sStringBuffer;
2631 // export connection kind
2632 drawing::ConnectorType eType = drawing::ConnectorType_STANDARD;
2633 uno::Any aAny = xProps->getPropertyValue("EdgeKind");
2634 aAny >>= eType;
2636 if( eType != drawing::ConnectorType_STANDARD )
2638 SvXMLUnitConverter::convertEnum( sStringBuffer, eType, aXML_ConnectionKind_EnumMap );
2639 aStr = sStringBuffer.makeStringAndClear();
2640 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TYPE, aStr);
2643 // export line skew
2644 sal_Int32 nDelta1 = 0, nDelta2 = 0, nDelta3 = 0;
2646 aAny = xProps->getPropertyValue("EdgeLine1Delta");
2647 aAny >>= nDelta1;
2648 aAny = xProps->getPropertyValue("EdgeLine2Delta");
2649 aAny >>= nDelta2;
2650 aAny = xProps->getPropertyValue("EdgeLine3Delta");
2651 aAny >>= nDelta3;
2653 if( nDelta1 != 0 || nDelta2 != 0 || nDelta3 != 0 )
2655 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2656 nDelta1);
2657 if( nDelta2 != 0 || nDelta3 != 0 )
2659 sStringBuffer.append( ' ' );
2660 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2661 nDelta2);
2662 if( nDelta3 != 0 )
2664 sStringBuffer.append( ' ' );
2665 mrExport.GetMM100UnitConverter().convertMeasureToXML(
2666 sStringBuffer, nDelta3);
2670 aStr = sStringBuffer.makeStringAndClear();
2671 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_LINE_SKEW, aStr);
2674 // export start and end point
2675 awt::Point aStart(0,0);
2676 awt::Point aEnd(1,1);
2678 /* Get <StartPositionInHoriL2R> and
2679 <EndPositionInHoriL2R>, if they exist and if the document is exported
2680 into the OpenOffice.org file format.
2681 These properties only exist at service css::text::Shape - the
2682 Writer UNO service for shapes.
2683 This code is needed, because the positioning attributes in the
2684 OpenOffice.org file format are given in horizontal left-to-right layout
2685 regardless the layout direction the shape is in. In the OASIS Open Office
2686 file format the positioning attributes are correctly given in the layout
2687 direction the shape is in. Thus, this code provides the conversion from
2688 the OASIS Open Office file format to the OpenOffice.org file format. (#i36248#)
2690 if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
2691 xProps->getPropertySetInfo()->hasPropertyByName("StartPositionInHoriL2R") &&
2692 xProps->getPropertySetInfo()->hasPropertyByName("EndPositionInHoriL2R") )
2694 xProps->getPropertyValue("StartPositionInHoriL2R") >>= aStart;
2695 xProps->getPropertyValue("EndPositionInHoriL2R") >>= aEnd;
2697 else
2699 xProps->getPropertyValue("StartPosition") >>= aStart;
2700 xProps->getPropertyValue("EndPosition") >>= aEnd;
2703 if( pRefPoint )
2705 aStart.X -= pRefPoint->X;
2706 aStart.Y -= pRefPoint->Y;
2707 aEnd.X -= pRefPoint->X;
2708 aEnd.Y -= pRefPoint->Y;
2711 if( nFeatures & XMLShapeExportFlags::X )
2713 // svg: x1
2714 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2715 aStart.X);
2716 aStr = sStringBuffer.makeStringAndClear();
2717 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
2719 else
2721 aEnd.X -= aStart.X;
2724 if( nFeatures & XMLShapeExportFlags::Y )
2726 // svg: y1
2727 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2728 aStart.Y);
2729 aStr = sStringBuffer.makeStringAndClear();
2730 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
2732 else
2734 aEnd.Y -= aStart.Y;
2737 // svg: x2
2738 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.X);
2739 aStr = sStringBuffer.makeStringAndClear();
2740 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
2742 // svg: y2
2743 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.Y);
2744 aStr = sStringBuffer.makeStringAndClear();
2745 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
2747 // #i39320#
2748 uno::Reference< uno::XInterface > xRefS;
2749 uno::Reference< uno::XInterface > xRefE;
2751 // export start connection
2752 xProps->getPropertyValue("StartShape") >>= xRefS;
2753 if( xRefS.is() )
2755 const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefS );
2756 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_SHAPE, rShapeId);
2758 aAny = xProps->getPropertyValue("StartGluePointIndex");
2759 sal_Int32 nGluePointId = 0;
2760 if( aAny >>= nGluePointId )
2762 if( nGluePointId != -1 )
2764 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_GLUE_POINT, OUString::number( nGluePointId ));
2769 // export end connection
2770 xProps->getPropertyValue("EndShape") >>= xRefE;
2771 if( xRefE.is() )
2773 const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefE );
2774 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_SHAPE, rShapeId);
2776 aAny = xProps->getPropertyValue("EndGluePointIndex");
2777 sal_Int32 nGluePointId = 0;
2778 if( aAny >>= nGluePointId )
2780 if( nGluePointId != -1 )
2782 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_GLUE_POINT, OUString::number( nGluePointId ));
2787 // get PolygonBezier
2788 aAny = xProps->getPropertyValue("PolyPolygonBezier");
2789 auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(aAny);
2790 if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength())
2792 const basegfx::B2DPolyPolygon aPolyPolygon(
2793 basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(
2794 *pSourcePolyPolygon));
2795 const OUString aPolygonString(
2796 basegfx::utils::exportToSvgD(
2797 aPolyPolygon,
2798 true, // bUseRelativeCoordinates
2799 false, // bDetectQuadraticBeziers: not used in old, but maybe activated now
2800 true)); // bHandleRelativeNextPointCompatible
2802 // write point array
2803 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
2806 // get matrix
2807 ::basegfx::B2DHomMatrix aMatrix;
2808 ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xProps);
2810 // decompose and correct about pRefPoint
2811 ::basegfx::B2DTuple aTRScale;
2812 double fTRShear(0.0);
2813 double fTRRotate(0.0);
2814 ::basegfx::B2DTuple aTRTranslate;
2815 ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear,
2816 fTRRotate, aTRTranslate, pRefPoint);
2818 // fdo#49678: create and export ViewBox
2819 awt::Size aSize(FRound(aTRScale.getX()), FRound(aTRScale.getY()));
2820 SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height);
2821 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
2823 // write connector shape. Add Export later.
2824 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2825 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONNECTOR, bCreateNewline, true);
2827 ImpExportDescription( xShape ); // #i68101#
2828 ImpExportEvents( xShape );
2829 ImpExportGluePoints( xShape );
2830 ImpExportText( xShape );
2833 void XMLShapeExport::ImpExportMeasureShape(
2834 const uno::Reference< drawing::XShape >& xShape,
2835 XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point const * pRefPoint /* = NULL */)
2837 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
2839 OUString aStr;
2840 OUStringBuffer sStringBuffer;
2842 // export start and end point
2843 awt::Point aStart(0,0);
2844 awt::Point aEnd(1,1);
2846 /* Get <StartPositionInHoriL2R> and
2847 <EndPositionInHoriL2R>, if they exist and if the document is exported
2848 into the OpenOffice.org file format.
2849 These properties only exist at service css::text::Shape - the
2850 Writer UNO service for shapes.
2851 This code is needed, because the positioning attributes in the
2852 OpenOffice.org file format are given in horizontal left-to-right layout
2853 regardless the layout direction the shape is in. In the OASIS Open Office
2854 file format the positioning attributes are correctly given in the layout
2855 direction the shape is in. Thus, this code provides the conversion from
2856 the OASIS Open Office file format to the OpenOffice.org file format. (#i36248#)
2858 if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
2859 xProps->getPropertySetInfo()->hasPropertyByName("StartPositionInHoriL2R") &&
2860 xProps->getPropertySetInfo()->hasPropertyByName("EndPositionInHoriL2R") )
2862 xProps->getPropertyValue("StartPositionInHoriL2R") >>= aStart;
2863 xProps->getPropertyValue("EndPositionInHoriL2R") >>= aEnd;
2865 else
2867 xProps->getPropertyValue("StartPosition") >>= aStart;
2868 xProps->getPropertyValue("EndPosition") >>= aEnd;
2871 if( pRefPoint )
2873 aStart.X -= pRefPoint->X;
2874 aStart.Y -= pRefPoint->Y;
2875 aEnd.X -= pRefPoint->X;
2876 aEnd.Y -= pRefPoint->Y;
2879 if( nFeatures & XMLShapeExportFlags::X )
2881 // svg: x1
2882 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2883 aStart.X);
2884 aStr = sStringBuffer.makeStringAndClear();
2885 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
2887 else
2889 aEnd.X -= aStart.X;
2892 if( nFeatures & XMLShapeExportFlags::Y )
2894 // svg: y1
2895 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2896 aStart.Y);
2897 aStr = sStringBuffer.makeStringAndClear();
2898 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
2900 else
2902 aEnd.Y -= aStart.Y;
2905 // svg: x2
2906 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.X);
2907 aStr = sStringBuffer.makeStringAndClear();
2908 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
2910 // svg: y2
2911 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.Y);
2912 aStr = sStringBuffer.makeStringAndClear();
2913 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
2915 // write measure shape
2916 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2917 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_MEASURE, bCreateNewline, true);
2919 ImpExportDescription( xShape ); // #i68101#
2920 ImpExportEvents( xShape );
2921 ImpExportGluePoints( xShape );
2923 uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY );
2924 if( xText.is() )
2925 mrExport.GetTextParagraphExport()->exportText( xText );
2928 void XMLShapeExport::ImpExportOLE2Shape(
2929 const uno::Reference< drawing::XShape >& xShape,
2930 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */,
2931 comphelper::AttributeList* pAttrList /* = NULL */ )
2933 uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2934 uno::Reference< container::XNamed > xNamed(xShape, uno::UNO_QUERY);
2936 SAL_WARN_IF( !xPropSet.is() || !xNamed.is(), "xmloff", "ole shape is not implementing needed interfaces");
2937 if(!(xPropSet.is() && xNamed.is()))
2938 return;
2940 // Transformation
2941 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2943 bool bIsEmptyPresObj = false;
2945 // presentation settings
2946 if(eShapeType == XmlShapeType::PresOLE2Shape)
2947 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_OBJECT) );
2948 else if(eShapeType == XmlShapeType::PresChartShape)
2949 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_CHART) );
2950 else if(eShapeType == XmlShapeType::PresSheetShape)
2951 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_TABLE) );
2953 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2954 bool bExportEmbedded(mrExport.getExportFlags() & SvXMLExportFlags::EMBEDDED);
2955 OUString sPersistName;
2956 SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
2957 XML_FRAME, bCreateNewline, true );
2959 if (!bIsEmptyPresObj)
2961 if (pAttrList)
2963 mrExport.AddAttributeList(pAttrList);
2966 OUString sClassId;
2967 OUString sURL;
2968 bool bInternal = false;
2969 xPropSet->getPropertyValue("IsInternal") >>= bInternal;
2973 if ( bInternal )
2975 // OOo internal links have no storage persistence, URL is stored in the XML file
2976 // the result LinkURL is empty in case the object is not a link
2977 xPropSet->getPropertyValue("LinkURL") >>= sURL;
2980 xPropSet->getPropertyValue("PersistName") >>= sPersistName;
2981 if ( sURL.isEmpty() )
2983 if( !sPersistName.isEmpty() )
2985 sURL = "vnd.sun.star.EmbeddedObject:" + sPersistName;
2989 if( !bInternal )
2990 xPropSet->getPropertyValue("CLSID") >>= sClassId;
2992 if( !sClassId.isEmpty() )
2993 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CLASS_ID, sClassId );
2995 if(!bExportEmbedded)
2997 // xlink:href
2998 if( !sURL.isEmpty() )
3000 // #96717# in theorie, if we don't have a URL we shouldn't even
3001 // export this OLE shape. But practically it's too risky right now
3002 // to change this so we better dispose this on load
3003 sURL = mrExport.AddEmbeddedObject( sURL );
3005 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL );
3006 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3007 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3008 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3010 else
3012 // tdf#153179 Export the preview graphic of the object if the object is missing.
3013 uno::Reference<graphic::XGraphic> xGraphic;
3014 xPropSet->getPropertyValue("Graphic") >>= xGraphic;
3016 if (xGraphic.is())
3018 OUString aMimeType;
3019 const OUString aHref = mrExport.AddEmbeddedXGraphic(xGraphic, aMimeType);
3021 if (aMimeType.isEmpty())
3022 mrExport.GetGraphicMimeTypeFromStream(xGraphic, aMimeType);
3024 if (!aHref.isEmpty())
3026 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aHref);
3027 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
3028 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
3029 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
3032 if (!aMimeType.isEmpty()
3033 && GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
3034 { // ODF 1.3 OFFICE-3943
3035 mrExport.AddAttribute(SvtSaveOptions::ODFSVER_013
3036 <= GetExport().getSaneDefaultVersion()
3037 ? XML_NAMESPACE_DRAW
3038 : XML_NAMESPACE_LO_EXT,
3039 "mime-type", aMimeType);
3042 SvXMLElementExport aImageElem(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true,
3043 true);
3045 // optional office:binary-data
3046 mrExport.AddEmbeddedXGraphicAsBase64(xGraphic);
3048 ImpExportEvents(xShape);
3049 ImpExportGluePoints(xShape);
3050 ImpExportDescription(xShape);
3052 return;
3058 enum XMLTokenEnum eElem = sClassId.isEmpty() ? XML_OBJECT : XML_OBJECT_OLE ;
3059 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, eElem, true, true );
3061 // tdf#112547 export text as child of draw:object, where import expects it
3062 if (!bIsEmptyPresObj && supportsText(eShapeType))
3064 // #i118485# Add text export, the draw OLE shape allows text now
3065 ImpExportText( xShape, TextPNS::EXTENSION );
3068 if(bExportEmbedded && !bIsEmptyPresObj)
3070 if(bInternal)
3072 // embedded XML
3073 uno::Reference< lang::XComponent > xComp;
3074 xPropSet->getPropertyValue("Model") >>= xComp;
3075 SAL_WARN_IF( !xComp.is(), "xmloff", "no xModel for own OLE format" );
3076 mrExport.ExportEmbeddedOwnObject( xComp );
3078 else
3080 // embed as Base64
3081 // this is an alien object ( currently MSOLE is the only supported type of such objects )
3082 // in case it is not an OASIS format the object should be asked to store replacement image if possible
3084 OUString sURLRequest( sURL );
3085 if ( !( mrExport.getExportFlags() & SvXMLExportFlags::OASIS ) )
3086 sURLRequest += "?oasis=false";
3087 mrExport.AddEmbeddedObjectAsBase64( sURLRequest );
3091 if( !bIsEmptyPresObj )
3093 OUString sURL = XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE + sPersistName;
3094 if( !bExportEmbedded )
3096 sURL = GetExport().AddEmbeddedObject( sURL );
3097 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL );
3098 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3099 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3100 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3103 SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW,
3104 XML_IMAGE, false, true );
3106 if( bExportEmbedded )
3107 GetExport().AddEmbeddedObjectAsBase64( sURL );
3110 ImpExportEvents( xShape );
3111 ImpExportGluePoints( xShape );
3112 ImpExportDescription( xShape ); // #i68101#
3116 void XMLShapeExport::ImpExportPageShape(
3117 const uno::Reference< drawing::XShape >& xShape,
3118 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
3120 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3121 if(!xPropSet.is())
3122 return;
3124 // #86163# Transformation
3125 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3127 // export page number used for this page
3128 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
3129 static const OUStringLiteral aPageNumberStr(u"PageNumber");
3130 if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(aPageNumberStr))
3132 sal_Int32 nPageNumber = 0;
3133 xPropSet->getPropertyValue(aPageNumberStr) >>= nPageNumber;
3134 if( nPageNumber )
3135 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_PAGE_NUMBER, OUString::number(nPageNumber));
3138 // a presentation page shape, normally used on notes pages only. If
3139 // it is used not as presentation shape, it may have been created with
3140 // copy-paste exchange between draw and impress (this IS possible...)
3141 if(eShapeType == XmlShapeType::PresPageShape)
3143 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS,
3144 XML_PAGE);
3147 // write Page shape
3148 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3149 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PAGE_THUMBNAIL, bCreateNewline, true);
3152 void XMLShapeExport::ImpExportCaptionShape(
3153 const uno::Reference< drawing::XShape >& xShape,
3154 XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
3156 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3157 if(!xPropSet.is())
3158 return;
3160 // Transformation
3161 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3163 // evtl. corner radius?
3164 sal_Int32 nCornerRadius(0);
3165 xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius;
3166 if(nCornerRadius)
3168 OUStringBuffer sStringBuffer;
3169 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
3170 nCornerRadius);
3171 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
3174 awt::Point aCaptionPoint;
3175 xPropSet->getPropertyValue("CaptionPoint") >>= aCaptionPoint;
3177 mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
3178 aCaptionPoint.X);
3179 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_X, msBuffer.makeStringAndClear() );
3180 mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
3181 aCaptionPoint.Y);
3182 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_Y, msBuffer.makeStringAndClear() );
3184 // write Caption shape. Add export later.
3185 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3186 bool bAnnotation( (nFeatures & XMLShapeExportFlags::ANNOTATION) == XMLShapeExportFlags::ANNOTATION );
3188 SvXMLElementExport aObj( mrExport,
3189 (bAnnotation ? XML_NAMESPACE_OFFICE
3190 : XML_NAMESPACE_DRAW),
3191 (bAnnotation ? XML_ANNOTATION : XML_CAPTION),
3192 bCreateNewline, true );
3194 ImpExportDescription( xShape ); // #i68101#
3195 ImpExportEvents( xShape );
3196 ImpExportGluePoints( xShape );
3197 if( bAnnotation )
3198 mrExport.exportAnnotationMeta( xShape );
3199 ImpExportText( xShape );
3203 void XMLShapeExport::ImpExportFrameShape(
3204 const uno::Reference< drawing::XShape >& xShape,
3205 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3207 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3208 if(!xPropSet.is())
3209 return;
3211 // Transformation
3212 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3214 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3215 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
3216 XML_FRAME, bCreateNewline, true );
3218 // export frame url
3219 OUString aStr;
3220 xPropSet->getPropertyValue("FrameURL") >>= aStr;
3221 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
3222 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3223 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3224 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3226 // export name
3227 xPropSet->getPropertyValue("FrameName") >>= aStr;
3228 if( !aStr.isEmpty() )
3229 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FRAME_NAME, aStr );
3231 // write floating frame
3233 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_FLOATING_FRAME, true, true);
3236 ImpExportDescription(xShape);
3239 void XMLShapeExport::ImpExportAppletShape(
3240 const uno::Reference< drawing::XShape >& xShape,
3241 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3243 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3244 if(!xPropSet.is())
3245 return;
3247 // Transformation
3248 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3250 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3251 SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
3252 XML_FRAME, bCreateNewline, true );
3254 // export frame url
3255 OUString aStr;
3256 xPropSet->getPropertyValue("AppletCodeBase") >>= aStr;
3257 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
3258 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3259 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3260 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3262 // export draw:applet-name
3263 xPropSet->getPropertyValue("AppletName") >>= aStr;
3264 if( !aStr.isEmpty() )
3265 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_APPLET_NAME, aStr );
3267 // export draw:code
3268 xPropSet->getPropertyValue("AppletCode") >>= aStr;
3269 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CODE, aStr );
3271 // export draw:may-script
3272 bool bIsScript = false;
3273 xPropSet->getPropertyValue("AppletIsScript") >>= bIsScript;
3274 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MAY_SCRIPT, bIsScript ? XML_TRUE : XML_FALSE );
3277 // write applet
3278 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_APPLET, true, true);
3280 // export parameters
3281 uno::Sequence< beans::PropertyValue > aCommands;
3282 xPropSet->getPropertyValue("AppletCommands") >>= aCommands;
3283 for( const auto& rCommand : std::as_const(aCommands) )
3285 rCommand.Value >>= aStr;
3286 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rCommand.Name );
3287 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr );
3288 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3292 ImpExportDescription(xShape);
3295 void XMLShapeExport::ImpExportPluginShape(
3296 const uno::Reference< drawing::XShape >& xShape,
3297 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3299 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3300 if(!xPropSet.is())
3301 return;
3303 // Transformation
3304 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3306 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3307 SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
3308 XML_FRAME, bCreateNewline, true );
3310 // export plugin url
3311 OUString aStr;
3312 xPropSet->getPropertyValue("PluginURL") >>= aStr;
3313 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
3314 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3315 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3316 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3318 // export mime-type
3319 xPropSet->getPropertyValue("PluginMimeType") >>= aStr;
3320 if(!aStr.isEmpty())
3321 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, aStr );
3324 // write plugin
3325 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, true, true);
3327 // export parameters
3328 uno::Sequence< beans::PropertyValue > aCommands;
3329 xPropSet->getPropertyValue("PluginCommands") >>= aCommands;
3330 for( const auto& rCommand : std::as_const(aCommands) )
3332 rCommand.Value >>= aStr;
3333 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rCommand.Name );
3334 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr );
3335 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3339 ImpExportDescription(xShape);
3342 static void lcl_CopyStream(
3343 uno::Reference<io::XInputStream> const& xInStream,
3344 uno::Reference<embed::XStorage> const& xTarget,
3345 OUString const& rPath, const OUString& rMimeType)
3347 ::comphelper::LifecycleProxy proxy;
3348 uno::Reference<io::XStream> const xStream(
3349 ::comphelper::OStorageHelper::GetStreamAtPackageURL(xTarget, rPath,
3350 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE, proxy));
3351 uno::Reference<io::XOutputStream> const xOutStream(
3352 (xStream.is()) ? xStream->getOutputStream() : nullptr);
3353 if (!xOutStream.is())
3355 SAL_WARN("xmloff", "no output stream");
3356 throw uno::Exception("no output stream",nullptr);
3358 uno::Reference< beans::XPropertySet > const xStreamProps(xStream,
3359 uno::UNO_QUERY);
3360 if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage
3361 xStreamProps->setPropertyValue("MediaType",
3362 uno::Any(rMimeType));
3363 xStreamProps->setPropertyValue( // turn off compression
3364 "Compressed",
3365 uno::Any(false));
3367 ::comphelper::OStorageHelper::CopyInputToOutput(xInStream, xOutStream);
3368 xOutStream->closeOutput();
3369 proxy.commitStorages();
3372 static OUString
3373 lcl_StoreMediaAndGetURL(SvXMLExport & rExport,
3374 uno::Reference<beans::XPropertySet> const& xPropSet,
3375 OUString const& rURL, const OUString& rMimeType)
3377 OUString urlPath;
3378 if (rURL.startsWithIgnoreAsciiCase("vnd.sun.star.Package:", &urlPath))
3380 try // video is embedded
3382 uno::Reference<embed::XStorage> const xTarget(
3383 rExport.GetTargetStorage(), uno::UNO_SET_THROW);
3384 uno::Reference<io::XInputStream> xInStream;
3385 xPropSet->getPropertyValue("PrivateStream")
3386 >>= xInStream;
3388 if (!xInStream.is())
3390 SAL_WARN("xmloff", "no input stream");
3391 return OUString();
3394 lcl_CopyStream(xInStream, xTarget, rURL, rMimeType);
3396 return urlPath;
3398 catch (uno::Exception const&)
3400 TOOLS_INFO_EXCEPTION("xmloff", "exception while storing embedded media");
3402 return OUString();
3404 else
3406 return rExport.GetRelativeReference(rURL); // linked
3410 namespace
3412 void ExportGraphicPreview(const uno::Reference<graphic::XGraphic>& xGraphic, SvXMLExport& rExport, const std::u16string_view& rPrefix, const std::u16string_view& rExtension, const OUString& rMimeType)
3414 const bool bExportEmbedded(rExport.getExportFlags() & SvXMLExportFlags::EMBEDDED);
3416 if( xGraphic.is() ) try
3418 uno::Reference< uno::XComponentContext > xContext = rExport.getComponentContext();
3420 uno::Reference< embed::XStorage > xPictureStorage;
3421 uno::Reference< embed::XStorage > xStorage;
3422 uno::Reference< io::XStream > xPictureStream;
3424 OUString sPictureName;
3425 if( bExportEmbedded )
3427 xPictureStream.set( xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.comp.MemoryStream", xContext), uno::UNO_QUERY_THROW );
3429 else
3431 xStorage.set( rExport.GetTargetStorage(), uno::UNO_SET_THROW );
3433 xPictureStorage.set( xStorage->openStorageElement( "Pictures" , ::embed::ElementModes::READWRITE ), uno::UNO_SET_THROW );
3435 sal_Int32 nIndex = 0;
3438 sPictureName = rPrefix + OUString::number( ++nIndex ) + rExtension;
3440 while( xPictureStorage->hasByName( sPictureName ) );
3442 xPictureStream.set( xPictureStorage->openStreamElement( sPictureName, ::embed::ElementModes::READWRITE ), uno::UNO_SET_THROW );
3445 uno::Reference< graphic::XGraphicProvider > xProvider( graphic::GraphicProvider::create(xContext) );
3446 uno::Sequence< beans::PropertyValue > aArgs{
3447 comphelper::makePropertyValue("MimeType", rMimeType ),
3448 comphelper::makePropertyValue("OutputStream", xPictureStream->getOutputStream())
3450 xProvider->storeGraphic( xGraphic, aArgs );
3452 if( xPictureStorage.is() )
3454 uno::Reference< embed::XTransactedObject > xTrans( xPictureStorage, uno::UNO_QUERY );
3455 if( xTrans.is() )
3456 xTrans->commit();
3459 if( !bExportEmbedded )
3461 OUString sURL = "Pictures/" + sPictureName;
3462 rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sURL );
3463 rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3464 rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3465 rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3468 SvXMLElementExport aElem( rExport, XML_NAMESPACE_DRAW, XML_IMAGE, false, true );
3470 if( bExportEmbedded )
3472 uno::Reference< io::XSeekableInputStream > xSeekable( xPictureStream, uno::UNO_QUERY_THROW );
3473 xSeekable->seek(0);
3475 XMLBase64Export aBase64Exp( rExport );
3476 aBase64Exp.exportOfficeBinaryDataElement( uno::Reference < io::XInputStream >( xPictureStream, uno::UNO_QUERY_THROW ) );
3479 catch( uno::Exception const & )
3481 DBG_UNHANDLED_EXCEPTION("xmloff.draw");
3486 void XMLShapeExport::ImpExportMediaShape(
3487 const uno::Reference< drawing::XShape >& xShape,
3488 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3490 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3491 if(!xPropSet.is())
3492 return;
3494 // Transformation
3495 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3497 if(eShapeType == XmlShapeType::PresMediaShape)
3499 (void)ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_OBJECT) );
3501 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3502 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
3503 XML_FRAME, bCreateNewline, true );
3505 // export media url
3506 OUString aMediaURL;
3507 xPropSet->getPropertyValue("MediaURL") >>= aMediaURL;
3508 OUString sMimeType;
3509 xPropSet->getPropertyValue("MediaMimeType") >>= sMimeType;
3511 OUString const persistentURL =
3512 lcl_StoreMediaAndGetURL(GetExport(), xPropSet, aMediaURL, sMimeType);
3514 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, persistentURL );
3515 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3516 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3517 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3519 // export mime-type
3520 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, sMimeType );
3522 // write plugin
3523 auto pPluginOBJ = std::make_unique<SvXMLElementExport>(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, !( nFeatures & XMLShapeExportFlags::NO_WS ), true);
3525 // export parameters
3526 const OUString aFalseStr( "false" ), aTrueStr( "true" );
3528 bool bLoop = false;
3529 static const OUStringLiteral aLoopStr( u"Loop" );
3530 xPropSet->getPropertyValue( aLoopStr ) >>= bLoop;
3531 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aLoopStr );
3532 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, bLoop ? aTrueStr : aFalseStr );
3533 delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3535 bool bMute = false;
3536 static const OUStringLiteral aMuteStr( u"Mute" );
3537 xPropSet->getPropertyValue( aMuteStr ) >>= bMute;
3538 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aMuteStr );
3539 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, bMute ? aTrueStr : aFalseStr );
3540 delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3542 sal_Int16 nVolumeDB = 0;
3543 xPropSet->getPropertyValue("VolumeDB") >>= nVolumeDB;
3544 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, "VolumeDB" );
3545 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, OUString::number( nVolumeDB ) );
3546 delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3548 media::ZoomLevel eZoom;
3549 OUString aZoomValue;
3550 xPropSet->getPropertyValue("Zoom") >>= eZoom;
3551 switch( eZoom )
3553 case media::ZoomLevel_ZOOM_1_TO_4 : aZoomValue = "25%"; break;
3554 case media::ZoomLevel_ZOOM_1_TO_2 : aZoomValue = "50%"; break;
3555 case media::ZoomLevel_ORIGINAL : aZoomValue = "100%"; break;
3556 case media::ZoomLevel_ZOOM_2_TO_1 : aZoomValue = "200%"; break;
3557 case media::ZoomLevel_ZOOM_4_TO_1 : aZoomValue = "400%"; break;
3558 case media::ZoomLevel_FIT_TO_WINDOW: aZoomValue = "fit"; break;
3559 case media::ZoomLevel_FIT_TO_WINDOW_FIXED_ASPECT: aZoomValue = "fixedfit"; break;
3560 case media::ZoomLevel_FULLSCREEN : aZoomValue = "fullscreen"; break;
3562 default:
3563 break;
3566 if( !aZoomValue.isEmpty() )
3568 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, "Zoom" );
3569 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aZoomValue );
3570 delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3573 pPluginOBJ.reset();
3575 uno::Reference<graphic::XGraphic> xGraphic;
3576 xPropSet->getPropertyValue("Graphic") >>= xGraphic;
3577 Graphic aGraphic(xGraphic);
3578 if (!aGraphic.IsNone())
3580 // The media has a preview, export it.
3581 ExportGraphicPreview(xGraphic, mrExport, u"MediaPreview", u".png", "image/png");
3584 ImpExportDescription(xShape);
3587 void XMLShapeExport::ImpExport3DSceneShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
3589 uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY);
3590 if(!(xShapes.is() && xShapes->getCount()))
3591 return;
3593 uno::Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
3594 SAL_WARN_IF( !xPropSet.is(), "xmloff", "XMLShapeExport::ImpExport3DSceneShape can't export a scene without a propertyset" );
3595 if( !xPropSet.is() )
3596 return;
3598 // Transformation
3599 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3601 // 3d attributes
3602 export3DSceneAttributes( xPropSet );
3604 // write 3DScene shape
3605 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3606 SvXMLElementExport aOBJ( mrExport, XML_NAMESPACE_DR3D, XML_SCENE, bCreateNewline, true);
3608 ImpExportDescription( xShape ); // #i68101#
3609 ImpExportEvents( xShape );
3611 // write 3DSceneLights
3612 export3DLamps( xPropSet );
3614 // #89764# if export of position is suppressed for group shape,
3615 // positions of contained objects should be written relative to
3616 // the upper left edge of the group.
3617 awt::Point aUpperLeft;
3619 if(!(nFeatures & XMLShapeExportFlags::POSITION))
3621 nFeatures |= XMLShapeExportFlags::POSITION;
3622 aUpperLeft = xShape->getPosition();
3623 pRefPoint = &aUpperLeft;
3626 // write members
3627 exportShapes( xShapes, nFeatures, pRefPoint );
3630 void XMLShapeExport::ImpExport3DShape(
3631 const uno::Reference< drawing::XShape >& xShape,
3632 XmlShapeType eShapeType)
3634 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3635 if(!xPropSet.is())
3636 return;
3638 OUString aStr;
3639 OUStringBuffer sStringBuffer;
3641 // transformation (UNO_NAME_3D_TRANSFORM_MATRIX == "D3DTransformMatrix")
3642 uno::Any aAny = xPropSet->getPropertyValue("D3DTransformMatrix");
3643 drawing::HomogenMatrix aHomMat;
3644 aAny >>= aHomMat;
3645 SdXMLImExTransform3D aTransform;
3646 aTransform.AddHomogenMatrix(aHomMat);
3647 if(aTransform.NeedsAction())
3648 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
3650 switch(eShapeType)
3652 case XmlShapeType::Draw3DCubeObject:
3654 // minEdge
3655 aAny = xPropSet->getPropertyValue("D3DPosition");
3656 drawing::Position3D aPosition3D;
3657 aAny >>= aPosition3D;
3658 ::basegfx::B3DVector aPos3D(aPosition3D.PositionX, aPosition3D.PositionY, aPosition3D.PositionZ);
3660 // maxEdge
3661 aAny = xPropSet->getPropertyValue("D3DSize");
3662 drawing::Direction3D aDirection3D;
3663 aAny >>= aDirection3D;
3664 ::basegfx::B3DVector aDir3D(aDirection3D.DirectionX, aDirection3D.DirectionY, aDirection3D.DirectionZ);
3666 // transform maxEdge from distance to pos
3667 aDir3D = aPos3D + aDir3D;
3669 // write minEdge
3670 if(aPos3D != ::basegfx::B3DVector(-2500.0, -2500.0, -2500.0)) // write only when not default
3672 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aPos3D);
3673 aStr = sStringBuffer.makeStringAndClear();
3674 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_MIN_EDGE, aStr);
3677 // write maxEdge
3678 if(aDir3D != ::basegfx::B3DVector(2500.0, 2500.0, 2500.0)) // write only when not default
3680 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aDir3D);
3681 aStr = sStringBuffer.makeStringAndClear();
3682 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_MAX_EDGE, aStr);
3685 // write 3DCube shape
3686 // #i123542# Do this *after* the attributes are added, else these will be lost since opening
3687 // the scope will clear the global attribute list at the exporter
3688 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_CUBE, true, true);
3690 break;
3692 case XmlShapeType::Draw3DSphereObject:
3694 // Center
3695 aAny = xPropSet->getPropertyValue("D3DPosition");
3696 drawing::Position3D aPosition3D;
3697 aAny >>= aPosition3D;
3698 ::basegfx::B3DVector aPos3D(aPosition3D.PositionX, aPosition3D.PositionY, aPosition3D.PositionZ);
3700 // Size
3701 aAny = xPropSet->getPropertyValue("D3DSize");
3702 drawing::Direction3D aDirection3D;
3703 aAny >>= aDirection3D;
3704 ::basegfx::B3DVector aDir3D(aDirection3D.DirectionX, aDirection3D.DirectionY, aDirection3D.DirectionZ);
3706 // write Center
3707 if(aPos3D != ::basegfx::B3DVector(0.0, 0.0, 0.0)) // write only when not default
3709 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aPos3D);
3710 aStr = sStringBuffer.makeStringAndClear();
3711 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_CENTER, aStr);
3714 // write Size
3715 if(aDir3D != ::basegfx::B3DVector(5000.0, 5000.0, 5000.0)) // write only when not default
3717 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aDir3D);
3718 aStr = sStringBuffer.makeStringAndClear();
3719 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SIZE, aStr);
3722 // write 3DSphere shape
3723 // #i123542# Do this *after* the attributes are added, else these will be lost since opening
3724 // the scope will clear the global attribute list at the exporter
3725 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_SPHERE, true, true);
3727 break;
3729 case XmlShapeType::Draw3DLatheObject:
3730 case XmlShapeType::Draw3DExtrudeObject:
3732 // write special 3DLathe/3DExtrude attributes, get 3D tools::PolyPolygon as drawing::PolyPolygonShape3D
3733 aAny = xPropSet->getPropertyValue("D3DPolyPolygon3D");
3734 drawing::PolyPolygonShape3D aUnoPolyPolygon3D;
3735 aAny >>= aUnoPolyPolygon3D;
3737 // convert to 3D PolyPolygon
3738 const basegfx::B3DPolyPolygon aPolyPolygon3D(
3739 basegfx::utils::UnoPolyPolygonShape3DToB3DPolyPolygon(
3740 aUnoPolyPolygon3D));
3742 // convert to 2D tools::PolyPolygon using identity 3D transformation (just grep X and Y)
3743 const basegfx::B3DHomMatrix aB3DHomMatrixFor2DConversion;
3744 const basegfx::B2DPolyPolygon aPolyPolygon(
3745 basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(
3746 aPolyPolygon3D,
3747 aB3DHomMatrixFor2DConversion));
3749 // get 2D range of it
3750 const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange());
3752 // export ViewBox
3753 SdXMLImExViewBox aViewBox(
3754 aPolyPolygonRange.getMinX(),
3755 aPolyPolygonRange.getMinY(),
3756 aPolyPolygonRange.getWidth(),
3757 aPolyPolygonRange.getHeight());
3759 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
3761 // prepare svg:d string
3762 const OUString aPolygonString(
3763 basegfx::utils::exportToSvgD(
3764 aPolyPolygon,
3765 true, // bUseRelativeCoordinates
3766 false, // bDetectQuadraticBeziers TTTT: not used in old, but maybe activated now
3767 true)); // bHandleRelativeNextPointCompatible
3769 // write point array
3770 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
3772 if(eShapeType == XmlShapeType::Draw3DLatheObject)
3774 // write 3DLathe shape
3775 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_ROTATE, true, true);
3777 else
3779 // write 3DExtrude shape
3780 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_EXTRUDE, true, true);
3782 break;
3784 default:
3785 break;
3789 /** helper for chart that adds all attributes of a 3d scene element to the export */
3790 void XMLShapeExport::export3DSceneAttributes( const css::uno::Reference< css::beans::XPropertySet >& xPropSet )
3792 OUString aStr;
3793 OUStringBuffer sStringBuffer;
3795 // world transformation (UNO_NAME_3D_TRANSFORM_MATRIX == "D3DTransformMatrix")
3796 uno::Any aAny = xPropSet->getPropertyValue("D3DTransformMatrix");
3797 drawing::HomogenMatrix aHomMat;
3798 aAny >>= aHomMat;
3799 SdXMLImExTransform3D aTransform;
3800 aTransform.AddHomogenMatrix(aHomMat);
3801 if(aTransform.NeedsAction())
3802 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
3804 // VRP, VPN, VUP
3805 aAny = xPropSet->getPropertyValue("D3DCameraGeometry");
3806 drawing::CameraGeometry aCamGeo;
3807 aAny >>= aCamGeo;
3809 ::basegfx::B3DVector aVRP(aCamGeo.vrp.PositionX, aCamGeo.vrp.PositionY, aCamGeo.vrp.PositionZ);
3810 if(aVRP != ::basegfx::B3DVector(0.0, 0.0, 1.0)) // write only when not default
3812 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVRP);
3813 aStr = sStringBuffer.makeStringAndClear();
3814 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VRP, aStr);
3817 ::basegfx::B3DVector aVPN(aCamGeo.vpn.DirectionX, aCamGeo.vpn.DirectionY, aCamGeo.vpn.DirectionZ);
3818 if(aVPN != ::basegfx::B3DVector(0.0, 0.0, 1.0)) // write only when not default
3820 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVPN);
3821 aStr = sStringBuffer.makeStringAndClear();
3822 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VPN, aStr);
3825 ::basegfx::B3DVector aVUP(aCamGeo.vup.DirectionX, aCamGeo.vup.DirectionY, aCamGeo.vup.DirectionZ);
3826 if(aVUP != ::basegfx::B3DVector(0.0, 1.0, 0.0)) // write only when not default
3828 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVUP);
3829 aStr = sStringBuffer.makeStringAndClear();
3830 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VUP, aStr);
3833 // projection "D3DScenePerspective" drawing::ProjectionMode
3834 aAny = xPropSet->getPropertyValue("D3DScenePerspective");
3835 drawing::ProjectionMode aPrjMode;
3836 aAny >>= aPrjMode;
3837 if(aPrjMode == drawing::ProjectionMode_PARALLEL)
3838 aStr = GetXMLToken(XML_PARALLEL);
3839 else
3840 aStr = GetXMLToken(XML_PERSPECTIVE);
3841 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_PROJECTION, aStr);
3843 // distance
3844 aAny = xPropSet->getPropertyValue("D3DSceneDistance");
3845 sal_Int32 nDistance = 0;
3846 aAny >>= nDistance;
3847 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
3848 nDistance);
3849 aStr = sStringBuffer.makeStringAndClear();
3850 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DISTANCE, aStr);
3852 // focalLength
3853 aAny = xPropSet->getPropertyValue("D3DSceneFocalLength");
3854 sal_Int32 nFocalLength = 0;
3855 aAny >>= nFocalLength;
3856 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
3857 nFocalLength);
3858 aStr = sStringBuffer.makeStringAndClear();
3859 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_FOCAL_LENGTH, aStr);
3861 // shadowSlant
3862 aAny = xPropSet->getPropertyValue("D3DSceneShadowSlant");
3863 sal_Int16 nShadowSlant = 0;
3864 aAny >>= nShadowSlant;
3865 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SHADOW_SLANT, OUString::number(static_cast<sal_Int32>(nShadowSlant)));
3867 // shadeMode
3868 aAny = xPropSet->getPropertyValue("D3DSceneShadeMode");
3869 drawing::ShadeMode aShadeMode;
3870 if(aAny >>= aShadeMode)
3872 if(aShadeMode == drawing::ShadeMode_FLAT)
3873 aStr = GetXMLToken(XML_FLAT);
3874 else if(aShadeMode == drawing::ShadeMode_PHONG)
3875 aStr = GetXMLToken(XML_PHONG);
3876 else if(aShadeMode == drawing::ShadeMode_SMOOTH)
3877 aStr = GetXMLToken(XML_GOURAUD);
3878 else
3879 aStr = GetXMLToken(XML_DRAFT);
3881 else
3883 // ShadeMode enum not there, write default
3884 aStr = GetXMLToken(XML_GOURAUD);
3886 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SHADE_MODE, aStr);
3888 // ambientColor
3889 aAny = xPropSet->getPropertyValue("D3DSceneAmbientColor");
3890 sal_Int32 nAmbientColor = 0;
3891 aAny >>= nAmbientColor;
3892 ::sax::Converter::convertColor(sStringBuffer, nAmbientColor);
3893 aStr = sStringBuffer.makeStringAndClear();
3894 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_AMBIENT_COLOR, aStr);
3896 // lightingMode
3897 aAny = xPropSet->getPropertyValue("D3DSceneTwoSidedLighting");
3898 bool bTwoSidedLighting = false;
3899 aAny >>= bTwoSidedLighting;
3900 ::sax::Converter::convertBool(sStringBuffer, bTwoSidedLighting);
3901 aStr = sStringBuffer.makeStringAndClear();
3902 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_LIGHTING_MODE, aStr);
3905 /** helper for chart that exports all lamps from the propertyset */
3906 void XMLShapeExport::export3DLamps( const css::uno::Reference< css::beans::XPropertySet >& xPropSet )
3908 // write lamps 1..8 as content
3909 OUString aStr;
3910 OUStringBuffer sStringBuffer;
3912 static const OUStringLiteral aColorPropName(u"D3DSceneLightColor");
3913 static const OUStringLiteral aDirectionPropName(u"D3DSceneLightDirection");
3914 static const OUStringLiteral aLightOnPropName(u"D3DSceneLightOn");
3916 ::basegfx::B3DVector aLightDirection;
3917 drawing::Direction3D aLightDir;
3918 bool bLightOnOff = false;
3919 for(sal_Int32 nLamp = 1; nLamp <= 8; nLamp++)
3921 OUString aIndexStr = OUString::number( nLamp );
3923 // lightcolor
3924 OUString aPropName = aColorPropName + aIndexStr;
3925 sal_Int32 nLightColor = 0;
3926 xPropSet->getPropertyValue( aPropName ) >>= nLightColor;
3927 ::sax::Converter::convertColor(sStringBuffer, nLightColor);
3928 aStr = sStringBuffer.makeStringAndClear();
3929 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DIFFUSE_COLOR, aStr);
3931 // lightdirection
3932 aPropName = aDirectionPropName + aIndexStr;
3933 xPropSet->getPropertyValue(aPropName) >>= aLightDir;
3934 aLightDirection = ::basegfx::B3DVector(aLightDir.DirectionX, aLightDir.DirectionY, aLightDir.DirectionZ);
3935 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aLightDirection);
3936 aStr = sStringBuffer.makeStringAndClear();
3937 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DIRECTION, aStr);
3939 // lighton
3940 aPropName = aLightOnPropName + aIndexStr;
3941 xPropSet->getPropertyValue(aPropName) >>= bLightOnOff;
3942 ::sax::Converter::convertBool(sStringBuffer, bLightOnOff);
3943 aStr = sStringBuffer.makeStringAndClear();
3944 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_ENABLED, aStr);
3946 // specular
3947 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SPECULAR,
3948 nLamp == 1 ? XML_TRUE : XML_FALSE);
3950 // write light entry
3951 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_LIGHT, true, true);
3956 // using namespace css::io;
3957 // using namespace ::xmloff::EnhancedCustomShapeToken;
3960 static void ExportParameter( OUStringBuffer& rStrBuffer, const css::drawing::EnhancedCustomShapeParameter& rParameter )
3962 if ( !rStrBuffer.isEmpty() )
3963 rStrBuffer.append( ' ' );
3964 if ( rParameter.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
3966 double fNumber = 0.0;
3967 rParameter.Value >>= fNumber;
3968 ::rtl::math::doubleToUStringBuffer( rStrBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true );
3970 else
3972 sal_Int32 nValue = 0;
3973 rParameter.Value >>= nValue;
3975 switch( rParameter.Type )
3977 case css::drawing::EnhancedCustomShapeParameterType::EQUATION :
3979 rStrBuffer.append( "?f" + OUString::number( nValue ) );
3981 break;
3983 case css::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT :
3985 rStrBuffer.append( '$' );
3986 rStrBuffer.append( nValue );
3988 break;
3990 case css::drawing::EnhancedCustomShapeParameterType::BOTTOM :
3991 rStrBuffer.append( GetXMLToken( XML_BOTTOM ) ); break;
3992 case css::drawing::EnhancedCustomShapeParameterType::RIGHT :
3993 rStrBuffer.append( GetXMLToken( XML_RIGHT ) ); break;
3994 case css::drawing::EnhancedCustomShapeParameterType::TOP :
3995 rStrBuffer.append( GetXMLToken( XML_TOP ) ); break;
3996 case css::drawing::EnhancedCustomShapeParameterType::LEFT :
3997 rStrBuffer.append( GetXMLToken( XML_LEFT ) ); break;
3998 case css::drawing::EnhancedCustomShapeParameterType::XSTRETCH :
3999 rStrBuffer.append( GetXMLToken( XML_XSTRETCH ) ); break;
4000 case css::drawing::EnhancedCustomShapeParameterType::YSTRETCH :
4001 rStrBuffer.append( GetXMLToken( XML_YSTRETCH ) ); break;
4002 case css::drawing::EnhancedCustomShapeParameterType::HASSTROKE :
4003 rStrBuffer.append( GetXMLToken( XML_HASSTROKE ) ); break;
4004 case css::drawing::EnhancedCustomShapeParameterType::HASFILL :
4005 rStrBuffer.append( GetXMLToken( XML_HASFILL ) ); break;
4006 case css::drawing::EnhancedCustomShapeParameterType::WIDTH :
4007 rStrBuffer.append( GetXMLToken( XML_WIDTH ) ); break;
4008 case css::drawing::EnhancedCustomShapeParameterType::HEIGHT :
4009 rStrBuffer.append( GetXMLToken( XML_HEIGHT ) ); break;
4010 case css::drawing::EnhancedCustomShapeParameterType::LOGWIDTH :
4011 rStrBuffer.append( GetXMLToken( XML_LOGWIDTH ) ); break;
4012 case css::drawing::EnhancedCustomShapeParameterType::LOGHEIGHT :
4013 rStrBuffer.append( GetXMLToken( XML_LOGHEIGHT ) ); break;
4014 default :
4015 rStrBuffer.append( nValue );
4020 static void ImpExportEquations( SvXMLExport& rExport, const uno::Sequence< OUString >& rEquations )
4022 sal_Int32 i;
4023 for ( i = 0; i < rEquations.getLength(); i++ )
4025 OUString aStr= "f" + OUString::number( i );
4026 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aStr );
4028 aStr = rEquations[ i ];
4029 sal_Int32 nIndex = 0;
4032 nIndex = aStr.indexOf( '?', nIndex );
4033 if ( nIndex != -1 )
4035 aStr = OUString::Concat(aStr.subView(0, nIndex + 1)) + "f"
4036 + aStr.subView(nIndex + 1, aStr.getLength() - nIndex - 1);
4037 nIndex++;
4039 } while( nIndex != -1 );
4040 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FORMULA, aStr );
4041 SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_EQUATION, true, true );
4045 static void ImpExportHandles( SvXMLExport& rExport, const uno::Sequence< beans::PropertyValues >& rHandles )
4047 if ( !rHandles.hasElements() )
4048 return;
4050 OUString aStr;
4051 OUStringBuffer aStrBuffer;
4053 for ( const uno::Sequence< beans::PropertyValue >& rPropSeq : rHandles )
4055 bool bPosition = false;
4056 for ( const beans::PropertyValue& rPropVal : rPropSeq )
4058 switch( EASGet( rPropVal.Name ) )
4060 case EAS_Position :
4062 css::drawing::EnhancedCustomShapeParameterPair aPosition;
4063 if ( rPropVal.Value >>= aPosition )
4065 ExportParameter( aStrBuffer, aPosition.First );
4066 ExportParameter( aStrBuffer, aPosition.Second );
4067 aStr = aStrBuffer.makeStringAndClear();
4068 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POSITION, aStr );
4069 bPosition = true;
4072 break;
4073 case EAS_MirroredX :
4075 bool bMirroredX;
4076 if ( rPropVal.Value >>= bMirroredX )
4077 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_MIRROR_HORIZONTAL,
4078 bMirroredX ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4080 break;
4081 case EAS_MirroredY :
4083 bool bMirroredY;
4084 if ( rPropVal.Value >>= bMirroredY )
4085 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_MIRROR_VERTICAL,
4086 bMirroredY ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4088 break;
4089 case EAS_Switched :
4091 bool bSwitched;
4092 if ( rPropVal.Value >>= bSwitched )
4093 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_SWITCHED,
4094 bSwitched ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4096 break;
4097 case EAS_Polar :
4099 css::drawing::EnhancedCustomShapeParameterPair aPolar;
4100 if ( rPropVal.Value >>= aPolar )
4102 ExportParameter( aStrBuffer, aPolar.First );
4103 ExportParameter( aStrBuffer, aPolar.Second );
4104 aStr = aStrBuffer.makeStringAndClear();
4105 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POLAR, aStr );
4108 break;
4109 case EAS_RadiusRangeMinimum :
4111 css::drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum;
4112 if ( rPropVal.Value >>= aRadiusRangeMinimum )
4114 ExportParameter( aStrBuffer, aRadiusRangeMinimum );
4115 aStr = aStrBuffer.makeStringAndClear();
4116 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RADIUS_RANGE_MINIMUM, aStr );
4119 break;
4120 case EAS_RadiusRangeMaximum :
4122 css::drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum;
4123 if ( rPropVal.Value >>= aRadiusRangeMaximum )
4125 ExportParameter( aStrBuffer, aRadiusRangeMaximum );
4126 aStr = aStrBuffer.makeStringAndClear();
4127 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RADIUS_RANGE_MAXIMUM, aStr );
4130 break;
4131 case EAS_RangeXMinimum :
4133 css::drawing::EnhancedCustomShapeParameter aXRangeMinimum;
4134 if ( rPropVal.Value >>= aXRangeMinimum )
4136 ExportParameter( aStrBuffer, aXRangeMinimum );
4137 aStr = aStrBuffer.makeStringAndClear();
4138 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_X_MINIMUM, aStr );
4141 break;
4142 case EAS_RangeXMaximum :
4144 css::drawing::EnhancedCustomShapeParameter aXRangeMaximum;
4145 if ( rPropVal.Value >>= aXRangeMaximum )
4147 ExportParameter( aStrBuffer, aXRangeMaximum );
4148 aStr = aStrBuffer.makeStringAndClear();
4149 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_X_MAXIMUM, aStr );
4152 break;
4153 case EAS_RangeYMinimum :
4155 css::drawing::EnhancedCustomShapeParameter aYRangeMinimum;
4156 if ( rPropVal.Value >>= aYRangeMinimum )
4158 ExportParameter( aStrBuffer, aYRangeMinimum );
4159 aStr = aStrBuffer.makeStringAndClear();
4160 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_Y_MINIMUM, aStr );
4163 break;
4164 case EAS_RangeYMaximum :
4166 css::drawing::EnhancedCustomShapeParameter aYRangeMaximum;
4167 if ( rPropVal.Value >>= aYRangeMaximum )
4169 ExportParameter( aStrBuffer, aYRangeMaximum );
4170 aStr = aStrBuffer.makeStringAndClear();
4171 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_Y_MAXIMUM, aStr );
4174 break;
4175 default:
4176 break;
4179 if ( bPosition )
4180 SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_HANDLE, true, true );
4181 else
4182 rExport.ClearAttrList();
4186 static void ImpExportEnhancedPath( SvXMLExport& rExport,
4187 const uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair >& rCoordinates,
4188 const uno::Sequence< css::drawing::EnhancedCustomShapeSegment >& rSegments,
4189 bool bExtended = false )
4192 OUString aStr;
4193 OUStringBuffer aStrBuffer;
4194 bool bNeedExtended = false;
4196 sal_Int32 i, j, k, l;
4198 sal_Int32 nCoords = rCoordinates.getLength();
4199 sal_Int32 nSegments = rSegments.getLength();
4200 bool bSimpleSegments = nSegments == 0;
4201 if ( bSimpleSegments )
4202 nSegments = 4;
4203 for ( j = i = 0; j < nSegments; j++ )
4205 css::drawing::EnhancedCustomShapeSegment aSegment;
4206 if ( bSimpleSegments )
4208 // if there are not enough segments we will default them
4209 switch( j )
4211 case 0 :
4213 aSegment.Count = 1;
4214 aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO;
4216 break;
4217 case 1 :
4219 aSegment.Count = static_cast<sal_Int16>(std::min( nCoords - 1, sal_Int32(32767) ));
4220 aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO;
4222 break;
4223 case 2 :
4225 aSegment.Count = 1;
4226 aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH;
4228 break;
4229 case 3 :
4231 aSegment.Count = 1;
4232 aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
4234 break;
4237 else
4238 aSegment = rSegments[ j ];
4240 if ( !aStrBuffer.isEmpty() )
4241 aStrBuffer.append( ' ' );
4243 sal_Int32 nParameter = 0;
4244 switch( aSegment.Command )
4246 case css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH :
4247 aStrBuffer.append( 'Z' ); break;
4248 case css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH :
4249 aStrBuffer.append( 'N' ); break;
4250 case css::drawing::EnhancedCustomShapeSegmentCommand::NOFILL :
4251 aStrBuffer.append( 'F' ); break;
4252 case css::drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE :
4253 aStrBuffer.append( 'S' ); break;
4255 case css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO :
4256 aStrBuffer.append( 'M' ); nParameter = 1; break;
4257 case css::drawing::EnhancedCustomShapeSegmentCommand::LINETO :
4258 aStrBuffer.append( 'L' ); nParameter = 1; break;
4259 case css::drawing::EnhancedCustomShapeSegmentCommand::CURVETO :
4260 aStrBuffer.append( 'C' ); nParameter = 3; break;
4261 case css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO :
4262 aStrBuffer.append( 'T' ); nParameter = 3; break;
4263 case css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE :
4264 aStrBuffer.append( 'U' ); nParameter = 3; break;
4265 case css::drawing::EnhancedCustomShapeSegmentCommand::ARCTO :
4266 aStrBuffer.append( 'A' ); nParameter = 4; break;
4267 case css::drawing::EnhancedCustomShapeSegmentCommand::ARC :
4268 aStrBuffer.append( 'B' ); nParameter = 4; break;
4269 case css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO :
4270 aStrBuffer.append( 'W' ); nParameter = 4; break;
4271 case css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC :
4272 aStrBuffer.append( 'V' ); nParameter = 4; break;
4273 case css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX :
4274 aStrBuffer.append( 'X' ); nParameter = 1; break;
4275 case css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY :
4276 aStrBuffer.append( 'Y' ); nParameter = 1; break;
4277 case css::drawing::EnhancedCustomShapeSegmentCommand::QUADRATICCURVETO :
4278 aStrBuffer.append( 'Q' ); nParameter = 2; break;
4279 case css::drawing::EnhancedCustomShapeSegmentCommand::ARCANGLETO :
4280 if ( bExtended ) {
4281 aStrBuffer.append( 'G' );
4282 nParameter = 2;
4283 } else {
4284 aStrBuffer.setLength( aStrBuffer.getLength() - 1);
4285 bNeedExtended = true;
4286 i += 2;
4288 break;
4289 case css::drawing::EnhancedCustomShapeSegmentCommand::DARKEN :
4290 if ( bExtended )
4291 aStrBuffer.append( 'H' );
4292 else
4293 bNeedExtended = true;
4294 break;
4295 case css::drawing::EnhancedCustomShapeSegmentCommand::DARKENLESS :
4296 if ( bExtended )
4297 aStrBuffer.append( 'I' );
4298 else
4299 bNeedExtended = true;
4300 break;
4301 case css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTEN :
4302 if ( bExtended )
4303 aStrBuffer.append( 'J' );
4304 else
4305 bNeedExtended = true;
4306 break;
4307 case css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTENLESS :
4308 if ( bExtended )
4309 aStrBuffer.append( 'K' );
4310 else
4311 bNeedExtended = true;
4312 break;
4313 default : // ups, seems to be something wrong
4315 aSegment.Count = 1;
4316 aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO;
4318 break;
4320 if ( nParameter )
4322 for ( k = 0; k < aSegment.Count; k++ )
4324 if ( ( i + nParameter ) <= nCoords )
4326 for ( l = 0; l < nParameter; l++ )
4328 ExportParameter( aStrBuffer, rCoordinates[ i ].First );
4329 ExportParameter( aStrBuffer, rCoordinates[ i++ ].Second );
4332 else
4334 j = nSegments; // error -> exiting
4335 break;
4340 aStr = aStrBuffer.makeStringAndClear();
4341 rExport.AddAttribute( bExtended ? XML_NAMESPACE_DRAW_EXT : XML_NAMESPACE_DRAW, XML_ENHANCED_PATH, aStr );
4342 if (!bExtended && bNeedExtended && (rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED))
4343 ImpExportEnhancedPath( rExport, rCoordinates, rSegments, true );
4346 static void ImpExportEnhancedGeometry( SvXMLExport& rExport, const uno::Reference< beans::XPropertySet >& xPropSet )
4348 bool bEquations = false;
4349 uno::Sequence< OUString > aEquations;
4351 bool bHandles = false;
4352 uno::Sequence< beans::PropertyValues > aHandles;
4354 uno::Sequence< css::drawing::EnhancedCustomShapeSegment > aSegments;
4355 uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates;
4357 uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentValues;
4359 OUString aStr;
4360 OUStringBuffer aStrBuffer;
4361 double fTextRotateAngle(0.0);
4362 double fTextPreRotateAngle(0.0); // will be consolidated with fTextRotateAngle at the end
4363 SvXMLUnitConverter& rUnitConverter = rExport.GetMM100UnitConverter();
4365 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
4367 // geometry
4368 static const OUStringLiteral sCustomShapeGeometry( u"CustomShapeGeometry" );
4369 if ( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName( sCustomShapeGeometry ) )
4371 uno::Any aGeoPropSet( xPropSet->getPropertyValue( sCustomShapeGeometry ) );
4372 uno::Sequence< beans::PropertyValue > aGeoPropSeq;
4374 if ( aGeoPropSet >>= aGeoPropSeq )
4376 bool bCoordinates = false;
4377 OUString aCustomShapeType( "non-primitive" );
4379 for ( const beans::PropertyValue& rGeoProp : std::as_const(aGeoPropSeq) )
4381 switch( EASGet( rGeoProp.Name ) )
4383 case EAS_Type :
4385 rGeoProp.Value >>= aCustomShapeType;
4387 break;
4388 case EAS_MirroredX :
4390 bool bMirroredX;
4391 if ( rGeoProp.Value >>= bMirroredX )
4392 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIRROR_HORIZONTAL,
4393 bMirroredX ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4395 break;
4396 case EAS_MirroredY :
4398 bool bMirroredY;
4399 if ( rGeoProp.Value >>= bMirroredY )
4400 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIRROR_VERTICAL,
4401 bMirroredY ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4403 break;
4404 case EAS_ViewBox :
4406 awt::Rectangle aRect;
4407 if ( rGeoProp.Value >>= aRect )
4409 SdXMLImExViewBox aViewBox( aRect.X, aRect.Y, aRect.Width, aRect.Height );
4410 rExport.AddAttribute( XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString() );
4413 break;
4414 case EAS_TextPreRotateAngle :
4416 rGeoProp.Value >>= fTextPreRotateAngle;
4418 break;
4419 case EAS_TextRotateAngle :
4421 rGeoProp.Value >>= fTextRotateAngle;
4423 break;
4424 case EAS_Extrusion :
4426 uno::Sequence< beans::PropertyValue > aExtrusionPropSeq;
4427 if ( rGeoProp.Value >>= aExtrusionPropSeq )
4429 bool bSkewValuesProvided = false;
4430 for ( const beans::PropertyValue& rProp : std::as_const(aExtrusionPropSeq) )
4432 switch( EASGet( rProp.Name ) )
4434 case EAS_Extrusion :
4436 bool bExtrusionOn;
4437 if ( rProp.Value >>= bExtrusionOn )
4438 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION,
4439 bExtrusionOn ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4441 break;
4442 case EAS_Brightness :
4444 double fExtrusionBrightness = 0;
4445 if ( rProp.Value >>= fExtrusionBrightness )
4447 ::sax::Converter::convertDouble(
4448 aStrBuffer,
4449 fExtrusionBrightness,
4450 false,
4451 util::MeasureUnit::PERCENT,
4452 util::MeasureUnit::PERCENT);
4453 aStrBuffer.append( '%' );
4454 aStr = aStrBuffer.makeStringAndClear();
4455 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_BRIGHTNESS, aStr );
4458 break;
4459 case EAS_Depth :
4461 css::drawing::EnhancedCustomShapeParameterPair aDepthParaPair;
4462 if ( rProp.Value >>= aDepthParaPair )
4464 double fDepth = 0;
4465 if ( aDepthParaPair.First.Value >>= fDepth )
4467 rExport.GetMM100UnitConverter().convertDouble( aStrBuffer, fDepth );
4468 ExportParameter( aStrBuffer, aDepthParaPair.Second );
4469 aStr = aStrBuffer.makeStringAndClear();
4470 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_DEPTH, aStr );
4474 break;
4475 case EAS_Diffusion :
4477 double fExtrusionDiffusion = 0;
4478 if ( rProp.Value >>= fExtrusionDiffusion )
4480 ::sax::Converter::convertDouble(
4481 aStrBuffer,
4482 fExtrusionDiffusion,
4483 false,
4484 util::MeasureUnit::PERCENT,
4485 util::MeasureUnit::PERCENT);
4486 aStrBuffer.append( '%' );
4487 aStr = aStrBuffer.makeStringAndClear();
4488 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_DIFFUSION, aStr );
4491 break;
4492 case EAS_NumberOfLineSegments :
4494 sal_Int32 nExtrusionNumberOfLineSegments = 0;
4495 if ( rProp.Value >>= nExtrusionNumberOfLineSegments )
4496 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_NUMBER_OF_LINE_SEGMENTS, OUString::number( nExtrusionNumberOfLineSegments ) );
4498 break;
4499 case EAS_LightFace :
4501 bool bExtrusionLightFace;
4502 if ( rProp.Value >>= bExtrusionLightFace )
4503 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_LIGHT_FACE,
4504 bExtrusionLightFace ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4506 break;
4507 case EAS_FirstLightHarsh :
4509 bool bExtrusionFirstLightHarsh;
4510 if ( rProp.Value >>= bExtrusionFirstLightHarsh )
4511 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_HARSH,
4512 bExtrusionFirstLightHarsh ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4514 break;
4515 case EAS_SecondLightHarsh :
4517 bool bExtrusionSecondLightHarsh;
4518 if ( rProp.Value >>= bExtrusionSecondLightHarsh )
4519 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_HARSH,
4520 bExtrusionSecondLightHarsh ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4522 break;
4523 case EAS_FirstLightLevel :
4525 double fExtrusionFirstLightLevel = 0;
4526 if ( rProp.Value >>= fExtrusionFirstLightLevel )
4528 ::sax::Converter::convertDouble(
4529 aStrBuffer,
4530 fExtrusionFirstLightLevel,
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_FIRST_LIGHT_LEVEL, aStr );
4539 break;
4540 case EAS_SecondLightLevel :
4542 double fExtrusionSecondLightLevel = 0;
4543 if ( rProp.Value >>= fExtrusionSecondLightLevel )
4545 ::sax::Converter::convertDouble(
4546 aStrBuffer,
4547 fExtrusionSecondLightLevel,
4548 false,
4549 util::MeasureUnit::PERCENT,
4550 util::MeasureUnit::PERCENT);
4551 aStrBuffer.append( '%' );
4552 aStr = aStrBuffer.makeStringAndClear();
4553 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_LEVEL, aStr );
4556 break;
4557 case EAS_FirstLightDirection :
4559 drawing::Direction3D aExtrusionFirstLightDirection;
4560 if ( rProp.Value >>= aExtrusionFirstLightDirection )
4562 ::basegfx::B3DVector aVec3D( aExtrusionFirstLightDirection.DirectionX, aExtrusionFirstLightDirection.DirectionY,
4563 aExtrusionFirstLightDirection.DirectionZ );
4564 SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D );
4565 aStr = aStrBuffer.makeStringAndClear();
4566 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_DIRECTION, aStr );
4569 break;
4570 case EAS_SecondLightDirection :
4572 drawing::Direction3D aExtrusionSecondLightDirection;
4573 if ( rProp.Value >>= aExtrusionSecondLightDirection )
4575 ::basegfx::B3DVector aVec3D( aExtrusionSecondLightDirection.DirectionX, aExtrusionSecondLightDirection.DirectionY,
4576 aExtrusionSecondLightDirection.DirectionZ );
4577 SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D );
4578 aStr = aStrBuffer.makeStringAndClear();
4579 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_DIRECTION, aStr );
4582 break;
4583 case EAS_Metal :
4585 bool bExtrusionMetal;
4586 if ( rProp.Value >>= bExtrusionMetal )
4587 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_METAL,
4588 bExtrusionMetal ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4590 break;
4591 case EAS_MetalType :
4593 // export only if ODF extensions are enabled
4594 sal_Int16 eMetalType;
4595 if (rProp.Value >>= eMetalType)
4597 SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion();
4598 if (eVersion > SvtSaveOptions::ODFSVER_013
4599 && (eVersion & SvtSaveOptions::ODFSVER_EXTENDED))
4601 if (eMetalType == drawing::EnhancedCustomShapeMetalType::MetalMSCompatible)
4602 aStr = "loext:MetalMSCompatible";
4603 else
4604 aStr = "draw:MetalODF";
4605 rExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_EXTRUSION_METAL_TYPE, aStr);
4609 break;
4610 case EAS_ShadeMode :
4612 // shadeMode
4613 drawing::ShadeMode eShadeMode;
4614 if( rProp.Value >>= eShadeMode )
4616 if( eShadeMode == drawing::ShadeMode_FLAT )
4617 aStr = GetXMLToken( XML_FLAT );
4618 else if( eShadeMode == drawing::ShadeMode_PHONG )
4619 aStr = GetXMLToken( XML_PHONG );
4620 else if( eShadeMode == drawing::ShadeMode_SMOOTH )
4621 aStr = GetXMLToken( XML_GOURAUD );
4622 else
4623 aStr = GetXMLToken( XML_DRAFT );
4625 else
4627 // ShadeMode enum not there, write default
4628 aStr = GetXMLToken( XML_FLAT);
4630 rExport.AddAttribute( XML_NAMESPACE_DR3D, XML_SHADE_MODE, aStr );
4632 break;
4633 case EAS_RotateAngle :
4635 css::drawing::EnhancedCustomShapeParameterPair aRotateAngleParaPair;
4636 if ( rProp.Value >>= aRotateAngleParaPair )
4638 ExportParameter( aStrBuffer, aRotateAngleParaPair.First );
4639 ExportParameter( aStrBuffer, aRotateAngleParaPair.Second );
4640 aStr = aStrBuffer.makeStringAndClear();
4641 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ROTATION_ANGLE, aStr );
4644 break;
4645 case EAS_RotationCenter :
4647 drawing::Direction3D aExtrusionRotationCenter;
4648 if ( rProp.Value >>= aExtrusionRotationCenter )
4650 ::basegfx::B3DVector aVec3D( aExtrusionRotationCenter.DirectionX, aExtrusionRotationCenter.DirectionY,
4651 aExtrusionRotationCenter.DirectionZ );
4652 SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D );
4653 aStr = aStrBuffer.makeStringAndClear();
4654 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ROTATION_CENTER, aStr );
4657 break;
4658 case EAS_Shininess :
4660 double fExtrusionShininess = 0;
4661 if ( rProp.Value >>= fExtrusionShininess )
4663 ::sax::Converter::convertDouble(
4664 aStrBuffer,
4665 fExtrusionShininess,
4666 false,
4667 util::MeasureUnit::PERCENT,
4668 util::MeasureUnit::PERCENT);
4669 aStrBuffer.append( '%' );
4670 aStr = aStrBuffer.makeStringAndClear();
4671 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SHININESS, aStr );
4674 break;
4675 case EAS_Skew :
4677 css::drawing::EnhancedCustomShapeParameterPair aSkewParaPair;
4678 if ( rProp.Value >>= aSkewParaPair )
4680 bSkewValuesProvided = true;
4681 ExportParameter( aStrBuffer, aSkewParaPair.First );
4682 ExportParameter( aStrBuffer, aSkewParaPair.Second );
4683 aStr = aStrBuffer.makeStringAndClear();
4684 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SKEW, aStr );
4687 break;
4688 case EAS_Specularity :
4690 double fExtrusionSpecularity = 0;
4691 if ( rProp.Value >>= fExtrusionSpecularity )
4693 SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion();
4694 if (fExtrusionSpecularity > 100.0 && eVersion >= SvtSaveOptions::ODFSVER_012
4695 && (eVersion & SvtSaveOptions::ODFSVER_EXTENDED))
4697 // tdf#147580 write values > 100% in loext
4698 ::sax::Converter::convertDouble(
4699 aStrBuffer,
4700 fExtrusionSpecularity,
4701 false,
4702 util::MeasureUnit::PERCENT,
4703 util::MeasureUnit::PERCENT);
4704 aStrBuffer.append( '%' );
4705 aStr = aStrBuffer.makeStringAndClear();
4706 rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_EXTRUSION_SPECULARITY_LOEXT, aStr );
4708 // tdf#147580 ODF 1 allows arbitrary percent, later versions not
4709 if (eVersion >= SvtSaveOptions::ODFSVER_012)
4711 fExtrusionSpecularity = std::clamp<double>(fExtrusionSpecularity, 0.0, 100.0);
4713 ::sax::Converter::convertDouble(
4714 aStrBuffer,
4715 fExtrusionSpecularity,
4716 false,
4717 util::MeasureUnit::PERCENT,
4718 util::MeasureUnit::PERCENT);
4719 aStrBuffer.append( '%' );
4720 aStr = aStrBuffer.makeStringAndClear();
4721 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SPECULARITY, aStr );
4724 break;
4725 case EAS_ProjectionMode :
4727 drawing::ProjectionMode eProjectionMode;
4728 if ( rProp.Value >>= eProjectionMode )
4729 rExport.AddAttribute( XML_NAMESPACE_DR3D, XML_PROJECTION,
4730 eProjectionMode == drawing::ProjectionMode_PARALLEL ? GetXMLToken( XML_PARALLEL ) : GetXMLToken( XML_PERSPECTIVE ) );
4732 break;
4733 case EAS_ViewPoint :
4735 drawing::Position3D aExtrusionViewPoint;
4736 if ( rProp.Value >>= aExtrusionViewPoint )
4738 rUnitConverter.convertPosition3D( aStrBuffer, aExtrusionViewPoint );
4739 aStr = aStrBuffer.makeStringAndClear();
4740 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_VIEWPOINT, aStr );
4743 break;
4744 case EAS_Origin :
4746 css::drawing::EnhancedCustomShapeParameterPair aOriginParaPair;
4747 if ( rProp.Value >>= aOriginParaPair )
4749 ExportParameter( aStrBuffer, aOriginParaPair.First );
4750 ExportParameter( aStrBuffer, aOriginParaPair.Second );
4751 aStr = aStrBuffer.makeStringAndClear();
4752 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ORIGIN, aStr );
4755 break;
4756 case EAS_Color :
4758 bool bExtrusionColor;
4759 if ( rProp.Value >>= bExtrusionColor )
4761 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_COLOR,
4762 bExtrusionColor ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4765 break;
4766 default:
4767 break;
4770 // tdf#141301: no specific skew values provided
4771 if (!bSkewValuesProvided)
4773 // so we need to export default values explicitly
4774 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SKEW, "50 -135");
4778 break;
4779 case EAS_TextPath :
4781 uno::Sequence< beans::PropertyValue > aTextPathPropSeq;
4782 if ( rGeoProp.Value >>= aTextPathPropSeq )
4784 for ( const beans::PropertyValue& rProp : std::as_const(aTextPathPropSeq) )
4786 switch( EASGet( rProp.Name ) )
4788 case EAS_TextPath :
4790 bool bTextPathOn;
4791 if ( rProp.Value >>= bTextPathOn )
4792 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH,
4793 bTextPathOn ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4795 break;
4796 case EAS_TextPathMode :
4798 css::drawing::EnhancedCustomShapeTextPathMode eTextPathMode;
4799 if ( rProp.Value >>= eTextPathMode )
4801 switch ( eTextPathMode )
4803 case css::drawing::EnhancedCustomShapeTextPathMode_NORMAL: aStr = GetXMLToken( XML_NORMAL ); break;
4804 case css::drawing::EnhancedCustomShapeTextPathMode_PATH : aStr = GetXMLToken( XML_PATH ); break;
4805 case css::drawing::EnhancedCustomShapeTextPathMode_SHAPE : aStr = GetXMLToken( XML_SHAPE ); break;
4806 default:
4807 break;
4809 if ( !aStr.isEmpty() )
4810 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_MODE, aStr );
4813 break;
4814 case EAS_ScaleX :
4816 bool bScaleX;
4817 if ( rProp.Value >>= bScaleX )
4819 aStr = bScaleX ? GetXMLToken( XML_SHAPE ) : GetXMLToken( XML_PATH );
4820 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_SCALE, aStr );
4823 break;
4824 case EAS_SameLetterHeights :
4826 bool bSameLetterHeights;
4827 if ( rProp.Value >>= bSameLetterHeights )
4828 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_SAME_LETTER_HEIGHTS,
4829 bSameLetterHeights ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4831 break;
4832 default:
4833 break;
4838 break;
4839 case EAS_Path :
4841 uno::Sequence< beans::PropertyValue > aPathPropSeq;
4842 if ( rGeoProp.Value >>= aPathPropSeq )
4844 for ( const beans::PropertyValue& rProp : std::as_const(aPathPropSeq) )
4846 switch( EASGet( rProp.Name ) )
4848 case EAS_SubViewSize:
4850 // export draw:sub-view-size (do not export in ODF 1.3 or older)
4851 if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
4853 continue;
4855 uno::Sequence< awt::Size > aSubViewSizes;
4856 rProp.Value >>= aSubViewSizes;
4858 for ( int nIdx = 0; nIdx < aSubViewSizes.getLength(); nIdx++ )
4860 if ( nIdx )
4861 aStrBuffer.append(' ');
4862 aStrBuffer.append( aSubViewSizes[nIdx].Width );
4863 aStrBuffer.append(' ');
4864 aStrBuffer.append( aSubViewSizes[nIdx].Height );
4866 aStr = aStrBuffer.makeStringAndClear();
4867 rExport.AddAttribute( XML_NAMESPACE_DRAW_EXT, XML_SUB_VIEW_SIZE, aStr );
4869 break;
4870 case EAS_ExtrusionAllowed :
4872 bool bExtrusionAllowed;
4873 if ( rProp.Value >>= bExtrusionAllowed )
4874 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ALLOWED,
4875 bExtrusionAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4877 break;
4878 case EAS_ConcentricGradientFillAllowed :
4880 bool bConcentricGradientFillAllowed;
4881 if ( rProp.Value >>= bConcentricGradientFillAllowed )
4882 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CONCENTRIC_GRADIENT_FILL_ALLOWED,
4883 bConcentricGradientFillAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4885 break;
4886 case EAS_TextPathAllowed :
4888 bool bTextPathAllowed;
4889 if ( rProp.Value >>= bTextPathAllowed )
4890 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_ALLOWED,
4891 bTextPathAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4893 break;
4894 case EAS_GluePoints :
4896 css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> aGluePoints;
4897 if ( rProp.Value >>= aGluePoints )
4899 if ( aGluePoints.hasElements() )
4901 for( const auto& rGluePoint : std::as_const(aGluePoints) )
4903 ExportParameter( aStrBuffer, rGluePoint.First );
4904 ExportParameter( aStrBuffer, rGluePoint.Second );
4906 aStr = aStrBuffer.makeStringAndClear();
4908 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GLUE_POINTS, aStr );
4911 break;
4912 case EAS_GluePointType :
4914 sal_Int16 nGluePointType = sal_Int16();
4915 if ( rProp.Value >>= nGluePointType )
4917 switch ( nGluePointType )
4919 case css::drawing::EnhancedCustomShapeGluePointType::NONE : aStr = GetXMLToken( XML_NONE ); break;
4920 case css::drawing::EnhancedCustomShapeGluePointType::SEGMENTS : aStr = GetXMLToken( XML_SEGMENTS ); break;
4921 case css::drawing::EnhancedCustomShapeGluePointType::RECT : aStr = GetXMLToken( XML_RECTANGLE ); break;
4923 if ( !aStr.isEmpty() )
4924 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GLUE_POINT_TYPE, aStr );
4927 break;
4928 case EAS_Coordinates :
4930 bCoordinates = ( rProp.Value >>= aCoordinates );
4932 break;
4933 case EAS_Segments :
4935 rProp.Value >>= aSegments;
4937 break;
4938 case EAS_StretchX :
4940 sal_Int32 nStretchPoint = 0;
4941 if ( rProp.Value >>= nStretchPoint )
4942 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PATH_STRETCHPOINT_X, OUString::number( nStretchPoint ) );
4944 break;
4945 case EAS_StretchY :
4947 sal_Int32 nStretchPoint = 0;
4948 if ( rProp.Value >>= nStretchPoint )
4949 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PATH_STRETCHPOINT_Y, OUString::number( nStretchPoint ) );
4951 break;
4952 case EAS_TextFrames :
4954 css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aPathTextFrames;
4955 if ( rProp.Value >>= aPathTextFrames )
4957 if ( aPathTextFrames.hasElements() )
4959 for ( const auto& rPathTextFrame : std::as_const(aPathTextFrames) )
4961 ExportParameter( aStrBuffer, rPathTextFrame.TopLeft.First );
4962 ExportParameter( aStrBuffer, rPathTextFrame.TopLeft.Second );
4963 ExportParameter( aStrBuffer, rPathTextFrame.BottomRight.First );
4964 ExportParameter( aStrBuffer, rPathTextFrame.BottomRight.Second );
4966 aStr = aStrBuffer.makeStringAndClear();
4968 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_AREAS, aStr );
4971 break;
4972 default:
4973 break;
4978 break;
4979 case EAS_Equations :
4981 bEquations = ( rGeoProp.Value >>= aEquations );
4983 break;
4984 case EAS_Handles :
4986 bHandles = ( rGeoProp.Value >>= aHandles );
4988 break;
4989 case EAS_AdjustmentValues :
4991 rGeoProp.Value >>= aAdjustmentValues;
4993 break;
4994 default:
4995 break;
4997 } // for
4999 // ToDo: Where is TextPreRotateAngle still used? We cannot save it in ODF.
5000 fTextRotateAngle += fTextPreRotateAngle;
5001 // Workaround for writing-mode bt-lr and tb-rl90 in ODF strict,
5002 // otherwise loext:writing-mode is used in style export.
5003 if (!(rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED))
5005 if (xPropSetInfo->hasPropertyByName(u"WritingMode"))
5007 sal_Int16 nDirection = -1;
5008 xPropSet->getPropertyValue(u"WritingMode") >>= nDirection;
5009 if (nDirection == text::WritingMode2::TB_RL90)
5010 fTextRotateAngle -= 90;
5011 else if (nDirection == text::WritingMode2::BT_LR)
5012 fTextRotateAngle -= 270;
5015 if (fTextRotateAngle != 0)
5017 ::sax::Converter::convertDouble( aStrBuffer, fTextRotateAngle );
5018 aStr = aStrBuffer.makeStringAndClear();
5019 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_ROTATE_ANGLE, aStr );
5022 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TYPE, aCustomShapeType );
5024 // adjustments
5025 sal_Int32 nAdjustmentValues = aAdjustmentValues.getLength();
5026 if ( nAdjustmentValues )
5028 sal_Int32 i, nValue = 0;
5029 for ( i = 0; i < nAdjustmentValues; i++ )
5031 if ( i )
5032 aStrBuffer.append( ' ' );
5034 const css::drawing::EnhancedCustomShapeAdjustmentValue& rAdj = aAdjustmentValues[ i ];
5035 if ( rAdj.State == beans::PropertyState_DIRECT_VALUE )
5037 if ( rAdj.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
5039 double fValue = 0.0;
5040 rAdj.Value >>= fValue;
5041 ::sax::Converter::convertDouble(aStrBuffer, fValue);
5043 else
5045 rAdj.Value >>= nValue;
5046 aStrBuffer.append(nValue);
5049 else
5051 // this should not be, but better than setting nothing
5052 aStrBuffer.append("0");
5055 aStr = aStrBuffer.makeStringAndClear();
5056 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MODIFIERS, aStr );
5058 if ( bCoordinates )
5059 ImpExportEnhancedPath( rExport, aCoordinates, aSegments );
5062 SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_ENHANCED_GEOMETRY, true, true );
5063 if ( bEquations )
5064 ImpExportEquations( rExport, aEquations );
5065 if ( bHandles )
5066 ImpExportHandles( rExport, aHandles );
5069 void XMLShapeExport::ImpExportCustomShape(
5070 const uno::Reference< drawing::XShape >& xShape,
5071 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint )
5073 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
5074 if ( !xPropSet.is() )
5075 return;
5077 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
5079 // Transformation
5080 ImpExportNewTrans( xPropSet, nFeatures, pRefPoint );
5082 if ( xPropSetInfo.is() )
5084 OUString aStr;
5085 if ( xPropSetInfo->hasPropertyByName( "CustomShapeEngine" ) )
5087 uno::Any aEngine( xPropSet->getPropertyValue( "CustomShapeEngine" ) );
5088 if ( ( aEngine >>= aStr ) && !aStr.isEmpty() )
5089 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ENGINE, aStr );
5091 if ( xPropSetInfo->hasPropertyByName( "CustomShapeData" ) )
5093 uno::Any aData( xPropSet->getPropertyValue( "CustomShapeData" ) );
5094 if ( ( aData >>= aStr ) && !aStr.isEmpty() )
5095 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DATA, aStr );
5098 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
5099 SvXMLElementExport aOBJ( mrExport, XML_NAMESPACE_DRAW, XML_CUSTOM_SHAPE, bCreateNewline, true );
5100 ImpExportDescription( xShape ); // #i68101#
5101 ImpExportEvents( xShape );
5102 ImpExportGluePoints( xShape );
5103 ImpExportText( xShape );
5104 ImpExportEnhancedGeometry( mrExport, xPropSet );
5108 void XMLShapeExport::ImpExportTableShape( const uno::Reference< drawing::XShape >& xShape, XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint )
5110 uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
5111 uno::Reference< container::XNamed > xNamed(xShape, uno::UNO_QUERY);
5113 SAL_WARN_IF( !xPropSet.is() || !xNamed.is(), "xmloff", "xmloff::XMLShapeExport::ImpExportTableShape(), table shape is not implementing needed interfaces");
5114 if(!(xPropSet.is() && xNamed.is()))
5115 return;
5119 // Transformation
5120 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
5122 bool bIsEmptyPresObj = false;
5124 // presentation settings
5125 if(eShapeType == XmlShapeType::PresTableShape)
5126 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_TABLE) );
5128 const bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE );
5130 SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW, XML_FRAME, bCreateNewline, true );
5132 // do not export in ODF 1.1 or older
5133 if (mrExport.getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012)
5135 if( !bIsEmptyPresObj )
5137 uno::Reference< container::XNamed > xTemplate( xPropSet->getPropertyValue("TableTemplate"), uno::UNO_QUERY );
5138 if( xTemplate.is() )
5140 const OUString sTemplate( xTemplate->getName() );
5141 if( !sTemplate.isEmpty() )
5143 mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_TEMPLATE_NAME, sTemplate );
5145 for( const XMLPropertyMapEntry* pEntry = &aXMLTableShapeAttributes[0]; !pEntry->IsEnd(); pEntry++ )
5149 bool bBool = false;
5150 xPropSet->getPropertyValue( pEntry->getApiName() ) >>= bBool;
5151 if( bBool )
5152 mrExport.AddAttribute(pEntry->mnNameSpace, pEntry->meXMLName, XML_TRUE );
5154 catch( uno::Exception& )
5156 DBG_UNHANDLED_EXCEPTION("xmloff.draw");
5162 uno::Reference< table::XColumnRowRange > xRange( xPropSet->getPropertyValue( gsModel ), uno::UNO_QUERY_THROW );
5163 GetShapeTableExport()->exportTable( xRange );
5167 if( !bIsEmptyPresObj )
5169 uno::Reference< graphic::XGraphic > xGraphic( xPropSet->getPropertyValue("ReplacementGraphic"), uno::UNO_QUERY );
5170 ExportGraphicPreview(xGraphic, mrExport, u"TablePreview", u".svm", "image/x-vclgraphic");
5173 ImpExportEvents( xShape );
5174 ImpExportGluePoints( xShape );
5175 ImpExportDescription( xShape ); // #i68101#
5177 catch( uno::Exception const & )
5179 DBG_UNHANDLED_EXCEPTION("xmloff.draw");
5183 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */