Fix: Use correct relative table width in docx export

It removes the HACK where the doc model was changed.
We introduce a pointer to a surrounding frame: an indicator
telling us that the table was placed in a frame to make it
floating.

During export, remove the frame and use the relative width of the
surrounding frame.

Change-Id: I43b45d9a9e67ee755782c9f18df22ae1d4014689
Reviewed-on: https://gerrit.libreoffice.org/67775
Tested-by: Jenkins
Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
(cherry picked from commit 167d4a9920b5858c3fc8cfb2a34b4f6dc5d5676a)
Reviewed-on: https://gerrit.libreoffice.org/68306
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
index c45bf3e..9c470e6 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
@@ -61,6 +61,15 @@ DECLARE_OOXMLEXPORT_TEST(testTdf121867, "tdf121867.odt")
    CPPUNIT_ASSERT_EQUAL(SvxZoomType::PAGEWIDTH, pEditShell->GetViewOptions()->GetZoomType());
}

DECLARE_OOXMLEXPORT_TEST(testFrameSizeExport, "floating-tables-anchor.docx")
{
    // Make sure the table width is 4000
    xmlDocPtr pXmlDoc = parseExport("word/document.xml");
    if (!pXmlDoc)
        return;
    assertXPath(pXmlDoc, "/w:document/w:body/w:tbl[1]/w:tblPr/w:tblW", "w", "4000");
}

CPPUNIT_PLUGIN_IMPLEMENT();

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/qa/extras/uiwriter/data2/frame_size_export.docx b/sw/qa/extras/uiwriter/data2/frame_size_export.docx
new file mode 100644
index 0000000..86147f3
--- /dev/null
+++ b/sw/qa/extras/uiwriter/data2/frame_size_export.docx
Binary files differ
diff --git a/sw/qa/extras/uiwriter/uiwriter2.cxx b/sw/qa/extras/uiwriter/uiwriter2.cxx
index dbc3b73..c0d4fdd 100644
--- a/sw/qa/extras/uiwriter/uiwriter2.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter2.cxx
@@ -42,6 +42,7 @@ public:
    void testTdf119824();
    void testTdf105413();
    void testTdf101873();
    void testTableWidth();

    CPPUNIT_TEST_SUITE(SwUiWriterTest2);
    CPPUNIT_TEST(testRedlineMoveInsertInDelete);
@@ -54,6 +55,7 @@ public:
    CPPUNIT_TEST(testTdf119824);
    CPPUNIT_TEST(testTdf105413);
    CPPUNIT_TEST(testTdf101873);
    CPPUNIT_TEST(testTableWidth);
    CPPUNIT_TEST_SUITE_END();

private:
@@ -478,6 +480,23 @@ void SwUiWriterTest2::testTdf101873()
    CPPUNIT_ASSERT_EQUAL(OUString("something"), pShellCursor->GetText());
}

void SwUiWriterTest2::testTableWidth()
{
    load(DATA_DIRECTORY, "frame_size_export.docx");

    uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
    utl::MediaDescriptor aMediaDescriptor;
    aMediaDescriptor["FilterName"] <<= OUString("Office Open XML Text");
    xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());

    // after exporting: table width was overwritten in the doc model
    uno::Reference<text::XTextTablesSupplier> xTablesSupplier(mxComponent, uno::UNO_QUERY);
    uno::Reference<container::XIndexAccess> xTables(xTablesSupplier->getTextTables(),
                                                    uno::UNO_QUERY);
    CPPUNIT_ASSERT_EQUAL(sal_Int16(100),
                         getProperty<sal_Int16>(xTables->getByIndex(0), "RelativeWidth"));
}

CPPUNIT_TEST_SUITE_REGISTRATION(SwUiWriterTest2);

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 4f17e40..9447215 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -329,10 +329,14 @@ void DocxAttributeOutput::WriteFloatingTable(ww8::Frame const* pParentFrame)
    //Save data here and restore when out of scope
    ExportDataSaveRestore aDataGuard(GetExport(), nStt, nEnd, pParentFrame);

    // unset parent frame, otherwise exporter thinks we are still in a frame
    // set a floatingTableFrame AND unset parent frame,
    // otherwise exporter thinks we are still in a frame
    m_rExport.SetFloatingTableFrame(pParentFrame);
    m_rExport.m_pParentFrame = nullptr;

    GetExport().WriteText();

    m_rExport.SetFloatingTableFrame(nullptr);
}

static void checkAndWriteFloatingTables(DocxAttributeOutput& rDocxAttributeOutput)
@@ -382,15 +386,7 @@ static void checkAndWriteFloatingTables(DocxAttributeOutput& rDocxAttributeOutpu
        if (aTableGrabBag.find("TablePosition") == aTableGrabBag.end())
            continue;

        // overwrite the table size from the surrounding frame format
        // TODO remove this de-const HACK
        const SwFormatFrameSize& aFramesize = pFrameFormat->GetFrameSize();
        SwFormatFrameSize* pFormatFrameSize = const_cast<SwFormatFrameSize*>(&pTableFormat->GetFrameSize());
        if(pFormatFrameSize)
        {
            *pFormatFrameSize = aFramesize;
        }

        // write table to docx
        ww8::Frame aFrame(*pFrameFormat,*pPosition);
        rDocxAttributeOutput.WriteFloatingTable(&aFrame);
    }
@@ -3704,6 +3700,13 @@ void DocxAttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t
    SwFrameFormat *pTableFormat = pTable->GetFrameFormat( );
    const SwFormatFrameSize &rSize = pTableFormat->GetFrameSize();
    int nWidthPercent = rSize.GetWidthPercent();
    // If we export a floating table: we use the widthPercent of the surrounding frame
    const ww8::Frame* pFloatingTableFrame = m_rExport.GetFloatingTableFrame();
    if (pFloatingTableFrame)
    {
        const SwFormatFrameSize &rFrameSize = pFloatingTableFrame->GetFrameFormat().GetFrameSize();
        nWidthPercent = rFrameSize.GetWidthPercent();
    }
    uno::Reference<beans::XPropertySet> xPropertySet(SwXTextTables::GetObject(*pTable->GetFrameFormat( )),uno::UNO_QUERY);
    bool isWidthRelative = false;
    xPropertySet->getPropertyValue("IsWidthRelative") >>= isWidthRelative;
diff --git a/sw/source/filter/ww8/docxexport.hxx b/sw/source/filter/ww8/docxexport.hxx
index f237460..011d7e1 100644
--- a/sw/source/filter/ww8/docxexport.hxx
+++ b/sw/source/filter/ww8/docxexport.hxx
@@ -110,11 +110,16 @@ class DocxExport : public MSWordExportBase

    DocxSettingsData m_aSettings;

    /// Pointer to the Frame of a floating table it is nested in
    const ww8::Frame *m_pFloatingTableFrame = nullptr;

public:

    DocxExportFilter& GetFilter() { return *m_pFilter; };
    const DocxExportFilter& GetFilter() const { return *m_pFilter; };

    const ww8::Frame* GetFloatingTableFrame() { return m_pFloatingTableFrame; }

    /// Access to the attribute output class.
    virtual AttributeOutputBase& AttrOutput() const override;

@@ -284,6 +289,8 @@ public:

    void SetFS(::sax_fastparser::FSHelperPtr const & mpFS);

    void SetFloatingTableFrame(const ww8::Frame* pF) { m_pFloatingTableFrame = pF; }

private:
    DocxExport( const DocxExport& ) = delete;