tdf#150927: properly handle nesting in tables

This re-implements the relevant part of commit
35021cd56b3b4e38035804087f215c80085564be, to follow the same
recursion logic that is used in SwXMLExport::ExportTable.

Additionally, it found a place where XML was still emitted
when collecting autostyles (breaks were exported); fixed.

Change-Id: I3b7eed06e0eca9ad20304b45db4c3e9d72478c9b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/139901
Tested-by: Jenkins
Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
(cherry picked from commit 58cb4fc7d17ae5b339c5ed6ae139e6ef2433c927)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/139843
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
diff --git a/sw/qa/extras/odfexport/data/table-in-frame-in-table-in-header-base.odt b/sw/qa/extras/odfexport/data/table-in-frame-in-table-in-header-base.odt
new file mode 100644
index 0000000..44dbf0b
--- /dev/null
+++ b/sw/qa/extras/odfexport/data/table-in-frame-in-table-in-header-base.odt
Binary files differ
diff --git a/sw/qa/extras/odfexport/odfexport.cxx b/sw/qa/extras/odfexport/odfexport.cxx
index 45e690a..87a7f93 100644
--- a/sw/qa/extras/odfexport/odfexport.cxx
+++ b/sw/qa/extras/odfexport/odfexport.cxx
@@ -3182,6 +3182,20 @@ CPPUNIT_TEST_FIXTURE(Test, tdf135942)
    assertXPath(pXmlDoc, "/office:document-styles/office:automatic-styles/style:style[@style:family='table']", 2);
}

CPPUNIT_TEST_FIXTURE(Test, tdf150927)
{
    // Similar to tdf135942

    loadAndReload("table-in-frame-in-table-in-header-base.odt");
    // All table autostyles should be collected, including nested, and must not crash.

    CPPUNIT_ASSERT_EQUAL(1, getPages());

    xmlDocUniquePtr pXmlDoc = parseExport("styles.xml");

    assertXPath(pXmlDoc, "/office:document-styles/office:automatic-styles/style:style[@style:family='table']", 2);
}

DECLARE_ODFEXPORT_TEST(testGutterLeft, "gutter-left.odt")
{
    CPPUNIT_ASSERT_EQUAL(1, getPages());
diff --git a/sw/source/filter/xml/xmltble.cxx b/sw/source/filter/xml/xmltble.cxx
index 81528e5b..8065c6a 100644
--- a/sw/source/filter/xml/xmltble.cxx
+++ b/sw/source/filter/xml/xmltble.cxx
@@ -1173,6 +1173,30 @@ void SwXMLTextParagraphExport::exportTableAutoStyles() {
    }
}

void SwXMLTextParagraphExport::CollectTableLinesAutoStyles(const SwTableLines& rLines,
                                                           SwFrameFormat& rFormat, bool _bProgress)
{
    // Follow SwXMLExport::ExportTableLines/ExportTableLine/ExportTableBox
    for (const SwTableLine* pLine : rLines)
    {
        for (SwTableBox* pBox : pLine->GetTabBoxes())
        {
            if (pBox->getRowSpan() <= 0)
                continue;
            if (pBox->GetSttNd())
            {
                if (rtl::Reference<SwXCell> xCell = SwXCell::CreateXCell(&rFormat, pBox))
                    exportText(xCell, true /*bAutoStyles*/, _bProgress, true /*bExportParagraph*/);
            }
            else
            {
                // no start node -> merged cells: export subtable in cell
                CollectTableLinesAutoStyles(pBox->GetTabLines(), rFormat, _bProgress);
            }
        }
    }
}

void SwXMLTextParagraphExport::exportTable(
        const Reference < XTextContent > & rTextContent,
        bool bAutoStyles, bool _bProgress )
@@ -1209,21 +1233,7 @@ void SwXMLTextParagraphExport::exportTable(
                    maTableNodes.push_back(pTableNd);
                    m_TableFormats.emplace(pTableNd, ::std::make_pair(SwXMLTextParagraphExport::FormatMap(), SwXMLTextParagraphExport::FormatMap()));
                    // Collect all tables inside cells of this table, too
                    const auto aCellNames = pXTable->getCellNames();
                    for (const OUString& rCellName : aCellNames)
                    {
                        css::uno::Reference<css::container::XEnumerationAccess> xCell(
                            pXTable->getCellByName(rCellName), css::uno::UNO_QUERY);
                        if (!xCell)
                            continue;
                        auto xEnumeration = xCell->createEnumeration();
                        while (xEnumeration->hasMoreElements())
                        {
                            if (css::uno::Reference<css::text::XTextTable> xInnerTable{
                                    xEnumeration->nextElement(), css::uno::UNO_QUERY })
                                exportTable(xInnerTable, bAutoStyles, _bProgress);
                        }
                    }
                    CollectTableLinesAutoStyles(pTable->GetTabLines(), *pFormat, _bProgress);
                }
            }
            else
diff --git a/sw/source/filter/xml/xmltexte.hxx b/sw/source/filter/xml/xmltexte.hxx
index 65f2604..09ce6c4 100644
--- a/sw/source/filter/xml/xmltexte.hxx
+++ b/sw/source/filter/xml/xmltexte.hxx
@@ -32,6 +32,7 @@ class SwXMLExport;
class SvXMLAutoStylePoolP;
class SwNoTextNode;
class SwTableNode;
class SwTableLines;
namespace com::sun::star::style { class XStyle; }

class SwXMLTextParagraphExport : public XMLTextParagraphExport
@@ -50,6 +51,9 @@ private:
    static SwNoTextNode *GetNoTextNode(
        const css::uno::Reference < css::beans::XPropertySet >& rPropSet );

    void CollectTableLinesAutoStyles(const SwTableLines& rLines, SwFrameFormat& rFormat,
                                     bool bProgress);

protected:
    virtual void _collectTextEmbeddedAutoStyles(
        const css::uno::Reference< css::beans::XPropertySet > & rPropSet ) override;
diff --git a/xmloff/source/text/txtparae.cxx b/xmloff/source/text/txtparae.cxx
index cf1a84b..3612bbe 100644
--- a/xmloff/source/text/txtparae.cxx
+++ b/xmloff/source/text/txtparae.cxx
@@ -2531,11 +2531,13 @@ void XMLTextParagraphExport::exportTextRangeEnumeration(
            }
            else if (sType == gsSoftPageBreak)
            {
                exportSoftPageBreak();
                if (!bAutoStyles)
                    exportSoftPageBreak();
            }
            else if (sType == "LineBreak")
            {
                exportTextLineBreak(xPropSet);
                if (!bAutoStyles)
                    exportTextLineBreak(xPropSet);
            }
            else {
                OSL_FAIL("unknown text portion type");