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 <sal/config.h>
21 
22 #include <sal/log.hxx>
23 #include <filter/msfilter/util.hxx>
24 #include <o3tl/string_view.hxx>
26 #include <oox/export/shapes.hxx>
27 #include <oox/export/utils.hxx>
28 #include <oox/token/namespaces.hxx>
30 #include <oox/token/tokens.hxx>
31 
32 #include <initializer_list>
33 #include <string_view>
34 
35 #include <com/sun/star/beans/PropertyValues.hpp>
36 #include <com/sun/star/beans/XPropertySet.hpp>
37 #include <com/sun/star/beans/XPropertySetInfo.hpp>
38 #include <com/sun/star/beans/XPropertyState.hpp>
39 #include <com/sun/star/container/XChild.hpp>
40 #include <com/sun/star/document/XExporter.hpp>
41 #include <com/sun/star/document/XStorageBasedDocument.hpp>
42 #include <com/sun/star/drawing/CircleKind.hpp>
43 #include <com/sun/star/drawing/FillStyle.hpp>
44 #include <com/sun/star/drawing/ConnectorType.hpp>
45 #include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
46 #include <com/sun/star/drawing/EnhancedCustomShapeParameterType.hpp>
47 #include <com/sun/star/embed/EmbedStates.hpp>
48 #include <com/sun/star/embed/XEmbeddedObject.hpp>
49 #include <com/sun/star/embed/XEmbedPersist.hpp>
50 #include <com/sun/star/frame/XStorable.hpp>
51 #include <com/sun/star/graphic/XGraphic.hpp>
52 #include <com/sun/star/i18n/ScriptType.hpp>
53 #include <com/sun/star/io/XOutputStream.hpp>
54 #include <com/sun/star/text/XSimpleText.hpp>
55 #include <com/sun/star/text/XText.hpp>
56 #include <com/sun/star/table/XTable.hpp>
57 #include <com/sun/star/table/XMergeableCell.hpp>
58 #include <com/sun/star/chart2/XChartDocument.hpp>
59 #include <com/sun/star/frame/XModel.hpp>
60 #include <com/sun/star/uno/XComponentContext.hpp>
61 #include <com/sun/star/drawing/XDrawPages.hpp>
62 #include <com/sun/star/drawing/XDrawPagesSupplier.hpp>
63 #include <com/sun/star/document/XEventsSupplier.hpp>
64 #include <com/sun/star/presentation/ClickAction.hpp>
65 #include <tools/globname.hxx>
66 #include <comphelper/classids.hxx>
69 #include <sot/exchange.hxx>
70 #include <utility>
71 #include <vcl/graph.hxx>
72 #include <vcl/outdev.hxx>
74 #include <svx/svdoashp.hxx>
75 #include <svx/svdoole2.hxx>
76 #include <tools/diagnose_ex.h>
77 #include <svx/unoapi.hxx>
79 #include <oox/mathml/export.hxx>
82 
83 using namespace ::css;
84 using namespace ::css::beans;
85 using namespace ::css::uno;
86 using namespace ::css::drawing;
87 using namespace ::css::i18n;
88 using namespace ::css::table;
89 using namespace ::css::container;
90 using namespace ::css::document;
91 using namespace ::css::text;
92 
93 using ::css::io::XOutputStream;
94 using ::css::chart2::XChartDocument;
95 using ::css::frame::XModel;
96 
97 using ::oox::core::XmlFilterBase;
98 using ::sax_fastparser::FSHelperPtr;
99 
100 
101 namespace oox {
102 
103 static void lcl_ConvertProgID(std::u16string_view rProgID,
104  OUString & o_rMediaType, OUString & o_rRelationType, OUString & o_rFileExtension)
105 {
106  if (rProgID == u"Excel.Sheet.12")
107  {
108  o_rMediaType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
109  o_rRelationType = oox::getRelationship(Relationship::PACKAGE);
110  o_rFileExtension = "xlsx";
111  }
112  else if (o3tl::starts_with(rProgID, u"Excel.SheetBinaryMacroEnabled.12") )
113  {
114  o_rMediaType = "application/vnd.ms-excel.sheet.binary.macroEnabled.12";
115  o_rRelationType = oox::getRelationship(Relationship::PACKAGE);
116  o_rFileExtension = "xlsb";
117  }
118  else if (o3tl::starts_with(rProgID, u"Excel.SheetMacroEnabled.12"))
119  {
120  o_rMediaType = "application/vnd.ms-excel.sheet.macroEnabled.12";
121  o_rRelationType = oox::getRelationship(Relationship::PACKAGE);
122  o_rFileExtension = "xlsm";
123  }
124  else if (o3tl::starts_with(rProgID, u"Excel.Sheet"))
125  {
126  o_rMediaType = "application/vnd.ms-excel";
128  o_rFileExtension = "xls";
129  }
130  else if (rProgID == u"PowerPoint.Show.12")
131  {
132  o_rMediaType = "application/vnd.openxmlformats-officedocument.presentationml.presentation";
133  o_rRelationType = oox::getRelationship(Relationship::PACKAGE);
134  o_rFileExtension = "pptx";
135  }
136  else if (rProgID == u"PowerPoint.ShowMacroEnabled.12")
137  {
138  o_rMediaType = "application/vnd.ms-powerpoint.presentation.macroEnabled.12";
139  o_rRelationType = oox::getRelationship(Relationship::PACKAGE);
140  o_rFileExtension = "pptm";
141  }
142  else if (o3tl::starts_with(rProgID, u"PowerPoint.Show"))
143  {
144  o_rMediaType = "application/vnd.ms-powerpoint";
146  o_rFileExtension = "ppt";
147  }
148  else if (o3tl::starts_with(rProgID, u"PowerPoint.Slide.12"))
149  {
150  o_rMediaType = "application/vnd.openxmlformats-officedocument.presentationml.slide";
151  o_rRelationType = oox::getRelationship(Relationship::PACKAGE);
152  o_rFileExtension = "sldx";
153  }
154  else if (rProgID == u"PowerPoint.SlideMacroEnabled.12")
155  {
156  o_rMediaType = "application/vnd.ms-powerpoint.slide.macroEnabled.12";
157  o_rRelationType = oox::getRelationship(Relationship::PACKAGE);
158  o_rFileExtension = "sldm";
159  }
160  else if (rProgID == u"Word.DocumentMacroEnabled.12")
161  {
162  o_rMediaType = "application/vnd.ms-word.document.macroEnabled.12";
163  o_rRelationType = oox::getRelationship(Relationship::PACKAGE);
164  o_rFileExtension = "docm";
165  }
166  else if (rProgID == u"Word.Document.12")
167  {
168  o_rMediaType = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
169  o_rRelationType = oox::getRelationship(Relationship::PACKAGE);
170  o_rFileExtension = "docx";
171  }
172  else if (rProgID == u"Word.Document.8")
173  {
174  o_rMediaType = "application/msword";
176  o_rFileExtension = "doc";
177  }
178  else if (rProgID == u"Excel.Chart.8")
179  {
180  o_rMediaType = "application/vnd.ms-excel";
182  o_rFileExtension = "xls";
183  }
184  else if (rProgID == u"AcroExch.Document.11")
185  {
186  o_rMediaType = "application/pdf";
188  o_rFileExtension = "pdf";
189  }
190  else
191  {
192  o_rMediaType = "application/vnd.openxmlformats-officedocument.oleObject";
194  o_rFileExtension = "bin";
195  }
196 }
197 
198 static uno::Reference<io::XInputStream> lcl_StoreOwnAsOOXML(
199  uno::Reference<uno::XComponentContext> const& xContext,
200  uno::Reference<embed::XEmbeddedObject> const& xObj,
201  char const*& o_rpProgID,
202  OUString & o_rMediaType, OUString & o_rRelationType, OUString & o_rSuffix)
203 {
204  static struct {
205  struct {
206  sal_uInt32 n1;
207  sal_uInt16 n2, n3;
208  sal_uInt8 b8, b9, b10, b11, b12, b13, b14, b15;
209  } ClassId;
210  char const* pFilterName;
211  char const* pMediaType;
212  char const* pProgID;
213  char const* pSuffix;
214  } const s_Mapping[] = {
215  { {SO3_SW_CLASSID_60}, "MS Word 2007 XML", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "Word.Document.12", "docx" },
216  { {SO3_SC_CLASSID_60}, "Calc MS Excel 2007 XML", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "Excel.Sheet.12", "xlsx" },
217  { {SO3_SIMPRESS_CLASSID_60}, "Impress MS PowerPoint 2007 XML", "application/vnd.openxmlformats-officedocument.presentationml.presentation", "PowerPoint.Show.12", "pptx" },
218  // FIXME: Draw does not appear to have a MSO format export filter?
219 // { {SO3_SDRAW_CLASSID}, "", "", "", "" },
220  { {SO3_SCH_CLASSID_60}, "unused", "", "", "" },
221  { {SO3_SM_CLASSID_60}, "unused", "", "", "" },
222  };
223 
224  const char * pFilterName(nullptr);
225  SvGlobalName const classId(xObj->getClassID());
226  for (auto & i : s_Mapping)
227  {
228  auto const& rId(i.ClassId);
229  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);
230  if (temp == classId)
231  {
232  assert(SvGlobalName(SO3_SCH_CLASSID_60) != classId); // chart should be written elsewhere!
233  assert(SvGlobalName(SO3_SM_CLASSID_60) != classId); // formula should be written elsewhere!
234  pFilterName = i.pFilterName;
235  o_rMediaType = OUString::createFromAscii(i.pMediaType);
236  o_rpProgID = i.pProgID;
237  o_rSuffix = OUString::createFromAscii(i.pSuffix);
238  o_rRelationType = oox::getRelationship(Relationship::PACKAGE);
239  break;
240  }
241  }
242 
243  if (!pFilterName)
244  {
245  SAL_WARN("oox.shape", "oox::GetOLEObjectStream: unknown ClassId " << classId.GetHexName());
246  return nullptr;
247  }
248 
249  if (embed::EmbedStates::LOADED == xObj->getCurrentState())
250  {
251  xObj->changeState(embed::EmbedStates::RUNNING);
252  }
253  // use a temp stream - while it would work to store directly to a
254  // fragment stream, an error during export means we'd have to delete it
255  uno::Reference<io::XStream> const xTempStream(
256  xContext->getServiceManager()->createInstanceWithContext(
257  "com.sun.star.comp.MemoryStream", xContext),
258  uno::UNO_QUERY_THROW);
259  uno::Sequence<beans::PropertyValue> args( comphelper::InitPropertySequence({
260  { "OutputStream", Any(xTempStream->getOutputStream()) },
261  { "FilterName", Any(OUString::createFromAscii(pFilterName)) }
262  }));
263  uno::Reference<frame::XStorable> xStorable(xObj->getComponent(), uno::UNO_QUERY);
264  try
265  {
266  xStorable->storeToURL("private:stream", args);
267  }
268  catch (uno::Exception const&)
269  {
270  TOOLS_WARN_EXCEPTION("oox.shape", "oox::GetOLEObjectStream");
271  return nullptr;
272  }
273  xTempStream->getOutputStream()->closeOutput();
274  return xTempStream->getInputStream();
275 }
276 
277 uno::Reference<io::XInputStream> GetOLEObjectStream(
278  uno::Reference<uno::XComponentContext> const& xContext,
279  uno::Reference<embed::XEmbeddedObject> const& xObj,
280  std::u16string_view i_rProgID,
281  OUString & o_rMediaType,
282  OUString & o_rRelationType,
283  OUString & o_rSuffix,
284  const char *& o_rpProgID)
285 {
286  uno::Reference<io::XInputStream> xInStream;
287  try
288  {
289  uno::Reference<document::XStorageBasedDocument> const xParent(
290  uno::Reference<container::XChild>(xObj, uno::UNO_QUERY_THROW)->getParent(),
291  uno::UNO_QUERY_THROW);
292  uno::Reference<embed::XStorage> const xParentStorage(xParent->getDocumentStorage());
293  OUString const entryName(
294  uno::Reference<embed::XEmbedPersist>(xObj, uno::UNO_QUERY_THROW)->getEntryName());
295 
296  if (xParentStorage->isStreamElement(entryName))
297  {
298  lcl_ConvertProgID(i_rProgID, o_rMediaType, o_rRelationType, o_rSuffix);
299  xInStream = xParentStorage->cloneStreamElement(entryName)->getInputStream();
300  // TODO: make it possible to take the sMediaType from the stream
301  }
302  else // the object is ODF - either the whole document is
303  { // ODF, or the OLE was edited so it was converted to ODF
304  xInStream = lcl_StoreOwnAsOOXML(xContext, xObj,
305  o_rpProgID, o_rMediaType, o_rRelationType, o_rSuffix);
306  }
307  }
308  catch (uno::Exception const&)
309  {
310  TOOLS_WARN_EXCEPTION("oox.shape", "oox::GetOLEObjectStream");
311  }
312  return xInStream;
313 }
314 
315 } // namespace oox
316 
317 namespace oox::drawingml {
318 
319 #define GETA(propName) \
320  GetProperty( rXPropSet, #propName)
321 
322 #define GETAD(propName) \
323  ( GetPropertyAndState( rXPropSet, rXPropState, #propName, eState ) && eState == beans::PropertyState_DIRECT_VALUE )
324 
325 #define GET(variable, propName) \
326  if ( GETA(propName) ) \
327  mAny >>= variable;
328 
329 ShapeExport::ShapeExport( sal_Int32 nXmlNamespace, FSHelperPtr pFS, ShapeHashMap* pShapeMap, XmlFilterBase* pFB, DocumentType eDocumentType, DMLTextExport* pTextExport, bool bUserShapes )
330  : DrawingML( std::move(pFS), pFB, eDocumentType, pTextExport )
331  , m_nEmbeddedObjects(0)
332  , mnShapeIdMax( 1 )
333  , mbUserShapes( bUserShapes )
334  , mnXmlNamespace( nXmlNamespace )
335  , maMapModeSrc( MapUnit::Map100thMM )
336  , maMapModeDest( MapUnit::MapInch, Point(), Fraction( 1, 576 ), Fraction( 1, 576 ) )
337  , mpShapeMap( pShapeMap ? pShapeMap : &maShapeMap )
338 {
339  mpURLTransformer = std::make_shared<URLTransformer>();
340 }
341 
342 void ShapeExport::SetURLTranslator(const std::shared_ptr<URLTransformer>& pTransformer)
343 {
344  mpURLTransformer = pTransformer;
345 }
346 
347 awt::Size ShapeExport::MapSize( const awt::Size& rSize ) const
348 {
349  Size aRetSize( OutputDevice::LogicToLogic( Size( rSize.Width, rSize.Height ), maMapModeSrc, maMapModeDest ) );
350 
351  if ( !aRetSize.Width() )
352  aRetSize.AdjustWidth( 1 );
353  if ( !aRetSize.Height() )
354  aRetSize.AdjustHeight( 1 );
355  return awt::Size( aRetSize.Width(), aRetSize.Height() );
356 }
357 
358 static bool IsNonEmptySimpleText(const Reference<XInterface>& xIface)
359 {
360  if (Reference<XSimpleText> xText{ xIface, UNO_QUERY })
361  return xText->getString().getLength();
362 
363  return false;
364 }
365 
367 {
368  Reference< XPropertySet > xPropSet( xIface, UNO_QUERY );
369 
370  if( xPropSet.is() )
371  {
372  Reference< XPropertySetInfo > xPropSetInfo = xPropSet->getPropertySetInfo();
373  if ( xPropSetInfo.is() )
374  {
375  if ( xPropSetInfo->hasPropertyByName( "IsEmptyPresentationObject" ) )
376  {
377  bool bIsEmptyPresObj = false;
378  if ( xPropSet->getPropertyValue( "IsEmptyPresentationObject" ) >>= bIsEmptyPresObj )
379  {
380  SAL_INFO("oox.shape", "empty presentation object " << bIsEmptyPresObj << " , props:");
381  if( bIsEmptyPresObj )
382  return true;
383  }
384  }
385 
386  if ( xPropSetInfo->hasPropertyByName( "IsPresentationObject" ) )
387  {
388  bool bIsPresObj = false;
389  if ( xPropSet->getPropertyValue( "IsPresentationObject" ) >>= bIsPresObj )
390  {
391  SAL_INFO("oox.shape", "presentation object " << bIsPresObj << ", props:");
392  if( bIsPresObj )
393  return true;
394  }
395  }
396  }
397  }
398 
399  return IsNonEmptySimpleText(xIface);
400 }
401 
403 {
404  SAL_INFO("oox.shape", "write polypolygon shape");
405 
406  FSHelperPtr pFS = GetFS();
407  pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp));
408 
409  awt::Point aPos = xShape->getPosition();
410  // Position is relative to group for child elements in Word, but absolute in API.
412  {
413  awt::Point aParentPos = m_xParent->getPosition();
414  aPos.X -= aParentPos.X;
415  aPos.Y -= aParentPos.Y;
416  }
417  awt::Size aSize = xShape->getSize();
418  tools::Rectangle aRect(Point(aPos.X, aPos.Y), Size(aSize.Width, aSize.Height));
419 
420 #if OSL_DEBUG_LEVEL > 0
422  awt::Size size = MapSize( awt::Size( aRect.GetWidth(), aRect.GetHeight() ) );
423  SAL_INFO("oox.shape", "poly count " << aPolyPolygon.Count());
424  SAL_INFO("oox.shape", "size: " << size.Width << " x " << size.Height);
425 #endif
426 
427  // non visual shape properties
429  {
430  pFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
431  pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
432  XML_id, OString::number(GetNewShapeID(xShape)),
433  XML_name, GetShapeName(xShape));
434  }
435  pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
437  {
438  WriteNonVisualProperties( xShape );
439  pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
440  }
441 
442  // visual shape properties
443  pFS->startElementNS(mnXmlNamespace, XML_spPr);
444  WriteTransformation( xShape, aRect, XML_a );
445  WritePolyPolygon(xShape, bClosed);
446  Reference< XPropertySet > xProps( xShape, UNO_QUERY );
447  if( xProps.is() ) {
448  if( bClosed )
449  WriteFill( xProps );
450  WriteOutline( xProps );
451  }
452 
453  pFS->endElementNS( mnXmlNamespace, XML_spPr );
454 
455  // write text
456  WriteTextBox( xShape, mnXmlNamespace );
457 
458  pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
459 
460  return *this;
461 }
462 
464 {
465  return WritePolyPolygonShape( xShape, true );
466 }
467 
469 {
470  return WritePolyPolygonShape( xShape, false );
471 }
472 
473 ShapeExport& ShapeExport::WriteGroupShape(const uno::Reference<drawing::XShape>& xShape)
474 {
475  FSHelperPtr pFS = GetFS();
476 
477  sal_Int32 nGroupShapeToken = XML_grpSp;
479  {
480  if (!m_xParent.is())
481  nGroupShapeToken = XML_wgp; // toplevel
482  else
483  mnXmlNamespace = XML_wpg;
484  }
485 
486  pFS->startElementNS(mnXmlNamespace, nGroupShapeToken);
487 
488  // non visual properties
490  {
491  pFS->startElementNS(mnXmlNamespace, XML_nvGrpSpPr);
492  pFS->singleElementNS(mnXmlNamespace, XML_cNvPr,
493  XML_id, OString::number(GetNewShapeID(xShape)),
494  XML_name, GetShapeName(xShape));
495  pFS->singleElementNS(mnXmlNamespace, XML_cNvGrpSpPr);
496  WriteNonVisualProperties(xShape );
497  pFS->endElementNS(mnXmlNamespace, XML_nvGrpSpPr);
498  }
499  else
500  pFS->singleElementNS(mnXmlNamespace, XML_cNvGrpSpPr);
501 
502  // visual properties
503  pFS->startElementNS(mnXmlNamespace, XML_grpSpPr);
504  WriteShapeTransformation(xShape, XML_a, false, false, true);
505  pFS->endElementNS(mnXmlNamespace, XML_grpSpPr);
506 
507  uno::Reference<drawing::XShapes> xGroupShape(xShape, uno::UNO_QUERY_THROW);
508  uno::Reference<drawing::XShape> xParent = m_xParent;
509  m_xParent = xShape;
510  for (sal_Int32 i = 0; i < xGroupShape->getCount(); ++i)
511  {
512  uno::Reference<drawing::XShape> xChild(xGroupShape->getByIndex(i), uno::UNO_QUERY_THROW);
513  sal_Int32 nSavedNamespace = mnXmlNamespace;
514 
515  uno::Reference<lang::XServiceInfo> xServiceInfo(xChild, uno::UNO_QUERY_THROW);
517  {
518  // tdf#128820: WriteGraphicObjectShapePart calls WriteTextShape for non-empty simple
519  // text objects, which needs writing into wps::wsp element, so make sure to use wps
520  // namespace for those objects
521  if (xServiceInfo->supportsService("com.sun.star.drawing.GraphicObjectShape")
522  && !IsNonEmptySimpleText(xChild))
523  mnXmlNamespace = XML_pic;
524  else
525  mnXmlNamespace = XML_wps;
526  }
527  WriteShape(xChild);
528 
529  mnXmlNamespace = nSavedNamespace;
530  }
531  m_xParent = xParent;
532 
533  pFS->endElementNS(mnXmlNamespace, nGroupShapeToken);
534  return *this;
535 }
536 
537 static bool lcl_IsOnDenylist(OUString const & rShapeType)
538 {
539  static const std::initializer_list<std::u16string_view> vDenylist = {
540  u"block-arc",
541  u"rectangle",
542  u"ellipse",
543  u"ring",
544  u"can",
545  u"cube",
546  u"paper",
547  u"frame",
548  u"forbidden",
549  u"smiley",
550  u"sun",
551  u"flower",
552  u"bracket-pair",
553  u"brace-pair",
554  u"col-60da8460",
555  u"col-502ad400",
556  u"quad-bevel",
557  u"round-rectangular-callout",
558  u"rectangular-callout",
559  u"round-callout",
560  u"cloud-callout",
561  u"line-callout-1",
562  u"line-callout-2",
563  u"line-callout-3",
564  u"paper",
565  u"vertical-scroll",
566  u"horizontal-scroll",
567  u"mso-spt34",
568  u"mso-spt75",
569  u"mso-spt164",
570  u"mso-spt180",
571  u"flowchart-process",
572  u"flowchart-alternate-process",
573  u"flowchart-decision",
574  u"flowchart-data",
575  u"flowchart-predefined-process",
576  u"flowchart-internal-storage",
577  u"flowchart-document",
578  u"flowchart-multidocument",
579  u"flowchart-terminator",
580  u"flowchart-preparation",
581  u"flowchart-manual-input",
582  u"flowchart-manual-operation",
583  u"flowchart-connector",
584  u"flowchart-off-page-connector",
585  u"flowchart-card",
586  u"flowchart-punched-tape",
587  u"flowchart-summing-junction",
588  u"flowchart-or",
589  u"flowchart-collate",
590  u"flowchart-sort",
591  u"flowchart-extract",
592  u"flowchart-merge",
593  u"flowchart-stored-data",
594  u"flowchart-delay",
595  u"flowchart-sequential-access",
596  u"flowchart-magnetic-disk",
597  u"flowchart-direct-access-storage",
598  u"flowchart-display"
599  };
600 
601  return std::find(vDenylist.begin(), vDenylist.end(), rShapeType) != vDenylist.end();
602 }
603 
604 static bool lcl_IsOnAllowlist(OUString const & rShapeType)
605 {
606  static const std::initializer_list<std::u16string_view> vAllowlist = {
607  u"heart",
608  u"puzzle"
609  };
610 
611  return std::find(vAllowlist.begin(), vAllowlist.end(), rShapeType) != vAllowlist.end();
612 }
613 
614 static bool lcl_GetHandlePosition( sal_Int32 &nValue, const EnhancedCustomShapeParameter &rParam, Sequence< EnhancedCustomShapeAdjustmentValue > &rSeq)
615 {
616  bool bAdj = false;
617  if ( rParam.Value.getValueTypeClass() == TypeClass_DOUBLE )
618  {
619  double fValue(0.0);
620  if ( rParam.Value >>= fValue )
621  nValue = static_cast<sal_Int32>(fValue);
622  }
623  else
624  rParam.Value >>= nValue;
625 
626  if ( rParam.Type == EnhancedCustomShapeParameterType::ADJUSTMENT)
627  {
628  bAdj = true;
629  sal_Int32 nIdx = nValue;
630  if ( nIdx < rSeq.getLength() )
631  {
632  if ( rSeq[ nIdx ] .Value.getValueTypeClass() == TypeClass_DOUBLE )
633  {
634  double fValue(0.0);
635  rSeq[ nIdx ].Value >>= fValue;
636  nValue = fValue;
637 
638  }
639  else
640  {
641  rSeq[ nIdx ].Value >>= nValue;
642  }
643  }
644  }
645  return bAdj;
646 }
647 
648 static void lcl_AnalyzeHandles( const uno::Sequence<beans::PropertyValues> & rHandles,
649  std::vector< std::pair< sal_Int32, sal_Int32> > &rHandlePositionList,
651 {
652  for ( const Sequence< PropertyValue >& rPropSeq : rHandles )
653  {
654  static const OUStringLiteral sPosition( u"Position" );
655  bool bPosition = false;
656  EnhancedCustomShapeParameterPair aPosition;
657  for ( const PropertyValue& rPropVal: rPropSeq )
658  {
659  if ( rPropVal.Name == sPosition )
660  {
661  if ( rPropVal.Value >>= aPosition )
662  bPosition = true;
663  }
664  }
665  if ( bPosition )
666  {
667  sal_Int32 nXPosition = 0;
668  sal_Int32 nYPosition = 0;
669  // For polar handles, nXPosition is radius and nYPosition is angle
670  lcl_GetHandlePosition( nXPosition, aPosition.First , rSeq );
671  lcl_GetHandlePosition( nYPosition, aPosition.Second, rSeq );
672  rHandlePositionList.emplace_back( nXPosition, nYPosition );
673  }
674  }
675 }
676 
677 static void lcl_AppendAdjustmentValue( std::vector< std::pair< sal_Int32, sal_Int32> > &rAvList, sal_Int32 nAdjIdx, sal_Int32 nValue )
678 {
679  rAvList.emplace_back( nAdjIdx , nValue );
680 }
681 
682 static sal_Int32 lcl_NormalizeAngle( sal_Int32 nAngle )
683 {
684  nAngle = nAngle % 360;
685  return nAngle < 0 ? ( nAngle + 360 ) : nAngle ;
686 }
687 
688 static sal_Int32 lcl_CircleAngle2CustomShapeEllipseAngleOOX(const sal_Int32 nInternAngle, const sal_Int32 nWidth, const sal_Int32 nHeight)
689 {
690  if (nWidth != 0 || nHeight != 0)
691  {
692  double fAngle = basegfx::deg2rad(nInternAngle / 100.0); // intern 1/100 deg to degree to rad
693  fAngle = atan2(nHeight * sin(fAngle), nWidth * cos(fAngle)); // circle to ellipse
694  fAngle = basegfx::rad2deg(fAngle) * 60000.0; // rad to degree to OOXML angle unit
695  sal_Int32 nAngle = basegfx::fround(fAngle); // normalize
696  nAngle = nAngle % 21600000;
697  return nAngle < 0 ? (nAngle + 21600000) : nAngle;
698  }
699  else // should be handled by caller, dummy value
700  return 0;
701 }
702 
703 static OUString lcl_GetTarget(const css::uno::Reference<css::frame::XModel>& xModel,
704  std::u16string_view rURL)
705 {
706  Reference<drawing::XDrawPagesSupplier> xDPS(xModel, uno::UNO_QUERY_THROW);
707  Reference<drawing::XDrawPages> xDrawPages(xDPS->getDrawPages(), uno::UNO_SET_THROW);
708  sal_uInt32 nPageCount = xDrawPages->getCount();
709  OUString sTarget;
710 
711  for (sal_uInt32 i = 0; i < nPageCount; ++i)
712  {
713  Reference<XDrawPage> xDrawPage;
714  xDrawPages->getByIndex(i) >>= xDrawPage;
715  Reference<container::XNamed> xNamed(xDrawPage, UNO_QUERY);
716  if (!xNamed)
717  continue;
718  OUString sSlideName = "#" + xNamed->getName();
719  if (rURL == sSlideName)
720  {
721  sTarget = "slide" + OUString::number(i + 1) + ".xml";
722  break;
723  }
724  }
725 
726  return sTarget;
727 }
728 
730 {
731  SAL_INFO("oox.shape", "write custom shape");
732  Reference< XPropertySet > rXPropSet( xShape, UNO_QUERY );
733  // First check, if this is a Fontwork-shape. For DrawingML, such a shape is a
734  // TextBox shape with body property prstTxWarp.
735  if (IsFontworkShape(rXPropSet))
736  {
737  ShapeExport::WriteTextShape(xShape); // qualifier to prevent PowerPointShapeExport
738  return *this;
739  }
740 
741  bool bHasGeometrySeq(false);
742  Sequence< PropertyValue > aGeometrySeq;
743  OUString sShapeType;
744  if (GETA(CustomShapeGeometry))
745  {
746  SAL_INFO("oox.shape", "got custom shape geometry");
747  if (mAny >>= aGeometrySeq)
748  {
749  bHasGeometrySeq = true;
750  SAL_INFO("oox.shape", "got custom shape geometry sequence");
751  for (const PropertyValue& rProp : std::as_const(aGeometrySeq))
752  {
753  SAL_INFO("oox.shape", "geometry property: " << rProp.Name);
754  if (rProp.Name == "Type")
755  rProp.Value >>= sShapeType;
756  }
757  }
758  }
759 
760  bool bPredefinedHandlesUsed = true;
761  bool bHasHandles = false;
762 
763  ShapeFlag nMirrorFlags = ShapeFlag::NONE;
764  MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType( xShape, nMirrorFlags, sShapeType );
765  assert(dynamic_cast< SdrObjCustomShape* >(SdrObject::getSdrObjectFromXShape(xShape)) && "Not a SdrObjCustomShape (!)");
766  SdrObjCustomShape& rSdrObjCustomShape(static_cast< SdrObjCustomShape& >(*SdrObject::getSdrObjectFromXShape(xShape)));
767  const bool bIsDefaultObject(
769  rSdrObjCustomShape,
770  eShapeType));
771  const char* sPresetShape = msfilter::util::GetOOXMLPresetGeometry(sShapeType.toUtf8().getStr());
772  SAL_INFO("oox.shape", "custom shape type: " << sShapeType << " ==> " << sPresetShape);
773 
774  sal_Int32 nAdjustmentValuesIndex = -1;
775  awt::Rectangle aViewBox;
776  uno::Sequence<beans::PropertyValues> aHandles;
777 
778  bool bFlipH = false;
779  bool bFlipV = false;
780 
781  if (bHasGeometrySeq)
782  {
783  for (int i = 0; i < aGeometrySeq.getLength(); i++)
784  {
785  const PropertyValue& rProp = aGeometrySeq[ i ];
786  SAL_INFO("oox.shape", "geometry property: " << rProp.Name);
787 
788  if ( rProp.Name == "MirroredX" )
789  rProp.Value >>= bFlipH;
790 
791  if ( rProp.Name == "MirroredY" )
792  rProp.Value >>= bFlipV;
793  if ( rProp.Name == "AdjustmentValues" )
794  nAdjustmentValuesIndex = i;
795  else if ( rProp.Name == "Handles" )
796  {
797  rProp.Value >>= aHandles;
798  if ( aHandles.hasElements() )
799  bHasHandles = true;
800  if( !bIsDefaultObject )
801  bPredefinedHandlesUsed = false;
802  // TODO: update nAdjustmentsWhichNeedsToBeConverted here
803  }
804  else if ( rProp.Name == "ViewBox" )
805  rProp.Value >>= aViewBox;
806  }
807  }
808 
809  FSHelperPtr pFS = GetFS();
810  pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp));
811 
812  // non visual shape properties
814  {
815  bool isVisible = true ;
816  if( GETA (Visible))
817  {
818  mAny >>= isVisible;
819  }
820  pFS->startElementNS( mnXmlNamespace, XML_nvSpPr );
821  pFS->startElementNS( mnXmlNamespace, XML_cNvPr,
822  XML_id, OString::number(GetNewShapeID(xShape)),
823  XML_name, GetShapeName(xShape),
824  XML_hidden, sax_fastparser::UseIf("1", !isVisible));
825 
826  if( GETA( URL ) )
827  {
828  OUString sURL;
829  mAny >>= sURL;
830  if( !sURL.isEmpty() )
831  {
832  OUString sRelId = mpFB->addRelation( mpFS->getOutputStream(),
834  mpURLTransformer->getTransformedString(sURL),
835  mpURLTransformer->isExternalURL(sURL));
836 
837  mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
838  }
839  }
840  pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
841  pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
842  WriteNonVisualProperties( xShape );
843  pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
844  }
845  else
846  pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
847 
848  // visual shape properties
849  pFS->startElementNS(mnXmlNamespace, XML_spPr);
850  // moon is flipped in MSO, and mso-spt89 (right up arrow) is mapped to leftUpArrow
851  if ( sShapeType == "moon" || sShapeType == "mso-spt89" )
852  bFlipH = !bFlipH;
853 
854  // we export non-primitive shapes to custom geometry
855  // we also export non-ooxml shapes which have handles/equations to custom geometry, because
856  // we cannot convert ODF equations to DrawingML equations. TODO: see what binary DOC export filter does.
857  // but our WritePolyPolygon()/WriteCustomGeometry() functions are incomplete, therefore we use a denylist
858  // we use a allowlist for shapes where mapping to MSO preset shape is not optimal
859  bool bCustGeom = true;
860  bool bOnDenylist = false;
861  if( sShapeType == "ooxml-non-primitive" )
862  bCustGeom = true;
863  else if( sShapeType.startsWith("ooxml") )
864  bCustGeom = false;
865  else if( lcl_IsOnAllowlist(sShapeType) )
866  bCustGeom = true;
867  else if( lcl_IsOnDenylist(sShapeType) )
868  {
869  bCustGeom = false;
870  bOnDenylist = true;
871  }
872  else if( bHasHandles )
873  bCustGeom = true;
874 
875  bool bPresetWriteSuccessful = false;
876  // Let the custom shapes what has name and preset information in OOXML, to be written
877  // as preset ones with parameters. Try that with this converter class.
878  if (!sShapeType.startsWith("ooxml") && sShapeType != "non-primitive"
880  && xShape->getShapeType() == "com.sun.star.drawing.CustomShape")
881  {
882  DMLPresetShapeExporter aCustomShapeConverter(this, xShape);
883  bPresetWriteSuccessful = aCustomShapeConverter.WriteShape();
884  }
885  // If preset writing has problems try to write the shape as it done before
886  if (bPresetWriteSuccessful)
887  ;// Already written do nothing.
888  else if (bHasHandles && bCustGeom)
889  {
890  WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV, false, true );// do not flip, polypolygon coordinates are flipped already
891  tools::PolyPolygon aPolyPolygon( rSdrObjCustomShape.GetLineGeometry(true) );
892  sal_Int32 nRotation = 0;
893  // The RotateAngle property's value is independent from any flipping, and that's exactly what we need here.
894  uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
895  uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
896  if (xPropertySetInfo->hasPropertyByName("RotateAngle"))
897  xPropertySet->getPropertyValue("RotateAngle") >>= nRotation;
898  // Remove rotation
899  bool bInvertRotation = bFlipH != bFlipV;
900  if (nRotation != 0)
901  aPolyPolygon.Rotate(Point(0,0), Degree10(static_cast<sal_Int16>(bInvertRotation ? nRotation/10 : 3600-nRotation/10)));
902  WritePolyPolygon(xShape, aPolyPolygon, false);
903  }
904  else if (bCustGeom)
905  {
906  WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV );
907  bool bSuccess = WriteCustomGeometry(xShape, rSdrObjCustomShape);
908  if (!bSuccess)
909  WritePresetShape( sPresetShape );
910  }
911  else if (bOnDenylist && bHasHandles && nAdjustmentValuesIndex !=-1 && !sShapeType.startsWith("mso-spt"))
912  {
913  WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV );
915  std::vector< std::pair< sal_Int32, sal_Int32> > aHandlePositionList;
916  std::vector< std::pair< sal_Int32, sal_Int32> > aAvList;
917  aGeometrySeq[ nAdjustmentValuesIndex ].Value >>= aAdjustmentSeq ;
918 
919  lcl_AnalyzeHandles( aHandles, aHandlePositionList, aAdjustmentSeq );
920 
921  sal_Int32 nXPosition = 0;
922  sal_Int32 nYPosition = 0;
923  if ( !aHandlePositionList.empty() )
924  {
925  nXPosition = aHandlePositionList[0].first ;
926  nYPosition = aHandlePositionList[0].second ;
927  }
928  switch( eShapeType )
929  {
931  {
932  sal_Int32 adj3 = double(nYPosition)/aViewBox.Height *100000;
933  sal_Int32 adj4 = double(nXPosition)/aViewBox.Width *100000;
934  lcl_AppendAdjustmentValue( aAvList, 1, 18750 );
935  lcl_AppendAdjustmentValue( aAvList, 2, -8333 );
936  lcl_AppendAdjustmentValue( aAvList, 3, adj3 );
937  lcl_AppendAdjustmentValue( aAvList, 4, adj4 );
938  break;
939  }
941  {
942  sal_Int32 adj5 = double(nYPosition)/aViewBox.Height *100000;
943  sal_Int32 adj6 = double(nXPosition)/aViewBox.Width *100000;
944  sal_Int32 adj3 = 18750;
945  sal_Int32 adj4 = -16667;
946  lcl_AppendAdjustmentValue( aAvList, 1, 18750 );
947  lcl_AppendAdjustmentValue( aAvList, 2, -8333 );
948  if ( aHandlePositionList.size() > 1 )
949  {
950  nXPosition = aHandlePositionList[1].first ;
951  nYPosition = aHandlePositionList[1].second ;
952  adj3 = double(nYPosition)/aViewBox.Height *100000;
953  adj4 = double(nXPosition)/aViewBox.Width *100000;
954  }
955  lcl_AppendAdjustmentValue( aAvList, 3, adj3 );
956  lcl_AppendAdjustmentValue( aAvList, 4, adj4 );
957  lcl_AppendAdjustmentValue( aAvList, 5, adj5 );
958  lcl_AppendAdjustmentValue( aAvList, 6, adj6 );
959  break;
960  }
964  case mso_sptCloudCallout:
965  {
966  sal_Int32 adj1 = (double(nXPosition)/aViewBox.Width -0.5) *100000;
967  sal_Int32 adj2 = (double(nYPosition)/aViewBox.Height -0.5) *100000;
968  lcl_AppendAdjustmentValue( aAvList, 1, adj1 );
969  lcl_AppendAdjustmentValue( aAvList, 2, adj2 );
970  if ( eShapeType == mso_sptWedgeRRectCallout)
971  {
972  lcl_AppendAdjustmentValue( aAvList, 3, 16667);
973  }
974 
975  break;
976  }
977  case mso_sptFoldedCorner:
978  {
979  sal_Int32 adj = double( aViewBox.Width - nXPosition) / std::min( aViewBox.Width,aViewBox.Height ) * 100000;
980  lcl_AppendAdjustmentValue( aAvList, 0, adj );
981  break;
982  }
983  case mso_sptDonut:
984  case mso_sptSun:
985  case mso_sptMoon:
986  case mso_sptNoSmoking:
988  case mso_sptBevel:
989  case mso_sptBracketPair:
990  {
991  sal_Int32 adj = double( nXPosition )/aViewBox.Width*100000 ;
992  lcl_AppendAdjustmentValue( aAvList, 0, adj );
993  break;
994  }
995  case mso_sptCan:
996  case mso_sptCube:
997  case mso_sptBracePair:
999  {
1000  sal_Int32 adj = double( nYPosition )/aViewBox.Height *100000 ;
1001  lcl_AppendAdjustmentValue( aAvList, 0, adj );
1002  break;
1003  }
1004  case mso_sptSmileyFace:
1005  {
1006  sal_Int32 adj = double( nYPosition )/aViewBox.Height *100000 - 76458.0;
1007  lcl_AppendAdjustmentValue( aAvList, 0, adj );
1008  break;
1009  }
1010  case mso_sptBlockArc:
1011  {
1012  sal_Int32 nRadius = 50000 * ( 1 - double(nXPosition) / 10800);
1013  sal_Int32 nAngleStart = lcl_NormalizeAngle( nYPosition );
1014  sal_Int32 nAngleEnd = lcl_NormalizeAngle( 180 - nAngleStart );
1015  lcl_AppendAdjustmentValue( aAvList, 1, 21600000 / 360 * nAngleStart );
1016  lcl_AppendAdjustmentValue( aAvList, 2, 21600000 / 360 * nAngleEnd );
1017  lcl_AppendAdjustmentValue( aAvList, 3, nRadius );
1018  break;
1019  }
1020  // case mso_sptNil:
1021  // case mso_sptBentConnector3:
1022  // case mso_sptBorderCallout3:
1023  default:
1024  {
1025  if (!strcmp( sPresetShape, "frame" ))
1026  {
1027  sal_Int32 adj1 = double( nYPosition )/aViewBox.Height *100000 ;
1028  lcl_AppendAdjustmentValue( aAvList, 1, adj1 );
1029  }
1030  break;
1031  }
1032  }
1033  WritePresetShape( sPresetShape , aAvList );
1034  }
1035  else // preset geometry
1036  {
1037  WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV );
1038  if( nAdjustmentValuesIndex != -1 )
1039  {
1040  WritePresetShape( sPresetShape, eShapeType, bPredefinedHandlesUsed,
1041  aGeometrySeq[ nAdjustmentValuesIndex ] );
1042  }
1043  else
1044  WritePresetShape( sPresetShape );
1045  }
1046  if( rXPropSet.is() )
1047  {
1048  WriteFill( rXPropSet );
1049  WriteOutline( rXPropSet );
1050  WriteShapeEffects( rXPropSet );
1051 
1052  bool bHas3DEffectinShape = false;
1053  uno::Sequence<beans::PropertyValue> grabBag;
1054  rXPropSet->getPropertyValue("InteropGrabBag") >>= grabBag;
1055 
1056  for (auto const& it : std::as_const(grabBag))
1057  if (it.Name == "3DEffectProperties")
1058  bHas3DEffectinShape = true;
1059 
1060  if( bHas3DEffectinShape)
1061  WriteShape3DEffects( rXPropSet );
1062  }
1063 
1064  pFS->endElementNS( mnXmlNamespace, XML_spPr );
1065 
1066  pFS->startElementNS(mnXmlNamespace, XML_style);
1067  WriteShapeStyle( rXPropSet );
1068  pFS->endElementNS( mnXmlNamespace, XML_style );
1069 
1070  // write text
1071  WriteTextBox( xShape, mnXmlNamespace );
1072 
1073  pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
1074 
1075  return *this;
1076 }
1077 
1079 {
1080  SAL_INFO("oox.shape", "write ellipse shape");
1081 
1082  FSHelperPtr pFS = GetFS();
1083 
1084  pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp));
1085 
1086  // TODO: connector ?
1087 
1088  // non visual shape properties
1090  {
1091  pFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
1092  pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
1093  XML_id, OString::number(GetNewShapeID(xShape)),
1094  XML_name, GetShapeName(xShape));
1095  pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr );
1096  WriteNonVisualProperties( xShape );
1097  pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
1098  }
1099  else
1100  pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
1101 
1102  Reference< XPropertySet > xProps( xShape, UNO_QUERY );
1103  CircleKind eCircleKind(CircleKind_FULL);
1104  if (xProps.is())
1105  xProps->getPropertyValue("CircleKind" ) >>= eCircleKind;
1106 
1107  // visual shape properties
1108  pFS->startElementNS( mnXmlNamespace, XML_spPr );
1109  WriteShapeTransformation( xShape, XML_a );
1110 
1111  if (CircleKind_FULL == eCircleKind)
1112  WritePresetShape("ellipse");
1113  else
1114  {
1115  sal_Int32 nStartAngleIntern(9000);
1116  sal_Int32 nEndAngleIntern(0);
1117  if (xProps.is())
1118  {
1119  xProps->getPropertyValue("CircleStartAngle" ) >>= nStartAngleIntern;
1120  xProps->getPropertyValue("CircleEndAngle") >>= nEndAngleIntern;
1121  }
1122  std::vector< std::pair<sal_Int32,sal_Int32>> aAvList;
1123  awt::Size aSize = xShape->getSize();
1124  if (aSize.Width != 0 || aSize.Height != 0)
1125  {
1126  // Our arc has 90° up, OOXML has 90° down, so mirror it.
1127  // API angles are 1/100 degree.
1128  sal_Int32 nStartAngleOOXML(lcl_CircleAngle2CustomShapeEllipseAngleOOX(36000 - nEndAngleIntern, aSize.Width, aSize.Height));
1129  sal_Int32 nEndAngleOOXML(lcl_CircleAngle2CustomShapeEllipseAngleOOX(36000 - nStartAngleIntern, aSize.Width, aSize.Height));
1130  lcl_AppendAdjustmentValue( aAvList, 1, nStartAngleOOXML);
1131  lcl_AppendAdjustmentValue( aAvList, 2, nEndAngleOOXML);
1132  }
1133  switch (eCircleKind)
1134  {
1135  case CircleKind_ARC :
1136  WritePresetShape("arc", aAvList);
1137  break;
1138  case CircleKind_SECTION :
1139  WritePresetShape("pie", aAvList);
1140  break;
1141  case CircleKind_CUT :
1142  WritePresetShape("chord", aAvList);
1143  break;
1144  default :
1145  WritePresetShape("ellipse");
1146  }
1147  }
1148  if( xProps.is() )
1149  {
1150  if (CircleKind_ARC == eCircleKind)
1151  {
1152  // An arc in ODF is never filled, even if a fill style other than
1153  // "none" is set. OOXML arc can be filled, so set fill explicit to
1154  // NONE, otherwise some hidden or inherited filling is shown.
1155  FillStyle eFillStyle(FillStyle_NONE);
1156  uno::Any aNewValue;
1157  aNewValue <<= eFillStyle;
1158  xProps->setPropertyValue("FillStyle", aNewValue);
1159  }
1160  WriteFill( xProps );
1161  WriteOutline( xProps );
1162  }
1163  pFS->endElementNS( mnXmlNamespace, XML_spPr );
1164 
1165  // write text
1166  WriteTextBox( xShape, mnXmlNamespace );
1167 
1168  pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
1169 
1170  return *this;
1171 }
1172 
1174 {
1175  WriteGraphicObjectShapePart( xShape );
1176 
1177  return *this;
1178 }
1179 
1181 {
1182  SAL_INFO("oox.shape", "write graphic object shape");
1183 
1184  if (IsNonEmptySimpleText(xShape))
1185  {
1186  SAL_INFO("oox.shape", "graphicObject: wrote only text");
1187 
1188  WriteTextShape(xShape);
1189 
1190  return;
1191  }
1192 
1193  SAL_INFO("oox.shape", "graphicObject without text");
1194 
1195  uno::Reference<graphic::XGraphic> xGraphic;
1196  OUString sMediaURL;
1197 
1198  Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
1199 
1200  if (pGraphic)
1201  {
1202  xGraphic.set(pGraphic->GetXGraphic());
1203  }
1204  else if (xShapeProps.is() && xShapeProps->getPropertySetInfo()->hasPropertyByName("Graphic"))
1205  {
1206  xShapeProps->getPropertyValue("Graphic") >>= xGraphic;
1207  }
1208 
1209  bool bHasMediaURL = xShapeProps.is() && xShapeProps->getPropertySetInfo()->hasPropertyByName("MediaURL") && (xShapeProps->getPropertyValue("MediaURL") >>= sMediaURL);
1210 
1211  if (!xGraphic.is() && !bHasMediaURL)
1212  {
1213  SAL_INFO("oox.shape", "no graphic or media URL found");
1214  return;
1215  }
1216 
1217  FSHelperPtr pFS = GetFS();
1218  XmlFilterBase* pFB = GetFB();
1219 
1221  pFS->startElementNS(mnXmlNamespace, XML_pic);
1222  else
1223  pFS->startElementNS(mnXmlNamespace, XML_pic,
1224  FSNS(XML_xmlns, XML_pic), pFB->getNamespaceURL(OOX_NS(dmlPicture)));
1225 
1226  pFS->startElementNS(mnXmlNamespace, XML_nvPicPr);
1227 
1228  presentation::ClickAction eClickAction = presentation::ClickAction_NONE;
1229  OUString sDescr, sURL, sBookmark, sPPAction;
1230  bool bHaveDesc;
1231 
1232  if ( ( bHaveDesc = GetProperty( xShapeProps, "Description" ) ) )
1233  mAny >>= sDescr;
1234  if ( GetProperty( xShapeProps, "URL" ) )
1235  mAny >>= sURL;
1236  if (GetProperty(xShapeProps, "Bookmark"))
1237  mAny >>= sBookmark;
1238  if (GetProperty(xShapeProps, "OnClick"))
1239  mAny >>= eClickAction;
1240 
1241  pFS->startElementNS( mnXmlNamespace, XML_cNvPr,
1242  XML_id, OString::number(GetNewShapeID(xShape)),
1243  XML_name, GetShapeName(xShape),
1244  XML_descr, sax_fastparser::UseIf(sDescr, bHaveDesc));
1245 
1246  if (eClickAction != presentation::ClickAction_NONE)
1247  {
1248  switch (eClickAction)
1249  {
1250  case presentation::ClickAction_STOPPRESENTATION:
1251  sPPAction = "ppaction://hlinkshowjump?jump=endshow";
1252  break;
1253  case presentation::ClickAction_NEXTPAGE:
1254  sPPAction = "ppaction://hlinkshowjump?jump=nextslide";
1255  break;
1256  case presentation::ClickAction_LASTPAGE:
1257  sPPAction = "ppaction://hlinkshowjump?jump=lastslide";
1258  break;
1259  case presentation::ClickAction_PREVPAGE:
1260  sPPAction = "ppaction://hlinkshowjump?jump=previousslide";
1261  break;
1262  case presentation::ClickAction_FIRSTPAGE:
1263  sPPAction = "ppaction://hlinkshowjump?jump=firstslide";
1264  break;
1265  case presentation::ClickAction_BOOKMARK:
1266  sBookmark = "#" + sBookmark;
1267  break;
1268  default:
1269  break;
1270  }
1271  }
1272 
1273  // OOXTODO: //cNvPr children: XML_extLst, XML_hlinkHover
1274  if (bHasMediaURL || !sPPAction.isEmpty())
1275  pFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), "", XML_action,
1276  bHasMediaURL ? "ppaction://media" : sPPAction);
1277  if( !sURL.isEmpty() )
1278  {
1279  OUString sRelId = mpFB->addRelation( mpFS->getOutputStream(),
1281  mpURLTransformer->getTransformedString(sURL),
1282  mpURLTransformer->isExternalURL(sURL));
1283 
1284  mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
1285  }
1286 
1287  if (!sBookmark.isEmpty())
1288  {
1289  bool bExtURL = URLTransformer().isExternalURL(sBookmark);
1290  sBookmark = bExtURL ? sBookmark : lcl_GetTarget(GetFB()->getModel(), sBookmark);
1291 
1292  OUString sRelId = mpFB->addRelation(mpFS->getOutputStream(),
1295  sBookmark, bExtURL);
1296 
1297  if (bExtURL)
1298  mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
1299  else
1300  mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId, XML_action,
1301  "ppaction://hlinksldjump");
1302  }
1303  pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
1304 
1305  pFS->singleElementNS(mnXmlNamespace, XML_cNvPicPr
1306  // OOXTODO: XML_preferRelativeSize
1307  );
1308  if (bHasMediaURL)
1310  else
1311  WriteNonVisualProperties(xShape);
1312 
1313  pFS->endElementNS( mnXmlNamespace, XML_nvPicPr );
1314 
1315  pFS->startElementNS(mnXmlNamespace, XML_blipFill);
1316 
1317  if (xGraphic.is())
1318  {
1319  WriteXGraphicBlip(xShapeProps, xGraphic, mbUserShapes);
1320  }
1321  else if (bHasMediaURL)
1322  {
1323  Reference<graphic::XGraphic> xFallbackGraphic;
1324  if (xShapeProps->getPropertySetInfo()->hasPropertyByName("FallbackGraphic"))
1325  xShapeProps->getPropertyValue("FallbackGraphic") >>= xFallbackGraphic;
1326 
1327  WriteXGraphicBlip(xShapeProps, xFallbackGraphic, mbUserShapes);
1328  }
1329 
1330  if (xGraphic.is())
1331  {
1332  WriteSrcRectXGraphic(xShapeProps, xGraphic);
1333  }
1334 
1335  // now we stretch always when we get pGraphic (when changing that
1336  // behavior, test n#780830 for regression, where the OLE sheet might get tiled
1337  bool bStretch = false;
1338  if( !pGraphic && GetProperty( xShapeProps, "FillBitmapStretch" ) )
1339  mAny >>= bStretch;
1340 
1341  if ( pGraphic || bStretch )
1342  pFS->singleElementNS(XML_a, XML_stretch);
1343 
1344  if (bHasMediaURL)
1345  {
1346  // Graphic of media shapes is always stretched.
1347  pFS->startElementNS(XML_a, XML_stretch);
1348  pFS->singleElementNS(XML_a, XML_fillRect);
1349  pFS->endElementNS(XML_a, XML_stretch);
1350  }
1351 
1352  pFS->endElementNS( mnXmlNamespace, XML_blipFill );
1353 
1354  // visual shape properties
1355  pFS->startElementNS(mnXmlNamespace, XML_spPr);
1356  bool bFlipH = false;
1357  if( xShapeProps->getPropertySetInfo()->hasPropertyByName("IsMirrored") )
1358  {
1359  xShapeProps->getPropertyValue("IsMirrored") >>= bFlipH;
1360  }
1361  WriteShapeTransformation( xShape, XML_a, bFlipH, false, false, false, true );
1362  WritePresetShape( "rect" );
1363  // graphic object can come with the frame (bnc#654525)
1364  WriteOutline( xShapeProps );
1365 
1366  WriteShapeEffects( xShapeProps );
1367  WriteShape3DEffects( xShapeProps );
1368 
1369  pFS->endElementNS( mnXmlNamespace, XML_spPr );
1370 
1371  pFS->endElementNS( mnXmlNamespace, XML_pic );
1372 }
1373 
1375 {
1376  bool bFlipH = false;
1377  bool bFlipV = false;
1378 
1379  SAL_INFO("oox.shape", "write connector shape");
1380 
1381  FSHelperPtr pFS = GetFS();
1382 
1383  const char* sGeometry = "line";
1384  Reference< XPropertySet > rXPropSet( xShape, UNO_QUERY );
1385  Reference< XPropertyState > rXPropState( xShape, UNO_QUERY );
1386  awt::Point aStartPoint, aEndPoint;
1387  Reference< XShape > rXShapeA;
1388  Reference< XShape > rXShapeB;
1389  PropertyState eState;
1390  ConnectorType eConnectorType;
1391  if( GETAD( EdgeKind ) ) {
1392  mAny >>= eConnectorType;
1393 
1394  switch( eConnectorType ) {
1395  case ConnectorType_CURVE:
1396  sGeometry = "curvedConnector3";
1397  break;
1398  case ConnectorType_STANDARD:
1399  sGeometry = "bentConnector3";
1400  break;
1401  default:
1402  case ConnectorType_LINE:
1403  case ConnectorType_LINES:
1404  sGeometry = "straightConnector1";
1405  break;
1406  }
1407 
1408  if( GETAD( EdgeStartPoint ) ) {
1409  mAny >>= aStartPoint;
1410  if( GETAD( EdgeEndPoint ) ) {
1411  mAny >>= aEndPoint;
1412  }
1413  }
1414  GET( rXShapeA, EdgeStartConnection );
1415  GET( rXShapeB, EdgeEndConnection );
1416  }
1417  // Position is relative to group in Word, but relative to anchor of group in API.
1418  if (GetDocumentType() == DOCUMENT_DOCX && !mbUserShapes && m_xParent.is())
1419  {
1420  awt::Point aParentPos = m_xParent->getPosition();
1421  aStartPoint.X -= aParentPos.X;
1422  aStartPoint.Y -= aParentPos.Y;
1423  aEndPoint.X -= aParentPos.X;
1424  aEndPoint.Y -= aParentPos.Y;
1425  }
1426  EscherConnectorListEntry aConnectorEntry( xShape, aStartPoint, rXShapeA, aEndPoint, rXShapeB );
1427  tools::Rectangle aRect( Point( aStartPoint.X, aStartPoint.Y ), Point( aEndPoint.X, aEndPoint.Y ) );
1428  if( aRect.getWidth() < 0 ) {
1429  bFlipH = true;
1430  aRect.SetLeft(aEndPoint.X);
1431  aRect.setWidth( aStartPoint.X - aEndPoint.X );
1432  }
1433 
1434  if( aRect.getHeight() < 0 ) {
1435  bFlipV = true;
1436  aRect.SetTop(aEndPoint.Y);
1437  aRect.setHeight( aStartPoint.Y - aEndPoint.Y );
1438  }
1439 
1440  // tdf#99810 connector shape (cxnSp) is not valid with namespace 'wps'
1441  const auto nShapeNode = (mnXmlNamespace == XML_wps ? XML_wsp : XML_cxnSp);
1442  pFS->startElementNS(mnXmlNamespace, nShapeNode);
1443 
1444  if (mnXmlNamespace == XML_wps)
1445  {
1446  // non visual connector shape drawing properties
1447  pFS->singleElementNS(mnXmlNamespace, XML_cNvCnPr);
1448  }
1449  else
1450  {
1451  // non visual shape properties
1452  pFS->startElementNS(mnXmlNamespace, XML_nvCxnSpPr);
1453  pFS->singleElementNS(mnXmlNamespace, XML_cNvPr,
1454  XML_id, OString::number(GetNewShapeID(xShape)),
1455  XML_name, GetShapeName(xShape));
1456  // non visual connector shape drawing properties
1457  pFS->startElementNS(mnXmlNamespace, XML_cNvCxnSpPr);
1458  WriteConnectorConnections(aConnectorEntry, GetShapeID(rXShapeA), GetShapeID(rXShapeB));
1459  pFS->endElementNS(mnXmlNamespace, XML_cNvCxnSpPr);
1460  pFS->singleElementNS(mnXmlNamespace, XML_nvPr);
1461  pFS->endElementNS(mnXmlNamespace, XML_nvCxnSpPr);
1462  }
1463 
1464  // visual shape properties
1465  pFS->startElementNS(mnXmlNamespace, XML_spPr);
1466  WriteTransformation( xShape, aRect, XML_a, bFlipH, bFlipV );
1467  // TODO: write adjustments (ppt export doesn't work well there either)
1468  WritePresetShape( sGeometry );
1469  Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
1470  if( xShapeProps.is() )
1471  WriteOutline( xShapeProps );
1472  pFS->endElementNS( mnXmlNamespace, XML_spPr );
1473 
1474  // write text
1475  WriteTextBox( xShape, mnXmlNamespace );
1476 
1477  pFS->endElementNS(mnXmlNamespace, nShapeNode);
1478 
1479  return *this;
1480 }
1481 
1483 {
1484  bool bFlipH = false;
1485  bool bFlipV = false;
1486 
1487  SAL_INFO("oox.shape", "write line shape");
1488 
1489  FSHelperPtr pFS = GetFS();
1490 
1491  pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp));
1492 
1494  if( aPolyPolygon.Count() == 1 && aPolyPolygon[ 0 ].GetSize() == 2)
1495  {
1496  const tools::Polygon& rPoly = aPolyPolygon[ 0 ];
1497 
1498  bFlipH = ( rPoly[ 0 ].X() > rPoly[ 1 ].X() );
1499  bFlipV = ( rPoly[ 0 ].Y() > rPoly[ 1 ].Y() );
1500  }
1501 
1502  // non visual shape properties
1504  {
1505  pFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
1506  pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
1507  XML_id, OString::number(GetNewShapeID(xShape)),
1508  XML_name, GetShapeName(xShape));
1509  }
1510  pFS->singleElementNS( mnXmlNamespace, XML_cNvSpPr );
1512  {
1513  WriteNonVisualProperties( xShape );
1514  pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
1515  }
1516 
1517  // visual shape properties
1518  pFS->startElementNS(mnXmlNamespace, XML_spPr);
1519  WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV, true);
1520  WritePresetShape( "line" );
1521  Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
1522  if( xShapeProps.is() )
1523  WriteOutline( xShapeProps );
1524  pFS->endElementNS( mnXmlNamespace, XML_spPr );
1525 
1526  //write style
1527  pFS->startElementNS(mnXmlNamespace, XML_style);
1528  WriteShapeStyle( xShapeProps );
1529  pFS->endElementNS( mnXmlNamespace, XML_style );
1530 
1531  // write text
1532  WriteTextBox( xShape, mnXmlNamespace );
1533 
1534  pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
1535 
1536  return *this;
1537 }
1538 
1540 {
1541  GetFS()->singleElementNS( mnXmlNamespace, XML_cNvPr,
1542  XML_id, OString::number(GetNewShapeID(xShape)),
1543  XML_name, pName );
1544 
1545  return *this;
1546 }
1547 
1549 {
1550  // Override to generate //nvPr elements.
1551  return *this;
1552 }
1553 
1555 {
1556  SAL_INFO("oox.shape", "write rectangle shape");
1557 
1558  FSHelperPtr pFS = GetFS();
1559 
1560  pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp));
1561 
1562  sal_Int32 nRadius = 0;
1563 
1564  Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
1565  if( xShapeProps.is() )
1566  {
1567  xShapeProps->getPropertyValue( "CornerRadius" ) >>= nRadius;
1568  }
1569 
1570  if( nRadius )
1571  {
1572  nRadius = MapSize( awt::Size( nRadius, 0 ) ).Width;
1573  }
1574  //TODO: use nRadius value more precisely than just deciding whether to use
1575  // "rect" or "roundRect" preset shape below
1576 
1577  // non visual shape properties
1579  pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
1580  pFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
1581  pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
1582  XML_id, OString::number(GetNewShapeID(xShape)),
1583  XML_name, GetShapeName(xShape));
1584  pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
1585  WriteNonVisualProperties( xShape );
1586  pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
1587 
1588  // visual shape properties
1589  pFS->startElementNS(mnXmlNamespace, XML_spPr);
1590  WriteShapeTransformation( xShape, XML_a );
1591  WritePresetShape( nRadius == 0 ? "rect" : "roundRect" );
1592  Reference< XPropertySet > xProps( xShape, UNO_QUERY );
1593  if( xProps.is() )
1594  {
1595  WriteFill( xProps );
1596  WriteOutline( xProps );
1597  }
1598  pFS->endElementNS( mnXmlNamespace, XML_spPr );
1599 
1600  // write text
1601  WriteTextBox( xShape, mnXmlNamespace );
1602 
1603  pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
1604 
1605  return *this;
1606 }
1607 
1609 typedef std::unordered_map< const char*, ShapeConverter, rtl::CStringHash, rtl::CStringEqual> NameToConvertMapType;
1610 
1611 static const NameToConvertMapType& lcl_GetConverters()
1612 {
1613  static NameToConvertMapType const shape_converters
1614  {
1615  { "com.sun.star.drawing.ClosedBezierShape" , &ShapeExport::WriteClosedPolyPolygonShape },
1616  { "com.sun.star.drawing.ConnectorShape" , &ShapeExport::WriteConnectorShape },
1617  { "com.sun.star.drawing.CustomShape" , &ShapeExport::WriteCustomShape },
1618  { "com.sun.star.drawing.EllipseShape" , &ShapeExport::WriteEllipseShape },
1619  { "com.sun.star.drawing.GraphicObjectShape" , &ShapeExport::WriteGraphicObjectShape },
1620  { "com.sun.star.drawing.LineShape" , &ShapeExport::WriteLineShape },
1621  { "com.sun.star.drawing.OpenBezierShape" , &ShapeExport::WriteOpenPolyPolygonShape },
1622  { "com.sun.star.drawing.PolyPolygonShape" , &ShapeExport::WriteClosedPolyPolygonShape },
1623  { "com.sun.star.drawing.PolyLineShape" , &ShapeExport::WriteOpenPolyPolygonShape },
1624  { "com.sun.star.drawing.RectangleShape" , &ShapeExport::WriteRectangleShape },
1625  { "com.sun.star.drawing.OLE2Shape" , &ShapeExport::WriteOLE2Shape },
1626  { "com.sun.star.drawing.TableShape" , &ShapeExport::WriteTableShape },
1627  { "com.sun.star.drawing.TextShape" , &ShapeExport::WriteTextShape },
1628  { "com.sun.star.drawing.GroupShape" , &ShapeExport::WriteGroupShape },
1629 
1630  { "com.sun.star.presentation.GraphicObjectShape" , &ShapeExport::WriteGraphicObjectShape },
1631  { "com.sun.star.presentation.MediaShape" , &ShapeExport::WriteGraphicObjectShape },
1632  { "com.sun.star.presentation.ChartShape" , &ShapeExport::WriteOLE2Shape },
1633  { "com.sun.star.presentation.OLE2Shape" , &ShapeExport::WriteOLE2Shape },
1634  { "com.sun.star.presentation.TableShape" , &ShapeExport::WriteTableShape },
1635  { "com.sun.star.presentation.TextShape" , &ShapeExport::WriteTextShape },
1636 
1637  { "com.sun.star.presentation.DateTimeShape" , &ShapeExport::WriteTextShape },
1638  { "com.sun.star.presentation.FooterShape" , &ShapeExport::WriteTextShape },
1639  { "com.sun.star.presentation.HeaderShape" , &ShapeExport::WriteTextShape },
1640  { "com.sun.star.presentation.NotesShape" , &ShapeExport::WriteTextShape },
1641  { "com.sun.star.presentation.OutlinerShape" , &ShapeExport::WriteTextShape },
1642  { "com.sun.star.presentation.SlideNumberShape" , &ShapeExport::WriteTextShape },
1643  { "com.sun.star.presentation.TitleTextShape" , &ShapeExport::WriteTextShape },
1644  };
1645  return shape_converters;
1646 }
1647 
1649 {
1650  OUString sShapeType = xShape->getShapeType();
1651  SAL_INFO("oox.shape", "write shape: " << sShapeType);
1652  NameToConvertMapType::const_iterator aConverter
1653  = lcl_GetConverters().find(sShapeType.toUtf8().getStr());
1654  if (aConverter == lcl_GetConverters().end())
1655  {
1656  SAL_INFO("oox.shape", "unknown shape");
1657  return WriteUnknownShape( xShape );
1658  }
1659  (this->*(aConverter->second))( xShape );
1660 
1661  return *this;
1662 }
1663 
1664 ShapeExport& ShapeExport::WriteTextBox( const Reference< XInterface >& xIface, sal_Int32 nXmlNamespace, bool bWritePropertiesAsLstStyles )
1665 {
1666  // In case this shape has an associated textbox, then export that, and we're done.
1668  {
1669  uno::Reference<beans::XPropertySet> xPropertySet(xIface, uno::UNO_QUERY);
1670  if (xPropertySet.is())
1671  {
1672  uno::Reference<beans::XPropertySetInfo> xPropertySetInfo = xPropertySet->getPropertySetInfo();
1673  if (xPropertySetInfo->hasPropertyByName("TextBox") && xPropertySet->getPropertyValue("TextBox").get<bool>())
1674  {
1675  GetTextExport()->WriteTextBox(uno::Reference<drawing::XShape>(xIface, uno::UNO_QUERY_THROW));
1676  WriteText( xIface, /*bBodyPr=*/true, /*bText=*/false, /*nXmlNamespace=*/nXmlNamespace );
1677  return *this;
1678  }
1679  }
1680  }
1681 
1682  Reference< XText > xXText( xIface, UNO_QUERY );
1683  if( NonEmptyText( xIface ) && xXText.is() )
1684  {
1685  FSHelperPtr pFS = GetFS();
1686 
1687  pFS->startElementNS(nXmlNamespace,
1688  (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_txBody : XML_txbx));
1689  WriteText(xIface, /*bBodyPr=*/(GetDocumentType() != DOCUMENT_DOCX || mbUserShapes), /*bText=*/true,
1690  /*nXmlNamespace=*/0, /*bWritePropertiesAsLstStyles=*/bWritePropertiesAsLstStyles);
1691  pFS->endElementNS( nXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_txBody : XML_txbx) );
1693  WriteText( xIface, /*bBodyPr=*/true, /*bText=*/false, /*nXmlNamespace=*/nXmlNamespace );
1694  }
1695  else if (GetDocumentType() == DOCUMENT_DOCX && !mbUserShapes)
1696  mpFS->singleElementNS(nXmlNamespace, XML_bodyPr);
1697 
1698  return *this;
1699 }
1700 
1702 {
1703  Reference< XTable > xTable;
1704  Reference< XPropertySet > xPropSet( rXShape, UNO_QUERY );
1705 
1706  mpFS->startElementNS(XML_a, XML_graphic);
1707  mpFS->startElementNS(XML_a, XML_graphicData,
1708  XML_uri, "http://schemas.openxmlformats.org/drawingml/2006/table");
1709 
1710  if ( xPropSet.is() && ( xPropSet->getPropertyValue( "Model" ) >>= xTable ) )
1711  {
1712  mpFS->startElementNS(XML_a, XML_tbl);
1713  mpFS->startElementNS(XML_a, XML_tblPr);
1714  WriteShapeEffects(xPropSet);
1715  mpFS->endElementNS(XML_a, XML_tblPr);
1716 
1717  Reference< container::XIndexAccess > xColumns( xTable->getColumns(), UNO_QUERY_THROW );
1718  Reference< container::XIndexAccess > xRows( xTable->getRows(), UNO_QUERY_THROW );
1719  sal_uInt16 nRowCount = static_cast< sal_uInt16 >( xRows->getCount() );
1720  sal_uInt16 nColumnCount = static_cast< sal_uInt16 >( xColumns->getCount() );
1721 
1722  mpFS->startElementNS(XML_a, XML_tblGrid);
1723 
1724  for ( sal_Int32 x = 0; x < nColumnCount; x++ )
1725  {
1726  Reference< XPropertySet > xColPropSet( xColumns->getByIndex( x ), UNO_QUERY_THROW );
1727  sal_Int32 nWidth(0);
1728  xColPropSet->getPropertyValue( "Width" ) >>= nWidth;
1729 
1730  mpFS->singleElementNS(XML_a, XML_gridCol,
1731  XML_w, OString::number(oox::drawingml::convertHmmToEmu(nWidth)));
1732  }
1733 
1734  mpFS->endElementNS( XML_a, XML_tblGrid );
1735 
1736  // map for holding the transpose index of the merged cells and pair<parentTransposeIndex, parentCell>
1737  typedef std::unordered_map<sal_Int32, std::pair<sal_Int32, Reference< XMergeableCell> > > transposeTableMap;
1738  transposeTableMap mergedCellMap;
1739 
1740  for( sal_Int32 nRow = 0; nRow < nRowCount; nRow++ )
1741  {
1742  Reference< XPropertySet > xRowPropSet( xRows->getByIndex( nRow ), UNO_QUERY_THROW );
1743  sal_Int32 nRowHeight(0);
1744 
1745  xRowPropSet->getPropertyValue( "Height" ) >>= nRowHeight;
1746 
1747  mpFS->startElementNS(XML_a, XML_tr,
1748  XML_h, OString::number(oox::drawingml::convertHmmToEmu(nRowHeight)));
1749  for( sal_Int32 nColumn = 0; nColumn < nColumnCount; nColumn++ )
1750  {
1751  Reference< XMergeableCell > xCell( xTable->getCellByPosition( nColumn, nRow ),
1752  UNO_QUERY_THROW );
1753  sal_Int32 transposedIndexofCell = (nRow * nColumnCount) + nColumn;
1754 
1755  //assume we will open a cell, set to false below if we won't
1756  bool bCellOpened = true;
1757 
1758  if(xCell->getColumnSpan() > 1 && xCell->getRowSpan() > 1)
1759  {
1760  // having both : horizontal and vertical merge
1761  mpFS->startElementNS(XML_a, XML_tc,
1762  XML_gridSpan, OString::number(xCell->getColumnSpan()),
1763  XML_rowSpan, OString::number(xCell->getRowSpan()));
1764  // since, XMergeableCell doesn't have the information about
1765  // cell having hMerge or vMerge.
1766  // So, Populating the merged cell map in-order to use it to
1767  // decide the attribute for the individual cell.
1768  for(sal_Int32 columnIndex = nColumn; columnIndex < nColumn+xCell->getColumnSpan(); ++columnIndex)
1769  {
1770  for(sal_Int32 rowIndex = nRow; rowIndex < nRow+xCell->getRowSpan(); ++rowIndex)
1771  {
1772  sal_Int32 transposeIndexForMergeCell =
1773  (rowIndex * nColumnCount) + columnIndex;
1774  mergedCellMap[transposeIndexForMergeCell] =
1775  std::make_pair(transposedIndexofCell, xCell);
1776  }
1777  }
1778 
1779  }
1780  else if(xCell->getColumnSpan() > 1)
1781  {
1782  // having : horizontal merge
1783  mpFS->startElementNS(XML_a, XML_tc,
1784  XML_gridSpan, OString::number(xCell->getColumnSpan()));
1785  for(sal_Int32 columnIndex = nColumn; columnIndex < nColumn + xCell->getColumnSpan(); ++columnIndex) {
1786  sal_Int32 transposeIndexForMergeCell = (nRow*nColumnCount) + columnIndex;
1787  mergedCellMap[transposeIndexForMergeCell] =
1788  std::make_pair(transposedIndexofCell, xCell);
1789  }
1790  }
1791  else if(xCell->getRowSpan() > 1)
1792  {
1793  // having : vertical merge
1794  mpFS->startElementNS(XML_a, XML_tc,
1795  XML_rowSpan, OString::number(xCell->getRowSpan()));
1796 
1797  for(sal_Int32 rowIndex = nRow; rowIndex < nRow + xCell->getRowSpan(); ++rowIndex) {
1798  sal_Int32 transposeIndexForMergeCell = (rowIndex*nColumnCount) + nColumn;
1799  mergedCellMap[transposeIndexForMergeCell] =
1800  std::make_pair(transposedIndexofCell, xCell);
1801  }
1802  }
1803  else
1804  {
1805  // now, the cell can be an independent cell or
1806  // it can be a cell which is been merged to some parent cell
1807  if(!xCell->isMerged())
1808  {
1809  // independent cell
1810  mpFS->startElementNS(XML_a, XML_tc);
1811  }
1812  else
1813  {
1814  // it a merged cell to some parent cell
1815  // find the parent cell for the current cell at hand
1816  transposeTableMap::iterator it = mergedCellMap.find(transposedIndexofCell);
1817  if(it != mergedCellMap.end())
1818  {
1819  sal_Int32 transposeIndexOfParent = it->second.first;
1820  Reference< XMergeableCell > parentCell = it->second.second;
1821  // finding the row and column index for the parent cell from transposed index
1822  sal_Int32 parentColumnIndex = transposeIndexOfParent % nColumnCount;
1823  sal_Int32 parentRowIndex = transposeIndexOfParent / nColumnCount;
1824  if(nColumn == parentColumnIndex)
1825  {
1826  // the cell is vertical merge and it might have gridspan
1827  if(parentCell->getColumnSpan() > 1)
1828  {
1829  // vMerge and has gridSpan
1830  mpFS->startElementNS(XML_a, XML_tc,
1831  XML_vMerge, OString::number(1),
1832  XML_gridSpan, OString::number(xCell->getColumnSpan()));
1833  }
1834  else
1835  {
1836  // only vMerge
1837  mpFS->startElementNS(XML_a, XML_tc,
1838  XML_vMerge, OString::number(1));
1839  }
1840  }
1841  else if(nRow == parentRowIndex)
1842  {
1843  // the cell is horizontal merge and it might have rowspan
1844  if(parentCell->getRowSpan() > 1)
1845  {
1846  // hMerge and has rowspan
1847  mpFS->startElementNS(XML_a, XML_tc,
1848  XML_hMerge, OString::number(1),
1849  XML_rowSpan, OString::number(xCell->getRowSpan()));
1850  }
1851  else
1852  {
1853  // only hMerge
1854  mpFS->startElementNS(XML_a, XML_tc,
1855  XML_hMerge, OString::number(1));
1856  }
1857  }
1858  else
1859  {
1860  // has hMerge and vMerge
1861  mpFS->startElementNS(XML_a, XML_tc,
1862  XML_vMerge, OString::number(1),
1863  XML_hMerge, OString::number(1));
1864  }
1865  }
1866  else
1867  bCellOpened = false;
1868  }
1869  }
1870 
1871  if (bCellOpened)
1872  {
1873  WriteTextBox( xCell, XML_a );
1874 
1875  Reference< XPropertySet > xCellPropSet(xCell, UNO_QUERY_THROW);
1876  WriteTableCellProperties(xCellPropSet);
1877 
1878  mpFS->endElementNS( XML_a, XML_tc );
1879  }
1880  }
1881 
1882  mpFS->endElementNS( XML_a, XML_tr );
1883  }
1884 
1885  mpFS->endElementNS( XML_a, XML_tbl );
1886  }
1887 
1888  mpFS->endElementNS( XML_a, XML_graphicData );
1889  mpFS->endElementNS( XML_a, XML_graphic );
1890 }
1891 
1893 {
1894  sal_Int32 nLeftMargin(0), nRightMargin(0);
1895  TextVerticalAdjust eVerticalAlignment;
1896  const char* sVerticalAlignment;
1897 
1898  Any aLeftMargin = xCellPropSet->getPropertyValue("TextLeftDistance");
1899  aLeftMargin >>= nLeftMargin;
1900 
1901  Any aRightMargin = xCellPropSet->getPropertyValue("TextRightDistance");
1902  aRightMargin >>= nRightMargin;
1903 
1904  Any aVerticalAlignment = xCellPropSet->getPropertyValue("TextVerticalAdjust");
1905  aVerticalAlignment >>= eVerticalAlignment;
1906  sVerticalAlignment = GetTextVerticalAdjust(eVerticalAlignment);
1907 
1908  mpFS->startElementNS(XML_a, XML_tcPr, XML_anchor, sVerticalAlignment,
1910  XML_marR, sax_fastparser::UseIf(OString::number(oox::drawingml::convertHmmToEmu(nRightMargin)), nRightMargin > 0));
1911 
1912  // Write background fill for table cell.
1913  // TODO
1914  // tcW : Table cell width
1915  WriteTableCellBorders(xCellPropSet);
1916  DrawingML::WriteFill(xCellPropSet);
1917  mpFS->endElementNS( XML_a, XML_tcPr );
1918 }
1919 
1920 void ShapeExport::WriteBorderLine(const sal_Int32 XML_line, const BorderLine2& rBorderLine)
1921 {
1922 // While importing the table cell border line width, it converts EMU->Hmm then divided result by 2.
1923 // To get original value of LineWidth need to multiple by 2.
1924  sal_Int32 nBorderWidth = rBorderLine.LineWidth;
1925  nBorderWidth *= 2;
1926  nBorderWidth = oox::drawingml::convertHmmToEmu( nBorderWidth );
1927 
1928  if ( nBorderWidth > 0 )
1929  {
1930  mpFS->startElementNS(XML_a, XML_line, XML_w, OString::number(nBorderWidth));
1931  if ( rBorderLine.Color == sal_Int32( COL_AUTO ) )
1932  mpFS->singleElementNS(XML_a, XML_noFill);
1933  else
1934  DrawingML::WriteSolidFill( ::Color(ColorTransparency, rBorderLine.Color) );
1935  mpFS->endElementNS( XML_a, XML_line );
1936  }
1937 }
1938 
1940 {
1941  BorderLine2 aBorderLine;
1942 
1943 // lnL - Left Border Line Properties of table cell
1944  xCellPropSet->getPropertyValue("LeftBorder") >>= aBorderLine;
1945  WriteBorderLine( XML_lnL, aBorderLine );
1946 
1947 // lnR - Right Border Line Properties of table cell
1948  xCellPropSet->getPropertyValue("RightBorder") >>= aBorderLine;
1949  WriteBorderLine( XML_lnR, aBorderLine );
1950 
1951 // lnT - Top Border Line Properties of table cell
1952  xCellPropSet->getPropertyValue("TopBorder") >>= aBorderLine;
1953  WriteBorderLine( XML_lnT, aBorderLine );
1954 
1955 // lnB - Bottom Border Line Properties of table cell
1956  xCellPropSet->getPropertyValue("BottomBorder") >>= aBorderLine;
1957  WriteBorderLine( XML_lnB, aBorderLine );
1958 }
1959 
1961 {
1962  FSHelperPtr pFS = GetFS();
1963 
1964  pFS->startElementNS(mnXmlNamespace, XML_graphicFrame);
1965 
1966  pFS->startElementNS(mnXmlNamespace, XML_nvGraphicFramePr);
1967 
1968  pFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
1969  XML_id, OString::number(GetNewShapeID(xShape)),
1970  XML_name, GetShapeName(xShape));
1971 
1972  pFS->singleElementNS(mnXmlNamespace, XML_cNvGraphicFramePr);
1973 
1974  if( GetDocumentType() == DOCUMENT_PPTX )
1975  pFS->singleElementNS(mnXmlNamespace, XML_nvPr);
1976  pFS->endElementNS( mnXmlNamespace, XML_nvGraphicFramePr );
1977 
1979  WriteTable( xShape );
1980 
1981  pFS->endElementNS( mnXmlNamespace, XML_graphicFrame );
1982 
1983  return *this;
1984 }
1985 
1987 {
1988  FSHelperPtr pFS = GetFS();
1989  Reference<XPropertySet> xShapeProps(xShape, UNO_QUERY);
1990 
1991  pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp));
1992 
1993  // non visual shape properties
1995  {
1996  pFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
1997  pFS->startElementNS(mnXmlNamespace, XML_cNvPr,
1998  XML_id, OString::number(GetNewShapeID(xShape)),
1999  XML_name, GetShapeName(xShape));
2000  OUString sURL;
2001  if (GetProperty(xShapeProps, "URL"))
2002  mAny >>= sURL;
2003 
2004  if (!sURL.isEmpty())
2005  {
2006  OUString sRelId = mpFB->addRelation(mpFS->getOutputStream(),
2008  mpURLTransformer->getTransformedString(sURL),
2009  mpURLTransformer->isExternalURL(sURL));
2010 
2011  mpFS->singleElementNS(XML_a, XML_hlinkClick, FSNS(XML_r, XML_id), sRelId);
2012  }
2013  pFS->endElementNS(mnXmlNamespace, XML_cNvPr);
2014  }
2015  pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr, XML_txBox, "1");
2017  {
2018  WriteNonVisualProperties( xShape );
2019  pFS->endElementNS( mnXmlNamespace, XML_nvSpPr );
2020  }
2021 
2022  // visual shape properties
2023  pFS->startElementNS(mnXmlNamespace, XML_spPr);
2024  WriteShapeTransformation( xShape, XML_a );
2025  WritePresetShape( "rect" );
2026  uno::Reference<beans::XPropertySet> xPropertySet(xShape, UNO_QUERY);
2027  if (!IsFontworkShape(xShapeProps)) // Fontwork needs fill and outline in run properties instead.
2028  {
2029  WriteBlipOrNormalFill(xPropertySet, "Graphic");
2030  WriteOutline(xPropertySet);
2031  WriteShapeEffects(xPropertySet);
2032  }
2033  pFS->endElementNS( mnXmlNamespace, XML_spPr );
2034 
2035  WriteTextBox( xShape, mnXmlNamespace );
2036 
2037  pFS->endElementNS( mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX || mbUserShapes ? XML_sp : XML_wsp) );
2038 
2039  return *this;
2040 }
2041 
2043 {
2044  Reference<XPropertySet> const xPropSet(xShape, UNO_QUERY);
2045  assert(xPropSet.is());
2046  Reference<XModel> xMathModel;
2047  xPropSet->getPropertyValue("Model") >>= xMathModel;
2048  assert(xMathModel.is());
2049  assert(GetDocumentType() != DOCUMENT_DOCX); // should be written in DocxAttributeOutput
2050  SAL_WARN_IF(GetDocumentType() == DOCUMENT_XLSX, "oox.shape", "Math export to XLSX isn't tested, should it happen here?");
2051 
2052  // ECMA standard does not actually allow oMath outside of
2053  // WordProcessingML so write a MCE like PPT 2010 does
2054  mpFS->startElementNS(XML_mc, XML_AlternateContent);
2055  mpFS->startElementNS(XML_mc, XML_Choice,
2056  FSNS(XML_xmlns, XML_a14), mpFB->getNamespaceURL(OOX_NS(a14)),
2057  XML_Requires, "a14");
2058  mpFS->startElementNS(mnXmlNamespace, XML_sp);
2059  mpFS->startElementNS(mnXmlNamespace, XML_nvSpPr);
2060  mpFS->singleElementNS(mnXmlNamespace, XML_cNvPr,
2061  XML_id, OString::number(GetNewShapeID(xShape)),
2062  XML_name, GetShapeName(xShape));
2063  mpFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr, XML_txBox, "1");
2064  mpFS->singleElementNS(mnXmlNamespace, XML_nvPr);
2065  mpFS->endElementNS(mnXmlNamespace, XML_nvSpPr);
2066  mpFS->startElementNS(mnXmlNamespace, XML_spPr);
2067  WriteShapeTransformation(xShape, XML_a);
2068  WritePresetShape("rect");
2069  mpFS->endElementNS(mnXmlNamespace, XML_spPr);
2070  mpFS->startElementNS(mnXmlNamespace, XML_txBody);
2071  mpFS->startElementNS(XML_a, XML_bodyPr);
2072  mpFS->endElementNS(XML_a, XML_bodyPr);
2073  mpFS->startElementNS(XML_a, XML_p);
2074  mpFS->startElementNS(XML_a14, XML_m);
2075 
2076  oox::FormulaExportBase *const pMagic(dynamic_cast<oox::FormulaExportBase*>(xMathModel.get()));
2077  assert(pMagic);
2078  pMagic->writeFormulaOoxml(GetFS(), GetFB()->getVersion(), GetDocumentType(),
2079  FormulaExportBase::eFormulaAlign::INLINE);
2080 
2081  mpFS->endElementNS(XML_a14, XML_m);
2082  mpFS->endElementNS(XML_a, XML_p);
2083  mpFS->endElementNS(mnXmlNamespace, XML_txBody);
2084  mpFS->endElementNS(mnXmlNamespace, XML_sp);
2085  mpFS->endElementNS(XML_mc, XML_Choice);
2086  mpFS->startElementNS(XML_mc, XML_Fallback);
2087  // TODO: export bitmap shape as fallback
2088  mpFS->endElementNS(XML_mc, XML_Fallback);
2089  mpFS->endElementNS(XML_mc, XML_AlternateContent);
2090 }
2091 
2093 {
2094  Reference< XPropertySet > xPropSet( xShape, UNO_QUERY );
2095  if (!xPropSet.is())
2096  return *this;
2097 
2098  enum { CHART, MATH, OTHER } eType(OTHER);
2099  OUString clsid;
2100  xPropSet->getPropertyValue("CLSID") >>= clsid;
2101  if (!clsid.isEmpty())
2102  {
2104  bool const isValid = aClassID.MakeId(clsid);
2105  assert(isValid); (void)isValid;
2106  if (SotExchange::IsChart(aClassID))
2107  eType = CHART;
2108  else if (SotExchange::IsMath(aClassID))
2109  eType = MATH;
2110  }
2111 
2112  if (CHART == eType)
2113  {
2114  Reference< XChartDocument > xChartDoc;
2115  xPropSet->getPropertyValue("Model") >>= xChartDoc;
2116  assert(xChartDoc.is());
2117  //export the chart
2118  ChartExport aChartExport( mnXmlNamespace, GetFS(), xChartDoc, GetFB(), GetDocumentType() );
2119  static sal_Int32 nChartCount = 0;
2120  aChartExport.WriteChartObj( xShape, GetNewShapeID( xShape ), ++nChartCount );
2121  return *this;
2122  }
2123 
2124  if (MATH == eType)
2125  {
2126  WriteMathShape(xShape);
2127  return *this;
2128  }
2129 
2130  uno::Reference<embed::XEmbeddedObject> const xObj(
2131  xPropSet->getPropertyValue("EmbeddedObject"), uno::UNO_QUERY);
2132 
2133  if (!xObj.is())
2134  {
2135  SAL_WARN("oox.shape", "ShapeExport::WriteOLE2Shape: no object");
2136  return *this;
2137  }
2138 
2139  uno::Sequence<beans::PropertyValue> grabBag;
2140  OUString entryName;
2141  try
2142  {
2143  uno::Reference<beans::XPropertySet> const xParent(
2144  uno::Reference<container::XChild>(xObj, uno::UNO_QUERY_THROW)->getParent(),
2145  uno::UNO_QUERY_THROW);
2146 
2147  xParent->getPropertyValue("InteropGrabBag") >>= grabBag;
2148 
2149  entryName = uno::Reference<embed::XEmbedPersist>(xObj, uno::UNO_QUERY_THROW)->getEntryName();
2150  }
2151  catch (uno::Exception const&)
2152  {
2153  TOOLS_WARN_EXCEPTION("oox.shape", "ShapeExport::WriteOLE2Shape");
2154  return *this;
2155  }
2156 
2157  OUString progID;
2158 
2159  for (auto const& it : std::as_const(grabBag))
2160  {
2161  if (it.Name == "EmbeddedObjects")
2162  {
2163  uno::Sequence<beans::PropertyValue> objects;
2164  it.Value >>= objects;
2165  for (auto const& object : std::as_const(objects))
2166  {
2167  if (object.Name == entryName)
2168  {
2169  uno::Sequence<beans::PropertyValue> props;
2170  object.Value >>= props;
2171  for (auto const& prop : std::as_const(props))
2172  {
2173  if (prop.Name == "ProgID")
2174  {
2175  prop.Value >>= progID;
2176  break;
2177  }
2178  }
2179  break;
2180  }
2181  }
2182  break;
2183  }
2184  }
2185 
2186  OUString sMediaType;
2187  OUString sRelationType;
2188  OUString sSuffix;
2189  const char * pProgID(nullptr);
2190 
2191  uno::Reference<io::XInputStream> const xInStream =
2193  mpFB->getComponentContext(), xObj, progID,
2194  sMediaType, sRelationType, sSuffix, pProgID);
2195 
2196  if (!xInStream.is())
2197  {
2198  return *this;
2199  }
2200 
2201  OString anotherProgID;
2202  if (!pProgID && !progID.isEmpty())
2203  {
2204  anotherProgID = OUStringToOString(progID, RTL_TEXTENCODING_UTF8);
2205  pProgID = anotherProgID.getStr();
2206  }
2207 
2208  assert(!sMediaType.isEmpty());
2209  assert(!sRelationType.isEmpty());
2210  assert(!sSuffix.isEmpty());
2211 
2212  OUString sFileName = "embeddings/oleObject" + OUString::number(++m_nEmbeddedObjects) + "." + sSuffix;
2213  uno::Reference<io::XOutputStream> const xOutStream(
2215  OUString::createFromAscii(GetComponentDir()) + "/" + sFileName,
2216  sMediaType));
2217  assert(xOutStream.is()); // no reason why that could fail
2218 
2219  try {
2220  ::comphelper::OStorageHelper::CopyInputToOutput(xInStream, xOutStream);
2221  } catch (uno::Exception const&) {
2222  TOOLS_WARN_EXCEPTION("oox.shape", "ShapeExport::WriteOLEObject");
2223  }
2224 
2225  OUString const sRelId = mpFB->addRelation(
2226  mpFS->getOutputStream(), sRelationType,
2227  OUStringConcatenation(OUString::createFromAscii(GetRelationCompPrefix()) + sFileName));
2228 
2229  mpFS->startElementNS(mnXmlNamespace, XML_graphicFrame);
2230 
2231  mpFS->startElementNS(mnXmlNamespace, XML_nvGraphicFramePr);
2232 
2233  mpFS->singleElementNS( mnXmlNamespace, XML_cNvPr,
2234  XML_id, OString::number(GetNewShapeID(xShape)),
2235  XML_name, GetShapeName(xShape));
2236 
2237  mpFS->singleElementNS(mnXmlNamespace, XML_cNvGraphicFramePr);
2238 
2239  if (GetDocumentType() == DOCUMENT_PPTX)
2240  mpFS->singleElementNS(mnXmlNamespace, XML_nvPr);
2241  mpFS->endElementNS( mnXmlNamespace, XML_nvGraphicFramePr );
2242 
2244 
2245  mpFS->startElementNS(XML_a, XML_graphic);
2246  mpFS->startElementNS(XML_a, XML_graphicData,
2247  XML_uri, "http://schemas.openxmlformats.org/presentationml/2006/ole");
2248  if (pProgID)
2249  {
2250  mpFS->startElementNS( mnXmlNamespace, XML_oleObj,
2251  XML_progId, pProgID,
2252  FSNS(XML_r, XML_id), sRelId,
2253  XML_spid, "" );
2254  }
2255  else
2256  {
2257  mpFS->startElementNS( mnXmlNamespace, XML_oleObj,
2258 //? XML_name, "Document",
2259  FSNS(XML_r, XML_id), sRelId,
2260  // The spec says that this is a required attribute, but PowerPoint can only handle an empty value.
2261  XML_spid, "" );
2262  }
2263 
2264  mpFS->singleElementNS( mnXmlNamespace, XML_embed );
2265 
2266  // pic element
2267  SdrObject* pSdrOLE2(SdrObject::getSdrObjectFromXShape(xShape));
2268  // The spec doesn't allow <p:pic> here, but PowerPoint requires it.
2269  bool bEcma = mpFB->getVersion() == oox::core::ECMA_DIALECT;
2270  if (bEcma)
2271  if (auto pOle2Obj = dynamic_cast<SdrOle2Obj*>(pSdrOLE2))
2272  {
2273  const Graphic* pGraphic = pOle2Obj->GetGraphic();
2274  if (pGraphic)
2275  WriteGraphicObjectShapePart( xShape, pGraphic );
2276  }
2277 
2278  mpFS->endElementNS( mnXmlNamespace, XML_oleObj );
2279 
2280  mpFS->endElementNS( XML_a, XML_graphicData );
2281  mpFS->endElementNS( XML_a, XML_graphic );
2282 
2283  mpFS->endElementNS( mnXmlNamespace, XML_graphicFrame );
2284 
2285  return *this;
2286 }
2287 
2289 {
2290  // Override this method to do something useful.
2291  return *this;
2292 }
2293 
2294 sal_Int32 ShapeExport::GetNewShapeID( const Reference< XShape >& rXShape )
2295 {
2296  return GetNewShapeID( rXShape, GetFB() );
2297 }
2298 
2299 sal_Int32 ShapeExport::GetNewShapeID( const Reference< XShape >& rXShape, XmlFilterBase* pFB )
2300 {
2301  if( !rXShape.is() )
2302  return -1;
2303 
2304  sal_Int32 nID = pFB->GetUniqueId();
2305 
2306  (*mpShapeMap)[ rXShape ] = nID;
2307 
2308  return nID;
2309 }
2310 
2311 sal_Int32 ShapeExport::GetShapeID( const Reference< XShape >& rXShape )
2312 {
2313  return GetShapeID( rXShape, mpShapeMap );
2314 }
2315 
2316 sal_Int32 ShapeExport::GetShapeID( const Reference< XShape >& rXShape, ShapeHashMap* pShapeMap )
2317 {
2318  if( !rXShape.is() )
2319  return -1;
2320 
2321  ShapeHashMap::const_iterator aIter = pShapeMap->find( rXShape );
2322 
2323  if( aIter == pShapeMap->end() )
2324  return -1;
2325 
2326  return aIter->second;
2327 }
2328 
2330 {
2331  Reference<XPropertySet> rXPropSet(xShape, UNO_QUERY);
2332 
2333  // Empty name keeps the object unnamed.
2334  OUString sName;
2335 
2336  if (GetProperty(rXPropSet, "Name"))
2337  mAny >>= sName;
2338  return sName;
2339 }
2340 
2341 }
2342 
2343 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
sal_uInt16 Count() const
void WriteTableCellBorders(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
Definition: shapes.cxx:1939
#define SO3_SM_CLASSID_60
Interface to be implemented by the parent exporter that knows how to handle shape text...
Definition: drawingml.hxx:122
ShapeExport & WriteTableShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1960
const char *const aClassID
const char * sName
Definition: olehelper.cxx:92
void WriteConnectorConnections(EscherConnectorListEntry &rConnectorEntry, sal_Int32 nStartID, sal_Int32 nEndID)
Definition: drawingml.cxx:4055
ShapeExport & WriteNonVisualDrawingProperties(const css::uno::Reference< css::drawing::XShape > &xShape, const char *sName)
Definition: shapes.cxx:1539
mso_sptSun
static bool IsNonEmptySimpleText(const Reference< XInterface > &xIface)
Definition: shapes.cxx:358
TextVerticalAdjust GetTextVerticalAdjust(sal_Int32 nToken)
static void CopyInputToOutput(const css::uno::Reference< css::io::XInputStream > &xInput, const css::uno::Reference< css::io::XOutputStream > &xOutput)
SAL_WARN_UNUSED_RESULT Point LogicToLogic(const Point &rPtSource, const MapMode *pMapModeSource, const MapMode *pMapModeDest) const
tools::Long getWidth() const
int n1
Visible
tools::Long const nLeftMargin
mso_sptCube
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:1771
static const NameToConvertMapType & lcl_GetConverters()
Definition: shapes.cxx:1611
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:3066
static SdrObject * getSdrObjectFromXShape(const css::uno::Reference< css::uno::XInterface > &xInt)
OoxmlVersion getVersion() const
Definition: filterbase.cxx:207
#define SO3_SIMPRESS_CLASSID_60
void WriteTable(const css::uno::Reference< css::drawing::XShape > &rXShape)
Definition: shapes.cxx:1701
constexpr::Color COL_AUTO(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
ShapeExport & WriteOLE2Shape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:2092
static void lcl_ConvertProgID(std::u16string_view rProgID, OUString &o_rMediaType, OUString &o_rRelationType, OUString &o_rFileExtension)
Definition: shapes.cxx:103
void WriteMathShape(css::uno::Reference< css::drawing::XShape > const &xShape)
Definition: shapes.cxx:2042
virtual ShapeExport & WriteUnknownShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:2288
mso_sptCan
tuple args
void WriteGraphicObjectShapePart(const css::uno::Reference< css::drawing::XShape > &xShape, const Graphic *pGraphic=nullptr)
Definition: shapes.cxx:1180
OUString GetShapeName(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:2329
void WriteShape3DEffects(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
Definition: drawingml.cxx:4635
std::shared_ptr< URLTransformer > mpURLTransformer
Definition: shapes.hxx:100
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...
mso_sptBracketPair
OUString Name
::sax_fastparser::FSHelperPtr mpFS
Definition: drawingml.hxx:160
ShapeExport & WriteGroupShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:473
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:329
ShapeExport & WriteGraphicObjectShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1173
float x
constexpr double rad2deg(double v)
ShapeExport & WriteClosedPolyPolygonShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:463
css::awt::Size MapSize(const css::awt::Size &) const
Definition: shapes.cxx:347
bool GetProperty(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, const OUString &aName)
Definition: drawingml.cxx:261
static sal_uInt16 IsChart(const SvGlobalName &rName)
ShapeExport & WriteEllipseShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1078
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:198
static sal_Int32 lcl_NormalizeAngle(sal_Int32 nAngle)
Definition: shapes.cxx:682
const char * GetRelationCompPrefix() const
Definition: drawingml.cxx:1163
constexpr bool starts_with(std::basic_string_view< charT, traits > sv, std::basic_string_view< charT, traits > x) noexcept
void WriteBlipOrNormalFill(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, const OUString &rURLPropName)
Definition: drawingml.cxx:1511
tools::Long getHeight() const
Value
constexpr tools::Long Width() const
mso_sptNoSmoking
bool IsFontworkShape(const css::uno::Reference< css::beans::XPropertySet > &rXShapePropSet)
Definition: drawingml.cxx:3035
mso_sptWedgeEllipseCallout
int n2
void WriteSolidFill(::Color nColor, sal_Int32 nAlpha=MAX_PERCENT)
Definition: drawingml.cxx:401
OUString getNamespaceURL(sal_Int32 nNSID) const
virtual ShapeExport & WriteTextShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1986
MSO_SPT
void WriteShapeEffects(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
Definition: drawingml.cxx:4394
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:1732
OUString sSuffix
ShapeExport & WriteShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Write the DrawingML for a particular shape.
Definition: shapes.cxx:1648
mso_sptBlockArc
virtual bool isExternalURL(const OUString &rURL) const
Definition: drawingml.cxx:166
mso_sptVerticalScroll
constexpr tools::Long GetWidth() const
OString OUStringToOString(std::u16string_view str, ConnectionSettings const *settings)
void WriteShapeStyle(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
Definition: drawingml.cxx:4177
#define SO3_SC_CLASSID_60
void WritePolyPolygon(const css::uno::Reference< css::drawing::XShape > &rXShape, const tools::PolyPolygon &rPolyPolygon, const bool bClosed)
Definition: drawingml.cxx:3877
static sal_uInt16 IsMath(const SvGlobalName &rName)
void WriteFill(const css::uno::Reference< css::beans::XPropertySet > &xPropSet)
Definition: drawingml.cxx:4105
#define SO3_SCH_CLASSID_60
css::uno::Sequence< css::beans::PropertyValue > InitPropertySequence(::std::initializer_list< ::std::pair< OUString, css::uno::Any > > vInit)
void WriteTableCellProperties(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet)
Definition: shapes.cxx:1892
OUString getRelationship(Relationship eRelationship)
B2IRange fround(const B2DRange &rRange)
ShapeExport & WriteCustomShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:729
const ::sax_fastparser::FSHelperPtr & GetFS() const
Definition: drawingml.hxx:207
static OUString lcl_GetTarget(const css::uno::Reference< css::frame::XModel > &xModel, std::u16string_view rURL)
Definition: drawingml.cxx:1866
static bool IsDefaultObject(const SdrObjCustomShape &rSdrObjCustomShape, const MSO_SPT eShapeType)
static tools::PolyPolygon GetPolyPolygon(const css::uno::Reference< css::drawing::XShape > &rXShape)
constexpr void SetLeft(tools::Long v)
DocumentType eType
ShapeFlag
sal_uInt16 char * pName
std::unordered_map< const char *, ShapeConverter, rtl::CStringHash, rtl::CStringEqual > NameToConvertMapType
Definition: shapes.cxx:1609
mso_sptHorizontalScroll
DocumentType GetDocumentType() const
Definition: drawingml.hxx:209
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:1294
#define TOOLS_WARN_EXCEPTION(area, stream)
bool WriteCustomGeometry(const css::uno::Reference< css::drawing::XShape > &rXShape, const SdrObjCustomShape &rSdrObjCustomShape)
Definition: drawingml.cxx:3603
Interface class, StarMath will implement writeFormula*() to write out markup representing the formula...
Definition: export.hxx:26
mso_sptWedgeRectCallout
mso_sptDonut
ShapeExport & WriteLineShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1482
mso_sptBorderCallout1
sal_Int32 GetShapeID(const css::uno::Reference< css::drawing::XShape > &rShape)
static bool lcl_GetHandlePosition(sal_Int32 &nValue, const EnhancedCustomShapeParameter &rParam, Sequence< EnhancedCustomShapeAdjustmentValue > &rSeq)
Definition: shapes.cxx:614
MATH
const char * GetOOXMLPresetGeometry(const char *sShapeType)
ShapeExport & WritePolyPolygonShape(const css::uno::Reference< css::drawing::XShape > &xShape, bool bClosed)
Definition: shapes.cxx:402
sal_Int64 convertHmmToEmu(sal_Int32 nValue)
Converts the passed 32-bit integer value from 1/100 mm to EMUs.
#define SO3_SW_CLASSID_60
float u
ShapeExport & WriteOpenPolyPolygonShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:468
const css::uno::Reference< css::uno::XComponentContext > & getComponentContext() const
Returns the component context passed in the filter constructor (always existing). ...
Definition: filterbase.cxx:212
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:277
dictionary props
Definition: properties.py:26
size
virtual void writeFormulaOoxml(::sax_fastparser::FSHelperPtr pSerializer, oox::core::OoxmlVersion version, oox::drawingml::DocumentType documentType, sal_Int8 nAlign)=0
constexpr double deg2rad(double v)
static sal_Int32 lcl_CircleAngle2CustomShapeEllipseAngleOOX(const sal_Int32 nInternAngle, const sal_Int32 nWidth, const sal_Int32 nHeight)
Definition: shapes.cxx:688
ColorTransparency
void WriteBorderLine(const sal_Int32 XML_line, const css::table::BorderLine2 &rBorderLine)
Definition: shapes.cxx:1920
mso_sptFoldedCorner
mso_sptBorderCallout2
#define GETAD(propName)
Definition: shapes.cxx:322
static bool lcl_IsOnDenylist(OUString const &rShapeType)
Definition: shapes.cxx:537
std::shared_ptr< FastSerializerHelper > FSHelperPtr
constexpr void SetTop(tools::Long v)
#define GETA(propName)
Definition: shapes.cxx:319
void WriteOutline(const css::uno::Reference< css::beans::XPropertySet > &rXPropSet, css::uno::Reference< css::frame::XModel > const &xModel=nullptr)
Definition: drawingml.cxx:816
ShapeExport &(ShapeExport::* ShapeConverter)(const Reference< XShape > &)
Definition: shapes.cxx:1608
ShapeExport & WriteConnectorShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1374
ShapeExport & WriteRectangleShape(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1554
basegfx::B2DPolyPolygon GetLineGeometry(const bool bBezierAllowed) const
#define GET(variable, propName)
Definition: shapes.cxx:325
mso_sptWedgeRRectCallout
static bool lcl_IsOnAllowlist(OUString const &rShapeType)
Definition: shapes.cxx:604
mutable::std::map< Reference< XShape >, Reference< XShape > > maShapeMap
static void lcl_AppendAdjustmentValue(std::vector< std::pair< sal_Int32, sal_Int32 > > &rAvList, sal_Int32 nAdjIdx, sal_Int32 nValue)
Definition: shapes.cxx:677
css::uno::Reference< css::drawing::XShape > m_xParent
If set, this is the parent of the currently handled shape.
Definition: drawingml.hxx:163
constexpr OUStringLiteral sMediaType
sal_Int32 GetNewShapeID(const css::uno::Reference< css::drawing::XShape > &rShape)
#define SAL_WARN_IF(condition, area, stream)
constexpr tools::Long Height() const
unsigned char sal_uInt8
void WriteSrcRectXGraphic(css::uno::Reference< css::beans::XPropertySet > const &rxPropertySet, css::uno::Reference< css::graphic::XGraphic > const &rxGraphic)
Definition: drawingml.cxx:1666
void setWidth(tools::Long n)
eFillStyle
static void lcl_AnalyzeHandles(const uno::Sequence< beans::PropertyValues > &rHandles, std::vector< std::pair< sal_Int32, sal_Int32 > > &rHandlePositionList, Sequence< EnhancedCustomShapeAdjustmentValue > &rSeq)
Definition: shapes.cxx:648
#define SAL_INFO(area, stream)
::oox::core::XmlFilterBase * GetFB()
Definition: drawingml.hxx:208
tools::Long AdjustWidth(tools::Long n)
void SetURLTranslator(const std::shared_ptr< URLTransformer > &pTransformer)
Definition: shapes.cxx:342
tools::Long const nRightMargin
DMLTextExport * GetTextExport()
The application-specific text exporter callback, if there is one.
Definition: drawingml.hxx:211
ShapeHashMap * mpShapeMap
Definition: shapes.hxx:105
tools::Long AdjustHeight(tools::Long n)
constexpr sal_Int32 FSNS(sal_Int32 namespc, sal_Int32 element)
const char * GetComponentDir() const
Definition: drawingml.cxx:1151
virtual ShapeExport & WriteNonVisualProperties(const css::uno::Reference< css::drawing::XShape > &xShape)
Definition: shapes.cxx:1548
css::uno::Reference< css::graphic::XGraphic > GetXGraphic() const
std::unordered_map< css::uno::Reference< css::drawing::XShape >, sal_Int32 > ShapeHashMap
Definition: shapes.hxx:87
::oox::core::XmlFilterBase * mpFB
Definition: drawingml.hxx:161
ShapeExport & WriteTextBox(const css::uno::Reference< css::uno::XInterface > &xIface, sal_Int32 nXmlNamespace, bool bWritePropertiesAsLstStyles=false)
Definition: shapes.cxx:1664
MapUnit
#define SAL_WARN(area, stream)
Class for exporting the custom shapes to OOXML preset ones, if possible.
static bool NonEmptyText(const css::uno::Reference< css::uno::XInterface > &xIface)
Definition: shapes.cxx:366
mso_sptMoon
mso_sptCloudCallout
mso_sptBracePair
const char * UseIf(const char *s, bool bUse)
virtual void WriteTextBox(css::uno::Reference< css::drawing::XShape > xShape)=0
Write the contents of the textbox that is associated to this shape.
OUString addRelation(const OUString &rType, std::u16string_view rTarget)
Adds new relation.
static MSO_SPT GetCustomShapeType(const css::uno::Reference< css::drawing::XShape > &rXShape, ShapeFlag &nMirrorFlags, OUString &rShapeType, bool bOOXML=false)
bool MakeId(const OUString &rId)
void setHeight(tools::Long n)
OUString WriteXGraphicBlip(css::uno::Reference< css::beans::XPropertySet > const &rXPropSet, css::uno::Reference< css::graphic::XGraphic > const &rxGraphic, bool bRelPathToMedia)
Definition: drawingml.cxx:1443
mso_sptBevel
mso_sptSmileyFace
constexpr tools::Long GetHeight() const
void WritePresetShape(const char *pShape, std::vector< std::pair< sal_Int32, sal_Int32 >> &rAvList)
Definition: drawingml.cxx:3502
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo