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