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

Michael Stahl Michael.Stahl at cib.de
Tue May 29 16:37:33 UTC 2018


 sw/inc/calbck.hxx                               |   72 +++++++++++---
 sw/source/core/access/accmap.cxx                |    4 
 sw/source/core/crsr/crstrvl.cxx                 |    8 -
 sw/source/core/doc/CntntIdxStore.cxx            |    6 -
 sw/source/core/doc/doc.cxx                      |    2 
 sw/source/core/doc/docnum.cxx                   |    7 -
 sw/source/core/doc/docredln.cxx                 |    4 
 sw/source/core/docnode/node.cxx                 |    6 -
 sw/source/core/docnode/node2lay.cxx             |   12 +-
 sw/source/core/draw/dcontact.cxx                |    4 
 sw/source/core/fields/docufld.cxx               |    5 
 sw/source/core/fields/postithelper.cxx          |    2 
 sw/source/core/inc/txtfrm.hxx                   |   44 ++++----
 sw/source/core/layout/atrfrm.cxx                |   12 +-
 sw/source/core/layout/calcmove.cxx              |    3 
 sw/source/core/layout/frmtool.cxx               |    4 
 sw/source/core/layout/ftnfrm.cxx                |    4 
 sw/source/core/layout/movedfwdfrmsbyobjpos.cxx  |    2 
 sw/source/core/layout/softpagebreak.cxx         |    2 
 sw/source/core/layout/ssfrm.cxx                 |    2 
 sw/source/core/layout/wsfrm.cxx                 |    2 
 sw/source/core/text/EnhancedPDFExportHelper.cxx |    2 
 sw/source/core/text/itratr.cxx                  |    8 -
 sw/source/core/text/porlay.cxx                  |    2 
 sw/source/core/text/redlnitr.cxx                |   15 ++
 sw/source/core/text/txtdrop.cxx                 |    6 -
 sw/source/core/text/txtfrm.cxx                  |  123 ++++++++++++++++++++----
 sw/source/core/txtnode/atrftn.cxx               |    4 
 sw/source/core/txtnode/ndtxt.cxx                |    6 -
 29 files changed, 270 insertions(+), 103 deletions(-)

New commits:
commit 2f475a555947ce151b2e5c4ac71320ac3b423693
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue May 29 18:33:06 2018 +0200

    sw_redlinehide: replace SwTextFrame::Modify() with SwClientNotify()
    
    This is critical because it needs to know what SwTextNode sent the hint.
    
    Fortunately it looks like we can just convert this one implementation
    and the backward compat stuff in SwClient will keep the other
    SwFrames working as before with their Modify().
    
    Change-Id: I16f0bf7495002e7393148429640262cb38dc4849

diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index 70f2566e06f2..456cfd4997f4 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -263,7 +263,7 @@ class SW_DLLPUBLIC SwTextFrame: public SwContentFrame
     virtual ~SwTextFrame() override;
 
 protected:
-    virtual void Modify( const SfxPoolItem*, const SfxPoolItem* ) override;
+    virtual void SwClientNotify(SwModify const& rModify, SfxHint const& rHint) override;
 
 public:
 
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index 047175b8eb8f..d5345e0822b4 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -1264,13 +1264,55 @@ static bool isA11yRelevantAttribute(sal_uInt16 nWhich)
     return nWhich != RES_CHRATR_RSID;
 }
 
-void SwTextFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
+// Note: for now this overrides SwClient::SwClientNotify; the intermediary
+// classes still override SwClient::Modify, which should continue to work
+// as their implementation of SwClientNotify is SwClient's which calls Modify.
+// Therefore we also don't need to call SwClient::SwClientNotify(rModify, rHint)
+// because that's all it does, and this implementation calls
+// 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*const pOld(pHint->m_pOld);
+    SfxPoolItem const*const pNew(pHint->m_pNew);
+
+#if 1
+    if (m_pMergedPara)
+    {
+            bool good(false);
+            struct HorribleDebugHack : public SwClient { SwClient * m; };
+            std::vector<HorribleDebugHack> const* p(reinterpret_cast<std::vector<HorribleDebugHack> const*>(&m_pMergedPara->listener));
+            for (HorribleDebugHack const& h : *p)
+            {
+                if (h.GetRegisteredIn() == &rModify)
+                {
+                    (void) h.m;
+                    good = true;
+                    break;
+                }
+            }
+            assert(good);
+    }
+#endif
+
     const sal_uInt16 nWhich = pOld ? pOld->Which() : pNew ? pNew->Which() : 0;
 
     // modifications concerning frame attributes are processed by the base class
     if( IsInRange( aFrameFormatSetRange, nWhich ) || RES_FMT_CHG == nWhich )
     {
+        if (m_pMergedPara)
+        {   // ignore item set changes that don't apply
+            SwTextNode const*const pAttrNode(
+                (nWhich == RES_PAGEDESC || nWhich == RES_BREAK)
+                    ? m_pMergedPara->pFirstNode
+                    : m_pMergedPara->pParaPropsNode);
+            if (pAttrNode != &rModify)
+            {
+                return;
+            }
+        }
         SwContentFrame::Modify( pOld, pNew );
         if( nWhich == RES_FMT_CHG && getRootFrame()->GetCurrShell() )
         {
@@ -1287,6 +1329,14 @@ void SwTextFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
         return;
     }
 
+    if (m_pMergedPara && m_pMergedPara->pParaPropsNode != &rModify)
+    {
+        if (isPARATR(nWhich) || isPARATR_LIST(nWhich))
+        {
+            return; // ignore it
+        }
+    }
+
     // while locked ignore all modifications
     if( IsLocked() )
         return;
@@ -1302,6 +1352,7 @@ void SwTextFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
     {
         case RES_LINENUMBER:
         {
+            assert(false); // should have been forwarded to SwContentFrame
             InvalidateLineNum();
         }
         break;
@@ -1484,23 +1535,27 @@ void SwTextFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
                                             RES_PARATR_REGISTER, false );
             if ( bLineSpace || bRegister )
             {
-                Prepare( bRegister ? PREP_REGISTER : PREP_ADJUST_FRM );
-                CalcLineSpace();
-                InvalidateSize();
-                InvalidatePrt_();
+                if (!m_pMergedPara || m_pMergedPara->pParaPropsNode == &rModify)
+                {
+                    Prepare( bRegister ? PREP_REGISTER : PREP_ADJUST_FRM );
+                    CalcLineSpace();
+                    InvalidateSize();
+                    InvalidatePrt_();
 
-                // i#11859
-                //  (1) Also invalidate next frame on next page/column.
-                //  (2) Skip empty sections and hidden paragraphs
-                //  Thus, use method <InvalidateNextPrtArea()>
-                InvalidateNextPrtArea();
+                    // i#11859
+                    //  (1) Also invalidate next frame on next page/column.
+                    //  (2) Skip empty sections and hidden paragraphs
+                    //  Thus, use method <InvalidateNextPrtArea()>
+                    InvalidateNextPrtArea();
 
-                SetCompletePaint();
+                    SetCompletePaint();
+                }
                 nClear |= 0x04;
                 if ( bLineSpace )
                 {
                     --nCount;
-                    if( IsInSct() && !GetPrev() )
+                    if ((!m_pMergedPara || m_pMergedPara->pParaPropsNode == &rModify)
+                        && IsInSct() && !GetPrev())
                     {
                         SwSectionFrame *pSect = FindSctFrame();
                         if( pSect->ContainsAny() == this )
@@ -1513,15 +1568,19 @@ void SwTextFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
             if ( SfxItemState::SET == rNewSet.GetItemState( RES_PARATR_SPLIT,
                                                        false ))
             {
-                if ( GetPrev() )
-                    CheckKeep();
-                Prepare();
-                InvalidateSize();
+                if (!m_pMergedPara || m_pMergedPara->pParaPropsNode == &rModify)
+                {
+                    if (GetPrev())
+                        CheckKeep();
+                    Prepare();
+                    InvalidateSize();
+                }
                 nClear |= 0x08;
                 --nCount;
             }
 
             if( SfxItemState::SET == rNewSet.GetItemState( RES_BACKGROUND, false)
+                && (!m_pMergedPara || m_pMergedPara->pParaPropsNode == &rModify)
                 && !IsFollow() && GetDrawObjs() )
             {
                 SwSortedObjs *pObjs = GetDrawObjs();
@@ -1575,7 +1634,8 @@ void SwTextFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
                       rNewSet.GetItemState( RES_CHRATR_CTL_FONT, false ) )
                 lcl_SetScriptInval( *this, 0 );
             else if ( SfxItemState::SET ==
-                      rNewSet.GetItemState( RES_FRAMEDIR, false ) )
+                      rNewSet.GetItemState( RES_FRAMEDIR, false )
+                && (!m_pMergedPara || m_pMergedPara->pParaPropsNode == &rModify))
             {
                 SetDerivedR2L( false );
                 CheckDirChange();
@@ -1591,11 +1651,32 @@ void SwTextFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
                     InvalidatePrt_();
                 }
 
-                if( nClear )
+                if (nClear || (m_pMergedPara &&
+                        (m_pMergedPara->pParaPropsNode != &rModify ||
+                         m_pMergedPara->pFirstNode != &rModify)))
                 {
                     SwAttrSetChg aOldSet( *static_cast<const SwAttrSetChg*>(pOld) );
                     SwAttrSetChg aNewSet( *static_cast<const SwAttrSetChg*>(pNew) );
 
+                    if (m_pMergedPara && m_pMergedPara->pParaPropsNode != &rModify)
+                    {
+                        for (sal_uInt16 i = RES_PARATR_BEGIN; i != RES_FRMATR_END; ++i)
+                        {
+                            if (i != RES_BREAK && i != RES_PAGEDESC)
+                            {
+                                aOldSet.ClearItem(i);
+                                aNewSet.ClearItem(i);
+                            }
+                        }
+                    }
+                    if (m_pMergedPara && m_pMergedPara->pFirstNode != &rModify)
+                    {
+                        aOldSet.ClearItem(RES_BREAK);
+                        aNewSet.ClearItem(RES_BREAK);
+                        aOldSet.ClearItem(RES_PAGEDESC);
+                        aNewSet.ClearItem(RES_PAGEDESC);
+                    }
+
                     if( 0x01 & nClear )
                     {
                         aOldSet.ClearItem( RES_TXTATR_FTN );
@@ -1663,6 +1744,7 @@ void SwTextFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem *pNew )
             bSetFieldsDirty = true;
             break;
         case RES_FRAMEDIR :
+            assert(false); // should have been forwarded to SwContentFrame
             SetDerivedR2L( false );
             CheckDirChange();
             break;
commit f07c97543d47a7e8c24494b01f50a8c8c72d0d3f
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue May 29 18:28:15 2018 +0200

    sw_redlinehide: SwFrame::IsCollapse() needs an extra check
    
    Could be that the node is empty but the frame not.
    
    Change-Id: I9b9af31f2ef9a6d862cfe38038222b5a46e6b0ab

diff --git a/sw/source/core/layout/calcmove.cxx b/sw/source/core/layout/calcmove.cxx
index 5a3e5b73b837..c00b5efe1758 100644
--- a/sw/source/core/layout/calcmove.cxx
+++ b/sw/source/core/layout/calcmove.cxx
@@ -999,7 +999,8 @@ bool SwFrame::IsCollapse() const
 
     const SwTextFrame *pTextFrame = static_cast<const SwTextFrame*>(this);
     const SwTextNode *pTextNode = pTextFrame->GetTextNodeForParaProps();
-    return pTextNode && pTextNode->IsCollapse();
+    // TODO this SwTextNode function is pointless and should be merged in here
+    return pTextFrame->GetText().isEmpty() && pTextNode && pTextNode->IsCollapse();
 }
 
 void SwContentFrame::MakePrtArea( const SwBorderAttrs &rAttrs )
commit 13c6f97ab60c5a3426b1e973098a378caa8c279e
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue May 29 14:09:08 2018 +0200

    sw_redlinehide: use WriterMultiListener to connect SwTextFrame
    
    ... with multiple SwTextNodes in CheckParaRedlineMerge()
    
    Change-Id: I57402ca7d2210fc30015b9a7e2e05216e0b8a8eb

diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index 3307378a1026..70f2566e06f2 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -88,28 +88,12 @@ struct Extent
     }
 };
 
-struct MergedPara
-{
-    std::vector<Extent> const extents;
-    /// note: cannot be const currently to avoid UB because SwTextGuess::Guess
-    /// const_casts it and modifies it
-    OUString mergedText;
-    /// most paragraph properties are taken from the first non-empty node
-    SwTextNode const*const pParaPropsNode;
-    /// except break attributes, those are taken from the first node
-    SwTextNode *const pFirstNode;
-    MergedPara(std::vector<Extent>&& rExtents, OUString const& rText, SwTextNode const*const pProps, SwTextNode *const pFirst)
-        : extents(std::move(rExtents)), mergedText(rText), pParaPropsNode(pProps), pFirstNode(pFirst)
-    {
-        assert(pParaPropsNode);
-        assert(pFirstNode);
-    }
-};
+struct MergedPara;
 
 std::pair<SwTextNode*, sal_Int32> MapViewToModel(MergedPara const&, TextFrameIndex nIndex);
 TextFrameIndex MapModelToView(MergedPara const&, SwTextNode const* pNode, sal_Int32 nIndex);
 
-std::unique_ptr<sw::MergedPara> CheckParaRedlineMerge(SwTextFrame const* pFrame, SwTextNode & rTextNode);
+std::unique_ptr<sw::MergedPara> CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode);
 
 } // namespace sw
 
@@ -917,7 +901,27 @@ public:
 
 namespace sw {
 
-struct MergedPara;
+struct MergedPara
+{
+    sw::WriterMultiListener listener;
+    std::vector<Extent> const extents;
+    /// note: cannot be const currently to avoid UB because SwTextGuess::Guess
+    /// const_casts it and modifies it
+    OUString mergedText;
+    /// most paragraph properties are taken from the first non-empty node
+    SwTextNode const*const pParaPropsNode;
+    /// except break attributes, those are taken from the first node
+    SwTextNode *const pFirstNode;
+    MergedPara(SwTextFrame & rFrame, std::vector<Extent>&& rExtents,
+            OUString const& rText,
+            SwTextNode const*const pProps, SwTextNode *const pFirst)
+        : listener(rFrame), extents(std::move(rExtents)), mergedText(rText)
+        , pParaPropsNode(pProps), pFirstNode(pFirst)
+    {
+        assert(pParaPropsNode);
+        assert(pFirstNode);
+    }
+};
 
 /// iterate SwTextAttr in potentially merged text frame
 class MergedAttrIterBase
diff --git a/sw/source/core/layout/ssfrm.cxx b/sw/source/core/layout/ssfrm.cxx
index bb6403b2d2b2..a0b035ebaee7 100644
--- a/sw/source/core/layout/ssfrm.cxx
+++ b/sw/source/core/layout/ssfrm.cxx
@@ -437,7 +437,7 @@ SwContentFrame::~SwContentFrame()
 void SwTextFrame::RegisterToNode(SwTextNode & rNode)
 {
     assert(&rNode != GetRegisteredIn());
-    m_pMergedPara = sw::CheckParaRedlineMerge(this, rNode);
+    m_pMergedPara = sw::CheckParaRedlineMerge(*this, rNode);
     rNode.Add( this );
 }
 
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index c6091a54aaaa..965b755bc79f 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -4173,7 +4173,7 @@ void SwRootFrame::SetHideRedlines(bool const bHideRedlines)
                 {
                     if (mbHideRedlines && pNode->IsCreateFrameWhenHidingRedlines())
                     {
-                        pFrame->SetMergedPara(CheckParaRedlineMerge(pFrame, rTextNode));
+                        pFrame->SetMergedPara(CheckParaRedlineMerge(*pFrame, rTextNode));
                     }
                     else
                     {
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 3d8225c79049..5d94354c9c90 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -47,14 +47,15 @@ using namespace ::com::sun::star;
 namespace sw {
 
 std::unique_ptr<sw::MergedPara>
-CheckParaRedlineMerge(SwTextFrame const*const pFrame, SwTextNode & rTextNode)
+CheckParaRedlineMerge(SwTextFrame & rFrame, SwTextNode & rTextNode)
 {
     IDocumentRedlineAccess const& rIDRA = rTextNode.getIDocumentRedlineAccess();
-    if (!pFrame->getRootFrame()->IsHideRedlines())
+    if (!rFrame.getRootFrame()->IsHideRedlines())
     {
         return nullptr;
     }
     bool bHaveRedlines(false);
+    std::vector<SwTextNode *> nodes{ &rTextNode };
     std::vector<sw::Extent> extents;
     OUStringBuffer mergedText;
     SwTextNode const* pParaPropsNode(nullptr);
@@ -92,6 +93,7 @@ CheckParaRedlineMerge(SwTextFrame const*const pFrame, SwTextNode & rTextNode)
             }
             pNode = pEnd->nNode.GetNode().GetTextNode();
             assert(pNode);
+            nodes.push_back(pNode);
             pNode->SetRedlineMergeFlag(SwNode::Merge::NonFirst);
         }
         nLastEnd = pEnd->nContent.GetIndex();
@@ -115,8 +117,13 @@ CheckParaRedlineMerge(SwTextFrame const*const pFrame, SwTextNode & rTextNode)
         assert(!mergedText.isEmpty());
         pParaPropsNode = extents.begin()->pNode; // para props from first node that isn't empty
     }
-    return o3tl::make_unique<sw::MergedPara>(std::move(extents),
-            mergedText.makeStringAndClear(), pParaPropsNode, &rTextNode);
+    auto pRet(o3tl::make_unique<sw::MergedPara>(rFrame, std::move(extents),
+                mergedText.makeStringAndClear(), pParaPropsNode, &rTextNode));
+    for (SwTextNode * pTmp : nodes)
+    {
+        pRet->listener.StartListening(pTmp);
+    }
+    return pRet;
 }
 
 } // namespace sw
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index 843c029f5767..047175b8eb8f 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -579,7 +579,8 @@ SwTextFrame::SwTextFrame(SwTextNode * const pNode, SwFrame* pSib )
     , mnFootnoteLine( 0 )
     , mnHeightOfLastLine( 0 )
     , mnAdditionalFirstLineOffset( 0 )
-    , m_pMergedPara(CheckParaRedlineMerge(this, *pNode)) // ensure it is inited
+    // note: this may change this->pRegisteredIn to m_pMergedPara->listeners
+    , m_pMergedPara(CheckParaRedlineMerge(*this, *pNode)) // ensure it is inited
     , mnOffset( 0 )
     , mnCacheIndex( USHRT_MAX )
     , mbLocked( false )
commit c4932c69f97067f4c31eb7017eacab0c8aca4a82
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue May 29 13:12:15 2018 +0200

    sw_redlinehide: disable optimisation in ContentIdxStoreImpl::SaveFlys()
    
    ... if there's a merged text frame.
    
    Change-Id: Ida468518ab3f0c2a077a831ec81522f7d3b2c9ff

diff --git a/sw/source/core/doc/CntntIdxStore.cxx b/sw/source/core/doc/CntntIdxStore.cxx
index 7f97c0c83250..ffdf2ff15764 100644
--- a/sw/source/core/doc/CntntIdxStore.cxx
+++ b/sw/source/core/doc/CntntIdxStore.cxx
@@ -38,6 +38,7 @@
 #include <sal/types.h>
 #include <unocrsr.hxx>
 #include <edimp.hxx>
+#include <txtfrm.hxx>
 #include <memory>
 
 using namespace ::boost;
@@ -321,7 +322,10 @@ void ContentIdxStoreImpl::SaveFlys(SwDoc* pDoc, sal_uLong nNode, sal_Int32 nCont
     SwFrame* pFrame = pNode->getLayoutFrame( pDoc->getIDocumentLayoutAccess().GetCurrentLayout() );
     if( pFrame )
     {
-        if( !pFrame->GetDrawObjs() )
+        // sw_redlinehide: this looks like an invalid optimisation if merged,
+        // assuming that flys in deleted redlines should be saved here too.
+        if ((!pFrame->IsTextFrame() || !static_cast<SwTextFrame const*>(pFrame)->GetMergedPara())
+                && !pFrame->GetDrawObjs())
             return; // if we have a layout and no DrawObjs, we can skip this
     }
     MarkEntry aSave = { 0, false, 0 };
commit 158c4765769bf51a97739c8cce4de2d166e236dc
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue May 29 13:07:32 2018 +0200

    sw_redlinehide: add some checks in places that require the node
    
    ... that contains the first text of the frame.
    
    Change-Id: I8efc1acd87a7fcb9e4e38925f1ba91ec1a004dfd

diff --git a/sw/source/core/doc/docnum.cxx b/sw/source/core/doc/docnum.cxx
index d38e0955d520..e61ae5bfdcbb 100644
--- a/sw/source/core/doc/docnum.cxx
+++ b/sw/source/core/doc/docnum.cxx
@@ -1114,8 +1114,11 @@ void SwDoc::StopNumRuleAnimations( OutputDevice* pOut )
             SwTextNode* pTNd = *aTextNodeIter;
             SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pTNd);
             for(SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
-                if( pFrame->HasAnimation() )
+                if (pFrame->HasAnimation() &&
+                    (!pFrame->GetMergedPara() || pFrame->GetMergedPara()->pParaPropsNode == pTNd))
+                {
                     pFrame->StopAnimation( pOut );
+                }
         }
     }
 }
diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index 292c887d04f0..c6749e02c403 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -1391,7 +1391,9 @@ SwTwips SwTextNode::GetWidthOfLeadingTabs() const
         for( SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
         {
             // Only consider master frames:
-            if ( !pFrame->IsFollow() )
+            if (!pFrame->IsFollow() &&
+                // sw_redlinehide: paraPropsNode has the first text of the frame
+                (!pFrame->GetMergedPara() || pFrame->GetMergedPara()->pParaPropsNode == this))
             {
                 SwRectFnSet aRectFnSet(pFrame);
                 SwRect aRect;
diff --git a/sw/source/core/text/txtdrop.cxx b/sw/source/core/text/txtdrop.cxx
index b4a1b88c0a6d..317eb084a4c1 100644
--- a/sw/source/core/text/txtdrop.cxx
+++ b/sw/source/core/text/txtdrop.cxx
@@ -250,7 +250,9 @@ bool SwTextNode::GetDropSize(int& rFontHeight, int& rDropHeight, int& rDropDesce
     for( SwTextFrame* pLastFrame = aIter.First(); pLastFrame; pLastFrame = aIter.Next() )
     {
         // Only (master-) text frames can have a drop cap.
-        if ( !pLastFrame->IsFollow() )
+        if (!pLastFrame->IsFollow() &&
+            // sw_redlinehide: paraPropsNode has the first text of the frame
+            (!pLastFrame->GetMergedPara() || pLastFrame->GetMergedPara()->pParaPropsNode == this))
         {
 
             if( !pLastFrame->HasPara() )
commit a31310300d0f2f0e639722f484b356de7675afac
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue May 29 13:03:27 2018 +0200

    sw_redlinehide: convert SwCursorShell::GotoTOXMarkBase()
    
    Better not to assume that index 0 of the node is visible.
    
    Change-Id: I50f4a53d853cc59d3d0403eae34af48a56b1776a

diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx
index 0c23fc1bb09a..310411ab3c65 100644
--- a/sw/source/core/crsr/crstrvl.cxx
+++ b/sw/source/core/crsr/crstrvl.cxx
@@ -394,8 +394,10 @@ void SwCursorShell::GotoTOXMarkBase()
                 {
                     SwCallLink aLk( *this ); // watch Cursor-Moves
                     SwCursorSaveState aSaveState( *m_pCurrentCursor );
-                    m_pCurrentCursor->GetPoint()->nNode = *pCNd;
-                    m_pCurrentCursor->GetPoint()->nContent.Assign( pCNd, 0 );
+                    assert(pCFrame->IsTextFrame());
+                    *m_pCurrentCursor->GetPoint() =
+                        static_cast<SwTextFrame const*>(pCFrame)
+                            ->MapViewToModelPos(TextFrameIndex(0));
                     bRet = !m_pCurrentCursor->IsInProtectTable() &&
                             !m_pCurrentCursor->IsSelOvr();
                     if( bRet )
commit cfa169856a71f5e3ef1d18e4ed292461a128c231
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue May 29 13:01:27 2018 +0200

    sw_redlinehide: convert the SwIterators in SwNode2Layout too
    
    Change-Id: Id0fb0ea0be731f2f4af372c2034d56fd6e20b4a1

diff --git a/sw/source/core/docnode/node2lay.cxx b/sw/source/core/docnode/node2lay.cxx
index 5fb682b28a7a..8957ca5780a7 100644
--- a/sw/source/core/docnode/node2lay.cxx
+++ b/sw/source/core/docnode/node2lay.cxx
@@ -36,7 +36,7 @@
  */
 class SwNode2LayImpl
 {
-    std::unique_ptr<SwIterator<SwFrame,SwModify>> pIter;
+    std::unique_ptr<SwIterator<SwFrame, SwModify, sw::IteratorMode::UnwrapMulti>> pIter;
     SwModify* pMod;
     std::vector<SwFrame*> mvUpperFrames; // To collect the Upper
     sal_uLong nIndex;        // The Index of the to-be-inserted Nodes
@@ -69,7 +69,9 @@ SwNode* GoNextWithFrame(const SwNodes& rNodes, SwNodeIndex *pIdx)
         pNd = &aTmp.GetNode();
         bool bFound = false;
         if ( pNd->IsContentNode() )
-            bFound = SwIterator<SwFrame,SwContentNode>(*static_cast<SwContentNode*>(pNd)).First();
+            // sw_redlinehide: assume that it's OK to find a node with the same
+            // frame as the caller's one
+            bFound = SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*static_cast<SwContentNode*>(pNd)).First();
         else if ( pNd->IsTableNode() )
             bFound = SwIterator<SwFrame,SwFormat>(*static_cast<SwTableNode*>(pNd)->GetTable().GetFrameFormat()).First() ;
         else if( pNd->IsEndNode() && !pNd->StartOfSectionNode()->IsSectionNode() )
@@ -101,7 +103,9 @@ SwNode* GoPreviousWithFrame(SwNodeIndex *pIdx)
         pNd = &aTmp.GetNode();
         bool bFound = false;
         if ( pNd->IsContentNode() )
-            bFound = SwIterator<SwFrame,SwContentNode>(*static_cast<SwContentNode*>(pNd)).First();
+            // sw_redlinehide: assume that it's OK to find a node with the same
+            // frame as the caller's one
+            bFound = SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*static_cast<SwContentNode*>(pNd)).First();
         else if ( pNd->IsTableNode() )
             bFound = SwIterator<SwFrame,SwFormat>(*static_cast<SwTableNode*>(pNd)->GetTable().GetFrameFormat()).First();
         else if( pNd->IsStartNode() && !pNd->IsSectionNode() )
@@ -169,7 +173,7 @@ SwNode2LayImpl::SwNode2LayImpl( const SwNode& rNode, sal_uLong nIdx, bool bSearc
             OSL_ENSURE( pNd->IsTableNode(), "For Tablenodes only" );
             pMod = pNd->GetTableNode()->GetTable().GetFrameFormat();
         }
-        pIter.reset(new SwIterator<SwFrame,SwModify>( *pMod ));
+        pIter.reset(new SwIterator<SwFrame, SwModify, sw::IteratorMode::UnwrapMulti>(*pMod));
     }
     else
     {
commit dbdfcb8684f0abc401013c8d08a4a0e5225cf0b0
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue May 29 12:40:51 2018 +0200

    sw_redlinehide: use unwrapping SwIterator when iterating SwModify
    
    ... that could be a SwTextNode, too.
    
    Change-Id: I5627564966ce331b07b69010d42d61ff8a04364c

diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index dd0ecf73a3c1..ee9eab110262 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -311,7 +311,7 @@ namespace
 void lcl_LOKInvalidateFrames(const SwModify& rMod, const SwRootFrame* pLayout,
         SwFrameType const nFrameType, const Point* pPoint)
 {
-    SwIterator<SwFrame,SwModify> aIter( rMod );
+    SwIterator<SwFrame, SwModify, sw::IteratorMode::UnwrapMulti> aIter(rMod);
 
     for (SwFrame* pTmpFrame = aIter.First(); pTmpFrame; pTmpFrame = aIter.Next() )
     {
diff --git a/sw/source/core/draw/dcontact.cxx b/sw/source/core/draw/dcontact.cxx
index 749f4eaee868..d3d36b12c5be 100644
--- a/sw/source/core/draw/dcontact.cxx
+++ b/sw/source/core/draw/dcontact.cxx
@@ -1836,7 +1836,7 @@ void SwDrawContact::ConnectToLayout( const SwFormatAnchor* pAnch )
                     break;
                 }
 
-                SwIterator<SwFrame,SwModify> aIter( *pModify );
+                SwIterator<SwFrame, SwModify, sw::IteratorMode::UnwrapMulti> aIter(*pModify);
                 SwFrame* pAnchorFrameOfMaster = nullptr;
                 for( SwFrame *pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
                 {
diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index de435a0224d1..0d602cc6630c 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -3232,7 +3232,7 @@ SwFrame* GetFrameOfModify( const SwRootFrame* pLayout, SwModify const& rMod, SwF
     SwRect aCalcRect;
     bool bClientIterChanged = false;
 
-    SwIterator<SwFrame,SwModify> aIter( rMod );
+    SwIterator<SwFrame, SwModify, sw::IteratorMode::UnwrapMulti> aIter(rMod);
     do {
         pMinFrame = nullptr;
         aHolder.Reset();
@@ -3424,7 +3424,7 @@ bool SwDeletionChecker::HasBeenDeleted()
     if ( !mpFrame || !mpRegIn )
         return false;
 
-    SwIterator<SwFrame,SwModify> aIter(*mpRegIn);
+    SwIterator<SwFrame, SwModify, sw::IteratorMode::UnwrapMulti> aIter(*mpRegIn);
     SwFrame* pLast = aIter.First();
     while ( pLast )
     {
commit 8e7b73d06e5fd7d4647d6a65e208f6b491655aff
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue May 29 11:50:52 2018 +0200

    sw_redlinehide: use unwrapping SwIterator when iterating SwTextNode
    
    ... or SwContentNode.
    
    Change-Id: Ib05038fd5a5550f5ed6dd90e129a2d7c3da74c1e

diff --git a/sw/source/core/access/accmap.cxx b/sw/source/core/access/accmap.cxx
index 712b70873507..601898ac6d6b 100644
--- a/sw/source/core/access/accmap.cxx
+++ b/sw/source/core/access/accmap.cxx
@@ -1320,7 +1320,7 @@ void SwAccessibleMap::InvalidateShapeInParaSelection()
                     if(nStartIndex.GetNode().IsContentNode())
                     {
                         SwContentNode* pCNd = static_cast<SwContentNode*>(&(nStartIndex.GetNode()));
-                        pFrame = SwIterator<SwFrame, SwContentNode>(*pCNd).First();
+                        pFrame = SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*pCNd).First();
                     }
                     else if( nStartIndex.GetNode().IsTableNode() )
                     {
@@ -3319,7 +3319,7 @@ SwAccessibleSelectedParas_Impl* SwAccessibleMap::BuildSelectedParas()
                 if ( pTextNode )
                 {
                     // loop on all text frames registered at the text node.
-                    SwIterator<SwTextFrame,SwTextNode> aIter( *pTextNode );
+                    SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pTextNode);
                     for( SwTextFrame* pTextFrame = aIter.First(); pTextFrame; pTextFrame = aIter.Next() )
                         {
                             uno::WeakReference < XAccessible > xWeakAcc;
diff --git a/sw/source/core/crsr/crstrvl.cxx b/sw/source/core/crsr/crstrvl.cxx
index a8c8fada8c40..0c23fc1bb09a 100644
--- a/sw/source/core/crsr/crstrvl.cxx
+++ b/sw/source/core/crsr/crstrvl.cxx
@@ -1763,7 +1763,7 @@ bool SwContentAtPos::IsInRTLText()const
     }
     if(pNd)
     {
-        SwIterator<SwTextFrame,SwTextNode> aIter(*pNd);
+        SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pNd);
         SwTextFrame* pTmpFrame = aIter.First();
         while( pTmpFrame )
         {
diff --git a/sw/source/core/doc/doc.cxx b/sw/source/core/doc/doc.cxx
index 5d57fb70d4fd..4795e92d9b46 100644
--- a/sw/source/core/doc/doc.cxx
+++ b/sw/source/core/doc/doc.cxx
@@ -519,7 +519,7 @@ sal_uInt16 PostItField_::GetPageNo(
     //Probably only once. For the page number we don't select a random one,
     //but the PostIt's first occurrence in the selected area.
     rVirtPgNo = 0;
-    SwIterator<SwTextFrame,SwTextNode> aIter( GetTextField()->GetTextNode() );
+    SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(GetTextField()->GetTextNode());
     for( SwTextFrame* pFrame = aIter.First(); pFrame;  pFrame = aIter.Next() )
     {
         TextFrameIndex const nPos = pFrame->MapModelToView(
diff --git a/sw/source/core/doc/docnum.cxx b/sw/source/core/doc/docnum.cxx
index 4c6716d3ad5b..d38e0955d520 100644
--- a/sw/source/core/doc/docnum.cxx
+++ b/sw/source/core/doc/docnum.cxx
@@ -1112,7 +1112,7 @@ void SwDoc::StopNumRuleAnimations( OutputDevice* pOut )
               aTextNodeIter != aTextNodeList.end(); ++aTextNodeIter )
         {
             SwTextNode* pTNd = *aTextNodeIter;
-            SwIterator<SwTextFrame,SwTextNode> aIter(*pTNd);
+            SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pTNd);
             for(SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
                 if( pFrame->HasAnimation() )
                     pFrame->StopAnimation( pOut );
diff --git a/sw/source/core/doc/docredln.cxx b/sw/source/core/doc/docredln.cxx
index 159d57fae414..dd0ecf73a3c1 100644
--- a/sw/source/core/doc/docredln.cxx
+++ b/sw/source/core/doc/docredln.cxx
@@ -1671,7 +1671,7 @@ void SwRangeRedline::MoveFromSection(size_t nMyPos)
         {
             if (SwTextNode const*const pNode = node.GetNode().GetTextNode())
             {
-                SwIterator<SwTextFrame,SwTextNode> aIter(*pNode);
+                SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*pNode);
                 for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
                 {
                     pFrame->SetMergedPara(nullptr);
diff --git a/sw/source/core/docnode/node.cxx b/sw/source/core/docnode/node.cxx
index 1e6abe609702..e9992790c2eb 100644
--- a/sw/source/core/docnode/node.cxx
+++ b/sw/source/core/docnode/node.cxx
@@ -717,7 +717,7 @@ SwFrameFormat* SwNode::GetFlyFormat() const
     {
         if( IsContentNode() )
         {
-            SwContentFrame* pFrame = SwIterator<SwContentFrame,SwContentNode>( *static_cast<const SwContentNode*>(this) ).First();
+            SwContentFrame* pFrame = SwIterator<SwContentFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*static_cast<const SwContentNode*>(this)).First();
             if( pFrame )
                 pRet = pFrame->FindFlyFrame()->GetFormat();
         }
@@ -1312,7 +1312,7 @@ void SwContentNode::DelFrames( bool bIsDisposeAccTable )
     if( !HasWriterListeners() )
         return;
 
-    SwIterator<SwContentFrame,SwContentNode> aIter( *this );
+    SwIterator<SwContentFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*this);
     for( SwContentFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
     {
         // #i27138#
@@ -1393,7 +1393,7 @@ bool SwContentNode::GetInfo( SfxPoolItem& rInfo ) const
     case RES_CONTENT_VISIBLE:
         {
             static_cast<SwPtrMsgPoolItem&>(rInfo).pObject =
-                SwIterator<SwFrame,SwContentNode>(*this).First();
+                SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*this).First();
         }
         return false;
     }
diff --git a/sw/source/core/draw/dcontact.cxx b/sw/source/core/draw/dcontact.cxx
index 67843b7f70ef..749f4eaee868 100644
--- a/sw/source/core/draw/dcontact.cxx
+++ b/sw/source/core/draw/dcontact.cxx
@@ -1803,7 +1803,7 @@ void SwDrawContact::ConnectToLayout( const SwFormatAnchor* pAnch )
                     {
                         SwNodeIndex aIdx( pAnch->GetContentAnchor()->nNode );
                         SwContentNode* pCNd = pDrawFrameFormat->GetDoc()->GetNodes().GoNext( &aIdx );
-                        if ( SwIterator<SwFrame,SwContentNode>( *pCNd ).First() )
+                        if (SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*pCNd).First())
                             pModify = pCNd;
                         else
                         {
diff --git a/sw/source/core/fields/docufld.cxx b/sw/source/core/fields/docufld.cxx
index fa08469d50fe..afb1ad525c52 100644
--- a/sw/source/core/fields/docufld.cxx
+++ b/sw/source/core/fields/docufld.cxx
@@ -152,7 +152,10 @@ void SwPageNumberFieldType::ChangeExpansion( SwDoc* pDoc,
                 const SwContentNode* pNd = dynamic_cast<const SwContentNode*>( pDesc->GetDefinedIn()  );
                 if( pNd )
                 {
-                    if ( SwIterator<SwFrame,SwContentNode>(*pNd).First() )
+                    if (SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*pNd).First())
+                    // sw_redlinehide: not sure if this should happen only if
+                    // it's the first node, because that's where RES_PAGEDESC
+                    // is effective?
                         m_bVirtual = true;
                 }
                 else if( dynamic_cast< const SwFormat* >(pDesc->GetDefinedIn()) !=  nullptr)
diff --git a/sw/source/core/fields/postithelper.cxx b/sw/source/core/fields/postithelper.cxx
index 6261e0ebc609..6858e7e7daf0 100644
--- a/sw/source/core/fields/postithelper.cxx
+++ b/sw/source/core/fields/postithelper.cxx
@@ -48,7 +48,7 @@ SwPostItHelper::SwLayoutStatus SwPostItHelper::getLayoutInfos(
     if ( pTextNode == nullptr )
         return aRet;
 
-    SwIterator<SwTextFrame,SwContentNode> aIter( *pTextNode );
+    SwIterator<SwTextFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pTextNode);
     for( SwTextFrame* pTextFrame = aIter.First(); pTextFrame != nullptr; pTextFrame = aIter.Next() )
     {
         if( !pTextFrame->IsFollow() )
diff --git a/sw/source/core/layout/atrfrm.cxx b/sw/source/core/layout/atrfrm.cxx
index bcc42a8b06f8..8523dc74b1f0 100644
--- a/sw/source/core/layout/atrfrm.cxx
+++ b/sw/source/core/layout/atrfrm.cxx
@@ -2933,7 +2933,7 @@ void SwFlyFrameFormat::MakeFrames()
             }
             if ( pCNd )
             {
-                if( SwIterator<SwFrame,SwContentNode>( *pCNd ).First() )
+                if (SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti>(*pCNd).First())
                 {
                     pModify = pCNd;
                 }
@@ -2964,7 +2964,7 @@ void SwFlyFrameFormat::MakeFrames()
             if( nPgNum == 0 && aAnchorAttr.GetContentAnchor() )
             {
                 SwContentNode *pCNd = aAnchorAttr.GetContentAnchor()->nNode.GetNode().GetContentNode();
-                SwIterator<SwFrame,SwContentNode> aIter( *pCNd );
+                SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pCNd);
                 for ( SwFrame* pFrame = aIter.First(); pFrame != nullptr; pFrame = aIter.Next() )
                 {
                     pPage = pFrame->FindPageFrame();
@@ -2996,7 +2996,7 @@ void SwFlyFrameFormat::MakeFrames()
 
     if( pModify )
     {
-        SwIterator<SwFrame,SwModify> aIter( *pModify );
+        SwIterator<SwFrame, SwModify, sw::IteratorMode::UnwrapMulti> aIter(*pModify);
         for( SwFrame *pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
         {
             bool bAdd = !pFrame->IsContentFrame() ||
@@ -3270,14 +3270,16 @@ SwHandleAnchorNodeChg::SwHandleAnchorNodeChg( SwFlyFrameFormat& _rFlyFrameFormat
         {
             // determine 'old' number of anchor frames
             sal_uInt32 nOldNumOfAnchFrame( 0 );
-            SwIterator<SwFrame,SwContentNode> aOldIter( *(aOldAnchorFormat.GetContentAnchor()->nNode.GetNode().GetContentNode()) );
+            SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aOldIter(
+                *(aOldAnchorFormat.GetContentAnchor()->nNode.GetNode().GetContentNode()) );
             for( SwFrame* pOld = aOldIter.First(); pOld; pOld = aOldIter.Next() )
             {
                 ++nOldNumOfAnchFrame;
             }
             // determine 'new' number of anchor frames
             sal_uInt32 nNewNumOfAnchFrame( 0 );
-            SwIterator<SwFrame,SwContentNode> aNewIter( *(_rNewAnchorFormat.GetContentAnchor()->nNode.GetNode().GetContentNode()) );
+            SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aNewIter(
+                *(_rNewAnchorFormat.GetContentAnchor()->nNode.GetNode().GetContentNode()) );
             for( SwFrame* pNew = aNewIter.First(); pNew; pNew = aNewIter.Next() )
             {
                 ++nNewNumOfAnchFrame;
diff --git a/sw/source/core/layout/ftnfrm.cxx b/sw/source/core/layout/ftnfrm.cxx
index e8eddce278c1..e34c2603d7bd 100644
--- a/sw/source/core/layout/ftnfrm.cxx
+++ b/sw/source/core/layout/ftnfrm.cxx
@@ -1104,7 +1104,7 @@ void SwFootnoteBossFrame::ResetFootnote( const SwFootnoteFrame *pCheck )
     if ( !pNd )
         pNd = pCheck->GetFormat()->GetDoc()->
               GetNodes().GoNextSection( &aIdx, true, false );
-    SwIterator<SwFrame,SwContentNode> aIter( *pNd );
+    SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pNd);
     SwFrame* pFrame = aIter.First();
     while( pFrame )
     {
@@ -1612,7 +1612,7 @@ SwFootnoteFrame *SwFootnoteBossFrame::FindFootnote( const SwContentFrame *pRef,
               GetNodes().GoNextSection( &aIdx, true, false );
     if ( !pNd )
         return nullptr;
-    SwIterator<SwFrame,SwContentNode> aIter( *pNd );
+    SwIterator<SwFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pNd);
     SwFrame* pFrame = aIter.First();
     if( pFrame )
         do
diff --git a/sw/source/core/layout/movedfwdfrmsbyobjpos.cxx b/sw/source/core/layout/movedfwdfrmsbyobjpos.cxx
index 3f1dbe34e0cf..c57d2f830361 100644
--- a/sw/source/core/layout/movedfwdfrmsbyobjpos.cxx
+++ b/sw/source/core/layout/movedfwdfrmsbyobjpos.cxx
@@ -76,7 +76,7 @@ bool SwMovedFwdFramesByObjPos::DoesRowContainMovedFwdFrame( const SwRowFrame& _r
         const NodeMapEntry& rEntry = *aIter;
         if ( rEntry.second >= nPageNumOfRow )
         {
-            SwIterator<SwTextFrame,SwTextNode> aFrameIter( *rEntry.first );
+            SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aFrameIter(*rEntry.first);
             for( SwTextFrame* pTextFrame = aFrameIter.First(); pTextFrame; pTextFrame = aFrameIter.Next() )
             {
                 // #115759# - assure that found text frame
diff --git a/sw/source/core/layout/softpagebreak.cxx b/sw/source/core/layout/softpagebreak.cxx
index 109730e8cfa0..9113ed72c274 100644
--- a/sw/source/core/layout/softpagebreak.cxx
+++ b/sw/source/core/layout/softpagebreak.cxx
@@ -27,7 +27,7 @@
 
 void SwTextNode::fillSoftPageBreakList( SwSoftPageBreakList& rBreak ) const
 {
-    SwIterator<SwTextFrame,SwTextNode> aIter( *this );
+    SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*this);
     for( const SwTextFrame *pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
     {
         // No soft page break in header or footer
diff --git a/sw/source/core/text/EnhancedPDFExportHelper.cxx b/sw/source/core/text/EnhancedPDFExportHelper.cxx
index f116dd6cfa9e..d171a5fbef80 100644
--- a/sw/source/core/text/EnhancedPDFExportHelper.cxx
+++ b/sw/source/core/text/EnhancedPDFExportHelper.cxx
@@ -2249,7 +2249,7 @@ void SwEnhancedPDFExportHelper::MakeHeaderFooterLinks( vcl::PDFExtOutDevData& rP
     // the offset of the link rectangle calculates as follows:
     const Point aOffset = rLinkRect.Pos() + mrOut.GetMapMode().GetOrigin();
 
-    SwIterator<SwTextFrame,SwTextNode> aIter( rTNd );
+    SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(rTNd);
     for ( SwTextFrame* pTmpFrame = aIter.First(); pTmpFrame; pTmpFrame = aIter.Next() )
         {
             // Add offset to current page:
diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index e3173840d91b..292c887d04f0 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -1332,7 +1332,7 @@ sal_uInt16 SwTextNode::GetScalingOfSelectedText( sal_Int32 nStt, sal_Int32 nEnd
     nWidth = std::max( nWidth, nProWidth );
 
     // search for a text frame this node belongs to
-    SwIterator<SwTextFrame,SwTextNode> aFrameIter( *this );
+    SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aFrameIter(*this);
     SwTextFrame* pFrame = nullptr;
     for( SwTextFrame* pTmpFrame = aFrameIter.First(); pTmpFrame; pTmpFrame = aFrameIter.Next() )
     {
@@ -1387,7 +1387,7 @@ SwTwips SwTextNode::GetWidthOfLeadingTabs() const
         aPos.nContent += nIdx;
 
         // Find the non-follow text frame:
-        SwIterator<SwTextFrame,SwTextNode> aIter( *this );
+        SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*this);
         for( SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
         {
             // Only consider master frames:
diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx
index dbd3f3211945..6fac143a200c 100644
--- a/sw/source/core/text/porlay.cxx
+++ b/sw/source/core/text/porlay.cxx
@@ -2097,7 +2097,7 @@ SwScriptInfo* SwScriptInfo::GetScriptInfo( const SwTextNode& rTNd,
                                            SwTextFrame const**const o_ppFrame,
                                            bool const bAllowInvalid)
 {
-    SwIterator<SwTextFrame,SwTextNode> aIter( rTNd );
+    SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(rTNd);
     SwScriptInfo* pScriptInfo = nullptr;
 
     for( SwTextFrame* pLast = aIter.First(); pLast; pLast = aIter.Next() )
diff --git a/sw/source/core/text/txtdrop.cxx b/sw/source/core/text/txtdrop.cxx
index 85138e2cd35f..b4a1b88c0a6d 100644
--- a/sw/source/core/text/txtdrop.cxx
+++ b/sw/source/core/text/txtdrop.cxx
@@ -246,7 +246,7 @@ bool SwTextNode::GetDropSize(int& rFontHeight, int& rDropHeight, int& rDropDesce
     }
 
     // get text frame
-    SwIterator<SwTextFrame,SwTextNode> aIter( *this );
+    SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*this);
     for( SwTextFrame* pLastFrame = aIter.First(); pLastFrame; pLastFrame = aIter.Next() )
     {
         // Only (master-) text frames can have a drop cap.
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index df597a2d1513..843c029f5767 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -3092,7 +3092,7 @@ SwTwips SwTextFrame::GetBaseVertOffsetForFly(bool bIgnoreFlysAnchoredAtThisFrame
  */
 void SwTextFrame::repaintTextFrames( const SwTextNode& rNode )
 {
-    SwIterator<SwTextFrame,SwTextNode> aIter( rNode );
+    SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(rNode);
     for( const SwTextFrame *pFrame = aIter.First(); pFrame; pFrame = aIter.Next() )
     {
         SwRect aRec( pFrame->GetPaintArea() );
diff --git a/sw/source/core/txtnode/atrftn.cxx b/sw/source/core/txtnode/atrftn.cxx
index 8cad3a892f58..26f41e0333eb 100644
--- a/sw/source/core/txtnode/atrftn.cxx
+++ b/sw/source/core/txtnode/atrftn.cxx
@@ -436,7 +436,7 @@ void SwTextFootnote::DelFrames( const SwFrame* pSib )
     const SwRootFrame* pRoot = pSib ? pSib->getRootFrame() : nullptr;
     bool bFrameFnd = false;
     {
-        SwIterator<SwContentFrame,SwTextNode> aIter( *m_pTextNode );
+        SwIterator<SwContentFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*m_pTextNode);
         for( SwContentFrame* pFnd = aIter.First(); pFnd; pFnd = aIter.Next() )
         {
             if( pRoot != pFnd->getRootFrame() && pRoot )
@@ -457,7 +457,7 @@ void SwTextFootnote::DelFrames( const SwFrame* pSib )
         SwContentNode* pCNd = m_pTextNode->GetNodes().GoNext( &aIdx );
         if( pCNd )
         {
-            SwIterator<SwContentFrame,SwContentNode> aIter( *pCNd );
+            SwIterator<SwContentFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pCNd);
             for( SwContentFrame* pFnd = aIter.First(); pFnd; pFnd = aIter.Next() )
             {
                 if( pRoot != pFnd->getRootFrame() && pRoot )
diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx
index 3609f40054fe..bf0b5d322a4f 100644
--- a/sw/source/core/txtnode/ndtxt.cxx
+++ b/sw/source/core/txtnode/ndtxt.cxx
@@ -309,7 +309,7 @@ static void lcl_ChangeFootnoteRef( SwTextNode &rNode )
             {
                 if( !pFrame )
                 {
-                    pFrame = SwIterator<SwContentFrame,SwTextNode>(rNode).First();
+                    pFrame = SwIterator<SwContentFrame, SwTextNode, sw::IteratorMode::UnwrapMulti>(rNode).First();
                     if (!pFrame)
                         return;
                 }
@@ -323,7 +323,7 @@ static void lcl_ChangeFootnoteRef( SwTextNode &rNode )
                 if ( !pNd )
                     continue;
 
-                SwIterator<SwContentFrame,SwContentNode> aIter( *pNd );
+                SwIterator<SwContentFrame, SwContentNode, sw::IteratorMode::UnwrapMulti> aIter(*pNd);
                 SwContentFrame* pContent = aIter.First();
                 if( pContent )
                 {
@@ -477,7 +477,7 @@ SwContentNode *SwTextNode::SplitContentNode( const SwPosition &rPos )
 
         }
 
-        SwIterator<SwTextFrame,SwTextNode> aIter( *this );
+        SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(*this);
         for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
         {
             pFrame->RegisterToNode( *pNode );
commit e91c888829b05885d9dcc0f3cc5e53f072f56b21
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue May 29 11:37:29 2018 +0200

    sw_redlinehide: add an indirect iteration mode to SwIterator
    
    There are lots of existing loops over SwTextFrames of SwTextNodes,
    and these need to keep finding the frames if there's a
    WriterMultiListener in between.
    
    Add a template parameter to SwIterator that can be used to make the
    iteration transparent, i.e. return the client of the
    WriterMultiListener instead of the WriterMultiListener itself.
    
    Change-Id: I8b67a027b392b08408f5fbf26be22884384aa6cf

diff --git a/sw/inc/calbck.hxx b/sw/inc/calbck.hxx
index 9f809ea24dbd..d3c9a531abca 100644
--- a/sw/inc/calbck.hxx
+++ b/sw/inc/calbck.hxx
@@ -92,14 +92,16 @@ namespace sw
         public:
             bool IsLast() const { return !m_pLeft && !m_pRight; }
     };
+    enum class IteratorMode { Exact, UnwrapMulti };
 }
+
 // SwClient
 class SW_DLLPUBLIC SwClient : public ::sw::WriterListener
 {
     // avoids making the details of the linked list and the callback method public
     friend class SwModify;
     friend class sw::ClientIteratorBase;
-    template<typename E, typename S> friend class SwIterator;
+    template<typename E, typename S, sw::IteratorMode> friend class SwIterator;
 
     SwModify *m_pRegisteredIn;        ///< event source
 
@@ -148,7 +150,7 @@ public:
 class SW_DLLPUBLIC SwModify: public SwClient
 {
     friend class sw::ClientIteratorBase;
-    template<typename E, typename S> friend class SwIterator;
+    template<typename E, typename S, sw::IteratorMode> friend class SwIterator;
     sw::WriterListener* m_pWriterListeners;                // the start of the linked list of clients
     bool m_bModifyLocked : 1;         // don't broadcast changes now
     bool m_bLockClientList : 1;       // may be set when this instance notifies its clients
@@ -208,6 +210,7 @@ namespace sw
     class ListenerEntry;
     class SW_DLLPUBLIC WriterMultiListener final
     {
+        template<typename E, typename S, sw::IteratorMode> friend class ::SwIterator;
         SwClient& m_rToTell;
         std::vector<ListenerEntry> m_vDepends;
         public:
@@ -267,7 +270,9 @@ namespace sw
     };
 }
 
-template< typename TElementType, typename TSource > class SwIterator final : private sw::ClientIteratorBase
+template<typename TElementType, typename TSource,
+        sw::IteratorMode eMode = sw::IteratorMode::Exact> class SwIterator final
+    : private sw::ClientIteratorBase
 {
     //static_assert(!std::is_base_of<SwPageDesc,TSource>::value, "SwPageDesc as TSource is deprecated.");
     static_assert(std::is_base_of<SwClient,TElementType>::value, "TElementType needs to be derived from SwClient.");
@@ -290,24 +295,69 @@ public:
             return static_cast<TElementType*>(Sync());
         while(GetRightOfPos())
             m_pPosition = GetRightOfPos();
-        if(dynamic_cast<const TElementType *>(m_pPosition) != nullptr)
-            return static_cast<TElementType*>(Sync());
+        sw::WriterListener * pCurrent(m_pPosition);
+        if (eMode == sw::IteratorMode::UnwrapMulti)
+        {
+            if (auto const pWL = dynamic_cast<sw::WriterMultiListener const*>(pCurrent))
+            {
+                pCurrent = &pWL->m_rToTell;
+            }
+        }
+        if (dynamic_cast<const TElementType *>(pCurrent) != nullptr)
+        {
+            Sync();
+            return static_cast<TElementType*>(pCurrent);
+        }
         return Previous();
     }
     TElementType* Next()
     {
         if(!IsChanged())
             m_pPosition = GetRightOfPos();
-        while(m_pPosition && dynamic_cast<const TElementType *>(m_pPosition) == nullptr)
-            m_pPosition = GetRightOfPos();
-        return static_cast<TElementType*>(Sync());
+        sw::WriterListener *pCurrent(m_pPosition);
+        while (m_pPosition)
+        {
+            if (eMode == sw::IteratorMode::UnwrapMulti)
+            {
+                if (auto const pWL = dynamic_cast<sw::WriterMultiListener const*>(m_pPosition))
+                {
+                    pCurrent = &pWL->m_rToTell;
+                }
+            }
+            if (dynamic_cast<const TElementType *>(pCurrent) == nullptr)
+            {
+                m_pPosition = GetRightOfPos();
+                pCurrent = m_pPosition;
+            }
+            else
+                break;
+        }
+        Sync();
+        return static_cast<TElementType*>(pCurrent);
     }
     TElementType* Previous()
     {
         m_pPosition = GetLeftOfPos();
-        while(m_pPosition && dynamic_cast<const TElementType *>(m_pPosition) == nullptr)
-            m_pPosition = GetLeftOfPos();
-        return static_cast<TElementType*>(Sync());
+        sw::WriterListener *pCurrent(m_pPosition);
+        while (m_pPosition)
+        {
+            if (eMode == sw::IteratorMode::UnwrapMulti)
+            {
+                if (auto const pWL = dynamic_cast<sw::WriterMultiListener const*>(m_pPosition))
+                {
+                    pCurrent = &pWL->m_rToTell;
+                }
+            }
+            if (dynamic_cast<const TElementType *>(pCurrent) == nullptr)
+            {
+                m_pPosition = GetLeftOfPos();
+                pCurrent = m_pPosition;
+            }
+            else
+                break;
+        }
+        Sync();
+        return static_cast<TElementType*>(pCurrent);
     }
     using sw::ClientIteratorBase::IsChanged;
 };


More information about the Libreoffice-commits mailing list