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

Michael Stahl Michael.Stahl at cib.de
Thu May 17 15:02:03 UTC 2018


Rebased ref, commits from common ancestor:
commit dede28cde5ba1eeb2f44eddcebbc8b2edaefc4e9
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 4ef8b57ab786..24a73f76aa8a 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("SWREDLINEHIDE")) // 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 f7d06f35535a07b84e53c7e7c867175635c6c8ba
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Thu May 17 12:54:33 2018 +0200

    sw_redlinehide: set node merge flag in CheckParaRedlineMerge
    
    Change-Id: Ie11096ce9c3d62fbe54dc53954caf6665c374b12

diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 563f77056da7..aeecc00bcada 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -82,8 +82,17 @@ CheckParaRedlineMerge(SwTextFrame const*const pFrame, SwTextNode & rTextNode)
         }
         if (&pEnd->nNode.GetNode() != pNode)
         {
+            if (pNode == &rTextNode)
+            {
+                pNode->SetRedlineMergeFlag(SwNode::Merge::First);
+            } // else: was already set before
+            for (sal_uLong j = pNode->GetIndex() + 1; j < pEnd->nNode.GetIndex(); ++j)
+            {
+                pNode->GetNodes()[j]->SetRedlineMergeFlag(SwNode::Merge::Hidden);
+            }
             pNode = pEnd->nNode.GetNode().GetTextNode();
             assert(pNode);
+            pNode->SetRedlineMergeFlag(SwNode::Merge::NonFirst);
         }
         nLastEnd = pEnd->nContent.GetIndex();
     }
commit 0df8d7fb46dba4c26869e10c70f7e76a7cf04c5d
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()

diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index 337c26b033b0..c6091a54aaaa 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -4147,6 +4147,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 bd10bec780643484766bacd71e1ae62753c29214
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Thu May 17 12:13:36 2018 +0200

    sw_redlinehide: fix the fieldmark toxic waste in GetNextAttr()
    
    Out of bounds indexes returned here trigger assertions in new
    mapping functions.
    
    Why would you set it to p+1 anyway?
    
    Change-Id: I024e1ab6f40b5545c2e9f71f63620be57fba31d2

diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index cf82c2c4c54f..b86af8711998 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -621,7 +621,9 @@ static sal_Int32 GetNextAttrImpl(SwTextNode const*const pTextNode,
         size_t const nStartIndex, size_t const nEndIndex,
         sal_Int32 const nPosition)
 {
-    sal_Int32 nNext = COMPLETE_STRING;
+    // note: this used to be COMPLETE_STRING, but was set to Len() + 1 below,
+    // which is rather silly, so set it to Len() instead
+    sal_Int32 nNext = pTextNode->Len();
     if (SwpHints const*const pHints = pTextNode->GetpSwpHints())
     {
         // are there attribute starts left?
@@ -646,29 +648,27 @@ static sal_Int32 GetNextAttrImpl(SwTextNode const*const pTextNode,
             }
         }
     }
-    if (pTextNode != nullptr)
+    // TODO: maybe use hints like FieldHints for this instead of looking at the text...
+    const sal_Int32 l = std::min(nNext, pTextNode->Len());
+    sal_Int32 p = nPosition;
+    const sal_Unicode* pStr = pTextNode->GetText().getStr();
+    while (p < l)
     {
-        // TODO: maybe use hints like FieldHints for this instead of looking at the text...
-        const sal_Int32 l = std::min(nNext, pTextNode->Len());
-        sal_Int32 p = nPosition;
-        const sal_Unicode* aStr = pTextNode->GetText().getStr();
-        while (p<l)
+        sal_Unicode aChar = pStr[p];
+        if (aChar < CH_TXT_ATR_FORMELEMENT
+            || aChar > CH_TXT_ATR_FIELDEND)
         {
-            sal_Unicode aChar = aStr[p];
-            if (aChar < CH_TXT_ATR_FORMELEMENT
-                || aChar > CH_TXT_ATR_FIELDEND)
-            {
-                ++p;
-            }
-            else
-            {
-                break;
-            }
+            ++p;
         }
-        if ((p < l && nPosition < p) || nNext <= p)
-        nNext=p;
         else
-        nNext=p+1;
+        {
+            break;
+        }
+    }
+    assert(p <= nNext);
+    if (p < l && nPosition < p)
+    {
+        nNext=p;
     }
     return nNext;
 }
commit f5ea71bbc51d7ecf44921a6f7f422c84ad08bfef
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Wed May 16 12:54:27 2018 +0200

    sw_redlinehide: remove "protected" SwAttrIter::m_pHints member
    
    Just get it from the current node when needed; it's a trivially
    inlinable function call.
    
    Change-Id: Ic2ba291fb43da263300ddaedc9ae21cd86cb07ac

diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index 966d72c8d09b..cf82c2c4c54f 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -168,7 +168,6 @@ bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const bool bParaFo
     {
         assert(m_pMergedPara);
         m_pTextNode = m_pMergedPara->pFirstNode;
-        m_pHints = m_pTextNode->GetpSwpHints();
         InitFontAndAttrHandler(*m_pTextNode, m_pMergedPara->mergedText, nullptr);
     }
 
@@ -191,12 +190,13 @@ bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const bool bParaFo
             m_pRedline->Reset();
     }
 
-    if ( m_pHints && !bParaFont )
+    SwpHints const*const pHints(m_pTextNode->GetpSwpHints());
+    if (pHints && !bParaFont)
     {
         SwTextAttr *pTextAttr;
         // While we've not reached the end of the StartArray && the TextAttribute starts at position 0...
-        while ( ( m_nStartIndex < m_pHints->Count() ) &&
-                !((pTextAttr = m_pHints->Get(m_nStartIndex))->GetStart()) )
+        while ((m_nStartIndex < pHints->Count()) &&
+               !((pTextAttr = pHints->Get(m_nStartIndex))->GetStart()))
         {
             // open the TextAttributes
             Chg( pTextAttr );
@@ -225,6 +225,7 @@ bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const bool bParaFo
 // AMA: New AttrIter Nov 94
 void SwAttrIter::SeekFwd( const sal_Int32 nNewPos )
 {
+    SwpHints const*const pHints(m_pTextNode->GetpSwpHints());
     SwTextAttr *pTextAttr;
 
     if ( m_nStartIndex ) // If attributes have been opened at all ...
@@ -233,8 +234,8 @@ void SwAttrIter::SeekFwd( const sal_Int32 nNewPos )
 
         // As long as we've not yet reached the end of EndArray and the
         // TextAttribute ends before or at the new position ...
-        while ( ( m_nEndIndex < m_pHints->Count() ) &&
-                (*(pTextAttr=m_pHints->GetSortedByEnd(m_nEndIndex))->GetAnyEnd()<=nNewPos))
+        while ((m_nEndIndex < pHints->Count()) &&
+               (*(pTextAttr = pHints->GetSortedByEnd(m_nEndIndex))->GetAnyEnd() <= nNewPos))
         {
             // Close the TextAttributes, whose StartPos were before or at
             // the old nPos and are currently open
@@ -244,8 +245,8 @@ void SwAttrIter::SeekFwd( const sal_Int32 nNewPos )
     }
     else // skip the not opened ends
     {
-        while ( (m_nEndIndex < m_pHints->Count()) &&
-                (*m_pHints->GetSortedByEnd(m_nEndIndex)->GetAnyEnd() <= nNewPos) )
+        while ((m_nEndIndex < pHints->Count()) &&
+               (*pHints->GetSortedByEnd(m_nEndIndex)->GetAnyEnd() <= nNewPos))
         {
             m_nEndIndex++;
         }
@@ -253,8 +254,8 @@ void SwAttrIter::SeekFwd( const sal_Int32 nNewPos )
 
     // As long as we've not yet reached the end of EndArray and the
     // TextAttribute ends before or at the new position...
-    while ( ( m_nStartIndex < m_pHints->Count() ) &&
-            ((pTextAttr=m_pHints->Get(m_nStartIndex))->GetStart()<=nNewPos) )
+    while ((m_nStartIndex < pHints->Count()) &&
+            ((pTextAttr = pHints->Get(m_nStartIndex))->GetStart() <= nNewPos))
     {
 
         // open the TextAttributes, whose ends lie behind the new position
@@ -300,7 +301,6 @@ bool SwAttrIter::Seek(TextFrameIndex const nNewPos)
         InitFontAndAttrHandler(*newPos.first, m_pMergedPara->mergedText, nullptr);
         // reset to next
         m_pTextNode = newPos.first;
-        m_pHints = m_pTextNode->GetpSwpHints();
         m_nStartIndex = 0;
         m_nEndIndex = 0;
         m_nPosition = 0;
@@ -314,7 +314,6 @@ bool SwAttrIter::Seek(TextFrameIndex const nNewPos)
             if (m_pTextNode != m_pMergedPara->pFirstNode)
             {
                 m_pTextNode = m_pMergedPara->pFirstNode;
-                m_pHints = m_pTextNode->GetpSwpHints();
                 // sw_redlinehide: hope it's okay to use the current text node
                 // here; the AttrHandler shouldn't care about non-char items
                 InitFontAndAttrHandler(*m_pTextNode, m_pMergedPara->mergedText, nullptr);
diff --git a/sw/source/core/text/itratr.hxx b/sw/source/core/text/itratr.hxx
index ec3243d0e48d..016f97c333bc 100644
--- a/sw/source/core/text/itratr.hxx
+++ b/sw/source/core/text/itratr.hxx
@@ -43,7 +43,6 @@ protected:
     SwAttrHandler m_aAttrHandler;
     SwViewShell *m_pViewShell;
     SwFont *m_pFont;
-    SwpHints const* m_pHints;
     SwScriptInfo* m_pScriptInfo;
 
 private:
@@ -76,7 +75,6 @@ protected:
     explicit SwAttrIter(SwTextNode const * pTextNode)
         : m_pViewShell(nullptr)
         , m_pFont(nullptr)
-        , m_pHints(nullptr)
         , m_pScriptInfo(nullptr)
         , m_pLastOut(nullptr)
         , m_nChgCnt(0)
@@ -96,7 +94,14 @@ public:
     /// constructor, but SwAttrIter itself may be created without a
     /// SwTextFrame in certain special cases via this ctor here
     SwAttrIter( SwTextNode& rTextNode, SwScriptInfo& rScrInf )
-        : m_pViewShell(nullptr), m_pFont(nullptr), m_pHints(nullptr), m_pScriptInfo(nullptr), m_pLastOut(nullptr), m_nChgCnt(0), m_pRedline(nullptr),m_nPropFont(0), m_pTextNode(&rTextNode)
+        : m_pViewShell(nullptr)
+        , m_pFont(nullptr)
+        , m_pScriptInfo(nullptr)
+        , m_pLastOut(nullptr)
+        , m_nChgCnt(0)
+        , m_pRedline(nullptr)
+        , m_nPropFont(0)
+        , m_pTextNode(&rTextNode)
         , m_pMergedPara(nullptr)
         { CtorInitAttrIter( rTextNode, rScrInf ); }
 
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 62da71606ecb..563f77056da7 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -180,9 +180,6 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
 
     m_pScriptInfo = &rScriptInfo;
 
-    // attribute array
-    m_pHints = rTextNode.GetpSwpHints();
-
     // set font to vertical if frame layout is vertical
     bool bVertLayout = false;
     bool bRTL = false;
commit aa868726b705d12a75641e1c038a9333312a0cdb
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Wed May 16 12:44:19 2018 +0200

    sw_redlinehide: rename it to SwAttrIter::MaybeHasHints()
    
    ... because it's only used as an optimization currently, so we just use
    the slow-path if there is a merged paragraph.
    
    Change-Id: I8b577174e65edd0e5210971511e054fd719de96a

diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index e0148f3487e3..966d72c8d09b 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -95,6 +95,11 @@ SwAttrIter::~SwAttrIter()
     delete m_pFont;
 }
 
+bool SwAttrIter::MaybeHasHints() const
+{
+    return nullptr != m_pTextNode->GetpSwpHints() || nullptr != m_pMergedPara;
+}
+
 /**
  * Returns the attribute for a position
  *
diff --git a/sw/source/core/text/itratr.hxx b/sw/source/core/text/itratr.hxx
index 495d4029ede0..ec3243d0e48d 100644
--- a/sw/source/core/text/itratr.hxx
+++ b/sw/source/core/text/itratr.hxx
@@ -118,8 +118,8 @@ public:
     bool SeekAndChgAttrIter(TextFrameIndex nPos, OutputDevice* pOut);
     bool SeekStartAndChgAttrIter( OutputDevice* pOut, const bool bParaFont );
 
-    // Do we have an attribute change at all?
-    bool HasHints() const { return nullptr != m_pHints; }
+    // Do we possibly have nasty things like footnotes?
+    bool MaybeHasHints() const;
 
     // Returns the attribute for a position
     SwTextAttr *GetAttr(TextFrameIndex nPos) const;
diff --git a/sw/source/core/text/itrtxt.cxx b/sw/source/core/text/itrtxt.cxx
index 12a5b59fbc84..cfd4d092ba6e 100644
--- a/sw/source/core/text/itrtxt.cxx
+++ b/sw/source/core/text/itrtxt.cxx
@@ -322,7 +322,7 @@ void SwTextIter::TruncLines( bool bNoteFollow )
     if( pDel )
     {
         m_pCurr->SetNext( nullptr );
-        if (HasHints() && bNoteFollow)
+        if (MaybeHasHints() && bNoteFollow)
         {
             GetInfo().GetParaPortion()->SetFollowField( pDel->IsRest() ||
                                                         lcl_NeedsFieldRest( m_pCurr ) );
@@ -367,7 +367,7 @@ void SwTextIter::TruncLines( bool bNoteFollow )
     {
         m_pCurr->SetRealHeight( 1 );
     }
-    if (HasHints())
+    if (MaybeHasHints())
         m_pFrame->RemoveFootnote( nEnd );
 }
 
commit 205430e43df147968351d71fd8304d07c3d4ee7c
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Wed May 16 12:26:35 2018 +0200

    sw_redlinehide: convert iteration in SwTextFormatter::TryNewNoLengthPortion()
    
    This is a bit slower, but the feature is virtually unused anyway...
    
    Change-Id: I338a03a3edf27911cd2da55c7e3a438d9c020d40

diff --git a/sw/source/core/text/txtfld.cxx b/sw/source/core/text/txtfld.cxx
index 88d29a4a3542..f1d5ef9f0dca 100644
--- a/sw/source/core/text/txtfld.cxx
+++ b/sw/source/core/text/txtfld.cxx
@@ -316,27 +316,39 @@ static SwFieldPortion * lcl_NewMetaPortion(SwTextAttr & rHint, const bool bPrefi
  */
 SwExpandPortion * SwTextFormatter::TryNewNoLengthPortion(SwTextFormatInfo const & rInfo)
 {
-    if (m_pHints)
+    const TextFrameIndex nIdx(rInfo.GetIdx());
+
+    // sw_redlinehide: because there is a dummy character at the start of these
+    // hints, it's impossible to have ends of hints from different nodes at the
+    // same view position, so it's sufficient to check the hints of the current
+    // node.  However, m_nHintEndIndex exists for the whole text frame, so
+    // it's necessary to iterate all hints for that purpose...
+    SwTextNode const* pNode(nullptr);
+    sw::MergedAttrIterByEnd iter(*rInfo.GetTextFrame());
+    size_t i(0);
+    for (SwTextAttr const* pHint = iter.NextAttr(&pNode); pHint;
+         pHint = iter.NextAttr(&pNode))
     {
-        const sal_Int32 nIdx(rInfo.GetIdx());
-        while (m_nHintEndIndex < m_pHints->Count())
+        if (i++ < m_nHintEndIndex)
         {
-            SwTextAttr & rHint( *m_pHints->GetSortedByEnd(m_nHintEndIndex) );
-            sal_Int32 const nEnd( *rHint.GetAnyEnd() );
-            if (nEnd > nIdx)
-            {
-                break;
-            }
-            ++m_nHintEndIndex;
-            if (nEnd == nIdx)
+            continue; // skip ones that were handled earlier
+        }
+        SwTextAttr & rHint(const_cast<SwTextAttr&>(*pHint));
+        TextFrameIndex const nEnd(
+            rInfo.GetTextFrame()->MapModelToView(pNode, *rHint.GetAnyEnd()));
+        if (nEnd > nIdx)
+        {
+            break;
+        }
+        ++m_nHintEndIndex;
+        if (nEnd == nIdx)
+        {
+            if (RES_TXTATR_METAFIELD == rHint.Which())
             {
-                if (RES_TXTATR_METAFIELD == rHint.Which())
-                {
-                    SwFieldPortion *const pPortion(
-                            lcl_NewMetaPortion(rHint, false));
-                    pPortion->SetNoLength(); // no CH_TXTATR at hint end!
-                    return pPortion;
-                }
+                SwFieldPortion *const pPortion(
+                        lcl_NewMetaPortion(rHint, false));
+                pPortion->SetNoLength(); // no CH_TXTATR at hint end!
+                return pPortion;
             }
         }
     }
commit c98dd8e1393fc9f8925eea54b6b680379ffc4a13
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Wed May 16 12:23:56 2018 +0200

    sw_redlinehide: need a MergedIterByEnd too...
    
    Change-Id: If806c41886510b7f7296d234fbec1e9164f88396

diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index ea25a86a6658..14e648f39abb 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -906,6 +906,14 @@ public:
     SwTextAttr const* NextAttr(SwTextNode const** ppNode = nullptr);
 };
 
+class MergedAttrIterByEnd
+    : public MergedAttrIterBase
+{
+public:
+    MergedAttrIterByEnd(SwTextFrame const& rFrame) : MergedAttrIterBase(rFrame) {}
+    SwTextAttr const* NextAttr(SwTextNode const** ppNode = nullptr);
+};
+
 class MergedAttrIterReverse
     : public MergedAttrIterBase
 {
diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx
index 9f39a4201366..1308009bf15c 100644
--- a/sw/source/core/text/txtfrm.cxx
+++ b/sw/source/core/text/txtfrm.cxx
@@ -146,6 +146,64 @@ namespace sw {
         }
     }
 
+    SwTextAttr const* MergedAttrIterByEnd::NextAttr(SwTextNode const** ppNode)
+    {
+        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->GetSortedByEnd(m_CurrentHint));
+                        if (rExtent.nEnd <= *pHint->GetAnyEnd())
+                        {
+                            break;
+                        }
+                        ++m_CurrentHint;
+                        if (rExtent.nStart < *pHint->GetAnyEnd())
+                        {
+                            if (ppNode)
+                            {
+                                *ppNode = 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
+                }
+            }
+            return nullptr;
+        }
+        else
+        {
+            SwpHints const*const pHints(m_pNode->GetpSwpHints());
+            if (pHints)
+            {
+                while (m_CurrentHint < pHints->Count())
+                {
+                    SwTextAttr const*const pHint(
+                            pHints->GetSortedByEnd(m_CurrentHint));
+                    ++m_CurrentHint;
+                    if (ppNode)
+                    {
+                        *ppNode = m_pNode;
+                    }
+                    return pHint;
+                }
+            }
+            return nullptr;
+        }
+    }
+
     MergedAttrIterReverse::MergedAttrIterReverse(SwTextFrame const& rFrame)
         : MergedAttrIterBase(rFrame)
     {
commit 939554ac51534362c05505dcaf846bfa9e4a65d7
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Wed May 16 11:40:44 2018 +0200

    sw_redlinehide: convert loop in SwTextPainter::CheckSpecialUnderline()
    
    If we first select by paragraph attributes, and then override that with
    hints, it ought to give the right result.
    
    Change-Id: I6929bb746db1229593ca1c2331d80650248e24d3

diff --git a/sw/source/core/text/itrpaint.cxx b/sw/source/core/text/itrpaint.cxx
index 2037eed2ec68..2a73d47cf0af 100644
--- a/sw/source/core/text/itrpaint.cxx
+++ b/sw/source/core/text/itrpaint.cxx
@@ -523,23 +523,45 @@ void SwTextPainter::CheckSpecialUnderline( const SwLinePortion* pPor,
     if( pParaFnt && pParaFnt->GetUnderline() == GetFnt()->GetUnderline() )
         aUnderMulti.SelectAll();
 
-    if( HasHints() )
+    if (sw::MergedPara const*const pMerged = GetTextFrame()->GetMergedPara())
     {
-        for ( size_t nTmp = 0; nTmp < m_pHints->Count(); ++nTmp )
+        // first, add the paragraph properties to MultiSelection - if there are
+        // Hints too, they will override the positions if they're added later
+        sal_Int32 nTmp(0);
+        for (auto const& e : pMerged->extents)
         {
-            SwTextAttr* const pTextAttr = m_pHints->Get( nTmp );
+            const SfxPoolItem* pItem;
+            if (SfxItemState::SET == e.pNode->GetSwAttrSet().GetItemState(
+                        RES_CHRATR_UNDERLINE, true, &pItem))
+            {
+                const bool bUnderSelect(m_pFont->GetUnderline() ==
+                    static_cast<SvxUnderlineItem const*>(pItem)->GetLineStyle());
+                aUnderMulti.Select(Range(nTmp, nTmp + e.nEnd - e.nStart - 1),
+                        bUnderSelect);
+            }
+            nTmp += e.nEnd - e.nStart;
+        }
+    }
 
-            const SvxUnderlineItem* pItem = CharFormat::GetItem( *pTextAttr, RES_CHRATR_UNDERLINE );
+    SwTextNode const* pNode(nullptr);
+    sw::MergedAttrIter iter(*GetTextFrame());
+    for (SwTextAttr const* pTextAttr = iter.NextAttr(&pNode); pTextAttr;
+         pTextAttr = iter.NextAttr(&pNode))
+    {
+        SvxUnderlineItem const*const pItem =
+            CharFormat::GetItem(*pTextAttr, RES_CHRATR_UNDERLINE);
 
-            if ( pItem )
+        if (pItem)
+        {
+            TextFrameIndex const nStart(
+                GetTextFrame()->MapModelToView(pNode, pTextAttr->GetStart()));
+            TextFrameIndex const nEnd(
+                GetTextFrame()->MapModelToView(pNode, *pTextAttr->End()));
+            if (nEnd > nStart)
             {
-                const sal_Int32 nSt = pTextAttr->GetStart();
-                const sal_Int32 nEnd = *pTextAttr->GetEnd();
-                if( nEnd > nSt )
-                {
-                    const bool bUnderSelect = m_pFont->GetUnderline() == pItem->GetLineStyle();
-                    aUnderMulti.Select( Range( nSt, nEnd - 1 ), bUnderSelect );
-                }
+                const bool bUnderSelect = m_pFont->GetUnderline() == pItem->GetLineStyle();
+                aUnderMulti.Select(Range(sal_Int32(nStart), sal_Int32(nEnd) - 1),
+                        bUnderSelect);
             }
         }
     }
commit e872f0b6e09cd451f7fa6a795ffae96d0b9865f4
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue May 15 18:04:06 2018 +0200

    sw_redlinehide: adapt more functions of SwAttrIter
    
    Change-Id: I17c14f9e66c82cafa2fb5b3e8e45b3bf94fc4a88

diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index 3c59f50f7cea..e0148f3487e3 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -112,12 +112,20 @@ SwAttrIter::~SwAttrIter()
  */
 SwTextAttr *SwAttrIter::GetAttr(TextFrameIndex const nPosition) const
 {
-    return (m_pTextNode) ? m_pTextNode->GetTextAttrForCharAt(nPosition) : nullptr;
+    std::pair<SwTextNode const*, sal_Int32> const pos( m_pMergedPara
+        ? sw::MapViewToModel(*m_pMergedPara, nPosition)
+        : std::make_pair(m_pTextNode, sal_Int32(nPosition)));
+    return pos.first->GetTextAttrForCharAt(pos.second);
 }
 
 bool SwAttrIter::SeekAndChgAttrIter(TextFrameIndex const nNewPos, OutputDevice* pOut)
 {
-    bool bChg = m_nStartIndex && nNewPos == m_nPosition ? m_pFont->IsFntChg() : Seek( nNewPos );
+    std::pair<SwTextNode const*, sal_Int32> const pos( m_pMergedPara
+        ? sw::MapViewToModel(*m_pMergedPara, nNewPos)
+        : std::make_pair(m_pTextNode, sal_Int32(nNewPos)));
+    bool bChg = m_nStartIndex && pos.first == m_pTextNode && pos.second == m_nPosition
+        ? m_pFont->IsFntChg()
+        : Seek( nNewPos );
     if ( m_pLastOut.get() != pOut )
     {
         m_pLastOut = pOut;
@@ -151,6 +159,14 @@ bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const bool bParaFo
     if ( m_pRedline && m_pRedline->ExtOn() )
         m_pRedline->LeaveExtend(*m_pFont, pFirstTextNode->GetIndex(), 0);
 
+    if (m_pTextNode != pFirstTextNode)
+    {
+        assert(m_pMergedPara);
+        m_pTextNode = m_pMergedPara->pFirstNode;
+        m_pHints = m_pTextNode->GetpSwpHints();
+        InitFontAndAttrHandler(*m_pTextNode, m_pMergedPara->mergedText, nullptr);
+    }
+
     // reset font to its original state
     m_aAttrHandler.Reset();
     m_aAttrHandler.ResetFont( *m_pFont );
commit e53e245aa858a8345b518296be10f0365d2f0365
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue May 15 17:30:22 2018 +0200

    sw_redlinehide: SwAttrIter::Seek()
    
    Change-Id: Ieb884f678d6521b609714def3f42c8494dc47769

diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index 4e4c5e4dc973..3c59f50f7cea 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -65,6 +65,9 @@
 using namespace ::com::sun::star::i18n;
 using namespace ::com::sun::star;
 
+static sal_Int32 GetNextAttrImpl(SwTextNode const* pTextNode,
+        size_t nStartIndex, size_t nEndIndex, sal_Int32 nPosition);
+
 void SwAttrIter::Chg( SwTextAttr const *pHt )
 {
     assert(pHt && m_pFont && "No attribute of font available for change");
@@ -243,17 +246,60 @@ void SwAttrIter::SeekFwd( const sal_Int32 nNewPos )
 bool SwAttrIter::Seek(TextFrameIndex const nNewPos)
 {
     // note: nNewPos isn't necessarily a index returned from GetNextAttr
-    sw::MergedPara * pMerged(nullptr); // FIXME
-    std::pair<SwTextNode const*, sal_Int32> const newPos( pMerged
-        ? sw::MapViewToModel(*pMerged, nNewPos)
-        : std::make_pair(m_pTextNode, nNewPos));
+    std::pair<SwTextNode const*, sal_Int32> const newPos( m_pMergedPara
+        ? sw::MapViewToModel(*m_pMergedPara, nNewPos)
+        : std::make_pair(m_pTextNode, sal_Int32(nNewPos)));
 
     if ( m_pRedline && m_pRedline->ExtOn() )
         m_pRedline->LeaveExtend(*m_pFont, newPos.first->GetIndex(), newPos.second);
+    if (m_pTextNode->GetIndex() < newPos.first->GetIndex())
+    {
+        // Skipping to a different node - first seek until the end of this node
+        // to get rid of all hint items
+        sal_Int32 nPos(m_nPosition);
+        do
+        {
+            nPos = GetNextAttrImpl(m_pTextNode, m_nStartIndex, m_nEndIndex, nPos);
+            if (nPos <= m_pTextNode->Len())
+            {
+                SeekFwd(nPos);
+            }
+            else
+            {
+                SeekFwd(m_pTextNode->Len());
+            }
+        }
+        while (nPos < m_pTextNode->Len());
+        assert(m_nChgCnt == 0); // should have reset it all? there cannot be ExtOn() inside of a Delete redline, surely?
+        // Unapply current para items:
+        // the SwAttrHandler doesn't appear to be capable of *unapplying*
+        // items at all; it can only apply a previously effective item.
+        // So do this by recreating the font from scratch.
+        // Apply new para items:
+        InitFontAndAttrHandler(*newPos.first, m_pMergedPara->mergedText, nullptr);
+        // reset to next
+        m_pTextNode = newPos.first;
+        m_pHints = m_pTextNode->GetpSwpHints();
+        m_nStartIndex = 0;
+        m_nEndIndex = 0;
+        m_nPosition = 0;
+        assert(m_pRedline);
+    }
 
-    if( m_pHints )
+    if (nNewPos == 0 || newPos.second < m_nPosition)
     {
-        if( !nNewPos || nNewPos < m_nPosition )
+        if (m_pMergedPara)
+        {
+            if (m_pTextNode != m_pMergedPara->pFirstNode)
+            {
+                m_pTextNode = m_pMergedPara->pFirstNode;
+                m_pHints = m_pTextNode->GetpSwpHints();
+                // sw_redlinehide: hope it's okay to use the current text node
+                // here; the AttrHandler shouldn't care about non-char items
+                InitFontAndAttrHandler(*m_pTextNode, m_pMergedPara->mergedText, nullptr);
+            }
+        }
+        if (m_pMergedPara || m_pTextNode->GetpSwpHints())
         {
             if( m_pRedline )
                 m_pRedline->Clear( nullptr );
@@ -278,14 +324,41 @@ bool SwAttrIter::Seek(TextFrameIndex const nNewPos)
                 ++m_nChgCnt;
             }
         }
-        SeekFwd( nNewPos );
+    }
+
+    if (SwpHints const*const pHints = m_pTextNode->GetpSwpHints())
+    {
+        if (m_pMergedPara)
+        {
+            // iterate hint by hint: SeekFwd does not mix ends and starts,
+            // it always applies all the starts last, so it must be called once
+            // per position where hints start/end!
+            sal_Int32 nPos(m_nPosition);
+            do
+            {
+                nPos = GetNextAttrImpl(m_pTextNode, m_nStartIndex, m_nEndIndex, nPos);
+                if (nPos <= newPos.second)
+                {
+                    SeekFwd(nPos);
+                }
+                else
+                {
+                    SeekFwd(newPos.second);
+                }
+            }
+            while (nPos < newPos.second);
+        }
+        else
+        {
+            SeekFwd(newPos.second);
+        }
     }
 
     m_pFont->SetActual( SwScriptInfo::WhichFont( nNewPos, nullptr, m_pScriptInfo ) );
 
     if( m_pRedline )
         m_nChgCnt = m_nChgCnt + m_pRedline->Seek(*m_pFont, newPos.first->GetIndex(), newPos.second, m_nPosition);
-    m_nPosition = nNewPos;
+    m_nPosition = newPos.second;
 
     if( m_nPropFont )
         m_pFont->SetProportion( m_nPropFont );
commit 0d280c1ace76232a04af099646d66afeab806a85
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue May 15 16:56:19 2018 +0200

    sw_redlinehide: split font/SwAttrHandler init out of CtorInitAttrIter
    
    ... so we can call it again later, when the text node changes.
    
    Change-Id: I4cd2ff064b829a70652bf1861bacf365be7277a2

diff --git a/sw/source/core/text/atrhndl.hxx b/sw/source/core/text/atrhndl.hxx
index 5c59de630c63..e6a08f422d1b 100644
--- a/sw/source/core/text/atrhndl.hxx
+++ b/sw/source/core/text/atrhndl.hxx
@@ -115,6 +115,8 @@ public:
                const SwViewShell* pShell, SwFont& rFnt,
                bool bVertLayout );
 
+    bool IsVertLayout() const { return m_bVertLayout; }
+
     // remove everything from internal stacks, keep default data
     void Reset( );
 
diff --git a/sw/source/core/text/itratr.hxx b/sw/source/core/text/itratr.hxx
index dd4f66c5c964..495d4029ede0 100644
--- a/sw/source/core/text/itratr.hxx
+++ b/sw/source/core/text/itratr.hxx
@@ -66,6 +66,8 @@ private:
 
     void SeekFwd( const sal_Int32 nPos );
     void SetFnt( SwFont* pNew ) { m_pFont = pNew; }
+    void InitFontAndAttrHandler(SwTextNode const& rTextNode,
+        OUString const& rText, bool const* pbVertLayout);
 
 protected:
     void Chg( SwTextAttr const *pHt );
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 048f78d79819..62da71606ecb 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -112,35 +112,20 @@ CheckParaRedlineMerge(SwTextFrame const*const pFrame, SwTextNode & rTextNode)
 
 } // namespace sw
 
-void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
-        SwScriptInfo & rScriptInfo, SwTextFrame *const pFrame)
+void SwAttrIter::InitFontAndAttrHandler(SwTextNode const& rTextNode,
+        OUString const& rText,
+        bool const*const pbVertLayout)
 {
-    // during HTML-Import it can happen, that no layout exists
-    SwRootFrame* pRootFrame = rTextNode.getIDocumentLayoutAccess().GetCurrentLayout();
-    m_pViewShell = pRootFrame ? pRootFrame->GetCurrShell() : nullptr;
-
-    m_pScriptInfo = &rScriptInfo;
-
-    // attribute array
-    m_pHints = rTextNode.GetpSwpHints();
-
     // Build a font matching the default paragraph style:
     SwFontAccess aFontAccess( &rTextNode.GetAnyFormatColl(), m_pViewShell );
     delete m_pFont;
     m_pFont = new SwFont( aFontAccess.Get()->GetFont() );
 
     // set font to vertical if frame layout is vertical
-    bool bVertLayout = false;
-    bool bRTL = false;
-    if ( pFrame )
+    // if it's a re-init, the vert flag never changes
+    if (pbVertLayout ? *pbVertLayout : m_aAttrHandler.IsVertLayout())
     {
-        if ( pFrame->IsVertical() )
-        {
-            bVertLayout = true;
-            m_pFont->SetVertical( m_pFont->GetOrientation(), true );
-        }
-        bRTL = pFrame->IsRightToLeft();
-        m_pMergedPara = pFrame->GetMergedPara();
+        m_pFont->SetVertical( m_pFont->GetOrientation(), true );
     }
 
     // Initialize the default attribute of the attribute handler
@@ -149,16 +134,11 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
     // consider them during construction of the default array, and apply
     // them to the font
     m_aAttrHandler.Init(aFontAccess.Get()->GetDefault(), rTextNode.GetpSwAttrSet(),
-                       *rTextNode.getIDocumentSettingAccess(), m_pViewShell, *m_pFont, bVertLayout );
+           *rTextNode.getIDocumentSettingAccess(), m_pViewShell, *m_pFont,
+           pbVertLayout ? *pbVertLayout : m_aAttrHandler.IsVertLayout() );
 
     m_aMagicNo[SwFontScript::Latin] = m_aMagicNo[SwFontScript::CJK] = m_aMagicNo[SwFontScript::CTL] = nullptr;
 
-    // TODO must init m_pRedline before this
-    // determine script changes if not already done for current paragraph
-    assert(m_pScriptInfo);
-    if ( m_pScriptInfo->GetInvalidityA() != COMPLETE_STRING )
-         m_pScriptInfo->InitScriptInfo( rTextNode, bRTL );
-
     assert(g_pBreakIt && g_pBreakIt->GetBreakIter().is());
 
     m_pFont->SetActual( SwScriptInfo::WhichFont( 0, nullptr, m_pScriptInfo ) );
@@ -187,7 +167,43 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
             m_pFont->ChkMagic( m_pViewShell, nTmp );
             m_pFont->GetMagic( m_aMagicNo[ nTmp ], m_aFontIdx[ nTmp ], nTmp );
         }
-    } while (nChg < rTextNode.GetText().getLength());
+    }
+    while (nChg < rText.getLength());
+}
+
+void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
+        SwScriptInfo & rScriptInfo, SwTextFrame *const pFrame)
+{
+    // during HTML-Import it can happen, that no layout exists
+    SwRootFrame* pRootFrame = rTextNode.getIDocumentLayoutAccess().GetCurrentLayout();
+    m_pViewShell = pRootFrame ? pRootFrame->GetCurrShell() : nullptr;
+
+    m_pScriptInfo = &rScriptInfo;
+
+    // attribute array
+    m_pHints = rTextNode.GetpSwpHints();
+
+    // set font to vertical if frame layout is vertical
+    bool bVertLayout = false;
+    bool bRTL = false;
+    if ( pFrame )
+    {
+        if ( pFrame->IsVertical() )
+        {
+            bVertLayout = true;
+        }
+        bRTL = pFrame->IsRightToLeft();
+        m_pMergedPara = pFrame->GetMergedPara();
+    }
+
+    // determine script changes if not already done for current paragraph
+    assert(m_pScriptInfo);
+    if ( m_pScriptInfo->GetInvalidityA() != COMPLETE_STRING )
+         m_pScriptInfo->InitScriptInfo( rTextNode, bRTL );
+
+    InitFontAndAttrHandler(rTextNode,
+            m_pMergedPara ? m_pMergedPara->mergedText : rTextNode.GetText(),
+            & bVertLayout);
 
     m_nStartIndex = m_nEndIndex = m_nPosition = m_nChgCnt = 0;
     m_nPropFont = 0;
commit bd9a2e1fcdc63844cca1885f2f35cc421ab4f2e5
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue May 15 11:37:54 2018 +0200

    sw_redlinehide: SwRedlineItr::Seek_() needs to do something
    
    ... in Hide mode, such as locate the next Delete that GetNextRedln looks
    for.
    
    Change-Id: Ie0ab35c99f34bd3a071798fd54efd12f1f82a118

diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index c82987e3bbe5..048f78d79819 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -299,7 +299,6 @@ SwRedlineItr::~SwRedlineItr() COVERITY_NOEXCEPT_FALSE
 // The return value of SwRedlineItr::Seek tells you if the current font
 // has been manipulated by leaving (-1) or accessing (+1) of a section
 short SwRedlineItr::Seek_(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const nNew, sal_Int32 const nOld)
-    //TODO use nNode to compare
 {
     short nRet = 0;
     if( ExtOn() )
@@ -384,6 +383,36 @@ short SwRedlineItr::Seek_(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const n
             m_nEnd = COMPLETE_STRING;
         }
     }
+    else if (m_eMode == Mode::Hide)
+    {   // ... just iterate to update m_nAct for GetNextRedln();
+        // there is no need to care about formatting in this mode
+        if (nOld == COMPLETE_STRING) // backward?
+        {
+            m_nAct = m_nFirst;
+        }
+        for ( ; m_nAct < m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().size(); ++m_nAct)
+        {   // only Start matters in this mode
+            // Seeks until it finds a RL that starts at or behind the seek pos.
+            // - then update m_nStart/m_nEnd to the intersection of it with the
+            // current node (if any).
+            // The only way to skip to a different node is if there is a Delete
+            // RL, so if there is no intersection we'll never skip again.
+            // Note: here, assume that delete can't nest inside delete!
+            SwRangeRedline const*const pRedline(
+                m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[m_nAct]);
+            SwPosition const*const pStart(pRedline->Start());
+            if (pRedline->GetType() == nsRedlineType_t::REDLINE_DELETE
+                && (nNode < pStart->nNode.GetIndex()
+                    || (nNode == pStart->nNode.GetIndex()
+                        && nNew <= pStart->nContent.GetIndex())))
+            {
+                pRedline->CalcStartEnd(nNode, m_nStart, m_nEnd);
+                break;
+            }
+            m_nStart = COMPLETE_STRING;
+            m_nEnd = COMPLETE_STRING;
+        }
+    }
     return nRet + EnterExtend(rFnt, nNode, nNew);
 }
 
commit 0149d715b734bf72cd01357e48ff847ee5528855
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue May 15 11:37:23 2018 +0200

    sw_redlinehide: more work on SwRedlineItr::GetNextRedln()
    
    Change-Id: I9f79a3f6ace1914f516e89c7ddb16835a63ddc00

diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index c44dc9eaa4d5..4e4c5e4dc973 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -593,21 +593,22 @@ TextFrameIndex SwAttrIter::GetNextAttr() const
         sal_Int32 nNext = GetNextAttrImpl(pTextNode, nStartIndex, nEndIndex, nPosition);
         if( m_pRedline )
         {
-            std::pair<sal_Int32, SwRangeRedline const*> const redline(
+            std::pair<sal_Int32, std::pair<SwRangeRedline const*, size_t>> const redline(
                     m_pRedline->GetNextRedln(nNext, pTextNode, nActRedline));
-            if (redline.second)
+            if (redline.second.first)
             {
                 assert(m_pMergedPara);
-                if (CanSkipOverRedline(*redline.second, nStartIndex, nEndIndex))
+                if (CanSkipOverRedline(*redline.second.first, nStartIndex, nEndIndex))
                 {
-                    if (&redline.second->End()->nNode.GetNode() != pTextNode)
+                    nActRedline += redline.second.second;
+                    if (&redline.second.first->End()->nNode.GetNode() != pTextNode)
                     {
-                        pTextNode = redline.second->End()->nNode.GetNode().GetTextNode();
-                        nPosition = redline.second->End()->nContent.GetIndex();
+                        pTextNode = redline.second.first->End()->nNode.GetNode().GetTextNode();
+                        nPosition = redline.second.first->End()->nContent.GetIndex();
                     }
                     else
                     {
-                        nPosition = redline.second->End()->nContent.GetIndex();
+                        nPosition = redline.second.first->End()->nContent.GetIndex();
                     }
                 }
                 else
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 11e3e5621768..c82987e3bbe5 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -442,57 +442,85 @@ void SwRedlineItr::Clear_( SwFont* pFnt )
     m_Hints.clear();
 }
 
-// TODO this must be ITERABLE pass in members as parameter
-std::pair<sal_Int32, SwRangeRedline const*>
-SwRedlineItr::GetNextRedln(sal_Int32 nNext, SwTextNode const*const pNode, SwRedlineTable::size_type & rAct)
+/// Ignore mode: does nothing.
+/// Show mode: returns end of redline if currently in one, or start of next
+/// Hide mode: returns start of next redline in current node, plus (if it's a
+///            Delete) its end position and number of consecutive RLs
+std::pair<sal_Int32, std::pair<SwRangeRedline const*, size_t>>
+SwRedlineItr::GetNextRedln(sal_Int32 nNext, SwTextNode const*const pNode,
+        SwRedlineTable::size_type & rAct)
 {
     sal_Int32 nStart(m_nStart);
     sal_Int32 nEnd(m_nEnd);
     nNext = NextExtend(pNode->GetIndex(), nNext);
     if (m_eMode == Mode::Ignore || SwRedlineTable::npos == m_nFirst)
-        return std::make_pair(nNext, nullptr);
+        return std::make_pair(nNext, std::make_pair(nullptr, 0));
     if (SwRedlineTable::npos == rAct)
     {
-        rAct = m_nFirst; // TODO???
-        m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[rAct]->CalcStartEnd(pNode->GetIndex(), nStart, nEnd);
+        rAct = m_nFirst;
     }
     if (rAct != m_nAct)
     {
-        m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[rAct]->CalcStartEnd(pNode->GetIndex(), nStart, nEnd);
+        while (rAct < m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().size())
+        {
+            SwRangeRedline const*const pRedline(
+                    m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[rAct]);
+            pRedline->CalcStartEnd(pNode->GetIndex(), nStart, nEnd);
+            if (m_eMode != Mode::Hide
+                || pRedline->GetType() == nsRedlineType_t::REDLINE_DELETE)
+            {
+                break;
+            }
+            ++rAct; // Hide mode: search a Delete RL
+        }
     }
-    if (m_bOn || !nStart)
+    if (rAct == m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().size())
     {
+        return std::make_pair(nNext, std::make_pair(nullptr, 0)); // no Delete here
+    }
+    if (m_bOn || (m_eMode == Mode::Show && nStart == 0))
+    {   // in Ignore mode, the end of redlines isn't relevant, except as returned in the second in the pair!
         if (nEnd < nNext)
             nNext = nEnd;
     }
     else if (nStart <= nNext)
     {
-        nNext = nStart;
-        if (m_eMode == Mode::Hide)
+        if (m_eMode == Mode::Show)
+        {
+            nNext = nStart;
+        }
+        else
         {
-            SwRangeRedline const* pRedline = m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[rAct];
+            assert(m_eMode == Mode::Hide);
+            SwRangeRedline const* pRedline(
+                    m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[rAct]);
+            assert(pRedline->GetType() == nsRedlineType_t::REDLINE_DELETE); //?
             if (pRedline->GetType() == nsRedlineType_t::REDLINE_DELETE)
             {
-                ++rAct;
-                while (rAct < m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().size())
+                nNext = nStart;
+                size_t nSkipped(1); // (consecutive) candidates to be skipped
+                while (rAct + nSkipped <
+                       m_rDoc.getIDocumentRedlineAccess().GetRedlineTable().size())
                 {
-                    SwRangeRedline *const pNext = m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[rAct];
+                    SwRangeRedline const*const pNext =
+                        m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[rAct + nSkipped];
                     if (pRedline->End() < pNext->Start())
                     {
                         break; // done for now
                     }
-                    else if (pNext->Start() == pRedline->End() && pNext->GetType() == nsRedlineType_t::REDLINE_DELETE)
+                    else if (pNext->Start() == pRedline->End() &&
+                            pNext->GetType() == nsRedlineType_t::REDLINE_DELETE)
                     {
                         // consecutive delete - continue
                         pRedline = pNext;
                     }
-                    ++rAct;
+                    ++nSkipped;
                 }
-                return std::make_pair(nNext, pRedline);
+                return std::make_pair(nNext, std::make_pair(pRedline, nSkipped));
             }
         }
     }
-    return std::make_pair(nNext, nullptr);
+    return std::make_pair(nNext, std::make_pair(nullptr, 0));
 }
 
 bool SwRedlineItr::ChkSpecialUnderline_() const
diff --git a/sw/source/core/text/redlnitr.hxx b/sw/source/core/text/redlnitr.hxx
index 310fd067ca23..f5737ce9d1c8 100644
--- a/sw/source/core/text/redlnitr.hxx
+++ b/sw/source/core/text/redlnitr.hxx
@@ -119,7 +119,8 @@ public:
         if (m_nAct != m_nFirst) m_nAct = SwRedlineTable::npos;
         if (m_pExt) m_pExt->Reset();
     }
-    std::pair<sal_Int32, SwRangeRedline const*> GetNextRedln(sal_Int32 nNext, SwTextNode const* pNode, SwRedlineTable::size_type & rAct);
+    std::pair<sal_Int32, std::pair<SwRangeRedline const*, size_t>> GetNextRedln(
+        sal_Int32 nNext, SwTextNode const* pNode, SwRedlineTable::size_type & rAct);
 #if 0
     {
         if (m_bShow || m_pExt) return GetNextRedln_( nNext );
commit b216e9dc525de6bed14f301a5d5283477d95e975
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue May 15 14:47:49 2018 +0200

    sw_redlinehide: this m_nCurrentIndexOffset is giving me headaches
    
    Just use the mapping functions in GetNextAttr().
    
    Change-Id: I4108e62ffbefbf3b0afe03b31ff97013969ea3a3

diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index d16bc458269e..c44dc9eaa4d5 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -593,36 +593,39 @@ TextFrameIndex SwAttrIter::GetNextAttr() const
         sal_Int32 nNext = GetNextAttrImpl(pTextNode, nStartIndex, nEndIndex, nPosition);
         if( m_pRedline )
         {
-            // TODO refactor this so it can iterate
-            std::pair<sal_Int32, SwRangeRedline const*> const redline(m_pRedline->GetNextRedln(nNext, pTextNode, nActRedline));
+            std::pair<sal_Int32, SwRangeRedline const*> const redline(
+                    m_pRedline->GetNextRedln(nNext, pTextNode, nActRedline));
             if (redline.second)
             {
+                assert(m_pMergedPara);
                 if (CanSkipOverRedline(*redline.second, nStartIndex, nEndIndex))
                 {
                     if (&redline.second->End()->nNode.GetNode() != pTextNode)
                     {
-                        // FIXME when to update the offset? now or when seeking?
-                        const_cast<SwAttrIter*>(this)->m_nCurrentIndexOffset += pTextNode->Len() - redline.first;
-                        // FIXME this needs to sum up *all* prev. nodes?
-                        const_cast<SwAttrIter*>(this)->m_nCurrentIndexOffset = redline.second->End()->nContent.GetIndex() - pTextNode->Len();
                         pTextNode = redline.second->End()->nNode.GetNode().GetTextNode();
                         nPosition = redline.second->End()->nContent.GetIndex();
-                        // TODO: reset m_pRedline ... its m_pExt ...
                     }
                     else
                     {
                         nPosition = redline.second->End()->nContent.GetIndex();
-                        const_cast<SwAttrIter*>(this)->m_nCurrentIndexOffset += (redline.second->End()->nContent.GetIndex() - redline.first);
                     }
                 }
                 else
-                    return redline.first - m_nCurrentIndexOffset;
+                {
+                    return sw::MapModelToView(*m_pMergedPara, pTextNode, redline.first);
+                }
             }
             else
-                return redline.first - m_nCurrentIndexOffset;
+            {
+                return m_pMergedPara
+                    ? sw::MapModelToView(*m_pMergedPara, pTextNode, redline.first)
+                    : TextFrameIndex(redline.first);
+            }
         }
         else
-            return nNext - m_nCurrentIndexOffset;
+        {
+            return TextFrameIndex(nNext);
+        }
     }
 }
 
diff --git a/sw/source/core/text/itratr.hxx b/sw/source/core/text/itratr.hxx
index c2e8955530e6..dd4f66c5c964 100644
--- a/sw/source/core/text/itratr.hxx
+++ b/sw/source/core/text/itratr.hxx
@@ -63,8 +63,6 @@ private:
     /// input: the current text node
     const SwTextNode* m_pTextNode;
     sw::MergedPara const* m_pMergedPara;
-    /// from view (text frame) index to current node index
-    sal_Int32 m_nCurrentIndexOffset;
 
     void SeekFwd( const sal_Int32 nPos );
     void SetFnt( SwFont* pNew ) { m_pFont = pNew; }
@@ -87,7 +85,6 @@ protected:
         , m_nPropFont(0)
         , m_pTextNode(pTextNode)
         , m_pMergedPara(nullptr)
-        , m_nCurrentIndexOffset(0)
         {
             m_aMagicNo[SwFontScript::Latin] = m_aMagicNo[SwFontScript::CJK] = m_aMagicNo[SwFontScript::CTL] = nullptr;
         }
@@ -99,7 +96,6 @@ public:
     SwAttrIter( SwTextNode& rTextNode, SwScriptInfo& rScrInf )
         : m_pViewShell(nullptr), m_pFont(nullptr), m_pHints(nullptr), m_pScriptInfo(nullptr), m_pLastOut(nullptr), m_nChgCnt(0), m_pRedline(nullptr),m_nPropFont(0), m_pTextNode(&rTextNode)
         , m_pMergedPara(nullptr)
-        , m_nCurrentIndexOffset(0)
         { CtorInitAttrIter( rTextNode, rScrInf ); }
 
     virtual ~SwAttrIter();
commit 12457b06d5be45419768b98458b6a7c629df45cd
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Mon May 14 17:47:08 2018 +0200

    sw_redlinehide: don't need SwAttrIter::m_pFirstNode
    
    Change-Id: Icdadd3d9daa5c0031c044004032723d7108d71ab

diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index 2cabf13235a2..d16bc458269e 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -144,8 +144,9 @@ bool SwAttrIter::IsSymbol(TextFrameIndex const nNewPos)
 
 bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const bool bParaFont )
 {
+    SwTextNode const*const pFirstTextNode(m_pMergedPara ? m_pMergedPara->pFirstNode : m_pTextNode);
     if ( m_pRedline && m_pRedline->ExtOn() )
-        m_pRedline->LeaveExtend(*m_pFont, m_pFirstTextNode->GetIndex(), 0);
+        m_pRedline->LeaveExtend(*m_pFont, pFirstTextNode->GetIndex(), 0);
 
     // reset font to its original state
     m_aAttrHandler.Reset();
@@ -161,7 +162,7 @@ bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const bool bParaFo
     {
         m_pRedline->Clear( m_pFont );
         if( !bParaFont )
-            m_nChgCnt = m_nChgCnt + m_pRedline->Seek(*m_pFont, m_pFirstTextNode->GetIndex(), 0, COMPLETE_STRING);
+            m_nChgCnt = m_nChgCnt + m_pRedline->Seek(*m_pFont, pFirstTextNode->GetIndex(), 0, COMPLETE_STRING);
         else
             m_pRedline->Reset();
     }
diff --git a/sw/source/core/text/itratr.hxx b/sw/source/core/text/itratr.hxx
index de11a6e170ef..c2e8955530e6 100644
--- a/sw/source/core/text/itratr.hxx
+++ b/sw/source/core/text/itratr.hxx
@@ -63,8 +63,6 @@ private:
     /// input: the current text node
     const SwTextNode* m_pTextNode;
     sw::MergedPara const* m_pMergedPara;
-    /// the 1st one, for reset
-    const SwTextNode* m_pFirstTextNode;
     /// from view (text frame) index to current node index
     sal_Int32 m_nCurrentIndexOffset;
 
@@ -89,7 +87,6 @@ protected:
         , m_nPropFont(0)
         , m_pTextNode(pTextNode)
         , m_pMergedPara(nullptr)
-        , m_pFirstTextNode(pTextNode)
         , m_nCurrentIndexOffset(0)
         {
             m_aMagicNo[SwFontScript::Latin] = m_aMagicNo[SwFontScript::CJK] = m_aMagicNo[SwFontScript::CTL] = nullptr;
@@ -102,7 +99,6 @@ public:
     SwAttrIter( SwTextNode& rTextNode, SwScriptInfo& rScrInf )
         : m_pViewShell(nullptr), m_pFont(nullptr), m_pHints(nullptr), m_pScriptInfo(nullptr), m_pLastOut(nullptr), m_nChgCnt(0), m_pRedline(nullptr),m_nPropFont(0), m_pTextNode(&rTextNode)
         , m_pMergedPara(nullptr)
-        , m_pFirstTextNode(&rTextNode)
         , m_nCurrentIndexOffset(0)
         { CtorInitAttrIter( rTextNode, rScrInf ); }
 
commit 10afe724a8f130008893b90575e866d85610a829
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Mon May 14 16:25:19 2018 +0200

    sw_redlinehide: add 3rd mode to SwRedlineItr
    
    So it can work both in the old ignore-redlines mode and in the new
    hide-redlines mode.
    
    Change-Id: I29b23c6749a0f314aff5e9b2342fb389b53bd107

diff --git a/sw/source/core/text/frmpaint.cxx b/sw/source/core/text/frmpaint.cxx
index a036e2d1e964..1ba4b8588d91 100644
--- a/sw/source/core/text/frmpaint.cxx
+++ b/sw/source/core/text/frmpaint.cxx
@@ -485,7 +485,7 @@ bool SwTextFrame::PaintEmpty( const SwRect &rRect, bool bCheck ) const
                     SwAttrHandler aAttrHandler;
                     aAttrHandler.Init(  rTextNode.GetSwAttrSet(),
                                        *rTextNode.getIDocumentSettingAccess() );
-                    SwRedlineItr aRedln( rTextNode, *pFnt, aAttrHandler, nRedlPos, true );
+                    SwRedlineItr aRedln(rTextNode, *pFnt, aAttrHandler, nRedlPos, SwRedlineItr::Mode::Show);
                 }
             }
 
diff --git a/sw/source/core/text/porrst.cxx b/sw/source/core/text/porrst.cxx
index a162577879f8..5d85adbf3c6d 100644
--- a/sw/source/core/text/porrst.cxx
+++ b/sw/source/core/text/porrst.cxx
@@ -259,7 +259,7 @@ SwTwips SwTextFrame::EmptyHeight() const
             aAttrHandler.Init(  GetTextNode()->GetSwAttrSet(),
                                *GetTextNode()->getIDocumentSettingAccess() );
             SwRedlineItr aRedln( rTextNode, *pFnt, aAttrHandler,
-                                 nRedlPos, true );
+                                 nRedlPos, SwRedlineItr::Mode::Show);
         }
     }
 
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 9e80637577cb..11e3e5621768 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -241,7 +241,12 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
             }
 
             m_pRedline = new SwRedlineItr( rTextNode, *m_pFont, m_aAttrHandler, nRedlPos,
-                            bShow, pArr, pExtInp ? pExtInp->Start() : nullptr);
+                            m_pMergedPara
+                                ? SwRedlineItr::Mode::Hide
+                                : bShow
+                                    ? SwRedlineItr::Mode::Show
+                                    : SwRedlineItr::Mode::Ignore,
+                            pArr, pExtInp ? pExtInp->Start() : nullptr);
 
             if( m_pRedline->IsOn() )
                 ++m_nChgCnt;
@@ -262,7 +267,8 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
 // If m_nAct is set to SwRedlineTable::npos (via Reset()), then currently no
 // Redline is active, m_nStart and m_nEnd are invalid.
 SwRedlineItr::SwRedlineItr( const SwTextNode& rTextNd, SwFont& rFnt,
-                            SwAttrHandler& rAH, sal_Int32 nRed, bool bShow,
+                            SwAttrHandler& rAH, sal_Int32 nRed,
+                            Mode const mode,
                             const std::vector<ExtTextInputAttr> *pArr,
                             SwPosition const*const pExtInputStart)
     : m_rDoc( *rTextNd.GetDoc() )
@@ -271,7 +277,7 @@ SwRedlineItr::SwRedlineItr( const SwTextNode& rTextNd, SwFont& rFnt,
     , m_nFirst( nRed )
     , m_nAct( SwRedlineTable::npos )
     , m_bOn( false )
-    , m_bShow( bShow )
+    , m_eMode( mode )
 {
     if( pArr )
     {
@@ -299,7 +305,8 @@ short SwRedlineItr::Seek_(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const n
     if( ExtOn() )
         return 0; // Abbreviation: if we're within an ExtendTextInputs
                   // there can't be other changes of attributes (not even by redlining)
-    if (m_bShow)
+    assert(m_eMode == Mode::Hide || m_nNdIdx == nNode);
+    if (m_eMode == Mode::Show)
     {
         if (m_bOn)
         {
@@ -403,7 +410,7 @@ void SwRedlineItr::ChangeTextAttr( SwFont* pFnt, SwTextAttr const &rHt, bool bCh
 {
     OSL_ENSURE( IsOn(), "SwRedlineItr::ChangeTextAttr: Off?" );
 
-    if (!m_bShow && !m_pExt)
+    if (m_eMode != Mode::Show && !m_pExt)
         return;
 
     if( bChg )
@@ -442,7 +449,7 @@ SwRedlineItr::GetNextRedln(sal_Int32 nNext, SwTextNode const*const pNode, SwRedl
     sal_Int32 nStart(m_nStart);
     sal_Int32 nEnd(m_nEnd);
     nNext = NextExtend(pNode->GetIndex(), nNext);
-    if (!m_bShow || SwRedlineTable::npos == m_nFirst)
+    if (m_eMode == Mode::Ignore || SwRedlineTable::npos == m_nFirst)
         return std::make_pair(nNext, nullptr);
     if (SwRedlineTable::npos == rAct)
     {
@@ -461,7 +468,7 @@ SwRedlineItr::GetNextRedln(sal_Int32 nNext, SwTextNode const*const pNode, SwRedl
     else if (nStart <= nNext)
     {
         nNext = nStart;
-        if (!m_bShow)
+        if (m_eMode == Mode::Hide)
         {
             SwRangeRedline const* pRedline = m_rDoc.getIDocumentRedlineAccess().GetRedlineTable()[rAct];
             if (pRedline->GetType() == nsRedlineType_t::REDLINE_DELETE)
@@ -509,7 +516,7 @@ bool SwRedlineItr::CheckLine(
 {
     // note: previously this would return true in the (!m_bShow && m_pExt)
     // case, but surely that was a bug?
-    if (m_nFirst == SwRedlineTable::npos || !m_bShow)
+    if (m_nFirst == SwRedlineTable::npos || m_eMode != Mode::Show)
         return false;
     assert(nStartNode == nEndNode);
     if( nChkEnd == nChkStart ) // empty lines look one char further
diff --git a/sw/source/core/text/redlnitr.hxx b/sw/source/core/text/redlnitr.hxx
index 43e4c5dba55c..310fd067ca23 100644
--- a/sw/source/core/text/redlnitr.hxx
+++ b/sw/source/core/text/redlnitr.hxx
@@ -81,7 +81,10 @@ class SwRedlineItr
     sal_Int32 m_nStart;
     sal_Int32 m_nEnd;
     bool m_bOn;
-    bool m_bShow;
+public:
+    enum class Mode { Show, Ignore, Hide };
+private:
+    Mode const m_eMode;
 
     void Clear_( SwFont* pFnt );
     bool ChkSpecialUnderline_() const;
@@ -99,7 +102,8 @@ class SwRedlineItr
     }
 public:
     SwRedlineItr( const SwTextNode& rTextNd, SwFont& rFnt, SwAttrHandler& rAH,
-        sal_Int32 nRedlPos, bool bShw, const std::vector<ExtTextInputAttr> *pArr = nullptr,
+        sal_Int32 nRedlPos, Mode mode,
+        const std::vector<ExtTextInputAttr> *pArr = nullptr,
         SwPosition const* pExtInputStart = nullptr);
     ~SwRedlineItr() COVERITY_NOEXCEPT_FALSE;
     SwRedlineTable::size_type GetAct() const { return m_nAct; }
@@ -108,7 +112,7 @@ public:
     void ChangeTextAttr( SwFont* pFnt, SwTextAttr const &rHt, bool bChg );
     short Seek(SwFont& rFnt, sal_uLong nNode, sal_Int32 nNew, sal_Int32 nOld)
     {
-        if (m_bShow || m_pExt) return Seek_(rFnt, nNode, nNew, nOld);
+        if (m_eMode != Mode::Hide || m_pExt) return Seek_(rFnt, nNode, nNew, nOld);
         return 0;
     }
     void Reset() {
commit ca3f28088613361c488ac85f94a9f390cec2175e
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Mon May 14 17:42:39 2018 +0200

    sw_redlinehide: add MergedPara member to SwAttrIter
    
    Change-Id: I304c333bb6aaca8933606b662743a1642c655de5

diff --git a/sw/source/core/text/itratr.hxx b/sw/source/core/text/itratr.hxx
index f1cc15dafae6..de11a6e170ef 100644
--- a/sw/source/core/text/itratr.hxx
+++ b/sw/source/core/text/itratr.hxx
@@ -24,6 +24,7 @@
 #include <swfont.hxx>
 #include "porlay.hxx"
 
+namespace sw { struct MergedPara; }
 class OutputDevice;
 class SwFont;
 class SwpHints;
@@ -61,6 +62,7 @@ private:
     o3tl::enumarray<SwFontScript, sal_uInt16> m_aFontIdx;
     /// input: the current text node
     const SwTextNode* m_pTextNode;
+    sw::MergedPara const* m_pMergedPara;
     /// the 1st one, for reset
     const SwTextNode* m_pFirstTextNode;
     /// from view (text frame) index to current node index
@@ -86,6 +88,7 @@ protected:
         , m_nPosition(0)
         , m_nPropFont(0)
         , m_pTextNode(pTextNode)
+        , m_pMergedPara(nullptr)
         , m_pFirstTextNode(pTextNode)
         , m_nCurrentIndexOffset(0)
         {
@@ -98,6 +101,7 @@ public:
     /// SwTextFrame in certain special cases via this ctor here
     SwAttrIter( SwTextNode& rTextNode, SwScriptInfo& rScrInf )
         : m_pViewShell(nullptr), m_pFont(nullptr), m_pHints(nullptr), m_pScriptInfo(nullptr), m_pLastOut(nullptr), m_nChgCnt(0), m_pRedline(nullptr),m_nPropFont(0), m_pTextNode(&rTextNode)
+        , m_pMergedPara(nullptr)
         , m_pFirstTextNode(&rTextNode)
         , m_nCurrentIndexOffset(0)
         { CtorInitAttrIter( rTextNode, rScrInf ); }
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 6f4d372860a6..9e80637577cb 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -132,7 +132,6 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
     // set font to vertical if frame layout is vertical
     bool bVertLayout = false;
     bool bRTL = false;
-    sw::MergedPara const* pMerged(nullptr);
     if ( pFrame )
     {
         if ( pFrame->IsVertical() )
@@ -141,7 +140,7 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
             m_pFont->SetVertical( m_pFont->GetOrientation(), true );
         }
         bRTL = pFrame->IsRightToLeft();
-        pMerged = pFrame->GetMergedPara();
+        m_pMergedPara = pFrame->GetMergedPara();
     }
 
     // Initialize the default attribute of the attribute handler
@@ -199,10 +198,10 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
     // the node.  It's not clear whether there can be more than 1 PaM in the
     // Ring, and this code doesn't handle that case; neither did the old code.
     const SwExtTextInput* pExtInp = pDoc->GetExtTextInput( rTextNode );
-    if (!pExtInp && pMerged)
+    if (!pExtInp && m_pMergedPara)
     {
         SwTextNode const* pNode(&rTextNode);
-        for (auto const& rExtent : pMerged->extents)
+        for (auto const& rExtent : m_pMergedPara->extents)
         {
             if (rExtent.pNode != pNode)
             {
@@ -214,16 +213,31 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
         }
     }
     const bool bShow = IDocumentRedlineAccess::IsShowChanges( rIDRA.GetRedlineFlags() );
-    if (pExtInp || pMerged || bShow)
+    if (pExtInp || m_pMergedPara || bShow)
     {
-        const SwRedlineTable::size_type nRedlPos = rIDRA.GetRedlinePos( rTextNode, USHRT_MAX );
-        if (pExtInp || pMerged || SwRedlineTable::npos != nRedlPos)
+        SwRedlineTable::size_type nRedlPos = rIDRA.GetRedlinePos( rTextNode, USHRT_MAX );
+        if (SwRedlineTable::npos == nRedlPos && m_pMergedPara)
+        {
+            SwTextNode const* pNode(&rTextNode);
+            for (auto const& rExtent : m_pMergedPara->extents)
+            {   // note: have to search because extents based only on Delete
+                if (rExtent.pNode != pNode)
+                {
+                    pNode = rExtent.pNode;
+                    nRedlPos = rIDRA.GetRedlinePos(*pNode, USHRT_MAX);
+                    if (SwRedlineTable::npos != nRedlPos)
+                        break;
+                }
+            }
+            assert(SwRedlineTable::npos != nRedlPos);
+        }
+        if (pExtInp || m_pMergedPara || SwRedlineTable::npos != nRedlPos)
         {
             const std::vector<ExtTextInputAttr> *pArr = nullptr;
             if( pExtInp )
             {
                 pArr = &pExtInp->GetAttrs();
-                Seek( 0 );
+                Seek( TextFrameIndex(0) );
             }
 
             m_pRedline = new SwRedlineItr( rTextNode, *m_pFont, m_aAttrHandler, nRedlPos,
commit 49affc0d12884744232ed6bd32860bb27fcc39e9
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Mon May 14 17:39:32 2018 +0200

    sw_redlinehide: SwRedlineItr::m_nNdIdx can be const
    
    Change-Id: I6231e25dd1cae8360b2561051cc06fb16788398a

diff --git a/sw/source/core/text/redlnitr.hxx b/sw/source/core/text/redlnitr.hxx
index 9cb6ad3af0d8..43e4c5dba55c 100644
--- a/sw/source/core/text/redlnitr.hxx
+++ b/sw/source/core/text/redlnitr.hxx
@@ -74,7 +74,8 @@ class SwRedlineItr
     SwAttrHandler& m_rAttrHandler;
     std::unique_ptr<SfxItemSet> m_pSet;
     SwExtend *m_pExt;
-    sal_uLong m_nNdIdx;
+    // note: this isn't actually used in the merged-para (Hide) case
+    sal_uLong const m_nNdIdx;
     SwRedlineTable::size_type const m_nFirst;
     SwRedlineTable::size_type m_nAct;
     sal_Int32 m_nStart;
commit 41ec60f5561979dc2dd471d7dda616529cd3628b
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Mon May 14 14:38:08 2018 +0200

    sw_redlinehide: SwRedlineItr::CheckLine()
    
    ... should just return early... but keep the changed interface.
    
    Change-Id: I6da6f62ebd66f1017946abac60c5f20d2dbb1fc5

diff --git a/sw/source/core/text/porlay.cxx b/sw/source/core/text/porlay.cxx
index e8fb45c23b86..454a5a5116e2 100644
--- a/sw/source/core/text/porlay.cxx
+++ b/sw/source/core/text/porlay.cxx
@@ -566,8 +566,13 @@ void SwLineLayout::CalcLine( SwTextFormatter &rLine, SwTextFormatInfo &rInf )
         Width( nLineWidth );
     SAL_WARN_IF( nLineWidth < Width(), "sw.core", "SwLineLayout::CalcLine: line is bursting" );
     SetDummy( bTmpDummy );
+    std::pair<SwTextNode const*, sal_Int32> const start(
+            rInf.GetTextFrame()->MapViewToModel(rLine.GetStart()));
+    std::pair<SwTextNode const*, sal_Int32> const end(
+            rInf.GetTextFrame()->MapViewToModel(rLine.GetEnd()));
     SetRedline( rLine.GetRedln() &&
-        rLine.GetRedln()->CheckLine( rLine.GetStart(), rLine.GetEnd() ) );
+        rLine.GetRedln()->CheckLine(start.first->GetIndex(), start.second,
+            end.first->GetIndex(), end.second) );
 }
 
 // #i47162# - add optional parameter <_bNoFlyCntPorAndLinePor>
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 32e64cd5ab6f..6f4d372860a6 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -489,10 +489,15 @@ bool SwRedlineItr::ChkSpecialUnderline_() const
     return false;
 }
 
-bool SwRedlineItr::CheckLine( sal_Int32 nChkStart, sal_Int32 nChkEnd )
+bool SwRedlineItr::CheckLine(
+        sal_uLong const nStartNode, sal_Int32 const nChkStart,
+        sal_uLong const nEndNode, sal_Int32 nChkEnd)
 {
-    if (m_nFirst == SwRedlineTable::npos)
+    // note: previously this would return true in the (!m_bShow && m_pExt)
+    // case, but surely that was a bug?
+    if (m_nFirst == SwRedlineTable::npos || !m_bShow)
         return false;
+    assert(nStartNode == nEndNode);
     if( nChkEnd == nChkStart ) // empty lines look one char further
         ++nChkEnd;
     sal_Int32 nOldStart = m_nStart;
diff --git a/sw/source/core/text/redlnitr.hxx b/sw/source/core/text/redlnitr.hxx
index 3deeb16bd2ae..9cb6ad3af0d8 100644
--- a/sw/source/core/text/redlnitr.hxx
+++ b/sw/source/core/text/redlnitr.hxx
@@ -123,7 +123,7 @@ public:
 #endif
     bool ChkSpecialUnderline() const
         { return IsOn() && ChkSpecialUnderline_(); }
-    bool CheckLine( sal_Int32 nChkStart, sal_Int32 nChkEnd );
+    bool CheckLine(sal_uLong nStartNode, sal_Int32 nChkStart, sal_uLong nEndNode, sal_Int32 nChkEnd);
     bool LeaveExtend(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const nNew)
         { return m_pExt->Leave(rFnt, nNode, nNew); }
     bool ExtOn() {
commit 5cbb55b18fd31e66780f60cad1265369923a6739
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri May 11 18:48:12 2018 +0200

    sw_redlinehide: adapt SwExtend to merged paragraph
    
    It needs a new member to know what node it's in, plus all the methods
    need a node passed in to compare.
    
    Change-Id: Ibcc5a1fb7031fbdc048cc6716bb5b74cd4b8f0bf

diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index afc88a33dfad..2cabf13235a2 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -145,7 +145,7 @@ bool SwAttrIter::IsSymbol(TextFrameIndex const nNewPos)
 bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const bool bParaFont )
 {
     if ( m_pRedline && m_pRedline->ExtOn() )
-        m_pRedline->LeaveExtend( *m_pFont, 0 );
+        m_pRedline->LeaveExtend(*m_pFont, m_pFirstTextNode->GetIndex(), 0);
 
     // reset font to its original state
     m_aAttrHandler.Reset();
@@ -161,7 +161,7 @@ bool SwAttrIter::SeekStartAndChgAttrIter( OutputDevice* pOut, const bool bParaFo
     {
         m_pRedline->Clear( m_pFont );
         if( !bParaFont )
-            m_nChgCnt = m_nChgCnt + m_pRedline->Seek(*m_pFont, 0, COMPLETE_STRING);
+            m_nChgCnt = m_nChgCnt + m_pRedline->Seek(*m_pFont, m_pFirstTextNode->GetIndex(), 0, COMPLETE_STRING);
         else
             m_pRedline->Reset();
     }
@@ -241,8 +241,14 @@ void SwAttrIter::SeekFwd( const sal_Int32 nNewPos )
 
 bool SwAttrIter::Seek(TextFrameIndex const nNewPos)
 {
+    // note: nNewPos isn't necessarily a index returned from GetNextAttr
+    sw::MergedPara * pMerged(nullptr); // FIXME
+    std::pair<SwTextNode const*, sal_Int32> const newPos( pMerged
+        ? sw::MapViewToModel(*pMerged, nNewPos)
+        : std::make_pair(m_pTextNode, nNewPos));
+
     if ( m_pRedline && m_pRedline->ExtOn() )
-        m_pRedline->LeaveExtend( *m_pFont, nNewPos );
+        m_pRedline->LeaveExtend(*m_pFont, newPos.first->GetIndex(), newPos.second);
 
     if( m_pHints )
     {
@@ -277,7 +283,7 @@ bool SwAttrIter::Seek(TextFrameIndex const nNewPos)
     m_pFont->SetActual( SwScriptInfo::WhichFont( nNewPos, nullptr, m_pScriptInfo ) );
 
     if( m_pRedline )
-        m_nChgCnt = m_nChgCnt + m_pRedline->Seek( *m_pFont, nNewPos, m_nPosition );
+        m_nChgCnt = m_nChgCnt + m_pRedline->Seek(*m_pFont, newPos.first->GetIndex(), newPos.second, m_nPosition);
     m_nPosition = nNewPos;
 
     if( m_nPropFont )
diff --git a/sw/source/core/text/itrpaint.cxx b/sw/source/core/text/itrpaint.cxx
index cc98272947d1..2037eed2ec68 100644
--- a/sw/source/core/text/itrpaint.cxx
+++ b/sw/source/core/text/itrpaint.cxx
@@ -317,10 +317,17 @@ void SwTextPainter::DrawTextLine( const SwRect &rPaint, SwSaveClip &rClip,
             SeekAndChgBefore( GetInfo() );
         else if ( pPor->IsQuoVadisPortion() )
         {
+            // A remark on QuoVadis/ErgoSum:
+            // We use the Font set for the Paragraph for these portions.
+            // Thus, we initialize:
             TextFrameIndex nOffset = GetInfo().GetIdx();
             SeekStartAndChg( GetInfo(), true );
             if( GetRedln() && m_pCurr->HasRedline() )
-                GetRedln()->Seek( *m_pFont, nOffset, 0 );
+            {
+                std::pair<SwTextNode const*, sal_Int32> const pos(
+                        GetTextFrame()->MapViewToModel(nOffset));
+                GetRedln()->Seek(*m_pFont, pos.first->GetIndex(), pos.second, 0);
+            }
         }
         else if( pPor->InTextGrp() || pPor->InFieldGrp() || pPor->InTabGrp() )
             SeekAndChg( GetInfo() );
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 86bfd2438a45..32e64cd5ab6f 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -267,7 +267,7 @@ SwRedlineItr::SwRedlineItr( const SwTextNode& rTextNd, SwFont& rFnt,
     }
     else
         m_pExt = nullptr;
-    Seek (rFnt, 0, COMPLETE_STRING);
+    Seek(rFnt, m_nNdIdx, 0, COMPLETE_STRING);
 }
 
 SwRedlineItr::~SwRedlineItr() COVERITY_NOEXCEPT_FALSE
@@ -278,7 +278,8 @@ SwRedlineItr::~SwRedlineItr() COVERITY_NOEXCEPT_FALSE
 
 // The return value of SwRedlineItr::Seek tells you if the current font
 // has been manipulated by leaving (-1) or accessing (+1) of a section
-short SwRedlineItr::Seek_(SwFont& rFnt, sal_Int32 nNew, sal_Int32 nOld)
+short SwRedlineItr::Seek_(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const nNew, sal_Int32 const nOld)
+    //TODO use nNode to compare
 {
     short nRet = 0;
     if( ExtOn() )
@@ -301,10 +302,10 @@ short SwRedlineItr::Seek_(SwFont& rFnt, sal_Int32 nNew, sal_Int32 nOld)
                 if (m_nAct > m_nFirst)
                     m_nAct = m_nFirst;  // the test has to run from the beginning
                 else
-                    return nRet + EnterExtend( rFnt, nNew ); // There's none prior to us
+                    return nRet + EnterExtend(rFnt, nNode, nNew); // There's none prior to us
             }
             else
-                return nRet + EnterExtend( rFnt, nNew ); // We stayed in the same section
+                return nRet + EnterExtend(rFnt, nNode, nNew); // We stayed in the same section
         }
         if (SwRedlineTable::npos == m_nAct || nOld > nNew)
             m_nAct = m_nFirst;
@@ -362,7 +363,7 @@ short SwRedlineItr::Seek_(SwFont& rFnt, sal_Int32 nNew, sal_Int32 nOld)
             m_nEnd = COMPLETE_STRING;
         }
     }
-    return nRet + EnterExtend( rFnt, nNew );
+    return nRet + EnterExtend(rFnt, nNode, nNew);
 }
 
 void SwRedlineItr::FillHints( std::size_t nAuthor, RedlineType_t eType )
@@ -426,7 +427,7 @@ SwRedlineItr::GetNextRedln(sal_Int32 nNext, SwTextNode const*const pNode, SwRedl
 {
     sal_Int32 nStart(m_nStart);
     sal_Int32 nEnd(m_nEnd);
-    nNext = NextExtend( nNext );
+    nNext = NextExtend(pNode->GetIndex(), nNext);
     if (!m_bShow || SwRedlineTable::npos == m_nFirst)
         return std::make_pair(nNext, nullptr);
     if (SwRedlineTable::npos == rAct)
@@ -541,10 +542,12 @@ void SwExtend::ActualizeFont( SwFont &rFnt, ExtTextInputAttr nAttr )
         rFnt.SetGreyWave( true );
 }
 
-short SwExtend::Enter(SwFont& rFnt, sal_Int32 nNew)
+short SwExtend::Enter(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const nNew)
 {
-    OSL_ENSURE( !Inside(), "SwExtend: Enter without Leave" );
     OSL_ENSURE( !m_pFont, "SwExtend: Enter with Font" );
+    if (nNode != m_nNode)
+        return 0;
+    OSL_ENSURE( !Inside(), "SwExtend: Enter without Leave" );
     m_nPos = nNew;
     if( Inside() )
     {
@@ -555,9 +558,11 @@ short SwExtend::Enter(SwFont& rFnt, sal_Int32 nNew)
     return 0;
 }
 
-bool SwExtend::Leave_(SwFont& rFnt, sal_Int32 nNew)
+bool SwExtend::Leave_(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const nNew)
 {
-    OSL_ENSURE( Inside(), "SwExtend: Leave without Enter" );
+    OSL_ENSURE(nNode == m_nNode && Inside(), "SwExtend: Leave without Enter");
+    if (nNode != m_nNode)
+        return true;
     const ExtTextInputAttr nOldAttr = m_rArr[m_nPos - m_nStart];
     m_nPos = nNew;
     if( Inside() )
@@ -578,9 +583,10 @@ bool SwExtend::Leave_(SwFont& rFnt, sal_Int32 nNew)
     return false;
 }
 
-sal_Int32 SwExtend::Next( sal_Int32 nNext )
+sal_Int32 SwExtend::Next(sal_uLong const nNode, sal_Int32 nNext)
 {
-    (void) m_nNode; // TODO use it here
+    if (nNode != m_nNode)
+        return nNext;
     if (m_nPos < m_nStart)
     {
         if (nNext > m_nStart)
diff --git a/sw/source/core/text/redlnitr.hxx b/sw/source/core/text/redlnitr.hxx
index 65f22be44f2b..3deeb16bd2ae 100644
--- a/sw/source/core/text/redlnitr.hxx
+++ b/sw/source/core/text/redlnitr.hxx
@@ -38,11 +38,14 @@ class SwExtend
 {
     std::unique_ptr<SwFont> m_pFont;
     const std::vector<ExtTextInputAttr> &m_rArr;
-    sal_uLong m_nNode;
-    sal_Int32 m_nStart;
+    /// position of start of SwExtTextInput
+    sal_uLong const m_nNode;
+    sal_Int32 const m_nStart;
+    /// current position (inside)
     sal_Int32 m_nPos;
-    sal_Int32 m_nEnd;
-    bool Leave_( SwFont& rFnt, sal_Int32 nNew );
+    /// position of end of SwExtTextInput (in same node as start)
+    sal_Int32 const m_nEnd;
+    bool Leave_(SwFont& rFnt, sal_uLong nNode, sal_Int32 nNew);
     bool Inside() const { return (m_nPos >= m_nStart && m_nPos < m_nEnd); }
     static void ActualizeFont( SwFont &rFnt, ExtTextInputAttr nAttr );
 public:
@@ -56,10 +59,10 @@ public:
     {}
     bool IsOn() const { return m_pFont != nullptr; }
     void Reset() { m_pFont.reset(); m_nPos = COMPLETE_STRING; }
-    bool Leave( SwFont& rFnt, sal_Int32 nNew )
-        { return m_pFont && Leave_( rFnt, nNew ); }
-    short Enter( SwFont& rFnt, sal_Int32 nNew );
-    sal_Int32 Next( sal_Int32 nNext );
+    bool Leave(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const nNew)
+        { return m_pFont && Leave_(rFnt, nNode, nNew); }
+    short Enter(SwFont& rFnt, sal_uLong nNode, sal_Int32 nNew);
+    sal_Int32 Next(sal_uLong nNode, sal_Int32 nNext);
     SwFont* GetFont() { return m_pFont.get(); }
     void UpdateFont(SwFont &rFont) { ActualizeFont(rFont, m_rArr[m_nPos - m_nStart]); }
 };
@@ -82,14 +85,15 @@ class SwRedlineItr
     void Clear_( SwFont* pFnt );
     bool ChkSpecialUnderline_() const;
     void FillHints( std::size_t nAuthor, RedlineType_t eType );
-    short Seek_( SwFont& rFnt, sal_Int32 nNew, sal_Int32 nOld );
+    short Seek_(SwFont& rFnt, sal_uLong nNode, sal_Int32 nNew, sal_Int32 nOld);
 //    sal_Int32 GetNextRedln_( sal_Int32 nNext );
-    short EnterExtend( SwFont& rFnt, sal_Int32 nNew ) {
-        if (m_pExt) return m_pExt->Enter( rFnt, nNew );
+    short EnterExtend(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const nNew)
+    {
+        if (m_pExt) return m_pExt->Enter(rFnt, nNode, nNew);
         return 0;
     }
-    sal_Int32 NextExtend( sal_Int32 nNext ) {
-        if (m_pExt) return m_pExt->Next( nNext );
+    sal_Int32 NextExtend(sal_uLong const nNode, sal_Int32 const nNext) {
+        if (m_pExt) return m_pExt->Next(nNode, nNext);
         return nNext;
     }
 public:
@@ -101,8 +105,9 @@ public:
     bool IsOn() const { return m_bOn || (m_pExt && m_pExt->IsOn()); }
     void Clear( SwFont* pFnt ) { if (m_bOn) Clear_( pFnt ); }
     void ChangeTextAttr( SwFont* pFnt, SwTextAttr const &rHt, bool bChg );
-    short Seek( SwFont& rFnt, sal_Int32 nNew, sal_Int32 nOld ) {
-        if (m_bShow || m_pExt) return Seek_( rFnt, nNew, nOld );
+    short Seek(SwFont& rFnt, sal_uLong nNode, sal_Int32 nNew, sal_Int32 nOld)
+    {
+        if (m_bShow || m_pExt) return Seek_(rFnt, nNode, nNew, nOld);
         return 0;
     }
     void Reset() {
@@ -119,8 +124,8 @@ public:
     bool ChkSpecialUnderline() const
         { return IsOn() && ChkSpecialUnderline_(); }
     bool CheckLine( sal_Int32 nChkStart, sal_Int32 nChkEnd );
-    bool LeaveExtend( SwFont& rFnt, sal_Int32 nNew )
-        { return m_pExt->Leave(rFnt, nNew ); }
+    bool LeaveExtend(SwFont& rFnt, sal_uLong const nNode, sal_Int32 const nNew)
+        { return m_pExt->Leave(rFnt, nNode, nNew); }
     bool ExtOn() {
         if (m_pExt) return m_pExt->IsOn();
         return false;
diff --git a/sw/source/core/text/txtftn.cxx b/sw/source/core/text/txtftn.cxx
index 34b353b10f80..1ccfd5fbecc0 100644
--- a/sw/source/core/text/txtftn.cxx
+++ b/sw/source/core/text/txtftn.cxx
@@ -1032,7 +1032,11 @@ TextFrameIndex SwTextFormatter::FormatQuoVadis(TextFrameIndex const nOffset)
     FeedInf( rInf );
     SeekStartAndChg( rInf, true );
     if( GetRedln() && m_pCurr->HasRedline() )
-        GetRedln()->Seek( *m_pFont, nOffset, 0 );
+    {
+        std::pair<SwTextNode const*, sal_Int32> const pos(
+                GetTextFrame()->MapViewToModel(nOffset));
+        GetRedln()->Seek(*m_pFont, pos.first->GetIndex(), pos.second, 0);
+    }
 
     // A tricky special case: Flyfrms extend into the Line and are at the
     // position we want to insert the Quovadis text
commit fdcced0f1d18d713a2e84a26490b61a7d863daf7
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri May 11 18:35:48 2018 +0200

    sw_redlinehide: SwExtend needs a node index for merged para
    
    Change-Id: I0742eea80e881f1a5f3714e283f4b913260c46ee

diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index e8d98c696e80..86bfd2438a45 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -132,6 +132,7 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
     // set font to vertical if frame layout is vertical
     bool bVertLayout = false;
     bool bRTL = false;
+    sw::MergedPara const* pMerged(nullptr);
     if ( pFrame )
     {
         if ( pFrame->IsVertical() )
@@ -140,6 +141,7 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
             m_pFont->SetVertical( m_pFont->GetOrientation(), true );
         }
         bRTL = pFrame->IsRightToLeft();
+        pMerged = pFrame->GetMergedPara();
     }
 
     // Initialize the default attribute of the attribute handler
@@ -193,24 +195,39 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
     SwDoc* pDoc = rTextNode.GetDoc();
     const IDocumentRedlineAccess& rIDRA = rTextNode.getIDocumentRedlineAccess();
 
+    // sw_redlinehide: this is a Ring - pExtInp is the first PaM that's inside
+    // the node.  It's not clear whether there can be more than 1 PaM in the
+    // Ring, and this code doesn't handle that case; neither did the old code.
     const SwExtTextInput* pExtInp = pDoc->GetExtTextInput( rTextNode );
+    if (!pExtInp && pMerged)
+    {
+        SwTextNode const* pNode(&rTextNode);
+        for (auto const& rExtent : pMerged->extents)
+        {
+            if (rExtent.pNode != pNode)
+            {
+                pNode = rExtent.pNode;
+                pExtInp = pDoc->GetExtTextInput(*pNode);
+                if (pExtInp)
+                    break;
+            }
+        }
+    }
     const bool bShow = IDocumentRedlineAccess::IsShowChanges( rIDRA.GetRedlineFlags() );
-    if( pExtInp || bShow )
+    if (pExtInp || pMerged || bShow)
     {
         const SwRedlineTable::size_type nRedlPos = rIDRA.GetRedlinePos( rTextNode, USHRT_MAX );
-        if( pExtInp || SwRedlineTable::npos != nRedlPos )
+        if (pExtInp || pMerged || SwRedlineTable::npos != nRedlPos)
         {
             const std::vector<ExtTextInputAttr> *pArr = nullptr;
-            sal_Int32 nInputStt = 0;
             if( pExtInp )
             {
                 pArr = &pExtInp->GetAttrs();
-                nInputStt = pExtInp->Start()->nContent.GetIndex();
                 Seek( 0 );
             }
 
             m_pRedline = new SwRedlineItr( rTextNode, *m_pFont, m_aAttrHandler, nRedlPos,
-                                        bShow, pArr, nInputStt );
+                            bShow, pArr, pExtInp ? pExtInp->Start() : nullptr);
 
             if( m_pRedline->IsOn() )
                 ++m_nChgCnt;
@@ -233,7 +250,7 @@ void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
 SwRedlineItr::SwRedlineItr( const SwTextNode& rTextNd, SwFont& rFnt,
                             SwAttrHandler& rAH, sal_Int32 nRed, bool bShow,
                             const std::vector<ExtTextInputAttr> *pArr,
-                            sal_Int32 nExtStart )
+                            SwPosition const*const pExtInputStart)
     : m_rDoc( *rTextNd.GetDoc() )
     , m_rAttrHandler( rAH )
     , m_nNdIdx( rTextNd.GetIndex() )
@@ -243,7 +260,11 @@ SwRedlineItr::SwRedlineItr( const SwTextNode& rTextNd, SwFont& rFnt,
     , m_bShow( bShow )
 {
     if( pArr )
-        m_pExt = new SwExtend( *pArr, nExtStart );
+    {
+        assert(pExtInputStart);
+        m_pExt = new SwExtend(*pArr, pExtInputStart->nNode.GetIndex(),
+                                     pExtInputStart->nContent.GetIndex());
+    }
     else
         m_pExt = nullptr;
     Seek (rFnt, 0, COMPLETE_STRING);
@@ -559,6 +580,7 @@ bool SwExtend::Leave_(SwFont& rFnt, sal_Int32 nNew)
 
 sal_Int32 SwExtend::Next( sal_Int32 nNext )
 {
+    (void) m_nNode; // TODO use it here
     if (m_nPos < m_nStart)
     {
         if (nNext > m_nStart)
diff --git a/sw/source/core/text/redlnitr.hxx b/sw/source/core/text/redlnitr.hxx
index 2cf419046b4d..65f22be44f2b 100644
--- a/sw/source/core/text/redlnitr.hxx
+++ b/sw/source/core/text/redlnitr.hxx
@@ -38,6 +38,7 @@ class SwExtend
 {
     std::unique_ptr<SwFont> m_pFont;
     const std::vector<ExtTextInputAttr> &m_rArr;
+    sal_uLong m_nNode;
     sal_Int32 m_nStart;
     sal_Int32 m_nPos;
     sal_Int32 m_nEnd;
@@ -45,8 +46,10 @@ class SwExtend
     bool Inside() const { return (m_nPos >= m_nStart && m_nPos < m_nEnd); }
     static void ActualizeFont( SwFont &rFnt, ExtTextInputAttr nAttr );
 public:
-    SwExtend(const std::vector<ExtTextInputAttr> &rArr, sal_Int32 const nStart)
+    SwExtend(const std::vector<ExtTextInputAttr> &rArr,
+             sal_uLong const nNode, sal_Int32 const nStart)
         : m_rArr(rArr)
+        , m_nNode(nNode)
         , m_nStart(nStart)
         , m_nPos(COMPLETE_STRING)
         , m_nEnd(m_nStart + rArr.size())
@@ -92,7 +95,7 @@ class SwRedlineItr
 public:
     SwRedlineItr( const SwTextNode& rTextNd, SwFont& rFnt, SwAttrHandler& rAH,
         sal_Int32 nRedlPos, bool bShw, const std::vector<ExtTextInputAttr> *pArr = nullptr,
-        sal_Int32 nExtStart = COMPLETE_STRING );
+        SwPosition const* pExtInputStart = nullptr);
     ~SwRedlineItr() COVERITY_NOEXCEPT_FALSE;
     SwRedlineTable::size_type GetAct() const { return m_nAct; }
     bool IsOn() const { return m_bOn || (m_pExt && m_pExt->IsOn()); }
commit 8fc73f7fee919d17a7c2defd404a15ae9cc5fdc5
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri May 11 17:35:28 2018 +0200

    sw_redlinehide: SwAttrIter::GetHints only used to check if there are
    
    hints, so replace it with something less dangerous.
    
    Change-Id: If35cf8157e6b88ee6873789847ed9c5ceea6e37e

diff --git a/sw/source/core/text/itratr.hxx b/sw/source/core/text/itratr.hxx
index 7229fd2519bc..f1cc15dafae6 100644
--- a/sw/source/core/text/itratr.hxx
+++ b/sw/source/core/text/itratr.hxx
@@ -126,8 +126,6 @@ public:
     // Returns the attribute for a position
     SwTextAttr *GetAttr(TextFrameIndex nPos) const;
 
-    const SwpHints *GetHints() const { return m_pHints; }
-
     SwFont *GetFnt() { return m_pFont; }
     const SwFont *GetFnt() const { return m_pFont; }
 
diff --git a/sw/source/core/text/itrtxt.cxx b/sw/source/core/text/itrtxt.cxx
index 002eaf932fb4..12a5b59fbc84 100644
--- a/sw/source/core/text/itrtxt.cxx
+++ b/sw/source/core/text/itrtxt.cxx
@@ -322,7 +322,7 @@ void SwTextIter::TruncLines( bool bNoteFollow )
     if( pDel )
     {
         m_pCurr->SetNext( nullptr );
-        if( GetHints() && bNoteFollow )
+        if (HasHints() && bNoteFollow)
         {
             GetInfo().GetParaPortion()->SetFollowField( pDel->IsRest() ||
                                                         lcl_NeedsFieldRest( m_pCurr ) );
@@ -367,7 +367,7 @@ void SwTextIter::TruncLines( bool bNoteFollow )
     {
         m_pCurr->SetRealHeight( 1 );
     }
-    if( GetHints() )
+    if (HasHints())
         m_pFrame->RemoveFootnote( nEnd );
 }
 
commit 938e2b5d225de0608016ed70677708aca48f5e53
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri May 11 18:42:44 2018 +0200

    itratr header
    
    Change-Id: Ib8a0e8bd01ef6dfa4c0e9f9c00c83ba935fca2fb

diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index 66e44cafbf74..afc88a33dfad 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -239,7 +239,7 @@ void SwAttrIter::SeekFwd( const sal_Int32 nNewPos )
 
 }
 
-bool SwAttrIter::Seek( const sal_Int32 nNewPos )
+bool SwAttrIter::Seek(TextFrameIndex const nNewPos)
 {
     if ( m_pRedline && m_pRedline->ExtOn() )
         m_pRedline->LeaveExtend( *m_pFont, nNewPos );
diff --git a/sw/source/core/text/itratr.hxx b/sw/source/core/text/itratr.hxx
index 3dde7480b70d..7229fd2519bc 100644
--- a/sw/source/core/text/itratr.hxx
+++ b/sw/source/core/text/itratr.hxx
@@ -107,7 +107,7 @@ public:
     SwRedlineItr *GetRedln() { return m_pRedline; }
     // The parameter returns the position of the next change before or at the
     // char position.
-    sal_Int32 GetNextAttr( ) const;
+    TextFrameIndex GetNextAttr() const;
     /// Enables the attributes used at char pos nPos in the logical font
     bool Seek(TextFrameIndex nPos);
     // Creates the font at the specified position via Seek() and checks
commit 1c43fc0f4ddf51a87cdbaf390a159e8280127e2c
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Fri May 11 12:47:16 2018 +0200

    itratr: GetNextAttr return TextFrameIndex
    
    Change-Id: I2b519f5379815abc943e05a79db609b3e93f82fc

diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index c1d86c33797f..66e44cafbf74 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -573,7 +573,7 @@ static sal_Int32 GetNextAttrImpl(SwTextNode const*const pTextNode,
     return nNext;
 }
 
-sal_Int32 SwAttrIter::GetNextAttr() const
+TextFrameIndex SwAttrIter::GetNextAttr() const
 {
     size_t nStartIndex(m_nStartIndex);
     size_t nEndIndex(m_nEndIndex);
diff --git a/sw/source/core/text/itratr.hxx b/sw/source/core/text/itratr.hxx
index a5b2c49729b7..3dde7480b70d 100644
--- a/sw/source/core/text/itratr.hxx
+++ b/sw/source/core/text/itratr.hxx
@@ -109,7 +109,7 @@ public:
     // char position.
     sal_Int32 GetNextAttr( ) const;
     /// Enables the attributes used at char pos nPos in the logical font
-    bool Seek( const sal_Int32 nPos );
+    bool Seek(TextFrameIndex nPos);
     // Creates the font at the specified position via Seek() and checks
     // if it's a symbol font.
     bool IsSymbol(TextFrameIndex nPos);
commit 959514ff6c98ed98c9e52d1e691e8753baf7ba49
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Wed May 9 18:40:21 2018 +0200

    sw_redlinehide: trivial conversions in objectpositioning/
    
    Change-Id: Ice9c49596d478bd02728827dbd0dc2c77d7a13db

diff --git a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
index 4144f8241154..43070b3547f1 100644
--- a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
+++ b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
@@ -223,7 +223,7 @@ void SwToContentAnchoredObjectPosition::CalcPosition()
             // #i22341# - get top of line, in which the anchor character is.
             mnToCharTopOfLine = GetAnchoredObj().GetLastTopOfLine();
             pOrientFrame = &(const_cast<SwTextFrame&>(rAnchorTextFrame).GetFrameAtOfst(
-                                rAnch.GetContentAnchor()->nContent.GetIndex() ) );
+                rAnchorTextFrame.MapModelToViewPos(*rAnch.GetContentAnchor())));
             mpToCharOrientFrame = pOrientFrame;
         }
     }
commit 8bce677c515c48e8fce4ae2f541c784a9b39c55e
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Wed May 9 18:39:59 2018 +0200

    sw_redlinehide: trivial conversions in trvlfrm.cxx
    
    Change-Id: I812ba7a03b9bd25134dab2e85fcead1c7bed617a

diff --git a/sw/source/core/layout/trvlfrm.cxx b/sw/source/core/layout/trvlfrm.cxx
index 1586d7e5753d..d4c1e5c002c9 100644
--- a/sw/source/core/layout/trvlfrm.cxx
+++ b/sw/source/core/layout/trvlfrm.cxx
@@ -1013,10 +1013,9 @@ sal_uInt16 SwRootFrame::SetCurrPage( SwCursor* pToSet, sal_uInt16 nPageNum )
             pContent = pContent->GetNextContentFrame();
     if ( pContent )
     {
-        SwContentNode* pCNd = const_cast<SwContentNode*>(pContent->GetNode());
-        pToSet->GetPoint()->nNode = *pCNd;
-        pCNd->MakeStartIndex( &pToSet->GetPoint()->nContent );
-        pToSet->GetPoint()->nContent = static_cast<const SwTextFrame*>(pContent)->GetOfst();
+        assert(pContent->IsTextFrame());
+        SwTextFrame const*const pFrame(static_cast<const SwTextFrame*>(pContent));
+        *pToSet->GetPoint() = pFrame->MapViewToModelPos(pFrame->GetOfst());
 
         SwShellCursor* pSCursor = dynamic_cast<SwShellCursor*>(pToSet);
         if( pSCursor )
@@ -1110,15 +1109,14 @@ bool GetFrameInPage( const SwContentFrame *pCnt, SwWhichPage fnWhichPage,
             }
         }
 
-        SwContentNode *pCNd = const_cast<SwContentNode*>(pCnt->GetNode());
-        pPam->GetPoint()->nNode = *pCNd;
-        sal_Int32 nIdx;
-        if( fnPosPage == GetFirstSub )
-            nIdx = static_cast<const SwTextFrame*>(pCnt)->GetOfst();
-        else
-            nIdx = pCnt->GetFollow() ?
-                    static_cast<const SwTextFrame*>(pCnt)->GetFollow()->GetOfst()-1 : pCNd->Len();
-        pPam->GetPoint()->nContent.Assign( pCNd, nIdx );
+        assert(pCnt->IsTextFrame());
+        SwTextFrame const*const pFrame(static_cast<const SwTextFrame*>(pCnt));
+        TextFrameIndex const nIdx((fnPosPage == GetFirstSub)
+            ? pFrame->GetOfst()
+            : (pFrame->GetFollow())
+                ? pFrame->GetFollow()->GetOfst() - TextFrameIndex(1)
+                : TextFrameIndex(pFrame->GetText().getLength()));
+        *pPam->GetPoint() = pFrame->MapViewToModelPos(nIdx);
         return true;
     }
 }
commit 38741ab5ef5fa4159c19998b1774ee85a104d5b5
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Wed May 9 18:39:09 2018 +0200

    sw_redlinehide: trivial conversions in softpagebreak.cxx
    
    Still a bit TODO here wrt. finding the frame from every node...
    
    Change-Id: Icff33d2fae3afee77c4329db0938b444f0e47537

diff --git a/sw/source/core/layout/softpagebreak.cxx b/sw/source/core/layout/softpagebreak.cxx
index 051364d935e4..109730e8cfa0 100644
--- a/sw/source/core/layout/softpagebreak.cxx
+++ b/sw/source/core/layout/softpagebreak.cxx
@@ -79,7 +79,11 @@ void SwTextNode::fillSoftPageBreakList( SwSoftPageBreakList& rBreak ) const
                         if( pFirst2 == pFrame )
                         {   // Here we are: a first content inside a cell
                             // inside the splitted row => soft page break
-                            rBreak.insert( pFrame->GetOfst() );
+                            auto const pos(pFrame->MapViewToModel(pFrame->GetOfst()));
+                            if (pos.first == this)
+                            {
+                                rBreak.insert(pos.second);
+                            }
                             break;
                         }
                         pCell = pCell->GetNext();
@@ -88,7 +92,14 @@ void SwTextNode::fillSoftPageBreakList( SwSoftPageBreakList& rBreak ) const
             }
             else // No soft page break if there's a "hard" page break attribute
             if( pFirst2 == pFrame && !pFrame->IsPageBreak( true ) )
-                rBreak.insert( pFrame->GetOfst() );
+            {
+                auto const pos(pFrame->MapViewToModel(pFrame->GetOfst()));
+                if (pos.first == this)
+                {   // in the !Show case, we have to iterate over the merged
+                    // SwTextFrame for every node
+                    rBreak.insert(pos.second);
+                }
+            }
         }
     }
 }
commit a55612323b2e208fe6cad79541afedbb23d9c158
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Wed May 9 18:38:03 2018 +0200

    sw_redlinehide: trivial conversions in layout/
    
    Change-Id: I5ce4590af52b3bfc08f89915999e86f4973fa9e3

diff --git a/sw/source/core/layout/anchoreddrawobject.cxx b/sw/source/core/layout/anchoreddrawobject.cxx
index aaf96027e7aa..0a4292638342 100644
--- a/sw/source/core/layout/anchoreddrawobject.cxx
+++ b/sw/source/core/layout/anchoreddrawobject.cxx
@@ -572,7 +572,7 @@ void SwAnchoredDrawObject::InvalidateObjPos()
                  (GetFrameFormat().GetAnchor().GetAnchorId() == RndStdIds::FLY_AS_CHAR) )
             {
                 SwTextFrame* pAnchorTextFrame( static_cast<SwTextFrame*>(AnchorFrame()) );
-                if (pAnchorTextFrame->CalcFlyPos(&GetFrameFormat()) != COMPLETE_STRING)
+                if (pAnchorTextFrame->CalcFlyPos(&GetFrameFormat()) != TextFrameIndex(COMPLETE_STRING))
                 {
                     AnchorFrame()->Prepare( PREP_FLY_ATTR_CHG, &GetFrameFormat() );
                 }
diff --git a/sw/source/core/layout/anchoredobject.cxx b/sw/source/core/layout/anchoredobject.cxx
index 0145389eab9e..5958f29085bc 100644
--- a/sw/source/core/layout/anchoredobject.cxx
+++ b/sw/source/core/layout/anchoredobject.cxx
@@ -545,7 +545,7 @@ bool SwAnchoredObject::HasClearedEnvironment() const
             const SwTextFrame* pTmpTextFrame = static_cast<const SwTextFrame*>(pTmpFrame);
             if ( pTmpTextFrame->IsUndersized() ||
                  ( pTmpTextFrame->GetFollow() &&

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list