1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_wasm_strip.h>
22 #include <sal/config.h>
23 #include <sal/log.hxx>
25 #include <filter/msfilter/util.hxx>
26 #include <o3tl/string_view.hxx>
27 #include <o3tl/any.hxx>
28 #include <oox/core/xmlfilterbase.hxx>
29 #include <oox/export/shapes.hxx>
30 #include <oox/export/utils.hxx>
31 #include <oox/token/namespaces.hxx>
32 #include <oox/token/relationship.hxx>
33 #include <oox/token/tokens.hxx>
35 #include <initializer_list>
36 #include <string_view>
38 #include <com/sun/star/beans/PropertyValues.hpp>
39 #include <com/sun/star/beans/XPropertySet.hpp>
40 #include <com/sun/star/beans/XPropertySetInfo.hpp>
41 #include <com/sun/star/beans/XPropertyState.hpp>
42 #include <com/sun/star/container/XChild.hpp>
43 #include <com/sun/star/document/XExporter.hpp>
44 #include <com/sun/star/document/XStorageBasedDocument.hpp>
45 #include <com/sun/star/drawing/CircleKind.hpp>
46 #include <com/sun/star/drawing/FillStyle.hpp>
47 #include <com/sun/star/drawing/ConnectorType.hpp>
48 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
49 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
50 #include <com/sun/star/embed/Aspects.hpp>
51 #include <com/sun/star/embed/EmbedStates.hpp>
52 #include <com/sun/star/embed/XEmbeddedObject.hpp>
53 #include <com/sun/star/embed/XEmbedPersist.hpp>
54 #include <com/sun/star/frame/XStorable.hpp>
55 #include <com/sun/star/graphic/XGraphic.hpp>
56 #include <com/sun/star/i18n/ScriptType.hpp>
57 #include <com/sun/star/io/XOutputStream.hpp>
58 #include <com/sun/star/text/XSimpleText.hpp>
59 #include <com/sun/star/text/XText.hpp>
60 #include <com/sun/star/table/XTable.hpp>
61 #include <com/sun/star/table/XMergeableCell.hpp>
62 #include <com/sun/star/chart2/XChartDocument.hpp>
63 #include <com/sun/star/frame/XModel.hpp>
64 #include <com/sun/star/uno/XComponentContext.hpp>
65 #include <com/sun/star/drawing/XDrawPages.hpp>
66 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
67 #include <com/sun/star/presentation/ClickAction.hpp>
68 #include <com/sun/star/drawing/XGluePointsSupplier.hpp>
69 #include <com/sun/star/container/XIdentifierAccess.hpp>
70 #include <com/sun/star/table/BorderLineStyle.hpp>
71 #include <tools/globname.hxx>
72 #include <comphelper/classids.hxx>
73 #include <comphelper/propertysequence.hxx>
74 #include <comphelper/storagehelper.hxx>
75 #include <sot/exchange.hxx>
77 #include <vcl/graph.hxx>
78 #include <vcl/outdev.hxx>
79 #include <filter/msfilter/escherex.hxx>
80 #include <svtools/embedhlp.hxx>
81 #include <svx/svdoashp.hxx>
82 #include <svx/svdoole2.hxx>
83 #include <comphelper/diagnose_ex.hxx>
84 #include <oox/export/chartexport.hxx>
85 #include <oox/mathml/imexport.hxx>
86 #include <basegfx/numeric/ftools.hxx>
87 #include <oox/export/DMLPresetShapeExport.hxx>
89 #include <frozen/bits/defines.h>
90 #include <frozen/bits/elsa_std.h>
91 #include <frozen/set.h>
92 #include <frozen/unordered_map.h>
94 #include <sax/fastattribs.hxx>
96 using namespace ::css
;
97 using namespace ::css::beans
;
98 using namespace ::css::uno
;
99 using namespace ::css::drawing
;
100 using namespace ::css::table
;
101 using namespace ::css::container
;
102 using namespace ::css::document
;
103 using namespace ::css::text
;
105 using ::css::io::XOutputStream
;
106 using ::css::chart2::XChartDocument
;
107 using ::css::frame::XModel
;
109 using ::oox::core::XmlFilterBase
;
110 using ::sax_fastparser::FSHelperPtr
;
115 static void lcl_ConvertProgID(std::u16string_view rProgID
,
116 OUString
& o_rMediaType
, OUString
& o_rRelationType
, OUString
& o_rFileExtension
)
118 if (rProgID
== u
"Excel.Sheet.12")
120 o_rMediaType
= "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
121 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
122 o_rFileExtension
= "xlsx";
124 else if (o3tl::starts_with(rProgID
, u
"Excel.SheetBinaryMacroEnabled.12") )
126 o_rMediaType
= "application/vnd.ms-excel.sheet.binary.macroEnabled.12";
127 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
128 o_rFileExtension
= "xlsb";
130 else if (o3tl::starts_with(rProgID
, u
"Excel.SheetMacroEnabled.12"))
132 o_rMediaType
= "application/vnd.ms-excel.sheet.macroEnabled.12";
133 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
134 o_rFileExtension
= "xlsm";
136 else if (o3tl::starts_with(rProgID
, u
"Excel.Sheet"))
138 o_rMediaType
= "application/vnd.ms-excel";
139 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
140 o_rFileExtension
= "xls";
142 else if (rProgID
== u
"PowerPoint.Show.12")
144 o_rMediaType
= "application/vnd.openxmlformats-officedocument.presentationml.presentation";
145 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
146 o_rFileExtension
= "pptx";
148 else if (rProgID
== u
"PowerPoint.ShowMacroEnabled.12")
150 o_rMediaType
= "application/vnd.ms-powerpoint.presentation.macroEnabled.12";
151 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
152 o_rFileExtension
= "pptm";
154 else if (o3tl::starts_with(rProgID
, u
"PowerPoint.Show"))
156 o_rMediaType
= "application/vnd.ms-powerpoint";
157 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
158 o_rFileExtension
= "ppt";
160 else if (o3tl::starts_with(rProgID
, u
"PowerPoint.Slide.12"))
162 o_rMediaType
= "application/vnd.openxmlformats-officedocument.presentationml.slide";
163 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
164 o_rFileExtension
= "sldx";
166 else if (rProgID
== u
"PowerPoint.SlideMacroEnabled.12")
168 o_rMediaType
= "application/vnd.ms-powerpoint.slide.macroEnabled.12";
169 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
170 o_rFileExtension
= "sldm";
172 else if (rProgID
== u
"Word.DocumentMacroEnabled.12")
174 o_rMediaType
= "application/vnd.ms-word.document.macroEnabled.12";
175 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
176 o_rFileExtension
= "docm";
178 else if (rProgID
== u
"Word.Document.12")
180 o_rMediaType
= "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
181 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
182 o_rFileExtension
= "docx";
184 else if (rProgID
== u
"Word.Document.8")
186 o_rMediaType
= "application/msword";
187 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
188 o_rFileExtension
= "doc";
190 else if (rProgID
== u
"Excel.Chart.8")
192 o_rMediaType
= "application/vnd.ms-excel";
193 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
194 o_rFileExtension
= "xls";
196 else if (rProgID
== u
"AcroExch.Document.11")
198 o_rMediaType
= "application/pdf";
199 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
200 o_rFileExtension
= "pdf";
204 o_rMediaType
= "application/vnd.openxmlformats-officedocument.oleObject";
205 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
206 o_rFileExtension
= "bin";
210 static uno::Reference
<io::XInputStream
> lcl_StoreOwnAsOOXML(
211 uno::Reference
<uno::XComponentContext
> const& xContext
,
212 uno::Reference
<embed::XEmbeddedObject
> const& xObj
,
213 char const*& o_rpProgID
,
214 OUString
& o_rMediaType
, OUString
& o_rRelationType
, OUString
& o_rSuffix
)
220 sal_uInt8 b8
, b9
, b10
, b11
, b12
, b13
, b14
, b15
;
222 char const* pFilterName
;
223 char const* pMediaType
;
226 } const s_Mapping
[] = {
227 { {SO3_SW_CLASSID_60
}, "MS Word 2007 XML", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "Word.Document.12", "docx" },
228 { {SO3_SC_CLASSID_60
}, "Calc MS Excel 2007 XML", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Excel.Sheet.12", "xlsx" },
229 { {SO3_SIMPRESS_CLASSID_60
}, "Impress MS PowerPoint 2007 XML", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "PowerPoint.Show.12", "pptx" },
230 // FIXME: Draw does not appear to have a MSO format export filter?
231 // { {SO3_SDRAW_CLASSID}, "", "", "", "" },
232 { {SO3_SCH_CLASSID_60
}, "unused", "", "", "" },
233 { {SO3_SM_CLASSID_60
}, "unused", "", "", "" },
236 const char * pFilterName(nullptr);
237 SvGlobalName
const classId(xObj
->getClassID());
238 for (auto & i
: s_Mapping
)
240 auto const& rId(i
.ClassId
);
241 SvGlobalName
const temp(rId
.n1
, rId
.n2
, rId
.n3
, rId
.b8
, rId
.b9
, rId
.b10
, rId
.b11
, rId
.b12
, rId
.b13
, rId
.b14
, rId
.b15
);
244 assert(SvGlobalName(SO3_SCH_CLASSID_60
) != classId
); // chart should be written elsewhere!
245 assert(SvGlobalName(SO3_SM_CLASSID_60
) != classId
); // formula should be written elsewhere!
246 pFilterName
= i
.pFilterName
;
247 o_rMediaType
= OUString::createFromAscii(i
.pMediaType
);
248 o_rpProgID
= i
.pProgID
;
249 o_rSuffix
= OUString::createFromAscii(i
.pSuffix
);
250 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
257 SAL_WARN("oox.shape", "oox::GetOLEObjectStream: unknown ClassId " << classId
.GetHexName());
261 if (embed::EmbedStates::LOADED
== xObj
->getCurrentState())
263 xObj
->changeState(embed::EmbedStates::RUNNING
);
265 // use a temp stream - while it would work to store directly to a
266 // fragment stream, an error during export means we'd have to delete it
267 uno::Reference
<io::XStream
> const xTempStream(
268 xContext
->getServiceManager()->createInstanceWithContext(
269 u
"com.sun.star.comp.MemoryStream"_ustr
, xContext
),
270 uno::UNO_QUERY_THROW
);
271 uno::Sequence
<beans::PropertyValue
> args( comphelper::InitPropertySequence({
272 { "OutputStream", Any(xTempStream
->getOutputStream()) },
273 { "FilterName", Any(OUString::createFromAscii(pFilterName
)) }
275 uno::Reference
<frame::XStorable
> xStorable(xObj
->getComponent(), uno::UNO_QUERY
);
278 xStorable
->storeToURL(u
"private:stream"_ustr
, args
);
280 catch (uno::Exception
const&)
282 TOOLS_WARN_EXCEPTION("oox.shape", "oox::GetOLEObjectStream");
285 xTempStream
->getOutputStream()->closeOutput();
286 return xTempStream
->getInputStream();
289 uno::Reference
<io::XInputStream
> GetOLEObjectStream(
290 uno::Reference
<uno::XComponentContext
> const& xContext
,
291 uno::Reference
<embed::XEmbeddedObject
> const& xObj
,
292 std::u16string_view i_rProgID
,
293 OUString
& o_rMediaType
,
294 OUString
& o_rRelationType
,
295 OUString
& o_rSuffix
,
296 const char *& o_rpProgID
)
298 uno::Reference
<io::XInputStream
> xInStream
;
301 uno::Reference
<document::XStorageBasedDocument
> const xParent(
302 uno::Reference
<container::XChild
>(xObj
, uno::UNO_QUERY_THROW
)->getParent(),
303 uno::UNO_QUERY_THROW
);
304 uno::Reference
<embed::XStorage
> const xParentStorage(xParent
->getDocumentStorage());
305 OUString
const entryName(
306 uno::Reference
<embed::XEmbedPersist
>(xObj
, uno::UNO_QUERY_THROW
)->getEntryName());
308 if (xParentStorage
->isStreamElement(entryName
))
310 lcl_ConvertProgID(i_rProgID
, o_rMediaType
, o_rRelationType
, o_rSuffix
);
311 xInStream
= xParentStorage
->cloneStreamElement(entryName
)->getInputStream();
312 // TODO: make it possible to take the sMediaType from the stream
314 else // the object is ODF - either the whole document is
315 { // ODF, or the OLE was edited so it was converted to ODF
316 xInStream
= lcl_StoreOwnAsOOXML(xContext
, xObj
,
317 o_rpProgID
, o_rMediaType
, o_rRelationType
, o_rSuffix
);
320 catch (uno::Exception
const&)
322 TOOLS_WARN_EXCEPTION("oox.shape", "oox::GetOLEObjectStream");
329 namespace oox::drawingml
{
331 ShapeExport::ShapeExport( sal_Int32 nXmlNamespace
, FSHelperPtr pFS
, ShapeHashMap
* pShapeMap
, XmlFilterBase
* pFB
, DocumentType eDocumentType
, DMLTextExport
* pTextExport
, bool bUserShapes
)
332 : DrawingML( std::move(pFS
), pFB
, eDocumentType
, pTextExport
)
333 , m_nEmbeddedObjects(0)
335 , mbUserShapes( bUserShapes
)
336 , mnXmlNamespace( nXmlNamespace
)
337 , maMapModeSrc( MapUnit::Map100thMM
)
338 , maMapModeDest( MapUnit::MapInch
, Point(), Fraction( 1, 576 ), Fraction( 1, 576 ) )
339 , mpShapeMap( pShapeMap
? pShapeMap
: &maShapeMap
)
341 mpURLTransformer
= std::make_shared
<URLTransformer
>();
344 void ShapeExport::SetURLTranslator(const std::shared_ptr
<URLTransformer
>& pTransformer
)
346 mpURLTransformer
= pTransformer
;
349 awt::Size
ShapeExport::MapSize( const awt::Size
& rSize
) const
351 Size
aRetSize( OutputDevice::LogicToLogic( Size( rSize
.Width
, rSize
.Height
), maMapModeSrc
, maMapModeDest
) );
353 if ( !aRetSize
.Width() )
354 aRetSize
.AdjustWidth( 1 );
355 if ( !aRetSize
.Height() )
356 aRetSize
.AdjustHeight( 1 );
357 return awt::Size( aRetSize
.Width(), aRetSize
.Height() );
360 static bool IsNonEmptySimpleText(const Reference
<XInterface
>& xIface
)
362 if (Reference
<XSimpleText
> xText
{ xIface
, UNO_QUERY
})
363 return xText
->getString().getLength();
368 bool ShapeExport::NonEmptyText( const Reference
< XInterface
>& xIface
)
370 Reference
< XPropertySet
> xPropSet( xIface
, UNO_QUERY
);
374 Reference
< XPropertySetInfo
> xPropSetInfo
= xPropSet
->getPropertySetInfo();
375 if ( xPropSetInfo
.is() )
377 if ( xPropSetInfo
->hasPropertyByName( u
"IsEmptyPresentationObject"_ustr
) )
379 bool bIsEmptyPresObj
= false;
380 if ( xPropSet
->getPropertyValue( u
"IsEmptyPresentationObject"_ustr
) >>= bIsEmptyPresObj
)
382 SAL_INFO("oox.shape", "empty presentation object " << bIsEmptyPresObj
<< " , props:");
383 if( bIsEmptyPresObj
)
388 if ( xPropSetInfo
->hasPropertyByName( u
"IsPresentationObject"_ustr
) )
390 bool bIsPresObj
= false;
391 if ( xPropSet
->getPropertyValue( u
"IsPresentationObject"_ustr
) >>= bIsPresObj
)
393 SAL_INFO("oox.shape", "presentation object " << bIsPresObj
<< ", props:");
401 return IsNonEmptySimpleText(xIface
);
404 static void AddExtLst(FSHelperPtr
const& pFS
, Reference
<XPropertySet
> const& xShape
)
406 if (xShape
->getPropertySetInfo()->hasPropertyByName(u
"Decorative"_ustr
)
407 && xShape
->getPropertyValue(u
"Decorative"_ustr
).get
<bool>())
409 pFS
->startElementNS(XML_a
, XML_extLst
);
410 // FSNS(XML_xmlns, XML_a), GetExport().GetFilter().getNamespaceURL(OOX_NS(dml)));
411 pFS
->startElementNS(XML_a
, XML_ext
,
412 // MSO uses this "URI" which is obviously not a URI
413 XML_uri
, "{C183D7F6-B498-43B3-948B-1728B52AA6E4}");
414 pFS
->singleElementNS(XML_adec
, XML_decorative
,
415 FSNS(XML_xmlns
, XML_adec
), "http://schemas.microsoft.com/office/drawing/2017/decorative",
417 pFS
->endElementNS(XML_a
, XML_ext
);
418 pFS
->endElementNS(XML_a
, XML_extLst
);
422 ShapeExport
& ShapeExport::WritePolyPolygonShape( const Reference
< XShape
>& xShape
, const bool bClosed
)
424 SAL_INFO("oox.shape", "write polypolygon shape");
426 FSHelperPtr pFS
= GetFS();
427 pFS
->startElementNS(mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
? XML_sp
: XML_wsp
));
429 awt::Point aPos
= xShape
->getPosition();
430 // Position is relative to group for child elements in Word, but absolute in API.
431 if (GetDocumentType() == DOCUMENT_DOCX
&& !mbUserShapes
&& m_xParent
.is())
433 awt::Point aParentPos
= m_xParent
->getPosition();
434 aPos
.X
-= aParentPos
.X
;
435 aPos
.Y
-= aParentPos
.Y
;
437 awt::Size aSize
= xShape
->getSize();
438 tools::Rectangle
aRect(Point(aPos
.X
, aPos
.Y
), Size(aSize
.Width
, aSize
.Height
));
440 #if OSL_DEBUG_LEVEL > 0
441 tools::PolyPolygon aPolyPolygon
= EscherPropertyContainer::GetPolyPolygon(xShape
);
442 awt::Size size
= MapSize( awt::Size( aRect
.GetWidth(), aRect
.GetHeight() ) );
443 SAL_INFO("oox.shape", "poly count " << aPolyPolygon
.Count());
444 SAL_INFO("oox.shape", "size: " << size
.Width
<< " x " << size
.Height
);
447 Reference
<XPropertySet
> const xProps(xShape
, UNO_QUERY
);
448 // non visual shape properties
449 if (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
)
451 pFS
->startElementNS(mnXmlNamespace
, XML_nvSpPr
);
452 pFS
->startElementNS(mnXmlNamespace
, XML_cNvPr
,
453 XML_id
, OString::number(GetNewShapeID(xShape
)),
454 XML_name
, GetShapeName(xShape
));
455 AddExtLst(pFS
, xProps
);
456 pFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
458 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
);
459 if (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
)
461 WriteNonVisualProperties( xShape
);
462 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
465 // visual shape properties
466 pFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
467 WriteTransformation( xShape
, aRect
, XML_a
);
468 WritePolyPolygon(xShape
, bClosed
);
471 WriteFill(xProps
, aSize
);
472 WriteOutline( xProps
);
475 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
478 WriteTextBox( xShape
, mnXmlNamespace
);
480 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
? XML_sp
: XML_wsp
) );
485 ShapeExport
& ShapeExport::WriteClosedPolyPolygonShape( const Reference
< XShape
>& xShape
)
487 return WritePolyPolygonShape( xShape
, true );
490 ShapeExport
& ShapeExport::WriteOpenPolyPolygonShape( const Reference
< XShape
>& xShape
)
492 return WritePolyPolygonShape( xShape
, false );
495 ShapeExport
& ShapeExport::WriteGroupShape(const uno::Reference
<drawing::XShape
>& xShape
)
497 FSHelperPtr pFS
= GetFS();
499 sal_Int32 nGroupShapeToken
= XML_grpSp
;
500 if (GetDocumentType() == DOCUMENT_DOCX
&& !mbUserShapes
)
503 nGroupShapeToken
= XML_wgp
; // toplevel
505 mnXmlNamespace
= XML_wpg
;
508 pFS
->startElementNS(mnXmlNamespace
, nGroupShapeToken
);
510 // non visual properties
511 if (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
)
513 pFS
->startElementNS(mnXmlNamespace
, XML_nvGrpSpPr
);
514 pFS
->startElementNS(mnXmlNamespace
, XML_cNvPr
,
515 XML_id
, OString::number(GetNewShapeID(xShape
)),
516 XML_name
, GetShapeName(xShape
));
517 uno::Reference
<beans::XPropertySet
> const xShapeProps(xShape
, uno::UNO_QUERY_THROW
);
518 AddExtLst(pFS
, xShapeProps
);
519 pFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
520 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvGrpSpPr
);
521 WriteNonVisualProperties(xShape
);
522 pFS
->endElementNS(mnXmlNamespace
, XML_nvGrpSpPr
);
525 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvGrpSpPr
);
528 pFS
->startElementNS(mnXmlNamespace
, XML_grpSpPr
);
529 WriteShapeTransformation(xShape
, XML_a
, false, false, true);
530 pFS
->endElementNS(mnXmlNamespace
, XML_grpSpPr
);
532 uno::Reference
<drawing::XShapes
> xGroupShape(xShape
, uno::UNO_QUERY_THROW
);
533 uno::Reference
<drawing::XShape
> xParent
= m_xParent
;
535 for (sal_Int32 i
= 0; i
< xGroupShape
->getCount(); ++i
)
537 uno::Reference
<drawing::XShape
> xChild(xGroupShape
->getByIndex(i
), uno::UNO_QUERY_THROW
);
538 sal_Int32 nSavedNamespace
= mnXmlNamespace
;
540 uno::Reference
<lang::XServiceInfo
> xServiceInfo(xChild
, uno::UNO_QUERY_THROW
);
541 if (GetDocumentType() == DOCUMENT_DOCX
&& !mbUserShapes
)
543 // tdf#128820: WriteGraphicObjectShapePart calls WriteTextShape for non-empty simple
544 // text objects, which needs writing into wps::wsp element, so make sure to use wps
545 // namespace for those objects
546 if (xServiceInfo
->supportsService(u
"com.sun.star.drawing.GraphicObjectShape"_ustr
)
547 && !IsNonEmptySimpleText(xChild
))
548 mnXmlNamespace
= XML_pic
;
550 mnXmlNamespace
= XML_wps
;
554 mnXmlNamespace
= nSavedNamespace
;
556 m_xParent
= std::move(xParent
);
558 pFS
->endElementNS(mnXmlNamespace
, nGroupShapeToken
);
564 constexpr frozen::set
<std::u16string_view
, 57> constDenySet(
581 u
"round-rectangular-callout",
582 u
"rectangular-callout",
590 u
"horizontal-scroll",
595 u
"flowchart-process",
596 u
"flowchart-alternate-process",
597 u
"flowchart-decision",
599 u
"flowchart-predefined-process",
600 u
"flowchart-internal-storage",
601 u
"flowchart-document",
602 u
"flowchart-multidocument",
603 u
"flowchart-terminator",
604 u
"flowchart-preparation",
605 u
"flowchart-manual-input",
606 u
"flowchart-manual-operation",
607 u
"flowchart-connector",
608 u
"flowchart-off-page-connector",
610 u
"flowchart-punched-tape",
611 u
"flowchart-summing-junction",
613 u
"flowchart-collate",
615 u
"flowchart-extract",
617 u
"flowchart-stored-data",
619 u
"flowchart-sequential-access",
620 u
"flowchart-magnetic-disk",
621 u
"flowchart-direct-access-storage",
625 constexpr frozen::set
<std::u16string_view
, 5> constAllowSet(
634 } // end anonymous namespace
636 static bool lcl_IsOnDenylist(OUString
const & rShapeType
)
638 return constDenySet
.find(rShapeType
) != constDenySet
.end();
641 static bool lcl_IsOnAllowlist(OUString
const & rShapeType
)
643 return constAllowSet
.find(rShapeType
) != constAllowSet
.end();
646 static bool lcl_GetHandlePosition( sal_Int32
&nValue
, const EnhancedCustomShapeParameter
&rParam
, const Sequence
< EnhancedCustomShapeAdjustmentValue
> &rSeq
)
649 if ( rParam
.Value
.getValueTypeClass() == TypeClass_DOUBLE
)
652 if ( rParam
.Value
>>= fValue
)
653 nValue
= static_cast<sal_Int32
>(fValue
);
656 rParam
.Value
>>= nValue
;
658 if ( rParam
.Type
== EnhancedCustomShapeParameterType::ADJUSTMENT
)
661 sal_Int32 nIdx
= nValue
;
662 if ( nIdx
< rSeq
.getLength() )
664 if ( rSeq
[ nIdx
] .Value
.getValueTypeClass() == TypeClass_DOUBLE
)
667 rSeq
[ nIdx
].Value
>>= fValue
;
673 rSeq
[ nIdx
].Value
>>= nValue
;
680 static void lcl_AnalyzeHandles( const uno::Sequence
<beans::PropertyValues
> & rHandles
,
681 std::vector
< std::pair
< sal_Int32
, sal_Int32
> > &rHandlePositionList
,
682 const Sequence
< EnhancedCustomShapeAdjustmentValue
> &rSeq
)
684 for ( const Sequence
< PropertyValue
>& rPropSeq
: rHandles
)
686 static constexpr OUStringLiteral
sPosition( u
"Position" );
687 bool bPosition
= false;
688 EnhancedCustomShapeParameterPair aPosition
;
689 for ( const PropertyValue
& rPropVal
: rPropSeq
)
691 if ( rPropVal
.Name
== sPosition
)
693 if ( rPropVal
.Value
>>= aPosition
)
699 sal_Int32 nXPosition
= 0;
700 sal_Int32 nYPosition
= 0;
701 // For polar handles, nXPosition is radius and nYPosition is angle
702 lcl_GetHandlePosition( nXPosition
, aPosition
.First
, rSeq
);
703 lcl_GetHandlePosition( nYPosition
, aPosition
.Second
, rSeq
);
704 rHandlePositionList
.emplace_back( nXPosition
, nYPosition
);
709 static void lcl_AppendAdjustmentValue( std::vector
< std::pair
< sal_Int32
, sal_Int32
> > &rAvList
, sal_Int32 nAdjIdx
, sal_Int32 nValue
)
711 rAvList
.emplace_back( nAdjIdx
, nValue
);
714 static sal_Int32
lcl_NormalizeAngle( sal_Int32 nAngle
)
716 nAngle
= nAngle
% 360;
717 return nAngle
< 0 ? ( nAngle
+ 360 ) : nAngle
;
720 static sal_Int32
lcl_CircleAngle2CustomShapeEllipseAngleOOX(const sal_Int32 nInternAngle
, const sal_Int32 nWidth
, const sal_Int32 nHeight
)
722 if (nWidth
!= 0 || nHeight
!= 0)
724 double fAngle
= basegfx::deg2rad
<100>(nInternAngle
); // intern 1/100 deg to rad
725 fAngle
= atan2(nHeight
* sin(fAngle
), nWidth
* cos(fAngle
)); // circle to ellipse
726 fAngle
= basegfx::rad2deg
<60000>(fAngle
); // rad to OOXML angle unit
727 sal_Int32 nAngle
= basegfx::fround(fAngle
); // normalize
728 nAngle
= nAngle
% 21600000;
729 return nAngle
< 0 ? (nAngle
+ 21600000) : nAngle
;
731 else // should be handled by caller, dummy value
735 static OUString
lcl_GetTarget(const css::uno::Reference
<css::frame::XModel
>& xModel
,
736 std::u16string_view rURL
)
738 Reference
<drawing::XDrawPagesSupplier
> xDPS(xModel
, uno::UNO_QUERY_THROW
);
739 Reference
<drawing::XDrawPages
> xDrawPages(xDPS
->getDrawPages(), uno::UNO_SET_THROW
);
740 sal_uInt32 nPageCount
= xDrawPages
->getCount();
743 for (sal_uInt32 i
= 0; i
< nPageCount
; ++i
)
745 Reference
<XDrawPage
> xDrawPage
;
746 xDrawPages
->getByIndex(i
) >>= xDrawPage
;
747 Reference
<container::XNamed
> xNamed(xDrawPage
, UNO_QUERY
);
750 OUString sSlideName
= "#" + xNamed
->getName();
751 if (rURL
== sSlideName
)
753 sTarget
= "slide" + OUString::number(i
+ 1) + ".xml";
761 ShapeExport
& ShapeExport::WriteCustomShape( const Reference
< XShape
>& xShape
)
763 SAL_INFO("oox.shape", "write custom shape");
764 Reference
< XPropertySet
> rXPropSet( xShape
, UNO_QUERY
);
765 // First check, if this is a Fontwork-shape. For DrawingML, such a shape is a
766 // TextBox shape with body property prstTxWarp.
767 if (IsFontworkShape(rXPropSet
))
769 ShapeExport::WriteTextShape(xShape
); // qualifier to prevent PowerPointShapeExport
773 bool bHasGeometrySeq(false);
774 Sequence
< PropertyValue
> aGeometrySeq
;
775 OUString
sShapeType(u
"non-primitive"_ustr
); // default in ODF
776 if (GetProperty(rXPropSet
, u
"CustomShapeGeometry"_ustr
))
778 SAL_INFO("oox.shape", "got custom shape geometry");
779 if (mAny
>>= aGeometrySeq
)
781 bHasGeometrySeq
= true;
782 SAL_INFO("oox.shape", "got custom shape geometry sequence");
783 for (const PropertyValue
& rProp
: aGeometrySeq
)
785 SAL_INFO("oox.shape", "geometry property: " << rProp
.Name
);
786 if (rProp
.Name
== "Type")
787 rProp
.Value
>>= sShapeType
;
792 bool bPredefinedHandlesUsed
= true;
793 bool bHasHandles
= false;
795 ShapeFlag nMirrorFlags
= ShapeFlag::NONE
;
796 MSO_SPT eShapeType
= EscherPropertyContainer::GetCustomShapeType( xShape
, nMirrorFlags
, sShapeType
);
797 assert(dynamic_cast< SdrObjCustomShape
* >(SdrObject::getSdrObjectFromXShape(xShape
)) && "Not a SdrObjCustomShape (!)");
798 SdrObjCustomShape
& rSdrObjCustomShape(static_cast< SdrObjCustomShape
& >(*SdrObject::getSdrObjectFromXShape(xShape
)));
799 const bool bIsDefaultObject(
800 EscherPropertyContainer::IsDefaultObject(
803 OString sPresetShape
= msfilter::util::GetOOXMLPresetGeometry(sShapeType
);
804 SAL_INFO("oox.shape", "custom shape type: " << sShapeType
<< " ==> " << sPresetShape
);
806 sal_Int32 nAdjustmentValuesIndex
= -1;
807 awt::Rectangle aViewBox
;
808 uno::Sequence
<beans::PropertyValues
> aHandles
;
815 for (int i
= 0; i
< aGeometrySeq
.getLength(); i
++)
817 const PropertyValue
& rProp
= aGeometrySeq
[ i
];
818 SAL_INFO("oox.shape", "geometry property: " << rProp
.Name
);
820 if ( rProp
.Name
== "MirroredX" )
821 rProp
.Value
>>= bFlipH
;
823 if ( rProp
.Name
== "MirroredY" )
824 rProp
.Value
>>= bFlipV
;
825 if ( rProp
.Name
== "AdjustmentValues" )
826 nAdjustmentValuesIndex
= i
;
827 else if ( rProp
.Name
== "Handles" )
829 rProp
.Value
>>= aHandles
;
830 if ( aHandles
.hasElements() )
832 if( !bIsDefaultObject
)
833 bPredefinedHandlesUsed
= false;
834 // TODO: update nAdjustmentsWhichNeedsToBeConverted here
836 else if ( rProp
.Name
== "ViewBox" )
837 rProp
.Value
>>= aViewBox
;
841 FSHelperPtr pFS
= GetFS();
842 // non visual shape properties
843 if (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
)
845 // get InteropGrabBag to export attributes stored in the grabbag
846 uno::Sequence
<beans::PropertyValue
> aGrabBagProps
;
847 rXPropSet
->getPropertyValue(u
"InteropGrabBag"_ustr
) >>= aGrabBagProps
;
849 bool bUseBackground
= false;
850 if (GetProperty(rXPropSet
, u
"FillUseSlideBackground"_ustr
))
851 mAny
>>= bUseBackground
;
853 mpFS
->startElementNS(mnXmlNamespace
, XML_sp
, XML_useBgFill
, "1");
856 rtl::Reference
<sax_fastparser::FastAttributeList
> pAttrListSp
857 = sax_fastparser::FastSerializerHelper::createAttrList();
859 for (auto const& it
: aGrabBagProps
)
861 // export macro attribute of <sp> element
862 if (it
.Name
== u
"mso-sp-macro"_ustr
)
867 if (!sMacro
.isEmpty())
868 pAttrListSp
->add(XML_macro
, sMacro
);
871 // export textlink attribute of <sp> element
872 if (it
.Name
== u
"mso-sp-textlink"_ustr
)
875 it
.Value
>>= sTextLink
;
877 if (!sTextLink
.isEmpty())
878 pAttrListSp
->add(XML_textlink
, sTextLink
);
881 // export fLocksText attribute of <sp> element
882 if (it
.Name
== u
"mso-sp-fLocksText"_ustr
)
884 bool bFLocksText
= true; // default="true"
885 it
.Value
>>= bFLocksText
;
886 pAttrListSp
->add(XML_fLocksText
, ToPsz10(bFLocksText
));
889 // export fPublished attribute of <sp> element
890 if (it
.Name
== u
"mso-sp-fPublished"_ustr
)
892 bool bFPublished
= false;
893 it
.Value
>>= bFPublished
;
894 pAttrListSp
->add(XML_fPublished
, ToPsz10(bFPublished
));
898 // export <sp> element (with a namespace prefix)
899 mpFS
->startElementNS(mnXmlNamespace
, XML_sp
, pAttrListSp
);
902 bool isVisible
= true ;
903 if( GetProperty(rXPropSet
, u
"Visible"_ustr
))
907 pFS
->startElementNS( mnXmlNamespace
, XML_nvSpPr
);
909 // export descr attribute of <cNvPr> element
911 if (GetProperty(rXPropSet
, u
"Description"_ustr
))
914 // export title attribute of <cNvPr> element
916 if (GetProperty(rXPropSet
, u
"Title"_ustr
))
919 // export <cNvPr> element
921 mnXmlNamespace
, XML_cNvPr
, XML_id
,
922 OString::number(GetShapeID(xShape
) == -1 ? GetNewShapeID(xShape
) : GetShapeID(xShape
)),
923 XML_name
, GetShapeName(xShape
), XML_hidden
, sax_fastparser::UseIf("1", !isVisible
),
924 XML_descr
, sax_fastparser::UseIf(sDescr
, !sDescr
.isEmpty()), XML_title
,
925 sax_fastparser::UseIf(sTitle
, !sTitle
.isEmpty()));
927 rtl::Reference
<sax_fastparser::FastAttributeList
> pAttrListHlinkClick
928 = sax_fastparser::FastSerializerHelper::createAttrList();
930 for (auto const& it
: aGrabBagProps
)
932 // export tooltip attribute of <hlinkClick> element
933 if (it
.Name
== u
"mso-hlinkClick-tooltip"_ustr
)
936 it
.Value
>>= sTooltip
;
938 if (!sTooltip
.isEmpty())
939 pAttrListHlinkClick
->add(XML_tooltip
, sTooltip
);
943 if( GetProperty(rXPropSet
, u
"URL"_ustr
) )
947 if( !sURL
.isEmpty() )
949 OUString sRelId
= mpFB
->addRelation( mpFS
->getOutputStream(),
950 oox::getRelationship(Relationship::HYPERLINK
),
951 mpURLTransformer
->getTransformedString(sURL
),
952 mpURLTransformer
->isExternalURL(sURL
));
954 mpFS
->singleElementNS(XML_a
, XML_hlinkClick
, FSNS(XML_r
, XML_id
), sRelId
);
955 // pAttrListHlinkClick->add(FSNS(XML_r, XML_id), sRelId);
959 // // export <hlinkClick> element
960 // mpFS->singleElementNS(XML_a, XML_hlinkClick, pAttrListHlinkClick);
963 if (GetProperty(rXPropSet
, u
"Bookmark"_ustr
))
966 if (GetProperty(rXPropSet
, u
"OnClick"_ustr
))
969 presentation::ClickAction eClickAction
= presentation::ClickAction_NONE
;
970 mAny
>>= eClickAction
;
971 if (eClickAction
!= presentation::ClickAction_NONE
)
973 switch (eClickAction
)
975 case presentation::ClickAction_STOPPRESENTATION
:
976 sPPAction
= "ppaction://hlinkshowjump?jump=endshow";
978 case presentation::ClickAction_NEXTPAGE
:
979 sPPAction
= "ppaction://hlinkshowjump?jump=nextslide";
981 case presentation::ClickAction_LASTPAGE
:
982 sPPAction
= "ppaction://hlinkshowjump?jump=lastslide";
984 case presentation::ClickAction_PREVPAGE
:
985 sPPAction
= "ppaction://hlinkshowjump?jump=previousslide";
987 case presentation::ClickAction_FIRSTPAGE
:
988 sPPAction
= "ppaction://hlinkshowjump?jump=firstslide";
990 case presentation::ClickAction_BOOKMARK
:
991 sBookmark
= "#" + sBookmark
;
997 if (!sPPAction
.isEmpty())
998 pFS
->singleElementNS(XML_a
, XML_hlinkClick
, FSNS(XML_r
, XML_id
), "", XML_action
,
1001 if (!sBookmark
.isEmpty())
1003 bool bExtURL
= URLTransformer().isExternalURL(sBookmark
);
1004 sBookmark
= bExtURL
? sBookmark
: lcl_GetTarget(GetFB()->getModel(), sBookmark
);
1007 = mpFB
->addRelation(mpFS
->getOutputStream(),
1008 bExtURL
? oox::getRelationship(Relationship::HYPERLINK
)
1009 : oox::getRelationship(Relationship::SLIDE
),
1010 sBookmark
, bExtURL
);
1012 mpFS
->singleElementNS(XML_a
, XML_hlinkClick
, FSNS(XML_r
, XML_id
), sRelId
);
1014 mpFS
->singleElementNS(XML_a
, XML_hlinkClick
, FSNS(XML_r
, XML_id
), sRelId
,
1015 XML_action
, "ppaction://hlinksldjump");
1017 AddExtLst(pFS
, rXPropSet
);
1018 pFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
1019 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
);
1020 WriteNonVisualProperties( xShape
);
1021 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
1025 pFS
->startElementNS(mnXmlNamespace
, XML_wsp
);
1028 pFS
->startElementNS(mnXmlNamespace
, XML_cNvPr
, XML_id
,
1029 OString::number(GetShapeID(xShape
) == -1 ? GetNewShapeID(xShape
)
1030 : GetShapeID(xShape
)),
1031 XML_name
, GetShapeName(xShape
));
1033 if (GetProperty(rXPropSet
, u
"Hyperlink"_ustr
))
1037 if (!sURL
.isEmpty())
1039 OUString sRelId
= mpFB
->addRelation(
1040 mpFS
->getOutputStream(), oox::getRelationship(Relationship::HYPERLINK
),
1041 mpURLTransformer
->getTransformedString(sURL
),
1042 mpURLTransformer
->isExternalURL(sURL
));
1044 mpFS
->singleElementNS(XML_a
, XML_hlinkClick
, FSNS(XML_r
, XML_id
), sRelId
);
1047 AddExtLst(pFS
, rXPropSet
);
1048 pFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
1050 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
);
1053 // visual shape properties
1054 pFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
1056 // we export non-primitive shapes to custom geometry
1057 // we also export non-ooxml shapes which have handles/equations to custom geometry, because
1058 // we cannot convert ODF equations to DrawingML equations. TODO: see what binary DOC export filter does.
1059 // but our WritePolyPolygon()/WriteCustomGeometry() functions are incomplete, therefore we use a denylist
1060 // we use a allowlist for shapes where mapping to MSO preset shape is not optimal
1061 bool bCustGeom
= true;
1062 bool bOnDenylist
= false;
1063 if( sShapeType
== "ooxml-non-primitive" )
1065 else if( sShapeType
.startsWith("ooxml") )
1067 else if( lcl_IsOnAllowlist(sShapeType
) )
1069 else if( lcl_IsOnDenylist(sShapeType
) )
1075 bool bPresetWriteSuccessful
= false;
1076 // Let the custom shapes what has name and preset information in OOXML, to be written
1077 // as preset ones with parameters. Try that with this converter class.
1078 if (!sShapeType
.startsWith("ooxml") && sShapeType
!= "non-primitive" && !mbUserShapes
1079 && xShape
->getShapeType() == "com.sun.star.drawing.CustomShape"
1080 && !lcl_IsOnAllowlist(sShapeType
))
1082 DMLPresetShapeExporter
aCustomShapeConverter(this, xShape
);
1083 bPresetWriteSuccessful
= aCustomShapeConverter
.WriteShape();
1085 // If preset writing has problems try to write the shape as it done before
1086 if (bPresetWriteSuccessful
)
1087 ;// Already written do nothing.
1090 WriteShapeTransformation( xShape
, XML_a
, bFlipH
, bFlipV
);
1091 bool bSuccess
= WriteCustomGeometry(xShape
, rSdrObjCustomShape
);
1092 // In case of Writer, the parent element is <wps:spPr>, and there the <a:custGeom> element
1094 if (!bSuccess
&& GetDocumentType() == DOCUMENT_DOCX
)
1096 WriteEmptyCustomGeometry();
1099 else if (bOnDenylist
&& bHasHandles
&& nAdjustmentValuesIndex
!=-1 && !sShapeType
.startsWith("mso-spt"))
1101 WriteShapeTransformation( xShape
, XML_a
, bFlipH
, bFlipV
);
1102 Sequence
< EnhancedCustomShapeAdjustmentValue
> aAdjustmentSeq
;
1103 std::vector
< std::pair
< sal_Int32
, sal_Int32
> > aHandlePositionList
;
1104 std::vector
< std::pair
< sal_Int32
, sal_Int32
> > aAvList
;
1105 aGeometrySeq
[ nAdjustmentValuesIndex
].Value
>>= aAdjustmentSeq
;
1107 lcl_AnalyzeHandles( aHandles
, aHandlePositionList
, aAdjustmentSeq
);
1109 sal_Int32 nXPosition
= 0;
1110 sal_Int32 nYPosition
= 0;
1111 if ( !aHandlePositionList
.empty() )
1113 nXPosition
= aHandlePositionList
[0].first
;
1114 nYPosition
= aHandlePositionList
[0].second
;
1116 switch( eShapeType
)
1118 case mso_sptBorderCallout1
:
1120 sal_Int32 adj3
= double(nYPosition
)/aViewBox
.Height
*100000;
1121 sal_Int32 adj4
= double(nXPosition
)/aViewBox
.Width
*100000;
1122 lcl_AppendAdjustmentValue( aAvList
, 1, 18750 );
1123 lcl_AppendAdjustmentValue( aAvList
, 2, -8333 );
1124 lcl_AppendAdjustmentValue( aAvList
, 3, adj3
);
1125 lcl_AppendAdjustmentValue( aAvList
, 4, adj4
);
1128 case mso_sptBorderCallout2
:
1130 sal_Int32 adj5
= double(nYPosition
)/aViewBox
.Height
*100000;
1131 sal_Int32 adj6
= double(nXPosition
)/aViewBox
.Width
*100000;
1132 sal_Int32 adj3
= 18750;
1133 sal_Int32 adj4
= -16667;
1134 lcl_AppendAdjustmentValue( aAvList
, 1, 18750 );
1135 lcl_AppendAdjustmentValue( aAvList
, 2, -8333 );
1136 if ( aHandlePositionList
.size() > 1 )
1138 nXPosition
= aHandlePositionList
[1].first
;
1139 nYPosition
= aHandlePositionList
[1].second
;
1140 adj3
= double(nYPosition
)/aViewBox
.Height
*100000;
1141 adj4
= double(nXPosition
)/aViewBox
.Width
*100000;
1143 lcl_AppendAdjustmentValue( aAvList
, 3, adj3
);
1144 lcl_AppendAdjustmentValue( aAvList
, 4, adj4
);
1145 lcl_AppendAdjustmentValue( aAvList
, 5, adj5
);
1146 lcl_AppendAdjustmentValue( aAvList
, 6, adj6
);
1149 case mso_sptWedgeRectCallout
:
1150 case mso_sptWedgeRRectCallout
:
1151 case mso_sptWedgeEllipseCallout
:
1152 case mso_sptCloudCallout
:
1154 sal_Int32 adj1
= (double(nXPosition
)/aViewBox
.Width
-0.5) *100000;
1155 sal_Int32 adj2
= (double(nYPosition
)/aViewBox
.Height
-0.5) *100000;
1156 lcl_AppendAdjustmentValue( aAvList
, 1, adj1
);
1157 lcl_AppendAdjustmentValue( aAvList
, 2, adj2
);
1158 if ( eShapeType
== mso_sptWedgeRRectCallout
)
1160 lcl_AppendAdjustmentValue( aAvList
, 3, 16667);
1165 case mso_sptFoldedCorner
:
1167 sal_Int32 adj
= double( aViewBox
.Width
- nXPosition
) / std::min( aViewBox
.Width
,aViewBox
.Height
) * 100000;
1168 lcl_AppendAdjustmentValue( aAvList
, 0, adj
);
1174 case mso_sptNoSmoking
:
1175 case mso_sptHorizontalScroll
:
1177 case mso_sptBracketPair
:
1179 sal_Int32 adj
= double( nXPosition
)/aViewBox
.Width
*100000 ;
1180 lcl_AppendAdjustmentValue( aAvList
, 0, adj
);
1185 case mso_sptBracePair
:
1186 case mso_sptVerticalScroll
:
1188 sal_Int32 adj
= double( nYPosition
)/aViewBox
.Height
*100000 ;
1189 lcl_AppendAdjustmentValue( aAvList
, 0, adj
);
1192 case mso_sptSmileyFace
:
1194 sal_Int32 adj
= double( nYPosition
)/aViewBox
.Height
*100000 - 76458.0;
1195 lcl_AppendAdjustmentValue( aAvList
, 0, adj
);
1198 case mso_sptBlockArc
:
1200 sal_Int32 nRadius
= 50000 * ( 1 - double(nXPosition
) / 10800);
1201 sal_Int32 nAngleStart
= lcl_NormalizeAngle( nYPosition
);
1202 sal_Int32 nAngleEnd
= lcl_NormalizeAngle( 180 - nAngleStart
);
1203 lcl_AppendAdjustmentValue( aAvList
, 1, 21600000 / 360 * nAngleStart
);
1204 lcl_AppendAdjustmentValue( aAvList
, 2, 21600000 / 360 * nAngleEnd
);
1205 lcl_AppendAdjustmentValue( aAvList
, 3, nRadius
);
1209 // case mso_sptBentConnector3:
1210 // case mso_sptBorderCallout3:
1213 if ( sPresetShape
== "frame" )
1215 sal_Int32 adj1
= double( nYPosition
)/aViewBox
.Height
*100000 ;
1216 lcl_AppendAdjustmentValue( aAvList
, 1, adj1
);
1221 WritePresetShape( sPresetShape
, aAvList
);
1223 else // preset geometry
1225 WriteShapeTransformation( xShape
, XML_a
, bFlipH
, bFlipV
);
1226 if( nAdjustmentValuesIndex
!= -1 )
1228 WritePresetShape( sPresetShape
, eShapeType
, bPredefinedHandlesUsed
,
1229 aGeometrySeq
[ nAdjustmentValuesIndex
] );
1232 WritePresetShape( sPresetShape
);
1234 if( rXPropSet
.is() )
1236 WriteFill(rXPropSet
, xShape
->getSize());
1237 WriteOutline( rXPropSet
);
1238 WriteShapeEffects( rXPropSet
);
1240 bool bHas3DEffectinShape
= false;
1241 uno::Sequence
<beans::PropertyValue
> grabBag
;
1242 rXPropSet
->getPropertyValue(u
"InteropGrabBag"_ustr
) >>= grabBag
;
1244 for (auto const& it
: grabBag
)
1245 if (it
.Name
== "3DEffectProperties")
1246 bHas3DEffectinShape
= true;
1248 if( bHas3DEffectinShape
)
1249 Write3DEffects( rXPropSet
, /*bIsText=*/false );
1252 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1254 pFS
->startElementNS(mnXmlNamespace
, XML_style
);
1255 WriteShapeStyle( rXPropSet
);
1256 pFS
->endElementNS( mnXmlNamespace
, XML_style
);
1259 WriteTextBox( xShape
, mnXmlNamespace
);
1261 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
? XML_sp
: XML_wsp
) );
1266 ShapeExport
& ShapeExport::WriteEllipseShape( const Reference
< XShape
>& xShape
)
1268 SAL_INFO("oox.shape", "write ellipse shape");
1270 FSHelperPtr pFS
= GetFS();
1272 pFS
->startElementNS(mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
? XML_sp
: XML_wsp
));
1274 // TODO: connector ?
1276 Reference
<XPropertySet
> const xProps(xShape
, UNO_QUERY
);
1277 // non visual shape properties
1278 if (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
)
1280 pFS
->startElementNS(mnXmlNamespace
, XML_nvSpPr
);
1281 pFS
->startElementNS(mnXmlNamespace
, XML_cNvPr
,
1282 XML_id
, OString::number(GetNewShapeID(xShape
)),
1283 XML_name
, GetShapeName(xShape
));
1284 AddExtLst(pFS
, xProps
);
1285 pFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
1286 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvSpPr
);
1287 WriteNonVisualProperties( xShape
);
1288 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
1291 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
);
1293 CircleKind
eCircleKind(CircleKind_FULL
);
1295 xProps
->getPropertyValue(u
"CircleKind"_ustr
) >>= eCircleKind
;
1297 // visual shape properties
1298 pFS
->startElementNS( mnXmlNamespace
, XML_spPr
);
1299 WriteShapeTransformation( xShape
, XML_a
);
1301 if (CircleKind_FULL
== eCircleKind
)
1302 WritePresetShape("ellipse"_ostr
);
1305 sal_Int32
nStartAngleIntern(9000);
1306 sal_Int32
nEndAngleIntern(0);
1309 xProps
->getPropertyValue(u
"CircleStartAngle"_ustr
) >>= nStartAngleIntern
;
1310 xProps
->getPropertyValue(u
"CircleEndAngle"_ustr
) >>= nEndAngleIntern
;
1312 std::vector
< std::pair
<sal_Int32
,sal_Int32
>> aAvList
;
1313 awt::Size aSize
= xShape
->getSize();
1314 if (aSize
.Width
!= 0 || aSize
.Height
!= 0)
1316 // Our arc has 90° up, OOXML has 90° down, so mirror it.
1317 // API angles are 1/100 degree.
1318 sal_Int32
nStartAngleOOXML(lcl_CircleAngle2CustomShapeEllipseAngleOOX(36000 - nEndAngleIntern
, aSize
.Width
, aSize
.Height
));
1319 sal_Int32
nEndAngleOOXML(lcl_CircleAngle2CustomShapeEllipseAngleOOX(36000 - nStartAngleIntern
, aSize
.Width
, aSize
.Height
));
1320 lcl_AppendAdjustmentValue( aAvList
, 1, nStartAngleOOXML
);
1321 lcl_AppendAdjustmentValue( aAvList
, 2, nEndAngleOOXML
);
1323 switch (eCircleKind
)
1325 case CircleKind_ARC
:
1326 WritePresetShape("arc"_ostr
, aAvList
);
1328 case CircleKind_SECTION
:
1329 WritePresetShape("pie"_ostr
, aAvList
);
1331 case CircleKind_CUT
:
1332 WritePresetShape("chord"_ostr
, aAvList
);
1335 WritePresetShape("ellipse"_ostr
);
1340 if (CircleKind_ARC
== eCircleKind
)
1342 // An arc in ODF is never filled, even if a fill style other than
1343 // "none" is set. OOXML arc can be filled, so set fill explicit to
1344 // NONE, otherwise some hidden or inherited filling is shown.
1345 FillStyle
eFillStyle(FillStyle_NONE
);
1347 aNewValue
<<= eFillStyle
;
1348 xProps
->setPropertyValue(u
"FillStyle"_ustr
, aNewValue
);
1350 WriteFill( xProps
);
1351 WriteOutline( xProps
);
1353 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1356 WriteTextBox( xShape
, mnXmlNamespace
);
1358 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
? XML_sp
: XML_wsp
) );
1363 ShapeExport
& ShapeExport::WriteGraphicObjectShape( const Reference
< XShape
>& xShape
)
1365 WriteGraphicObjectShapePart( xShape
);
1370 void ShapeExport::WriteGraphicObjectShapePart( const Reference
< XShape
>& xShape
, const Graphic
* pGraphic
)
1372 SAL_INFO("oox.shape", "write graphic object shape");
1374 if (IsNonEmptySimpleText(xShape
))
1376 SAL_INFO("oox.shape", "graphicObject: wrote only text");
1378 WriteTextShape(xShape
);
1383 SAL_INFO("oox.shape", "graphicObject without text");
1385 uno::Reference
<graphic::XGraphic
> xGraphic
;
1388 Reference
< XPropertySet
> xShapeProps( xShape
, UNO_QUERY
);
1392 xGraphic
.set(pGraphic
->GetXGraphic());
1394 else if (xShapeProps
.is() && xShapeProps
->getPropertySetInfo()->hasPropertyByName(u
"Graphic"_ustr
))
1396 xShapeProps
->getPropertyValue(u
"Graphic"_ustr
) >>= xGraphic
;
1399 // tdf#155903 Only for PPTX, Microsoft does not support this feature in Word and Excel.
1400 bool bHasMediaURL
= GetDocumentType() == DOCUMENT_PPTX
&& xShapeProps
.is()
1401 && xShapeProps
->getPropertySetInfo()->hasPropertyByName(u
"MediaURL"_ustr
)
1402 && (xShapeProps
->getPropertyValue(u
"MediaURL"_ustr
) >>= sMediaURL
);
1404 if (!xGraphic
.is() && !bHasMediaURL
)
1406 SAL_INFO("oox.shape", "no graphic or media URL found");
1410 FSHelperPtr pFS
= GetFS();
1411 XmlFilterBase
* pFB
= GetFB();
1413 if (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
)
1414 pFS
->startElementNS(mnXmlNamespace
, XML_pic
);
1416 pFS
->startElementNS(mnXmlNamespace
, XML_pic
,
1417 FSNS(XML_xmlns
, XML_pic
), pFB
->getNamespaceURL(OOX_NS(dmlPicture
)));
1419 pFS
->startElementNS(mnXmlNamespace
, XML_nvPicPr
);
1421 presentation::ClickAction eClickAction
= presentation::ClickAction_NONE
;
1422 OUString sDescr
, sURL
, sBookmark
, sPPAction
;
1425 if ( ( bHaveDesc
= GetProperty( xShapeProps
, u
"Description"_ustr
) ) )
1427 if ( GetProperty( xShapeProps
, u
"URL"_ustr
) )
1429 if (GetProperty(xShapeProps
, u
"Bookmark"_ustr
))
1431 if (GetProperty(xShapeProps
, u
"OnClick"_ustr
))
1432 mAny
>>= eClickAction
;
1434 pFS
->startElementNS( mnXmlNamespace
, XML_cNvPr
,
1435 XML_id
, OString::number(GetNewShapeID(xShape
)),
1436 XML_name
, GetShapeName(xShape
),
1437 XML_descr
, sax_fastparser::UseIf(sDescr
, bHaveDesc
));
1439 if (eClickAction
!= presentation::ClickAction_NONE
)
1441 switch (eClickAction
)
1443 case presentation::ClickAction_STOPPRESENTATION
:
1444 sPPAction
= "ppaction://hlinkshowjump?jump=endshow";
1446 case presentation::ClickAction_NEXTPAGE
:
1447 sPPAction
= "ppaction://hlinkshowjump?jump=nextslide";
1449 case presentation::ClickAction_LASTPAGE
:
1450 sPPAction
= "ppaction://hlinkshowjump?jump=lastslide";
1452 case presentation::ClickAction_PREVPAGE
:
1453 sPPAction
= "ppaction://hlinkshowjump?jump=previousslide";
1455 case presentation::ClickAction_FIRSTPAGE
:
1456 sPPAction
= "ppaction://hlinkshowjump?jump=firstslide";
1458 case presentation::ClickAction_BOOKMARK
:
1459 sBookmark
= "#" + sBookmark
;
1466 // OOXTODO: //cNvPr children: XML_extLst, XML_hlinkHover
1467 if (bHasMediaURL
|| !sPPAction
.isEmpty())
1468 pFS
->singleElementNS(XML_a
, XML_hlinkClick
, FSNS(XML_r
, XML_id
), "", XML_action
,
1469 bHasMediaURL
? u
"ppaction://media"_ustr
: sPPAction
);
1470 if( !sURL
.isEmpty() )
1472 OUString sRelId
= mpFB
->addRelation( mpFS
->getOutputStream(),
1473 oox::getRelationship(Relationship::HYPERLINK
),
1474 mpURLTransformer
->getTransformedString(sURL
),
1475 mpURLTransformer
->isExternalURL(sURL
));
1477 mpFS
->singleElementNS(XML_a
, XML_hlinkClick
, FSNS(XML_r
, XML_id
), sRelId
);
1480 if (!sBookmark
.isEmpty())
1482 bool bExtURL
= URLTransformer().isExternalURL(sBookmark
);
1483 sBookmark
= bExtURL
? sBookmark
: lcl_GetTarget(GetFB()->getModel(), sBookmark
);
1485 OUString sRelId
= mpFB
->addRelation(mpFS
->getOutputStream(),
1486 bExtURL
? oox::getRelationship(Relationship::HYPERLINK
)
1487 : oox::getRelationship(Relationship::SLIDE
),
1488 sBookmark
, bExtURL
);
1491 mpFS
->singleElementNS(XML_a
, XML_hlinkClick
, FSNS(XML_r
, XML_id
), sRelId
);
1493 mpFS
->singleElementNS(XML_a
, XML_hlinkClick
, FSNS(XML_r
, XML_id
), sRelId
, XML_action
,
1494 "ppaction://hlinksldjump");
1496 AddExtLst(pFS
, xShapeProps
);
1497 pFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
1499 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvPicPr
1500 // OOXTODO: XML_preferRelativeSize
1503 WriteMediaNonVisualProperties(xShape
);
1505 WriteNonVisualProperties(xShape
);
1507 pFS
->endElementNS( mnXmlNamespace
, XML_nvPicPr
);
1509 pFS
->startElementNS(mnXmlNamespace
, XML_blipFill
);
1513 WriteXGraphicBlip(xShapeProps
, xGraphic
, mbUserShapes
);
1515 else if (bHasMediaURL
)
1517 Reference
<graphic::XGraphic
> xFallbackGraphic
;
1518 if (xShapeProps
->getPropertySetInfo()->hasPropertyByName(u
"FallbackGraphic"_ustr
))
1519 xShapeProps
->getPropertyValue(u
"FallbackGraphic"_ustr
) >>= xFallbackGraphic
;
1521 WriteXGraphicBlip(xShapeProps
, xFallbackGraphic
, mbUserShapes
);
1526 WriteSrcRectXGraphic(xShapeProps
, xGraphic
);
1529 // now we stretch always when we get pGraphic (when changing that
1530 // behavior, test n#780830 for regression, where the OLE sheet might get tiled
1531 bool bStretch
= false;
1532 if( !pGraphic
&& GetProperty( xShapeProps
, u
"FillBitmapStretch"_ustr
) )
1535 if ( pGraphic
|| bStretch
)
1536 pFS
->singleElementNS(XML_a
, XML_stretch
);
1540 // Graphic of media shapes is always stretched.
1541 pFS
->startElementNS(XML_a
, XML_stretch
);
1542 pFS
->singleElementNS(XML_a
, XML_fillRect
);
1543 pFS
->endElementNS(XML_a
, XML_stretch
);
1546 pFS
->endElementNS( mnXmlNamespace
, XML_blipFill
);
1548 // visual shape properties
1549 pFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
1550 bool bFlipH
= false;
1551 if( xShapeProps
->getPropertySetInfo()->hasPropertyByName(u
"IsMirrored"_ustr
) )
1553 xShapeProps
->getPropertyValue(u
"IsMirrored"_ustr
) >>= bFlipH
;
1555 WriteShapeTransformation( xShape
, XML_a
, bFlipH
, false, false, false, true );
1556 WritePresetShape( "rect"_ostr
);
1557 WriteFill(xShapeProps
);
1558 // graphic object can come with the frame (bnc#654525)
1559 WriteOutline( xShapeProps
);
1561 WriteShapeEffects( xShapeProps
);
1562 Write3DEffects( xShapeProps
, /*bIsText=*/false );
1564 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1566 pFS
->endElementNS( mnXmlNamespace
, XML_pic
);
1569 static void lcl_Rotate(sal_Int32 nAngle
, Point center
, awt::Point
& pt
)
1571 sal_Int16 nCos
, nSin
;
1589 sal_Int32 x
= pt
.X
- center
.X();
1590 sal_Int32 y
= pt
.Y
- center
.Y();
1591 pt
.X
= center
.X() + x
* nCos
- y
* nSin
;
1592 pt
.Y
= center
.Y() + y
* nCos
+ x
* nSin
;
1595 static void lcl_FlipHFlipV(const tools::Polygon
& rPoly
, sal_Int32 nAngle
, bool& rFlipH
, bool& rFlipV
)
1597 Point aStart
= rPoly
[0];
1598 Point aEnd
= rPoly
[rPoly
.GetSize() - 1];
1600 if (aStart
.X() > aEnd
.X() && aStart
.Y() > aEnd
.Y())
1616 if (aStart
.X() < aEnd
.X() && aStart
.Y() < aEnd
.Y())
1630 if (aStart
.Y() < aEnd
.Y() && aStart
.X() > aEnd
.X())
1648 if (aStart
.Y() > aEnd
.Y() && aStart
.X() < aEnd
.X())
1665 static sal_Int32
lcl_GetAngle(const tools::Polygon
& rPoly
)
1668 Point aStartPoint
= rPoly
[0];
1669 Point aEndPoint
= rPoly
[rPoly
.GetSize() - 1];
1670 if (aStartPoint
.X() == rPoly
[1].X())
1672 if ((aStartPoint
.X() < aEndPoint
.X() && aStartPoint
.Y() > aEndPoint
.Y())
1673 || (aStartPoint
.X() > aEndPoint
.X() && aStartPoint
.Y() < aEndPoint
.Y()))
1682 if (aStartPoint
.X() > rPoly
[1].X())
1691 // Adjust value decide the position, where the connector should turn.
1692 static void lcl_GetConnectorAdjustValue(const Reference
<XShape
>& xShape
, const tools::Polygon
& rPoly
,
1693 ConnectorType eConnectorType
,
1694 std::vector
<std::pair
<sal_Int32
, sal_Int32
>>& rAvList
)
1696 Reference
<XPropertySet
> xShapeProps(xShape
, UNO_QUERY
);
1697 bool bIsOOXMLCurve(false);
1698 xShapeProps
->getPropertyValue(u
"EdgeOOXMLCurve"_ustr
) >>= bIsOOXMLCurve
;
1699 sal_Int32 nAdjCount
= 0;
1700 if (eConnectorType
== ConnectorType_CURVE
)
1704 nAdjCount
= (rPoly
.GetSize() - 4) / 3;
1706 else if (rPoly
.GetSize() == 4)
1708 if ((rPoly
[0].X() == rPoly
[1].X() && rPoly
[2].X() == rPoly
[3].X())
1709 || (rPoly
[0].Y() == rPoly
[1].Y() && rPoly
[2].Y() == rPoly
[3].Y()))
1711 nAdjCount
= 1; // curvedConnector3, control vectors parallel
1714 nAdjCount
= 0; // curvedConnector2, control vectors orthogonal
1716 else if (rPoly
.GetSize() > 4)
1718 if ((rPoly
[2].X() == rPoly
[3].X() && rPoly
[3].X() == rPoly
[4].X())
1719 || (rPoly
[2].Y() == rPoly
[3].Y() && rPoly
[3].Y() == rPoly
[4].Y()))
1721 nAdjCount
= 3; // curvedConnector5
1724 nAdjCount
= 2; // curvedConnector4
1729 switch (rPoly
.GetSize())
1732 nAdjCount
= 0; // bentConnector2
1735 nAdjCount
= 1; // bentConnector3
1738 nAdjCount
= 2; // bentConnector4
1741 nAdjCount
= 3; // bentConnector5
1748 sal_Int32 nAdjustValue
;
1749 Point aStart
= rPoly
[0];
1750 Point aEnd
= rPoly
[rPoly
.GetSize() - 1];
1752 for (sal_Int32 i
= 1; i
<= nAdjCount
; ++i
)
1754 Point aPt
= rPoly
[i
];
1756 if (aEnd
.Y() == aStart
.Y())
1757 aEnd
.setY(aStart
.Y() + 1);
1758 if (aEnd
.X() == aStart
.X())
1759 aEnd
.setX(aStart
.X() + 1);
1761 bool bVertical
= rPoly
[1].X() - aStart
.X() != 0 ? true : false;
1762 // vertical and horizon alternate
1764 bVertical
= !bVertical
;
1766 if (eConnectorType
== ConnectorType_CURVE
)
1774 awt::Size aSize
= xShape
->getSize();
1775 awt::Point aShapePosition
= xShape
->getPosition();
1776 tools::Rectangle aBoundRect
= rPoly
.GetBoundRect();
1780 if ((aBoundRect
.GetSize().Height() - aSize
.Height
) == 1)
1781 aPt
.setY(rPoly
[i
+ 1].Y());
1782 else if (aStart
.Y() > aPt
.Y())
1783 aPt
.setY(aShapePosition
.Y
);
1785 aPt
.setY(aShapePosition
.Y
+ aSize
.Height
);
1789 if ((aBoundRect
.GetSize().Width() - aSize
.Width
) == 1)
1790 aPt
.setX(rPoly
[i
+ 1].X());
1791 else if (aStart
.X() > aPt
.X())
1792 aPt
.setX(aShapePosition
.X
);
1794 aPt
.setX(aShapePosition
.X
+ aSize
.Width
);
1800 nAdjustValue
= ((aPt
.Y() - aStart
.Y()) * 100000) / (aEnd
.Y() - aStart
.Y());
1802 nAdjustValue
= ((aPt
.X() - aStart
.X()) * 100000) / (aEnd
.X() - aStart
.X());
1804 rAvList
.emplace_back(i
, nAdjustValue
);
1809 static sal_Int32
lcl_GetGluePointId(const Reference
<XShape
>& xShape
, sal_Int32 nGluePointId
)
1811 if (nGluePointId
> 3)
1812 return nGluePointId
- 4;
1815 bool bFlipH
= false;
1816 bool bFlipV
= false;
1817 Reference
<XPropertySet
> xShapeProps(xShape
, UNO_QUERY
);
1818 if (xShapeProps
.is() && xShapeProps
->getPropertySetInfo()
1819 && xShapeProps
->getPropertySetInfo()->hasPropertyByName(u
"CustomShapeGeometry"_ustr
))
1821 Sequence
<PropertyValue
> aGeometrySeq
;
1822 xShapeProps
->getPropertyValue(u
"CustomShapeGeometry"_ustr
) >>= aGeometrySeq
;
1823 for (int i
= 0; i
< aGeometrySeq
.getLength(); i
++)
1825 const PropertyValue
& rProp
= aGeometrySeq
[i
];
1826 if (rProp
.Name
== "MirroredX")
1827 rProp
.Value
>>= bFlipH
;
1829 if (rProp
.Name
== "MirroredY")
1830 rProp
.Value
>>= bFlipV
;
1834 if ((!bFlipH
&& !bFlipV
) || (bFlipH
&& bFlipV
))
1836 // change id of the bounding box (1 <-> 3)
1837 if (nGluePointId
== 1)
1838 nGluePointId
= 3; // Right
1839 else if (nGluePointId
== 3)
1840 nGluePointId
= 1; // Left
1844 return nGluePointId
;
1847 ShapeExport
& ShapeExport::WriteConnectorShape( const Reference
< XShape
>& xShape
)
1849 bool bFlipH
= false;
1850 bool bFlipV
= false;
1851 sal_Int32 nAngle
= 0;
1852 sal_Int32 nStartGlueId
= 0;
1853 sal_Int32 nEndGlueId
= 0;
1855 SAL_INFO("oox.shape", "write connector shape");
1857 FSHelperPtr pFS
= GetFS();
1860 std::vector
<std::pair
<sal_Int32
, sal_Int32
>> aAdjustValueList
;
1861 Reference
< XPropertySet
> rXPropSet( xShape
, UNO_QUERY
);
1862 Reference
< XPropertyState
> rXPropState( xShape
, UNO_QUERY
);
1863 awt::Point aStartPoint
, aEndPoint
;
1864 Reference
< XShape
> rXShapeA
;
1865 Reference
< XShape
> rXShapeB
;
1866 PropertyState eState
;
1867 ConnectorType eConnectorType
= ConnectorType_STANDARD
;
1868 if (GetProperty(rXPropSet
, u
"EdgeKind"_ustr
))
1869 mAny
>>= eConnectorType
;
1871 switch( eConnectorType
) {
1872 case ConnectorType_CURVE
:
1873 sGeometry
= "curvedConnector";
1875 case ConnectorType_LINES
:
1876 case ConnectorType_STANDARD
:
1877 sGeometry
= "bentConnector";
1880 case ConnectorType_LINE
:
1881 sGeometry
= "straightConnector1";
1885 if (GetPropertyAndState( rXPropSet
, rXPropState
, u
"EdgeStartPoint"_ustr
, eState
) && eState
== beans::PropertyState_DIRECT_VALUE
)
1887 mAny
>>= aStartPoint
;
1888 if (GetPropertyAndState( rXPropSet
, rXPropState
, u
"EdgeEndPoint"_ustr
, eState
) && eState
== beans::PropertyState_DIRECT_VALUE
)
1891 if (GetProperty(rXPropSet
, u
"EdgeStartConnection"_ustr
))
1893 if (GetProperty(rXPropSet
, u
"EdgeEndConnection"_ustr
))
1896 if (GetProperty(rXPropSet
, u
"StartGluePointIndex"_ustr
))
1897 mAny
>>= nStartGlueId
;
1898 if (nStartGlueId
!= -1)
1899 nStartGlueId
= lcl_GetGluePointId(rXShapeA
, nStartGlueId
);
1901 if (GetProperty(rXPropSet
, u
"EndGluePointIndex"_ustr
))
1902 mAny
>>= nEndGlueId
;
1903 if (nEndGlueId
!= -1)
1904 nEndGlueId
= lcl_GetGluePointId(rXShapeB
, nEndGlueId
);
1906 // Position is relative to group in Word, but relative to anchor of group in API.
1907 if (GetDocumentType() == DOCUMENT_DOCX
&& !mbUserShapes
&& m_xParent
.is())
1909 awt::Point aParentPos
= m_xParent
->getPosition();
1910 aStartPoint
.X
-= aParentPos
.X
;
1911 aStartPoint
.Y
-= aParentPos
.Y
;
1912 aEndPoint
.X
-= aParentPos
.X
;
1913 aEndPoint
.Y
-= aParentPos
.Y
;
1915 EscherConnectorListEntry
aConnectorEntry( xShape
, aStartPoint
, rXShapeA
, aEndPoint
, rXShapeB
);
1917 if (eConnectorType
!= ConnectorType_LINE
)
1919 tools::PolyPolygon aPolyPolygon
= EscherPropertyContainer::GetPolyPolygon(xShape
);
1920 if (aPolyPolygon
.Count() > 0)
1922 const tools::Polygon
& aPoly
= aPolyPolygon
.GetObject(0);
1923 lcl_GetConnectorAdjustValue(xShape
, aPoly
, eConnectorType
, aAdjustValueList
);
1924 nAngle
= lcl_GetAngle(aPoly
);
1925 lcl_FlipHFlipV(aPoly
, nAngle
, bFlipH
, bFlipV
);
1928 Point
center((aEndPoint
.X
+ aStartPoint
.X
) / 2, (aEndPoint
.Y
+ aStartPoint
.Y
) / 2);
1929 lcl_Rotate(nAngle
, center
, aStartPoint
);
1930 lcl_Rotate(nAngle
, center
, aEndPoint
);
1933 sGeometry
= sGeometry
+ OUString::number(aAdjustValueList
.size() + 2);
1937 tools::Rectangle
aRect( Point( aStartPoint
.X
, aStartPoint
.Y
), Point( aEndPoint
.X
, aEndPoint
.Y
) );
1938 if( aRect
.getOpenWidth() < 0 ) {
1939 aRect
.SetLeft(aEndPoint
.X
);
1940 aRect
.setWidth( aStartPoint
.X
- aEndPoint
.X
);
1941 if (eConnectorType
== ConnectorType_LINE
)
1945 if( aRect
.getOpenHeight() < 0 ) {
1946 aRect
.SetTop(aEndPoint
.Y
);
1947 aRect
.setHeight( aStartPoint
.Y
- aEndPoint
.Y
);
1948 if (eConnectorType
== ConnectorType_LINE
)
1952 // tdf#99810 connector shape (cxnSp) is not valid with namespace 'wps'
1953 const auto nShapeNode
= (mnXmlNamespace
== XML_wps
? XML_wsp
: XML_cxnSp
);
1954 pFS
->startElementNS(mnXmlNamespace
, nShapeNode
);
1956 if (mnXmlNamespace
== XML_wps
)
1958 // non visual connector shape drawing properties
1959 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvCnPr
);
1963 // non visual shape properties
1964 pFS
->startElementNS(mnXmlNamespace
, XML_nvCxnSpPr
);
1965 pFS
->startElementNS(mnXmlNamespace
, XML_cNvPr
,
1966 XML_id
, OString::number(GetNewShapeID(xShape
)),
1967 XML_name
, GetShapeName(xShape
));
1968 AddExtLst(pFS
, rXPropSet
);
1969 pFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
1970 // non visual connector shape drawing properties
1971 pFS
->startElementNS(mnXmlNamespace
, XML_cNvCxnSpPr
);
1973 if (GetShapeID(rXShapeA
) == -1)
1974 GetNewShapeID(rXShapeA
);
1975 if (GetShapeID(rXShapeB
) == -1)
1976 GetNewShapeID(rXShapeB
);
1977 WriteConnectorConnections(nStartGlueId
, nEndGlueId
, GetShapeID(rXShapeA
), GetShapeID(rXShapeB
));
1978 pFS
->endElementNS(mnXmlNamespace
, XML_cNvCxnSpPr
);
1979 if (GetDocumentType() == DOCUMENT_PPTX
)
1980 pFS
->singleElementNS(mnXmlNamespace
, XML_nvPr
);
1981 pFS
->endElementNS(mnXmlNamespace
, XML_nvCxnSpPr
);
1984 // visual shape properties
1985 pFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
1986 WriteTransformation( xShape
, aRect
, XML_a
, bFlipH
, bFlipV
, nAngle
);
1987 // TODO: write adjustments (ppt export doesn't work well there either)
1988 WritePresetShape( sGeometry
.toUtf8(), aAdjustValueList
);
1989 Reference
< XPropertySet
> xShapeProps( xShape
, UNO_QUERY
);
1990 if( xShapeProps
.is() )
1991 WriteOutline( xShapeProps
);
1992 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1994 // connector shape (cxnSp) cannot contain text (txBody) (according to schema)
1995 if( nShapeNode
!= XML_cxnSp
)
1998 WriteTextBox( xShape
, mnXmlNamespace
);
2001 pFS
->endElementNS(mnXmlNamespace
, nShapeNode
);
2006 ShapeExport
& ShapeExport::WriteLineShape( const Reference
< XShape
>& xShape
)
2008 bool bFlipH
= false;
2009 bool bFlipV
= false;
2011 SAL_INFO("oox.shape", "write line shape");
2013 FSHelperPtr pFS
= GetFS();
2015 pFS
->startElementNS(mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
? XML_sp
: XML_wsp
));
2017 tools::PolyPolygon aPolyPolygon
= EscherPropertyContainer::GetPolyPolygon( xShape
);
2018 if( aPolyPolygon
.Count() == 1 && aPolyPolygon
[ 0 ].GetSize() == 2)
2020 const tools::Polygon
& rPoly
= aPolyPolygon
[ 0 ];
2022 bFlipH
= ( rPoly
[ 0 ].X() > rPoly
[ 1 ].X() );
2023 bFlipV
= ( rPoly
[ 0 ].Y() > rPoly
[ 1 ].Y() );
2026 Reference
<XPropertySet
> const xShapeProps(xShape
, UNO_QUERY
);
2027 // non visual shape properties
2028 if (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
)
2030 pFS
->startElementNS(mnXmlNamespace
, XML_nvSpPr
);
2031 pFS
->startElementNS(mnXmlNamespace
, XML_cNvPr
,
2032 XML_id
, OString::number(GetNewShapeID(xShape
)),
2033 XML_name
, GetShapeName(xShape
));
2034 AddExtLst(pFS
, xShapeProps
);
2035 pFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
2037 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvSpPr
);
2038 if (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
)
2040 WriteNonVisualProperties( xShape
);
2041 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
2044 // visual shape properties
2045 pFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
2046 WriteShapeTransformation( xShape
, XML_a
, bFlipH
, bFlipV
, true);
2047 WritePresetShape( "line"_ostr
);
2048 if( xShapeProps
.is() )
2049 WriteOutline( xShapeProps
);
2050 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
2053 pFS
->startElementNS(mnXmlNamespace
, XML_style
);
2054 WriteShapeStyle( xShapeProps
);
2055 pFS
->endElementNS( mnXmlNamespace
, XML_style
);
2058 WriteTextBox( xShape
, mnXmlNamespace
);
2060 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
? XML_sp
: XML_wsp
) );
2065 ShapeExport
& ShapeExport::WriteNonVisualDrawingProperties( const Reference
< XShape
>& xShape
, const char* pName
)
2067 FSHelperPtr pFS
= GetFS();
2069 Reference
<XPropertySet
> const xShapeProps(xShape
, UNO_QUERY
);
2070 pFS
->startElementNS(mnXmlNamespace
, XML_cNvPr
,
2071 XML_id
, OString::number(GetNewShapeID(xShape
)),
2073 AddExtLst(pFS
, xShapeProps
);
2074 pFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
2079 ShapeExport
& ShapeExport::WriteNonVisualProperties( const Reference
< XShape
>& )
2081 // Override to generate //nvPr elements.
2085 ShapeExport
& ShapeExport::WriteRectangleShape( const Reference
< XShape
>& xShape
)
2087 SAL_INFO("oox.shape", "write rectangle shape");
2089 FSHelperPtr pFS
= GetFS();
2091 pFS
->startElementNS(mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
? XML_sp
: XML_wsp
));
2093 sal_Int32 nRadius
= 0;
2095 Reference
< XPropertySet
> xShapeProps( xShape
, UNO_QUERY
);
2096 if( xShapeProps
.is() )
2098 xShapeProps
->getPropertyValue( u
"CornerRadius"_ustr
) >>= nRadius
;
2103 nRadius
= MapSize( awt::Size( nRadius
, 0 ) ).Width
;
2105 //TODO: use nRadius value more precisely than just deciding whether to use
2106 // "rect" or "roundRect" preset shape below
2108 // non visual shape properties
2109 if (GetDocumentType() == DOCUMENT_DOCX
&& !mbUserShapes
)
2110 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
);
2111 pFS
->startElementNS(mnXmlNamespace
, XML_nvSpPr
);
2112 pFS
->startElementNS(mnXmlNamespace
, XML_cNvPr
,
2113 XML_id
, OString::number(GetNewShapeID(xShape
)),
2114 XML_name
, GetShapeName(xShape
));
2115 AddExtLst(pFS
, xShapeProps
);
2116 pFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
2117 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
);
2118 WriteNonVisualProperties( xShape
);
2119 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
2121 // visual shape properties
2122 pFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
2123 WriteShapeTransformation( xShape
, XML_a
);
2124 WritePresetShape( nRadius
== 0 ? "rect" : "roundRect" );
2125 Reference
< XPropertySet
> xProps( xShape
, UNO_QUERY
);
2128 WriteFill( xProps
);
2129 WriteOutline( xProps
);
2131 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
2134 WriteTextBox( xShape
, mnXmlNamespace
);
2136 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
? XML_sp
: XML_wsp
) );
2142 typedef ShapeExport
& (ShapeExport::*ShapeConverter
)( const Reference
< XShape
>& );
2143 typedef std::unordered_map
< const char*, ShapeConverter
, rtl::CStringHash
, rtl::CStringEqual
> NameToConvertMapType
;
2148 constexpr auto constMap
= frozen::make_unordered_map
<std::u16string_view
, ShapeConverter
>(
2150 { u
"com.sun.star.drawing.CaptionShape", &ShapeExport::WriteTextShape
},
2151 { u
"com.sun.star.drawing.ClosedBezierShape", &ShapeExport::WriteClosedPolyPolygonShape
},
2152 { u
"com.sun.star.drawing.ConnectorShape", &ShapeExport::WriteConnectorShape
},
2153 { u
"com.sun.star.drawing.CustomShape", &ShapeExport::WriteCustomShape
},
2154 { u
"com.sun.star.drawing.EllipseShape", &ShapeExport::WriteEllipseShape
},
2155 { u
"com.sun.star.drawing.GraphicObjectShape", &ShapeExport::WriteGraphicObjectShape
},
2156 { u
"com.sun.star.drawing.LineShape", &ShapeExport::WriteLineShape
},
2157 { u
"com.sun.star.drawing.MediaShape", &ShapeExport::WriteGraphicObjectShape
},
2158 { u
"com.sun.star.drawing.OpenBezierShape", &ShapeExport::WriteOpenPolyPolygonShape
},
2159 { u
"com.sun.star.drawing.PolyPolygonShape", &ShapeExport::WriteClosedPolyPolygonShape
},
2160 { u
"com.sun.star.drawing.PolyLineShape", &ShapeExport::WriteOpenPolyPolygonShape
},
2161 { u
"com.sun.star.drawing.RectangleShape", &ShapeExport::WriteRectangleShape
},
2162 { u
"com.sun.star.drawing.OLE2Shape", &ShapeExport::WriteOLE2Shape
},
2163 { u
"com.sun.star.drawing.TableShape", &ShapeExport::WriteTableShape
},
2164 { u
"com.sun.star.drawing.TextShape", &ShapeExport::WriteTextShape
},
2165 { u
"com.sun.star.drawing.GroupShape", &ShapeExport::WriteGroupShape
},
2166 { u
"com.sun.star.presentation.GraphicObjectShape", &ShapeExport::WriteGraphicObjectShape
},
2167 { u
"com.sun.star.presentation.MediaShape", &ShapeExport::WriteGraphicObjectShape
},
2168 { u
"com.sun.star.presentation.ChartShape", &ShapeExport::WriteOLE2Shape
},
2169 { u
"com.sun.star.presentation.OLE2Shape", &ShapeExport::WriteOLE2Shape
},
2170 { u
"com.sun.star.presentation.TableShape", &ShapeExport::WriteTableShape
},
2171 { u
"com.sun.star.presentation.TextShape", &ShapeExport::WriteTextShape
},
2172 { u
"com.sun.star.presentation.DateTimeShape", &ShapeExport::WriteTextShape
},
2173 { u
"com.sun.star.presentation.FooterShape", &ShapeExport::WriteTextShape
},
2174 { u
"com.sun.star.presentation.HeaderShape", &ShapeExport::WriteTextShape
},
2175 { u
"com.sun.star.presentation.NotesShape", &ShapeExport::WriteTextShape
},
2176 { u
"com.sun.star.presentation.OutlinerShape", &ShapeExport::WriteTextShape
},
2177 { u
"com.sun.star.presentation.SlideNumberShape", &ShapeExport::WriteTextShape
},
2178 { u
"com.sun.star.presentation.TitleTextShape", &ShapeExport::WriteTextShape
},
2181 } // end anonymous namespace
2183 ShapeExport
& ShapeExport::WriteShape( const Reference
< XShape
>& xShape
)
2186 throw lang::IllegalArgumentException();
2188 OUString sShapeType
= xShape
->getShapeType();
2189 SAL_INFO("oox.shape", "write shape: " << sShapeType
);
2190 auto aConverterIterator
= constMap
.find(sShapeType
);
2191 if (aConverterIterator
== constMap
.end())
2193 SAL_INFO("oox.shape", "unknown shape");
2194 return WriteUnknownShape( xShape
);
2197 if (GetDocumentType() == DOCUMENT_PPTX
)
2199 Reference
< XPropertySet
> xShapeProperties(xShape
, UNO_QUERY
);
2200 if (xShapeProperties
&& xShapeProperties
->getPropertySetInfo()
2201 && xShapeProperties
->getPropertySetInfo()->hasPropertyByName(u
"IsPresentationObject"_ustr
)
2202 && xShapeProperties
->getPropertyValue(u
"IsPresentationObject"_ustr
).hasValue())
2203 mbPlaceholder
= xShapeProperties
->getPropertyValue(u
"IsPresentationObject"_ustr
).get
<bool>();
2206 (this->*(aConverterIterator
->second
))(xShape
);
2211 static bool lcl_isTextBox(const Reference
<XInterface
>& xIface
)
2213 uno::Reference
<beans::XPropertySet
> xPropertySet(xIface
, uno::UNO_QUERY
);
2214 if (!xPropertySet
.is())
2216 uno::Reference
<beans::XPropertySetInfo
> xPropertySetInfo
= xPropertySet
->getPropertySetInfo();
2217 if (!xPropertySetInfo
->hasPropertyByName(u
"TextBox"_ustr
))
2219 css::uno::Any
aTextBox(xPropertySet
->getPropertyValue(u
"TextBox"_ustr
));
2220 if (!aTextBox
.hasValue())
2222 return aTextBox
.get
<bool>();
2225 ShapeExport
& ShapeExport::WriteTextBox( const Reference
< XInterface
>& xIface
, sal_Int32 nXmlNamespace
, bool bWritePropertiesAsLstStyles
)
2227 // In case this shape has an associated textbox, then export that, and we're done.
2228 if (GetDocumentType() == DOCUMENT_DOCX
&& !mbUserShapes
&& GetTextExport())
2230 if (lcl_isTextBox(xIface
))
2232 GetTextExport()->WriteTextBox(uno::Reference
<drawing::XShape
>(xIface
, uno::UNO_QUERY_THROW
));
2233 WriteText( xIface
, /*bBodyPr=*/true, /*bText=*/false, /*nXmlNamespace=*/nXmlNamespace
);
2238 Reference
< XText
> xXText( xIface
, UNO_QUERY
);
2239 if( (NonEmptyText( xIface
) || GetDocumentType() == DOCUMENT_PPTX
)
2242 FSHelperPtr pFS
= GetFS();
2244 pFS
->startElementNS(nXmlNamespace
,
2245 (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
? XML_txBody
: XML_txbx
));
2246 WriteText(xIface
, /*bBodyPr=*/(GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
), /*bText=*/true,
2247 /*nXmlNamespace=*/0, /*bWritePropertiesAsLstStyles=*/bWritePropertiesAsLstStyles
);
2248 pFS
->endElementNS( nXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
? XML_txBody
: XML_txbx
) );
2249 if (GetDocumentType() == DOCUMENT_DOCX
&& !mbUserShapes
)
2250 WriteText( xIface
, /*bBodyPr=*/true, /*bText=*/false, /*nXmlNamespace=*/nXmlNamespace
);
2252 else if (GetDocumentType() == DOCUMENT_DOCX
&& !mbUserShapes
)
2253 mpFS
->singleElementNS(nXmlNamespace
, XML_bodyPr
);
2258 void ShapeExport::WriteTable( const Reference
< XShape
>& rXShape
)
2260 Reference
< XTable
> xTable
;
2261 Reference
< XPropertySet
> xPropSet( rXShape
, UNO_QUERY
);
2263 mpFS
->startElementNS(XML_a
, XML_graphic
);
2264 mpFS
->startElementNS(XML_a
, XML_graphicData
,
2265 XML_uri
, "http://schemas.openxmlformats.org/drawingml/2006/table");
2267 if ( xPropSet
.is() && ( xPropSet
->getPropertyValue( u
"Model"_ustr
) >>= xTable
) )
2269 mpFS
->startElementNS(XML_a
, XML_tbl
);
2270 mpFS
->startElementNS(XML_a
, XML_tblPr
);
2271 WriteShapeEffects(xPropSet
);
2272 mpFS
->endElementNS(XML_a
, XML_tblPr
);
2274 Reference
< container::XIndexAccess
> xColumns( xTable
->getColumns(), UNO_QUERY_THROW
);
2275 Reference
< container::XIndexAccess
> xRows( xTable
->getRows(), UNO_QUERY_THROW
);
2276 sal_uInt16 nRowCount
= static_cast< sal_uInt16
>( xRows
->getCount() );
2277 sal_uInt16 nColumnCount
= static_cast< sal_uInt16
>( xColumns
->getCount() );
2279 mpFS
->startElementNS(XML_a
, XML_tblGrid
);
2281 for ( sal_Int32 x
= 0; x
< nColumnCount
; x
++ )
2283 Reference
< XPropertySet
> xColPropSet( xColumns
->getByIndex( x
), UNO_QUERY_THROW
);
2284 sal_Int32
nWidth(0);
2285 xColPropSet
->getPropertyValue( u
"Width"_ustr
) >>= nWidth
;
2287 mpFS
->singleElementNS(XML_a
, XML_gridCol
,
2288 XML_w
, OString::number(oox::drawingml::convertHmmToEmu(nWidth
)));
2291 mpFS
->endElementNS( XML_a
, XML_tblGrid
);
2293 // map for holding the transpose index of the merged cells and pair<parentTransposeIndex, parentCell>
2294 typedef std::unordered_map
<sal_Int32
, std::pair
<sal_Int32
, Reference
< XMergeableCell
> > > transposeTableMap
;
2295 transposeTableMap mergedCellMap
;
2297 for( sal_Int32 nRow
= 0; nRow
< nRowCount
; nRow
++ )
2299 Reference
< XPropertySet
> xRowPropSet( xRows
->getByIndex( nRow
), UNO_QUERY_THROW
);
2300 sal_Int32
nRowHeight(0);
2302 xRowPropSet
->getPropertyValue( u
"Height"_ustr
) >>= nRowHeight
;
2304 mpFS
->startElementNS(XML_a
, XML_tr
,
2305 XML_h
, OString::number(oox::drawingml::convertHmmToEmu(nRowHeight
)));
2306 for( sal_Int32 nColumn
= 0; nColumn
< nColumnCount
; nColumn
++ )
2308 Reference
< XMergeableCell
> xCell( xTable
->getCellByPosition( nColumn
, nRow
),
2310 sal_Int32 transposedIndexofCell
= (nRow
* nColumnCount
) + nColumn
;
2312 //assume we will open a cell, set to false below if we won't
2313 bool bCellOpened
= true;
2315 if(xCell
->getColumnSpan() > 1 && xCell
->getRowSpan() > 1)
2317 // having both : horizontal and vertical merge
2318 mpFS
->startElementNS(XML_a
, XML_tc
,
2319 XML_gridSpan
, OString::number(xCell
->getColumnSpan()),
2320 XML_rowSpan
, OString::number(xCell
->getRowSpan()));
2321 // since, XMergeableCell doesn't have the information about
2322 // cell having hMerge or vMerge.
2323 // So, Populating the merged cell map in-order to use it to
2324 // decide the attribute for the individual cell.
2325 for(sal_Int32 columnIndex
= nColumn
; columnIndex
< nColumn
+xCell
->getColumnSpan(); ++columnIndex
)
2327 for(sal_Int32 rowIndex
= nRow
; rowIndex
< nRow
+xCell
->getRowSpan(); ++rowIndex
)
2329 sal_Int32 transposeIndexForMergeCell
=
2330 (rowIndex
* nColumnCount
) + columnIndex
;
2331 mergedCellMap
[transposeIndexForMergeCell
] =
2332 std::make_pair(transposedIndexofCell
, xCell
);
2337 else if(xCell
->getColumnSpan() > 1)
2339 // having : horizontal merge
2340 mpFS
->startElementNS(XML_a
, XML_tc
,
2341 XML_gridSpan
, OString::number(xCell
->getColumnSpan()));
2342 for(sal_Int32 columnIndex
= nColumn
; columnIndex
< nColumn
+ xCell
->getColumnSpan(); ++columnIndex
) {
2343 sal_Int32 transposeIndexForMergeCell
= (nRow
*nColumnCount
) + columnIndex
;
2344 mergedCellMap
[transposeIndexForMergeCell
] =
2345 std::make_pair(transposedIndexofCell
, xCell
);
2348 else if(xCell
->getRowSpan() > 1)
2350 // having : vertical merge
2351 mpFS
->startElementNS(XML_a
, XML_tc
,
2352 XML_rowSpan
, OString::number(xCell
->getRowSpan()));
2354 for(sal_Int32 rowIndex
= nRow
; rowIndex
< nRow
+ xCell
->getRowSpan(); ++rowIndex
) {
2355 sal_Int32 transposeIndexForMergeCell
= (rowIndex
*nColumnCount
) + nColumn
;
2356 mergedCellMap
[transposeIndexForMergeCell
] =
2357 std::make_pair(transposedIndexofCell
, xCell
);
2362 // now, the cell can be an independent cell or
2363 // it can be a cell which is been merged to some parent cell
2364 if(!xCell
->isMerged())
2367 mpFS
->startElementNS(XML_a
, XML_tc
);
2371 // it a merged cell to some parent cell
2372 // find the parent cell for the current cell at hand
2373 transposeTableMap::iterator it
= mergedCellMap
.find(transposedIndexofCell
);
2374 if(it
!= mergedCellMap
.end())
2376 sal_Int32 transposeIndexOfParent
= it
->second
.first
;
2377 Reference
< XMergeableCell
> parentCell
= it
->second
.second
;
2378 // finding the row and column index for the parent cell from transposed index
2379 sal_Int32 parentColumnIndex
= transposeIndexOfParent
% nColumnCount
;
2380 sal_Int32 parentRowIndex
= transposeIndexOfParent
/ nColumnCount
;
2381 if(nColumn
== parentColumnIndex
)
2383 // the cell is vertical merge and it might have gridspan
2384 if(parentCell
->getColumnSpan() > 1)
2386 // vMerge and has gridSpan
2387 mpFS
->startElementNS(XML_a
, XML_tc
,
2388 XML_vMerge
, OString::number(1),
2389 XML_gridSpan
, OString::number(xCell
->getColumnSpan()));
2394 mpFS
->startElementNS(XML_a
, XML_tc
,
2395 XML_vMerge
, OString::number(1));
2398 else if(nRow
== parentRowIndex
)
2400 // the cell is horizontal merge and it might have rowspan
2401 if(parentCell
->getRowSpan() > 1)
2403 // hMerge and has rowspan
2404 mpFS
->startElementNS(XML_a
, XML_tc
,
2405 XML_hMerge
, OString::number(1),
2406 XML_rowSpan
, OString::number(xCell
->getRowSpan()));
2411 mpFS
->startElementNS(XML_a
, XML_tc
,
2412 XML_hMerge
, OString::number(1));
2417 // has hMerge and vMerge
2418 mpFS
->startElementNS(XML_a
, XML_tc
,
2419 XML_vMerge
, OString::number(1),
2420 XML_hMerge
, OString::number(1));
2424 bCellOpened
= false;
2430 WriteTextBox( xCell
, XML_a
);
2432 Reference
< XPropertySet
> xCellPropSet(xCell
, UNO_QUERY_THROW
);
2433 WriteTableCellProperties(xCellPropSet
);
2435 mpFS
->endElementNS( XML_a
, XML_tc
);
2439 mpFS
->endElementNS( XML_a
, XML_tr
);
2442 mpFS
->endElementNS( XML_a
, XML_tbl
);
2445 mpFS
->endElementNS( XML_a
, XML_graphicData
);
2446 mpFS
->endElementNS( XML_a
, XML_graphic
);
2449 void ShapeExport::WriteTableCellProperties(const Reference
< XPropertySet
>& xCellPropSet
)
2451 sal_Int32
nLeftMargin(0), nRightMargin(0);
2452 TextVerticalAdjust eVerticalAlignment
;
2453 const char* sVerticalAlignment
;
2455 Any aLeftMargin
= xCellPropSet
->getPropertyValue(u
"TextLeftDistance"_ustr
);
2456 aLeftMargin
>>= nLeftMargin
;
2458 Any aRightMargin
= xCellPropSet
->getPropertyValue(u
"TextRightDistance"_ustr
);
2459 aRightMargin
>>= nRightMargin
;
2461 Any aVerticalAlignment
= xCellPropSet
->getPropertyValue(u
"TextVerticalAdjust"_ustr
);
2462 aVerticalAlignment
>>= eVerticalAlignment
;
2463 sVerticalAlignment
= GetTextVerticalAdjust(eVerticalAlignment
);
2465 sal_Int32 nRotateAngle
= 0;
2466 Any aRotateAngle
= xCellPropSet
->getPropertyValue(u
"RotateAngle"_ustr
);
2467 aRotateAngle
>>= nRotateAngle
;
2468 std::optional
<OString
> aTextVerticalValue
= GetTextVerticalType(nRotateAngle
);
2470 Sequence
<PropertyValue
> aGrabBag
;
2471 if( !aTextVerticalValue
&&
2472 (xCellPropSet
->getPropertyValue(u
"CellInteropGrabBag"_ustr
) >>= aGrabBag
) )
2474 for (auto const& rIt
: aGrabBag
)
2476 if (rIt
.Name
== "mso-tcPr-vert-value")
2478 aTextVerticalValue
= rIt
.Value
.get
<OUString
>().toUtf8();
2484 mpFS
->startElementNS(XML_a
, XML_tcPr
, XML_anchor
, sVerticalAlignment
,
2485 XML_vert
, aTextVerticalValue
,
2486 XML_marL
, sax_fastparser::UseIf(OString::number(oox::drawingml::convertHmmToEmu(nLeftMargin
)), nLeftMargin
> 0),
2487 XML_marR
, sax_fastparser::UseIf(OString::number(oox::drawingml::convertHmmToEmu(nRightMargin
)), nRightMargin
> 0));
2489 // Write background fill for table cell.
2491 // tcW : Table cell width
2492 WriteTableCellBorders(xCellPropSet
);
2493 DrawingML::WriteFill(xCellPropSet
);
2494 mpFS
->endElementNS( XML_a
, XML_tcPr
);
2497 void ShapeExport::WriteBorderLine(const sal_Int32 xml_line_element
, const BorderLine2
& rBorderLine
)
2499 // While importing the table cell border line width, it converts EMU->Hmm then divided result by 2.
2500 // To get original value of LineWidth need to multiple by 2.
2501 sal_Int32 nBorderWidth
= rBorderLine
.LineWidth
;
2503 nBorderWidth
= oox::drawingml::convertHmmToEmu( nBorderWidth
);
2505 if ( nBorderWidth
> 0 )
2507 mpFS
->startElementNS(XML_a
, xml_line_element
, XML_w
, OString::number(nBorderWidth
));
2508 if ( rBorderLine
.Color
== sal_Int32( COL_AUTO
) )
2509 mpFS
->singleElementNS(XML_a
, XML_noFill
);
2511 DrawingML::WriteSolidFill( ::Color(ColorTransparency
, rBorderLine
.Color
) );
2513 OUString sBorderStyle
;
2514 sal_Int16 nStyle
= rBorderLine
.LineStyle
;
2515 mAny
.setValue(&nStyle
, cppu::UnoType
<sal_Int16
>::get());
2516 switch (*o3tl::doAccess
<sal_Int16
>(mAny
))
2518 case ::table::BorderLineStyle::SOLID
:
2519 sBorderStyle
= "solid";
2521 case ::table::BorderLineStyle::DOTTED
:
2522 sBorderStyle
= "dot";
2524 case ::table::BorderLineStyle::DASHED
:
2525 sBorderStyle
= "dash";
2527 case ::table::BorderLineStyle::DASH_DOT
:
2528 sBorderStyle
= "dashDot";
2530 case ::table::BorderLineStyle::DASH_DOT_DOT
:
2531 sBorderStyle
= "sysDashDotDot";
2534 mpFS
->singleElementNS(XML_a
, XML_prstDash
, XML_val
, sBorderStyle
);
2535 mpFS
->endElementNS(XML_a
, xml_line_element
);
2537 else if( nBorderWidth
== 0)
2539 mpFS
->startElementNS(XML_a
, xml_line_element
);
2540 mpFS
->singleElementNS(XML_a
, XML_noFill
);
2541 mpFS
->endElementNS(XML_a
, xml_line_element
);
2545 void ShapeExport::WriteTableCellBorders(const Reference
< XPropertySet
>& xCellPropSet
)
2547 BorderLine2 aBorderLine
;
2549 // lnL - Left Border Line Properties of table cell
2550 xCellPropSet
->getPropertyValue(u
"LeftBorder"_ustr
) >>= aBorderLine
;
2551 WriteBorderLine( XML_lnL
, aBorderLine
);
2553 // lnR - Right Border Line Properties of table cell
2554 xCellPropSet
->getPropertyValue(u
"RightBorder"_ustr
) >>= aBorderLine
;
2555 WriteBorderLine( XML_lnR
, aBorderLine
);
2557 // lnT - Top Border Line Properties of table cell
2558 xCellPropSet
->getPropertyValue(u
"TopBorder"_ustr
) >>= aBorderLine
;
2559 WriteBorderLine( XML_lnT
, aBorderLine
);
2561 // lnB - Bottom Border Line Properties of table cell
2562 xCellPropSet
->getPropertyValue(u
"BottomBorder"_ustr
) >>= aBorderLine
;
2563 WriteBorderLine( XML_lnB
, aBorderLine
);
2566 ShapeExport
& ShapeExport::WriteTableShape( const Reference
< XShape
>& xShape
)
2568 FSHelperPtr pFS
= GetFS();
2570 pFS
->startElementNS(mnXmlNamespace
, XML_graphicFrame
);
2572 pFS
->startElementNS(mnXmlNamespace
, XML_nvGraphicFramePr
);
2574 Reference
<XPropertySet
> const xShapeProps(xShape
, UNO_QUERY
);
2575 pFS
->startElementNS(mnXmlNamespace
, XML_cNvPr
,
2576 XML_id
, OString::number(GetNewShapeID(xShape
)),
2577 XML_name
, GetShapeName(xShape
));
2578 AddExtLst(pFS
, xShapeProps
);
2579 pFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
2581 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvGraphicFramePr
);
2583 if( GetDocumentType() == DOCUMENT_PPTX
)
2584 pFS
->singleElementNS(mnXmlNamespace
, XML_nvPr
);
2585 pFS
->endElementNS( mnXmlNamespace
, XML_nvGraphicFramePr
);
2587 WriteShapeTransformation( xShape
, mnXmlNamespace
);
2588 WriteTable( xShape
);
2590 pFS
->endElementNS( mnXmlNamespace
, XML_graphicFrame
);
2595 ShapeExport
& ShapeExport::WriteTextShape( const Reference
< XShape
>& xShape
)
2597 FSHelperPtr pFS
= GetFS();
2598 Reference
<XPropertySet
> xShapeProps(xShape
, UNO_QUERY
);
2600 pFS
->startElementNS(mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
? XML_sp
: XML_wsp
));
2602 // non visual shape properties
2603 if (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
)
2605 pFS
->startElementNS(mnXmlNamespace
, XML_nvSpPr
);
2606 pFS
->startElementNS(mnXmlNamespace
, XML_cNvPr
,
2607 XML_id
, OString::number(GetNewShapeID(xShape
)),
2608 XML_name
, GetShapeName(xShape
));
2610 if (GetProperty(xShapeProps
, u
"URL"_ustr
))
2613 if (!sURL
.isEmpty())
2615 OUString sRelId
= mpFB
->addRelation(mpFS
->getOutputStream(),
2616 oox::getRelationship(Relationship::HYPERLINK
),
2617 mpURLTransformer
->getTransformedString(sURL
),
2618 mpURLTransformer
->isExternalURL(sURL
));
2620 mpFS
->singleElementNS(XML_a
, XML_hlinkClick
, FSNS(XML_r
, XML_id
), sRelId
);
2622 AddExtLst(pFS
, xShapeProps
);
2623 pFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
2625 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
, XML_txBox
, "1");
2626 if (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
)
2628 WriteNonVisualProperties( xShape
);
2629 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
2632 // visual shape properties
2633 pFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
2634 WriteShapeTransformation( xShape
, XML_a
);
2635 WritePresetShape( "rect"_ostr
);
2636 uno::Reference
<beans::XPropertySet
> xPropertySet(xShape
, UNO_QUERY
);
2637 if (!IsFontworkShape(xShapeProps
)) // Fontwork needs fill and outline in run properties instead.
2639 WriteBlipOrNormalFill(xPropertySet
, u
"Graphic"_ustr
, xShape
->getSize());
2640 WriteOutline(xPropertySet
);
2641 WriteShapeEffects(xPropertySet
);
2643 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
2645 WriteTextBox( xShape
, mnXmlNamespace
);
2647 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
|| mbUserShapes
? XML_sp
: XML_wsp
) );
2652 void ShapeExport::WriteMathShape(Reference
<XShape
> const& xShape
)
2654 Reference
<XPropertySet
> const xPropSet(xShape
, UNO_QUERY
);
2655 assert(xPropSet
.is());
2656 Reference
<XModel
> xMathModel
;
2657 xPropSet
->getPropertyValue(u
"Model"_ustr
) >>= xMathModel
;
2658 assert(xMathModel
.is());
2659 assert(GetDocumentType() != DOCUMENT_DOCX
); // should be written in DocxAttributeOutput
2660 SAL_WARN_IF(GetDocumentType() == DOCUMENT_XLSX
, "oox.shape", "Math export to XLSX isn't tested, should it happen here?");
2661 const OString cNvPr_id
= OString::number(GetNewShapeID(xShape
));
2662 const OUString shapeName
= GetShapeName(xShape
);
2664 // ECMA standard does not actually allow oMath outside of
2665 // WordProcessingML so write a MCE like PPT 2010 does
2666 mpFS
->startElementNS(XML_mc
, XML_AlternateContent
);
2667 mpFS
->startElementNS(XML_mc
, XML_Choice
,
2668 FSNS(XML_xmlns
, XML_a14
), mpFB
->getNamespaceURL(OOX_NS(a14
)),
2669 XML_Requires
, "a14");
2670 mpFS
->startElementNS(mnXmlNamespace
, XML_sp
);
2671 mpFS
->startElementNS(mnXmlNamespace
, XML_nvSpPr
);
2672 mpFS
->startElementNS(mnXmlNamespace
, XML_cNvPr
, XML_id
, cNvPr_id
, XML_name
, shapeName
);
2673 AddExtLst(mpFS
, xPropSet
);
2674 mpFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
2675 mpFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
, XML_txBox
, "1");
2676 mpFS
->singleElementNS(mnXmlNamespace
, XML_nvPr
);
2677 mpFS
->endElementNS(mnXmlNamespace
, XML_nvSpPr
);
2678 mpFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
2679 WriteShapeTransformation(xShape
, XML_a
);
2680 WritePresetShape("rect"_ostr
);
2681 mpFS
->endElementNS(mnXmlNamespace
, XML_spPr
);
2682 mpFS
->startElementNS(mnXmlNamespace
, XML_txBody
);
2683 mpFS
->startElementNS(XML_a
, XML_bodyPr
);
2684 mpFS
->endElementNS(XML_a
, XML_bodyPr
);
2685 mpFS
->startElementNS(XML_a
, XML_p
);
2686 mpFS
->startElementNS(XML_a14
, XML_m
);
2688 oox::FormulaImExportBase
*const pMagic(
2689 dynamic_cast<oox::FormulaImExportBase
*>(xMathModel
.get()));
2691 pMagic
->writeFormulaOoxml(GetFS(), GetFB()->getVersion(), GetDocumentType(),
2692 FormulaImExportBase::eFormulaAlign::INLINE
);
2694 mpFS
->endElementNS(XML_a14
, XML_m
);
2695 mpFS
->endElementNS(XML_a
, XML_p
);
2696 mpFS
->endElementNS(mnXmlNamespace
, XML_txBody
);
2697 mpFS
->endElementNS(mnXmlNamespace
, XML_sp
);
2698 mpFS
->endElementNS(XML_mc
, XML_Choice
);
2699 mpFS
->startElementNS(XML_mc
, XML_Fallback
);
2701 svt::EmbeddedObjectRef
ref(
2702 xPropSet
->getPropertyValue(u
"EmbeddedObject"_ustr
).query
<css::embed::XEmbeddedObject
>(),
2703 embed::Aspects::MSOLE_CONTENT
);
2704 if (auto* graphic
= ref
.GetGraphic(); graphic
&& graphic
->GetType() != GraphicType::NONE
)
2706 if (OUString r_id
= writeGraphicToStorage(*graphic
); !r_id
.isEmpty())
2708 mpFS
->startElementNS(mnXmlNamespace
, XML_sp
);
2709 mpFS
->startElementNS(mnXmlNamespace
, XML_nvSpPr
);
2710 mpFS
->startElementNS(mnXmlNamespace
, XML_cNvPr
, XML_id
, cNvPr_id
, XML_name
, shapeName
);
2711 AddExtLst(mpFS
, xPropSet
);
2712 mpFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
2713 mpFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
, XML_txBox
, "1");
2714 mpFS
->singleElementNS(mnXmlNamespace
, XML_nvPr
);
2715 mpFS
->endElementNS(mnXmlNamespace
, XML_nvSpPr
);
2716 mpFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
2717 WriteShapeTransformation(xShape
, XML_a
);
2718 WritePresetShape("rect"_ostr
);
2719 mpFS
->startElementNS(XML_a
, XML_blipFill
);
2720 mpFS
->singleElementNS(XML_a
, XML_blip
, FSNS(XML_r
, XML_embed
), r_id
);
2721 mpFS
->startElementNS(XML_a
, XML_stretch
);
2722 mpFS
->singleElementNS(XML_a
, XML_fillRect
);
2723 mpFS
->endElementNS(XML_a
, XML_stretch
);
2724 mpFS
->endElementNS(XML_a
, XML_blipFill
);
2725 mpFS
->endElementNS(mnXmlNamespace
, XML_spPr
);
2726 mpFS
->endElementNS(mnXmlNamespace
, XML_sp
);
2730 mpFS
->endElementNS(XML_mc
, XML_Fallback
);
2731 mpFS
->endElementNS(XML_mc
, XML_AlternateContent
);
2734 ShapeExport
& ShapeExport::WriteOLE2Shape( const Reference
< XShape
>& xShape
)
2736 Reference
< XPropertySet
> xPropSet( xShape
, UNO_QUERY
);
2740 enum { CHART
, MATH
, OTHER
} eType(OTHER
);
2742 xPropSet
->getPropertyValue(u
"CLSID"_ustr
) >>= clsid
;
2743 if (!clsid
.isEmpty())
2745 SvGlobalName aClassID
;
2746 bool const isValid
= aClassID
.MakeId(clsid
);
2747 assert(isValid
); (void)isValid
;
2748 if (SotExchange::IsChart(aClassID
))
2750 else if (SotExchange::IsMath(aClassID
))
2756 Reference
< XChartDocument
> xChartDoc
;
2757 xPropSet
->getPropertyValue(u
"Model"_ustr
) >>= xChartDoc
;
2758 assert(xChartDoc
.is());
2760 #if !ENABLE_WASM_STRIP_CHART
2761 // WASM_CHART change
2762 // TODO: With Chart extracted this cannot really happen since
2763 // no Chart could've been added at all
2764 ChartExport
aChartExport( mnXmlNamespace
, GetFS(), xChartDoc
, GetFB(), GetDocumentType() );
2765 aChartExport
.WriteChartObj( xShape
, GetNewShapeID( xShape
), ++mnChartCount
);
2772 WriteMathShape(xShape
);
2776 uno::Reference
<embed::XEmbeddedObject
> const xObj(
2777 xPropSet
->getPropertyValue(u
"EmbeddedObject"_ustr
), uno::UNO_QUERY
);
2781 SAL_WARN("oox.shape", "ShapeExport::WriteOLE2Shape: no object");
2783 // tdf#152436 Export the preview graphic of the object if the object is missing.
2784 SdrObject
* pSdrOLE2(SdrObject::getSdrObjectFromXShape(xShape
));
2785 if (auto pOle2Obj
= dynamic_cast<SdrOle2Obj
*>(pSdrOLE2
))
2787 const Graphic
* pGraphic
= pOle2Obj
->GetGraphic();
2789 WriteGraphicObjectShapePart(xShape
, pGraphic
);
2795 uno::Sequence
<beans::PropertyValue
> grabBag
;
2799 uno::Reference
<beans::XPropertySet
> const xParent(
2800 uno::Reference
<container::XChild
>(xObj
, uno::UNO_QUERY_THROW
)->getParent(),
2801 uno::UNO_QUERY_THROW
);
2803 xParent
->getPropertyValue(u
"InteropGrabBag"_ustr
) >>= grabBag
;
2805 entryName
= uno::Reference
<embed::XEmbedPersist
>(xObj
, uno::UNO_QUERY_THROW
)->getEntryName();
2807 catch (uno::Exception
const&)
2809 TOOLS_WARN_EXCEPTION("oox.shape", "ShapeExport::WriteOLE2Shape");
2815 for (auto const& it
: grabBag
)
2817 if (it
.Name
== "EmbeddedObjects")
2819 uno::Sequence
<beans::PropertyValue
> objects
;
2820 it
.Value
>>= objects
;
2821 for (auto const& object
: objects
)
2823 if (object
.Name
== entryName
)
2825 uno::Sequence
<beans::PropertyValue
> props
;
2826 object
.Value
>>= props
;
2827 for (auto const& prop
: props
)
2829 if (prop
.Name
== "ProgID")
2831 prop
.Value
>>= progID
;
2842 OUString sMediaType
;
2843 OUString sRelationType
;
2845 const char * pProgID(nullptr);
2846 OString anotherProgID
;
2848 uno::Reference
<io::XInputStream
> const xInStream
=
2849 oox::GetOLEObjectStream(
2850 mpFB
->getComponentContext(), xObj
, progID
,
2851 sMediaType
, sRelationType
, sSuffix
, pProgID
);
2855 if (!xInStream
.is())
2857 xPropSet
->getPropertyValue(u
"LinkURL"_ustr
) >>= sURL
;
2861 sRelId
= mpFB
->addRelation(mpFS
->getOutputStream(),
2862 oox::getRelationship(Relationship::OLEOBJECT
), sURL
, true);
2866 if (!pProgID
&& !progID
.isEmpty())
2868 anotherProgID
= OUStringToOString(progID
, RTL_TEXTENCODING_UTF8
);
2869 pProgID
= anotherProgID
.getStr();
2872 assert(!sMediaType
.isEmpty());
2873 assert(!sRelationType
.isEmpty());
2874 assert(!sSuffix
.isEmpty());
2876 OUString sNumber
= OUString::number(++m_nEmbeddedObjects
);
2877 OUString sFileName
= u
"embeddings/oleObject"_ustr
+ sNumber
+ u
"."_ustr
+ sSuffix
;
2878 OUString sFilePath
= GetComponentDir() + u
"/"_ustr
+ sFileName
;
2879 uno::Reference
<io::XOutputStream
> const xOutStream(mpFB
->openFragmentStream(sFilePath
, sMediaType
));
2880 assert(xOutStream
.is()); // no reason why that could fail
2884 ::comphelper::OStorageHelper::CopyInputToOutput(xInStream
, xOutStream
);
2886 catch (uno::Exception
const&)
2888 TOOLS_WARN_EXCEPTION("oox.shape", "ShapeExport::WriteOLEObject");
2891 sRelId
= mpFB
->addRelation(
2892 mpFS
->getOutputStream(), sRelationType
,
2893 Concat2View(GetRelationCompPrefix() + sFileName
));
2897 bool bShowAsIcon
= (xPropSet
->getPropertyValue(u
"Aspect"_ustr
) >>= nAspect
)
2898 && nAspect
== embed::Aspects::MSOLE_ICON
;
2900 mpFS
->startElementNS(mnXmlNamespace
, XML_graphicFrame
);
2902 mpFS
->startElementNS(mnXmlNamespace
, XML_nvGraphicFramePr
);
2904 mpFS
->startElementNS(mnXmlNamespace
, XML_cNvPr
,
2905 XML_id
, OString::number(GetNewShapeID(xShape
)),
2906 XML_name
, GetShapeName(xShape
));
2907 AddExtLst(mpFS
, xPropSet
);
2908 mpFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
2910 mpFS
->singleElementNS(mnXmlNamespace
, XML_cNvGraphicFramePr
);
2912 if (GetDocumentType() == DOCUMENT_PPTX
)
2913 mpFS
->singleElementNS(mnXmlNamespace
, XML_nvPr
);
2914 mpFS
->endElementNS( mnXmlNamespace
, XML_nvGraphicFramePr
);
2916 WriteShapeTransformation( xShape
, mnXmlNamespace
);
2918 mpFS
->startElementNS(XML_a
, XML_graphic
);
2919 mpFS
->startElementNS(XML_a
, XML_graphicData
,
2920 XML_uri
, "http://schemas.openxmlformats.org/presentationml/2006/ole");
2923 mpFS
->startElementNS( mnXmlNamespace
, XML_oleObj
,
2924 XML_showAsIcon
, sax_fastparser::UseIf("1", bShowAsIcon
),
2925 XML_progId
, pProgID
,
2926 FSNS(XML_r
, XML_id
), sRelId
,
2931 mpFS
->startElementNS( mnXmlNamespace
, XML_oleObj
,
2932 //? XML_name, "Document",
2933 XML_showAsIcon
, sax_fastparser::UseIf("1", bShowAsIcon
),
2934 FSNS(XML_r
, XML_id
), sRelId
,
2935 // The spec says that this is a required attribute, but PowerPoint can only handle an empty value.
2940 mpFS
->singleElementNS(mnXmlNamespace
, XML_embed
);
2942 mpFS
->singleElementNS(mnXmlNamespace
, XML_link
, XML_updateAutomatic
, "1");
2945 SdrObject
* pSdrOLE2(SdrObject::getSdrObjectFromXShape(xShape
));
2946 if (auto pOle2Obj
= dynamic_cast<SdrOle2Obj
*>(pSdrOLE2
))
2948 const Graphic
* pGraphic
= pOle2Obj
->GetGraphic();
2950 WriteGraphicObjectShapePart(xShape
, pGraphic
);
2953 mpFS
->endElementNS( mnXmlNamespace
, XML_oleObj
);
2955 mpFS
->endElementNS( XML_a
, XML_graphicData
);
2956 mpFS
->endElementNS( XML_a
, XML_graphic
);
2958 mpFS
->endElementNS( mnXmlNamespace
, XML_graphicFrame
);
2963 ShapeExport
& ShapeExport::WriteUnknownShape( const Reference
< XShape
>& )
2965 // Override this method to do something useful.
2969 sal_Int32
ShapeExport::GetNewShapeID( const Reference
< XShape
>& rXShape
)
2971 return GetNewShapeID( rXShape
, GetFB() );
2974 sal_Int32
ShapeExport::GetNewShapeID( const Reference
< XShape
>& rXShape
, XmlFilterBase
* pFB
)
2979 sal_Int32 nID
= pFB
->GetUniqueId();
2981 (*mpShapeMap
)[ rXShape
] = nID
;
2986 sal_Int32
ShapeExport::GetShapeID( const Reference
< XShape
>& rXShape
)
2988 return GetShapeID( rXShape
, mpShapeMap
);
2991 sal_Int32
ShapeExport::GetShapeID( const Reference
< XShape
>& rXShape
, ShapeHashMap
* pShapeMap
)
2996 ShapeHashMap::const_iterator aIter
= pShapeMap
->find( rXShape
);
2998 if( aIter
== pShapeMap
->end() )
3001 return aIter
->second
;
3004 OUString
ShapeExport::GetShapeName(const Reference
<XShape
>& xShape
)
3006 Reference
<XPropertySet
> rXPropSet(xShape
, UNO_QUERY
);
3008 // Empty name keeps the object unnamed.
3011 if (GetProperty(rXPropSet
, u
"Name"_ustr
))
3018 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */