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