Revert "tdf#147919 PPTX export: fix curved and bent connector shape"

This reverts commit 1f8c6efbfea10997f188962d036f5c7db4c13f8a, as it caues

> warn:legacy.tools:12871:12871:tools/source/generic/poly.cxx:1581: Polygon::[]: nPos >= nPoints
> =================================================================
> ==12871==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x603000445080 at pc 0x7f6303ec7854 bp 0x7ffd23271600 sp 0x7ffd232715f8
> READ of size 8 at 0x603000445080 thread T0
>     #0 0x7f6303ec7853 in Point::X() const /include/tools/gen.hxx:83:51
>     #1 0x7f63045baaa1 in oox::drawingml::lcl_GetConnectorAdjustValue(com::sun::star::uno::Reference<com::sun::star::drawing::XShape> const&, tools::Polygon, com::sun::star::drawing::ConnectorType, std::__debug::vector<std::pair<int, int>, std::allocator<std::pair<int, int> > >&) /oox/source/export/shapes.cxx:1556:27
>     #2 0x7f63045b731f in oox::drawingml::ShapeExport::WriteConnectorShape(com::sun::star::uno::Reference<com::sun::star::drawing::XShape> const&) /oox/source/export/shapes.cxx:1701:13
>     #3 0x7f63045984e7 in oox::drawingml::ShapeExport::WriteShape(com::sun::star::uno::Reference<com::sun::star::drawing::XShape> const&) /oox/source/export/shapes.cxx:1956:5
>     #4 0x7f62b399ad3b in oox::core::PowerPointExport::WriteShapeTree(std::shared_ptr<sax_fastparser::FastSerializerHelper> const&, PageType, bool) /sd/source/filter/eppt/pptx-epptooxml.cxx:1658:22

during CppunitTest_sd_export_tests-ooxml3
CPPUNIT_TEST_NAME=SdOOXMLExportTest3::testTdf114848
(<https://ci.libreoffice.org/job/lo_ubsan/2388/consoleFull#-1714579836d893063f-7f3d-4b7e-b56f-4e0f225817cd>)

Change-Id: I7eab9d3ef8e6604a57d3e59a77905edf6ce6e6ac
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/133870
Tested-by: Jenkins
Reviewed-by: Stephan Bergmann <sbergman@redhat.com>
diff --git a/oox/source/export/shapes.cxx b/oox/source/export/shapes.cxx
index de1527e..3308d5a 100644
--- a/oox/source/export/shapes.cxx
+++ b/oox/source/export/shapes.cxx
@@ -1411,276 +1411,49 @@ void ShapeExport::WriteGraphicObjectShapePart( const Reference< XShape >& xShape
    pFS->endElementNS( mnXmlNamespace, XML_pic );
}

static void lcl_Rotate(sal_Int32 nAngle, Point center, awt::Point& pt)
{
    sal_Int16 nCos, nSin;
    switch (nAngle)
    {
        case 90:
            nCos = 0;
            nSin = 1;
            break;
        case 180:
            nCos = -1;
            nSin = 0;
            break;
        case 270:
            nCos = 0;
            nSin = -1;
            break;
        default:
            return;
    }
    sal_Int32 x = pt.X - center.X();
    sal_Int32 y = pt.Y - center.Y();
    pt.X = center.X() + x * nCos - y * nSin;
    pt.Y = center.Y() + y * nCos + x * nSin;
}

static void lcl_FlipHFlipV(tools::Polygon aPoly, sal_Int32 nAngle, bool& rFlipH, bool& rFlipV)
{
    Point aStart = aPoly[0];
    Point aEnd = aPoly[aPoly.GetSize() - 1];

    if (aStart.X() > aEnd.X() && aStart.Y() > aEnd.Y())
    {
        if (nAngle)
        {
            if (nAngle == 90)
                rFlipH = true;
            if (nAngle == 270)
                rFlipV = true;
        }
        else // 0°
        {
            rFlipH = true;
            rFlipV = true;
        }
    }

    if (aStart.X() < aEnd.X() && aStart.Y() < aEnd.Y())
    {
        if (nAngle)
        {
            if (nAngle != 270)
            {
                rFlipH = true;
                rFlipV = true;
            }
            else
                rFlipH = true;
        }
    }

    if (aStart.Y() < aEnd.Y() && aStart.X() > aEnd.X())
    {
        if (nAngle)
        {
            if (nAngle == 180)
                rFlipV = true;
            if (nAngle == 270)
            {
                rFlipV = true;
                rFlipH = true;
            }
        }
        else // 0°
        {
            rFlipH = true;
        }
    }

    if (aStart.Y() > aEnd.Y() && aStart.X() < aEnd.X())
    {
        if (nAngle)
        {
            if (nAngle == 90)
            {
                rFlipH = true;
                rFlipV = true;
            }
            if (nAngle == 180)
                rFlipH = true;
        }
        else // 0°
            rFlipV = true;
    }
}

static sal_Int32 lcl_GetAngle(tools::Polygon aPoly)
{
    sal_Int32 nAngle;
    Point aStartPoint = aPoly[0];
    Point aEndPoint = aPoly[aPoly.GetSize() - 1];
    if (aStartPoint.X() == aPoly[1].X())
    {
        if ((aStartPoint.X() < aEndPoint.X() && aStartPoint.Y() > aEndPoint.Y())
            || (aStartPoint.X() > aEndPoint.X() && aStartPoint.Y() < aEndPoint.Y()))
        {
            nAngle = 90;
        }
        else
            nAngle = 270;
    }
    else
    {
        if (aStartPoint.X() > aPoly[1].X())
            nAngle = 180;
        else
            nAngle = 0;
    }

    return nAngle;
}

// Adjust value decide the position, where the connector should turn.
static void lcl_GetConnectorAdjustValue(const Reference<XShape>& xShape, tools::Polygon aPoly,
                                        ConnectorType eConnectorType,
                                        std::vector<std::pair<sal_Int32, sal_Int32>>& rAvList)
{
    sal_Int32 nAdjCount = 0;
    if (eConnectorType == ConnectorType_CURVE)
    {
        if (aPoly.GetSize() == 4)
        {
            if ((aPoly[0].X() == aPoly[1].X() && aPoly[2].X() == aPoly[3].X())
                || (aPoly[0].Y() == aPoly[1].Y() && aPoly[2].Y() == aPoly[3].Y()))
            {
                nAdjCount = 1; // curvedConnector3
            }
            else
                nAdjCount = 0; // curvedConnector2
        }
        else
        {
            if ((aPoly[2].X() == aPoly[3].X() && aPoly[3].X() == aPoly[4].X())
                || (aPoly[2].Y() == aPoly[3].Y() && aPoly[3].Y() == aPoly[4].Y()))
            {
                nAdjCount = 3; // curvedConnector5
            }
            else
                nAdjCount = 2; // curvedConnector4
        }
    }
    else
    {
        switch (aPoly.GetSize())
        {
            case 3:
                nAdjCount = 0; // bentConnector2
                break;
            case 4:
                nAdjCount = 1; // bentConnector3
                break;
            case 5:
                nAdjCount = 2; // bentConnector4
                break;
            case 6:
                nAdjCount = 3; // bentConnector5
                break;
        }
    }

    if (nAdjCount)
    {
        sal_Int32 nAdjustValue;
        Point aStart = aPoly[0];
        Point aEnd = aPoly[aPoly.GetSize() - 1];

        for (sal_Int32 i = 1; i <= nAdjCount; ++i)
        {
            Point aPt = aPoly[i];

            if (aEnd.Y() == aStart.Y())
                aEnd.setY(aStart.Y() + 1);
            if (aEnd.X() == aStart.X())
                aEnd.setX(aStart.X() + 1);

            bool bVertical = aPoly[1].X() - aStart.X() != 0 ? true : false;
            // vertical and horizon alternate
            if (i % 2 == 1)
                bVertical = !bVertical;

            if (eConnectorType == ConnectorType_CURVE)
            {
                awt::Size aSize = xShape->getSize();
                awt::Point aShapePosition = xShape->getPosition();
                tools::Rectangle aBoundRect = aPoly.GetBoundRect();

                if (bVertical)
                {
                    if ((aBoundRect.GetSize().Height() - aSize.Height) == 1)
                        aPt.setY(aPoly[i + 1].Y());
                    else if (aStart.Y() > aPt.Y())
                        aPt.setY(aShapePosition.Y);
                    else
                        aPt.setY(aShapePosition.Y + aSize.Height);
                }
                else
                {
                    if ((aBoundRect.GetSize().Width() - aSize.Width) == 1)
                        aPt.setX(aPoly[i + 1].X());
                    else if (aStart.X() > aPt.X())
                        aPt.setX(aShapePosition.X);
                    else
                        aPt.setX(aShapePosition.X + aSize.Width);
                }
            }

            if (bVertical)
                nAdjustValue = ((aPt.Y() - aStart.Y()) * 100000) / (aEnd.Y() - aStart.Y());
            else
                nAdjustValue = ((aPt.X() - aStart.X()) * 100000) / (aEnd.X() - aStart.X());

            rAvList.emplace_back(i, nAdjustValue);
        }
    }
}

ShapeExport& ShapeExport::WriteConnectorShape( const Reference< XShape >& xShape )
{
    bool bFlipH = false;
    bool bFlipV = false;
    sal_Int32 nAngle = 0;

    SAL_INFO("oox.shape", "write connector shape");

    FSHelperPtr pFS = GetFS();

    OUString sGeometry;
    std::vector<std::pair<sal_Int32, sal_Int32>> aAdjustValueList;
    const char* sGeometry = "line";
    Reference< XPropertySet > rXPropSet( xShape, UNO_QUERY );
    Reference< XPropertyState > rXPropState( xShape, UNO_QUERY );
    awt::Point aStartPoint, aEndPoint;
    Reference< XShape > rXShapeA;
    Reference< XShape > rXShapeB;
    PropertyState eState;
    ConnectorType eConnectorType = ConnectorType_STANDARD;
    GET(eConnectorType, EdgeKind);
    ConnectorType eConnectorType;
    if( GETAD( EdgeKind ) ) {
        mAny >>= eConnectorType;

    switch( eConnectorType ) {
        case ConnectorType_CURVE:
            sGeometry = "curvedConnector";
            break;
        case ConnectorType_STANDARD:
            sGeometry = "bentConnector";
            break;
        default:
        case ConnectorType_LINE:
        case ConnectorType_LINES:
            sGeometry = "straightConnector1";
            break;
    }

    if( GETAD( EdgeStartPoint ) ) {
        mAny >>= aStartPoint;
        if( GETAD( EdgeEndPoint ) ) {
            mAny >>= aEndPoint;
        switch( eConnectorType ) {
            case ConnectorType_CURVE:
                sGeometry = "curvedConnector3";
                break;
            case ConnectorType_STANDARD:
                sGeometry = "bentConnector3";
                break;
            default:
            case ConnectorType_LINE:
            case ConnectorType_LINES:
                sGeometry = "straightConnector1";
                break;
        }
    }
    GET( rXShapeA, EdgeStartConnection );
    GET( rXShapeB, EdgeEndConnection );

        if( GETAD( EdgeStartPoint ) ) {
            mAny >>= aStartPoint;
            if( GETAD( EdgeEndPoint ) ) {
                mAny >>= aEndPoint;
            }
        }
        GET( rXShapeA, EdgeStartConnection );
        GET( rXShapeB, EdgeEndConnection );
    }
    // Position is relative to group in Word, but relative to anchor of group in API.
    if (GetDocumentType() == DOCUMENT_DOCX && !mbUserShapes && m_xParent.is())
    {
@@ -1691,40 +1464,17 @@ ShapeExport& ShapeExport::WriteConnectorShape( const Reference< XShape >& xShape
        aEndPoint.Y -= aParentPos.Y;
    }
    EscherConnectorListEntry aConnectorEntry( xShape, aStartPoint, rXShapeA, aEndPoint, rXShapeB );

    if (eConnectorType == ConnectorType_CURVE || eConnectorType == ConnectorType_STANDARD)
    {
        tools::PolyPolygon aPolyPolygon = EscherPropertyContainer::GetPolyPolygon(xShape);
        if (aPolyPolygon.Count() > 0)
        {
            tools::Polygon aPoly = aPolyPolygon.GetObject(0);
            lcl_GetConnectorAdjustValue(xShape, aPoly, eConnectorType, aAdjustValueList);
            nAngle = lcl_GetAngle(aPoly);
            lcl_FlipHFlipV(aPoly, nAngle, bFlipH, bFlipV);
            if (nAngle)
            {
                Point center((aEndPoint.X + aStartPoint.X) / 2, (aEndPoint.Y + aStartPoint.Y) / 2);
                lcl_Rotate(nAngle, center, aStartPoint);
                lcl_Rotate(nAngle, center, aEndPoint);
                nAngle *= 60000;
            }
            sGeometry = sGeometry + OUString::number(aAdjustValueList.size() + 2);
        }
    }

    tools::Rectangle aRect( Point( aStartPoint.X, aStartPoint.Y ), Point( aEndPoint.X, aEndPoint.Y ) );
    if( aRect.getWidth() < 0 ) {
        bFlipH = true;
        aRect.SetLeft(aEndPoint.X);
        aRect.setWidth( aStartPoint.X - aEndPoint.X );
        if (eConnectorType == ConnectorType_LINE)
            bFlipH = true;
    }

    if( aRect.getHeight() < 0 ) {
        bFlipV = true;
        aRect.SetTop(aEndPoint.Y);
        aRect.setHeight( aStartPoint.Y - aEndPoint.Y );
        if (eConnectorType == ConnectorType_LINE)
            bFlipV = true;
    }

    // tdf#99810 connector shape (cxnSp) is not valid with namespace 'wps'
@@ -1754,9 +1504,9 @@ ShapeExport& ShapeExport::WriteConnectorShape( const Reference< XShape >& xShape

    // visual shape properties
    pFS->startElementNS(mnXmlNamespace, XML_spPr);
    WriteTransformation( xShape, aRect, XML_a, bFlipH, bFlipV, nAngle );
    WriteTransformation( xShape, aRect, XML_a, bFlipH, bFlipV );
    // TODO: write adjustments (ppt export doesn't work well there either)
    WritePresetShape( sGeometry.toUtf8(), aAdjustValueList);
    WritePresetShape( sGeometry );
    Reference< XPropertySet > xShapeProps( xShape, UNO_QUERY );
    if( xShapeProps.is() )
        WriteOutline( xShapeProps );
diff --git a/sd/qa/unit/data/odp/tdf147919.odp b/sd/qa/unit/data/odp/tdf147919.odp
deleted file mode 100644
index 2676b0e..0000000
--- a/sd/qa/unit/data/odp/tdf147919.odp
+++ /dev/null
Binary files differ
diff --git a/sd/qa/unit/export-tests-ooxml1.cxx b/sd/qa/unit/export-tests-ooxml1.cxx
index a1dac4f..db33355 100644
--- a/sd/qa/unit/export-tests-ooxml1.cxx
+++ b/sd/qa/unit/export-tests-ooxml1.cxx
@@ -48,7 +48,6 @@ using namespace css;
class SdOOXMLExportTest1 : public SdModelTestBaseXML
{
public:
    void testTdf147919();
    void testTdf130165();
    void testTdf124781();
    void testTdf144914();
@@ -118,7 +117,6 @@ public:

    CPPUNIT_TEST_SUITE(SdOOXMLExportTest1);

    CPPUNIT_TEST(testTdf147919);
    CPPUNIT_TEST(testTdf130165);
    CPPUNIT_TEST(testTdf124781);
    CPPUNIT_TEST(testTdf144914);
@@ -215,66 +213,6 @@ void checkFontAttributes( const SdrTextObj* pObj, ItemValue nVal, sal_uInt32 nId

}

void SdOOXMLExportTest1::testTdf147919()
{
    sd::DrawDocShellRef xDocShRef
        = loadURL(m_directories.getURLFromSrc(u"/sd/qa/unit/data/odp/tdf147919.odp"), ODP);
    utl::TempFile tempFile;
    xDocShRef = saveAndReload(xDocShRef.get(), PPTX, &tempFile);
    xDocShRef->DoClose();

    xmlDocUniquePtr pXmlDoc = parseExport(tempFile, "ppt/slides/slide1.xml");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[1]/p:spPr/a:prstGeom", "prst",
                "bentConnector2");

    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[2]/p:spPr/a:prstGeom/a:avLst/a:gd", "name", "adj1");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[2]/p:spPr/a:prstGeom", "prst",
                "bentConnector3");

    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[3]/p:spPr/a:xfrm", "flipH", "1");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[3]/p:spPr/a:xfrm", "rot", "16200000");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[3]/p:spPr/a:prstGeom/a:avLst/a:gd[1]", "name", "adj1");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[3]/p:spPr/a:prstGeom/a:avLst/a:gd[2]", "name", "adj2");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[3]/p:spPr/a:prstGeom", "prst",
                "bentConnector4");

    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[4]/p:spPr/a:xfrm", "flipH", "1");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[4]/p:spPr/a:xfrm", "flipV", "1");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[4]/p:spPr/a:xfrm", "rot", "10800000");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[4]/p:spPr/a:prstGeom/a:avLst/a:gd[1]", "name", "adj1");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[4]/p:spPr/a:prstGeom/a:avLst/a:gd[2]", "name", "adj2");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[4]/p:spPr/a:prstGeom/a:avLst/a:gd[3]", "name", "adj3");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[4]/p:spPr/a:prstGeom", "prst",
                "bentConnector5");

    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[5]/p:spPr/a:xfrm", "flipH", "1");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[5]/p:spPr/a:xfrm", "rot", "16200000");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[5]/p:spPr/a:prstGeom", "prst",
                "curvedConnector2");

    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[6]/p:spPr/a:xfrm", "flipH", "1");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[6]/p:spPr/a:xfrm", "rot", "16200000");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[6]/p:spPr/a:prstGeom/a:avLst/a:gd", "name", "adj1");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[6]/p:spPr/a:prstGeom", "prst",
                "curvedConnector3");

    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[7]/p:spPr/a:xfrm", "flipH", "1");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[7]/p:spPr/a:xfrm", "flipV", "1");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[7]/p:spPr/a:xfrm", "rot", "10800000");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[7]/p:spPr/a:prstGeom/a:avLst/a:gd[1]", "name", "adj1");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[7]/p:spPr/a:prstGeom/a:avLst/a:gd[2]", "name", "adj2");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[7]/p:spPr/a:prstGeom", "prst",
                "curvedConnector4");

    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[8]/p:spPr/a:xfrm", "flipV", "1");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[8]/p:spPr/a:xfrm", "rot", "16200000");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[8]/p:spPr/a:prstGeom/a:avLst/a:gd[1]", "name", "adj1");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[8]/p:spPr/a:prstGeom/a:avLst/a:gd[2]", "name", "adj2");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[8]/p:spPr/a:prstGeom/a:avLst/a:gd[3]", "name", "adj3");
    assertXPath(pXmlDoc, "/p:sld/p:cSld/p:spTree/p:cxnSp[8]/p:spPr/a:prstGeom", "prst",
                "curvedConnector5");
}

void SdOOXMLExportTest1::testTdf130165()
{
    sd::DrawDocShellRef xDocShRef