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
398{
399 SAL_INFO("oox.shape", "write polypolygon shape");
400
401 FSHelperPtr pFS = GetFS();
402 pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp));
403
404 awt::Point aPos = xShape->getPosition();
405 // Position is relative to group for child elements in Word, but absolute in API.
407 {
408 awt::Point aParentPos = m_xParent->getPosition();
409 aPos.X -= aParentPos.X;
410 aPos.Y -= aParentPos.Y;
411 }
412 awt::Size aSize = xShape->getSize();
413 tools::Rectangle aRect(Point(aPos.X, aPos.Y), Size(aSize.Width, aSize.Height));
414
415#if OSL_DEBUG_LEVEL > 0
417 awt::Size size = MapSize( awt::Size( aRect.GetWidth(), aRect.GetHeight() ) );
418 SAL_INFO("oox.shape", "poly count " << aPolyPolygon.Count());
419 SAL_INFO("oox.shape", "size: " << size.Width << " x " << size.Height);
420#endif
421
422 // non visual shape properties
424 {
425 pFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
426 pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
427 XML_id, OString::number(GetNewShapeID(xShape)),
428 XML_name, GetShapeName(xShape));
429 }
430 pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
432 {
433 WriteNonVisualProperties( xShape );
434 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
435 }
436
437 // visual shape properties
438 pFS->startElementNS(mnXmlNamespace, XML_spPr);
439 WriteTransformation( xShape, aRect, XML_a );
440 WritePolyPolygon(xShape, bClosed);
441 Reference< XPropertySet > xProps( xShape, UNO_QUERY );
442 if( xProps.is() ) {
443 if( bClosed )
444 WriteFill(xProps, aSize);
445 WriteOutline( xProps );
446 }
447
448 pFS->endElementNS( mnXmlNamespace, XML_spPr );
449
450 // write text
451 WriteTextBox( xShape, mnXmlNamespace );
452
453 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
454
455 return *this;
456}
457
459{
460 return WritePolyPolygonShape( xShape, true );
461}
462
464{
465 return WritePolyPolygonShape( xShape, false );
466}
467
468ShapeExport& ShapeExport::WriteGroupShape(const uno::Reference<drawing::XShape>& xShape)
469{
470 FSHelperPtr pFS = GetFS();
471
472 sal_Int32 nGroupShapeToken = XML_grpSp;
474 {
475 if (!m_xParent.is())
476 nGroupShapeToken = XML_wgp; // toplevel
477 else
478 mnXmlNamespace = XML_wpg;
479 }
480
481 pFS->startElementNS(mnXmlNamespace, nGroupShapeToken);
482
483 // non visual properties
485 {
486 pFS->startElementNS(mnXmlNamespace, XML_nvGrpSpPr);
487 pFS->singleElementNS(mnXmlNamespace, XML_cNvPr,
488 XML_id, OString::number(GetNewShapeID(xShape)),
489 XML_name, GetShapeName(xShape));
490 pFS->singleElementNS(mnXmlNamespace, XML_cNvGrpSpPr);
492 pFS->endElementNS(mnXmlNamespace, XML_nvGrpSpPr);
493 }
494 else
495 pFS->singleElementNS(mnXmlNamespace, XML_cNvGrpSpPr);
496
497 // visual properties
498 pFS->startElementNS(mnXmlNamespace, XML_grpSpPr);
499 WriteShapeTransformation(xShape, XML_a, false, false, true);
500 pFS->endElementNS(mnXmlNamespace, XML_grpSpPr);
501
502 uno::Reference<drawing::XShapes> xGroupShape(xShape, uno::UNO_QUERY_THROW);
503 uno::Reference<drawing::XShape> xParent = m_xParent;
504 m_xParent = xShape;
505 for (sal_Int32 i = 0; i < xGroupShape->getCount(); ++i)
506 {
507 uno::Reference<drawing::XShape> xChild(xGroupShape->getByIndex(i), uno::UNO_QUERY_THROW);
508 sal_Int32 nSavedNamespace = mnXmlNamespace;
509
510 uno::Reference<lang::XServiceInfo> xServiceInfo(xChild, uno::UNO_QUERY_THROW);
512 {
513 // tdf#128820: WriteGraphicObjectShapePart calls WriteTextShape for non-empty simple
514 // text objects, which needs writing into wps::wsp element, so make sure to use wps
515 // namespace for those objects
516 if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape")
517 && !IsNonEmptySimpleText(xChild))
518 mnXmlNamespace = XML_pic;
519 else
520 mnXmlNamespace = XML_wps;
521 }
522 WriteShape(xChild);
523
524 mnXmlNamespace = nSavedNamespace;
525 }
526 m_xParent = xParent;
527
528 pFS->endElementNS(mnXmlNamespace, nGroupShapeToken);
529 return *this;
530}
531
532static bool lcl_IsOnDenylist(OUString const & rShapeType)
533{
534 static const std::initializer_list<std::u16string_view> vDenylist = {
535 u"block-arc",
536 u"rectangle",
537 u"ellipse",
538 u"ring",
539 u"can",
540 u"cube",
541 u"paper",
542 u"frame",
543 u"forbidden",
544 u"smiley",
545 u"sun",
546 u"flower",
547 u"bracket-pair",
548 u"brace-pair",
549 u"quad-bevel",
550 u"round-rectangular-callout",
551 u"rectangular-callout",
552 u"round-callout",
553 u"cloud-callout",
554 u"line-callout-1",
555 u"line-callout-2",
556 u"line-callout-3",
557 u"paper",
558 u"vertical-scroll",
559 u"horizontal-scroll",
560 u"mso-spt34",
561 u"mso-spt75",
562 u"mso-spt164",
563 u"mso-spt180",
564 u"flowchart-process",
565 u"flowchart-alternate-process",
566 u"flowchart-decision",
567 u"flowchart-data",
568 u"flowchart-predefined-process",
569 u"flowchart-internal-storage",
570 u"flowchart-document",
571 u"flowchart-multidocument",
572 u"flowchart-terminator",
573 u"flowchart-preparation",
574 u"flowchart-manual-input",
575 u"flowchart-manual-operation",
576 u"flowchart-connector",
577 u"flowchart-off-page-connector",
578 u"flowchart-card",
579 u"flowchart-punched-tape",
580 u"flowchart-summing-junction",
581 u"flowchart-or",
582 u"flowchart-collate",
583 u"flowchart-sort",
584 u"flowchart-extract",
585 u"flowchart-merge",
586 u"flowchart-stored-data",
587 u"flowchart-delay",
588 u"flowchart-sequential-access",
589 u"flowchart-magnetic-disk",
590 u"flowchart-direct-access-storage",
591 u"flowchart-display"
592 };
593
594 return std::find(vDenylist.begin(), vDenylist.end(), rShapeType) != vDenylist.end();
595}
596
597static bool lcl_IsOnAllowlist(OUString const & rShapeType)
598{
599 static const std::initializer_list<std::u16string_view> vAllowlist = {
600 u"heart",
601 u"puzzle",
602 u"col-60da8460",
603 u"col-502ad400"
604 };
605
606 return std::find(vAllowlist.begin(), vAllowlist.end(), rShapeType) != vAllowlist.end();
607}
608
609static bool lcl_GetHandlePosition( sal_Int32 &nValue, const EnhancedCustomShapeParameter &rParam, const Sequence< EnhancedCustomShapeAdjustmentValue > &rSeq)
610{
611 bool bAdj = false;
612 if ( rParam.Value.getValueTypeClass() == TypeClass_DOUBLE )
613 {
614 double fValue(0.0);
615 if ( rParam.Value >>= fValue )
616 nValue = static_cast<sal_Int32>(fValue);
617 }
618 else
619 rParam.Value >>= nValue;
620
621 if ( rParam.Type == EnhancedCustomShapeParameterType::ADJUSTMENT)
622 {
623 bAdj = true;
624 sal_Int32 nIdx = nValue;
625 if ( nIdx < rSeq.getLength() )
626 {
627 if ( rSeq[ nIdx ] .Value.getValueTypeClass() == TypeClass_DOUBLE )
628 {
629 double fValue(0.0);
630 rSeq[ nIdx ].Value >>= fValue;
631 nValue = fValue;
632
633 }
634 else
635 {
636 rSeq[ nIdx ].Value >>= nValue;
637 }
638 }
639 }
640 return bAdj;
641}
642
643static void lcl_AnalyzeHandles( const uno::Sequence<beans::PropertyValues> & rHandles,
644 std::vector< std::pair< sal_Int32, sal_Int32> > &rHandlePositionList,
646{
647 for ( const Sequence< PropertyValue >& rPropSeq : rHandles )
648 {
649 static const OUStringLiteral sPosition( u"Position" );
650 bool bPosition = false;
651 EnhancedCustomShapeParameterPair aPosition;
652 for ( const PropertyValue& rPropVal: rPropSeq )
653 {
654 if ( rPropVal.Name == sPosition )
655 {
656 if ( rPropVal.Value >>= aPosition )
657 bPosition = true;
658 }
659 }
660 if ( bPosition )
661 {
662 sal_Int32 nXPosition = 0;
663 sal_Int32 nYPosition = 0;
664 // For polar handles, nXPosition is radius and nYPosition is angle
665 lcl_GetHandlePosition( nXPosition, aPosition.First , rSeq );
666 lcl_GetHandlePosition( nYPosition, aPosition.Second, rSeq );
667 rHandlePositionList.emplace_back( nXPosition, nYPosition );
668 }
669 }
670}
671
672static void lcl_AppendAdjustmentValue( std::vector< std::pair< sal_Int32, sal_Int32> > &rAvList, sal_Int32 nAdjIdx, sal_Int32 nValue )
673{
674 rAvList.emplace_back( nAdjIdx , nValue );
675}
676
677static sal_Int32 lcl_NormalizeAngle( sal_Int32 nAngle )
678{
679 nAngle = nAngle % 360;
680 return nAngle < 0 ? ( nAngle + 360 ) : nAngle ;
681}
682
683static sal_Int32 lcl_CircleAngle2CustomShapeEllipseAngleOOX(const sal_Int32 nInternAngle, const sal_Int32 nWidth, const sal_Int32 nHeight)
684{
685 if (nWidth != 0 || nHeight != 0)
686 {
687 double fAngle = basegfx::deg2rad<100>(nInternAngle); // intern 1/100 deg to rad
688 fAngle = atan2(nHeight * sin(fAngle), nWidth * cos(fAngle)); // circle to ellipse
689 fAngle = basegfx::rad2deg<60000>(fAngle); // rad to OOXML angle unit
690 sal_Int32 nAngle = basegfx::fround(fAngle); // normalize
691 nAngle = nAngle % 21600000;
692 return nAngle < 0 ? (nAngle + 21600000) : nAngle;
693 }
694 else // should be handled by caller, dummy value
695 return 0;
696}
697
698static OUString lcl_GetTarget(const css::uno::Reference<css::frame::XModel>& xModel,
699 std::u16string_view rURL)
700{
701 Reference<drawing::XDrawPagesSupplier> xDPS(xModel, uno::UNO_QUERY_THROW);
702 Reference<drawing::XDrawPages> xDrawPages(xDPS->getDrawPages(), uno::UNO_SET_THROW);
703 sal_uInt32 nPageCount = xDrawPages->getCount();
704 OUString sTarget;
705
706 for (sal_uInt32 i = 0; i < nPageCount; ++i)
707 {
708 Reference<XDrawPage> xDrawPage;
709 xDrawPages->getByIndex(i) >>= xDrawPage;
710 Reference<container::XNamed> xNamed(xDrawPage, UNO_QUERY);
711 if (!xNamed)
712 continue;
713 OUString sSlideName = "#" + xNamed->getName();
714 if (rURL == sSlideName)
715 {
716 sTarget = "slide" + OUString::number(i + 1) + ".xml";
717 break;
718 }
719 }
720
721 return sTarget;
722}
723
725{
726 SAL_INFO("oox.shape", "write custom shape");
727 Reference< XPropertySet > rXPropSet( xShape, UNO_QUERY );
728 // First check, if this is a Fontwork-shape. For DrawingML, such a shape is a
729 // TextBox shape with body property prstTxWarp.
730 if (IsFontworkShape(rXPropSet))
731 {
732 ShapeExport::WriteTextShape(xShape); // qualifier to prevent PowerPointShapeExport
733 return *this;
734 }
735
736 bool bHasGeometrySeq(false);
737 Sequence< PropertyValue > aGeometrySeq;
738 OUString sShapeType("non-primitive"); // default in ODF
739 if (GetProperty(rXPropSet, "CustomShapeGeometry"))
740 {
741 SAL_INFO("oox.shape", "got custom shape geometry");
742 if (mAny >>= aGeometrySeq)
743 {
744 bHasGeometrySeq = true;
745 SAL_INFO("oox.shape", "got custom shape geometry sequence");
746 for (const PropertyValue& rProp : std::as_const(aGeometrySeq))
747 {
748 SAL_INFO("oox.shape", "geometry property: " << rProp.Name);
749 if (rProp.Name == "Type")
750 rProp.Value >>= sShapeType;
751 }
752 }
753 }
754
755 bool bPredefinedHandlesUsed = true;
756 bool bHasHandles = false;
757
758 ShapeFlag nMirrorFlags = ShapeFlag::NONE;
759 MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType( xShape, nMirrorFlags, sShapeType );
760 assert(dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(xShape)) && "Not a SdrObjCustomShape (!)");
761 SdrObjCustomShape& rSdrObjCustomShape(static_cast< SdrObjCustomShape& >(*SdrObject::getSdrObjectFromXShape(xShape)));
762 const bool bIsDefaultObject(
764 rSdrObjCustomShape,
765 eShapeType));
766 OString sPresetShape = msfilter::util::GetOOXMLPresetGeometry(sShapeType);
767 SAL_INFO("oox.shape", "custom shape type: " << sShapeType << " ==> " << sPresetShape);
768
769 sal_Int32 nAdjustmentValuesIndex = -1;
770 awt::Rectangle aViewBox;
771 uno::Sequence<beans::PropertyValues> aHandles;
772
773 bool bFlipH = false;
774 bool bFlipV = false;
775
776 if (bHasGeometrySeq)
777 {
778 for (int i = 0; i < aGeometrySeq.getLength(); i++)
779 {
780 const PropertyValue& rProp = aGeometrySeq[ i ];
781 SAL_INFO("oox.shape", "geometry property: " << rProp.Name);
782
783 if ( rProp.Name == "MirroredX" )
784 rProp.Value >>= bFlipH;
785
786 if ( rProp.Name == "MirroredY" )
787 rProp.Value >>= bFlipV;
788 if ( rProp.Name == "AdjustmentValues" )
789 nAdjustmentValuesIndex = i;
790 else if ( rProp.Name == "Handles" )
791 {
792 rProp.Value >>= aHandles;
793 if ( aHandles.hasElements() )
794 bHasHandles = true;
795 if( !bIsDefaultObject )
796 bPredefinedHandlesUsed = false;
797 // TODO: update nAdjustmentsWhichNeedsToBeConverted here
798 }
799 else if ( rProp.Name == "ViewBox" )
800 rProp.Value >>= aViewBox;
801 }
802 }
803
804 FSHelperPtr pFS = GetFS();
805 // non visual shape properties
807 {
808 bool bUseBackground = false;
809 if (GetProperty(rXPropSet, "FillUseSlideBackground"))
810 mAny >>= bUseBackground;
811 if (bUseBackground)
812 mpFS->startElementNS(mnXmlNamespace, XML_sp, XML_useBgFill, "1");
813 else
814 mpFS->startElementNS(mnXmlNamespace, XML_sp);
815
816 bool isVisible = true ;
817 if( GetProperty(rXPropSet, "Visible"))
818 {
819 mAny >>= isVisible;
820 }
821 pFS->startElementNS( mnXmlNamespace, XML_nvSpPr );
822 pFS->startElementNS(
823 mnXmlNamespace, XML_cNvPr, XML_id,
824 OString::number(GetShapeID(xShape) == -1 ? GetNewShapeID(xShape) : GetShapeID(xShape)),
825 XML_name, GetShapeName(xShape), XML_hidden, sax_fastparser::UseIf("1", !isVisible));
826
827 if( GetProperty(rXPropSet, "URL") )
828 {
829 OUString sURL;
830 mAny >>= sURL;
831 if( !sURL.isEmpty() )
832 {
833 OUString sRelId = mpFB->addRelation( mpFS->getOutputStream(),
835 mpURLTransformer->getTransformedString(sURL),
836 mpURLTransformer->isExternalURL(sURL));
837
838 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
839 }
840 }
841
842 OUString sBookmark;
843 if (GetProperty(rXPropSet, "Bookmark"))
844 mAny >>= sBookmark;
845
846 if (GetProperty(rXPropSet, "OnClick"))
847 {
848 OUString sPPAction;
849 presentation::ClickAction eClickAction = presentation::ClickAction_NONE;
850 mAny >>= eClickAction;
851 if (eClickAction != presentation::ClickAction_NONE)
852 {
853 switch (eClickAction)
854 {
855 case presentation::ClickAction_STOPPRESENTATION:
856 sPPAction = "ppaction://hlinkshowjump?jump=endshow";
857 break;
858 case presentation::ClickAction_NEXTPAGE:
859 sPPAction = "ppaction://hlinkshowjump?jump=nextslide";
860 break;
861 case presentation::ClickAction_LASTPAGE:
862 sPPAction = "ppaction://hlinkshowjump?jump=lastslide";
863 break;
864 case presentation::ClickAction_PREVPAGE:
865 sPPAction = "ppaction://hlinkshowjump?jump=previousslide";
866 break;
867 case presentation::ClickAction_FIRSTPAGE:
868 sPPAction = "ppaction://hlinkshowjump?jump=firstslide";
869 break;
870 case presentation::ClickAction_BOOKMARK:
871 sBookmark = "#" + sBookmark;
872 break;
873 default:
874 break;
875 }
876 }
877 if (!sPPAction.isEmpty())
878 pFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), "", XML_action,
879 sPPAction);
880 }
881 if (!sBookmark.isEmpty())
882 {
883 bool bExtURL = URLTransformer().isExternalURL(sBookmark);
884 sBookmark = bExtURL ? sBookmark : lcl_GetTarget(GetFB()->getModel(), sBookmark);
885
886 OUString sRelId
887 = mpFB->addRelation(mpFS->getOutputStream(),
890 sBookmark, bExtURL);
891 if (bExtURL)
892 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
893 else
894 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId,
895 XML_action, "ppaction://hlinksldjump");
896 }
897 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
898 pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
899 WriteNonVisualProperties( xShape );
900 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
901 }
902 else
903 {
904 pFS->startElementNS(mnXmlNamespace, XML_wsp);
905 if (m_xParent.is())
906 {
907 pFS->startElementNS(mnXmlNamespace, XML_cNvPr, XML_id,
908 OString::number(GetShapeID(xShape) == -1 ? GetNewShapeID(xShape)
909 : GetShapeID(xShape)),
910 XML_name, GetShapeName(xShape));
911
912 if (GetProperty(rXPropSet, "Hyperlink"))
913 {
914 OUString sURL;
915 mAny >>= sURL;
916 if (!sURL.isEmpty())
917 {
918 OUString sRelId = mpFB->addRelation(
920 mpURLTransformer->getTransformedString(sURL),
921 mpURLTransformer->isExternalURL(sURL));
922
923 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
924 }
925 }
926 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
927 }
928 pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
929 }
930
931 // visual shape properties
932 pFS->startElementNS(mnXmlNamespace, XML_spPr);
933
934 // we export non-primitive shapes to custom geometry
935 // we also export non-ooxml shapes which have handles/equations to custom geometry, because
936 // we cannot convert ODF equations to DrawingML equations. TODO: see what binary DOC export filter does.
937 // but our WritePolyPolygon()/WriteCustomGeometry() functions are incomplete, therefore we use a denylist
938 // we use a allowlist for shapes where mapping to MSO preset shape is not optimal
939 bool bCustGeom = true;
940 bool bOnDenylist = false;
941 if( sShapeType == "ooxml-non-primitive" )
942 bCustGeom = true;
943 else if( sShapeType.startsWith("ooxml") )
944 bCustGeom = false;
945 else if( lcl_IsOnAllowlist(sShapeType) )
946 bCustGeom = true;
947 else if( lcl_IsOnDenylist(sShapeType) )
948 {
949 bCustGeom = false;
950 bOnDenylist = true;
951 }
952
953 bool bPresetWriteSuccessful = false;
954 // Let the custom shapes what has name and preset information in OOXML, to be written
955 // as preset ones with parameters. Try that with this converter class.
956 if (!sShapeType.startsWith("ooxml") && sShapeType != "non-primitive" && !mbUserShapes
957 && xShape->getShapeType() == "com.sun.star.drawing.CustomShape"
958 && !lcl_IsOnAllowlist(sShapeType))
959 {
960 DMLPresetShapeExporter aCustomShapeConverter(this, xShape);
961 bPresetWriteSuccessful = aCustomShapeConverter.WriteShape();
962 }
963 // If preset writing has problems try to write the shape as it done before
964 if (bPresetWriteSuccessful)
965 ;// Already written do nothing.
966 else if (bCustGeom)
967 {
968 WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV );
969 bool bSuccess = WriteCustomGeometry(xShape, rSdrObjCustomShape);
970 // In case of Writer, the parent element is <wps:spPr>, and there the <a:custGeom> element
971 // is not optional.
972 if (!bSuccess && GetDocumentType() == DOCUMENT_DOCX)
973 {
975 }
976 }
977 else if (bOnDenylist && bHasHandles && nAdjustmentValuesIndex !=-1 && !sShapeType.startsWith("mso-spt"))
978 {
979 WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV );
981 std::vector< std::pair< sal_Int32, sal_Int32> > aHandlePositionList;
982 std::vector< std::pair< sal_Int32, sal_Int32> > aAvList;
983 aGeometrySeq[ nAdjustmentValuesIndex ].Value >>= aAdjustmentSeq ;
984
985 lcl_AnalyzeHandles( aHandles, aHandlePositionList, aAdjustmentSeq );
986
987 sal_Int32 nXPosition = 0;
988 sal_Int32 nYPosition = 0;
989 if ( !aHandlePositionList.empty() )
990 {
991 nXPosition = aHandlePositionList[0].first ;
992 nYPosition = aHandlePositionList[0].second ;
993 }
994 switch( eShapeType )
995 {
997 {
998 sal_Int32 adj3 = double(nYPosition)/aViewBox.Height *100000;
999 sal_Int32 adj4 = double(nXPosition)/aViewBox.Width *100000;
1000 lcl_AppendAdjustmentValue( aAvList, 1, 18750 );
1001 lcl_AppendAdjustmentValue( aAvList, 2, -8333 );
1002 lcl_AppendAdjustmentValue( aAvList, 3, adj3 );
1003 lcl_AppendAdjustmentValue( aAvList, 4, adj4 );
1004 break;
1005 }
1007 {
1008 sal_Int32 adj5 = double(nYPosition)/aViewBox.Height *100000;
1009 sal_Int32 adj6 = double(nXPosition)/aViewBox.Width *100000;
1010 sal_Int32 adj3 = 18750;
1011 sal_Int32 adj4 = -16667;
1012 lcl_AppendAdjustmentValue( aAvList, 1, 18750 );
1013 lcl_AppendAdjustmentValue( aAvList, 2, -8333 );
1014 if ( aHandlePositionList.size() > 1 )
1015 {
1016 nXPosition = aHandlePositionList[1].first ;
1017 nYPosition = aHandlePositionList[1].second ;
1018 adj3 = double(nYPosition)/aViewBox.Height *100000;
1019 adj4 = double(nXPosition)/aViewBox.Width *100000;
1020 }
1021 lcl_AppendAdjustmentValue( aAvList, 3, adj3 );
1022 lcl_AppendAdjustmentValue( aAvList, 4, adj4 );
1023 lcl_AppendAdjustmentValue( aAvList, 5, adj5 );
1024 lcl_AppendAdjustmentValue( aAvList, 6, adj6 );
1025 break;
1026 }
1031 {
1032 sal_Int32 adj1 = (double(nXPosition)/aViewBox.Width -0.5) *100000;
1033 sal_Int32 adj2 = (double(nYPosition)/aViewBox.Height -0.5) *100000;
1034 lcl_AppendAdjustmentValue( aAvList, 1, adj1 );
1035 lcl_AppendAdjustmentValue( aAvList, 2, adj2 );
1036 if ( eShapeType == mso_sptWedgeRRectCallout)
1037 {
1038 lcl_AppendAdjustmentValue( aAvList, 3, 16667);
1039 }
1040
1041 break;
1042 }
1044 {
1045 sal_Int32 adj = double( aViewBox.Width - nXPosition) / std::min( aViewBox.Width,aViewBox.Height ) * 100000;
1046 lcl_AppendAdjustmentValue( aAvList, 0, adj );
1047 break;
1048 }
1049 case mso_sptDonut:
1050 case mso_sptSun:
1051 case mso_sptMoon:
1052 case mso_sptNoSmoking:
1054 case mso_sptBevel:
1055 case mso_sptBracketPair:
1056 {
1057 sal_Int32 adj = double( nXPosition )/aViewBox.Width*100000 ;
1058 lcl_AppendAdjustmentValue( aAvList, 0, adj );
1059 break;
1060 }
1061 case mso_sptCan:
1062 case mso_sptCube:
1063 case mso_sptBracePair:
1065 {
1066 sal_Int32 adj = double( nYPosition )/aViewBox.Height *100000 ;
1067 lcl_AppendAdjustmentValue( aAvList, 0, adj );
1068 break;
1069 }
1070 case mso_sptSmileyFace:
1071 {
1072 sal_Int32 adj = double( nYPosition )/aViewBox.Height *100000 - 76458.0;
1073 lcl_AppendAdjustmentValue( aAvList, 0, adj );
1074 break;
1075 }
1076 case mso_sptBlockArc:
1077 {
1078 sal_Int32 nRadius = 50000 * ( 1 - double(nXPosition) / 10800);
1079 sal_Int32 nAngleStart = lcl_NormalizeAngle( nYPosition );
1080 sal_Int32 nAngleEnd = lcl_NormalizeAngle( 180 - nAngleStart );
1081 lcl_AppendAdjustmentValue( aAvList, 1, 21600000 / 360 * nAngleStart );
1082 lcl_AppendAdjustmentValue( aAvList, 2, 21600000 / 360 * nAngleEnd );
1083 lcl_AppendAdjustmentValue( aAvList, 3, nRadius );
1084 break;
1085 }
1086 // case mso_sptNil:
1087 // case mso_sptBentConnector3:
1088 // case mso_sptBorderCallout3:
1089 default:
1090 {
1091 if ( sPresetShape == "frame" )
1092 {
1093 sal_Int32 adj1 = double( nYPosition )/aViewBox.Height *100000 ;
1094 lcl_AppendAdjustmentValue( aAvList, 1, adj1 );
1095 }
1096 break;
1097 }
1098 }
1099 WritePresetShape( sPresetShape , aAvList );
1100 }
1101 else // preset geometry
1102 {
1103 WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV );
1104 if( nAdjustmentValuesIndex != -1 )
1105 {
1106 WritePresetShape( sPresetShape, eShapeType, bPredefinedHandlesUsed,
1107 aGeometrySeq[ nAdjustmentValuesIndex ] );
1108 }
1109 else
1110 WritePresetShape( sPresetShape );
1111 }
1112 if( rXPropSet.is() )
1113 {
1114 WriteFill(rXPropSet, xShape->getSize());
1115 WriteOutline( rXPropSet );
1116 WriteShapeEffects( rXPropSet );
1117
1118 bool bHas3DEffectinShape = false;
1119 uno::Sequence<beans::PropertyValue> grabBag;
1120 rXPropSet->getPropertyValue("InteropGrabBag") >>= grabBag;
1121
1122 for (auto const& it : std::as_const(grabBag))
1123 if (it.Name == "3DEffectProperties")
1124 bHas3DEffectinShape = true;
1125
1126 if( bHas3DEffectinShape)
1127 Write3DEffects( rXPropSet, /*bIsText=*/false );
1128 }
1129
1130 pFS->endElementNS( mnXmlNamespace, XML_spPr );
1131
1132 pFS->startElementNS(mnXmlNamespace, XML_style);
1133 WriteShapeStyle( rXPropSet );
1134 pFS->endElementNS( mnXmlNamespace, XML_style );
1135
1136 // write text
1137 WriteTextBox( xShape, mnXmlNamespace );
1138
1139 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
1140
1141 return *this;
1142}
1143
1145{
1146 SAL_INFO("oox.shape", "write ellipse shape");
1147
1148 FSHelperPtr pFS = GetFS();
1149
1150 pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp));
1151
1152 // TODO: connector ?
1153
1154 // non visual shape properties
1156 {
1157 pFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
1158 pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
1159 XML_id, OString::number(GetNewShapeID(xShape)),
1160 XML_name, GetShapeName(xShape));
1161 pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr );
1162 WriteNonVisualProperties( xShape );
1163 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
1164 }
1165 else
1166 pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
1167
1168 Reference< XPropertySet > xProps( xShape, UNO_QUERY );
1169 CircleKind eCircleKind(CircleKind_FULL);
1170 if (xProps.is())
1171 xProps->getPropertyValue("CircleKind" ) >>= eCircleKind;
1172
1173 // visual shape properties
1174 pFS->startElementNS( mnXmlNamespace, XML_spPr );
1175 WriteShapeTransformation( xShape, XML_a );
1176
1177 if (CircleKind_FULL == eCircleKind)
1178 WritePresetShape("ellipse");
1179 else
1180 {
1181 sal_Int32 nStartAngleIntern(9000);
1182 sal_Int32 nEndAngleIntern(0);
1183 if (xProps.is())
1184 {
1185 xProps->getPropertyValue("CircleStartAngle" ) >>= nStartAngleIntern;
1186 xProps->getPropertyValue("CircleEndAngle") >>= nEndAngleIntern;
1187 }
1188 std::vector< std::pair<sal_Int32,sal_Int32>> aAvList;
1189 awt::Size aSize = xShape->getSize();
1190 if (aSize.Width != 0 || aSize.Height != 0)
1191 {
1192 // Our arc has 90° up, OOXML has 90° down, so mirror it.
1193 // API angles are 1/100 degree.
1194 sal_Int32 nStartAngleOOXML(lcl_CircleAngle2CustomShapeEllipseAngleOOX(36000 - nEndAngleIntern, aSize.Width, aSize.Height));
1195 sal_Int32 nEndAngleOOXML(lcl_CircleAngle2CustomShapeEllipseAngleOOX(36000 - nStartAngleIntern, aSize.Width, aSize.Height));
1196 lcl_AppendAdjustmentValue( aAvList, 1, nStartAngleOOXML);
1197 lcl_AppendAdjustmentValue( aAvList, 2, nEndAngleOOXML);
1198 }
1199 switch (eCircleKind)
1200 {
1201 case CircleKind_ARC :
1202 WritePresetShape("arc", aAvList);
1203 break;
1204 case CircleKind_SECTION :
1205 WritePresetShape("pie", aAvList);
1206 break;
1207 case CircleKind_CUT :
1208 WritePresetShape("chord", aAvList);
1209 break;
1210 default :
1211 WritePresetShape("ellipse");
1212 }
1213 }
1214 if( xProps.is() )
1215 {
1216 if (CircleKind_ARC == eCircleKind)
1217 {
1218 // An arc in ODF is never filled, even if a fill style other than
1219 // "none" is set. OOXML arc can be filled, so set fill explicit to
1220 // NONE, otherwise some hidden or inherited filling is shown.
1221 FillStyle eFillStyle(FillStyle_NONE);
1222 uno::Any aNewValue;
1223 aNewValue <<= eFillStyle;
1224 xProps->setPropertyValue("FillStyle", aNewValue);
1225 }
1226 WriteFill( xProps );
1227 WriteOutline( xProps );
1228 }
1229 pFS->endElementNS( mnXmlNamespace, XML_spPr );
1230
1231 // write text
1232 WriteTextBox( xShape, mnXmlNamespace );
1233
1234 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
1235
1236 return *this;
1237}
1238
1240{
1242
1243 return *this;
1244}
1245
1247{
1248 SAL_INFO("oox.shape", "write graphic object shape");
1249
1250 if (IsNonEmptySimpleText(xShape))
1251 {
1252 SAL_INFO("oox.shape", "graphicObject: wrote only text");
1253
1254 WriteTextShape(xShape);
1255
1256 return;
1257 }
1258
1259 SAL_INFO("oox.shape", "graphicObject without text");
1260
1261 uno::Reference<graphic::XGraphic> xGraphic;
1262 OUString sMediaURL;
1263
1264 Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
1265
1266 if (pGraphic)
1267 {
1268 xGraphic.set(pGraphic->GetXGraphic());
1269 }
1270 else if (xShapeProps.is() && xShapeProps->getPropertySetInfo()->hasPropertyByName("Graphic"))
1271 {
1272 xShapeProps->getPropertyValue("Graphic") >>= xGraphic;
1273 }
1274
1275 bool bHasMediaURL = xShapeProps.is() && xShapeProps->getPropertySetInfo()->hasPropertyByName("MediaURL") && (xShapeProps->getPropertyValue("MediaURL") >>= sMediaURL);
1276
1277 if (!xGraphic.is() && !bHasMediaURL)
1278 {
1279 SAL_INFO("oox.shape", "no graphic or media URL found");
1280 return;
1281 }
1282
1283 FSHelperPtr pFS = GetFS();
1284 XmlFilterBase* pFB = GetFB();
1285
1287 pFS->startElementNS(mnXmlNamespace, XML_pic);
1288 else
1289 pFS->startElementNS(mnXmlNamespace, XML_pic,
1290 FSNS(XML_xmlns, XML_pic), pFB->getNamespaceURL(OOX_NS(dmlPicture)));
1291
1292 pFS->startElementNS(mnXmlNamespace, XML_nvPicPr);
1293
1294 presentation::ClickAction eClickAction = presentation::ClickAction_NONE;
1295 OUString sDescr, sURL, sBookmark, sPPAction;
1296 bool bHaveDesc;
1297
1298 if ( ( bHaveDesc = GetProperty( xShapeProps, "Description" ) ) )
1299 mAny >>= sDescr;
1300 if ( GetProperty( xShapeProps, "URL" ) )
1301 mAny >>= sURL;
1302 if (GetProperty(xShapeProps, "Bookmark"))
1303 mAny >>= sBookmark;
1304 if (GetProperty(xShapeProps, "OnClick"))
1305 mAny >>= eClickAction;
1306
1307 pFS->startElementNS( mnXmlNamespace, XML_cNvPr,
1308 XML_id, OString::number(GetNewShapeID(xShape)),
1309 XML_name, GetShapeName(xShape),
1310 XML_descr, sax_fastparser::UseIf(sDescr, bHaveDesc));
1311
1312 if (eClickAction != presentation::ClickAction_NONE)
1313 {
1314 switch (eClickAction)
1315 {
1316 case presentation::ClickAction_STOPPRESENTATION:
1317 sPPAction = "ppaction://hlinkshowjump?jump=endshow";
1318 break;
1319 case presentation::ClickAction_NEXTPAGE:
1320 sPPAction = "ppaction://hlinkshowjump?jump=nextslide";
1321 break;
1322 case presentation::ClickAction_LASTPAGE:
1323 sPPAction = "ppaction://hlinkshowjump?jump=lastslide";
1324 break;
1325 case presentation::ClickAction_PREVPAGE:
1326 sPPAction = "ppaction://hlinkshowjump?jump=previousslide";
1327 break;
1328 case presentation::ClickAction_FIRSTPAGE:
1329 sPPAction = "ppaction://hlinkshowjump?jump=firstslide";
1330 break;
1331 case presentation::ClickAction_BOOKMARK:
1332 sBookmark = "#" + sBookmark;
1333 break;
1334 default:
1335 break;
1336 }
1337 }
1338
1339 // OOXTODO: //cNvPr children: XML_extLst, XML_hlinkHover
1340 if (bHasMediaURL || !sPPAction.isEmpty())
1341 pFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), "", XML_action,
1342 bHasMediaURL ? "ppaction://media" : sPPAction);
1343 if( !sURL.isEmpty() )
1344 {
1345 OUString sRelId = mpFB->addRelation( mpFS->getOutputStream(),
1347 mpURLTransformer->getTransformedString(sURL),
1348 mpURLTransformer->isExternalURL(sURL));
1349
1350 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
1351 }
1352
1353 if (!sBookmark.isEmpty())
1354 {
1355 bool bExtURL = URLTransformer().isExternalURL(sBookmark);
1356 sBookmark = bExtURL ? sBookmark : lcl_GetTarget(GetFB()->getModel(), sBookmark);
1357
1358 OUString sRelId = mpFB->addRelation(mpFS->getOutputStream(),
1361 sBookmark, bExtURL);
1362
1363 if (bExtURL)
1364 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
1365 else
1366 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId, XML_action,
1367 "ppaction://hlinksldjump");
1368 }
1369 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
1370
1371 pFS->singleElementNS(mnXmlNamespace, XML_cNvPicPr
1372 // OOXTODO: XML_preferRelativeSize
1373 );
1374 if (bHasMediaURL)
1376 else
1378
1379 pFS->endElementNS( mnXmlNamespace, XML_nvPicPr );
1380
1381 pFS->startElementNS(mnXmlNamespace, XML_blipFill);
1382
1383 if (xGraphic.is())
1384 {
1385 WriteXGraphicBlip(xShapeProps, xGraphic, mbUserShapes);
1386 }
1387 else if (bHasMediaURL)
1388 {
1389 Reference<graphic::XGraphic> xFallbackGraphic;
1390 if (xShapeProps->getPropertySetInfo()->hasPropertyByName("FallbackGraphic"))
1391 xShapeProps->getPropertyValue("FallbackGraphic") >>= xFallbackGraphic;
1392
1393 WriteXGraphicBlip(xShapeProps, xFallbackGraphic, mbUserShapes);
1394 }
1395
1396 if (xGraphic.is())
1397 {
1398 WriteSrcRectXGraphic(xShapeProps, xGraphic);
1399 }
1400
1401 // now we stretch always when we get pGraphic (when changing that
1402 // behavior, test n#780830 for regression, where the OLE sheet might get tiled
1403 bool bStretch = false;
1404 if( !pGraphic && GetProperty( xShapeProps, "FillBitmapStretch" ) )
1405 mAny >>= bStretch;
1406
1407 if ( pGraphic || bStretch )
1408 pFS->singleElementNS(XML_a, XML_stretch);
1409
1410 if (bHasMediaURL)
1411 {
1412 // Graphic of media shapes is always stretched.
1413 pFS->startElementNS(XML_a, XML_stretch);
1414 pFS->singleElementNS(XML_a, XML_fillRect);
1415 pFS->endElementNS(XML_a, XML_stretch);
1416 }
1417
1418 pFS->endElementNS( mnXmlNamespace, XML_blipFill );
1419
1420 // visual shape properties
1421 pFS->startElementNS(mnXmlNamespace, XML_spPr);
1422 bool bFlipH = false;
1423 if( xShapeProps->getPropertySetInfo()->hasPropertyByName("IsMirrored") )
1424 {
1425 xShapeProps->getPropertyValue("IsMirrored") >>= bFlipH;
1426 }
1427 WriteShapeTransformation( xShape, XML_a, bFlipH, false, false, false, true );
1428 WritePresetShape( "rect" );
1429 // graphic object can come with the frame (bnc#654525)
1430 WriteOutline( xShapeProps );
1431
1432 WriteShapeEffects( xShapeProps );
1433 Write3DEffects( xShapeProps, /*bIsText=*/false );
1434
1435 pFS->endElementNS( mnXmlNamespace, XML_spPr );
1436
1437 pFS->endElementNS( mnXmlNamespace, XML_pic );
1438}
1439
1440static void lcl_Rotate(sal_Int32 nAngle, Point center, awt::Point& pt)
1441{
1442 sal_Int16 nCos, nSin;
1443 switch (nAngle)
1444 {
1445 case 90:
1446 nCos = 0;
1447 nSin = 1;
1448 break;
1449 case 180:
1450 nCos = -1;
1451 nSin = 0;
1452 break;
1453 case 270:
1454 nCos = 0;
1455 nSin = -1;
1456 break;
1457 default:
1458 return;
1459 }
1460 sal_Int32 x = pt.X - center.X();
1461 sal_Int32 y = pt.Y - center.Y();
1462 pt.X = center.X() + x * nCos - y * nSin;
1463 pt.Y = center.Y() + y * nCos + x * nSin;
1464}
1465
1466static void lcl_FlipHFlipV(tools::Polygon aPoly, sal_Int32 nAngle, bool& rFlipH, bool& rFlipV)
1467{
1468 Point aStart = aPoly[0];
1469 Point aEnd = aPoly[aPoly.GetSize() - 1];
1470
1471 if (aStart.X() > aEnd.X() && aStart.Y() > aEnd.Y())
1472 {
1473 if (nAngle)
1474 {
1475 if (nAngle == 90)
1476 rFlipH = true;
1477 if (nAngle == 270)
1478 rFlipV = true;
1479 }
1480 else // 0°
1481 {
1482 rFlipH = true;
1483 rFlipV = true;
1484 }
1485 }
1486
1487 if (aStart.X() < aEnd.X() && aStart.Y() < aEnd.Y())
1488 {
1489 if (nAngle)
1490 {
1491 if (nAngle != 270)
1492 {
1493 rFlipH = true;
1494 rFlipV = true;
1495 }
1496 else
1497 rFlipH = true;
1498 }
1499 }
1500
1501 if (aStart.Y() < aEnd.Y() && aStart.X() > aEnd.X())
1502 {
1503 if (nAngle)
1504 {
1505 if (nAngle == 180)
1506 rFlipV = true;
1507 if (nAngle == 270)
1508 {
1509 rFlipV = true;
1510 rFlipH = true;
1511 }
1512 }
1513 else // 0°
1514 {
1515 rFlipH = true;
1516 }
1517 }
1518
1519 if (aStart.Y() > aEnd.Y() && aStart.X() < aEnd.X())
1520 {
1521 if (nAngle)
1522 {
1523 if (nAngle == 90)
1524 {
1525 rFlipH = true;
1526 rFlipV = true;
1527 }
1528 if (nAngle == 180)
1529 rFlipH = true;
1530 }
1531 else // 0°
1532 rFlipV = true;
1533 }
1534}
1535
1536static sal_Int32 lcl_GetAngle(tools::Polygon aPoly)
1537{
1538 sal_Int32 nAngle;
1539 Point aStartPoint = aPoly[0];
1540 Point aEndPoint = aPoly[aPoly.GetSize() - 1];
1541 if (aStartPoint.X() == aPoly[1].X())
1542 {
1543 if ((aStartPoint.X() < aEndPoint.X() && aStartPoint.Y() > aEndPoint.Y())
1544 || (aStartPoint.X() > aEndPoint.X() && aStartPoint.Y() < aEndPoint.Y()))
1545 {
1546 nAngle = 90;
1547 }
1548 else
1549 nAngle = 270;
1550 }
1551 else
1552 {
1553 if (aStartPoint.X() > aPoly[1].X())
1554 nAngle = 180;
1555 else
1556 nAngle = 0;
1557 }
1558
1559 return nAngle;
1560}
1561
1562// Adjust value decide the position, where the connector should turn.
1564 ConnectorType eConnectorType,
1565 std::vector<std::pair<sal_Int32, sal_Int32>>& rAvList)
1566{
1567 sal_Int32 nAdjCount = 0;
1568 if (eConnectorType == ConnectorType_CURVE)
1569 {
1570 if (aPoly.GetSize() == 4)
1571 {
1572 if ((aPoly[0].X() == aPoly[1].X() && aPoly[2].X() == aPoly[3].X())
1573 || (aPoly[0].Y() == aPoly[1].Y() && aPoly[2].Y() == aPoly[3].Y()))
1574 {
1575 nAdjCount = 1; // curvedConnector3
1576 }
1577 else
1578 nAdjCount = 0; // curvedConnector2
1579 }
1580 else if (aPoly.GetSize() > 4)
1581 {
1582 if ((aPoly[2].X() == aPoly[3].X() && aPoly[3].X() == aPoly[4].X())
1583 || (aPoly[2].Y() == aPoly[3].Y() && aPoly[3].Y() == aPoly[4].Y()))
1584 {
1585 nAdjCount = 3; // curvedConnector5
1586 }
1587 else
1588 nAdjCount = 2; // curvedConnector4
1589 }
1590 }
1591 else
1592 {
1593 switch (aPoly.GetSize())
1594 {
1595 case 3:
1596 nAdjCount = 0; // bentConnector2
1597 break;
1598 case 4:
1599 nAdjCount = 1; // bentConnector3
1600 break;
1601 case 5:
1602 nAdjCount = 2; // bentConnector4
1603 break;
1604 case 6:
1605 nAdjCount = 3; // bentConnector5
1606 break;
1607 }
1608 }
1609
1610 if (nAdjCount)
1611 {
1612 sal_Int32 nAdjustValue;
1613 Point aStart = aPoly[0];
1614 Point aEnd = aPoly[aPoly.GetSize() - 1];
1615
1616 for (sal_Int32 i = 1; i <= nAdjCount; ++i)
1617 {
1618 Point aPt = aPoly[i];
1619
1620 if (aEnd.Y() == aStart.Y())
1621 aEnd.setY(aStart.Y() + 1);
1622 if (aEnd.X() == aStart.X())
1623 aEnd.setX(aStart.X() + 1);
1624
1625 bool bVertical = aPoly[1].X() - aStart.X() != 0 ? true : false;
1626 // vertical and horizon alternate
1627 if (i % 2 == 1)
1628 bVertical = !bVertical;
1629
1630 if (eConnectorType == ConnectorType_CURVE)
1631 {
1632 awt::Size aSize = xShape->getSize();
1633 awt::Point aShapePosition = xShape->getPosition();
1634 tools::Rectangle aBoundRect = aPoly.GetBoundRect();
1635
1636 if (bVertical)
1637 {
1638 if ((aBoundRect.GetSize().Height() - aSize.Height) == 1)
1639 aPt.setY(aPoly[i + 1].Y());
1640 else if (aStart.Y() > aPt.Y())
1641 aPt.setY(aShapePosition.Y);
1642 else
1643 aPt.setY(aShapePosition.Y + aSize.Height);
1644 }
1645 else
1646 {
1647 if ((aBoundRect.GetSize().Width() - aSize.Width) == 1)
1648 aPt.setX(aPoly[i + 1].X());
1649 else if (aStart.X() > aPt.X())
1650 aPt.setX(aShapePosition.X);
1651 else
1652 aPt.setX(aShapePosition.X + aSize.Width);
1653 }
1654 }
1655
1656 if (bVertical)
1657 nAdjustValue = ((aPt.Y() - aStart.Y()) * 100000) / (aEnd.Y() - aStart.Y());
1658 else
1659 nAdjustValue = ((aPt.X() - aStart.X()) * 100000) / (aEnd.X() - aStart.X());
1660
1661 rAvList.emplace_back(i, nAdjustValue);
1662 }
1663 }
1664}
1665
1666static sal_Int32 lcl_GetGluePointId(const Reference<XShape>& xShape, sal_Int32 nGluePointId)
1667{
1668 if (nGluePointId > 3)
1669 return nGluePointId - 4;
1670 else
1671 {
1672 bool bFlipH = false;
1673 bool bFlipV = false;
1674 Reference<XPropertySet> xShapeProps(xShape, UNO_QUERY);
1675 if (xShapeProps->getPropertySetInfo()->hasPropertyByName("CustomShapeGeometry"))
1676 {
1677 Sequence<PropertyValue> aGeometrySeq;
1678 xShapeProps->getPropertyValue("CustomShapeGeometry") >>= aGeometrySeq;
1679 for (int i = 0; i < aGeometrySeq.getLength(); i++)
1680 {
1681 const PropertyValue& rProp = aGeometrySeq[i];
1682 if (rProp.Name == "MirroredX")
1683 rProp.Value >>= bFlipH;
1684
1685 if (rProp.Name == "MirroredY")
1686 rProp.Value >>= bFlipV;
1687 }
1688 }
1689
1690 if ((!bFlipH && !bFlipV) || (bFlipH && bFlipV))
1691 {
1692 // change id of the bounding box (1 <-> 3)
1693 if (nGluePointId == 1)
1694 nGluePointId = 3; // Right
1695 else if (nGluePointId == 3)
1696 nGluePointId = 1; // Left
1697 }
1698 }
1699
1700 return nGluePointId;
1701}
1702
1704{
1705 bool bFlipH = false;
1706 bool bFlipV = false;
1707 sal_Int32 nAngle = 0;
1708 sal_Int32 nStartGlueId = 0;
1709 sal_Int32 nEndGlueId = 0;
1710
1711 SAL_INFO("oox.shape", "write connector shape");
1712
1713 FSHelperPtr pFS = GetFS();
1714
1715 OUString sGeometry;
1716 std::vector<std::pair<sal_Int32, sal_Int32>> aAdjustValueList;
1717 Reference< XPropertySet > rXPropSet( xShape, UNO_QUERY );
1718 Reference< XPropertyState > rXPropState( xShape, UNO_QUERY );
1719 awt::Point aStartPoint, aEndPoint;
1720 Reference< XShape > rXShapeA;
1721 Reference< XShape > rXShapeB;
1722 PropertyState eState;
1723 ConnectorType eConnectorType = ConnectorType_STANDARD;
1724 if (GetProperty(rXPropSet, "EdgeKind"))
1725 mAny >>= eConnectorType;
1726
1727 switch( eConnectorType ) {
1728 case ConnectorType_CURVE:
1729 sGeometry = "curvedConnector";
1730 break;
1731 case ConnectorType_LINES:
1732 case ConnectorType_STANDARD:
1733 sGeometry = "bentConnector";
1734 break;
1735 default:
1736 case ConnectorType_LINE:
1737 sGeometry = "straightConnector1";
1738 break;
1739 }
1740
1741 if (GetPropertyAndState( rXPropSet, rXPropState, "EdgeStartPoint", eState ) && eState == beans::PropertyState_DIRECT_VALUE )
1742 {
1743 mAny >>= aStartPoint;
1744 if (GetPropertyAndState( rXPropSet, rXPropState, "EdgeEndPoint", eState ) && eState == beans::PropertyState_DIRECT_VALUE )
1745 mAny >>= aEndPoint;
1746 }
1747 if (GetProperty(rXPropSet, "EdgeStartConnection"))
1748 mAny >>= rXShapeA;
1749 if (GetProperty(rXPropSet, "EdgeEndConnection"))
1750 mAny >>= rXShapeB;
1751
1752 if (GetProperty(rXPropSet, "StartGluePointIndex"))
1753 mAny >>= nStartGlueId;
1754 if (nStartGlueId != -1)
1755 nStartGlueId = lcl_GetGluePointId(rXShapeA, nStartGlueId);
1756
1757 if (GetProperty(rXPropSet, "EndGluePointIndex"))
1758 mAny >>= nEndGlueId;
1759 if (nEndGlueId != -1)
1760 nEndGlueId = lcl_GetGluePointId(rXShapeB, nEndGlueId);
1761
1762 // Position is relative to group in Word, but relative to anchor of group in API.
1764 {
1765 awt::Point aParentPos = m_xParent->getPosition();
1766 aStartPoint.X -= aParentPos.X;
1767 aStartPoint.Y -= aParentPos.Y;
1768 aEndPoint.X -= aParentPos.X;
1769 aEndPoint.Y -= aParentPos.Y;
1770 }
1771 EscherConnectorListEntry aConnectorEntry( xShape, aStartPoint, rXShapeA, aEndPoint, rXShapeB );
1772
1773 if (eConnectorType != ConnectorType_LINE)
1774 {
1776 if (aPolyPolygon.Count() > 0)
1777 {
1778 tools::Polygon aPoly = aPolyPolygon.GetObject(0);
1779 lcl_GetConnectorAdjustValue(xShape, aPoly, eConnectorType, aAdjustValueList);
1780 nAngle = lcl_GetAngle(aPoly);
1781 lcl_FlipHFlipV(aPoly, nAngle, bFlipH, bFlipV);
1782 if (nAngle)
1783 {
1784 Point center((aEndPoint.X + aStartPoint.X) / 2, (aEndPoint.Y + aStartPoint.Y) / 2);
1785 lcl_Rotate(nAngle, center, aStartPoint);
1786 lcl_Rotate(nAngle, center, aEndPoint);
1787 nAngle *= 60000;
1788 }
1789 sGeometry = sGeometry + OUString::number(aAdjustValueList.size() + 2);
1790 }
1791 }
1792
1793 tools::Rectangle aRect( Point( aStartPoint.X, aStartPoint.Y ), Point( aEndPoint.X, aEndPoint.Y ) );
1794 if( aRect.getOpenWidth() < 0 ) {
1795 aRect.SetLeft(aEndPoint.X);
1796 aRect.setWidth( aStartPoint.X - aEndPoint.X );
1797 if (eConnectorType == ConnectorType_LINE)
1798 bFlipH = true;
1799 }
1800
1801 if( aRect.getOpenHeight() < 0 ) {
1802 aRect.SetTop(aEndPoint.Y);
1803 aRect.setHeight( aStartPoint.Y - aEndPoint.Y );
1804 if (eConnectorType == ConnectorType_LINE)
1805 bFlipV = true;
1806 }
1807
1808 // tdf#99810 connector shape (cxnSp) is not valid with namespace 'wps'
1809 const auto nShapeNode = (mnXmlNamespace == XML_wps ? XML_wsp : XML_cxnSp);
1810 pFS->startElementNS(mnXmlNamespace, nShapeNode);
1811
1812 if (mnXmlNamespace == XML_wps)
1813 {
1814 // non visual connector shape drawing properties
1815 pFS->singleElementNS(mnXmlNamespace, XML_cNvCnPr);
1816 }
1817 else
1818 {
1819 // non visual shape properties
1820 pFS->startElementNS(mnXmlNamespace, XML_nvCxnSpPr);
1821 pFS->singleElementNS(mnXmlNamespace, XML_cNvPr,
1822 XML_id, OString::number(GetNewShapeID(xShape)),
1823 XML_name, GetShapeName(xShape));
1824 // non visual connector shape drawing properties
1825 pFS->startElementNS(mnXmlNamespace, XML_cNvCxnSpPr);
1826
1827 if (GetShapeID(rXShapeA) == -1)
1828 GetNewShapeID(rXShapeA);
1829 if (GetShapeID(rXShapeB) == -1)
1830 GetNewShapeID(rXShapeB);
1831 WriteConnectorConnections(nStartGlueId, nEndGlueId, GetShapeID(rXShapeA), GetShapeID(rXShapeB));
1832 pFS->endElementNS(mnXmlNamespace, XML_cNvCxnSpPr);
1834 pFS->singleElementNS(mnXmlNamespace, XML_nvPr);
1835 pFS->endElementNS(mnXmlNamespace, XML_nvCxnSpPr);
1836 }
1837
1838 // visual shape properties
1839 pFS->startElementNS(mnXmlNamespace, XML_spPr);
1840 WriteTransformation( xShape, aRect, XML_a, bFlipH, bFlipV, nAngle );
1841 // TODO: write adjustments (ppt export doesn't work well there either)
1842 WritePresetShape( sGeometry.toUtf8(), aAdjustValueList);
1843 Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
1844 if( xShapeProps.is() )
1845 WriteOutline( xShapeProps );
1846 pFS->endElementNS( mnXmlNamespace, XML_spPr );
1847
1848 // connector shape (cxnSp) cannot contain text (txBody) (according to schema)
1849 if( nShapeNode != XML_cxnSp )
1850 {
1851 // write text
1852 WriteTextBox( xShape, mnXmlNamespace );
1853 }
1854
1855 pFS->endElementNS(mnXmlNamespace, nShapeNode);
1856
1857 return *this;
1858}
1859
1861{
1862 bool bFlipH = false;
1863 bool bFlipV = false;
1864
1865 SAL_INFO("oox.shape", "write line shape");
1866
1867 FSHelperPtr pFS = GetFS();
1868
1869 pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp));
1870
1872 if( aPolyPolygon.Count() == 1 && aPolyPolygon[ 0 ].GetSize() == 2)
1873 {
1874 const tools::Polygon& rPoly = aPolyPolygon[ 0 ];
1875
1876 bFlipH = ( rPoly[ 0 ].X() > rPoly[ 1 ].X() );
1877 bFlipV = ( rPoly[ 0 ].Y() > rPoly[ 1 ].Y() );
1878 }
1879
1880 // non visual shape properties
1882 {
1883 pFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
1884 pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
1885 XML_id, OString::number(GetNewShapeID(xShape)),
1886 XML_name, GetShapeName(xShape));
1887 }
1888 pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr );
1890 {
1891 WriteNonVisualProperties( xShape );
1892 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
1893 }
1894
1895 // visual shape properties
1896 pFS->startElementNS(mnXmlNamespace, XML_spPr);
1897 WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV, true);
1898 WritePresetShape( "line" );
1899 Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
1900 if( xShapeProps.is() )
1901 WriteOutline( xShapeProps );
1902 pFS->endElementNS( mnXmlNamespace, XML_spPr );
1903
1904 //write style
1905 pFS->startElementNS(mnXmlNamespace, XML_style);
1906 WriteShapeStyle( xShapeProps );
1907 pFS->endElementNS( mnXmlNamespace, XML_style );
1908
1909 // write text
1910 WriteTextBox( xShape, mnXmlNamespace );
1911
1912 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
1913
1914 return *this;
1915}
1916
1918{
1919 GetFS()->singleElementNS( mnXmlNamespace, XML_cNvPr,
1920 XML_id, OString::number(GetNewShapeID(xShape)),
1921 XML_name, pName );
1922
1923 return *this;
1924}
1925
1927{
1928 // Override to generate //nvPr elements.
1929 return *this;
1930}
1931
1933{
1934 SAL_INFO("oox.shape", "write rectangle shape");
1935
1936 FSHelperPtr pFS = GetFS();
1937
1938 pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp));
1939
1940 sal_Int32 nRadius = 0;
1941
1942 Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
1943 if( xShapeProps.is() )
1944 {
1945 xShapeProps->getPropertyValue( "CornerRadius" ) >>= nRadius;
1946 }
1947
1948 if( nRadius )
1949 {
1950 nRadius = MapSize( awt::Size( nRadius, 0 ) ).Width;
1951 }
1952 //TODO: use nRadius value more precisely than just deciding whether to use
1953 // "rect" or "roundRect" preset shape below
1954
1955 // non visual shape properties
1957 pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
1958 pFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
1959 pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
1960 XML_id, OString::number(GetNewShapeID(xShape)),
1961 XML_name, GetShapeName(xShape));
1962 pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
1963 WriteNonVisualProperties( xShape );
1964 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
1965
1966 // visual shape properties
1967 pFS->startElementNS(mnXmlNamespace, XML_spPr);
1968 WriteShapeTransformation( xShape, XML_a );
1969 WritePresetShape( nRadius == 0 ? "rect" : "roundRect" );
1970 Reference< XPropertySet > xProps( xShape, UNO_QUERY );
1971 if( xProps.is() )
1972 {
1973 WriteFill( xProps );
1974 WriteOutline( xProps );
1975 }
1976 pFS->endElementNS( mnXmlNamespace, XML_spPr );
1977
1978 // write text
1979 WriteTextBox( xShape, mnXmlNamespace );
1980
1981 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
1982
1983 return *this;
1984}
1985
1987typedef std::unordered_map< const char*, ShapeConverter, rtl::CStringHash, rtl::CStringEqual> NameToConvertMapType;
1988
1990{
1991 static NameToConvertMapType const shape_converters
1992 {
1993 // tdf#98736 export CaptionShape as TextShape, because it is non-ooxml shape and
1994 // we can't export this shape as CustomShape
1995 // TODO: WriteCaptionShape
1996 { "com.sun.star.drawing.CaptionShape" , &ShapeExport::WriteTextShape },
1997
1998 { "com.sun.star.drawing.ClosedBezierShape" , &ShapeExport::WriteClosedPolyPolygonShape },
1999 { "com.sun.star.drawing.ConnectorShape" , &ShapeExport::WriteConnectorShape },
2000 { "com.sun.star.drawing.CustomShape" , &ShapeExport::WriteCustomShape },
2001 { "com.sun.star.drawing.EllipseShape" , &ShapeExport::WriteEllipseShape },
2002 { "com.sun.star.drawing.GraphicObjectShape" , &ShapeExport::WriteGraphicObjectShape },
2003 { "com.sun.star.drawing.LineShape" , &ShapeExport::WriteLineShape },
2004 { "com.sun.star.drawing.MediaShape" , &ShapeExport::WriteGraphicObjectShape },
2005 { "com.sun.star.drawing.OpenBezierShape" , &ShapeExport::WriteOpenPolyPolygonShape },
2006 { "com.sun.star.drawing.PolyPolygonShape" , &ShapeExport::WriteClosedPolyPolygonShape },
2007 { "com.sun.star.drawing.PolyLineShape" , &ShapeExport::WriteOpenPolyPolygonShape },
2008 { "com.sun.star.drawing.RectangleShape" , &ShapeExport::WriteRectangleShape },
2009 { "com.sun.star.drawing.OLE2Shape" , &ShapeExport::WriteOLE2Shape },
2010 { "com.sun.star.drawing.TableShape" , &ShapeExport::WriteTableShape },
2011 { "com.sun.star.drawing.TextShape" , &ShapeExport::WriteTextShape },
2012 { "com.sun.star.drawing.GroupShape" , &ShapeExport::WriteGroupShape },
2013
2014 { "com.sun.star.presentation.GraphicObjectShape" , &ShapeExport::WriteGraphicObjectShape },
2015 { "com.sun.star.presentation.MediaShape" , &ShapeExport::WriteGraphicObjectShape },
2016 { "com.sun.star.presentation.ChartShape" , &ShapeExport::WriteOLE2Shape },
2017 { "com.sun.star.presentation.OLE2Shape" , &ShapeExport::WriteOLE2Shape },
2018 { "com.sun.star.presentation.TableShape" , &ShapeExport::WriteTableShape },
2019 { "com.sun.star.presentation.TextShape" , &ShapeExport::WriteTextShape },
2020
2021 { "com.sun.star.presentation.DateTimeShape" , &ShapeExport::WriteTextShape },
2022 { "com.sun.star.presentation.FooterShape" , &ShapeExport::WriteTextShape },
2023 { "com.sun.star.presentation.HeaderShape" , &ShapeExport::WriteTextShape },
2024 { "com.sun.star.presentation.NotesShape" , &ShapeExport::WriteTextShape },
2025 { "com.sun.star.presentation.OutlinerShape" , &ShapeExport::WriteTextShape },
2026 { "com.sun.star.presentation.SlideNumberShape" , &ShapeExport::WriteTextShape },
2027 { "com.sun.star.presentation.TitleTextShape" , &ShapeExport::WriteTextShape },
2028 };
2029 return shape_converters;
2030}
2031
2033{
2034 if (!xShape)
2035 throw lang::IllegalArgumentException();
2036
2037 OUString sShapeType = xShape->getShapeType();
2038 SAL_INFO("oox.shape", "write shape: " << sShapeType);
2039 NameToConvertMapType::const_iterator aConverter
2040 = lcl_GetConverters().find(sShapeType.toUtf8().getStr());
2041 if (aConverter == lcl_GetConverters().end())
2042 {
2043 SAL_INFO("oox.shape", "unknown shape");
2044 return WriteUnknownShape( xShape );
2045 }
2046
2048 {
2049 Reference< XPropertySet > xShapeProperties(xShape, UNO_QUERY);
2050 if (xShapeProperties && xShapeProperties->getPropertySetInfo()
2051 && xShapeProperties->getPropertySetInfo()->hasPropertyByName("IsPresentationObject")
2052 && xShapeProperties->getPropertyValue("IsPresentationObject").hasValue())
2053 mbPlaceholder = xShapeProperties->getPropertyValue("IsPresentationObject").get<bool>();
2054 }
2055
2056 (this->*(aConverter->second))( xShape );
2057
2058 return *this;
2059}
2060
2061static bool lcl_isTextBox(const Reference<XInterface>& xIface)
2062{
2063 uno::Reference<beans::XPropertySet> xPropertySet(xIface, uno::UNO_QUERY);
2064 if (!xPropertySet.is())
2065 return false;
2066 uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
2067 if (!xPropertySetInfo->hasPropertyByName("TextBox"))
2068 return false;
2069 css::uno::Any aTextBox(xPropertySet->getPropertyValue("TextBox"));
2070 if (!aTextBox.hasValue())
2071 return false;
2072 return aTextBox.get<bool>();
2073}
2074
2075ShapeExport& ShapeExport::WriteTextBox( const Reference< XInterface >& xIface, sal_Int32 nXmlNamespace, bool bWritePropertiesAsLstStyles )
2076{
2077 // In case this shape has an associated textbox, then export that, and we're done.
2079 {
2080 if (lcl_isTextBox(xIface))
2081 {
2082 GetTextExport()->WriteTextBox(uno::Reference<drawing::XShape>(xIface, uno::UNO_QUERY_THROW));
2083 WriteText( xIface, /*bBodyPr=*/true, /*bText=*/false, /*nXmlNamespace=*/nXmlNamespace );
2084 return *this;
2085 }
2086 }
2087
2088 Reference< XText > xXText( xIface, UNO_QUERY );
2089 if( (NonEmptyText( xIface ) || GetDocumentType() == DOCUMENT_PPTX)
2090 && xXText.is() )
2091 {
2092 FSHelperPtr pFS = GetFS();
2093
2094 pFS->startElementNS(nXmlNamespace,
2095 (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_txBody : XML_txbx));
2096 WriteText(xIface, /*bBodyPr=*/(GetDocumentType() != DOCUMENT_DOCX || mbUserShapes), /*bText=*/true,
2097 /*nXmlNamespace=*/0, /*bWritePropertiesAsLstStyles=*/bWritePropertiesAsLstStyles);
2098 pFS->endElementNS( nXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_txBody : XML_txbx) );
2100 WriteText( xIface, /*bBodyPr=*/true, /*bText=*/false, /*nXmlNamespace=*/nXmlNamespace );
2101 }
2102 else if (GetDocumentType() == DOCUMENT_DOCX && !mbUserShapes)
2103 mpFS->singleElementNS(nXmlNamespace, XML_bodyPr);
2104
2105 return *this;
2106}
2107
2109{
2110 Reference< XTable > xTable;
2111 Reference< XPropertySet > xPropSet( rXShape, UNO_QUERY );
2112
2113 mpFS->startElementNS(XML_a, XML_graphic);
2114 mpFS->startElementNS(XML_a, XML_graphicData,
2115 XML_uri, "http://schemas.openxmlformats.org/drawingml/2006/table");
2116
2117 if ( xPropSet.is() && ( xPropSet->getPropertyValue( "Model" ) >>= xTable ) )
2118 {
2119 mpFS->startElementNS(XML_a, XML_tbl);
2120 mpFS->startElementNS(XML_a, XML_tblPr);
2121 WriteShapeEffects(xPropSet);
2122 mpFS->endElementNS(XML_a, XML_tblPr);
2123
2124 Reference< container::XIndexAccess > xColumns( xTable->getColumns(), UNO_QUERY_THROW );
2125 Reference< container::XIndexAccess > xRows( xTable->getRows(), UNO_QUERY_THROW );
2126 sal_uInt16 nRowCount = static_cast< sal_uInt16 >( xRows->getCount() );
2127 sal_uInt16 nColumnCount = static_cast< sal_uInt16 >( xColumns->getCount() );
2128
2129 mpFS->startElementNS(XML_a, XML_tblGrid);
2130
2131 for ( sal_Int32 x = 0; x < nColumnCount; x++ )
2132 {
2133 Reference< XPropertySet > xColPropSet( xColumns->getByIndex( x ), UNO_QUERY_THROW );
2134 sal_Int32 nWidth(0);
2135 xColPropSet->getPropertyValue( "Width" ) >>= nWidth;
2136
2137 mpFS->singleElementNS(XML_a, XML_gridCol,
2138 XML_w, OString::number(oox::drawingml::convertHmmToEmu(nWidth)));
2139 }
2140
2141 mpFS->endElementNS( XML_a, XML_tblGrid );
2142
2143 // map for holding the transpose index of the merged cells and pair<parentTransposeIndex, parentCell>
2144 typedef std::unordered_map<sal_Int32, std::pair<sal_Int32, Reference< XMergeableCell> > > transposeTableMap;
2145 transposeTableMap mergedCellMap;
2146
2147 for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ )
2148 {
2149 Reference< XPropertySet > xRowPropSet( xRows->getByIndex( nRow ), UNO_QUERY_THROW );
2150 sal_Int32 nRowHeight(0);
2151
2152 xRowPropSet->getPropertyValue( "Height" ) >>= nRowHeight;
2153
2154 mpFS->startElementNS(XML_a, XML_tr,
2155 XML_h, OString::number(oox::drawingml::convertHmmToEmu(nRowHeight)));
2156 for( sal_Int32 nColumn = 0; nColumn < nColumnCount; nColumn++ )
2157 {
2158 Reference< XMergeableCell > xCell( xTable->getCellByPosition( nColumn, nRow ),
2159 UNO_QUERY_THROW );
2160 sal_Int32 transposedIndexofCell = (nRow * nColumnCount) + nColumn;
2161
2162 //assume we will open a cell, set to false below if we won't
2163 bool bCellOpened = true;
2164
2165 if(xCell->getColumnSpan() > 1 && xCell->getRowSpan() > 1)
2166 {
2167 // having both : horizontal and vertical merge
2168 mpFS->startElementNS(XML_a, XML_tc,
2169 XML_gridSpan, OString::number(xCell->getColumnSpan()),
2170 XML_rowSpan, OString::number(xCell->getRowSpan()));
2171 // since, XMergeableCell doesn't have the information about
2172 // cell having hMerge or vMerge.
2173 // So, Populating the merged cell map in-order to use it to
2174 // decide the attribute for the individual cell.
2175 for(sal_Int32 columnIndex = nColumn; columnIndex < nColumn+xCell->getColumnSpan(); ++columnIndex)
2176 {
2177 for(sal_Int32 rowIndex = nRow; rowIndex < nRow+xCell->getRowSpan(); ++rowIndex)
2178 {
2179 sal_Int32 transposeIndexForMergeCell =
2180 (rowIndex * nColumnCount) + columnIndex;
2181 mergedCellMap[transposeIndexForMergeCell] =
2182 std::make_pair(transposedIndexofCell, xCell);
2183 }
2184 }
2185
2186 }
2187 else if(xCell->getColumnSpan() > 1)
2188 {
2189 // having : horizontal merge
2190 mpFS->startElementNS(XML_a, XML_tc,
2191 XML_gridSpan, OString::number(xCell->getColumnSpan()));
2192 for(sal_Int32 columnIndex = nColumn; columnIndex < nColumn + xCell->getColumnSpan(); ++columnIndex) {
2193 sal_Int32 transposeIndexForMergeCell = (nRow*nColumnCount) + columnIndex;
2194 mergedCellMap[transposeIndexForMergeCell] =
2195 std::make_pair(transposedIndexofCell, xCell);
2196 }
2197 }
2198 else if(xCell->getRowSpan() > 1)
2199 {
2200 // having : vertical merge
2201 mpFS->startElementNS(XML_a, XML_tc,
2202 XML_rowSpan, OString::number(xCell->getRowSpan()));
2203
2204 for(sal_Int32 rowIndex = nRow; rowIndex < nRow + xCell->getRowSpan(); ++rowIndex) {
2205 sal_Int32 transposeIndexForMergeCell = (rowIndex*nColumnCount) + nColumn;
2206 mergedCellMap[transposeIndexForMergeCell] =
2207 std::make_pair(transposedIndexofCell, xCell);
2208 }
2209 }
2210 else
2211 {
2212 // now, the cell can be an independent cell or
2213 // it can be a cell which is been merged to some parent cell
2214 if(!xCell->isMerged())
2215 {
2216 // independent cell
2217 mpFS->startElementNS(XML_a, XML_tc);
2218 }
2219 else
2220 {
2221 // it a merged cell to some parent cell
2222 // find the parent cell for the current cell at hand
2223 transposeTableMap::iterator it = mergedCellMap.find(transposedIndexofCell);
2224 if(it != mergedCellMap.end())
2225 {
2226 sal_Int32 transposeIndexOfParent = it->second.first;
2227 Reference< XMergeableCell > parentCell = it->second.second;
2228 // finding the row and column index for the parent cell from transposed index
2229 sal_Int32 parentColumnIndex = transposeIndexOfParent % nColumnCount;
2230 sal_Int32 parentRowIndex = transposeIndexOfParent / nColumnCount;
2231 if(nColumn == parentColumnIndex)
2232 {
2233 // the cell is vertical merge and it might have gridspan
2234 if(parentCell->getColumnSpan() > 1)
2235 {
2236 // vMerge and has gridSpan
2237 mpFS->startElementNS(XML_a, XML_tc,
2238 XML_vMerge, OString::number(1),
2239 XML_gridSpan, OString::number(xCell->getColumnSpan()));
2240 }
2241 else
2242 {
2243 // only vMerge
2244 mpFS->startElementNS(XML_a, XML_tc,
2245 XML_vMerge, OString::number(1));
2246 }
2247 }
2248 else if(nRow == parentRowIndex)
2249 {
2250 // the cell is horizontal merge and it might have rowspan
2251 if(parentCell->getRowSpan() > 1)
2252 {
2253 // hMerge and has rowspan
2254 mpFS->startElementNS(XML_a, XML_tc,
2255 XML_hMerge, OString::number(1),
2256 XML_rowSpan, OString::number(xCell->getRowSpan()));
2257 }
2258 else
2259 {
2260 // only hMerge
2261 mpFS->startElementNS(XML_a, XML_tc,
2262 XML_hMerge, OString::number(1));
2263 }
2264 }
2265 else
2266 {
2267 // has hMerge and vMerge
2268 mpFS->startElementNS(XML_a, XML_tc,
2269 XML_vMerge, OString::number(1),
2270 XML_hMerge, OString::number(1));
2271 }
2272 }
2273 else
2274 bCellOpened = false;
2275 }
2276 }
2277
2278 if (bCellOpened)
2279 {
2280 WriteTextBox( xCell, XML_a );
2281
2282 Reference< XPropertySet > xCellPropSet(xCell, UNO_QUERY_THROW);
2283 WriteTableCellProperties(xCellPropSet);
2284
2285 mpFS->endElementNS( XML_a, XML_tc );
2286 }
2287 }
2288
2289 mpFS->endElementNS( XML_a, XML_tr );
2290 }
2291
2292 mpFS->endElementNS( XML_a, XML_tbl );
2293 }
2294
2295 mpFS->endElementNS( XML_a, XML_graphicData );
2296 mpFS->endElementNS( XML_a, XML_graphic );
2297}
2298
2300{
2301 sal_Int32 nLeftMargin(0), nRightMargin(0);
2302 TextVerticalAdjust eVerticalAlignment;
2303 const char* sVerticalAlignment;
2304
2305 Any aLeftMargin = xCellPropSet->getPropertyValue("TextLeftDistance");
2306 aLeftMargin >>= nLeftMargin;
2307
2308 Any aRightMargin = xCellPropSet->getPropertyValue("TextRightDistance");
2309 aRightMargin >>= nRightMargin;
2310
2311 Any aVerticalAlignment = xCellPropSet->getPropertyValue("TextVerticalAdjust");
2312 aVerticalAlignment >>= eVerticalAlignment;
2313 sVerticalAlignment = GetTextVerticalAdjust(eVerticalAlignment);
2314
2315 sal_Int32 nRotateAngle = 0;
2316 Any aRotateAngle = xCellPropSet->getPropertyValue("RotateAngle");
2317 aRotateAngle >>= nRotateAngle;
2318 std::optional<OString> aTextVerticalValue = GetTextVerticalType(nRotateAngle);
2319
2320 Sequence<PropertyValue> aGrabBag;
2321 if( !aTextVerticalValue &&
2322 (xCellPropSet->getPropertyValue("CellInteropGrabBag") >>= aGrabBag) )
2323 {
2324 for (auto const& rIt : std::as_const(aGrabBag))
2325 {
2326 if (rIt.Name == "mso-tcPr-vert-value")
2327 {
2328 aTextVerticalValue = rIt.Value.get<OUString>().toUtf8();
2329 break;
2330 }
2331 }
2332 }
2333
2334 mpFS->startElementNS(XML_a, XML_tcPr, XML_anchor, sVerticalAlignment,
2335 XML_vert, aTextVerticalValue,
2338
2339 // Write background fill for table cell.
2340 // TODO
2341 // tcW : Table cell width
2342 WriteTableCellBorders(xCellPropSet);
2343 DrawingML::WriteFill(xCellPropSet);
2344 mpFS->endElementNS( XML_a, XML_tcPr );
2345}
2346
2347void ShapeExport::WriteBorderLine(const sal_Int32 XML_line, const BorderLine2& rBorderLine)
2348{
2349// While importing the table cell border line width, it converts EMU->Hmm then divided result by 2.
2350// To get original value of LineWidth need to multiple by 2.
2351 sal_Int32 nBorderWidth = rBorderLine.LineWidth;
2352 nBorderWidth *= 2;
2354
2355 if ( nBorderWidth > 0 )
2356 {
2357 mpFS->startElementNS(XML_a, XML_line, XML_w, OString::number(nBorderWidth));
2358 if ( rBorderLine.Color == sal_Int32( COL_AUTO ) )
2359 mpFS->singleElementNS(XML_a, XML_noFill);
2360 else
2362
2363 OUString sBorderStyle;
2364 sal_Int16 nStyle = rBorderLine.LineStyle;
2365 mAny.setValue(&nStyle, cppu::UnoType<sal_Int16>::get());
2366 switch (*o3tl::doAccess<sal_Int16>(mAny))
2367 {
2368 case ::table::BorderLineStyle::SOLID:
2369 sBorderStyle = "solid";
2370 break;
2371 case ::table::BorderLineStyle::DOTTED:
2372 sBorderStyle = "dot";
2373 break;
2374 case ::table::BorderLineStyle::DASHED:
2375 sBorderStyle = "dash";
2376 break;
2377 case ::table::BorderLineStyle::DASH_DOT:
2378 sBorderStyle = "dashDot";
2379 break;
2380 case ::table::BorderLineStyle::DASH_DOT_DOT:
2381 sBorderStyle = "sysDashDotDot";
2382 break;
2383 }
2384 mpFS->singleElementNS(XML_a, XML_prstDash, XML_val, sBorderStyle);
2385 mpFS->endElementNS(XML_a, XML_line);
2386 }
2387 else if( nBorderWidth == 0)
2388 {
2389 mpFS->startElementNS(XML_a, XML_line);
2390 mpFS->singleElementNS(XML_a, XML_noFill);
2391 mpFS->endElementNS( XML_a, XML_line );
2392 }
2393}
2394
2396{
2397 BorderLine2 aBorderLine;
2398
2399// lnL - Left Border Line Properties of table cell
2400 xCellPropSet->getPropertyValue("LeftBorder") >>= aBorderLine;
2401 WriteBorderLine( XML_lnL, aBorderLine );
2402
2403// lnR - Right Border Line Properties of table cell
2404 xCellPropSet->getPropertyValue("RightBorder") >>= aBorderLine;
2405 WriteBorderLine( XML_lnR, aBorderLine );
2406
2407// lnT - Top Border Line Properties of table cell
2408 xCellPropSet->getPropertyValue("TopBorder") >>= aBorderLine;
2409 WriteBorderLine( XML_lnT, aBorderLine );
2410
2411// lnB - Bottom Border Line Properties of table cell
2412 xCellPropSet->getPropertyValue("BottomBorder") >>= aBorderLine;
2413 WriteBorderLine( XML_lnB, aBorderLine );
2414}
2415
2417{
2418 FSHelperPtr pFS = GetFS();
2419
2420 pFS->startElementNS(mnXmlNamespace, XML_graphicFrame);
2421
2422 pFS->startElementNS(mnXmlNamespace, XML_nvGraphicFramePr);
2423
2424 pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
2425 XML_id, OString::number(GetNewShapeID(xShape)),
2426 XML_name, GetShapeName(xShape));
2427
2428 pFS->singleElementNS(mnXmlNamespace, XML_cNvGraphicFramePr);
2429
2431 pFS->singleElementNS(mnXmlNamespace, XML_nvPr);
2432 pFS->endElementNS( mnXmlNamespace, XML_nvGraphicFramePr );
2433
2435 WriteTable( xShape );
2436
2437 pFS->endElementNS( mnXmlNamespace, XML_graphicFrame );
2438
2439 return *this;
2440}
2441
2443{
2444 FSHelperPtr pFS = GetFS();
2445 Reference<XPropertySet> xShapeProps(xShape, UNO_QUERY);
2446
2447 pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp));
2448
2449 // non visual shape properties
2451 {
2452 pFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
2453 pFS->startElementNS(mnXmlNamespace, XML_cNvPr,
2454 XML_id, OString::number(GetNewShapeID(xShape)),
2455 XML_name, GetShapeName(xShape));
2456 OUString sURL;
2457 if (GetProperty(xShapeProps, "URL"))
2458 mAny >>= sURL;
2459
2460 if (!sURL.isEmpty())
2461 {
2462 OUString sRelId = mpFB->addRelation(mpFS->getOutputStream(),
2464 mpURLTransformer->getTransformedString(sURL),
2465 mpURLTransformer->isExternalURL(sURL));
2466
2467 mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
2468 }
2469 pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
2470 }
2471 pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr, XML_txBox, "1");
2473 {
2474 WriteNonVisualProperties( xShape );
2475 pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
2476 }
2477
2478 // visual shape properties
2479 pFS->startElementNS(mnXmlNamespace, XML_spPr);
2480 WriteShapeTransformation( xShape, XML_a );
2481 WritePresetShape( "rect" );
2482 uno::Reference<beans::XPropertySet> xPropertySet(xShape, UNO_QUERY);
2483 if (!IsFontworkShape(xShapeProps)) // Fontwork needs fill and outline in run properties instead.
2484 {
2485 WriteBlipOrNormalFill(xPropertySet, "Graphic", xShape->getSize());
2486 WriteOutline(xPropertySet);
2487 WriteShapeEffects(xPropertySet);
2488 }
2489 pFS->endElementNS( mnXmlNamespace, XML_spPr );
2490
2491 WriteTextBox( xShape, mnXmlNamespace );
2492
2493 pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
2494
2495 return *this;
2496}
2497
2499{
2500 Reference<XPropertySet> const xPropSet(xShape, UNO_QUERY);
2501 assert(xPropSet.is());
2502 Reference<XModel> xMathModel;
2503 xPropSet->getPropertyValue("Model") >>= xMathModel;
2504 assert(xMathModel.is());
2505 assert(GetDocumentType() != DOCUMENT_DOCX); // should be written in DocxAttributeOutput
2506 SAL_WARN_IF(GetDocumentType() == DOCUMENT_XLSX, "oox.shape", "Math export to XLSX isn't tested, should it happen here?");
2507
2508 // ECMA standard does not actually allow oMath outside of
2509 // WordProcessingML so write a MCE like PPT 2010 does
2510 mpFS->startElementNS(XML_mc, XML_AlternateContent);
2511 mpFS->startElementNS(XML_mc, XML_Choice,
2512 FSNS(XML_xmlns, XML_a14), mpFB->getNamespaceURL(OOX_NS(a14)),
2513 XML_Requires, "a14");
2514 mpFS->startElementNS(mnXmlNamespace, XML_sp);
2515 mpFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
2516 mpFS->singleElementNS(mnXmlNamespace, XML_cNvPr,
2517 XML_id, OString::number(GetNewShapeID(xShape)),
2518 XML_name, GetShapeName(xShape));
2519 mpFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr, XML_txBox, "1");
2520 mpFS->singleElementNS(mnXmlNamespace, XML_nvPr);
2521 mpFS->endElementNS(mnXmlNamespace, XML_nvSpPr);
2522 mpFS->startElementNS(mnXmlNamespace, XML_spPr);
2523 WriteShapeTransformation(xShape, XML_a);
2524 WritePresetShape("rect");
2525 mpFS->endElementNS(mnXmlNamespace, XML_spPr);
2526 mpFS->startElementNS(mnXmlNamespace, XML_txBody);
2527 mpFS->startElementNS(XML_a, XML_bodyPr);
2528 mpFS->endElementNS(XML_a, XML_bodyPr);
2529 mpFS->startElementNS(XML_a, XML_p);
2530 mpFS->startElementNS(XML_a14, XML_m);
2531
2532 oox::FormulaImExportBase *const pMagic(
2533 dynamic_cast<oox::FormulaImExportBase*>(xMathModel.get()));
2534 assert(pMagic);
2535 pMagic->writeFormulaOoxml(GetFS(), GetFB()->getVersion(), GetDocumentType(),
2536 FormulaImExportBase::eFormulaAlign::INLINE);
2537
2538 mpFS->endElementNS(XML_a14, XML_m);
2539 mpFS->endElementNS(XML_a, XML_p);
2540 mpFS->endElementNS(mnXmlNamespace, XML_txBody);
2541 mpFS->endElementNS(mnXmlNamespace, XML_sp);
2542 mpFS->endElementNS(XML_mc, XML_Choice);
2543 mpFS->startElementNS(XML_mc, XML_Fallback);
2544 // TODO: export bitmap shape as fallback
2545 mpFS->endElementNS(XML_mc, XML_Fallback);
2546 mpFS->endElementNS(XML_mc, XML_AlternateContent);
2547}
2548
2550{
2551 Reference< XPropertySet > xPropSet( xShape, UNO_QUERY );
2552 if (!xPropSet.is())
2553 return *this;
2554
2555 enum { CHART, MATH, OTHER } eType(OTHER);
2556 OUString clsid;
2557 xPropSet->getPropertyValue("CLSID") >>= clsid;
2558 if (!clsid.isEmpty())
2559 {
2561 bool const isValid = aClassID.MakeId(clsid);
2562 assert(isValid); (void)isValid;
2564 eType = CHART;
2565 else if (SotExchange::IsMath(aClassID))
2566 eType = MATH;
2567 }
2568
2569 if (CHART == eType)
2570 {
2572 xPropSet->getPropertyValue("Model") >>= xChartDoc;
2573 assert(xChartDoc.is());
2574 //export the chart
2575#if !ENABLE_WASM_STRIP_CHART
2576 // WASM_CHART change
2577 // TODO: With Chart extracted this cannot really happen since
2578 // no Chart could've been added at all
2579 ChartExport aChartExport( mnXmlNamespace, GetFS(), xChartDoc, GetFB(), GetDocumentType() );
2580 aChartExport.WriteChartObj( xShape, GetNewShapeID( xShape ), ++mnChartCount );
2581#endif
2582 return *this;
2583 }
2584
2585 if (MATH == eType)
2586 {
2587 WriteMathShape(xShape);
2588 return *this;
2589 }
2590
2591 uno::Reference<embed::XEmbeddedObject> const xObj(
2592 xPropSet->getPropertyValue("EmbeddedObject"), uno::UNO_QUERY);
2593
2594 if (!xObj.is())
2595 {
2596 SAL_WARN("oox.shape", "ShapeExport::WriteOLE2Shape: no object");
2597
2598 // tdf#152436 Export the preview graphic of the object if the object is missing.
2600 if (auto pOle2Obj = dynamic_cast<SdrOle2Obj*>(pSdrOLE2))
2601 {
2602 const Graphic* pGraphic = pOle2Obj->GetGraphic();
2603 if (pGraphic)
2604 WriteGraphicObjectShapePart(xShape, pGraphic);
2605 }
2606
2607 return *this;
2608 }
2609
2610 uno::Sequence<beans::PropertyValue> grabBag;
2611 OUString entryName;
2612 try
2613 {
2614 uno::Reference<beans::XPropertySet> const xParent(
2615 uno::Reference<container::XChild>(xObj, uno::UNO_QUERY_THROW)->getParent(),
2616 uno::UNO_QUERY_THROW);
2617
2618 xParent->getPropertyValue("InteropGrabBag") >>= grabBag;
2619
2620 entryName = uno::Reference<embed::XEmbedPersist>(xObj, uno::UNO_QUERY_THROW)->getEntryName();
2621 }
2622 catch (uno::Exception const&)
2623 {
2624 TOOLS_WARN_EXCEPTION("oox.shape", "ShapeExport::WriteOLE2Shape");
2625 return *this;
2626 }
2627
2628 OUString progID;
2629
2630 for (auto const& it : std::as_const(grabBag))
2631 {
2632 if (it.Name == "EmbeddedObjects")
2633 {
2634 uno::Sequence<beans::PropertyValue> objects;
2635 it.Value >>= objects;
2636 for (auto const& object : std::as_const(objects))
2637 {
2638 if (object.Name == entryName)
2639 {
2640 uno::Sequence<beans::PropertyValue> props;
2641 object.Value >>= props;
2642 for (auto const& prop : std::as_const(props))
2643 {
2644 if (prop.Name == "ProgID")
2645 {
2646 prop.Value >>= progID;
2647 break;
2648 }
2649 }
2650 break;
2651 }
2652 }
2653 break;
2654 }
2655 }
2656
2657 OUString sMediaType;
2658 OUString sRelationType;
2659 OUString sSuffix;
2660 const char * pProgID(nullptr);
2661 OString anotherProgID;
2662
2663 uno::Reference<io::XInputStream> const xInStream =
2665 mpFB->getComponentContext(), xObj, progID,
2666 sMediaType, sRelationType, sSuffix, pProgID);
2667
2668 OUString sURL;
2669 OUString sRelId;
2670 if (!xInStream.is())
2671 {
2672 xPropSet->getPropertyValue("LinkURL") >>= sURL;
2673 if (sURL.isEmpty())
2674 return *this;
2675
2676 sRelId = mpFB->addRelation(mpFS->getOutputStream(),
2678 }
2679 else
2680 {
2681 if (!pProgID && !progID.isEmpty())
2682 {
2683 anotherProgID = OUStringToOString(progID, RTL_TEXTENCODING_UTF8);
2684 pProgID = anotherProgID.getStr();
2685 }
2686
2687 assert(!sMediaType.isEmpty());
2688 assert(!sRelationType.isEmpty());
2689 assert(!sSuffix.isEmpty());
2690
2691 OUString sFileName
2692 = "embeddings/oleObject" + OUString::number(++m_nEmbeddedObjects) + "." + sSuffix;
2693 uno::Reference<io::XOutputStream> const xOutStream(mpFB->openFragmentStream(
2694 OUString::createFromAscii(GetComponentDir()) + "/" + sFileName, sMediaType));
2695 assert(xOutStream.is()); // no reason why that could fail
2696
2697 try
2698 {
2700 }
2701 catch (uno::Exception const&)
2702 {
2703 TOOLS_WARN_EXCEPTION("oox.shape", "ShapeExport::WriteOLEObject");
2704 }
2705
2706 sRelId = mpFB->addRelation(
2707 mpFS->getOutputStream(), sRelationType,
2708 Concat2View(OUString::createFromAscii(GetRelationCompPrefix()) + sFileName));
2709 }
2710
2711 sal_Int64 nAspect;
2712 bool bShowAsIcon = (xPropSet->getPropertyValue("Aspect") >>= nAspect)
2713 && nAspect == embed::Aspects::MSOLE_ICON;
2714
2715 mpFS->startElementNS(mnXmlNamespace, XML_graphicFrame);
2716
2717 mpFS->startElementNS(mnXmlNamespace, XML_nvGraphicFramePr);
2718
2719 mpFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
2720 XML_id, OString::number(GetNewShapeID(xShape)),
2721 XML_name, GetShapeName(xShape));
2722
2723 mpFS->singleElementNS(mnXmlNamespace, XML_cNvGraphicFramePr);
2724
2726 mpFS->singleElementNS(mnXmlNamespace, XML_nvPr);
2727 mpFS->endElementNS( mnXmlNamespace, XML_nvGraphicFramePr );
2728
2730
2731 mpFS->startElementNS(XML_a, XML_graphic);
2732 mpFS->startElementNS(XML_a, XML_graphicData,
2733 XML_uri, "http://schemas.openxmlformats.org/presentationml/2006/ole");
2734 if (pProgID)
2735 {
2736 mpFS->startElementNS( mnXmlNamespace, XML_oleObj,
2737 XML_showAsIcon, sax_fastparser::UseIf("1", bShowAsIcon),
2738 XML_progId, pProgID,
2739 FSNS(XML_r, XML_id), sRelId,
2740 XML_spid, "" );
2741 }
2742 else
2743 {
2744 mpFS->startElementNS( mnXmlNamespace, XML_oleObj,
2745//? XML_name, "Document",
2746 XML_showAsIcon, sax_fastparser::UseIf("1", bShowAsIcon),
2747 FSNS(XML_r, XML_id), sRelId,
2748 // The spec says that this is a required attribute, but PowerPoint can only handle an empty value.
2749 XML_spid, "" );
2750 }
2751
2752 if (sURL.isEmpty())
2753 mpFS->singleElementNS(mnXmlNamespace, XML_embed);
2754 else
2755 mpFS->singleElementNS(mnXmlNamespace, XML_link, XML_updateAutomatic, "1");
2756
2757 // pic element
2759 // The spec doesn't allow <p:pic> here, but PowerPoint requires it.
2760 bool const bEcma = mpFB->getVersion() == oox::core::ECMA_376_1ST_EDITION;
2761 if (bEcma)
2762 if (auto pOle2Obj = dynamic_cast<SdrOle2Obj*>(pSdrOLE2))
2763 {
2764 const Graphic* pGraphic = pOle2Obj->GetGraphic();
2765 if (pGraphic)
2766 WriteGraphicObjectShapePart( xShape, pGraphic );
2767 }
2768
2769 mpFS->endElementNS( mnXmlNamespace, XML_oleObj );
2770
2771 mpFS->endElementNS( XML_a, XML_graphicData );
2772 mpFS->endElementNS( XML_a, XML_graphic );
2773
2774 mpFS->endElementNS( mnXmlNamespace, XML_graphicFrame );
2775
2776 return *this;
2777}
2778
2780{
2781 // Override this method to do something useful.
2782 return *this;
2783}
2784
2785sal_Int32 ShapeExport::GetNewShapeID( const Reference< XShape >& rXShape )
2786{
2787 return GetNewShapeID( rXShape, GetFB() );
2788}
2789
2790sal_Int32 ShapeExport::GetNewShapeID( const Reference< XShape >& rXShape, XmlFilterBase* pFB )
2791{
2792 if( !rXShape.is() )
2793 return -1;
2794
2795 sal_Int32 nID = pFB->GetUniqueId();
2796
2797 (*mpShapeMap)[ rXShape ] = nID;
2798
2799 return nID;
2800}
2801
2802sal_Int32 ShapeExport::GetShapeID( const Reference< XShape >& rXShape )
2803{
2804 return GetShapeID( rXShape, mpShapeMap );
2805}
2806
2807sal_Int32 ShapeExport::GetShapeID( const Reference< XShape >& rXShape, ShapeHashMap* pShapeMap )
2808{
2809 if( !rXShape.is() )
2810 return -1;
2811
2812 ShapeHashMap::const_iterator aIter = pShapeMap->find( rXShape );
2813
2814 if( aIter == pShapeMap->end() )
2815 return -1;
2816
2817 return aIter->second;
2818}
2819
2821{
2822 Reference<XPropertySet> rXPropSet(xShape, UNO_QUERY);
2823
2824 // Empty name keeps the object unnamed.
2825 OUString sName;
2826
2827 if (GetProperty(rXPropSet, "Name"))
2828 mAny >>= sName;
2829 return sName;
2830}
2831
2832}
2833
2834/* 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
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:1301
::oox::core::XmlFilterBase * mpFB
Definition: drawingml.hxx:287
void WriteShapeStyle(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
Definition: drawingml.cxx:5406
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:1569
void WriteShapeEffects(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
Definition: drawingml.cxx:5623
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:3642
::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:5263
void Write3DEffects(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, bool bIsText)
Populates scene3d tag.
Definition: drawingml.cxx:5815
bool WriteCustomGeometry(const css::uno::Reference< css::drawing::XShape > &rXShape, const SdrObjCustomShape &rSdrObjCustomShape)
Definition: drawingml.cxx:4546
void WriteFill(const css::uno::Reference< css::beans::XPropertySet > &xPropSet, const css::awt::Size &rSize={})
Definition: drawingml.cxx:5313
bool IsFontworkShape(const css::uno::Reference< css::beans::XPropertySet > &rXShapePropSet)
Definition: drawingml.cxx:3611
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:2202
::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:1778
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:1306
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:2241
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:1944
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:4287
void WritePolyPolygon(const css::uno::Reference< css::drawing::XShape > &rXShape, const bool bClosed)
Definition: drawingml.cxx:5172
void WriteOutline(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, css::uno::Reference< css::frame::XModel > const &xModel=nullptr)
Definition: drawingml.cxx:962
OUString WriteXGraphicBlip(css::uno::Reference< css::beans::XPropertySet > const &rXPropSet, css::uno::Reference< css::graphic::XGraphic > const &rxGraphic, bool bRelPathToMedia)
Definition: drawingml.cxx:1729
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:2442
ShapeExport & WriteCustomShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:724
ShapeExport & WriteGroupShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:468
OUString GetShapeName(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:2820
ShapeExport & WriteClosedPolyPolygonShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:458
virtual ShapeExport & WriteNonVisualProperties(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1926
ShapeHashMap * mpShapeMap
Definition: shapes.hxx:105
ShapeExport & WriteGraphicObjectShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1239
ShapeExport & WriteRectangleShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1932
ShapeExport & WriteLineShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1860
ShapeExport & WriteOpenPolyPolygonShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:463
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:1144
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:397
ShapeExport & WriteConnectorShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1703
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:1917
std::shared_ptr< URLTransformer > mpURLTransformer
Definition: shapes.hxx:100
void WriteTableCellBorders(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
Definition: shapes.cxx:2395
void WriteMathShape(css::uno::Reference< css::drawing::XShape > const &xShape)
Definition: shapes.cxx:2498
virtual ShapeExport & WriteUnknownShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:2779
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:2416
ShapeExport & WriteShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Write the DrawingML for a particular shape.
Definition: shapes.cxx:2032
void WriteGraphicObjectShapePart(const css::uno::Reference< css::drawing::XShape > &xShape, const Graphic *pGraphic=nullptr)
Definition: shapes.cxx:1246
ShapeExport & WriteTextBox(const css::uno::Reference< css::uno::XInterface > &xIface, sal_Int32 nXmlNamespace, bool bWritePropertiesAsLstStyles=false)
Definition: shapes.cxx:2075
void WriteTableCellProperties(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
Definition: shapes.cxx:2299
void WriteTable(const css::uno::Reference< css::drawing::XShape > &rXShape)
Definition: shapes.cxx:2108
void WriteBorderLine(const sal_Int32 XML_line, const css::table::BorderLine2 &rBorderLine)
Definition: shapes.cxx:2347
ShapeExport & WriteOLE2Shape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:2549
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:4478
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:1989
static void lcl_Rotate(sal_Int32 nAngle, Point center, awt::Point &pt)
Definition: shapes.cxx:1440
static sal_Int32 lcl_GetAngle(tools::Polygon aPoly)
Definition: shapes.cxx:1536
static sal_Int32 lcl_GetGluePointId(const Reference< XShape > &xShape, sal_Int32 nGluePointId)
Definition: shapes.cxx:1666
static bool lcl_IsOnDenylist(OUString const &rShapeType)
Definition: shapes.cxx:532
static bool lcl_isTextBox(const Reference< XInterface > &xIface)
Definition: shapes.cxx:2061
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:643
static void lcl_FlipHFlipV(tools::Polygon aPoly, sal_Int32 nAngle, bool &rFlipH, bool &rFlipV)
Definition: shapes.cxx:1466
static sal_Int32 lcl_NormalizeAngle(sal_Int32 nAngle)
Definition: shapes.cxx:677
static OUString lcl_GetTarget(const css::uno::Reference< css::frame::XModel > &xModel, OUString &rURL)
Definition: drawingml.cxx:2336
std::unordered_map< const char *, ShapeConverter, rtl::CStringHash, rtl::CStringEqual > NameToConvertMapType
Definition: shapes.cxx:1987
static void lcl_AppendAdjustmentValue(std::vector< std::pair< sal_Int32, sal_Int32 > > &rAvList, sal_Int32 nAdjIdx, sal_Int32 nValue)
Definition: shapes.cxx:672
static bool lcl_IsOnAllowlist(OUString const &rShapeType)
Definition: shapes.cxx:597
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:1563
ShapeExport &(ShapeExport::* ShapeConverter)(const Reference< XShape > &)
Definition: shapes.cxx:1986
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:609
static sal_Int32 lcl_CircleAngle2CustomShapeEllipseAngleOOX(const sal_Int32 nInternAngle, const sal_Int32 nWidth, const sal_Int32 nHeight)
Definition: shapes.cxx:683
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