diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2023-02-07 13:43:12 +0100 |
---|---|---|
committer | Miklos Vajna <vmiklos@collabora.com> | 2023-02-07 13:39:52 +0000 |
commit | ddfb800e60d98340c99c8013f6df3f2060687dd0 (patch) | |
tree | 5d08daf1af578a111d0ac29e46cdd6e0cdcf168d /sw/source | |
parent | 909a25d30b09ebd3a023105a9c3cc4d20add094a (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.hxx | 4 | ||||
-rw-r--r-- | sw/source/core/layout/anchoredobject.cxx | 19 | ||||
-rw-r--r-- | sw/source/core/layout/fly.cxx | 6 | ||||
-rw-r--r-- | sw/source/core/layout/flycnt.cxx | 28 | ||||
-rw-r--r-- | sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx | 18 | ||||
-rw-r--r-- | sw/source/core/text/frmform.cxx | 12 | ||||
-rw-r--r-- | sw/source/core/text/itratr.cxx | 32 | ||||
-rw-r--r-- | sw/source/core/text/itrform2.cxx | 29 |
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()); } } |