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 <sal/config.h>
22 #include <config_global.h>
23 #include <unotools/mediadescriptor.hxx>
24 #include <filter/msfilter/util.hxx>
25 #include "oox/core/xmlfilterbase.hxx"
26 #include "oox/export/shapes.hxx"
27 #include "oox/export/utils.hxx"
28 #include <oox/token/namespaces.hxx>
29 #include <oox/token/relationship.hxx>
30 #include <oox/token/tokens.hxx>
33 #include <initializer_list>
35 #include <com/sun/star/awt/CharSet.hpp>
36 #include <com/sun/star/awt/FontDescriptor.hpp>
37 #include <com/sun/star/awt/FontSlant.hpp>
38 #include <com/sun/star/awt/FontWeight.hpp>
39 #include <com/sun/star/awt/FontUnderline.hpp>
40 #include <com/sun/star/awt/Gradient.hpp>
41 #include <com/sun/star/beans/PropertyValues.hpp>
42 #include <com/sun/star/beans/XPropertySet.hpp>
43 #include <com/sun/star/beans/XPropertySetInfo.hpp>
44 #include <com/sun/star/beans/XPropertyState.hpp>
45 #include <com/sun/star/container/XChild.hpp>
46 #include <com/sun/star/container/XEnumerationAccess.hpp>
47 #include <com/sun/star/document/XExporter.hpp>
48 #include <com/sun/star/document/XStorageBasedDocument.hpp>
49 #include <com/sun/star/drawing/FillStyle.hpp>
50 #include <com/sun/star/drawing/BitmapMode.hpp>
51 #include <com/sun/star/drawing/ConnectorType.hpp>
52 #include <com/sun/star/drawing/LineDash.hpp>
53 #include <com/sun/star/drawing/LineJoint.hpp>
54 #include <com/sun/star/drawing/LineStyle.hpp>
55 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
56 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
57 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
58 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
59 #include <com/sun/star/embed/EmbedStates.hpp>
60 #include <com/sun/star/embed/XEmbeddedObject.hpp>
61 #include <com/sun/star/embed/XEmbedPersist.hpp>
62 #include <com/sun/star/frame/XStorable.hpp>
63 #include <com/sun/star/i18n/ScriptType.hpp>
64 #include <com/sun/star/io/XOutputStream.hpp>
65 #include <com/sun/star/style/ParagraphAdjust.hpp>
66 #include <com/sun/star/text/XSimpleText.hpp>
67 #include <com/sun/star/text/XText.hpp>
68 #include <com/sun/star/text/XTextContent.hpp>
69 #include <com/sun/star/text/XTextDocument.hpp>
70 #include <com/sun/star/text/XTextField.hpp>
71 #include <com/sun/star/text/XTextRange.hpp>
72 #include <com/sun/star/table/XTable.hpp>
73 #include <com/sun/star/table/XColumnRowRange.hpp>
74 #include <com/sun/star/table/XCellRange.hpp>
75 #include <com/sun/star/table/XMergeableCell.hpp>
76 #include <com/sun/star/chart2/XChartDocument.hpp>
77 #include <com/sun/star/frame/XModel.hpp>
78 #include <com/sun/star/table/BorderLine2.hpp>
79 #include <tools/stream.hxx>
80 #include <tools/globname.hxx>
81 #include <comphelper/classids.hxx>
82 #include <comphelper/storagehelper.hxx>
83 #include <sot/exchange.hxx>
84 #include <vcl/cvtgrf.hxx>
85 #include <unotools/fontcvt.hxx>
86 #include <vcl/graph.hxx>
87 #include <vcl/outdev.hxx>
88 #include <svtools/grfmgr.hxx>
89 #include <rtl/strbuf.hxx>
90 #include <sfx2/app.hxx>
91 #include <svl/languageoptions.hxx>
92 #include <filter/msfilter/escherex.hxx>
93 #include <svx/svdoashp.hxx>
94 #include <svx/svdoole2.hxx>
95 #include <editeng/svxenum.hxx>
96 #include <svx/unoapi.hxx>
97 #include <oox/export/chartexport.hxx>
98 #include <oox/mathml/export.hxx>
100 using namespace ::css
;
101 using namespace ::css::beans
;
102 using namespace ::css::uno
;
103 using namespace ::css::drawing
;
104 using namespace ::css::i18n
;
105 using namespace ::css::table
;
106 using namespace ::css::container
;
107 using namespace ::css::document
;
108 using namespace ::css::text
;
110 using ::css::io::XOutputStream
;
111 using ::css::chart2::XChartDocument
;
112 using ::css::frame::XModel
;
114 using ::oox::core::XmlFilterBase
;
115 using ::sax_fastparser::FSHelperPtr
;
117 #define IDS(x) OString(OStringLiteral(#x " ") + OString::number( mnShapeIdMax++ )).getStr()
121 static void lcl_ConvertProgID(OUString
const& rProgID
,
122 OUString
& o_rMediaType
, OUString
& o_rRelationType
, OUString
& o_rFileExtension
)
124 if (rProgID
== "Excel.Sheet.12")
126 o_rMediaType
= "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
127 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
128 o_rFileExtension
= "xlsx";
130 else if (rProgID
.startsWith("Excel.SheetBinaryMacroEnabled.12") )
132 o_rMediaType
= "application/vnd.ms-excel.sheet.binary.macroEnabled.12";
133 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
134 o_rFileExtension
= "xlsb";
136 else if (rProgID
.startsWith("Excel.SheetMacroEnabled.12"))
138 o_rMediaType
= "application/vnd.ms-excel.sheet.macroEnabled.12";
139 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
140 o_rFileExtension
= "xlsm";
142 else if (rProgID
.startsWith("Excel.Sheet"))
144 o_rMediaType
= "application/vnd.ms-excel";
145 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
146 o_rFileExtension
= "xls";
148 else if (rProgID
== "PowerPoint.Show.12")
150 o_rMediaType
= "application/vnd.openxmlformats-officedocument.presentationml.presentation";
151 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
152 o_rFileExtension
= "pptx";
154 else if (rProgID
== "PowerPoint.ShowMacroEnabled.12")
156 o_rMediaType
= "application/vnd.ms-powerpoint.presentation.macroEnabled.12";
157 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
158 o_rFileExtension
= "pptm";
160 else if (rProgID
.startsWith("PowerPoint.Show"))
162 o_rMediaType
= "application/vnd.ms-powerpoint";
163 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
164 o_rFileExtension
= "ppt";
166 else if (rProgID
.startsWith("PowerPoint.Slide.12"))
168 o_rMediaType
= "application/vnd.openxmlformats-officedocument.presentationml.slide";
169 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
170 o_rFileExtension
= "sldx";
172 else if (rProgID
== "PowerPoint.SlideMacroEnabled.12")
174 o_rMediaType
= "application/vnd.ms-powerpoint.slide.macroEnabled.12";
175 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
176 o_rFileExtension
= "sldm";
178 else if (rProgID
== "Word.DocumentMacroEnabled.12")
180 o_rMediaType
= "application/vnd.ms-word.document.macroEnabled.12";
181 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
182 o_rFileExtension
= "docm";
184 else if (rProgID
== "Word.Document.12")
186 o_rMediaType
= "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
187 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
188 o_rFileExtension
= "docx";
190 else if (rProgID
== "Word.Document.8")
192 o_rMediaType
= "application/msword";
193 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
194 o_rFileExtension
= "doc";
196 else if (rProgID
== "Excel.Chart.8")
198 o_rMediaType
= "application/vnd.ms-excel";
199 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
200 o_rFileExtension
= "xls";
202 else if (rProgID
== "AcroExch.Document.11")
204 o_rMediaType
= "application/pdf";
205 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
206 o_rFileExtension
= "pdf";
210 o_rMediaType
= "application/vnd.openxmlformats-officedocument.oleObject";
211 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
212 o_rFileExtension
= "bin";
216 static uno::Reference
<io::XInputStream
> lcl_StoreOwnAsOOXML(
217 uno::Reference
<uno::XComponentContext
> const& xContext
,
218 uno::Reference
<embed::XEmbeddedObject
> const& xObj
,
219 char const*& o_rpProgID
,
220 OUString
& o_rMediaType
, OUString
& o_rRelationType
, OUString
& o_rSuffix
)
226 sal_uInt8 b8
, b9
, b10
, b11
, b12
, b13
, b14
, b15
;
228 char const* pFilterName
;
229 char const* pMediaType
;
233 { {SO3_SW_CLASSID_60
}, "MS Word 2007 XML", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "Word.Document.12", "docx" },
234 { {SO3_SC_CLASSID_60
}, "Calc MS Excel 2007 XML", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Excel.Sheet.12", "xlsx" },
235 { {SO3_SIMPRESS_CLASSID_60
}, "Impress MS PowerPoint 2007 XML", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "PowerPoint.Show.12", "pptx" },
236 // FIXME: Draw does not appear to have a MSO format export filter?
237 // { {SO3_SDRAW_CLASSID}, "", "", "", "" },
238 { {SO3_SCH_CLASSID_60
}, "unused", "", "", "" },
239 { {SO3_SM_CLASSID_60
}, "unused", "", "", "" },
242 const char * pFilterName(nullptr);
243 SvGlobalName
const classId(xObj
->getClassID());
244 for (auto & i
: s_Mapping
)
246 auto const& rId(i
.ClassId
);
247 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
);
250 assert(SvGlobalName(SO3_SCH_CLASSID_60
) != classId
); // chart should be written elsewhere!
251 assert(SvGlobalName(SO3_SM_CLASSID_60
) != classId
); // formula should be written elsewhere!
252 pFilterName
= i
.pFilterName
;
253 o_rMediaType
= OUString::createFromAscii(i
.pMediaType
);
254 o_rpProgID
= i
.pProgID
;
255 o_rSuffix
= OUString::createFromAscii(i
.pSuffix
);
256 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
263 SAL_WARN("oox.shape", "oox::GetOLEObjectStream: unknown ClassId " << classId
.GetHexName());
267 if (embed::EmbedStates::LOADED
== xObj
->getCurrentState())
269 xObj
->changeState(embed::EmbedStates::RUNNING
);
271 // use a temp stream - while it would work to store directly to a
272 // fragment stream, an error during export means we'd have to delete it
273 uno::Reference
<io::XStream
> const xTempStream(
274 xContext
->getServiceManager()->createInstanceWithContext(
275 "com.sun.star.comp.MemoryStream", xContext
),
276 uno::UNO_QUERY_THROW
);
277 uno::Sequence
<beans::PropertyValue
> args(2);
278 args
[0].Name
= "OutputStream";
279 args
[0].Value
<<= xTempStream
->getOutputStream();
280 args
[1].Name
= "FilterName";
281 args
[1].Value
<<= OUString::createFromAscii(pFilterName
);
282 uno::Reference
<frame::XStorable
> xStorable(xObj
->getComponent(), uno::UNO_QUERY
);
285 xStorable
->storeToURL("private:stream", args
);
287 catch (uno::Exception
const& e
)
289 SAL_WARN("oox.shape", "oox::GetOLEObjectStream: exception: \"" << e
.Message
<< "\"");
292 xTempStream
->getOutputStream()->closeOutput();
293 return xTempStream
->getInputStream();
296 uno::Reference
<io::XInputStream
> GetOLEObjectStream(
297 uno::Reference
<uno::XComponentContext
> const& xContext
,
298 uno::Reference
<embed::XEmbeddedObject
> const& xObj
,
299 OUString
const& i_rProgID
,
300 OUString
& o_rMediaType
,
301 OUString
& o_rRelationType
,
302 OUString
& o_rSuffix
,
303 const char *& o_rpProgID
)
305 uno::Reference
<io::XInputStream
> xInStream
;
308 uno::Reference
<document::XStorageBasedDocument
> const xParent(
309 uno::Reference
<container::XChild
>(xObj
, uno::UNO_QUERY_THROW
)->getParent(),
310 uno::UNO_QUERY_THROW
);
311 uno::Reference
<embed::XStorage
> const xParentStorage(xParent
->getDocumentStorage());
312 OUString
const entryName(
313 uno::Reference
<embed::XEmbedPersist
>(xObj
, uno::UNO_QUERY_THROW
)->getEntryName());
315 if (xParentStorage
->isStreamElement(entryName
))
317 lcl_ConvertProgID(i_rProgID
, o_rMediaType
, o_rRelationType
, o_rSuffix
);
318 xInStream
= xParentStorage
->cloneStreamElement(entryName
)->getInputStream();
319 // TODO: make it possible to take the sMediaType from the stream
321 else // the object is ODF - either the whole document is
322 { // ODF, or the OLE was edited so it was converted to ODF
323 xInStream
= lcl_StoreOwnAsOOXML(xContext
, xObj
,
324 o_rpProgID
, o_rMediaType
, o_rRelationType
, o_rSuffix
);
327 catch (uno::Exception
const& e
)
329 SAL_WARN("oox.shape", "oox::GetOLEObjectStream: exception: " << e
.Message
);
336 namespace oox
{ namespace drawingml
{
338 URLTransformer::~URLTransformer()
342 OUString
URLTransformer::getTransformedString(const OUString
& rString
) const
347 bool URLTransformer::isExternalURL(const OUString
& /*rURL*/) const
352 #define GETA(propName) \
353 GetProperty( rXPropSet, #propName)
355 #define GETAD(propName) \
356 ( GetPropertyAndState( rXPropSet, rXPropState, #propName, eState ) && eState == beans::PropertyState_DIRECT_VALUE )
358 #define GET(variable, propName) \
359 if ( GETA(propName) ) \
362 ShapeExport::ShapeExport( sal_Int32 nXmlNamespace
, FSHelperPtr pFS
, ShapeHashMap
* pShapeMap
, XmlFilterBase
* pFB
, DocumentType eDocumentType
, DMLTextExport
* pTextExport
)
363 : DrawingML( pFS
, pFB
, eDocumentType
, pTextExport
)
364 , m_nEmbeddedObjects(0)
366 , mnPictureIdMax( 1 )
367 , mnXmlNamespace( nXmlNamespace
)
368 , maFraction( 1, 576 )
369 , maMapModeSrc( MapUnit::Map100thMM
)
370 , maMapModeDest( MapUnit::MapInch
, Point(), maFraction
, maFraction
)
371 , mpShapeMap( pShapeMap
? pShapeMap
: &maShapeMap
)
373 mpURLTransformer
.reset(new URLTransformer
);
376 void ShapeExport::SetURLTranslator(const std::shared_ptr
<URLTransformer
>& pTransformer
)
378 mpURLTransformer
= pTransformer
;
381 awt::Size
ShapeExport::MapSize( const awt::Size
& rSize
) const
383 Size
aRetSize( OutputDevice::LogicToLogic( Size( rSize
.Width
, rSize
.Height
), maMapModeSrc
, maMapModeDest
) );
385 if ( !aRetSize
.Width() )
387 if ( !aRetSize
.Height() )
389 return awt::Size( aRetSize
.Width(), aRetSize
.Height() );
392 bool ShapeExport::NonEmptyText( const Reference
< XInterface
>& xIface
)
394 Reference
< XPropertySet
> xPropSet( xIface
, UNO_QUERY
);
398 Reference
< XPropertySetInfo
> xPropSetInfo
= xPropSet
->getPropertySetInfo();
399 if ( xPropSetInfo
.is() )
401 if ( xPropSetInfo
->hasPropertyByName( "IsEmptyPresentationObject" ) )
403 bool bIsEmptyPresObj
= false;
404 if ( xPropSet
->getPropertyValue( "IsEmptyPresentationObject" ) >>= bIsEmptyPresObj
)
406 SAL_INFO("oox.shape", "empty presentation object " << bIsEmptyPresObj
<< " , props:");
407 if( bIsEmptyPresObj
)
412 if ( xPropSetInfo
->hasPropertyByName( "IsPresentationObject" ) )
414 bool bIsPresObj
= false;
415 if ( xPropSet
->getPropertyValue( "IsPresentationObject" ) >>= bIsPresObj
)
417 SAL_INFO("oox.shape", "presentation object " << bIsPresObj
<< ", props:");
425 Reference
< XSimpleText
> xText( xIface
, UNO_QUERY
);
428 return xText
->getString().getLength();
433 ShapeExport
& ShapeExport::WritePolyPolygonShape( const Reference
< XShape
>& xShape
, bool bClosed
)
435 SAL_INFO("oox.shape", "write polypolygon shape");
437 FSHelperPtr pFS
= GetFS();
438 pFS
->startElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
), FSEND
);
440 tools::PolyPolygon aPolyPolygon
= EscherPropertyContainer::GetPolyPolygon( xShape
);
441 tools::Rectangle
aRect( aPolyPolygon
.GetBoundRect() );
443 #if OSL_DEBUG_LEVEL > 0
444 awt::Size size
= MapSize( awt::Size( aRect
.GetWidth(), aRect
.GetHeight() ) );
445 SAL_INFO("oox.shape", "poly count " << aPolyPolygon
.Count());
446 SAL_INFO("oox.shape", "size: " << size
.Width
<< " x " << size
.Height
);
449 // non visual shape properties
450 if (GetDocumentType() != DOCUMENT_DOCX
)
452 pFS
->startElementNS( mnXmlNamespace
, XML_nvSpPr
, FSEND
);
453 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
454 XML_id
, I32S( GetNewShapeID( xShape
) ),
455 XML_name
, IDS( Freeform
),
458 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvSpPr
, FSEND
);
459 if (GetDocumentType() != DOCUMENT_DOCX
)
461 WriteNonVisualProperties( xShape
);
462 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
465 // visual shape properties
466 pFS
->startElementNS( mnXmlNamespace
, XML_spPr
, FSEND
);
467 WriteTransformation( aRect
, XML_a
);
468 WritePolyPolygon( aPolyPolygon
);
469 Reference
< XPropertySet
> xProps( xShape
, UNO_QUERY
);
473 WriteOutline( xProps
);
476 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
479 WriteTextBox( xShape
, mnXmlNamespace
);
481 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
) );
486 ShapeExport
& ShapeExport::WriteClosedPolyPolygonShape( const Reference
< XShape
>& xShape
)
488 return WritePolyPolygonShape( xShape
, true );
491 ShapeExport
& ShapeExport::WriteOpenPolyPolygonShape( const Reference
< XShape
>& xShape
)
493 return WritePolyPolygonShape( xShape
, false );
496 ShapeExport
& ShapeExport::WriteGroupShape(const uno::Reference
<drawing::XShape
>& xShape
)
498 FSHelperPtr pFS
= GetFS();
499 bool bToplevel
= !m_xParent
.is();
501 mnXmlNamespace
= XML_wpg
;
502 pFS
->startElementNS(mnXmlNamespace
, (bToplevel
? XML_wgp
: XML_grpSp
), FSEND
);
504 // non visual properties
505 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvGrpSpPr
, FSEND
);
508 pFS
->startElementNS(mnXmlNamespace
, XML_grpSpPr
, FSEND
);
509 WriteShapeTransformation(xShape
, XML_a
);
510 pFS
->endElementNS(mnXmlNamespace
, XML_grpSpPr
);
512 uno::Reference
<drawing::XShapes
> xGroupShape(xShape
, uno::UNO_QUERY_THROW
);
513 uno::Reference
<drawing::XShape
> xParent
= m_xParent
;
515 for (sal_Int32 i
= 0; i
< xGroupShape
->getCount(); ++i
)
517 uno::Reference
<drawing::XShape
> xChild(xGroupShape
->getByIndex(i
), uno::UNO_QUERY_THROW
);
518 sal_Int32 nSavedNamespace
= mnXmlNamespace
;
520 uno::Reference
<lang::XServiceInfo
> xServiceInfo(xChild
, uno::UNO_QUERY_THROW
);
521 if (xServiceInfo
->supportsService("com.sun.star.drawing.GraphicObjectShape"))
522 mnXmlNamespace
= XML_pic
;
524 mnXmlNamespace
= XML_wps
;
527 mnXmlNamespace
= nSavedNamespace
;
531 pFS
->endElementNS(mnXmlNamespace
, (bToplevel
? XML_wgp
: XML_grpSp
));
535 static bool lcl_IsOnBlacklist(OUString
& rShapeType
)
537 static const std::initializer_list
<OUStringLiteral
> vBlacklist
= {
554 "round-rectangular-callout",
555 "rectangular-callout",
569 "flowchart-alternate-process",
570 "flowchart-decision",
572 "flowchart-predefined-process",
573 "flowchart-internal-storage",
574 "flowchart-document",
575 "flowchart-multidocument",
576 "flowchart-terminator",
577 "flowchart-preparation",
578 "flowchart-manual-input",
579 "flowchart-manual-operation",
580 "flowchart-connector",
581 "flowchart-off-page-connector",
583 "flowchart-punched-tape",
584 "flowchart-summing-junction",
590 "flowchart-stored-data",
592 "flowchart-sequential-access",
593 "flowchart-magnetic-disk",
594 "flowchart-direct-access-storage",
598 return std::find(vBlacklist
.begin(), vBlacklist
.end(), rShapeType
) != vBlacklist
.end();
601 static bool lcl_IsOnWhitelist(OUString
& rShapeType
)
603 static const std::initializer_list
<OUStringLiteral
> vWhitelist
= {
609 return std::find(vWhitelist
.begin(), vWhitelist
.end(), rShapeType
) != vWhitelist
.end();
612 bool lcl_GetHandlePosition( sal_Int32
&nValue
, const EnhancedCustomShapeParameter
&rParam
, Sequence
< EnhancedCustomShapeAdjustmentValue
> &rSeq
)
615 if ( rParam
.Value
.getValueTypeClass() == TypeClass_DOUBLE
)
618 if ( rParam
.Value
>>= fValue
)
619 nValue
= (sal_Int32
)fValue
;
622 rParam
.Value
>>= nValue
;
624 if ( rParam
.Type
== EnhancedCustomShapeParameterType::ADJUSTMENT
)
627 sal_Int32 nIdx
= nValue
;
628 if ( nIdx
< rSeq
.getLength() )
630 if ( rSeq
[ nIdx
] .Value
.getValueTypeClass() == TypeClass_DOUBLE
)
633 rSeq
[ nIdx
].Value
>>= fValue
;
639 rSeq
[ nIdx
].Value
>>= nValue
;
646 void lcl_AnalyzeHandles( const uno::Sequence
<beans::PropertyValues
> & rHandles
,
647 std::vector
< std::pair
< sal_Int32
, sal_Int32
> > &rHandlePositionList
,
648 Sequence
< EnhancedCustomShapeAdjustmentValue
> &rSeq
)
651 sal_uInt16 nHandles
= rHandles
.getLength();
652 for ( k
= 0; k
< nHandles
; k
++ )
654 const OUString
sSwitched( "Switched" );
655 const OUString
sPosition( "Position" );
656 bool bSwitched
= false;
657 bool bPosition
= false;
658 EnhancedCustomShapeParameterPair aPosition
;
659 EnhancedCustomShapeParameterPair aPolar
;
660 const Sequence
< PropertyValue
>& rPropSeq
= rHandles
[ k
];
661 for ( const PropertyValue
& rPropVal
: rPropSeq
)
663 if ( rPropVal
.Name
.equals( sPosition
) )
665 if ( rPropVal
.Value
>>= aPosition
)
668 else if ( rPropVal
.Name
.equals( sSwitched
) )
670 rPropVal
.Value
>>= bSwitched
;
675 sal_Int32 nXPosition
= 0;
676 sal_Int32 nYPosition
= 0;
677 // For polar handles, nXPosition is radius and nYPosition is angle
678 lcl_GetHandlePosition( nXPosition
, aPosition
.First
, rSeq
);
679 lcl_GetHandlePosition( nYPosition
, aPosition
.Second
, rSeq
);
680 rHandlePositionList
.push_back( std::pair
<sal_Int32
, sal_Int32
> ( nXPosition
, nYPosition
) );
685 void lcl_AppendAdjustmentValue( std::vector
< std::pair
< sal_Int32
, sal_Int32
> > &rAvList
, sal_Int32 nAdjIdx
, sal_Int32 nValue
)
687 rAvList
.push_back( std::pair
<sal_Int32
, sal_Int32
> ( nAdjIdx
, nValue
) );
690 sal_Int32
lcl_NormalizeAngle( sal_Int32 nAngle
)
692 nAngle
= nAngle
% 360;
693 return nAngle
< 0 ? ( nAngle
+ 360 ) : nAngle
;
696 ShapeExport
& ShapeExport::WriteCustomShape( const Reference
< XShape
>& xShape
)
698 SAL_INFO("oox.shape", "write custom shape");
700 Reference
< XPropertySet
> rXPropSet( xShape
, UNO_QUERY
);
701 bool bPredefinedHandlesUsed
= true;
702 bool bHasHandles
= false;
705 sal_uInt32 nMirrorFlags
= 0;
706 MSO_SPT eShapeType
= EscherPropertyContainer::GetCustomShapeType( xShape
, nMirrorFlags
, sShapeType
);
707 SdrObjCustomShape
* pShape
= static_cast<SdrObjCustomShape
*>( GetSdrObjectFromXShape( xShape
) );
708 bool bIsDefaultObject
= EscherPropertyContainer::IsDefaultObject( pShape
, eShapeType
);
709 const char* sPresetShape
= msfilter::util::GetOOXMLPresetGeometry( USS( sShapeType
) );
710 SAL_INFO("oox.shape", "custom shape type: " << sShapeType
<< " ==> " << sPresetShape
);
711 Sequence
< PropertyValue
> aGeometrySeq
;
712 sal_Int32 nAdjustmentValuesIndex
= -1;
713 awt::Rectangle aViewBox
;
714 uno::Sequence
<beans::PropertyValues
> aHandles
;
719 if( GETA( CustomShapeGeometry
) ) {
720 SAL_INFO("oox.shape", "got custom shape geometry");
721 if( mAny
>>= aGeometrySeq
) {
723 SAL_INFO("oox.shape", "got custom shape geometry sequence");
724 for( int i
= 0; i
< aGeometrySeq
.getLength(); i
++ ) {
725 const PropertyValue
& rProp
= aGeometrySeq
[ i
];
726 SAL_INFO("oox.shape", "geometry property: " << rProp
.Name
);
728 if ( rProp
.Name
== "MirroredX" )
729 rProp
.Value
>>= bFlipH
;
731 if ( rProp
.Name
== "MirroredY" )
732 rProp
.Value
>>= bFlipV
;
733 if ( rProp
.Name
== "AdjustmentValues" )
734 nAdjustmentValuesIndex
= i
;
735 else if ( rProp
.Name
== "Handles" )
737 rProp
.Value
>>= aHandles
;
738 if ( aHandles
.getLength() )
740 if( !bIsDefaultObject
)
741 bPredefinedHandlesUsed
= false;
742 // TODO: update nAdjustmentsWhichNeedsToBeConverted here
744 else if ( rProp
.Name
== "PresetTextWarp" )
746 rProp
.Value
>>= m_presetWarp
;
748 else if ( rProp
.Name
== "ViewBox" )
749 rProp
.Value
>>= aViewBox
;
754 FSHelperPtr pFS
= GetFS();
755 pFS
->startElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
), FSEND
);
757 // non visual shape properties
758 if (GetDocumentType() != DOCUMENT_DOCX
)
760 bool isVisible
= true ;
765 pFS
->startElementNS( mnXmlNamespace
, XML_nvSpPr
, FSEND
);
766 pFS
->startElementNS( mnXmlNamespace
, XML_cNvPr
,
767 XML_id
, I32S( GetNewShapeID( xShape
) ),
768 XML_name
, IDS( CustomShape
),
769 XML_hidden
, isVisible
? nullptr : "1",
776 if( !sURL
.isEmpty() )
778 OUString sRelId
= mpFB
->addRelation( mpFS
->getOutputStream(),
779 oox::getRelationship(Relationship::HYPERLINK
),
780 mpURLTransformer
->getTransformedString(sURL
),
781 mpURLTransformer
->isExternalURL(sURL
));
783 mpFS
->singleElementNS( XML_a
, XML_hlinkClick
,
784 FSNS( XML_r
,XML_id
), USS( sRelId
),
788 pFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
789 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvSpPr
, FSEND
);
790 WriteNonVisualProperties( xShape
);
791 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
794 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
, FSEND
);
796 // visual shape properties
797 pFS
->startElementNS( mnXmlNamespace
, XML_spPr
, FSEND
);
798 // moon is flipped in MSO, and mso-spt89 (right up arrow) is mapped to leftUpArrow
799 if ( sShapeType
== "moon" || sShapeType
== "mso-spt89" )
802 // we export non-primitive shapes to custom geometry
803 // we also export non-ooxml shapes which have handles/equations to custom geometry, because
804 // we cannot convert ODF equations to DrawingML equations. TODO: see what binary DOC export filter does.
805 // but our WritePolyPolygon()/WriteCustomGeometry() functions are incomplete, therefore we use a blacklist
806 // we use a whitelist for shapes where mapping to MSO preset shape is not optimal
807 bool bCustGeom
= true;
808 bool bOnBlacklist
= false;
809 if( sShapeType
== "ooxml-non-primitive" )
811 else if( sShapeType
.startsWith("ooxml") )
813 else if( lcl_IsOnWhitelist(sShapeType
) )
815 else if( lcl_IsOnBlacklist(sShapeType
) )
820 else if( bHasHandles
)
823 if (bHasHandles
&& bCustGeom
&& pShape
)
825 WriteShapeTransformation( xShape
, XML_a
); // do not flip, polypolygon coordinates are flipped already
826 tools::PolyPolygon
aPolyPolygon( pShape
->GetLineGeometry(true) );
827 sal_Int32 nRotation
= 0;
828 // The RotateAngle property's value is independent from any flipping, and that's exactly what we need here.
829 uno::Reference
<beans::XPropertySet
> xPropertySet(xShape
, uno::UNO_QUERY
);
830 uno::Reference
<beans::XPropertySetInfo
> xPropertySetInfo
= xPropertySet
->getPropertySetInfo();
831 if (xPropertySetInfo
->hasPropertyByName("RotateAngle"))
832 xPropertySet
->getPropertyValue("RotateAngle") >>= nRotation
;
834 aPolyPolygon
.Rotate(Point(0,0), static_cast<sal_uInt16
>(3600-nRotation
/10));
835 WritePolyPolygon( aPolyPolygon
);
839 WriteShapeTransformation( xShape
, XML_a
, bFlipH
, bFlipV
);
840 bool bSuccess
= WriteCustomGeometry( xShape
, pShape
);
842 WritePresetShape( sPresetShape
);
844 else if (bOnBlacklist
&& bHasHandles
&& nAdjustmentValuesIndex
!=-1 && !sShapeType
.startsWith("mso-spt"))
846 WriteShapeTransformation( xShape
, XML_a
, bFlipH
, bFlipV
);
847 Sequence
< EnhancedCustomShapeAdjustmentValue
> aAdjustmentSeq
;
848 std::vector
< std::pair
< sal_Int32
, sal_Int32
> > aHandlePositionList
;
849 std::vector
< std::pair
< sal_Int32
, sal_Int32
> > aAvList
;
850 aGeometrySeq
[ nAdjustmentValuesIndex
].Value
>>= aAdjustmentSeq
;
852 lcl_AnalyzeHandles( aHandles
, aHandlePositionList
, aAdjustmentSeq
);
854 sal_Int32 nXPosition
= 0;
855 sal_Int32 nYPosition
= 0;
856 if ( !aHandlePositionList
.empty() )
858 nXPosition
= aHandlePositionList
[0].first
;
859 nYPosition
= aHandlePositionList
[0].second
;
863 case mso_sptBorderCallout1
:
865 sal_Int32 adj3
= double(nYPosition
)/aViewBox
.Height
*100000;
866 sal_Int32 adj4
= double(nXPosition
)/aViewBox
.Width
*100000;
867 lcl_AppendAdjustmentValue( aAvList
, 1, 18750 );
868 lcl_AppendAdjustmentValue( aAvList
, 2, -8333 );
869 lcl_AppendAdjustmentValue( aAvList
, 3, adj3
);
870 lcl_AppendAdjustmentValue( aAvList
, 4, adj4
);
873 case mso_sptBorderCallout2
:
875 sal_Int32 adj5
= double(nYPosition
)/aViewBox
.Height
*100000;
876 sal_Int32 adj6
= double(nXPosition
)/aViewBox
.Width
*100000;
877 sal_Int32 adj3
= 18750;
878 sal_Int32 adj4
= -16667;
879 lcl_AppendAdjustmentValue( aAvList
, 1, 18750 );
880 lcl_AppendAdjustmentValue( aAvList
, 2, -8333 );
881 if ( aHandlePositionList
.size() > 1 )
883 nXPosition
= aHandlePositionList
[1].first
;
884 nYPosition
= aHandlePositionList
[1].second
;
885 adj3
= double(nYPosition
)/aViewBox
.Height
*100000;
886 adj4
= double(nXPosition
)/aViewBox
.Width
*100000;
888 lcl_AppendAdjustmentValue( aAvList
, 3, adj3
);
889 lcl_AppendAdjustmentValue( aAvList
, 4, adj4
);
890 lcl_AppendAdjustmentValue( aAvList
, 5, adj5
);
891 lcl_AppendAdjustmentValue( aAvList
, 6, adj6
);
894 case mso_sptWedgeRectCallout
:
895 case mso_sptWedgeRRectCallout
:
896 case mso_sptWedgeEllipseCallout
:
897 case mso_sptCloudCallout
:
899 sal_Int32 adj1
= (double(nXPosition
)/aViewBox
.Width
-0.5) *100000;
900 sal_Int32 adj2
= (double(nYPosition
)/aViewBox
.Height
-0.5) *100000;
901 lcl_AppendAdjustmentValue( aAvList
, 1, adj1
);
902 lcl_AppendAdjustmentValue( aAvList
, 2, adj2
);
903 if ( eShapeType
== mso_sptWedgeRRectCallout
)
905 lcl_AppendAdjustmentValue( aAvList
, 3, 16667);
910 case mso_sptFoldedCorner
:
912 sal_Int32 adj
= double( aViewBox
.Width
- nXPosition
) / std::min( aViewBox
.Width
,aViewBox
.Height
) * 100000;
913 lcl_AppendAdjustmentValue( aAvList
, 0, adj
);
919 case mso_sptHorizontalScroll
:
921 case mso_sptBracketPair
:
923 sal_Int32 adj
= double( nXPosition
)/aViewBox
.Width
*100000 ;
924 lcl_AppendAdjustmentValue( aAvList
, 0, adj
);
929 case mso_sptBracePair
:
930 case mso_sptVerticalScroll
:
932 sal_Int32 adj
= double( nYPosition
)/aViewBox
.Height
*100000 ;
933 lcl_AppendAdjustmentValue( aAvList
, 0, adj
);
936 case mso_sptSmileyFace
:
938 sal_Int32 adj
= double( nYPosition
)/aViewBox
.Height
*100000 - 76458.0;
939 lcl_AppendAdjustmentValue( aAvList
, 0, adj
);
942 case mso_sptBlockArc
:
944 sal_Int32 nRadius
= 50000 * ( 1 - double(nXPosition
) / 10800);
945 sal_Int32 nAngleStart
= lcl_NormalizeAngle( nYPosition
);
946 sal_Int32 nAngleEnd
= lcl_NormalizeAngle( 180 - nAngleStart
);
947 lcl_AppendAdjustmentValue( aAvList
, 1, 21600000 / 360 * nAngleStart
);
948 lcl_AppendAdjustmentValue( aAvList
, 2, 21600000 / 360 * nAngleEnd
);
949 lcl_AppendAdjustmentValue( aAvList
, 3, nRadius
);
953 // case mso_sptBentConnector3:
954 // case mso_sptBorderCallout3:
957 if (!strcmp( sPresetShape
, "frame" ))
959 sal_Int32 adj1
= double( nYPosition
)/aViewBox
.Height
*100000 ;
960 lcl_AppendAdjustmentValue( aAvList
, 1, adj1
);
965 WritePresetShape( sPresetShape
, aAvList
);
967 else // preset geometry
969 WriteShapeTransformation( xShape
, XML_a
, bFlipH
, bFlipV
);
970 if( nAdjustmentValuesIndex
!= -1 )
972 sal_Int32 nAdjustmentsWhichNeedsToBeConverted
= 0;
973 WritePresetShape( sPresetShape
, eShapeType
, bPredefinedHandlesUsed
,
974 nAdjustmentsWhichNeedsToBeConverted
, aGeometrySeq
[ nAdjustmentValuesIndex
] );
977 WritePresetShape( sPresetShape
);
981 WriteFill( rXPropSet
);
982 WriteOutline( rXPropSet
);
983 WriteShapeEffects( rXPropSet
);
984 WriteShape3DEffects( rXPropSet
);
987 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
989 pFS
->startElementNS( mnXmlNamespace
, XML_style
, FSEND
);
990 WriteShapeStyle( rXPropSet
);
991 pFS
->endElementNS( mnXmlNamespace
, XML_style
);
994 WriteTextBox( xShape
, mnXmlNamespace
);
996 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
) );
1001 ShapeExport
& ShapeExport::WriteEllipseShape( const Reference
< XShape
>& xShape
)
1003 SAL_INFO("oox.shape", "write ellipse shape");
1005 FSHelperPtr pFS
= GetFS();
1007 pFS
->startElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
), FSEND
);
1009 // TODO: arc, section, cut, connector
1011 // non visual shape properties
1012 if (GetDocumentType() != DOCUMENT_DOCX
)
1014 pFS
->startElementNS( mnXmlNamespace
, XML_nvSpPr
, FSEND
);
1015 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
1016 XML_id
, I32S( GetNewShapeID( xShape
) ),
1017 XML_name
, IDS( Ellipse
),
1019 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvSpPr
, FSEND
);
1020 WriteNonVisualProperties( xShape
);
1021 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
1024 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
, FSEND
);
1026 // visual shape properties
1027 pFS
->startElementNS( mnXmlNamespace
, XML_spPr
, FSEND
);
1028 WriteShapeTransformation( xShape
, XML_a
);
1029 WritePresetShape( "ellipse" );
1030 Reference
< XPropertySet
> xProps( xShape
, UNO_QUERY
);
1033 WriteFill( xProps
);
1034 WriteOutline( xProps
);
1036 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1039 WriteTextBox( xShape
, mnXmlNamespace
);
1041 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
) );
1046 ShapeExport
& ShapeExport::WriteGraphicObjectShape( const Reference
< XShape
>& xShape
)
1048 WriteGraphicObjectShapePart( xShape
);
1053 void ShapeExport::WriteGraphicObjectShapePart( const Reference
< XShape
>& xShape
, const Graphic
* pGraphic
)
1055 SAL_INFO("oox.shape", "write graphic object shape");
1057 if( NonEmptyText( xShape
) )
1059 // avoid treating all 'IsPresentationObject' objects as having text.
1060 Reference
< XSimpleText
> xText( xShape
, UNO_QUERY
);
1062 if( xText
.is() && !xText
->getString().isEmpty() )
1064 SAL_INFO("oox.shape", "graphicObject: wrote only text");
1066 WriteTextShape( xShape
);
1072 SAL_INFO("oox.shape", "graphicObject without text");
1074 OUString sGraphicURL
;
1075 Reference
< XPropertySet
> xShapeProps( xShape
, UNO_QUERY
);
1076 if( !pGraphic
&& ( !xShapeProps
.is() || !( xShapeProps
->getPropertyValue( "GraphicURL" ) >>= sGraphicURL
) ) )
1078 SAL_INFO("oox.shape", "no graphic URL found");
1082 FSHelperPtr pFS
= GetFS();
1083 XmlFilterBase
* pFB
= GetFB();
1085 if (GetDocumentType() != DOCUMENT_DOCX
)
1086 pFS
->startElementNS( mnXmlNamespace
, XML_pic
, FSEND
);
1088 pFS
->startElementNS( mnXmlNamespace
, XML_pic
,
1089 FSNS(XML_xmlns
, XML_pic
), OUStringToOString(pFB
->getNamespaceURL(OOX_NS(dmlPicture
)), RTL_TEXTENCODING_UTF8
).getStr(),
1092 pFS
->startElementNS( mnXmlNamespace
, XML_nvPicPr
, FSEND
);
1094 OUString sName
, sDescr
;
1095 bool bHaveName
, bHaveDesc
;
1097 if ( ( bHaveName
= GetProperty( xShapeProps
, "Name" ) ) )
1099 if ( ( bHaveDesc
= GetProperty( xShapeProps
, "Description" ) ) )
1102 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
1103 XML_id
, I32S( GetNewShapeID( xShape
) ),
1104 XML_name
, bHaveName
? USS( sName
) : OString( "Picture " + OString::number( mnPictureIdMax
++ )).getStr(),
1105 XML_descr
, bHaveDesc
? USS( sDescr
) : nullptr,
1107 // OOXTODO: //cNvPr children: XML_extLst, XML_hlinkClick, XML_hlinkHover
1109 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvPicPr
,
1110 // OOXTODO: XML_preferRelativeSize
1113 WriteNonVisualProperties( xShape
);
1115 pFS
->endElementNS( mnXmlNamespace
, XML_nvPicPr
);
1117 pFS
->startElementNS( mnXmlNamespace
, XML_blipFill
, FSEND
);
1119 WriteBlip( xShapeProps
, sGraphicURL
, false, pGraphic
);
1121 WriteSrcRect( xShapeProps
, sGraphicURL
);
1123 // now we stretch always when we get pGraphic (when changing that
1124 // behavior, test n#780830 for regression, where the OLE sheet might get tiled
1125 bool bStretch
= false;
1126 if( !pGraphic
&& GetProperty( xShapeProps
, "FillBitmapStretch" ) )
1129 if ( pGraphic
|| bStretch
)
1130 pFS
->singleElementNS( XML_a
, XML_stretch
, FSEND
);
1132 pFS
->endElementNS( mnXmlNamespace
, XML_blipFill
);
1134 // visual shape properties
1135 pFS
->startElementNS( mnXmlNamespace
, XML_spPr
, FSEND
);
1136 WriteShapeTransformation( xShape
, XML_a
);
1137 WritePresetShape( "rect" );
1138 // graphic object can come with the frame (bnc#654525)
1139 WriteOutline( xShapeProps
);
1141 WriteShapeEffects( xShapeProps
);
1142 WriteShape3DEffects( xShapeProps
);
1144 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1146 pFS
->endElementNS( mnXmlNamespace
, XML_pic
);
1149 ShapeExport
& ShapeExport::WriteConnectorShape( const Reference
< XShape
>& xShape
)
1151 bool bFlipH
= false;
1152 bool bFlipV
= false;
1154 SAL_INFO("oox.shape", "write connector shape");
1156 FSHelperPtr pFS
= GetFS();
1158 const char* sGeometry
= "line";
1159 Reference
< XPropertySet
> rXPropSet( xShape
, UNO_QUERY
);
1160 Reference
< XPropertyState
> rXPropState( xShape
, UNO_QUERY
);
1161 awt::Point aStartPoint
, aEndPoint
;
1162 Reference
< XShape
> rXShapeA
;
1163 Reference
< XShape
> rXShapeB
;
1164 PropertyState eState
;
1165 ConnectorType eConnectorType
;
1166 if( GETAD( EdgeKind
) ) {
1167 mAny
>>= eConnectorType
;
1169 switch( eConnectorType
) {
1170 case ConnectorType_CURVE
:
1171 sGeometry
= "curvedConnector3";
1173 case ConnectorType_STANDARD
:
1174 sGeometry
= "bentConnector3";
1177 case ConnectorType_LINE
:
1178 case ConnectorType_LINES
:
1179 sGeometry
= "straightConnector1";
1183 if( GETAD( EdgeStartPoint
) ) {
1184 mAny
>>= aStartPoint
;
1185 if( GETAD( EdgeEndPoint
) ) {
1189 GET( rXShapeA
, EdgeStartConnection
);
1190 GET( rXShapeB
, EdgeEndConnection
);
1192 EscherConnectorListEntry
aConnectorEntry( xShape
, aStartPoint
, rXShapeA
, aEndPoint
, rXShapeB
);
1194 tools::Rectangle
aRect( Point( aStartPoint
.X
, aStartPoint
.Y
), Point( aEndPoint
.X
, aEndPoint
.Y
) );
1195 if( aRect
.getWidth() < 0 ) {
1197 aRect
.setX( aEndPoint
.X
);
1198 aRect
.setWidth( aStartPoint
.X
- aEndPoint
.X
);
1201 if( aRect
.getHeight() < 0 ) {
1203 aRect
.setY( aEndPoint
.Y
);
1204 aRect
.setHeight( aStartPoint
.Y
- aEndPoint
.Y
);
1207 pFS
->startElementNS( mnXmlNamespace
, XML_cxnSp
, FSEND
);
1209 // non visual shape properties
1210 pFS
->startElementNS( mnXmlNamespace
, XML_nvCxnSpPr
, FSEND
);
1211 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
1212 XML_id
, I32S( GetNewShapeID( xShape
) ),
1213 XML_name
, IDS( Line
),
1215 // non visual connector shape drawing properties
1216 pFS
->startElementNS( mnXmlNamespace
, XML_cNvCxnSpPr
, FSEND
);
1217 WriteConnectorConnections( aConnectorEntry
, GetShapeID( rXShapeA
), GetShapeID( rXShapeB
) );
1218 pFS
->endElementNS( mnXmlNamespace
, XML_cNvCxnSpPr
);
1219 pFS
->singleElementNS( mnXmlNamespace
, XML_nvPr
, FSEND
);
1220 pFS
->endElementNS( mnXmlNamespace
, XML_nvCxnSpPr
);
1222 // visual shape properties
1223 pFS
->startElementNS( mnXmlNamespace
, XML_spPr
, FSEND
);
1224 WriteTransformation( aRect
, XML_a
, bFlipH
, bFlipV
);
1225 // TODO: write adjustments (ppt export doesn't work well there either)
1226 WritePresetShape( sGeometry
);
1227 Reference
< XPropertySet
> xShapeProps( xShape
, UNO_QUERY
);
1228 if( xShapeProps
.is() )
1229 WriteOutline( xShapeProps
);
1230 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1233 WriteTextBox( xShape
, mnXmlNamespace
);
1235 pFS
->endElementNS( mnXmlNamespace
, XML_cxnSp
);
1240 ShapeExport
& ShapeExport::WriteLineShape( const Reference
< XShape
>& xShape
)
1242 bool bFlipH
= false;
1243 bool bFlipV
= false;
1245 SAL_INFO("oox.shape", "write line shape");
1247 FSHelperPtr pFS
= GetFS();
1249 pFS
->startElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
), FSEND
);
1251 tools::PolyPolygon aPolyPolygon
= EscherPropertyContainer::GetPolyPolygon( xShape
);
1252 if( aPolyPolygon
.Count() == 1 && aPolyPolygon
[ 0 ].GetSize() == 2)
1254 const tools::Polygon
& rPoly
= aPolyPolygon
[ 0 ];
1256 bFlipH
= ( rPoly
[ 0 ].X() > rPoly
[ 1 ].X() );
1257 bFlipV
= ( rPoly
[ 0 ].Y() > rPoly
[ 1 ].Y() );
1260 // non visual shape properties
1261 if (GetDocumentType() != DOCUMENT_DOCX
)
1263 pFS
->startElementNS( mnXmlNamespace
, XML_nvSpPr
, FSEND
);
1264 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
1265 XML_id
, I32S( GetNewShapeID( xShape
) ),
1266 XML_name
, IDS( Line
),
1269 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvSpPr
, FSEND
);
1270 if (GetDocumentType() != DOCUMENT_DOCX
)
1272 WriteNonVisualProperties( xShape
);
1273 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
1276 // visual shape properties
1277 pFS
->startElementNS( mnXmlNamespace
, XML_spPr
, FSEND
);
1278 WriteShapeTransformation( xShape
, XML_a
, bFlipH
, bFlipV
, true);
1279 WritePresetShape( "line" );
1280 Reference
< XPropertySet
> xShapeProps( xShape
, UNO_QUERY
);
1281 if( xShapeProps
.is() )
1282 WriteOutline( xShapeProps
);
1283 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1286 pFS
->startElementNS( mnXmlNamespace
, XML_style
, FSEND
);
1287 WriteShapeStyle( xShapeProps
);
1288 pFS
->endElementNS( mnXmlNamespace
, XML_style
);
1291 WriteTextBox( xShape
, mnXmlNamespace
);
1293 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
) );
1298 ShapeExport
& ShapeExport::WriteNonVisualDrawingProperties( const Reference
< XShape
>& xShape
, const char* pName
)
1300 GetFS()->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
1301 XML_id
, I32S( GetNewShapeID( xShape
) ),
1308 ShapeExport
& ShapeExport::WriteNonVisualProperties( const Reference
< XShape
>& )
1310 // Override to generate //nvPr elements.
1314 ShapeExport
& ShapeExport::WriteRectangleShape( const Reference
< XShape
>& xShape
)
1316 SAL_INFO("oox.shape", "write rectangle shape");
1318 FSHelperPtr pFS
= GetFS();
1320 pFS
->startElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
), FSEND
);
1322 sal_Int32 nRadius
= 0;
1324 Reference
< XPropertySet
> xShapeProps( xShape
, UNO_QUERY
);
1325 if( xShapeProps
.is() )
1327 xShapeProps
->getPropertyValue( "CornerRadius" ) >>= nRadius
;
1332 nRadius
= MapSize( awt::Size( nRadius
, 0 ) ).Width
;
1334 //TODO: use nRadius value more precisely than just deciding whether to use
1335 // "rect" or "roundRect" preset shape below
1337 // non visual shape properties
1338 if (GetDocumentType() == DOCUMENT_DOCX
)
1339 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvSpPr
, FSEND
);
1340 pFS
->startElementNS( mnXmlNamespace
, XML_nvSpPr
, FSEND
);
1341 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
1342 XML_id
, I32S( GetNewShapeID( xShape
) ),
1343 XML_name
, IDS( Rectangle
),
1345 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvSpPr
, FSEND
);
1346 WriteNonVisualProperties( xShape
);
1347 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
1349 // visual shape properties
1350 pFS
->startElementNS( mnXmlNamespace
, XML_spPr
, FSEND
);
1351 WriteShapeTransformation( xShape
, XML_a
);
1352 WritePresetShape( nRadius
== 0 ? "rect" : "roundRect" );
1353 Reference
< XPropertySet
> xProps( xShape
, UNO_QUERY
);
1356 WriteFill( xProps
);
1357 WriteOutline( xProps
);
1359 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1362 WriteTextBox( xShape
, mnXmlNamespace
);
1364 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
) );
1369 typedef ShapeExport
& (ShapeExport::*ShapeConverter
)( const Reference
< XShape
>& );
1370 typedef std::unordered_map
< const char*, ShapeConverter
, rtl::CStringHash
, rtl::CStringEqual
> NameToConvertMapType
;
1372 static const NameToConvertMapType
& lcl_GetConverters(DocumentType eDocumentType
)
1374 static bool shape_map_inited
= false;
1375 static NameToConvertMapType shape_converters
;
1376 if( shape_map_inited
)
1378 return shape_converters
;
1381 shape_converters
[ "com.sun.star.drawing.ClosedBezierShape" ] = &ShapeExport::WriteClosedPolyPolygonShape
;
1382 shape_converters
[ "com.sun.star.drawing.ConnectorShape" ] = &ShapeExport::WriteConnectorShape
;
1383 shape_converters
[ "com.sun.star.drawing.CustomShape" ] = &ShapeExport::WriteCustomShape
;
1384 shape_converters
[ "com.sun.star.drawing.EllipseShape" ] = &ShapeExport::WriteEllipseShape
;
1385 shape_converters
[ "com.sun.star.drawing.GraphicObjectShape" ] = &ShapeExport::WriteGraphicObjectShape
;
1386 shape_converters
[ "com.sun.star.drawing.LineShape" ] = &ShapeExport::WriteLineShape
;
1387 shape_converters
[ "com.sun.star.drawing.OpenBezierShape" ] = &ShapeExport::WriteOpenPolyPolygonShape
;
1388 shape_converters
[ "com.sun.star.drawing.PolyPolygonShape" ] = &ShapeExport::WriteClosedPolyPolygonShape
;
1389 shape_converters
[ "com.sun.star.drawing.PolyLineShape" ] = &ShapeExport::WriteClosedPolyPolygonShape
;
1390 shape_converters
[ "com.sun.star.drawing.RectangleShape" ] = &ShapeExport::WriteRectangleShape
;
1391 shape_converters
[ "com.sun.star.drawing.OLE2Shape" ] = &ShapeExport::WriteOLE2Shape
;
1392 shape_converters
[ "com.sun.star.drawing.TableShape" ] = &ShapeExport::WriteTableShape
;
1393 shape_converters
[ "com.sun.star.drawing.TextShape" ] = &ShapeExport::WriteTextShape
;
1395 shape_converters
[ "com.sun.star.presentation.GraphicObjectShape" ] = &ShapeExport::WriteGraphicObjectShape
;
1396 shape_converters
[ "com.sun.star.presentation.OLE2Shape" ] = &ShapeExport::WriteOLE2Shape
;
1397 shape_converters
[ "com.sun.star.presentation.TableShape" ] = &ShapeExport::WriteTableShape
;
1398 shape_converters
[ "com.sun.star.presentation.TextShape" ] = &ShapeExport::WriteTextShape
;
1400 shape_converters
[ "com.sun.star.presentation.DateTimeShape" ] = &ShapeExport::WriteTextShape
;
1401 shape_converters
[ "com.sun.star.presentation.FooterShape" ] = &ShapeExport::WriteTextShape
;
1402 shape_converters
[ "com.sun.star.presentation.HeaderShape" ] = &ShapeExport::WriteTextShape
;
1403 shape_converters
[ "com.sun.star.presentation.NotesShape" ] = &ShapeExport::WriteTextShape
;
1404 shape_converters
[ "com.sun.star.presentation.OutlinerShape" ] = &ShapeExport::WriteTextShape
;
1405 shape_converters
[ "com.sun.star.presentation.SlideNumberShape" ] = &ShapeExport::WriteTextShape
;
1406 shape_converters
[ "com.sun.star.presentation.TitleTextShape" ] = &ShapeExport::WriteTextShape
;
1407 if (eDocumentType
== DOCUMENT_DOCX
)
1408 shape_converters
[ "com.sun.star.drawing.GroupShape" ] = &ShapeExport::WriteGroupShape
;
1409 shape_map_inited
= true;
1411 return shape_converters
;
1414 ShapeExport
& ShapeExport::WriteShape( const Reference
< XShape
>& xShape
)
1416 OUString sShapeType
= xShape
->getShapeType();
1417 SAL_INFO("oox.shape", "write shape: " << sShapeType
);
1418 NameToConvertMapType::const_iterator aConverter
= lcl_GetConverters(GetDocumentType()).find( USS( sShapeType
) );
1419 if( aConverter
== lcl_GetConverters(GetDocumentType()).end() )
1421 SAL_INFO("oox.shape", "unknown shape");
1422 return WriteUnknownShape( xShape
);
1424 (this->*(aConverter
->second
))( xShape
);
1429 ShapeExport
& ShapeExport::WriteTextBox( const Reference
< XInterface
>& xIface
, sal_Int32 nXmlNamespace
)
1431 // In case this shape has an associated textbox, then export that, and we're done.
1432 if (GetDocumentType() == DOCUMENT_DOCX
&& GetTextExport())
1434 uno::Reference
<beans::XPropertySet
> xPropertySet(xIface
, uno::UNO_QUERY
);
1435 if (xPropertySet
.is())
1437 uno::Reference
<beans::XPropertySetInfo
> xPropertySetInfo
= xPropertySet
->getPropertySetInfo();
1438 if (xPropertySetInfo
->hasPropertyByName("TextBox") && xPropertySet
->getPropertyValue("TextBox").get
<bool>())
1440 GetTextExport()->WriteTextBox(uno::Reference
<drawing::XShape
>(xIface
, uno::UNO_QUERY_THROW
));
1441 WriteText( xIface
, m_presetWarp
, /*bBodyPr=*/true, /*bText=*/false, /*nXmlNamespace=*/nXmlNamespace
);
1447 if( NonEmptyText( xIface
) )
1449 FSHelperPtr pFS
= GetFS();
1451 pFS
->startElementNS( nXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_txBody
: XML_txbx
), FSEND
);
1452 WriteText( xIface
, m_presetWarp
, /*bBodyPr=*/(GetDocumentType() != DOCUMENT_DOCX
) );
1453 pFS
->endElementNS( nXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_txBody
: XML_txbx
) );
1454 if (GetDocumentType() == DOCUMENT_DOCX
)
1455 WriteText( xIface
, m_presetWarp
, /*bBodyPr=*/true, /*bText=*/false, /*nXmlNamespace=*/nXmlNamespace
);
1457 else if (GetDocumentType() == DOCUMENT_DOCX
)
1458 mpFS
->singleElementNS(nXmlNamespace
, XML_bodyPr
, FSEND
);
1463 void ShapeExport::WriteTable( const Reference
< XShape
>& rXShape
)
1465 Reference
< XTable
> xTable
;
1466 Reference
< XPropertySet
> xPropSet( rXShape
, UNO_QUERY
);
1468 mpFS
->startElementNS( XML_a
, XML_graphic
, FSEND
);
1469 mpFS
->startElementNS( XML_a
, XML_graphicData
, XML_uri
, "http://schemas.openxmlformats.org/drawingml/2006/table", FSEND
);
1471 if ( xPropSet
.is() && ( xPropSet
->getPropertyValue( "Model" ) >>= xTable
) )
1473 mpFS
->startElementNS( XML_a
, XML_tbl
, FSEND
);
1474 mpFS
->singleElementNS( XML_a
, XML_tblPr
, FSEND
);
1476 Reference
< container::XIndexAccess
> xColumns( xTable
->getColumns(), UNO_QUERY_THROW
);
1477 Reference
< container::XIndexAccess
> xRows( xTable
->getRows(), UNO_QUERY_THROW
);
1478 sal_uInt16 nRowCount
= static_cast< sal_uInt16
>( xRows
->getCount() );
1479 sal_uInt16 nColumnCount
= static_cast< sal_uInt16
>( xColumns
->getCount() );
1481 mpFS
->startElementNS( XML_a
, XML_tblGrid
, FSEND
);
1483 for ( sal_Int32 x
= 0; x
< nColumnCount
; x
++ )
1485 Reference
< XPropertySet
> xColPropSet( xColumns
->getByIndex( x
), UNO_QUERY_THROW
);
1486 sal_Int32
nWidth(0);
1487 xColPropSet
->getPropertyValue( "Width" ) >>= nWidth
;
1489 mpFS
->singleElementNS( XML_a
, XML_gridCol
, XML_w
, I64S(oox::drawingml::convertHmmToEmu(nWidth
)), FSEND
);
1492 mpFS
->endElementNS( XML_a
, XML_tblGrid
);
1494 // map for holding the transpose index of the merged cells and pair<parentTransposeIndex, parentCell>
1495 typedef std::unordered_map
<sal_Int32
, std::pair
<sal_Int32
, Reference
< XMergeableCell
> > > transposeTableMap
;
1496 transposeTableMap mergedCellMap
;
1498 for( sal_Int32 nRow
= 0; nRow
< nRowCount
; nRow
++ )
1500 Reference
< XPropertySet
> xRowPropSet( xRows
->getByIndex( nRow
), UNO_QUERY_THROW
);
1501 sal_Int32
nRowHeight(0);
1503 xRowPropSet
->getPropertyValue( "Height" ) >>= nRowHeight
;
1505 mpFS
->startElementNS( XML_a
, XML_tr
, XML_h
, I64S( oox::drawingml::convertHmmToEmu( nRowHeight
) ), FSEND
);
1506 for( sal_Int32 nColumn
= 0; nColumn
< nColumnCount
; nColumn
++ )
1508 Reference
< XMergeableCell
> xCell( xTable
->getCellByPosition( nColumn
, nRow
),
1510 sal_Int32 transposedIndexofCell
= (nRow
* nColumnCount
) + nColumn
;
1512 //assume we will open a cell, set to false below if we won't
1513 bool bCellOpened
= true;
1515 if(xCell
->getColumnSpan() > 1 && xCell
->getRowSpan() > 1)
1517 // having both : horizontal and vertical merge
1518 mpFS
->startElementNS(XML_a
, XML_tc
, XML_gridSpan
,
1519 I32S(xCell
->getColumnSpan()),
1520 XML_rowSpan
, I32S(xCell
->getRowSpan()),
1522 // since, XMergeableCell doesn't have the information about
1523 // cell having hMerge or vMerge.
1524 // So, Populating the merged cell map in-order to use it to
1525 // decide the attribute for the individual cell.
1526 for(sal_Int32 columnIndex
= nColumn
; columnIndex
< nColumn
+xCell
->getColumnSpan(); ++columnIndex
)
1528 for(sal_Int32 rowIndex
= nRow
; rowIndex
< nRow
+xCell
->getRowSpan(); ++rowIndex
)
1530 sal_Int32 transposeIndexForMergeCell
=
1531 (rowIndex
* nColumnCount
) + columnIndex
;
1532 mergedCellMap
[transposeIndexForMergeCell
] =
1533 std::make_pair(transposedIndexofCell
, xCell
);
1538 else if(xCell
->getColumnSpan() > 1)
1540 // having : horizontal merge
1541 mpFS
->startElementNS(XML_a
, XML_tc
, XML_gridSpan
,
1542 I32S(xCell
->getColumnSpan()), FSEND
);
1543 for(sal_Int32 columnIndex
= nColumn
; columnIndex
< nColumn
+ xCell
->getColumnSpan(); ++columnIndex
) {
1544 sal_Int32 transposeIndexForMergeCell
= (nRow
*nColumnCount
) + columnIndex
;
1545 mergedCellMap
[transposeIndexForMergeCell
] =
1546 std::make_pair(transposedIndexofCell
, xCell
);
1549 else if(xCell
->getRowSpan() > 1)
1551 // having : vertical merge
1552 mpFS
->startElementNS(XML_a
, XML_tc
, XML_rowSpan
,
1553 I32S(xCell
->getRowSpan()), FSEND
);
1555 for(sal_Int32 rowIndex
= nRow
; rowIndex
< nRow
+ xCell
->getRowSpan(); ++rowIndex
) {
1556 sal_Int32 transposeIndexForMergeCell
= (rowIndex
*nColumnCount
) + nColumn
;
1557 mergedCellMap
[transposeIndexForMergeCell
] =
1558 std::make_pair(transposedIndexofCell
, xCell
);
1563 // now, the cell can be an independent cell or
1564 // it can be a cell which is been merged to some parent cell
1565 if(!xCell
->isMerged())
1568 mpFS
->startElementNS( XML_a
, XML_tc
, FSEND
);
1572 // it a merged cell to some parent cell
1573 // find the parent cell for the current cell at hand
1574 transposeTableMap::iterator it
= mergedCellMap
.find(transposedIndexofCell
);
1575 if(it
!= mergedCellMap
.end())
1577 sal_Int32 transposeIndexOfParent
= it
->second
.first
;
1578 Reference
< XMergeableCell
> parentCell
= it
->second
.second
;
1579 // finding the row and column index for the parent cell from transposed index
1580 sal_Int32 parentColumnIndex
= transposeIndexOfParent
% nColumnCount
;
1581 sal_Int32 parentRowIndex
= transposeIndexOfParent
/ nColumnCount
;
1582 if(nColumn
== parentColumnIndex
)
1584 // the cell is vertical merge and it might have gridspan
1585 if(parentCell
->getColumnSpan() > 1)
1587 // vMerge and has gridSpan
1588 mpFS
->startElementNS( XML_a
, XML_tc
,
1589 XML_vMerge
, I32S(1),
1590 XML_gridSpan
, I32S(xCell
->getColumnSpan()),
1596 mpFS
->startElementNS( XML_a
, XML_tc
,
1597 XML_vMerge
, I32S(1), FSEND
);
1600 else if(nRow
== parentRowIndex
)
1602 // the cell is horizontal merge and it might have rowspan
1603 if(parentCell
->getRowSpan() > 1)
1605 // hMerge and has rowspan
1606 mpFS
->startElementNS( XML_a
, XML_tc
,
1607 XML_hMerge
, I32S(1),
1608 XML_rowSpan
, I32S(xCell
->getRowSpan()),
1614 mpFS
->startElementNS( XML_a
, XML_tc
,
1615 XML_hMerge
, I32S(1), FSEND
);
1620 // has hMerge and vMerge
1621 mpFS
->startElementNS( XML_a
, XML_tc
,
1622 XML_vMerge
, I32S(1),
1623 XML_hMerge
, I32S(1),
1628 bCellOpened
= false;
1634 WriteTextBox( xCell
, XML_a
);
1636 Reference
< XPropertySet
> xCellPropSet(xCell
, UNO_QUERY_THROW
);
1637 WriteTableCellProperties(xCellPropSet
);
1639 mpFS
->endElementNS( XML_a
, XML_tc
);
1643 mpFS
->endElementNS( XML_a
, XML_tr
);
1646 mpFS
->endElementNS( XML_a
, XML_tbl
);
1649 mpFS
->endElementNS( XML_a
, XML_graphicData
);
1650 mpFS
->endElementNS( XML_a
, XML_graphic
);
1653 void ShapeExport::WriteTableCellProperties(const Reference
< XPropertySet
>& xCellPropSet
)
1655 sal_Int32
nLeftMargin(0), nRightMargin(0);
1657 Any aLeftMargin
= xCellPropSet
->getPropertyValue("TextLeftDistance");
1658 aLeftMargin
>>= nLeftMargin
;
1660 Any aRightMargin
= xCellPropSet
->getPropertyValue("TextRightDistance");
1661 aRightMargin
>>= nRightMargin
;
1663 mpFS
->startElementNS( XML_a
, XML_tcPr
,
1664 XML_marL
, nLeftMargin
> 0 ? I32S( oox::drawingml::convertHmmToEmu( nLeftMargin
) ) : nullptr,
1665 XML_marR
, nRightMargin
> 0 ? I32S( oox::drawingml::convertHmmToEmu( nRightMargin
) ): nullptr,
1668 // Write background fill for table cell.
1670 // tcW : Table cell width
1671 WriteTableCellBorders(xCellPropSet
);
1672 DrawingML::WriteFill(xCellPropSet
);
1673 mpFS
->endElementNS( XML_a
, XML_tcPr
);
1676 void ShapeExport::WriteTableCellBorders(const Reference
< XPropertySet
>& xCellPropSet
)
1678 BorderLine2 aBorderLine
;
1680 // lnL - Left Border Line Properties of table cell
1681 xCellPropSet
->getPropertyValue("LeftBorder") >>= aBorderLine
;
1682 sal_Int32 nLeftBorder
= aBorderLine
.LineWidth
;
1683 util::Color aLeftBorderColor
= aBorderLine
.Color
;
1685 // While importing the table cell border line width, it converts EMU->Hmm then divided result by 2.
1686 // To get original value of LineWidth need to multiple by 2.
1687 nLeftBorder
= nLeftBorder
*2;
1688 nLeftBorder
= oox::drawingml::convertHmmToEmu( nLeftBorder
);
1692 mpFS
->startElementNS( XML_a
, XML_lnL
, XML_w
, I32S(nLeftBorder
), FSEND
);
1693 DrawingML::WriteSolidFill(aLeftBorderColor
);
1694 mpFS
->endElementNS( XML_a
, XML_lnL
);
1697 // lnR - Right Border Line Properties of table cell
1698 xCellPropSet
->getPropertyValue("RightBorder") >>= aBorderLine
;
1699 sal_Int32 nRightBorder
= aBorderLine
.LineWidth
;
1700 util::Color aRightBorderColor
= aBorderLine
.Color
;
1701 nRightBorder
= nRightBorder
* 2 ;
1702 nRightBorder
= oox::drawingml::convertHmmToEmu( nRightBorder
);
1704 if(nRightBorder
> 0)
1706 mpFS
->startElementNS( XML_a
, XML_lnR
, XML_w
, I32S(nRightBorder
), FSEND
);
1707 DrawingML::WriteSolidFill(aRightBorderColor
);
1708 mpFS
->endElementNS( XML_a
, XML_lnR
);
1711 // lnT - Top Border Line Properties of table cell
1712 xCellPropSet
->getPropertyValue("TopBorder") >>= aBorderLine
;
1713 sal_Int32 nTopBorder
= aBorderLine
.LineWidth
;
1714 util::Color aTopBorderColor
= aBorderLine
.Color
;
1715 nTopBorder
= nTopBorder
* 2;
1716 nTopBorder
= oox::drawingml::convertHmmToEmu( nTopBorder
);
1720 mpFS
->startElementNS( XML_a
, XML_lnT
, XML_w
, I32S(nTopBorder
), FSEND
);
1721 DrawingML::WriteSolidFill(aTopBorderColor
);
1722 mpFS
->endElementNS( XML_a
, XML_lnT
);
1725 // lnB - Bottom Border Line Properties of table cell
1726 xCellPropSet
->getPropertyValue("BottomBorder") >>= aBorderLine
;
1727 sal_Int32 nBottomBorder
= aBorderLine
.LineWidth
;
1728 util::Color aBottomBorderColor
= aBorderLine
.Color
;
1729 nBottomBorder
= nBottomBorder
* 2;
1730 nBottomBorder
= oox::drawingml::convertHmmToEmu( nBottomBorder
);
1732 if(nBottomBorder
> 0)
1734 mpFS
->startElementNS( XML_a
, XML_lnB
, XML_w
, I32S(nBottomBorder
), FSEND
);
1735 DrawingML::WriteSolidFill(aBottomBorderColor
);
1736 mpFS
->endElementNS( XML_a
, XML_lnB
);
1740 ShapeExport
& ShapeExport::WriteTableShape( const Reference
< XShape
>& xShape
)
1742 FSHelperPtr pFS
= GetFS();
1744 pFS
->startElementNS( mnXmlNamespace
, XML_graphicFrame
, FSEND
);
1746 pFS
->startElementNS( mnXmlNamespace
, XML_nvGraphicFramePr
, FSEND
);
1748 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
1749 XML_id
, I32S( GetNewShapeID( xShape
) ),
1750 XML_name
, IDS(Table
),
1753 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvGraphicFramePr
,
1756 if( GetDocumentType() == DOCUMENT_PPTX
)
1757 pFS
->singleElementNS( mnXmlNamespace
, XML_nvPr
,
1759 pFS
->endElementNS( mnXmlNamespace
, XML_nvGraphicFramePr
);
1761 WriteShapeTransformation( xShape
, mnXmlNamespace
);
1762 WriteTable( xShape
);
1764 pFS
->endElementNS( mnXmlNamespace
, XML_graphicFrame
);
1769 ShapeExport
& ShapeExport::WriteTextShape( const Reference
< XShape
>& xShape
)
1771 FSHelperPtr pFS
= GetFS();
1773 pFS
->startElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
), FSEND
);
1775 // non visual shape properties
1776 if (GetDocumentType() != DOCUMENT_DOCX
)
1778 pFS
->startElementNS( mnXmlNamespace
, XML_nvSpPr
, FSEND
);
1779 WriteNonVisualDrawingProperties( xShape
, IDS( TextShape
) );
1781 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvSpPr
, XML_txBox
, "1", FSEND
);
1782 if (GetDocumentType() != DOCUMENT_DOCX
)
1784 WriteNonVisualProperties( xShape
);
1785 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
1788 // visual shape properties
1789 pFS
->startElementNS( mnXmlNamespace
, XML_spPr
, FSEND
);
1790 WriteShapeTransformation( xShape
, XML_a
);
1791 WritePresetShape( "rect" );
1792 uno::Reference
<beans::XPropertySet
> xPropertySet(xShape
, UNO_QUERY
);
1793 WriteBlipOrNormalFill(xPropertySet
, "GraphicURL");
1794 WriteOutline(xPropertySet
);
1795 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1797 WriteTextBox( xShape
, mnXmlNamespace
);
1799 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
) );
1804 void ShapeExport::WriteMathShape(Reference
<XShape
> const& xShape
)
1806 Reference
<XPropertySet
> const xPropSet(xShape
, UNO_QUERY
);
1807 assert(xPropSet
.is());
1808 Reference
<XModel
> xMathModel
;
1809 xPropSet
->getPropertyValue("Model") >>= xMathModel
;
1810 assert(xMathModel
.is());
1811 assert(GetDocumentType() != DOCUMENT_DOCX
); // should be written in DocxAttributeOutput
1812 SAL_WARN_IF(GetDocumentType() == DOCUMENT_XLSX
, "oox.shape", "Math export to XLSX isn't tested, should it happen here?");
1814 // ECMA standard does not actually allow oMath outside of
1815 // WordProcessingML so write a MCE like PPT 2010 does
1816 mpFS
->startElementNS(XML_mc
, XML_AlternateContent
, FSEND
);
1817 mpFS
->startElementNS(XML_mc
, XML_Choice
,
1818 FSNS(XML_xmlns
, XML_a14
), OUStringToOString(mpFB
->getNamespaceURL(OOX_NS(a14
)), RTL_TEXTENCODING_UTF8
).getStr(),
1819 XML_Requires
, "a14",
1821 mpFS
->startElementNS(mnXmlNamespace
, XML_sp
, FSEND
);
1822 mpFS
->startElementNS(mnXmlNamespace
, XML_nvSpPr
, FSEND
);
1823 mpFS
->singleElementNS(mnXmlNamespace
, XML_cNvPr
,
1824 XML_id
, OString::number(GetNewShapeID(xShape
)).getStr(),
1825 XML_name
, OString("Formula " + OString::number(mnShapeIdMax
++)).getStr(),
1827 mpFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
, XML_txBox
, "1", FSEND
);
1828 mpFS
->singleElementNS(mnXmlNamespace
, XML_nvPr
, FSEND
);
1829 mpFS
->endElementNS(mnXmlNamespace
, XML_nvSpPr
);
1830 mpFS
->startElementNS(mnXmlNamespace
, XML_spPr
, FSEND
);
1831 WriteShapeTransformation(xShape
, XML_a
);
1832 WritePresetShape("rect");
1833 mpFS
->endElementNS(mnXmlNamespace
, XML_spPr
);
1834 mpFS
->startElementNS(mnXmlNamespace
, XML_txBody
, FSEND
);
1835 mpFS
->startElementNS(XML_a
, XML_bodyPr
, FSEND
);
1836 mpFS
->endElementNS(XML_a
, XML_bodyPr
);
1837 mpFS
->startElementNS(XML_a
, XML_p
, FSEND
);
1838 mpFS
->startElementNS(XML_a14
, XML_m
, FSEND
);
1840 oox::FormulaExportBase
*const pMagic(dynamic_cast<oox::FormulaExportBase
*>(xMathModel
.get()));
1842 pMagic
->writeFormulaOoxml(GetFS(), GetFB()->getVersion(), GetDocumentType());
1844 mpFS
->endElementNS(XML_a14
, XML_m
);
1845 mpFS
->endElementNS(XML_a
, XML_p
);
1846 mpFS
->endElementNS(mnXmlNamespace
, XML_txBody
);
1847 mpFS
->endElementNS(mnXmlNamespace
, XML_sp
);
1848 mpFS
->endElementNS(XML_mc
, XML_Choice
);
1849 mpFS
->startElementNS(XML_mc
, XML_Fallback
, FSEND
);
1850 // TODO: export bitmap shape as fallback
1851 mpFS
->endElementNS(XML_mc
, XML_Fallback
);
1852 mpFS
->endElementNS(XML_mc
, XML_AlternateContent
);
1855 ShapeExport
& ShapeExport::WriteOLE2Shape( const Reference
< XShape
>& xShape
)
1857 Reference
< XPropertySet
> xPropSet( xShape
, UNO_QUERY
);
1861 enum { CHART
, MATH
, OTHER
} eType(OTHER
);
1863 xPropSet
->getPropertyValue("CLSID") >>= clsid
;
1864 if (!clsid
.isEmpty())
1866 SvGlobalName aClassID
;
1867 bool const isValid
= aClassID
.MakeId(clsid
);
1868 assert(isValid
); (void)isValid
;
1869 if (SotExchange::IsChart(aClassID
))
1871 else if (SotExchange::IsMath(aClassID
))
1877 Reference
< XChartDocument
> xChartDoc
;
1878 xPropSet
->getPropertyValue("Model") >>= xChartDoc
;
1879 assert(xChartDoc
.is());
1881 Reference
< XModel
> xModel( xChartDoc
, UNO_QUERY
);
1882 ChartExport
aChartExport( mnXmlNamespace
, GetFS(), xModel
, GetFB(), GetDocumentType() );
1883 static sal_Int32 nChartCount
= 0;
1884 aChartExport
.WriteChartObj( xShape
, ++nChartCount
);
1890 WriteMathShape(xShape
);
1894 uno::Reference
<embed::XEmbeddedObject
> const xObj(
1895 xPropSet
->getPropertyValue("EmbeddedObject"), uno::UNO_QUERY
);
1899 SAL_WARN("oox.shape", "ShapeExport::WriteOLE2Shape: no object");
1903 uno::Sequence
<beans::PropertyValue
> grabBag
;
1907 uno::Reference
<beans::XPropertySet
> const xParent(
1908 uno::Reference
<container::XChild
>(xObj
, uno::UNO_QUERY_THROW
)->getParent(),
1909 uno::UNO_QUERY_THROW
);
1911 xParent
->getPropertyValue("InteropGrabBag") >>= grabBag
;
1913 entryName
= uno::Reference
<embed::XEmbedPersist
>(xObj
, uno::UNO_QUERY
)->getEntryName();
1915 catch (uno::Exception
const& e
)
1917 SAL_WARN("oox.shape", "ShapeExport::WriteOLE2Shape: exception: " << e
.Message
);
1923 for (auto const& it
: grabBag
)
1925 if (it
.Name
== "EmbeddedObjects")
1927 uno::Sequence
<beans::PropertyValue
> objects
;
1928 it
.Value
>>= objects
;
1929 for (auto const& object
: objects
)
1931 if (object
.Name
== entryName
)
1933 uno::Sequence
<beans::PropertyValue
> props
;
1934 object
.Value
>>= props
;
1935 for (auto const& prop
: props
)
1937 if (prop
.Name
== "ProgID")
1939 prop
.Value
>>= progID
;
1950 OUString sMediaType
;
1951 OUString sRelationType
;
1953 const char * pProgID(nullptr);
1955 uno::Reference
<io::XInputStream
> const xInStream
=
1956 oox::GetOLEObjectStream(
1957 mpFB
->getComponentContext(), xObj
, progID
,
1958 sMediaType
, sRelationType
, sSuffix
, pProgID
);
1960 if (!xInStream
.is())
1965 OString anotherProgID
;
1966 if (!pProgID
&& !progID
.isEmpty())
1968 anotherProgID
= OUStringToOString(progID
, RTL_TEXTENCODING_UTF8
);
1969 pProgID
= anotherProgID
.getStr();
1972 assert(!sMediaType
.isEmpty());
1973 assert(!sRelationType
.isEmpty());
1974 assert(!sSuffix
.isEmpty());
1976 OUString sFileName
= "embeddings/oleObject" + OUString::number(++m_nEmbeddedObjects
) + "." + sSuffix
;
1977 uno::Reference
<io::XOutputStream
> const xOutStream(
1978 mpFB
->openFragmentStream(
1979 OUString::createFromAscii(GetComponentDir()) + "/" + sFileName
,
1981 assert(xOutStream
.is()); // no reason why that could fail
1984 ::comphelper::OStorageHelper::CopyInputToOutput(xInStream
, xOutStream
);
1985 } catch (uno::Exception
const& e
) {
1986 SAL_WARN("oox.shape", "ShapeExport::WriteOLEObject: exception: " << e
.Message
);
1989 OUString
const sRelId
= mpFB
->addRelation(
1990 mpFS
->getOutputStream(), sRelationType
,
1991 OUString::createFromAscii(GetRelationCompPrefix()) + sFileName
);
1993 mpFS
->startElementNS( mnXmlNamespace
, XML_graphicFrame
, FSEND
);
1995 mpFS
->startElementNS( mnXmlNamespace
, XML_nvGraphicFramePr
, FSEND
);
1997 mpFS
->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
1998 XML_id
, I32S( GetNewShapeID( xShape
) ),
1999 XML_name
, IDS(Object
),
2002 mpFS
->singleElementNS( mnXmlNamespace
, XML_cNvGraphicFramePr
,
2005 if (GetDocumentType() == DOCUMENT_PPTX
)
2006 mpFS
->singleElementNS( mnXmlNamespace
, XML_nvPr
,
2008 mpFS
->endElementNS( mnXmlNamespace
, XML_nvGraphicFramePr
);
2010 WriteShapeTransformation( xShape
, mnXmlNamespace
);
2012 mpFS
->startElementNS( XML_a
, XML_graphic
, FSEND
);
2013 mpFS
->startElementNS( XML_a
, XML_graphicData
,
2014 XML_uri
, "http://schemas.openxmlformats.org/presentationml/2006/ole",
2018 mpFS
->startElementNS( mnXmlNamespace
, XML_oleObj
,
2019 XML_progId
, pProgID
,
2020 FSNS(XML_r
, XML_id
), USS( sRelId
),
2026 mpFS
->startElementNS( mnXmlNamespace
, XML_oleObj
,
2027 //? XML_name, "Document",
2028 FSNS(XML_r
, XML_id
), USS( sRelId
),
2029 // The spec says that this is a required attribute, but PowerPoint can only handle an empty value.
2034 mpFS
->singleElementNS( mnXmlNamespace
, XML_embed
, FSEND
);
2037 SdrObject
* pSdrOLE2( GetSdrObjectFromXShape( xShape
) );
2038 // The spec doesn't allow <p:pic> here, but PowerPoint requires it.
2039 bool bEcma
= mpFB
->getVersion() == oox::core::ECMA_DIALECT
;
2040 if (pSdrOLE2
&& dynamic_cast<const SdrOle2Obj
*>( pSdrOLE2
) != nullptr && bEcma
)
2042 const Graphic
* pGraphic
= static_cast<SdrOle2Obj
*>(pSdrOLE2
)->GetGraphic();
2044 WriteGraphicObjectShapePart( xShape
, pGraphic
);
2047 mpFS
->endElementNS( mnXmlNamespace
, XML_oleObj
);
2049 mpFS
->endElementNS( XML_a
, XML_graphicData
);
2050 mpFS
->endElementNS( XML_a
, XML_graphic
);
2052 mpFS
->endElementNS( mnXmlNamespace
, XML_graphicFrame
);
2057 ShapeExport
& ShapeExport::WriteUnknownShape( const Reference
< XShape
>& )
2059 // Override this method to do something useful.
2063 size_t ShapeExport::ShapeHash::operator()( const Reference
< XShape
>& rXShape
) const
2065 return rXShape
->getShapeType().hashCode();
2068 sal_Int32
ShapeExport::GetNewShapeID( const Reference
< XShape
>& rXShape
)
2070 return GetNewShapeID( rXShape
, GetFB() );
2073 sal_Int32
ShapeExport::GetNewShapeID( const Reference
< XShape
>& rXShape
, XmlFilterBase
* pFB
)
2078 sal_Int32 nID
= pFB
->GetUniqueId();
2080 (*mpShapeMap
)[ rXShape
] = nID
;
2085 sal_Int32
ShapeExport::GetShapeID( const Reference
< XShape
>& rXShape
)
2087 return GetShapeID( rXShape
, mpShapeMap
);
2090 sal_Int32
ShapeExport::GetShapeID( const Reference
< XShape
>& rXShape
, ShapeHashMap
* pShapeMap
)
2095 ShapeHashMap::const_iterator aIter
= pShapeMap
->find( rXShape
);
2097 if( aIter
== pShapeMap
->end() )
2100 return aIter
->second
;
2105 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */