tdf#99497 CircleKind ARC, CUT, SECTION to OOXML arc, chord, pie

Before this patch, a classical ellipse or circle was exported as
OOXML preset type 'ellipse', regardless of the value of property
CircleKind. Now the property is evaluated and the corresponding
preset type is used.

Change-Id: I49ff43cf7e2ce02654979e82f7d83d60ace39e23
Reviewed-on: https://gerrit.libreoffice.org/77785
Tested-by: Jenkins
Reviewed-by: Regina Henschel <rb.henschel@t-online.de>
This commit is contained in:
Regina Henschel
2019-08-23 23:38:33 +02:00
parent 7b4b70afba
commit 72b50be019
3 changed files with 113 additions and 3 deletions
+71 -3
View File
@@ -47,6 +47,7 @@
#include <com/sun/star/container/XEnumerationAccess.hpp>
#include <com/sun/star/document/XExporter.hpp>
#include <com/sun/star/document/XStorageBasedDocument.hpp>
#include <com/sun/star/drawing/CircleKind.hpp>
#include <com/sun/star/drawing/FillStyle.hpp>
#include <com/sun/star/drawing/BitmapMode.hpp>
#include <com/sun/star/drawing/ConnectorType.hpp>
@@ -102,6 +103,7 @@
#include <oox/export/chartexport.hxx>
#include <oox/mathml/export.hxx>
#include <drawingml/presetgeometrynames.hxx>
#include <basegfx/numeric/ftools.hxx>
using namespace ::css;
using namespace ::css::beans;
@@ -697,6 +699,21 @@ static sal_Int32 lcl_NormalizeAngle( sal_Int32 nAngle )
return nAngle < 0 ? ( nAngle + 360 ) : nAngle ;
}
static sal_Int32 lcl_CircleAngle2CustomShapeEllipseAngleOOX(const sal_Int32 nInternAngle, const sal_Int32 nWidth, const sal_Int32 nHeight)
{
if (nWidth != 0 || nHeight != 0)
{
double fAngle = basegfx::deg2rad(nInternAngle / 100.0); // intern 1/100 deg to degree to rad
fAngle = atan2(nHeight * sin(fAngle), nWidth * cos(fAngle)); // circle to ellipse
fAngle = basegfx::rad2deg(fAngle) * 60000.0; // rad to degree to OOXML angle unit
sal_Int32 nAngle = basegfx::fround(fAngle); // normalize
nAngle = nAngle % 21600000;
return nAngle < 0 ? (nAngle + 21600000) : nAngle;
}
else // should be handled by caller, dummy value
return 0;
}
ShapeExport& ShapeExport::WriteCustomShape( const Reference< XShape >& xShape )
{
// First check, if this is a Fontwork-shape. For DrawingML, such a shape is a
@@ -1055,7 +1072,7 @@ ShapeExport& ShapeExport::WriteEllipseShape( const Reference< XShape >& xShape )
pFS->startElementNS(mnXmlNamespace, (GetDocumentType() != DOCUMENT_DOCX ? XML_sp : XML_wsp));
// TODO: arc, section, cut, connector
// TODO: connector ?
// non visual shape properties
if (GetDocumentType() != DOCUMENT_DOCX)
@@ -1071,13 +1088,64 @@ ShapeExport& ShapeExport::WriteEllipseShape( const Reference< XShape >& xShape )
else
pFS->singleElementNS(mnXmlNamespace, XML_cNvSpPr);
Reference< XPropertySet > xProps( xShape, UNO_QUERY );
CircleKind eCircleKind(CircleKind_FULL);
if (xProps.is())
xProps->getPropertyValue("CircleKind" ) >>= eCircleKind;
// visual shape properties
pFS->startElementNS( mnXmlNamespace, XML_spPr );
WriteShapeTransformation( xShape, XML_a );
WritePresetShape( "ellipse" );
Reference< XPropertySet > xProps( xShape, UNO_QUERY );
if (CircleKind_FULL == eCircleKind)
WritePresetShape("ellipse");
else
{
sal_Int32 nStartAngleIntern(9000);
sal_Int32 nEndAngleIntern(0);
if (xProps.is())
{
xProps->getPropertyValue("CircleStartAngle" ) >>= nStartAngleIntern;
xProps->getPropertyValue("CircleEndAngle") >>= nEndAngleIntern;
}
std::vector< std::pair<sal_Int32,sal_Int32>> aAvList;
awt::Size aSize = xShape->getSize();
if (aSize.Width != 0 || aSize.Height != 0)
{
// Our arc has 90° up, OOXML has 90° down, so mirror it.
// API angles are 1/100 degree.
sal_Int32 nStartAngleOOXML(lcl_CircleAngle2CustomShapeEllipseAngleOOX(36000 - nEndAngleIntern, aSize.Width, aSize.Height));
sal_Int32 nEndAngleOOXML(lcl_CircleAngle2CustomShapeEllipseAngleOOX(36000 - nStartAngleIntern, aSize.Width, aSize.Height));
lcl_AppendAdjustmentValue( aAvList, 1, nStartAngleOOXML);
lcl_AppendAdjustmentValue( aAvList, 2, nEndAngleOOXML);
}
switch (eCircleKind)
{
case CircleKind_ARC :
WritePresetShape("arc", aAvList);
break;
case CircleKind_SECTION :
WritePresetShape("pie", aAvList);
break;
case CircleKind_CUT :
WritePresetShape("chord", aAvList);
break;
default :
WritePresetShape("ellipse");
}
}
if( xProps.is() )
{
if (CircleKind_ARC == eCircleKind)
{
// An arc in ODF is never filled, even if a fill style other than
// "none" is set. OOXML arc can be filled, so set fill explicit to
// NONE, otherwise some hidden or inherited filling is shown.
FillStyle eFillStyle(FillStyle_NONE);
uno::Any aNewValue;
aNewValue <<= eFillStyle;
xProps->setPropertyValue("FillStyle", aNewValue);
}
WriteFill( xProps );
WriteOutline( xProps );
}
Binary file not shown.
+42
View File
@@ -193,6 +193,7 @@ public:
void testTdf111789();
void testTdf100348_convert_Fontwork2TextWarp();
void testTdf1225573_FontWorkScaleX();
void testTdf99497_keepAppearanceOfCircleKind();
/// SmartArt animated elements
void testTdf104792();
void testTdf90627();
@@ -288,6 +289,7 @@ public:
CPPUNIT_TEST(testTdf111789);
CPPUNIT_TEST(testTdf100348_convert_Fontwork2TextWarp);
CPPUNIT_TEST(testTdf1225573_FontWorkScaleX);
CPPUNIT_TEST(testTdf99497_keepAppearanceOfCircleKind);
CPPUNIT_TEST(testTdf104792);
CPPUNIT_TEST(testTdf90627);
CPPUNIT_TEST(testTdf104786);
@@ -2538,6 +2540,46 @@ void SdOOXMLExportTest2::testTdf126741()
xDocShRef->DoClose();
}
void SdOOXMLExportTest2::testTdf99497_keepAppearanceOfCircleKind()
{
// Error was, that all CircleKind were exported to 'ellipse'.
// Resulting pptx has to contain the customshapes of the corresponding kind
// slide 1 ARC -> arc, slide 2 CUT -> chord, slide 3 SECTION -> pie
// Adjustment values need to exist and their values need to correspond to the
// orignal angles. Shape 'arc' needs to be unfilled.
const OUString sPath("/sd/qa/unit/data/odp/tdf99497_CircleKind.odp");
::sd::DrawDocShellRef xDocShRef = loadURL(m_directories.getURLFromSrc(sPath), ODP);
utl::TempFile tempFile;
xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile);
// slide 1 45° -> adj1 = 20493903, 270° -> adj2 = 5400000, <a:noFill/> exists
xmlDocPtr pXmlDocContent1 = parseExport(tempFile, "ppt/slides/slide1.xml");
const OString sPathStart1("/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:prstGeom");
assertXPath(pXmlDocContent1, sPathStart1 + "[@prst='arc']");
const OString sPathAdj1(sPathStart1 + "/a:avLst/a:gd");
assertXPath(pXmlDocContent1, sPathAdj1 + "[@name='adj1' and @fmla='val 20493903']");
assertXPath(pXmlDocContent1, sPathAdj1 + "[@name='adj2' and @fmla='val 5400000']");
assertXPath(pXmlDocContent1, "/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:noFill");
// slide 2 270° -> adj1 = 5400000, 180° -> adj2 = 10800000
xmlDocPtr pXmlDocContent2 = parseExport(tempFile, "ppt/slides/slide2.xml");
const OString sPathStart2("/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:prstGeom");
assertXPath(pXmlDocContent2, sPathStart2 + "[@prst='chord']");
const OString sPathAdj2(sPathStart2 + "/a:avLst/a:gd");
assertXPath(pXmlDocContent2, sPathAdj2 + "[@name='adj1' and @fmla='val 5400000']");
assertXPath(pXmlDocContent2, sPathAdj2 + "[@name='adj2' and @fmla='val 10800000']");
// slide 3 120° -> adj1 = 12600000, 30° -> adj2 = 20946396
xmlDocPtr pXmlDocContent3 = parseExport(tempFile, "ppt/slides/slide3.xml");
const OString sPathStart3("/p:sld/p:cSld/p:spTree/p:sp/p:spPr/a:prstGeom");
assertXPath(pXmlDocContent3, sPathStart3 + "[@prst='pie']");
const OString sPathAdj3(sPathStart3 + "/a:avLst/a:gd");
assertXPath(pXmlDocContent3, sPathAdj3 + "[@name='adj1' and @fmla='val 12600000']");
assertXPath(pXmlDocContent3, sPathAdj3 + "[@name='adj2' and @fmla='val 20946396']");
xDocShRef->DoClose();
}
CPPUNIT_TEST_SUITE_REGISTRATION(SdOOXMLExportTest2);
CPPUNIT_PLUGIN_IMPLEMENT();