tdf#118701 DOCX import: fix image position on page break

If an image anchored to an empty paragraph only with
section properties, don't remove that paragraph to keep
the image on the page before the page break.

IsLastParaEmpty() tries to move a text cursor over the
empty paragraph marked for deletion. If it contains an
image anchored as a character, the cursor won't reach
the end of the previous paragraph by goLeft(2).

Co-authored-by: Attila Bánhegyi (NISZ)

Change-Id: Ic22c7553948eb06739232d7e35fc49ad14f96518
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/97518
Tested-by: László Németh <nemeth@numbertext.org>
Reviewed-by: László Németh <nemeth@numbertext.org>
diff --git a/sw/qa/extras/ooxmlexport/data/tdf118701.docx b/sw/qa/extras/ooxmlexport/data/tdf118701.docx
new file mode 100644
index 0000000..654a227
--- /dev/null
+++ b/sw/qa/extras/ooxmlexport/data/tdf118701.docx
Binary files differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx
index 9c1fb2c..67e9a95 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport15.cxx
@@ -33,6 +33,11 @@ DECLARE_OOXMLEXPORT_TEST(testTdf133334_followPgStyle, "tdf133334_followPgStyle.o
    CPPUNIT_ASSERT_EQUAL(2, getPages());
}

DECLARE_OOXMLIMPORT_TEST(testTdf118701, "tdf118701.docx")
{
    CPPUNIT_ASSERT_EQUAL_MESSAGE("At least one paragraph is missing from the file!", 3, getParagraphs());
}

DECLARE_OOXMLEXPORT_TEST(testTdf133370_columnBreak, "tdf133370_columnBreak.odt")
{
    // Since non-DOCX formats ignores column breaks in non-column situations, don't export to docx.
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index d07f045..5df7bb3 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -3516,7 +3516,7 @@ void DomainMapper::lcl_utext(const sal_uInt8 * data_, size_t len)
            }
            m_pImpl->SetParaSectpr(false);
            finishParagraph(bRemove);
            if (bRemove)
            if (bRemove && m_pImpl->IsLastParaEmpty())
                m_pImpl->RemoveLastParagraph();
        }
        else
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index 04e087f..16b56a6 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -474,6 +474,22 @@ void DomainMapper_Impl::AddDummyParaForTableInSection()
    }
}

bool DomainMapper_Impl::IsLastParaEmpty()
{
    bool bRet = true;
    if (!m_aTextAppendStack.empty() && m_aTextAppendStack.top().xTextAppend)
    {
        //creating cursor for finding text content
        uno::Reference<text::XTextCursor> xCursor = m_aTextAppendStack.top().xTextAppend->createTextCursor();
        xCursor->gotoEnd(false);
        //selecting the last 2 characters in the document
        xCursor->goLeft(2, true);
        //the last paragraph is empty, if they are newlines
        bRet = xCursor->getString().match(OUString(SAL_NEWLINE_STRING).concat(SAL_NEWLINE_STRING));
    }
    return bRet;
}

void DomainMapper_Impl::RemoveLastParagraph( )
{
    if (m_bDiscardHeaderFooter)
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index db0a03f..e145547 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -626,6 +626,7 @@ public:

    void RemoveDummyParaForTableInSection();
    void AddDummyParaForTableInSection();
    bool IsLastParaEmpty();
    void RemoveLastParagraph( );
    void SetIsLastParagraphInSection( bool bIsLast );
    bool GetIsLastParagraphInSection() const { return m_bIsLastParaInSection;}