sw/qa/core/layout/data/floattable-nested-overlap.odt               |binary
 sw/qa/core/layout/flycnt.cxx                                       |   23 
+++++++++
 sw/qa/extras/ooxmlexport/data/floattable-nested.odt                |binary
 sw/qa/extras/ooxmlexport/ooxmlexport10.cxx                         |   17 
+++++++
 sw/source/core/layout/tabfrm.cxx                                   |   23 
+--------
 sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx |   24 
++++++++--
 sw/source/filter/ww8/docxattributeoutput.cxx                       |    5 +-
 7 files changed, 69 insertions(+), 23 deletions(-)

New commits:
commit ec69325afbedf3a28f90f5665c41bbe0f703ee4e
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Sep 12 08:42:31 2023 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Sep 14 08:10:17 2023 +0200

    sw floattable, nesting: fix DOCX export
    
    There were two problems here:
    
    1) DocxAttributeOutput::StartParagraph() didn't try to export an inner
       floating table as a floating table, resulting in writing a shape that
       can't span over multiple pages.
    
       Dropping the !pTextNodeInfo check should be OK, we'll just now
       clear the m_aFloatingTablesOfParagraph list at the end of the outer
       table.
    
    2) Once we tried to export the inner fly, the actual table/row/cell
       start was missing, because m_tableReference.m_nTableDepth wasn't
       reset, so DocxAttributeOutput::StartParagraph() didn't know it has to
       emit a table definition before the first para of the table.
    
       Fix this by stashing away the table state before the inner fly's
       export and restoring it after the inner fly export, similar to how this
       is done in e.g. DocxExport::WriteHeaderFooter().
    
    This is related to tdf#55160.
    
    (cherry picked from commit 2887e6b8edbb4fdb093515a3a68269ed40e42116)
    
    Change-Id: Ib860283d32e392e2906aa12bc9eb61b5af5ca8de
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156866
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/qa/extras/ooxmlexport/data/floattable-nested.odt 
b/sw/qa/extras/ooxmlexport/data/floattable-nested.odt
new file mode 100644
index 000000000000..8644412f60b6
Binary files /dev/null and 
b/sw/qa/extras/ooxmlexport/data/floattable-nested.odt differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
index c9bfc2e97d45..0f9e8c08d8a7 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport10.cxx
@@ -158,6 +158,23 @@ DECLARE_OOXMLEXPORT_TEST(testWpsOnly, "wps-only.docx")
     CPPUNIT_ASSERT_EQUAL(false, getProperty<bool>(getShape(2), "Opaque"));
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testFloattableNestedDOCXExport)
+{
+    // Given a document with nested floating tables:
+    createSwDoc("floattable-nested.odt");
+
+    // When exporting to DOCX:
+    save("Office Open XML Text");
+
+    // Then make sure both floating table is exported:
+    xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
+    // Without the accompanying fix in place, this test would have failed with
+    // - Expected: 2
+    // - Actual  : 1
+    // i.e. the inner floating table was lost.
+    assertXPath(pXmlDoc, "//w:tblpPr", 2);
+}
+
 DECLARE_OOXMLEXPORT_TEST(testWpgOnly, "wpg-only.docx")
 {
     uno::Reference<drawing::XShape> xShape = getShape(1);
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index a1dcc1d98d09..da6824648b28 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -434,6 +434,9 @@ void DocxAttributeOutput::WriteFloatingTable(ww8::Frame 
const* pParentFrame)
     //Save data here and restore when out of scope
     ExportDataSaveRestore aDataGuard(GetExport(), nStt, nEnd, pParentFrame);
 
+    // Stash away info about the current table, so m_tableReference is clean.
+    DocxTableExportContext aTableExportContext(*this);
+
     // set a floatingTableFrame AND unset parent frame,
     // otherwise exporter thinks we are still in a frame
     m_rExport.SetFloatingTableFrame(pParentFrame);
@@ -515,7 +518,7 @@ sal_Int32 
DocxAttributeOutput::StartParagraph(ww8::WW8TableNodeInfo::Pointer_t p
 
     // look ahead for floating tables that were put into a frame during import
     // floating tables in shapes are not supported: exclude this case
-    if (!pTextNodeInfo && !m_rExport.SdrExporter().IsDMLAndVMLDrawingOpen())
+    if (!m_rExport.SdrExporter().IsDMLAndVMLDrawingOpen())
     {
         checkAndWriteFloatingTables(*this);
     }
commit 77d4d7cfaf955d1d438bcf8dc05f710d8b00f4c3
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Mon Sep 11 08:26:43 2023 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Sep 14 08:10:08 2023 +0200

    sw floattable, nesting: fix overlap support
    
    The bugdoc had a nested, split floating table with overlap=never and
    that lead to a layout loop.
    
    The root of the trouble seems to be that the inner fly will obviously
    overlap with its outer fly but we tried to prevent that and we failed.
    
    Fix the problem by ignoring inner flys in
    SwToContentAnchoredObjectPosition::CalcOverlap().
    
    This also allows removing special handling of nested split flys in
    lcl_ArrangeLowers() and special handling of split flys at an other place
    in the same function, because now the non-bDirectMove case works out of
    the box.
    
    (cherry picked from commit e20bacc209a8e8483209cb4ec51c9e0b55423cdb)
    
    Change-Id: Icf3a8f776aa758ef4ae2c2994a7216c5a6142a62
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/156835
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/qa/core/layout/data/floattable-nested-overlap.odt 
b/sw/qa/core/layout/data/floattable-nested-overlap.odt
new file mode 100644
index 000000000000..b90ae9a7b01e
Binary files /dev/null and 
b/sw/qa/core/layout/data/floattable-nested-overlap.odt differ
diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx
index 1f2fbeeb76bb..102a78afc0b7 100644
--- a/sw/qa/core/layout/flycnt.cxx
+++ b/sw/qa/core/layout/flycnt.cxx
@@ -1080,6 +1080,29 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyNested)
     CPPUNIT_ASSERT(!pPage2Fly2->GetAnchorFrameContainingAnchPos()->IsInFly());
     CPPUNIT_ASSERT(pPage2Fly2->GetPrecede());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testSplitFlyNestedOverlap)
+{
+    // Given a document with a nested, multi-page floating table, enabling the 
"don't overlap" logic:
+    // When calculating the layout:
+    createSwDoc("floattable-nested-overlap.odt");
+    calcLayout();
+
+    // Then make sure we get 2 pages (2 flys on each page):
+    // Without the accompanying fix in place, this test would have failed with 
a layout loop.
+    SwDoc* pDoc = getSwDoc();
+    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+    auto pPage1 = pLayout->Lower()->DynCastPageFrame();
+    CPPUNIT_ASSERT(pPage1);
+    CPPUNIT_ASSERT(pPage1->GetSortedObjs());
+    SwSortedObjs& rPage1Objs = *pPage1->GetSortedObjs();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPage1Objs.size());
+    auto pPage2 = pPage1->GetNext()->DynCastPageFrame();
+    CPPUNIT_ASSERT(pPage2);
+    CPPUNIT_ASSERT(pPage2->GetSortedObjs());
+    SwSortedObjs& rPage2Objs = *pPage2->GetSortedObjs();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(2), rPage2Objs.size());
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index 67e60cea9c1d..d63b96fa71c2 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -5217,24 +5217,11 @@ static bool lcl_ArrangeLowers( SwLayoutFrame *pLay, 
tools::Long lYStart, bool bI
                 lcl_ArrangeLowers( static_cast<SwLayoutFrame*>(pFrame),
                     
aRectFnSet.GetTop(static_cast<SwLayoutFrame*>(pFrame)->Lower()->getFrameArea())
                     + lDiffX, bInva );
-            SwSortedObjs* pDrawObjs = pFrame->GetDrawObjs();
-            auto pTextFrame = pFrame->DynCastTextFrame();
-            if (pTextFrame && pTextFrame->IsInFly())
+            if ( pFrame->GetDrawObjs() )
             {
-                // See if this is a follow anchor. If so, we want the flys 
anchored in the master
-                // which are also lowers of pFrame.
-                SwTextFrame* pMaster = pTextFrame;
-                while (pMaster->IsFollow())
+                for ( size_t i = 0; i < pFrame->GetDrawObjs()->size(); ++i )
                 {
-                    pMaster = pMaster->FindMaster();
-                }
-                pDrawObjs = pMaster->GetDrawObjs();
-            }
-            if (pDrawObjs)
-            {
-                for (size_t i = 0; i < pDrawObjs->size(); ++i)
-                {
-                    SwAnchoredObject* pAnchoredObj = (*pDrawObjs)[i];
+                    SwAnchoredObject* pAnchoredObj = 
(*pFrame->GetDrawObjs())[i];
                     // #i26945# - check, if anchored object
                     // is lower of layout frame by checking, if the anchor
                     // frame, which contains the anchor position, is a lower
@@ -5268,12 +5255,10 @@ static bool lcl_ArrangeLowers( SwLayoutFrame *pLay, 
tools::Long lYStart, bool bI
                         // on the object positioning.
                         // #i52904# - no direct move of objects,
                         // whose vertical position doesn't depend on anchor 
frame.
-                        // Also move split flys directly, otherwise the 
follows would not be moved
-                        // at all.
                         const bool bDirectMove =
                                 FAR_AWAY != pFly->getFrameArea().Top() &&
                                 bVertPosDepOnAnchor &&
-                                (!pFly->ConsiderObjWrapInfluenceOnObjPos() || 
pFly->IsFlySplitAllowed());
+                                !pFly->ConsiderObjWrapInfluenceOnObjPos();
                         if ( bDirectMove )
                         {
                             {
diff --git a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx 
b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
index 9c1c491b24c9..b83d979d31b7 100644
--- a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
+++ b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
@@ -1212,6 +1212,14 @@ void 
SwToContentAnchoredObjectPosition::CalcOverlap(const SwTextFrame* pAnchorFr
         // At least for split flys we need to consider objects on the same 
page, but anchored in
         // different text frames.
         bSplitFly = true;
+
+        SwFrame* pFlyFrameAnchor = 
pFlyFrame->GetAnchorFrameContainingAnchPos();
+        if (pFlyFrameAnchor && pFlyFrameAnchor->IsInFly())
+        {
+            // An inner fly overlapping with its outer fly is fine.
+            return;
+        }
+
         const SwPageFrame* pPageFrame = 
pAnchorFrameForVertPos->FindPageFrame();
         if (pPageFrame)
         {
@@ -1239,10 +1247,20 @@ void 
SwToContentAnchoredObjectPosition::CalcOverlap(const SwTextFrame* pAnchorFr
         }
 
         SwFlyFrame* pAnchoredObjFly = pAnchoredObj->DynCastFlyFrame();
-        if (bSplitFly && !pAnchoredObjFly)
+        if (bSplitFly)
         {
-            // This is a split fly, then overlap is only checked against other 
split flys.
-            continue;
+            if (!pAnchoredObjFly)
+            {
+                // This is a split fly, then overlap is only checked against 
other split flys.
+                continue;
+            }
+
+            SwFrame* pAnchoredObjFlyAnchor = 
pAnchoredObjFly->GetAnchorFrameContainingAnchPos();
+            if (pAnchoredObjFlyAnchor && pAnchoredObjFlyAnchor->IsInFly())
+            {
+                // An inner fly overlapping with its outer fly is fine.
+                continue;
+            }
         }
 
         css::text::WrapTextMode eWrap = 
pAnchoredObj->GetFrameFormat().GetSurround().GetSurround();

Reply via email to