[Libreoffice-commits] core.git: sw/qa sw/source writerfilter/source

László Németh (via logerrit) logerrit at kemper.freedesktop.org
Sun Mar 28 12:49:46 UTC 2021


 sw/qa/extras/odfexport/data/tdf95806.docx                |binary
 sw/qa/extras/odfexport/odfexport.cxx                     |   17 ++++
 sw/qa/extras/ooxmlexport/data/tdf141172.docx             |binary
 sw/qa/extras/ooxmlexport/ooxmlexport14.cxx               |    8 +
 sw/source/filter/ww8/docxattributeoutput.cxx             |    5 -
 writerfilter/source/dmapper/DomainMapperTableHandler.cxx |   61 ++++++++++++++-
 writerfilter/source/dmapper/DomainMapperTableHandler.hxx |    4 
 writerfilter/source/dmapper/DomainMapper_Impl.hxx        |    7 +
 writerfilter/source/dmapper/PropertyMap.cxx              |    8 +
 9 files changed, 101 insertions(+), 9 deletions(-)

New commits:
commit e11c51eefe8c3210cef2b5850f401ba67a401d01
Author:     László Németh <nemeth at numbertext.org>
AuthorDate: Fri Mar 26 16:28:03 2021 +0100
Commit:     László Németh <nemeth at numbertext.org>
CommitDate: Sun Mar 28 14:49:08 2021 +0200

    tdf#95806 tdf#125877 tdf#141172 DOCX: fix tables in footnotes
    
    and endnotes by converting them to floating tables during the
    import, and removing floating at the DOCX export.
    
    Writer core doesn't support non-floating tables in footnotes
    and endnotes officially, (flowfrm:cxx: "Tables in footnotes
    are not truly supported"), so their DOCX import resulted
    serious problems:
    
    – missing table paint (tdf#95806);
    
    – table loss during saving to ODT (tdf#125877);
    
    – table loss during copying them or their footnotes and
      endnotes in the document (this resulted the regression
      of the optimized footnote and endnote import: tdf#141172);
    
    – table loss during changing the order of the chapters in
      the Navigator.
    
    Change-Id: Ife8af41936ae3ab003a3a9ad33b98c1d813e9c82
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/113162
    Tested-by: László Németh <nemeth at numbertext.org>
    Reviewed-by: László Németh <nemeth at numbertext.org>

diff --git a/sw/qa/extras/odfexport/data/tdf95806.docx b/sw/qa/extras/odfexport/data/tdf95806.docx
new file mode 100644
index 000000000000..65bfaae3e423
Binary files /dev/null and b/sw/qa/extras/odfexport/data/tdf95806.docx differ
diff --git a/sw/qa/extras/odfexport/odfexport.cxx b/sw/qa/extras/odfexport/odfexport.cxx
index 841019b3073b..f570e9f5d40a 100644
--- a/sw/qa/extras/odfexport/odfexport.cxx
+++ b/sw/qa/extras/odfexport/odfexport.cxx
@@ -263,6 +263,23 @@ DECLARE_ODFEXPORT_TEST(testTdf139126, "tdf139126.odt")
     CPPUNIT_ASSERT_EQUAL(OUString("** Expression is faulty **"), xE2->getString());
 }
 
+DECLARE_ODFEXPORT_TEST(testTdf125877, "tdf95806.docx")
+{
+    CPPUNIT_ASSERT_EQUAL(1, getPages());
+    uno::Reference<text::XTextTablesSupplier> xSupplier(mxComponent, uno::UNO_QUERY);
+    uno::Reference<container::XIndexAccess> xTables(xSupplier->getTextTables(), uno::UNO_QUERY);
+    uno::Reference<text::XTextTablesSupplier> xTextTablesSupplier(mxComponent, uno::UNO_QUERY);
+
+    // This was 0 (lost table during ODT export in footnotes)
+    // Note: fix also tdf#95806: painting table layout is correct
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xTables->getCount());
+
+    // floating table: there is a frame now
+    uno::Reference<text::XTextFramesSupplier> xTextFramesSupplier(mxComponent, uno::UNO_QUERY);
+    uno::Reference<container::XIndexAccess> xIndexAccess(xTextFramesSupplier->getTextFrames(), uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(1), xIndexAccess->getCount());
+}
+
 DECLARE_ODFEXPORT_TEST(testTdf103567, "tdf103567.odt")
 {
     CPPUNIT_ASSERT_EQUAL(1, getShapes());
diff --git a/sw/qa/extras/ooxmlexport/data/tdf141172.docx b/sw/qa/extras/ooxmlexport/data/tdf141172.docx
new file mode 100644
index 000000000000..0e1647ae27e1
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf141172.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
index 77fcb3fd1091..cd3ca2f39e46 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
@@ -1169,6 +1169,14 @@ DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf123757, "tdf123757.docx")
     assertXPath(pXml, "/w:document/w:body/w:tbl", 2);
 }
 
+DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf141172, "tdf141172.docx")
+{
+    xmlDocUniquePtr pXml = parseExport("word/endnotes.xml");
+    CPPUNIT_ASSERT(pXml);
+    // This was 1 (lost table during copying endnote content)
+    assertXPath(pXml, "/w:endnotes/w:endnote/w:tbl", 2);
+}
+
 DECLARE_OOXMLEXPORT_TEST(testContSectBreakHeaderFooter, "cont-sect-break-header-footer.docx")
 {
     // Load a document with a continuous section break on page 2.
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index 4b9c72829c3b..f4688e5f6a01 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -3982,7 +3982,10 @@ void DocxAttributeOutput::TableDefinition( ww8::WW8TableNodeInfoInner::Pointer_t
 
             m_pSerializer->singleElementNS(XML_w, XML_tblLook, pAttributeList);
         }
-        else if (rGrabBagElement.first == "TablePosition" )
+        else if (rGrabBagElement.first == "TablePosition" &&
+                        // skip empty table position (tables in footnotes converted to
+                        // floating tables temporarily, don't export this)
+                        rGrabBagElement.second != uno::Any() )
         {
             rtl::Reference<FastAttributeList> attrListTablePos = FastSerializerHelper::createAttrList( );
             const uno::Sequence<beans::PropertyValue> aTablePosition = rGrabBagElement.second.get<uno::Sequence<beans::PropertyValue> >();
diff --git a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
index fd21827211bb..55c48740f0ec 100644
--- a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
+++ b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
@@ -32,6 +32,7 @@
 #include <com/sun/star/table/XCellRange.hpp>
 #include <com/sun/star/text/HoriOrientation.hpp>
 #include <com/sun/star/text/SizeType.hpp>
+#include <com/sun/star/text/TextContentAnchorType.hpp>
 #include <com/sun/star/text/XTextField.hpp>
 #include <com/sun/star/text/XTextRangeCompare.hpp>
 #include <com/sun/star/beans/XPropertySet.hpp>
@@ -339,9 +340,43 @@ void lcl_adjustBorderDistance(TableInfo& rInfo, const table::BorderLine2& rLeftB
     rInfo.nRightBorderDistance = nActualR;
 }
 
+void lcl_fillEmptyFrameProperties(std::vector<beans::PropertyValue>& rFrameProperties)
+{
+    // fill empty frame properties to create an invisible frame around the table:
+    // hide frame borders and zero inner and outer frame margins
+    beans::PropertyValue aValue;
+    aValue.Name = getPropertyName( PROP_ANCHOR_TYPE );
+    aValue.Value <<= text::TextContentAnchorType_AS_CHARACTER;
+    rFrameProperties.push_back(aValue);
+
+    table::BorderLine2 aEmptyBorder;
+    static const std::vector<std::u16string_view> aBorderNames
+        = { u"TopBorder", u"LeftBorder", u"BottomBorder", u"RightBorder" };
+    for (size_t i = 0; i < aBorderNames.size(); ++i)
+    {
+        beans::PropertyValue aBorderValue;
+        aBorderValue.Name = aBorderNames[i];
+        aBorderValue.Value <<= aEmptyBorder;
+        rFrameProperties.push_back(aBorderValue);
+    }
+    static const std::vector<std::u16string_view> aMarginNames
+        = { u"TopBorderDistance", u"LeftBorderDistance",
+            u"BottomBorderDistance", u"RightBorderDistance",
+            u"TopMargin", u"LeftMargin", u"BottomMargin", u"RightMargin" };
+    for (size_t i = 0; i < aMarginNames.size(); ++i)
+    {
+        beans::PropertyValue aMarginValue;
+        aMarginValue.Name = aMarginNames[i];
+        aMarginValue.Value <<= sal_Int32(10);
+        rFrameProperties.push_back(aMarginValue);
+    }
+}
+
 }
 
-TableStyleSheetEntry * DomainMapperTableHandler::endTableGetTableStyle(TableInfo & rInfo, std::vector<beans::PropertyValue>& rFrameProperties)
+TableStyleSheetEntry * DomainMapperTableHandler::endTableGetTableStyle(TableInfo & rInfo,
+                std::vector<beans::PropertyValue>& rFrameProperties,
+                bool bConvertToFloatingInFootnote)
 {
     // will receive the table style if any
     TableStyleSheetEntry* pTableStyle = nullptr;
@@ -394,6 +429,11 @@ TableStyleSheetEntry * DomainMapperTableHandler::endTableGetTableStyle(TableInfo
 
             aGrabBag["TablePosition"] <<= aGrabBagTS;
         }
+        else if (bConvertToFloatingInFootnote)
+        {
+            // define empty "TablePosition" to avoid export temporary floating
+            aGrabBag["TablePosition"] = uno::Any();
+        }
 
         std::optional<PropertyMap::Property> aTableStyleVal = m_aTableProperties->getProperty(META_PROP_TABLE_STYLE_NAME);
         if(aTableStyleVal)
@@ -1375,7 +1415,15 @@ void DomainMapperTableHandler::endTable(unsigned int nestedTableLevel, bool bTab
             (m_rDMapper_Impl.getTableManager().getCurrentTablePosition());
     TableInfo aTableInfo;
     aTableInfo.nNestLevel = nestedTableLevel;
-    aTableInfo.pTableStyle = endTableGetTableStyle(aTableInfo, aFrameProperties);
+
+    // non-floating tables need floating in footnotes and endnotes, because
+    // Writer core cannot handle (i.e. save in ODT, copy, edit etc.) them otherwise
+    bool bConvertToFloating = aFrameProperties.empty() &&
+            nestedTableLevel <= 1 &&
+            m_rDMapper_Impl.IsInFootOrEndnote();
+    bool bFloating = !aFrameProperties.empty() || bConvertToFloating;
+
+    aTableInfo.pTableStyle = endTableGetTableStyle(aTableInfo, aFrameProperties, bConvertToFloating);
     //  expands to uno::Sequence< Sequence< beans::PropertyValues > >
 
     std::vector<HorizontallyMergedCell> aMerges;
@@ -1392,7 +1440,8 @@ void DomainMapperTableHandler::endTable(unsigned int nestedTableLevel, bool bTab
         uno::Reference<text::XTextRange> xStart;
         uno::Reference<text::XTextRange> xEnd;
 
-        bool bFloating = !aFrameProperties.empty();
+        if ( bConvertToFloating )
+            lcl_fillEmptyFrameProperties(aFrameProperties);
 
         // OOXML table style may contain paragraph properties, apply these on cell paragraphs
         if ( m_aTableRanges[0].hasElements() && m_aTableRanges[0][0].hasElements() )
@@ -1585,7 +1634,11 @@ void DomainMapperTableHandler::endTable(unsigned int nestedTableLevel, bool bTab
             sal_Int32 nTableWidthType = text::SizeType::FIX;
             m_aTableProperties->getValue(TablePropertyMap::TABLE_WIDTH_TYPE, nTableWidthType);
             if (m_rDMapper_Impl.GetSectionContext() && nestedTableLevel <= 1 && !m_rDMapper_Impl.IsInHeaderFooter())
-                m_rDMapper_Impl.m_aPendingFloatingTables.emplace_back(xStart, xEnd, comphelper::containerToSequence(aFrameProperties), nTableWidth, nTableWidthType);
+            {
+                m_rDMapper_Impl.m_aPendingFloatingTables.emplace_back(xStart, xEnd,
+                                comphelper::containerToSequence(aFrameProperties),
+                                nTableWidth, nTableWidthType, bConvertToFloating);
+            }
             else
             {
                 // m_xText points to the body text, get the current xText from m_rDMapper_Impl, in case e.g. we would be in a header.
diff --git a/writerfilter/source/dmapper/DomainMapperTableHandler.hxx b/writerfilter/source/dmapper/DomainMapperTableHandler.hxx
index 900ff747f4cc..5a2a37acd90f 100644
--- a/writerfilter/source/dmapper/DomainMapperTableHandler.hxx
+++ b/writerfilter/source/dmapper/DomainMapperTableHandler.hxx
@@ -70,7 +70,9 @@ class DomainMapperTableHandler final : public virtual SvRefBase
     /// Did we have a foot or endnote in this table?
     bool m_bHadFootOrEndnote;
 
-    TableStyleSheetEntry * endTableGetTableStyle(TableInfo & rInfo, std::vector<css::beans::PropertyValue>& rFrameProperties);
+    TableStyleSheetEntry * endTableGetTableStyle(TableInfo & rInfo,
+                    std::vector<css::beans::PropertyValue>& rFrameProperties,
+                    bool bConvertToFloating);
     CellPropertyValuesSeq_t endTableGetCellProperties(TableInfo & rInfo, std::vector<HorizontallyMergedCell>& rMerges);
     css::uno::Sequence<css::beans::PropertyValues> endTableGetRowProperties();
 
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index 6aa33913d924..1b29e96cbc27 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -395,16 +395,19 @@ struct FloatingTableInfo
     sal_Int32 m_nTableWidthType;
     /// Break type of the section that contains this table.
     sal_Int32 m_nBreakType = -1;
+    /// Tables in footnotes and endnotes are always floating
+    bool m_bConvertToFloatingInFootnote = false;
 
     FloatingTableInfo(css::uno::Reference<css::text::XTextRange> const& xStart,
             css::uno::Reference<css::text::XTextRange> const& xEnd,
             const css::uno::Sequence<css::beans::PropertyValue>& aFrameProperties,
-            sal_Int32 nTableWidth, sal_Int32 nTableWidthType)
+            sal_Int32 nTableWidth, sal_Int32 nTableWidthType, bool bConvertToFloatingInFootnote)
         : m_xStart(xStart),
         m_xEnd(xEnd),
         m_aFrameProperties(aFrameProperties),
         m_nTableWidth(nTableWidth),
-        m_nTableWidthType(nTableWidthType)
+        m_nTableWidthType(nTableWidthType),
+        m_bConvertToFloatingInFootnote(bConvertToFloatingInFootnote)
     {
     }
     css::uno::Any getPropertyValue(std::u16string_view propertyName);
diff --git a/writerfilter/source/dmapper/PropertyMap.cxx b/writerfilter/source/dmapper/PropertyMap.cxx
index f7a8f800d7d0..cc556ddc6330 100644
--- a/writerfilter/source/dmapper/PropertyMap.cxx
+++ b/writerfilter/source/dmapper/PropertyMap.cxx
@@ -1138,6 +1138,9 @@ void SectionPropertyMap::HandleMarginsHeaderFooter( bool bFirstPage, DomainMappe
 
 bool SectionPropertyMap::FloatingTableConversion( const DomainMapper_Impl& rDM_Impl, FloatingTableInfo& rInfo )
 {
+    // always convert non-floating tables to floating ones in footnotes and endnotes
+    if ( rInfo.m_bConvertToFloatingInFootnote )
+        return true;
     // This is OOXML version of the code deciding if the table needs to be
     // in a floating frame.
     // For ww8 code, see SwWW8ImplReader::FloatingTableConversion in
@@ -1388,12 +1391,15 @@ void SectionPropertyMap::CloseSectionGroup( DomainMapper_Impl& rDM_Impl )
 
     // Text area width is known at the end of a section: decide if tables should be converted or not.
     std::vector<FloatingTableInfo>& rPendingFloatingTables = rDM_Impl.m_aPendingFloatingTables;
-    uno::Reference<text::XTextAppendAndConvert> xBodyText( rDM_Impl.GetBodyText(), uno::UNO_QUERY );
     for ( FloatingTableInfo & rInfo : rPendingFloatingTables )
     {
         rInfo.m_nBreakType = m_nBreakType;
         if ( FloatingTableConversion( rDM_Impl, rInfo ) )
         {
+            uno::Reference<text::XTextAppendAndConvert> xBodyText(
+                            rInfo.m_bConvertToFloatingInFootnote
+                                ? rInfo.m_xStart->getText()
+                                : rDM_Impl.GetBodyText(), uno::UNO_QUERY );
             std::deque<css::uno::Any> aFramedRedlines = rDM_Impl.m_aStoredRedlines[StoredRedlines::FRAME];
             try
             {


More information about the Libreoffice-commits mailing list