summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2023-03-13 08:14:38 +0100
committerMiklos Vajna <vmiklos@collabora.com>2023-03-13 08:05:22 +0000
commitda2707a83f13cba98b22aba1ca6568dbbc4c5fd8 (patch)
tree1b921713136ea485cde849bf8a7c0ca68a25cc79
parent1519ae101abf32187db983c8a08f7bf1899d5d22 (diff)
sw floattable: handle Word 2010 legacy mode in SwFlyFrame
The tdf#61594 bugdoc has 3 non-header rows on the first page, while Writer splits the 3rd row, so the follow row goes to the 2nd page. It turns out that the 3rd row fits the first page in Word because >= 2013 matches Writer, but <= 2010 used to behave differently, see <https://answers.microsoft.com/en-us/msoffice/forum/all/floating-tables-in-word-2013-will-not-extend/576962cc-392d-43e5-b603-654406e1969f>. (The spec doesn't seem to document this, sadly.) Fix the problem by using one of the existing compat flags that we only set in the Word <= 2010 case (triggered by <w:compatSetting w:name="compatibilityMode" w:val="14"> or lower values), that scenario wants to allow the fly frame to extend till the bottom of the page, not only till the bottom of the body frame print area. The bugdoc now doesn't split that 3rd row, but the layout of the 4th row is still bad with this. Change-Id: I547abb19df250e5fbe4d8e123593a645cdbdc6b0 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/148751 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
-rw-r--r--sw/qa/core/layout/data/floattable-compat14.docxbin0 -> 28479 bytes
-rw-r--r--sw/qa/core/layout/flycnt.cxx36
-rw-r--r--sw/source/core/inc/cellfrm.hxx2
-rw-r--r--sw/source/core/layout/fly.cxx47
4 files changed, 75 insertions, 10 deletions
diff --git a/sw/qa/core/layout/data/floattable-compat14.docx b/sw/qa/core/layout/data/floattable-compat14.docx
new file mode 100644
index 000000000000..5afb0af477d8
--- /dev/null
+++ b/sw/qa/core/layout/data/floattable-compat14.docx
Binary files differ
diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx
index d76a3447b938..079030d80054 100644
--- a/sw/qa/core/layout/flycnt.cxx
+++ b/sw/qa/core/layout/flycnt.cxx
@@ -28,6 +28,7 @@
#include <itabenum.hxx>
#include <frmmgr.hxx>
#include <frameformats.hxx>
+#include <cellfrm.hxx>
namespace
{
@@ -475,6 +476,41 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyWidow)
// And then similarly this was 1, not 2.
CPPUNIT_ASSERT_EQUAL(static_cast<sal_uLong>(2), pText2->GetThisLines());
}
+
+CPPUNIT_TEST_FIXTURE(Test, testSplitFlyCompat14)
+{
+ // Given a Word 2010 document with 2 pages, one table row each:
+ std::shared_ptr<comphelper::ConfigurationChanges> pChanges(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Writer::Filter::Import::DOCX::ImportFloatingTableAsSplitFly::set(true,
+ pChanges);
+ pChanges->commit();
+ comphelper::ScopeGuard g([pChanges] {
+ officecfg::Office::Writer::Filter::Import::DOCX::ImportFloatingTableAsSplitFly::set(
+ false, pChanges);
+ pChanges->commit();
+ });
+ createSwDoc("floattable-compat14.docx");
+
+ // When laying out that document:
+ calcLayout();
+
+ // Then make sure that the first row is entirely on page 1:
+ SwDoc* pDoc = getSwDoc();
+ SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+ auto pPage1 = dynamic_cast<SwPageFrame*>(pLayout->Lower());
+ CPPUNIT_ASSERT(pPage1);
+ const SwSortedObjs& rPage1Objs = *pPage1->GetSortedObjs();
+ CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage1Objs.size());
+ auto pPage1Fly = dynamic_cast<SwFlyAtContentFrame*>(rPage1Objs[0]);
+ CPPUNIT_ASSERT(pPage1Fly);
+ SwFrame* pTab1 = pPage1Fly->GetLower();
+ SwFrame* pRow1 = pTab1->GetLower();
+ auto pCell1 = dynamic_cast<SwCellFrame*>(pRow1->GetLower());
+ // Without the accompanying fix in place, this test would have failed, the first row was split,
+ // but not in Word.
+ CPPUNIT_ASSERT(!pCell1->GetFollowCell());
+}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/inc/cellfrm.hxx b/sw/source/core/inc/cellfrm.hxx
index 2e34b8a2fddf..4fdbc707de6e 100644
--- a/sw/source/core/inc/cellfrm.hxx
+++ b/sw/source/core/inc/cellfrm.hxx
@@ -27,7 +27,7 @@ struct SwCursorMoveState;
class SwBorderAttrs;
/// SwCellFrame is one table cell in the document layout.
-class SwCellFrame final : public SwLayoutFrame
+class SW_DLLPUBLIC SwCellFrame final : public SwLayoutFrame
{
const SwTableBox* m_pTabBox;
diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index b1955e845af6..7f9256a5e940 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -79,6 +79,38 @@
using namespace ::com::sun::star;
+namespace
+{
+/// Gets the bottom position which is a deadline for a split fly.
+SwTwips GetFlyAnchorBottom(SwFlyFrame* pFly, const SwFrame& rAnchor)
+{
+ SwRectFnSet aRectFnSet(pFly);
+
+ const IDocumentSettingAccess& rIDSA = pFly->GetFrameFormat().getIDocumentSettingAccess();
+ bool bLegacy = rIDSA.get(DocumentSettingId::TAB_OVER_MARGIN);
+ if (bLegacy)
+ {
+ // Word <= 2010 style: the fly can overlap with the bottom margin / footer area.
+ const SwFrame* pAnchorUpper = rAnchor.FindPageFrame();
+ if (!pAnchorUpper)
+ {
+ return 0;
+ }
+
+ return aRectFnSet.GetBottom(pAnchorUpper->getFrameArea());
+ }
+
+ // Word >= 2013 style: the fly has to stay inside the body frame.
+ const SwFrame* pAnchorUpper = rAnchor.GetUpper();
+ if (!pAnchorUpper)
+ {
+ return 0;
+ }
+
+ return aRectFnSet.GetPrtBottom(*pAnchorUpper);
+}
+}
+
static SwTwips lcl_CalcAutoWidth( const SwLayoutFrame& rFrame );
SwFlyFrame::SwFlyFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch, bool bFollow ) :
@@ -1325,12 +1357,11 @@ void SwFlyFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderA
// then use that as the anchor for sizing purposes.
pAnchor = pAnchorChar;
}
- const SwFrame* pAnchorUpper = pAnchor ? pAnchor->GetUpper() : nullptr;
- if (pAnchorUpper && IsFlySplitAllowed())
+ if (pAnchor && IsFlySplitAllowed())
{
// If the fly is allowed to be split, then limit its size to the upper of the
// anchor.
- SwTwips nDeadline = aRectFnSet.GetPrtBottom(*pAnchorUpper);
+ SwTwips nDeadline = GetFlyAnchorBottom(this, *pAnchor);
SwTwips nTop = aRectFnSet.GetTop(getFrameArea());
SwTwips nBottom = aRectFnSet.GetTop(getFrameArea()) + nRemaining;
if (nBottom > nDeadline)
@@ -2064,10 +2095,9 @@ SwTwips SwFlyFrame::Grow_( SwTwips nDist, bool bTst )
{
pAnchor = pAnchorChar;
}
- const SwFrame* pAnchorUpper = pAnchor ? pAnchor->GetUpper() : nullptr;
- if (pAnchorUpper)
+ if (pAnchor)
{
- SwTwips nDeadline = aRectFnSet.GetPrtBottom(*pAnchorUpper);
+ SwTwips nDeadline = GetFlyAnchorBottom(this, *pAnchor);
SwTwips nTop = aRectFnSet.GetTop(getFrameArea());
SwTwips nBottom = nTop + aRectFnSet.GetHeight(getFrameArea());
SwTwips nMaxGrow = nDeadline - nBottom;
@@ -2105,10 +2135,9 @@ SwTwips SwFlyFrame::Grow_( SwTwips nDist, bool bTst )
{
pAnchor = pAnchorChar;
}
- const SwFrame* pAnchorUpper = pAnchor ? pAnchor->GetUpper() : nullptr;
- if (pAnchorUpper && IsFlySplitAllowed())
+ if (pAnchor && IsFlySplitAllowed())
{
- SwTwips nDeadline = aRectFnSet.GetPrtBottom(*pAnchorUpper);
+ SwTwips nDeadline = GetFlyAnchorBottom(this, *pAnchor);
SwTwips nTop = aRectFnSet.GetTop(getFrameArea());
SwTwips nBottom = nTop + aRectFnSet.GetHeight(getFrameArea());
// Calculate max grow and compare to the requested growth, adding to nDist may