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