summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2023-02-14 08:12:40 +0100
committerMiklos Vajna <vmiklos@collabora.com>2023-02-14 08:42:28 +0000
commit1cf13b8b11e7c122631394e308b66b46ffaae718 (patch)
treeee6621e675ef01bc8d900baa8dc86ea6f1220950
parentc4de5f1f40f7392306daaae8c05481ea346bbeb0 (diff)
sw floattable: improve handling of split flys in SwTextFrame::FormatEmpty()
The bugdoc had a non-empty paragraph after the floating table, we painted that text on both page 1 and page 2, while only page 2 is expected. We want that paragraph to be on both pages, but we want to split it before the first char, so apart from providing a place to serve as an anchor, it should be invisible on page 1. Fix the problem by extending SwTextFrame::FormatEmpty() to consider the master anchor text frame as empty in case it has no text, just intersects with a fly frame. Also improve SwTextFrame::HasNonLastSplitFlyDrawObj() a bit, so it returns early when the own and the follow offset is not the same. These are cheap checks and some callers already did it before iterating over all the draw objects of the text frame, but other callers didn't do this. Now we check for this consistently, everywhere. Change-Id: I4b399ae3f9e9f364c61d977359f6c9b16c648629 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146969 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
-rw-r--r--sw/qa/core/layout/flycnt.cxx6
-rw-r--r--sw/source/core/inc/cntfrm.hxx3
-rw-r--r--sw/source/core/text/frmform.cxx10
-rw-r--r--sw/source/core/text/itratr.cxx14
-rw-r--r--sw/source/core/text/porrst.cxx5
5 files changed, 28 insertions, 10 deletions
diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx
index a006ecb54f00..2f1e1e54deac 100644
--- a/sw/qa/core/layout/flycnt.cxx
+++ b/sw/qa/core/layout/flycnt.cxx
@@ -19,6 +19,7 @@
#include <rootfrm.hxx>
#include <sortedobjs.hxx>
#include <tabfrm.hxx>
+#include <txtfrm.hxx>
namespace
{
@@ -75,6 +76,11 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyWithTable)
CPPUNIT_ASSERT(pPage2Table);
CPPUNIT_ASSERT(pPage2Table->GetPrecede());
CPPUNIT_ASSERT(!pPage2Table->GetFollow());
+ // Page 1 anchor has no text:
+ auto pPage1Anchor = dynamic_cast<SwTextFrame*>(pPage1->FindLastBodyContent());
+ CPPUNIT_ASSERT(pPage1Anchor);
+ // This failed, page 1 anchor had unexpected, leftover text.
+ CPPUNIT_ASSERT(!pPage1Anchor->HasPara());
}
}
diff --git a/sw/source/core/inc/cntfrm.hxx b/sw/source/core/inc/cntfrm.hxx
index b972a7aaafd8..2f6c8b5ba3e4 100644
--- a/sw/source/core/inc/cntfrm.hxx
+++ b/sw/source/core/inc/cntfrm.hxx
@@ -20,6 +20,7 @@
#ifndef INCLUDED_SW_SOURCE_CORE_INC_CNTFRM_HXX
#define INCLUDED_SW_SOURCE_CORE_INC_CNTFRM_HXX
+#include <swdllapi.h>
#include "frame.hxx"
#include "flowfrm.hxx"
#include <cshtyp.hxx>
@@ -54,7 +55,7 @@ namespace o3tl {
* SwContentFrame is the layout for content nodes: a common base class for text (paragraph) and
* non-text (e.g. graphic) frames.
*/
-class SAL_DLLPUBLIC_RTTI SwContentFrame: public SwFrame, public SwFlowFrame
+class SW_DLLPUBLIC SwContentFrame: public SwFrame, public SwFlowFrame
{
friend void MakeNxt( SwFrame *pFrame, SwFrame *pNxt ); // calls MakePrtArea
diff --git a/sw/source/core/text/frmform.cxx b/sw/source/core/text/frmform.cxx
index 329f9d784ed1..5b3db006a2ee 100644
--- a/sw/source/core/text/frmform.cxx
+++ b/sw/source/core/text/frmform.cxx
@@ -1837,14 +1837,10 @@ void SwTextFrame::Format( vcl::RenderContext* pRenderContext, const SwBorderAttr
TextFrameIndex nStrLen(GetText().getLength());
- SwTextFrame* pFollow = GetFollow();
- if (pFollow && pFollow->GetOffset() == mnOffset)
+ if (HasNonLastSplitFlyDrawObj())
{
- if (HasNonLastSplitFlyDrawObj())
- {
- // Non-last part of split fly anchor: consider this empty.
- nStrLen = TextFrameIndex(0);
- }
+ // Non-last part of split fly anchor: consider this empty.
+ nStrLen = TextFrameIndex(0);
}
if ( nStrLen || !FormatEmpty() )
diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index 93ae3e4c6ed0..4a0cdc5e6807 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -1481,6 +1481,20 @@ std::vector<SwFlyAtContentFrame*> SwTextFrame::GetSplitFlyDrawObjs() const
bool SwTextFrame::HasNonLastSplitFlyDrawObj() const
{
+ const SwTextFrame* pFollow = GetFollow();
+ if (!pFollow)
+ {
+ return false;
+ }
+
+ if (mnOffset != pFollow->GetOffset())
+ {
+ return false;
+ }
+
+ // At this point we know what we're part of a chain that is an anchor for split fly frames, but
+ // we're not the last one. See if we have a matching fly.
+
for (const auto& pFly : GetSplitFlyDrawObjs())
{
if (pFly->GetFollow())
diff --git a/sw/source/core/text/porrst.cxx b/sw/source/core/text/porrst.cxx
index eb128eaa662e..90f4d763578d 100644
--- a/sw/source/core/text/porrst.cxx
+++ b/sw/source/core/text/porrst.cxx
@@ -412,7 +412,8 @@ bool SwTextFrame::FormatEmpty()
// sw_redlinehide: just disable FormatEmpty optimisation for now
// Split fly frames: non-last parts of the anchor want this optimization to clear the old
// content.
- if ((HasFollow() && mnOffset != GetFollow()->GetOffset()) || GetMergedPara() || GetTextNodeFirst()->GetpSwpHints() ||
+ bool bHasNonLastSplitFlyDrawObj = HasNonLastSplitFlyDrawObj();
+ if ((HasFollow() && !bHasNonLastSplitFlyDrawObj) || GetMergedPara() || GetTextNodeFirst()->GetpSwpHints() ||
nullptr != GetTextNodeForParaProps()->GetNumRule() ||
GetTextNodeFirst()->HasHiddenCharAttribute(true) ||
IsInFootnote() || ( HasPara() && GetPara()->IsPrepMustFit() ) )
@@ -433,7 +434,7 @@ bool SwTextFrame::FormatEmpty()
SwRect aRect;
bool bFirstFlyCheck = 0 != getFramePrintArea().Height();
if ( !bCollapse && bFirstFlyCheck &&
- aTextFly.IsOn() && aTextFly.IsAnyObj( aRect ) )
+ aTextFly.IsOn() && aTextFly.IsAnyObj( aRect ) && !bHasNonLastSplitFlyDrawObj )
return false;
// only need to check one node because of early return on GetMerged()