LibreOffice Module oox (master) 1
shapes.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <config_wasm_strip.h>
21
22#include <sal/config.h>
23#include <sal/log.hxx>
24
26#include <o3tl/string_view.hxx>
27#include <o3tl/any.hxx>
29#include <oox/export/shapes.hxx>
30#include <oox/export/utils.hxx>
31#include <oox/token/namespaces.hxx>
33#include <oox/token/tokens.hxx>
34
35#include <initializer_list>
36#include <string_view>
37
38#include <com/sun/star/beans/PropertyValues.hpp>
39#include <com/sun/star/beans/XPropertySet.hpp>
40#include <com/sun/star/beans/XPropertySetInfo.hpp>
41#include <com/sun/star/beans/XPropertyState.hpp>
42#include <com/sun/star/container/XChild.hpp>
43#include <com/sun/star/document/XExporter.hpp>
44#include <com/sun/star/document/XStorageBasedDocument.hpp>
45#include <com/sun/star/drawing/CircleKind.hpp>
46#include <com/sun/star/drawing/FillStyle.hpp>
47#include <com/sun/star/drawing/ConnectorType.hpp>
48#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
49#include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
50#include <com/sun/star/embed/Aspects.hpp>
51#include <com/sun/star/embed/EmbedStates.hpp>
52#include <com/sun/star/embed/XEmbeddedObject.hpp>
53#include <com/sun/star/embed/XEmbedPersist.hpp>
54#include <com/sun/star/frame/XStorable.hpp>
55#include <com/sun/star/graphic/XGraphic.hpp>
56#include <com/sun/star/i18n/ScriptType.hpp>
57#include <com/sun/star/io/XOutputStream.hpp>
58#include <com/sun/star/text/XSimpleText.hpp>
59#include <com/sun/star/text/XText.hpp>
60#include <com/sun/star/table/XTable.hpp>
61#include <com/sun/star/table/XMergeableCell.hpp>
62#include <com/sun/star/chart2/XChartDocument.hpp>
63#include <com/sun/star/frame/XModel.hpp>
64#include <com/sun/star/uno/XComponentContext.hpp>
65#include <com/sun/star/drawing/XDrawPages.hpp>
66#include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
67#include <com/sun/star/presentation/ClickAction.hpp>
68#include <com/sun/star/drawing/XGluePointsSupplier.hpp>
69#include <com/sun/star/container/XIdentifierAccess.hpp>
70#include <com/sun/star/table/BorderLineStyle.hpp>
71#include <tools/globname.hxx>
75#include <sot/exchange.hxx>
76#include <utility>
77#include <vcl/graph.hxx>
78#include <vcl/outdev.hxx>
80#include <svx/svdoashp.hxx>
81#include <svx/svdoole2.hxx>
87
88using namespace ::css;
89using namespace ::css::beans;
90using namespace ::css::uno;
91using namespace ::css::drawing;
92using namespace ::css::i18n;
93using namespace ::css::table;
94using namespace ::css::container;
95using namespace ::css::document;
96using namespace ::css::text;
97
98using ::css::io::XOutputStream;
99using ::css::chart2::XChartDocument;
100using ::css::frame::XModel;
101
102using ::oox::core::XmlFilterBase;
103using ::sax_fastparser::FSHelperPtr;
104
105
106namespace oox {
107
108static void lcl_ConvertProgID(std::u16string_view rProgID,
109 OUString & o_rMediaType, OUString & o_rRelationType, OUString & o_rFileExtension)
110{
111 if (rProgID == u"Excel.Sheet.12")
112 {
113 o_rMediaType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
115 o_rFileExtension = "xlsx";
116 }
117 else if (o3tl::starts_with(rProgID, u"Excel.SheetBinaryMacroEnabled.12") )
118 {
119 o_rMediaType = "application/vnd.ms-excel.sheet.binary.macroEnabled.12";
121 o_rFileExtension = "xlsb";
122 }
123 else if (o3tl::starts_with(rProgID, u"Excel.SheetMacroEnabled.12"))
124 {
125 o_rMediaType = "application/vnd.ms-excel.sheet.macroEnabled.12";
127 o_rFileExtension = "xlsm";
128 }
129 else if (o3tl::starts_with(rProgID, u"Excel.Sheet"))
130 {
131 o_rMediaType = "application/vnd.ms-excel";
133 o_rFileExtension = "xls";
134 }
135 else if (rProgID == u"PowerPoint.Show.12")
136 {
137 o_rMediaType = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
139 o_rFileExtension = "pptx";
140 }
141 else if (rProgID == u"PowerPoint.ShowMacroEnabled.12")
142 {
143 o_rMediaType = "application/vnd.ms-powerpoint.presentation.macroEnabled.12";
145 o_rFileExtension = "pptm";
146 }
147 else if (o3tl::starts_with(rProgID, u"PowerPoint.Show"))
148 {
149 o_rMediaType = "application/vnd.ms-powerpoint";
151 o_rFileExtension = "ppt";
152 }
153 else if (o3tl::starts_with(rProgID, u"PowerPoint.Slide.12"))
154 {
155 o_rMediaType = "application/vnd.openxmlformats-officedocument.presentationml.slide";
157 o_rFileExtension = "sldx";
158 }
159 else if (rProgID == u"PowerPoint.SlideMacroEnabled.12")
160 {
161 o_rMediaType = "application/vnd.ms-powerpoint.slide.macroEnabled.12";
163 o_rFileExtension = "sldm";
164 }
165 else if (rProgID == u"Word.DocumentMacroEnabled.12")
166 {
167 o_rMediaType = "application/vnd.ms-word.document.macroEnabled.12";
169 o_rFileExtension = "docm";
170 }
171 else if (rProgID == u"Word.Document.12")
172 {
173 o_rMediaType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
175 o_rFileExtension = "docx";
176 }
177 else if (rProgID == u"Word.Document.8")
178 {
179 o_rMediaType = "application/msword";
181 o_rFileExtension = "doc";
182 }
183 else if (rProgID == u"Excel.Chart.8")
184 {
185 o_rMediaType = "application/vnd.ms-excel";
187 o_rFileExtension = "xls";
188 }
189 else if (rProgID == u"AcroExch.Document.11")
190 {
191 o_rMediaType = "application/pdf";
193 o_rFileExtension = "pdf";
194 }
195 else
196 {
197 o_rMediaType = "application/vnd.openxmlformats-officedocument.oleObject";
199 o_rFileExtension = "bin";
200 }
201}
202
203static uno::Reference<io::XInputStream> lcl_StoreOwnAsOOXML(
204 uno::Reference<uno::XComponentContext> const& xContext,
205 uno::Reference<embed::XEmbeddedObject> const& xObj,
206 char const*& o_rpProgID,
207 OUString & o_rMediaType, OUString & o_rRelationType, OUString & o_rSuffix)
208{
209 static struct {
210 struct {
211 sal_uInt32 n1;
212 sal_uInt16 n2, n3;
213 sal_uInt8 b8, b9, b10, b11, b12, b13, b14, b15;
214 } ClassId;
215 char const* pFilterName;
216 char const* pMediaType;
217 char const* pProgID;
218 char const* pSuffix;
219 } const s_Mapping[] = {
220 { {SO3_SW_CLASSID_60}, "MS Word 2007 XML", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "Word.Document.12", "docx" },
221 { {SO3_SC_CLASSID_60}, "Calc MS Excel 2007 XML", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Excel.Sheet.12", "xlsx" },
222 { {SO3_SIMPRESS_CLASSID_60}, "Impress MS PowerPoint 2007 XML", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "PowerPoint.Show.12", "pptx" },
223 // FIXME: Draw does not appear to have a MSO format export filter?
224// { {SO3_SDRAW_CLASSID}, "", "", "", "" },
225 { {SO3_SCH_CLASSID_60}, "unused", "", "", "" },
226 { {SO3_SM_CLASSID_60}, "unused", "", "", "" },
227 };
228
229 const char * pFilterName(nullptr);
230 SvGlobalName const classId(xObj->getClassID());
231 for (auto & i : s_Mapping)
232 {
233 auto const& rId(i.ClassId);
234 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);
235 if (temp == classId)
236 {
237 assert(SvGlobalName(SO3_SCH_CLASSID_60) != classId); // chart should be written elsewhere!
238 assert(SvGlobalName(SO3_SM_CLASSID_60) != classId); // formula should be written elsewhere!
239 pFilterName = i.pFilterName;
240 o_rMediaType = OUString::createFromAscii(i.pMediaType);
241 o_rpProgID = i.pProgID;
242 o_rSuffix = OUString::createFromAscii(i.pSuffix);
244 break;
245 }
246 }
247
248 if (!pFilterName)
249 {
250 SAL_WARN("oox.shape", "oox::GetOLEObjectStream: unknown ClassId " << classId.GetHexName());
251 return nullptr;
252 }
253
254 if (embed::EmbedStates::LOADED == xObj->getCurrentState())
255 {
256 xObj->changeState(embed::EmbedStates::RUNNING);
257 }
258 // use a temp stream - while it would work to store directly to a
259 // fragment stream, an error during export means we'd have to delete it
260 uno::Reference<io::XStream> const xTempStream(
261 xContext->getServiceManager()->createInstanceWithContext(
262 "com.sun.star.comp.MemoryStream", xContext),
263 uno::UNO_QUERY_THROW);
264 uno::Sequence<beans::PropertyValue> args( comphelper::InitPropertySequence({
265 { "OutputStream", Any(xTempStream->getOutputStream()) },
266 { "FilterName", Any(OUString::createFromAscii(pFilterName)) }
267 }));
268 uno::Reference<frame::XStorable> xStorable(xObj->getComponent(), uno::UNO_QUERY);
269 try
270 {
271 xStorable->storeToURL("private:stream", args);
272 }
273 catch (uno::Exception const&)
274 {
275 TOOLS_WARN_EXCEPTION("oox.shape", "oox::GetOLEObjectStream");
276 return nullptr;
277 }
278 xTempStream->getOutputStream()->closeOutput();
279 return xTempStream->getInputStream();
280}
281
282uno::Reference<io::XInputStream> GetOLEObjectStream(
283 uno::Reference<uno::XComponentContext> const& xContext,
284 uno::Reference<embed::XEmbeddedObject> const& xObj,
285 std::u16string_view i_rProgID,
286 OUString & o_rMediaType,
287 OUString & o_rRelationType,
288 OUString & o_rSuffix,
289 const char *& o_rpProgID)
290{
291 uno::Reference<io::XInputStream> xInStream;
292 try
293 {
294 uno::Reference<document::XStorageBasedDocument> const xParent(
295 uno::Reference<container::XChild>(xObj, uno::UNO_QUERY_THROW)->getParent(),
296 uno::UNO_QUERY_THROW);
297 uno::Reference<embed::XStorage> const xParentStorage(xParent->getDocumentStorage());
298 OUString const entryName(
299 uno::Reference<embed::XEmbedPersist>(xObj, uno::UNO_QUERY_THROW)->getEntryName());
300
301 if (xParentStorage->isStreamElement(entryName))
302 {
303 lcl_ConvertProgID(i_rProgID, o_rMediaType, o_rRelationType, o_rSuffix);
304 xInStream = xParentStorage->cloneStreamElement(entryName)->getInputStream();
305 // TODO: make it possible to take the sMediaType from the stream
306 }
307 else // the object is ODF - either the whole document is
308 { // ODF, or the OLE was edited so it was converted to ODF
309 xInStream = lcl_StoreOwnAsOOXML(xContext, xObj,
310 o_rpProgID, o_rMediaType, o_rRelationType, o_rSuffix);
311 }
312 }
313 catch (uno::Exception const&)
314 {
315 TOOLS_WARN_EXCEPTION("oox.shape", "oox::GetOLEObjectStream");
316 }
317 return xInStream;
318}
319
320} // namespace oox
321
322namespace oox::drawingml {
323
324ShapeExport::ShapeExport( sal_Int32 nXmlNamespace, FSHelperPtr pFS, ShapeHashMap* pShapeMap, XmlFilterBase* pFB, DocumentType eDocumentType, DMLTextExport* pTextExport, bool bUserShapes )
325 : DrawingML( std::move(pFS), pFB, eDocumentType, pTextExport )
326 , m_nEmbeddedObjects(0)
327 , mnShapeIdMax( 1 )
328 , mbUserShapes( bUserShapes )
329 , mnXmlNamespace( nXmlNamespace )
330 , maMapModeSrc( MapUnit::Map100thMM )
331 , maMapModeDest( MapUnit::MapInch, Point(), Fraction( 1, 576 ), Fraction( 1, 576 ) )
332 , mpShapeMap( pShapeMap ? pShapeMap : &maShapeMap )
333{
334 mpURLTransformer = std::make_shared<URLTransformer>();
335}
336
337void ShapeExport::SetURLTranslator(const std::shared_ptr<URLTransformer>& pTransformer)
338{
339 mpURLTransformer = pTransformer;
340}
341
342awt::Size ShapeExport::MapSize( const awt::Size& rSize ) const
343{
344 Size aRetSize( OutputDevice::LogicToLogic( Size( rSize.Width, rSize.Height ), maMapModeSrc, maMapModeDest ) );
345
346 if ( !aRetSize.Width() )
347 aRetSize.AdjustWidth( 1 );
348 if ( !aRetSize.Height() )
349 aRetSize.AdjustHeight( 1 );
350 return awt::Size( aRetSize.Width(), aRetSize.Height() );
351}
352
354{
355 if (Reference<XSimpleText> xText{ xIface, UNO_QUERY })
356 return xText->getString().getLength();
357
358 return false;
359}
360
362{
363 Reference< XPropertySet > xPropSet( xIface, UNO_QUERY );
364
365 if( xPropSet.is() )
366 {
367 Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
368 if ( xPropSetInfo.is() )
369 {
370 if ( xPropSetInfo->hasPropertyByName( "IsEmptyPresentationObject" ) )
371 {
372 bool bIsEmptyPresObj = false;
373 if ( xPropSet->getPropertyValue( "IsEmptyPresentationObject" ) >>= bIsEmptyPresObj )
374 {
375 SAL_INFO("oox.shape", "empty presentation object " << bIsEmptyPresObj << " , props:");
376 if( bIsEmptyPresObj )
377 return true;
378 }
379 }
380
381 if ( xPropSetInfo->hasPropertyByName( "IsPresentationObject" ) )
382 {
383 bool bIsPresObj = false;
384 if ( xPropSet->getPropertyValue( "IsPresentationObject" ) >>= bIsPresObj )
385 {
386 SAL_INFO("oox.shape", "presentation object " << bIsPresObj << ", props:");
387 if( bIsPresObj )
388 return true;
389 }
390 }
391 }
392 }
393
394 return IsNonEmptySimpleText(xIface);
395}
396
397static void AddExtLst(FSHelperPtr const& pFS, Reference<XPropertySet> const& xShape)
398{
399 if (xShape->getPropertySetInfo()->hasPropertyByName("Decorative")
400 && xShape->getPropertyValue("Decorative").get<bool>())
401 {
402 pFS->startElementNS(XML_a, XML_extLst);
403// FSNS(XML_xmlns, XML_a), GetExport().GetFilter().getNamespaceURL(OOX_NS(dml)));
404 pFS->startElementNS(XML_a, XML_ext,
405 // MSO uses this "URI" which is obviously not a URI
406 XML_uri, "{C183D7F6-B498-43B3-948B-1728B52AA6E4}");
407 pFS->singleElementNS(XML_adec, XML_decorative,
408 FSNS(XML_xmlns, XML_adec), "http://schemas.microsoft.com/office/drawing/2017/decorative",
409 XML_val, "1");
410 pFS->endElementNS(XML_a, XML_ext);
411 pFS->endElementNS(XML_a, XML_extLst);
412 }
413}
414
416{
417 SAL_INFO("oox.shape", "write polypolygon shape");
418
419 FSHelperPtr pFS = GetFS();
420 pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp));
421
422 awt::Point aPos = xShape->getPosition();
423 // Position is relative to group for child elements in Word, but absolute in API.
425 {
426 awt::Point aParentPos = m_xParent->getPosition();
427 aPos.X -= aParentPos.X;
428 aPos.Y -= aParentPos.Y;
429 }
430 awt::Size aSize = xShape->getSize();
431 tools::Rectangle aRect(Point(aPos.X, aPos.Y), Size(aSize.Width, aSize.Height));
432
433#if OSL_DEBUG_LEVEL > 0
435 awt::Size size = MapSize( awt::Size( aRect.GetWidth(), aRect.GetHeight() ) );
436 SAL_INFO("oox.shape", "poly count " << aPolyPolygon.Count());
437 SAL_INFO("oox.shape", "size: " << size.Width << " x " << size.Height);
438#endif
439
440 Reference<XPropertySet> const xProps(xShape, UNO_QUERY);
441 // non visual shape properties
443 {
444 pFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
445 pFS->startElementNS(mnXmlNamespace, XML_cNvPr,
446 XML_id, OString::number(GetNewShapeID(xShape)),
447 XML_name, GetShapeName(xShape));
448 AddExtLst(pFS, xProps);
449 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
450 }
451 pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
453 {
454 WriteNonVisualProperties( xShape );
455 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
456 }
457
458 // visual shape properties
459 pFS->startElementNS(mnXmlNamespace, XML_spPr);
460 WriteTransformation( xShape, aRect, XML_a );
461 WritePolyPolygon(xShape, bClosed);
462 if( xProps.is() ) {
463 if( bClosed )
464 WriteFill(xProps, aSize);
465 WriteOutline( xProps );
466 }
467
468 pFS->endElementNS( mnXmlNamespace, XML_spPr );
469
470 // write text
471 WriteTextBox( xShape, mnXmlNamespace );
472
473 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
474
475 return *this;
476}
477
479{
480 return WritePolyPolygonShape( xShape, true );
481}
482
484{
485 return WritePolyPolygonShape( xShape, false );
486}
487
488ShapeExport& ShapeExport::WriteGroupShape(const uno::Reference<drawing::XShape>& xShape)
489{
490 FSHelperPtr pFS = GetFS();
491
492 sal_Int32 nGroupShapeToken = XML_grpSp;
494 {
495 if (!m_xParent.is())
496 nGroupShapeToken = XML_wgp; // toplevel
497 else
498 mnXmlNamespace = XML_wpg;
499 }
500
501 pFS->startElementNS(mnXmlNamespace, nGroupShapeToken);
502
503 // non visual properties
505 {
506 pFS->startElementNS(mnXmlNamespace, XML_nvGrpSpPr);
507 pFS->startElementNS(mnXmlNamespace, XML_cNvPr,
508 XML_id, OString::number(GetNewShapeID(xShape)),
509 XML_name, GetShapeName(xShape));
510 uno::Reference<beans::XPropertySet> const xShapeProps(xShape, uno::UNO_QUERY_THROW);
511 AddExtLst(pFS, xShapeProps);
512 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
513 pFS->singleElementNS(mnXmlNamespace, XML_cNvGrpSpPr);
515 pFS->endElementNS(mnXmlNamespace, XML_nvGrpSpPr);
516 }
517 else
518 pFS->singleElementNS(mnXmlNamespace, XML_cNvGrpSpPr);
519
520 // visual properties
521 pFS->startElementNS(mnXmlNamespace, XML_grpSpPr);
522 WriteShapeTransformation(xShape, XML_a, false, false, true);
523 pFS->endElementNS(mnXmlNamespace, XML_grpSpPr);
524
525 uno::Reference<drawing::XShapes> xGroupShape(xShape, uno::UNO_QUERY_THROW);
526 uno::Reference<drawing::XShape> xParent = m_xParent;
527 m_xParent = xShape;
528 for (sal_Int32 i = 0; i < xGroupShape->getCount(); ++i)
529 {
530 uno::Reference<drawing::XShape> xChild(xGroupShape->getByIndex(i), uno::UNO_QUERY_THROW);
531 sal_Int32 nSavedNamespace = mnXmlNamespace;
532
533 uno::Reference<lang::XServiceInfo> xServiceInfo(xChild, uno::UNO_QUERY_THROW);
535 {
536 // tdf#128820: WriteGraphicObjectShapePart calls WriteTextShape for non-empty simple
537 // text objects, which needs writing into wps::wsp element, so make sure to use wps
538 // namespace for those objects
539 if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape")
540 && !IsNonEmptySimpleText(xChild))
541 mnXmlNamespace = XML_pic;
542 else
543 mnXmlNamespace = XML_wps;
544 }
545 WriteShape(xChild);
546
547 mnXmlNamespace = nSavedNamespace;
548 }
549 m_xParent = xParent;
550
551 pFS->endElementNS(mnXmlNamespace, nGroupShapeToken);
552 return *this;
553}
554
555static bool lcl_IsOnDenylist(OUString const & rShapeType)
556{
557 static const std::initializer_list<std::u16string_view> vDenylist = {
558 u"block-arc",
559 u"rectangle",
560 u"ellipse",
561 u"ring",
562 u"can",
563 u"cube",
564 u"paper",
565 u"frame",
566 u"forbidden",
567 u"smiley",
568 u"sun",
569 u"flower",
570 u"bracket-pair",
571 u"brace-pair",
572 u"quad-bevel",
573 u"round-rectangular-callout",
574 u"rectangular-callout",
575 u"round-callout",
576 u"cloud-callout",
577 u"line-callout-1",
578 u"line-callout-2",
579 u"line-callout-3",
580 u"paper",
581 u"vertical-scroll",
582 u"horizontal-scroll",
583 u"mso-spt34",
584 u"mso-spt75",
585 u"mso-spt164",
586 u"mso-spt180",
587 u"flowchart-process",
588 u"flowchart-alternate-process",
589 u"flowchart-decision",
590 u"flowchart-data",
591 u"flowchart-predefined-process",
592 u"flowchart-internal-storage",
593 u"flowchart-document",
594 u"flowchart-multidocument",
595 u"flowchart-terminator",
596 u"flowchart-preparation",
597 u"flowchart-manual-input",
598 u"flowchart-manual-operation",
599 u"flowchart-connector",
600 u"flowchart-off-page-connector",
601 u"flowchart-card",
602 u"flowchart-punched-tape",
603 u"flowchart-summing-junction",
604 u"flowchart-or",
605 u"flowchart-collate",
606 u"flowchart-sort",
607 u"flowchart-extract",
608 u"flowchart-merge",
609 u"flowchart-stored-data",
610 u"flowchart-delay",
611 u"flowchart-sequential-access",
612 u"flowchart-magnetic-disk",
613 u"flowchart-direct-access-storage",
614 u"flowchart-display"
615 };
616
617 return std::find(vDenylist.begin(), vDenylist.end(), rShapeType) != vDenylist.end();
618}
619
620static bool lcl_IsOnAllowlist(OUString const & rShapeType)
621{
622 static const std::initializer_list<std::u16string_view> vAllowlist = {
623 u"heart",
624 u"puzzle",
625 u"col-60da8460",
626 u"col-502ad400"
627 };
628
629 return std::find(vAllowlist.begin(), vAllowlist.end(), rShapeType) != vAllowlist.end();
630}
631
632static bool lcl_GetHandlePosition( sal_Int32 &nValue, const EnhancedCustomShapeParameter &rParam, const Sequence< EnhancedCustomShapeAdjustmentValue > &rSeq)
633{
634 bool bAdj = false;
635 if ( rParam.Value.getValueTypeClass() == TypeClass_DOUBLE )
636 {
637 double fValue(0.0);
638 if ( rParam.Value >>= fValue )
639 nValue = static_cast<sal_Int32>(fValue);
640 }
641 else
642 rParam.Value >>= nValue;
643
644 if ( rParam.Type == EnhancedCustomShapeParameterType::ADJUSTMENT)
645 {
646 bAdj = true;
647 sal_Int32 nIdx = nValue;
648 if ( nIdx < rSeq.getLength() )
649 {
650 if ( rSeq[ nIdx ] .Value.getValueTypeClass() == TypeClass_DOUBLE )
651 {
652 double fValue(0.0);
653 rSeq[ nIdx ].Value >>= fValue;
654 nValue = fValue;
655
656 }
657 else
658 {
659 rSeq[ nIdx ].Value >>= nValue;
660 }
661 }
662 }
663 return bAdj;
664}
665
666static void lcl_AnalyzeHandles( const uno::Sequence<beans::PropertyValues> & rHandles,
667 std::vector< std::pair< sal_Int32, sal_Int32> > &rHandlePositionList,
669{
670 for ( const Sequence< PropertyValue >& rPropSeq : rHandles )
671 {
672 static constexpr OUStringLiteral sPosition( u"Position" );
673 bool bPosition = false;
674 EnhancedCustomShapeParameterPair aPosition;
675 for ( const PropertyValue& rPropVal: rPropSeq )
676 {
677 if ( rPropVal.Name == sPosition )
678 {
679 if ( rPropVal.Value >>= aPosition )
680 bPosition = true;
681 }
682 }
683 if ( bPosition )
684 {
685 sal_Int32 nXPosition = 0;
686 sal_Int32 nYPosition = 0;
687 // For polar handles, nXPosition is radius and nYPosition is angle
688 lcl_GetHandlePosition( nXPosition, aPosition.First , rSeq );
689 lcl_GetHandlePosition( nYPosition, aPosition.Second, rSeq );
690 rHandlePositionList.emplace_back( nXPosition, nYPosition );
691 }
692 }
693}
694
695static void lcl_AppendAdjustmentValue( std::vector< std::pair< sal_Int32, sal_Int32> > &rAvList, sal_Int32 nAdjIdx, sal_Int32 nValue )
696{
697 rAvList.emplace_back( nAdjIdx , nValue );
698}
699
700static sal_Int32 lcl_NormalizeAngle( sal_Int32 nAngle )
701{
702 nAngle = nAngle % 360;
703 return nAngle < 0 ? ( nAngle + 360 ) : nAngle ;
704}
705
706static sal_Int32 lcl_CircleAngle2CustomShapeEllipseAngleOOX(const sal_Int32 nInternAngle, const sal_Int32 nWidth, const sal_Int32 nHeight)
707{
708 if (nWidth != 0 || nHeight != 0)
709 {
710 double fAngle = basegfx::deg2rad<100>(nInternAngle); // intern 1/100 deg to rad
711 fAngle = atan2(nHeight * sin(fAngle), nWidth * cos(fAngle)); // circle to ellipse
712 fAngle = basegfx::rad2deg<60000>(fAngle); // rad to OOXML angle unit
713 sal_Int32 nAngle = basegfx::fround(fAngle); // normalize
714 nAngle = nAngle % 21600000;
715 return nAngle < 0 ? (nAngle + 21600000) : nAngle;
716 }
717 else // should be handled by caller, dummy value
718 return 0;
719}
720
721static OUString lcl_GetTarget(const css::uno::Reference<css::frame::XModel>& xModel,
722 std::u16string_view rURL)
723{
724 Reference<drawing::XDrawPagesSupplier> xDPS(xModel, uno::UNO_QUERY_THROW);
725 Reference<drawing::XDrawPages> xDrawPages(xDPS->getDrawPages(), uno::UNO_SET_THROW);
726 sal_uInt32 nPageCount = xDrawPages->getCount();
727 OUString sTarget;
728
729 for (sal_uInt32 i = 0; i < nPageCount; ++i)
730 {
731 Reference<XDrawPage> xDrawPage;
732 xDrawPages->getByIndex(i) >>= xDrawPage;
733 Reference<container::XNamed> xNamed(xDrawPage, UNO_QUERY);
734 if (!xNamed)
735 continue;
736 OUString sSlideName = "#" + xNamed->getName();
737 if (rURL == sSlideName)
738 {
739 sTarget = "slide" + OUString::number(i + 1) + ".xml";
740 break;
741 }
742 }
743
744 return sTarget;
745}
746
748{
749 SAL_INFO("oox.shape", "write custom shape");
750 Reference< XPropertySet > rXPropSet( xShape, UNO_QUERY );
751 // First check, if this is a Fontwork-shape. For DrawingML, such a shape is a
752 // TextBox shape with body property prstTxWarp.
753 if (IsFontworkShape(rXPropSet))
754 {
755 ShapeExport::WriteTextShape(xShape); // qualifier to prevent PowerPointShapeExport
756 return *this;
757 }
758
759 bool bHasGeometrySeq(false);
760 Sequence< PropertyValue > aGeometrySeq;
761 OUString sShapeType("non-primitive"); // default in ODF
762 if (GetProperty(rXPropSet, "CustomShapeGeometry"))
763 {
764 SAL_INFO("oox.shape", "got custom shape geometry");
765 if (mAny >>= aGeometrySeq)
766 {
767 bHasGeometrySeq = true;
768 SAL_INFO("oox.shape", "got custom shape geometry sequence");
769 for (const PropertyValue& rProp : std::as_const(aGeometrySeq))
770 {
771 SAL_INFO("oox.shape", "geometry property: " << rProp.Name);
772 if (rProp.Name == "Type")
773 rProp.Value >>= sShapeType;
774 }
775 }
776 }
777
778 bool bPredefinedHandlesUsed = true;
779 bool bHasHandles = false;
780
781 ShapeFlag nMirrorFlags = ShapeFlag::NONE;
782 MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType( xShape, nMirrorFlags, sShapeType );
783 assert(dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(xShape)) && "Not a SdrObjCustomShape (!)");
784 SdrObjCustomShape& rSdrObjCustomShape(static_cast< SdrObjCustomShape& >(*SdrObject::getSdrObjectFromXShape(xShape)));
785 const bool bIsDefaultObject(
787 rSdrObjCustomShape,
788 eShapeType));
789 OString sPresetShape = msfilter::util::GetOOXMLPresetGeometry(sShapeType);
790 SAL_INFO("oox.shape", "custom shape type: " << sShapeType << " ==> " << sPresetShape);
791
792 sal_Int32 nAdjustmentValuesIndex = -1;
793 awt::Rectangle aViewBox;
794 uno::Sequence<beans::PropertyValues> aHandles;
795
796 bool bFlipH = false;
797 bool bFlipV = false;
798
799 if (bHasGeometrySeq)
800 {
801 for (int i = 0; i < aGeometrySeq.getLength(); i++)
802 {
803 const PropertyValue& rProp = aGeometrySeq[ i ];
804 SAL_INFO("oox.shape", "geometry property: " << rProp.Name);
805
806 if ( rProp.Name == "MirroredX" )
807 rProp.Value >>= bFlipH;
808
809 if ( rProp.Name == "MirroredY" )
810 rProp.Value >>= bFlipV;
811 if ( rProp.Name == "AdjustmentValues" )
812 nAdjustmentValuesIndex = i;
813 else if ( rProp.Name == "Handles" )
814 {
815 rProp.Value >>= aHandles;
816 if ( aHandles.hasElements() )
817 bHasHandles = true;
818 if( !bIsDefaultObject )
819 bPredefinedHandlesUsed = false;
820 // TODO: update nAdjustmentsWhichNeedsToBeConverted here
821 }
822 else if ( rProp.Name == "ViewBox" )
823 rProp.Value >>= aViewBox;
824 }
825 }
826
827 FSHelperPtr pFS = GetFS();
828 // non visual shape properties
830 {
831 bool bUseBackground = false;
832 if (GetProperty(rXPropSet, "FillUseSlideBackground"))
833 mAny >>= bUseBackground;
834 if (bUseBackground)
835 mpFS->startElementNS(mnXmlNamespace, XML_sp, XML_useBgFill, "1");
836 else
837 mpFS->startElementNS(mnXmlNamespace, XML_sp);
838
839 bool isVisible = true ;
840 if( GetProperty(rXPropSet, "Visible"))
841 {
842 mAny >>= isVisible;
843 }
844 pFS->startElementNS( mnXmlNamespace, XML_nvSpPr );
845 pFS->startElementNS(
846 mnXmlNamespace, XML_cNvPr, XML_id,
847 OString::number(GetShapeID(xShape) == -1 ? GetNewShapeID(xShape) : GetShapeID(xShape)),
848 XML_name, GetShapeName(xShape), XML_hidden, sax_fastparser::UseIf("1", !isVisible));
849
850 if( GetProperty(rXPropSet, "URL") )
851 {
852 OUString sURL;
853 mAny >>= sURL;
854 if( !sURL.isEmpty() )
855 {
856 OUString sRelId = mpFB->addRelation( mpFS->getOutputStream(),
858 mpURLTransformer->getTransformedString(sURL),
859 mpURLTransformer->isExternalURL(sURL));
860
861 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
862 }
863 }
864
865 OUString sBookmark;
866 if (GetProperty(rXPropSet, "Bookmark"))
867 mAny >>= sBookmark;
868
869 if (GetProperty(rXPropSet, "OnClick"))
870 {
871 OUString sPPAction;
872 presentation::ClickAction eClickAction = presentation::ClickAction_NONE;
873 mAny >>= eClickAction;
874 if (eClickAction != presentation::ClickAction_NONE)
875 {
876 switch (eClickAction)
877 {
878 case presentation::ClickAction_STOPPRESENTATION:
879 sPPAction = "ppaction://hlinkshowjump?jump=endshow";
880 break;
881 case presentation::ClickAction_NEXTPAGE:
882 sPPAction = "ppaction://hlinkshowjump?jump=nextslide";
883 break;
884 case presentation::ClickAction_LASTPAGE:
885 sPPAction = "ppaction://hlinkshowjump?jump=lastslide";
886 break;
887 case presentation::ClickAction_PREVPAGE:
888 sPPAction = "ppaction://hlinkshowjump?jump=previousslide";
889 break;
890 case presentation::ClickAction_FIRSTPAGE:
891 sPPAction = "ppaction://hlinkshowjump?jump=firstslide";
892 break;
893 case presentation::ClickAction_BOOKMARK:
894 sBookmark = "#" + sBookmark;
895 break;
896 default:
897 break;
898 }
899 }
900 if (!sPPAction.isEmpty())
901 pFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), "", XML_action,
902 sPPAction);
903 }
904 if (!sBookmark.isEmpty())
905 {
906 bool bExtURL = URLTransformer().isExternalURL(sBookmark);
907 sBookmark = bExtURL ? sBookmark : lcl_GetTarget(GetFB()->getModel(), sBookmark);
908
909 OUString sRelId
910 = mpFB->addRelation(mpFS->getOutputStream(),
913 sBookmark, bExtURL);
914 if (bExtURL)
915 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
916 else
917 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId,
918 XML_action, "ppaction://hlinksldjump");
919 }
920 AddExtLst(pFS, rXPropSet);
921 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
922 pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
923 WriteNonVisualProperties( xShape );
924 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
925 }
926 else
927 {
928 pFS->startElementNS(mnXmlNamespace, XML_wsp);
929 if (m_xParent.is())
930 {
931 pFS->startElementNS(mnXmlNamespace, XML_cNvPr, XML_id,
932 OString::number(GetShapeID(xShape) == -1 ? GetNewShapeID(xShape)
933 : GetShapeID(xShape)),
934 XML_name, GetShapeName(xShape));
935
936 if (GetProperty(rXPropSet, "Hyperlink"))
937 {
938 OUString sURL;
939 mAny >>= sURL;
940 if (!sURL.isEmpty())
941 {
942 OUString sRelId = mpFB->addRelation(
944 mpURLTransformer->getTransformedString(sURL),
945 mpURLTransformer->isExternalURL(sURL));
946
947 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
948 }
949 }
950 AddExtLst(pFS, rXPropSet);
951 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
952 }
953 pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
954 }
955
956 // visual shape properties
957 pFS->startElementNS(mnXmlNamespace, XML_spPr);
958
959 // we export non-primitive shapes to custom geometry
960 // we also export non-ooxml shapes which have handles/equations to custom geometry, because
961 // we cannot convert ODF equations to DrawingML equations. TODO: see what binary DOC export filter does.
962 // but our WritePolyPolygon()/WriteCustomGeometry() functions are incomplete, therefore we use a denylist
963 // we use a allowlist for shapes where mapping to MSO preset shape is not optimal
964 bool bCustGeom = true;
965 bool bOnDenylist = false;
966 if( sShapeType == "ooxml-non-primitive" )
967 bCustGeom = true;
968 else if( sShapeType.startsWith("ooxml") )
969 bCustGeom = false;
970 else if( lcl_IsOnAllowlist(sShapeType) )
971 bCustGeom = true;
972 else if( lcl_IsOnDenylist(sShapeType) )
973 {
974 bCustGeom = false;
975 bOnDenylist = true;
976 }
977
978 bool bPresetWriteSuccessful = false;
979 // Let the custom shapes what has name and preset information in OOXML, to be written
980 // as preset ones with parameters. Try that with this converter class.
981 if (!sShapeType.startsWith("ooxml") && sShapeType != "non-primitive" && !mbUserShapes
982 && xShape->getShapeType() == "com.sun.star.drawing.CustomShape"
983 && !lcl_IsOnAllowlist(sShapeType))
984 {
985 DMLPresetShapeExporter aCustomShapeConverter(this, xShape);
986 bPresetWriteSuccessful = aCustomShapeConverter.WriteShape();
987 }
988 // If preset writing has problems try to write the shape as it done before
989 if (bPresetWriteSuccessful)
990 ;// Already written do nothing.
991 else if (bCustGeom)
992 {
993 WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV );
994 bool bSuccess = WriteCustomGeometry(xShape, rSdrObjCustomShape);
995 // In case of Writer, the parent element is <wps:spPr>, and there the <a:custGeom> element
996 // is not optional.
997 if (!bSuccess && GetDocumentType() == DOCUMENT_DOCX)
998 {
1000 }
1001 }
1002 else if (bOnDenylist && bHasHandles && nAdjustmentValuesIndex !=-1 && !sShapeType.startsWith("mso-spt"))
1003 {
1004 WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV );
1006 std::vector< std::pair< sal_Int32, sal_Int32> > aHandlePositionList;
1007 std::vector< std::pair< sal_Int32, sal_Int32> > aAvList;
1008 aGeometrySeq[ nAdjustmentValuesIndex ].Value >>= aAdjustmentSeq ;
1009
1010 lcl_AnalyzeHandles( aHandles, aHandlePositionList, aAdjustmentSeq );
1011
1012 sal_Int32 nXPosition = 0;
1013 sal_Int32 nYPosition = 0;
1014 if ( !aHandlePositionList.empty() )
1015 {
1016 nXPosition = aHandlePositionList[0].first ;
1017 nYPosition = aHandlePositionList[0].second ;
1018 }
1019 switch( eShapeType )
1020 {
1022 {
1023 sal_Int32 adj3 = double(nYPosition)/aViewBox.Height *100000;
1024 sal_Int32 adj4 = double(nXPosition)/aViewBox.Width *100000;
1025 lcl_AppendAdjustmentValue( aAvList, 1, 18750 );
1026 lcl_AppendAdjustmentValue( aAvList, 2, -8333 );
1027 lcl_AppendAdjustmentValue( aAvList, 3, adj3 );
1028 lcl_AppendAdjustmentValue( aAvList, 4, adj4 );
1029 break;
1030 }
1032 {
1033 sal_Int32 adj5 = double(nYPosition)/aViewBox.Height *100000;
1034 sal_Int32 adj6 = double(nXPosition)/aViewBox.Width *100000;
1035 sal_Int32 adj3 = 18750;
1036 sal_Int32 adj4 = -16667;
1037 lcl_AppendAdjustmentValue( aAvList, 1, 18750 );
1038 lcl_AppendAdjustmentValue( aAvList, 2, -8333 );
1039 if ( aHandlePositionList.size() > 1 )
1040 {
1041 nXPosition = aHandlePositionList[1].first ;
1042 nYPosition = aHandlePositionList[1].second ;
1043 adj3 = double(nYPosition)/aViewBox.Height *100000;
1044 adj4 = double(nXPosition)/aViewBox.Width *100000;
1045 }
1046 lcl_AppendAdjustmentValue( aAvList, 3, adj3 );
1047 lcl_AppendAdjustmentValue( aAvList, 4, adj4 );
1048 lcl_AppendAdjustmentValue( aAvList, 5, adj5 );
1049 lcl_AppendAdjustmentValue( aAvList, 6, adj6 );
1050 break;
1051 }
1056 {
1057 sal_Int32 adj1 = (double(nXPosition)/aViewBox.Width -0.5) *100000;
1058 sal_Int32 adj2 = (double(nYPosition)/aViewBox.Height -0.5) *100000;
1059 lcl_AppendAdjustmentValue( aAvList, 1, adj1 );
1060 lcl_AppendAdjustmentValue( aAvList, 2, adj2 );
1061 if ( eShapeType == mso_sptWedgeRRectCallout)
1062 {
1063 lcl_AppendAdjustmentValue( aAvList, 3, 16667);
1064 }
1065
1066 break;
1067 }
1069 {
1070 sal_Int32 adj = double( aViewBox.Width - nXPosition) / std::min( aViewBox.Width,aViewBox.Height ) * 100000;
1071 lcl_AppendAdjustmentValue( aAvList, 0, adj );
1072 break;
1073 }
1074 case mso_sptDonut:
1075 case mso_sptSun:
1076 case mso_sptMoon:
1077 case mso_sptNoSmoking:
1079 case mso_sptBevel:
1080 case mso_sptBracketPair:
1081 {
1082 sal_Int32 adj = double( nXPosition )/aViewBox.Width*100000 ;
1083 lcl_AppendAdjustmentValue( aAvList, 0, adj );
1084 break;
1085 }
1086 case mso_sptCan:
1087 case mso_sptCube:
1088 case mso_sptBracePair:
1090 {
1091 sal_Int32 adj = double( nYPosition )/aViewBox.Height *100000 ;
1092 lcl_AppendAdjustmentValue( aAvList, 0, adj );
1093 break;
1094 }
1095 case mso_sptSmileyFace:
1096 {
1097 sal_Int32 adj = double( nYPosition )/aViewBox.Height *100000 - 76458.0;
1098 lcl_AppendAdjustmentValue( aAvList, 0, adj );
1099 break;
1100 }
1101 case mso_sptBlockArc:
1102 {
1103 sal_Int32 nRadius = 50000 * ( 1 - double(nXPosition) / 10800);
1104 sal_Int32 nAngleStart = lcl_NormalizeAngle( nYPosition );
1105 sal_Int32 nAngleEnd = lcl_NormalizeAngle( 180 - nAngleStart );
1106 lcl_AppendAdjustmentValue( aAvList, 1, 21600000 / 360 * nAngleStart );
1107 lcl_AppendAdjustmentValue( aAvList, 2, 21600000 / 360 * nAngleEnd );
1108 lcl_AppendAdjustmentValue( aAvList, 3, nRadius );
1109 break;
1110 }
1111 // case mso_sptNil:
1112 // case mso_sptBentConnector3:
1113 // case mso_sptBorderCallout3:
1114 default:
1115 {
1116 if ( sPresetShape == "frame" )
1117 {
1118 sal_Int32 adj1 = double( nYPosition )/aViewBox.Height *100000 ;
1119 lcl_AppendAdjustmentValue( aAvList, 1, adj1 );
1120 }
1121 break;
1122 }
1123 }
1124 WritePresetShape( sPresetShape , aAvList );
1125 }
1126 else // preset geometry
1127 {
1128 WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV );
1129 if( nAdjustmentValuesIndex != -1 )
1130 {
1131 WritePresetShape( sPresetShape, eShapeType, bPredefinedHandlesUsed,
1132 aGeometrySeq[ nAdjustmentValuesIndex ] );
1133 }
1134 else
1135 WritePresetShape( sPresetShape );
1136 }
1137 if( rXPropSet.is() )
1138 {
1139 WriteFill(rXPropSet, xShape->getSize());
1140 WriteOutline( rXPropSet );
1141 WriteShapeEffects( rXPropSet );
1142
1143 bool bHas3DEffectinShape = false;
1144 uno::Sequence<beans::PropertyValue> grabBag;
1145 rXPropSet->getPropertyValue("InteropGrabBag") >>= grabBag;
1146
1147 for (auto const& it : std::as_const(grabBag))
1148 if (it.Name == "3DEffectProperties")
1149 bHas3DEffectinShape = true;
1150
1151 if( bHas3DEffectinShape)
1152 Write3DEffects( rXPropSet, /*bIsText=*/false );
1153 }
1154
1155 pFS->endElementNS( mnXmlNamespace, XML_spPr );
1156
1157 pFS->startElementNS(mnXmlNamespace, XML_style);
1158 WriteShapeStyle( rXPropSet );
1159 pFS->endElementNS( mnXmlNamespace, XML_style );
1160
1161 // write text
1162 WriteTextBox( xShape, mnXmlNamespace );
1163
1164 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
1165
1166 return *this;
1167}
1168
1170{
1171 SAL_INFO("oox.shape", "write ellipse shape");
1172
1173 FSHelperPtr pFS = GetFS();
1174
1175 pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp));
1176
1177 // TODO: connector ?
1178
1179 Reference<XPropertySet> const xProps(xShape, UNO_QUERY);
1180 // non visual shape properties
1182 {
1183 pFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
1184 pFS->startElementNS(mnXmlNamespace, XML_cNvPr,
1185 XML_id, OString::number(GetNewShapeID(xShape)),
1186 XML_name, GetShapeName(xShape));
1187 AddExtLst(pFS, xProps);
1188 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
1189 pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr );
1190 WriteNonVisualProperties( xShape );
1191 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
1192 }
1193 else
1194 pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
1195
1196 CircleKind eCircleKind(CircleKind_FULL);
1197 if (xProps.is())
1198 xProps->getPropertyValue("CircleKind" ) >>= eCircleKind;
1199
1200 // visual shape properties
1201 pFS->startElementNS( mnXmlNamespace, XML_spPr );
1202 WriteShapeTransformation( xShape, XML_a );
1203
1204 if (CircleKind_FULL == eCircleKind)
1205 WritePresetShape("ellipse");
1206 else
1207 {
1208 sal_Int32 nStartAngleIntern(9000);
1209 sal_Int32 nEndAngleIntern(0);
1210 if (xProps.is())
1211 {
1212 xProps->getPropertyValue("CircleStartAngle" ) >>= nStartAngleIntern;
1213 xProps->getPropertyValue("CircleEndAngle") >>= nEndAngleIntern;
1214 }
1215 std::vector< std::pair<sal_Int32,sal_Int32>> aAvList;
1216 awt::Size aSize = xShape->getSize();
1217 if (aSize.Width != 0 || aSize.Height != 0)
1218 {
1219 // Our arc has 90° up, OOXML has 90° down, so mirror it.
1220 // API angles are 1/100 degree.
1221 sal_Int32 nStartAngleOOXML(lcl_CircleAngle2CustomShapeEllipseAngleOOX(36000 - nEndAngleIntern, aSize.Width, aSize.Height));
1222 sal_Int32 nEndAngleOOXML(lcl_CircleAngle2CustomShapeEllipseAngleOOX(36000 - nStartAngleIntern, aSize.Width, aSize.Height));
1223 lcl_AppendAdjustmentValue( aAvList, 1, nStartAngleOOXML);
1224 lcl_AppendAdjustmentValue( aAvList, 2, nEndAngleOOXML);
1225 }
1226 switch (eCircleKind)
1227 {
1228 case CircleKind_ARC :
1229 WritePresetShape("arc", aAvList);
1230 break;
1231 case CircleKind_SECTION :
1232 WritePresetShape("pie", aAvList);
1233 break;
1234 case CircleKind_CUT :
1235 WritePresetShape("chord", aAvList);
1236 break;
1237 default :
1238 WritePresetShape("ellipse");
1239 }
1240 }
1241 if( xProps.is() )
1242 {
1243 if (CircleKind_ARC == eCircleKind)
1244 {
1245 // An arc in ODF is never filled, even if a fill style other than
1246 // "none" is set. OOXML arc can be filled, so set fill explicit to
1247 // NONE, otherwise some hidden or inherited filling is shown.
1248 FillStyle eFillStyle(FillStyle_NONE);
1249 uno::Any aNewValue;
1250 aNewValue <<= eFillStyle;
1251 xProps->setPropertyValue("FillStyle", aNewValue);
1252 }
1253 WriteFill( xProps );
1254 WriteOutline( xProps );
1255 }
1256 pFS->endElementNS( mnXmlNamespace, XML_spPr );
1257
1258 // write text
1259 WriteTextBox( xShape, mnXmlNamespace );
1260
1261 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
1262
1263 return *this;
1264}
1265
1267{
1269
1270 return *this;
1271}
1272
1274{
1275 SAL_INFO("oox.shape", "write graphic object shape");
1276
1277 if (IsNonEmptySimpleText(xShape))
1278 {
1279 SAL_INFO("oox.shape", "graphicObject: wrote only text");
1280
1281 WriteTextShape(xShape);
1282
1283 return;
1284 }
1285
1286 SAL_INFO("oox.shape", "graphicObject without text");
1287
1288 uno::Reference<graphic::XGraphic> xGraphic;
1289 OUString sMediaURL;
1290
1291 Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
1292
1293 if (pGraphic)
1294 {
1295 xGraphic.set(pGraphic->GetXGraphic());
1296 }
1297 else if (xShapeProps.is() && xShapeProps->getPropertySetInfo()->hasPropertyByName("Graphic"))
1298 {
1299 xShapeProps->getPropertyValue("Graphic") >>= xGraphic;
1300 }
1301
1302 // tdf#155903 Only for PPTX, Microsoft does not support this feature in Word and Excel.
1303 bool bHasMediaURL = GetDocumentType() == DOCUMENT_PPTX && xShapeProps.is()
1304 && xShapeProps->getPropertySetInfo()->hasPropertyByName("MediaURL")
1305 && (xShapeProps->getPropertyValue("MediaURL") >>= sMediaURL);
1306
1307 if (!xGraphic.is() && !bHasMediaURL)
1308 {
1309 SAL_INFO("oox.shape", "no graphic or media URL found");
1310 return;
1311 }
1312
1313 FSHelperPtr pFS = GetFS();
1314 XmlFilterBase* pFB = GetFB();
1315
1317 pFS->startElementNS(mnXmlNamespace, XML_pic);
1318 else
1319 pFS->startElementNS(mnXmlNamespace, XML_pic,
1320 FSNS(XML_xmlns, XML_pic), pFB->getNamespaceURL(OOX_NS(dmlPicture)));
1321
1322 pFS->startElementNS(mnXmlNamespace, XML_nvPicPr);
1323
1324 presentation::ClickAction eClickAction = presentation::ClickAction_NONE;
1325 OUString sDescr, sURL, sBookmark, sPPAction;
1326 bool bHaveDesc;
1327
1328 if ( ( bHaveDesc = GetProperty( xShapeProps, "Description" ) ) )
1329 mAny >>= sDescr;
1330 if ( GetProperty( xShapeProps, "URL" ) )
1331 mAny >>= sURL;
1332 if (GetProperty(xShapeProps, "Bookmark"))
1333 mAny >>= sBookmark;
1334 if (GetProperty(xShapeProps, "OnClick"))
1335 mAny >>= eClickAction;
1336
1337 pFS->startElementNS( mnXmlNamespace, XML_cNvPr,
1338 XML_id, OString::number(GetNewShapeID(xShape)),
1339 XML_name, GetShapeName(xShape),
1340 XML_descr, sax_fastparser::UseIf(sDescr, bHaveDesc));
1341
1342 if (eClickAction != presentation::ClickAction_NONE)
1343 {
1344 switch (eClickAction)
1345 {
1346 case presentation::ClickAction_STOPPRESENTATION:
1347 sPPAction = "ppaction://hlinkshowjump?jump=endshow";
1348 break;
1349 case presentation::ClickAction_NEXTPAGE:
1350 sPPAction = "ppaction://hlinkshowjump?jump=nextslide";
1351 break;
1352 case presentation::ClickAction_LASTPAGE:
1353 sPPAction = "ppaction://hlinkshowjump?jump=lastslide";
1354 break;
1355 case presentation::ClickAction_PREVPAGE:
1356 sPPAction = "ppaction://hlinkshowjump?jump=previousslide";
1357 break;
1358 case presentation::ClickAction_FIRSTPAGE:
1359 sPPAction = "ppaction://hlinkshowjump?jump=firstslide";
1360 break;
1361 case presentation::ClickAction_BOOKMARK:
1362 sBookmark = "#" + sBookmark;
1363 break;
1364 default:
1365 break;
1366 }
1367 }
1368
1369 // OOXTODO: //cNvPr children: XML_extLst, XML_hlinkHover
1370 if (bHasMediaURL || !sPPAction.isEmpty())
1371 pFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), "", XML_action,
1372 bHasMediaURL ? "ppaction://media" : sPPAction);
1373 if( !sURL.isEmpty() )
1374 {
1375 OUString sRelId = mpFB->addRelation( mpFS->getOutputStream(),
1377 mpURLTransformer->getTransformedString(sURL),
1378 mpURLTransformer->isExternalURL(sURL));
1379
1380 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
1381 }
1382
1383 if (!sBookmark.isEmpty())
1384 {
1385 bool bExtURL = URLTransformer().isExternalURL(sBookmark);
1386 sBookmark = bExtURL ? sBookmark : lcl_GetTarget(GetFB()->getModel(), sBookmark);
1387
1388 OUString sRelId = mpFB->addRelation(mpFS->getOutputStream(),
1391 sBookmark, bExtURL);
1392
1393 if (bExtURL)
1394 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
1395 else
1396 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId, XML_action,
1397 "ppaction://hlinksldjump");
1398 }
1399 AddExtLst(pFS, xShapeProps);
1400 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
1401
1402 pFS->singleElementNS(mnXmlNamespace, XML_cNvPicPr
1403 // OOXTODO: XML_preferRelativeSize
1404 );
1405 if (bHasMediaURL)
1407 else
1409
1410 pFS->endElementNS( mnXmlNamespace, XML_nvPicPr );
1411
1412 pFS->startElementNS(mnXmlNamespace, XML_blipFill);
1413
1414 if (xGraphic.is())
1415 {
1416 WriteXGraphicBlip(xShapeProps, xGraphic, mbUserShapes);
1417 }
1418 else if (bHasMediaURL)
1419 {
1420 Reference<graphic::XGraphic> xFallbackGraphic;
1421 if (xShapeProps->getPropertySetInfo()->hasPropertyByName("FallbackGraphic"))
1422 xShapeProps->getPropertyValue("FallbackGraphic") >>= xFallbackGraphic;
1423
1424 WriteXGraphicBlip(xShapeProps, xFallbackGraphic, mbUserShapes);
1425 }
1426
1427 if (xGraphic.is())
1428 {
1429 WriteSrcRectXGraphic(xShapeProps, xGraphic);
1430 }
1431
1432 // now we stretch always when we get pGraphic (when changing that
1433 // behavior, test n#780830 for regression, where the OLE sheet might get tiled
1434 bool bStretch = false;
1435 if( !pGraphic && GetProperty( xShapeProps, "FillBitmapStretch" ) )
1436 mAny >>= bStretch;
1437
1438 if ( pGraphic || bStretch )
1439 pFS->singleElementNS(XML_a, XML_stretch);
1440
1441 if (bHasMediaURL)
1442 {
1443 // Graphic of media shapes is always stretched.
1444 pFS->startElementNS(XML_a, XML_stretch);
1445 pFS->singleElementNS(XML_a, XML_fillRect);
1446 pFS->endElementNS(XML_a, XML_stretch);
1447 }
1448
1449 pFS->endElementNS( mnXmlNamespace, XML_blipFill );
1450
1451 // visual shape properties
1452 pFS->startElementNS(mnXmlNamespace, XML_spPr);
1453 bool bFlipH = false;
1454 if( xShapeProps->getPropertySetInfo()->hasPropertyByName("IsMirrored") )
1455 {
1456 xShapeProps->getPropertyValue("IsMirrored") >>= bFlipH;
1457 }
1458 WriteShapeTransformation( xShape, XML_a, bFlipH, false, false, false, true );
1459 WritePresetShape( "rect" );
1460 // graphic object can come with the frame (bnc#654525)
1461 WriteOutline( xShapeProps );
1462
1463 WriteShapeEffects( xShapeProps );
1464 Write3DEffects( xShapeProps, /*bIsText=*/false );
1465
1466 pFS->endElementNS( mnXmlNamespace, XML_spPr );
1467
1468 pFS->endElementNS( mnXmlNamespace, XML_pic );
1469}
1470
1471static void lcl_Rotate(sal_Int32 nAngle, Point center, awt::Point& pt)
1472{
1473 sal_Int16 nCos, nSin;
1474 switch (nAngle)
1475 {
1476 case 90:
1477 nCos = 0;
1478 nSin = 1;
1479 break;
1480 case 180:
1481 nCos = -1;
1482 nSin = 0;
1483 break;
1484 case 270:
1485 nCos = 0;
1486 nSin = -1;
1487 break;
1488 default:
1489 return;
1490 }
1491 sal_Int32 x = pt.X - center.X();
1492 sal_Int32 y = pt.Y - center.Y();
1493 pt.X = center.X() + x * nCos - y * nSin;
1494 pt.Y = center.Y() + y * nCos + x * nSin;
1495}
1496
1497static void lcl_FlipHFlipV(tools::Polygon aPoly, sal_Int32 nAngle, bool& rFlipH, bool& rFlipV)
1498{
1499 Point aStart = aPoly[0];
1500 Point aEnd = aPoly[aPoly.GetSize() - 1];
1501
1502 if (aStart.X() > aEnd.X() && aStart.Y() > aEnd.Y())
1503 {
1504 if (nAngle)
1505 {
1506 if (nAngle == 90)
1507 rFlipH = true;
1508 if (nAngle == 270)
1509 rFlipV = true;
1510 }
1511 else // 0°
1512 {
1513 rFlipH = true;
1514 rFlipV = true;
1515 }
1516 }
1517
1518 if (aStart.X() < aEnd.X() && aStart.Y() < aEnd.Y())
1519 {
1520 if (nAngle)
1521 {
1522 if (nAngle != 270)
1523 {
1524 rFlipH = true;
1525 rFlipV = true;
1526 }
1527 else
1528 rFlipH = true;
1529 }
1530 }
1531
1532 if (aStart.Y() < aEnd.Y() && aStart.X() > aEnd.X())
1533 {
1534 if (nAngle)
1535 {
1536 if (nAngle == 180)
1537 rFlipV = true;
1538 if (nAngle == 270)
1539 {
1540 rFlipV = true;
1541 rFlipH = true;
1542 }
1543 }
1544 else // 0°
1545 {
1546 rFlipH = true;
1547 }
1548 }
1549
1550 if (aStart.Y() > aEnd.Y() && aStart.X() < aEnd.X())
1551 {
1552 if (nAngle)
1553 {
1554 if (nAngle == 90)
1555 {
1556 rFlipH = true;
1557 rFlipV = true;
1558 }
1559 if (nAngle == 180)
1560 rFlipH = true;
1561 }
1562 else // 0°
1563 rFlipV = true;
1564 }
1565}
1566
1567static sal_Int32 lcl_GetAngle(tools::Polygon aPoly)
1568{
1569 sal_Int32 nAngle;
1570 Point aStartPoint = aPoly[0];
1571 Point aEndPoint = aPoly[aPoly.GetSize() - 1];
1572 if (aStartPoint.X() == aPoly[1].X())
1573 {
1574 if ((aStartPoint.X() < aEndPoint.X() && aStartPoint.Y() > aEndPoint.Y())
1575 || (aStartPoint.X() > aEndPoint.X() && aStartPoint.Y() < aEndPoint.Y()))
1576 {
1577 nAngle = 90;
1578 }
1579 else
1580 nAngle = 270;
1581 }
1582 else
1583 {
1584 if (aStartPoint.X() > aPoly[1].X())
1585 nAngle = 180;
1586 else
1587 nAngle = 0;
1588 }
1589
1590 return nAngle;
1591}
1592
1593// Adjust value decide the position, where the connector should turn.
1595 ConnectorType eConnectorType,
1596 std::vector<std::pair<sal_Int32, sal_Int32>>& rAvList)
1597{
1598 sal_Int32 nAdjCount = 0;
1599 if (eConnectorType == ConnectorType_CURVE)
1600 {
1601 if (aPoly.GetSize() == 4)
1602 {
1603 if ((aPoly[0].X() == aPoly[1].X() && aPoly[2].X() == aPoly[3].X())
1604 || (aPoly[0].Y() == aPoly[1].Y() && aPoly[2].Y() == aPoly[3].Y()))
1605 {
1606 nAdjCount = 1; // curvedConnector3
1607 }
1608 else
1609 nAdjCount = 0; // curvedConnector2
1610 }
1611 else if (aPoly.GetSize() > 4)
1612 {
1613 if ((aPoly[2].X() == aPoly[3].X() && aPoly[3].X() == aPoly[4].X())
1614 || (aPoly[2].Y() == aPoly[3].Y() && aPoly[3].Y() == aPoly[4].Y()))
1615 {
1616 nAdjCount = 3; // curvedConnector5
1617 }
1618 else
1619 nAdjCount = 2; // curvedConnector4
1620 }
1621 }
1622 else
1623 {
1624 switch (aPoly.GetSize())
1625 {
1626 case 3:
1627 nAdjCount = 0; // bentConnector2
1628 break;
1629 case 4:
1630 nAdjCount = 1; // bentConnector3
1631 break;
1632 case 5:
1633 nAdjCount = 2; // bentConnector4
1634 break;
1635 case 6:
1636 nAdjCount = 3; // bentConnector5
1637 break;
1638 }
1639 }
1640
1641 if (nAdjCount)
1642 {
1643 sal_Int32 nAdjustValue;
1644 Point aStart = aPoly[0];
1645 Point aEnd = aPoly[aPoly.GetSize() - 1];
1646
1647 for (sal_Int32 i = 1; i <= nAdjCount; ++i)
1648 {
1649 Point aPt = aPoly[i];
1650
1651 if (aEnd.Y() == aStart.Y())
1652 aEnd.setY(aStart.Y() + 1);
1653 if (aEnd.X() == aStart.X())
1654 aEnd.setX(aStart.X() + 1);
1655
1656 bool bVertical = aPoly[1].X() - aStart.X() != 0 ? true : false;
1657 // vertical and horizon alternate
1658 if (i % 2 == 1)
1659 bVertical = !bVertical;
1660
1661 if (eConnectorType == ConnectorType_CURVE)
1662 {
1663 awt::Size aSize = xShape->getSize();
1664 awt::Point aShapePosition = xShape->getPosition();
1665 tools::Rectangle aBoundRect = aPoly.GetBoundRect();
1666
1667 if (bVertical)
1668 {
1669 if ((aBoundRect.GetSize().Height() - aSize.Height) == 1)
1670 aPt.setY(aPoly[i + 1].Y());
1671 else if (aStart.Y() > aPt.Y())
1672 aPt.setY(aShapePosition.Y);
1673 else
1674 aPt.setY(aShapePosition.Y + aSize.Height);
1675 }
1676 else
1677 {
1678 if ((aBoundRect.GetSize().Width() - aSize.Width) == 1)
1679 aPt.setX(aPoly[i + 1].X());
1680 else if (aStart.X() > aPt.X())
1681 aPt.setX(aShapePosition.X);
1682 else
1683 aPt.setX(aShapePosition.X + aSize.Width);
1684 }
1685 }
1686
1687 if (bVertical)
1688 nAdjustValue = ((aPt.Y() - aStart.Y()) * 100000) / (aEnd.Y() - aStart.Y());
1689 else
1690 nAdjustValue = ((aPt.X() - aStart.X()) * 100000) / (aEnd.X() - aStart.X());
1691
1692 rAvList.emplace_back(i, nAdjustValue);
1693 }
1694 }
1695}
1696
1697static sal_Int32 lcl_GetGluePointId(const Reference<XShape>& xShape, sal_Int32 nGluePointId)
1698{
1699 if (nGluePointId > 3)
1700 return nGluePointId - 4;
1701 else
1702 {
1703 bool bFlipH = false;
1704 bool bFlipV = false;
1705 Reference<XPropertySet> xShapeProps(xShape, UNO_QUERY);
1706 if (xShapeProps.is() && xShapeProps->getPropertySetInfo()
1707 && xShapeProps->getPropertySetInfo()->hasPropertyByName("CustomShapeGeometry"))
1708 {
1709 Sequence<PropertyValue> aGeometrySeq;
1710 xShapeProps->getPropertyValue("CustomShapeGeometry") >>= aGeometrySeq;
1711 for (int i = 0; i < aGeometrySeq.getLength(); i++)
1712 {
1713 const PropertyValue& rProp = aGeometrySeq[i];
1714 if (rProp.Name == "MirroredX")
1715 rProp.Value >>= bFlipH;
1716
1717 if (rProp.Name == "MirroredY")
1718 rProp.Value >>= bFlipV;
1719 }
1720 }
1721
1722 if ((!bFlipH && !bFlipV) || (bFlipH && bFlipV))
1723 {
1724 // change id of the bounding box (1 <-> 3)
1725 if (nGluePointId == 1)
1726 nGluePointId = 3; // Right
1727 else if (nGluePointId == 3)
1728 nGluePointId = 1; // Left
1729 }
1730 }
1731
1732 return nGluePointId;
1733}
1734
1736{
1737 bool bFlipH = false;
1738 bool bFlipV = false;
1739 sal_Int32 nAngle = 0;
1740 sal_Int32 nStartGlueId = 0;
1741 sal_Int32 nEndGlueId = 0;
1742
1743 SAL_INFO("oox.shape", "write connector shape");
1744
1745 FSHelperPtr pFS = GetFS();
1746
1747 OUString sGeometry;
1748 std::vector<std::pair<sal_Int32, sal_Int32>> aAdjustValueList;
1749 Reference< XPropertySet > rXPropSet( xShape, UNO_QUERY );
1750 Reference< XPropertyState > rXPropState( xShape, UNO_QUERY );
1751 awt::Point aStartPoint, aEndPoint;
1752 Reference< XShape > rXShapeA;
1753 Reference< XShape > rXShapeB;
1754 PropertyState eState;
1755 ConnectorType eConnectorType = ConnectorType_STANDARD;
1756 if (GetProperty(rXPropSet, "EdgeKind"))
1757 mAny >>= eConnectorType;
1758
1759 switch( eConnectorType ) {
1760 case ConnectorType_CURVE:
1761 sGeometry = "curvedConnector";
1762 break;
1763 case ConnectorType_LINES:
1764 case ConnectorType_STANDARD:
1765 sGeometry = "bentConnector";
1766 break;
1767 default:
1768 case ConnectorType_LINE:
1769 sGeometry = "straightConnector1";
1770 break;
1771 }
1772
1773 if (GetPropertyAndState( rXPropSet, rXPropState, "EdgeStartPoint", eState ) && eState == beans::PropertyState_DIRECT_VALUE )
1774 {
1775 mAny >>= aStartPoint;
1776 if (GetPropertyAndState( rXPropSet, rXPropState, "EdgeEndPoint", eState ) && eState == beans::PropertyState_DIRECT_VALUE )
1777 mAny >>= aEndPoint;
1778 }
1779 if (GetProperty(rXPropSet, "EdgeStartConnection"))
1780 mAny >>= rXShapeA;
1781 if (GetProperty(rXPropSet, "EdgeEndConnection"))
1782 mAny >>= rXShapeB;
1783
1784 if (GetProperty(rXPropSet, "StartGluePointIndex"))
1785 mAny >>= nStartGlueId;
1786 if (nStartGlueId != -1)
1787 nStartGlueId = lcl_GetGluePointId(rXShapeA, nStartGlueId);
1788
1789 if (GetProperty(rXPropSet, "EndGluePointIndex"))
1790 mAny >>= nEndGlueId;
1791 if (nEndGlueId != -1)
1792 nEndGlueId = lcl_GetGluePointId(rXShapeB, nEndGlueId);
1793
1794 // Position is relative to group in Word, but relative to anchor of group in API.
1796 {
1797 awt::Point aParentPos = m_xParent->getPosition();
1798 aStartPoint.X -= aParentPos.X;
1799 aStartPoint.Y -= aParentPos.Y;
1800 aEndPoint.X -= aParentPos.X;
1801 aEndPoint.Y -= aParentPos.Y;
1802 }
1803 EscherConnectorListEntry aConnectorEntry( xShape, aStartPoint, rXShapeA, aEndPoint, rXShapeB );
1804
1805 if (eConnectorType != ConnectorType_LINE)
1806 {
1808 if (aPolyPolygon.Count() > 0)
1809 {
1810 tools::Polygon aPoly = aPolyPolygon.GetObject(0);
1811 lcl_GetConnectorAdjustValue(xShape, aPoly, eConnectorType, aAdjustValueList);
1812 nAngle = lcl_GetAngle(aPoly);
1813 lcl_FlipHFlipV(aPoly, nAngle, bFlipH, bFlipV);
1814 if (nAngle)
1815 {
1816 Point center((aEndPoint.X + aStartPoint.X) / 2, (aEndPoint.Y + aStartPoint.Y) / 2);
1817 lcl_Rotate(nAngle, center, aStartPoint);
1818 lcl_Rotate(nAngle, center, aEndPoint);
1819 nAngle *= 60000;
1820 }
1821 sGeometry = sGeometry + OUString::number(aAdjustValueList.size() + 2);
1822 }
1823 }
1824
1825 tools::Rectangle aRect( Point( aStartPoint.X, aStartPoint.Y ), Point( aEndPoint.X, aEndPoint.Y ) );
1826 if( aRect.getOpenWidth() < 0 ) {
1827 aRect.SetLeft(aEndPoint.X);
1828 aRect.setWidth( aStartPoint.X - aEndPoint.X );
1829 if (eConnectorType == ConnectorType_LINE)
1830 bFlipH = true;
1831 }
1832
1833 if( aRect.getOpenHeight() < 0 ) {
1834 aRect.SetTop(aEndPoint.Y);
1835 aRect.setHeight( aStartPoint.Y - aEndPoint.Y );
1836 if (eConnectorType == ConnectorType_LINE)
1837 bFlipV = true;
1838 }
1839
1840 // tdf#99810 connector shape (cxnSp) is not valid with namespace 'wps'
1841 const auto nShapeNode = (mnXmlNamespace == XML_wps ? XML_wsp : XML_cxnSp);
1842 pFS->startElementNS(mnXmlNamespace, nShapeNode);
1843
1844 if (mnXmlNamespace == XML_wps)
1845 {
1846 // non visual connector shape drawing properties
1847 pFS->singleElementNS(mnXmlNamespace, XML_cNvCnPr);
1848 }
1849 else
1850 {
1851 // non visual shape properties
1852 pFS->startElementNS(mnXmlNamespace, XML_nvCxnSpPr);
1853 pFS->startElementNS(mnXmlNamespace, XML_cNvPr,
1854 XML_id, OString::number(GetNewShapeID(xShape)),
1855 XML_name, GetShapeName(xShape));
1856 AddExtLst(pFS, rXPropSet);
1857 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
1858 // non visual connector shape drawing properties
1859 pFS->startElementNS(mnXmlNamespace, XML_cNvCxnSpPr);
1860
1861 if (GetShapeID(rXShapeA) == -1)
1862 GetNewShapeID(rXShapeA);
1863 if (GetShapeID(rXShapeB) == -1)
1864 GetNewShapeID(rXShapeB);
1865 WriteConnectorConnections(nStartGlueId, nEndGlueId, GetShapeID(rXShapeA), GetShapeID(rXShapeB));
1866 pFS->endElementNS(mnXmlNamespace, XML_cNvCxnSpPr);
1868 pFS->singleElementNS(mnXmlNamespace, XML_nvPr);
1869 pFS->endElementNS(mnXmlNamespace, XML_nvCxnSpPr);
1870 }
1871
1872 // visual shape properties
1873 pFS->startElementNS(mnXmlNamespace, XML_spPr);
1874 WriteTransformation( xShape, aRect, XML_a, bFlipH, bFlipV, nAngle );
1875 // TODO: write adjustments (ppt export doesn't work well there either)
1876 WritePresetShape( sGeometry.toUtf8(), aAdjustValueList);
1877 Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
1878 if( xShapeProps.is() )
1879 WriteOutline( xShapeProps );
1880 pFS->endElementNS( mnXmlNamespace, XML_spPr );
1881
1882 // connector shape (cxnSp) cannot contain text (txBody) (according to schema)
1883 if( nShapeNode != XML_cxnSp )
1884 {
1885 // write text
1886 WriteTextBox( xShape, mnXmlNamespace );
1887 }
1888
1889 pFS->endElementNS(mnXmlNamespace, nShapeNode);
1890
1891 return *this;
1892}
1893
1895{
1896 bool bFlipH = false;
1897 bool bFlipV = false;
1898
1899 SAL_INFO("oox.shape", "write line shape");
1900
1901 FSHelperPtr pFS = GetFS();
1902
1903 pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp));
1904
1906 if( aPolyPolygon.Count() == 1 && aPolyPolygon[ 0 ].GetSize() == 2)
1907 {
1908 const tools::Polygon& rPoly = aPolyPolygon[ 0 ];
1909
1910 bFlipH = ( rPoly[ 0 ].X() > rPoly[ 1 ].X() );
1911 bFlipV = ( rPoly[ 0 ].Y() > rPoly[ 1 ].Y() );
1912 }
1913
1914 Reference<XPropertySet> const xShapeProps(xShape, UNO_QUERY);
1915 // non visual shape properties
1917 {
1918 pFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
1919 pFS->startElementNS(mnXmlNamespace, XML_cNvPr,
1920 XML_id, OString::number(GetNewShapeID(xShape)),
1921 XML_name, GetShapeName(xShape));
1922 AddExtLst(pFS, xShapeProps);
1923 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
1924 }
1925 pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr );
1927 {
1928 WriteNonVisualProperties( xShape );
1929 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
1930 }
1931
1932 // visual shape properties
1933 pFS->startElementNS(mnXmlNamespace, XML_spPr);
1934 WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV, true);
1935 WritePresetShape( "line" );
1936 if( xShapeProps.is() )
1937 WriteOutline( xShapeProps );
1938 pFS->endElementNS( mnXmlNamespace, XML_spPr );
1939
1940 //write style
1941 pFS->startElementNS(mnXmlNamespace, XML_style);
1942 WriteShapeStyle( xShapeProps );
1943 pFS->endElementNS( mnXmlNamespace, XML_style );
1944
1945 // write text
1946 WriteTextBox( xShape, mnXmlNamespace );
1947
1948 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
1949
1950 return *this;
1951}
1952
1954{
1955 FSHelperPtr pFS = GetFS();
1956
1957 Reference<XPropertySet> const xShapeProps(xShape, UNO_QUERY);
1958 pFS->startElementNS(mnXmlNamespace, XML_cNvPr,
1959 XML_id, OString::number(GetNewShapeID(xShape)),
1960 XML_name, pName );
1961 AddExtLst(pFS, xShapeProps);
1962 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
1963
1964 return *this;
1965}
1966
1968{
1969 // Override to generate //nvPr elements.
1970 return *this;
1971}
1972
1974{
1975 SAL_INFO("oox.shape", "write rectangle shape");
1976
1977 FSHelperPtr pFS = GetFS();
1978
1979 pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp));
1980
1981 sal_Int32 nRadius = 0;
1982
1983 Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
1984 if( xShapeProps.is() )
1985 {
1986 xShapeProps->getPropertyValue( "CornerRadius" ) >>= nRadius;
1987 }
1988
1989 if( nRadius )
1990 {
1991 nRadius = MapSize( awt::Size( nRadius, 0 ) ).Width;
1992 }
1993 //TODO: use nRadius value more precisely than just deciding whether to use
1994 // "rect" or "roundRect" preset shape below
1995
1996 // non visual shape properties
1998 pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
1999 pFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
2000 pFS->startElementNS(mnXmlNamespace, XML_cNvPr,
2001 XML_id, OString::number(GetNewShapeID(xShape)),
2002 XML_name, GetShapeName(xShape));
2003 AddExtLst(pFS, xShapeProps);
2004 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
2005 pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
2006 WriteNonVisualProperties( xShape );
2007 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
2008
2009 // visual shape properties
2010 pFS->startElementNS(mnXmlNamespace, XML_spPr);
2011 WriteShapeTransformation( xShape, XML_a );
2012 WritePresetShape( nRadius == 0 ? "rect" : "roundRect" );
2013 Reference< XPropertySet > xProps( xShape, UNO_QUERY );
2014 if( xProps.is() )
2015 {
2016 WriteFill( xProps );
2017 WriteOutline( xProps );
2018 }
2019 pFS->endElementNS( mnXmlNamespace, XML_spPr );
2020
2021 // write text
2022 WriteTextBox( xShape, mnXmlNamespace );
2023
2024 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
2025
2026 return *this;
2027}
2028
2030typedef std::unordered_map< const char*, ShapeConverter, rtl::CStringHash, rtl::CStringEqual> NameToConvertMapType;
2031
2033{
2034 static NameToConvertMapType const shape_converters
2035 {
2036 // tdf#98736 export CaptionShape as TextShape, because it is non-ooxml shape and
2037 // we can't export this shape as CustomShape
2038 // TODO: WriteCaptionShape
2039 { "com.sun.star.drawing.CaptionShape" , &ShapeExport::WriteTextShape },
2040
2041 { "com.sun.star.drawing.ClosedBezierShape" , &ShapeExport::WriteClosedPolyPolygonShape },
2042 { "com.sun.star.drawing.ConnectorShape" , &ShapeExport::WriteConnectorShape },
2043 { "com.sun.star.drawing.CustomShape" , &ShapeExport::WriteCustomShape },
2044 { "com.sun.star.drawing.EllipseShape" , &ShapeExport::WriteEllipseShape },
2045 { "com.sun.star.drawing.GraphicObjectShape" , &ShapeExport::WriteGraphicObjectShape },
2046 { "com.sun.star.drawing.LineShape" , &ShapeExport::WriteLineShape },
2047 { "com.sun.star.drawing.MediaShape" , &ShapeExport::WriteGraphicObjectShape },
2048 { "com.sun.star.drawing.OpenBezierShape" , &ShapeExport::WriteOpenPolyPolygonShape },
2049 { "com.sun.star.drawing.PolyPolygonShape" , &ShapeExport::WriteClosedPolyPolygonShape },
2050 { "com.sun.star.drawing.PolyLineShape" , &ShapeExport::WriteOpenPolyPolygonShape },
2051 { "com.sun.star.drawing.RectangleShape" , &ShapeExport::WriteRectangleShape },
2052 { "com.sun.star.drawing.OLE2Shape" , &ShapeExport::WriteOLE2Shape },
2053 { "com.sun.star.drawing.TableShape" , &ShapeExport::WriteTableShape },
2054 { "com.sun.star.drawing.TextShape" , &ShapeExport::WriteTextShape },
2055 { "com.sun.star.drawing.GroupShape" , &ShapeExport::WriteGroupShape },
2056
2057 { "com.sun.star.presentation.GraphicObjectShape" , &ShapeExport::WriteGraphicObjectShape },
2058 { "com.sun.star.presentation.MediaShape" , &ShapeExport::WriteGraphicObjectShape },
2059 { "com.sun.star.presentation.ChartShape" , &ShapeExport::WriteOLE2Shape },
2060 { "com.sun.star.presentation.OLE2Shape" , &ShapeExport::WriteOLE2Shape },
2061 { "com.sun.star.presentation.TableShape" , &ShapeExport::WriteTableShape },
2062 { "com.sun.star.presentation.TextShape" , &ShapeExport::WriteTextShape },
2063
2064 { "com.sun.star.presentation.DateTimeShape" , &ShapeExport::WriteTextShape },
2065 { "com.sun.star.presentation.FooterShape" , &ShapeExport::WriteTextShape },
2066 { "com.sun.star.presentation.HeaderShape" , &ShapeExport::WriteTextShape },
2067 { "com.sun.star.presentation.NotesShape" , &ShapeExport::WriteTextShape },
2068 { "com.sun.star.presentation.OutlinerShape" , &ShapeExport::WriteTextShape },
2069 { "com.sun.star.presentation.SlideNumberShape" , &ShapeExport::WriteTextShape },
2070 { "com.sun.star.presentation.TitleTextShape" , &ShapeExport::WriteTextShape },
2071 };
2072 return shape_converters;
2073}
2074
2076{
2077 if (!xShape)
2078 throw lang::IllegalArgumentException();
2079
2080 OUString sShapeType = xShape->getShapeType();
2081 SAL_INFO("oox.shape", "write shape: " << sShapeType);
2082 NameToConvertMapType::const_iterator aConverter
2083 = lcl_GetConverters().find(sShapeType.toUtf8().getStr());
2084 if (aConverter == lcl_GetConverters().end())
2085 {
2086 SAL_INFO("oox.shape", "unknown shape");
2087 return WriteUnknownShape( xShape );
2088 }
2089
2091 {
2092 Reference< XPropertySet > xShapeProperties(xShape, UNO_QUERY);
2093 if (xShapeProperties && xShapeProperties->getPropertySetInfo()
2094 && xShapeProperties->getPropertySetInfo()->hasPropertyByName("IsPresentationObject")
2095 && xShapeProperties->getPropertyValue("IsPresentationObject").hasValue())
2096 mbPlaceholder = xShapeProperties->getPropertyValue("IsPresentationObject").get<bool>();
2097 }
2098
2099 (this->*(aConverter->second))( xShape );
2100
2101 return *this;
2102}
2103
2104static bool lcl_isTextBox(const Reference<XInterface>& xIface)
2105{
2106 uno::Reference<beans::XPropertySet> xPropertySet(xIface, uno::UNO_QUERY);
2107 if (!xPropertySet.is())
2108 return false;
2109 uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
2110 if (!xPropertySetInfo->hasPropertyByName("TextBox"))
2111 return false;
2112 css::uno::Any aTextBox(xPropertySet->getPropertyValue("TextBox"));
2113 if (!aTextBox.hasValue())
2114 return false;
2115 return aTextBox.get<bool>();
2116}
2117
2118ShapeExport& ShapeExport::WriteTextBox( const Reference< XInterface >& xIface, sal_Int32 nXmlNamespace, bool bWritePropertiesAsLstStyles )
2119{
2120 // In case this shape has an associated textbox, then export that, and we're done.
2122 {
2123 if (lcl_isTextBox(xIface))
2124 {
2125 GetTextExport()->WriteTextBox(uno::Reference<drawing::XShape>(xIface, uno::UNO_QUERY_THROW));
2126 WriteText( xIface, /*bBodyPr=*/true, /*bText=*/false, /*nXmlNamespace=*/nXmlNamespace );
2127 return *this;
2128 }
2129 }
2130
2131 Reference< XText > xXText( xIface, UNO_QUERY );
2132 if( (NonEmptyText( xIface ) || GetDocumentType() == DOCUMENT_PPTX)
2133 && xXText.is() )
2134 {
2135 FSHelperPtr pFS = GetFS();
2136
2137 pFS->startElementNS(nXmlNamespace,
2138 (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_txBody : XML_txbx));
2139 WriteText(xIface, /*bBodyPr=*/(GetDocumentType() != DOCUMENT_DOCX || mbUserShapes), /*bText=*/true,
2140 /*nXmlNamespace=*/0, /*bWritePropertiesAsLstStyles=*/bWritePropertiesAsLstStyles);
2141 pFS->endElementNS( nXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_txBody : XML_txbx) );
2143 WriteText( xIface, /*bBodyPr=*/true, /*bText=*/false, /*nXmlNamespace=*/nXmlNamespace );
2144 }
2145 else if (GetDocumentType() == DOCUMENT_DOCX && !mbUserShapes)
2146 mpFS->singleElementNS(nXmlNamespace, XML_bodyPr);
2147
2148 return *this;
2149}
2150
2152{
2153 Reference< XTable > xTable;
2154 Reference< XPropertySet > xPropSet( rXShape, UNO_QUERY );
2155
2156 mpFS->startElementNS(XML_a, XML_graphic);
2157 mpFS->startElementNS(XML_a, XML_graphicData,
2158 XML_uri, "http://schemas.openxmlformats.org/drawingml/2006/table");
2159
2160 if ( xPropSet.is() && ( xPropSet->getPropertyValue( "Model" ) >>= xTable ) )
2161 {
2162 mpFS->startElementNS(XML_a, XML_tbl);
2163 mpFS->startElementNS(XML_a, XML_tblPr);
2164 WriteShapeEffects(xPropSet);
2165 mpFS->endElementNS(XML_a, XML_tblPr);
2166
2167 Reference< container::XIndexAccess > xColumns( xTable->getColumns(), UNO_QUERY_THROW );
2168 Reference< container::XIndexAccess > xRows( xTable->getRows(), UNO_QUERY_THROW );
2169 sal_uInt16 nRowCount = static_cast< sal_uInt16 >( xRows->getCount() );
2170 sal_uInt16 nColumnCount = static_cast< sal_uInt16 >( xColumns->getCount() );
2171
2172 mpFS->startElementNS(XML_a, XML_tblGrid);
2173
2174 for ( sal_Int32 x = 0; x < nColumnCount; x++ )
2175 {
2176 Reference< XPropertySet > xColPropSet( xColumns->getByIndex( x ), UNO_QUERY_THROW );
2177 sal_Int32 nWidth(0);
2178 xColPropSet->getPropertyValue( "Width" ) >>= nWidth;
2179
2180 mpFS->singleElementNS(XML_a, XML_gridCol,
2181 XML_w, OString::number(oox::drawingml::convertHmmToEmu(nWidth)));
2182 }
2183
2184 mpFS->endElementNS( XML_a, XML_tblGrid );
2185
2186 // map for holding the transpose index of the merged cells and pair<parentTransposeIndex, parentCell>
2187 typedef std::unordered_map<sal_Int32, std::pair<sal_Int32, Reference< XMergeableCell> > > transposeTableMap;
2188 transposeTableMap mergedCellMap;
2189
2190 for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ )
2191 {
2192 Reference< XPropertySet > xRowPropSet( xRows->getByIndex( nRow ), UNO_QUERY_THROW );
2193 sal_Int32 nRowHeight(0);
2194
2195 xRowPropSet->getPropertyValue( "Height" ) >>= nRowHeight;
2196
2197 mpFS->startElementNS(XML_a, XML_tr,
2198 XML_h, OString::number(oox::drawingml::convertHmmToEmu(nRowHeight)));
2199 for( sal_Int32 nColumn = 0; nColumn < nColumnCount; nColumn++ )
2200 {
2201 Reference< XMergeableCell > xCell( xTable->getCellByPosition( nColumn, nRow ),
2202 UNO_QUERY_THROW );
2203 sal_Int32 transposedIndexofCell = (nRow * nColumnCount) + nColumn;
2204
2205 //assume we will open a cell, set to false below if we won't
2206 bool bCellOpened = true;
2207
2208 if(xCell->getColumnSpan() > 1 && xCell->getRowSpan() > 1)
2209 {
2210 // having both : horizontal and vertical merge
2211 mpFS->startElementNS(XML_a, XML_tc,
2212 XML_gridSpan, OString::number(xCell->getColumnSpan()),
2213 XML_rowSpan, OString::number(xCell->getRowSpan()));
2214 // since, XMergeableCell doesn't have the information about
2215 // cell having hMerge or vMerge.
2216 // So, Populating the merged cell map in-order to use it to
2217 // decide the attribute for the individual cell.
2218 for(sal_Int32 columnIndex = nColumn; columnIndex < nColumn+xCell->getColumnSpan(); ++columnIndex)
2219 {
2220 for(sal_Int32 rowIndex = nRow; rowIndex < nRow+xCell->getRowSpan(); ++rowIndex)
2221 {
2222 sal_Int32 transposeIndexForMergeCell =
2223 (rowIndex * nColumnCount) + columnIndex;
2224 mergedCellMap[transposeIndexForMergeCell] =
2225 std::make_pair(transposedIndexofCell, xCell);
2226 }
2227 }
2228
2229 }
2230 else if(xCell->getColumnSpan() > 1)
2231 {
2232 // having : horizontal merge
2233 mpFS->startElementNS(XML_a, XML_tc,
2234 XML_gridSpan, OString::number(xCell->getColumnSpan()));
2235 for(sal_Int32 columnIndex = nColumn; columnIndex < nColumn + xCell->getColumnSpan(); ++columnIndex) {
2236 sal_Int32 transposeIndexForMergeCell = (nRow*nColumnCount) + columnIndex;
2237 mergedCellMap[transposeIndexForMergeCell] =
2238 std::make_pair(transposedIndexofCell, xCell);
2239 }
2240 }
2241 else if(xCell->getRowSpan() > 1)
2242 {
2243 // having : vertical merge
2244 mpFS->startElementNS(XML_a, XML_tc,
2245 XML_rowSpan, OString::number(xCell->getRowSpan()));
2246
2247 for(sal_Int32 rowIndex = nRow; rowIndex < nRow + xCell->getRowSpan(); ++rowIndex) {
2248 sal_Int32 transposeIndexForMergeCell = (rowIndex*nColumnCount) + nColumn;
2249 mergedCellMap[transposeIndexForMergeCell] =
2250 std::make_pair(transposedIndexofCell, xCell);
2251 }
2252 }
2253 else
2254 {
2255 // now, the cell can be an independent cell or
2256 // it can be a cell which is been merged to some parent cell
2257 if(!xCell->isMerged())
2258 {
2259 // independent cell
2260 mpFS->startElementNS(XML_a, XML_tc);
2261 }
2262 else
2263 {
2264 // it a merged cell to some parent cell
2265 // find the parent cell for the current cell at hand
2266 transposeTableMap::iterator it = mergedCellMap.find(transposedIndexofCell);
2267 if(it != mergedCellMap.end())
2268 {
2269 sal_Int32 transposeIndexOfParent = it->second.first;
2270 Reference< XMergeableCell > parentCell = it->second.second;
2271 // finding the row and column index for the parent cell from transposed index
2272 sal_Int32 parentColumnIndex = transposeIndexOfParent % nColumnCount;
2273 sal_Int32 parentRowIndex = transposeIndexOfParent / nColumnCount;
2274 if(nColumn == parentColumnIndex)
2275 {
2276 // the cell is vertical merge and it might have gridspan
2277 if(parentCell->getColumnSpan() > 1)
2278 {
2279 // vMerge and has gridSpan
2280 mpFS->startElementNS(XML_a, XML_tc,
2281 XML_vMerge, OString::number(1),
2282 XML_gridSpan, OString::number(xCell->getColumnSpan()));
2283 }
2284 else
2285 {
2286 // only vMerge
2287 mpFS->startElementNS(XML_a, XML_tc,
2288 XML_vMerge, OString::number(1));
2289 }
2290 }
2291 else if(nRow == parentRowIndex)
2292 {
2293 // the cell is horizontal merge and it might have rowspan
2294 if(parentCell->getRowSpan() > 1)
2295 {
2296 // hMerge and has rowspan
2297 mpFS->startElementNS(XML_a, XML_tc,
2298 XML_hMerge, OString::number(1),
2299 XML_rowSpan, OString::number(xCell->getRowSpan()));
2300 }
2301 else
2302 {
2303 // only hMerge
2304 mpFS->startElementNS(XML_a, XML_tc,
2305 XML_hMerge, OString::number(1));
2306 }
2307 }
2308 else
2309 {
2310 // has hMerge and vMerge
2311 mpFS->startElementNS(XML_a, XML_tc,
2312 XML_vMerge, OString::number(1),
2313 XML_hMerge, OString::number(1));
2314 }
2315 }
2316 else
2317 bCellOpened = false;
2318 }
2319 }
2320
2321 if (bCellOpened)
2322 {
2323 WriteTextBox( xCell, XML_a );
2324
2325 Reference< XPropertySet > xCellPropSet(xCell, UNO_QUERY_THROW);
2326 WriteTableCellProperties(xCellPropSet);
2327
2328 mpFS->endElementNS( XML_a, XML_tc );
2329 }
2330 }
2331
2332 mpFS->endElementNS( XML_a, XML_tr );
2333 }
2334
2335 mpFS->endElementNS( XML_a, XML_tbl );
2336 }
2337
2338 mpFS->endElementNS( XML_a, XML_graphicData );
2339 mpFS->endElementNS( XML_a, XML_graphic );
2340}
2341
2343{
2344 sal_Int32 nLeftMargin(0), nRightMargin(0);
2345 TextVerticalAdjust eVerticalAlignment;
2346 const char* sVerticalAlignment;
2347
2348 Any aLeftMargin = xCellPropSet->getPropertyValue("TextLeftDistance");
2349 aLeftMargin >>= nLeftMargin;
2350
2351 Any aRightMargin = xCellPropSet->getPropertyValue("TextRightDistance");
2352 aRightMargin >>= nRightMargin;
2353
2354 Any aVerticalAlignment = xCellPropSet->getPropertyValue("TextVerticalAdjust");
2355 aVerticalAlignment >>= eVerticalAlignment;
2356 sVerticalAlignment = GetTextVerticalAdjust(eVerticalAlignment);
2357
2358 sal_Int32 nRotateAngle = 0;
2359 Any aRotateAngle = xCellPropSet->getPropertyValue("RotateAngle");
2360 aRotateAngle >>= nRotateAngle;
2361 std::optional<OString> aTextVerticalValue = GetTextVerticalType(nRotateAngle);
2362
2363 Sequence<PropertyValue> aGrabBag;
2364 if( !aTextVerticalValue &&
2365 (xCellPropSet->getPropertyValue("CellInteropGrabBag") >>= aGrabBag) )
2366 {
2367 for (auto const& rIt : std::as_const(aGrabBag))
2368 {
2369 if (rIt.Name == "mso-tcPr-vert-value")
2370 {
2371 aTextVerticalValue = rIt.Value.get<OUString>().toUtf8();
2372 break;
2373 }
2374 }
2375 }
2376
2377 mpFS->startElementNS(XML_a, XML_tcPr, XML_anchor, sVerticalAlignment,
2378 XML_vert, aTextVerticalValue,
2381
2382 // Write background fill for table cell.
2383 // TODO
2384 // tcW : Table cell width
2385 WriteTableCellBorders(xCellPropSet);
2386 DrawingML::WriteFill(xCellPropSet);
2387 mpFS->endElementNS( XML_a, XML_tcPr );
2388}
2389
2390void ShapeExport::WriteBorderLine(const sal_Int32 XML_line, const BorderLine2& rBorderLine)
2391{
2392// While importing the table cell border line width, it converts EMU->Hmm then divided result by 2.
2393// To get original value of LineWidth need to multiple by 2.
2394 sal_Int32 nBorderWidth = rBorderLine.LineWidth;
2395 nBorderWidth *= 2;
2397
2398 if ( nBorderWidth > 0 )
2399 {
2400 mpFS->startElementNS(XML_a, XML_line, XML_w, OString::number(nBorderWidth));
2401 if ( rBorderLine.Color == sal_Int32( COL_AUTO ) )
2402 mpFS->singleElementNS(XML_a, XML_noFill);
2403 else
2405
2406 OUString sBorderStyle;
2407 sal_Int16 nStyle = rBorderLine.LineStyle;
2408 mAny.setValue(&nStyle, cppu::UnoType<sal_Int16>::get());
2409 switch (*o3tl::doAccess<sal_Int16>(mAny))
2410 {
2411 case ::table::BorderLineStyle::SOLID:
2412 sBorderStyle = "solid";
2413 break;
2414 case ::table::BorderLineStyle::DOTTED:
2415 sBorderStyle = "dot";
2416 break;
2417 case ::table::BorderLineStyle::DASHED:
2418 sBorderStyle = "dash";
2419 break;
2420 case ::table::BorderLineStyle::DASH_DOT:
2421 sBorderStyle = "dashDot";
2422 break;
2423 case ::table::BorderLineStyle::DASH_DOT_DOT:
2424 sBorderStyle = "sysDashDotDot";
2425 break;
2426 }
2427 mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, sBorderStyle);
2428 mpFS->endElementNS(XML_a, XML_line);
2429 }
2430 else if( nBorderWidth == 0)
2431 {
2432 mpFS->startElementNS(XML_a, XML_line);
2433 mpFS->singleElementNS(XML_a, XML_noFill);
2434 mpFS->endElementNS( XML_a, XML_line );
2435 }
2436}
2437
2439{
2440 BorderLine2 aBorderLine;
2441
2442// lnL - Left Border Line Properties of table cell
2443 xCellPropSet->getPropertyValue("LeftBorder") >>= aBorderLine;
2444 WriteBorderLine( XML_lnL, aBorderLine );
2445
2446// lnR - Right Border Line Properties of table cell
2447 xCellPropSet->getPropertyValue("RightBorder") >>= aBorderLine;
2448 WriteBorderLine( XML_lnR, aBorderLine );
2449
2450// lnT - Top Border Line Properties of table cell
2451 xCellPropSet->getPropertyValue("TopBorder") >>= aBorderLine;
2452 WriteBorderLine( XML_lnT, aBorderLine );
2453
2454// lnB - Bottom Border Line Properties of table cell
2455 xCellPropSet->getPropertyValue("BottomBorder") >>= aBorderLine;
2456 WriteBorderLine( XML_lnB, aBorderLine );
2457}
2458
2460{
2461 FSHelperPtr pFS = GetFS();
2462
2463 pFS->startElementNS(mnXmlNamespace, XML_graphicFrame);
2464
2465 pFS->startElementNS(mnXmlNamespace, XML_nvGraphicFramePr);
2466
2467 Reference<XPropertySet> const xShapeProps(xShape, UNO_QUERY);
2468 pFS->startElementNS(mnXmlNamespace, XML_cNvPr,
2469 XML_id, OString::number(GetNewShapeID(xShape)),
2470 XML_name, GetShapeName(xShape));
2471 AddExtLst(pFS, xShapeProps);
2472 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
2473
2474 pFS->singleElementNS(mnXmlNamespace, XML_cNvGraphicFramePr);
2475
2477 pFS->singleElementNS(mnXmlNamespace, XML_nvPr);
2478 pFS->endElementNS( mnXmlNamespace, XML_nvGraphicFramePr );
2479
2481 WriteTable( xShape );
2482
2483 pFS->endElementNS( mnXmlNamespace, XML_graphicFrame );
2484
2485 return *this;
2486}
2487
2489{
2490 FSHelperPtr pFS = GetFS();
2491 Reference<XPropertySet> xShapeProps(xShape, UNO_QUERY);
2492
2493 pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp));
2494
2495 // non visual shape properties
2497 {
2498 pFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
2499 pFS->startElementNS(mnXmlNamespace, XML_cNvPr,
2500 XML_id, OString::number(GetNewShapeID(xShape)),
2501 XML_name, GetShapeName(xShape));
2502 OUString sURL;
2503 if (GetProperty(xShapeProps, "URL"))
2504 mAny >>= sURL;
2505
2506 if (!sURL.isEmpty())
2507 {
2508 OUString sRelId = mpFB->addRelation(mpFS->getOutputStream(),
2510 mpURLTransformer->getTransformedString(sURL),
2511 mpURLTransformer->isExternalURL(sURL));
2512
2513 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
2514 }
2515 AddExtLst(pFS, xShapeProps);
2516 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
2517 }
2518 pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr, XML_txBox, "1");
2520 {
2521 WriteNonVisualProperties( xShape );
2522 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
2523 }
2524
2525 // visual shape properties
2526 pFS->startElementNS(mnXmlNamespace, XML_spPr);
2527 WriteShapeTransformation( xShape, XML_a );
2528 WritePresetShape( "rect" );
2529 uno::Reference<beans::XPropertySet> xPropertySet(xShape, UNO_QUERY);
2530 if (!IsFontworkShape(xShapeProps)) // Fontwork needs fill and outline in run properties instead.
2531 {
2532 WriteBlipOrNormalFill(xPropertySet, "Graphic", xShape->getSize());
2533 WriteOutline(xPropertySet);
2534 WriteShapeEffects(xPropertySet);
2535 }
2536 pFS->endElementNS( mnXmlNamespace, XML_spPr );
2537
2538 WriteTextBox( xShape, mnXmlNamespace );
2539
2540 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
2541
2542 return *this;
2543}
2544
2546{
2547 Reference<XPropertySet> const xPropSet(xShape, UNO_QUERY);
2548 assert(xPropSet.is());
2549 Reference<XModel> xMathModel;
2550 xPropSet->getPropertyValue("Model") >>= xMathModel;
2551 assert(xMathModel.is());
2552 assert(GetDocumentType() != DOCUMENT_DOCX); // should be written in DocxAttributeOutput
2553 SAL_WARN_IF(GetDocumentType() == DOCUMENT_XLSX, "oox.shape", "Math export to XLSX isn't tested, should it happen here?");
2554
2555 // ECMA standard does not actually allow oMath outside of
2556 // WordProcessingML so write a MCE like PPT 2010 does
2557 mpFS->startElementNS(XML_mc, XML_AlternateContent);
2558 mpFS->startElementNS(XML_mc, XML_Choice,
2559 FSNS(XML_xmlns, XML_a14), mpFB->getNamespaceURL(OOX_NS(a14)),
2560 XML_Requires, "a14");
2561 mpFS->startElementNS(mnXmlNamespace, XML_sp);
2562 mpFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
2563 mpFS->startElementNS(mnXmlNamespace, XML_cNvPr,
2564 XML_id, OString::number(GetNewShapeID(xShape)),
2565 XML_name, GetShapeName(xShape));
2566 AddExtLst(mpFS, xPropSet);
2567 mpFS->endElementNS(mnXmlNamespace, XML_cNvPr);
2568 mpFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr, XML_txBox, "1");
2569 mpFS->singleElementNS(mnXmlNamespace, XML_nvPr);
2570 mpFS->endElementNS(mnXmlNamespace, XML_nvSpPr);
2571 mpFS->startElementNS(mnXmlNamespace, XML_spPr);
2572 WriteShapeTransformation(xShape, XML_a);
2573 WritePresetShape("rect");
2574 mpFS->endElementNS(mnXmlNamespace, XML_spPr);
2575 mpFS->startElementNS(mnXmlNamespace, XML_txBody);
2576 mpFS->startElementNS(XML_a, XML_bodyPr);
2577 mpFS->endElementNS(XML_a, XML_bodyPr);
2578 mpFS->startElementNS(XML_a, XML_p);
2579 mpFS->startElementNS(XML_a14, XML_m);
2580
2581 oox::FormulaImExportBase *const pMagic(
2582 dynamic_cast<oox::FormulaImExportBase*>(xMathModel.get()));
2583 assert(pMagic);
2584 pMagic->writeFormulaOoxml(GetFS(), GetFB()->getVersion(), GetDocumentType(),
2585 FormulaImExportBase::eFormulaAlign::INLINE);
2586
2587 mpFS->endElementNS(XML_a14, XML_m);
2588 mpFS->endElementNS(XML_a, XML_p);
2589 mpFS->endElementNS(mnXmlNamespace, XML_txBody);
2590 mpFS->endElementNS(mnXmlNamespace, XML_sp);
2591 mpFS->endElementNS(XML_mc, XML_Choice);
2592 mpFS->startElementNS(XML_mc, XML_Fallback);
2593 // TODO: export bitmap shape as fallback
2594 mpFS->endElementNS(XML_mc, XML_Fallback);
2595 mpFS->endElementNS(XML_mc, XML_AlternateContent);
2596}
2597
2599{
2600 Reference< XPropertySet > xPropSet( xShape, UNO_QUERY );
2601 if (!xPropSet.is())
2602 return *this;
2603
2604 enum { CHART, MATH, OTHER } eType(OTHER);
2605 OUString clsid;
2606 xPropSet->getPropertyValue("CLSID") >>= clsid;
2607 if (!clsid.isEmpty())
2608 {
2610 bool const isValid = aClassID.MakeId(clsid);
2611 assert(isValid); (void)isValid;
2613 eType = CHART;
2614 else if (SotExchange::IsMath(aClassID))
2615 eType = MATH;
2616 }
2617
2618 if (CHART == eType)
2619 {
2621 xPropSet->getPropertyValue("Model") >>= xChartDoc;
2622 assert(xChartDoc.is());
2623 //export the chart
2624#if !ENABLE_WASM_STRIP_CHART
2625 // WASM_CHART change
2626 // TODO: With Chart extracted this cannot really happen since
2627 // no Chart could've been added at all
2628 ChartExport aChartExport( mnXmlNamespace, GetFS(), xChartDoc, GetFB(), GetDocumentType() );
2629 aChartExport.WriteChartObj( xShape, GetNewShapeID( xShape ), ++mnChartCount );
2630#endif
2631 return *this;
2632 }
2633
2634 if (MATH == eType)
2635 {
2636 WriteMathShape(xShape);
2637 return *this;
2638 }
2639
2640 uno::Reference<embed::XEmbeddedObject> const xObj(
2641 xPropSet->getPropertyValue("EmbeddedObject"), uno::UNO_QUERY);
2642
2643 if (!xObj.is())
2644 {
2645 SAL_WARN("oox.shape", "ShapeExport::WriteOLE2Shape: no object");
2646
2647 // tdf#152436 Export the preview graphic of the object if the object is missing.
2649 if (auto pOle2Obj = dynamic_cast<SdrOle2Obj*>(pSdrOLE2))
2650 {
2651 const Graphic* pGraphic = pOle2Obj->GetGraphic();
2652 if (pGraphic)
2653 WriteGraphicObjectShapePart(xShape, pGraphic);
2654 }
2655
2656 return *this;
2657 }
2658
2659 uno::Sequence<beans::PropertyValue> grabBag;
2660 OUString entryName;
2661 try
2662 {
2663 uno::Reference<beans::XPropertySet> const xParent(
2664 uno::Reference<container::XChild>(xObj, uno::UNO_QUERY_THROW)->getParent(),
2665 uno::UNO_QUERY_THROW);
2666
2667 xParent->getPropertyValue("InteropGrabBag") >>= grabBag;
2668
2669 entryName = uno::Reference<embed::XEmbedPersist>(xObj, uno::UNO_QUERY_THROW)->getEntryName();
2670 }
2671 catch (uno::Exception const&)
2672 {
2673 TOOLS_WARN_EXCEPTION("oox.shape", "ShapeExport::WriteOLE2Shape");
2674 return *this;
2675 }
2676
2677 OUString progID;
2678
2679 for (auto const& it : std::as_const(grabBag))
2680 {
2681 if (it.Name == "EmbeddedObjects")
2682 {
2683 uno::Sequence<beans::PropertyValue> objects;
2684 it.Value >>= objects;
2685 for (auto const& object : std::as_const(objects))
2686 {
2687 if (object.Name == entryName)
2688 {
2689 uno::Sequence<beans::PropertyValue> props;
2690 object.Value >>= props;
2691 for (auto const& prop : std::as_const(props))
2692 {
2693 if (prop.Name == "ProgID")
2694 {
2695 prop.Value >>= progID;
2696 break;
2697 }
2698 }
2699 break;
2700 }
2701 }
2702 break;
2703 }
2704 }
2705
2706 OUString sMediaType;
2707 OUString sRelationType;
2708 OUString sSuffix;
2709 const char * pProgID(nullptr);
2710 OString anotherProgID;
2711
2712 uno::Reference<io::XInputStream> const xInStream =
2714 mpFB->getComponentContext(), xObj, progID,
2715 sMediaType, sRelationType, sSuffix, pProgID);
2716
2717 OUString sURL;
2718 OUString sRelId;
2719 if (!xInStream.is())
2720 {
2721 xPropSet->getPropertyValue("LinkURL") >>= sURL;
2722 if (sURL.isEmpty())
2723 return *this;
2724
2725 sRelId = mpFB->addRelation(mpFS->getOutputStream(),
2727 }
2728 else
2729 {
2730 if (!pProgID && !progID.isEmpty())
2731 {
2732 anotherProgID = OUStringToOString(progID, RTL_TEXTENCODING_UTF8);
2733 pProgID = anotherProgID.getStr();
2734 }
2735
2736 assert(!sMediaType.isEmpty());
2737 assert(!sRelationType.isEmpty());
2738 assert(!sSuffix.isEmpty());
2739
2740 OUString sFileName
2741 = "embeddings/oleObject" + OUString::number(++m_nEmbeddedObjects) + "." + sSuffix;
2742 uno::Reference<io::XOutputStream> const xOutStream(mpFB->openFragmentStream(
2743 OUString::createFromAscii(GetComponentDir()) + "/" + sFileName, sMediaType));
2744 assert(xOutStream.is()); // no reason why that could fail
2745
2746 try
2747 {
2749 }
2750 catch (uno::Exception const&)
2751 {
2752 TOOLS_WARN_EXCEPTION("oox.shape", "ShapeExport::WriteOLEObject");
2753 }
2754
2755 sRelId = mpFB->addRelation(
2756 mpFS->getOutputStream(), sRelationType,
2757 Concat2View(OUString::createFromAscii(GetRelationCompPrefix()) + sFileName));
2758 }
2759
2760 sal_Int64 nAspect;
2761 bool bShowAsIcon = (xPropSet->getPropertyValue("Aspect") >>= nAspect)
2762 && nAspect == embed::Aspects::MSOLE_ICON;
2763
2764 mpFS->startElementNS(mnXmlNamespace, XML_graphicFrame);
2765
2766 mpFS->startElementNS(mnXmlNamespace, XML_nvGraphicFramePr);
2767
2768 mpFS->startElementNS(mnXmlNamespace, XML_cNvPr,
2769 XML_id, OString::number(GetNewShapeID(xShape)),
2770 XML_name, GetShapeName(xShape));
2771 AddExtLst(mpFS, xPropSet);
2772 mpFS->endElementNS(mnXmlNamespace, XML_cNvPr);
2773
2774 mpFS->singleElementNS(mnXmlNamespace, XML_cNvGraphicFramePr);
2775
2777 mpFS->singleElementNS(mnXmlNamespace, XML_nvPr);
2778 mpFS->endElementNS( mnXmlNamespace, XML_nvGraphicFramePr );
2779
2781
2782 mpFS->startElementNS(XML_a, XML_graphic);
2783 mpFS->startElementNS(XML_a, XML_graphicData,
2784 XML_uri, "http://schemas.openxmlformats.org/presentationml/2006/ole");
2785 if (pProgID)
2786 {
2787 mpFS->startElementNS( mnXmlNamespace, XML_oleObj,
2788 XML_showAsIcon, sax_fastparser::UseIf("1", bShowAsIcon),
2789 XML_progId, pProgID,
2790 FSNS(XML_r, XML_id), sRelId,
2791 XML_spid, "" );
2792 }
2793 else
2794 {
2795 mpFS->startElementNS( mnXmlNamespace, XML_oleObj,
2796//? XML_name, "Document",
2797 XML_showAsIcon, sax_fastparser::UseIf("1", bShowAsIcon),
2798 FSNS(XML_r, XML_id), sRelId,
2799 // The spec says that this is a required attribute, but PowerPoint can only handle an empty value.
2800 XML_spid, "" );
2801 }
2802
2803 if (sURL.isEmpty())
2804 mpFS->singleElementNS(mnXmlNamespace, XML_embed);
2805 else
2806 mpFS->singleElementNS(mnXmlNamespace, XML_link, XML_updateAutomatic, "1");
2807
2808 // pic element
2810 // The spec doesn't allow <p:pic> here, but PowerPoint requires it.
2811 bool const bEcma = mpFB->getVersion() == oox::core::ECMA_376_1ST_EDITION;
2812 if (bEcma)
2813 if (auto pOle2Obj = dynamic_cast<SdrOle2Obj*>(pSdrOLE2))
2814 {
2815 const Graphic* pGraphic = pOle2Obj->GetGraphic();
2816 if (pGraphic)
2817 WriteGraphicObjectShapePart( xShape, pGraphic );
2818 }
2819
2820 mpFS->endElementNS( mnXmlNamespace, XML_oleObj );
2821
2822 mpFS->endElementNS( XML_a, XML_graphicData );
2823 mpFS->endElementNS( XML_a, XML_graphic );
2824
2825 mpFS->endElementNS( mnXmlNamespace, XML_graphicFrame );
2826
2827 return *this;
2828}
2829
2831{
2832 // Override this method to do something useful.
2833 return *this;
2834}
2835
2836sal_Int32 ShapeExport::GetNewShapeID( const Reference< XShape >& rXShape )
2837{
2838 return GetNewShapeID( rXShape, GetFB() );
2839}
2840
2841sal_Int32 ShapeExport::GetNewShapeID( const Reference< XShape >& rXShape, XmlFilterBase* pFB )
2842{
2843 if( !rXShape.is() )
2844 return -1;
2845
2846 sal_Int32 nID = pFB->GetUniqueId();
2847
2848 (*mpShapeMap)[ rXShape ] = nID;
2849
2850 return nID;
2851}
2852
2853sal_Int32 ShapeExport::GetShapeID( const Reference< XShape >& rXShape )
2854{
2855 return GetShapeID( rXShape, mpShapeMap );
2856}
2857
2858sal_Int32 ShapeExport::GetShapeID( const Reference< XShape >& rXShape, ShapeHashMap* pShapeMap )
2859{
2860 if( !rXShape.is() )
2861 return -1;
2862
2863 ShapeHashMap::const_iterator aIter = pShapeMap->find( rXShape );
2864
2865 if( aIter == pShapeMap->end() )
2866 return -1;
2867
2868 return aIter->second;
2869}
2870
2872{
2873 Reference<XPropertySet> rXPropSet(xShape, UNO_QUERY);
2874
2875 // Empty name keeps the object unnamed.
2876 OUString sName;
2877
2878 if (GetProperty(rXPropSet, "Name"))
2879 mAny >>= sName;
2880 return sName;
2881}
2882
2883}
2884
2885/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
const char * pName
constexpr OUStringLiteral sMediaType
constexpr int nBorderWidth
static MSO_SPT GetCustomShapeType(const css::uno::Reference< css::drawing::XShape > &rXShape, ShapeFlag &nMirrorFlags, OUString &rShapeType, bool bOOXML=false)
static tools::PolyPolygon GetPolyPolygon(const css::uno::Reference< css::drawing::XShape > &rXShape)
static bool IsDefaultObject(const SdrObjCustomShape &rSdrObjCustomShape, const MSO_SPT eShapeType)
css::uno::Reference< css::graphic::XGraphic > GetXGraphic() const
SAL_WARN_UNUSED_RESULT Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
constexpr tools::Long Y() const
void setX(tools::Long nX)
void setY(tools::Long nY)
constexpr tools::Long X() const
static SdrObject * getSdrObjectFromXShape(const css::uno::Reference< css::uno::XInterface > &xInt)
constexpr tools::Long Height() const
tools::Long AdjustHeight(tools::Long n)
tools::Long AdjustWidth(tools::Long n)
constexpr tools::Long Width() const
static sal_uInt16 IsChart(const SvGlobalName &rName)
static sal_uInt16 IsMath(const SvGlobalName &rName)
OUString GetHexName() const
static void CopyInputToOutput(const css::uno::Reference< css::io::XInputStream > &xInput, const css::uno::Reference< css::io::XOutputStream > &xOutput)
#define SO3_SC_CLASSID_60
#define SO3_SM_CLASSID_60
#define SO3_SW_CLASSID_60
#define SO3_SCH_CLASSID_60
#define SO3_SIMPRESS_CLASSID_60
OoxmlVersion getVersion() const
Definition: filterbase.cxx:210
const css::uno::Reference< css::uno::XComponentContext > & getComponentContext() const
Returns the component context passed in the filter constructor (always existing).
Definition: filterbase.cxx:215
OUString addRelation(const OUString &rType, std::u16string_view rTarget)
Adds new relation.
css::uno::Reference< css::io::XOutputStream > openFragmentStream(const OUString &rStreamName, const OUString &rMediaType)
Opens and returns the specified output stream from the base storage with specified media type.
OUString getNamespaceURL(sal_Int32 nNSID) const
void WriteChartObj(const css::uno::Reference< css::drawing::XShape > &xShape, sal_Int32 nID, sal_Int32 nChartCount)
Class for exporting the custom shapes to OOXML preset ones, if possible.
Interface to be implemented by the parent exporter that knows how to handle shape text.
Definition: drawingml.hxx:130
virtual void WriteTextBox(css::uno::Reference< css::drawing::XShape > xShape)=0
Write the contents of the textbox that is associated to this shape.
const char * GetComponentDir() const
Definition: drawingml.cxx:1276
::oox::core::XmlFilterBase * mpFB
Definition: drawingml.hxx:287
void WriteShapeStyle(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
Definition: drawingml.cxx:5379
static sal_Int32 mnChartCount
Definition: drawingml.hxx:291
DMLTextExport * GetTextExport()
The application-specific text exporter callback, if there is one.
Definition: drawingml.hxx:349
void WriteMediaNonVisualProperties(const css::uno::Reference< css::drawing::XShape > &xShape)
Output the media (including copying a video from vnd.sun.star.Package: to the output if necessary).
Definition: drawingml.cxx:1542
void WriteShapeEffects(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
Definition: drawingml.cxx:5596
void WriteText(const css::uno::Reference< css::uno::XInterface > &rXIface, bool bBodyPr, bool bText=true, sal_Int32 nXmlNamespace=0, bool bWritePropertiesAsLstStyles=false)
Definition: drawingml.cxx:3615
::sax_fastparser::FSHelperPtr mpFS
Definition: drawingml.hxx:286
bool GetProperty(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, const OUString &aName)
Definition: drawingml.cxx:275
void WriteConnectorConnections(sal_Int32 nStartGlueId, sal_Int32 nEndGlueId, sal_Int32 nStartID, sal_Int32 nEndID)
Definition: drawingml.cxx:5236
void Write3DEffects(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, bool bIsText)
Populates scene3d tag.
Definition: drawingml.cxx:5788
bool WriteCustomGeometry(const css::uno::Reference< css::drawing::XShape > &rXShape, const SdrObjCustomShape &rSdrObjCustomShape)
Definition: drawingml.cxx:4519
void WriteFill(const css::uno::Reference< css::beans::XPropertySet > &xPropSet, const css::awt::Size &rSize={})
Definition: drawingml.cxx:5286
bool IsFontworkShape(const css::uno::Reference< css::beans::XPropertySet > &rXShapePropSet)
Definition: drawingml.cxx:3584
const ::sax_fastparser::FSHelperPtr & GetFS() const
Definition: drawingml.hxx:345
void WriteTransformation(const css::uno::Reference< css::drawing::XShape > &xShape, const tools::Rectangle &rRectangle, sal_Int32 nXmlNamespace, bool bFlipH=false, bool bFlipV=false, sal_Int32 nRotation=0, bool bIsGroupShape=false)
Definition: drawingml.cxx:2175
::oox::core::XmlFilterBase * GetFB()
Definition: drawingml.hxx:346
void WriteBlipOrNormalFill(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, const OUString &rURLPropName, const css::awt::Size &rSize={})
Definition: drawingml.cxx:1751
DocumentType GetDocumentType() const
Definition: drawingml.hxx:347
css::uno::Reference< css::drawing::XShape > m_xParent
If set, this is the parent of the currently handled shape.
Definition: drawingml.hxx:289
const char * GetRelationCompPrefix() const
Definition: drawingml.cxx:1281
void WriteShapeTransformation(const css::uno::Reference< css::drawing::XShape > &rXShape, sal_Int32 nXmlNamespace, bool bFlipH=false, bool bFlipV=false, bool bSuppressRotation=false, bool bSuppressFlipping=false, bool bFlippedBeforeRotation=false)
Definition: drawingml.cxx:2214
void WriteSolidFill(::Color nColor, sal_Int32 nAlpha=MAX_PERCENT)
Definition: drawingml.cxx:415
bool GetPropertyAndState(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, const css::uno::Reference< css::beans::XPropertyState > &rXPropState, const OUString &aName, css::beans::PropertyState &eState)
Definition: drawingml.cxx:290
void WriteSrcRectXGraphic(css::uno::Reference< css::beans::XPropertySet > const &rxPropertySet, css::uno::Reference< css::graphic::XGraphic > const &rxGraphic)
Definition: drawingml.cxx:1917
bool mbPlaceholder
True when exporting presentation placeholder shape.
Definition: drawingml.hxx:294
void WritePresetShape(const OString &pShape, std::vector< std::pair< sal_Int32, sal_Int32 > > &rAvList)
Definition: drawingml.cxx:4260
void WritePolyPolygon(const css::uno::Reference< css::drawing::XShape > &rXShape, const bool bClosed)
Definition: drawingml.cxx:5145
void WriteOutline(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, css::uno::Reference< css::frame::XModel > const &xModel=nullptr)
Definition: drawingml.cxx:937
OUString WriteXGraphicBlip(css::uno::Reference< css::beans::XPropertySet > const &rXPropSet, css::uno::Reference< css::graphic::XGraphic > const &rxGraphic, bool bRelPathToMedia)
Definition: drawingml.cxx:1702
css::awt::Size MapSize(const css::awt::Size &) const
Definition: shapes.cxx:342
virtual ShapeExport & WriteTextShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:2488
ShapeExport & WriteCustomShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:747
ShapeExport & WriteGroupShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:488
OUString GetShapeName(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:2871
ShapeExport & WriteClosedPolyPolygonShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:478
virtual ShapeExport & WriteNonVisualProperties(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1967
ShapeHashMap * mpShapeMap
Definition: shapes.hxx:105
ShapeExport & WriteGraphicObjectShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1266
ShapeExport & WriteRectangleShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1973
ShapeExport & WriteLineShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1894
ShapeExport & WriteOpenPolyPolygonShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:483
ShapeExport(sal_Int32 nXmlNamespace, ::sax_fastparser::FSHelperPtr pFS, ShapeHashMap *pShapeMap, ::oox::core::XmlFilterBase *pFB, DocumentType eDocumentType=DOCUMENT_PPTX, DMLTextExport *pTextExport=nullptr, bool bUserShapes=false)
Definition: shapes.cxx:324
sal_Int32 GetNewShapeID(const css::uno::Reference< css::drawing::XShape > &rShape)
ShapeExport & WriteEllipseShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1169
std::unordered_map< css::uno::Reference< css::drawing::XShape >, sal_Int32 > ShapeHashMap
Definition: shapes.hxx:87
sal_Int32 GetShapeID(const css::uno::Reference< css::drawing::XShape > &rShape)
ShapeExport & WritePolyPolygonShape(const css::uno::Reference< css::drawing::XShape > &xShape, bool bClosed)
Definition: shapes.cxx:415
ShapeExport & WriteConnectorShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1735
void SetURLTranslator(const std::shared_ptr< URLTransformer > &pTransformer)
Definition: shapes.cxx:337
ShapeExport & WriteNonVisualDrawingProperties(const css::uno::Reference< css::drawing::XShape > &xShape, const char *sName)
Definition: shapes.cxx:1953
std::shared_ptr< URLTransformer > mpURLTransformer
Definition: shapes.hxx:100
void WriteTableCellBorders(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
Definition: shapes.cxx:2438
void WriteMathShape(css::uno::Reference< css::drawing::XShape > const &xShape)
Definition: shapes.cxx:2545
virtual ShapeExport & WriteUnknownShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:2830
static bool NonEmptyText(const css::uno::Reference< css::uno::XInterface > &xIface)
Definition: shapes.cxx:361
ShapeExport & WriteTableShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:2459
ShapeExport & WriteShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Write the DrawingML for a particular shape.
Definition: shapes.cxx:2075
void WriteGraphicObjectShapePart(const css::uno::Reference< css::drawing::XShape > &xShape, const Graphic *pGraphic=nullptr)
Definition: shapes.cxx:1273
ShapeExport & WriteTextBox(const css::uno::Reference< css::uno::XInterface > &xIface, sal_Int32 nXmlNamespace, bool bWritePropertiesAsLstStyles=false)
Definition: shapes.cxx:2118
void WriteTableCellProperties(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
Definition: shapes.cxx:2342
void WriteTable(const css::uno::Reference< css::drawing::XShape > &rXShape)
Definition: shapes.cxx:2151
void WriteBorderLine(const sal_Int32 XML_line, const css::table::BorderLine2 &rBorderLine)
Definition: shapes.cxx:2390
ShapeExport & WriteOLE2Shape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:2598
virtual bool isExternalURL(const OUString &rURL) const
Definition: drawingml.cxx:182
sal_uInt16 Count() const
const tools::Polygon & GetObject(sal_uInt16 nPos) const
sal_uInt16 GetSize() const
tools::Rectangle GetBoundRect() const
constexpr tools::Long GetWidth() const
constexpr void SetLeft(tools::Long v)
constexpr void SetTop(tools::Long v)
tools::Long getOpenHeight() const
void setWidth(tools::Long n)
constexpr Size GetSize() const
constexpr tools::Long GetHeight() const
void setHeight(tools::Long n)
tools::Long getOpenWidth() const
ColorTransparency
constexpr ::Color COL_AUTO(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
#define TOOLS_WARN_EXCEPTION(area, stream)
OString sName
Definition: drawingml.cxx:4451
float u
float y
float x
ShapeFlag
MATH
DocumentType eType
sal_Int16 nValue
constexpr sal_Int32 FSNS(sal_Int32 namespc, sal_Int32 element)
OUString sSuffix
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
#define SAL_INFO(area, stream)
MapUnit
int n2
int n1
MSO_SPT
mso_sptSun
mso_sptBorderCallout2
mso_sptMoon
mso_sptWedgeRectCallout
mso_sptCloudCallout
mso_sptDonut
mso_sptBracePair
mso_sptSmileyFace
mso_sptNoSmoking
mso_sptBevel
mso_sptHorizontalScroll
mso_sptWedgeEllipseCallout
mso_sptFoldedCorner
mso_sptCan
mso_sptWedgeRRectCallout
mso_sptCube
mso_sptBlockArc
mso_sptBracketPair
mso_sptVerticalScroll
mso_sptBorderCallout1
sal_uInt32 n3
tools::Long const nRightMargin
tools::Long const nLeftMargin
B2IRange fround(const B2DRange &rRange)
size
enum SAL_DLLPUBLIC_RTTI FillStyle
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
Value
OString GetOOXMLPresetGeometry(std::u16string_view rShapeType)
constexpr bool starts_with(std::basic_string_view< charT, traits > sv, std::basic_string_view< charT, traits > x) noexcept
@ ECMA_376_1ST_EDITION
There are currently 5 editions of ECMA-376, latest is from 2021.
Definition: filterbase.hxx:82
TextVerticalAdjust GetTextVerticalAdjust(sal_Int32 nToken)
static const NameToConvertMapType & lcl_GetConverters()
Definition: shapes.cxx:2032
static void lcl_Rotate(sal_Int32 nAngle, Point center, awt::Point &pt)
Definition: shapes.cxx:1471
static void AddExtLst(FSHelperPtr const &pFS, Reference< XPropertySet > const &xShape)
Definition: shapes.cxx:397
static sal_Int32 lcl_GetAngle(tools::Polygon aPoly)
Definition: shapes.cxx:1567
static sal_Int32 lcl_GetGluePointId(const Reference< XShape > &xShape, sal_Int32 nGluePointId)
Definition: shapes.cxx:1697
static bool lcl_IsOnDenylist(OUString const &rShapeType)
Definition: shapes.cxx:555
static bool lcl_isTextBox(const Reference< XInterface > &xIface)
Definition: shapes.cxx:2104
std::optional< OString > GetTextVerticalType(sal_Int32 nRotateAngle)
Converts nRotate angle to TextVerticalType string appearing in ooxml.
static void lcl_AnalyzeHandles(const uno::Sequence< beans::PropertyValues > &rHandles, std::vector< std::pair< sal_Int32, sal_Int32 > > &rHandlePositionList, const Sequence< EnhancedCustomShapeAdjustmentValue > &rSeq)
Definition: shapes.cxx:666
static void lcl_FlipHFlipV(tools::Polygon aPoly, sal_Int32 nAngle, bool &rFlipH, bool &rFlipV)
Definition: shapes.cxx:1497
static sal_Int32 lcl_NormalizeAngle(sal_Int32 nAngle)
Definition: shapes.cxx:700
static OUString lcl_GetTarget(const css::uno::Reference< css::frame::XModel > &xModel, OUString &rURL)
Definition: drawingml.cxx:2309
std::unordered_map< const char *, ShapeConverter, rtl::CStringHash, rtl::CStringEqual > NameToConvertMapType
Definition: shapes.cxx:2030
static void lcl_AppendAdjustmentValue(std::vector< std::pair< sal_Int32, sal_Int32 > > &rAvList, sal_Int32 nAdjIdx, sal_Int32 nValue)
Definition: shapes.cxx:695
static bool lcl_IsOnAllowlist(OUString const &rShapeType)
Definition: shapes.cxx:620
static void lcl_GetConnectorAdjustValue(const Reference< XShape > &xShape, tools::Polygon aPoly, ConnectorType eConnectorType, std::vector< std::pair< sal_Int32, sal_Int32 > > &rAvList)
Definition: shapes.cxx:1594
ShapeExport &(ShapeExport::* ShapeConverter)(const Reference< XShape > &)
Definition: shapes.cxx:2029
static bool IsNonEmptySimpleText(const Reference< XInterface > &xIface)
Definition: shapes.cxx:353
static bool lcl_GetHandlePosition(sal_Int32 &nValue, const EnhancedCustomShapeParameter &rParam, const Sequence< EnhancedCustomShapeAdjustmentValue > &rSeq)
Definition: shapes.cxx:632
static sal_Int32 lcl_CircleAngle2CustomShapeEllipseAngleOOX(const sal_Int32 nInternAngle, const sal_Int32 nWidth, const sal_Int32 nHeight)
Definition: shapes.cxx:706
sal_Int64 convertHmmToEmu(sal_Int32 nValue)
Converts the passed 32-bit integer value from 1/100 mm to EMUs.
uno::Reference< io::XInputStream > GetOLEObjectStream(uno::Reference< uno::XComponentContext > const &xContext, uno::Reference< embed::XEmbeddedObject > const &xObj, std::u16string_view i_rProgID, OUString &o_rMediaType, OUString &o_rRelationType, OUString &o_rSuffix, const char *&o_rpProgID)
Definition: shapes.cxx:282
static uno::Reference< io::XInputStream > lcl_StoreOwnAsOOXML(uno::Reference< uno::XComponentContext > const &xContext, uno::Reference< embed::XEmbeddedObject > const &xObj, char const *&o_rpProgID, OUString &o_rMediaType, OUString &o_rRelationType, OUString &o_rSuffix)
Definition: shapes.cxx:203
OUString getRelationship(Relationship eRelationship)
static void lcl_ConvertProgID(std::u16string_view rProgID, OUString &o_rMediaType, OUString &o_rRelationType, OUString &o_rFileExtension)
Definition: shapes.cxx:108
end
args
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
dictionary props
Definition: properties.py:26
const char * UseIf(const char *s, bool bUse)
std::shared_ptr< FastSerializerHelper > FSHelperPtr
#define Y
const char *const aClassID
Reference< XModel > xModel
OUString Name
unsigned char sal_uInt8