summaryrefslogtreecommitdiff
path: root/sw/source
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2023-02-07 13:43:12 +0100
committerMiklos Vajna <vmiklos@collabora.com>2023-02-07 13:39:52 +0000
commitddfb800e60d98340c99c8013f6df3f2060687dd0 (patch)
tree5d08daf1af578a111d0ac29e46cdd6e0cdcf168d /sw/source
parent909a25d30b09ebd3a023105a9c3cc4d20add094a (diff)
sw: fix anchoring in SwFrame::GetNextFlyLeaf()
The core of this change is in SwFrame::GetNextFlyLeaf(), which used to assume that there is a next frame after the fly's anchor, but it's perfectly valid to not have such a frame. Instead if a fly is split, then also split its anchor, so effectively only the last follow of such anchor hosts content, all the others are empty and only serve as an anchor of a non-last member of a split fly frame chain. Once this anchoring is changed, adjustments are needed at other places, so a sample split fly frame (2 paragraphs, 1st para on first page, 2nd para on second page) is still layout out correctly: - SwAnchoredObject::FindAnchorCharFrame(): return the right follow text frame for follow flys. This is needed because flys have to be anchored to masters, and then this function can find the frame that's used for positioning. - SwFlyFrame::Format(): get the rectangle of the correct body frame, otherwise we would get the bottom of the 1st body frame instead of the 2nd body frame for the follow fly, leading to a negative height of the follow fly frame. - SwToContentAnchoredObjectPosition::CalcPosition(): position against the right follow text frame, similar to SwAnchoredObject::FindAnchorCharFrame(). - SwTextFrame::AdjustFollow_(): don't join a master with its follow if there is a split fly frame anchored in the master. The assumption is that first the fly has to be moved away, then we can do such a join. - Introduce a SwTextFrame::GetSplitFlyDrawObjs() to avoid copy&paste in SwTextFrame::AdjustFollow_() & SwTextFormatter::FormatLine(). With this, a sample split fly frame is split to two pages with correct anchors if SW_FORCE_FLY_SPLIT=1 is set. The anchor frame has duplicated text on the 1st and 2nd page still, though. Towards an initial working layout for multi-page fly frames. Change-Id: Ie99b13c2e318ec63f69c8a47bbc604771509e24a Reviewed-on: https://gerrit.libreoffice.org/c/core/+/146607 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
Diffstat (limited to 'sw/source')
-rw-r--r--sw/source/core/inc/txtfrm.hxx4
-rw-r--r--sw/source/core/layout/anchoredobject.cxx19
-rw-r--r--sw/source/core/layout/fly.cxx6
-rw-r--r--sw/source/core/layout/flycnt.cxx28
-rw-r--r--sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx18
-rw-r--r--sw/source/core/text/frmform.cxx12
-rw-r--r--sw/source/core/text/itratr.cxx32
-rw-r--r--sw/source/core/text/itrform2.cxx29
8 files changed, 108 insertions, 40 deletions
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index 3fd73ea2c6ec..cb22ebc439f8 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -50,6 +50,7 @@ enum class ExpandMode;
class SwTextAttr;
class SwWrtShell;
class SwNode;
+class SwFlyAtContentFrame;
#define NON_PRINTING_CHARACTER_COLOR Color(0x26, 0x8b, 0xd2)
@@ -783,6 +784,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();
+
virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer) const override;
};
diff --git a/sw/source/core/layout/anchoredobject.cxx b/sw/source/core/layout/anchoredobject.cxx
index 130a5d8c7553..4272437f9e25 100644
--- a/sw/source/core/layout/anchoredobject.cxx
+++ b/sw/source/core/layout/anchoredobject.cxx
@@ -31,6 +31,7 @@
#include <pagefrm.hxx>
#include <layouter.hxx>
#include <osl/diagnose.h>
+#include <flyfrms.hxx>
using namespace ::com::sun::star;
@@ -716,6 +717,24 @@ SwTextFrame* SwAnchoredObject::FindAnchorCharFrame()
TextFrameIndex const nOffset(pFrame->MapModelToViewPos(*rAnch.GetContentAnchor()));
pAnchorCharFrame = &pFrame->GetFrameAtOfst(nOffset);
}
+ else if (SwFlyFrame* pFlyFrame = DynCastFlyFrame())
+ {
+ // See if this fly is split. If so, then the anchor is also split. All anchors are
+ // empty, except the last follow.
+ if (pFlyFrame->IsFlySplitAllowed())
+ {
+ auto pFlyAtContentFrame = static_cast<SwFlyAtContentFrame*>(pFlyFrame);
+ if (pFlyAtContentFrame->GetPrecede())
+ {
+ SwTextFrame* pFrame(static_cast<SwTextFrame*>(AnchorFrame()));
+ const SwTextFrame* pFollow = pFrame->GetFollow();
+ if (pFollow)
+ {
+ pAnchorCharFrame = const_cast<SwTextFrame*>(pFollow);
+ }
+ }
+ }
+ }
}
return pAnchorCharFrame;
diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index e256a0b9e0ac..91c0f0549680 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -1318,6 +1318,12 @@ void SwFlyFrame::Format( vcl::RenderContext* /*pRenderContext*/, const SwBorderA
nRemaining = MINFLY;
const SwFrame* pAnchor = GetAnchorFrame();
+ if (SwFrame* pAnchorChar = FindAnchorCharFrame())
+ {
+ // If we find a follow of the anchor that is effectively the anchor of this fly,
+ // then use that as the anchor for sizing purposes.
+ pAnchor = pAnchorChar;
+ }
const SwFrame* pAnchorUpper = pAnchor ? pAnchor->GetUpper() : nullptr;
if (pAnchorUpper && IsFlySplitAllowed())
{
diff --git a/sw/source/core/layout/flycnt.cxx b/sw/source/core/layout/flycnt.cxx
index 2fcd1723d0fc..474d21bd7f97 100644
--- a/sw/source/core/layout/flycnt.cxx
+++ b/sw/source/core/layout/flycnt.cxx
@@ -1566,24 +1566,18 @@ SwLayoutFrame *SwFrame::GetNextFlyLeaf( MakePageType eMakePage )
{
SwFlyAtContentFrame* pNew = nullptr;
SwFrame* pFlyAnchor = const_cast<SwFrame*>(pFly->GetAnchorFrame());
- if (pFlyAnchor)
+ if (pFlyAnchor && pFlyAnchor->IsTextFrame())
{
- SwFrame* pTmp = pFlyAnchor->GetNext();
- if (pTmp)
- {
- SwFlowFrame* pNxt = nullptr;
- if (pTmp->IsContentFrame())
- {
- pNxt = static_cast<SwContentFrame*>(pTmp);
- }
- if (pNxt)
- {
- pNxt->MoveSubTree(pLayLeaf);
-
- pNew = new SwFlyAtContentFrame( *pFly );
- pNxt->GetFrame().AppendFly( pNew );
- }
- }
+ // Split the anchor at char 0: all the content goes to the follow of the anchor.
+ auto pFlyAnchorTextFrame = static_cast<SwTextFrame*>(pFlyAnchor);
+ pFlyAnchorTextFrame->SplitFrame(TextFrameIndex(0));
+ auto pNext = static_cast<SwTextFrame*>(pFlyAnchor->GetNext());
+ pNext->MoveSubTree(pLayLeaf);
+
+ // Now create the follow of the fly and anchor it in the just created follow of the
+ // anchor.
+ pNew = new SwFlyAtContentFrame(*pFly);
+ pFlyAnchorTextFrame->AppendFly(pNew);
}
pLayLeaf = pNew;
}
diff --git a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
index 700b737b1689..7a9dd8546a3a 100644
--- a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
+++ b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
@@ -41,6 +41,7 @@
#include <fmtwrapinfluenceonobjpos.hxx>
#include <sortedobjs.hxx>
#include <textboxhelper.hxx>
+#include <flyfrms.hxx>
using namespace ::com::sun::star;
@@ -225,6 +226,23 @@ void SwToContentAnchoredObjectPosition::CalcPosition()
rAnchorTextFrame.MapModelToViewPos(*rAnch.GetContentAnchor())));
mpToCharOrientFrame = pOrientFrame;
}
+ else if (SwFlyFrame* pFlyFrame = GetAnchoredObj().DynCastFlyFrame())
+ {
+ // See if this fly is split. If so, then the anchor is also split. All anchors are
+ // empty, except the last follow.
+ if (pFlyFrame->IsFlySplitAllowed())
+ {
+ auto pFlyAtContentFrame = static_cast<SwFlyAtContentFrame*>(pFlyFrame);
+ if (pFlyAtContentFrame->GetPrecede())
+ {
+ const SwTextFrame* pFollow = rAnchorTextFrame.GetFollow();
+ if (pFollow)
+ {
+ pOrientFrame = pFollow;
+ }
+ }
+ }
+ }
}
aRectFnSet.Refresh(pOrientFrame);
diff --git a/sw/source/core/text/frmform.cxx b/sw/source/core/text/frmform.cxx
index 46d2613021cb..f36d27e68ac5 100644
--- a/sw/source/core/text/frmform.cxx
+++ b/sw/source/core/text/frmform.cxx
@@ -49,6 +49,7 @@
#include <editeng/tstpitem.hxx>
#include <redline.hxx>
#include <comphelper/lok.hxx>
+#include <flyfrms.hxx>
// Tolerance in formatting and text output
#define SLOPPY_TWIPS 5
@@ -579,6 +580,17 @@ void SwTextFrame::AdjustFollow_( SwTextFormatter &rLine,
}
if (GetFollow()->IsDeleteForbidden())
return;
+
+ for (const auto& pFlyFrame : GetSplitFlyDrawObjs())
+ {
+ // 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;
+ }
+ }
+
JoinFrame();
}
diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index 886baef79a23..105fc5e3af30 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -57,6 +57,10 @@
#include <editeng/lrspitem.hxx>
#include <calbck.hxx>
#include <frameformats.hxx>
+#include <sortedobjs.hxx>
+#include <anchoredobject.hxx>
+#include <flyfrm.hxx>
+#include <flyfrms.hxx>
using namespace ::com::sun::star::i18n;
using namespace ::com::sun::star;
@@ -1447,6 +1451,34 @@ 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*> aObjs;
+ SwSortedObjs* pSortedObjs = GetDrawObjs();
+ if (!pSortedObjs)
+ {
+ return aObjs;
+ }
+
+ for (const auto& pSortedObj : *pSortedObjs)
+ {
+ SwFlyFrame* pFlyFrame = pSortedObj->DynCastFlyFrame();
+ if (!pFlyFrame)
+ {
+ continue;
+ }
+
+ if (!pFlyFrame->IsFlySplitAllowed())
+ {
+ continue;
+ }
+
+ aObjs.push_back(static_cast<SwFlyAtContentFrame*>(pFlyFrame));
+ }
+
+ return aObjs;
+}
+
SwTwips SwTextNode::GetWidthOfLeadingTabs() const
{
SwTwips nRet = 0;
diff --git a/sw/source/core/text/itrform2.cxx b/sw/source/core/text/itrform2.cxx
index 48ad43bde8ef..e65468d62d4c 100644
--- a/sw/source/core/text/itrform2.cxx
+++ b/sw/source/core/text/itrform2.cxx
@@ -1936,36 +1936,19 @@ TextFrameIndex SwTextFormatter::FormatLine(TextFrameIndex const nStartPos)
if (m_pFrame)
{
// Don't oversize the line in case of split flys, so we don't try to move the anchor
- // of a precede fly forward.
+ // of a precede fly forward, next to its follow.
bool bHasNonLastFlySplitAnchored = false;
- SwSortedObjs* pSortedObjs = m_pFrame->GetDrawObjs();
- if (pSortedObjs)
+ for (const auto& pFlyFrame : m_pFrame->GetSplitFlyDrawObjs())
{
- for (const auto& pSortedObj : *pSortedObjs)
+ if (pFlyFrame->GetFollow())
{
- SwFlyFrame* pFlyFrame = pSortedObj->DynCastFlyFrame();
- if (!pFlyFrame)
- {
- continue;
- }
-
- if (!pFlyFrame->IsFlySplitAllowed())
- {
- continue;
- }
-
- auto pFlyAtContentFrame = static_cast<SwFlyAtContentFrame*>(pFlyFrame);
- if (pFlyAtContentFrame->GetFollow())
- {
- bHasNonLastFlySplitAnchored = true;
- break;
- }
+ bHasNonLastFlySplitAnchored = true;
+ break;
}
}
-
if (bHasNonLastFlySplitAnchored)
{
- m_pCurr->SetRealHeight( GetFrameRstHeight() );
+ m_pCurr->SetRealHeight(GetFrameRstHeight());
}
}