sw/qa/core/unocore/data/floattable-split.docx |binary
 sw/qa/core/unocore/unocore.cxx                |   19 +++++++++++++++++++
 sw/source/core/inc/flyfrm.hxx                 |    3 +++
 sw/source/core/layout/fly.cxx                 |    5 +++++
 sw/source/core/unocore/unoobj2.cxx            |   18 ++++++++++++++++++
 5 files changed, 45 insertions(+)

New commits:
commit 140ebce3b81a09d163c34ae792d090154302c8e7
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Jul 31 08:24:03 2023 +0200
Commit:     Mike Kaganski <mike.kagan...@collabora.com>
CommitDate: Wed Aug 2 08:11:09 2023 +0200

    tdf#156350 sw floattable: fix bad additional <draw:frame> in ODT with layout
    
    The document has a floating table, split on two pages. Saving as ODT
    creates two <draw:frame> elements, while we only expect one.
    
    The document model is correct, SwDoc::mpSpzFrameFormatTable only
    contains one frame, and in general the ODT export works with the SwDoc,
    but CollectFrameAtNode() uses the layout to help performance, and the
    layout is available when saving interactively (i.e. not --convert-to),
    which visits both layout frames of the same frame format.
    
    Fix the problem by ignoring follow fly frames in
    lcl_CollectFrameAtNodeWithLayout(), just working from master should
    ensure there is no duplication.
    
    This is similar to 4721729fba32a02683ecc930b630491599f8c6c5
    (SwXParaFrameEnumeration: ignore textboxes, 2014-05-27), but that was
    for fly frames of draw shapes, and this is for split flys.
    
    Change-Id: I09729c0b0f9afd694e3cbf8886ccbc530bfc9674
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155081
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins
    (cherry picked from commit 2b401b7c0322d9ff972d252208ebe9a77913778d)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/155136
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>

diff --git a/sw/qa/core/unocore/data/floattable-split.docx 
b/sw/qa/core/unocore/data/floattable-split.docx
new file mode 100644
index 000000000000..2e2c9c705df9
Binary files /dev/null and b/sw/qa/core/unocore/data/floattable-split.docx 
differ
diff --git a/sw/qa/core/unocore/unocore.cxx b/sw/qa/core/unocore/unocore.cxx
index 199da2e72a79..cb6f52d0fdbb 100644
--- a/sw/qa/core/unocore/unocore.cxx
+++ b/sw/qa/core/unocore/unocore.cxx
@@ -965,6 +965,25 @@ CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testTdf155951)
     xText->insertString(xCursor, "test", /*bAbsorb=*/false);
 }
 
+CPPUNIT_TEST_FIXTURE(SwCoreUnocoreTest, testCollectFrameAtNodeWithLayout)
+{
+    // Given a document with a floating table on 2 pages, with a calculated 
layout:
+    createSwDoc("floattable-split.docx");
+    calcLayout();
+
+    // When saving to ODT:
+    save("writer8");
+
+    // Then make sure the output is valid and hasa 1 <draw:frame>:
+    // Without the accompanying fix in place, this test would have failed with:
+    // Error: uncompleted content model.
+    // i.e. the output was not valid, the second <draw:frame> has an empty 
<table:table> as a child
+    // element.
+    xmlDocUniquePtr pXmlDoc = parseExport("content.xml");
+    // Also make sure that we don't have multiple <draw:frame> elements in the 
first place.
+    assertXPath(pXmlDoc, "//draw:frame", 1);
+}
+
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/inc/flyfrm.hxx b/sw/source/core/inc/flyfrm.hxx
index d3815a82835a..4b47f0ad2b4e 100644
--- a/sw/source/core/inc/flyfrm.hxx
+++ b/sw/source/core/inc/flyfrm.hxx
@@ -38,6 +38,7 @@ class SwFormat;
 class SwViewShell;
 class SwFEShell;
 class SwWrtShell;
+class SwFlyAtContentFrame;
 
 
 /** search an anchor for paragraph bound frames starting from pOldAnch
@@ -307,6 +308,8 @@ public:
     virtual const SwFlyFrame* DynCastFlyFrame() const override;
     virtual SwFlyFrame* DynCastFlyFrame() override;
 
+    SwFlyAtContentFrame* DynCastFlyAtContentFrame();
+
 private:
     void UpdateUnfloatButton(SwWrtShell* pWrtSh, bool bShow) const;
     void PaintDecorators() const;
diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index 68184da48fd6..a365668c4ce2 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -2100,6 +2100,11 @@ void SwFlyFrame::UpdateUnfloatButton(SwWrtShell* pWrtSh, 
bool bShow) const
     rMngr.SetUnfloatTableButton(this, bShow,  aTopRightPixel);
 }
 
+SwFlyAtContentFrame* SwFlyFrame::DynCastFlyAtContentFrame()
+{
+    return IsFlyAtContentFrame() ? static_cast<SwFlyAtContentFrame*>(this) : 
nullptr;
+}
+
 SwTwips SwFlyFrame::Grow_( SwTwips nDist, bool bTst )
 {
     SwRectFnSet aRectFnSet(this);
diff --git a/sw/source/core/unocore/unoobj2.cxx 
b/sw/source/core/unocore/unoobj2.cxx
index 01682ef48587..472babcd8243 100644
--- a/sw/source/core/unocore/unoobj2.cxx
+++ b/sw/source/core/unocore/unoobj2.cxx
@@ -48,6 +48,8 @@
 #include <docsh.hxx>
 #include <pagedesc.hxx>
 #include <cntfrm.hxx>
+#include <flyfrm.hxx>
+#include <flyfrms.hxx>
 #include <unoparaframeenum.hxx>
 #include <unofootnote.hxx>
 #include <unotextbodyhf.hxx>
@@ -123,6 +125,22 @@ struct FrameClientSortListLess
             // Filter out textboxes, which are not interesting at a UNO level.
             if(SwTextBoxHelper::isTextBox(&rFormat, RES_FLYFRMFMT))
                 continue;
+
+            if (nAnchorType == RndStdIds::FLY_AT_PARA)
+            {
+                SwFlyFrame* pFly = pAnchoredObj->DynCastFlyFrame();
+                if (pFly)
+                {
+                    auto pFlyAtContentFrame = pFly->DynCastFlyAtContentFrame();
+                    if (pFlyAtContentFrame && pFlyAtContentFrame->IsFollow())
+                    {
+                        // We're collecting frame formats, ignore non-master 
fly frames to prevent
+                        // duplication.
+                        continue;
+                    }
+                }
+            }
+
             if(rFormat.GetAnchor().GetAnchorId() == nAnchorType)
             {
                 const sal_Int32 nIdx = 
rFormat.GetAnchor().GetAnchorContentOffset();

Reply via email to