summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/oox/export/DMLPresetShapeExport.hxx138
-rw-r--r--oox/Library_oox.mk1
-rw-r--r--oox/source/export/DMLPresetShapeExport.cxx1287
-rw-r--r--oox/source/export/shapes.cxx15
-rw-r--r--sw/qa/extras/ooxmlexport/data/testCustomShapePresetExport.odtbin0 -> 86157 bytes
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport16.cxx31
6 files changed, 1471 insertions, 1 deletions
diff --git a/include/oox/export/DMLPresetShapeExport.hxx b/include/oox/export/DMLPresetShapeExport.hxx
new file mode 100644
index 000000000000..1ab460d26845
--- /dev/null
+++ b/include/oox/export/DMLPresetShapeExport.hxx
@@ -0,0 +1,138 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+* This file is part of the LibreOffice project.
+*
+* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/.
+*/
+
+#ifndef INCLUDED_OOX_EXPORT_DMLPRESETSHAPEXPORT_HXX
+#define INCLUDED_OOX_EXPORT_DMLPRESETSHAPEXPORT_HXX
+
+#include <com/sun/star/awt/Rectangle.hpp>
+#include <com/sun/star/uno/Any.hxx>
+#include <com/sun/star/uno/Reference.hxx>
+#include <com/sun/star/uno/Sequence.hxx>
+
+#include <rtl/ustring.hxx>
+#include <sal/types.h>
+
+#include <string_view>
+
+#include <oox/export/drawingml.hxx>
+
+namespace com::sun::star::beans
+{
+struct PropertyValue;
+}
+
+namespace com::sun::star::drawing
+{
+class XShape;
+struct EnhancedCustomShapeAdjustmentValue;
+}
+
+namespace oox::core
+{
+class XmlFilterBase;
+}
+
+namespace oox::drawingml
+{
+/// Class for exporting the custom shapes to OOXML preset ones, if possible.
+/// This functionality needed for keeping the information for the office programs
+/// about the shape type, and geometry data. Before these shapes were exported
+/// with custom geometry, and they kept their geometry but has no information
+/// about the shape itself. This lead to lost textbox size/position/padding for
+/// example.
+class DMLPresetShapeExporter
+{
+private:
+ // the shape to export
+ css::uno::Reference<css::drawing::XShape> m_xShape;
+ // the DMLwriter
+ DrawingML* m_pDMLexporter;
+ // the type of the custom shape (diamond/rectangle/circle/triangle...)
+ OUString m_sPresetShapeType;
+ // True if the shape has points where its geometry can be modified
+ bool m_bHasHandleValues;
+ // The first the x the second the y coordinate, of flipping
+ std::pair<bool, bool> m_bIsFlipped;
+
+ // Custom Shape Geometry information for export:
+
+ // The adjusting values stored in this sequence:
+ css::uno::Sequence<css::drawing::EnhancedCustomShapeAdjustmentValue> m_AdjustmentValues;
+ // Shapes what have adjusting points, the range of these points
+ // and the index of the value stored in this sequence:
+ css::uno::Sequence<css::uno::Sequence<css::beans::PropertyValue>> m_HandleValues;
+
+ //TODO:
+ //css::awt::Rectangle m_ViewBox;
+ //css::uno::Sequence<css::beans::PropertyValue> m_Path;
+ //css::uno::Sequence<OUString> m_Equations;
+
+public:
+ DMLPresetShapeExporter() = delete;
+ ~DMLPresetShapeExporter();
+
+ DMLPresetShapeExporter(DrawingML* pDMLExporter,
+ css::uno::Reference<css::drawing::XShape> xShape);
+
+ // Writes the preset shape to the xml
+ bool WriteShape();
+
+private:
+ struct AdjustmentPointValueBase
+ {
+ double nMaxVal;
+ double nMinVal;
+ double nCurrVal;
+ };
+
+ typedef AdjustmentPointValueBase RadiusAdjustmentValue;
+ typedef AdjustmentPointValueBase AngleAdjustmentValue;
+ typedef AdjustmentPointValueBase XAdjustmentValue;
+ typedef AdjustmentPointValueBase YAdjustmentValue;
+
+ // Returns true, if the shape has adjusting points
+ bool HasHandleValue();
+
+ // Returns true if the shape flipped.
+ bool IsXFlipped() { return m_bIsFlipped.first; };
+ bool IsYFlipped() { return m_bIsFlipped.second; };
+
+ // Returns with the shape type, like triangle for example
+ OUString GetShapeType();
+ // Returns with the handle points
+ css::uno::Sequence<css::uno::Sequence<css::beans::PropertyValue>> GetHandleValues();
+ // Returns with the adjustment values
+ css::uno::Sequence<css::drawing::EnhancedCustomShapeAdjustmentValue> GetAdjustmentValues();
+ // Returns with the raw value of the given property of the shape geometry.
+ css::uno::Any GetHandleValueOfModificationPoint(sal_Int32 nPoint, std::u16string_view sType);
+ // Returns with the appropriate value of the handle point.
+ RadiusAdjustmentValue GetAdjustmentPointRadiusValue(sal_Int32 nPoint);
+ AngleAdjustmentValue GetAdjustmentPointAngleValue(sal_Int32 nPoint);
+ XAdjustmentValue GetAdjustmentPointXValue(sal_Int32 nPoint);
+ YAdjustmentValue GetAdjustmentPointYValue(sal_Int32 nPoint);
+
+ // Writes one adjustment point.
+ bool WriteAV(const OUString& sValName, const OUString& sVal);
+ // Opens/Closes the AVlist tag.
+ bool StartAVListWriting();
+ bool EndAVListWriting();
+
+ // Finds the given value in the sequence
+ static css::uno::Any FindHandleValue(css::uno::Sequence<css::beans::PropertyValue> aValues,
+ std::u16string_view sKey);
+ // Writes and converts the adjustment points from sdr to ooxml ones per shape type.
+ bool WriteShapeWithAVlist();
+
+}; // end of DMLPresetShapeExporter class
+
+} // end of namespace oox::drawingml
+
+#endif
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/oox/Library_oox.mk b/oox/Library_oox.mk
index 287a4bb70003..6550a3942c88 100644
--- a/oox/Library_oox.mk
+++ b/oox/Library_oox.mk
@@ -217,6 +217,7 @@ $(eval $(call gb_Library_add_exception_objects,oox,\
oox/source/export/chartexport \
oox/source/export/ColorPropertySet \
oox/source/export/drawingml \
+ oox/source/export/DMLPresetShapeExport \
oox/source/export/shapes \
oox/source/export/vmlexport \
oox/source/helper/attributelist \
diff --git a/oox/source/export/DMLPresetShapeExport.cxx b/oox/source/export/DMLPresetShapeExport.cxx
new file mode 100644
index 000000000000..8e4ebafcce98
--- /dev/null
+++ b/oox/source/export/DMLPresetShapeExport.cxx
@@ -0,0 +1,1287 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+* This file is part of the LibreOffice project.
+*
+* This Source Code Form is subject to the terms of the Mozilla Public
+* License, v. 2.0. If a copy of the MPL was not distributed with this
+* file, You can obtain one at http://mozilla.org/MPL/2.0/.
+*/
+
+#include <oox/export/DMLPresetShapeExport.hxx>
+#include <oox/token/tokens.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeAdjustmentValue.hpp>
+#include <com/sun/star/drawing/EnhancedCustomShapeParameterPair.hpp>
+#include <com/sun/star/drawing/XShape.hpp>
+
+#include <osl/diagnose.h>
+#include <filter/msfilter/util.hxx>
+
+#include <string_view>
+
+using namespace ::css;
+using namespace ::css::drawing;
+
+namespace oox::drawingml
+{
+// DMLPresetShapeExporter class
+
+// ctor
+DMLPresetShapeExporter::DMLPresetShapeExporter(DrawingML* pDMLExporter,
+ css::uno::Reference<css::drawing::XShape> xShape)
+ : m_pDMLexporter(pDMLExporter)
+{
+ // This class only work with custom shapes!
+ OSL_ASSERT(xShape->getShapeType() == "com.sun.star.drawing.CustomShape");
+
+ m_xShape = xShape;
+ m_bHasHandleValues = false;
+ uno::Reference<beans::XPropertySet> xShapeProps(m_xShape, uno::UNO_QUERY);
+ css::uno::Sequence<css::beans::PropertyValue> aCustomShapeGeometry
+ = xShapeProps->getPropertyValue("CustomShapeGeometry")
+ .get<uno::Sequence<beans::PropertyValue>>();
+
+ for (sal_uInt32 i = 0; i < aCustomShapeGeometry.size(); i++)
+ {
+ if (aCustomShapeGeometry[i].Name == "Type")
+ {
+ m_sPresetShapeType = aCustomShapeGeometry[i].Value.get<OUString>();
+ }
+ if (aCustomShapeGeometry[i].Name == "Handles")
+ {
+ m_bHasHandleValues = true;
+ m_HandleValues
+ = aCustomShapeGeometry[i]
+ .Value
+ .get<css::uno::Sequence<css::uno::Sequence<css::beans::PropertyValue>>>();
+ }
+ if (aCustomShapeGeometry[i].Name == "AdjustmentValues")
+ {
+ m_AdjustmentValues
+ = aCustomShapeGeometry[i]
+ .Value
+ .get<css::uno::Sequence<css::drawing::EnhancedCustomShapeAdjustmentValue>>();
+ }
+ if (aCustomShapeGeometry[i].Name == "MirroredX")
+ {
+ m_bIsFlipped.first = aCustomShapeGeometry[i].Value.get<bool>();
+ }
+ if (aCustomShapeGeometry[i].Name == "MirroredY")
+ {
+ m_bIsFlipped.second = aCustomShapeGeometry[i].Value.get<bool>();
+ }
+ //if (aCustomShapeGeometry[i].Name == "Equations")
+ //{
+ // m_Equations = aCustomShapeGeometry[i].Value.get<css::uno::Sequence<OUString>>();
+ //}
+ //if (aCustomShapeGeometry[i].Name == "Path")
+ //{
+ // m_Path = aCustomShapeGeometry[i]
+ // .Value.get<css::uno::Sequence<css::beans::PropertyValue>>();
+ //}
+ //if (aCustomShapeGeometry[i].Name == "ViewBox")
+ //{
+ // m_ViewBox = aCustomShapeGeometry[i].Value.get<css::awt::Rectangle>();
+ //}
+ }
+};
+
+// dtor
+DMLPresetShapeExporter::~DMLPresetShapeExporter(){
+ // Do nothing
+};
+
+bool DMLPresetShapeExporter::HasHandleValue() { return m_bHasHandleValues; }
+
+OUString DMLPresetShapeExporter::GetShapeType() { return m_sPresetShapeType; }
+
+css::uno::Sequence<css::uno::Sequence<css::beans::PropertyValue>>
+DMLPresetShapeExporter::GetHandleValues()
+{
+ return m_HandleValues;
+};
+
+css::uno::Sequence<css::drawing::EnhancedCustomShapeAdjustmentValue>
+DMLPresetShapeExporter::GetAdjustmentValues()
+{
+ return m_AdjustmentValues;
+};
+
+css::uno::Any DMLPresetShapeExporter::GetHandleValueOfModificationPoint(sal_Int32 nPoint,
+ std::u16string_view sType)
+{
+ uno::Any aRet;
+ if (GetHandleValues().getLength() > nPoint)
+ {
+ for (sal_Int32 i = 0; i < GetHandleValues()[nPoint].getLength(); i++)
+ {
+ if (GetHandleValues()[nPoint][i].Name == sType)
+ {
+ aRet = GetHandleValues()[nPoint][i].Value;
+ break;
+ }
+ }
+ }
+ return aRet;
+};
+
+DMLPresetShapeExporter::RadiusAdjustmentValue
+DMLPresetShapeExporter::GetAdjustmentPointRadiusValue(sal_Int32 nPoint)
+{
+ RadiusAdjustmentValue aRet;
+ auto aValPos = GetHandleValueOfModificationPoint(nPoint, u"Position")
+ .get<EnhancedCustomShapeParameterPair>();
+ aRet.nMinVal = GetHandleValueOfModificationPoint(nPoint, u"RadiusRangeMinimum")
+ .get<EnhancedCustomShapeParameter>()
+ .Value.get<double>();
+ aRet.nMaxVal = GetHandleValueOfModificationPoint(nPoint, u"RadiusRangeMaximum")
+ .get<EnhancedCustomShapeParameter>()
+ .Value.get<double>();
+ aRet.nCurrVal = GetAdjustmentValues()[aValPos.First.Value.get<long>()].Value.get<double>();
+ return aRet;
+};
+
+DMLPresetShapeExporter::AngleAdjustmentValue
+DMLPresetShapeExporter::GetAdjustmentPointAngleValue(sal_Int32 nPoint)
+{
+ AngleAdjustmentValue aRet;
+ auto aValPos = GetHandleValueOfModificationPoint(nPoint, u"Position")
+ .get<EnhancedCustomShapeParameterPair>();
+ aRet.nMinVal = 0;
+ aRet.nMaxVal = 360;
+ aRet.nCurrVal = GetAdjustmentValues()[aValPos.Second.Value.get<long>()].Value.get<double>();
+ return aRet;
+};
+
+DMLPresetShapeExporter::XAdjustmentValue
+DMLPresetShapeExporter::GetAdjustmentPointXValue(sal_Int32 nPoint)
+{
+ XAdjustmentValue aRet;
+ auto aValPos = GetHandleValueOfModificationPoint(nPoint, u"Position")
+ .get<EnhancedCustomShapeParameterPair>();
+ aRet.nMinVal = GetHandleValueOfModificationPoint(nPoint, u"RangeXMinimum")
+ .get<EnhancedCustomShapeParameter>()
+ .Value.get<double>();
+ aRet.nMaxVal = GetHandleValueOfModificationPoint(nPoint, u"RangeXMaximum")
+ .get<EnhancedCustomShapeParameter>()
+ .Value.get<double>();
+ aRet.nCurrVal = GetAdjustmentValues()[aValPos.First.Value.get<long>()].Value.get<double>();
+ return aRet;
+};
+
+DMLPresetShapeExporter::YAdjustmentValue
+DMLPresetShapeExporter::GetAdjustmentPointYValue(sal_Int32 nPoint)
+{
+ YAdjustmentValue aRet;
+ auto aValPos = GetHandleValueOfModificationPoint(nPoint, u"Position")
+ .get<EnhancedCustomShapeParameterPair>();
+ aRet.nMinVal = GetHandleValueOfModificationPoint(nPoint, u"RangeYMinimum")
+ .get<EnhancedCustomShapeParameter>()
+ .Value.get<double>();
+ aRet.nMaxVal = GetHandleValueOfModificationPoint(nPoint, u"RangeYMinimum")
+ .get<EnhancedCustomShapeParameter>()
+ .Value.get<double>();
+ aRet.nCurrVal = GetAdjustmentValues()[aValPos.Second.Value.get<long>()].Value.get<double>();
+ return aRet;
+};
+
+bool DMLPresetShapeExporter::WriteShape()
+{
+ if (m_pDMLexporter && m_xShape)
+ {
+ // Case 1: We do not have adjustment points of the shape: just export it as preset
+ if (!m_bHasHandleValues)
+ {
+ OUString sShapeType = GetShapeType();
+ const char* sPresetShape
+ = msfilter::util::GetOOXMLPresetGeometry(sShapeType.toUtf8().getStr());
+ m_pDMLexporter->WriteShapeTransformation(m_xShape, XML_a, IsXFlipped(), IsYFlipped(),
+ false, false);
+ m_pDMLexporter->WritePresetShape(sPresetShape);
+ return true;
+ }
+ else // Case2: There are adjustment points what have to be converted and exported.
+ {
+ return WriteShapeWithAVlist();
+ }
+ }
+ return false;
+};
+
+bool DMLPresetShapeExporter::WriteAV(const OUString& sValName, const OUString& sVal)
+{
+ try
+ {
+ m_pDMLexporter->GetFS()->singleElementNS(XML_a, XML_gd, XML_name, sValName, XML_fmla, sVal);
+ return true;
+ }
+ catch (...)
+ {
+ return false;
+ }
+};
+
+bool DMLPresetShapeExporter::StartAVListWriting()
+{
+ try
+ {
+ const char* pShape
+ = msfilter::util::GetOOXMLPresetGeometry(GetShapeType().toUtf8().getStr());
+ m_pDMLexporter->GetFS()->startElementNS(XML_a, XML_prstGeom, XML_prst, pShape);
+ m_pDMLexporter->GetFS()->startElementNS(XML_a, XML_avLst);
+ return true;
+ }
+ catch (...)
+ {
+ return false;
+ }
+};
+bool DMLPresetShapeExporter::EndAVListWriting()
+{
+ try
+ {
+ m_pDMLexporter->GetFS()->endElementNS(XML_a, XML_avLst);
+ m_pDMLexporter->GetFS()->endElementNS(XML_a, XML_prstGeom);
+ return true;
+ }
+ catch (...)
+ {
+ return false;
+ }
+};
+
+bool DMLPresetShapeExporter::WriteShapeWithAVlist()
+{
+ // Remark: This method is under development. If a shape type is implemented, the corresponding,
+ // return must be set to true. False means nothing done true, export done. There are many
+ // types which do not have pairs in LO, they are do not have to be mapped, because import
+ // filter it does with GrabBag, this method only maps the SDR ones to OOXML shapes.
+
+ OString sShapeType(msfilter::util::GetOOXMLPresetGeometry(GetShapeType().toUtf8().getStr()));
+
+ // OOXML uses 60th of degree, so 360 degree is 21 600 000 60thdeg
+ const tools::Long nConstOfMaxDegreeOf60th = 21600000;
+ try
+ {
+ if (sShapeType == "accentBorderCallout1")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "accentBorderCallout2")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "accentBorderCallout3")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "accentCallout1")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "accentCallout2")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "accentCallout3")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "actionButtonBackPrevious")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "actionButtonBeginning")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "actionButtonBlank")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "actionButtonDocument")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "actionButtonEnd")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "actionButtonForwardNext")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "actionButtonHelp")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "actionButtonHome")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "actionButtonInformation")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "actionButtonMovie")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "actionButtonReturn")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "actionButtonSound")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "arc")
+ {
+ // LO does not have handle points for this, so CustGeom is enough.
+ return false;
+ }
+ if (sShapeType == "bentArrow")
+ {
+ // LO has only one type, which have to be rotated, without handling points
+ // So CustGeom enough.
+ return false;
+ }
+ if (sShapeType == "bentConnector2")
+ {
+ // CustGeom Enough
+ return false;
+ }
+ if (sShapeType == "bentConnector3")
+ {
+ // CustGeom Enough
+ return false;
+ }
+ if (sShapeType == "bentConnector4")
+ {
+ // CustGeom Enough
+ return false;
+ }
+ if (sShapeType == "bentConnector5")
+ {
+ // CustGeom Enough
+ return false;
+ }
+ if (sShapeType == "bentUpArrow")
+ {
+ // CustGeom Enough, no handle points
+ return false;
+ }
+ if (sShapeType == "bevel")
+ {
+ m_pDMLexporter->WriteShapeTransformation(m_xShape, XML_a, IsXFlipped(), IsYFlipped(),
+ false, false);
+ auto aPoint1 = GetAdjustmentPointXValue(0);
+ tools::Long nVal1
+ = std::lround(aPoint1.nCurrVal / (aPoint1.nMaxVal - aPoint1.nMinVal) * 50000);
+ return StartAVListWriting()
+ && WriteAV(u"adj", OUString(u"val " + OUString::number(nVal1)))
+ && EndAVListWriting();
+ }
+ if (sShapeType == "blockArc")
+ {
+ m_pDMLexporter->WriteShapeTransformation(m_xShape, XML_a, IsXFlipped(), IsYFlipped(),
+ false, false);
+ auto aPointR = GetAdjustmentPointRadiusValue(0);
+ auto aPointA = GetAdjustmentPointAngleValue(0);
+ tools::Long nVal1
+ = std::lround((aPointA.nCurrVal < 0 ? 360 + aPointA.nCurrVal : aPointA.nCurrVal)
+ / (aPointA.nMaxVal - aPointA.nMinVal) * nConstOfMaxDegreeOf60th);
+ tools::Long nVal2 = std::lround(
+ (aPointA.nCurrVal > 180 ? 360 - aPointA.nCurrVal : 180 - aPointA.nCurrVal)
+ / (aPointA.nMaxVal - aPointA.nMinVal) * nConstOfMaxDegreeOf60th);
+ tools::Long nVal3 = std::lround(
+ 50000 - (aPointR.nCurrVal / (aPointR.nMaxVal - aPointR.nMinVal) * 50000));
+ return StartAVListWriting()
+ && WriteAV(u"adj1", OUString(u"val " + OUString::number(nVal1)))
+ && WriteAV(u"adj2", OUString(u"val " + OUString::number(nVal2)))
+ && WriteAV(u"adj3", OUString(u"val " + OUString::number(nVal3)))
+ && EndAVListWriting();
+ }
+ if (sShapeType == "borderCallout1")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "borderCallout2")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "borderCallout3")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "bracePair")
+ {
+ m_pDMLexporter->WriteShapeTransformation(m_xShape, XML_a, IsXFlipped(), IsYFlipped(),
+ false, false);
+ auto aPoint1 = GetAdjustmentPointXValue(0);
+ tools::Long nVal1
+ = std::lround(aPoint1.nCurrVal / (aPoint1.nMaxVal - aPoint1.nMinVal) * 25000);
+ return StartAVListWriting()
+ && WriteAV(u"adj", OUString(u"val " + OUString::number(nVal1)))
+ && EndAVListWriting();
+ }
+ if (sShapeType == "bracketPair")
+ {
+ m_pDMLexporter->WriteShapeTransformation(m_xShape, XML_a, IsXFlipped(), IsYFlipped(),
+ false, false);
+ auto aPoint1 = GetAdjustmentPointYValue(0);
+ tools::Long nVal1
+ = std::lround(aPoint1.nCurrVal / (aPoint1.nMaxVal - aPoint1.nMinVal) * 50000);
+ return StartAVListWriting()
+ && WriteAV(u"adj", OUString(u"val " + OUString::number(nVal1)))
+ && EndAVListWriting();
+ }
+ if (sShapeType == "callout1")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "callout2")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "callout3")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "can")
+ {
+ return false;
+ // Do the export as before.
+ }
+ if (sShapeType == "chartPlus")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "chartStar")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "chartX")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "chord")
+ {
+ // CustGeom, because LO does not have handle points
+ return false;
+ }
+ if (sShapeType == "circularArrow")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "cloud")
+ {
+ // CustGeom enough
+ return false;
+ }
+ if (sShapeType == "cloudCallout")
+ {
+ return false;
+ // Works fine without this, so export it like before.
+ }
+ if (sShapeType == "cornerTabs")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "cube")
+ {
+ // Works fine without this, so export it like before.
+ return false;
+ }
+ if (sShapeType == "curvedConnector2")
+ {
+ // Not necessary to be mapped
+ return false;
+ }
+ if (sShapeType == "curvedConnector3")
+ {
+ // Not necessary to be mapped
+ return false;
+ }
+ if (sShapeType == "curvedConnector4")
+ {
+ // Not necessary to be mapped
+ return false;
+ }
+ if (sShapeType == "curvedConnector5")
+ {
+ // Not necessary to be mapped
+ return false;
+ }
+ if (sShapeType == "curvedDownArrow")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "curvedLeftArrow")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "curvedRightArrow")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "curvedUpArrow")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "decagon")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "diagStripe")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "diamond")
+ {
+ // It does not have handle points so it do not have to be mapped.
+ return false;
+ }
+ if (sShapeType == "dodecagon")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "donut")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "doubleWave")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "downArrow")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "downArrowCallout")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "ellipse")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "ellipseRibbon")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "ellipseRibbon2")
+ {
+ // LO does not have this type, so it does not necessary to be mapped.
+ return false;
+ }
+ if (sShapeType == "flowChartAlternateProcess")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartCollate")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartConnector")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartDecision")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartDecision")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartDelay")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartDisplay")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartDocument")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartExtract")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartInputOutput")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartInternalStorage")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartMagneticDisk")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartMagneticDrum")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartMagneticTape")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartManualInput")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartManualOperation")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartMerge")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartMultidocument")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartOfflineStorage")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartOffpageConnector")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartOnlineStorage")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartOr")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartDecision")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartPredefinedProcess")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartPreparation")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartPunchedCard")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartPunchedTape")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartSort")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartSummingJunction")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "flowChartTerminator")
+ {
+ // Does not have handle points, so preset enough.
+ return false;
+ }
+ if (sShapeType == "foldedCorner")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "frame")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "funnel")
+ {
+ // Not found in word
+ return false;
+ }
+ if (sShapeType == "gear6")
+ {
+ // Not found in word
+ return false;
+ }
+ if (sShapeType == "gear9")
+ {
+ // Not found in word
+ return false;
+ }
+ if (sShapeType == "halfFrame")
+ {
+ // LO does not have this type, not necessary to map
+ return false;
+ }
+ if (sShapeType == "heart")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "heptagon")
+ {
+ // LO does not have this type, not necessary to map
+ return false;
+ }
+ if (sShapeType == "hexagon")
+ {
+ m_pDMLexporter->WriteShapeTransformation(m_xShape, XML_a, IsXFlipped(), IsYFlipped(),
+ false, false);
+ auto aPoint1 = GetAdjustmentPointXValue(0);
+ tools::Long nMaxVal = 50000 * m_xShape->getSize().Width
+ / std::min(m_xShape->getSize().Width, m_xShape->getSize().Height);
+ tools::Long nVal1
+ = std::lround(aPoint1.nCurrVal / (aPoint1.nMaxVal - aPoint1.nMinVal) * nMaxVal);
+ return StartAVListWriting()
+ && WriteAV(u"adj", OUString(u"val " + OUString::number(nVal1)))
+ && WriteAV(u"vf", OUString(u"val " + OUString::number(115470)))
+ && EndAVListWriting();
+ }
+ if (sShapeType == "homePlate")
+ {
+ // Not found in word
+ return false;
+ }
+ if (sShapeType == "horizontalScroll")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "irregularSeal1")
+ {
+ // Not found in word
+ return false;
+ }
+ if (sShapeType == "irregularSeal2")
+ {
+ // Not found in word
+ return false;
+ }
+ if (sShapeType == "leftArrow")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "leftArrowCallout")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "leftBrace")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "leftBracket")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "leftCircularArrow")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "leftRightArrow")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "leftRightArrowCallout")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "leftRightCircularArrow")
+ {
+ // Not found in word
+ return false;
+ }
+ if (sShapeType == "leftRightRibbon")
+ {
+ // LO does not have this type so mapping not necessary
+ return false;
+ }
+ if (sShapeType == "leftRightUpArrow")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "leftUpArrow")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "lightningBolt")
+ {
+ // Difference between the SDR and OOXML variants, custgeom?
+ return false;
+ }
+ if (sShapeType == "line")
+ {
+ // Not necessary
+ return false;
+ }
+ if (sShapeType == "lineInv")
+ {
+ // Not necessary
+ return false;
+ }
+ if (sShapeType == "mathDivide")
+ {
+ // LO does not have this type so mapping not necessary
+ return false;
+ }
+ if (sShapeType == "mathEqual")
+ {
+ // LO does not have this type so mapping not necessary
+ return false;
+ }
+ if (sShapeType == "mathMinus")
+ {
+ // LO does not have this type so mapping not necessary
+ return false;
+ }
+ if (sShapeType == "mathMultiply")
+ {
+ // LO does not have this type so mapping not necessary
+ return false;
+ }
+ if (sShapeType == "mathNotEqual")
+ {
+ // LO does not have this type so mapping not necessary
+ return false;
+ }
+ if (sShapeType == "mathPlus")
+ {
+ // LO does not have this type so mapping not necessary
+ return false;
+ }
+ if (sShapeType == "nonIsoscelesTrapezoid")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "noSmoking")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "notchedRightArrow")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "octagon")
+ {
+ m_pDMLexporter->WriteShapeTransformation(m_xShape, XML_a, IsXFlipped(), IsYFlipped(),
+ false, false);
+ auto aPoint1 = GetAdjustmentPointXValue(0);
+ tools::Long nVal1
+ = std::lround(aPoint1.nCurrVal / (aPoint1.nMaxVal - aPoint1.nMinVal) * 50000);
+ return StartAVListWriting()
+ && WriteAV(u"adj", OUString(u"val " + OUString::number(nVal1)))
+ && EndAVListWriting();
+ }
+ if (sShapeType == "parallelogram")
+ {
+ m_pDMLexporter->WriteShapeTransformation(m_xShape, XML_a, IsXFlipped(), IsYFlipped(),
+ false, false);
+ auto aPoint1 = GetAdjustmentPointXValue(0);
+ tools::Long nMaxVal = 100000 * m_xShape->getSize().Width
+ / std::min(m_xShape->getSize().Width, m_xShape->getSize().Height);
+ tools::Long nVal1
+ = std::lround(aPoint1.nCurrVal / (aPoint1.nMaxVal - aPoint1.nMinVal) * nMaxVal);
+ return StartAVListWriting()
+ && WriteAV(u"adj", OUString(u"val " + OUString::number(nVal1)))
+ && EndAVListWriting();
+ }
+ if (sShapeType == "pentagon")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "pie")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "pieWedge")
+ {
+ // Not found in word.
+ return false;
+ }
+ if (sShapeType == "plaque")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "plaqueTabs")
+ {
+ // LO does not have this, so not necessary to map.
+ return false;
+ }
+ if (sShapeType == "plus")
+ {
+ m_pDMLexporter->WriteShapeTransformation(m_xShape, XML_a, IsXFlipped(), IsYFlipped(),
+ false, false);
+ auto aPoint1 = GetAdjustmentPointXValue(0);
+ tools::Long nVal1
+ = std::lround(aPoint1.nCurrVal / (aPoint1.nMaxVal - aPoint1.nMinVal) * 50000);
+ return StartAVListWriting()
+ && WriteAV(u"adj", OUString(u"val " + OUString::number(nVal1)))
+ && EndAVListWriting();
+ }
+ if (sShapeType == "quadArrow")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "quadArrowCallout")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "rect")
+ {
+ // preset enough without AV points.
+ return false;
+ }
+ if (sShapeType == "ribbon")
+ {
+ // LO does not have this, so not necessary to map.
+ return false;
+ }
+ if (sShapeType == "ribbon2")
+ {
+ // LO does not have this, so not necessary to map.
+ return false;
+ }
+ if (sShapeType == "rightArrow")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "rightArrowCallout")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "rightBrace")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "rightBracket")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "round1Rect")
+ {
+ // LO does not have this, so not necessary to map.
+ return false;
+ }
+ if (sShapeType == "round2DiagRect")
+ {
+ // LO does not have this, so not necessary to map.
+ return false;
+ }
+ if (sShapeType == "round2SameRect")
+ {
+ // LO does not have this, so not necessary to map.
+ return false;
+ }
+ if (sShapeType == "roundRect")
+ {
+ m_pDMLexporter->WriteShapeTransformation(m_xShape, XML_a, IsXFlipped(), IsYFlipped(),
+ false, false);
+ tools::Long nVal1 = 0;
+ if (m_xShape->getSize().Width >= m_xShape->getSize().Height)
+ {
+ auto aPointX = GetAdjustmentPointXValue(0);
+ nVal1 = std::lround(aPointX.nCurrVal / (aPointX.nMaxVal - aPointX.nMinVal) * 50000);
+ }
+ else
+ {
+ auto aPointY = GetAdjustmentPointYValue(0);
+ nVal1 = std::lround(aPointY.nCurrVal / (aPointY.nMaxVal - aPointY.nMinVal) * 50000);
+ }
+ return StartAVListWriting()
+ && WriteAV(u"adj", OUString(u"val " + OUString::number(nVal1)))
+ && EndAVListWriting();
+ }
+ if (sShapeType == "rtTriangle")
+ {
+ // Does not have AV points not necessary to map
+ return false;
+ }
+ if (sShapeType == "smileyFace")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "snip1Rect")
+ {
+ // LO does not have this, so not necessary to map.
+ return false;
+ }
+ if (sShapeType == "snip2DiagRect")
+ {
+ // LO does not have this, so not necessary to map.
+ return false;
+ }
+ if (sShapeType == "snip2SameRect")
+ {
+ // LO does not have this, so not necessary to map.
+ return false;
+ }
+ if (sShapeType == "snipRoundRect")
+ {
+ // LO does not have this, so not necessary to map.
+ return false;
+ }
+ if (sShapeType == "squareTabs")
+ {
+ // LO does not have this, so not necessary to map.
+ return false;
+ }
+ if (sShapeType == "star10")
+ {
+ // LO does not have this, so not necessary to map.
+ return false;
+ }
+ if (sShapeType == "star12")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "star16")
+ {
+ // LO does not have this, so not necessary to map.
+ return false;
+ }
+ if (sShapeType == "star24")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "star32")
+ {
+ // LO does not have this, so not necessary to map.
+ return false;
+ }
+ if (sShapeType == "star4")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "star5")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "star6")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "star7")
+ {
+ // LO does not have this, so not necessary to map.
+ return false;
+ }
+ if (sShapeType == "star8")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "straightConnector1")
+ {
+ // Not necessary to map.
+ return false;
+ }
+ if (sShapeType == "stripedRightArrow")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "sun")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "swooshArrow")
+ {
+ // Not found in word.
+ return false;
+ }
+ if (sShapeType == "teardrop")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "trapezoid")
+ {
+ // Preset enough.
+ return false;
+ }
+ if (sShapeType == "triangle")
+ {
+ m_pDMLexporter->WriteShapeTransformation(m_xShape, XML_a, IsXFlipped(), IsYFlipped(),
+ false, false);
+ auto aPoint1 = GetAdjustmentPointXValue(0);
+ tools::Long nMaxVal = 100000;
+ tools::Long nVal1
+ = std::lround(aPoint1.nCurrVal / (aPoint1.nMaxVal - aPoint1.nMinVal) * nMaxVal);
+ return StartAVListWriting()
+ && WriteAV(u"adj", OUString(u"val " + OUString::number(nVal1)))
+ && EndAVListWriting();
+ }
+ if (sShapeType == "upArrowCallout")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "upDownArrow")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "upArrow")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "upDownArrowCallout")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "uturnArrow")
+ {
+ // LO does not have like this.
+ return false;
+ }
+ if (sShapeType == "verticalScroll")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "wave")
+ {
+ // LO does not have.
+ return false;
+ }
+ if (sShapeType == "wedgeEllipseCallout")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "wedgeRectCallout")
+ {
+ // TODO
+ return false;
+ }
+ if (sShapeType == "wedgeRoundRectCallout")
+ {
+ // TODO
+ return false;
+ }
+ }
+ catch (...)
+ {
+ // Problem detected with the writing, aborting and trying to find another way.
+ return false;
+ }
+
+ // Default, nothing happened return.
+ return false;
+};
+}
diff --git a/oox/source/export/shapes.cxx b/oox/source/export/shapes.cxx
index f45b0aabc61d..d52d6696be2a 100644
--- a/oox/source/export/shapes.cxx
+++ b/oox/source/export/shapes.cxx
@@ -73,6 +73,7 @@
#include <oox/export/chartexport.hxx>
#include <oox/mathml/export.hxx>
#include <basegfx/numeric/ftools.hxx>
+#include <oox/export/DMLPresetShapeExport.hxx>
using namespace ::css;
using namespace ::css::beans;
@@ -832,7 +833,19 @@ ShapeExport& ShapeExport::WriteCustomShape( const Reference< XShape >& xShape )
else if( bHasHandles )
bCustGeom = true;
- if (bHasHandles && bCustGeom)
+ bool bPresetWriteSuccessful = false;
+ // Let the custom shapes what has name and preset information in OOXML, to be written
+ // as preset ones with parameters. Try that with this converter class.
+ if (!sShapeType.startsWith("ooxml") && GetDocumentType() == DOCUMENT_DOCX
+ && xShape->getShapeType() == "com.sun.star.drawing.CustomShape")
+ {
+ DMLPresetShapeExporter aCustomShapeConverter(this, xShape);
+ bPresetWriteSuccessful = aCustomShapeConverter.WriteShape();
+ }
+ // If preset writing has problems try to write the shape as it done before
+ if (bPresetWriteSuccessful)
+ ;// Already written do nothing.
+ else if (bHasHandles && bCustGeom)
{
WriteShapeTransformation( xShape, XML_a, bFlipH, bFlipV, false, true );// do not flip, polypolygon coordinates are flipped already
tools::PolyPolygon aPolyPolygon( rSdrObjCustomShape.GetLineGeometry(true) );
diff --git a/sw/qa/extras/ooxmlexport/data/testCustomShapePresetExport.odt b/sw/qa/extras/ooxmlexport/data/testCustomShapePresetExport.odt
new file mode 100644
index 000000000000..4f132e760460
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/testCustomShapePresetExport.odt
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
index 5666c3f1b1d1..2b3d92b55701 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport16.cxx
@@ -129,6 +129,37 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testGutterTop, "gutter-top.docx")
assertXPath(pXmlSettings, "/w:settings/w:gutterAtTop", 1);
}
+DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testCustomShapePresetExport, "testCustomShapePresetExport.odt")
+{
+ // Check if the load failed.
+ CPPUNIT_ASSERT(getPages());
+
+ // Check all shapes of the file
+ int nCount = 0;
+ for (int i = 1; i <= getShapes(); i++)
+ {
+ uno::Reference<beans::XPropertySet> xProperties(getShape(i), uno::UNO_QUERY);
+ if (!xProperties->getPropertySetInfo()->hasPropertyByName("CustomShapeGeometry"))
+ continue;
+ // Get the custom shape property
+ auto aCustomShapeGeometry = xProperties->getPropertyValue("CustomShapeGeometry")
+ .get<uno::Sequence<beans::PropertyValue>>();
+ // Find for shape type
+ for (const auto& aCustomGeometryIterator : std::as_const(aCustomShapeGeometry))
+ {
+ if (aCustomGeometryIterator.Name == "Type")
+ CPPUNIT_ASSERT_MESSAGE(
+ "This is an ooxml preset shape with custom geometry! Shape type lost!",
+ aCustomGeometryIterator.Value.get<OUString>() != "ooxml-non-primitive");
+ // Without the fix, all shapes have ooxml-non-primitive type, and lost their
+ // real type (like triangle) with the textbox padding.
+ }
+ nCount++;
+ }
+ // Without the fix the count does not match.
+ CPPUNIT_ASSERT_EQUAL(17, nCount);
+}
+
DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf69635, "tdf69635.docx")
{
xmlDocUniquePtr pXmlHeader1 = parseExport("word/header1.xml");