Bump version to 24.04.3.4
[LibreOffice.git] / xmloff / source / draw / shapeexport.cxx
blobcbb02782971317b9b21354876dfc90464d88df9b
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 OUString gsZIndex( u"ZOrder"_ustr );
158 constexpr OUStringLiteral gsPrintable( u"Printable" );
159 constexpr OUStringLiteral gsVisible( u"Visible" );
160 constexpr OUString gsModel( u"Model"_ustr );
161 constexpr OUStringLiteral gsStartShape( u"StartShape" );
162 constexpr OUStringLiteral gsEndShape( u"EndShape" );
163 constexpr OUString gsOnClick( u"OnClick"_ustr );
164 constexpr OUStringLiteral gsEventType( u"EventType" );
165 constexpr OUStringLiteral gsPresentation( u"Presentation" );
166 constexpr OUStringLiteral gsMacroName( u"MacroName" );
167 constexpr OUString gsScript( u"Script"_ustr );
168 constexpr OUStringLiteral gsLibrary( u"Library" );
169 constexpr OUStringLiteral gsClickAction( u"ClickAction" );
170 constexpr OUString gsBookmark( u"Bookmark"_ustr );
171 constexpr OUStringLiteral gsEffect( u"Effect" );
172 constexpr OUStringLiteral gsPlayFull( u"PlayFull" );
173 constexpr OUStringLiteral gsVerb( u"Verb" );
174 constexpr OUStringLiteral gsSoundURL( u"SoundURL" );
175 constexpr OUStringLiteral gsSpeed( u"Speed" );
176 constexpr OUStringLiteral gsStarBasic( u"StarBasic" );
177 constexpr OUStringLiteral gsHyperlink( u"Hyperlink" );
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 std::erase_if(layers, [](Layer const& rLayer) { return rLayer.shapes.empty(); });
1050 bool isSorted(true);
1051 for (size_t i = 1; i < layers.size(); ++i)
1053 assert(layers[i].nMin != layers[i-1].nMax); // unique!
1054 if (layers[i].nMin < layers[i-1].nMax)
1056 isSorted = false;
1057 break;
1060 if (isSorted)
1062 return; // nothing to do
1064 uno::Sequence<sal_Int32> aNewOrder(nCount);
1065 auto iterInsert(aNewOrder.getArray());
1066 for (auto const& rLayer : layers)
1068 assert(rLayer.nMin <= rLayer.nMax); // empty layers have been removed
1069 iterInsert = std::copy(rLayer.shapes.begin(), rLayer.shapes.end(), iterInsert);
1073 xShapes3->sort(aNewOrder);
1075 catch (uno::Exception const&)
1077 SAL_WARN("xmloff", "FixZOrder: exception");
1081 } // namespace xmloff
1083 void XMLShapeExport::seekShapes( const uno::Reference< drawing::XShapes >& xShapes ) noexcept
1085 if( xShapes.is() )
1087 maCurrentShapesIter = maShapesInfos.find( xShapes );
1088 if( maCurrentShapesIter == maShapesInfos.end() )
1090 auto itPair = maShapesInfos.emplace( xShapes, ImplXMLShapeExportInfoVector( static_cast<ShapesInfos::size_type>(xShapes->getCount()) ) );
1092 maCurrentShapesIter = itPair.first;
1094 SAL_WARN_IF( maCurrentShapesIter == maShapesInfos.end(), "xmloff", "XMLShapeExport::seekShapes(): insert into stl::map failed" );
1097 SAL_WARN_IF( (*maCurrentShapesIter).second.size() != static_cast<ShapesInfos::size_type>(xShapes->getCount()), "xmloff", "XMLShapeExport::seekShapes(): XShapes size varied between calls" );
1100 else
1102 maCurrentShapesIter = maShapesInfos.end();
1106 void XMLShapeExport::exportAutoStyles()
1108 // export all autostyle infos
1110 // ...for graphic
1112 GetExport().GetAutoStylePool()->exportXML( XmlStyleFamily::SD_GRAPHICS_ID );
1115 // ...for presentation
1117 GetExport().GetAutoStylePool()->exportXML( XmlStyleFamily::SD_PRESENTATION_ID );
1120 if( mxShapeTableExport.is() )
1121 mxShapeTableExport->exportAutoStyles();
1124 /// returns the export property mapper for external chaining
1125 SvXMLExportPropertyMapper* XMLShapeExport::CreateShapePropMapper(
1126 SvXMLExport& rExport )
1128 rtl::Reference< XMLPropertyHandlerFactory > xFactory = new XMLSdPropHdlFactory( rExport.GetModel(), rExport );
1129 rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( xFactory, true );
1130 rExport.GetTextParagraphExport(); // get or create text paragraph export
1131 SvXMLExportPropertyMapper* pResult =
1132 new XMLShapeExportPropertyMapper( xMapper, rExport );
1133 // chain text attributes
1134 return pResult;
1137 void XMLShapeExport::ImpCalcShapeType(const uno::Reference< drawing::XShape >& xShape,
1138 XmlShapeType& eShapeType)
1140 // set in every case, so init here
1141 eShapeType = XmlShapeType::Unknown;
1143 if(!xShape.is())
1144 return;
1146 OUString aType(xShape->getShapeType());
1148 if(!aType.match("com.sun.star."))
1149 return;
1151 if(aType.match("drawing.", 13))
1153 // drawing shapes
1154 if (aType.match("Rectangle", 21)) { eShapeType = XmlShapeType::DrawRectangleShape; }
1156 // #i72177# Note: Correcting CustomShape, CustomShape->Custom, len from 9 (was wrong anyways) to 6.
1157 // As can be seen at the other compares, the appendix "Shape" is left out of the comparison.
1158 else if(aType.match("Custom", 21)) { eShapeType = XmlShapeType::DrawCustomShape; }
1160 else if(aType.match("Ellipse", 21)) { eShapeType = XmlShapeType::DrawEllipseShape; }
1161 else if(aType.match("Control", 21)) { eShapeType = XmlShapeType::DrawControlShape; }
1162 else if(aType.match("Connector", 21)) { eShapeType = XmlShapeType::DrawConnectorShape; }
1163 else if(aType.match("Measure", 21)) { eShapeType = XmlShapeType::DrawMeasureShape; }
1164 else if(aType.match("Line", 21)) { eShapeType = XmlShapeType::DrawLineShape; }
1166 // #i72177# Note: This covers two types by purpose, PolyPolygonShape and PolyPolygonPathShape
1167 else if(aType.match("PolyPolygon", 21)) { eShapeType = XmlShapeType::DrawPolyPolygonShape; }
1169 // #i72177# Note: This covers two types by purpose, PolyLineShape and PolyLinePathShape
1170 else if(aType.match("PolyLine", 21)) { eShapeType = XmlShapeType::DrawPolyLineShape; }
1172 else if(aType.match("OpenBezier", 21)) { eShapeType = XmlShapeType::DrawOpenBezierShape; }
1173 else if(aType.match("ClosedBezier", 21)) { eShapeType = XmlShapeType::DrawClosedBezierShape; }
1175 // #i72177# FreeHand (opened and closed) now supports the types OpenFreeHandShape and
1176 // ClosedFreeHandShape respectively. Represent them as bezier shapes
1177 else if(aType.match("OpenFreeHand", 21)) { eShapeType = XmlShapeType::DrawOpenBezierShape; }
1178 else if(aType.match("ClosedFreeHand", 21)) { eShapeType = XmlShapeType::DrawClosedBezierShape; }
1180 else if(aType.match("GraphicObject", 21)) { eShapeType = XmlShapeType::DrawGraphicObjectShape; }
1181 else if(aType.match("Group", 21)) { eShapeType = XmlShapeType::DrawGroupShape; }
1182 else if(aType.match("Text", 21)) { eShapeType = XmlShapeType::DrawTextShape; }
1183 else if(aType.match("OLE2", 21))
1185 eShapeType = XmlShapeType::DrawOLE2Shape;
1187 // get info about presentation shape
1188 uno::Reference <beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1190 if(xPropSet.is())
1192 OUString sCLSID;
1193 if(xPropSet->getPropertyValue("CLSID") >>= sCLSID)
1195 #if !ENABLE_WASM_STRIP_CHART
1196 // WASM_CHART change
1197 // TODO: With Chart extracted this cannot really happen since
1198 // no Chart could've been added at all
1199 if (sCLSID == mrExport.GetChartExport()->getChartCLSID() ||
1200 #else
1202 #endif
1203 sCLSID == SvGlobalName( SO3_RPTCH_CLASSID ).GetHexName() )
1205 eShapeType = XmlShapeType::DrawChartShape;
1207 else if (sCLSID == SvGlobalName( SO3_SC_CLASSID ).GetHexName() )
1209 eShapeType = XmlShapeType::DrawSheetShape;
1211 else
1213 // general OLE2 Object
1218 else if(aType.match("Page", 21)) { eShapeType = XmlShapeType::DrawPageShape; }
1219 else if(aType.match("Frame", 21)) { eShapeType = XmlShapeType::DrawFrameShape; }
1220 else if(aType.match("Caption", 21)) { eShapeType = XmlShapeType::DrawCaptionShape; }
1221 else if(aType.match("Plugin", 21)) { eShapeType = XmlShapeType::DrawPluginShape; }
1222 else if(aType.match("Applet", 21)) { eShapeType = XmlShapeType::DrawAppletShape; }
1223 else if(aType.match("MediaShape", 21)) { eShapeType = XmlShapeType::DrawMediaShape; }
1224 else if(aType.match("TableShape", 21)) { eShapeType = XmlShapeType::DrawTableShape; }
1226 // 3D shapes
1227 else if(aType.match("Scene", 21 + 7)) { eShapeType = XmlShapeType::Draw3DSceneObject; }
1228 else if(aType.match("Cube", 21 + 7)) { eShapeType = XmlShapeType::Draw3DCubeObject; }
1229 else if(aType.match("Sphere", 21 + 7)) { eShapeType = XmlShapeType::Draw3DSphereObject; }
1230 else if(aType.match("Lathe", 21 + 7)) { eShapeType = XmlShapeType::Draw3DLatheObject; }
1231 else if(aType.match("Extrude", 21 + 7)) { eShapeType = XmlShapeType::Draw3DExtrudeObject; }
1233 else if(aType.match("presentation.", 13))
1235 // presentation shapes
1236 if (aType.match("TitleText", 26)) { eShapeType = XmlShapeType::PresTitleTextShape; }
1237 else if(aType.match("Outliner", 26)) { eShapeType = XmlShapeType::PresOutlinerShape; }
1238 else if(aType.match("Subtitle", 26)) { eShapeType = XmlShapeType::PresSubtitleShape; }
1239 else if(aType.match("GraphicObject", 26)) { eShapeType = XmlShapeType::PresGraphicObjectShape; }
1240 else if(aType.match("Page", 26)) { eShapeType = XmlShapeType::PresPageShape; }
1241 else if(aType.match("OLE2", 26))
1243 eShapeType = XmlShapeType::PresOLE2Shape;
1245 // get info about presentation shape
1246 uno::Reference <beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1248 if(xPropSet.is()) try
1250 OUString sCLSID;
1251 if(xPropSet->getPropertyValue("CLSID") >>= sCLSID)
1253 if( sCLSID == SvGlobalName( SO3_SC_CLASSID ).GetHexName() )
1255 eShapeType = XmlShapeType::PresSheetShape;
1259 catch(const uno::Exception&)
1261 SAL_WARN( "xmloff", "XMLShapeExport::ImpCalcShapeType(), expected ole shape to have the CLSID property?" );
1264 else if(aType.match("Chart", 26)) { eShapeType = XmlShapeType::PresChartShape; }
1265 else if(aType.match("OrgChart", 26)) { eShapeType = XmlShapeType::PresOrgChartShape; }
1266 else if(aType.match("CalcShape", 26)) { eShapeType = XmlShapeType::PresSheetShape; }
1267 else if(aType.match("TableShape", 26)) { eShapeType = XmlShapeType::PresTableShape; }
1268 else if(aType.match("Notes", 26)) { eShapeType = XmlShapeType::PresNotesShape; }
1269 else if(aType.match("HandoutShape", 26)) { eShapeType = XmlShapeType::HandoutShape; }
1270 else if(aType.match("HeaderShape", 26)) { eShapeType = XmlShapeType::PresHeaderShape; }
1271 else if(aType.match("FooterShape", 26)) { eShapeType = XmlShapeType::PresFooterShape; }
1272 else if(aType.match("SlideNumberShape", 26)) { eShapeType = XmlShapeType::PresSlideNumberShape; }
1273 else if(aType.match("DateTimeShape", 26)) { eShapeType = XmlShapeType::PresDateTimeShape; }
1274 else if(aType.match("MediaShape", 26)) { eShapeType = XmlShapeType::PresMediaShape; }
1278 /** exports all user defined gluepoints */
1279 void XMLShapeExport::ImpExportGluePoints( const uno::Reference< drawing::XShape >& xShape )
1281 uno::Reference< drawing::XGluePointsSupplier > xSupplier( xShape, uno::UNO_QUERY );
1282 if( !xSupplier.is() )
1283 return;
1285 uno::Reference< container::XIdentifierAccess > xGluePoints( xSupplier->getGluePoints(), uno::UNO_QUERY );
1286 if( !xGluePoints.is() )
1287 return;
1289 drawing::GluePoint2 aGluePoint;
1291 const uno::Sequence< sal_Int32 > aIdSequence( xGluePoints->getIdentifiers() );
1293 for( const sal_Int32 nIdentifier : aIdSequence )
1295 if( (xGluePoints->getByIdentifier( nIdentifier ) >>= aGluePoint) && aGluePoint.IsUserDefined )
1297 // export only user defined gluepoints
1299 const OUString sId( OUString::number( nIdentifier ) );
1300 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_ID, sId );
1302 mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
1303 aGluePoint.Position.X);
1304 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, msBuffer.makeStringAndClear());
1306 mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
1307 aGluePoint.Position.Y);
1308 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, msBuffer.makeStringAndClear());
1310 if( !aGluePoint.IsRelative )
1312 SvXMLUnitConverter::convertEnum( msBuffer, aGluePoint.PositionAlignment, aXML_GlueAlignment_EnumMap );
1313 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ALIGN, msBuffer.makeStringAndClear() );
1316 if( aGluePoint.Escape != drawing::EscapeDirection_SMART )
1318 SvXMLUnitConverter::convertEnum( msBuffer, aGluePoint.Escape, aXML_GlueEscapeDirection_EnumMap );
1319 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ESCAPE_DIRECTION, msBuffer.makeStringAndClear() );
1322 SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_DRAW, XML_GLUE_POINT, true, true);
1327 void XMLShapeExport::ImpExportSignatureLine(const uno::Reference<drawing::XShape>& xShape)
1329 uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1331 bool bIsSignatureLine = false;
1332 xPropSet->getPropertyValue("IsSignatureLine") >>= bIsSignatureLine;
1333 if (!bIsSignatureLine)
1334 return;
1336 OUString aSignatureLineId;
1337 xPropSet->getPropertyValue("SignatureLineId") >>= aSignatureLineId;
1338 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_ID, aSignatureLineId);
1340 OUString aSuggestedSignerName;
1341 xPropSet->getPropertyValue("SignatureLineSuggestedSignerName") >>= aSuggestedSignerName;
1342 if (!aSuggestedSignerName.isEmpty())
1343 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_NAME, aSuggestedSignerName);
1345 OUString aSuggestedSignerTitle;
1346 xPropSet->getPropertyValue("SignatureLineSuggestedSignerTitle") >>= aSuggestedSignerTitle;
1347 if (!aSuggestedSignerTitle.isEmpty())
1348 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_TITLE, aSuggestedSignerTitle);
1350 OUString aSuggestedSignerEmail;
1351 xPropSet->getPropertyValue("SignatureLineSuggestedSignerEmail") >>= aSuggestedSignerEmail;
1352 if (!aSuggestedSignerEmail.isEmpty())
1353 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_EMAIL, aSuggestedSignerEmail);
1355 OUString aSigningInstructions;
1356 xPropSet->getPropertyValue("SignatureLineSigningInstructions") >>= aSigningInstructions;
1357 if (!aSigningInstructions.isEmpty())
1358 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SIGNING_INSTRUCTIONS, aSigningInstructions);
1360 bool bShowSignDate = false;
1361 xPropSet->getPropertyValue("SignatureLineShowSignDate") >>= bShowSignDate;
1362 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SHOW_SIGN_DATE,
1363 bShowSignDate ? XML_TRUE : XML_FALSE);
1365 bool bCanAddComment = false;
1366 xPropSet->getPropertyValue("SignatureLineCanAddComment") >>= bCanAddComment;
1367 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_CAN_ADD_COMMENT,
1368 bCanAddComment ? XML_TRUE : XML_FALSE);
1370 SvXMLElementExport aSignatureLineElement(mrExport, XML_NAMESPACE_LO_EXT, XML_SIGNATURELINE, true,
1371 true);
1374 void XMLShapeExport::ImpExportQRCode(const uno::Reference<drawing::XShape>& xShape)
1376 uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1378 uno::Any aAny = xPropSet->getPropertyValue("BarCodeProperties");
1380 css::drawing::BarCode aBarCode;
1381 if(!(aAny >>= aBarCode))
1382 return;
1384 mrExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_STRING_VALUE, aBarCode.Payload);
1385 /* Export QR Code as per customised schema, @see OpenDocument-schema-v1.3+libreoffice */
1386 OUString temp;
1387 switch(aBarCode.ErrorCorrection){
1388 case css::drawing::BarCodeErrorCorrection::LOW :
1389 temp = "low";
1390 break;
1391 case css::drawing::BarCodeErrorCorrection::MEDIUM:
1392 temp = "medium";
1393 break;
1394 case css::drawing::BarCodeErrorCorrection::QUARTILE:
1395 temp = "quartile";
1396 break;
1397 case css::drawing::BarCodeErrorCorrection::HIGH:
1398 temp = "high";
1399 break;
1401 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_ERROR_CORRECTION, temp);
1402 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_BORDER, OUStringBuffer(20).append(aBarCode.Border).makeStringAndClear());
1403 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_TYPE, OUStringBuffer(20).append(aBarCode.Type).makeStringAndClear());
1405 SvXMLElementExport aBarCodeElement(mrExport, XML_NAMESPACE_LO_EXT, XML_QRCODE, true,
1406 true);
1409 void XMLShapeExport::ExportGraphicDefaults()
1411 rtl::Reference<XMLStyleExport> aStEx(new XMLStyleExport(mrExport, mrExport.GetAutoStylePool().get()));
1413 // construct PropertySetMapper
1414 rtl::Reference< SvXMLExportPropertyMapper > xPropertySetMapper( CreateShapePropMapper( mrExport ) );
1415 static_cast<XMLShapeExportPropertyMapper*>(xPropertySetMapper.get())->SetAutoStyles( false );
1417 // chain text attributes
1418 xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(mrExport));
1420 // chain special Writer/text frame default attributes
1421 xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaDefaultExtPropMapper(mrExport));
1423 // write graphic family default style
1424 uno::Reference< lang::XMultiServiceFactory > xFact( mrExport.GetModel(), uno::UNO_QUERY );
1425 if( !xFact.is() )
1426 return;
1430 uno::Reference< beans::XPropertySet > xDefaults( xFact->createInstance("com.sun.star.drawing.Defaults"), uno::UNO_QUERY );
1431 if( xDefaults.is() )
1433 aStEx->exportDefaultStyle( xDefaults, XML_STYLE_FAMILY_SD_GRAPHICS_NAME, xPropertySetMapper );
1435 // write graphic styles (family name differs depending on the module)
1436 aStEx->exportStyleFamily("graphics", XML_STYLE_FAMILY_SD_GRAPHICS_NAME, xPropertySetMapper, false, XmlStyleFamily::SD_GRAPHICS_ID);
1437 aStEx->exportStyleFamily("GraphicStyles", XML_STYLE_FAMILY_SD_GRAPHICS_NAME, xPropertySetMapper, false, XmlStyleFamily::SD_GRAPHICS_ID);
1440 catch(const lang::ServiceNotRegisteredException&)
1445 void XMLShapeExport::onExport( const css::uno::Reference < css::drawing::XShape >& )
1449 const rtl::Reference< XMLTableExport >& XMLShapeExport::GetShapeTableExport()
1451 if( !mxShapeTableExport.is() )
1453 rtl::Reference< XMLPropertyHandlerFactory > xFactory( new XMLSdPropHdlFactory( mrExport.GetModel(), mrExport ) );
1454 rtl::Reference < XMLPropertySetMapper > xMapper( new XMLShapePropertySetMapper( xFactory, true ) );
1455 mrExport.GetTextParagraphExport(); // get or create text paragraph export
1456 rtl::Reference< SvXMLExportPropertyMapper > xPropertySetMapper( new XMLShapeExportPropertyMapper( xMapper, mrExport ) );
1457 mxShapeTableExport = new XMLTableExport( mrExport, xPropertySetMapper, xFactory );
1460 return mxShapeTableExport;
1463 void XMLShapeExport::ImpExportNewTrans(const uno::Reference< beans::XPropertySet >& xPropSet,
1464 XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
1466 // get matrix
1467 ::basegfx::B2DHomMatrix aMatrix;
1468 ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
1470 // decompose and correct about pRefPoint
1471 ::basegfx::B2DTuple aTRScale;
1472 double fTRShear(0.0);
1473 double fTRRotate(0.0);
1474 ::basegfx::B2DTuple aTRTranslate;
1475 ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
1477 // use features and write
1478 ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures);
1481 void XMLShapeExport::ImpExportNewTrans_GetB2DHomMatrix(::basegfx::B2DHomMatrix& rMatrix,
1482 const uno::Reference< beans::XPropertySet >& xPropSet)
1484 /* Get <TransformationInHoriL2R>, if it exist
1485 and if the document is exported into the OpenOffice.org file format.
1486 This property only exists at service css::text::Shape - the
1487 Writer UNO service for shapes.
1488 This code is needed, because the positioning attributes in the
1489 OpenOffice.org file format are given in horizontal left-to-right layout
1490 regardless the layout direction the shape is in. In the OASIS Open Office
1491 file format the positioning attributes are correctly given in the layout
1492 direction the shape is in. Thus, this code provides the conversion from
1493 the OASIS Open Office file format to the OpenOffice.org file format. (#i28749#)
1495 uno::Any aAny;
1496 if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
1497 xPropSet->getPropertySetInfo()->hasPropertyByName("TransformationInHoriL2R") )
1499 aAny = xPropSet->getPropertyValue("TransformationInHoriL2R");
1501 else
1503 aAny = xPropSet->getPropertyValue("Transformation");
1505 drawing::HomogenMatrix3 aMatrix;
1506 aAny >>= aMatrix;
1508 rMatrix.set(0, 0, aMatrix.Line1.Column1);
1509 rMatrix.set(0, 1, aMatrix.Line1.Column2);
1510 rMatrix.set(0, 2, aMatrix.Line1.Column3);
1511 rMatrix.set(1, 0, aMatrix.Line2.Column1);
1512 rMatrix.set(1, 1, aMatrix.Line2.Column2);
1513 rMatrix.set(1, 2, aMatrix.Line2.Column3);
1514 // For this to be a valid 2D transform matrix, the last row must be [0,0,1]
1515 assert( aMatrix.Line3.Column1 == 0 );
1516 assert( aMatrix.Line3.Column2 == 0 );
1517 assert( aMatrix.Line3.Column3 == 1 );
1520 void XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint(const ::basegfx::B2DHomMatrix& rMatrix, ::basegfx::B2DTuple& rTRScale,
1521 double& fTRShear, double& fTRRotate, ::basegfx::B2DTuple& rTRTranslate, css::awt::Point* pRefPoint)
1523 // decompose matrix
1524 rMatrix.decompose(rTRScale, rTRTranslate, fTRRotate, fTRShear);
1526 // correct translation about pRefPoint
1527 if(pRefPoint)
1529 rTRTranslate -= ::basegfx::B2DTuple(pRefPoint->X, pRefPoint->Y);
1533 void XMLShapeExport::ImpExportNewTrans_FeaturesAndWrite(::basegfx::B2DTuple const & rTRScale, double fTRShear,
1534 double fTRRotate, ::basegfx::B2DTuple const & rTRTranslate, const XMLShapeExportFlags nFeatures)
1536 // always write Size (rTRScale) since this statement carries the union
1537 // of the object
1538 OUString aStr;
1539 OUStringBuffer sStringBuffer;
1540 ::basegfx::B2DTuple aTRScale(rTRScale);
1542 // svg: width
1543 if(!(nFeatures & XMLShapeExportFlags::WIDTH))
1545 aTRScale.setX(1.0);
1547 else
1549 if( aTRScale.getX() > 0.0 )
1550 aTRScale.setX(aTRScale.getX() - 1.0);
1551 else if( aTRScale.getX() < 0.0 )
1552 aTRScale.setX(aTRScale.getX() + 1.0);
1555 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1556 FRound(aTRScale.getX()));
1557 aStr = sStringBuffer.makeStringAndClear();
1558 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, aStr);
1560 // svg: height
1561 if(!(nFeatures & XMLShapeExportFlags::HEIGHT))
1563 aTRScale.setY(1.0);
1565 else
1567 if( aTRScale.getY() > 0.0 )
1568 aTRScale.setY(aTRScale.getY() - 1.0);
1569 else if( aTRScale.getY() < 0.0 )
1570 aTRScale.setY(aTRScale.getY() + 1.0);
1573 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1574 FRound(aTRScale.getY()));
1575 aStr = sStringBuffer.makeStringAndClear();
1576 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, aStr);
1578 // decide if transformation is necessary
1579 bool bTransformationIsNecessary(fTRShear != 0.0 || fTRRotate != 0.0);
1581 if(bTransformationIsNecessary)
1583 // write transformation, but WITHOUT scale which is exported as size above
1584 SdXMLImExTransform2D aTransform;
1586 aTransform.AddSkewX(atan(fTRShear));
1588 // #i78696#
1589 // fTRRotate is mathematically correct, but due to the error
1590 // we export/import it mirrored. Since the API implementation is fixed and
1591 // uses the correctly oriented angle, it is necessary for compatibility to
1592 // mirror the angle here to stay at the old behaviour. There is a follow-up
1593 // task (#i78698#) to fix this in the next ODF FileFormat version
1594 aTransform.AddRotate(-fTRRotate);
1596 aTransform.AddTranslate(rTRTranslate);
1598 // does transformation need to be exported?
1599 if(aTransform.NeedsAction())
1600 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
1602 else
1604 // no shear, no rotate; just add object position to export and we are done
1605 if(nFeatures & XMLShapeExportFlags::X)
1607 // svg: x
1608 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1609 FRound(rTRTranslate.getX()));
1610 aStr = sStringBuffer.makeStringAndClear();
1611 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, aStr);
1614 if(nFeatures & XMLShapeExportFlags::Y)
1616 // svg: y
1617 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1618 FRound(rTRTranslate.getY()));
1619 aStr = sStringBuffer.makeStringAndClear();
1620 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, aStr);
1625 bool XMLShapeExport::ImpExportPresentationAttributes( const uno::Reference< beans::XPropertySet >& xPropSet, const OUString& rClass )
1627 bool bIsEmpty = false;
1629 // write presentation class entry
1630 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS, rClass);
1632 if( xPropSet.is() )
1634 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
1637 // is empty pres. shape?
1638 if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsEmptyPresentationObject"))
1640 xPropSet->getPropertyValue("IsEmptyPresentationObject") >>= bIsEmpty;
1641 if( bIsEmpty )
1642 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PLACEHOLDER, XML_TRUE);
1645 // is user-transformed?
1646 if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsPlaceholderDependent"))
1648 bool bTemp = false;
1649 xPropSet->getPropertyValue("IsPlaceholderDependent") >>= bTemp;
1650 if(!bTemp)
1651 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_USER_TRANSFORMED, XML_TRUE);
1655 return bIsEmpty;
1658 void XMLShapeExport::ImpExportText( const uno::Reference< drawing::XShape >& xShape, TextPNS eExtensionNS )
1660 if (eExtensionNS == TextPNS::EXTENSION)
1662 if ((mrExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
1664 return; // do not export to ODF 1.1/1.2/1.3
1667 uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY );
1668 if( xText.is() )
1670 uno::Reference< container::XEnumerationAccess > xEnumAccess( xShape, uno::UNO_QUERY );
1671 if( xEnumAccess.is() && xEnumAccess->hasElements() )
1672 mrExport.GetTextParagraphExport()->exportText( xText, false, true, eExtensionNS );
1676 namespace {
1678 enum class Found {
1679 NONE = 0x0000,
1680 CLICKACTION = 0x0001,
1681 BOOKMARK = 0x0002,
1682 EFFECT = 0x0004,
1683 PLAYFULL = 0x0008,
1684 VERB = 0x0010,
1685 SOUNDURL = 0x0020,
1686 SPEED = 0x0040,
1687 CLICKEVENTTYPE = 0x0080,
1688 MACRO = 0x0100,
1689 LIBRARY = 0x0200,
1694 namespace o3tl {
1695 template<> struct typed_flags<Found> : is_typed_flags<Found, 0x03ff> {};
1698 void XMLShapeExport::ImpExportEvents( const uno::Reference< drawing::XShape >& xShape )
1700 uno::Reference< document::XEventsSupplier > xEventsSupplier( xShape, uno::UNO_QUERY );
1701 if( !xEventsSupplier.is() )
1702 return;
1704 uno::Reference< container::XNameAccess > xEvents = xEventsSupplier->getEvents();
1705 SAL_WARN_IF( !xEvents.is(), "xmloff", "XEventsSupplier::getEvents() returned NULL" );
1706 if( !xEvents.is() )
1707 return;
1709 Found nFound = Found::NONE;
1711 OUString aClickEventType;
1712 presentation::ClickAction eClickAction = presentation::ClickAction_NONE;
1713 presentation::AnimationEffect eEffect = presentation::AnimationEffect_NONE;
1714 presentation::AnimationSpeed eSpeed = presentation::AnimationSpeed_SLOW;
1715 OUString aStrSoundURL;
1716 bool bPlayFull = false;
1717 sal_Int32 nVerb = 0;
1718 OUString aStrMacro;
1719 OUString aStrLibrary;
1720 OUString aStrBookmark;
1722 uno::Sequence< beans::PropertyValue > aClickProperties;
1723 if( xEvents->hasByName( gsOnClick ) && (xEvents->getByName( gsOnClick ) >>= aClickProperties) )
1725 for( const auto& rProperty : std::as_const(aClickProperties) )
1727 if( !( nFound & Found::CLICKEVENTTYPE ) && rProperty.Name == gsEventType )
1729 if( rProperty.Value >>= aClickEventType )
1730 nFound |= Found::CLICKEVENTTYPE;
1732 else if( !( nFound & Found::CLICKACTION ) && rProperty.Name == gsClickAction )
1734 if( rProperty.Value >>= eClickAction )
1735 nFound |= Found::CLICKACTION;
1737 else if( !( nFound & Found::MACRO ) && ( rProperty.Name == gsMacroName || rProperty.Name == gsScript ) )
1739 if( rProperty.Value >>= aStrMacro )
1740 nFound |= Found::MACRO;
1742 else if( !( nFound & Found::LIBRARY ) && rProperty.Name == gsLibrary )
1744 if( rProperty.Value >>= aStrLibrary )
1745 nFound |= Found::LIBRARY;
1747 else if( !( nFound & Found::EFFECT ) && rProperty.Name == gsEffect )
1749 if( rProperty.Value >>= eEffect )
1750 nFound |= Found::EFFECT;
1752 else if( !( nFound & Found::BOOKMARK ) && rProperty.Name == gsBookmark )
1754 if( rProperty.Value >>= aStrBookmark )
1755 nFound |= Found::BOOKMARK;
1757 else if( !( nFound & Found::SPEED ) && rProperty.Name == gsSpeed )
1759 if( rProperty.Value >>= eSpeed )
1760 nFound |= Found::SPEED;
1762 else if( !( nFound & Found::SOUNDURL ) && rProperty.Name == gsSoundURL )
1764 if( rProperty.Value >>= aStrSoundURL )
1765 nFound |= Found::SOUNDURL;
1767 else if( !( nFound & Found::PLAYFULL ) && rProperty.Name == gsPlayFull )
1769 if( rProperty.Value >>= bPlayFull )
1770 nFound |= Found::PLAYFULL;
1772 else if( !( nFound & Found::VERB ) && rProperty.Name == gsVerb )
1774 if( rProperty.Value >>= nVerb )
1775 nFound |= Found::VERB;
1780 // create the XML elements
1782 if( aClickEventType == gsPresentation )
1784 if( !(nFound & Found::CLICKACTION) || (eClickAction == presentation::ClickAction_NONE) )
1785 return;
1787 SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
1789 enum XMLTokenEnum eStrAction;
1791 switch( eClickAction )
1793 case presentation::ClickAction_PREVPAGE: eStrAction = XML_PREVIOUS_PAGE; break;
1794 case presentation::ClickAction_NEXTPAGE: eStrAction = XML_NEXT_PAGE; break;
1795 case presentation::ClickAction_FIRSTPAGE: eStrAction = XML_FIRST_PAGE; break;
1796 case presentation::ClickAction_LASTPAGE: eStrAction = XML_LAST_PAGE; break;
1797 case presentation::ClickAction_INVISIBLE: eStrAction = XML_HIDE; break;
1798 case presentation::ClickAction_STOPPRESENTATION:eStrAction = XML_STOP; break;
1799 case presentation::ClickAction_PROGRAM: eStrAction = XML_EXECUTE; break;
1800 case presentation::ClickAction_BOOKMARK: eStrAction = XML_SHOW; break;
1801 case presentation::ClickAction_DOCUMENT: eStrAction = XML_SHOW; break;
1802 case presentation::ClickAction_MACRO: eStrAction = XML_EXECUTE_MACRO; break;
1803 case presentation::ClickAction_VERB: eStrAction = XML_VERB; break;
1804 case presentation::ClickAction_VANISH: eStrAction = XML_FADE_OUT; break;
1805 case presentation::ClickAction_SOUND: eStrAction = XML_SOUND; break;
1806 default:
1807 OSL_FAIL( "unknown presentation::ClickAction found!" );
1808 eStrAction = XML_UNKNOWN;
1811 OUString aEventQName(
1812 mrExport.GetNamespaceMap().GetQNameByKey(
1813 XML_NAMESPACE_DOM, "click" ) );
1814 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
1815 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_ACTION, eStrAction );
1817 if( eClickAction == presentation::ClickAction_VANISH )
1819 if( nFound & Found::EFFECT )
1821 XMLEffect eKind;
1822 XMLEffectDirection eDirection;
1823 sal_Int16 nStartScale;
1824 bool bIn;
1826 SdXMLImplSetEffect( eEffect, eKind, eDirection, nStartScale, bIn );
1828 if( eKind != EK_none )
1830 SvXMLUnitConverter::convertEnum( msBuffer, eKind, aXML_AnimationEffect_EnumMap );
1831 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_EFFECT, msBuffer.makeStringAndClear() );
1834 if( eDirection != ED_none )
1836 SvXMLUnitConverter::convertEnum( msBuffer, eDirection, aXML_AnimationDirection_EnumMap );
1837 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_DIRECTION, msBuffer.makeStringAndClear() );
1840 if( nStartScale != -1 )
1842 ::sax::Converter::convertPercent( msBuffer, nStartScale );
1843 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_START_SCALE, msBuffer.makeStringAndClear() );
1847 if( nFound & Found::SPEED && eEffect != presentation::AnimationEffect_NONE )
1849 if( eSpeed != presentation::AnimationSpeed_MEDIUM )
1851 SvXMLUnitConverter::convertEnum( msBuffer, eSpeed, aXML_AnimationSpeed_EnumMap );
1852 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_SPEED, msBuffer.makeStringAndClear() );
1857 if( eClickAction == presentation::ClickAction_PROGRAM ||
1858 eClickAction == presentation::ClickAction_BOOKMARK ||
1859 eClickAction == presentation::ClickAction_DOCUMENT )
1861 if( eClickAction == presentation::ClickAction_BOOKMARK )
1862 msBuffer.append( '#' );
1864 msBuffer.append( aStrBookmark );
1865 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(msBuffer.makeStringAndClear()) );
1866 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
1867 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
1868 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST );
1871 if( ( nFound & Found::VERB ) && eClickAction == presentation::ClickAction_VERB )
1873 msBuffer.append( nVerb );
1874 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_VERB, msBuffer.makeStringAndClear());
1877 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_PRESENTATION, XML_EVENT_LISTENER, true, true);
1879 if( eClickAction == presentation::ClickAction_VANISH || eClickAction == presentation::ClickAction_SOUND )
1881 if( ( nFound & Found::SOUNDURL ) && !aStrSoundURL.isEmpty() )
1883 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStrSoundURL) );
1884 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
1885 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_NEW );
1886 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST );
1887 if( nFound & Found::PLAYFULL && bPlayFull )
1888 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PLAY_FULL, XML_TRUE );
1890 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_PRESENTATION, XML_SOUND, true, true );
1894 else if( aClickEventType == gsStarBasic )
1896 if( nFound & Found::MACRO )
1898 SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
1900 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE,
1901 mrExport.GetNamespaceMap().GetQNameByKey(
1902 XML_NAMESPACE_OOO,
1903 "starbasic" ) );
1904 OUString aEventQName(
1905 mrExport.GetNamespaceMap().GetQNameByKey(
1906 XML_NAMESPACE_DOM, "click" ) );
1907 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
1909 if( nFound & Found::LIBRARY )
1911 const OUString& sLocation( GetXMLToken(
1912 (aStrLibrary.equalsIgnoreAsciiCase("StarOffice") ||
1913 aStrLibrary.equalsIgnoreAsciiCase("application") ) ? XML_APPLICATION
1914 : XML_DOCUMENT ) );
1915 mrExport.AddAttribute(XML_NAMESPACE_SCRIPT, XML_MACRO_NAME,
1916 sLocation + ":" + aStrMacro);
1918 else
1920 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_MACRO_NAME, aStrMacro );
1923 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, true, true);
1926 else if( aClickEventType == gsScript )
1928 if( nFound & Found::MACRO )
1930 SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
1932 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE, mrExport.GetNamespaceMap().GetQNameByKey(
1933 XML_NAMESPACE_OOO, GetXMLToken(XML_SCRIPT) ) );
1934 OUString aEventQName(
1935 mrExport.GetNamespaceMap().GetQNameByKey(
1936 XML_NAMESPACE_DOM, "click" ) );
1937 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
1938 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aStrMacro );
1939 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, "simple" );
1941 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, true, true);
1946 /** #i68101# export shape Title and Description */
1947 void XMLShapeExport::ImpExportDescription( const uno::Reference< drawing::XShape >& xShape )
1951 OUString aTitle;
1952 OUString aDescription;
1954 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY_THROW );
1955 xProps->getPropertyValue("Title") >>= aTitle;
1956 xProps->getPropertyValue("Description") >>= aDescription;
1958 if(!aTitle.isEmpty())
1960 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_TITLE, true, false);
1961 mrExport.Characters( aTitle );
1964 if(!aDescription.isEmpty())
1966 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_DESC, true, false );
1967 mrExport.Characters( aDescription );
1970 catch( uno::Exception& )
1972 DBG_UNHANDLED_EXCEPTION( "xmloff", "exporting Title and/or Description for shape" );
1976 void XMLShapeExport::ImpExportGroupShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
1978 uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY);
1979 if(!(xShapes.is() && xShapes->getCount()))
1980 return;
1982 // write group shape
1983 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
1984 SvXMLElementExport aPGR(mrExport, XML_NAMESPACE_DRAW, XML_G, bCreateNewline, true);
1986 ImpExportDescription( xShape ); // #i68101#
1987 ImpExportEvents( xShape );
1988 ImpExportGluePoints( xShape );
1990 // #89764# if export of position is suppressed for group shape,
1991 // positions of contained objects should be written relative to
1992 // the upper left edge of the group.
1993 awt::Point aUpperLeft;
1995 if(!(nFeatures & XMLShapeExportFlags::POSITION))
1997 nFeatures |= XMLShapeExportFlags::POSITION;
1998 aUpperLeft = xShape->getPosition();
1999 pRefPoint = &aUpperLeft;
2002 // write members
2003 exportShapes( xShapes, nFeatures, pRefPoint );
2006 void XMLShapeExport::ImpExportTextBoxShape(
2007 const uno::Reference< drawing::XShape >& xShape,
2008 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2010 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2011 if(!xPropSet.is())
2012 return;
2014 // presentation attribute (if presentation)
2015 bool bIsPresShape(false);
2016 bool bIsEmptyPresObj(false);
2017 OUString aStr;
2019 switch(eShapeType)
2021 case XmlShapeType::PresSubtitleShape:
2023 aStr = GetXMLToken(XML_SUBTITLE);
2024 bIsPresShape = true;
2025 break;
2027 case XmlShapeType::PresTitleTextShape:
2029 aStr = GetXMLToken(XML_TITLE);
2030 bIsPresShape = true;
2031 break;
2033 case XmlShapeType::PresOutlinerShape:
2035 aStr = GetXMLToken(XML_PRESENTATION_OUTLINE);
2036 bIsPresShape = true;
2037 break;
2039 case XmlShapeType::PresNotesShape:
2041 aStr = GetXMLToken(XML_NOTES);
2042 bIsPresShape = true;
2043 break;
2045 case XmlShapeType::PresHeaderShape:
2047 aStr = GetXMLToken(XML_HEADER);
2048 bIsPresShape = true;
2049 break;
2051 case XmlShapeType::PresFooterShape:
2053 aStr = GetXMLToken(XML_FOOTER);
2054 bIsPresShape = true;
2055 break;
2057 case XmlShapeType::PresSlideNumberShape:
2059 aStr = GetXMLToken(XML_PAGE_NUMBER);
2060 bIsPresShape = true;
2061 break;
2063 case XmlShapeType::PresDateTimeShape:
2065 aStr = GetXMLToken(XML_DATE_TIME);
2066 bIsPresShape = true;
2067 break;
2069 default:
2070 break;
2073 // Transformation
2074 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2076 if(bIsPresShape)
2077 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, aStr );
2079 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2080 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
2081 XML_FRAME, bCreateNewline, true );
2083 // evtl. corner radius?
2084 sal_Int32 nCornerRadius(0);
2085 xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius;
2086 if(nCornerRadius)
2088 OUStringBuffer sStringBuffer;
2089 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2090 nCornerRadius);
2091 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
2095 // write text-box
2096 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_TEXT_BOX, true, true);
2097 if(!bIsEmptyPresObj)
2098 ImpExportText( xShape );
2101 ImpExportDescription( xShape ); // #i68101#
2102 ImpExportEvents( xShape );
2103 ImpExportGluePoints( xShape );
2107 void XMLShapeExport::ImpExportRectangleShape(
2108 const uno::Reference< drawing::XShape >& xShape,
2109 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
2111 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2112 if(!xPropSet.is())
2113 return;
2115 // Transformation
2116 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2118 // evtl. corner radius?
2119 sal_Int32 nCornerRadius(0);
2120 xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius;
2121 if(nCornerRadius)
2123 OUStringBuffer sStringBuffer;
2124 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2125 nCornerRadius);
2126 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
2129 // write rectangle
2130 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2131 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_RECT, bCreateNewline, true);
2133 ImpExportDescription( xShape ); // #i68101#
2134 ImpExportEvents( xShape );
2135 ImpExportGluePoints( xShape );
2136 ImpExportText( xShape );
2139 void XMLShapeExport::ImpExportLineShape(
2140 const uno::Reference< drawing::XShape >& xShape,
2141 XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2143 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2144 if(!xPropSet.is())
2145 return;
2147 OUString aStr;
2148 OUStringBuffer sStringBuffer;
2149 awt::Point aStart(0,0);
2150 awt::Point aEnd(1,1);
2152 // #85920# use 'Geometry' to get the points of the line
2153 // since this slot take anchor pos into account.
2155 // get matrix
2156 ::basegfx::B2DHomMatrix aMatrix;
2157 ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
2159 // decompose and correct about pRefPoint
2160 ::basegfx::B2DTuple aTRScale;
2161 double fTRShear(0.0);
2162 double fTRRotate(0.0);
2163 ::basegfx::B2DTuple aTRTranslate;
2164 ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
2166 // create base position
2167 awt::Point aBasePosition(FRound(aTRTranslate.getX()), FRound(aTRTranslate.getY()));
2169 if (xPropSet->getPropertySetInfo()->hasPropertyByName("Geometry"))
2171 // get the two points
2172 uno::Any aAny(xPropSet->getPropertyValue("Geometry"));
2173 if (auto pSourcePolyPolygon
2174 = o3tl::tryAccess<drawing::PointSequenceSequence>(aAny))
2176 if (pSourcePolyPolygon->getLength() > 0)
2178 const drawing::PointSequence& rInnerSequence = (*pSourcePolyPolygon)[0];
2179 if (rInnerSequence.hasElements())
2181 const awt::Point& rPoint = rInnerSequence[0];
2182 aStart = awt::Point(rPoint.X + aBasePosition.X, rPoint.Y + aBasePosition.Y);
2184 if (rInnerSequence.getLength() > 1)
2186 const awt::Point& rPoint = rInnerSequence[1];
2187 aEnd = awt::Point(rPoint.X + aBasePosition.X, rPoint.Y + aBasePosition.Y);
2193 if( nFeatures & XMLShapeExportFlags::X )
2195 // svg: x1
2196 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2197 aStart.X);
2198 aStr = sStringBuffer.makeStringAndClear();
2199 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
2201 else
2203 aEnd.X -= aStart.X;
2206 if( nFeatures & XMLShapeExportFlags::Y )
2208 // svg: y1
2209 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2210 aStart.Y);
2211 aStr = sStringBuffer.makeStringAndClear();
2212 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
2214 else
2216 aEnd.Y -= aStart.Y;
2219 // svg: x2
2220 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2221 aEnd.X);
2222 aStr = sStringBuffer.makeStringAndClear();
2223 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
2225 // svg: y2
2226 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2227 aEnd.Y);
2228 aStr = sStringBuffer.makeStringAndClear();
2229 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
2231 // write line
2232 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2233 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_LINE, bCreateNewline, true);
2235 ImpExportDescription( xShape ); // #i68101#
2236 ImpExportEvents( xShape );
2237 ImpExportGluePoints( xShape );
2238 ImpExportText( xShape );
2242 void XMLShapeExport::ImpExportEllipseShape(
2243 const uno::Reference< drawing::XShape >& xShape,
2244 XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2246 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2247 if(!xPropSet.is())
2248 return;
2250 // get size to decide between Circle and Ellipse
2251 awt::Size aSize = xShape->getSize();
2252 sal_Int32 nRx((aSize.Width + 1) / 2);
2253 sal_Int32 nRy((aSize.Height + 1) / 2);
2254 bool bCircle(nRx == nRy);
2256 // Transformation
2257 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2259 drawing::CircleKind eKind = drawing::CircleKind_FULL;
2260 xPropSet->getPropertyValue("CircleKind") >>= eKind;
2261 if( eKind != drawing::CircleKind_FULL )
2263 OUStringBuffer sStringBuffer;
2264 sal_Int32 nStartAngle = 0;
2265 sal_Int32 nEndAngle = 0;
2266 xPropSet->getPropertyValue("CircleStartAngle") >>= nStartAngle;
2267 xPropSet->getPropertyValue("CircleEndAngle") >>= nEndAngle;
2269 const double dStartAngle = nStartAngle / 100.0;
2270 const double dEndAngle = nEndAngle / 100.0;
2272 // export circle kind
2273 SvXMLUnitConverter::convertEnum( sStringBuffer, eKind, aXML_CircleKind_EnumMap );
2274 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_KIND, sStringBuffer.makeStringAndClear() );
2276 // export start angle
2277 ::sax::Converter::convertDouble( sStringBuffer, dStartAngle );
2278 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_ANGLE, sStringBuffer.makeStringAndClear() );
2280 // export end angle
2281 ::sax::Converter::convertDouble( sStringBuffer, dEndAngle );
2282 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_ANGLE, sStringBuffer.makeStringAndClear() );
2285 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2287 // write ellipse or circle
2288 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW,
2289 bCircle ? XML_CIRCLE : XML_ELLIPSE,
2290 bCreateNewline, true);
2292 ImpExportDescription( xShape ); // #i68101#
2293 ImpExportEvents( xShape );
2294 ImpExportGluePoints( xShape );
2295 ImpExportText( xShape );
2299 void XMLShapeExport::ImpExportPolygonShape(
2300 const uno::Reference< drawing::XShape >& xShape,
2301 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2303 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2304 if(!xPropSet.is())
2305 return;
2307 bool bBezier(eShapeType == XmlShapeType::DrawClosedBezierShape
2308 || eShapeType == XmlShapeType::DrawOpenBezierShape);
2310 // get matrix
2311 ::basegfx::B2DHomMatrix aMatrix;
2312 ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
2314 // decompose and correct about pRefPoint
2315 ::basegfx::B2DTuple aTRScale;
2316 double fTRShear(0.0);
2317 double fTRRotate(0.0);
2318 ::basegfx::B2DTuple aTRTranslate;
2319 ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
2321 // use features and write
2322 ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures);
2324 // create and export ViewBox
2325 awt::Size aSize(FRound(aTRScale.getX()), FRound(aTRScale.getY()));
2326 SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height);
2327 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
2329 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2331 // prepare name (with most used)
2332 enum ::xmloff::token::XMLTokenEnum eName(XML_PATH);
2334 uno::Any aAny( xPropSet->getPropertyValue("Geometry") );
2335 basegfx::B2DPolyPolygon aPolyPolygon;
2337 // tdf#145240 the Any can contain PolyPolygonBezierCoords or PointSequenceSequence
2338 // (see OWN_ATTR_BASE_GEOMETRY in SvxShapePolyPolygon::getPropertyValueImpl),
2339 // so be more flexible in interpreting it. Try to access bezier first:
2341 auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(aAny);
2343 if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength())
2345 aPolyPolygon = basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(*pSourcePolyPolygon);
2349 // if received no data, try to access point sequence second:
2350 if(0 == aPolyPolygon.count())
2352 auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PointSequenceSequence>(aAny);
2354 if(pSourcePolyPolygon)
2356 aPolyPolygon = basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(*pSourcePolyPolygon);
2360 if(aPolyPolygon.count())
2362 if(!bBezier && !aPolyPolygon.areControlPointsUsed() && 1 == aPolyPolygon.count())
2364 // simple polygon shape, can be written as svg:points sequence
2365 const basegfx::B2DPolygon& aPolygon(aPolyPolygon.getB2DPolygon(0));
2366 const OUString aPointString(basegfx::utils::exportToSvgPoints(aPolygon));
2368 // write point array
2369 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString);
2371 // set name
2372 eName = aPolygon.isClosed() ? XML_POLYGON : XML_POLYLINE;
2374 else
2376 // complex polygon shape, write as svg:d
2377 const OUString aPolygonString(
2378 basegfx::utils::exportToSvgD(
2379 aPolyPolygon,
2380 true, // bUseRelativeCoordinates
2381 false, // bDetectQuadraticBeziers: not used in old, but maybe activated now
2382 true)); // bHandleRelativeNextPointCompatible
2384 // write point array
2385 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
2389 // write object, but after attributes are added since this call will
2390 // consume all of these added attributes and the destructor will close the
2391 // scope. Also before text is added; this may add sub-scopes as needed
2392 SvXMLElementExport aOBJ(
2393 mrExport,
2394 XML_NAMESPACE_DRAW,
2395 eName,
2396 bCreateNewline,
2397 true);
2399 ImpExportDescription( xShape ); // #i68101#
2400 ImpExportEvents( xShape );
2401 ImpExportGluePoints( xShape );
2402 ImpExportText( xShape );
2406 namespace
2409 OUString getNameFromStreamURL(std::u16string_view rURL)
2411 static constexpr std::u16string_view sPackageURL(u"vnd.sun.star.Package:");
2413 OUString sResult;
2415 if (o3tl::starts_with(rURL, sPackageURL))
2417 std::u16string_view sRequestedName = rURL.substr(sPackageURL.size());
2418 size_t nLastIndex = sRequestedName.rfind('/') + 1;
2419 if ((nLastIndex > 0) && (nLastIndex < sRequestedName.size()))
2420 sRequestedName = sRequestedName.substr(nLastIndex);
2421 nLastIndex = sRequestedName.rfind('.');
2422 if (nLastIndex != std::u16string_view::npos)
2423 sRequestedName = sRequestedName.substr(0, nLastIndex);
2424 if (!sRequestedName.empty())
2425 sResult = sRequestedName;
2428 return sResult;
2431 } // end anonymous namespace
2433 void XMLShapeExport::ImpExportGraphicObjectShape(
2434 const uno::Reference< drawing::XShape >& xShape,
2435 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2437 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2438 if(!xPropSet.is())
2439 return;
2441 bool bIsEmptyPresObj = false;
2443 // Transformation
2444 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2446 if(eShapeType == XmlShapeType::PresGraphicObjectShape)
2447 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_GRAPHIC) );
2449 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2450 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
2451 XML_FRAME, bCreateNewline, true );
2453 if (!bIsEmptyPresObj)
2455 uno::Reference<graphic::XGraphic> xGraphic;
2456 OUString sOutMimeType;
2459 OUString aStreamURL;
2460 xPropSet->getPropertyValue("GraphicStreamURL") >>= aStreamURL;
2461 OUString sRequestedName = getNameFromStreamURL(aStreamURL);
2463 xPropSet->getPropertyValue("Graphic") >>= xGraphic;
2465 OUString sInternalURL;
2467 if (xGraphic.is())
2468 sInternalURL = mrExport.AddEmbeddedXGraphic(xGraphic, sOutMimeType, sRequestedName);
2470 if (!sInternalURL.isEmpty())
2472 // apply possible changed stream URL to embedded image object
2473 if (!sRequestedName.isEmpty())
2475 OUString newStreamURL = "vnd.sun.star.Package:";
2476 if (sInternalURL[0] == '#')
2478 newStreamURL += sInternalURL.subView(1, sInternalURL.getLength() - 1);
2480 else
2482 newStreamURL += sInternalURL;
2485 if (newStreamURL != aStreamURL)
2487 xPropSet->setPropertyValue("GraphicStreamURL", uno::Any(newStreamURL));
2491 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL);
2492 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
2493 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
2494 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
2499 if (GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
2501 if (sOutMimeType.isEmpty())
2503 GetExport().GetGraphicMimeTypeFromStream(xGraphic, sOutMimeType);
2505 if (!sOutMimeType.isEmpty())
2506 { // ODF 1.3 OFFICE-3943
2507 GetExport().AddAttribute(
2508 SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion()
2509 ? XML_NAMESPACE_DRAW
2510 : XML_NAMESPACE_LO_EXT,
2511 "mime-type", sOutMimeType);
2515 SvXMLElementExport aElement(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, true);
2517 // optional office:binary-data
2518 if (xGraphic.is())
2520 mrExport.AddEmbeddedXGraphicAsBase64(xGraphic);
2522 if (!bIsEmptyPresObj)
2523 ImpExportText(xShape);
2526 //Resolves: fdo#62461 put preferred image first above, followed by
2527 //fallback here
2528 const bool bAddReplacementImages = officecfg::Office::Common::Save::Graphic::AddReplacementImages::get();
2529 if( !bIsEmptyPresObj && bAddReplacementImages)
2531 uno::Reference<graphic::XGraphic> xReplacementGraphic;
2532 xPropSet->getPropertyValue("ReplacementGraphic") >>= xReplacementGraphic;
2534 // If there is no url, then the graphic is empty
2535 if (xReplacementGraphic.is())
2537 OUString aMimeType;
2538 const OUString aHref = mrExport.AddEmbeddedXGraphic(xReplacementGraphic, aMimeType);
2540 if (aMimeType.isEmpty())
2541 mrExport.GetGraphicMimeTypeFromStream(xReplacementGraphic, aMimeType);
2543 if (!aHref.isEmpty())
2545 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aHref);
2546 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
2547 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
2548 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
2551 if (!aMimeType.isEmpty() && GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
2552 { // ODF 1.3 OFFICE-3943
2553 mrExport.AddAttribute(
2554 SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion()
2555 ? XML_NAMESPACE_DRAW
2556 : XML_NAMESPACE_LO_EXT,
2557 "mime-type", aMimeType);
2560 SvXMLElementExport aElement(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, true);
2562 // optional office:binary-data
2563 mrExport.AddEmbeddedXGraphicAsBase64(xReplacementGraphic);
2568 ImpExportEvents( xShape );
2569 ImpExportGluePoints( xShape );
2571 // image map
2572 GetExport().GetImageMapExport().Export( xPropSet );
2573 ImpExportDescription( xShape ); // #i68101#
2575 // Signature Line, QR Code - needs to be after the images!
2576 if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
2578 ImpExportSignatureLine(xShape);
2579 ImpExportQRCode(xShape);
2583 void XMLShapeExport::ImpExportChartShape(
2584 const uno::Reference< drawing::XShape >& xShape,
2585 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint,
2586 comphelper::AttributeList* pAttrList )
2588 ImpExportOLE2Shape( xShape, eShapeType, nFeatures, pRefPoint, pAttrList );
2591 void XMLShapeExport::ImpExportControlShape(
2592 const uno::Reference< drawing::XShape >& xShape,
2593 XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2595 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2596 if(xPropSet.is())
2598 // Transformation
2599 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2602 uno::Reference< drawing::XControlShape > xControl( xShape, uno::UNO_QUERY );
2603 SAL_WARN_IF( !xControl.is(), "xmloff", "Control shape is not supporting XControlShape" );
2604 if( xControl.is() )
2606 uno::Reference< beans::XPropertySet > xControlModel( xControl->getControl(), uno::UNO_QUERY );
2607 SAL_WARN_IF( !xControlModel.is(), "xmloff", "Control shape has not XControlModel" );
2608 if( xControlModel.is() )
2610 OUString sControlId = mrExport.GetFormExport()->getControlId( xControlModel );
2611 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CONTROL, sControlId );
2615 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2616 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONTROL, bCreateNewline, true);
2618 ImpExportDescription( xShape ); // #i68101#
2621 void XMLShapeExport::ImpExportConnectorShape(
2622 const uno::Reference< drawing::XShape >& xShape,
2623 XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
2625 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
2627 OUString aStr;
2628 OUStringBuffer sStringBuffer;
2630 // export connection kind
2631 drawing::ConnectorType eType = drawing::ConnectorType_STANDARD;
2632 uno::Any aAny = xProps->getPropertyValue("EdgeKind");
2633 aAny >>= eType;
2635 if( eType != drawing::ConnectorType_STANDARD )
2637 SvXMLUnitConverter::convertEnum( sStringBuffer, eType, aXML_ConnectionKind_EnumMap );
2638 aStr = sStringBuffer.makeStringAndClear();
2639 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TYPE, aStr);
2642 // export line skew
2643 sal_Int32 nDelta1 = 0, nDelta2 = 0, nDelta3 = 0;
2645 aAny = xProps->getPropertyValue("EdgeLine1Delta");
2646 aAny >>= nDelta1;
2647 aAny = xProps->getPropertyValue("EdgeLine2Delta");
2648 aAny >>= nDelta2;
2649 aAny = xProps->getPropertyValue("EdgeLine3Delta");
2650 aAny >>= nDelta3;
2652 if( nDelta1 != 0 || nDelta2 != 0 || nDelta3 != 0 )
2654 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2655 nDelta1);
2656 if( nDelta2 != 0 || nDelta3 != 0 )
2658 sStringBuffer.append( ' ' );
2659 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2660 nDelta2);
2661 if( nDelta3 != 0 )
2663 sStringBuffer.append( ' ' );
2664 mrExport.GetMM100UnitConverter().convertMeasureToXML(
2665 sStringBuffer, nDelta3);
2669 aStr = sStringBuffer.makeStringAndClear();
2670 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_LINE_SKEW, aStr);
2673 // export start and end point
2674 awt::Point aStart(0,0);
2675 awt::Point aEnd(1,1);
2677 /* Get <StartPositionInHoriL2R> and
2678 <EndPositionInHoriL2R>, if they exist and if the document is exported
2679 into the OpenOffice.org file format.
2680 These properties only exist at service css::text::Shape - the
2681 Writer UNO service for shapes.
2682 This code is needed, because the positioning attributes in the
2683 OpenOffice.org file format are given in horizontal left-to-right layout
2684 regardless the layout direction the shape is in. In the OASIS Open Office
2685 file format the positioning attributes are correctly given in the layout
2686 direction the shape is in. Thus, this code provides the conversion from
2687 the OASIS Open Office file format to the OpenOffice.org file format. (#i36248#)
2689 if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
2690 xProps->getPropertySetInfo()->hasPropertyByName("StartPositionInHoriL2R") &&
2691 xProps->getPropertySetInfo()->hasPropertyByName("EndPositionInHoriL2R") )
2693 xProps->getPropertyValue("StartPositionInHoriL2R") >>= aStart;
2694 xProps->getPropertyValue("EndPositionInHoriL2R") >>= aEnd;
2696 else
2698 xProps->getPropertyValue("StartPosition") >>= aStart;
2699 xProps->getPropertyValue("EndPosition") >>= aEnd;
2702 if( pRefPoint )
2704 aStart.X -= pRefPoint->X;
2705 aStart.Y -= pRefPoint->Y;
2706 aEnd.X -= pRefPoint->X;
2707 aEnd.Y -= pRefPoint->Y;
2710 if( nFeatures & XMLShapeExportFlags::X )
2712 // svg: x1
2713 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2714 aStart.X);
2715 aStr = sStringBuffer.makeStringAndClear();
2716 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
2718 else
2720 aEnd.X -= aStart.X;
2723 if( nFeatures & XMLShapeExportFlags::Y )
2725 // svg: y1
2726 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2727 aStart.Y);
2728 aStr = sStringBuffer.makeStringAndClear();
2729 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
2731 else
2733 aEnd.Y -= aStart.Y;
2736 // svg: x2
2737 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.X);
2738 aStr = sStringBuffer.makeStringAndClear();
2739 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
2741 // svg: y2
2742 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.Y);
2743 aStr = sStringBuffer.makeStringAndClear();
2744 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
2746 // #i39320#
2747 uno::Reference< uno::XInterface > xRefS;
2748 uno::Reference< uno::XInterface > xRefE;
2750 // export start connection
2751 xProps->getPropertyValue("StartShape") >>= xRefS;
2752 if( xRefS.is() )
2754 const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefS );
2755 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_SHAPE, rShapeId);
2757 aAny = xProps->getPropertyValue("StartGluePointIndex");
2758 sal_Int32 nGluePointId = 0;
2759 if( aAny >>= nGluePointId )
2761 if( nGluePointId != -1 )
2763 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_GLUE_POINT, OUString::number( nGluePointId ));
2768 // export end connection
2769 xProps->getPropertyValue("EndShape") >>= xRefE;
2770 if( xRefE.is() )
2772 const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefE );
2773 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_SHAPE, rShapeId);
2775 aAny = xProps->getPropertyValue("EndGluePointIndex");
2776 sal_Int32 nGluePointId = 0;
2777 if( aAny >>= nGluePointId )
2779 if( nGluePointId != -1 )
2781 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_GLUE_POINT, OUString::number( nGluePointId ));
2786 // get PolygonBezier
2787 aAny = xProps->getPropertyValue("PolyPolygonBezier");
2788 auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(aAny);
2789 if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength())
2791 const basegfx::B2DPolyPolygon aPolyPolygon(
2792 basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(
2793 *pSourcePolyPolygon));
2794 const OUString aPolygonString(
2795 basegfx::utils::exportToSvgD(
2796 aPolyPolygon,
2797 true, // bUseRelativeCoordinates
2798 false, // bDetectQuadraticBeziers: not used in old, but maybe activated now
2799 true)); // bHandleRelativeNextPointCompatible
2801 // write point array
2802 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
2805 // get matrix
2806 ::basegfx::B2DHomMatrix aMatrix;
2807 ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xProps);
2809 // decompose and correct about pRefPoint
2810 ::basegfx::B2DTuple aTRScale;
2811 double fTRShear(0.0);
2812 double fTRRotate(0.0);
2813 ::basegfx::B2DTuple aTRTranslate;
2814 ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear,
2815 fTRRotate, aTRTranslate, pRefPoint);
2817 // fdo#49678: create and export ViewBox
2818 awt::Size aSize(FRound(aTRScale.getX()), FRound(aTRScale.getY()));
2819 SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height);
2820 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
2822 // write connector shape. Add Export later.
2823 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2824 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONNECTOR, bCreateNewline, true);
2826 ImpExportDescription( xShape ); // #i68101#
2827 ImpExportEvents( xShape );
2828 ImpExportGluePoints( xShape );
2829 ImpExportText( xShape );
2832 void XMLShapeExport::ImpExportMeasureShape(
2833 const uno::Reference< drawing::XShape >& xShape,
2834 XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point const * pRefPoint /* = NULL */)
2836 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
2838 OUString aStr;
2839 OUStringBuffer sStringBuffer;
2841 // export start and end point
2842 awt::Point aStart(0,0);
2843 awt::Point aEnd(1,1);
2845 /* Get <StartPositionInHoriL2R> and
2846 <EndPositionInHoriL2R>, if they exist and if the document is exported
2847 into the OpenOffice.org file format.
2848 These properties only exist at service css::text::Shape - the
2849 Writer UNO service for shapes.
2850 This code is needed, because the positioning attributes in the
2851 OpenOffice.org file format are given in horizontal left-to-right layout
2852 regardless the layout direction the shape is in. In the OASIS Open Office
2853 file format the positioning attributes are correctly given in the layout
2854 direction the shape is in. Thus, this code provides the conversion from
2855 the OASIS Open Office file format to the OpenOffice.org file format. (#i36248#)
2857 if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
2858 xProps->getPropertySetInfo()->hasPropertyByName("StartPositionInHoriL2R") &&
2859 xProps->getPropertySetInfo()->hasPropertyByName("EndPositionInHoriL2R") )
2861 xProps->getPropertyValue("StartPositionInHoriL2R") >>= aStart;
2862 xProps->getPropertyValue("EndPositionInHoriL2R") >>= aEnd;
2864 else
2866 xProps->getPropertyValue("StartPosition") >>= aStart;
2867 xProps->getPropertyValue("EndPosition") >>= aEnd;
2870 if( pRefPoint )
2872 aStart.X -= pRefPoint->X;
2873 aStart.Y -= pRefPoint->Y;
2874 aEnd.X -= pRefPoint->X;
2875 aEnd.Y -= pRefPoint->Y;
2878 if( nFeatures & XMLShapeExportFlags::X )
2880 // svg: x1
2881 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2882 aStart.X);
2883 aStr = sStringBuffer.makeStringAndClear();
2884 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
2886 else
2888 aEnd.X -= aStart.X;
2891 if( nFeatures & XMLShapeExportFlags::Y )
2893 // svg: y1
2894 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2895 aStart.Y);
2896 aStr = sStringBuffer.makeStringAndClear();
2897 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
2899 else
2901 aEnd.Y -= aStart.Y;
2904 // svg: x2
2905 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.X);
2906 aStr = sStringBuffer.makeStringAndClear();
2907 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
2909 // svg: y2
2910 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.Y);
2911 aStr = sStringBuffer.makeStringAndClear();
2912 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
2914 // write measure shape
2915 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2916 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_MEASURE, bCreateNewline, true);
2918 ImpExportDescription( xShape ); // #i68101#
2919 ImpExportEvents( xShape );
2920 ImpExportGluePoints( xShape );
2922 uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY );
2923 if( xText.is() )
2924 mrExport.GetTextParagraphExport()->exportText( xText );
2927 void XMLShapeExport::ImpExportOLE2Shape(
2928 const uno::Reference< drawing::XShape >& xShape,
2929 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */,
2930 comphelper::AttributeList* pAttrList /* = NULL */ )
2932 uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2933 uno::Reference< container::XNamed > xNamed(xShape, uno::UNO_QUERY);
2935 SAL_WARN_IF( !xPropSet.is() || !xNamed.is(), "xmloff", "ole shape is not implementing needed interfaces");
2936 if(!(xPropSet.is() && xNamed.is()))
2937 return;
2939 // Transformation
2940 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2942 bool bIsEmptyPresObj = false;
2944 // presentation settings
2945 if(eShapeType == XmlShapeType::PresOLE2Shape)
2946 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_OBJECT) );
2947 else if(eShapeType == XmlShapeType::PresChartShape)
2948 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_CHART) );
2949 else if(eShapeType == XmlShapeType::PresSheetShape)
2950 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_TABLE) );
2952 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2953 bool bExportEmbedded(mrExport.getExportFlags() & SvXMLExportFlags::EMBEDDED);
2954 OUString sPersistName;
2955 SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
2956 XML_FRAME, bCreateNewline, true );
2958 if (!bIsEmptyPresObj)
2960 if (pAttrList)
2962 mrExport.AddAttributeList(pAttrList);
2965 OUString sClassId;
2966 OUString sURL;
2967 bool bInternal = false;
2968 xPropSet->getPropertyValue("IsInternal") >>= bInternal;
2972 if ( bInternal )
2974 // OOo internal links have no storage persistence, URL is stored in the XML file
2975 // the result LinkURL is empty in case the object is not a link
2976 xPropSet->getPropertyValue("LinkURL") >>= sURL;
2979 xPropSet->getPropertyValue("PersistName") >>= sPersistName;
2980 if ( sURL.isEmpty() )
2982 if( !sPersistName.isEmpty() )
2984 sURL = "vnd.sun.star.EmbeddedObject:" + sPersistName;
2988 if( !bInternal )
2989 xPropSet->getPropertyValue("CLSID") >>= sClassId;
2991 if( !sClassId.isEmpty() )
2992 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CLASS_ID, sClassId );
2994 if(!bExportEmbedded)
2996 // xlink:href
2997 if( !sURL.isEmpty() )
2999 // #96717# in theorie, if we don't have a URL we shouldn't even
3000 // export this OLE shape. But practically it's too risky right now
3001 // to change this so we better dispose this on load
3002 sURL = mrExport.AddEmbeddedObject( sURL );
3004 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL );
3005 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3006 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3007 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3009 else
3011 // tdf#153179 Export the preview graphic of the object if the object is missing.
3012 uno::Reference<graphic::XGraphic> xGraphic;
3013 xPropSet->getPropertyValue("Graphic") >>= xGraphic;
3015 if (xGraphic.is())
3017 OUString aMimeType;
3018 const OUString aHref = mrExport.AddEmbeddedXGraphic(xGraphic, aMimeType);
3020 if (aMimeType.isEmpty())
3021 mrExport.GetGraphicMimeTypeFromStream(xGraphic, aMimeType);
3023 if (!aHref.isEmpty())
3025 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aHref);
3026 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
3027 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
3028 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
3031 if (!aMimeType.isEmpty()
3032 && GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
3033 { // ODF 1.3 OFFICE-3943
3034 mrExport.AddAttribute(SvtSaveOptions::ODFSVER_013
3035 <= GetExport().getSaneDefaultVersion()
3036 ? XML_NAMESPACE_DRAW
3037 : XML_NAMESPACE_LO_EXT,
3038 "mime-type", aMimeType);
3041 SvXMLElementExport aImageElem(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true,
3042 true);
3044 // optional office:binary-data
3045 mrExport.AddEmbeddedXGraphicAsBase64(xGraphic);
3047 ImpExportEvents(xShape);
3048 ImpExportGluePoints(xShape);
3049 ImpExportDescription(xShape);
3051 return;
3057 enum XMLTokenEnum eElem = sClassId.isEmpty() ? XML_OBJECT : XML_OBJECT_OLE ;
3058 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, eElem, true, true );
3060 // tdf#112547 export text as child of draw:object, where import expects it
3061 if (!bIsEmptyPresObj && supportsText(eShapeType))
3063 // #i118485# Add text export, the draw OLE shape allows text now
3064 ImpExportText( xShape, TextPNS::EXTENSION );
3067 if(bExportEmbedded && !bIsEmptyPresObj)
3069 if(bInternal)
3071 // embedded XML
3072 uno::Reference< lang::XComponent > xComp;
3073 xPropSet->getPropertyValue("Model") >>= xComp;
3074 SAL_WARN_IF( !xComp.is(), "xmloff", "no xModel for own OLE format" );
3075 mrExport.ExportEmbeddedOwnObject( xComp );
3077 else
3079 // embed as Base64
3080 // this is an alien object ( currently MSOLE is the only supported type of such objects )
3081 // in case it is not an OASIS format the object should be asked to store replacement image if possible
3083 OUString sURLRequest( sURL );
3084 if ( !( mrExport.getExportFlags() & SvXMLExportFlags::OASIS ) )
3085 sURLRequest += "?oasis=false";
3086 mrExport.AddEmbeddedObjectAsBase64( sURLRequest );
3090 if( !bIsEmptyPresObj )
3092 OUString sURL = XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE + sPersistName;
3093 if( !bExportEmbedded )
3095 sURL = GetExport().AddEmbeddedObject( sURL );
3096 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL );
3097 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3098 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3099 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3102 SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW,
3103 XML_IMAGE, false, true );
3105 if( bExportEmbedded )
3106 GetExport().AddEmbeddedObjectAsBase64( sURL );
3109 ImpExportEvents( xShape );
3110 ImpExportGluePoints( xShape );
3111 ImpExportDescription( xShape ); // #i68101#
3115 void XMLShapeExport::ImpExportPageShape(
3116 const uno::Reference< drawing::XShape >& xShape,
3117 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
3119 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3120 if(!xPropSet.is())
3121 return;
3123 // #86163# Transformation
3124 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3126 // export page number used for this page
3127 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
3128 static constexpr OUString aPageNumberStr(u"PageNumber"_ustr);
3129 if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(aPageNumberStr))
3131 sal_Int32 nPageNumber = 0;
3132 xPropSet->getPropertyValue(aPageNumberStr) >>= nPageNumber;
3133 if( nPageNumber )
3134 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_PAGE_NUMBER, OUString::number(nPageNumber));
3137 // a presentation page shape, normally used on notes pages only. If
3138 // it is used not as presentation shape, it may have been created with
3139 // copy-paste exchange between draw and impress (this IS possible...)
3140 if(eShapeType == XmlShapeType::PresPageShape)
3142 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS,
3143 XML_PAGE);
3146 // write Page shape
3147 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3148 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PAGE_THUMBNAIL, bCreateNewline, true);
3151 void XMLShapeExport::ImpExportCaptionShape(
3152 const uno::Reference< drawing::XShape >& xShape,
3153 XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
3155 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3156 if(!xPropSet.is())
3157 return;
3159 // Transformation
3160 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3162 // evtl. corner radius?
3163 sal_Int32 nCornerRadius(0);
3164 xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius;
3165 if(nCornerRadius)
3167 OUStringBuffer sStringBuffer;
3168 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
3169 nCornerRadius);
3170 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
3173 awt::Point aCaptionPoint;
3174 xPropSet->getPropertyValue("CaptionPoint") >>= aCaptionPoint;
3176 mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
3177 aCaptionPoint.X);
3178 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_X, msBuffer.makeStringAndClear() );
3179 mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
3180 aCaptionPoint.Y);
3181 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_Y, msBuffer.makeStringAndClear() );
3183 // write Caption shape. Add export later.
3184 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3185 bool bAnnotation( (nFeatures & XMLShapeExportFlags::ANNOTATION) == XMLShapeExportFlags::ANNOTATION );
3187 SvXMLElementExport aObj( mrExport,
3188 (bAnnotation ? XML_NAMESPACE_OFFICE
3189 : XML_NAMESPACE_DRAW),
3190 (bAnnotation ? XML_ANNOTATION : XML_CAPTION),
3191 bCreateNewline, true );
3193 ImpExportDescription( xShape ); // #i68101#
3194 ImpExportEvents( xShape );
3195 ImpExportGluePoints( xShape );
3196 if( bAnnotation )
3197 mrExport.exportAnnotationMeta( xShape );
3198 ImpExportText( xShape );
3202 void XMLShapeExport::ImpExportFrameShape(
3203 const uno::Reference< drawing::XShape >& xShape,
3204 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3206 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3207 if(!xPropSet.is())
3208 return;
3210 // Transformation
3211 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3213 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3214 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
3215 XML_FRAME, bCreateNewline, true );
3217 // export frame url
3218 OUString aStr;
3219 xPropSet->getPropertyValue("FrameURL") >>= aStr;
3220 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
3221 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3222 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3223 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3225 // export name
3226 xPropSet->getPropertyValue("FrameName") >>= aStr;
3227 if( !aStr.isEmpty() )
3228 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FRAME_NAME, aStr );
3230 // write floating frame
3232 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_FLOATING_FRAME, true, true);
3235 ImpExportDescription(xShape);
3238 void XMLShapeExport::ImpExportAppletShape(
3239 const uno::Reference< drawing::XShape >& xShape,
3240 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3242 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3243 if(!xPropSet.is())
3244 return;
3246 // Transformation
3247 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3249 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3250 SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
3251 XML_FRAME, bCreateNewline, true );
3253 // export frame url
3254 OUString aStr;
3255 xPropSet->getPropertyValue("AppletCodeBase") >>= aStr;
3256 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
3257 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3258 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3259 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3261 // export draw:applet-name
3262 xPropSet->getPropertyValue("AppletName") >>= aStr;
3263 if( !aStr.isEmpty() )
3264 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_APPLET_NAME, aStr );
3266 // export draw:code
3267 xPropSet->getPropertyValue("AppletCode") >>= aStr;
3268 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CODE, aStr );
3270 // export draw:may-script
3271 bool bIsScript = false;
3272 xPropSet->getPropertyValue("AppletIsScript") >>= bIsScript;
3273 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MAY_SCRIPT, bIsScript ? XML_TRUE : XML_FALSE );
3276 // write applet
3277 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_APPLET, true, true);
3279 // export parameters
3280 uno::Sequence< beans::PropertyValue > aCommands;
3281 xPropSet->getPropertyValue("AppletCommands") >>= aCommands;
3282 for( const auto& rCommand : std::as_const(aCommands) )
3284 rCommand.Value >>= aStr;
3285 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rCommand.Name );
3286 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr );
3287 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3291 ImpExportDescription(xShape);
3294 void XMLShapeExport::ImpExportPluginShape(
3295 const uno::Reference< drawing::XShape >& xShape,
3296 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3298 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3299 if(!xPropSet.is())
3300 return;
3302 // Transformation
3303 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3305 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3306 SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
3307 XML_FRAME, bCreateNewline, true );
3309 // export plugin url
3310 OUString aStr;
3311 xPropSet->getPropertyValue("PluginURL") >>= aStr;
3312 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
3313 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3314 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3315 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3317 // export mime-type
3318 xPropSet->getPropertyValue("PluginMimeType") >>= aStr;
3319 if(!aStr.isEmpty())
3320 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, aStr );
3323 // write plugin
3324 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, true, true);
3326 // export parameters
3327 uno::Sequence< beans::PropertyValue > aCommands;
3328 xPropSet->getPropertyValue("PluginCommands") >>= aCommands;
3329 for( const auto& rCommand : std::as_const(aCommands) )
3331 rCommand.Value >>= aStr;
3332 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rCommand.Name );
3333 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr );
3334 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3338 ImpExportDescription(xShape);
3341 static void lcl_CopyStream(
3342 uno::Reference<io::XInputStream> const& xInStream,
3343 uno::Reference<embed::XStorage> const& xTarget,
3344 OUString const& rPath, const OUString& rMimeType)
3346 ::comphelper::LifecycleProxy proxy;
3347 uno::Reference<io::XStream> const xStream(
3348 ::comphelper::OStorageHelper::GetStreamAtPackageURL(xTarget, rPath,
3349 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE, proxy));
3350 uno::Reference<io::XOutputStream> const xOutStream(
3351 (xStream.is()) ? xStream->getOutputStream() : nullptr);
3352 if (!xOutStream.is())
3354 SAL_WARN("xmloff", "no output stream");
3355 throw uno::Exception("no output stream",nullptr);
3357 uno::Reference< beans::XPropertySet > const xStreamProps(xStream,
3358 uno::UNO_QUERY);
3359 if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage
3360 xStreamProps->setPropertyValue("MediaType",
3361 uno::Any(rMimeType));
3362 xStreamProps->setPropertyValue( // turn off compression
3363 "Compressed",
3364 uno::Any(false));
3366 ::comphelper::OStorageHelper::CopyInputToOutput(xInStream, xOutStream);
3367 xOutStream->closeOutput();
3368 proxy.commitStorages();
3371 static OUString
3372 lcl_StoreMediaAndGetURL(SvXMLExport & rExport,
3373 uno::Reference<beans::XPropertySet> const& xPropSet,
3374 OUString const& rURL, const OUString& rMimeType)
3376 OUString urlPath;
3377 if (rURL.startsWithIgnoreAsciiCase("vnd.sun.star.Package:", &urlPath))
3379 try // video is embedded
3381 uno::Reference<embed::XStorage> const xTarget(
3382 rExport.GetTargetStorage(), uno::UNO_SET_THROW);
3383 uno::Reference<io::XInputStream> xInStream;
3384 xPropSet->getPropertyValue("PrivateStream")
3385 >>= xInStream;
3387 if (!xInStream.is())
3389 SAL_WARN("xmloff", "no input stream");
3390 return OUString();
3393 lcl_CopyStream(xInStream, xTarget, rURL, rMimeType);
3395 return urlPath;
3397 catch (uno::Exception const&)
3399 TOOLS_INFO_EXCEPTION("xmloff", "exception while storing embedded media");
3401 return OUString();
3403 else
3405 return rExport.GetRelativeReference(rURL); // linked
3409 namespace
3411 void ExportGraphicPreview(const uno::Reference<graphic::XGraphic>& xGraphic, SvXMLExport& rExport, const std::u16string_view& rPrefix, const std::u16string_view& rExtension, const OUString& rMimeType)
3413 const bool bExportEmbedded(rExport.getExportFlags() & SvXMLExportFlags::EMBEDDED);
3415 if( xGraphic.is() ) try
3417 uno::Reference< uno::XComponentContext > xContext = rExport.getComponentContext();
3419 uno::Reference< embed::XStorage > xPictureStorage;
3420 uno::Reference< embed::XStorage > xStorage;
3421 uno::Reference< io::XStream > xPictureStream;
3423 OUString sPictureName;
3424 if( bExportEmbedded )
3426 xPictureStream.set( xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.comp.MemoryStream", xContext), uno::UNO_QUERY_THROW );
3428 else
3430 xStorage.set( rExport.GetTargetStorage(), uno::UNO_SET_THROW );
3432 xPictureStorage.set( xStorage->openStorageElement( "Pictures" , ::embed::ElementModes::READWRITE ), uno::UNO_SET_THROW );
3434 sal_Int32 nIndex = 0;
3437 sPictureName = rPrefix + OUString::number( ++nIndex ) + rExtension;
3439 while( xPictureStorage->hasByName( sPictureName ) );
3441 xPictureStream.set( xPictureStorage->openStreamElement( sPictureName, ::embed::ElementModes::READWRITE ), uno::UNO_SET_THROW );
3444 uno::Reference< graphic::XGraphicProvider > xProvider( graphic::GraphicProvider::create(xContext) );
3445 uno::Sequence< beans::PropertyValue > aArgs{
3446 comphelper::makePropertyValue("MimeType", rMimeType ),
3447 comphelper::makePropertyValue("OutputStream", xPictureStream->getOutputStream())
3449 xProvider->storeGraphic( xGraphic, aArgs );
3451 if( xPictureStorage.is() )
3453 uno::Reference< embed::XTransactedObject > xTrans( xPictureStorage, uno::UNO_QUERY );
3454 if( xTrans.is() )
3455 xTrans->commit();
3458 if( !bExportEmbedded )
3460 OUString sURL = "Pictures/" + sPictureName;
3461 rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sURL );
3462 rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3463 rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3464 rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3467 SvXMLElementExport aElem( rExport, XML_NAMESPACE_DRAW, XML_IMAGE, false, true );
3469 if( bExportEmbedded )
3471 uno::Reference< io::XSeekableInputStream > xSeekable( xPictureStream, uno::UNO_QUERY_THROW );
3472 xSeekable->seek(0);
3474 XMLBase64Export aBase64Exp( rExport );
3475 aBase64Exp.exportOfficeBinaryDataElement( uno::Reference < io::XInputStream >( xPictureStream, uno::UNO_QUERY_THROW ) );
3478 catch( uno::Exception const & )
3480 DBG_UNHANDLED_EXCEPTION("xmloff.draw");
3485 void XMLShapeExport::ImpExportMediaShape(
3486 const uno::Reference< drawing::XShape >& xShape,
3487 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3489 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3490 if(!xPropSet.is())
3491 return;
3493 // Transformation
3494 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3496 if(eShapeType == XmlShapeType::PresMediaShape)
3498 (void)ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_OBJECT) );
3500 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3501 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
3502 XML_FRAME, bCreateNewline, true );
3504 // export media url
3505 OUString aMediaURL;
3506 xPropSet->getPropertyValue("MediaURL") >>= aMediaURL;
3507 OUString sMimeType;
3508 xPropSet->getPropertyValue("MediaMimeType") >>= sMimeType;
3510 OUString const persistentURL =
3511 lcl_StoreMediaAndGetURL(GetExport(), xPropSet, aMediaURL, sMimeType);
3513 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, persistentURL );
3514 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3515 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3516 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3518 // export mime-type
3519 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, sMimeType );
3521 // write plugin
3522 auto pPluginOBJ = std::make_unique<SvXMLElementExport>(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, !( nFeatures & XMLShapeExportFlags::NO_WS ), true);
3524 // export parameters
3525 static constexpr OUString aFalseStr( u"false"_ustr );
3526 static constexpr OUString aTrueStr( u"true"_ustr );
3528 bool bLoop = false;
3529 static constexpr OUString aLoopStr( u"Loop"_ustr );
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 constexpr OUString aMuteStr( u"Mute"_ustr );
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 constexpr OUStringLiteral aColorPropName(u"D3DSceneLightColor");
3913 static constexpr OUStringLiteral aDirectionPropName(u"D3DSceneLightDirection");
3914 static constexpr 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 constexpr OUString sCustomShapeGeometry( u"CustomShapeGeometry"_ustr );
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"_ustr))
5007 sal_Int16 nDirection = -1;
5008 xPropSet->getPropertyValue(u"WritingMode"_ustr) >>= 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: */