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 <sal/log.hxx>
24 #include <unotools/mediadescriptor.hxx>
25 #include <filter/msfilter/util.hxx>
26 #include <oox/core/xmlfilterbase.hxx>
27 #include <oox/export/shapes.hxx>
28 #include <oox/export/utils.hxx>
29 #include <oox/token/namespaces.hxx>
30 #include <oox/token/relationship.hxx>
31 #include <oox/token/tokens.hxx>
34 #include <initializer_list>
36 #include <com/sun/star/awt/CharSet.hpp>
37 #include <com/sun/star/awt/FontDescriptor.hpp>
38 #include <com/sun/star/awt/FontSlant.hpp>
39 #include <com/sun/star/awt/FontWeight.hpp>
40 #include <com/sun/star/awt/FontUnderline.hpp>
41 #include <com/sun/star/awt/Gradient.hpp>
42 #include <com/sun/star/beans/PropertyValues.hpp>
43 #include <com/sun/star/beans/XPropertySet.hpp>
44 #include <com/sun/star/beans/XPropertySetInfo.hpp>
45 #include <com/sun/star/beans/XPropertyState.hpp>
46 #include <com/sun/star/container/XChild.hpp>
47 #include <com/sun/star/container/XEnumerationAccess.hpp>
48 #include <com/sun/star/document/XExporter.hpp>
49 #include <com/sun/star/document/XStorageBasedDocument.hpp>
50 #include <com/sun/star/drawing/CircleKind.hpp>
51 #include <com/sun/star/drawing/FillStyle.hpp>
52 #include <com/sun/star/drawing/BitmapMode.hpp>
53 #include <com/sun/star/drawing/ConnectorType.hpp>
54 #include <com/sun/star/drawing/LineDash.hpp>
55 #include <com/sun/star/drawing/LineJoint.hpp>
56 #include <com/sun/star/drawing/LineStyle.hpp>
57 #include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
58 #include <com/sun/star/drawing/TextVerticalAdjust.hpp>
59 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
60 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
61 #include <com/sun/star/embed/EmbedStates.hpp>
62 #include <com/sun/star/embed/XEmbeddedObject.hpp>
63 #include <com/sun/star/embed/XEmbedPersist.hpp>
64 #include <com/sun/star/frame/XStorable.hpp>
65 #include <com/sun/star/graphic/XGraphic.hpp>
66 #include <com/sun/star/i18n/ScriptType.hpp>
67 #include <com/sun/star/io/XOutputStream.hpp>
68 #include <com/sun/star/style/ParagraphAdjust.hpp>
69 #include <com/sun/star/text/XSimpleText.hpp>
70 #include <com/sun/star/text/XText.hpp>
71 #include <com/sun/star/text/XTextContent.hpp>
72 #include <com/sun/star/text/XTextDocument.hpp>
73 #include <com/sun/star/text/XTextField.hpp>
74 #include <com/sun/star/text/XTextRange.hpp>
75 #include <com/sun/star/table/XTable.hpp>
76 #include <com/sun/star/table/XColumnRowRange.hpp>
77 #include <com/sun/star/table/XCellRange.hpp>
78 #include <com/sun/star/table/XMergeableCell.hpp>
79 #include <com/sun/star/chart2/XChartDocument.hpp>
80 #include <com/sun/star/frame/XModel.hpp>
81 #include <com/sun/star/uno/XComponentContext.hpp>
82 #include <tools/stream.hxx>
83 #include <tools/globname.hxx>
84 #include <comphelper/classids.hxx>
85 #include <comphelper/propertysequence.hxx>
86 #include <comphelper/storagehelper.hxx>
87 #include <sot/exchange.hxx>
89 #include <vcl/cvtgrf.hxx>
90 #include <unotools/fontcvt.hxx>
91 #include <vcl/graph.hxx>
92 #include <vcl/outdev.hxx>
93 #include <vcl/GraphicObject.hxx>
94 #include <rtl/strbuf.hxx>
95 #include <sfx2/app.hxx>
96 #include <svl/languageoptions.hxx>
97 #include <filter/msfilter/escherex.hxx>
98 #include <svx/svdoashp.hxx>
99 #include <svx/svdoole2.hxx>
100 #include <tools/diagnose_ex.h>
101 #include <editeng/svxenum.hxx>
102 #include <svx/unoapi.hxx>
103 #include <oox/export/chartexport.hxx>
104 #include <oox/mathml/export.hxx>
105 #include <drawingml/presetgeometrynames.hxx>
106 #include <basegfx/numeric/ftools.hxx>
108 using namespace ::css
;
109 using namespace ::css::beans
;
110 using namespace ::css::uno
;
111 using namespace ::css::drawing
;
112 using namespace ::css::i18n
;
113 using namespace ::css::table
;
114 using namespace ::css::container
;
115 using namespace ::css::document
;
116 using namespace ::css::text
;
118 using ::css::io::XOutputStream
;
119 using ::css::chart2::XChartDocument
;
120 using ::css::frame::XModel
;
122 using ::oox::core::XmlFilterBase
;
123 using ::sax_fastparser::FSHelperPtr
;
125 #define IDS(x) OString(#x " " + OString::number(mnShapeIdMax++)).getStr()
129 static void lcl_ConvertProgID(OUString
const& rProgID
,
130 OUString
& o_rMediaType
, OUString
& o_rRelationType
, OUString
& o_rFileExtension
)
132 if (rProgID
== "Excel.Sheet.12")
134 o_rMediaType
= "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
135 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
136 o_rFileExtension
= "xlsx";
138 else if (rProgID
.startsWith("Excel.SheetBinaryMacroEnabled.12") )
140 o_rMediaType
= "application/vnd.ms-excel.sheet.binary.macroEnabled.12";
141 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
142 o_rFileExtension
= "xlsb";
144 else if (rProgID
.startsWith("Excel.SheetMacroEnabled.12"))
146 o_rMediaType
= "application/vnd.ms-excel.sheet.macroEnabled.12";
147 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
148 o_rFileExtension
= "xlsm";
150 else if (rProgID
.startsWith("Excel.Sheet"))
152 o_rMediaType
= "application/vnd.ms-excel";
153 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
154 o_rFileExtension
= "xls";
156 else if (rProgID
== "PowerPoint.Show.12")
158 o_rMediaType
= "application/vnd.openxmlformats-officedocument.presentationml.presentation";
159 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
160 o_rFileExtension
= "pptx";
162 else if (rProgID
== "PowerPoint.ShowMacroEnabled.12")
164 o_rMediaType
= "application/vnd.ms-powerpoint.presentation.macroEnabled.12";
165 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
166 o_rFileExtension
= "pptm";
168 else if (rProgID
.startsWith("PowerPoint.Show"))
170 o_rMediaType
= "application/vnd.ms-powerpoint";
171 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
172 o_rFileExtension
= "ppt";
174 else if (rProgID
.startsWith("PowerPoint.Slide.12"))
176 o_rMediaType
= "application/vnd.openxmlformats-officedocument.presentationml.slide";
177 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
178 o_rFileExtension
= "sldx";
180 else if (rProgID
== "PowerPoint.SlideMacroEnabled.12")
182 o_rMediaType
= "application/vnd.ms-powerpoint.slide.macroEnabled.12";
183 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
184 o_rFileExtension
= "sldm";
186 else if (rProgID
== "Word.DocumentMacroEnabled.12")
188 o_rMediaType
= "application/vnd.ms-word.document.macroEnabled.12";
189 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
190 o_rFileExtension
= "docm";
192 else if (rProgID
== "Word.Document.12")
194 o_rMediaType
= "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
195 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
196 o_rFileExtension
= "docx";
198 else if (rProgID
== "Word.Document.8")
200 o_rMediaType
= "application/msword";
201 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
202 o_rFileExtension
= "doc";
204 else if (rProgID
== "Excel.Chart.8")
206 o_rMediaType
= "application/vnd.ms-excel";
207 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
208 o_rFileExtension
= "xls";
210 else if (rProgID
== "AcroExch.Document.11")
212 o_rMediaType
= "application/pdf";
213 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
214 o_rFileExtension
= "pdf";
218 o_rMediaType
= "application/vnd.openxmlformats-officedocument.oleObject";
219 o_rRelationType
= oox::getRelationship(Relationship::OLEOBJECT
);
220 o_rFileExtension
= "bin";
224 static uno::Reference
<io::XInputStream
> lcl_StoreOwnAsOOXML(
225 uno::Reference
<uno::XComponentContext
> const& xContext
,
226 uno::Reference
<embed::XEmbeddedObject
> const& xObj
,
227 char const*& o_rpProgID
,
228 OUString
& o_rMediaType
, OUString
& o_rRelationType
, OUString
& o_rSuffix
)
234 sal_uInt8 b8
, b9
, b10
, b11
, b12
, b13
, b14
, b15
;
236 char const* pFilterName
;
237 char const* pMediaType
;
240 } const s_Mapping
[] = {
241 { {SO3_SW_CLASSID_60
}, "MS Word 2007 XML", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "Word.Document.12", "docx" },
242 { {SO3_SC_CLASSID_60
}, "Calc MS Excel 2007 XML", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Excel.Sheet.12", "xlsx" },
243 { {SO3_SIMPRESS_CLASSID_60
}, "Impress MS PowerPoint 2007 XML", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "PowerPoint.Show.12", "pptx" },
244 // FIXME: Draw does not appear to have a MSO format export filter?
245 // { {SO3_SDRAW_CLASSID}, "", "", "", "" },
246 { {SO3_SCH_CLASSID_60
}, "unused", "", "", "" },
247 { {SO3_SM_CLASSID_60
}, "unused", "", "", "" },
250 const char * pFilterName(nullptr);
251 SvGlobalName
const classId(xObj
->getClassID());
252 for (auto & i
: s_Mapping
)
254 auto const& rId(i
.ClassId
);
255 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
);
258 assert(SvGlobalName(SO3_SCH_CLASSID_60
) != classId
); // chart should be written elsewhere!
259 assert(SvGlobalName(SO3_SM_CLASSID_60
) != classId
); // formula should be written elsewhere!
260 pFilterName
= i
.pFilterName
;
261 o_rMediaType
= OUString::createFromAscii(i
.pMediaType
);
262 o_rpProgID
= i
.pProgID
;
263 o_rSuffix
= OUString::createFromAscii(i
.pSuffix
);
264 o_rRelationType
= oox::getRelationship(Relationship::PACKAGE
);
271 SAL_WARN("oox.shape", "oox::GetOLEObjectStream: unknown ClassId " << classId
.GetHexName());
275 if (embed::EmbedStates::LOADED
== xObj
->getCurrentState())
277 xObj
->changeState(embed::EmbedStates::RUNNING
);
279 // use a temp stream - while it would work to store directly to a
280 // fragment stream, an error during export means we'd have to delete it
281 uno::Reference
<io::XStream
> const xTempStream(
282 xContext
->getServiceManager()->createInstanceWithContext(
283 "com.sun.star.comp.MemoryStream", xContext
),
284 uno::UNO_QUERY_THROW
);
285 uno::Sequence
<beans::PropertyValue
> args( comphelper::InitPropertySequence({
286 { "OutputStream", Any(xTempStream
->getOutputStream()) },
287 { "FilterName", Any(OUString::createFromAscii(pFilterName
)) }
289 uno::Reference
<frame::XStorable
> xStorable(xObj
->getComponent(), uno::UNO_QUERY
);
292 xStorable
->storeToURL("private:stream", args
);
294 catch (uno::Exception
const&)
296 TOOLS_WARN_EXCEPTION("oox.shape", "oox::GetOLEObjectStream");
299 xTempStream
->getOutputStream()->closeOutput();
300 return xTempStream
->getInputStream();
303 uno::Reference
<io::XInputStream
> GetOLEObjectStream(
304 uno::Reference
<uno::XComponentContext
> const& xContext
,
305 uno::Reference
<embed::XEmbeddedObject
> const& xObj
,
306 OUString
const& i_rProgID
,
307 OUString
& o_rMediaType
,
308 OUString
& o_rRelationType
,
309 OUString
& o_rSuffix
,
310 const char *& o_rpProgID
)
312 uno::Reference
<io::XInputStream
> xInStream
;
315 uno::Reference
<document::XStorageBasedDocument
> const xParent(
316 uno::Reference
<container::XChild
>(xObj
, uno::UNO_QUERY_THROW
)->getParent(),
317 uno::UNO_QUERY_THROW
);
318 uno::Reference
<embed::XStorage
> const xParentStorage(xParent
->getDocumentStorage());
319 OUString
const entryName(
320 uno::Reference
<embed::XEmbedPersist
>(xObj
, uno::UNO_QUERY_THROW
)->getEntryName());
322 if (xParentStorage
->isStreamElement(entryName
))
324 lcl_ConvertProgID(i_rProgID
, o_rMediaType
, o_rRelationType
, o_rSuffix
);
325 xInStream
= xParentStorage
->cloneStreamElement(entryName
)->getInputStream();
326 // TODO: make it possible to take the sMediaType from the stream
328 else // the object is ODF - either the whole document is
329 { // ODF, or the OLE was edited so it was converted to ODF
330 xInStream
= lcl_StoreOwnAsOOXML(xContext
, xObj
,
331 o_rpProgID
, o_rMediaType
, o_rRelationType
, o_rSuffix
);
334 catch (uno::Exception
const&)
336 TOOLS_WARN_EXCEPTION("oox.shape", "oox::GetOLEObjectStream");
343 namespace oox
{ namespace drawingml
{
345 #define GETA(propName) \
346 GetProperty( rXPropSet, #propName)
348 #define GETAD(propName) \
349 ( GetPropertyAndState( rXPropSet, rXPropState, #propName, eState ) && eState == beans::PropertyState_DIRECT_VALUE )
351 #define GET(variable, propName) \
352 if ( GETA(propName) ) \
355 ShapeExport::ShapeExport( sal_Int32 nXmlNamespace
, FSHelperPtr pFS
, ShapeHashMap
* pShapeMap
, XmlFilterBase
* pFB
, DocumentType eDocumentType
, DMLTextExport
* pTextExport
)
356 : DrawingML( std::move(pFS
), pFB
, eDocumentType
, pTextExport
)
357 , m_nEmbeddedObjects(0)
359 , mnPictureIdMax( 1 )
360 , mnXmlNamespace( nXmlNamespace
)
361 , maMapModeSrc( MapUnit::Map100thMM
)
362 , maMapModeDest( MapUnit::MapInch
, Point(), Fraction( 1, 576 ), Fraction( 1, 576 ) )
363 , mpShapeMap( pShapeMap
? pShapeMap
: &maShapeMap
)
365 mpURLTransformer
.reset(new URLTransformer
);
368 void ShapeExport::SetURLTranslator(const std::shared_ptr
<URLTransformer
>& pTransformer
)
370 mpURLTransformer
= pTransformer
;
373 awt::Size
ShapeExport::MapSize( const awt::Size
& rSize
) const
375 Size
aRetSize( OutputDevice::LogicToLogic( Size( rSize
.Width
, rSize
.Height
), maMapModeSrc
, maMapModeDest
) );
377 if ( !aRetSize
.Width() )
378 aRetSize
.AdjustWidth( 1 );
379 if ( !aRetSize
.Height() )
380 aRetSize
.AdjustHeight( 1 );
381 return awt::Size( aRetSize
.Width(), aRetSize
.Height() );
384 bool ShapeExport::NonEmptyText( const Reference
< XInterface
>& xIface
)
386 Reference
< XPropertySet
> xPropSet( xIface
, UNO_QUERY
);
390 Reference
< XPropertySetInfo
> xPropSetInfo
= xPropSet
->getPropertySetInfo();
391 if ( xPropSetInfo
.is() )
393 if ( xPropSetInfo
->hasPropertyByName( "IsEmptyPresentationObject" ) )
395 bool bIsEmptyPresObj
= false;
396 if ( xPropSet
->getPropertyValue( "IsEmptyPresentationObject" ) >>= bIsEmptyPresObj
)
398 SAL_INFO("oox.shape", "empty presentation object " << bIsEmptyPresObj
<< " , props:");
399 if( bIsEmptyPresObj
)
404 if ( xPropSetInfo
->hasPropertyByName( "IsPresentationObject" ) )
406 bool bIsPresObj
= false;
407 if ( xPropSet
->getPropertyValue( "IsPresentationObject" ) >>= bIsPresObj
)
409 SAL_INFO("oox.shape", "presentation object " << bIsPresObj
<< ", props:");
417 Reference
< XSimpleText
> xText( xIface
, UNO_QUERY
);
420 return xText
->getString().getLength();
425 ShapeExport
& ShapeExport::WritePolyPolygonShape( const Reference
< XShape
>& xShape
, const bool bClosed
)
427 SAL_INFO("oox.shape", "write polypolygon shape");
429 FSHelperPtr pFS
= GetFS();
430 pFS
->startElementNS(mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
));
432 tools::PolyPolygon aPolyPolygon
= EscherPropertyContainer::GetPolyPolygon( xShape
);
433 tools::Rectangle
aRect( aPolyPolygon
.GetBoundRect() );
435 #if OSL_DEBUG_LEVEL > 0
436 awt::Size size
= MapSize( awt::Size( aRect
.GetWidth(), aRect
.GetHeight() ) );
437 SAL_INFO("oox.shape", "poly count " << aPolyPolygon
.Count());
438 SAL_INFO("oox.shape", "size: " << size
.Width
<< " x " << size
.Height
);
441 // non visual shape properties
442 if (GetDocumentType() != DOCUMENT_DOCX
)
444 pFS
->startElementNS(mnXmlNamespace
, XML_nvSpPr
);
445 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
446 XML_id
, OString::number(GetNewShapeID(xShape
)),
447 XML_name
, IDS( Freeform
) );
449 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
);
450 if (GetDocumentType() != DOCUMENT_DOCX
)
452 WriteNonVisualProperties( xShape
);
453 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
456 // visual shape properties
457 pFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
458 WriteTransformation( aRect
, XML_a
);
459 WritePolyPolygon( aPolyPolygon
, bClosed
);
460 Reference
< XPropertySet
> xProps( xShape
, UNO_QUERY
);
464 WriteOutline( xProps
);
467 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
470 WriteTextBox( xShape
, mnXmlNamespace
);
472 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
) );
477 ShapeExport
& ShapeExport::WriteClosedPolyPolygonShape( const Reference
< XShape
>& xShape
)
479 return WritePolyPolygonShape( xShape
, true );
482 ShapeExport
& ShapeExport::WriteOpenPolyPolygonShape( const Reference
< XShape
>& xShape
)
484 return WritePolyPolygonShape( xShape
, false );
487 ShapeExport
& ShapeExport::WriteGroupShape(const uno::Reference
<drawing::XShape
>& xShape
)
489 FSHelperPtr pFS
= GetFS();
491 sal_Int32 nGroupShapeToken
= XML_grpSp
;
492 if (GetDocumentType() == DOCUMENT_DOCX
)
495 nGroupShapeToken
= XML_wgp
; // toplevel
497 mnXmlNamespace
= XML_wpg
;
500 pFS
->startElementNS(mnXmlNamespace
, nGroupShapeToken
);
502 // non visual properties
503 if (GetDocumentType() != DOCUMENT_DOCX
)
505 pFS
->startElementNS(mnXmlNamespace
, XML_nvGrpSpPr
);
506 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvPr
,
507 XML_id
, OString::number(GetNewShapeID(xShape
)),
508 XML_name
, IDS(Group
));
509 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvGrpSpPr
);
510 WriteNonVisualProperties(xShape
);
511 pFS
->endElementNS(mnXmlNamespace
, XML_nvGrpSpPr
);
514 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvGrpSpPr
);
517 pFS
->startElementNS(mnXmlNamespace
, XML_grpSpPr
);
518 WriteShapeTransformation(xShape
, XML_a
, false, false, true);
519 pFS
->endElementNS(mnXmlNamespace
, XML_grpSpPr
);
521 uno::Reference
<drawing::XShapes
> xGroupShape(xShape
, uno::UNO_QUERY_THROW
);
522 uno::Reference
<drawing::XShape
> xParent
= m_xParent
;
524 for (sal_Int32 i
= 0; i
< xGroupShape
->getCount(); ++i
)
526 uno::Reference
<drawing::XShape
> xChild(xGroupShape
->getByIndex(i
), uno::UNO_QUERY_THROW
);
527 sal_Int32 nSavedNamespace
= mnXmlNamespace
;
529 uno::Reference
<lang::XServiceInfo
> xServiceInfo(xChild
, uno::UNO_QUERY_THROW
);
530 if (GetDocumentType() == DOCUMENT_DOCX
)
532 if (xServiceInfo
->supportsService("com.sun.star.drawing.GraphicObjectShape"))
533 mnXmlNamespace
= XML_pic
;
535 mnXmlNamespace
= XML_wps
;
539 mnXmlNamespace
= nSavedNamespace
;
543 pFS
->endElementNS(mnXmlNamespace
, nGroupShapeToken
);
547 static bool lcl_IsOnBlacklist(OUString
const & rShapeType
)
549 static const std::initializer_list
<OUStringLiteral
> vBlacklist
= {
566 "round-rectangular-callout",
567 "rectangular-callout",
581 "flowchart-alternate-process",
582 "flowchart-decision",
584 "flowchart-predefined-process",
585 "flowchart-internal-storage",
586 "flowchart-document",
587 "flowchart-multidocument",
588 "flowchart-terminator",
589 "flowchart-preparation",
590 "flowchart-manual-input",
591 "flowchart-manual-operation",
592 "flowchart-connector",
593 "flowchart-off-page-connector",
595 "flowchart-punched-tape",
596 "flowchart-summing-junction",
602 "flowchart-stored-data",
604 "flowchart-sequential-access",
605 "flowchart-magnetic-disk",
606 "flowchart-direct-access-storage",
610 return std::find(vBlacklist
.begin(), vBlacklist
.end(), rShapeType
) != vBlacklist
.end();
613 static bool lcl_IsOnWhitelist(OUString
const & rShapeType
)
615 static const std::initializer_list
<OUStringLiteral
> vWhitelist
= {
621 return std::find(vWhitelist
.begin(), vWhitelist
.end(), rShapeType
) != vWhitelist
.end();
624 static bool lcl_GetHandlePosition( sal_Int32
&nValue
, const EnhancedCustomShapeParameter
&rParam
, Sequence
< EnhancedCustomShapeAdjustmentValue
> &rSeq
)
627 if ( rParam
.Value
.getValueTypeClass() == TypeClass_DOUBLE
)
630 if ( rParam
.Value
>>= fValue
)
631 nValue
= static_cast<sal_Int32
>(fValue
);
634 rParam
.Value
>>= nValue
;
636 if ( rParam
.Type
== EnhancedCustomShapeParameterType::ADJUSTMENT
)
639 sal_Int32 nIdx
= nValue
;
640 if ( nIdx
< rSeq
.getLength() )
642 if ( rSeq
[ nIdx
] .Value
.getValueTypeClass() == TypeClass_DOUBLE
)
645 rSeq
[ nIdx
].Value
>>= fValue
;
651 rSeq
[ nIdx
].Value
>>= nValue
;
658 static void lcl_AnalyzeHandles( const uno::Sequence
<beans::PropertyValues
> & rHandles
,
659 std::vector
< std::pair
< sal_Int32
, sal_Int32
> > &rHandlePositionList
,
660 Sequence
< EnhancedCustomShapeAdjustmentValue
> &rSeq
)
662 for ( const Sequence
< PropertyValue
>& rPropSeq
: rHandles
)
664 const OUString
sPosition( "Position" );
665 bool bPosition
= false;
666 EnhancedCustomShapeParameterPair aPosition
;
667 EnhancedCustomShapeParameterPair aPolar
;
668 for ( const PropertyValue
& rPropVal
: rPropSeq
)
670 if ( rPropVal
.Name
== sPosition
)
672 if ( rPropVal
.Value
>>= aPosition
)
678 sal_Int32 nXPosition
= 0;
679 sal_Int32 nYPosition
= 0;
680 // For polar handles, nXPosition is radius and nYPosition is angle
681 lcl_GetHandlePosition( nXPosition
, aPosition
.First
, rSeq
);
682 lcl_GetHandlePosition( nYPosition
, aPosition
.Second
, rSeq
);
683 rHandlePositionList
.emplace_back( nXPosition
, nYPosition
);
688 static void lcl_AppendAdjustmentValue( std::vector
< std::pair
< sal_Int32
, sal_Int32
> > &rAvList
, sal_Int32 nAdjIdx
, sal_Int32 nValue
)
690 rAvList
.emplace_back( nAdjIdx
, nValue
);
693 static sal_Int32
lcl_NormalizeAngle( sal_Int32 nAngle
)
695 nAngle
= nAngle
% 360;
696 return nAngle
< 0 ? ( nAngle
+ 360 ) : nAngle
;
699 static sal_Int32
lcl_CircleAngle2CustomShapeEllipseAngleOOX(const sal_Int32 nInternAngle
, const sal_Int32 nWidth
, const sal_Int32 nHeight
)
701 if (nWidth
!= 0 || nHeight
!= 0)
703 double fAngle
= basegfx::deg2rad(nInternAngle
/ 100.0); // intern 1/100 deg to degree to rad
704 fAngle
= atan2(nHeight
* sin(fAngle
), nWidth
* cos(fAngle
)); // circle to ellipse
705 fAngle
= basegfx::rad2deg(fAngle
) * 60000.0; // rad to degree to OOXML angle unit
706 sal_Int32 nAngle
= basegfx::fround(fAngle
); // normalize
707 nAngle
= nAngle
% 21600000;
708 return nAngle
< 0 ? (nAngle
+ 21600000) : nAngle
;
710 else // should be handled by caller, dummy value
714 ShapeExport
& ShapeExport::WriteCustomShape( const Reference
< XShape
>& xShape
)
716 // First check, if this is a Fontwork-shape. For DrawingML, such a shape is a
717 // TextBox shape with body property prstTxWarp.
718 SAL_INFO("oox.shape", "write custom shape");
719 Reference
< XPropertySet
> rXPropSet( xShape
, UNO_QUERY
);
720 bool bIsFontworkShape(false);
721 bool bHasGeometrySeq(false);
722 Sequence
< PropertyValue
> aGeometrySeq
;
724 if (GETA(CustomShapeGeometry
))
726 SAL_INFO("oox.shape", "got custom shape geometry");
727 if (mAny
>>= aGeometrySeq
)
729 bHasGeometrySeq
= true;
730 SAL_INFO("oox.shape", "got custom shape geometry sequence");
731 for (const PropertyValue
& rProp
: std::as_const(aGeometrySeq
))
733 SAL_INFO("oox.shape", "geometry property: " << rProp
.Name
);
734 if (rProp
.Name
== "TextPath")
736 uno::Sequence
<beans::PropertyValue
> aTextPathSeq
;
737 rProp
.Value
>>= aTextPathSeq
;
738 for (const PropertyValue
& rTextProp
: std::as_const(aTextPathSeq
))
740 if (rTextProp
.Name
== "TextPath")
742 rTextProp
.Value
>>= bIsFontworkShape
;
746 else if (rProp
.Name
== "Type")
747 rProp
.Value
>>= sShapeType
;
751 if (bIsFontworkShape
)
753 // write the correct type to m_presetWarp, WriteTextShape() needs it
755 m_presetWarp
= PresetGeometryTypeNames::GetMsoName(sShapeType
);
756 ShapeExport::WriteTextShape(xShape
); // qualifier to prevent PowerPointShapeExport
761 bool bPredefinedHandlesUsed
= true;
762 bool bHasHandles
= false;
764 ShapeFlag nMirrorFlags
= ShapeFlag::NONE
;
765 MSO_SPT eShapeType
= EscherPropertyContainer::GetCustomShapeType( xShape
, nMirrorFlags
, sShapeType
);
766 OSL_ENSURE(nullptr != dynamic_cast< SdrObjCustomShape
* >(GetSdrObjectFromXShape(xShape
)), "Not a SdrObjCustomShape (!)");
767 SdrObjCustomShape
& rSdrObjCustomShape(static_cast< SdrObjCustomShape
& >(*GetSdrObjectFromXShape(xShape
)));
768 const bool bIsDefaultObject(
769 EscherPropertyContainer::IsDefaultObject(
772 const char* sPresetShape
= msfilter::util::GetOOXMLPresetGeometry(sShapeType
.toUtf8().getStr());
773 SAL_INFO("oox.shape", "custom shape type: " << sShapeType
<< " ==> " << sPresetShape
);
775 sal_Int32 nAdjustmentValuesIndex
= -1;
776 awt::Rectangle aViewBox
;
777 uno::Sequence
<beans::PropertyValues
> aHandles
;
782 // Avoid interference of preset type to the next shape
787 for (int i
= 0; i
< aGeometrySeq
.getLength(); i
++)
789 const PropertyValue
& rProp
= aGeometrySeq
[ i
];
790 SAL_INFO("oox.shape", "geometry property: " << rProp
.Name
);
792 if ( rProp
.Name
== "MirroredX" )
793 rProp
.Value
>>= bFlipH
;
795 if ( rProp
.Name
== "MirroredY" )
796 rProp
.Value
>>= bFlipV
;
797 if ( rProp
.Name
== "AdjustmentValues" )
798 nAdjustmentValuesIndex
= i
;
799 else if ( rProp
.Name
== "Handles" )
801 rProp
.Value
>>= aHandles
;
802 if ( aHandles
.hasElements() )
804 if( !bIsDefaultObject
)
805 bPredefinedHandlesUsed
= false;
806 // TODO: update nAdjustmentsWhichNeedsToBeConverted here
808 else if ( rProp
.Name
== "PresetTextWarp" )
810 rProp
.Value
>>= m_presetWarp
;
812 else if ( rProp
.Name
== "ViewBox" )
813 rProp
.Value
>>= aViewBox
;
817 FSHelperPtr pFS
= GetFS();
818 pFS
->startElementNS(mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
));
820 // non visual shape properties
821 if (GetDocumentType() != DOCUMENT_DOCX
)
823 bool isVisible
= true ;
828 pFS
->startElementNS( mnXmlNamespace
, XML_nvSpPr
);
829 pFS
->startElementNS( mnXmlNamespace
, XML_cNvPr
,
830 XML_id
, OString::number(GetNewShapeID(xShape
)),
831 XML_name
, IDS( CustomShape
),
832 XML_hidden
, isVisible
? nullptr : "1" );
838 if( !sURL
.isEmpty() )
840 OUString sRelId
= mpFB
->addRelation( mpFS
->getOutputStream(),
841 oox::getRelationship(Relationship::HYPERLINK
),
842 mpURLTransformer
->getTransformedString(sURL
),
843 mpURLTransformer
->isExternalURL(sURL
));
845 mpFS
->singleElementNS(XML_a
, XML_hlinkClick
, FSNS(XML_r
, XML_id
), sRelId
.toUtf8());
848 pFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
849 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
);
850 WriteNonVisualProperties( xShape
);
851 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
854 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
);
856 // visual shape properties
857 pFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
858 // moon is flipped in MSO, and mso-spt89 (right up arrow) is mapped to leftUpArrow
859 if ( sShapeType
== "moon" || sShapeType
== "mso-spt89" )
862 // we export non-primitive shapes to custom geometry
863 // we also export non-ooxml shapes which have handles/equations to custom geometry, because
864 // we cannot convert ODF equations to DrawingML equations. TODO: see what binary DOC export filter does.
865 // but our WritePolyPolygon()/WriteCustomGeometry() functions are incomplete, therefore we use a blacklist
866 // we use a whitelist for shapes where mapping to MSO preset shape is not optimal
867 bool bCustGeom
= true;
868 bool bOnBlacklist
= false;
869 if( sShapeType
== "ooxml-non-primitive" )
871 else if( sShapeType
.startsWith("ooxml") )
873 else if( lcl_IsOnWhitelist(sShapeType
) )
875 else if( lcl_IsOnBlacklist(sShapeType
) )
880 else if( bHasHandles
)
883 if (bHasHandles
&& bCustGeom
)
885 WriteShapeTransformation( xShape
, XML_a
, bFlipH
, bFlipV
, false, true );// do not flip, polypolygon coordinates are flipped already
886 tools::PolyPolygon
aPolyPolygon( rSdrObjCustomShape
.GetLineGeometry(true) );
887 sal_Int32 nRotation
= 0;
888 // The RotateAngle property's value is independent from any flipping, and that's exactly what we need here.
889 uno::Reference
<beans::XPropertySet
> xPropertySet(xShape
, uno::UNO_QUERY
);
890 uno::Reference
<beans::XPropertySetInfo
> xPropertySetInfo
= xPropertySet
->getPropertySetInfo();
891 if (xPropertySetInfo
->hasPropertyByName("RotateAngle"))
892 xPropertySet
->getPropertyValue("RotateAngle") >>= nRotation
;
894 bool bInvertRotation
= bFlipH
!= bFlipV
;
896 aPolyPolygon
.Rotate(Point(0,0), static_cast<sal_uInt16
>(bInvertRotation
? nRotation
/10 : 3600-nRotation
/10));
897 WritePolyPolygon( aPolyPolygon
, false );
901 WriteShapeTransformation( xShape
, XML_a
, bFlipH
, bFlipV
);
902 bool bSuccess
= WriteCustomGeometry(xShape
, rSdrObjCustomShape
);
904 WritePresetShape( sPresetShape
);
906 else if (bOnBlacklist
&& bHasHandles
&& nAdjustmentValuesIndex
!=-1 && !sShapeType
.startsWith("mso-spt"))
908 WriteShapeTransformation( xShape
, XML_a
, bFlipH
, bFlipV
);
909 Sequence
< EnhancedCustomShapeAdjustmentValue
> aAdjustmentSeq
;
910 std::vector
< std::pair
< sal_Int32
, sal_Int32
> > aHandlePositionList
;
911 std::vector
< std::pair
< sal_Int32
, sal_Int32
> > aAvList
;
912 aGeometrySeq
[ nAdjustmentValuesIndex
].Value
>>= aAdjustmentSeq
;
914 lcl_AnalyzeHandles( aHandles
, aHandlePositionList
, aAdjustmentSeq
);
916 sal_Int32 nXPosition
= 0;
917 sal_Int32 nYPosition
= 0;
918 if ( !aHandlePositionList
.empty() )
920 nXPosition
= aHandlePositionList
[0].first
;
921 nYPosition
= aHandlePositionList
[0].second
;
925 case mso_sptBorderCallout1
:
927 sal_Int32 adj3
= double(nYPosition
)/aViewBox
.Height
*100000;
928 sal_Int32 adj4
= double(nXPosition
)/aViewBox
.Width
*100000;
929 lcl_AppendAdjustmentValue( aAvList
, 1, 18750 );
930 lcl_AppendAdjustmentValue( aAvList
, 2, -8333 );
931 lcl_AppendAdjustmentValue( aAvList
, 3, adj3
);
932 lcl_AppendAdjustmentValue( aAvList
, 4, adj4
);
935 case mso_sptBorderCallout2
:
937 sal_Int32 adj5
= double(nYPosition
)/aViewBox
.Height
*100000;
938 sal_Int32 adj6
= double(nXPosition
)/aViewBox
.Width
*100000;
939 sal_Int32 adj3
= 18750;
940 sal_Int32 adj4
= -16667;
941 lcl_AppendAdjustmentValue( aAvList
, 1, 18750 );
942 lcl_AppendAdjustmentValue( aAvList
, 2, -8333 );
943 if ( aHandlePositionList
.size() > 1 )
945 nXPosition
= aHandlePositionList
[1].first
;
946 nYPosition
= aHandlePositionList
[1].second
;
947 adj3
= double(nYPosition
)/aViewBox
.Height
*100000;
948 adj4
= double(nXPosition
)/aViewBox
.Width
*100000;
950 lcl_AppendAdjustmentValue( aAvList
, 3, adj3
);
951 lcl_AppendAdjustmentValue( aAvList
, 4, adj4
);
952 lcl_AppendAdjustmentValue( aAvList
, 5, adj5
);
953 lcl_AppendAdjustmentValue( aAvList
, 6, adj6
);
956 case mso_sptWedgeRectCallout
:
957 case mso_sptWedgeRRectCallout
:
958 case mso_sptWedgeEllipseCallout
:
959 case mso_sptCloudCallout
:
961 sal_Int32 adj1
= (double(nXPosition
)/aViewBox
.Width
-0.5) *100000;
962 sal_Int32 adj2
= (double(nYPosition
)/aViewBox
.Height
-0.5) *100000;
963 lcl_AppendAdjustmentValue( aAvList
, 1, adj1
);
964 lcl_AppendAdjustmentValue( aAvList
, 2, adj2
);
965 if ( eShapeType
== mso_sptWedgeRRectCallout
)
967 lcl_AppendAdjustmentValue( aAvList
, 3, 16667);
972 case mso_sptFoldedCorner
:
974 sal_Int32 adj
= double( aViewBox
.Width
- nXPosition
) / std::min( aViewBox
.Width
,aViewBox
.Height
) * 100000;
975 lcl_AppendAdjustmentValue( aAvList
, 0, adj
);
981 case mso_sptHorizontalScroll
:
983 case mso_sptBracketPair
:
985 sal_Int32 adj
= double( nXPosition
)/aViewBox
.Width
*100000 ;
986 lcl_AppendAdjustmentValue( aAvList
, 0, adj
);
991 case mso_sptBracePair
:
992 case mso_sptVerticalScroll
:
994 sal_Int32 adj
= double( nYPosition
)/aViewBox
.Height
*100000 ;
995 lcl_AppendAdjustmentValue( aAvList
, 0, adj
);
998 case mso_sptSmileyFace
:
1000 sal_Int32 adj
= double( nYPosition
)/aViewBox
.Height
*100000 - 76458.0;
1001 lcl_AppendAdjustmentValue( aAvList
, 0, adj
);
1004 case mso_sptBlockArc
:
1006 sal_Int32 nRadius
= 50000 * ( 1 - double(nXPosition
) / 10800);
1007 sal_Int32 nAngleStart
= lcl_NormalizeAngle( nYPosition
);
1008 sal_Int32 nAngleEnd
= lcl_NormalizeAngle( 180 - nAngleStart
);
1009 lcl_AppendAdjustmentValue( aAvList
, 1, 21600000 / 360 * nAngleStart
);
1010 lcl_AppendAdjustmentValue( aAvList
, 2, 21600000 / 360 * nAngleEnd
);
1011 lcl_AppendAdjustmentValue( aAvList
, 3, nRadius
);
1015 // case mso_sptBentConnector3:
1016 // case mso_sptBorderCallout3:
1019 if (!strcmp( sPresetShape
, "frame" ))
1021 sal_Int32 adj1
= double( nYPosition
)/aViewBox
.Height
*100000 ;
1022 lcl_AppendAdjustmentValue( aAvList
, 1, adj1
);
1027 WritePresetShape( sPresetShape
, aAvList
);
1029 else // preset geometry
1031 WriteShapeTransformation( xShape
, XML_a
, bFlipH
, bFlipV
);
1032 if( nAdjustmentValuesIndex
!= -1 )
1034 WritePresetShape( sPresetShape
, eShapeType
, bPredefinedHandlesUsed
,
1035 aGeometrySeq
[ nAdjustmentValuesIndex
] );
1038 WritePresetShape( sPresetShape
);
1040 if( rXPropSet
.is() )
1042 WriteFill( rXPropSet
);
1043 WriteOutline( rXPropSet
);
1044 WriteShapeEffects( rXPropSet
);
1045 WriteShape3DEffects( rXPropSet
);
1048 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1050 pFS
->startElementNS(mnXmlNamespace
, XML_style
);
1051 WriteShapeStyle( rXPropSet
);
1052 pFS
->endElementNS( mnXmlNamespace
, XML_style
);
1055 WriteTextBox( xShape
, mnXmlNamespace
);
1057 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
) );
1062 ShapeExport
& ShapeExport::WriteEllipseShape( const Reference
< XShape
>& xShape
)
1064 SAL_INFO("oox.shape", "write ellipse shape");
1066 FSHelperPtr pFS
= GetFS();
1068 pFS
->startElementNS(mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
));
1070 // TODO: connector ?
1072 // non visual shape properties
1073 if (GetDocumentType() != DOCUMENT_DOCX
)
1075 pFS
->startElementNS(mnXmlNamespace
, XML_nvSpPr
);
1076 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
1077 XML_id
, OString::number(GetNewShapeID(xShape
)),
1078 XML_name
, IDS( Ellipse
) );
1079 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvSpPr
);
1080 WriteNonVisualProperties( xShape
);
1081 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
1084 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
);
1086 Reference
< XPropertySet
> xProps( xShape
, UNO_QUERY
);
1087 CircleKind
eCircleKind(CircleKind_FULL
);
1089 xProps
->getPropertyValue("CircleKind" ) >>= eCircleKind
;
1091 // visual shape properties
1092 pFS
->startElementNS( mnXmlNamespace
, XML_spPr
);
1093 WriteShapeTransformation( xShape
, XML_a
);
1095 if (CircleKind_FULL
== eCircleKind
)
1096 WritePresetShape("ellipse");
1099 sal_Int32
nStartAngleIntern(9000);
1100 sal_Int32
nEndAngleIntern(0);
1103 xProps
->getPropertyValue("CircleStartAngle" ) >>= nStartAngleIntern
;
1104 xProps
->getPropertyValue("CircleEndAngle") >>= nEndAngleIntern
;
1106 std::vector
< std::pair
<sal_Int32
,sal_Int32
>> aAvList
;
1107 awt::Size aSize
= xShape
->getSize();
1108 if (aSize
.Width
!= 0 || aSize
.Height
!= 0)
1110 // Our arc has 90° up, OOXML has 90° down, so mirror it.
1111 // API angles are 1/100 degree.
1112 sal_Int32
nStartAngleOOXML(lcl_CircleAngle2CustomShapeEllipseAngleOOX(36000 - nEndAngleIntern
, aSize
.Width
, aSize
.Height
));
1113 sal_Int32
nEndAngleOOXML(lcl_CircleAngle2CustomShapeEllipseAngleOOX(36000 - nStartAngleIntern
, aSize
.Width
, aSize
.Height
));
1114 lcl_AppendAdjustmentValue( aAvList
, 1, nStartAngleOOXML
);
1115 lcl_AppendAdjustmentValue( aAvList
, 2, nEndAngleOOXML
);
1117 switch (eCircleKind
)
1119 case CircleKind_ARC
:
1120 WritePresetShape("arc", aAvList
);
1122 case CircleKind_SECTION
:
1123 WritePresetShape("pie", aAvList
);
1125 case CircleKind_CUT
:
1126 WritePresetShape("chord", aAvList
);
1129 WritePresetShape("ellipse");
1134 if (CircleKind_ARC
== eCircleKind
)
1136 // An arc in ODF is never filled, even if a fill style other than
1137 // "none" is set. OOXML arc can be filled, so set fill explicit to
1138 // NONE, otherwise some hidden or inherited filling is shown.
1139 FillStyle
eFillStyle(FillStyle_NONE
);
1141 aNewValue
<<= eFillStyle
;
1142 xProps
->setPropertyValue("FillStyle", aNewValue
);
1144 WriteFill( xProps
);
1145 WriteOutline( xProps
);
1147 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1150 WriteTextBox( xShape
, mnXmlNamespace
);
1152 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
) );
1157 ShapeExport
& ShapeExport::WriteGraphicObjectShape( const Reference
< XShape
>& xShape
)
1159 WriteGraphicObjectShapePart( xShape
);
1164 void ShapeExport::WriteGraphicObjectShapePart( const Reference
< XShape
>& xShape
, const Graphic
* pGraphic
)
1166 SAL_INFO("oox.shape", "write graphic object shape");
1168 if( NonEmptyText( xShape
) )
1170 // avoid treating all 'IsPresentationObject' objects as having text.
1171 Reference
< XSimpleText
> xText( xShape
, UNO_QUERY
);
1173 if( xText
.is() && !xText
->getString().isEmpty() )
1175 SAL_INFO("oox.shape", "graphicObject: wrote only text");
1177 WriteTextShape( xShape
);
1183 SAL_INFO("oox.shape", "graphicObject without text");
1185 uno::Reference
<graphic::XGraphic
> xGraphic
;
1188 Reference
< XPropertySet
> xShapeProps( xShape
, UNO_QUERY
);
1192 xGraphic
.set(pGraphic
->GetXGraphic());
1194 else if (xShapeProps
.is() && xShapeProps
->getPropertySetInfo()->hasPropertyByName("Graphic"))
1196 xShapeProps
->getPropertyValue("Graphic") >>= xGraphic
;
1199 bool bHasMediaURL
= xShapeProps
.is() && xShapeProps
->getPropertySetInfo()->hasPropertyByName("MediaURL") && (xShapeProps
->getPropertyValue("MediaURL") >>= sMediaURL
);
1201 if (!xGraphic
.is() && !bHasMediaURL
)
1203 SAL_INFO("oox.shape", "no graphic or media URL found");
1207 FSHelperPtr pFS
= GetFS();
1208 XmlFilterBase
* pFB
= GetFB();
1210 if (GetDocumentType() != DOCUMENT_DOCX
)
1211 pFS
->startElementNS(mnXmlNamespace
, XML_pic
);
1213 pFS
->startElementNS(mnXmlNamespace
, XML_pic
,
1214 FSNS(XML_xmlns
, XML_pic
), pFB
->getNamespaceURL(OOX_NS(dmlPicture
)).toUtf8());
1216 pFS
->startElementNS(mnXmlNamespace
, XML_nvPicPr
);
1218 OUString sName
, sDescr
, sURL
;
1219 bool bHaveName
, bHaveDesc
, bHaveURL
;
1221 if ( ( bHaveName
= GetProperty( xShapeProps
, "Name" ) ) )
1223 if ( ( bHaveDesc
= GetProperty( xShapeProps
, "Description" ) ) )
1225 if ( ( bHaveURL
= GetProperty( xShapeProps
, "URL" ) ) )
1228 pFS
->startElementNS( mnXmlNamespace
, XML_cNvPr
,
1229 XML_id
, OString::number(GetNewShapeID(xShape
)),
1232 : OString("Picture " + OString::number(mnPictureIdMax
++)),
1233 XML_descr
, bHaveDesc
? sDescr
.toUtf8().getStr() : nullptr );
1235 // OOXTODO: //cNvPr children: XML_extLst, XML_hlinkHover
1237 pFS
->singleElementNS(XML_a
, XML_hlinkClick
,
1238 FSNS(XML_r
, XML_id
), "",
1239 XML_action
, "ppaction://media");
1240 if( !sURL
.isEmpty() )
1242 OUString sRelId
= mpFB
->addRelation( mpFS
->getOutputStream(),
1243 oox::getRelationship(Relationship::HYPERLINK
),
1244 mpURLTransformer
->getTransformedString(sURL
),
1245 mpURLTransformer
->isExternalURL(sURL
));
1247 mpFS
->singleElementNS(XML_a
, XML_hlinkClick
, FSNS(XML_r
, XML_id
), sRelId
.toUtf8());
1249 pFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
1251 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvPicPr
1252 // OOXTODO: XML_preferRelativeSize
1255 WriteMediaNonVisualProperties(xShape
);
1257 WriteNonVisualProperties(xShape
);
1259 pFS
->endElementNS( mnXmlNamespace
, XML_nvPicPr
);
1261 pFS
->startElementNS(mnXmlNamespace
, XML_blipFill
);
1265 WriteXGraphicBlip(xShapeProps
, xGraphic
, false);
1267 else if (bHasMediaURL
)
1269 Reference
<graphic::XGraphic
> xFallbackGraphic
;
1270 if (xShapeProps
->getPropertySetInfo()->hasPropertyByName("FallbackGraphic"))
1271 xShapeProps
->getPropertyValue("FallbackGraphic") >>= xFallbackGraphic
;
1273 WriteXGraphicBlip(xShapeProps
, xFallbackGraphic
, false);
1278 WriteSrcRectXGraphic(xShapeProps
, xGraphic
);
1281 // now we stretch always when we get pGraphic (when changing that
1282 // behavior, test n#780830 for regression, where the OLE sheet might get tiled
1283 bool bStretch
= false;
1284 if( !pGraphic
&& GetProperty( xShapeProps
, "FillBitmapStretch" ) )
1287 if ( pGraphic
|| bStretch
)
1288 pFS
->singleElementNS(XML_a
, XML_stretch
);
1290 pFS
->endElementNS( mnXmlNamespace
, XML_blipFill
);
1292 // visual shape properties
1293 pFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
1294 bool bFlipH
= false;
1295 if( xShapeProps
->getPropertySetInfo()->hasPropertyByName("IsMirrored") )
1297 xShapeProps
->getPropertyValue("IsMirrored") >>= bFlipH
;
1299 WriteShapeTransformation( xShape
, XML_a
, bFlipH
, false, false, false, true );
1300 WritePresetShape( "rect" );
1301 // graphic object can come with the frame (bnc#654525)
1302 WriteOutline( xShapeProps
);
1304 WriteShapeEffects( xShapeProps
);
1305 WriteShape3DEffects( xShapeProps
);
1307 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1309 pFS
->endElementNS( mnXmlNamespace
, XML_pic
);
1312 ShapeExport
& ShapeExport::WriteConnectorShape( const Reference
< XShape
>& xShape
)
1314 bool bFlipH
= false;
1315 bool bFlipV
= false;
1317 SAL_INFO("oox.shape", "write connector shape");
1319 FSHelperPtr pFS
= GetFS();
1321 const char* sGeometry
= "line";
1322 Reference
< XPropertySet
> rXPropSet( xShape
, UNO_QUERY
);
1323 Reference
< XPropertyState
> rXPropState( xShape
, UNO_QUERY
);
1324 awt::Point aStartPoint
, aEndPoint
;
1325 Reference
< XShape
> rXShapeA
;
1326 Reference
< XShape
> rXShapeB
;
1327 PropertyState eState
;
1328 ConnectorType eConnectorType
;
1329 if( GETAD( EdgeKind
) ) {
1330 mAny
>>= eConnectorType
;
1332 switch( eConnectorType
) {
1333 case ConnectorType_CURVE
:
1334 sGeometry
= "curvedConnector3";
1336 case ConnectorType_STANDARD
:
1337 sGeometry
= "bentConnector3";
1340 case ConnectorType_LINE
:
1341 case ConnectorType_LINES
:
1342 sGeometry
= "straightConnector1";
1346 if( GETAD( EdgeStartPoint
) ) {
1347 mAny
>>= aStartPoint
;
1348 if( GETAD( EdgeEndPoint
) ) {
1352 GET( rXShapeA
, EdgeStartConnection
);
1353 GET( rXShapeB
, EdgeEndConnection
);
1355 EscherConnectorListEntry
aConnectorEntry( xShape
, aStartPoint
, rXShapeA
, aEndPoint
, rXShapeB
);
1357 tools::Rectangle
aRect( Point( aStartPoint
.X
, aStartPoint
.Y
), Point( aEndPoint
.X
, aEndPoint
.Y
) );
1358 if( aRect
.getWidth() < 0 ) {
1360 aRect
.setX( aEndPoint
.X
);
1361 aRect
.setWidth( aStartPoint
.X
- aEndPoint
.X
);
1364 if( aRect
.getHeight() < 0 ) {
1366 aRect
.setY( aEndPoint
.Y
);
1367 aRect
.setHeight( aStartPoint
.Y
- aEndPoint
.Y
);
1370 pFS
->startElementNS(mnXmlNamespace
, XML_cxnSp
);
1372 // non visual shape properties
1373 pFS
->startElementNS(mnXmlNamespace
, XML_nvCxnSpPr
);
1374 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
1375 XML_id
, OString::number(GetNewShapeID(xShape
)),
1376 XML_name
, IDS( Line
) );
1377 // non visual connector shape drawing properties
1378 pFS
->startElementNS(mnXmlNamespace
, XML_cNvCxnSpPr
);
1379 WriteConnectorConnections( aConnectorEntry
, GetShapeID( rXShapeA
), GetShapeID( rXShapeB
) );
1380 pFS
->endElementNS( mnXmlNamespace
, XML_cNvCxnSpPr
);
1381 pFS
->singleElementNS(mnXmlNamespace
, XML_nvPr
);
1382 pFS
->endElementNS( mnXmlNamespace
, XML_nvCxnSpPr
);
1384 // visual shape properties
1385 pFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
1386 WriteTransformation( aRect
, XML_a
, bFlipH
, bFlipV
);
1387 // TODO: write adjustments (ppt export doesn't work well there either)
1388 WritePresetShape( sGeometry
);
1389 Reference
< XPropertySet
> xShapeProps( xShape
, UNO_QUERY
);
1390 if( xShapeProps
.is() )
1391 WriteOutline( xShapeProps
);
1392 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1395 WriteTextBox( xShape
, mnXmlNamespace
);
1397 pFS
->endElementNS( mnXmlNamespace
, XML_cxnSp
);
1402 ShapeExport
& ShapeExport::WriteLineShape( const Reference
< XShape
>& xShape
)
1404 bool bFlipH
= false;
1405 bool bFlipV
= false;
1407 SAL_INFO("oox.shape", "write line shape");
1409 FSHelperPtr pFS
= GetFS();
1411 pFS
->startElementNS(mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
));
1413 tools::PolyPolygon aPolyPolygon
= EscherPropertyContainer::GetPolyPolygon( xShape
);
1414 if( aPolyPolygon
.Count() == 1 && aPolyPolygon
[ 0 ].GetSize() == 2)
1416 const tools::Polygon
& rPoly
= aPolyPolygon
[ 0 ];
1418 bFlipH
= ( rPoly
[ 0 ].X() > rPoly
[ 1 ].X() );
1419 bFlipV
= ( rPoly
[ 0 ].Y() > rPoly
[ 1 ].Y() );
1422 // non visual shape properties
1423 if (GetDocumentType() != DOCUMENT_DOCX
)
1425 pFS
->startElementNS(mnXmlNamespace
, XML_nvSpPr
);
1426 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
1427 XML_id
, OString::number(GetNewShapeID(xShape
)),
1428 XML_name
, IDS( Line
) );
1430 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvSpPr
);
1431 if (GetDocumentType() != DOCUMENT_DOCX
)
1433 WriteNonVisualProperties( xShape
);
1434 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
1437 // visual shape properties
1438 pFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
1439 WriteShapeTransformation( xShape
, XML_a
, bFlipH
, bFlipV
, true);
1440 WritePresetShape( "line" );
1441 Reference
< XPropertySet
> xShapeProps( xShape
, UNO_QUERY
);
1442 if( xShapeProps
.is() )
1443 WriteOutline( xShapeProps
);
1444 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1447 pFS
->startElementNS(mnXmlNamespace
, XML_style
);
1448 WriteShapeStyle( xShapeProps
);
1449 pFS
->endElementNS( mnXmlNamespace
, XML_style
);
1452 WriteTextBox( xShape
, mnXmlNamespace
);
1454 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
) );
1459 ShapeExport
& ShapeExport::WriteNonVisualDrawingProperties( const Reference
< XShape
>& xShape
, const char* pName
)
1461 GetFS()->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
1462 XML_id
, OString::number(GetNewShapeID(xShape
)),
1468 ShapeExport
& ShapeExport::WriteNonVisualProperties( const Reference
< XShape
>& )
1470 // Override to generate //nvPr elements.
1474 ShapeExport
& ShapeExport::WriteRectangleShape( const Reference
< XShape
>& xShape
)
1476 SAL_INFO("oox.shape", "write rectangle shape");
1478 FSHelperPtr pFS
= GetFS();
1480 pFS
->startElementNS(mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
));
1482 sal_Int32 nRadius
= 0;
1484 Reference
< XPropertySet
> xShapeProps( xShape
, UNO_QUERY
);
1485 if( xShapeProps
.is() )
1487 xShapeProps
->getPropertyValue( "CornerRadius" ) >>= nRadius
;
1492 nRadius
= MapSize( awt::Size( nRadius
, 0 ) ).Width
;
1494 //TODO: use nRadius value more precisely than just deciding whether to use
1495 // "rect" or "roundRect" preset shape below
1497 // non visual shape properties
1498 if (GetDocumentType() == DOCUMENT_DOCX
)
1499 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
);
1500 pFS
->startElementNS(mnXmlNamespace
, XML_nvSpPr
);
1501 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
1502 XML_id
, OString::number(GetNewShapeID(xShape
)),
1503 XML_name
, IDS( Rectangle
) );
1504 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
);
1505 WriteNonVisualProperties( xShape
);
1506 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
1508 // visual shape properties
1509 pFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
1510 WriteShapeTransformation( xShape
, XML_a
);
1511 WritePresetShape( nRadius
== 0 ? "rect" : "roundRect" );
1512 Reference
< XPropertySet
> xProps( xShape
, UNO_QUERY
);
1515 WriteFill( xProps
);
1516 WriteOutline( xProps
);
1518 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1521 WriteTextBox( xShape
, mnXmlNamespace
);
1523 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
) );
1528 typedef ShapeExport
& (ShapeExport::*ShapeConverter
)( const Reference
< XShape
>& );
1529 typedef std::unordered_map
< const char*, ShapeConverter
, rtl::CStringHash
, rtl::CStringEqual
> NameToConvertMapType
;
1531 static const NameToConvertMapType
& lcl_GetConverters()
1533 static NameToConvertMapType
const shape_converters
1535 { "com.sun.star.drawing.ClosedBezierShape" , &ShapeExport::WriteClosedPolyPolygonShape
},
1536 { "com.sun.star.drawing.ConnectorShape" , &ShapeExport::WriteConnectorShape
},
1537 { "com.sun.star.drawing.CustomShape" , &ShapeExport::WriteCustomShape
},
1538 { "com.sun.star.drawing.EllipseShape" , &ShapeExport::WriteEllipseShape
},
1539 { "com.sun.star.drawing.GraphicObjectShape" , &ShapeExport::WriteGraphicObjectShape
},
1540 { "com.sun.star.drawing.LineShape" , &ShapeExport::WriteLineShape
},
1541 { "com.sun.star.drawing.OpenBezierShape" , &ShapeExport::WriteOpenPolyPolygonShape
},
1542 { "com.sun.star.drawing.PolyPolygonShape" , &ShapeExport::WriteClosedPolyPolygonShape
},
1543 { "com.sun.star.drawing.PolyLineShape" , &ShapeExport::WriteOpenPolyPolygonShape
},
1544 { "com.sun.star.drawing.RectangleShape" , &ShapeExport::WriteRectangleShape
},
1545 { "com.sun.star.drawing.OLE2Shape" , &ShapeExport::WriteOLE2Shape
},
1546 { "com.sun.star.drawing.TableShape" , &ShapeExport::WriteTableShape
},
1547 { "com.sun.star.drawing.TextShape" , &ShapeExport::WriteTextShape
},
1548 { "com.sun.star.drawing.GroupShape" , &ShapeExport::WriteGroupShape
},
1550 { "com.sun.star.presentation.GraphicObjectShape" , &ShapeExport::WriteGraphicObjectShape
},
1551 { "com.sun.star.presentation.MediaShape" , &ShapeExport::WriteGraphicObjectShape
},
1552 { "com.sun.star.presentation.OLE2Shape" , &ShapeExport::WriteOLE2Shape
},
1553 { "com.sun.star.presentation.TableShape" , &ShapeExport::WriteTableShape
},
1554 { "com.sun.star.presentation.TextShape" , &ShapeExport::WriteTextShape
},
1556 { "com.sun.star.presentation.DateTimeShape" , &ShapeExport::WriteTextShape
},
1557 { "com.sun.star.presentation.FooterShape" , &ShapeExport::WriteTextShape
},
1558 { "com.sun.star.presentation.HeaderShape" , &ShapeExport::WriteTextShape
},
1559 { "com.sun.star.presentation.NotesShape" , &ShapeExport::WriteTextShape
},
1560 { "com.sun.star.presentation.OutlinerShape" , &ShapeExport::WriteTextShape
},
1561 { "com.sun.star.presentation.SlideNumberShape" , &ShapeExport::WriteTextShape
},
1562 { "com.sun.star.presentation.TitleTextShape" , &ShapeExport::WriteTextShape
},
1564 return shape_converters
;
1567 ShapeExport
& ShapeExport::WriteShape( const Reference
< XShape
>& xShape
)
1569 OUString sShapeType
= xShape
->getShapeType();
1570 SAL_INFO("oox.shape", "write shape: " << sShapeType
);
1571 NameToConvertMapType::const_iterator aConverter
1572 = lcl_GetConverters().find(sShapeType
.toUtf8().getStr());
1573 if (aConverter
== lcl_GetConverters().end())
1575 SAL_INFO("oox.shape", "unknown shape");
1576 return WriteUnknownShape( xShape
);
1578 (this->*(aConverter
->second
))( xShape
);
1583 ShapeExport
& ShapeExport::WriteTextBox( const Reference
< XInterface
>& xIface
, sal_Int32 nXmlNamespace
)
1585 // In case this shape has an associated textbox, then export that, and we're done.
1586 if (GetDocumentType() == DOCUMENT_DOCX
&& GetTextExport())
1588 uno::Reference
<beans::XPropertySet
> xPropertySet(xIface
, uno::UNO_QUERY
);
1589 if (xPropertySet
.is())
1591 uno::Reference
<beans::XPropertySetInfo
> xPropertySetInfo
= xPropertySet
->getPropertySetInfo();
1592 if (xPropertySetInfo
->hasPropertyByName("TextBox") && xPropertySet
->getPropertyValue("TextBox").get
<bool>())
1594 GetTextExport()->WriteTextBox(uno::Reference
<drawing::XShape
>(xIface
, uno::UNO_QUERY_THROW
));
1595 WriteText( xIface
, m_presetWarp
, /*bBodyPr=*/true, /*bText=*/false, /*nXmlNamespace=*/nXmlNamespace
);
1601 Reference
< XText
> xXText( xIface
, UNO_QUERY
);
1602 if( NonEmptyText( xIface
) && xXText
.is() )
1604 FSHelperPtr pFS
= GetFS();
1606 pFS
->startElementNS(nXmlNamespace
,
1607 (GetDocumentType() != DOCUMENT_DOCX
? XML_txBody
: XML_txbx
));
1608 WriteText( xIface
, m_presetWarp
, /*bBodyPr=*/(GetDocumentType() != DOCUMENT_DOCX
) );
1609 pFS
->endElementNS( nXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_txBody
: XML_txbx
) );
1610 if (GetDocumentType() == DOCUMENT_DOCX
)
1611 WriteText( xIface
, m_presetWarp
, /*bBodyPr=*/true, /*bText=*/false, /*nXmlNamespace=*/nXmlNamespace
);
1613 else if (GetDocumentType() == DOCUMENT_DOCX
)
1614 mpFS
->singleElementNS(nXmlNamespace
, XML_bodyPr
);
1619 void ShapeExport::WriteTable( const Reference
< XShape
>& rXShape
)
1621 Reference
< XTable
> xTable
;
1622 Reference
< XPropertySet
> xPropSet( rXShape
, UNO_QUERY
);
1624 mpFS
->startElementNS(XML_a
, XML_graphic
);
1625 mpFS
->startElementNS(XML_a
, XML_graphicData
,
1626 XML_uri
, "http://schemas.openxmlformats.org/drawingml/2006/table");
1628 if ( xPropSet
.is() && ( xPropSet
->getPropertyValue( "Model" ) >>= xTable
) )
1630 mpFS
->startElementNS(XML_a
, XML_tbl
);
1631 mpFS
->singleElementNS(XML_a
, XML_tblPr
);
1633 Reference
< container::XIndexAccess
> xColumns( xTable
->getColumns(), UNO_QUERY_THROW
);
1634 Reference
< container::XIndexAccess
> xRows( xTable
->getRows(), UNO_QUERY_THROW
);
1635 sal_uInt16 nRowCount
= static_cast< sal_uInt16
>( xRows
->getCount() );
1636 sal_uInt16 nColumnCount
= static_cast< sal_uInt16
>( xColumns
->getCount() );
1638 mpFS
->startElementNS(XML_a
, XML_tblGrid
);
1640 for ( sal_Int32 x
= 0; x
< nColumnCount
; x
++ )
1642 Reference
< XPropertySet
> xColPropSet( xColumns
->getByIndex( x
), UNO_QUERY_THROW
);
1643 sal_Int32
nWidth(0);
1644 xColPropSet
->getPropertyValue( "Width" ) >>= nWidth
;
1646 mpFS
->singleElementNS(XML_a
, XML_gridCol
,
1647 XML_w
, OString::number(oox::drawingml::convertHmmToEmu(nWidth
)));
1650 mpFS
->endElementNS( XML_a
, XML_tblGrid
);
1652 // map for holding the transpose index of the merged cells and pair<parentTransposeIndex, parentCell>
1653 typedef std::unordered_map
<sal_Int32
, std::pair
<sal_Int32
, Reference
< XMergeableCell
> > > transposeTableMap
;
1654 transposeTableMap mergedCellMap
;
1656 for( sal_Int32 nRow
= 0; nRow
< nRowCount
; nRow
++ )
1658 Reference
< XPropertySet
> xRowPropSet( xRows
->getByIndex( nRow
), UNO_QUERY_THROW
);
1659 sal_Int32
nRowHeight(0);
1661 xRowPropSet
->getPropertyValue( "Height" ) >>= nRowHeight
;
1663 mpFS
->startElementNS(XML_a
, XML_tr
,
1664 XML_h
, OString::number(oox::drawingml::convertHmmToEmu(nRowHeight
)));
1665 for( sal_Int32 nColumn
= 0; nColumn
< nColumnCount
; nColumn
++ )
1667 Reference
< XMergeableCell
> xCell( xTable
->getCellByPosition( nColumn
, nRow
),
1669 sal_Int32 transposedIndexofCell
= (nRow
* nColumnCount
) + nColumn
;
1671 //assume we will open a cell, set to false below if we won't
1672 bool bCellOpened
= true;
1674 if(xCell
->getColumnSpan() > 1 && xCell
->getRowSpan() > 1)
1676 // having both : horizontal and vertical merge
1677 mpFS
->startElementNS(XML_a
, XML_tc
,
1678 XML_gridSpan
, OString::number(xCell
->getColumnSpan()),
1679 XML_rowSpan
, OString::number(xCell
->getRowSpan()));
1680 // since, XMergeableCell doesn't have the information about
1681 // cell having hMerge or vMerge.
1682 // So, Populating the merged cell map in-order to use it to
1683 // decide the attribute for the individual cell.
1684 for(sal_Int32 columnIndex
= nColumn
; columnIndex
< nColumn
+xCell
->getColumnSpan(); ++columnIndex
)
1686 for(sal_Int32 rowIndex
= nRow
; rowIndex
< nRow
+xCell
->getRowSpan(); ++rowIndex
)
1688 sal_Int32 transposeIndexForMergeCell
=
1689 (rowIndex
* nColumnCount
) + columnIndex
;
1690 mergedCellMap
[transposeIndexForMergeCell
] =
1691 std::make_pair(transposedIndexofCell
, xCell
);
1696 else if(xCell
->getColumnSpan() > 1)
1698 // having : horizontal merge
1699 mpFS
->startElementNS(XML_a
, XML_tc
,
1700 XML_gridSpan
, OString::number(xCell
->getColumnSpan()));
1701 for(sal_Int32 columnIndex
= nColumn
; columnIndex
< nColumn
+ xCell
->getColumnSpan(); ++columnIndex
) {
1702 sal_Int32 transposeIndexForMergeCell
= (nRow
*nColumnCount
) + columnIndex
;
1703 mergedCellMap
[transposeIndexForMergeCell
] =
1704 std::make_pair(transposedIndexofCell
, xCell
);
1707 else if(xCell
->getRowSpan() > 1)
1709 // having : vertical merge
1710 mpFS
->startElementNS(XML_a
, XML_tc
,
1711 XML_rowSpan
, OString::number(xCell
->getRowSpan()));
1713 for(sal_Int32 rowIndex
= nRow
; rowIndex
< nRow
+ xCell
->getRowSpan(); ++rowIndex
) {
1714 sal_Int32 transposeIndexForMergeCell
= (rowIndex
*nColumnCount
) + nColumn
;
1715 mergedCellMap
[transposeIndexForMergeCell
] =
1716 std::make_pair(transposedIndexofCell
, xCell
);
1721 // now, the cell can be an independent cell or
1722 // it can be a cell which is been merged to some parent cell
1723 if(!xCell
->isMerged())
1726 mpFS
->startElementNS(XML_a
, XML_tc
);
1730 // it a merged cell to some parent cell
1731 // find the parent cell for the current cell at hand
1732 transposeTableMap::iterator it
= mergedCellMap
.find(transposedIndexofCell
);
1733 if(it
!= mergedCellMap
.end())
1735 sal_Int32 transposeIndexOfParent
= it
->second
.first
;
1736 Reference
< XMergeableCell
> parentCell
= it
->second
.second
;
1737 // finding the row and column index for the parent cell from transposed index
1738 sal_Int32 parentColumnIndex
= transposeIndexOfParent
% nColumnCount
;
1739 sal_Int32 parentRowIndex
= transposeIndexOfParent
/ nColumnCount
;
1740 if(nColumn
== parentColumnIndex
)
1742 // the cell is vertical merge and it might have gridspan
1743 if(parentCell
->getColumnSpan() > 1)
1745 // vMerge and has gridSpan
1746 mpFS
->startElementNS(XML_a
, XML_tc
,
1747 XML_vMerge
, OString::number(1),
1748 XML_gridSpan
, OString::number(xCell
->getColumnSpan()));
1753 mpFS
->startElementNS(XML_a
, XML_tc
,
1754 XML_vMerge
, OString::number(1));
1757 else if(nRow
== parentRowIndex
)
1759 // the cell is horizontal merge and it might have rowspan
1760 if(parentCell
->getRowSpan() > 1)
1762 // hMerge and has rowspan
1763 mpFS
->startElementNS(XML_a
, XML_tc
,
1764 XML_hMerge
, OString::number(1),
1765 XML_rowSpan
, OString::number(xCell
->getRowSpan()));
1770 mpFS
->startElementNS(XML_a
, XML_tc
,
1771 XML_hMerge
, OString::number(1));
1776 // has hMerge and vMerge
1777 mpFS
->startElementNS(XML_a
, XML_tc
,
1778 XML_vMerge
, OString::number(1),
1779 XML_hMerge
, OString::number(1));
1783 bCellOpened
= false;
1789 WriteTextBox( xCell
, XML_a
);
1791 Reference
< XPropertySet
> xCellPropSet(xCell
, UNO_QUERY_THROW
);
1792 WriteTableCellProperties(xCellPropSet
);
1794 mpFS
->endElementNS( XML_a
, XML_tc
);
1798 mpFS
->endElementNS( XML_a
, XML_tr
);
1801 mpFS
->endElementNS( XML_a
, XML_tbl
);
1804 mpFS
->endElementNS( XML_a
, XML_graphicData
);
1805 mpFS
->endElementNS( XML_a
, XML_graphic
);
1808 void ShapeExport::WriteTableCellProperties(const Reference
< XPropertySet
>& xCellPropSet
)
1810 sal_Int32
nLeftMargin(0), nRightMargin(0);
1812 Any aLeftMargin
= xCellPropSet
->getPropertyValue("TextLeftDistance");
1813 aLeftMargin
>>= nLeftMargin
;
1815 Any aRightMargin
= xCellPropSet
->getPropertyValue("TextRightDistance");
1816 aRightMargin
>>= nRightMargin
;
1818 mpFS
->startElementNS(XML_a
, XML_tcPr
,
1819 XML_marL
, nLeftMargin
> 0 ? OString::number(oox::drawingml::convertHmmToEmu(nLeftMargin
)).getStr() : nullptr,
1820 XML_marR
, nRightMargin
> 0 ? OString::number(oox::drawingml::convertHmmToEmu(nRightMargin
)).getStr() : nullptr);
1822 // Write background fill for table cell.
1824 // tcW : Table cell width
1825 WriteTableCellBorders(xCellPropSet
);
1826 DrawingML::WriteFill(xCellPropSet
);
1827 mpFS
->endElementNS( XML_a
, XML_tcPr
);
1830 void ShapeExport::WriteBorderLine(const sal_Int32 XML_line
, const BorderLine2
& rBorderLine
)
1832 // While importing the table cell border line width, it converts EMU->Hmm then divided result by 2.
1833 // To get original value of LineWidth need to multiple by 2.
1834 sal_Int32 nBorderWidth
= rBorderLine
.LineWidth
;
1836 nBorderWidth
= oox::drawingml::convertHmmToEmu( nBorderWidth
);
1838 if ( nBorderWidth
> 0 )
1840 mpFS
->startElementNS(XML_a
, XML_line
, XML_w
, OString::number(nBorderWidth
));
1841 if ( rBorderLine
.Color
== sal_Int32( COL_AUTO
) )
1842 mpFS
->singleElementNS(XML_a
, XML_noFill
);
1844 DrawingML::WriteSolidFill( ::Color(rBorderLine
.Color
) );
1845 mpFS
->endElementNS( XML_a
, XML_line
);
1849 void ShapeExport::WriteTableCellBorders(const Reference
< XPropertySet
>& xCellPropSet
)
1851 BorderLine2 aBorderLine
;
1853 // lnL - Left Border Line Properties of table cell
1854 xCellPropSet
->getPropertyValue("LeftBorder") >>= aBorderLine
;
1855 WriteBorderLine( XML_lnL
, aBorderLine
);
1857 // lnR - Right Border Line Properties of table cell
1858 xCellPropSet
->getPropertyValue("RightBorder") >>= aBorderLine
;
1859 WriteBorderLine( XML_lnR
, aBorderLine
);
1861 // lnT - Top Border Line Properties of table cell
1862 xCellPropSet
->getPropertyValue("TopBorder") >>= aBorderLine
;
1863 WriteBorderLine( XML_lnT
, aBorderLine
);
1865 // lnB - Bottom Border Line Properties of table cell
1866 xCellPropSet
->getPropertyValue("BottomBorder") >>= aBorderLine
;
1867 WriteBorderLine( XML_lnB
, aBorderLine
);
1870 ShapeExport
& ShapeExport::WriteTableShape( const Reference
< XShape
>& xShape
)
1872 FSHelperPtr pFS
= GetFS();
1874 pFS
->startElementNS(mnXmlNamespace
, XML_graphicFrame
);
1876 pFS
->startElementNS(mnXmlNamespace
, XML_nvGraphicFramePr
);
1878 pFS
->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
1879 XML_id
, OString::number(GetNewShapeID(xShape
)),
1880 XML_name
, IDS(Table
) );
1882 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvGraphicFramePr
);
1884 if( GetDocumentType() == DOCUMENT_PPTX
)
1885 pFS
->singleElementNS(mnXmlNamespace
, XML_nvPr
);
1886 pFS
->endElementNS( mnXmlNamespace
, XML_nvGraphicFramePr
);
1888 WriteShapeTransformation( xShape
, mnXmlNamespace
);
1889 WriteTable( xShape
);
1891 pFS
->endElementNS( mnXmlNamespace
, XML_graphicFrame
);
1896 ShapeExport
& ShapeExport::WriteTextShape( const Reference
< XShape
>& xShape
)
1898 bool bIsFontworkShape(m_presetWarp
.startsWith("text") && m_presetWarp
!= "textNoShape");
1899 FSHelperPtr pFS
= GetFS();
1900 Reference
<XPropertySet
> xShapeProps(xShape
, UNO_QUERY
);
1901 pFS
->startElementNS(mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
));
1903 // non visual shape properties
1904 if (GetDocumentType() != DOCUMENT_DOCX
)
1906 pFS
->startElementNS(mnXmlNamespace
, XML_nvSpPr
);
1907 pFS
->startElementNS(mnXmlNamespace
, XML_cNvPr
,
1908 XML_id
, OString::number(GetNewShapeID(xShape
)),
1909 XML_name
, IDS(TextShape
));
1911 if (GetProperty(xShapeProps
, "URL"))
1914 if (!sURL
.isEmpty())
1916 OUString sRelId
= mpFB
->addRelation(mpFS
->getOutputStream(),
1917 oox::getRelationship(Relationship::HYPERLINK
),
1918 mpURLTransformer
->getTransformedString(sURL
),
1919 mpURLTransformer
->isExternalURL(sURL
));
1921 mpFS
->singleElementNS(XML_a
, XML_hlinkClick
, FSNS(XML_r
, XML_id
), sRelId
.toUtf8());
1923 pFS
->endElementNS(mnXmlNamespace
, XML_cNvPr
);
1925 pFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
, XML_txBox
, "1");
1926 if (GetDocumentType() != DOCUMENT_DOCX
)
1928 WriteNonVisualProperties( xShape
);
1929 pFS
->endElementNS( mnXmlNamespace
, XML_nvSpPr
);
1932 // visual shape properties
1933 pFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
1934 WriteShapeTransformation( xShape
, XML_a
);
1935 WritePresetShape( "rect" );
1936 uno::Reference
<beans::XPropertySet
> xPropertySet(xShape
, UNO_QUERY
);
1937 if (!bIsFontworkShape
) // Fontwork needs fill and outline on char instead.
1939 WriteBlipOrNormalFill(xPropertySet
, "Graphic");
1940 WriteOutline(xPropertySet
);
1942 WriteShapeEffects(xPropertySet
);
1943 pFS
->endElementNS( mnXmlNamespace
, XML_spPr
);
1945 WriteTextBox( xShape
, mnXmlNamespace
);
1947 pFS
->endElementNS( mnXmlNamespace
, (GetDocumentType() != DOCUMENT_DOCX
? XML_sp
: XML_wsp
) );
1952 void ShapeExport::WriteMathShape(Reference
<XShape
> const& xShape
)
1954 Reference
<XPropertySet
> const xPropSet(xShape
, UNO_QUERY
);
1955 assert(xPropSet
.is());
1956 Reference
<XModel
> xMathModel
;
1957 xPropSet
->getPropertyValue("Model") >>= xMathModel
;
1958 assert(xMathModel
.is());
1959 assert(GetDocumentType() != DOCUMENT_DOCX
); // should be written in DocxAttributeOutput
1960 SAL_WARN_IF(GetDocumentType() == DOCUMENT_XLSX
, "oox.shape", "Math export to XLSX isn't tested, should it happen here?");
1962 // ECMA standard does not actually allow oMath outside of
1963 // WordProcessingML so write a MCE like PPT 2010 does
1964 mpFS
->startElementNS(XML_mc
, XML_AlternateContent
);
1965 mpFS
->startElementNS(XML_mc
, XML_Choice
,
1966 FSNS(XML_xmlns
, XML_a14
), mpFB
->getNamespaceURL(OOX_NS(a14
)).toUtf8(),
1967 XML_Requires
, "a14");
1968 mpFS
->startElementNS(mnXmlNamespace
, XML_sp
);
1969 mpFS
->startElementNS(mnXmlNamespace
, XML_nvSpPr
);
1970 mpFS
->singleElementNS(mnXmlNamespace
, XML_cNvPr
,
1971 XML_id
, OString::number(GetNewShapeID(xShape
)),
1972 XML_name
, IDS(Formula
));
1973 mpFS
->singleElementNS(mnXmlNamespace
, XML_cNvSpPr
, XML_txBox
, "1");
1974 mpFS
->singleElementNS(mnXmlNamespace
, XML_nvPr
);
1975 mpFS
->endElementNS(mnXmlNamespace
, XML_nvSpPr
);
1976 mpFS
->startElementNS(mnXmlNamespace
, XML_spPr
);
1977 WriteShapeTransformation(xShape
, XML_a
);
1978 WritePresetShape("rect");
1979 mpFS
->endElementNS(mnXmlNamespace
, XML_spPr
);
1980 mpFS
->startElementNS(mnXmlNamespace
, XML_txBody
);
1981 mpFS
->startElementNS(XML_a
, XML_bodyPr
);
1982 mpFS
->endElementNS(XML_a
, XML_bodyPr
);
1983 mpFS
->startElementNS(XML_a
, XML_p
);
1984 mpFS
->startElementNS(XML_a14
, XML_m
);
1986 oox::FormulaExportBase
*const pMagic(dynamic_cast<oox::FormulaExportBase
*>(xMathModel
.get()));
1988 pMagic
->writeFormulaOoxml(GetFS(), GetFB()->getVersion(), GetDocumentType());
1990 mpFS
->endElementNS(XML_a14
, XML_m
);
1991 mpFS
->endElementNS(XML_a
, XML_p
);
1992 mpFS
->endElementNS(mnXmlNamespace
, XML_txBody
);
1993 mpFS
->endElementNS(mnXmlNamespace
, XML_sp
);
1994 mpFS
->endElementNS(XML_mc
, XML_Choice
);
1995 mpFS
->startElementNS(XML_mc
, XML_Fallback
);
1996 // TODO: export bitmap shape as fallback
1997 mpFS
->endElementNS(XML_mc
, XML_Fallback
);
1998 mpFS
->endElementNS(XML_mc
, XML_AlternateContent
);
2001 ShapeExport
& ShapeExport::WriteOLE2Shape( const Reference
< XShape
>& xShape
)
2003 Reference
< XPropertySet
> xPropSet( xShape
, UNO_QUERY
);
2007 enum { CHART
, MATH
, OTHER
} eType(OTHER
);
2009 xPropSet
->getPropertyValue("CLSID") >>= clsid
;
2010 if (!clsid
.isEmpty())
2012 SvGlobalName aClassID
;
2013 bool const isValid
= aClassID
.MakeId(clsid
);
2014 assert(isValid
); (void)isValid
;
2015 if (SotExchange::IsChart(aClassID
))
2017 else if (SotExchange::IsMath(aClassID
))
2023 Reference
< XChartDocument
> xChartDoc
;
2024 xPropSet
->getPropertyValue("Model") >>= xChartDoc
;
2025 assert(xChartDoc
.is());
2027 ChartExport
aChartExport( mnXmlNamespace
, GetFS(), xChartDoc
, GetFB(), GetDocumentType() );
2028 static sal_Int32 nChartCount
= 0;
2029 aChartExport
.WriteChartObj( xShape
, GetNewShapeID( xShape
), ++nChartCount
);
2035 WriteMathShape(xShape
);
2039 uno::Reference
<embed::XEmbeddedObject
> const xObj(
2040 xPropSet
->getPropertyValue("EmbeddedObject"), uno::UNO_QUERY
);
2044 SAL_WARN("oox.shape", "ShapeExport::WriteOLE2Shape: no object");
2048 uno::Sequence
<beans::PropertyValue
> grabBag
;
2052 uno::Reference
<beans::XPropertySet
> const xParent(
2053 uno::Reference
<container::XChild
>(xObj
, uno::UNO_QUERY_THROW
)->getParent(),
2054 uno::UNO_QUERY_THROW
);
2056 xParent
->getPropertyValue("InteropGrabBag") >>= grabBag
;
2058 entryName
= uno::Reference
<embed::XEmbedPersist
>(xObj
, uno::UNO_QUERY_THROW
)->getEntryName();
2060 catch (uno::Exception
const&)
2062 TOOLS_WARN_EXCEPTION("oox.shape", "ShapeExport::WriteOLE2Shape");
2068 for (auto const& it
: std::as_const(grabBag
))
2070 if (it
.Name
== "EmbeddedObjects")
2072 uno::Sequence
<beans::PropertyValue
> objects
;
2073 it
.Value
>>= objects
;
2074 for (auto const& object
: std::as_const(objects
))
2076 if (object
.Name
== entryName
)
2078 uno::Sequence
<beans::PropertyValue
> props
;
2079 object
.Value
>>= props
;
2080 for (auto const& prop
: std::as_const(props
))
2082 if (prop
.Name
== "ProgID")
2084 prop
.Value
>>= progID
;
2095 OUString sMediaType
;
2096 OUString sRelationType
;
2098 const char * pProgID(nullptr);
2100 uno::Reference
<io::XInputStream
> const xInStream
=
2101 oox::GetOLEObjectStream(
2102 mpFB
->getComponentContext(), xObj
, progID
,
2103 sMediaType
, sRelationType
, sSuffix
, pProgID
);
2105 if (!xInStream
.is())
2110 OString anotherProgID
;
2111 if (!pProgID
&& !progID
.isEmpty())
2113 anotherProgID
= OUStringToOString(progID
, RTL_TEXTENCODING_UTF8
);
2114 pProgID
= anotherProgID
.getStr();
2117 assert(!sMediaType
.isEmpty());
2118 assert(!sRelationType
.isEmpty());
2119 assert(!sSuffix
.isEmpty());
2121 OUString sFileName
= "embeddings/oleObject" + OUString::number(++m_nEmbeddedObjects
) + "." + sSuffix
;
2122 uno::Reference
<io::XOutputStream
> const xOutStream(
2123 mpFB
->openFragmentStream(
2124 OUString::createFromAscii(GetComponentDir()) + "/" + sFileName
,
2126 assert(xOutStream
.is()); // no reason why that could fail
2129 ::comphelper::OStorageHelper::CopyInputToOutput(xInStream
, xOutStream
);
2130 } catch (uno::Exception
const&) {
2131 TOOLS_WARN_EXCEPTION("oox.shape", "ShapeExport::WriteOLEObject");
2134 OUString
const sRelId
= mpFB
->addRelation(
2135 mpFS
->getOutputStream(), sRelationType
,
2136 OUString::createFromAscii(GetRelationCompPrefix()) + sFileName
);
2138 mpFS
->startElementNS(mnXmlNamespace
, XML_graphicFrame
);
2140 mpFS
->startElementNS(mnXmlNamespace
, XML_nvGraphicFramePr
);
2142 mpFS
->singleElementNS( mnXmlNamespace
, XML_cNvPr
,
2143 XML_id
, OString::number(GetNewShapeID(xShape
)),
2144 XML_name
, IDS(Object
) );
2146 mpFS
->singleElementNS(mnXmlNamespace
, XML_cNvGraphicFramePr
);
2148 if (GetDocumentType() == DOCUMENT_PPTX
)
2149 mpFS
->singleElementNS(mnXmlNamespace
, XML_nvPr
);
2150 mpFS
->endElementNS( mnXmlNamespace
, XML_nvGraphicFramePr
);
2152 WriteShapeTransformation( xShape
, mnXmlNamespace
);
2154 mpFS
->startElementNS(XML_a
, XML_graphic
);
2155 mpFS
->startElementNS(XML_a
, XML_graphicData
,
2156 XML_uri
, "http://schemas.openxmlformats.org/presentationml/2006/ole");
2159 mpFS
->startElementNS( mnXmlNamespace
, XML_oleObj
,
2160 XML_progId
, pProgID
,
2161 FSNS(XML_r
, XML_id
), sRelId
.toUtf8(),
2166 mpFS
->startElementNS( mnXmlNamespace
, XML_oleObj
,
2167 //? XML_name, "Document",
2168 FSNS(XML_r
, XML_id
), sRelId
.toUtf8(),
2169 // The spec says that this is a required attribute, but PowerPoint can only handle an empty value.
2173 mpFS
->singleElementNS( mnXmlNamespace
, XML_embed
);
2176 SdrObject
* pSdrOLE2( GetSdrObjectFromXShape( xShape
) );
2177 // The spec doesn't allow <p:pic> here, but PowerPoint requires it.
2178 bool bEcma
= mpFB
->getVersion() == oox::core::ECMA_DIALECT
;
2179 if (dynamic_cast<const SdrOle2Obj
*>( pSdrOLE2
) && bEcma
)
2181 const Graphic
* pGraphic
= static_cast<SdrOle2Obj
*>(pSdrOLE2
)->GetGraphic();
2183 WriteGraphicObjectShapePart( xShape
, pGraphic
);
2186 mpFS
->endElementNS( mnXmlNamespace
, XML_oleObj
);
2188 mpFS
->endElementNS( XML_a
, XML_graphicData
);
2189 mpFS
->endElementNS( XML_a
, XML_graphic
);
2191 mpFS
->endElementNS( mnXmlNamespace
, XML_graphicFrame
);
2196 ShapeExport
& ShapeExport::WriteUnknownShape( const Reference
< XShape
>& )
2198 // Override this method to do something useful.
2202 sal_Int32
ShapeExport::GetNewShapeID( const Reference
< XShape
>& rXShape
)
2204 return GetNewShapeID( rXShape
, GetFB() );
2207 sal_Int32
ShapeExport::GetNewShapeID( const Reference
< XShape
>& rXShape
, XmlFilterBase
* pFB
)
2212 sal_Int32 nID
= pFB
->GetUniqueId();
2214 (*mpShapeMap
)[ rXShape
] = nID
;
2219 sal_Int32
ShapeExport::GetShapeID( const Reference
< XShape
>& rXShape
)
2221 return GetShapeID( rXShape
, mpShapeMap
);
2224 sal_Int32
ShapeExport::GetShapeID( const Reference
< XShape
>& rXShape
, ShapeHashMap
* pShapeMap
)
2229 ShapeHashMap::const_iterator aIter
= pShapeMap
->find( rXShape
);
2231 if( aIter
== pShapeMap
->end() )
2234 return aIter
->second
;
2239 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */