sw/source/core/attr/formatflysplit.cxx |   12 ++++++++++++
 sw/source/core/inc/txtfrm.hxx          |    8 ++++++--
 sw/source/core/text/frmform.cxx        |   20 ++++++++++++++------
 sw/source/core/text/frmpaint.cxx       |    3 ++-
 sw/source/core/text/itratr.cxx         |   17 +++++++++++++++--
 sw/source/core/text/itrform2.cxx       |   11 +----------
 sw/source/core/text/porrst.cxx         |    4 +++-
 7 files changed, 53 insertions(+), 22 deletions(-)

New commits:
commit 00b9b33334791079c2dc26b1ed4c123450cabf7d
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu Feb 9 08:26:21 2023 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Feb 9 08:25:07 2023 +0000

    sw: call FormatEmpty() in SwTextFrame::Format() for split fly masters
    
    The problem was that the text in the anchor frame of a split fly frame
    was duplicated on the old page and the new page as well. The reason for
    this seems to be that the master has no content and the follow has all
    the content (this is wanted), but then there is no code to explicitly
    clear the master.
    
    In other cases the master always gets some new content where portion
    building for that new content starts by throwing away the old portions.
    
    Once SwTextFrame::Format() and SwTextFrame::FormatEmpty() explicitly
    checks for these master anchors, the unwanted text in the master anchor
    disappears.
    
    An extra tweak is needed in SwTextFrame::PaintEmpty() to even hide the
    paragraph marker: this frame is empty but has a follow frame, so we
    should not show a paragraph marker there.
    
    Finally introduce a SwTextFrame::HasNonLastSplitFlyDrawObj() to be able
    to check for this "empty master anchor for split fly" case at a single
    place.
    
    With this <https://bugs.documentfoundation.org/attachment.cgi?id=185144>
    from <https://bugs.documentfoundation.org/show_bug.cgi?id=61594> gets
    laid out reasonably: the position is not perfect but we detect that only
    1 para of the text frame fits page 1, we create a 2nd page and we
    correctly move exactly the text frame's 2nd para to page 2.
    
    Change-Id: I871bba2de5b829e667d5cfb1cbe0ba4cc2274edd
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146680
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/sw/source/core/attr/formatflysplit.cxx 
b/sw/source/core/attr/formatflysplit.cxx
index bcbfcc2d5e96..904fd9a8bb5c 100644
--- a/sw/source/core/attr/formatflysplit.cxx
+++ b/sw/source/core/attr/formatflysplit.cxx
@@ -24,6 +24,18 @@
 SwFormatFlySplit::SwFormatFlySplit(bool bSplit)
     : SfxBoolItem(RES_FLY_SPLIT, bSplit)
 {
+    // Once this pool item is true, a floating table (text frame + table 
inside it) is meant to
+    // split across multiple pages.
+    //
+    // The layout representation is the following:
+    //
+    // - We assume that the anchor type is at-para for such fly frames, and 
SwFlyAtContentFrame
+    // derives from SwFlowFrame to be able to split in general.
+    //
+    // - Both the master fly and the follow flys need an anchor. At the same 
time, we want all text
+    // of the anchor frame to be wrapped around the last follow fly frame, for 
Word compatibility.
+    // These are solved by splitting the anchor frame as many times as needed, 
always at text
+    // TextFrameIndex 0.
     if (getenv("SW_FORCE_FLY_SPLIT"))
     {
         SetValue(true);
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index cb22ebc439f8..942867882626 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -332,6 +332,9 @@ class SW_DLLPUBLIC SwTextFrame final : public SwContentFrame
 
     virtual void SwClientNotify(SwModify const& rModify, SfxHint const& rHint) 
override;
 
+    /// Like GetDrawObjs(), but limit to fly frames which are allowed to split.
+    std::vector<SwFlyAtContentFrame*> GetSplitFlyDrawObjs() const;
+
 public:
 
     virtual const SvxFormatBreakItem& GetBreakItem() const override;
@@ -784,8 +787,9 @@ public:
     OUString GetCurWord(SwPosition const&) const;
     sal_uInt16 GetScalingOfSelectedText(TextFrameIndex nStt, TextFrameIndex 
nEnd);
 
-    /// Like GetDrawObjs(), but limit to fly frames which are allowed to split.
-    std::vector<SwFlyAtContentFrame*> GetSplitFlyDrawObjs();
+    /// This text frame may have a split fly frames anchored to it. Is any of 
them a frame that has
+    /// a follow, i.e. not the last in a master -> follow 1 -> ... -> last 
follow chain?
+    bool HasNonLastSplitFlyDrawObj() const;
 
     virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer) const override;
 };
diff --git a/sw/source/core/text/frmform.cxx b/sw/source/core/text/frmform.cxx
index f36d27e68ac5..329f9d784ed1 100644
--- a/sw/source/core/text/frmform.cxx
+++ b/sw/source/core/text/frmform.cxx
@@ -581,14 +581,11 @@ void SwTextFrame::AdjustFollow_( SwTextFormatter &rLine,
             if (GetFollow()->IsDeleteForbidden())
                 return;
 
-            for (const auto& pFlyFrame : GetSplitFlyDrawObjs())
+            if (HasNonLastSplitFlyDrawObj())
             {
                 // If a fly frame is anchored to us that has a follow, then 
don't join the anchor.
                 // First those fly frames have to be joined.
-                if (pFlyFrame->GetFollow())
-                {
-                    return;
-                }
+                return;
             }
 
             JoinFrame();
@@ -1838,7 +1835,18 @@ void SwTextFrame::Format( vcl::RenderContext* 
pRenderContext, const SwBorderAttr
         return;
     }
 
-    const TextFrameIndex nStrLen(GetText().getLength());
+    TextFrameIndex nStrLen(GetText().getLength());
+
+    SwTextFrame* pFollow = GetFollow();
+    if (pFollow && pFollow->GetOffset() == mnOffset)
+    {
+        if (HasNonLastSplitFlyDrawObj())
+        {
+            // Non-last part of split fly anchor: consider this empty.
+            nStrLen = TextFrameIndex(0);
+        }
+    }
+
     if ( nStrLen || !FormatEmpty() )
     {
 
diff --git a/sw/source/core/text/frmpaint.cxx b/sw/source/core/text/frmpaint.cxx
index e09ad12373cb..461c8094c0ac 100644
--- a/sw/source/core/text/frmpaint.cxx
+++ b/sw/source/core/text/frmpaint.cxx
@@ -601,7 +601,8 @@ bool SwTextFrame::PaintEmpty( const SwRect &rRect, bool 
bCheck ) const
                 }
 
                 // Don't show the paragraph mark for collapsed paragraphs, 
when they are hidden
-                if ( EmptyHeight( ) > 1 )
+                // No paragraph marker in the non-last part of a split fly 
anchor, either.
+                if ( EmptyHeight( ) > 1 && !HasNonLastSplitFlyDrawObj() )
                 {
                     SwDrawTextInfo aDrawInf( pSh, *pSh->GetOut(), CH_PAR, 0, 1 
);
                     aDrawInf.SetPos( aPos );
diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index 105fc5e3af30..93ae3e4c6ed0 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -1451,10 +1451,10 @@ sal_uInt16 SwTextFrame::GetScalingOfSelectedText(
     return o3tl::narrowing<sal_uInt16>( nWidth ? ((100 * 
aIter.GetFnt()->GetTextSize_( aDrawInf ).Height()) / nWidth ) : 0 );
 }
 
-std::vector<SwFlyAtContentFrame*> SwTextFrame::GetSplitFlyDrawObjs()
+std::vector<SwFlyAtContentFrame*> SwTextFrame::GetSplitFlyDrawObjs() const
 {
     std::vector<SwFlyAtContentFrame*> aObjs;
-    SwSortedObjs* pSortedObjs = GetDrawObjs();
+    const SwSortedObjs* pSortedObjs = GetDrawObjs();
     if (!pSortedObjs)
     {
         return aObjs;
@@ -1479,6 +1479,19 @@ std::vector<SwFlyAtContentFrame*> 
SwTextFrame::GetSplitFlyDrawObjs()
     return aObjs;
 }
 
+bool SwTextFrame::HasNonLastSplitFlyDrawObj() const
+{
+    for (const auto& pFly : GetSplitFlyDrawObjs())
+    {
+        if (pFly->GetFollow())
+        {
+            return true;
+        }
+    }
+
+    return false;
+}
+
 SwTwips SwTextNode::GetWidthOfLeadingTabs() const
 {
     SwTwips nRet = 0;
diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx
index 03ce7666c911..6c1f0c06a5a5 100644
--- a/sw/source/core/text/itrform2.cxx
+++ b/sw/source/core/text/itrform2.cxx
@@ -1936,16 +1936,7 @@ TextFrameIndex 
SwTextFormatter::FormatLine(TextFrameIndex const nStartPos)
             {
                 // Don't oversize the line in case of split flys, so we don't 
try to move the anchor
                 // of a precede fly forward, next to its follow.
-                bool bHasNonLastFlySplitAnchored = false;
-                for (const auto& pFlyFrame : m_pFrame->GetSplitFlyDrawObjs())
-                {
-                    if (pFlyFrame->GetFollow())
-                    {
-                        bHasNonLastFlySplitAnchored = true;
-                        break;
-                    }
-                }
-                if (bHasNonLastFlySplitAnchored)
+                if (m_pFrame->HasNonLastSplitFlyDrawObj())
                 {
                     m_pCurr->SetRealHeight(GetFrameRstHeight());
                 }
diff --git a/sw/source/core/text/porrst.cxx b/sw/source/core/text/porrst.cxx
index 3a8dd51e014d..eb128eaa662e 100644
--- a/sw/source/core/text/porrst.cxx
+++ b/sw/source/core/text/porrst.cxx
@@ -410,7 +410,9 @@ bool SwTextFrame::FormatEmpty()
     bool bCollapse = EmptyHeight( ) == 1 && IsCollapse( );
 
     // sw_redlinehide: just disable FormatEmpty optimisation for now
-    if (HasFollow() || GetMergedPara() || GetTextNodeFirst()->GetpSwpHints() ||
+    // 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() ||
         nullptr != GetTextNodeForParaProps()->GetNumRule() ||
         GetTextNodeFirst()->HasHiddenCharAttribute(true) ||
          IsInFootnote() || ( HasPara() && GetPara()->IsPrepMustFit() ) )

Reply via email to