tdf#122589 rtfexport: no duplicate section at document start

If the document starts with a real section, then RTF export should
not write out \sect before the first paragraph, because there already
is an implicit section. Otherwise on import it is treated as an
empty paragraph.

The reason this problem doesn't multiply on each round-trip
is that the import process puts a PageBreak on the first
paragraph, and so it follows a different code path.
The ODT file does not contain a PageBreak on the first paragraph.

Change-Id: I8f2d48c932587aaf162e8f7352adf12ec15645f0
Reviewed-on: https://gerrit.libreoffice.org/66017
Tested-by: Jenkins
Reviewed-by: Justin Luth <justin_luth@sil.org>
diff --git a/sw/qa/extras/rtfexport/data/tdf122589_firstSection.odt b/sw/qa/extras/rtfexport/data/tdf122589_firstSection.odt
new file mode 100644
index 0000000..751517c
--- /dev/null
+++ b/sw/qa/extras/rtfexport/data/tdf122589_firstSection.odt
Binary files differ
diff --git a/sw/qa/extras/rtfexport/rtfexport3.cxx b/sw/qa/extras/rtfexport/rtfexport3.cxx
index deb380f..13b0524 100644
--- a/sw/qa/extras/rtfexport/rtfexport3.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport3.cxx
@@ -11,6 +11,7 @@

#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
#include <com/sun/star/style/PageStyleLayout.hpp>
#include <com/sun/star/text/WritingMode2.hpp>
#include <com/sun/star/text/XFootnote.hpp>
#include <com/sun/star/text/XFootnotesSupplier.hpp>
#include <com/sun/star/text/XPageCursor.hpp>
@@ -77,6 +78,17 @@ DECLARE_RTFEXPORT_TEST(testTdf116436_tableBackground, "tdf116436_tableBackground
        CPPUNIT_ASSERT_EQUAL(sal_Int32(0xFFFBCC), getProperty<sal_Int32>(xCell, "BackColor"));
}

DECLARE_RTFEXPORT_TEST(testTdf122589_firstSection, "tdf122589_firstSection.odt")
{
    uno::Reference<beans::XPropertySet> xPageStyle(getStyles("PageStyles")->getByName("Standard"),
                                                   uno::UNO_QUERY);
    uno::Reference<text::XTextRange> xHeaderText
        = getProperty<uno::Reference<text::XTextRange>>(xPageStyle, "HeaderText");
    CPPUNIT_ASSERT_EQUAL(OUString("My header"), xHeaderText->getString());

    CPPUNIT_ASSERT_EQUAL_MESSAGE("# of paragraphs", 2, getParagraphs());
}

DECLARE_RTFEXPORT_TEST(testTdf104035, "tdf104035.rtf")
{
    auto aTabStops = getProperty<uno::Sequence<style::TabStop>>(getParagraph(1), "ParaTabStops");
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx
index f55f4a7..34f8bb5 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -243,6 +243,9 @@ void RtfAttributeOutput::RTLAndCJKState(bool bIsRTL, sal_uInt16 nScript)

void RtfAttributeOutput::StartParagraph(ww8::WW8TableNodeInfo::Pointer_t pTextNodeInfo)
{
    if (m_bIsBeforeFirstParagraph && m_rExport.m_nTextTyp != TXT_HDFT)
        m_bIsBeforeFirstParagraph = false;

    // Output table/table row/table cell starts if needed
    if (pTextNodeInfo)
    {
@@ -1181,6 +1184,9 @@ void RtfAttributeOutput::SectionBreak(sal_uInt8 nC, const WW8_SepInfo* pSectionI

void RtfAttributeOutput::StartSection()
{
    if (m_bIsBeforeFirstParagraph)
        return;

    m_aSectionBreaks.append(OOO_STRING_SVTOOLS_RTF_SECT OOO_STRING_SVTOOLS_RTF_SECTD);
    if (!m_bBufferSectionBreaks)
        m_rExport.Strm().WriteCharPtr(m_aSectionBreaks.makeStringAndClear().getStr());
@@ -3614,6 +3620,7 @@ RtfAttributeOutput::RtfAttributeOutput(RtfExport& rExport)
    , m_bLastTable(true)
    , m_bWroteCellInfo(false)
    , m_bTableRowEnded(false)
    , m_bIsBeforeFirstParagraph(true)
    , m_bSingleEmptyRun(false)
    , m_bInRun(false)
    , m_pFlyFrameSize(nullptr)
diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx b/sw/source/filter/ww8/rtfattributeoutput.hxx
index af740f2..d65e49d 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.hxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.hxx
@@ -589,6 +589,8 @@ private:
    /// Number of cells from the table definition, by depth.
    std::map<sal_uInt32, sal_uInt32> m_aCells;

    bool m_bIsBeforeFirstParagraph;

    /// If we're in a paragraph that has a single empty run only.
    bool m_bSingleEmptyRun;