writerfilter/CppunitTest_writerfilter_rtftok.mk             |    1 
 writerfilter/qa/cppunittests/rtftok/data/floating-table.rtf |   10 +
 writerfilter/qa/cppunittests/rtftok/rtfdispatchflag.cxx     |   70 ++++++++
 writerfilter/source/rtftok/rtfdispatchflag.cxx              |   97 ++++++++++++
 writerfilter/source/rtftok/rtfdispatchvalue.cxx             |   66 ++++++++
 writerfilter/source/rtftok/rtfdocumentimpl.hxx              |    5 
 6 files changed, 249 insertions(+)

New commits:
commit 05425f73bfa41d3f7591461e2ad0beb4fafc39b4
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri Apr 21 07:05:26 2023 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Apr 21 08:21:45 2023 +0200

    sw floatable: teach the RTF import about SwFormatFlySplit
    
    - if the document has no \nobrkwrptbl, then ignore all floating table
      control word for now
    
    - map the rest of the RTF control words to OOXML attributes under the
      NS_ooxml::LN_CT_TblPrBase_tblpPr sprm:
    
     - \tpv{para,mrg,pg} -> NS_ooxml::LN_CT_TblPPr_vertAnchor
    
     - \tph{col,mrg,pg} -> NS_ooxml::LN_CT_TblPPr_horzAnchor
    
     - \tposy -> NS_ooxml::LN_CT_TblPPr_tblpY
    
     - \tposy{c,b} -> NS_ooxml::LN_CT_TblPPr_tblpYSpec
    
     - \tposx -> NS_ooxml::LN_CT_TblPPr_tblpX
    
     - \tposx{c,r} -> NS_ooxml::LN_CT_TblPPr_tblpXSpec
    
     - \tdfrmtxtLeft -> NS_ooxml::LN_CT_TblPPr_leftFromText
    
     - \tdfrmtxtRight -> NS_ooxml::LN_CT_TblPPr_rightFromText
    
     - \tdfrmtxtTop -> NS_ooxml::LN_CT_TblPPr_topFromText
    
     - \tdfrmtxtBottom -> NS_ooxml::LN_CT_TblPPr_bottomFromText
    
    Change-Id: I0b30d0eba8c1b7b6d3497334c958146717d06552
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/150738
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/writerfilter/CppunitTest_writerfilter_rtftok.mk 
b/writerfilter/CppunitTest_writerfilter_rtftok.mk
index 990aa6596d3d..2c91cbb8cb2f 100644
--- a/writerfilter/CppunitTest_writerfilter_rtftok.mk
+++ b/writerfilter/CppunitTest_writerfilter_rtftok.mk
@@ -16,6 +16,7 @@ $(eval $(call 
gb_CppunitTest_use_externals,writerfilter_rtftok,\
 ))
 
 $(eval $(call gb_CppunitTest_add_exception_objects,writerfilter_rtftok, \
+    writerfilter/qa/cppunittests/rtftok/rtfdispatchflag \
     writerfilter/qa/cppunittests/rtftok/rtfdispatchsymbol \
     writerfilter/qa/cppunittests/rtftok/rtfdispatchvalue \
     writerfilter/qa/cppunittests/rtftok/rtfdocumentimpl \
diff --git a/writerfilter/qa/cppunittests/rtftok/data/floating-table.rtf 
b/writerfilter/qa/cppunittests/rtftok/data/floating-table.rtf
new file mode 100644
index 000000000000..b88664139070
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/data/floating-table.rtf
@@ -0,0 +1,10 @@
+{\rtf1
+\paperw12240\paperh6203\margl1440\margr1440\margt1440\margb1440\nobrkwrptbl
+\pard\plain First paragraph\par
+\pard\plain\intbl A1\cell
+\pard\plain\trowd\trrh1812\tpvpara\tphcol\tposy10\tposx20\tdfrmtxtLeft30\tdfrmtxtRight40\cellx3828\row
+\pard\plain\intbl A2\cell
+\pard\plain\trowd\trrh1812\tpvpara\tphcol\tposy10\tposx20\tdfrmtxtLeft30\tdfrmtxtRight40\cellx3828\row
+\pard\plain Second paragraph.
+\par
+}
diff --git a/writerfilter/qa/cppunittests/rtftok/rtfdispatchflag.cxx 
b/writerfilter/qa/cppunittests/rtftok/rtfdispatchflag.cxx
new file mode 100644
index 000000000000..810dc750d7d7
--- /dev/null
+++ b/writerfilter/qa/cppunittests/rtftok/rtfdispatchflag.cxx
@@ -0,0 +1,70 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/unoapi_test.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/text/RelOrientation.hpp>
+
+using namespace ::com::sun::star;
+
+namespace
+{
+/// Tests for writerfilter/source/rtftok/rtfdispatchflag.cxx.
+class Test : public UnoApiTest
+{
+public:
+    Test()
+        : UnoApiTest("/writerfilter/qa/cppunittests/rtftok/data/")
+    {
+    }
+};
+
+CPPUNIT_TEST_FIXTURE(Test, testFloatingTable)
+{
+    // Given a document with a floating table, when importing that document:
+    loadFromURL(u"floating-table.rtf");
+
+    // Then make sure the floating table is there & has the expected 
properties:
+    uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<drawing::XDrawPage> xDrawPage = 
xDrawPageSupplier->getDrawPage();
+    // Without the accompanying fix in place, this test would have failed with:
+    // An uncaught exception of type 
com.sun.star.lang.IndexOutOfBoundsException
+    // i.e. the table was not floating / was not in a fly frame.
+    uno::Reference<beans::XPropertySet> xFrame(xDrawPage->getByIndex(0), 
uno::UNO_QUERY);
+    bool bIsSplitAllowed{};
+    xFrame->getPropertyValue("IsSplitAllowed") >>= bIsSplitAllowed;
+    CPPUNIT_ASSERT(bIsSplitAllowed);
+    sal_Int16 nVertOrientRelation{};
+    xFrame->getPropertyValue("VertOrientRelation") >>= nVertOrientRelation;
+    CPPUNIT_ASSERT_EQUAL(text::RelOrientation::FRAME, nVertOrientRelation);
+    sal_Int16 nHoriOrientRelation{};
+    xFrame->getPropertyValue("HoriOrientRelation") >>= nHoriOrientRelation;
+    CPPUNIT_ASSERT_EQUAL(text::RelOrientation::FRAME, nHoriOrientRelation);
+    sal_Int32 nVertOrientPosition{};
+    xFrame->getPropertyValue("VertOrientPosition") >>= nVertOrientPosition;
+    sal_Int32 nExpected = o3tl::convert(10, o3tl::Length::twip, 
o3tl::Length::mm100);
+    CPPUNIT_ASSERT_EQUAL(nExpected, nVertOrientPosition);
+    sal_Int32 nHoriOrientPosition{};
+    xFrame->getPropertyValue("HoriOrientPosition") >>= nHoriOrientPosition;
+    nExpected = o3tl::convert(20, o3tl::Length::twip, o3tl::Length::mm100);
+    CPPUNIT_ASSERT_EQUAL(nExpected, nHoriOrientPosition);
+    sal_Int32 nLeftMargin{};
+    xFrame->getPropertyValue("LeftMargin") >>= nLeftMargin;
+    nExpected = o3tl::convert(30, o3tl::Length::twip, o3tl::Length::mm100);
+    CPPUNIT_ASSERT_EQUAL(nExpected, nLeftMargin);
+    sal_Int32 nRightMargin{};
+    xFrame->getPropertyValue("RightMargin") >>= nRightMargin;
+    nExpected = o3tl::convert(40, o3tl::Length::twip, o3tl::Length::mm100);
+    CPPUNIT_ASSERT_EQUAL(nExpected, nRightMargin);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/source/rtftok/rtfdispatchflag.cxx 
b/writerfilter/source/rtftok/rtfdispatchflag.cxx
index 0ef4f21729d6..bc3c3037e16d 100644
--- a/writerfilter/source/rtftok/rtfdispatchflag.cxx
+++ b/writerfilter/source/rtftok/rtfdispatchflag.cxx
@@ -32,6 +32,93 @@ using namespace com::sun::star;
 
 namespace writerfilter::rtftok
 {
+bool RTFDocumentImpl::dispatchFloatingTableFlag(RTFKeyword nKeyword)
+{
+    if (!m_bBreakWrappedTables)
+    {
+        return false;
+    }
+
+    // Positioned Wrapped Tables
+    OUString aParam;
+    switch (nKeyword)
+    {
+        case RTFKeyword::TPVPARA:
+            aParam = "text";
+            break;
+        case RTFKeyword::TPVMRG:
+            aParam = "margin";
+            break;
+        case RTFKeyword::TPVPG:
+            aParam = "page";
+            break;
+        default:
+            break;
+    }
+    if (!aParam.isEmpty())
+    {
+        putNestedAttribute(m_aStates.top().getTableRowSprms(), 
NS_ooxml::LN_CT_TblPrBase_tblpPr,
+                           NS_ooxml::LN_CT_TblPPr_vertAnchor, new 
RTFValue(aParam));
+        return true;
+    }
+    switch (nKeyword)
+    {
+        case RTFKeyword::TPHCOL:
+            aParam = "text";
+            break;
+        case RTFKeyword::TPHMRG:
+            aParam = "margin";
+            break;
+        case RTFKeyword::TPHPG:
+            aParam = "page";
+            break;
+        default:
+            break;
+    }
+    if (!aParam.isEmpty())
+    {
+        putNestedAttribute(m_aStates.top().getTableRowSprms(), 
NS_ooxml::LN_CT_TblPrBase_tblpPr,
+                           NS_ooxml::LN_CT_TblPPr_horzAnchor, new 
RTFValue(aParam));
+        return true;
+    }
+    switch (nKeyword)
+    {
+        case RTFKeyword::TPOSYC:
+            aParam = "center";
+            break;
+        case RTFKeyword::TPOSYB:
+            aParam = "bottom";
+            break;
+        default:
+            break;
+    }
+    if (!aParam.isEmpty())
+    {
+        putNestedAttribute(m_aStates.top().getTableRowSprms(), 
NS_ooxml::LN_CT_TblPrBase_tblpPr,
+                           NS_ooxml::LN_CT_TblPPr_tblpYSpec, new 
RTFValue(aParam));
+        return true;
+    }
+    switch (nKeyword)
+    {
+        case RTFKeyword::TPOSXC:
+            aParam = "center";
+            break;
+        case RTFKeyword::TPOSXR:
+            aParam = "right";
+            break;
+        default:
+            break;
+    }
+    if (!aParam.isEmpty())
+    {
+        putNestedAttribute(m_aStates.top().getTableRowSprms(), 
NS_ooxml::LN_CT_TblPrBase_tblpPr,
+                           NS_ooxml::LN_CT_TblPPr_tblpXSpec, new 
RTFValue(aParam));
+        return true;
+    }
+
+    return false;
+}
+
 RTFError RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword)
 {
     setNeedSect(true);
@@ -442,6 +529,11 @@ RTFError RTFDocumentImpl::dispatchFlag(RTFKeyword nKeyword)
         return RTFError::OK;
     }
 
+    if (dispatchFloatingTableFlag(nKeyword))
+    {
+        return RTFError::OK;
+    }
+
     switch (nKeyword)
     {
         case RTFKeyword::FNIL:
@@ -1243,6 +1335,11 @@ RTFError RTFDocumentImpl::dispatchFlag(RTFKeyword 
nKeyword)
                 m_aStates.top().setFieldLocked(true);
         }
         break;
+        case RTFKeyword::NOBRKWRPTBL:
+        {
+            m_bBreakWrappedTables = true;
+        }
+        break;
         default:
         {
             SAL_INFO("writerfilter", "TODO handle flag '" << 
keywordToString(nKeyword) << "'");
diff --git a/writerfilter/source/rtftok/rtfdispatchvalue.cxx 
b/writerfilter/source/rtftok/rtfdispatchvalue.cxx
index a56d8e00d819..f580ec69c5e9 100644
--- a/writerfilter/source/rtftok/rtfdispatchvalue.cxx
+++ b/writerfilter/source/rtftok/rtfdispatchvalue.cxx
@@ -1823,6 +1823,72 @@ RTFError RTFDocumentImpl::dispatchValue(RTFKeyword 
nKeyword, int nParam)
             }
         }
         break;
+        case RTFKeyword::TPOSY:
+        {
+            if (!m_bBreakWrappedTables)
+            {
+                break;
+            }
+
+            putNestedAttribute(m_aStates.top().getTableRowSprms(), 
NS_ooxml::LN_CT_TblPrBase_tblpPr,
+                               NS_ooxml::LN_CT_TblPPr_tblpY, new 
RTFValue(nParam));
+        }
+        break;
+        case RTFKeyword::TPOSX:
+        {
+            if (!m_bBreakWrappedTables)
+            {
+                break;
+            }
+
+            putNestedAttribute(m_aStates.top().getTableRowSprms(), 
NS_ooxml::LN_CT_TblPrBase_tblpPr,
+                               NS_ooxml::LN_CT_TblPPr_tblpX, new 
RTFValue(nParam));
+        }
+        break;
+        case RTFKeyword::TDFRMTXTLEFT:
+        {
+            if (!m_bBreakWrappedTables)
+            {
+                break;
+            }
+
+            putNestedAttribute(m_aStates.top().getTableRowSprms(), 
NS_ooxml::LN_CT_TblPrBase_tblpPr,
+                               NS_ooxml::LN_CT_TblPPr_leftFromText, new 
RTFValue(nParam));
+        }
+        break;
+        case RTFKeyword::TDFRMTXTRIGHT:
+        {
+            if (!m_bBreakWrappedTables)
+            {
+                break;
+            }
+
+            putNestedAttribute(m_aStates.top().getTableRowSprms(), 
NS_ooxml::LN_CT_TblPrBase_tblpPr,
+                               NS_ooxml::LN_CT_TblPPr_rightFromText, new 
RTFValue(nParam));
+        }
+        break;
+        case RTFKeyword::TDFRMTXTTOP:
+        {
+            if (!m_bBreakWrappedTables)
+            {
+                break;
+            }
+
+            putNestedAttribute(m_aStates.top().getTableRowSprms(), 
NS_ooxml::LN_CT_TblPrBase_tblpPr,
+                               NS_ooxml::LN_CT_TblPPr_topFromText, new 
RTFValue(nParam));
+        }
+        break;
+        case RTFKeyword::TDFRMTXTBOTTOM:
+        {
+            if (!m_bBreakWrappedTables)
+            {
+                break;
+            }
+
+            putNestedAttribute(m_aStates.top().getTableRowSprms(), 
NS_ooxml::LN_CT_TblPrBase_tblpPr,
+                               NS_ooxml::LN_CT_TblPPr_bottomFromText, new 
RTFValue(nParam));
+        }
+        break;
         default:
         {
             SAL_INFO("writerfilter", "TODO handle value '" << 
keywordToString(nKeyword) << "'");
diff --git a/writerfilter/source/rtftok/rtfdocumentimpl.hxx 
b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
index 71ecd06c8cd8..bf1ff2c30611 100644
--- a/writerfilter/source/rtftok/rtfdocumentimpl.hxx
+++ b/writerfilter/source/rtftok/rtfdocumentimpl.hxx
@@ -701,6 +701,8 @@ public:
     // RTFListener
     RTFError dispatchDestination(RTFKeyword nKeyword) override;
     RTFError dispatchFlag(RTFKeyword nKeyword) override;
+    /// Dispatches flags related to Positioned Wrapped Tables.
+    bool dispatchFloatingTableFlag(RTFKeyword nKeyword);
     RTFError dispatchSymbol(RTFKeyword nKeyword) override;
     RTFError dispatchToggle(RTFKeyword nKeyword, bool bParam, int nParam) 
override;
     RTFError dispatchValue(RTFKeyword nKeyword, int nParam) override;
@@ -989,6 +991,9 @@ private:
 
     /// Are we after a \cell, but before a \row?
     bool m_bAfterCellBeforeRow;
+
+    /// Floating tables are single-page by default.
+    bool m_bBreakWrappedTables = false;
 };
 } // namespace writerfilter::rtftok
 

Reply via email to