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();