[Libreoffice-commits] core.git: Branch 'private/mst/sw_redlinehide' - 199 commits - sw/inc sw/source

Michael Stahl Michael.Stahl at cib.de
Wed Jun 6 12:56:42 UTC 2018


Rebased ref, commits from common ancestor:
commit f2d9e4f42c0562a84d3f3c7977866227dc94dba9
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue Jun 5 15:49:21 2018 +0200

    fix sw_redlinehide: use WriterMultiListener to connect SwTextFrame
    
    Unfortunately there's still a few GetTextNode() left and those will
    crash now...
    
    Change-Id: I3318b422eaa8108ada5978f09f3c2801f4442ce2

diff --git a/sw/source/core/layout/ssfrm.cxx b/sw/source/core/layout/ssfrm.cxx
index 3012bd954a94..7be4a5615a5d 100644
--- a/sw/source/core/layout/ssfrm.cxx
+++ b/sw/source/core/layout/ssfrm.cxx
@@ -443,7 +443,10 @@ void SwTextFrame::RegisterToNode(SwTextNode & rNode)
 {
     assert(&rNode != GetDep());
     m_pMergedPara = sw::CheckParaRedlineMerge(*this, rNode);
-    rNode.Add( this );
+    if (!m_pMergedPara)
+    {
+        rNode.Add(this);
+    }
 }
 
 void SwLayoutFrame::DestroyImpl()
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 09e72ea5a75d..9ae23cb69772 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -123,6 +123,7 @@ CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode)
     {
         pRet->listener.StartListening(pTmp);
     }
+    rFrame.EndListeningAll();
     return pRet;
 }
 
commit d8944f1d12c8de5088f5026495b970dd9521e4e0
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Mon May 7 17:44:44 2018 +0200

    hack in Show - not sure if...
    
    Change-Id: I6ca49cfe9c61b3562e87ca994b284e056c2bab54

diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index a7a56c6f81aa..ad1a5925d644 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -60,6 +60,7 @@
 #include <txtfld.hxx>
 
 #include <flowfrm.hxx>
+#include <txtfrm.hxx>
 
 using namespace com::sun::star;
 
@@ -1672,6 +1673,20 @@ void SwRangeRedline::MoveFromSection(size_t nMyPos)
             *pItem = *Start();
         for( auto& pItem : aBehindArr )
             *pItem = *End();
+
+        // sw_redlinehide: assume that Show will only be called by filters;
+        // when it is called, ensure that no MergedPara instance survives
+        for (SwNodeIndex node = Start()->nNode; node.GetIndex() <= End()->nNode.GetIndex(); ++node)
+        {
+            if (SwTextNode const*const pNode = node.GetNode().GetTextNode())
+            {
+                SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pNode);
+                for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
+                {
+                    pFrame->SetMergedPara(nullptr);
+                }
+            }
+        }
     }
     else
         InvalidateRange();
commit 9989e3d5de22747fc82093f8819cb4a78a0e3a12
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Thu May 17 13:00:33 2018 +0200

    sw_redlinehide: let the Show menu item toggle new mode
    
    Change-Id: I1201e84b231be17e6a5ec2294acfb1e3111c9ada

diff --git a/sw/source/uibase/uiview/view2.cxx b/sw/source/uibase/uiview/view2.cxx
index 90ca68a0f404..1d57aefdd498 100644
--- a/sw/source/uibase/uiview/view2.cxx
+++ b/sw/source/uibase/uiview/view2.cxx
@@ -140,6 +140,7 @@
 #include <vcl/settings.hxx>
 #include <i18nutil/searchopt.hxx>
 #include <paratr.hxx>
+#include <rootfrm.hxx>
 
 #include <memory>
 
@@ -639,7 +640,15 @@ void SwView::Execute(SfxRequest &rReq)
                 if( static_cast<const SfxBoolItem*>(pItem)->GetValue() )
                     nMode |= RedlineFlags::ShowDelete;
 
-                m_pWrtShell->SetRedlineFlagsAndCheckInsMode( nMode );
+                if (getenv("SW_REDLINEHIDE")) // TODO...
+                {
+                    m_pWrtShell->GetLayout()->SetHideRedlines(
+                        !static_cast<const SfxBoolItem*>(pItem)->GetValue());
+                    if (m_pWrtShell->IsRedlineOn())
+                        m_pWrtShell->SetInsMode();
+                }
+                else
+                    m_pWrtShell->SetRedlineFlagsAndCheckInsMode( nMode );
             }
             break;
         case FN_MAILMERGE_SENDMAIL_CHILDWINDOW:
commit c72566666f327313a780053a623e6c14195e0e59
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Thu May 17 14:16:27 2018 +0200

    sw_redlinehide: very incomplete impl. of SwRootFrame::SetHideRedlines()
    
    Change-Id: Icff1b1aac20a0a6d3f957e7025f6a08a6d0edbee

diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index a25bb8d7bb9f..2406868f5c4c 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -4171,6 +4171,47 @@ void SwRootFrame::SetHideRedlines(bool const bHideRedlines)
         return;
     }
     mbHideRedlines = bHideRedlines;
+    SwNodes const& rNodes(GetFormat()->GetDoc()->GetNodes());
+    // Hide->Show: clear MergedPara, create frames
+    // Show->Hide: call CheckParaRedlineMerge, delete frames
+    // TODO how to traverse
+    // * via layout
+    //      - but that won't find nodes that don't have frames in ->Show case
+    // * via nodes
+    //      - what about special sections before content? flys? footnotes?
+    //        is order of these predictable? flys not anchored in content?
+    // * ideally should call something existing that tries to create everything?
+    //      - is that done automatically somewhere already?
+    // * other direction ->Hide - delete frames!
+    // in-order traversal should init flags in nodes *before* the nodes are found
+    for (sal_uLong i = 0; i < rNodes.Count(); ++i)
+    {
+        SwNode *const pNode(rNodes[i]);
+        if (pNode->IsTextNode())
+        {
+            SwTextNode & rTextNode(*pNode->GetTextNode());
+            SwIterator<SwTextFrame, SwTextNode> aIter(rTextNode);
+            for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
+            {
+                if (pFrame->getRootFrame() == this)
+                {
+                    if (mbHideRedlines && pNode->IsCreateFrameWhenHidingRedlines())
+                    {
+                        pFrame->SetMergedPara(CheckParaRedlineMerge(*pFrame, rTextNode));
+                    }
+                    else
+                    {
+                        if (pFrame->GetMergedPara())
+                        {
+                            pFrame->SetMergedPara(nullptr);
+                            rTextNode.DelFrames(); // FIXME only those in this layout?
+                        }
+                    }
+                }
+            }
+        }
+    }
+    InvalidateAllContent(SwInvalidateFlags::Size); // ??? TODO what to invalidate?
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit ecebfac5a120ef9afcf142280df2c2fe230b5863
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue Jun 5 13:41:58 2018 +0200

    sw_redlinehide: send a hint to the SwTextFrame when Delete redline
    
    ... is created or updated; there is already a SwUpdateAttr
    hint being sent from SwRangeRedline::InvalidateRange(),
    but it doesn't contain any info about the redline other than the
    position; add a new hint sw::RedlineDelText and send it from there in
    addition to the existing one.
    
    Change-Id: I37150b2a5ca6a0e70ea4a5788f720f8522227631

diff --git a/sw/inc/hints.hxx b/sw/inc/hints.hxx
index 4da6408dfe99..dc31d7424756 100644
--- a/sw/inc/hints.hxx
+++ b/sw/inc/hints.hxx
@@ -93,6 +93,19 @@ public:
     SwDelText( sal_Int32 nS, sal_Int32 nL );
 };
 
+namespace sw {
+
+class RedlineDelText : public SfxHint
+{
+public:
+    sal_Int32 nStart;
+    sal_Int32 nLen;
+
+    RedlineDelText(sal_Int32 nS, sal_Int32 nL);
+};
+
+}
+
 class SwUpdateAttr : public SwMsgPoolItem
 {
 private:
diff --git a/sw/source/core/attr/hints.cxx b/sw/source/core/attr/hints.cxx
index 678db2590528..44c60ff0fd17 100644
--- a/sw/source/core/attr/hints.cxx
+++ b/sw/source/core/attr/hints.cxx
@@ -46,6 +46,15 @@ SwDelText::SwDelText( sal_Int32 nS, sal_Int32 nL )
 {
 }
 
+namespace sw {
+
+RedlineDelText::RedlineDelText(sal_Int32 const nS, sal_Int32 const nL)
+    : nStart(nS), nLen(nL)
+{
+}
+
+} // namespace sw
+
 SwUpdateAttr::SwUpdateAttr( sal_Int32 nS, sal_Int32 nE, sal_uInt16 nW )
     : SwMsgPoolItem( RES_UPDATE_ATTR ), m_nStart( nS ), m_nEnd( nE ), m_nWhichAttr( nW )
 {
diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index c5731c36c457..a7a56c6f81aa 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -1269,6 +1269,15 @@ void SwRangeRedline::InvalidateRange()       // trigger the Layout
         if (pNode && pNode->IsTextNode())
         {
             SwTextNode* pNd = pNode->GetTextNode();
+
+            if (GetType() == nsRedlineType_t::REDLINE_DELETE)
+            {
+                sw::RedlineDelText const hint(
+                    n == nSttNd ? nSttCnt : 0,
+                    n == nEndNd ? nEndCnt : pNd->GetText().getLength());
+                pNd->CallSwClientNotify(hint);
+            }
+
             SwUpdateAttr aHt(
                 n == nSttNd ? nSttCnt : 0,
                 n == nEndNd ? nEndCnt : pNd->GetText().getLength(),
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index fae1cb86bf09..22502f48d6df 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -1510,18 +1510,30 @@ static bool isA11yRelevantAttribute(sal_uInt16 nWhich)
 // SwContentFrame::Modify() when appropriate.
 void SwTextFrame::SwClientNotify(SwModify const& rModify, SfxHint const& rHint)
 {
-    auto const pHint(dynamic_cast<sw::LegacyModifyHint const*>(&rHint));
-    assert(pHint); // TODO this is the only type expected here for now
+    SfxPoolItem const* pOld(nullptr);
+    SfxPoolItem const* pNew(nullptr);
+    sw::RedlineDelText const* pRedlineDelText(nullptr);
 
-    SfxPoolItem const*const pOld(pHint->m_pOld);
-    SfxPoolItem const*const pNew(pHint->m_pNew);
-    SwTextNode const& rNode(static_cast<SwTextNode const&>(rModify));
+    if (auto const pHint = dynamic_cast<sw::LegacyModifyHint const*>(&rHint))
+    {
+        pOld = pHint->m_pOld;
+        pNew = pHint->m_pNew;
+    }
+    else if (auto const pHynt = dynamic_cast<sw::RedlineDelText const*>(&rHint))
+    {
+        pRedlineDelText = pHynt;
+    }
+    else
+    {
+        assert(!"unexpected hint");
+    }
 
     if (m_pMergedPara)
     {
         assert(m_pMergedPara->listener.IsListeningTo(&rModify));
     }
 
+    SwTextNode const& rNode(static_cast<SwTextNode const&>(rModify));
     const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
 
     // modifications concerning frame attributes are processed by the base class
@@ -1573,7 +1585,34 @@ void SwTextFrame::SwClientNotify(SwModify const& rModify, SfxHint const& rHint)
     bool bSetFieldsDirty = false;
     bool bRecalcFootnoteFlag = false;
 
-    switch( nWhich )
+    if (pRedlineDelText)
+    {
+        if (m_pMergedPara)
+        {
+            sal_Int32 const nNPos = pRedlineDelText->nStart;
+            sal_Int32 const nNLen = pRedlineDelText->nLen;
+            nPos = MapModelToView(&rNode, nNPos);
+            // update merged before doing anything else
+            nLen = UpdateMergedParaForDelete(*m_pMergedPara, rNode, nNPos, nNLen);
+            const sal_Int32 m = -nNLen;
+            if (nLen && IsIdxInside(nPos, nLen))
+            {
+                if (!nLen)
+                    InvalidateSize();
+                else
+                    InvalidateRange( SwCharRange(nPos, TextFrameIndex(1)), m );
+            }
+            lcl_SetWrong( *this, rNode, nNPos, m, true );
+            if (nLen)
+            {
+                lcl_SetScriptInval( *this, nPos );
+                bSetFieldsDirty = bRecalcFootnoteFlag = true;
+                if (HasFollow())
+                    lcl_ModifyOfst( this, nPos, nLen );
+            }
+        }
+    }
+    else switch (nWhich)
     {
         case RES_LINENUMBER:
         {
commit b5f25729dace62e0b426b0a6d5133111a6f3e0d4
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri Jun 1 22:45:55 2018 +0200

    sw_redlinehide: SwTextNode::Insert(): send SwInsText hint before
    
    ... adjusting hints, as the latter sends RES_UPDATE_ATTR hints
    and the ModelToViewPos() asserts because the mergedText is too short.
    
    Change-Id: I48bf6388ce69f3294decf96dc6dd11ba3bf4bc7b

diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index b044a7439429..a241caf00d4e 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -1993,6 +1993,12 @@ OUString SwTextNode::InsertText( const OUString & rStr, const SwIndex & rIdx,
         SetIgnoreDontExpand( bOldExpFlg );
     }
 
+    if ( HasWriterListeners() )
+    {   // send this before messing with hints, which will send RES_UPDATE_ATTR
+        SwInsText aHint( aPos, nLen );
+        NotifyClients( nullptr, &aHint );
+    }
+
     if ( HasHints() )
     {
         bool const bHadHints(!m_pSwpHints->CanBeDeleted());
@@ -2064,12 +2070,6 @@ OUString SwTextNode::InsertText( const OUString & rStr, const SwIndex & rIdx,
                 "SwTextNode::InsertText: unexpected loss of hints");
     }
 
-    if ( HasWriterListeners() )
-    {
-        SwInsText aHint( aPos, nLen );
-        NotifyClients( nullptr, &aHint );
-    }
-
     // By inserting a character, the hidden flags
     // at the TextNode can become invalid:
     SetCalcHiddenCharFlags();
commit 47cdd88ff6c4b8c0e0ae0960a4ac10a4f5eedb4f
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Wed Jun 6 13:29:04 2018 +0200

    sw_redlinehide: convert SwTextSizeInfo::GetMultiCreator()
    
    Very tricky ... i'd be surprised if this actually works :-/
    
    Change-Id: I309db66e64838aaf92609313d04c4fe3d096c6ee

diff --git a/sw/source/core/text/pormulti.cxx b/sw/source/core/text/pormulti.cxx
index 838f90cb296d..7d671961dff0 100644
--- a/sw/source/core/text/pormulti.cxx
+++ b/sw/source/core/text/pormulti.cxx
@@ -756,10 +756,9 @@ void SwRubyPortion::CalcRubyOffset()
 // no 2-line-format reference is passed. If there is a 2-line-format reference,
 // then the rValue is set only, if the 2-line-attribute's value is set _and_
 // the 2-line-formats has the same brackets.
-static bool lcl_Has2Lines( const SwTextAttr& rAttr, const SvxTwoLinesItem* &rpRef,
-    bool &rValue )
+static bool lcl_Check2Lines(const SfxPoolItem *const pItem,
+        const SvxTwoLinesItem* &rpRef, bool &rValue)
 {
-    const SfxPoolItem* pItem = CharFormat::GetItem( rAttr, RES_CHRATR_TWO_LINES );
     if( pItem )
     {
         rValue = static_cast<const SvxTwoLinesItem*>(pItem)->GetValue();
@@ -775,6 +774,13 @@ static bool lcl_Has2Lines( const SwTextAttr& rAttr, const SvxTwoLinesItem* &rpRe
     return false;
 }
 
+static bool lcl_Has2Lines(const SwTextAttr& rAttr,
+        const SvxTwoLinesItem* &rpRef, bool &rValue)
+{
+    const SfxPoolItem* pItem = CharFormat::GetItem(rAttr, RES_CHRATR_TWO_LINES);
+    return lcl_Check2Lines(pItem, rpRef, rValue);
+}
+
 // is a little help function for GetMultiCreator(..)
 // It extracts the charrotation from a charrotate-attribute or a character style.
 // The rValue is set to true, if the charrotate-attribute's value is set and
@@ -782,10 +788,9 @@ static bool lcl_Has2Lines( const SwTextAttr& rAttr, const SvxTwoLinesItem* &rpRe
 // If there is a charrotate-format reference, then the rValue is set only,
 // if the charrotate-attribute's value is set _and_ identical
 // to the charrotate-format's value.
-static bool lcl_HasRotation( const SwTextAttr& rAttr,
-    const SvxCharRotateItem* &rpRef, bool &rValue )
+static bool lcl_CheckRotation(const SfxPoolItem *const pItem,
+        const SvxCharRotateItem* &rpRef, bool &rValue)
 {
-    const SfxPoolItem* pItem = CharFormat::GetItem( rAttr, RES_CHRATR_ROTATE );
     if ( pItem )
     {
         rValue = static_cast<const SvxCharRotateItem*>(pItem)->GetValue();
@@ -800,6 +805,100 @@ static bool lcl_HasRotation( const SwTextAttr& rAttr,
     return false;
 }
 
+static bool lcl_HasRotation(const SwTextAttr& rAttr,
+        const SvxCharRotateItem* &rpRef, bool &rValue)
+{
+    const SfxPoolItem* pItem = CharFormat::GetItem( rAttr, RES_CHRATR_ROTATE );
+    return lcl_CheckRotation(pItem, rpRef, rValue);
+}
+
+namespace sw {
+
+    // need to use a very special attribute iterator here that returns
+    // both the hints and the nodes, so that GetMultiCreator() can handle
+    // items in the nodes' set properly
+    class MergedAttrIterMulti
+        : public MergedAttrIterBase
+    {
+    private:
+        bool m_First = true;
+    public:
+        MergedAttrIterMulti(SwTextFrame const& rFrame) : MergedAttrIterBase(rFrame) {}
+        SwTextAttr const* NextAttr(SwTextNode const*& rpNode);
+        // can't have operator= because m_pMerged/m_pNode const
+        void Assign(MergedAttrIterMulti const& rOther)
+        {
+            assert(m_pMerged == rOther.m_pMerged);
+            assert(m_pNode == rOther.m_pNode);
+            m_CurrentExtent = rOther.m_CurrentExtent;
+            m_CurrentHint = rOther.m_CurrentHint;
+            m_First = rOther.m_First;
+        }
+    };
+
+    SwTextAttr const* MergedAttrIterMulti::NextAttr(SwTextNode const*& rpNode)
+    {
+        if (m_First)
+        {
+            m_First = false;
+            rpNode = m_pMerged
+                ? m_pMerged->extents.size()
+                    ? m_pMerged->extents[0].pNode
+                    : m_pMerged->pFirstNode
+                : m_pNode;
+            return nullptr;
+        }
+        if (m_pMerged)
+        {
+            while (m_CurrentExtent < m_pMerged->extents.size())
+            {
+                sw::Extent const& rExtent(m_pMerged->extents[m_CurrentExtent]);
+                if (SwpHints const*const pHints = rExtent.pNode->GetpSwpHints())
+                {
+                    while (m_CurrentHint < pHints->Count())
+                    {
+                        SwTextAttr const*const pHint(pHints->Get(m_CurrentHint));
+                        if (rExtent.nEnd < pHint->GetStart())
+                        {
+                            break;
+                        }
+                        ++m_CurrentHint;
+                        if (rExtent.nStart <= pHint->GetStart())
+                        {
+                            rpNode = rExtent.pNode;
+                            return pHint;
+                        }
+                    }
+                }
+                ++m_CurrentExtent;
+                if (m_CurrentExtent < m_pMerged->extents.size() &&
+                    rExtent.pNode != m_pMerged->extents[m_CurrentExtent].pNode)
+                {
+                    m_CurrentHint = 0; // reset
+                    rpNode = rExtent.pNode;
+                    return nullptr;
+                }
+            }
+            return nullptr;
+        }
+        else
+        {
+            SwpHints const*const pHints(m_pNode->GetpSwpHints());
+            if (pHints)
+            {
+                while (m_CurrentHint < pHints->Count())
+                {
+                    SwTextAttr const*const pHint(pHints->Get(m_CurrentHint));
+                    ++m_CurrentHint;
+                    rpNode = m_pNode;
+                    return pHint;
+                }
+            }
+            return nullptr;
+        }
+    }
+}
+
 // If we (e.g. the position rPos) are inside a two-line-attribute or
 // a ruby-attribute, the attribute will be returned in a SwMultiCreator-struct,
 // otherwise the function returns zero.
@@ -854,66 +953,99 @@ SwMultiCreator* SwTextSizeInfo::GetMultiCreator(TextFrameIndex &rPos,
     if ( pMulti )
         return nullptr;
 
-    const SvxCharRotateItem* pRotate = nullptr;
-    const SfxPoolItem* pRotItem;
-    if( SfxItemState::SET == m_pFrame->GetTextNode()->GetSwAttrSet().
-        GetItemState( RES_CHRATR_ROTATE, true, &pRotItem ) &&
-        static_cast<const SvxCharRotateItem*>(pRotItem)->GetValue() )
-        pRotate = static_cast<const SvxCharRotateItem*>(pRotItem);
-    else
-        pRotItem = nullptr;
-    const SvxTwoLinesItem* p2Lines = nullptr;
-    const SwTextNode *pLclTextNode = m_pFrame->GetTextNode();
-    if( !pLclTextNode )
-        return nullptr;
-    const SfxPoolItem* pItem;
-    if( SfxItemState::SET == pLclTextNode->GetSwAttrSet().
-        GetItemState( RES_CHRATR_TWO_LINES, true, &pItem ) &&
-        static_cast<const SvxTwoLinesItem*>(pItem)->GetValue() )
-        p2Lines = static_cast<const SvxTwoLinesItem*>(pItem);
-    else
-        pItem = nullptr;
-
-    const SwpHints *pHints = pLclTextNode->GetpSwpHints();
-    if( !pHints && !p2Lines && !pRotate )
-        return nullptr;
+    // need the node that contains input rPos
+    std::pair<SwTextNode const*, sal_Int32> startPos(m_pFrame->MapViewToModel(rPos));
+    const SvxCharRotateItem* pActiveRotateItem = nullptr;
+    const SfxPoolItem* pNodeRotateItem;
+    const SvxTwoLinesItem* pActiveTwoLinesItem = nullptr;
+    const SfxPoolItem* pNodeTwoLinesItem;
+    SwTextAttr const* pActiveTwoLinesHint(nullptr);
+    SwTextAttr const* pActiveRotateHint(nullptr);
     const SwTextAttr *pRuby = nullptr;
+    sw::MergedAttrIterMulti iterAtStartOfNode(*m_pFrame);
     bool bTwo = false;
     bool bRot = false;
-    size_t n2Lines = SAL_MAX_SIZE;
-    size_t nRotate = SAL_MAX_SIZE;
-    const size_t nCount = pHints ? pHints->Count() : 0;
-    for( size_t i = 0; i < nCount; ++i )
-    {
-        const SwTextAttr *pTmp = pHints->Get(i);
-        sal_Int32 nStart = pTmp->GetStart();
-        if( rPos < nStart )
+
+    for (sw::MergedAttrIterMulti iter = *m_pFrame; ; )
+    {
+        SwTextNode const* pNode(nullptr);
+        SwTextAttr const*const pAttr = iter.NextAttr(pNode);
+        if (!pNode)
+        {
             break;
-        if( *pTmp->GetAnyEnd() > rPos )
+        }
+        if (pAttr)
         {
-            if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
-                pRuby = pTmp;
-            else
+            assert(pNode->GetIndex() <= startPos.first->GetIndex()); // should break earlier
+            if (startPos.first->GetIndex() <= pNode->GetIndex())
             {
-                const SvxCharRotateItem* pRoTmp = nullptr;
-                if( lcl_HasRotation( *pTmp, pRoTmp, bRot ) )
+                if (startPos.first->GetIndex() != pNode->GetIndex()
+                    || startPos.second < pAttr->GetStart())
                 {
-                    nRotate = bRot ? i : nCount;
-                    pRotate = pRoTmp;
+                    break;
                 }
-                const SvxTwoLinesItem* p2Tmp = nullptr;
-                if( lcl_Has2Lines( *pTmp, p2Tmp, bTwo ) )
+                if (startPos.second < *pAttr->GetAnyEnd())
                 {
-                    n2Lines = bTwo ? i : nCount;
-                    p2Lines = p2Tmp;
+                    // sw_redlinehide: ruby *always* splits
+                    if (RES_TXTATR_CJK_RUBY == pAttr->Which())
+                        pRuby = pAttr;
+                    else
+                    {
+                        const SvxCharRotateItem* pRoTmp = nullptr;
+                        if (lcl_HasRotation( *pAttr, pRoTmp, bRot ))
+                        {
+                            pActiveRotateHint = bRot ? pAttr : nullptr;
+                            pActiveRotateItem = pRoTmp;
+                        }
+                        const SvxTwoLinesItem* p2Tmp = nullptr;
+                        if (lcl_Has2Lines( *pAttr, p2Tmp, bTwo ))
+                        {
+                            pActiveTwoLinesHint = bTwo ? pAttr : nullptr;
+                            pActiveTwoLinesItem = p2Tmp;
+                        }
+                    }
+                }
+            }
+        }
+        else if (pNode) // !pAttr && pNode means the node changed
+        {
+            if (startPos.first->GetIndex() < pNode->GetIndex())
+            {
+                break; // only one node initially
+            }
+            if (startPos.first->GetIndex() == pNode->GetIndex())
+            {
+                iterAtStartOfNode.Assign(iter);
+                if (SfxItemState::SET == pNode->GetSwAttrSet().GetItemState(
+                            RES_CHRATR_ROTATE, true, &pNodeRotateItem) &&
+                    static_cast<const SvxCharRotateItem*>(pNodeRotateItem)->GetValue())
+                {
+                    pActiveRotateItem = static_cast<const SvxCharRotateItem*>(pNodeRotateItem);
+                }
+                else
+                {
+                    pNodeRotateItem = nullptr;
+                }
+                if (SfxItemState::SET == startPos.first->GetSwAttrSet().GetItemState(
+                            RES_CHRATR_TWO_LINES, true, &pNodeTwoLinesItem) &&
+                    static_cast<const SvxTwoLinesItem*>(pNodeTwoLinesItem)->GetValue())
+                {
+                    pActiveTwoLinesItem = static_cast<const SvxTwoLinesItem*>(pNodeTwoLinesItem);
+                }
+                else
+                {
+                    pNodeTwoLinesItem = nullptr;
                 }
             }
         }
     }
+    if (!pRuby && !pActiveTwoLinesItem && !pActiveRotateItem)
+        return nullptr;
+
     if( pRuby )
     {   // The winner is ... a ruby attribute and so
         // the end of the multiportion is the end of the ruby attribute.
-        rPos = *pRuby->End();
+        rPos = m_pFrame->MapModelToView(startPos.first, *pRuby->End());
         SwMultiCreator *pRet = new SwMultiCreator;
         pRet->pItem = nullptr;
         pRet->pAttr = pRuby;
@@ -921,44 +1053,48 @@ SwMultiCreator* SwTextSizeInfo::GetMultiCreator(TextFrameIndex &rPos,
         pRet->nLevel = GetTextFrame()->IsRightToLeft() ? 1 : 0;
         return pRet;
     }
-    if( n2Lines < nCount || ( pItem && pItem == p2Lines &&
-        rPos < TextFrameIndex(GetText().getLength())))
+    if (pActiveTwoLinesHint ||
+        (pNodeTwoLinesItem && pNodeTwoLinesItem == pActiveTwoLinesItem &&
+         rPos < TextFrameIndex(GetText().getLength())))
     {   // The winner is a 2-line-attribute,
         // the end of the multiportion depends on the following attributes...
         SwMultiCreator *pRet = new SwMultiCreator;
 
         // We note the endpositions of the 2-line attributes in aEnd as stack
-        std::deque< sal_Int32 > aEnd;
+        std::deque<TextFrameIndex> aEnd;
 
         // The bOn flag signs the state of the last 2-line attribute in the
         // aEnd-stack, it is compatible with the winner-attribute or
         // it interrupts the other attribute.
         bool bOn = true;
 
-        if( n2Lines < nCount )
+        if (pActiveTwoLinesHint)
         {
             pRet->pItem = nullptr;
-            pRet->pAttr = pHints->Get(n2Lines);
-            aEnd.push_front( *pRet->pAttr->End() );
-            if( pItem )
+            pRet->pAttr = pActiveTwoLinesHint;
+            if (pNodeTwoLinesItem)
+            {
+                aEnd.push_front(m_pFrame->MapModelToView(startPos.first, startPos.first->Len()));
+                bOn = static_cast<const SvxTwoLinesItem*>(pNodeTwoLinesItem)->GetEndBracket() ==
+                        pActiveTwoLinesItem->GetEndBracket() &&
+                      static_cast<const SvxTwoLinesItem*>(pNodeTwoLinesItem)->GetStartBracket() ==
+                        pActiveTwoLinesItem->GetStartBracket();
+            }
+            else
             {
-                aEnd.front() = GetText().getLength();
-                bOn = static_cast<const SvxTwoLinesItem*>(pItem)->GetEndBracket() ==
-                        p2Lines->GetEndBracket() &&
-                      static_cast<const SvxTwoLinesItem*>(pItem)->GetStartBracket() ==
-                        p2Lines->GetStartBracket();
+                aEnd.push_front(m_pFrame->MapModelToView(startPos.first, *pRet->pAttr->End()));
             }
         }
         else
         {
-            pRet->pItem = pItem;
+            pRet->pItem = pNodeTwoLinesItem;
             pRet->pAttr = nullptr;
-            aEnd.push_front( GetText().getLength() );
+            aEnd.push_front(m_pFrame->MapModelToView(startPos.first, startPos.first->Len()));
         }
         pRet->nId = SwMultiCreatorId::Double;
         pRet->nLevel = GetTextFrame()->IsRightToLeft() ? 1 : 0;
 
-        // n2Lines is the index of the last 2-line-attribute, which contains
+        // pActiveTwoLinesHint is the last 2-line-attribute, which contains
         // the actual position.
 
         // At this moment we know that at position rPos the "winner"-attribute
@@ -975,23 +1111,49 @@ SwMultiCreator* SwTextSizeInfo::GetMultiCreator(TextFrameIndex &rPos,
         // In the following loop rPos is the critical position and it will be
         // evaluated, if at rPos starts a interrupting or a maintaining
         // continuity attribute.
-        for( size_t i = 0; i < nCount; ++i )
+
+        // iterAtStartOfNode is positioned to the first hint of the node
+        // (if any); the node item itself has already been handled above
+        for (sw::MergedAttrIterMulti iter = iterAtStartOfNode; ; )
         {
-            const SwTextAttr *pTmp = pHints->Get(i);
-            if( *pTmp->GetAnyEnd() <= rPos )
-                continue;
-            if( rPos < pTmp->GetStart() )
+            SwTextNode const* pNode(nullptr);
+            SwTextAttr const*const pTmp = iter.NextAttr(pNode);
+            if (!pNode)
+            {
+                break;
+            }
+            assert(startPos.first->GetIndex() <= pNode->GetIndex());
+            TextFrameIndex nTmpStart;
+            TextFrameIndex nTmpEnd;
+            if (pTmp)
+            {
+                nTmpEnd = m_pFrame->MapModelToView(pNode, *pTmp->GetAnyEnd());
+                if (nTmpEnd <= rPos)
+                    continue;
+                nTmpStart = m_pFrame->MapModelToView(pNode, pTmp->GetStart());
+            }
+            else
+            {
+                pNodeTwoLinesItem = nullptr;
+                pNode->GetSwAttrSet().GetItemState(
+                            RES_CHRATR_TWO_LINES, true, &pNodeTwoLinesItem);
+                nTmpStart = m_pFrame->MapModelToView(pNode, 0);
+                nTmpEnd = m_pFrame->MapModelToView(pNode, pNode->Len());
+                assert(rPos <= nTmpEnd); // next node must not have smaller index
+            }
+
+            if (rPos < nTmpStart)
             {
                 // If bOn is false and the next attribute starts later than rPos
                 // the winner attribute is interrupted at rPos.
                 // If the start of the next attribute is behind the end of
                 // the last attribute on the aEnd-stack, this is the endposition
                 // on the stack is the end of the 2-line portion.
-                if( !bOn || aEnd.back() < pTmp->GetStart() )
+                if (!bOn || aEnd.back() < nTmpStart)
                     break;
                 // At this moment, bOn is true and the next attribute starts
                 // behind rPos, so we could move rPos to the next startpoint
-                rPos = pTmp->GetStart();
+                rPos = nTmpStart;
                 // We clean up the aEnd-stack, endpositions equal to rPos are
                 // superfluous.
                 while( !aEnd.empty() && aEnd.back() <= rPos )
@@ -1008,15 +1170,16 @@ SwMultiCreator* SwTextSizeInfo::GetMultiCreator(TextFrameIndex &rPos,
                 }
             }
             // A ruby attribute stops the 2-line immediately
-            if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
+            if (pTmp && RES_TXTATR_CJK_RUBY == pTmp->Which())
                 return pRet;
-            if( lcl_Has2Lines( *pTmp, p2Lines, bTwo ) )
+            if (pTmp ? lcl_Has2Lines(*pTmp, pActiveTwoLinesItem, bTwo)
+                     : lcl_Check2Lines(pNodeTwoLinesItem, pActiveTwoLinesItem, bTwo))
             {   // We have an interesting attribute..
                 if( bTwo == bOn )
                 {   // .. with the same state, so the last attribute could
                     // be continued.
-                    if( aEnd.back() < *pTmp->End() )
-                        aEnd.back() = *pTmp->End();
+                    if (aEnd.back() < nTmpEnd)
+                        aEnd.back() = nTmpEnd;
                 }
                 else
                 {   // .. with a different state.
@@ -1024,12 +1187,12 @@ SwMultiCreator* SwTextSizeInfo::GetMultiCreator(TextFrameIndex &rPos,
                     // If this is smaller than the last on the stack, we put
                     // it on the stack. If it has the same endposition, the last
                     // could be removed.
-                    if( aEnd.back() > *pTmp->End() )
-                        aEnd.push_back( *pTmp->End() );
+                    if (nTmpEnd < aEnd.back())
+                        aEnd.push_back( nTmpEnd );
                     else if( aEnd.size() > 1 )
                         aEnd.pop_back();
                     else
-                        aEnd.back() = *pTmp->End();
+                        aEnd.back() = nTmpEnd;
                 }
             }
         }
@@ -1037,32 +1200,58 @@ SwMultiCreator* SwTextSizeInfo::GetMultiCreator(TextFrameIndex &rPos,
             rPos = aEnd.back();
         return pRet;
     }
-    if (nRotate < nCount || ( pRotItem && pRotItem == pRotate &&
-        rPos < TextFrameIndex(GetText().getLength())))
+    if (pActiveRotateHint ||
+        (pNodeRotateItem && pNodeRotateItem == pActiveRotateItem &&
+         rPos < TextFrameIndex(GetText().getLength())))
     {   // The winner is a rotate-attribute,
         // the end of the multiportion depends on the following attributes...
         SwMultiCreator *pRet = new SwMultiCreator;
         pRet->nId = SwMultiCreatorId::Rotate;
 
         // We note the endpositions of the 2-line attributes in aEnd as stack
-        std::deque< sal_Int32 > aEnd;
+        std::deque<TextFrameIndex> aEnd;
 
         // The bOn flag signs the state of the last 2-line attribute in the
         // aEnd-stack, which could interrupts the winning rotation attribute.
-        bool bOn = pItem;
-        aEnd.push_front( GetText().getLength() );
+        bool bOn = pNodeTwoLinesItem != nullptr;
+        aEnd.push_front(TextFrameIndex(GetText().getLength()));
 
-        sal_Int32 n2Start = rPos;
-        for( size_t i = 0; i < nCount; ++i )
+        // first, search for the start position of the next TWOLINE portion
+        // because the ROTATE portion must end there at the latest
+        TextFrameIndex n2Start = rPos;
+        for (sw::MergedAttrIterMulti iter = iterAtStartOfNode; ; )
         {
-            const SwTextAttr *pTmp = pHints->Get(i);
-            if( *pTmp->GetAnyEnd() <= n2Start )
-                continue;
-            if( n2Start < pTmp->GetStart() )
+            SwTextNode const* pNode(nullptr);
+            SwTextAttr const*const pTmp = iter.NextAttr(pNode);
+            if (!pNode)
+            {
+                break;
+            }
+            assert(startPos.first->GetIndex() <= pNode->GetIndex());
+            TextFrameIndex nTmpStart;
+            TextFrameIndex nTmpEnd;
+            if (pTmp)
+            {
+                nTmpEnd = m_pFrame->MapModelToView(pNode, *pTmp->GetAnyEnd());
+                if (nTmpEnd <= n2Start)
+                    continue;
+                nTmpStart = m_pFrame->MapModelToView(pNode, pTmp->GetStart());
+            }
+            else
+            {
+                pNodeTwoLinesItem = nullptr;
+                pNode->GetSwAttrSet().GetItemState(
+                            RES_CHRATR_TWO_LINES, true, &pNodeTwoLinesItem);
+                nTmpStart = m_pFrame->MapModelToView(pNode, 0);
+                nTmpEnd = m_pFrame->MapModelToView(pNode, pNode->Len());
+                assert(n2Start <= nTmpEnd); // next node must not have smaller index
+            }
+
+            if (n2Start < nTmpStart)
             {
-                if( bOn || aEnd.back() < pTmp->GetStart() )
+                if (bOn || aEnd.back() < nTmpStart)
                     break;
-                n2Start = pTmp->GetStart();
+                n2Start = nTmpStart;
                 while( !aEnd.empty() && aEnd.back() <= n2Start )
                 {
                     bOn = !bOn;
@@ -1075,28 +1264,29 @@ SwMultiCreator* SwTextSizeInfo::GetMultiCreator(TextFrameIndex &rPos,
                 }
             }
             // A ruby attribute stops immediately
-            if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
+            if (pTmp && RES_TXTATR_CJK_RUBY == pTmp->Which())
             {
                 bOn = true;
                 break;
             }
-            p2Lines = nullptr;
-            if( lcl_Has2Lines( *pTmp, p2Lines, bTwo ) )
+            const SvxTwoLinesItem* p2Lines = nullptr;
+            if (pTmp ? lcl_Has2Lines(*pTmp, p2Lines, bTwo)
+                     : lcl_Check2Lines(pNodeTwoLinesItem, p2Lines, bTwo))
             {
                 if( bTwo == bOn )
                 {
-                    if( aEnd.back() < *pTmp->End() )
-                        aEnd.back() = *pTmp->End();
+                    if (aEnd.back() < nTmpEnd)
+                        aEnd.back() = nTmpEnd;
                 }
                 else
                 {
                     bOn = bTwo;
-                    if( aEnd.back() > *pTmp->End() )
-                        aEnd.push_back( *pTmp->End() );
+                    if (nTmpEnd < aEnd.back())
+                        aEnd.push_back( nTmpEnd );
                     else if( aEnd.size() > 1 )
                         aEnd.pop_back();
                     else
-                        aEnd.back() = *pTmp->End();
+                        aEnd.back() = nTmpEnd;
                 }
             }
         }
@@ -1106,35 +1296,62 @@ SwMultiCreator* SwTextSizeInfo::GetMultiCreator(TextFrameIndex &rPos,
         if( !aEnd.empty() )
             aEnd.clear();
 
+        // now, search for the end of the ROTATE portion, similar to above
         bOn = true;
-        if( nRotate < nCount )
+        if (pActiveRotateHint)
         {
             pRet->pItem = nullptr;
-            pRet->pAttr = pHints->Get(nRotate);
-            aEnd.push_front( *pRet->pAttr->End() );
-            if( pRotItem )
+            pRet->pAttr = pActiveRotateHint;
+            if (pNodeRotateItem)
             {
-                aEnd.front() = GetText().getLength();
-                bOn = static_cast<const SvxCharRotateItem*>(pRotItem)->GetValue() ==
-                        pRotate->GetValue();
+                aEnd.push_front(m_pFrame->MapModelToView(startPos.first, startPos.first->Len()));
+                bOn = static_cast<const SvxCharRotateItem*>(pNodeRotateItem)->GetValue() ==
+                        pActiveRotateItem->GetValue();
+            }
+            else
+            {
+                aEnd.push_front(m_pFrame->MapModelToView(startPos.first, *pRet->pAttr->End()));
             }
         }
         else
         {
-            pRet->pItem = pRotItem;
+            pRet->pItem = pNodeRotateItem;
             pRet->pAttr = nullptr;
-            aEnd.push_front( GetText().getLength() );
+            aEnd.push_front(m_pFrame->MapModelToView(startPos.first, startPos.first->Len()));
         }
-        for( size_t i = 0; i < nCount; ++i )
+        for (sw::MergedAttrIterMulti iter = iterAtStartOfNode; ; )
         {
-            const SwTextAttr *pTmp = pHints->Get(i);
-            if( *pTmp->GetAnyEnd() <= rPos )
-                continue;
-            if( rPos < pTmp->GetStart() )
+            SwTextNode const* pNode(nullptr);
+            SwTextAttr const*const pTmp = iter.NextAttr(pNode);
+            if (!pNode)
+            {
+                break;
+            }
+            assert(startPos.first->GetIndex() <= pNode->GetIndex());
+            TextFrameIndex nTmpStart;
+            TextFrameIndex nTmpEnd;
+            if (pTmp)
+            {
+                nTmpEnd = m_pFrame->MapModelToView(pNode, *pTmp->GetAnyEnd());
+                if (nTmpEnd <= rPos)
+                    continue;
+                nTmpStart = m_pFrame->MapModelToView(pNode, pTmp->GetStart());
+            }
+            else
+            {
+                pNodeRotateItem = nullptr;
+                pNode->GetSwAttrSet().GetItemState(
+                            RES_CHRATR_ROTATE, true, &pNodeRotateItem);
+                nTmpStart = m_pFrame->MapModelToView(pNode, 0);
+                nTmpEnd = m_pFrame->MapModelToView(pNode, pNode->Len());
+                assert(rPos <= nTmpEnd); // next node must not have smaller index
+            }
+
+            if (rPos < nTmpStart)
             {
-                if( !bOn || aEnd.back() < pTmp->GetStart() )
+                if (!bOn || aEnd.back() < nTmpStart)
                     break;
-                rPos = pTmp->GetStart();
+                rPos = nTmpStart;
                 while( !aEnd.empty() && aEnd.back() <= rPos )
                 {
                     bOn = !bOn;
@@ -1146,27 +1363,29 @@ SwMultiCreator* SwTextSizeInfo::GetMultiCreator(TextFrameIndex &rPos,
                     bOn = true;
                 }
             }
-            if( RES_TXTATR_CJK_RUBY == pTmp->Which() )
+            if (pTmp && RES_TXTATR_CJK_RUBY == pTmp->Which())
             {
                 bOn = false;
                 break;
             }
-            if( lcl_HasRotation( *pTmp, pRotate, bTwo ) )
+            // TODO why does this use bTwo, not bRot ???
+            if (pTmp ? lcl_HasRotation(*pTmp, pActiveRotateItem, bTwo)
+                     : lcl_CheckRotation(pNodeRotateItem, pActiveRotateItem, bTwo))
             {
                 if( bTwo == bOn )
                 {
-                    if( aEnd.back() < *pTmp->End() )
-                        aEnd.back() = *pTmp->End();
+                    if (aEnd.back() < nTmpEnd)
+                        aEnd.back() = nTmpEnd;
                 }
                 else
                 {
                     bOn = bTwo;
-                    if( aEnd.back() > *pTmp->End() )
-                        aEnd.push_back( *pTmp->End() );
+                    if (nTmpEnd < aEnd.back())
+                        aEnd.push_back( nTmpEnd );
                     else if( aEnd.size() > 1 )
                         aEnd.pop_back();
                     else
-                        aEnd.back() = *pTmp->End();
+                        aEnd.back() = nTmpEnd;
                 }
             }
         }
commit 4b684cc2e11ffc8e034cc255de6d774767da531d
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri Jun 1 22:41:06 2018 +0200

    sw_redlinehide: convert GetAttrSet() in txtfrm.cxx, frmtool.cxx
    
    Change-Id: I3541fa79ff48f6829fc459ab5bd8224c29c51cbb

diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index cfafce5b3d51..3713439f3f53 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -738,8 +738,7 @@ SwContentNotify::SwContentNotify( SwContentFrame *pContentFrame ) :
         SwTextFrame* pTextFrame = static_cast<SwTextFrame*>(pContentFrame);
         if (!pTextFrame->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::OLD_LINE_SPACING))
         {
-            const SwAttrSet* pSet = pTextFrame->GetAttrSet();
-            const SvxLineSpacingItem &rSpace = pSet->GetLineSpacing();
+            const SvxLineSpacingItem &rSpace = pTextFrame->GetAttrSet()->GetLineSpacing();
             if ( rSpace.GetInterLineSpaceRule() == SvxInterLineSpaceRule::Prop )
             {
                 mbChkHeightOfLastLine = true;
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index 339c23e2a430..fae1cb86bf09 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -2998,7 +2998,8 @@ void SwTextFrame::CalcHeightOfLastLine( const bool _bUseFont )
     {
         // former determination of last line height for proprotional line
         // spacing - take height of font set at the paragraph
-        SwFont aFont( GetAttrSet(), pIDSA );
+        // FIXME actually ... must the font match across all nodes?
+        SwFont aFont( &GetTextNodeForParaProps()->GetSwAttrSet(), pIDSA );
 
         // we must ensure that the font is restored correctly on the OutputDevice
         // otherwise Last!=Owner could occur
@@ -3104,8 +3105,7 @@ long SwTextFrame::GetLineSpace( const bool _bNoPropLineSpace ) const
 {
     long nRet = 0;
 
-    const SwAttrSet* pSet = GetAttrSet();
-    const SvxLineSpacingItem &rSpace = pSet->GetLineSpacing();
+    const SvxLineSpacingItem &rSpace = GetTextNodeForParaProps()->GetSwAttrSet().GetLineSpacing();
 
     switch( rSpace.GetInterLineSpaceRule() )
     {
@@ -3206,7 +3206,7 @@ void SwTextFrame::ChgThisLines()
 
     if ( nNew != mnThisLines )
     {
-        if ( !IsInTab() && GetAttrSet()->GetLineNumber().IsCount() )
+        if (!IsInTab() && GetTextNodeForParaProps()->GetSwAttrSet().GetLineNumber().IsCount())
         {
             mnAllLines -= mnThisLines;
             mnThisLines = nNew;
@@ -3237,12 +3237,10 @@ void SwTextFrame::RecalcAllLines()
 {
     ValidateLineNum();
 
-    const SwAttrSet *pAttrSet = GetAttrSet();
-
     if ( !IsInTab() )
     {
         const sal_uLong nOld = GetAllLines();
-        const SwFormatLineNumber &rLineNum = pAttrSet->GetLineNumber();
+        const SwFormatLineNumber &rLineNum = GetTextNodeForParaProps()->GetSwAttrSet().GetLineNumber();
         sal_uLong nNewNum;
         const bool bRestart = GetDoc().GetLineNumberInfo().IsRestartEachPage();
 
commit c04b4f8900af087998adf85f1988833ae617d104
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri Jun 1 22:37:02 2018 +0200

    sw_redlinehide: move SwContentNode::GetNode() to SwNoTextNode
    
    SwTextNode's GetDep() may be a WriterMultiListener, which isn't even a
    node.
    
    SwTextNode has GetTextNodeForParaProps()/GetTextNodeFirst().
    
    Change-Id: Ica177a6a3cf7c886c9a8d2733fb9cb452a475450

diff --git a/sw/source/core/inc/cntfrm.hxx b/sw/source/core/inc/cntfrm.hxx
index 62413e38de8c..aa28f580f3ad 100644
--- a/sw/source/core/inc/cntfrm.hxx
+++ b/sw/source/core/inc/cntfrm.hxx
@@ -71,9 +71,6 @@ public:
     virtual void Cut() override;
     virtual void Paste( SwFrame* pParent, SwFrame* pSibling = nullptr ) override;
 
-    inline const SwContentNode *GetNode() const;
-    inline       SwContentNode *GetNode();
-
     inline const SwContentFrame *GetFollow() const;
     inline       SwContentFrame *GetFollow();
     SwTextFrame* FindMaster() const;
@@ -114,15 +111,6 @@ inline SwContentFrame* SwContentFrame::GetPrevContentFrame() const
         return const_cast<SwContentFrame*>(ImplGetNextContentFrame( false ));
 }
 
-inline SwContentNode *SwContentFrame::GetNode()
-{
-    return static_cast< SwContentNode* >( GetDep() );
-}
-inline const SwContentNode *SwContentFrame::GetNode() const
-{
-    return static_cast< const SwContentNode* >( GetDep() );
-}
-
 inline const SwContentFrame *SwContentFrame::GetFollow() const
 {
     return static_cast<const SwContentFrame*>(SwFlowFrame::GetFollow());
diff --git a/sw/source/core/inc/notxtfrm.hxx b/sw/source/core/inc/notxtfrm.hxx
index 9de5fd31abfe..eaa10653964b 100644
--- a/sw/source/core/inc/notxtfrm.hxx
+++ b/sw/source/core/inc/notxtfrm.hxx
@@ -54,6 +54,11 @@ protected:
 public:
     SwNoTextFrame( SwNoTextNode * const, SwFrame* );
 
+    const SwContentNode *GetNode() const
+        { return static_cast<SwContentNode const*>(GetDep()); }
+          SwContentNode *GetNode()
+        { return static_cast<SwContentNode      *>(GetDep()); }
+
     virtual bool LeftMargin(SwPaM *) const override;
     virtual bool RightMargin(SwPaM *, bool bAPI = false) const override;
 
diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index 9c0f787060f7..f6fbb686903e 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -398,9 +398,9 @@ public:
     const OUString& GetText() const;
     // TODO: remove GetTextNode
     SwTextNode *GetTextNode()
-        { return static_cast< SwTextNode* >( SwContentFrame::GetNode()); }
+        { return static_cast<SwTextNode*>(SwFrame::GetDep()); }
     const SwTextNode *GetTextNode() const
-        { return static_cast< const SwTextNode* >( SwContentFrame::GetNode()); }
+        { return static_cast<const SwTextNode*>(SwFrame::GetDep()); }
     SwTextNode const* GetTextNodeForParaProps() const;
     SwTextNode      * GetTextNodeFirst()
         { return const_cast<SwTextNode*>(const_cast<SwTextFrame const*>(this)->GetTextNodeFirst()); };
commit 0122409c59ff22ada2cbd7c4ed5d1d07794b2824
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri May 4 13:45:09 2018 +0200

    sw_redlinehide: use FrameContainsNode in anchoredobjectposition.cxx
    
    Change-Id: I648810c1d5549d700a64f120a52416a951d56dca

diff --git a/sw/source/core/objectpositioning/anchoredobjectposition.cxx b/sw/source/core/objectpositioning/anchoredobjectposition.cxx
index 0bae1d1c8ade..f9fa2c8d11cd 100644
--- a/sw/source/core/objectpositioning/anchoredobjectposition.cxx
+++ b/sw/source/core/objectpositioning/anchoredobjectposition.cxx
@@ -947,7 +947,7 @@ SwTwips SwAnchoredObjectPosition::AdjustHoriRelPosForDrawAside(
     const sal_uInt32 nObjOrdNum = GetObject().GetOrdNum();
     const SwPageFrame* pObjPage = rFlyAtContentFrame.FindPageFrame();
     const SwFrame* pObjContext = ::FindContext( &rAnchorTextFrame, SwFrameType::Column );
-    sal_uLong nObjIndex = rAnchorTextFrame.GetTextNode()->GetIndex();
+    sal_uLong nObjIndex = rAnchorTextFrame.GetTextNodeFirst()->GetIndex();
     SwOrderIter aIter( pObjPage );
     const SwFlyFrame* pFly = static_cast<const SwVirtFlyDrawObj*>(aIter.Bottom())->GetFlyFrame();
     while ( pFly && nObjOrdNum > pFly->GetVirtDrawObj()->GetOrdNumDirect() )
@@ -1058,8 +1058,9 @@ bool SwAnchoredObjectPosition::DrawAsideFly( const SwFlyFrame* _pFly,
          ::FindContext( _pFly->GetAnchorFrame(), SwFrameType::Column ) == _pObjContext )
     {
         sal_uLong nOtherIndex =
-            static_cast<const SwTextFrame*>(_pFly->GetAnchorFrame())->GetTextNode()->GetIndex();
-        if( _nObjIndex >= nOtherIndex )
+            static_cast<const SwTextFrame*>(_pFly->GetAnchorFrame())->GetTextNodeFirst()->GetIndex();
+        if (sw::FrameContainsNode(static_cast<SwTextFrame const&>(*_pFly->GetAnchorFrame()), _nObjIndex)
+            || nOtherIndex < _nObjIndex)
         {
             const SwFormatHoriOrient& rHori = _pFly->GetFormat()->GetHoriOrient();
             sal_Int16 eOtherRelOrient = rHori.GetRelationOrient();
commit 40ac63a973e007b656e6e5ae15afb3770acba302
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri Jun 1 22:32:26 2018 +0200

    sw_redlinehide: convert GetNode(), use FrameContainsNode(), txtfly.cxx
    
    Change-Id: I0e4961acc191a764db74ede75e140e63ad1318a0

diff --git a/sw/source/core/layout/trvlfrm.cxx b/sw/source/core/layout/trvlfrm.cxx
index 39843fd25efb..fee388a696c1 100644
--- a/sw/source/core/layout/trvlfrm.cxx
+++ b/sw/source/core/layout/trvlfrm.cxx
@@ -692,7 +692,7 @@ static const SwContentFrame * lcl_MissProtectedFrames( const SwContentFrame *pCn
 static bool lcl_UpDown( SwPaM *pPam, const SwContentFrame *pStart,
                     GetNxtPrvCnt fnNxtPrv, bool bInReadOnly )
 {
-    OSL_ENSURE( &pPam->GetNode() == pStart->GetNode(),
+    OSL_ENSURE( FrameContainsNode(*pStart, pPam->GetNode().GetIndex()),
             "lcl_UpDown doesn't work for others." );
 
     const SwContentFrame *pCnt = nullptr;
diff --git a/sw/source/core/text/txtfly.cxx b/sw/source/core/text/txtfly.cxx
index c7d3f891fa0d..45950b93ec6b 100644
--- a/sw/source/core/text/txtfly.cxx
+++ b/sw/source/core/text/txtfly.cxx
@@ -834,9 +834,9 @@ bool SwTextFly::GetTop( const SwAnchoredObject* _pAnchoredObj,
                 // If possible determine Index via SwFormatAnchor because
                 // otherwise it's quite expensive.
                 if (ULONG_MAX == m_nCurrFrameNodeIndex)
-                    m_nCurrFrameNodeIndex = m_pCurrFrame->GetNode()->GetIndex();
+                    m_nCurrFrameNodeIndex = m_pCurrFrame->GetTextNodeFirst()->GetIndex();
 
-                if (nTmpIndex < m_nCurrFrameNodeIndex)
+                if (FrameContainsNode(*m_pCurrFrame, nTmpIndex) || nTmpIndex < m_nCurrFrameNodeIndex)
                     return true;
             }
         }
commit 02e47953098593b7a872554f65b8067f15af1ed1
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri Jun 1 22:30:58 2018 +0200

    sw_redlinehide: iterate merged nodes in SwLayIdle::DoIdleJob_()
    
    Change-Id: I42924448749385bb0e5bc2c187e37053e104c0da

diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index a4df2477ea01..e98f19ccb771 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -1847,19 +1847,50 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
     if( !pCnt->IsTextFrame() )
         return false;
 
-    const SwTextNode* pTextNode = pCnt->GetNode()->GetTextNode();
+    SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>(pCnt));
+    // sw_redlinehide: spell check only the nodes with visible content?
+    const SwTextNode* pTextNode = pTextFrame->GetTextNodeForParaProps();
 
     bool bProcess = false;
-    switch ( eJob )
+    for (size_t i = 0; pTextNode; )
     {
-        case ONLINE_SPELLING :
-            bProcess = pTextNode->IsWrongDirty(); break;
-        case AUTOCOMPLETE_WORDS :
-            bProcess = pTextNode->IsAutoCompleteWordDirty(); break;
-        case WORD_COUNT :
-            bProcess = pTextNode->IsWordCountDirty(); break;
-        case SMART_TAGS :
-            bProcess = pTextNode->IsSmartTagDirty(); break;
+        switch ( eJob )
+        {
+            case ONLINE_SPELLING :
+                bProcess = pTextNode->IsWrongDirty(); break;
+            case AUTOCOMPLETE_WORDS :
+                bProcess = pTextNode->IsAutoCompleteWordDirty(); break;
+            case WORD_COUNT :
+                bProcess = pTextNode->IsWordCountDirty(); break;
+            case SMART_TAGS :
+                bProcess = pTextNode->IsSmartTagDirty(); break;
+        }
+        if (bProcess)
+        {
+            break;
+        }
+        if (sw::MergedPara const* pMerged = pTextFrame->GetMergedPara())
+        {
+            while (true)
+            {
+                ++i;
+                if (i < pMerged->extents.size())
+                {
+                    if (pMerged->extents[i].pNode != pTextNode)
+                    {
+                        pTextNode = pMerged->extents[i].pNode;
+                        break;
+                    }
+                }
+                else
+                {
+                    pTextNode = nullptr;
+                    break;
+                }
+            }
+        }
+        else
+            pTextNode = nullptr;
     }
 
     if( bProcess )
commit ff21c6c6ef20dd1de383b01b1e521956e1a4c16c
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri Jun 1 22:29:16 2018 +0200

    sw_redlinehide: convert GetNode() in frmtool.cxx
    
    Change-Id: I6787ec787190ad297717ab01a78414cac34aa2cb

diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index 12a5b322cc07..cfafce5b3d51 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -823,8 +823,8 @@ SwContentNotify::~SwContentNotify()
         SwViewShell *pSh  = pCnt->getRootFrame()->GetCurrShell();
         if ( pSh )
         {
-            SwOLENode *pNd;
-            if ( nullptr != (pNd = pCnt->GetNode()->GetOLENode()) &&
+            SwOLENode *const pNd(static_cast<SwNoTextFrame*>(pCnt)->GetNode()->GetOLENode());
+            if (nullptr != pNd &&
                  (pNd->GetOLEObj().IsOleRef() ||
                   pNd->IsOLESizeInvalid()) )
             {
@@ -882,7 +882,9 @@ SwContentNotify::~SwContentNotify()
     {
         pCnt->SetRetouche();    //fix(13870)
 
-        SwDoc *pDoc = pCnt->GetNode()->GetDoc();
+        SwDoc *const pDoc = pCnt->IsTextFrame()
+            ? &static_cast<SwTextFrame*>(pCnt)->GetDoc()
+            : static_cast<SwNoTextFrame*>(pCnt)->GetNode()->GetDoc();
         if ( !pDoc->GetSpzFrameFormats()->empty() &&
              pDoc->DoesContainAtPageObjWithContentAnchor() && !pDoc->getIDocumentState().IsNewDoc() )
         {
@@ -895,7 +897,6 @@ SwContentNotify::~SwContentNotify()
             // the page is known. Thus, this data can be corrected now.
 
             const SwPageFrame *pPage = nullptr;
-            SwNodeIndex *pIdx  = nullptr;
             SwFrameFormats *pTable = pDoc->GetSpzFrameFormats();
 
             for ( size_t i = 0; i < pTable->size(); ++i )
@@ -908,11 +909,7 @@ SwContentNotify::~SwContentNotify()
                     continue;
                 }
 
-                if ( !pIdx )
-                {
-                    pIdx = new SwNodeIndex( *pCnt->GetNode() );
-                }
-                if ( rAnch.GetContentAnchor()->nNode == *pIdx )
+                if (FrameContainsNode(*pCnt, rAnch.GetContentAnchor()->nNode.GetIndex()))
                 {
                     OSL_FAIL( "<SwContentNotify::~SwContentNotify()> - to page anchored object with content position." );
                     if ( !pPage )
@@ -929,7 +926,6 @@ SwContentNotify::~SwContentNotify()
                     }
                 }
             }
-            delete pIdx;
         }
     }
 
@@ -1829,7 +1825,9 @@ void MakeFrames( SwDoc *pDoc, const SwNodeIndex &rSttIdx,
 SwBorderAttrs::SwBorderAttrs(const SwModify *pMod, const SwFrame *pConstructor)
     : SwCacheObj(pMod)
     , m_rAttrSet(pConstructor->IsContentFrame()
-                    ? static_cast<const SwContentFrame*>(pConstructor)->GetNode()->GetSwAttrSet()
+                    ? pConstructor->IsTextFrame()
+                        ? static_cast<const SwTextFrame*>(pConstructor)->GetTextNodeForParaProps()->GetSwAttrSet()
+                        : static_cast<const SwNoTextFrame*>(pConstructor)->GetNode()->GetSwAttrSet()
                     : static_cast<const SwLayoutFrame*>(pConstructor)->GetFormat()->GetAttrSet())
     , m_rUL(m_rAttrSet.GetULSpace())
     // #i96772#
@@ -2206,14 +2204,20 @@ void SwBorderAttrs::GetBottomLine_( const SwFrame& _rFrame )
     m_nGetBottomLine = nRet;
 }
 
+static SwModify const* GetCacheOwner(SwFrame const& rFrame)
+{
+    return rFrame.IsContentFrame()
+        ? static_cast<SwModify const*>(rFrame.IsTextFrame()
+        // sw_redlinehide: presumably this caches the border attrs at the model level and can be shared across different layouts so we want the ParaProps node here
+            ? static_cast<const SwTextFrame&>(rFrame).GetTextNodeForParaProps()
+            : static_cast<const SwNoTextFrame&>(rFrame).GetNode())
+        : static_cast<SwModify const*>(static_cast<const SwLayoutFrame&>(rFrame).GetFormat());
+}
+
 SwBorderAttrAccess::SwBorderAttrAccess( SwCache &rCach, const SwFrame *pFrame ) :
     SwCacheAccess( rCach,
-                   (pFrame->IsContentFrame() ?
-                      const_cast<void*>(static_cast<void const *>(static_cast<const SwContentFrame*>(pFrame)->GetNode())) :
-                      const_cast<void*>(static_cast<void const *>(static_cast<const SwLayoutFrame*>(pFrame)->GetFormat()))),
-                   (pFrame->IsContentFrame() ?
-                      static_cast<SwModify const *>(static_cast<const SwContentFrame*>(pFrame)->GetNode())->IsInCache() :
-                      static_cast<SwModify const *>(static_cast<const SwLayoutFrame*>(pFrame)->GetFormat())->IsInCache()) ),
+        static_cast<void const *>(GetCacheOwner(*pFrame)),
+        GetCacheOwner(*pFrame)->IsInCache()),
     m_pConstructor( pFrame )
 {
 }
commit ba68b0965d7d61c37235a43139e01934490227be
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri Jun 1 22:26:52 2018 +0200

    sw_redlinehide: convert GetNode(), use FrameContainsNode() in flycnt.cxx
    
    Change-Id: I551d37c961149bb043bed4cde7b52822f5e3db81

diff --git a/sw/source/core/layout/flycnt.cxx b/sw/source/core/layout/flycnt.cxx
index 71cdcc029235..7e1f1079a686 100644
--- a/sw/source/core/layout/flycnt.cxx
+++ b/sw/source/core/layout/flycnt.cxx
@@ -20,6 +20,7 @@
 #include <tools/bigint.hxx>
 #include <pagefrm.hxx>
 #include <txtfrm.hxx>
+#include <notxtfrm.hxx>
 #include <doc.hxx>
 #include <pam.hxx>
 #include <IDocumentUndoRedo.hxx>
@@ -114,7 +115,11 @@ void SwFlyAtContentFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pN
         // Search the new anchor using the NodeIdx; the relation between old
         // and new NodeIdx determines the search direction
         const SwNodeIndex aNewIdx( pAnch->GetContentAnchor()->nNode );
-        SwNodeIndex aOldIdx( *pContent->GetNode() );
+        SwNodeIndex aOldIdx( pContent->IsTextFrame()
+                // sw_redlinehide: can pick any node here, the compare with
+                // FrameContainsNode should catch it
+                ? *static_cast<SwTextFrame *>(pContent)->GetTextNodeFirst()
+                : *static_cast<SwNoTextFrame *>(pContent)->GetNode() );
 
         //fix: depending on which index was smaller, searching in the do-while
         //loop previously was done forward or backwards respectively. This however
@@ -122,12 +127,12 @@ void SwFlyAtContentFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pN
         //is now done in only one direction. Getting hold of a frame from the node
         //is still possible if the new anchor could not be found. Chances are
         //good that this will be the correct one.
-        const bool bNext = aOldIdx < aNewIdx;
         // consider the case that at found anchor frame candidate already a
         // fly frame of the given fly format is registered.
         // consider, that <pContent> is the already
         // the new anchor frame.
-        bool bFound( aOldIdx == aNewIdx );
+        bool bFound( FrameContainsNode(*pContent, aNewIdx.GetIndex()) );
+        const bool bNext = !bFound && aOldIdx < aNewIdx;
         while ( pContent && !bFound )
         {
             do
@@ -140,11 +145,10 @@ void SwFlyAtContentFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pN
                       ( bBodyFootnote != ( pContent->IsInDocBody() ||
                                            pContent->IsInFootnote() ) ) );
             if ( pContent )
-                aOldIdx = *pContent->GetNode();
+                bFound = FrameContainsNode(*pContent, aNewIdx.GetIndex());
 
             // check, if at found anchor frame candidate already a fly frame
             // of the given fly frame format is registered.
-            bFound = aOldIdx == aNewIdx;
             if (bFound && pContent && pContent->GetDrawObjs())
             {
                 SwFrameFormat* pMyFlyFrameFormat( &GetFrameFormat() );
@@ -1327,19 +1331,18 @@ void SwFlyAtContentFrame::SetAbsPos( const Point &rNew )
         SwPosition pos = *aAnch.GetContentAnchor();
         if( IsAutoPos() && pCnt->IsTextFrame() )
         {
+            SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>(pCnt));
             SwCursorMoveState eTmpState( MV_SETONLYTEXT );
             Point aPt( rNew );
             if( pCnt->GetCursorOfst( &pos, aPt, &eTmpState )
-                && pos.nNode == *pCnt->GetNode() )
+                && FrameContainsNode(*pTextFrame, pos.nNode.GetIndex()))
             {
-                if ( pCnt->GetNode()->GetTextNode() != nullptr )
+                const SwTextAttr *const pTextInputField =
+                    pos.nNode.GetNode().GetTextNode()->GetTextAttrAt(
+                        pos.nContent.GetIndex(), RES_TXTATR_INPUTFIELD, SwTextNode::PARENT );
+                if (pTextInputField != nullptr)
                 {
-                    const SwTextAttr* pTextInputField =
-                        pCnt->GetNode()->GetTextNode()->GetTextAttrAt( pos.nContent.GetIndex(), RES_TXTATR_INPUTFIELD, SwTextNode::PARENT );
-                    if ( pTextInputField != nullptr )
-                    {
-                        pos.nContent = pTextInputField->GetStart();
-                    }
+                    pos.nContent = pTextInputField->GetStart();
                 }
                 ResetLastCharRectHeight();
                 if( text::RelOrientation::CHAR == pFormat->GetVertOrient().GetRelationOrient() )
@@ -1349,14 +1352,18 @@ void SwFlyAtContentFrame::SetAbsPos( const Point &rNew )
             }
             else
             {
-                pos.nNode = *pCnt->GetNode();
-                pos.nContent.Assign( pCnt->GetNode(), 0 );
+                pos = pTextFrame->MapViewToModelPos(TextFrameIndex(0));
             }
         }
-        else
+        else if (pCnt->IsTextFrame())
+        {
+            pos = static_cast<SwTextFrame const*>(pCnt)->MapViewToModelPos(TextFrameIndex(0));
+        }
+        else // is that even possible? maybe if there was a change of anchor type from AT_FLY or something?
         {
-            pos.nNode = *pCnt->GetNode();
-            pos.nContent.Assign( pCnt->GetNode(), 0 );
+            assert(pCnt->IsNoTextFrame());
+            pos.nNode = *static_cast<SwNoTextFrame*>(pCnt)->GetNode();
+            pos.nContent.Assign(static_cast<SwNoTextFrame*>(pCnt)->GetNode(), 0);
         }
         aAnch.SetAnchor( &pos );
 
commit c9aee70ed3fde52680a2033df12958eb5d7fbc1c
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri Jun 1 22:24:24 2018 +0200

    sw_redlinehide: convert GetNode() in SwFlowFrame::BwdMoveNecessary()
    
    Change-Id: Iaefed6ebee4f4cf47697c174abc275b1287f643f

diff --git a/sw/source/core/layout/flowfrm.cxx b/sw/source/core/layout/flowfrm.cxx
index 1dce5a5131ff..46af46fbe942 100644
--- a/sw/source/core/layout/flowfrm.cxx
+++ b/sw/source/core/layout/flowfrm.cxx
@@ -343,21 +343,28 @@ sal_uInt8 SwFlowFrame::BwdMoveNecessary( const SwPageFrame *pPage, const SwRect
                         if( ULONG_MAX == nIndex )
                         {
                             const SwNode *pNode;
-                            if ( m_rThis.IsContentFrame() )
-                                pNode = static_cast<SwContentFrame&>(m_rThis).GetNode();
+                            if (m_rThis.IsTextFrame())
+                                pNode = static_cast<SwTextFrame&>(m_rThis).GetTextNodeFirst();
+                            else if (m_rThis.IsNoTextFrame())
+                                pNode = static_cast<SwNoTextFrame&>(m_rThis).GetNode();
                             else if( m_rThis.IsSctFrame() )
                                 pNode = static_cast<SwSectionFormat*>(static_cast<SwSectionFrame&>(m_rThis).
                                         GetFormat())->GetSectionNode();
                             else
                             {
+                                assert(!m_rThis.IsContentFrame());
                                 OSL_ENSURE( m_rThis.IsTabFrame(), "new FowFrame?" );
                                 pNode = static_cast<SwTabFrame&>(m_rThis).GetTable()->
                                     GetTabSortBoxes()[0]->GetSttNd()->FindTableNode();
                             }
                             nIndex = pNode->GetIndex();
                         }
-                        if( nIndex < nTmpIndex )
+                        if (nIndex < nTmpIndex &&
+                            (!m_rThis.IsTextFrame() ||
+                             !FrameContainsNode(static_cast<SwTextFrame&>(m_rThis), nTmpIndex)))
+                        {
                             continue;
+                        }
                     }
                 }
                 else
commit 760613190a70768ec3b7e77e27687c380200c41a
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri Jun 1 22:22:48 2018 +0200

    sw_redlinehide: convert GetNode() in SwCursor::IsSelOvr()
    
    Change-Id: I3cca2091f4a3fe903bbd606c93a368662e997899

diff --git a/sw/source/core/crsr/swcrsr.cxx b/sw/source/core/crsr/swcrsr.cxx
index 91e9e2e61551..2b934cb6c576 100644
--- a/sw/source/core/crsr/swcrsr.cxx
+++ b/sw/source/core/crsr/swcrsr.cxx
@@ -39,6 +39,7 @@
 #include <cntfrm.hxx>
 #include <rootfrm.hxx>
 #include <txtfrm.hxx>
+#include <notxtfrm.hxx>
 #include <scriptinfo.hxx>
 #include <crstate.hxx>
 #include <docsh.hxx>
@@ -351,18 +352,31 @@ bool SwCursor::IsSelOvr( SwCursorSelOverFlags eFlags )
                 }
             }
 
-            SwContentNode* pCNd = (pFrame != nullptr) ? const_cast<SwContentNode*>(pFrame->GetNode()) : nullptr;
-            if ( pCNd != nullptr )
+            if (pFrame != nullptr)
             {
-                // set this ContentNode as new position
-                rPtIdx = *pCNd;
+                if (pFrame->IsTextFrame())
+                {
+                    SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>(pFrame));
+                    *GetPoint() = pTextFrame->MapViewToModelPos(TextFrameIndex(
+                            bGoNxt ? 0 : pTextFrame->GetText().getLength()));
+                }
+                else
+                {
+                    assert(pFrame->IsNoTextFrame());
+                    SwContentNode *const pCNd = const_cast<SwContentNode*>(
+                        static_cast<SwNoTextFrame const*>(pFrame)->GetNode());
+                    assert(pCNd);
+
+                    // set this ContentNode as new position
+                    rPtIdx = *pCNd;
+                    // assign corresponding ContentIndex
+                    const sal_Int32 nTmpPos = bGoNxt ? 0 : pCNd->Len();
+                    GetPoint()->nContent.Assign( pCNd, nTmpPos );
+                }
 
-                // assign corresponding ContentIndex
-                const sal_Int32 nTmpPos = bGoNxt ? 0 : pCNd->Len();
-                GetPoint()->nContent.Assign( pCNd, nTmpPos );
 
                 if (rPtIdx.GetIndex() == m_vSavePos.back().nNode
-                    && nTmpPos == m_vSavePos.back().nContent)
+                    && GetPoint()->nContent.GetIndex() == m_vSavePos.back().nContent)
                 {
                     // new position equals saved one
                     // --> trigger restore of saved pos by setting <pFrame> to NULL - see below
commit a9ba71040e7d1671c94a4723467e70cbc2725c65
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri Jun 1 22:16:28 2018 +0200

    sw_redlinehide: refactor AppendObjs to iterate merged paragraphs
    
    Change-Id: I5860b9791c0839d4b83eec6a3db0b2d1926d2ccd

diff --git a/sw/source/core/inc/flyfrm.hxx b/sw/source/core/inc/flyfrm.hxx
index 0c4c9319b3ed..c28dcd98b882 100644
--- a/sw/source/core/inc/flyfrm.hxx
+++ b/sw/source/core/inc/flyfrm.hxx
@@ -25,6 +25,7 @@
 #include <frmfmt.hxx>
 #include <anchoredobject.hxx>
 
+class SwFormatAnchor;
 class SwPageFrame;
 class SwFormatFrameSize;
 struct SwCursorMoveState;
@@ -58,7 +59,7 @@ bool CalcClipRect( const SdrObject *pSdrObj, SwRect &rRect, bool bMove = true );
 class SwFlyFrame : public SwLayoutFrame, public SwAnchoredObject
 {
     // is allowed to lock, implemented in frmtool.cxx
-    friend void AppendObjs   ( const SwFrameFormats *, sal_uLong, SwFrame *, SwPageFrame *, SwDoc* );
+    friend void AppendObj(SwFrame *const pFrame, SwPageFrame *const pPage, SwFrameFormat *const pFormat, const SwFormatAnchor & rAnch);
     friend void Notify( SwFlyFrame *, SwPageFrame *pOld, const SwRect &rOld,
                         const SwRect* pOldPrt );
 
diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index bfdb15bc1a86..12a5b322cc07 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -973,38 +973,9 @@ SwContentNotify::~SwContentNotify()
     }
 }
 
-void AppendObjs( const SwFrameFormats *pTable, sal_uLong nIndex,
-                        SwFrame *pFrame, SwPageFrame *pPage, SwDoc* doc )
+// note this *cannot* be static because it's a friend
+void AppendObj(SwFrame *const pFrame, SwPageFrame *const pPage, SwFrameFormat *const pFormat, const SwFormatAnchor & rAnch)
 {
-#if OSL_DEBUG_LEVEL > 0
-    std::vector<SwFrameFormat*> checkFormats;
-    for ( size_t i = 0; i < pTable->size(); ++i )
-    {
-        SwFrameFormat *pFormat = (*pTable)[i];
-        const SwFormatAnchor &rAnch = pFormat->GetAnchor();
-        if ( rAnch.GetContentAnchor() &&
-             (rAnch.GetContentAnchor()->nNode.GetIndex() == nIndex) )
-        {
-            checkFormats.push_back( pFormat );
-        }
-    }
-#else
-    (void)pTable;
-#endif
-    SwNode const& rNode(*doc->GetNodes()[nIndex]);
-    std::vector<SwFrameFormat*> const*const pFlys(rNode.GetAnchoredFlys());
-    for (size_t it = 0; pFlys && it != pFlys->size(); )
-    {
-        SwFrameFormat *const pFormat = (*pFlys)[it];
-        const SwFormatAnchor &rAnch = pFormat->GetAnchor();
-        if ( rAnch.GetContentAnchor() &&
-             (rAnch.GetContentAnchor()->nNode.GetIndex() == nIndex) )
-        {
-#if OSL_DEBUG_LEVEL > 0
-            std::vector<SwFrameFormat*>::iterator checkPos = std::find( checkFormats.begin(), checkFormats.end(), pFormat );
-            assert( checkPos != checkFormats.end());
-            checkFormats.erase( checkPos );
-#endif
             const bool bFlyAtFly = rAnch.GetAnchorId() == RndStdIds::FLY_AT_FLY; // LAYER_IMPL
             //Is a frame or a SdrObject described?
             const bool bSdrObj = RES_DRAWFRMFMT == pFormat->Which();
@@ -1022,9 +993,8 @@ void AppendObjs( const SwFrameFormats *pTable, sal_uLong nIndex,
                 if ( bSdrObj && nullptr == (pSdrObj = pFormat->FindSdrObject()) )
                 {
                     OSL_ENSURE( !bSdrObj, "DrawObject not found." );
-                    ++it;
                     pFormat->GetDoc()->DelFrameFormat( pFormat );
-                    continue;
+                    return;
                 }
                 if ( pSdrObj )
                 {
@@ -1051,7 +1021,6 @@ void AppendObjs( const SwFrameFormats *pTable, sal_uLong nIndex,
 
                         pDrawVirtObj->ActionChanged();
                     }
-
                 }
                 else
                 {
@@ -1067,14 +1036,133 @@ void AppendObjs( const SwFrameFormats *pTable, sal_uLong nIndex,
                         ::RegistFlys( pPage, pFly );
                 }
             }
+}
+
+static bool IsShown(sal_uLong const nIndex,
+    const SwFormatAnchor & rAnch,
+    std::vector<sw::Extent>::const_iterator *const pIter,
+    std::vector<sw::Extent>::const_iterator const*const pEnd)
+{
+    SwPosition const& rAnchor(*rAnch.GetContentAnchor());
+    if (pIter && rAnch.GetAnchorId() != RndStdIds::FLY_AT_PARA)
+    {
+        // TODO are frames sorted by anchor positions perhaps?
+        assert(pEnd);
+        assert(rAnch.GetAnchorId() != RndStdIds::FLY_AT_FLY);
+        for ( ; *pIter != *pEnd; ++*pIter)
+        {
+            assert((**pIter).pNode->GetIndex() == nIndex);
+            if ((**pIter).nStart <= rAnchor.nContent.GetIndex())
+            {
+                // TODO off by one? need < for AS_CHAR but what for AT_CHAR?
+                if (rAnchor.nContent.GetIndex() < (**pIter).nEnd)
+                {
+                    return true;
+                }
+                else
+                {
+                    return false;
+                }
+            }
+        }
+        return false;
+    }
+    else
+    {
+        return rAnch.GetContentAnchor()->nNode.GetIndex() == nIndex;
+    }
+}
+
+void AppendObjsOfNode(SwFrameFormats const*const pTable, sal_uLong const nIndex,
+    SwFrame *const pFrame, SwPageFrame *const pPage, SwDoc *const pDoc,
+    std::vector<sw::Extent>::const_iterator *const pIter,
+    std::vector<sw::Extent>::const_iterator const*const pEnd)
+{
+#if OSL_DEBUG_LEVEL > 0
+    std::vector<SwFrameFormat*> checkFormats;
+    for ( size_t i = 0; i < pTable->size(); ++i )
+    {
+        SwFrameFormat *pFormat = (*pTable)[i];
+        const SwFormatAnchor &rAnch = pFormat->GetAnchor();
+        if ( rAnch.GetContentAnchor() &&
+            IsShown(nIndex, rAnch, pIter, pEnd))
+        {
+            checkFormats.push_back( pFormat );
+        }
+    }
+#else
+    (void)pTable;
+#endif
+
+    SwNode const& rNode(*pDoc->GetNodes()[nIndex]);
+    std::vector<SwFrameFormat*> const*const pFlys(rNode.GetAnchoredFlys());
+    for (size_t it = 0; pFlys && it != pFlys->size(); )
+    {
+        SwFrameFormat *const pFormat = (*pFlys)[it];
+        const SwFormatAnchor &rAnch = pFormat->GetAnchor();
+        if ( rAnch.GetContentAnchor() &&
+            IsShown(nIndex, rAnch, pIter, pEnd))
+        {
+#if OSL_DEBUG_LEVEL > 0
+            std::vector<SwFrameFormat*>::iterator checkPos = std::find( checkFormats.begin(), checkFormats.end(), pFormat );
+            assert( checkPos != checkFormats.end());
+            checkFormats.erase( checkPos );
+#endif
+            AppendObj(pFrame, pPage, pFormat, rAnch);
         }
         ++it;
     }
+
 #if OSL_DEBUG_LEVEL > 0
     assert( checkFormats.empty());
 #endif
 }
 
+
+void AppendObjs(const SwFrameFormats *const pTable, sal_uLong const nIndex,
+        SwFrame *const pFrame, SwPageFrame *const pPage, SwDoc *const pDoc)
+{
+    if (pFrame->IsTextFrame())
+    {
+        SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>(pFrame));
+        if (sw::MergedPara const*const pMerged = pTextFrame->GetMergedPara())
+        {
+            std::vector<sw::Extent>::const_iterator iterFirst(pMerged->extents.begin());
+            std::vector<sw::Extent>::const_iterator iter(iterFirst);
+            SwTextNode const* pNode(nullptr);
+            for ( ; iter != pMerged->extents.end(); ++iter)
+            {
+                if (iter->pNode != pNode)
+                {
+                    if (pNode)
+                    {
+                        AppendObjsOfNode(pTable, pNode->GetIndex(), pFrame, pPage, pDoc, &iterFirst, &iter);
+                    }
+                    else
+                    {
+                        assert(nIndex == iter->pNode->GetIndex()); // first iteration
+                    }
+                    pNode = iter->pNode;
+                    iterFirst = iter;
+                }
+            }
+            if (!pNode)
+            {   // no extents?
+                pNode = pMerged->pFirstNode;
+            }
+            AppendObjsOfNode(pTable, pNode->GetIndex(), pFrame, pPage, pDoc, &iterFirst, &iter);
+        }
+        else
+        {
+            return AppendObjsOfNode(pTable, nIndex, pFrame, pPage, pDoc, nullptr, nullptr);
+        }
+    }
+    else
+    {
+        return AppendObjsOfNode(pTable, nIndex, pFrame, pPage, pDoc, nullptr, nullptr);
+    }
+}
+
 void AppendAllObjs(const SwFrameFormats* pTable, const SwFrame* pSib)
 {
     //Connecting of all Objects, which are described in the SpzTable with the
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index 43723ef67518..9817b082b688 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -47,6 +47,7 @@
 #include <cellfrm.hxx>
 #include <flyfrms.hxx>
 #include <txtfrm.hxx>
+#include <notxtfrm.hxx>
 #include <htmltbl.hxx>
 #include <sectfrm.hxx>
 #include <fmtfollowtextflow.hxx>
@@ -1178,7 +1179,11 @@ bool SwTabFrame::Split( const SwTwips nCutPos, bool bTryToSplit, bool bTableRowK
                 SwContentFrame* pFrame = pHeadline->ContainsContent();
                 while( pFrame )
                 {
-                    nIndex = pFrame->GetNode()->GetIndex();
+                    // sw_redlinehide: the implementation of AppendObjs
+                    // takes care of iterating merged SwTextFrame
+                    nIndex = pFrame->IsTextFrame()
+                        ? static_cast<SwTextFrame*>(pFrame)->GetTextNodeFirst()->GetIndex()
+                        : static_cast<SwNoTextFrame*>(pFrame)->GetNode()->GetIndex();
                     AppendObjs( pTable, nIndex, pFrame, pPage, GetFormat()->GetDoc());
                     pFrame = pFrame->GetNextContentFrame();
                     if( !pHeadline->IsAnLower( pFrame ) )
commit d05d49148b7f997e055e0d9c3f19061df7389e91
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri Jun 1 22:03:42 2018 +0200

    sw_redlinehide: trivial convert to GetPageDescItem()/GetBreakItem()
    
    Change-Id: Ia652ff428c232b9307e41da8f6b9648f486f7179

diff --git a/sw/source/core/frmedt/fedesc.cxx b/sw/source/core/frmedt/fedesc.cxx
index 588dd8e1dd6b..2177047e19aa 100644
--- a/sw/source/core/frmedt/fedesc.cxx
+++ b/sw/source/core/frmedt/fedesc.cxx
@@ -68,7 +68,7 @@ void SwFEShell::ChgCurPageDesc( const SwPageDesc& rDesc )
         {
             if ( pFlow->IsInTab() )
                 pFlow = pFlow->FindTabFrame();
-            const SwFormatPageDesc& rPgDesc = pFlow->GetAttrSet()->GetPageDesc();
+            const SwFormatPageDesc& rPgDesc = pFlow->GetPageDescItem();
             if( rPgDesc.GetPageDesc() )
             {
                 // we found the culprit
diff --git a/sw/source/core/frmedt/fews.cxx b/sw/source/core/frmedt/fews.cxx
index 4d5743a2a957..9035c0e85f7c 100644
--- a/sw/source/core/frmedt/fews.cxx
+++ b/sw/source/core/frmedt/fews.cxx
@@ -369,7 +369,7 @@ void SwFEShell::SetPageOffset( sal_uInt16 nOffset )
         {
             if ( pFlow->IsInTab() )
                 pFlow = pFlow->FindTabFrame();
-            const SwFormatPageDesc& rPgDesc = pFlow->GetAttrSet()->GetPageDesc();
+            const SwFormatPageDesc& rPgDesc = pFlow->GetPageDescItem();
             if ( rPgDesc.GetNumOffset() )
             {
                 pDocLayout->SetVirtPageNum( true );
@@ -391,7 +391,7 @@ sal_uInt16 SwFEShell::GetPageOffset() const
         {
             if ( pFlow->IsInTab() )
                 pFlow = pFlow->FindTabFrame();
-            ::boost::optional<sal_uInt16> oNumOffset = pFlow->GetAttrSet()->GetPageDesc().GetNumOffset();
+            ::boost::optional<sal_uInt16> oNumOffset = pFlow->GetPageDescItem().GetNumOffset();
             if ( oNumOffset )
                 return oNumOffset.get();
         }
diff --git a/sw/source/core/layout/flowfrm.cxx b/sw/source/core/layout/flowfrm.cxx
index d7c651a7c597..1dce5a5131ff 100644
--- a/sw/source/core/layout/flowfrm.cxx
+++ b/sw/source/core/layout/flowfrm.cxx
@@ -841,7 +841,7 @@ bool SwFrame::WrongPageDesc( SwPageFrame* pNew )
     SwFlowFrame *pFlow = SwFlowFrame::CastFlowFrame( this );
     if ( !pFlow || !pFlow->IsFollow() )
     {
-        const SwFormatPageDesc &rFormatDesc = GetAttrSet()->GetPageDesc();
+        const SwFormatPageDesc &rFormatDesc = GetPageDescItem();
         pDesc = rFormatDesc.GetPageDesc();
         if( pDesc )
         {
@@ -870,7 +870,8 @@ bool SwFrame::WrongPageDesc( SwPageFrame* pNew )
     if ( pNewFlow && pNewFlow->GetFrame().IsInTab() )
         pNewFlow = pNewFlow->GetFrame().FindTabFrame();
     const SwPageDesc *pNewDesc= ( pNewFlow && !pNewFlow->IsFollow() )
-            ? pNewFlow->GetFrame().GetAttrSet()->GetPageDesc().GetPageDesc() : nullptr;
+            ? pNewFlow->GetFrame().GetPageDescItem().GetPageDesc()
+            : nullptr;
 
     SAL_INFO( "sw.pageframe", "WrongPageDesc p: " << pNew << " phys: " << pNew->GetPhyPageNum() );
     SAL_INFO( "sw.pageframe", "WrongPageDesc " << pNew->GetPageDesc() << " " << pDesc );
@@ -1130,7 +1131,6 @@ bool SwFlowFrame::IsPageBreak( bool bAct ) const
         const SwViewShell *pSh = m_rThis.getRootFrame()->GetCurrShell();
         if( pSh && pSh->GetViewOptions()->getBrowseMode() )
             return false;
-        const SwAttrSet *pSet = m_rThis.GetAttrSet();
 
         // Determine predecessor
         const SwFrame *pPrev = m_rThis.FindPrev();
@@ -1153,18 +1153,20 @@ bool SwFlowFrame::IsPageBreak( bool bAct ) const
             //for compatibility, also break at column break if no columns exist
             const IDocumentSettingAccess& rIDSA = m_rThis.GetUpper()->GetFormat()->getIDocumentSettingAccess();
             const bool bTreatSingleColumnBreakAsPageBreak = rIDSA.get(DocumentSettingId::TREAT_SINGLE_COLUMN_BREAK_AS_PAGE_BREAK);
-            const SvxBreak eBreak = pSet->GetBreak().GetBreak();
+            const SvxBreak eBreak = m_rThis.GetBreakItem().GetBreak();
             if ( eBreak == SvxBreak::PageBefore ||
                  eBreak == SvxBreak::PageBoth ||
                  ( bTreatSingleColumnBreakAsPageBreak && eBreak == SvxBreak::ColumnBefore && !m_rThis.FindColFrame() ))
                 return true;
             else
             {
-                const SvxBreak &ePrB = pPrev->GetAttrSet()->GetBreak().GetBreak();
+                const SvxBreak &ePrB = pPrev->GetBreakItem().GetBreak();
                 if ( ePrB == SvxBreak::PageAfter ||
                      ePrB == SvxBreak::PageBoth  ||
-                     pSet->GetPageDesc().GetPageDesc() )
+                    m_rThis.GetPageDescItem().GetPageDesc())
+                {
                     return true;
+                }
             }
         }
     }
@@ -1208,13 +1210,13 @@ bool SwFlowFrame::IsColBreak( bool bAct ) const
                         return false;
                 }
 
-                const SvxBreak eBreak = m_rThis.GetAttrSet()->GetBreak().GetBreak();
+                const SvxBreak eBreak = m_rThis.GetBreakItem().GetBreak();
                 if ( eBreak == SvxBreak::ColumnBefore ||
                      eBreak == SvxBreak::ColumnBoth )
                     return true;
                 else
                 {
-                    const SvxBreak &ePrB = pPrev->GetAttrSet()->GetBreak().GetBreak();
+                    const SvxBreak &ePrB = pPrev->GetBreakItem().GetBreak();
                     if ( ePrB == SvxBreak::ColumnAfter ||
                          ePrB == SvxBreak::ColumnBoth )
                         return true;
@@ -1998,7 +2000,7 @@ bool SwFlowFrame::MoveFwd( bool bMakePage, bool bPageBreak, bool bMoveAlways )
             // #i106452#
             // check page description not only in situation with sections.
             if ( !bSamePage &&
-                 ( m_rThis.GetAttrSet()->GetPageDesc().GetPageDesc() ||
+                 ( m_rThis.GetPageDescItem().GetPageDesc() ||
                    pOldPage->GetPageDesc()->GetFollow() != pNewPage->GetPageDesc() ) )
             {
                 SwFrame::CheckPageDescs( pNewPage, false );
@@ -2545,7 +2547,7 @@ bool SwFlowFrame::MoveBwd( bool &rbReformat )
                                             static_cast<SwPageFrame*>(pNewPage->GetNext());
                     SwFrame::CheckPageDescs( pStartPage, false);
                 }
-                else if ( m_rThis.GetAttrSet()->GetPageDesc().GetPageDesc() )
+                else if (m_rThis.GetPageDescItem().GetPageDesc())
                 {
                     // First page could get empty for example by disabling
                     // a section
diff --git a/sw/source/core/layout/laycache.cxx b/sw/source/core/layout/laycache.cxx
index 992dcfd52789..73c38c19f4eb 100644
--- a/sw/source/core/layout/laycache.cxx
+++ b/sw/source/core/layout/laycache.cxx
@@ -630,9 +630,8 @@ sal_uLong SwLayHelper::CalcPageCount()
 bool SwLayHelper::CheckInsertPage()
 {
     bool bEnd = nullptr == mrpPage->GetNext();
-    const SwAttrSet* pAttr = mrpFrame->GetAttrSet();
-    const SvxFormatBreakItem& rBrk = pAttr->GetBreak();
-    const SwFormatPageDesc& rDesc = pAttr->GetPageDesc();
+    const SvxFormatBreakItem& rBrk = mrpFrame->GetBreakItem();
+    const SwFormatPageDesc& rDesc = mrpFrame->GetPageDescItem();
     // #118195# Do not evaluate page description if frame
     // is a follow frame!
     const SwPageDesc* pDesc = mrpFrame->IsFlowFrame() &&
diff --git a/sw/source/core/layout/pagechg.cxx b/sw/source/core/layout/pagechg.cxx
index 11095f1dec62..036e3371e97c 100644
--- a/sw/source/core/layout/pagechg.cxx
+++ b/sw/source/core/layout/pagechg.cxx
@@ -770,7 +770,7 @@ SwPageDesc *SwPageFrame::FindPageDesc()
             SwFrame *pFlow = pFrame;
             if ( pFlow->IsInTab() )
                 pFlow = pFlow->FindTabFrame();
-            pRet = const_cast<SwPageDesc*>(pFlow->GetAttrSet()->GetPageDesc().GetPageDesc());
+            pRet = const_cast<SwPageDesc*>(pFlow->GetPageDescItem().GetPageDesc());
         }
         if ( !pRet )
             pRet = &GetFormat()->GetDoc()->GetPageDesc( 0 );
@@ -786,7 +786,7 @@ SwPageDesc *SwPageFrame::FindPageDesc()
     {
         SwFlowFrame *pTmp = SwFlowFrame::CastFlowFrame( pFlow );
         if ( !pTmp->IsFollow() )
-            pRet = const_cast<SwPageDesc*>(pFlow->GetAttrSet()->GetPageDesc().GetPageDesc());
+            pRet = const_cast<SwPageDesc*>(pFlow->GetPageDescItem().GetPageDesc());
     }
 
     //3. and 3.1
@@ -1288,7 +1288,8 @@ SwPageFrame *SwFrame::InsertPage( SwPageFrame *pPrevPage, bool bFootnote )
     // For ContentFrame take the one from format if provided,
     // otherwise from the Follow of the PrevPage
     if ( IsFlowFrame() && !SwFlowFrame::CastFlowFrame( this )->IsFollow() )
-    {   SwFormatPageDesc &rDesc = const_cast<SwFormatPageDesc&>(GetAttrSet()->GetPageDesc());
+    {
+        SwFormatPageDesc &rDesc = const_cast<SwFormatPageDesc&>(GetPageDescItem());
         pDesc = rDesc.GetPageDesc();
         if ( rDesc.GetNumOffset() )
         {
diff --git a/sw/source/core/layout/trvlfrm.cxx b/sw/source/core/layout/trvlfrm.cxx
index 240d57078038..39843fd25efb 100644
--- a/sw/source/core/layout/trvlfrm.cxx
+++ b/sw/source/core/layout/trvlfrm.cxx
@@ -1726,7 +1726,7 @@ bool SwFrame::WannaRightPage() const
         const SwFlowFrame *pTmp = SwFlowFrame::CastFlowFrame( pFlow );
         if ( !pTmp->IsFollow() )
         {
-            const SwFormatPageDesc& rPgDesc = pFlow->GetAttrSet()->GetPageDesc();
+            const SwFormatPageDesc& rPgDesc = pFlow->GetPageDescItem();
             pDesc = rPgDesc.GetPageDesc();
             oPgNum = rPgDesc.GetNumOffset();
         }
@@ -1852,7 +1852,7 @@ sal_uInt16 SwFrame::GetVirtPageNum() const
     }
     if ( pFrame )
     {
-        ::boost::optional<sal_uInt16> oNumOffset = pFrame->GetAttrSet()->GetPageDesc().GetNumOffset();
+        ::boost::optional<sal_uInt16> oNumOffset = pFrame->GetPageDescItem().GetNumOffset();
         if (oNumOffset)
         {
             return nPhyPage - pFrame->GetPhyPageNum() + oNumOffset.get();
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index bb04d4ed74db..a25bb8d7bb9f 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -2382,7 +2382,7 @@ void SwContentFrame::UpdateAttr_( const SfxPoolItem* pOld, const SfxPoolItem* pN
                 SwPageFrame *pPage = FindPageFrame();
                 if ( !GetPrev() )
                     CheckPageDescs( pPage );
-                if ( GetAttrSet()->GetPageDesc().GetNumOffset() )
+                if (GetPageDescItem().GetNumOffset())
                     static_cast<SwRootFrame*>(pPage->GetUpper())->SetVirtPageNum( true );
                 SwDocPosUpdate aMsgHint( pPage->getFrameArea().Top() );
                 pPage->GetFormat()->GetDoc()->getIDocumentFieldsAccess().UpdatePageFields( &aMsgHint );
commit 0cad69c5f55c1ec086c4c49739e465f8ff5d781a
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri Jun 1 21:53:39 2018 +0200

    sw_redlinehide: refactor SwFlowFrame::IsKeep()
    
    This thing uses 2 items, a normal one and RES_BREAK, so they need to be
    passed in separately, a merged text frame does not necessarily have any
    item set with the matching items.
    
    Change-Id: I5e50ac60137ba8d94adeaee2ef015551d8a3bdd8

diff --git a/sw/source/core/inc/flowfrm.hxx b/sw/source/core/inc/flowfrm.hxx
index 818f0fb4f597..6f08a70bd39f 100644
--- a/sw/source/core/inc/flowfrm.hxx
+++ b/sw/source/core/inc/flowfrm.hxx
@@ -22,6 +22,8 @@
 
 #include "frmtool.hxx"
 
+class SvxFormatKeepItem;
+class SvxFormatBreakItem;
 class SwPageFrame;
 class SwRect;
 class SwBorderAttrs;
@@ -177,7 +179,9 @@ public:
     bool IsColBreak( bool bAct ) const;
 
     /** method to determine if a Keep needs to be considered (Breaks!) */
-    bool IsKeep( const SwAttrSet& rAttrs, bool bBreakCheck = false ) const;
+    bool IsKeep(SvxFormatKeepItem const& rKeep,
+                SvxFormatBreakItem const& rBreak,
+                bool bBreakCheck = false ) const;
 
     bool HasLockedFollow() const;
 
diff --git a/sw/source/core/layout/calcmove.cxx b/sw/source/core/layout/calcmove.cxx
index c00b5efe1758..2b56272bf49c 100644
--- a/sw/source/core/layout/calcmove.cxx
+++ b/sw/source/core/layout/calcmove.cxx
@@ -1214,7 +1214,7 @@ void SwContentFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
         pNotify->SetBordersJoinedWithPrev();
     }
 
-    const bool bKeep = IsKeep( rAttrs.GetAttrSet() );
+    const bool bKeep = IsKeep(rAttrs.GetAttrSet().GetKeep(), GetBreakItem());
 
     SwSaveFootnoteHeight *pSaveFootnote = nullptr;
     if ( bFootnote )
@@ -2092,7 +2092,7 @@ bool SwContentFrame::WouldFit_( SwTwips nSpace,
             }
         }
 
-        if ( bRet && !bSplit && pFrame->IsKeep( rAttrs.GetAttrSet() ) )
+        if (bRet && !bSplit && pFrame->IsKeep(rAttrs.GetAttrSet().GetKeep(), GetBreakItem()))
         {
             if( bTstMove )
             {
diff --git a/sw/source/core/layout/flowfrm.cxx b/sw/source/core/layout/flowfrm.cxx
index 952708ae0342..d7c651a7c597 100644
--- a/sw/source/core/layout/flowfrm.cxx
+++ b/sw/source/core/layout/flowfrm.cxx
@@ -41,6 +41,7 @@
 #include <paratr.hxx>
 #include <ftnfrm.hxx>
 #include <txtfrm.hxx>
+#include <notxtfrm.hxx>
 #include <tabfrm.hxx>
 #include <pagedesc.hxx>
 #include <layact.hxx>
@@ -169,7 +170,9 @@ void SwFlowFrame::CheckKeep()
         pPre->InvalidatePos();
 }
 
-bool SwFlowFrame::IsKeep( const SwAttrSet& rAttrs, bool bCheckIfLastRowShouldKeep ) const
+bool SwFlowFrame::IsKeep(SvxFormatKeepItem const& rKeep,
+        SvxFormatBreakItem const& rBreak,
+        bool const bCheckIfLastRowShouldKeep) const
 {
     // 1. The keep attribute is ignored inside footnotes
     // 2. For compatibility reasons, the keep attribute is
@@ -180,7 +183,7 @@ bool SwFlowFrame::IsKeep( const SwAttrSet& rAttrs, bool bCheckIfLastRowShouldKee
     bool bKeep = bCheckIfLastRowShouldKeep ||
                  (  !m_rThis.IsInFootnote() &&
                     ( !m_rThis.IsInTab() || m_rThis.IsTabFrame() ) &&
-                    rAttrs.GetKeep().GetValue() );
+                    rKeep.GetValue() );
 
     OSL_ENSURE( !bCheckIfLastRowShouldKeep || m_rThis.IsTabFrame(),
             "IsKeep with bCheckIfLastRowShouldKeep should only be used for tabfrms" );
@@ -188,7 +191,7 @@ bool SwFlowFrame::IsKeep( const SwAttrSet& rAttrs, bool bCheckIfLastRowShouldKee
     // Ignore keep attribute if there are break situations:
     if ( bKeep )
     {
-        switch ( rAttrs.GetBreak().GetBreak() )
+        switch (rBreak.GetBreak())
         {
             case SvxBreak::ColumnAfter:
             case SvxBreak::ColumnBoth:
@@ -227,23 +230,24 @@ bool SwFlowFrame::IsKeep( const SwAttrSet& rAttrs, bool bCheckIfLastRowShouldKee
 
                 if ( bKeep )
                 {
-                    const SwAttrSet* pSet = nullptr;
-
+                    SvxFormatBreakItem const* pBreak;
+                    SwFormatPageDesc const* pPageDesc;
                     SwTabFrame* pTab = pNxt->IsInTab() ? pNxt->FindTabFrame() : nullptr;
-                    if (pTab)
+                    if (pTab && (!m_rThis.IsInTab() || m_rThis.FindTabFrame() != pTab))
                     {
-                        if ( ! m_rThis.IsInTab() || m_rThis.FindTabFrame() != pTab )
-                            pSet = &pTab->GetFormat()->GetAttrSet();
+                        const SwAttrSet *const pSet = &pTab->GetFormat()->GetAttrSet();
+                        pBreak = &pSet->GetBreak();
+                        pPageDesc = &pSet->GetPageDesc();
+                    }
+                    else
+                    {
+                        pBreak = &pNxt->GetBreakItem();
+                        pPageDesc = &pNxt->GetPageDescItem();
                     }
 
-                    if ( ! pSet )
-                        pSet = pNxt->GetAttrSet();
-
-                    assert(pSet && "No AttrSet to check keep attribute");
-
-                    if ( pSet->GetPageDesc().GetPageDesc() )
+                    if (pPageDesc->GetPageDesc())
                         bKeep = false;
-                    else switch ( pSet->GetBreak().GetBreak() )
+                    else switch (pBreak->GetBreak())
                     {
                         case SvxBreak::ColumnBefore:
                         case SvxBreak::ColumnBoth:
diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index faba4d0e1aa4..74a2f6201e4b 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -1457,7 +1457,7 @@ void CalcContent( SwLayoutFrame *pLay, bool bNoColl )
                                !pTmpFlowFrame->IsJoinLocked() &&
                                !pTmpPrev->isFrameAreaPositionValid() &&
                                 pLay->IsAnLower( pTmpPrev ) &&
-                                pTmpPrevFlowFrame->IsKeep( *pTmpPrev->GetAttrSet() ) &&
+                                pTmpPrevFlowFrame->IsKeep(pTmpPrev->GetAttrSet()->GetKeep(), pTmpPrev->GetBreakItem()) &&
                                 pTmpPrevFlowFrame->IsKeepFwdMoveAllowed();
 
             // format floating screen objects anchored to the frame.
diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index 6552f45a6e0a..bfdb15bc1a86 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -125,7 +125,8 @@ SwFrameNotify::~SwFrameNotify() COVERITY_NOEXCEPT_FALSE
                     if ( pPre && pPre->IsFlowFrame() )
                     {
                         // 1. pPre wants to keep with me:
-                        bool bInvalidPrePos = SwFlowFrame::CastFlowFrame( pPre )->IsKeep( *pPre->GetAttrSet() ) && pPre->GetIndPrev();
+                        bool bInvalidPrePos = SwFlowFrame::CastFlowFrame(pPre)->IsKeep(pPre->GetAttrSet()->GetKeep(), pPre->GetBreakItem())
+                            && pPre->GetIndPrev();
 
                         // 2. pPre is a table and the last row wants to keep with me:
                         if ( !bInvalidPrePos && pPre->IsTabFrame() )
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index 501d756f714f..43723ef67518 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -1859,7 +1859,7 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext)
 
     // The beloved keep attribute
     const bool bEmulateTableKeep = AreAllRowsKeepWithNext( GetFirstNonHeadlineRow() );
-    const bool bKeep = IsKeep( pAttrs->GetAttrSet(), bEmulateTableKeep );
+    const bool bKeep = IsKeep(pAttrs->GetAttrSet().GetKeep(), GetBreakItem(), bEmulateTableKeep);
 
     // All rows should keep together
     const bool bDontSplit = !IsFollow() &&
@@ -2225,9 +2225,12 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext)
                     // 6. There is no section change behind the table (see IsKeep)
                     // 7. The last table row wants to keep with its next.
                     const SwRowFrame* pLastRow = static_cast<const SwRowFrame*>(GetLastLower());
-                    if ( pLastRow && IsKeep( pAttrs->GetAttrSet(), true ) &&
-                         pLastRow->ShouldRowKeepWithNext() )
+                    if (pLastRow
+                        && IsKeep(pAttrs->GetAttrSet().GetKeep(), GetBreakItem(), true)
+                        && pLastRow->ShouldRowKeepWithNext())
+                    {
                         bFormat = true;
+                    }
                 }
 
                 if ( bFormat )
commit a2511bc3fa4f22fd3b6ac59d0cc1e078f00011b3

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list