tdf#119187 fix: Top-aligned text in PPTX becomes bottom-aligned

Change-Id: Ic6c03e512ce3f6e240d86186fb16e24c86942343
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/92051
Tested-by: Jenkins
Reviewed-by: Thorsten Behrens <Thorsten.Behrens@CIB.de>
diff --git a/oox/source/ppt/pptshape.cxx b/oox/source/ppt/pptshape.cxx
index 335e373..a781aa5 100644
--- a/oox/source/ppt/pptshape.cxx
+++ b/oox/source/ppt/pptshape.cxx
@@ -425,65 +425,102 @@ namespace
oox::drawingml::ShapePtr PPTShape::findPlaceholder( sal_Int32 nFirstSubType, sal_Int32 nSecondSubType,
    const OptValue< sal_Int32 >& oSubTypeIndex, std::vector< oox::drawingml::ShapePtr >& rShapes, bool bMasterOnly )
{
    oox::drawingml::ShapePtr aShapePtr;
    oox::drawingml::ShapePtr aChoiceShapePtr1;
    oox::drawingml::ShapePtr aChoiceShapePtr2;
    oox::drawingml::ShapePtr aChoiceShapePtr3;
    oox::drawingml::ShapePtr aChoiceShapePtr4;
    std::vector< oox::drawingml::ShapePtr >::reverse_iterator aRevIter( rShapes.rbegin() );
    while (aRevIter != rShapes.rend())
    class Placeholders
    {
    public:
        Placeholders()
            : aChoice(5) // resize to 5
        {
        }

        void add(const oox::drawingml::ShapePtr& aShape, sal_Int32 nFirstSubType, sal_Int32 nSecondSubType, const OptValue< sal_Int32 >& oSubTypeIndex)
        {
            if (!aShape.get())
                return;

            // get flags
            const bool bSameFirstSubType = aShape->getSubType() == nFirstSubType;
            const bool bSameSecondSubType = aShape->getSubType() == nSecondSubType;
            const bool bSameIndex = aShape->getSubTypeIndex() == oSubTypeIndex;

            // get prio
            int aPrioIndex = -1;
            if (bSameIndex && bSameFirstSubType)
                aPrioIndex = 0;
            else if (!bSameIndex && bSameFirstSubType)
                aPrioIndex = 1;
            else if (bSameIndex && bSameSecondSubType)
                aPrioIndex = 2;
            else if (!bSameIndex && bSameSecondSubType)
                aPrioIndex = 3;
            else if (bSameIndex)
                aPrioIndex = 4;

            // add
            if (aPrioIndex != -1)
            {
                if (!aChoice.at(aPrioIndex).get())
                {
                    aChoice.at(aPrioIndex) = aShape;
                }
            }
        }

        // return according to prio
        oox::drawingml::ShapePtr getByPrio() const
        {
            for (const oox::drawingml::ShapePtr& aShape : aChoice)
            {
                if (aShape.get())
                {
                    return aShape;
                }
            }

            return oox::drawingml::ShapePtr();
        }

        bool hasByPrio(size_t aIndex) const
        {
            return aChoice.at(aIndex).get();
        }

    private:
        std::vector< oox::drawingml::ShapePtr > aChoice;

    } aPlaceholders;

    // check all shapes
    std::vector< oox::drawingml::ShapePtr >::reverse_iterator aRevIter( rShapes.rbegin() );
    for (; aRevIter != rShapes.rend(); ++aRevIter)
    {
        // check shape
        if (!bMasterOnly || ShapeLocationIsMaster((*aRevIter).get()))
        {
            if ((*aRevIter)->getSubTypeIndex() == oSubTypeIndex)
            {
                if ((*aRevIter)->getSubType() == nFirstSubType)
                {
                    aShapePtr = *aRevIter;
                    break;
                }
                else if ((*aRevIter)->getSubType() == nSecondSubType && !aChoiceShapePtr2.get())
                    aChoiceShapePtr2 = *aRevIter;
                else if (!aChoiceShapePtr4.get())
                    aChoiceShapePtr4 = *aRevIter;
            }
            else if ((*aRevIter)->getSubType() == nFirstSubType && !aChoiceShapePtr1.get())
                aChoiceShapePtr1 = *aRevIter;
            else if ((*aRevIter)->getSubType() == nSecondSubType && !aChoiceShapePtr3.get())
                aChoiceShapePtr3 = *aRevIter;
            const oox::drawingml::ShapePtr& aShape = *aRevIter;
            aPlaceholders.add(aShape, nFirstSubType, nSecondSubType, oSubTypeIndex);
        }

        // check children
        std::vector< oox::drawingml::ShapePtr >& rChildren = (*aRevIter)->getChildren();
        aChoiceShapePtr4 = findPlaceholder( nFirstSubType, nSecondSubType, oSubTypeIndex, rChildren, bMasterOnly );
        if (aChoiceShapePtr4.get())
        if (!rChildren.empty())
        {
            if (aChoiceShapePtr4->getSubType() == nFirstSubType)
            const oox::drawingml::ShapePtr aShape = findPlaceholder( nFirstSubType, nSecondSubType, oSubTypeIndex, rChildren, bMasterOnly );
            if (aShape.get())
            {
                if (aChoiceShapePtr4->getSubTypeIndex() == oSubTypeIndex)
                    aShapePtr = aChoiceShapePtr4;
                else
                    aChoiceShapePtr1 = aChoiceShapePtr4;
            }
            else if (aChoiceShapePtr4->getSubType() == nSecondSubType)
            {
                if (aChoiceShapePtr4->getSubTypeIndex() == oSubTypeIndex)
                    aChoiceShapePtr2 = aChoiceShapePtr4;
                else
                    aChoiceShapePtr3 = aChoiceShapePtr4;
                aPlaceholders.add(aShape, nFirstSubType, nSecondSubType, oSubTypeIndex);
            }
        }
        if (aShapePtr.get() || aChoiceShapePtr2.get())

        if (aPlaceholders.hasByPrio(0) ||
            aPlaceholders.hasByPrio(2))
        {
            break;
        ++aRevIter;
        }
    }
    if (aShapePtr.get())
        return aShapePtr;
    if (aChoiceShapePtr1.get())
        return aChoiceShapePtr1;
    if (aChoiceShapePtr2.get())
        return aChoiceShapePtr2;
    if (aChoiceShapePtr3.get())
        return aChoiceShapePtr3;
    return aChoiceShapePtr4;

    // return something according to prio
    return aPlaceholders.getByPrio();
}

oox::drawingml::ShapePtr PPTShape::findPlaceholderByIndex( const sal_Int32 nIdx, std::vector< oox::drawingml::ShapePtr >& rShapes, bool bMasterOnly )
diff --git a/sd/qa/unit/data/pptx/tdf119187.pptx b/sd/qa/unit/data/pptx/tdf119187.pptx
new file mode 100644
index 0000000..0c4501a
--- /dev/null
+++ b/sd/qa/unit/data/pptx/tdf119187.pptx
Binary files differ
diff --git a/sd/qa/unit/import-tests.cxx b/sd/qa/unit/import-tests.cxx
index bccfc56..ef03208 100644
--- a/sd/qa/unit/import-tests.cxx
+++ b/sd/qa/unit/import-tests.cxx
@@ -208,6 +208,7 @@ public:
    void testTdf77747();
    void testTdf116266();
    void testTdf128684();
    void testTdf119187();
    void testShapeGlowEffectPPTXImpoer();

    bool checkPattern(sd::DrawDocShellRef const & rDocRef, int nShapeNumber, std::vector<sal_uInt8>& rExpected);
@@ -327,6 +328,7 @@ public:
    CPPUNIT_TEST(testTdf106638);
    CPPUNIT_TEST(testTdf128684);
    CPPUNIT_TEST(testTdf113198);
    CPPUNIT_TEST(testTdf119187);
    CPPUNIT_TEST(testShapeGlowEffectPPTXImpoer);

    CPPUNIT_TEST_SUITE_END();
@@ -3080,6 +3082,31 @@ void SdImportTest::testTdf113198()
    CPPUNIT_ASSERT_EQUAL(style::ParagraphAdjust_CENTER, static_cast<style::ParagraphAdjust>(nParaAdjust));
}

void SdImportTest::testTdf119187()
{
    std::vector< sd::DrawDocShellRef > xDocShRef;
    // load document
    xDocShRef.push_back(loadURL(m_directories.getURLFromSrc("sd/qa/unit/data/pptx/tdf119187.pptx"), PPTX));
    // load resaved document
    xDocShRef.push_back(saveAndReload( xDocShRef.at(0).get(), PPTX ));

    // check documents
    for (const sd::DrawDocShellRef& xDoc : xDocShRef)
    {
        // get shape properties
        const SdrPage* pPage = GetPage(1, xDoc);
        CPPUNIT_ASSERT(pPage);
        SdrObject* pObj = pPage->GetObj(0);
        CPPUNIT_ASSERT(pObj);
        const sdr::properties::BaseProperties & rProperties = pObj->GetProperties();

        // chcek text vertical alignment
        const SdrTextVertAdjustItem& rSdrTextVertAdjustItem = rProperties.GetItem(SDRATTR_TEXT_VERTADJUST);
        const SdrTextVertAdjust eTVA = rSdrTextVertAdjustItem.GetValue();
        CPPUNIT_ASSERT_EQUAL(SDRTEXTVERTADJUST_TOP, eTVA);
    }
}

void SdImportTest::testShapeGlowEffectPPTXImpoer()
{
    sd::DrawDocShellRef xDocShRef