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