bump product version to 7.6.3.2-android
[LibreOffice.git] / xmloff / source / draw / shapeexport.cxx
blob51976a625c971a75f1b8b7bb282060544c949205
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_wasm_strip.h>
22 #include <basegfx/matrix/b2dhommatrix.hxx>
23 #include <basegfx/matrix/b3dhommatrix.hxx>
24 #include <basegfx/polygon/b2dpolypolygon.hxx>
25 #include <basegfx/polygon/b2dpolypolygontools.hxx>
26 #include <basegfx/polygon/b2dpolygontools.hxx>
27 #include <basegfx/polygon/b3dpolypolygon.hxx>
28 #include <basegfx/polygon/b3dpolypolygontools.hxx>
29 #include <basegfx/tuple/b2dtuple.hxx>
30 #include <basegfx/vector/b3dvector.hxx>
32 #include <com/sun/star/beans/XPropertyState.hpp>
33 #include <com/sun/star/beans/PropertyValues.hpp>
34 #include <com/sun/star/container/XChild.hpp>
35 #include <com/sun/star/container/XEnumerationAccess.hpp>
36 #include <com/sun/star/container/XIdentifierAccess.hpp>
37 #include <com/sun/star/container/XNamed.hpp>
38 #include <com/sun/star/document/XEventsSupplier.hpp>
39 #include <com/sun/star/drawing/Alignment.hpp>
40 #include <com/sun/star/drawing/CameraGeometry.hpp>
41 #include <com/sun/star/drawing/CircleKind.hpp>
42 #include <com/sun/star/drawing/ConnectorType.hpp>
43 #include <com/sun/star/drawing/Direction3D.hpp>
44 #include <com/sun/star/drawing/EscapeDirection.hpp>
45 #include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
46 #include <com/sun/star/drawing/EnhancedCustomShapeGluePointType.hpp>
47 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
48 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
49 #include <com/sun/star/drawing/EnhancedCustomShapeMetalType.hpp>
50 #include <com/sun/star/drawing/EnhancedCustomShapeSegment.hpp>
51 #include <com/sun/star/drawing/EnhancedCustomShapeSegmentCommand.hpp>
52 #include <com/sun/star/drawing/EnhancedCustomShapeTextFrame.hpp>
53 #include <com/sun/star/drawing/EnhancedCustomShapeTextPathMode.hpp>
54 #include <com/sun/star/drawing/GluePoint2.hpp>
55 #include <com/sun/star/drawing/HomogenMatrix.hpp>
56 #include <com/sun/star/drawing/HomogenMatrix3.hpp>
57 #include <com/sun/star/drawing/PolyPolygonBezierCoords.hpp>
58 #include <com/sun/star/drawing/PolyPolygonShape3D.hpp>
59 #include <com/sun/star/drawing/Position3D.hpp>
60 #include <com/sun/star/drawing/ProjectionMode.hpp>
61 #include <com/sun/star/drawing/ShadeMode.hpp>
62 #include <com/sun/star/drawing/XControlShape.hpp>
63 #include <com/sun/star/drawing/XCustomShapeEngine.hpp>
64 #include <com/sun/star/drawing/XGluePointsSupplier.hpp>
65 #include <com/sun/star/drawing/BarCode.hpp>
66 #include <com/sun/star/drawing/BarCodeErrorCorrection.hpp>
67 #include <com/sun/star/drawing/XShapes3.hpp>
68 #include <com/sun/star/embed/ElementModes.hpp>
69 #include <com/sun/star/embed/XStorage.hpp>
70 #include <com/sun/star/embed/XTransactedObject.hpp>
71 #include <com/sun/star/graphic/XGraphic.hpp>
72 #include <com/sun/star/graphic/GraphicProvider.hpp>
73 #include <com/sun/star/graphic/XGraphicProvider.hpp>
74 #include <com/sun/star/io/XSeekableInputStream.hpp>
75 #include <com/sun/star/io/XStream.hpp>
76 #include <com/sun/star/lang/ServiceNotRegisteredException.hpp>
77 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
78 #include <com/sun/star/media/ZoomLevel.hpp>
79 #include <com/sun/star/presentation/AnimationSpeed.hpp>
80 #include <com/sun/star/presentation/ClickAction.hpp>
81 #include <com/sun/star/style/XStyle.hpp>
82 #include <com/sun/star/table/XColumnRowRange.hpp>
83 #include <com/sun/star/text/WritingMode2.hpp>
84 #include <com/sun/star/text/XText.hpp>
86 #include <comphelper/classids.hxx>
87 #include <comphelper/processfactory.hxx>
88 #include <comphelper/propertyvalue.hxx>
89 #include <comphelper/storagehelper.hxx>
90 #include <officecfg/Office/Common.hxx>
92 #include <o3tl/any.hxx>
93 #include <o3tl/typed_flags_set.hxx>
94 #include <o3tl/string_view.hxx>
96 #include <rtl/math.hxx>
97 #include <rtl/ustrbuf.hxx>
98 #include <rtl/ustring.hxx>
99 #include <sal/log.hxx>
101 #include <sax/tools/converter.hxx>
103 #include <tools/debug.hxx>
104 #include <tools/globname.hxx>
105 #include <tools/helpers.hxx>
106 #include <comphelper/diagnose_ex.hxx>
107 #include <vcl/graph.hxx>
109 #include <xmloff/contextid.hxx>
110 #include <xmloff/families.hxx>
111 #include <xmloff/namespacemap.hxx>
112 #include <xmloff/shapeexport.hxx>
113 #include <xmloff/unointerfacetouniqueidentifiermapper.hxx>
114 #include <xmloff/xmlexp.hxx>
115 #include <xmloff/xmlnamespace.hxx>
116 #include <xmloff/xmltoken.hxx>
117 #include <xmloff/xmluconv.hxx>
118 #include <xmloff/table/XMLTableExport.hxx>
119 #include <xmloff/ProgressBarHelper.hxx>
121 #include <anim.hxx>
122 #include <EnhancedCustomShapeToken.hxx>
123 #include "sdpropls.hxx"
124 #include <xexptran.hxx>
125 #include "ximpshap.hxx"
126 #include <XMLBase64Export.hxx>
127 #include <XMLImageMapExport.hxx>
128 #include <memory>
130 using namespace ::com::sun::star;
131 using namespace ::xmloff::EnhancedCustomShapeToken;
132 using namespace ::xmloff::token;
134 constexpr OUStringLiteral XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE = u"vnd.sun.star.GraphicObject:";
136 namespace {
138 bool supportsText(XmlShapeType eShapeType)
140 return eShapeType != XmlShapeType::PresChartShape &&
141 eShapeType != XmlShapeType::PresOLE2Shape &&
142 eShapeType != XmlShapeType::DrawSheetShape &&
143 eShapeType != XmlShapeType::PresSheetShape &&
144 eShapeType != XmlShapeType::Draw3DSceneObject &&
145 eShapeType != XmlShapeType::Draw3DCubeObject &&
146 eShapeType != XmlShapeType::Draw3DSphereObject &&
147 eShapeType != XmlShapeType::Draw3DLatheObject &&
148 eShapeType != XmlShapeType::Draw3DExtrudeObject &&
149 eShapeType != XmlShapeType::DrawPageShape &&
150 eShapeType != XmlShapeType::PresPageShape &&
151 eShapeType != XmlShapeType::DrawGroupShape;
157 constexpr OUStringLiteral gsZIndex( u"ZOrder" );
158 constexpr OUStringLiteral gsPrintable( u"Printable" );
159 constexpr OUStringLiteral gsVisible( u"Visible" );
160 constexpr OUStringLiteral gsModel( u"Model" );
161 constexpr OUStringLiteral gsStartShape( u"StartShape" );
162 constexpr OUStringLiteral gsEndShape( u"EndShape" );
163 constexpr OUStringLiteral gsOnClick( u"OnClick" );
164 constexpr OUStringLiteral gsEventType( u"EventType" );
165 constexpr OUStringLiteral gsPresentation( u"Presentation" );
166 constexpr OUStringLiteral gsMacroName( u"MacroName" );
167 constexpr OUStringLiteral gsScript( u"Script" );
168 constexpr OUStringLiteral gsLibrary( u"Library" );
169 constexpr OUStringLiteral gsClickAction( u"ClickAction" );
170 constexpr OUStringLiteral gsBookmark( u"Bookmark" );
171 constexpr OUStringLiteral gsEffect( u"Effect" );
172 constexpr OUStringLiteral gsPlayFull( u"PlayFull" );
173 constexpr OUStringLiteral gsVerb( u"Verb" );
174 constexpr OUStringLiteral gsSoundURL( u"SoundURL" );
175 constexpr OUStringLiteral gsSpeed( u"Speed" );
176 constexpr OUStringLiteral gsStarBasic( u"StarBasic" );
177 constexpr OUStringLiteral gsHyperlink( u"Hyperlink" );
179 XMLShapeExport::XMLShapeExport(SvXMLExport& rExp,
180 SvXMLExportPropertyMapper *pExtMapper )
181 : mrExport( rExp ),
182 maCurrentShapesIter(maShapesInfos.end()),
183 mbExportLayer( false ),
184 // #88546# init to sal_False
185 mbHandleProgressBar( false )
187 // construct PropertySetMapper
188 mxPropertySetMapper = CreateShapePropMapper( mrExport );
189 if( pExtMapper )
191 rtl::Reference < SvXMLExportPropertyMapper > xExtMapper( pExtMapper );
192 mxPropertySetMapper->ChainExportMapper( xExtMapper );
196 // chain text attributes
197 xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(rExp));
200 mrExport.GetAutoStylePool()->AddFamily(
201 XmlStyleFamily::SD_GRAPHICS_ID,
202 XML_STYLE_FAMILY_SD_GRAPHICS_NAME,
203 GetPropertySetMapper(),
204 XML_STYLE_FAMILY_SD_GRAPHICS_PREFIX);
205 mrExport.GetAutoStylePool()->AddFamily(
206 XmlStyleFamily::SD_PRESENTATION_ID,
207 XML_STYLE_FAMILY_SD_PRESENTATION_NAME,
208 GetPropertySetMapper(),
209 XML_STYLE_FAMILY_SD_PRESENTATION_PREFIX);
211 // create table export helper and let him add his families in time
212 GetShapeTableExport();
215 XMLShapeExport::~XMLShapeExport()
219 // sj: replacing CustomShapes with standard objects that are also supported in OpenOffice.org format
220 uno::Reference< drawing::XShape > XMLShapeExport::checkForCustomShapeReplacement( const uno::Reference< drawing::XShape >& xShape )
222 uno::Reference< drawing::XShape > xCustomShapeReplacement;
224 if( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) )
226 OUString aType( xShape->getShapeType() );
227 if( aType == "com.sun.star.drawing.CustomShape" )
229 uno::Reference< beans::XPropertySet > xSet( xShape, uno::UNO_QUERY );
230 if( xSet.is() )
232 OUString aEngine;
233 xSet->getPropertyValue("CustomShapeEngine") >>= aEngine;
234 if ( aEngine.isEmpty() )
236 aEngine = "com.sun.star.drawing.EnhancedCustomShapeEngine";
238 uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
240 if ( !aEngine.isEmpty() )
242 uno::Sequence< beans::PropertyValue > aPropValues{
243 comphelper::makePropertyValue("CustomShape", xShape),
244 comphelper::makePropertyValue("ForceGroupWithText", true)
246 uno::Sequence< uno::Any > aArgument = { uno::Any(aPropValues) };
247 uno::Reference< uno::XInterface > xInterface(
248 xContext->getServiceManager()->createInstanceWithArgumentsAndContext(aEngine, aArgument, xContext) );
249 if ( xInterface.is() )
251 uno::Reference< drawing::XCustomShapeEngine > xCustomShapeEngine(
252 uno::Reference< drawing::XCustomShapeEngine >( xInterface, uno::UNO_QUERY ) );
253 if ( xCustomShapeEngine.is() )
254 xCustomShapeReplacement = xCustomShapeEngine->render();
260 return xCustomShapeReplacement;
263 // This method collects all automatic styles for the given XShape
264 void XMLShapeExport::collectShapeAutoStyles(const uno::Reference< drawing::XShape >& xShape )
266 if( maCurrentShapesIter == maShapesInfos.end() )
268 OSL_FAIL( "XMLShapeExport::collectShapeAutoStyles(): no call to seekShapes()!" );
269 return;
271 sal_Int32 nZIndex = 0;
272 uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
273 if( xPropSet.is() )
274 xPropSet->getPropertyValue(gsZIndex) >>= nZIndex;
276 ImplXMLShapeExportInfoVector& aShapeInfoVector = (*maCurrentShapesIter).second;
278 if( static_cast<sal_Int32>(aShapeInfoVector.size()) <= nZIndex )
280 OSL_FAIL( "XMLShapeExport::collectShapeAutoStyles(): no shape info allocated for a given shape" );
281 return;
284 ImplXMLShapeExportInfo& aShapeInfo = aShapeInfoVector[nZIndex];
286 uno::Reference< drawing::XShape > xCustomShapeReplacement = checkForCustomShapeReplacement( xShape );
287 if ( xCustomShapeReplacement.is() )
288 aShapeInfo.xCustomShapeReplacement = xCustomShapeReplacement;
290 // first compute the shapes type
291 ImpCalcShapeType(xShape, aShapeInfo.meShapeType);
293 // #i118485# enabled XmlShapeType::DrawChartShape and XmlShapeType::DrawOLE2Shape
294 // to have text
295 const bool bObjSupportsText =
296 supportsText(aShapeInfo.meShapeType);
298 const bool bObjSupportsStyle =
299 aShapeInfo.meShapeType != XmlShapeType::DrawGroupShape;
301 bool bIsEmptyPresObj = false;
303 if ( aShapeInfo.xCustomShapeReplacement.is() )
304 xPropSet.clear();
306 // prep text styles
307 if( xPropSet.is() && bObjSupportsText )
309 uno::Reference< text::XText > xText(xShape, uno::UNO_QUERY);
310 if (xText.is())
314 // tdf#153161: it seems that the call to XTextRange::getString flushes the changes
315 // for some objects, that otherwise fail to get exported correctly. Maybe at some
316 // point it would make sense to find a better place for more targeted flush.
317 xText->getString();
319 catch (uno::RuntimeException const&)
321 // E.g., SwXTextFrame that contains only a table will throw; this is not an error
324 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
326 if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsEmptyPresentationObject") )
328 uno::Any aAny = xPropSet->getPropertyValue("IsEmptyPresentationObject");
329 aAny >>= bIsEmptyPresObj;
332 if(!bIsEmptyPresObj)
334 GetExport().GetTextParagraphExport()->collectTextAutoStyles( xText );
339 // compute the shape parent style
340 if( xPropSet.is() )
342 uno::Reference< beans::XPropertySetInfo > xPropertySetInfo( xPropSet->getPropertySetInfo() );
344 OUString aParentName;
345 uno::Reference< style::XStyle > xStyle;
347 if( bObjSupportsStyle )
349 if( xPropertySetInfo.is() && xPropertySetInfo->hasPropertyByName("Style") )
350 xPropSet->getPropertyValue("Style") >>= xStyle;
352 if(xStyle.is())
354 // get family ID
355 uno::Reference< beans::XPropertySet > xStylePropSet(xStyle, uno::UNO_QUERY);
356 SAL_WARN_IF( !xStylePropSet.is(), "xmloff", "style without a XPropertySet?" );
359 if(xStylePropSet.is())
361 OUString aFamilyName;
362 xStylePropSet->getPropertyValue("Family") >>= aFamilyName;
363 if( !aFamilyName.isEmpty() && aFamilyName != "graphics" )
364 aShapeInfo.mnFamily = XmlStyleFamily::SD_PRESENTATION_ID;
367 catch(const beans::UnknownPropertyException&)
369 // Ignored.
370 SAL_WARN( "xmloff",
371 "XMLShapeExport::collectShapeAutoStyles: style has no 'Family' property");
374 // get parent-style name
375 if(XmlStyleFamily::SD_PRESENTATION_ID == aShapeInfo.mnFamily)
377 aParentName = msPresentationStylePrefix;
380 aParentName += xStyle->getName();
384 if (aParentName.isEmpty() && xPropertySetInfo->hasPropertyByName("TextBox") && xPropSet->getPropertyValue("TextBox").hasValue() && xPropSet->getPropertyValue("TextBox").get<bool>())
386 // Shapes with a Writer TextBox always have a parent style.
387 // If there would be none, then assign the default one.
388 aParentName = "Frame";
391 // filter propset
392 std::vector< XMLPropertyState > aPropStates;
394 sal_Int32 nCount = 0;
395 if( !bIsEmptyPresObj || (aShapeInfo.meShapeType != XmlShapeType::PresPageShape) )
397 aPropStates = GetPropertySetMapper()->Filter(mrExport, xPropSet);
399 if (XmlShapeType::DrawControlShape == aShapeInfo.meShapeType)
401 // for control shapes, we additionally need the number format style (if any)
402 uno::Reference< drawing::XControlShape > xControl(xShape, uno::UNO_QUERY);
403 DBG_ASSERT(xControl.is(), "XMLShapeExport::collectShapeAutoStyles: ShapeType control, but no XControlShape!");
404 if (xControl.is())
406 uno::Reference< beans::XPropertySet > xControlModel(xControl->getControl(), uno::UNO_QUERY);
407 DBG_ASSERT(xControlModel.is(), "XMLShapeExport::collectShapeAutoStyles: no control model on the control shape!");
409 OUString sNumberStyle = mrExport.GetFormExport()->getControlNumberStyle(xControlModel);
410 if (!sNumberStyle.isEmpty())
412 sal_Int32 nIndex = GetPropertySetMapper()->getPropertySetMapper()->FindEntryIndex(CTF_SD_CONTROL_SHAPE_DATA_STYLE);
413 // TODO : this retrieval of the index could be moved into the ctor, holding the index
414 // as member, thus saving time.
415 DBG_ASSERT(-1 != nIndex, "XMLShapeExport::collectShapeAutoStyles: could not obtain the index for our context id!");
417 XMLPropertyState aNewState(nIndex, uno::Any(sNumberStyle));
418 aPropStates.push_back(aNewState);
423 nCount = std::count_if(aPropStates.cbegin(), aPropStates.cend(),
424 [](const XMLPropertyState& rProp) { return rProp.mnIndex != -1; });
427 if(nCount == 0)
429 // no hard attributes, use parent style name for export
430 aShapeInfo.msStyleName = aParentName;
432 else
434 // there are filtered properties -> hard attributes
435 // try to find this style in AutoStylePool
436 aShapeInfo.msStyleName = mrExport.GetAutoStylePool()->Find(aShapeInfo.mnFamily, aParentName, aPropStates);
438 if(aShapeInfo.msStyleName.isEmpty())
440 // Style did not exist, add it to AutoStalePool
441 aShapeInfo.msStyleName = mrExport.GetAutoStylePool()->Add(aShapeInfo.mnFamily, aParentName, std::move(aPropStates));
445 // optionally generate auto style for text attributes
446 if( (!bIsEmptyPresObj || (aShapeInfo.meShapeType != XmlShapeType::PresPageShape)) && bObjSupportsText )
448 aPropStates = GetExport().GetTextParagraphExport()->GetParagraphPropertyMapper()->Filter(mrExport, xPropSet);
450 // yet more additionally, we need to care for the ParaAdjust property
451 if ( XmlShapeType::DrawControlShape == aShapeInfo.meShapeType )
453 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
454 uno::Reference< beans::XPropertyState > xPropState( xPropSet, uno::UNO_QUERY );
455 if ( xPropSetInfo.is() && xPropState.is() )
457 // this is because:
458 // * if controls shapes have a ParaAdjust property, then this is the Align property of the control model
459 // * control models are allowed to have an Align of "void"
460 // * the Default for control model's Align is TextAlign_LEFT
461 // * defaults for style properties are not written, but we need to write the "left",
462 // because we need to distinguish this "left" from the case where not align attribute
463 // is present which means "void"
464 if ( xPropSetInfo->hasPropertyByName( "ParaAdjust" )
465 && ( beans::PropertyState_DEFAULT_VALUE == xPropState->getPropertyState( "ParaAdjust" ) )
468 sal_Int32 nIndex = GetExport().GetTextParagraphExport()->GetParagraphPropertyMapper()->getPropertySetMapper()->FindEntryIndex( CTF_SD_SHAPE_PARA_ADJUST );
469 // TODO : this retrieval of the index should be moved into the ctor, holding the index
470 // as member, thus saving time.
471 DBG_ASSERT(-1 != nIndex, "XMLShapeExport::collectShapeAutoStyles: could not obtain the index for the ParaAdjust context id!");
473 uno::Any aParaAdjustValue = xPropSet->getPropertyValue( "ParaAdjust" );
474 XMLPropertyState aAlignDefaultState( nIndex, aParaAdjustValue );
476 aPropStates.push_back( aAlignDefaultState );
481 nCount = std::count_if(aPropStates.cbegin(), aPropStates.cend(),
482 [](const XMLPropertyState& rProp) { return rProp.mnIndex != -1; });
484 if( nCount )
486 aShapeInfo.msTextStyleName = mrExport.GetAutoStylePool()->Find( XmlStyleFamily::TEXT_PARAGRAPH, "", aPropStates );
487 if(aShapeInfo.msTextStyleName.isEmpty())
489 // Style did not exist, add it to AutoStalePool
490 aShapeInfo.msTextStyleName = mrExport.GetAutoStylePool()->Add(XmlStyleFamily::TEXT_PARAGRAPH, "", std::move(aPropStates));
496 // prepare animation information if needed
497 if( mxAnimationsExporter.is() )
498 XMLAnimationsExporter::prepare( xShape );
500 // check for special shapes
502 switch( aShapeInfo.meShapeType )
504 case XmlShapeType::DrawConnectorShape:
506 uno::Reference< uno::XInterface > xConnection;
508 // create shape ids for export later
509 xPropSet->getPropertyValue( gsStartShape ) >>= xConnection;
510 if( xConnection.is() )
511 mrExport.getInterfaceToIdentifierMapper().registerReference( xConnection );
513 xPropSet->getPropertyValue( gsEndShape ) >>= xConnection;
514 if( xConnection.is() )
515 mrExport.getInterfaceToIdentifierMapper().registerReference( xConnection );
516 break;
518 case XmlShapeType::PresTableShape:
519 case XmlShapeType::DrawTableShape:
523 uno::Reference< table::XColumnRowRange > xRange( xPropSet->getPropertyValue( gsModel ), uno::UNO_QUERY_THROW );
524 GetShapeTableExport()->collectTableAutoStyles( xRange );
526 catch(const uno::Exception&)
528 DBG_UNHANDLED_EXCEPTION( "xmloff", "collecting auto styles for a table" );
530 break;
532 default:
533 break;
536 // check for shape collections (group shape or 3d scene)
537 // and collect contained shapes style infos
538 const uno::Reference< drawing::XShape >& xCollection = aShapeInfo.xCustomShapeReplacement.is()
539 ? aShapeInfo.xCustomShapeReplacement : xShape;
541 uno::Reference< drawing::XShapes > xShapes( xCollection, uno::UNO_QUERY );
542 if( xShapes.is() )
544 collectShapesAutoStyles( xShapes );
549 namespace
551 class NewTextListsHelper
553 public:
554 explicit NewTextListsHelper( SvXMLExport& rExp )
555 : mrExport( rExp )
557 mrExport.GetTextParagraphExport()->PushNewTextListsHelper();
560 ~NewTextListsHelper()
562 mrExport.GetTextParagraphExport()->PopTextListsHelper();
565 private:
566 SvXMLExport& mrExport;
569 // This method exports the given XShape
570 void XMLShapeExport::exportShape(const uno::Reference< drawing::XShape >& xShape,
571 XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */,
572 css::awt::Point* pRefPoint /* = NULL */,
573 comphelper::AttributeList* pAttrList /* = NULL */ )
575 SAL_INFO("xmloff", xShape->getShapeType());
576 if( maCurrentShapesIter == maShapesInfos.end() )
578 SAL_WARN( "xmloff", "XMLShapeExport::exportShape(): no auto styles where collected before export" );
579 return;
581 sal_Int32 nZIndex = 0;
582 uno::Reference< beans::XPropertySet > xSet( xShape, uno::UNO_QUERY );
583 OUString sHyperlink;
586 xSet->getPropertyValue(gsHyperlink) >>= sHyperlink;
588 catch (beans::UnknownPropertyException)
592 std::unique_ptr< SvXMLElementExport > pHyperlinkElement;
594 // Need to stash the attributes that are pre-loaded for the shape export
595 // (otherwise they will become attributes of the draw:a element)
596 uno::Reference<xml::sax::XAttributeList> xSaveAttribs(
597 new comphelper::AttributeList(GetExport().GetAttrList()));
598 GetExport().ClearAttrList();
599 if( xSet.is() && (GetExport().GetModelType() == SvtModuleOptions::EFactory::DRAW) )
601 // export hyperlinks with <a><shape/></a>. Currently only in draw since draw
602 // does not support document events
605 presentation::ClickAction eAction = presentation::ClickAction_NONE;
606 xSet->getPropertyValue(gsOnClick) >>= eAction;
608 if( (eAction == presentation::ClickAction_DOCUMENT) ||
609 (eAction == presentation::ClickAction_BOOKMARK) )
611 OUString sURL;
612 xSet->getPropertyValue(gsBookmark) >>= sURL;
614 if( !sURL.isEmpty() )
616 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sURL );
617 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
618 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
619 pHyperlinkElement.reset( new SvXMLElementExport(mrExport, XML_NAMESPACE_DRAW, XML_A, true, true) );
623 catch(const uno::Exception&)
625 TOOLS_WARN_EXCEPTION("xmloff", "XMLShapeExport::exportShape(): exception during hyperlink export");
628 else if (xSet.is() && !sHyperlink.isEmpty())
630 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sHyperlink );
631 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
632 pHyperlinkElement.reset( new SvXMLElementExport(mrExport, XML_NAMESPACE_DRAW, XML_A, true, true) );
634 // re-add stashed attributes
635 GetExport().AddAttributeList(xSaveAttribs);
637 if( xSet.is() )
638 xSet->getPropertyValue(gsZIndex) >>= nZIndex;
640 ImplXMLShapeExportInfoVector& aShapeInfoVector = (*maCurrentShapesIter).second;
642 if( static_cast<sal_Int32>(aShapeInfoVector.size()) <= nZIndex )
644 SAL_WARN( "xmloff", "XMLShapeExport::exportShape(): no shape info collected for a given shape" );
645 return;
648 NewTextListsHelper aNewTextListsHelper( mrExport );
650 const ImplXMLShapeExportInfo& aShapeInfo = aShapeInfoVector[nZIndex];
652 #ifdef DBG_UTIL
653 // check if this is the correct ShapesInfo
654 uno::Reference< container::XChild > xChild( xShape, uno::UNO_QUERY );
655 if( xChild.is() )
657 uno::Reference< drawing::XShapes > xParent( xChild->getParent(), uno::UNO_QUERY );
658 SAL_WARN_IF( !xParent.is() && xParent.get() == (*maCurrentShapesIter).first.get(), "xmloff", "XMLShapeExport::exportShape(): Wrong call to XMLShapeExport::seekShapes()" );
661 // first compute the shapes type
663 XmlShapeType eShapeType(XmlShapeType::NotYetSet);
664 ImpCalcShapeType(xShape, eShapeType);
666 SAL_WARN_IF( eShapeType != aShapeInfo.meShapeType, "xmloff", "exportShape callings do not correspond to collectShapeAutoStyles calls!: " << xShape->getShapeType() );
668 #endif
670 // collect animation information if needed
671 if( mxAnimationsExporter.is() )
672 mxAnimationsExporter->collect( xShape, mrExport );
674 /* Export shapes name if he has one (#i51726#)
675 Export of the shape name for text documents only if the OpenDocument
676 file format is written - exceptions are group shapes.
677 Note: Writer documents in OpenOffice.org file format doesn't contain
678 any names for shapes, except for group shapes.
681 if ( ( GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITER &&
682 GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITERWEB &&
683 GetExport().GetModelType() != SvtModuleOptions::EFactory::WRITERGLOBAL ) ||
684 ( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) ||
685 aShapeInfo.meShapeType == XmlShapeType::DrawGroupShape ||
686 ( aShapeInfo.meShapeType == XmlShapeType::DrawCustomShape &&
687 aShapeInfo.xCustomShapeReplacement.is() ) )
689 uno::Reference< container::XNamed > xNamed( xShape, uno::UNO_QUERY );
690 if( xNamed.is() )
692 const OUString aName( xNamed->getName() );
693 if( !aName.isEmpty() )
694 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_NAME, aName );
699 // export style name
700 if( !aShapeInfo.msStyleName.isEmpty() )
702 if(XmlStyleFamily::SD_GRAPHICS_ID == aShapeInfo.mnFamily)
703 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_STYLE_NAME, mrExport.EncodeStyleName( aShapeInfo.msStyleName) );
704 else
705 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_STYLE_NAME, mrExport.EncodeStyleName( aShapeInfo.msStyleName) );
708 // export text style name
709 if( !aShapeInfo.msTextStyleName.isEmpty() )
711 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TEXT_STYLE_NAME, aShapeInfo.msTextStyleName );
714 // export shapes id if needed
716 uno::Reference< uno::XInterface > xRef( xShape, uno::UNO_QUERY );
717 const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRef );
718 if( !rShapeId.isEmpty() )
720 mrExport.AddAttributeIdLegacy(XML_NAMESPACE_DRAW, rShapeId);
724 // export layer information
725 if( mbExportLayer )
727 // check for group or scene shape and not export layer if this is one
728 uno::Reference< drawing::XShapes > xShapes( xShape, uno::UNO_QUERY );
729 if( !xShapes.is() )
733 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
734 OUString aLayerName;
735 xProps->getPropertyValue("LayerName") >>= aLayerName;
736 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_LAYER, aLayerName );
739 catch(const uno::Exception&)
741 DBG_UNHANDLED_EXCEPTION( "xmloff", "exporting layer name for shape" );
746 // export draw:display (do not export in ODF 1.3 or older)
747 if (xSet.is() && (mrExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED))
749 if( aShapeInfo.meShapeType != XmlShapeType::DrawPageShape && aShapeInfo.meShapeType != XmlShapeType::PresPageShape &&
750 aShapeInfo.meShapeType != XmlShapeType::HandoutShape && aShapeInfo.meShapeType != XmlShapeType::DrawChartShape )
753 bool bVisible = true;
754 bool bPrintable = true;
756 xSet->getPropertyValue(gsVisible) >>= bVisible;
757 xSet->getPropertyValue(gsPrintable) >>= bPrintable;
759 XMLTokenEnum eDisplayToken = XML_TOKEN_INVALID;
760 const unsigned short nDisplay = (bVisible ? 2 : 0) | (bPrintable ? 1 : 0);
761 switch( nDisplay )
763 case 0: eDisplayToken = XML_NONE; break;
764 case 1: eDisplayToken = XML_PRINTER; break;
765 case 2: eDisplayToken = XML_SCREEN; break;
766 // case 3: eDisplayToken = XML_ALWAYS break; this is the default
769 if( eDisplayToken != XML_TOKEN_INVALID )
770 mrExport.AddAttribute(XML_NAMESPACE_DRAW_EXT, XML_DISPLAY, eDisplayToken );
772 catch(const uno::Exception&)
774 DBG_UNHANDLED_EXCEPTION("xmloff.draw");
778 // #82003# test export count
779 // #91587# ALWAYS increment since now ALL to be exported shapes are counted.
780 if(mrExport.GetShapeExport()->IsHandleProgressBarEnabled())
782 mrExport.GetProgressBarHelper()->Increment();
785 onExport( xShape );
787 // export shape element
788 switch(aShapeInfo.meShapeType)
790 case XmlShapeType::DrawRectangleShape:
792 ImpExportRectangleShape(xShape, nFeatures, pRefPoint );
793 break;
795 case XmlShapeType::DrawEllipseShape:
797 ImpExportEllipseShape(xShape, nFeatures, pRefPoint );
798 break;
800 case XmlShapeType::DrawLineShape:
802 ImpExportLineShape(xShape, nFeatures, pRefPoint );
803 break;
805 case XmlShapeType::DrawPolyPolygonShape: // closed PolyPolygon
806 case XmlShapeType::DrawPolyLineShape: // open PolyPolygon
807 case XmlShapeType::DrawClosedBezierShape: // closed tools::PolyPolygon containing curves
808 case XmlShapeType::DrawOpenBezierShape: // open tools::PolyPolygon containing curves
810 ImpExportPolygonShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
811 break;
814 case XmlShapeType::DrawTextShape:
815 case XmlShapeType::PresTitleTextShape:
816 case XmlShapeType::PresOutlinerShape:
817 case XmlShapeType::PresSubtitleShape:
818 case XmlShapeType::PresNotesShape:
819 case XmlShapeType::PresHeaderShape:
820 case XmlShapeType::PresFooterShape:
821 case XmlShapeType::PresSlideNumberShape:
822 case XmlShapeType::PresDateTimeShape:
824 ImpExportTextBoxShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
825 break;
828 case XmlShapeType::DrawGraphicObjectShape:
829 case XmlShapeType::PresGraphicObjectShape:
831 ImpExportGraphicObjectShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
832 break;
835 case XmlShapeType::DrawChartShape:
836 case XmlShapeType::PresChartShape:
838 ImpExportChartShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint, pAttrList );
839 break;
842 case XmlShapeType::DrawControlShape:
844 ImpExportControlShape(xShape, nFeatures, pRefPoint );
845 break;
848 case XmlShapeType::DrawConnectorShape:
850 ImpExportConnectorShape(xShape, nFeatures, pRefPoint );
851 break;
854 case XmlShapeType::DrawMeasureShape:
856 ImpExportMeasureShape(xShape, nFeatures, pRefPoint );
857 break;
860 case XmlShapeType::DrawOLE2Shape:
861 case XmlShapeType::PresOLE2Shape:
862 case XmlShapeType::DrawSheetShape:
863 case XmlShapeType::PresSheetShape:
865 ImpExportOLE2Shape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
866 break;
869 case XmlShapeType::PresTableShape:
870 case XmlShapeType::DrawTableShape:
872 ImpExportTableShape( xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
873 break;
876 case XmlShapeType::DrawPageShape:
877 case XmlShapeType::PresPageShape:
878 case XmlShapeType::HandoutShape:
880 ImpExportPageShape(xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
881 break;
884 case XmlShapeType::DrawCaptionShape:
886 ImpExportCaptionShape(xShape, nFeatures, pRefPoint );
887 break;
890 case XmlShapeType::Draw3DCubeObject:
891 case XmlShapeType::Draw3DSphereObject:
892 case XmlShapeType::Draw3DLatheObject:
893 case XmlShapeType::Draw3DExtrudeObject:
895 ImpExport3DShape(xShape, aShapeInfo.meShapeType);
896 break;
899 case XmlShapeType::Draw3DSceneObject:
901 ImpExport3DSceneShape( xShape, nFeatures, pRefPoint );
902 break;
905 case XmlShapeType::DrawGroupShape:
907 // empty group
908 ImpExportGroupShape( xShape, nFeatures, pRefPoint );
909 break;
912 case XmlShapeType::DrawFrameShape:
914 ImpExportFrameShape(xShape, nFeatures, pRefPoint );
915 break;
918 case XmlShapeType::DrawAppletShape:
920 ImpExportAppletShape(xShape, nFeatures, pRefPoint );
921 break;
924 case XmlShapeType::DrawPluginShape:
926 ImpExportPluginShape(xShape, nFeatures, pRefPoint );
927 break;
930 case XmlShapeType::DrawCustomShape:
932 if ( aShapeInfo.xCustomShapeReplacement.is() )
933 ImpExportGroupShape( aShapeInfo.xCustomShapeReplacement, nFeatures, pRefPoint );
934 else
935 ImpExportCustomShape( xShape, nFeatures, pRefPoint );
936 break;
939 case XmlShapeType::PresMediaShape:
940 case XmlShapeType::DrawMediaShape:
942 ImpExportMediaShape( xShape, aShapeInfo.meShapeType, nFeatures, pRefPoint );
943 break;
946 case XmlShapeType::PresOrgChartShape:
947 case XmlShapeType::Unknown:
948 case XmlShapeType::NotYetSet:
949 default:
951 // this should never happen and is an error
952 OSL_FAIL("XMLEXP: WriteShape: unknown or unexpected type of shape in export!");
953 break;
957 pHyperlinkElement.reset();
959 // #97489# #97111#
960 // if there was an error and no element for the shape was exported
961 // we need to clear the attribute list or the attributes will be
962 // set on the next exported element, which can result in corrupt
963 // xml files due to duplicate attributes
965 mrExport.CheckAttrList(); // asserts in non pro if we have attributes left
966 mrExport.ClearAttrList(); // clears the attributes
969 // This method collects all automatic styles for the shapes inside the given XShapes collection
970 void XMLShapeExport::collectShapesAutoStyles( const uno::Reference < drawing::XShapes >& xShapes )
972 ShapesInfos::iterator aOldCurrentShapesIter = maCurrentShapesIter;
973 seekShapes( xShapes );
975 uno::Reference< drawing::XShape > xShape;
976 const sal_Int32 nShapeCount(xShapes->getCount());
977 for(sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++)
979 xShapes->getByIndex(nShapeId) >>= xShape;
980 SAL_WARN_IF( !xShape.is(), "xmloff", "Shape without a XShape?" );
981 if(!xShape.is())
982 continue;
984 collectShapeAutoStyles( xShape );
987 maCurrentShapesIter = aOldCurrentShapesIter;
990 // This method exports all XShape inside the given XShapes collection
991 void XMLShapeExport::exportShapes( const uno::Reference < drawing::XShapes >& xShapes, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */ )
993 ShapesInfos::iterator aOldCurrentShapesIter = maCurrentShapesIter;
994 seekShapes( xShapes );
996 uno::Reference< drawing::XShape > xShape;
997 const sal_Int32 nShapeCount(xShapes->getCount());
998 for(sal_Int32 nShapeId = 0; nShapeId < nShapeCount; nShapeId++)
1000 xShapes->getByIndex(nShapeId) >>= xShape;
1001 SAL_WARN_IF( !xShape.is(), "xmloff", "Shape without a XShape?" );
1002 if(!xShape.is())
1003 continue;
1005 exportShape( xShape, nFeatures, pRefPoint );
1008 maCurrentShapesIter = aOldCurrentShapesIter;
1011 namespace xmloff {
1013 void FixZOrder(uno::Reference<drawing::XShapes> const& xShapes,
1014 std::function<unsigned int (uno::Reference<beans::XPropertySet> const&)> const& rGetLayer)
1016 uno::Reference<drawing::XShapes3> const xShapes3(xShapes, uno::UNO_QUERY);
1017 assert(xShapes3.is());
1018 if (!xShapes3.is())
1020 return; // only SvxDrawPage implements this
1022 struct Layer { std::vector<sal_Int32> shapes; sal_Int32 nMin = SAL_MAX_INT32; sal_Int32 nMax = 0; };
1023 std::vector<Layer> layers;
1024 // shapes are sorted by ZOrder
1025 sal_Int32 const nCount(xShapes->getCount());
1026 for (sal_Int32 i = 0; i < nCount; ++i)
1028 uno::Reference<beans::XPropertySet> const xShape(xShapes->getByIndex(i), uno::UNO_QUERY);
1029 if (!xShape.is())
1031 SAL_WARN("xmloff", "FixZOrder: null shape, cannot sort");
1032 return;
1034 unsigned int const nLayer(rGetLayer(xShape));
1035 if (layers.size() <= nLayer)
1037 layers.resize(nLayer + 1);
1039 layers[nLayer].shapes.emplace_back(i);
1040 if (i < layers[nLayer].nMin)
1042 layers[nLayer].nMin = i;
1044 if (layers[nLayer].nMax < i)
1046 layers[nLayer].nMax = i;
1049 layers.erase(std::remove_if(layers.begin(), layers.end(),
1050 [](Layer const& rLayer) { return rLayer.shapes.empty(); }),
1051 layers.end());
1052 bool isSorted(true);
1053 for (size_t i = 1; i < layers.size(); ++i)
1055 assert(layers[i].nMin != layers[i-1].nMax); // unique!
1056 if (layers[i].nMin < layers[i-1].nMax)
1058 isSorted = false;
1059 break;
1062 if (isSorted)
1064 return; // nothing to do
1066 uno::Sequence<sal_Int32> aNewOrder(nCount);
1067 auto iterInsert(aNewOrder.getArray());
1068 for (auto const& rLayer : layers)
1070 assert(rLayer.nMin <= rLayer.nMax); // empty layers have been removed
1071 iterInsert = std::copy(rLayer.shapes.begin(), rLayer.shapes.end(), iterInsert);
1075 xShapes3->sort(aNewOrder);
1077 catch (uno::Exception const&)
1079 SAL_WARN("xmloff", "FixZOrder: exception");
1083 } // namespace xmloff
1085 void XMLShapeExport::seekShapes( const uno::Reference< drawing::XShapes >& xShapes ) noexcept
1087 if( xShapes.is() )
1089 maCurrentShapesIter = maShapesInfos.find( xShapes );
1090 if( maCurrentShapesIter == maShapesInfos.end() )
1092 auto itPair = maShapesInfos.emplace( xShapes, ImplXMLShapeExportInfoVector( static_cast<ShapesInfos::size_type>(xShapes->getCount()) ) );
1094 maCurrentShapesIter = itPair.first;
1096 SAL_WARN_IF( maCurrentShapesIter == maShapesInfos.end(), "xmloff", "XMLShapeExport::seekShapes(): insert into stl::map failed" );
1099 SAL_WARN_IF( (*maCurrentShapesIter).second.size() != static_cast<ShapesInfos::size_type>(xShapes->getCount()), "xmloff", "XMLShapeExport::seekShapes(): XShapes size varied between calls" );
1102 else
1104 maCurrentShapesIter = maShapesInfos.end();
1108 void XMLShapeExport::exportAutoStyles()
1110 // export all autostyle infos
1112 // ...for graphic
1114 GetExport().GetAutoStylePool()->exportXML( XmlStyleFamily::SD_GRAPHICS_ID );
1117 // ...for presentation
1119 GetExport().GetAutoStylePool()->exportXML( XmlStyleFamily::SD_PRESENTATION_ID );
1122 if( mxShapeTableExport.is() )
1123 mxShapeTableExport->exportAutoStyles();
1126 /// returns the export property mapper for external chaining
1127 SvXMLExportPropertyMapper* XMLShapeExport::CreateShapePropMapper(
1128 SvXMLExport& rExport )
1130 rtl::Reference< XMLPropertyHandlerFactory > xFactory = new XMLSdPropHdlFactory( rExport.GetModel(), rExport );
1131 rtl::Reference < XMLPropertySetMapper > xMapper = new XMLShapePropertySetMapper( xFactory, true );
1132 rExport.GetTextParagraphExport(); // get or create text paragraph export
1133 SvXMLExportPropertyMapper* pResult =
1134 new XMLShapeExportPropertyMapper( xMapper, rExport );
1135 // chain text attributes
1136 return pResult;
1139 void XMLShapeExport::ImpCalcShapeType(const uno::Reference< drawing::XShape >& xShape,
1140 XmlShapeType& eShapeType)
1142 // set in every case, so init here
1143 eShapeType = XmlShapeType::Unknown;
1145 if(!xShape.is())
1146 return;
1148 OUString aType(xShape->getShapeType());
1150 if(!aType.match("com.sun.star."))
1151 return;
1153 if(aType.match("drawing.", 13))
1155 // drawing shapes
1156 if (aType.match("Rectangle", 21)) { eShapeType = XmlShapeType::DrawRectangleShape; }
1158 // #i72177# Note: Correcting CustomShape, CustomShape->Custom, len from 9 (was wrong anyways) to 6.
1159 // As can be seen at the other compares, the appendix "Shape" is left out of the comparison.
1160 else if(aType.match("Custom", 21)) { eShapeType = XmlShapeType::DrawCustomShape; }
1162 else if(aType.match("Ellipse", 21)) { eShapeType = XmlShapeType::DrawEllipseShape; }
1163 else if(aType.match("Control", 21)) { eShapeType = XmlShapeType::DrawControlShape; }
1164 else if(aType.match("Connector", 21)) { eShapeType = XmlShapeType::DrawConnectorShape; }
1165 else if(aType.match("Measure", 21)) { eShapeType = XmlShapeType::DrawMeasureShape; }
1166 else if(aType.match("Line", 21)) { eShapeType = XmlShapeType::DrawLineShape; }
1168 // #i72177# Note: This covers two types by purpose, PolyPolygonShape and PolyPolygonPathShape
1169 else if(aType.match("PolyPolygon", 21)) { eShapeType = XmlShapeType::DrawPolyPolygonShape; }
1171 // #i72177# Note: This covers two types by purpose, PolyLineShape and PolyLinePathShape
1172 else if(aType.match("PolyLine", 21)) { eShapeType = XmlShapeType::DrawPolyLineShape; }
1174 else if(aType.match("OpenBezier", 21)) { eShapeType = XmlShapeType::DrawOpenBezierShape; }
1175 else if(aType.match("ClosedBezier", 21)) { eShapeType = XmlShapeType::DrawClosedBezierShape; }
1177 // #i72177# FreeHand (opened and closed) now supports the types OpenFreeHandShape and
1178 // ClosedFreeHandShape respectively. Represent them as bezier shapes
1179 else if(aType.match("OpenFreeHand", 21)) { eShapeType = XmlShapeType::DrawOpenBezierShape; }
1180 else if(aType.match("ClosedFreeHand", 21)) { eShapeType = XmlShapeType::DrawClosedBezierShape; }
1182 else if(aType.match("GraphicObject", 21)) { eShapeType = XmlShapeType::DrawGraphicObjectShape; }
1183 else if(aType.match("Group", 21)) { eShapeType = XmlShapeType::DrawGroupShape; }
1184 else if(aType.match("Text", 21)) { eShapeType = XmlShapeType::DrawTextShape; }
1185 else if(aType.match("OLE2", 21))
1187 eShapeType = XmlShapeType::DrawOLE2Shape;
1189 // get info about presentation shape
1190 uno::Reference <beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1192 if(xPropSet.is())
1194 OUString sCLSID;
1195 if(xPropSet->getPropertyValue("CLSID") >>= sCLSID)
1197 #if !ENABLE_WASM_STRIP_CHART
1198 // WASM_CHART change
1199 // TODO: With Chart extracted this cannot really happen since
1200 // no Chart could've been added at all
1201 if (sCLSID == mrExport.GetChartExport()->getChartCLSID() ||
1202 #else
1204 #endif
1205 sCLSID == SvGlobalName( SO3_RPTCH_CLASSID ).GetHexName() )
1207 eShapeType = XmlShapeType::DrawChartShape;
1209 else if (sCLSID == SvGlobalName( SO3_SC_CLASSID ).GetHexName() )
1211 eShapeType = XmlShapeType::DrawSheetShape;
1213 else
1215 // general OLE2 Object
1220 else if(aType.match("Page", 21)) { eShapeType = XmlShapeType::DrawPageShape; }
1221 else if(aType.match("Frame", 21)) { eShapeType = XmlShapeType::DrawFrameShape; }
1222 else if(aType.match("Caption", 21)) { eShapeType = XmlShapeType::DrawCaptionShape; }
1223 else if(aType.match("Plugin", 21)) { eShapeType = XmlShapeType::DrawPluginShape; }
1224 else if(aType.match("Applet", 21)) { eShapeType = XmlShapeType::DrawAppletShape; }
1225 else if(aType.match("MediaShape", 21)) { eShapeType = XmlShapeType::DrawMediaShape; }
1226 else if(aType.match("TableShape", 21)) { eShapeType = XmlShapeType::DrawTableShape; }
1228 // 3D shapes
1229 else if(aType.match("Scene", 21 + 7)) { eShapeType = XmlShapeType::Draw3DSceneObject; }
1230 else if(aType.match("Cube", 21 + 7)) { eShapeType = XmlShapeType::Draw3DCubeObject; }
1231 else if(aType.match("Sphere", 21 + 7)) { eShapeType = XmlShapeType::Draw3DSphereObject; }
1232 else if(aType.match("Lathe", 21 + 7)) { eShapeType = XmlShapeType::Draw3DLatheObject; }
1233 else if(aType.match("Extrude", 21 + 7)) { eShapeType = XmlShapeType::Draw3DExtrudeObject; }
1235 else if(aType.match("presentation.", 13))
1237 // presentation shapes
1238 if (aType.match("TitleText", 26)) { eShapeType = XmlShapeType::PresTitleTextShape; }
1239 else if(aType.match("Outliner", 26)) { eShapeType = XmlShapeType::PresOutlinerShape; }
1240 else if(aType.match("Subtitle", 26)) { eShapeType = XmlShapeType::PresSubtitleShape; }
1241 else if(aType.match("GraphicObject", 26)) { eShapeType = XmlShapeType::PresGraphicObjectShape; }
1242 else if(aType.match("Page", 26)) { eShapeType = XmlShapeType::PresPageShape; }
1243 else if(aType.match("OLE2", 26))
1245 eShapeType = XmlShapeType::PresOLE2Shape;
1247 // get info about presentation shape
1248 uno::Reference <beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1250 if(xPropSet.is()) try
1252 OUString sCLSID;
1253 if(xPropSet->getPropertyValue("CLSID") >>= sCLSID)
1255 if( sCLSID == SvGlobalName( SO3_SC_CLASSID ).GetHexName() )
1257 eShapeType = XmlShapeType::PresSheetShape;
1261 catch(const uno::Exception&)
1263 SAL_WARN( "xmloff", "XMLShapeExport::ImpCalcShapeType(), expected ole shape to have the CLSID property?" );
1266 else if(aType.match("Chart", 26)) { eShapeType = XmlShapeType::PresChartShape; }
1267 else if(aType.match("OrgChart", 26)) { eShapeType = XmlShapeType::PresOrgChartShape; }
1268 else if(aType.match("CalcShape", 26)) { eShapeType = XmlShapeType::PresSheetShape; }
1269 else if(aType.match("TableShape", 26)) { eShapeType = XmlShapeType::PresTableShape; }
1270 else if(aType.match("Notes", 26)) { eShapeType = XmlShapeType::PresNotesShape; }
1271 else if(aType.match("HandoutShape", 26)) { eShapeType = XmlShapeType::HandoutShape; }
1272 else if(aType.match("HeaderShape", 26)) { eShapeType = XmlShapeType::PresHeaderShape; }
1273 else if(aType.match("FooterShape", 26)) { eShapeType = XmlShapeType::PresFooterShape; }
1274 else if(aType.match("SlideNumberShape", 26)) { eShapeType = XmlShapeType::PresSlideNumberShape; }
1275 else if(aType.match("DateTimeShape", 26)) { eShapeType = XmlShapeType::PresDateTimeShape; }
1276 else if(aType.match("MediaShape", 26)) { eShapeType = XmlShapeType::PresMediaShape; }
1280 /** exports all user defined gluepoints */
1281 void XMLShapeExport::ImpExportGluePoints( const uno::Reference< drawing::XShape >& xShape )
1283 uno::Reference< drawing::XGluePointsSupplier > xSupplier( xShape, uno::UNO_QUERY );
1284 if( !xSupplier.is() )
1285 return;
1287 uno::Reference< container::XIdentifierAccess > xGluePoints( xSupplier->getGluePoints(), uno::UNO_QUERY );
1288 if( !xGluePoints.is() )
1289 return;
1291 drawing::GluePoint2 aGluePoint;
1293 const uno::Sequence< sal_Int32 > aIdSequence( xGluePoints->getIdentifiers() );
1295 for( const sal_Int32 nIdentifier : aIdSequence )
1297 if( (xGluePoints->getByIdentifier( nIdentifier ) >>= aGluePoint) && aGluePoint.IsUserDefined )
1299 // export only user defined gluepoints
1301 const OUString sId( OUString::number( nIdentifier ) );
1302 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_ID, sId );
1304 mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
1305 aGluePoint.Position.X);
1306 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, msBuffer.makeStringAndClear());
1308 mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
1309 aGluePoint.Position.Y);
1310 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, msBuffer.makeStringAndClear());
1312 if( !aGluePoint.IsRelative )
1314 SvXMLUnitConverter::convertEnum( msBuffer, aGluePoint.PositionAlignment, aXML_GlueAlignment_EnumMap );
1315 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ALIGN, msBuffer.makeStringAndClear() );
1318 if( aGluePoint.Escape != drawing::EscapeDirection_SMART )
1320 SvXMLUnitConverter::convertEnum( msBuffer, aGluePoint.Escape, aXML_GlueEscapeDirection_EnumMap );
1321 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ESCAPE_DIRECTION, msBuffer.makeStringAndClear() );
1324 SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_DRAW, XML_GLUE_POINT, true, true);
1329 void XMLShapeExport::ImpExportSignatureLine(const uno::Reference<drawing::XShape>& xShape)
1331 uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1333 bool bIsSignatureLine = false;
1334 xPropSet->getPropertyValue("IsSignatureLine") >>= bIsSignatureLine;
1335 if (!bIsSignatureLine)
1336 return;
1338 OUString aSignatureLineId;
1339 xPropSet->getPropertyValue("SignatureLineId") >>= aSignatureLineId;
1340 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_ID, aSignatureLineId);
1342 OUString aSuggestedSignerName;
1343 xPropSet->getPropertyValue("SignatureLineSuggestedSignerName") >>= aSuggestedSignerName;
1344 if (!aSuggestedSignerName.isEmpty())
1345 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_NAME, aSuggestedSignerName);
1347 OUString aSuggestedSignerTitle;
1348 xPropSet->getPropertyValue("SignatureLineSuggestedSignerTitle") >>= aSuggestedSignerTitle;
1349 if (!aSuggestedSignerTitle.isEmpty())
1350 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_TITLE, aSuggestedSignerTitle);
1352 OUString aSuggestedSignerEmail;
1353 xPropSet->getPropertyValue("SignatureLineSuggestedSignerEmail") >>= aSuggestedSignerEmail;
1354 if (!aSuggestedSignerEmail.isEmpty())
1355 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SUGGESTED_SIGNER_EMAIL, aSuggestedSignerEmail);
1357 OUString aSigningInstructions;
1358 xPropSet->getPropertyValue("SignatureLineSigningInstructions") >>= aSigningInstructions;
1359 if (!aSigningInstructions.isEmpty())
1360 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SIGNING_INSTRUCTIONS, aSigningInstructions);
1362 bool bShowSignDate = false;
1363 xPropSet->getPropertyValue("SignatureLineShowSignDate") >>= bShowSignDate;
1364 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_SHOW_SIGN_DATE,
1365 bShowSignDate ? XML_TRUE : XML_FALSE);
1367 bool bCanAddComment = false;
1368 xPropSet->getPropertyValue("SignatureLineCanAddComment") >>= bCanAddComment;
1369 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_CAN_ADD_COMMENT,
1370 bCanAddComment ? XML_TRUE : XML_FALSE);
1372 SvXMLElementExport aSignatureLineElement(mrExport, XML_NAMESPACE_LO_EXT, XML_SIGNATURELINE, true,
1373 true);
1376 void XMLShapeExport::ImpExportQRCode(const uno::Reference<drawing::XShape>& xShape)
1378 uno::Reference<beans::XPropertySet> xPropSet(xShape, uno::UNO_QUERY);
1380 uno::Any aAny = xPropSet->getPropertyValue("BarCodeProperties");
1382 css::drawing::BarCode aBarCode;
1383 if(!(aAny >>= aBarCode))
1384 return;
1386 mrExport.AddAttribute(XML_NAMESPACE_OFFICE, XML_STRING_VALUE, aBarCode.Payload);
1387 /* Export QR Code as per customised schema, @see OpenDocument-schema-v1.3+libreoffice */
1388 OUString temp;
1389 switch(aBarCode.ErrorCorrection){
1390 case css::drawing::BarCodeErrorCorrection::LOW :
1391 temp = "low";
1392 break;
1393 case css::drawing::BarCodeErrorCorrection::MEDIUM:
1394 temp = "medium";
1395 break;
1396 case css::drawing::BarCodeErrorCorrection::QUARTILE:
1397 temp = "quartile";
1398 break;
1399 case css::drawing::BarCodeErrorCorrection::HIGH:
1400 temp = "high";
1401 break;
1403 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_ERROR_CORRECTION, temp);
1404 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_BORDER, OUStringBuffer(20).append(aBarCode.Border).makeStringAndClear());
1405 mrExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_QRCODE_TYPE, OUStringBuffer(20).append(aBarCode.Type).makeStringAndClear());
1407 SvXMLElementExport aBarCodeElement(mrExport, XML_NAMESPACE_LO_EXT, XML_QRCODE, true,
1408 true);
1411 void XMLShapeExport::ExportGraphicDefaults()
1413 rtl::Reference<XMLStyleExport> aStEx(new XMLStyleExport(mrExport, mrExport.GetAutoStylePool().get()));
1415 // construct PropertySetMapper
1416 rtl::Reference< SvXMLExportPropertyMapper > xPropertySetMapper( CreateShapePropMapper( mrExport ) );
1417 static_cast<XMLShapeExportPropertyMapper*>(xPropertySetMapper.get())->SetAutoStyles( false );
1419 // chain text attributes
1420 xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaExtPropMapper(mrExport));
1422 // chain special Writer/text frame default attributes
1423 xPropertySetMapper->ChainExportMapper(XMLTextParagraphExport::CreateParaDefaultExtPropMapper(mrExport));
1425 // write graphic family default style
1426 uno::Reference< lang::XMultiServiceFactory > xFact( mrExport.GetModel(), uno::UNO_QUERY );
1427 if( !xFact.is() )
1428 return;
1432 uno::Reference< beans::XPropertySet > xDefaults( xFact->createInstance("com.sun.star.drawing.Defaults"), uno::UNO_QUERY );
1433 if( xDefaults.is() )
1435 aStEx->exportDefaultStyle( xDefaults, XML_STYLE_FAMILY_SD_GRAPHICS_NAME, xPropertySetMapper );
1437 // write graphic styles (family name differs depending on the module)
1438 aStEx->exportStyleFamily("graphics", OUString(XML_STYLE_FAMILY_SD_GRAPHICS_NAME), xPropertySetMapper, false, XmlStyleFamily::SD_GRAPHICS_ID);
1439 aStEx->exportStyleFamily("GraphicStyles", OUString(XML_STYLE_FAMILY_SD_GRAPHICS_NAME), xPropertySetMapper, false, XmlStyleFamily::SD_GRAPHICS_ID);
1442 catch(const lang::ServiceNotRegisteredException&)
1447 void XMLShapeExport::onExport( const css::uno::Reference < css::drawing::XShape >& )
1451 const rtl::Reference< XMLTableExport >& XMLShapeExport::GetShapeTableExport()
1453 if( !mxShapeTableExport.is() )
1455 rtl::Reference< XMLPropertyHandlerFactory > xFactory( new XMLSdPropHdlFactory( mrExport.GetModel(), mrExport ) );
1456 rtl::Reference < XMLPropertySetMapper > xMapper( new XMLShapePropertySetMapper( xFactory, true ) );
1457 mrExport.GetTextParagraphExport(); // get or create text paragraph export
1458 rtl::Reference< SvXMLExportPropertyMapper > xPropertySetMapper( new XMLShapeExportPropertyMapper( xMapper, mrExport ) );
1459 mxShapeTableExport = new XMLTableExport( mrExport, xPropertySetMapper, xFactory );
1462 return mxShapeTableExport;
1465 void XMLShapeExport::ImpExportNewTrans(const uno::Reference< beans::XPropertySet >& xPropSet,
1466 XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
1468 // get matrix
1469 ::basegfx::B2DHomMatrix aMatrix;
1470 ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
1472 // decompose and correct about pRefPoint
1473 ::basegfx::B2DTuple aTRScale;
1474 double fTRShear(0.0);
1475 double fTRRotate(0.0);
1476 ::basegfx::B2DTuple aTRTranslate;
1477 ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
1479 // use features and write
1480 ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures);
1483 void XMLShapeExport::ImpExportNewTrans_GetB2DHomMatrix(::basegfx::B2DHomMatrix& rMatrix,
1484 const uno::Reference< beans::XPropertySet >& xPropSet)
1486 /* Get <TransformationInHoriL2R>, if it exist
1487 and if the document is exported into the OpenOffice.org file format.
1488 This property only exists at service css::text::Shape - the
1489 Writer UNO service for shapes.
1490 This code is needed, because the positioning attributes in the
1491 OpenOffice.org file format are given in horizontal left-to-right layout
1492 regardless the layout direction the shape is in. In the OASIS Open Office
1493 file format the positioning attributes are correctly given in the layout
1494 direction the shape is in. Thus, this code provides the conversion from
1495 the OASIS Open Office file format to the OpenOffice.org file format. (#i28749#)
1497 uno::Any aAny;
1498 if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
1499 xPropSet->getPropertySetInfo()->hasPropertyByName("TransformationInHoriL2R") )
1501 aAny = xPropSet->getPropertyValue("TransformationInHoriL2R");
1503 else
1505 aAny = xPropSet->getPropertyValue("Transformation");
1507 drawing::HomogenMatrix3 aMatrix;
1508 aAny >>= aMatrix;
1510 rMatrix.set(0, 0, aMatrix.Line1.Column1);
1511 rMatrix.set(0, 1, aMatrix.Line1.Column2);
1512 rMatrix.set(0, 2, aMatrix.Line1.Column3);
1513 rMatrix.set(1, 0, aMatrix.Line2.Column1);
1514 rMatrix.set(1, 1, aMatrix.Line2.Column2);
1515 rMatrix.set(1, 2, aMatrix.Line2.Column3);
1516 // For this to be a valid 2D transform matrix, the last row must be [0,0,1]
1517 assert( aMatrix.Line3.Column1 == 0 );
1518 assert( aMatrix.Line3.Column2 == 0 );
1519 assert( aMatrix.Line3.Column3 == 1 );
1522 void XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint(const ::basegfx::B2DHomMatrix& rMatrix, ::basegfx::B2DTuple& rTRScale,
1523 double& fTRShear, double& fTRRotate, ::basegfx::B2DTuple& rTRTranslate, css::awt::Point* pRefPoint)
1525 // decompose matrix
1526 rMatrix.decompose(rTRScale, rTRTranslate, fTRRotate, fTRShear);
1528 // correct translation about pRefPoint
1529 if(pRefPoint)
1531 rTRTranslate -= ::basegfx::B2DTuple(pRefPoint->X, pRefPoint->Y);
1535 void XMLShapeExport::ImpExportNewTrans_FeaturesAndWrite(::basegfx::B2DTuple const & rTRScale, double fTRShear,
1536 double fTRRotate, ::basegfx::B2DTuple const & rTRTranslate, const XMLShapeExportFlags nFeatures)
1538 // always write Size (rTRScale) since this statement carries the union
1539 // of the object
1540 OUString aStr;
1541 OUStringBuffer sStringBuffer;
1542 ::basegfx::B2DTuple aTRScale(rTRScale);
1544 // svg: width
1545 if(!(nFeatures & XMLShapeExportFlags::WIDTH))
1547 aTRScale.setX(1.0);
1549 else
1551 if( aTRScale.getX() > 0.0 )
1552 aTRScale.setX(aTRScale.getX() - 1.0);
1553 else if( aTRScale.getX() < 0.0 )
1554 aTRScale.setX(aTRScale.getX() + 1.0);
1557 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1558 FRound(aTRScale.getX()));
1559 aStr = sStringBuffer.makeStringAndClear();
1560 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_WIDTH, aStr);
1562 // svg: height
1563 if(!(nFeatures & XMLShapeExportFlags::HEIGHT))
1565 aTRScale.setY(1.0);
1567 else
1569 if( aTRScale.getY() > 0.0 )
1570 aTRScale.setY(aTRScale.getY() - 1.0);
1571 else if( aTRScale.getY() < 0.0 )
1572 aTRScale.setY(aTRScale.getY() + 1.0);
1575 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1576 FRound(aTRScale.getY()));
1577 aStr = sStringBuffer.makeStringAndClear();
1578 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_HEIGHT, aStr);
1580 // decide if transformation is necessary
1581 bool bTransformationIsNecessary(fTRShear != 0.0 || fTRRotate != 0.0);
1583 if(bTransformationIsNecessary)
1585 // write transformation, but WITHOUT scale which is exported as size above
1586 SdXMLImExTransform2D aTransform;
1588 aTransform.AddSkewX(atan(fTRShear));
1590 // #i78696#
1591 // fTRRotate is mathematically correct, but due to the error
1592 // we export/import it mirrored. Since the API implementation is fixed and
1593 // uses the correctly oriented angle, it is necessary for compatibility to
1594 // mirror the angle here to stay at the old behaviour. There is a follow-up
1595 // task (#i78698#) to fix this in the next ODF FileFormat version
1596 aTransform.AddRotate(-fTRRotate);
1598 aTransform.AddTranslate(rTRTranslate);
1600 // does transformation need to be exported?
1601 if(aTransform.NeedsAction())
1602 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
1604 else
1606 // no shear, no rotate; just add object position to export and we are done
1607 if(nFeatures & XMLShapeExportFlags::X)
1609 // svg: x
1610 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1611 FRound(rTRTranslate.getX()));
1612 aStr = sStringBuffer.makeStringAndClear();
1613 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X, aStr);
1616 if(nFeatures & XMLShapeExportFlags::Y)
1618 // svg: y
1619 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
1620 FRound(rTRTranslate.getY()));
1621 aStr = sStringBuffer.makeStringAndClear();
1622 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y, aStr);
1627 bool XMLShapeExport::ImpExportPresentationAttributes( const uno::Reference< beans::XPropertySet >& xPropSet, const OUString& rClass )
1629 bool bIsEmpty = false;
1631 // write presentation class entry
1632 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS, rClass);
1634 if( xPropSet.is() )
1636 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
1639 // is empty pres. shape?
1640 if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsEmptyPresentationObject"))
1642 xPropSet->getPropertyValue("IsEmptyPresentationObject") >>= bIsEmpty;
1643 if( bIsEmpty )
1644 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_PLACEHOLDER, XML_TRUE);
1647 // is user-transformed?
1648 if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName("IsPlaceholderDependent"))
1650 bool bTemp = false;
1651 xPropSet->getPropertyValue("IsPlaceholderDependent") >>= bTemp;
1652 if(!bTemp)
1653 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_USER_TRANSFORMED, XML_TRUE);
1657 return bIsEmpty;
1660 void XMLShapeExport::ImpExportText( const uno::Reference< drawing::XShape >& xShape, TextPNS eExtensionNS )
1662 if (eExtensionNS == TextPNS::EXTENSION)
1664 if ((mrExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
1666 return; // do not export to ODF 1.1/1.2/1.3
1669 uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY );
1670 if( xText.is() )
1672 uno::Reference< container::XEnumerationAccess > xEnumAccess( xShape, uno::UNO_QUERY );
1673 if( xEnumAccess.is() && xEnumAccess->hasElements() )
1674 mrExport.GetTextParagraphExport()->exportText( xText, false, true, eExtensionNS );
1678 namespace {
1680 enum class Found {
1681 NONE = 0x0000,
1682 CLICKACTION = 0x0001,
1683 BOOKMARK = 0x0002,
1684 EFFECT = 0x0004,
1685 PLAYFULL = 0x0008,
1686 VERB = 0x0010,
1687 SOUNDURL = 0x0020,
1688 SPEED = 0x0040,
1689 CLICKEVENTTYPE = 0x0080,
1690 MACRO = 0x0100,
1691 LIBRARY = 0x0200,
1696 namespace o3tl {
1697 template<> struct typed_flags<Found> : is_typed_flags<Found, 0x03ff> {};
1700 void XMLShapeExport::ImpExportEvents( const uno::Reference< drawing::XShape >& xShape )
1702 uno::Reference< document::XEventsSupplier > xEventsSupplier( xShape, uno::UNO_QUERY );
1703 if( !xEventsSupplier.is() )
1704 return;
1706 uno::Reference< container::XNameAccess > xEvents = xEventsSupplier->getEvents();
1707 SAL_WARN_IF( !xEvents.is(), "xmloff", "XEventsSupplier::getEvents() returned NULL" );
1708 if( !xEvents.is() )
1709 return;
1711 Found nFound = Found::NONE;
1713 OUString aClickEventType;
1714 presentation::ClickAction eClickAction = presentation::ClickAction_NONE;
1715 presentation::AnimationEffect eEffect = presentation::AnimationEffect_NONE;
1716 presentation::AnimationSpeed eSpeed = presentation::AnimationSpeed_SLOW;
1717 OUString aStrSoundURL;
1718 bool bPlayFull = false;
1719 sal_Int32 nVerb = 0;
1720 OUString aStrMacro;
1721 OUString aStrLibrary;
1722 OUString aStrBookmark;
1724 uno::Sequence< beans::PropertyValue > aClickProperties;
1725 if( xEvents->hasByName( gsOnClick ) && (xEvents->getByName( gsOnClick ) >>= aClickProperties) )
1727 for( const auto& rProperty : std::as_const(aClickProperties) )
1729 if( !( nFound & Found::CLICKEVENTTYPE ) && rProperty.Name == gsEventType )
1731 if( rProperty.Value >>= aClickEventType )
1732 nFound |= Found::CLICKEVENTTYPE;
1734 else if( !( nFound & Found::CLICKACTION ) && rProperty.Name == gsClickAction )
1736 if( rProperty.Value >>= eClickAction )
1737 nFound |= Found::CLICKACTION;
1739 else if( !( nFound & Found::MACRO ) && ( rProperty.Name == gsMacroName || rProperty.Name == gsScript ) )
1741 if( rProperty.Value >>= aStrMacro )
1742 nFound |= Found::MACRO;
1744 else if( !( nFound & Found::LIBRARY ) && rProperty.Name == gsLibrary )
1746 if( rProperty.Value >>= aStrLibrary )
1747 nFound |= Found::LIBRARY;
1749 else if( !( nFound & Found::EFFECT ) && rProperty.Name == gsEffect )
1751 if( rProperty.Value >>= eEffect )
1752 nFound |= Found::EFFECT;
1754 else if( !( nFound & Found::BOOKMARK ) && rProperty.Name == gsBookmark )
1756 if( rProperty.Value >>= aStrBookmark )
1757 nFound |= Found::BOOKMARK;
1759 else if( !( nFound & Found::SPEED ) && rProperty.Name == gsSpeed )
1761 if( rProperty.Value >>= eSpeed )
1762 nFound |= Found::SPEED;
1764 else if( !( nFound & Found::SOUNDURL ) && rProperty.Name == gsSoundURL )
1766 if( rProperty.Value >>= aStrSoundURL )
1767 nFound |= Found::SOUNDURL;
1769 else if( !( nFound & Found::PLAYFULL ) && rProperty.Name == gsPlayFull )
1771 if( rProperty.Value >>= bPlayFull )
1772 nFound |= Found::PLAYFULL;
1774 else if( !( nFound & Found::VERB ) && rProperty.Name == gsVerb )
1776 if( rProperty.Value >>= nVerb )
1777 nFound |= Found::VERB;
1782 // create the XML elements
1784 if( aClickEventType == gsPresentation )
1786 if( !(nFound & Found::CLICKACTION) || (eClickAction == presentation::ClickAction_NONE) )
1787 return;
1789 SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
1791 enum XMLTokenEnum eStrAction;
1793 switch( eClickAction )
1795 case presentation::ClickAction_PREVPAGE: eStrAction = XML_PREVIOUS_PAGE; break;
1796 case presentation::ClickAction_NEXTPAGE: eStrAction = XML_NEXT_PAGE; break;
1797 case presentation::ClickAction_FIRSTPAGE: eStrAction = XML_FIRST_PAGE; break;
1798 case presentation::ClickAction_LASTPAGE: eStrAction = XML_LAST_PAGE; break;
1799 case presentation::ClickAction_INVISIBLE: eStrAction = XML_HIDE; break;
1800 case presentation::ClickAction_STOPPRESENTATION:eStrAction = XML_STOP; break;
1801 case presentation::ClickAction_PROGRAM: eStrAction = XML_EXECUTE; break;
1802 case presentation::ClickAction_BOOKMARK: eStrAction = XML_SHOW; break;
1803 case presentation::ClickAction_DOCUMENT: eStrAction = XML_SHOW; break;
1804 case presentation::ClickAction_MACRO: eStrAction = XML_EXECUTE_MACRO; break;
1805 case presentation::ClickAction_VERB: eStrAction = XML_VERB; break;
1806 case presentation::ClickAction_VANISH: eStrAction = XML_FADE_OUT; break;
1807 case presentation::ClickAction_SOUND: eStrAction = XML_SOUND; break;
1808 default:
1809 OSL_FAIL( "unknown presentation::ClickAction found!" );
1810 eStrAction = XML_UNKNOWN;
1813 OUString aEventQName(
1814 mrExport.GetNamespaceMap().GetQNameByKey(
1815 XML_NAMESPACE_DOM, "click" ) );
1816 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
1817 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_ACTION, eStrAction );
1819 if( eClickAction == presentation::ClickAction_VANISH )
1821 if( nFound & Found::EFFECT )
1823 XMLEffect eKind;
1824 XMLEffectDirection eDirection;
1825 sal_Int16 nStartScale;
1826 bool bIn;
1828 SdXMLImplSetEffect( eEffect, eKind, eDirection, nStartScale, bIn );
1830 if( eKind != EK_none )
1832 SvXMLUnitConverter::convertEnum( msBuffer, eKind, aXML_AnimationEffect_EnumMap );
1833 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_EFFECT, msBuffer.makeStringAndClear() );
1836 if( eDirection != ED_none )
1838 SvXMLUnitConverter::convertEnum( msBuffer, eDirection, aXML_AnimationDirection_EnumMap );
1839 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_DIRECTION, msBuffer.makeStringAndClear() );
1842 if( nStartScale != -1 )
1844 ::sax::Converter::convertPercent( msBuffer, nStartScale );
1845 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_START_SCALE, msBuffer.makeStringAndClear() );
1849 if( nFound & Found::SPEED && eEffect != presentation::AnimationEffect_NONE )
1851 if( eSpeed != presentation::AnimationSpeed_MEDIUM )
1853 SvXMLUnitConverter::convertEnum( msBuffer, eSpeed, aXML_AnimationSpeed_EnumMap );
1854 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_SPEED, msBuffer.makeStringAndClear() );
1859 if( eClickAction == presentation::ClickAction_PROGRAM ||
1860 eClickAction == presentation::ClickAction_BOOKMARK ||
1861 eClickAction == presentation::ClickAction_DOCUMENT )
1863 if( eClickAction == presentation::ClickAction_BOOKMARK )
1864 msBuffer.append( '#' );
1866 msBuffer.append( aStrBookmark );
1867 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(msBuffer.makeStringAndClear()) );
1868 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
1869 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
1870 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST );
1873 if( ( nFound & Found::VERB ) && eClickAction == presentation::ClickAction_VERB )
1875 msBuffer.append( nVerb );
1876 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_VERB, msBuffer.makeStringAndClear());
1879 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_PRESENTATION, XML_EVENT_LISTENER, true, true);
1881 if( eClickAction == presentation::ClickAction_VANISH || eClickAction == presentation::ClickAction_SOUND )
1883 if( ( nFound & Found::SOUNDURL ) && !aStrSoundURL.isEmpty() )
1885 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStrSoundURL) );
1886 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
1887 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_NEW );
1888 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONREQUEST );
1889 if( nFound & Found::PLAYFULL && bPlayFull )
1890 mrExport.AddAttribute( XML_NAMESPACE_PRESENTATION, XML_PLAY_FULL, XML_TRUE );
1892 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_PRESENTATION, XML_SOUND, true, true );
1896 else if( aClickEventType == gsStarBasic )
1898 if( nFound & Found::MACRO )
1900 SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
1902 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE,
1903 mrExport.GetNamespaceMap().GetQNameByKey(
1904 XML_NAMESPACE_OOO,
1905 "starbasic" ) );
1906 OUString aEventQName(
1907 mrExport.GetNamespaceMap().GetQNameByKey(
1908 XML_NAMESPACE_DOM, "click" ) );
1909 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
1911 if( nFound & Found::LIBRARY )
1913 const OUString& sLocation( GetXMLToken(
1914 (aStrLibrary.equalsIgnoreAsciiCase("StarOffice") ||
1915 aStrLibrary.equalsIgnoreAsciiCase("application") ) ? XML_APPLICATION
1916 : XML_DOCUMENT ) );
1917 mrExport.AddAttribute(XML_NAMESPACE_SCRIPT, XML_MACRO_NAME,
1918 sLocation + ":" + aStrMacro);
1920 else
1922 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_MACRO_NAME, aStrMacro );
1925 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, true, true);
1928 else if( aClickEventType == gsScript )
1930 if( nFound & Found::MACRO )
1932 SvXMLElementExport aEventsElemt(mrExport, XML_NAMESPACE_OFFICE, XML_EVENT_LISTENERS, true, true);
1934 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_LANGUAGE, mrExport.GetNamespaceMap().GetQNameByKey(
1935 XML_NAMESPACE_OOO, GetXMLToken(XML_SCRIPT) ) );
1936 OUString aEventQName(
1937 mrExport.GetNamespaceMap().GetQNameByKey(
1938 XML_NAMESPACE_DOM, "click" ) );
1939 mrExport.AddAttribute( XML_NAMESPACE_SCRIPT, XML_EVENT_NAME, aEventQName );
1940 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, aStrMacro );
1941 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, "simple" );
1943 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SCRIPT, XML_EVENT_LISTENER, true, true);
1948 /** #i68101# export shape Title and Description */
1949 void XMLShapeExport::ImpExportDescription( const uno::Reference< drawing::XShape >& xShape )
1953 OUString aTitle;
1954 OUString aDescription;
1956 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY_THROW );
1957 xProps->getPropertyValue("Title") >>= aTitle;
1958 xProps->getPropertyValue("Description") >>= aDescription;
1960 if(!aTitle.isEmpty())
1962 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_TITLE, true, false);
1963 mrExport.Characters( aTitle );
1966 if(!aDescription.isEmpty())
1968 SvXMLElementExport aEventElemt(mrExport, XML_NAMESPACE_SVG, XML_DESC, true, false );
1969 mrExport.Characters( aDescription );
1972 catch( uno::Exception& )
1974 DBG_UNHANDLED_EXCEPTION( "xmloff", "exporting Title and/or Description for shape" );
1978 void XMLShapeExport::ImpExportGroupShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
1980 uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY);
1981 if(!(xShapes.is() && xShapes->getCount()))
1982 return;
1984 // write group shape
1985 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
1986 SvXMLElementExport aPGR(mrExport, XML_NAMESPACE_DRAW, XML_G, bCreateNewline, true);
1988 ImpExportDescription( xShape ); // #i68101#
1989 ImpExportEvents( xShape );
1990 ImpExportGluePoints( xShape );
1992 // #89764# if export of position is suppressed for group shape,
1993 // positions of contained objects should be written relative to
1994 // the upper left edge of the group.
1995 awt::Point aUpperLeft;
1997 if(!(nFeatures & XMLShapeExportFlags::POSITION))
1999 nFeatures |= XMLShapeExportFlags::POSITION;
2000 aUpperLeft = xShape->getPosition();
2001 pRefPoint = &aUpperLeft;
2004 // write members
2005 exportShapes( xShapes, nFeatures, pRefPoint );
2008 void XMLShapeExport::ImpExportTextBoxShape(
2009 const uno::Reference< drawing::XShape >& xShape,
2010 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2012 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2013 if(!xPropSet.is())
2014 return;
2016 // presentation attribute (if presentation)
2017 bool bIsPresShape(false);
2018 bool bIsEmptyPresObj(false);
2019 OUString aStr;
2021 switch(eShapeType)
2023 case XmlShapeType::PresSubtitleShape:
2025 aStr = GetXMLToken(XML_SUBTITLE);
2026 bIsPresShape = true;
2027 break;
2029 case XmlShapeType::PresTitleTextShape:
2031 aStr = GetXMLToken(XML_TITLE);
2032 bIsPresShape = true;
2033 break;
2035 case XmlShapeType::PresOutlinerShape:
2037 aStr = GetXMLToken(XML_PRESENTATION_OUTLINE);
2038 bIsPresShape = true;
2039 break;
2041 case XmlShapeType::PresNotesShape:
2043 aStr = GetXMLToken(XML_NOTES);
2044 bIsPresShape = true;
2045 break;
2047 case XmlShapeType::PresHeaderShape:
2049 aStr = GetXMLToken(XML_HEADER);
2050 bIsPresShape = true;
2051 break;
2053 case XmlShapeType::PresFooterShape:
2055 aStr = GetXMLToken(XML_FOOTER);
2056 bIsPresShape = true;
2057 break;
2059 case XmlShapeType::PresSlideNumberShape:
2061 aStr = GetXMLToken(XML_PAGE_NUMBER);
2062 bIsPresShape = true;
2063 break;
2065 case XmlShapeType::PresDateTimeShape:
2067 aStr = GetXMLToken(XML_DATE_TIME);
2068 bIsPresShape = true;
2069 break;
2071 default:
2072 break;
2075 // Transformation
2076 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2078 if(bIsPresShape)
2079 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, aStr );
2081 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2082 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
2083 XML_FRAME, bCreateNewline, true );
2085 // evtl. corner radius?
2086 sal_Int32 nCornerRadius(0);
2087 xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius;
2088 if(nCornerRadius)
2090 OUStringBuffer sStringBuffer;
2091 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2092 nCornerRadius);
2093 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
2097 // write text-box
2098 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_TEXT_BOX, true, true);
2099 if(!bIsEmptyPresObj)
2100 ImpExportText( xShape );
2103 ImpExportDescription( xShape ); // #i68101#
2104 ImpExportEvents( xShape );
2105 ImpExportGluePoints( xShape );
2109 void XMLShapeExport::ImpExportRectangleShape(
2110 const uno::Reference< drawing::XShape >& xShape,
2111 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
2113 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2114 if(!xPropSet.is())
2115 return;
2117 // Transformation
2118 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2120 // evtl. corner radius?
2121 sal_Int32 nCornerRadius(0);
2122 xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius;
2123 if(nCornerRadius)
2125 OUStringBuffer sStringBuffer;
2126 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2127 nCornerRadius);
2128 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
2131 // write rectangle
2132 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2133 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_RECT, bCreateNewline, true);
2135 ImpExportDescription( xShape ); // #i68101#
2136 ImpExportEvents( xShape );
2137 ImpExportGluePoints( xShape );
2138 ImpExportText( xShape );
2141 void XMLShapeExport::ImpExportLineShape(
2142 const uno::Reference< drawing::XShape >& xShape,
2143 XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2145 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2146 if(!xPropSet.is())
2147 return;
2149 OUString aStr;
2150 OUStringBuffer sStringBuffer;
2151 awt::Point aStart(0,0);
2152 awt::Point aEnd(1,1);
2154 // #85920# use 'Geometry' to get the points of the line
2155 // since this slot take anchor pos into account.
2157 // get matrix
2158 ::basegfx::B2DHomMatrix aMatrix;
2159 ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
2161 // decompose and correct about pRefPoint
2162 ::basegfx::B2DTuple aTRScale;
2163 double fTRShear(0.0);
2164 double fTRRotate(0.0);
2165 ::basegfx::B2DTuple aTRTranslate;
2166 ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
2168 // create base position
2169 awt::Point aBasePosition(FRound(aTRTranslate.getX()), FRound(aTRTranslate.getY()));
2171 if (xPropSet->getPropertySetInfo()->hasPropertyByName("Geometry"))
2173 // get the two points
2174 uno::Any aAny(xPropSet->getPropertyValue("Geometry"));
2175 if (auto pSourcePolyPolygon
2176 = o3tl::tryAccess<drawing::PointSequenceSequence>(aAny))
2178 if (pSourcePolyPolygon->getLength() > 0)
2180 const drawing::PointSequence& rInnerSequence = (*pSourcePolyPolygon)[0];
2181 if (rInnerSequence.hasElements())
2183 const awt::Point& rPoint = rInnerSequence[0];
2184 aStart = awt::Point(rPoint.X + aBasePosition.X, rPoint.Y + aBasePosition.Y);
2186 if (rInnerSequence.getLength() > 1)
2188 const awt::Point& rPoint = rInnerSequence[1];
2189 aEnd = awt::Point(rPoint.X + aBasePosition.X, rPoint.Y + aBasePosition.Y);
2195 if( nFeatures & XMLShapeExportFlags::X )
2197 // svg: x1
2198 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2199 aStart.X);
2200 aStr = sStringBuffer.makeStringAndClear();
2201 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
2203 else
2205 aEnd.X -= aStart.X;
2208 if( nFeatures & XMLShapeExportFlags::Y )
2210 // svg: y1
2211 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2212 aStart.Y);
2213 aStr = sStringBuffer.makeStringAndClear();
2214 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
2216 else
2218 aEnd.Y -= aStart.Y;
2221 // svg: x2
2222 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2223 aEnd.X);
2224 aStr = sStringBuffer.makeStringAndClear();
2225 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
2227 // svg: y2
2228 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2229 aEnd.Y);
2230 aStr = sStringBuffer.makeStringAndClear();
2231 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
2233 // write line
2234 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2235 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_LINE, bCreateNewline, true);
2237 ImpExportDescription( xShape ); // #i68101#
2238 ImpExportEvents( xShape );
2239 ImpExportGluePoints( xShape );
2240 ImpExportText( xShape );
2244 void XMLShapeExport::ImpExportEllipseShape(
2245 const uno::Reference< drawing::XShape >& xShape,
2246 XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2248 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2249 if(!xPropSet.is())
2250 return;
2252 // get size to decide between Circle and Ellipse
2253 awt::Size aSize = xShape->getSize();
2254 sal_Int32 nRx((aSize.Width + 1) / 2);
2255 sal_Int32 nRy((aSize.Height + 1) / 2);
2256 bool bCircle(nRx == nRy);
2258 // Transformation
2259 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2261 drawing::CircleKind eKind = drawing::CircleKind_FULL;
2262 xPropSet->getPropertyValue("CircleKind") >>= eKind;
2263 if( eKind != drawing::CircleKind_FULL )
2265 OUStringBuffer sStringBuffer;
2266 sal_Int32 nStartAngle = 0;
2267 sal_Int32 nEndAngle = 0;
2268 xPropSet->getPropertyValue("CircleStartAngle") >>= nStartAngle;
2269 xPropSet->getPropertyValue("CircleEndAngle") >>= nEndAngle;
2271 const double dStartAngle = nStartAngle / 100.0;
2272 const double dEndAngle = nEndAngle / 100.0;
2274 // export circle kind
2275 SvXMLUnitConverter::convertEnum( sStringBuffer, eKind, aXML_CircleKind_EnumMap );
2276 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_KIND, sStringBuffer.makeStringAndClear() );
2278 // export start angle
2279 ::sax::Converter::convertDouble( sStringBuffer, dStartAngle );
2280 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_ANGLE, sStringBuffer.makeStringAndClear() );
2282 // export end angle
2283 ::sax::Converter::convertDouble( sStringBuffer, dEndAngle );
2284 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_ANGLE, sStringBuffer.makeStringAndClear() );
2287 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2289 // write ellipse or circle
2290 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW,
2291 bCircle ? XML_CIRCLE : XML_ELLIPSE,
2292 bCreateNewline, true);
2294 ImpExportDescription( xShape ); // #i68101#
2295 ImpExportEvents( xShape );
2296 ImpExportGluePoints( xShape );
2297 ImpExportText( xShape );
2301 void XMLShapeExport::ImpExportPolygonShape(
2302 const uno::Reference< drawing::XShape >& xShape,
2303 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2305 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2306 if(!xPropSet.is())
2307 return;
2309 bool bBezier(eShapeType == XmlShapeType::DrawClosedBezierShape
2310 || eShapeType == XmlShapeType::DrawOpenBezierShape);
2312 // get matrix
2313 ::basegfx::B2DHomMatrix aMatrix;
2314 ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xPropSet);
2316 // decompose and correct about pRefPoint
2317 ::basegfx::B2DTuple aTRScale;
2318 double fTRShear(0.0);
2319 double fTRRotate(0.0);
2320 ::basegfx::B2DTuple aTRTranslate;
2321 ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear, fTRRotate, aTRTranslate, pRefPoint);
2323 // use features and write
2324 ImpExportNewTrans_FeaturesAndWrite(aTRScale, fTRShear, fTRRotate, aTRTranslate, nFeatures);
2326 // create and export ViewBox
2327 awt::Size aSize(FRound(aTRScale.getX()), FRound(aTRScale.getY()));
2328 SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height);
2329 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
2331 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2333 // prepare name (with most used)
2334 enum ::xmloff::token::XMLTokenEnum eName(XML_PATH);
2336 uno::Any aAny( xPropSet->getPropertyValue("Geometry") );
2337 basegfx::B2DPolyPolygon aPolyPolygon;
2339 // tdf#145240 the Any can contain PolyPolygonBezierCoords or PointSequenceSequence
2340 // (see OWN_ATTR_BASE_GEOMETRY in SvxShapePolyPolygon::getPropertyValueImpl),
2341 // so be more flexible in interpreting it. Try to access bezier first:
2343 auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(aAny);
2345 if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength())
2347 aPolyPolygon = basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(*pSourcePolyPolygon);
2351 // if received no data, try to access point sequence second:
2352 if(0 == aPolyPolygon.count())
2354 auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PointSequenceSequence>(aAny);
2356 if(pSourcePolyPolygon)
2358 aPolyPolygon = basegfx::utils::UnoPointSequenceSequenceToB2DPolyPolygon(*pSourcePolyPolygon);
2362 if(aPolyPolygon.count())
2364 if(!bBezier && !aPolyPolygon.areControlPointsUsed() && 1 == aPolyPolygon.count())
2366 // simple polygon shape, can be written as svg:points sequence
2367 const basegfx::B2DPolygon& aPolygon(aPolyPolygon.getB2DPolygon(0));
2368 const OUString aPointString(basegfx::utils::exportToSvgPoints(aPolygon));
2370 // write point array
2371 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_POINTS, aPointString);
2373 // set name
2374 eName = aPolygon.isClosed() ? XML_POLYGON : XML_POLYLINE;
2376 else
2378 // complex polygon shape, write as svg:d
2379 const OUString aPolygonString(
2380 basegfx::utils::exportToSvgD(
2381 aPolyPolygon,
2382 true, // bUseRelativeCoordinates
2383 false, // bDetectQuadraticBeziers: not used in old, but maybe activated now
2384 true)); // bHandleRelativeNextPointCompatible
2386 // write point array
2387 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
2391 // write object, but after attributes are added since this call will
2392 // consume all of these added attributes and the destructor will close the
2393 // scope. Also before text is added; this may add sub-scopes as needed
2394 SvXMLElementExport aOBJ(
2395 mrExport,
2396 XML_NAMESPACE_DRAW,
2397 eName,
2398 bCreateNewline,
2399 true);
2401 ImpExportDescription( xShape ); // #i68101#
2402 ImpExportEvents( xShape );
2403 ImpExportGluePoints( xShape );
2404 ImpExportText( xShape );
2408 namespace
2411 OUString getNameFromStreamURL(std::u16string_view rURL)
2413 static constexpr std::u16string_view sPackageURL(u"vnd.sun.star.Package:");
2415 OUString sResult;
2417 if (o3tl::starts_with(rURL, sPackageURL))
2419 std::u16string_view sRequestedName = rURL.substr(sPackageURL.size());
2420 size_t nLastIndex = sRequestedName.rfind('/') + 1;
2421 if ((nLastIndex > 0) && (nLastIndex < sRequestedName.size()))
2422 sRequestedName = sRequestedName.substr(nLastIndex);
2423 nLastIndex = sRequestedName.rfind('.');
2424 if (nLastIndex != std::u16string_view::npos)
2425 sRequestedName = sRequestedName.substr(0, nLastIndex);
2426 if (!sRequestedName.empty())
2427 sResult = sRequestedName;
2430 return sResult;
2433 } // end anonymous namespace
2435 void XMLShapeExport::ImpExportGraphicObjectShape(
2436 const uno::Reference< drawing::XShape >& xShape,
2437 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2439 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2440 if(!xPropSet.is())
2441 return;
2443 bool bIsEmptyPresObj = false;
2445 // Transformation
2446 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2448 if(eShapeType == XmlShapeType::PresGraphicObjectShape)
2449 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_GRAPHIC) );
2451 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2452 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
2453 XML_FRAME, bCreateNewline, true );
2455 if (!bIsEmptyPresObj)
2457 uno::Reference<graphic::XGraphic> xGraphic;
2458 OUString sOutMimeType;
2461 OUString aStreamURL;
2462 xPropSet->getPropertyValue("GraphicStreamURL") >>= aStreamURL;
2463 OUString sRequestedName = getNameFromStreamURL(aStreamURL);
2465 xPropSet->getPropertyValue("Graphic") >>= xGraphic;
2467 OUString sInternalURL;
2469 if (xGraphic.is())
2470 sInternalURL = mrExport.AddEmbeddedXGraphic(xGraphic, sOutMimeType, sRequestedName);
2472 if (!sInternalURL.isEmpty())
2474 // apply possible changed stream URL to embedded image object
2475 if (!sRequestedName.isEmpty())
2477 OUString newStreamURL = "vnd.sun.star.Package:";
2478 if (sInternalURL[0] == '#')
2480 newStreamURL += sInternalURL.subView(1, sInternalURL.getLength() - 1);
2482 else
2484 newStreamURL += sInternalURL;
2487 if (newStreamURL != aStreamURL)
2489 xPropSet->setPropertyValue("GraphicStreamURL", uno::Any(newStreamURL));
2493 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sInternalURL);
2494 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
2495 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
2496 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
2501 if (GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
2503 if (sOutMimeType.isEmpty())
2505 GetExport().GetGraphicMimeTypeFromStream(xGraphic, sOutMimeType);
2507 if (!sOutMimeType.isEmpty())
2508 { // ODF 1.3 OFFICE-3943
2509 GetExport().AddAttribute(
2510 SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion()
2511 ? XML_NAMESPACE_DRAW
2512 : XML_NAMESPACE_LO_EXT,
2513 "mime-type", sOutMimeType);
2517 SvXMLElementExport aElement(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, true);
2519 // optional office:binary-data
2520 if (xGraphic.is())
2522 mrExport.AddEmbeddedXGraphicAsBase64(xGraphic);
2524 if (!bIsEmptyPresObj)
2525 ImpExportText(xShape);
2528 //Resolves: fdo#62461 put preferred image first above, followed by
2529 //fallback here
2530 const bool bAddReplacementImages = officecfg::Office::Common::Save::Graphic::AddReplacementImages::get();
2531 if( !bIsEmptyPresObj && bAddReplacementImages)
2533 uno::Reference<graphic::XGraphic> xReplacementGraphic;
2534 xPropSet->getPropertyValue("ReplacementGraphic") >>= xReplacementGraphic;
2536 // If there is no url, then the graphic is empty
2537 if (xReplacementGraphic.is())
2539 OUString aMimeType;
2540 const OUString aHref = mrExport.AddEmbeddedXGraphic(xReplacementGraphic, aMimeType);
2542 if (aMimeType.isEmpty())
2543 mrExport.GetGraphicMimeTypeFromStream(xReplacementGraphic, aMimeType);
2545 if (!aHref.isEmpty())
2547 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aHref);
2548 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
2549 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
2550 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
2553 if (!aMimeType.isEmpty() && GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
2554 { // ODF 1.3 OFFICE-3943
2555 mrExport.AddAttribute(
2556 SvtSaveOptions::ODFSVER_013 <= GetExport().getSaneDefaultVersion()
2557 ? XML_NAMESPACE_DRAW
2558 : XML_NAMESPACE_LO_EXT,
2559 "mime-type", aMimeType);
2562 SvXMLElementExport aElement(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true, true);
2564 // optional office:binary-data
2565 mrExport.AddEmbeddedXGraphicAsBase64(xReplacementGraphic);
2570 ImpExportEvents( xShape );
2571 ImpExportGluePoints( xShape );
2573 // image map
2574 GetExport().GetImageMapExport().Export( xPropSet );
2575 ImpExportDescription( xShape ); // #i68101#
2577 // Signature Line, QR Code - needs to be after the images!
2578 if (GetExport().getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED)
2580 ImpExportSignatureLine(xShape);
2581 ImpExportQRCode(xShape);
2585 void XMLShapeExport::ImpExportChartShape(
2586 const uno::Reference< drawing::XShape >& xShape,
2587 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint,
2588 comphelper::AttributeList* pAttrList )
2590 ImpExportOLE2Shape( xShape, eShapeType, nFeatures, pRefPoint, pAttrList );
2593 void XMLShapeExport::ImpExportControlShape(
2594 const uno::Reference< drawing::XShape >& xShape,
2595 XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
2597 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2598 if(xPropSet.is())
2600 // Transformation
2601 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2604 uno::Reference< drawing::XControlShape > xControl( xShape, uno::UNO_QUERY );
2605 SAL_WARN_IF( !xControl.is(), "xmloff", "Control shape is not supporting XControlShape" );
2606 if( xControl.is() )
2608 uno::Reference< beans::XPropertySet > xControlModel( xControl->getControl(), uno::UNO_QUERY );
2609 SAL_WARN_IF( !xControlModel.is(), "xmloff", "Control shape has not XControlModel" );
2610 if( xControlModel.is() )
2612 OUString sControlId = mrExport.GetFormExport()->getControlId( xControlModel );
2613 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CONTROL, sControlId );
2617 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2618 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONTROL, bCreateNewline, true);
2620 ImpExportDescription( xShape ); // #i68101#
2623 void XMLShapeExport::ImpExportConnectorShape(
2624 const uno::Reference< drawing::XShape >& xShape,
2625 XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
2627 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
2629 OUString aStr;
2630 OUStringBuffer sStringBuffer;
2632 // export connection kind
2633 drawing::ConnectorType eType = drawing::ConnectorType_STANDARD;
2634 uno::Any aAny = xProps->getPropertyValue("EdgeKind");
2635 aAny >>= eType;
2637 if( eType != drawing::ConnectorType_STANDARD )
2639 SvXMLUnitConverter::convertEnum( sStringBuffer, eType, aXML_ConnectionKind_EnumMap );
2640 aStr = sStringBuffer.makeStringAndClear();
2641 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_TYPE, aStr);
2644 // export line skew
2645 sal_Int32 nDelta1 = 0, nDelta2 = 0, nDelta3 = 0;
2647 aAny = xProps->getPropertyValue("EdgeLine1Delta");
2648 aAny >>= nDelta1;
2649 aAny = xProps->getPropertyValue("EdgeLine2Delta");
2650 aAny >>= nDelta2;
2651 aAny = xProps->getPropertyValue("EdgeLine3Delta");
2652 aAny >>= nDelta3;
2654 if( nDelta1 != 0 || nDelta2 != 0 || nDelta3 != 0 )
2656 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2657 nDelta1);
2658 if( nDelta2 != 0 || nDelta3 != 0 )
2660 sStringBuffer.append( ' ' );
2661 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2662 nDelta2);
2663 if( nDelta3 != 0 )
2665 sStringBuffer.append( ' ' );
2666 mrExport.GetMM100UnitConverter().convertMeasureToXML(
2667 sStringBuffer, nDelta3);
2671 aStr = sStringBuffer.makeStringAndClear();
2672 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_LINE_SKEW, aStr);
2675 // export start and end point
2676 awt::Point aStart(0,0);
2677 awt::Point aEnd(1,1);
2679 /* Get <StartPositionInHoriL2R> and
2680 <EndPositionInHoriL2R>, if they exist and if the document is exported
2681 into the OpenOffice.org file format.
2682 These properties only exist at service css::text::Shape - the
2683 Writer UNO service for shapes.
2684 This code is needed, because the positioning attributes in the
2685 OpenOffice.org file format are given in horizontal left-to-right layout
2686 regardless the layout direction the shape is in. In the OASIS Open Office
2687 file format the positioning attributes are correctly given in the layout
2688 direction the shape is in. Thus, this code provides the conversion from
2689 the OASIS Open Office file format to the OpenOffice.org file format. (#i36248#)
2691 if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
2692 xProps->getPropertySetInfo()->hasPropertyByName("StartPositionInHoriL2R") &&
2693 xProps->getPropertySetInfo()->hasPropertyByName("EndPositionInHoriL2R") )
2695 xProps->getPropertyValue("StartPositionInHoriL2R") >>= aStart;
2696 xProps->getPropertyValue("EndPositionInHoriL2R") >>= aEnd;
2698 else
2700 xProps->getPropertyValue("StartPosition") >>= aStart;
2701 xProps->getPropertyValue("EndPosition") >>= aEnd;
2704 if( pRefPoint )
2706 aStart.X -= pRefPoint->X;
2707 aStart.Y -= pRefPoint->Y;
2708 aEnd.X -= pRefPoint->X;
2709 aEnd.Y -= pRefPoint->Y;
2712 if( nFeatures & XMLShapeExportFlags::X )
2714 // svg: x1
2715 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2716 aStart.X);
2717 aStr = sStringBuffer.makeStringAndClear();
2718 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
2720 else
2722 aEnd.X -= aStart.X;
2725 if( nFeatures & XMLShapeExportFlags::Y )
2727 // svg: y1
2728 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2729 aStart.Y);
2730 aStr = sStringBuffer.makeStringAndClear();
2731 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
2733 else
2735 aEnd.Y -= aStart.Y;
2738 // svg: x2
2739 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.X);
2740 aStr = sStringBuffer.makeStringAndClear();
2741 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
2743 // svg: y2
2744 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.Y);
2745 aStr = sStringBuffer.makeStringAndClear();
2746 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
2748 // #i39320#
2749 uno::Reference< uno::XInterface > xRefS;
2750 uno::Reference< uno::XInterface > xRefE;
2752 // export start connection
2753 xProps->getPropertyValue("StartShape") >>= xRefS;
2754 if( xRefS.is() )
2756 const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefS );
2757 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_SHAPE, rShapeId);
2759 aAny = xProps->getPropertyValue("StartGluePointIndex");
2760 sal_Int32 nGluePointId = 0;
2761 if( aAny >>= nGluePointId )
2763 if( nGluePointId != -1 )
2765 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_START_GLUE_POINT, OUString::number( nGluePointId ));
2770 // export end connection
2771 xProps->getPropertyValue("EndShape") >>= xRefE;
2772 if( xRefE.is() )
2774 const OUString& rShapeId = mrExport.getInterfaceToIdentifierMapper().getIdentifier( xRefE );
2775 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_SHAPE, rShapeId);
2777 aAny = xProps->getPropertyValue("EndGluePointIndex");
2778 sal_Int32 nGluePointId = 0;
2779 if( aAny >>= nGluePointId )
2781 if( nGluePointId != -1 )
2783 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_END_GLUE_POINT, OUString::number( nGluePointId ));
2788 // get PolygonBezier
2789 aAny = xProps->getPropertyValue("PolyPolygonBezier");
2790 auto pSourcePolyPolygon = o3tl::tryAccess<drawing::PolyPolygonBezierCoords>(aAny);
2791 if(pSourcePolyPolygon && pSourcePolyPolygon->Coordinates.getLength())
2793 const basegfx::B2DPolyPolygon aPolyPolygon(
2794 basegfx::utils::UnoPolyPolygonBezierCoordsToB2DPolyPolygon(
2795 *pSourcePolyPolygon));
2796 const OUString aPolygonString(
2797 basegfx::utils::exportToSvgD(
2798 aPolyPolygon,
2799 true, // bUseRelativeCoordinates
2800 false, // bDetectQuadraticBeziers: not used in old, but maybe activated now
2801 true)); // bHandleRelativeNextPointCompatible
2803 // write point array
2804 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
2807 // get matrix
2808 ::basegfx::B2DHomMatrix aMatrix;
2809 ImpExportNewTrans_GetB2DHomMatrix(aMatrix, xProps);
2811 // decompose and correct about pRefPoint
2812 ::basegfx::B2DTuple aTRScale;
2813 double fTRShear(0.0);
2814 double fTRRotate(0.0);
2815 ::basegfx::B2DTuple aTRTranslate;
2816 ImpExportNewTrans_DecomposeAndRefPoint(aMatrix, aTRScale, fTRShear,
2817 fTRRotate, aTRTranslate, pRefPoint);
2819 // fdo#49678: create and export ViewBox
2820 awt::Size aSize(FRound(aTRScale.getX()), FRound(aTRScale.getY()));
2821 SdXMLImExViewBox aViewBox(0, 0, aSize.Width, aSize.Height);
2822 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
2824 // write connector shape. Add Export later.
2825 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2826 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_CONNECTOR, bCreateNewline, true);
2828 ImpExportDescription( xShape ); // #i68101#
2829 ImpExportEvents( xShape );
2830 ImpExportGluePoints( xShape );
2831 ImpExportText( xShape );
2834 void XMLShapeExport::ImpExportMeasureShape(
2835 const uno::Reference< drawing::XShape >& xShape,
2836 XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point const * pRefPoint /* = NULL */)
2838 uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY );
2840 OUString aStr;
2841 OUStringBuffer sStringBuffer;
2843 // export start and end point
2844 awt::Point aStart(0,0);
2845 awt::Point aEnd(1,1);
2847 /* Get <StartPositionInHoriL2R> and
2848 <EndPositionInHoriL2R>, if they exist and if the document is exported
2849 into the OpenOffice.org file format.
2850 These properties only exist at service css::text::Shape - the
2851 Writer UNO service for shapes.
2852 This code is needed, because the positioning attributes in the
2853 OpenOffice.org file format are given in horizontal left-to-right layout
2854 regardless the layout direction the shape is in. In the OASIS Open Office
2855 file format the positioning attributes are correctly given in the layout
2856 direction the shape is in. Thus, this code provides the conversion from
2857 the OASIS Open Office file format to the OpenOffice.org file format. (#i36248#)
2859 if ( !( GetExport().getExportFlags() & SvXMLExportFlags::OASIS ) &&
2860 xProps->getPropertySetInfo()->hasPropertyByName("StartPositionInHoriL2R") &&
2861 xProps->getPropertySetInfo()->hasPropertyByName("EndPositionInHoriL2R") )
2863 xProps->getPropertyValue("StartPositionInHoriL2R") >>= aStart;
2864 xProps->getPropertyValue("EndPositionInHoriL2R") >>= aEnd;
2866 else
2868 xProps->getPropertyValue("StartPosition") >>= aStart;
2869 xProps->getPropertyValue("EndPosition") >>= aEnd;
2872 if( pRefPoint )
2874 aStart.X -= pRefPoint->X;
2875 aStart.Y -= pRefPoint->Y;
2876 aEnd.X -= pRefPoint->X;
2877 aEnd.Y -= pRefPoint->Y;
2880 if( nFeatures & XMLShapeExportFlags::X )
2882 // svg: x1
2883 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2884 aStart.X);
2885 aStr = sStringBuffer.makeStringAndClear();
2886 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X1, aStr);
2888 else
2890 aEnd.X -= aStart.X;
2893 if( nFeatures & XMLShapeExportFlags::Y )
2895 // svg: y1
2896 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
2897 aStart.Y);
2898 aStr = sStringBuffer.makeStringAndClear();
2899 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y1, aStr);
2901 else
2903 aEnd.Y -= aStart.Y;
2906 // svg: x2
2907 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.X);
2908 aStr = sStringBuffer.makeStringAndClear();
2909 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_X2, aStr);
2911 // svg: y2
2912 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer, aEnd.Y);
2913 aStr = sStringBuffer.makeStringAndClear();
2914 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_Y2, aStr);
2916 // write measure shape
2917 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2918 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_MEASURE, bCreateNewline, true);
2920 ImpExportDescription( xShape ); // #i68101#
2921 ImpExportEvents( xShape );
2922 ImpExportGluePoints( xShape );
2924 uno::Reference< text::XText > xText( xShape, uno::UNO_QUERY );
2925 if( xText.is() )
2926 mrExport.GetTextParagraphExport()->exportText( xText );
2929 void XMLShapeExport::ImpExportOLE2Shape(
2930 const uno::Reference< drawing::XShape >& xShape,
2931 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */,
2932 comphelper::AttributeList* pAttrList /* = NULL */ )
2934 uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
2935 uno::Reference< container::XNamed > xNamed(xShape, uno::UNO_QUERY);
2937 SAL_WARN_IF( !xPropSet.is() || !xNamed.is(), "xmloff", "ole shape is not implementing needed interfaces");
2938 if(!(xPropSet.is() && xNamed.is()))
2939 return;
2941 // Transformation
2942 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
2944 bool bIsEmptyPresObj = false;
2946 // presentation settings
2947 if(eShapeType == XmlShapeType::PresOLE2Shape)
2948 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_OBJECT) );
2949 else if(eShapeType == XmlShapeType::PresChartShape)
2950 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_CHART) );
2951 else if(eShapeType == XmlShapeType::PresSheetShape)
2952 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_TABLE) );
2954 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
2955 bool bExportEmbedded(mrExport.getExportFlags() & SvXMLExportFlags::EMBEDDED);
2956 OUString sPersistName;
2957 SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
2958 XML_FRAME, bCreateNewline, true );
2960 if (!bIsEmptyPresObj)
2962 if (pAttrList)
2964 mrExport.AddAttributeList(pAttrList);
2967 OUString sClassId;
2968 OUString sURL;
2969 bool bInternal = false;
2970 xPropSet->getPropertyValue("IsInternal") >>= bInternal;
2974 if ( bInternal )
2976 // OOo internal links have no storage persistence, URL is stored in the XML file
2977 // the result LinkURL is empty in case the object is not a link
2978 xPropSet->getPropertyValue("LinkURL") >>= sURL;
2981 xPropSet->getPropertyValue("PersistName") >>= sPersistName;
2982 if ( sURL.isEmpty() )
2984 if( !sPersistName.isEmpty() )
2986 sURL = "vnd.sun.star.EmbeddedObject:" + sPersistName;
2990 if( !bInternal )
2991 xPropSet->getPropertyValue("CLSID") >>= sClassId;
2993 if( !sClassId.isEmpty() )
2994 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CLASS_ID, sClassId );
2996 if(!bExportEmbedded)
2998 // xlink:href
2999 if( !sURL.isEmpty() )
3001 // #96717# in theorie, if we don't have a URL we shouldn't even
3002 // export this OLE shape. But practically it's too risky right now
3003 // to change this so we better dispose this on load
3004 sURL = mrExport.AddEmbeddedObject( sURL );
3006 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL );
3007 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3008 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3009 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3011 else
3013 // tdf#153179 Export the preview graphic of the object if the object is missing.
3014 uno::Reference<graphic::XGraphic> xGraphic;
3015 xPropSet->getPropertyValue("Graphic") >>= xGraphic;
3017 if (xGraphic.is())
3019 OUString aMimeType;
3020 const OUString aHref = mrExport.AddEmbeddedXGraphic(xGraphic, aMimeType);
3022 if (aMimeType.isEmpty())
3023 mrExport.GetGraphicMimeTypeFromStream(xGraphic, aMimeType);
3025 if (!aHref.isEmpty())
3027 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, aHref);
3028 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE);
3029 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED);
3030 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD);
3033 if (!aMimeType.isEmpty()
3034 && GetExport().getSaneDefaultVersion() > SvtSaveOptions::ODFSVER_012)
3035 { // ODF 1.3 OFFICE-3943
3036 mrExport.AddAttribute(SvtSaveOptions::ODFSVER_013
3037 <= GetExport().getSaneDefaultVersion()
3038 ? XML_NAMESPACE_DRAW
3039 : XML_NAMESPACE_LO_EXT,
3040 "mime-type", aMimeType);
3043 SvXMLElementExport aImageElem(mrExport, XML_NAMESPACE_DRAW, XML_IMAGE, true,
3044 true);
3046 // optional office:binary-data
3047 mrExport.AddEmbeddedXGraphicAsBase64(xGraphic);
3049 ImpExportEvents(xShape);
3050 ImpExportGluePoints(xShape);
3051 ImpExportDescription(xShape);
3053 return;
3059 enum XMLTokenEnum eElem = sClassId.isEmpty() ? XML_OBJECT : XML_OBJECT_OLE ;
3060 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, eElem, true, true );
3062 // tdf#112547 export text as child of draw:object, where import expects it
3063 if (!bIsEmptyPresObj && supportsText(eShapeType))
3065 // #i118485# Add text export, the draw OLE shape allows text now
3066 ImpExportText( xShape, TextPNS::EXTENSION );
3069 if(bExportEmbedded && !bIsEmptyPresObj)
3071 if(bInternal)
3073 // embedded XML
3074 uno::Reference< lang::XComponent > xComp;
3075 xPropSet->getPropertyValue("Model") >>= xComp;
3076 SAL_WARN_IF( !xComp.is(), "xmloff", "no xModel for own OLE format" );
3077 mrExport.ExportEmbeddedOwnObject( xComp );
3079 else
3081 // embed as Base64
3082 // this is an alien object ( currently MSOLE is the only supported type of such objects )
3083 // in case it is not an OASIS format the object should be asked to store replacement image if possible
3085 OUString sURLRequest( sURL );
3086 if ( !( mrExport.getExportFlags() & SvXMLExportFlags::OASIS ) )
3087 sURLRequest += "?oasis=false";
3088 mrExport.AddEmbeddedObjectAsBase64( sURLRequest );
3092 if( !bIsEmptyPresObj )
3094 OUString sURL = XML_EMBEDDEDOBJECTGRAPHIC_URL_BASE + sPersistName;
3095 if( !bExportEmbedded )
3097 sURL = GetExport().AddEmbeddedObject( sURL );
3098 mrExport.AddAttribute(XML_NAMESPACE_XLINK, XML_HREF, sURL );
3099 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3100 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3101 mrExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3104 SvXMLElementExport aElem( GetExport(), XML_NAMESPACE_DRAW,
3105 XML_IMAGE, false, true );
3107 if( bExportEmbedded )
3108 GetExport().AddEmbeddedObjectAsBase64( sURL );
3111 ImpExportEvents( xShape );
3112 ImpExportGluePoints( xShape );
3113 ImpExportDescription( xShape ); // #i68101#
3117 void XMLShapeExport::ImpExportPageShape(
3118 const uno::Reference< drawing::XShape >& xShape,
3119 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
3121 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3122 if(!xPropSet.is())
3123 return;
3125 // #86163# Transformation
3126 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3128 // export page number used for this page
3129 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
3130 static const OUStringLiteral aPageNumberStr(u"PageNumber");
3131 if( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName(aPageNumberStr))
3133 sal_Int32 nPageNumber = 0;
3134 xPropSet->getPropertyValue(aPageNumberStr) >>= nPageNumber;
3135 if( nPageNumber )
3136 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_PAGE_NUMBER, OUString::number(nPageNumber));
3139 // a presentation page shape, normally used on notes pages only. If
3140 // it is used not as presentation shape, it may have been created with
3141 // copy-paste exchange between draw and impress (this IS possible...)
3142 if(eShapeType == XmlShapeType::PresPageShape)
3144 mrExport.AddAttribute(XML_NAMESPACE_PRESENTATION, XML_CLASS,
3145 XML_PAGE);
3148 // write Page shape
3149 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3150 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PAGE_THUMBNAIL, bCreateNewline, true);
3153 void XMLShapeExport::ImpExportCaptionShape(
3154 const uno::Reference< drawing::XShape >& xShape,
3155 XMLShapeExportFlags nFeatures /* = SEF_DEFAULT */, awt::Point* pRefPoint /* = NULL */)
3157 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3158 if(!xPropSet.is())
3159 return;
3161 // Transformation
3162 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3164 // evtl. corner radius?
3165 sal_Int32 nCornerRadius(0);
3166 xPropSet->getPropertyValue("CornerRadius") >>= nCornerRadius;
3167 if(nCornerRadius)
3169 OUStringBuffer sStringBuffer;
3170 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
3171 nCornerRadius);
3172 mrExport.AddAttribute(XML_NAMESPACE_DRAW, XML_CORNER_RADIUS, sStringBuffer.makeStringAndClear());
3175 awt::Point aCaptionPoint;
3176 xPropSet->getPropertyValue("CaptionPoint") >>= aCaptionPoint;
3178 mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
3179 aCaptionPoint.X);
3180 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_X, msBuffer.makeStringAndClear() );
3181 mrExport.GetMM100UnitConverter().convertMeasureToXML(msBuffer,
3182 aCaptionPoint.Y);
3183 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CAPTION_POINT_Y, msBuffer.makeStringAndClear() );
3185 // write Caption shape. Add export later.
3186 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3187 bool bAnnotation( (nFeatures & XMLShapeExportFlags::ANNOTATION) == XMLShapeExportFlags::ANNOTATION );
3189 SvXMLElementExport aObj( mrExport,
3190 (bAnnotation ? XML_NAMESPACE_OFFICE
3191 : XML_NAMESPACE_DRAW),
3192 (bAnnotation ? XML_ANNOTATION : XML_CAPTION),
3193 bCreateNewline, true );
3195 ImpExportDescription( xShape ); // #i68101#
3196 ImpExportEvents( xShape );
3197 ImpExportGluePoints( xShape );
3198 if( bAnnotation )
3199 mrExport.exportAnnotationMeta( xShape );
3200 ImpExportText( xShape );
3204 void XMLShapeExport::ImpExportFrameShape(
3205 const uno::Reference< drawing::XShape >& xShape,
3206 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3208 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3209 if(!xPropSet.is())
3210 return;
3212 // Transformation
3213 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3215 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3216 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
3217 XML_FRAME, bCreateNewline, true );
3219 // export frame url
3220 OUString aStr;
3221 xPropSet->getPropertyValue("FrameURL") >>= aStr;
3222 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
3223 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3224 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3225 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3227 // export name
3228 xPropSet->getPropertyValue("FrameName") >>= aStr;
3229 if( !aStr.isEmpty() )
3230 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FRAME_NAME, aStr );
3232 // write floating frame
3234 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_FLOATING_FRAME, true, true);
3237 ImpExportDescription(xShape);
3240 void XMLShapeExport::ImpExportAppletShape(
3241 const uno::Reference< drawing::XShape >& xShape,
3242 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3244 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3245 if(!xPropSet.is())
3246 return;
3248 // Transformation
3249 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3251 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3252 SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
3253 XML_FRAME, bCreateNewline, true );
3255 // export frame url
3256 OUString aStr;
3257 xPropSet->getPropertyValue("AppletCodeBase") >>= aStr;
3258 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
3259 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3260 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3261 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3263 // export draw:applet-name
3264 xPropSet->getPropertyValue("AppletName") >>= aStr;
3265 if( !aStr.isEmpty() )
3266 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_APPLET_NAME, aStr );
3268 // export draw:code
3269 xPropSet->getPropertyValue("AppletCode") >>= aStr;
3270 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CODE, aStr );
3272 // export draw:may-script
3273 bool bIsScript = false;
3274 xPropSet->getPropertyValue("AppletIsScript") >>= bIsScript;
3275 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MAY_SCRIPT, bIsScript ? XML_TRUE : XML_FALSE );
3278 // write applet
3279 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_APPLET, true, true);
3281 // export parameters
3282 uno::Sequence< beans::PropertyValue > aCommands;
3283 xPropSet->getPropertyValue("AppletCommands") >>= aCommands;
3284 for( const auto& rCommand : std::as_const(aCommands) )
3286 rCommand.Value >>= aStr;
3287 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rCommand.Name );
3288 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr );
3289 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3293 ImpExportDescription(xShape);
3296 void XMLShapeExport::ImpExportPluginShape(
3297 const uno::Reference< drawing::XShape >& xShape,
3298 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3300 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3301 if(!xPropSet.is())
3302 return;
3304 // Transformation
3305 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3307 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3308 SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW,
3309 XML_FRAME, bCreateNewline, true );
3311 // export plugin url
3312 OUString aStr;
3313 xPropSet->getPropertyValue("PluginURL") >>= aStr;
3314 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, GetExport().GetRelativeReference(aStr) );
3315 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3316 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3317 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3319 // export mime-type
3320 xPropSet->getPropertyValue("PluginMimeType") >>= aStr;
3321 if(!aStr.isEmpty())
3322 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, aStr );
3325 // write plugin
3326 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, true, true);
3328 // export parameters
3329 uno::Sequence< beans::PropertyValue > aCommands;
3330 xPropSet->getPropertyValue("PluginCommands") >>= aCommands;
3331 for( const auto& rCommand : std::as_const(aCommands) )
3333 rCommand.Value >>= aStr;
3334 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, rCommand.Name );
3335 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aStr );
3336 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3340 ImpExportDescription(xShape);
3343 static void lcl_CopyStream(
3344 uno::Reference<io::XInputStream> const& xInStream,
3345 uno::Reference<embed::XStorage> const& xTarget,
3346 OUString const& rPath, const OUString& rMimeType)
3348 ::comphelper::LifecycleProxy proxy;
3349 uno::Reference<io::XStream> const xStream(
3350 ::comphelper::OStorageHelper::GetStreamAtPackageURL(xTarget, rPath,
3351 embed::ElementModes::WRITE | embed::ElementModes::TRUNCATE, proxy));
3352 uno::Reference<io::XOutputStream> const xOutStream(
3353 (xStream.is()) ? xStream->getOutputStream() : nullptr);
3354 if (!xOutStream.is())
3356 SAL_WARN("xmloff", "no output stream");
3357 throw uno::Exception("no output stream",nullptr);
3359 uno::Reference< beans::XPropertySet > const xStreamProps(xStream,
3360 uno::UNO_QUERY);
3361 if (xStreamProps.is()) { // this is NOT supported in FileSystemStorage
3362 xStreamProps->setPropertyValue("MediaType",
3363 uno::Any(rMimeType));
3364 xStreamProps->setPropertyValue( // turn off compression
3365 "Compressed",
3366 uno::Any(false));
3368 ::comphelper::OStorageHelper::CopyInputToOutput(xInStream, xOutStream);
3369 xOutStream->closeOutput();
3370 proxy.commitStorages();
3373 static OUString
3374 lcl_StoreMediaAndGetURL(SvXMLExport & rExport,
3375 uno::Reference<beans::XPropertySet> const& xPropSet,
3376 OUString const& rURL, const OUString& rMimeType)
3378 OUString urlPath;
3379 if (rURL.startsWithIgnoreAsciiCase("vnd.sun.star.Package:", &urlPath))
3381 try // video is embedded
3383 uno::Reference<embed::XStorage> const xTarget(
3384 rExport.GetTargetStorage(), uno::UNO_SET_THROW);
3385 uno::Reference<io::XInputStream> xInStream;
3386 xPropSet->getPropertyValue("PrivateStream")
3387 >>= xInStream;
3389 if (!xInStream.is())
3391 SAL_WARN("xmloff", "no input stream");
3392 return OUString();
3395 lcl_CopyStream(xInStream, xTarget, rURL, rMimeType);
3397 return urlPath;
3399 catch (uno::Exception const&)
3401 TOOLS_INFO_EXCEPTION("xmloff", "exception while storing embedded media");
3403 return OUString();
3405 else
3407 return rExport.GetRelativeReference(rURL); // linked
3411 namespace
3413 void ExportGraphicPreview(const uno::Reference<graphic::XGraphic>& xGraphic, SvXMLExport& rExport, const std::u16string_view& rPrefix, const std::u16string_view& rExtension, const OUString& rMimeType)
3415 const bool bExportEmbedded(rExport.getExportFlags() & SvXMLExportFlags::EMBEDDED);
3417 if( xGraphic.is() ) try
3419 uno::Reference< uno::XComponentContext > xContext = rExport.getComponentContext();
3421 uno::Reference< embed::XStorage > xPictureStorage;
3422 uno::Reference< embed::XStorage > xStorage;
3423 uno::Reference< io::XStream > xPictureStream;
3425 OUString sPictureName;
3426 if( bExportEmbedded )
3428 xPictureStream.set( xContext->getServiceManager()->createInstanceWithContext( "com.sun.star.comp.MemoryStream", xContext), uno::UNO_QUERY_THROW );
3430 else
3432 xStorage.set( rExport.GetTargetStorage(), uno::UNO_SET_THROW );
3434 xPictureStorage.set( xStorage->openStorageElement( "Pictures" , ::embed::ElementModes::READWRITE ), uno::UNO_SET_THROW );
3436 sal_Int32 nIndex = 0;
3439 sPictureName = rPrefix + OUString::number( ++nIndex ) + rExtension;
3441 while( xPictureStorage->hasByName( sPictureName ) );
3443 xPictureStream.set( xPictureStorage->openStreamElement( sPictureName, ::embed::ElementModes::READWRITE ), uno::UNO_SET_THROW );
3446 uno::Reference< graphic::XGraphicProvider > xProvider( graphic::GraphicProvider::create(xContext) );
3447 uno::Sequence< beans::PropertyValue > aArgs{
3448 comphelper::makePropertyValue("MimeType", rMimeType ),
3449 comphelper::makePropertyValue("OutputStream", xPictureStream->getOutputStream())
3451 xProvider->storeGraphic( xGraphic, aArgs );
3453 if( xPictureStorage.is() )
3455 uno::Reference< embed::XTransactedObject > xTrans( xPictureStorage, uno::UNO_QUERY );
3456 if( xTrans.is() )
3457 xTrans->commit();
3460 if( !bExportEmbedded )
3462 OUString sURL = "Pictures/" + sPictureName;
3463 rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_HREF, sURL );
3464 rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3465 rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3466 rExport.AddAttribute( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3469 SvXMLElementExport aElem( rExport, XML_NAMESPACE_DRAW, XML_IMAGE, false, true );
3471 if( bExportEmbedded )
3473 uno::Reference< io::XSeekableInputStream > xSeekable( xPictureStream, uno::UNO_QUERY_THROW );
3474 xSeekable->seek(0);
3476 XMLBase64Export aBase64Exp( rExport );
3477 aBase64Exp.exportOfficeBinaryDataElement( uno::Reference < io::XInputStream >( xPictureStream, uno::UNO_QUERY_THROW ) );
3480 catch( uno::Exception const & )
3482 DBG_UNHANDLED_EXCEPTION("xmloff.draw");
3487 void XMLShapeExport::ImpExportMediaShape(
3488 const uno::Reference< drawing::XShape >& xShape,
3489 XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint)
3491 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3492 if(!xPropSet.is())
3493 return;
3495 // Transformation
3496 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3498 if(eShapeType == XmlShapeType::PresMediaShape)
3500 (void)ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_OBJECT) );
3502 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3503 SvXMLElementExport aElem( mrExport, XML_NAMESPACE_DRAW,
3504 XML_FRAME, bCreateNewline, true );
3506 // export media url
3507 OUString aMediaURL;
3508 xPropSet->getPropertyValue("MediaURL") >>= aMediaURL;
3509 OUString sMimeType;
3510 xPropSet->getPropertyValue("MediaMimeType") >>= sMimeType;
3512 OUString const persistentURL =
3513 lcl_StoreMediaAndGetURL(GetExport(), xPropSet, aMediaURL, sMimeType);
3515 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_HREF, persistentURL );
3516 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_TYPE, XML_SIMPLE );
3517 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_SHOW, XML_EMBED );
3518 mrExport.AddAttribute ( XML_NAMESPACE_XLINK, XML_ACTUATE, XML_ONLOAD );
3520 // export mime-type
3521 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIME_TYPE, sMimeType );
3523 // write plugin
3524 auto pPluginOBJ = std::make_unique<SvXMLElementExport>(mrExport, XML_NAMESPACE_DRAW, XML_PLUGIN, !( nFeatures & XMLShapeExportFlags::NO_WS ), true);
3526 // export parameters
3527 const OUString aFalseStr( "false" ), aTrueStr( "true" );
3529 bool bLoop = false;
3530 static const OUStringLiteral aLoopStr( u"Loop" );
3531 xPropSet->getPropertyValue( aLoopStr ) >>= bLoop;
3532 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aLoopStr );
3533 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, bLoop ? aTrueStr : aFalseStr );
3534 delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3536 bool bMute = false;
3537 static const OUStringLiteral aMuteStr( u"Mute" );
3538 xPropSet->getPropertyValue( aMuteStr ) >>= bMute;
3539 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aMuteStr );
3540 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, bMute ? aTrueStr : aFalseStr );
3541 delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3543 sal_Int16 nVolumeDB = 0;
3544 xPropSet->getPropertyValue("VolumeDB") >>= nVolumeDB;
3545 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, "VolumeDB" );
3546 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, OUString::number( nVolumeDB ) );
3547 delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3549 media::ZoomLevel eZoom;
3550 OUString aZoomValue;
3551 xPropSet->getPropertyValue("Zoom") >>= eZoom;
3552 switch( eZoom )
3554 case media::ZoomLevel_ZOOM_1_TO_4 : aZoomValue = "25%"; break;
3555 case media::ZoomLevel_ZOOM_1_TO_2 : aZoomValue = "50%"; break;
3556 case media::ZoomLevel_ORIGINAL : aZoomValue = "100%"; break;
3557 case media::ZoomLevel_ZOOM_2_TO_1 : aZoomValue = "200%"; break;
3558 case media::ZoomLevel_ZOOM_4_TO_1 : aZoomValue = "400%"; break;
3559 case media::ZoomLevel_FIT_TO_WINDOW: aZoomValue = "fit"; break;
3560 case media::ZoomLevel_FIT_TO_WINDOW_FIXED_ASPECT: aZoomValue = "fixedfit"; break;
3561 case media::ZoomLevel_FULLSCREEN : aZoomValue = "fullscreen"; break;
3563 default:
3564 break;
3567 if( !aZoomValue.isEmpty() )
3569 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, "Zoom" );
3570 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_VALUE, aZoomValue );
3571 delete new SvXMLElementExport( mrExport, XML_NAMESPACE_DRAW, XML_PARAM, false, true );
3574 pPluginOBJ.reset();
3576 uno::Reference<graphic::XGraphic> xGraphic;
3577 xPropSet->getPropertyValue("Graphic") >>= xGraphic;
3578 Graphic aGraphic(xGraphic);
3579 if (!aGraphic.IsNone())
3581 // The media has a preview, export it.
3582 ExportGraphicPreview(xGraphic, mrExport, u"MediaPreview", u".png", "image/png");
3585 ImpExportDescription(xShape);
3588 void XMLShapeExport::ImpExport3DSceneShape( const uno::Reference< drawing::XShape >& xShape, XMLShapeExportFlags nFeatures, awt::Point* pRefPoint)
3590 uno::Reference< drawing::XShapes > xShapes(xShape, uno::UNO_QUERY);
3591 if(!(xShapes.is() && xShapes->getCount()))
3592 return;
3594 uno::Reference< beans::XPropertySet > xPropSet( xShape, uno::UNO_QUERY );
3595 SAL_WARN_IF( !xPropSet.is(), "xmloff", "XMLShapeExport::ImpExport3DSceneShape can't export a scene without a propertyset" );
3596 if( !xPropSet.is() )
3597 return;
3599 // Transformation
3600 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
3602 // 3d attributes
3603 export3DSceneAttributes( xPropSet );
3605 // write 3DScene shape
3606 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
3607 SvXMLElementExport aOBJ( mrExport, XML_NAMESPACE_DR3D, XML_SCENE, bCreateNewline, true);
3609 ImpExportDescription( xShape ); // #i68101#
3610 ImpExportEvents( xShape );
3612 // write 3DSceneLights
3613 export3DLamps( xPropSet );
3615 // #89764# if export of position is suppressed for group shape,
3616 // positions of contained objects should be written relative to
3617 // the upper left edge of the group.
3618 awt::Point aUpperLeft;
3620 if(!(nFeatures & XMLShapeExportFlags::POSITION))
3622 nFeatures |= XMLShapeExportFlags::POSITION;
3623 aUpperLeft = xShape->getPosition();
3624 pRefPoint = &aUpperLeft;
3627 // write members
3628 exportShapes( xShapes, nFeatures, pRefPoint );
3631 void XMLShapeExport::ImpExport3DShape(
3632 const uno::Reference< drawing::XShape >& xShape,
3633 XmlShapeType eShapeType)
3635 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
3636 if(!xPropSet.is())
3637 return;
3639 OUString aStr;
3640 OUStringBuffer sStringBuffer;
3642 // transformation (UNO_NAME_3D_TRANSFORM_MATRIX == "D3DTransformMatrix")
3643 uno::Any aAny = xPropSet->getPropertyValue("D3DTransformMatrix");
3644 drawing::HomogenMatrix aHomMat;
3645 aAny >>= aHomMat;
3646 SdXMLImExTransform3D aTransform;
3647 aTransform.AddHomogenMatrix(aHomMat);
3648 if(aTransform.NeedsAction())
3649 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
3651 switch(eShapeType)
3653 case XmlShapeType::Draw3DCubeObject:
3655 // minEdge
3656 aAny = xPropSet->getPropertyValue("D3DPosition");
3657 drawing::Position3D aPosition3D;
3658 aAny >>= aPosition3D;
3659 ::basegfx::B3DVector aPos3D(aPosition3D.PositionX, aPosition3D.PositionY, aPosition3D.PositionZ);
3661 // maxEdge
3662 aAny = xPropSet->getPropertyValue("D3DSize");
3663 drawing::Direction3D aDirection3D;
3664 aAny >>= aDirection3D;
3665 ::basegfx::B3DVector aDir3D(aDirection3D.DirectionX, aDirection3D.DirectionY, aDirection3D.DirectionZ);
3667 // transform maxEdge from distance to pos
3668 aDir3D = aPos3D + aDir3D;
3670 // write minEdge
3671 if(aPos3D != ::basegfx::B3DVector(-2500.0, -2500.0, -2500.0)) // write only when not default
3673 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aPos3D);
3674 aStr = sStringBuffer.makeStringAndClear();
3675 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_MIN_EDGE, aStr);
3678 // write maxEdge
3679 if(aDir3D != ::basegfx::B3DVector(2500.0, 2500.0, 2500.0)) // write only when not default
3681 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aDir3D);
3682 aStr = sStringBuffer.makeStringAndClear();
3683 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_MAX_EDGE, aStr);
3686 // write 3DCube shape
3687 // #i123542# Do this *after* the attributes are added, else these will be lost since opening
3688 // the scope will clear the global attribute list at the exporter
3689 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_CUBE, true, true);
3691 break;
3693 case XmlShapeType::Draw3DSphereObject:
3695 // Center
3696 aAny = xPropSet->getPropertyValue("D3DPosition");
3697 drawing::Position3D aPosition3D;
3698 aAny >>= aPosition3D;
3699 ::basegfx::B3DVector aPos3D(aPosition3D.PositionX, aPosition3D.PositionY, aPosition3D.PositionZ);
3701 // Size
3702 aAny = xPropSet->getPropertyValue("D3DSize");
3703 drawing::Direction3D aDirection3D;
3704 aAny >>= aDirection3D;
3705 ::basegfx::B3DVector aDir3D(aDirection3D.DirectionX, aDirection3D.DirectionY, aDirection3D.DirectionZ);
3707 // write Center
3708 if(aPos3D != ::basegfx::B3DVector(0.0, 0.0, 0.0)) // write only when not default
3710 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aPos3D);
3711 aStr = sStringBuffer.makeStringAndClear();
3712 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_CENTER, aStr);
3715 // write Size
3716 if(aDir3D != ::basegfx::B3DVector(5000.0, 5000.0, 5000.0)) // write only when not default
3718 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aDir3D);
3719 aStr = sStringBuffer.makeStringAndClear();
3720 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SIZE, aStr);
3723 // write 3DSphere shape
3724 // #i123542# Do this *after* the attributes are added, else these will be lost since opening
3725 // the scope will clear the global attribute list at the exporter
3726 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_SPHERE, true, true);
3728 break;
3730 case XmlShapeType::Draw3DLatheObject:
3731 case XmlShapeType::Draw3DExtrudeObject:
3733 // write special 3DLathe/3DExtrude attributes, get 3D tools::PolyPolygon as drawing::PolyPolygonShape3D
3734 aAny = xPropSet->getPropertyValue("D3DPolyPolygon3D");
3735 drawing::PolyPolygonShape3D aUnoPolyPolygon3D;
3736 aAny >>= aUnoPolyPolygon3D;
3738 // convert to 3D PolyPolygon
3739 const basegfx::B3DPolyPolygon aPolyPolygon3D(
3740 basegfx::utils::UnoPolyPolygonShape3DToB3DPolyPolygon(
3741 aUnoPolyPolygon3D));
3743 // convert to 2D tools::PolyPolygon using identity 3D transformation (just grep X and Y)
3744 const basegfx::B3DHomMatrix aB3DHomMatrixFor2DConversion;
3745 const basegfx::B2DPolyPolygon aPolyPolygon(
3746 basegfx::utils::createB2DPolyPolygonFromB3DPolyPolygon(
3747 aPolyPolygon3D,
3748 aB3DHomMatrixFor2DConversion));
3750 // get 2D range of it
3751 const basegfx::B2DRange aPolyPolygonRange(aPolyPolygon.getB2DRange());
3753 // export ViewBox
3754 SdXMLImExViewBox aViewBox(
3755 aPolyPolygonRange.getMinX(),
3756 aPolyPolygonRange.getMinY(),
3757 aPolyPolygonRange.getWidth(),
3758 aPolyPolygonRange.getHeight());
3760 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString());
3762 // prepare svg:d string
3763 const OUString aPolygonString(
3764 basegfx::utils::exportToSvgD(
3765 aPolyPolygon,
3766 true, // bUseRelativeCoordinates
3767 false, // bDetectQuadraticBeziers TTTT: not used in old, but maybe activated now
3768 true)); // bHandleRelativeNextPointCompatible
3770 // write point array
3771 mrExport.AddAttribute(XML_NAMESPACE_SVG, XML_D, aPolygonString);
3773 if(eShapeType == XmlShapeType::Draw3DLatheObject)
3775 // write 3DLathe shape
3776 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_ROTATE, true, true);
3778 else
3780 // write 3DExtrude shape
3781 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_EXTRUDE, true, true);
3783 break;
3785 default:
3786 break;
3790 /** helper for chart that adds all attributes of a 3d scene element to the export */
3791 void XMLShapeExport::export3DSceneAttributes( const css::uno::Reference< css::beans::XPropertySet >& xPropSet )
3793 OUString aStr;
3794 OUStringBuffer sStringBuffer;
3796 // world transformation (UNO_NAME_3D_TRANSFORM_MATRIX == "D3DTransformMatrix")
3797 uno::Any aAny = xPropSet->getPropertyValue("D3DTransformMatrix");
3798 drawing::HomogenMatrix aHomMat;
3799 aAny >>= aHomMat;
3800 SdXMLImExTransform3D aTransform;
3801 aTransform.AddHomogenMatrix(aHomMat);
3802 if(aTransform.NeedsAction())
3803 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_TRANSFORM, aTransform.GetExportString(mrExport.GetMM100UnitConverter()));
3805 // VRP, VPN, VUP
3806 aAny = xPropSet->getPropertyValue("D3DCameraGeometry");
3807 drawing::CameraGeometry aCamGeo;
3808 aAny >>= aCamGeo;
3810 ::basegfx::B3DVector aVRP(aCamGeo.vrp.PositionX, aCamGeo.vrp.PositionY, aCamGeo.vrp.PositionZ);
3811 if(aVRP != ::basegfx::B3DVector(0.0, 0.0, 1.0)) // write only when not default
3813 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVRP);
3814 aStr = sStringBuffer.makeStringAndClear();
3815 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VRP, aStr);
3818 ::basegfx::B3DVector aVPN(aCamGeo.vpn.DirectionX, aCamGeo.vpn.DirectionY, aCamGeo.vpn.DirectionZ);
3819 if(aVPN != ::basegfx::B3DVector(0.0, 0.0, 1.0)) // write only when not default
3821 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVPN);
3822 aStr = sStringBuffer.makeStringAndClear();
3823 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VPN, aStr);
3826 ::basegfx::B3DVector aVUP(aCamGeo.vup.DirectionX, aCamGeo.vup.DirectionY, aCamGeo.vup.DirectionZ);
3827 if(aVUP != ::basegfx::B3DVector(0.0, 1.0, 0.0)) // write only when not default
3829 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aVUP);
3830 aStr = sStringBuffer.makeStringAndClear();
3831 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_VUP, aStr);
3834 // projection "D3DScenePerspective" drawing::ProjectionMode
3835 aAny = xPropSet->getPropertyValue("D3DScenePerspective");
3836 drawing::ProjectionMode aPrjMode;
3837 aAny >>= aPrjMode;
3838 if(aPrjMode == drawing::ProjectionMode_PARALLEL)
3839 aStr = GetXMLToken(XML_PARALLEL);
3840 else
3841 aStr = GetXMLToken(XML_PERSPECTIVE);
3842 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_PROJECTION, aStr);
3844 // distance
3845 aAny = xPropSet->getPropertyValue("D3DSceneDistance");
3846 sal_Int32 nDistance = 0;
3847 aAny >>= nDistance;
3848 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
3849 nDistance);
3850 aStr = sStringBuffer.makeStringAndClear();
3851 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DISTANCE, aStr);
3853 // focalLength
3854 aAny = xPropSet->getPropertyValue("D3DSceneFocalLength");
3855 sal_Int32 nFocalLength = 0;
3856 aAny >>= nFocalLength;
3857 mrExport.GetMM100UnitConverter().convertMeasureToXML(sStringBuffer,
3858 nFocalLength);
3859 aStr = sStringBuffer.makeStringAndClear();
3860 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_FOCAL_LENGTH, aStr);
3862 // shadowSlant
3863 aAny = xPropSet->getPropertyValue("D3DSceneShadowSlant");
3864 sal_Int16 nShadowSlant = 0;
3865 aAny >>= nShadowSlant;
3866 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SHADOW_SLANT, OUString::number(static_cast<sal_Int32>(nShadowSlant)));
3868 // shadeMode
3869 aAny = xPropSet->getPropertyValue("D3DSceneShadeMode");
3870 drawing::ShadeMode aShadeMode;
3871 if(aAny >>= aShadeMode)
3873 if(aShadeMode == drawing::ShadeMode_FLAT)
3874 aStr = GetXMLToken(XML_FLAT);
3875 else if(aShadeMode == drawing::ShadeMode_PHONG)
3876 aStr = GetXMLToken(XML_PHONG);
3877 else if(aShadeMode == drawing::ShadeMode_SMOOTH)
3878 aStr = GetXMLToken(XML_GOURAUD);
3879 else
3880 aStr = GetXMLToken(XML_DRAFT);
3882 else
3884 // ShadeMode enum not there, write default
3885 aStr = GetXMLToken(XML_GOURAUD);
3887 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SHADE_MODE, aStr);
3889 // ambientColor
3890 aAny = xPropSet->getPropertyValue("D3DSceneAmbientColor");
3891 sal_Int32 nAmbientColor = 0;
3892 aAny >>= nAmbientColor;
3893 ::sax::Converter::convertColor(sStringBuffer, nAmbientColor);
3894 aStr = sStringBuffer.makeStringAndClear();
3895 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_AMBIENT_COLOR, aStr);
3897 // lightingMode
3898 aAny = xPropSet->getPropertyValue("D3DSceneTwoSidedLighting");
3899 bool bTwoSidedLighting = false;
3900 aAny >>= bTwoSidedLighting;
3901 ::sax::Converter::convertBool(sStringBuffer, bTwoSidedLighting);
3902 aStr = sStringBuffer.makeStringAndClear();
3903 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_LIGHTING_MODE, aStr);
3906 /** helper for chart that exports all lamps from the propertyset */
3907 void XMLShapeExport::export3DLamps( const css::uno::Reference< css::beans::XPropertySet >& xPropSet )
3909 // write lamps 1..8 as content
3910 OUString aStr;
3911 OUStringBuffer sStringBuffer;
3913 static const OUStringLiteral aColorPropName(u"D3DSceneLightColor");
3914 static const OUStringLiteral aDirectionPropName(u"D3DSceneLightDirection");
3915 static const OUStringLiteral aLightOnPropName(u"D3DSceneLightOn");
3917 ::basegfx::B3DVector aLightDirection;
3918 drawing::Direction3D aLightDir;
3919 bool bLightOnOff = false;
3920 for(sal_Int32 nLamp = 1; nLamp <= 8; nLamp++)
3922 OUString aIndexStr = OUString::number( nLamp );
3924 // lightcolor
3925 OUString aPropName = aColorPropName + aIndexStr;
3926 sal_Int32 nLightColor = 0;
3927 xPropSet->getPropertyValue( aPropName ) >>= nLightColor;
3928 ::sax::Converter::convertColor(sStringBuffer, nLightColor);
3929 aStr = sStringBuffer.makeStringAndClear();
3930 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DIFFUSE_COLOR, aStr);
3932 // lightdirection
3933 aPropName = aDirectionPropName + aIndexStr;
3934 xPropSet->getPropertyValue(aPropName) >>= aLightDir;
3935 aLightDirection = ::basegfx::B3DVector(aLightDir.DirectionX, aLightDir.DirectionY, aLightDir.DirectionZ);
3936 SvXMLUnitConverter::convertB3DVector(sStringBuffer, aLightDirection);
3937 aStr = sStringBuffer.makeStringAndClear();
3938 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_DIRECTION, aStr);
3940 // lighton
3941 aPropName = aLightOnPropName + aIndexStr;
3942 xPropSet->getPropertyValue(aPropName) >>= bLightOnOff;
3943 ::sax::Converter::convertBool(sStringBuffer, bLightOnOff);
3944 aStr = sStringBuffer.makeStringAndClear();
3945 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_ENABLED, aStr);
3947 // specular
3948 mrExport.AddAttribute(XML_NAMESPACE_DR3D, XML_SPECULAR,
3949 nLamp == 1 ? XML_TRUE : XML_FALSE);
3951 // write light entry
3952 SvXMLElementExport aOBJ(mrExport, XML_NAMESPACE_DR3D, XML_LIGHT, true, true);
3957 // using namespace css::io;
3958 // using namespace ::xmloff::EnhancedCustomShapeToken;
3961 static void ExportParameter( OUStringBuffer& rStrBuffer, const css::drawing::EnhancedCustomShapeParameter& rParameter )
3963 if ( !rStrBuffer.isEmpty() )
3964 rStrBuffer.append( ' ' );
3965 if ( rParameter.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
3967 double fNumber = 0.0;
3968 rParameter.Value >>= fNumber;
3969 ::rtl::math::doubleToUStringBuffer( rStrBuffer, fNumber, rtl_math_StringFormat_Automatic, rtl_math_DecimalPlaces_Max, '.', true );
3971 else
3973 sal_Int32 nValue = 0;
3974 rParameter.Value >>= nValue;
3976 switch( rParameter.Type )
3978 case css::drawing::EnhancedCustomShapeParameterType::EQUATION :
3980 rStrBuffer.append( "?f" + OUString::number( nValue ) );
3982 break;
3984 case css::drawing::EnhancedCustomShapeParameterType::ADJUSTMENT :
3986 rStrBuffer.append( '$' );
3987 rStrBuffer.append( nValue );
3989 break;
3991 case css::drawing::EnhancedCustomShapeParameterType::BOTTOM :
3992 rStrBuffer.append( GetXMLToken( XML_BOTTOM ) ); break;
3993 case css::drawing::EnhancedCustomShapeParameterType::RIGHT :
3994 rStrBuffer.append( GetXMLToken( XML_RIGHT ) ); break;
3995 case css::drawing::EnhancedCustomShapeParameterType::TOP :
3996 rStrBuffer.append( GetXMLToken( XML_TOP ) ); break;
3997 case css::drawing::EnhancedCustomShapeParameterType::LEFT :
3998 rStrBuffer.append( GetXMLToken( XML_LEFT ) ); break;
3999 case css::drawing::EnhancedCustomShapeParameterType::XSTRETCH :
4000 rStrBuffer.append( GetXMLToken( XML_XSTRETCH ) ); break;
4001 case css::drawing::EnhancedCustomShapeParameterType::YSTRETCH :
4002 rStrBuffer.append( GetXMLToken( XML_YSTRETCH ) ); break;
4003 case css::drawing::EnhancedCustomShapeParameterType::HASSTROKE :
4004 rStrBuffer.append( GetXMLToken( XML_HASSTROKE ) ); break;
4005 case css::drawing::EnhancedCustomShapeParameterType::HASFILL :
4006 rStrBuffer.append( GetXMLToken( XML_HASFILL ) ); break;
4007 case css::drawing::EnhancedCustomShapeParameterType::WIDTH :
4008 rStrBuffer.append( GetXMLToken( XML_WIDTH ) ); break;
4009 case css::drawing::EnhancedCustomShapeParameterType::HEIGHT :
4010 rStrBuffer.append( GetXMLToken( XML_HEIGHT ) ); break;
4011 case css::drawing::EnhancedCustomShapeParameterType::LOGWIDTH :
4012 rStrBuffer.append( GetXMLToken( XML_LOGWIDTH ) ); break;
4013 case css::drawing::EnhancedCustomShapeParameterType::LOGHEIGHT :
4014 rStrBuffer.append( GetXMLToken( XML_LOGHEIGHT ) ); break;
4015 default :
4016 rStrBuffer.append( nValue );
4021 static void ImpExportEquations( SvXMLExport& rExport, const uno::Sequence< OUString >& rEquations )
4023 sal_Int32 i;
4024 for ( i = 0; i < rEquations.getLength(); i++ )
4026 OUString aStr= "f" + OUString::number( i );
4027 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_NAME, aStr );
4029 aStr = rEquations[ i ];
4030 sal_Int32 nIndex = 0;
4033 nIndex = aStr.indexOf( '?', nIndex );
4034 if ( nIndex != -1 )
4036 aStr = OUString::Concat(aStr.subView(0, nIndex + 1)) + "f"
4037 + aStr.subView(nIndex + 1, aStr.getLength() - nIndex - 1);
4038 nIndex++;
4040 } while( nIndex != -1 );
4041 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_FORMULA, aStr );
4042 SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_EQUATION, true, true );
4046 static void ImpExportHandles( SvXMLExport& rExport, const uno::Sequence< beans::PropertyValues >& rHandles )
4048 if ( !rHandles.hasElements() )
4049 return;
4051 OUString aStr;
4052 OUStringBuffer aStrBuffer;
4054 for ( const uno::Sequence< beans::PropertyValue >& rPropSeq : rHandles )
4056 bool bPosition = false;
4057 for ( const beans::PropertyValue& rPropVal : rPropSeq )
4059 switch( EASGet( rPropVal.Name ) )
4061 case EAS_Position :
4063 css::drawing::EnhancedCustomShapeParameterPair aPosition;
4064 if ( rPropVal.Value >>= aPosition )
4066 ExportParameter( aStrBuffer, aPosition.First );
4067 ExportParameter( aStrBuffer, aPosition.Second );
4068 aStr = aStrBuffer.makeStringAndClear();
4069 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POSITION, aStr );
4070 bPosition = true;
4073 break;
4074 case EAS_MirroredX :
4076 bool bMirroredX;
4077 if ( rPropVal.Value >>= bMirroredX )
4078 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_MIRROR_HORIZONTAL,
4079 bMirroredX ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4081 break;
4082 case EAS_MirroredY :
4084 bool bMirroredY;
4085 if ( rPropVal.Value >>= bMirroredY )
4086 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_MIRROR_VERTICAL,
4087 bMirroredY ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4089 break;
4090 case EAS_Switched :
4092 bool bSwitched;
4093 if ( rPropVal.Value >>= bSwitched )
4094 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_SWITCHED,
4095 bSwitched ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4097 break;
4098 case EAS_Polar :
4100 css::drawing::EnhancedCustomShapeParameterPair aPolar;
4101 if ( rPropVal.Value >>= aPolar )
4103 ExportParameter( aStrBuffer, aPolar.First );
4104 ExportParameter( aStrBuffer, aPolar.Second );
4105 aStr = aStrBuffer.makeStringAndClear();
4106 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_POLAR, aStr );
4109 break;
4110 case EAS_RadiusRangeMinimum :
4112 css::drawing::EnhancedCustomShapeParameter aRadiusRangeMinimum;
4113 if ( rPropVal.Value >>= aRadiusRangeMinimum )
4115 ExportParameter( aStrBuffer, aRadiusRangeMinimum );
4116 aStr = aStrBuffer.makeStringAndClear();
4117 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RADIUS_RANGE_MINIMUM, aStr );
4120 break;
4121 case EAS_RadiusRangeMaximum :
4123 css::drawing::EnhancedCustomShapeParameter aRadiusRangeMaximum;
4124 if ( rPropVal.Value >>= aRadiusRangeMaximum )
4126 ExportParameter( aStrBuffer, aRadiusRangeMaximum );
4127 aStr = aStrBuffer.makeStringAndClear();
4128 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RADIUS_RANGE_MAXIMUM, aStr );
4131 break;
4132 case EAS_RangeXMinimum :
4134 css::drawing::EnhancedCustomShapeParameter aXRangeMinimum;
4135 if ( rPropVal.Value >>= aXRangeMinimum )
4137 ExportParameter( aStrBuffer, aXRangeMinimum );
4138 aStr = aStrBuffer.makeStringAndClear();
4139 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_X_MINIMUM, aStr );
4142 break;
4143 case EAS_RangeXMaximum :
4145 css::drawing::EnhancedCustomShapeParameter aXRangeMaximum;
4146 if ( rPropVal.Value >>= aXRangeMaximum )
4148 ExportParameter( aStrBuffer, aXRangeMaximum );
4149 aStr = aStrBuffer.makeStringAndClear();
4150 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_X_MAXIMUM, aStr );
4153 break;
4154 case EAS_RangeYMinimum :
4156 css::drawing::EnhancedCustomShapeParameter aYRangeMinimum;
4157 if ( rPropVal.Value >>= aYRangeMinimum )
4159 ExportParameter( aStrBuffer, aYRangeMinimum );
4160 aStr = aStrBuffer.makeStringAndClear();
4161 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_Y_MINIMUM, aStr );
4164 break;
4165 case EAS_RangeYMaximum :
4167 css::drawing::EnhancedCustomShapeParameter aYRangeMaximum;
4168 if ( rPropVal.Value >>= aYRangeMaximum )
4170 ExportParameter( aStrBuffer, aYRangeMaximum );
4171 aStr = aStrBuffer.makeStringAndClear();
4172 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_HANDLE_RANGE_Y_MAXIMUM, aStr );
4175 break;
4176 default:
4177 break;
4180 if ( bPosition )
4181 SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_HANDLE, true, true );
4182 else
4183 rExport.ClearAttrList();
4187 static void ImpExportEnhancedPath( SvXMLExport& rExport,
4188 const uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair >& rCoordinates,
4189 const uno::Sequence< css::drawing::EnhancedCustomShapeSegment >& rSegments,
4190 bool bExtended = false )
4193 OUString aStr;
4194 OUStringBuffer aStrBuffer;
4195 bool bNeedExtended = false;
4197 sal_Int32 i, j, k, l;
4199 sal_Int32 nCoords = rCoordinates.getLength();
4200 sal_Int32 nSegments = rSegments.getLength();
4201 bool bSimpleSegments = nSegments == 0;
4202 if ( bSimpleSegments )
4203 nSegments = 4;
4204 for ( j = i = 0; j < nSegments; j++ )
4206 css::drawing::EnhancedCustomShapeSegment aSegment;
4207 if ( bSimpleSegments )
4209 // if there are not enough segments we will default them
4210 switch( j )
4212 case 0 :
4214 aSegment.Count = 1;
4215 aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO;
4217 break;
4218 case 1 :
4220 aSegment.Count = static_cast<sal_Int16>(std::min( nCoords - 1, sal_Int32(32767) ));
4221 aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO;
4223 break;
4224 case 2 :
4226 aSegment.Count = 1;
4227 aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH;
4229 break;
4230 case 3 :
4232 aSegment.Count = 1;
4233 aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH;
4235 break;
4238 else
4239 aSegment = rSegments[ j ];
4241 if ( !aStrBuffer.isEmpty() )
4242 aStrBuffer.append( ' ' );
4244 sal_Int32 nParameter = 0;
4245 switch( aSegment.Command )
4247 case css::drawing::EnhancedCustomShapeSegmentCommand::CLOSESUBPATH :
4248 aStrBuffer.append( 'Z' ); break;
4249 case css::drawing::EnhancedCustomShapeSegmentCommand::ENDSUBPATH :
4250 aStrBuffer.append( 'N' ); break;
4251 case css::drawing::EnhancedCustomShapeSegmentCommand::NOFILL :
4252 aStrBuffer.append( 'F' ); break;
4253 case css::drawing::EnhancedCustomShapeSegmentCommand::NOSTROKE :
4254 aStrBuffer.append( 'S' ); break;
4256 case css::drawing::EnhancedCustomShapeSegmentCommand::MOVETO :
4257 aStrBuffer.append( 'M' ); nParameter = 1; break;
4258 case css::drawing::EnhancedCustomShapeSegmentCommand::LINETO :
4259 aStrBuffer.append( 'L' ); nParameter = 1; break;
4260 case css::drawing::EnhancedCustomShapeSegmentCommand::CURVETO :
4261 aStrBuffer.append( 'C' ); nParameter = 3; break;
4262 case css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSETO :
4263 aStrBuffer.append( 'T' ); nParameter = 3; break;
4264 case css::drawing::EnhancedCustomShapeSegmentCommand::ANGLEELLIPSE :
4265 aStrBuffer.append( 'U' ); nParameter = 3; break;
4266 case css::drawing::EnhancedCustomShapeSegmentCommand::ARCTO :
4267 aStrBuffer.append( 'A' ); nParameter = 4; break;
4268 case css::drawing::EnhancedCustomShapeSegmentCommand::ARC :
4269 aStrBuffer.append( 'B' ); nParameter = 4; break;
4270 case css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARCTO :
4271 aStrBuffer.append( 'W' ); nParameter = 4; break;
4272 case css::drawing::EnhancedCustomShapeSegmentCommand::CLOCKWISEARC :
4273 aStrBuffer.append( 'V' ); nParameter = 4; break;
4274 case css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTX :
4275 aStrBuffer.append( 'X' ); nParameter = 1; break;
4276 case css::drawing::EnhancedCustomShapeSegmentCommand::ELLIPTICALQUADRANTY :
4277 aStrBuffer.append( 'Y' ); nParameter = 1; break;
4278 case css::drawing::EnhancedCustomShapeSegmentCommand::QUADRATICCURVETO :
4279 aStrBuffer.append( 'Q' ); nParameter = 2; break;
4280 case css::drawing::EnhancedCustomShapeSegmentCommand::ARCANGLETO :
4281 if ( bExtended ) {
4282 aStrBuffer.append( 'G' );
4283 nParameter = 2;
4284 } else {
4285 aStrBuffer.setLength( aStrBuffer.getLength() - 1);
4286 bNeedExtended = true;
4287 i += 2;
4289 break;
4290 case css::drawing::EnhancedCustomShapeSegmentCommand::DARKEN :
4291 if ( bExtended )
4292 aStrBuffer.append( 'H' );
4293 else
4294 bNeedExtended = true;
4295 break;
4296 case css::drawing::EnhancedCustomShapeSegmentCommand::DARKENLESS :
4297 if ( bExtended )
4298 aStrBuffer.append( 'I' );
4299 else
4300 bNeedExtended = true;
4301 break;
4302 case css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTEN :
4303 if ( bExtended )
4304 aStrBuffer.append( 'J' );
4305 else
4306 bNeedExtended = true;
4307 break;
4308 case css::drawing::EnhancedCustomShapeSegmentCommand::LIGHTENLESS :
4309 if ( bExtended )
4310 aStrBuffer.append( 'K' );
4311 else
4312 bNeedExtended = true;
4313 break;
4314 default : // ups, seems to be something wrong
4316 aSegment.Count = 1;
4317 aSegment.Command = css::drawing::EnhancedCustomShapeSegmentCommand::LINETO;
4319 break;
4321 if ( nParameter )
4323 for ( k = 0; k < aSegment.Count; k++ )
4325 if ( ( i + nParameter ) <= nCoords )
4327 for ( l = 0; l < nParameter; l++ )
4329 ExportParameter( aStrBuffer, rCoordinates[ i ].First );
4330 ExportParameter( aStrBuffer, rCoordinates[ i++ ].Second );
4333 else
4335 j = nSegments; // error -> exiting
4336 break;
4341 aStr = aStrBuffer.makeStringAndClear();
4342 rExport.AddAttribute( bExtended ? XML_NAMESPACE_DRAW_EXT : XML_NAMESPACE_DRAW, XML_ENHANCED_PATH, aStr );
4343 if (!bExtended && bNeedExtended && (rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED))
4344 ImpExportEnhancedPath( rExport, rCoordinates, rSegments, true );
4347 static void ImpExportEnhancedGeometry( SvXMLExport& rExport, const uno::Reference< beans::XPropertySet >& xPropSet )
4349 bool bEquations = false;
4350 uno::Sequence< OUString > aEquations;
4352 bool bHandles = false;
4353 uno::Sequence< beans::PropertyValues > aHandles;
4355 uno::Sequence< css::drawing::EnhancedCustomShapeSegment > aSegments;
4356 uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair > aCoordinates;
4358 uno::Sequence< css::drawing::EnhancedCustomShapeAdjustmentValue > aAdjustmentValues;
4360 OUString aStr;
4361 OUStringBuffer aStrBuffer;
4362 double fTextRotateAngle(0.0);
4363 double fTextPreRotateAngle(0.0); // will be consolidated with fTextRotateAngle at the end
4364 SvXMLUnitConverter& rUnitConverter = rExport.GetMM100UnitConverter();
4366 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
4368 // geometry
4369 static const OUStringLiteral sCustomShapeGeometry( u"CustomShapeGeometry" );
4370 if ( xPropSetInfo.is() && xPropSetInfo->hasPropertyByName( sCustomShapeGeometry ) )
4372 uno::Any aGeoPropSet( xPropSet->getPropertyValue( sCustomShapeGeometry ) );
4373 uno::Sequence< beans::PropertyValue > aGeoPropSeq;
4375 if ( aGeoPropSet >>= aGeoPropSeq )
4377 bool bCoordinates = false;
4378 OUString aCustomShapeType( "non-primitive" );
4380 for ( const beans::PropertyValue& rGeoProp : std::as_const(aGeoPropSeq) )
4382 switch( EASGet( rGeoProp.Name ) )
4384 case EAS_Type :
4386 rGeoProp.Value >>= aCustomShapeType;
4388 break;
4389 case EAS_MirroredX :
4391 bool bMirroredX;
4392 if ( rGeoProp.Value >>= bMirroredX )
4393 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIRROR_HORIZONTAL,
4394 bMirroredX ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4396 break;
4397 case EAS_MirroredY :
4399 bool bMirroredY;
4400 if ( rGeoProp.Value >>= bMirroredY )
4401 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MIRROR_VERTICAL,
4402 bMirroredY ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4404 break;
4405 case EAS_ViewBox :
4407 awt::Rectangle aRect;
4408 if ( rGeoProp.Value >>= aRect )
4410 SdXMLImExViewBox aViewBox( aRect.X, aRect.Y, aRect.Width, aRect.Height );
4411 rExport.AddAttribute( XML_NAMESPACE_SVG, XML_VIEWBOX, aViewBox.GetExportString() );
4414 break;
4415 case EAS_TextPreRotateAngle :
4417 rGeoProp.Value >>= fTextPreRotateAngle;
4419 break;
4420 case EAS_TextRotateAngle :
4422 rGeoProp.Value >>= fTextRotateAngle;
4424 break;
4425 case EAS_Extrusion :
4427 uno::Sequence< beans::PropertyValue > aExtrusionPropSeq;
4428 if ( rGeoProp.Value >>= aExtrusionPropSeq )
4430 bool bSkewValuesProvided = false;
4431 for ( const beans::PropertyValue& rProp : std::as_const(aExtrusionPropSeq) )
4433 switch( EASGet( rProp.Name ) )
4435 case EAS_Extrusion :
4437 bool bExtrusionOn;
4438 if ( rProp.Value >>= bExtrusionOn )
4439 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION,
4440 bExtrusionOn ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4442 break;
4443 case EAS_Brightness :
4445 double fExtrusionBrightness = 0;
4446 if ( rProp.Value >>= fExtrusionBrightness )
4448 ::sax::Converter::convertDouble(
4449 aStrBuffer,
4450 fExtrusionBrightness,
4451 false,
4452 util::MeasureUnit::PERCENT,
4453 util::MeasureUnit::PERCENT);
4454 aStrBuffer.append( '%' );
4455 aStr = aStrBuffer.makeStringAndClear();
4456 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_BRIGHTNESS, aStr );
4459 break;
4460 case EAS_Depth :
4462 css::drawing::EnhancedCustomShapeParameterPair aDepthParaPair;
4463 if ( rProp.Value >>= aDepthParaPair )
4465 double fDepth = 0;
4466 if ( aDepthParaPair.First.Value >>= fDepth )
4468 rExport.GetMM100UnitConverter().convertDouble( aStrBuffer, fDepth );
4469 ExportParameter( aStrBuffer, aDepthParaPair.Second );
4470 aStr = aStrBuffer.makeStringAndClear();
4471 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_DEPTH, aStr );
4475 break;
4476 case EAS_Diffusion :
4478 double fExtrusionDiffusion = 0;
4479 if ( rProp.Value >>= fExtrusionDiffusion )
4481 ::sax::Converter::convertDouble(
4482 aStrBuffer,
4483 fExtrusionDiffusion,
4484 false,
4485 util::MeasureUnit::PERCENT,
4486 util::MeasureUnit::PERCENT);
4487 aStrBuffer.append( '%' );
4488 aStr = aStrBuffer.makeStringAndClear();
4489 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_DIFFUSION, aStr );
4492 break;
4493 case EAS_NumberOfLineSegments :
4495 sal_Int32 nExtrusionNumberOfLineSegments = 0;
4496 if ( rProp.Value >>= nExtrusionNumberOfLineSegments )
4497 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_NUMBER_OF_LINE_SEGMENTS, OUString::number( nExtrusionNumberOfLineSegments ) );
4499 break;
4500 case EAS_LightFace :
4502 bool bExtrusionLightFace;
4503 if ( rProp.Value >>= bExtrusionLightFace )
4504 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_LIGHT_FACE,
4505 bExtrusionLightFace ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4507 break;
4508 case EAS_FirstLightHarsh :
4510 bool bExtrusionFirstLightHarsh;
4511 if ( rProp.Value >>= bExtrusionFirstLightHarsh )
4512 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_HARSH,
4513 bExtrusionFirstLightHarsh ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4515 break;
4516 case EAS_SecondLightHarsh :
4518 bool bExtrusionSecondLightHarsh;
4519 if ( rProp.Value >>= bExtrusionSecondLightHarsh )
4520 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_HARSH,
4521 bExtrusionSecondLightHarsh ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4523 break;
4524 case EAS_FirstLightLevel :
4526 double fExtrusionFirstLightLevel = 0;
4527 if ( rProp.Value >>= fExtrusionFirstLightLevel )
4529 ::sax::Converter::convertDouble(
4530 aStrBuffer,
4531 fExtrusionFirstLightLevel,
4532 false,
4533 util::MeasureUnit::PERCENT,
4534 util::MeasureUnit::PERCENT);
4535 aStrBuffer.append( '%' );
4536 aStr = aStrBuffer.makeStringAndClear();
4537 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_LEVEL, aStr );
4540 break;
4541 case EAS_SecondLightLevel :
4543 double fExtrusionSecondLightLevel = 0;
4544 if ( rProp.Value >>= fExtrusionSecondLightLevel )
4546 ::sax::Converter::convertDouble(
4547 aStrBuffer,
4548 fExtrusionSecondLightLevel,
4549 false,
4550 util::MeasureUnit::PERCENT,
4551 util::MeasureUnit::PERCENT);
4552 aStrBuffer.append( '%' );
4553 aStr = aStrBuffer.makeStringAndClear();
4554 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_LEVEL, aStr );
4557 break;
4558 case EAS_FirstLightDirection :
4560 drawing::Direction3D aExtrusionFirstLightDirection;
4561 if ( rProp.Value >>= aExtrusionFirstLightDirection )
4563 ::basegfx::B3DVector aVec3D( aExtrusionFirstLightDirection.DirectionX, aExtrusionFirstLightDirection.DirectionY,
4564 aExtrusionFirstLightDirection.DirectionZ );
4565 SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D );
4566 aStr = aStrBuffer.makeStringAndClear();
4567 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_FIRST_LIGHT_DIRECTION, aStr );
4570 break;
4571 case EAS_SecondLightDirection :
4573 drawing::Direction3D aExtrusionSecondLightDirection;
4574 if ( rProp.Value >>= aExtrusionSecondLightDirection )
4576 ::basegfx::B3DVector aVec3D( aExtrusionSecondLightDirection.DirectionX, aExtrusionSecondLightDirection.DirectionY,
4577 aExtrusionSecondLightDirection.DirectionZ );
4578 SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D );
4579 aStr = aStrBuffer.makeStringAndClear();
4580 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SECOND_LIGHT_DIRECTION, aStr );
4583 break;
4584 case EAS_Metal :
4586 bool bExtrusionMetal;
4587 if ( rProp.Value >>= bExtrusionMetal )
4588 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_METAL,
4589 bExtrusionMetal ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4591 break;
4592 case EAS_MetalType :
4594 // export only if ODF extensions are enabled
4595 sal_Int16 eMetalType;
4596 if (rProp.Value >>= eMetalType)
4598 SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion();
4599 if (eVersion > SvtSaveOptions::ODFSVER_013
4600 && (eVersion & SvtSaveOptions::ODFSVER_EXTENDED))
4602 if (eMetalType == drawing::EnhancedCustomShapeMetalType::MetalMSCompatible)
4603 aStr = "loext:MetalMSCompatible";
4604 else
4605 aStr = "draw:MetalODF";
4606 rExport.AddAttribute(XML_NAMESPACE_LO_EXT, XML_EXTRUSION_METAL_TYPE, aStr);
4610 break;
4611 case EAS_ShadeMode :
4613 // shadeMode
4614 drawing::ShadeMode eShadeMode;
4615 if( rProp.Value >>= eShadeMode )
4617 if( eShadeMode == drawing::ShadeMode_FLAT )
4618 aStr = GetXMLToken( XML_FLAT );
4619 else if( eShadeMode == drawing::ShadeMode_PHONG )
4620 aStr = GetXMLToken( XML_PHONG );
4621 else if( eShadeMode == drawing::ShadeMode_SMOOTH )
4622 aStr = GetXMLToken( XML_GOURAUD );
4623 else
4624 aStr = GetXMLToken( XML_DRAFT );
4626 else
4628 // ShadeMode enum not there, write default
4629 aStr = GetXMLToken( XML_FLAT);
4631 rExport.AddAttribute( XML_NAMESPACE_DR3D, XML_SHADE_MODE, aStr );
4633 break;
4634 case EAS_RotateAngle :
4636 css::drawing::EnhancedCustomShapeParameterPair aRotateAngleParaPair;
4637 if ( rProp.Value >>= aRotateAngleParaPair )
4639 ExportParameter( aStrBuffer, aRotateAngleParaPair.First );
4640 ExportParameter( aStrBuffer, aRotateAngleParaPair.Second );
4641 aStr = aStrBuffer.makeStringAndClear();
4642 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ROTATION_ANGLE, aStr );
4645 break;
4646 case EAS_RotationCenter :
4648 drawing::Direction3D aExtrusionRotationCenter;
4649 if ( rProp.Value >>= aExtrusionRotationCenter )
4651 ::basegfx::B3DVector aVec3D( aExtrusionRotationCenter.DirectionX, aExtrusionRotationCenter.DirectionY,
4652 aExtrusionRotationCenter.DirectionZ );
4653 SvXMLUnitConverter::convertB3DVector( aStrBuffer, aVec3D );
4654 aStr = aStrBuffer.makeStringAndClear();
4655 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ROTATION_CENTER, aStr );
4658 break;
4659 case EAS_Shininess :
4661 double fExtrusionShininess = 0;
4662 if ( rProp.Value >>= fExtrusionShininess )
4664 ::sax::Converter::convertDouble(
4665 aStrBuffer,
4666 fExtrusionShininess,
4667 false,
4668 util::MeasureUnit::PERCENT,
4669 util::MeasureUnit::PERCENT);
4670 aStrBuffer.append( '%' );
4671 aStr = aStrBuffer.makeStringAndClear();
4672 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SHININESS, aStr );
4675 break;
4676 case EAS_Skew :
4678 css::drawing::EnhancedCustomShapeParameterPair aSkewParaPair;
4679 if ( rProp.Value >>= aSkewParaPair )
4681 bSkewValuesProvided = true;
4682 ExportParameter( aStrBuffer, aSkewParaPair.First );
4683 ExportParameter( aStrBuffer, aSkewParaPair.Second );
4684 aStr = aStrBuffer.makeStringAndClear();
4685 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SKEW, aStr );
4688 break;
4689 case EAS_Specularity :
4691 double fExtrusionSpecularity = 0;
4692 if ( rProp.Value >>= fExtrusionSpecularity )
4694 SvtSaveOptions::ODFSaneDefaultVersion eVersion = rExport.getSaneDefaultVersion();
4695 if (fExtrusionSpecularity > 100.0 && eVersion >= SvtSaveOptions::ODFSVER_012
4696 && (eVersion & SvtSaveOptions::ODFSVER_EXTENDED))
4698 // tdf#147580 write values > 100% in loext
4699 ::sax::Converter::convertDouble(
4700 aStrBuffer,
4701 fExtrusionSpecularity,
4702 false,
4703 util::MeasureUnit::PERCENT,
4704 util::MeasureUnit::PERCENT);
4705 aStrBuffer.append( '%' );
4706 aStr = aStrBuffer.makeStringAndClear();
4707 rExport.AddAttribute( XML_NAMESPACE_LO_EXT, XML_EXTRUSION_SPECULARITY_LOEXT, aStr );
4709 // tdf#147580 ODF 1 allows arbitrary percent, later versions not
4710 if (eVersion >= SvtSaveOptions::ODFSVER_012)
4712 fExtrusionSpecularity = std::clamp<double>(fExtrusionSpecularity, 0.0, 100.0);
4714 ::sax::Converter::convertDouble(
4715 aStrBuffer,
4716 fExtrusionSpecularity,
4717 false,
4718 util::MeasureUnit::PERCENT,
4719 util::MeasureUnit::PERCENT);
4720 aStrBuffer.append( '%' );
4721 aStr = aStrBuffer.makeStringAndClear();
4722 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SPECULARITY, aStr );
4725 break;
4726 case EAS_ProjectionMode :
4728 drawing::ProjectionMode eProjectionMode;
4729 if ( rProp.Value >>= eProjectionMode )
4730 rExport.AddAttribute( XML_NAMESPACE_DR3D, XML_PROJECTION,
4731 eProjectionMode == drawing::ProjectionMode_PARALLEL ? GetXMLToken( XML_PARALLEL ) : GetXMLToken( XML_PERSPECTIVE ) );
4733 break;
4734 case EAS_ViewPoint :
4736 drawing::Position3D aExtrusionViewPoint;
4737 if ( rProp.Value >>= aExtrusionViewPoint )
4739 rUnitConverter.convertPosition3D( aStrBuffer, aExtrusionViewPoint );
4740 aStr = aStrBuffer.makeStringAndClear();
4741 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_VIEWPOINT, aStr );
4744 break;
4745 case EAS_Origin :
4747 css::drawing::EnhancedCustomShapeParameterPair aOriginParaPair;
4748 if ( rProp.Value >>= aOriginParaPair )
4750 ExportParameter( aStrBuffer, aOriginParaPair.First );
4751 ExportParameter( aStrBuffer, aOriginParaPair.Second );
4752 aStr = aStrBuffer.makeStringAndClear();
4753 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ORIGIN, aStr );
4756 break;
4757 case EAS_Color :
4759 bool bExtrusionColor;
4760 if ( rProp.Value >>= bExtrusionColor )
4762 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_COLOR,
4763 bExtrusionColor ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4766 break;
4767 default:
4768 break;
4771 // tdf#141301: no specific skew values provided
4772 if (!bSkewValuesProvided)
4774 // so we need to export default values explicitly
4775 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_SKEW, "50 -135");
4779 break;
4780 case EAS_TextPath :
4782 uno::Sequence< beans::PropertyValue > aTextPathPropSeq;
4783 if ( rGeoProp.Value >>= aTextPathPropSeq )
4785 for ( const beans::PropertyValue& rProp : std::as_const(aTextPathPropSeq) )
4787 switch( EASGet( rProp.Name ) )
4789 case EAS_TextPath :
4791 bool bTextPathOn;
4792 if ( rProp.Value >>= bTextPathOn )
4793 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH,
4794 bTextPathOn ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4796 break;
4797 case EAS_TextPathMode :
4799 css::drawing::EnhancedCustomShapeTextPathMode eTextPathMode;
4800 if ( rProp.Value >>= eTextPathMode )
4802 switch ( eTextPathMode )
4804 case css::drawing::EnhancedCustomShapeTextPathMode_NORMAL: aStr = GetXMLToken( XML_NORMAL ); break;
4805 case css::drawing::EnhancedCustomShapeTextPathMode_PATH : aStr = GetXMLToken( XML_PATH ); break;
4806 case css::drawing::EnhancedCustomShapeTextPathMode_SHAPE : aStr = GetXMLToken( XML_SHAPE ); break;
4807 default:
4808 break;
4810 if ( !aStr.isEmpty() )
4811 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_MODE, aStr );
4814 break;
4815 case EAS_ScaleX :
4817 bool bScaleX;
4818 if ( rProp.Value >>= bScaleX )
4820 aStr = bScaleX ? GetXMLToken( XML_SHAPE ) : GetXMLToken( XML_PATH );
4821 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_SCALE, aStr );
4824 break;
4825 case EAS_SameLetterHeights :
4827 bool bSameLetterHeights;
4828 if ( rProp.Value >>= bSameLetterHeights )
4829 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_SAME_LETTER_HEIGHTS,
4830 bSameLetterHeights ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4832 break;
4833 default:
4834 break;
4839 break;
4840 case EAS_Path :
4842 uno::Sequence< beans::PropertyValue > aPathPropSeq;
4843 if ( rGeoProp.Value >>= aPathPropSeq )
4845 for ( const beans::PropertyValue& rProp : std::as_const(aPathPropSeq) )
4847 switch( EASGet( rProp.Name ) )
4849 case EAS_SubViewSize:
4851 // export draw:sub-view-size (do not export in ODF 1.3 or older)
4852 if ((rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED) == 0)
4854 continue;
4856 uno::Sequence< awt::Size > aSubViewSizes;
4857 rProp.Value >>= aSubViewSizes;
4859 for ( int nIdx = 0; nIdx < aSubViewSizes.getLength(); nIdx++ )
4861 if ( nIdx )
4862 aStrBuffer.append(' ');
4863 aStrBuffer.append( aSubViewSizes[nIdx].Width );
4864 aStrBuffer.append(' ');
4865 aStrBuffer.append( aSubViewSizes[nIdx].Height );
4867 aStr = aStrBuffer.makeStringAndClear();
4868 rExport.AddAttribute( XML_NAMESPACE_DRAW_EXT, XML_SUB_VIEW_SIZE, aStr );
4870 break;
4871 case EAS_ExtrusionAllowed :
4873 bool bExtrusionAllowed;
4874 if ( rProp.Value >>= bExtrusionAllowed )
4875 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_EXTRUSION_ALLOWED,
4876 bExtrusionAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4878 break;
4879 case EAS_ConcentricGradientFillAllowed :
4881 bool bConcentricGradientFillAllowed;
4882 if ( rProp.Value >>= bConcentricGradientFillAllowed )
4883 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_CONCENTRIC_GRADIENT_FILL_ALLOWED,
4884 bConcentricGradientFillAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4886 break;
4887 case EAS_TextPathAllowed :
4889 bool bTextPathAllowed;
4890 if ( rProp.Value >>= bTextPathAllowed )
4891 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_PATH_ALLOWED,
4892 bTextPathAllowed ? GetXMLToken( XML_TRUE ) : GetXMLToken( XML_FALSE ) );
4894 break;
4895 case EAS_GluePoints :
4897 css::uno::Sequence< css::drawing::EnhancedCustomShapeParameterPair> aGluePoints;
4898 if ( rProp.Value >>= aGluePoints )
4900 if ( aGluePoints.hasElements() )
4902 for( const auto& rGluePoint : std::as_const(aGluePoints) )
4904 ExportParameter( aStrBuffer, rGluePoint.First );
4905 ExportParameter( aStrBuffer, rGluePoint.Second );
4907 aStr = aStrBuffer.makeStringAndClear();
4909 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GLUE_POINTS, aStr );
4912 break;
4913 case EAS_GluePointType :
4915 sal_Int16 nGluePointType = sal_Int16();
4916 if ( rProp.Value >>= nGluePointType )
4918 switch ( nGluePointType )
4920 case css::drawing::EnhancedCustomShapeGluePointType::NONE : aStr = GetXMLToken( XML_NONE ); break;
4921 case css::drawing::EnhancedCustomShapeGluePointType::SEGMENTS : aStr = GetXMLToken( XML_SEGMENTS ); break;
4922 case css::drawing::EnhancedCustomShapeGluePointType::RECT : aStr = GetXMLToken( XML_RECTANGLE ); break;
4924 if ( !aStr.isEmpty() )
4925 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GLUE_POINT_TYPE, aStr );
4928 break;
4929 case EAS_Coordinates :
4931 bCoordinates = ( rProp.Value >>= aCoordinates );
4933 break;
4934 case EAS_Segments :
4936 rProp.Value >>= aSegments;
4938 break;
4939 case EAS_StretchX :
4941 sal_Int32 nStretchPoint = 0;
4942 if ( rProp.Value >>= nStretchPoint )
4943 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PATH_STRETCHPOINT_X, OUString::number( nStretchPoint ) );
4945 break;
4946 case EAS_StretchY :
4948 sal_Int32 nStretchPoint = 0;
4949 if ( rProp.Value >>= nStretchPoint )
4950 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_PATH_STRETCHPOINT_Y, OUString::number( nStretchPoint ) );
4952 break;
4953 case EAS_TextFrames :
4955 css::uno::Sequence< css::drawing::EnhancedCustomShapeTextFrame > aPathTextFrames;
4956 if ( rProp.Value >>= aPathTextFrames )
4958 if ( aPathTextFrames.hasElements() )
4960 for ( const auto& rPathTextFrame : std::as_const(aPathTextFrames) )
4962 ExportParameter( aStrBuffer, rPathTextFrame.TopLeft.First );
4963 ExportParameter( aStrBuffer, rPathTextFrame.TopLeft.Second );
4964 ExportParameter( aStrBuffer, rPathTextFrame.BottomRight.First );
4965 ExportParameter( aStrBuffer, rPathTextFrame.BottomRight.Second );
4967 aStr = aStrBuffer.makeStringAndClear();
4969 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_AREAS, aStr );
4972 break;
4973 default:
4974 break;
4979 break;
4980 case EAS_Equations :
4982 bEquations = ( rGeoProp.Value >>= aEquations );
4984 break;
4985 case EAS_Handles :
4987 bHandles = ( rGeoProp.Value >>= aHandles );
4989 break;
4990 case EAS_AdjustmentValues :
4992 rGeoProp.Value >>= aAdjustmentValues;
4994 break;
4995 default:
4996 break;
4998 } // for
5000 // ToDo: Where is TextPreRotateAngle still used? We cannot save it in ODF.
5001 fTextRotateAngle += fTextPreRotateAngle;
5002 // Workaround for writing-mode bt-lr and tb-rl90 in ODF strict,
5003 // otherwise loext:writing-mode is used in style export.
5004 if (!(rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED))
5006 if (xPropSetInfo->hasPropertyByName(u"WritingMode"))
5008 sal_Int16 nDirection = -1;
5009 xPropSet->getPropertyValue(u"WritingMode") >>= nDirection;
5010 if (nDirection == text::WritingMode2::TB_RL90)
5011 fTextRotateAngle -= 90;
5012 else if (nDirection == text::WritingMode2::BT_LR)
5013 fTextRotateAngle -= 270;
5016 if (fTextRotateAngle != 0)
5018 ::sax::Converter::convertDouble( aStrBuffer, fTextRotateAngle );
5019 aStr = aStrBuffer.makeStringAndClear();
5020 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_ROTATE_ANGLE, aStr );
5023 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TYPE, aCustomShapeType );
5025 // adjustments
5026 sal_Int32 nAdjustmentValues = aAdjustmentValues.getLength();
5027 if ( nAdjustmentValues )
5029 sal_Int32 i, nValue = 0;
5030 for ( i = 0; i < nAdjustmentValues; i++ )
5032 if ( i )
5033 aStrBuffer.append( ' ' );
5035 const css::drawing::EnhancedCustomShapeAdjustmentValue& rAdj = aAdjustmentValues[ i ];
5036 if ( rAdj.State == beans::PropertyState_DIRECT_VALUE )
5038 if ( rAdj.Value.getValueTypeClass() == uno::TypeClass_DOUBLE )
5040 double fValue = 0.0;
5041 rAdj.Value >>= fValue;
5042 ::sax::Converter::convertDouble(aStrBuffer, fValue);
5044 else
5046 rAdj.Value >>= nValue;
5047 aStrBuffer.append(nValue);
5050 else
5052 // this should not be, but better than setting nothing
5053 aStrBuffer.append("0");
5056 aStr = aStrBuffer.makeStringAndClear();
5057 rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_MODIFIERS, aStr );
5059 if ( bCoordinates )
5060 ImpExportEnhancedPath( rExport, aCoordinates, aSegments );
5063 SvXMLElementExport aOBJ( rExport, XML_NAMESPACE_DRAW, XML_ENHANCED_GEOMETRY, true, true );
5064 if ( bEquations )
5065 ImpExportEquations( rExport, aEquations );
5066 if ( bHandles )
5067 ImpExportHandles( rExport, aHandles );
5070 void XMLShapeExport::ImpExportCustomShape(
5071 const uno::Reference< drawing::XShape >& xShape,
5072 XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint )
5074 const uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
5075 if ( !xPropSet.is() )
5076 return;
5078 uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
5080 // Transformation
5081 ImpExportNewTrans( xPropSet, nFeatures, pRefPoint );
5083 if ( xPropSetInfo.is() )
5085 OUString aStr;
5086 if ( xPropSetInfo->hasPropertyByName( "CustomShapeEngine" ) )
5088 uno::Any aEngine( xPropSet->getPropertyValue( "CustomShapeEngine" ) );
5089 if ( ( aEngine >>= aStr ) && !aStr.isEmpty() )
5090 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ENGINE, aStr );
5092 if ( xPropSetInfo->hasPropertyByName( "CustomShapeData" ) )
5094 uno::Any aData( xPropSet->getPropertyValue( "CustomShapeData" ) );
5095 if ( ( aData >>= aStr ) && !aStr.isEmpty() )
5096 mrExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DATA, aStr );
5099 bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE ); // #86116#/#92210#
5100 SvXMLElementExport aOBJ( mrExport, XML_NAMESPACE_DRAW, XML_CUSTOM_SHAPE, bCreateNewline, true );
5101 ImpExportDescription( xShape ); // #i68101#
5102 ImpExportEvents( xShape );
5103 ImpExportGluePoints( xShape );
5104 ImpExportText( xShape );
5105 ImpExportEnhancedGeometry( mrExport, xPropSet );
5109 void XMLShapeExport::ImpExportTableShape( const uno::Reference< drawing::XShape >& xShape, XmlShapeType eShapeType, XMLShapeExportFlags nFeatures, css::awt::Point* pRefPoint )
5111 uno::Reference< beans::XPropertySet > xPropSet(xShape, uno::UNO_QUERY);
5112 uno::Reference< container::XNamed > xNamed(xShape, uno::UNO_QUERY);
5114 SAL_WARN_IF( !xPropSet.is() || !xNamed.is(), "xmloff", "xmloff::XMLShapeExport::ImpExportTableShape(), table shape is not implementing needed interfaces");
5115 if(!(xPropSet.is() && xNamed.is()))
5116 return;
5120 // Transformation
5121 ImpExportNewTrans(xPropSet, nFeatures, pRefPoint);
5123 bool bIsEmptyPresObj = false;
5125 // presentation settings
5126 if(eShapeType == XmlShapeType::PresTableShape)
5127 bIsEmptyPresObj = ImpExportPresentationAttributes( xPropSet, GetXMLToken(XML_TABLE) );
5129 const bool bCreateNewline( (nFeatures & XMLShapeExportFlags::NO_WS) == XMLShapeExportFlags::NONE );
5131 SvXMLElementExport aElement( mrExport, XML_NAMESPACE_DRAW, XML_FRAME, bCreateNewline, true );
5133 // do not export in ODF 1.1 or older
5134 if (mrExport.getSaneDefaultVersion() >= SvtSaveOptions::ODFSVER_012)
5136 if( !bIsEmptyPresObj )
5138 uno::Reference< container::XNamed > xTemplate( xPropSet->getPropertyValue("TableTemplate"), uno::UNO_QUERY );
5139 if( xTemplate.is() )
5141 const OUString sTemplate( xTemplate->getName() );
5142 if( !sTemplate.isEmpty() )
5144 mrExport.AddAttribute(XML_NAMESPACE_TABLE, XML_TEMPLATE_NAME, sTemplate );
5146 for( const XMLPropertyMapEntry* pEntry = &aXMLTableShapeAttributes[0]; !pEntry->IsEnd(); pEntry++ )
5150 bool bBool = false;
5151 xPropSet->getPropertyValue( pEntry->getApiName() ) >>= bBool;
5152 if( bBool )
5153 mrExport.AddAttribute(pEntry->mnNameSpace, pEntry->meXMLName, XML_TRUE );
5155 catch( uno::Exception& )
5157 DBG_UNHANDLED_EXCEPTION("xmloff.draw");
5163 uno::Reference< table::XColumnRowRange > xRange( xPropSet->getPropertyValue( gsModel ), uno::UNO_QUERY_THROW );
5164 GetShapeTableExport()->exportTable( xRange );
5168 if( !bIsEmptyPresObj )
5170 uno::Reference< graphic::XGraphic > xGraphic( xPropSet->getPropertyValue("ReplacementGraphic"), uno::UNO_QUERY );
5171 ExportGraphicPreview(xGraphic, mrExport, u"TablePreview", u".svm", "image/x-vclgraphic");
5174 ImpExportEvents( xShape );
5175 ImpExportGluePoints( xShape );
5176 ImpExportDescription( xShape ); // #i68101#
5178 catch( uno::Exception const & )
5180 DBG_UNHANDLED_EXCEPTION("xmloff.draw");
5184 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */