[Libreoffice-commits] core.git: 209 commits - sw/inc sw/source

Michael Stahl Michael.Stahl at cib.de
Fri Jun 8 19:52:34 UTC 2018


 sw/inc/anchoredobject.hxx                                          |    3 
 sw/inc/calbck.hxx                                                  |  106 
 sw/inc/hints.hxx                                                   |   13 
 sw/inc/ndtxt.hxx                                                   |    3 
 sw/inc/node.hxx                                                    |   11 
 sw/inc/splargs.hxx                                                 |   10 
 sw/inc/swscanner.hxx                                               |   10 
 sw/source/core/access/acccontext.cxx                               |    7 
 sw/source/core/access/accembedded.cxx                              |    4 
 sw/source/core/access/accframebase.cxx                             |    5 
 sw/source/core/access/accmap.cxx                                   |    4 
 sw/source/core/access/accnotextframe.cxx                           |    5 
 sw/source/core/access/accpara.cxx                                  |    8 
 sw/source/core/access/accportions.cxx                              |    8 
 sw/source/core/access/accportions.hxx                              |    6 
 sw/source/core/access/parachangetrackinginfo.cxx                   |   22 
 sw/source/core/attr/calbck.cxx                                     |   56 
 sw/source/core/attr/hints.cxx                                      |    9 
 sw/source/core/crsr/callnk.cxx                                     |    5 
 sw/source/core/crsr/crstrvl.cxx                                    |   18 
 sw/source/core/crsr/swcrsr.cxx                                     |   51 
 sw/source/core/crsr/trvlfnfl.cxx                                   |    9 
 sw/source/core/doc/CntntIdxStore.cxx                               |    6 
 sw/source/core/doc/doc.cxx                                         |    5 
 sw/source/core/doc/docedt.cxx                                      |    2 
 sw/source/core/doc/docfld.cxx                                      |    6 
 sw/source/core/doc/docfly.cxx                                      |   22 
 sw/source/core/doc/doclay.cxx                                      |    6 
 sw/source/core/doc/docnum.cxx                                      |    7 
 sw/source/core/doc/docredln.cxx                                    |   12 
 sw/source/core/doc/doctxm.cxx                                      |    5 
 sw/source/core/docnode/ndtbl.cxx                                   |    8 
 sw/source/core/docnode/node.cxx                                    |    8 
 sw/source/core/docnode/node2lay.cxx                                |   12 
 sw/source/core/draw/dcontact.cxx                                   |   11 
 sw/source/core/draw/dflyobj.cxx                                    |    9 
 sw/source/core/draw/dview.cxx                                      |    7 
 sw/source/core/edit/edattr.cxx                                     |   57 
 sw/source/core/edit/editsh.cxx                                     |   32 
 sw/source/core/fields/docufld.cxx                                  |    5 
 sw/source/core/fields/expfld.cxx                                   |   14 
 sw/source/core/fields/postithelper.cxx                             |    2 
 sw/source/core/fields/reffld.cxx                                   |    9 
 sw/source/core/frmedt/fedesc.cxx                                   |    9 
 sw/source/core/frmedt/fefly1.cxx                                   |   55 
 sw/source/core/frmedt/feshview.cxx                                 |   88 
 sw/source/core/frmedt/fetab.cxx                                    |   10 
 sw/source/core/frmedt/fews.cxx                                     |   10 
 sw/source/core/inc/SwPortionHandler.hxx                            |   19 
 sw/source/core/inc/TextFrameIndex.hxx                              |   24 
 sw/source/core/inc/cntfrm.hxx                                      |   17 
 sw/source/core/inc/drawfont.hxx                                    |   59 
 sw/source/core/inc/flowfrm.hxx                                     |    6 
 sw/source/core/inc/flyfrm.hxx                                      |    3 
 sw/source/core/inc/fntcache.hxx                                    |    3 
 sw/source/core/inc/fntcap.hxx                                      |    9 
 sw/source/core/inc/frame.hxx                                       |   13 
 sw/source/core/inc/frminf.hxx                                      |    7 
 sw/source/core/inc/frmtool.hxx                                     |    6 
 sw/source/core/inc/notxtfrm.hxx                                    |    8 
 sw/source/core/inc/rootfrm.hxx                                     |    4 
 sw/source/core/inc/scriptinfo.hxx                                  |  122 -
 sw/source/core/inc/swfont.hxx                                      |   19 
 sw/source/core/inc/txtfly.hxx                                      |   14 
 sw/source/core/inc/txtfrm.hxx                                      |  221 +
 sw/source/core/inc/wrong.hxx                                       |   36 
 sw/source/core/layout/anchoreddrawobject.cxx                       |    3 
 sw/source/core/layout/anchoredobject.cxx                           |    7 
 sw/source/core/layout/atrfrm.cxx                                   |   15 
 sw/source/core/layout/calcmove.cxx                                 |   12 
 sw/source/core/layout/dbg_lay.cxx                                  |    2 
 sw/source/core/layout/findfrm.cxx                                  |   44 
 sw/source/core/layout/flowfrm.cxx                                  |   75 
 sw/source/core/layout/fly.cxx                                      |   22 
 sw/source/core/layout/flycnt.cxx                                   |   43 
 sw/source/core/layout/flylay.cxx                                   |    4 
 sw/source/core/layout/frmtool.cxx                                  |  230 +
 sw/source/core/layout/ftnfrm.cxx                                   |    4 
 sw/source/core/layout/hffrm.cxx                                    |    4 
 sw/source/core/layout/layact.cxx                                   |   61 
 sw/source/core/layout/laycache.cxx                                 |   14 
 sw/source/core/layout/movedfwdfrmsbyobjpos.cxx                     |   12 
 sw/source/core/layout/newfrm.cxx                                   |    3 
 sw/source/core/layout/objectformattertxtfrm.cxx                    |    4 
 sw/source/core/layout/pagechg.cxx                                  |   16 
 sw/source/core/layout/sectfrm.cxx                                  |    2 
 sw/source/core/layout/softpagebreak.cxx                            |   17 
 sw/source/core/layout/ssfrm.cxx                                    |   20 
 sw/source/core/layout/tabfrm.cxx                                   |   26 
 sw/source/core/layout/trvlfrm.cxx                                  |   90 
 sw/source/core/layout/wsfrm.cxx                                    |   92 
 sw/source/core/objectpositioning/anchoredobjectposition.cxx        |    7 
 sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx |    2 
 sw/source/core/text/EnhancedPDFExportHelper.cxx                    |   31 
 sw/source/core/text/atrhndl.hxx                                    |    2 
 sw/source/core/text/frmcrsr.cxx                                    |  196 -
 sw/source/core/text/frmform.cxx                                    |  196 -
 sw/source/core/text/frminf.cxx                                     |   59 
 sw/source/core/text/frmpaint.cxx                                   |   48 
 sw/source/core/text/guess.cxx                                      |  145 -
 sw/source/core/text/guess.hxx                                      |   18 
 sw/source/core/text/inftxt.cxx                                     |  264 +-
 sw/source/core/text/inftxt.hxx                                     |  141 -
 sw/source/core/text/itradj.cxx                                     |   73 
 sw/source/core/text/itratr.cxx                                     |  512 +++-
 sw/source/core/text/itratr.hxx                                     |   46 
 sw/source/core/text/itrcrsr.cxx                                    |  100 
 sw/source/core/text/itrform2.cxx                                   |  186 -
 sw/source/core/text/itrform2.hxx                                   |   16 
 sw/source/core/text/itrpaint.cxx                                   |   90 
 sw/source/core/text/itrpaint.hxx                                   |    2 
 sw/source/core/text/itrtxt.cxx                                     |   36 
 sw/source/core/text/itrtxt.hxx                                     |   32 
 sw/source/core/text/pordrop.hxx                                    |    8 
 sw/source/core/text/porexp.cxx                                     |   22 
 sw/source/core/text/porexp.hxx                                     |    6 
 sw/source/core/text/porfld.cxx                                     |   81 
 sw/source/core/text/porfld.hxx                                     |   12 
 sw/source/core/text/porfly.cxx                                     |   39 
 sw/source/core/text/porftn.hxx                                     |    2 
 sw/source/core/text/porglue.cxx                                    |   27 
 sw/source/core/text/porglue.hxx                                    |    2 
 sw/source/core/text/porlay.cxx                                     |  426 ++-
 sw/source/core/text/porlay.hxx                                     |   25 
 sw/source/core/text/porlin.cxx                                     |    4 
 sw/source/core/text/porlin.hxx                                     |   10 
 sw/source/core/text/pormulti.cxx                                   |  595 +++--
 sw/source/core/text/pormulti.hxx                                   |   38 
 sw/source/core/text/porref.cxx                                     |    2 
 sw/source/core/text/porrst.cxx                                     |   39 
 sw/source/core/text/porrst.hxx                                     |   16 
 sw/source/core/text/portab.hxx                                     |    4 
 sw/source/core/text/portox.cxx                                     |    2 
 sw/source/core/text/portxt.cxx                                     |  138 -
 sw/source/core/text/portxt.hxx                                     |    4 
 sw/source/core/text/redlnitr.cxx                                   |  374 ++-
 sw/source/core/text/redlnitr.hxx                                   |   64 
 sw/source/core/text/txtdrop.cxx                                    |  108 
 sw/source/core/text/txtfld.cxx                                     |  121 -
 sw/source/core/text/txtfly.cxx                                     |  161 -
 sw/source/core/text/txtfrm.cxx                                     | 1163 ++++++++--
 sw/source/core/text/txtftn.cxx                                     |  309 +-
 sw/source/core/text/txthyph.cxx                                    |   70 
 sw/source/core/text/txttab.cxx                                     |   34 
 sw/source/core/text/widorp.cxx                                     |   10 
 sw/source/core/text/wrong.cxx                                      |  195 +
 sw/source/core/text/xmldump.cxx                                    |   30 
 sw/source/core/txtnode/atrftn.cxx                                  |    4 
 sw/source/core/txtnode/fntcache.cxx                                |  360 +--
 sw/source/core/txtnode/fntcap.cxx                                  |  132 -
 sw/source/core/txtnode/ndtxt.cxx                                   |   26 
 sw/source/core/txtnode/swfont.cxx                                  |  102 
 sw/source/core/txtnode/txtedt.cxx                                  |  111 
 sw/source/core/unocore/unoflatpara.cxx                             |   49 
 sw/source/uibase/docvw/PageBreakWin.cxx                            |   15 
 sw/source/uibase/uiview/view2.cxx                                  |   11 
 sw/source/uibase/uiview/viewling.cxx                               |    3 
 157 files changed, 6266 insertions(+), 3092 deletions(-)

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

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

diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index a25bb8d7bb9f..cdce7870a536 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -4171,6 +4171,53 @@ 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, sw::IteratorMode::UnwrapMulti> aIter(rTextNode);
+            std::vector<SwTextFrame*> frames;
+            for (SwTextFrame * pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
+            {
+                if (pFrame->getRootFrame() == this)
+                {
+                    frames.push_back(pFrame);
+                }
+            }
+            // this messes with pRegisteredIn so do it outside SwIterator
+            for (SwTextFrame * pFrame : frames)
+            {
+                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 4216fbc7503f1bb95d9a27d6195cec239eb47576
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Thu Jun 7 19:36:06 2018 +0200

    sw_redlinehide: trivial conversions in lcl_DrawLineForWrongListData
    
    Change-Id: I7425bac439df7518b7fe1b62cd6f3fd7a9f88fec

diff --git a/sw/source/core/txtnode/fntcache.cxx b/sw/source/core/txtnode/fntcache.cxx
index ed1b86f36218..a0a38aa94364 100644
--- a/sw/source/core/txtnode/fntcache.cxx
+++ b/sw/source/core/txtnode/fntcache.cxx
@@ -639,7 +639,7 @@ static bool lcl_IsFullstopCentered( const vcl::RenderContext& rOut )
 /* This helper structure (SwForbidden) contains the already marked parts of the string
     to avoid double lines (e.g grammar + spell check error) */
 
-typedef std::vector< std::pair< sal_Int32, sal_Int32 > > SwForbidden;
+typedef std::vector<std::pair<TextFrameIndex, TextFrameIndex>> SwForbidden;
 
 static void lcl_DrawLineForWrongListData(
     SwForbidden &rForbidden,
@@ -679,23 +679,20 @@ static void lcl_DrawLineForWrongListData(
     {
         nStart -= rInf.GetIdx();
 
-        const sal_Int32 nEnd = nStart + nWrLen;
-        sal_Int32 nNext = nStart;
+        const TextFrameIndex nEnd = nStart + nWrLen;
+        TextFrameIndex nNext = nStart;
         while( nNext < nEnd )
         {
             while( pIter != rForbidden.end() && pIter->second <= nNext )
                 ++pIter;
 
-            const sal_Int32 nNextStart = nNext;
-            sal_Int32 nNextEnd = nEnd;
+            const TextFrameIndex nNextStart = nNext;
+            TextFrameIndex nNextEnd = nEnd;
 
             if( pIter == rForbidden.end() || nNextEnd <= pIter->first )
             {
                 // No overlapping mark up found
-                std::pair< sal_Int32, sal_Int32 > aNew;
-                aNew.first = nNextStart;
-                aNew.second = nNextEnd;
-                rForbidden.insert( pIter, aNew );
+                rForbidden.insert(pIter, std::make_pair(nNextStart, nNextEnd));
                 pIter = rForbidden.begin();
                 nNext = nEnd;
             }
commit ab1b2a0d6243f03849b7ac80962d08760ada6418
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Thu Jun 7 17:37:00 2018 +0200

    sw_redlinehide: use WrongListIterator in text formatting code
    
    Change-Id: Ie13119d456fa6fe3919871cc541a9ad927b5982e

diff --git a/sw/source/core/inc/drawfont.hxx b/sw/source/core/inc/drawfont.hxx
index f484e56546c9..8cfa4b720082 100644
--- a/sw/source/core/inc/drawfont.hxx
+++ b/sw/source/core/inc/drawfont.hxx
@@ -30,7 +30,7 @@ class SwTextFrame;
 class SwViewShell;
 class SwScriptInfo;
 class Point;
-class SwWrongList;
+namespace sw { class WrongListIterator; }
 class Size;
 class SwFont;
 namespace vcl {
@@ -50,9 +50,9 @@ class SW_DLLPUBLIC SwDrawTextInfo
     Point m_aPos;
     vcl::TextLayoutCache const* m_pCachedVclData;
     OUString m_aText;
-    const SwWrongList* m_pWrong;
-    const SwWrongList* m_pGrammarCheck;
-    const SwWrongList* m_pSmartTags;
+    sw::WrongListIterator* m_pWrong;
+    sw::WrongListIterator* m_pGrammarCheck;
+    sw::WrongListIterator* m_pSmartTags;
     Size m_aSize;
     SwFont *m_pFnt;
     SwUnderlineFont* m_pUnderFnt;
@@ -220,7 +220,7 @@ public:
         return m_aText;
     }
 
-    const SwWrongList* GetWrong() const
+    sw::WrongListIterator* GetWrong() const
     {
 #ifdef DBG_UTIL
         OSL_ENSURE( m_bWrong, "DrawTextInfo: Undefined WrongList" );
@@ -228,7 +228,7 @@ public:
         return m_pWrong;
     }
 
-    const SwWrongList* GetGrammarCheck() const
+    sw::WrongListIterator* GetGrammarCheck() const
     {
 #ifdef DBG_UTIL
         OSL_ENSURE( m_bGrammarCheck, "DrawTextInfo: Undefined GrammarCheck List" );
@@ -236,7 +236,7 @@ public:
         return m_pGrammarCheck;
     }
 
-    const SwWrongList* GetSmartTags() const
+    sw::WrongListIterator* GetSmartTags() const
     {
         return m_pSmartTags;
     }
@@ -418,7 +418,7 @@ public:
         m_pCachedVclData = nullptr; // would any case benefit from save/restore?
     }
 
-    void SetWrong( const SwWrongList* pNew )
+    void SetWrong(sw::WrongListIterator *const pNew)
     {
         m_pWrong = pNew;
 #ifdef DBG_UTIL
@@ -426,7 +426,7 @@ public:
 #endif
     }
 
-    void SetGrammarCheck( const SwWrongList* pNew )
+    void SetGrammarCheck(sw::WrongListIterator *const pNew)
     {
         m_pGrammarCheck = pNew;
 #ifdef DBG_UTIL
@@ -434,7 +434,7 @@ public:
 #endif
     }
 
-    void SetSmartTags( const SwWrongList* pNew )
+    void SetSmartTags(sw::WrongListIterator *const pNew)
     {
         m_pSmartTags = pNew;
     }
diff --git a/sw/source/core/text/frmpaint.cxx b/sw/source/core/text/frmpaint.cxx
index 217615337e37..5cbc6dbd38c5 100644
--- a/sw/source/core/text/frmpaint.cxx
+++ b/sw/source/core/text/frmpaint.cxx
@@ -45,6 +45,7 @@
 #include <tabfrm.hxx>
 #include <numrule.hxx>
 #include <SwGrammarMarkUp.hxx>
+#include <wrong.hxx>
 
 #include <EnhancedPDFExportHelper.hxx>
 
@@ -651,9 +652,21 @@ void SwTextFrame::PaintSwFrame(vcl::RenderContext& rRenderContext, SwRect const&
             SwitchRTLtoLTR( const_cast<SwRect&>(rRect) );
 
         SwTextPaintInfo aInf( const_cast<SwTextFrame*>(this), rRect );
-        aInf.SetWrongList( const_cast<SwTextNode*>(GetTextNode())->GetWrong() );
-        aInf.SetGrammarCheckList( const_cast<SwTextNode*>(GetTextNode())->GetGrammarCheck() );
-        aInf.SetSmartTags( const_cast<SwTextNode*>(GetTextNode())->GetSmartTags() );
+        sw::WrongListIterator iterWrong(*this, &SwTextNode::GetWrong);
+        sw::WrongListIterator iterGrammar(*this, &SwTextNode::GetGrammarCheck);
+        sw::WrongListIterator iterSmartTags(*this, &SwTextNode::GetSmartTags);
+        if (iterWrong.LooksUseful())
+        {
+            aInf.SetWrongList( &iterWrong );
+        }
+        if (iterGrammar.LooksUseful())
+        {
+            aInf.SetGrammarCheckList( &iterGrammar );
+        }
+        if (iterSmartTags.LooksUseful())
+        {
+            aInf.SetSmartTags( &iterSmartTags );
+        }
         aInf.GetTextFly().SetTopRule();
 
         SwTextPainter  aLine( const_cast<SwTextFrame*>(this), &aInf );
diff --git a/sw/source/core/text/inftxt.cxx b/sw/source/core/text/inftxt.cxx
index a0e7c1c06131..9a29d58d0b19 100644
--- a/sw/source/core/text/inftxt.cxx
+++ b/sw/source/core/text/inftxt.cxx
@@ -487,18 +487,18 @@ void SwTextPaintInfo::CtorInitTextPaintInfo( OutputDevice* pRenderContext, SwTex
     aPaintRect = rPaint;
     nSpaceIdx = 0;
     pSpaceAdd = nullptr;
-    pWrongList = nullptr;
-    pGrammarCheckList = nullptr;
-    pSmartTags = nullptr;
+    m_pWrongList = nullptr;
+    m_pGrammarCheckList = nullptr;
+    m_pSmartTags = nullptr;
     pBrushItem = nullptr;
 }
 
 SwTextPaintInfo::SwTextPaintInfo( const SwTextPaintInfo &rInf, const OUString* pText )
-    : SwTextSizeInfo( rInf, pText ),
-      pWrongList( rInf.GetpWrongList() ),
-      pGrammarCheckList( rInf.GetGrammarCheckList() ),
-      pSmartTags( rInf.GetSmartTags() ),
-      pSpaceAdd( rInf.GetpSpaceAdd() ),
+    : SwTextSizeInfo( rInf, pText )
+    , m_pWrongList( rInf.GetpWrongList() )
+    , m_pGrammarCheckList( rInf.GetGrammarCheckList() )
+    , m_pSmartTags( rInf.GetSmartTags() )
+    , pSpaceAdd( rInf.GetpSpaceAdd() ),
       pBrushItem( rInf.GetBrushItem() ),
       aTextFly( rInf.GetTextFly() ),
       aPos( rInf.GetPos() ),
@@ -507,11 +507,11 @@ SwTextPaintInfo::SwTextPaintInfo( const SwTextPaintInfo &rInf, const OUString* p
 { }
 
 SwTextPaintInfo::SwTextPaintInfo( const SwTextPaintInfo &rInf )
-    : SwTextSizeInfo( rInf ),
-      pWrongList( rInf.GetpWrongList() ),
-      pGrammarCheckList( rInf.GetGrammarCheckList() ),
-      pSmartTags( rInf.GetSmartTags() ),
-      pSpaceAdd( rInf.GetpSpaceAdd() ),
+    : SwTextSizeInfo( rInf )
+    , m_pWrongList( rInf.GetpWrongList() )
+    , m_pGrammarCheckList( rInf.GetGrammarCheckList() )
+    , m_pSmartTags( rInf.GetSmartTags() )
+    , pSpaceAdd( rInf.GetpSpaceAdd() ),
       pBrushItem( rInf.GetBrushItem() ),
       aTextFly( rInf.GetTextFly() ),
       aPos( rInf.GetPos() ),
@@ -693,9 +693,9 @@ void SwTextPaintInfo::DrawText_( const OUString &rText, const SwLinePortion &rPo
         aDrawInf.SetSize( aSize );
         aDrawInf.SetAscent( rPor.GetAscent() );
         aDrawInf.SetKern( bKern ? rPor.Width() : 0 );
-        aDrawInf.SetWrong( bTmpWrong ? pWrongList : nullptr );
-        aDrawInf.SetGrammarCheck( bTmpGrammarCheck ? pGrammarCheckList : nullptr );
-        aDrawInf.SetSmartTags( bTmpSmart ? pSmartTags : nullptr );
+        aDrawInf.SetWrong( bTmpWrong ? m_pWrongList : nullptr );
+        aDrawInf.SetGrammarCheck( bTmpGrammarCheck ? m_pGrammarCheckList : nullptr );
+        aDrawInf.SetSmartTags( bTmpSmart ? m_pSmartTags : nullptr );
         GetTextFly().DrawTextOpaque( aDrawInf );
     }
     else
@@ -705,9 +705,9 @@ void SwTextPaintInfo::DrawText_( const OUString &rText, const SwLinePortion &rPo
             m_pFnt->DrawStretchText_( aDrawInf );
         else
         {
-            aDrawInf.SetWrong( bTmpWrong ? pWrongList : nullptr );
-            aDrawInf.SetGrammarCheck( bTmpGrammarCheck ? pGrammarCheckList : nullptr );
-            aDrawInf.SetSmartTags( bTmpSmart ? pSmartTags : nullptr );
+            aDrawInf.SetWrong( bTmpWrong ? m_pWrongList : nullptr );
+            aDrawInf.SetGrammarCheck( bTmpGrammarCheck ? m_pGrammarCheckList : nullptr );
+            aDrawInf.SetSmartTags( bTmpSmart ? m_pSmartTags : nullptr );
             m_pFnt->DrawText_( aDrawInf );
         }
     }
@@ -1718,9 +1718,8 @@ SwTextSlot::SwTextSlot(
     bool bExgLists,
     OUString const & rCh )
     : pOldText(nullptr)
-    , pOldSmartTagList(nullptr)
-    , pOldGrammarCheckList(nullptr)
-    , pTempList(nullptr)
+    , m_pOldSmartTagList(nullptr)
+    , m_pOldGrammarCheckList(nullptr)
     , nIdx(0)
     , nLen(0)
     , pInf(nullptr)
@@ -1751,37 +1750,63 @@ SwTextSlot::SwTextSlot(
         // ST2
         if ( bExgLists )
         {
-            pOldSmartTagList = static_cast<SwTextPaintInfo*>(pInf)->GetSmartTags();
-            if ( pOldSmartTagList )
+            m_pOldSmartTagList = static_cast<SwTextPaintInfo*>(pInf)->GetSmartTags();
+            if (m_pOldSmartTagList)
             {
-                const sal_uInt16 nPos = pOldSmartTagList->GetWrongPos(nIdx);
-                const sal_Int32 nListPos = pOldSmartTagList->Pos(nPos);
-                if( nListPos == nIdx )
-                    static_cast<SwTextPaintInfo*>(pInf)->SetSmartTags( pOldSmartTagList->SubList( nPos ) );
-                else if( !pTempList && nPos < pOldSmartTagList->Count() && nListPos < nIdx && !aText.isEmpty() )
+                std::pair<SwTextNode const*, sal_Int32> pos(pNew->GetTextFrame()->MapViewToModel(nIdx));
+                SwWrongList const*const pSmartTags(pos.first->GetSmartTags());
+                assert(m_pOldSmartTagList->MergedOrSame(pSmartTags));
+                if (pSmartTags)
                 {
-                    pTempList = new SwWrongList( WRONGLIST_SMARTTAG );
-                    pTempList->Insert( OUString(), nullptr, 0, aText.getLength(), 0 );
-                    static_cast<SwTextPaintInfo*>(pInf)->SetSmartTags( pTempList );
+                    const sal_uInt16 nPos = pSmartTags->GetWrongPos(pos.second);
+                    const sal_Int32 nListPos = pSmartTags->Pos(nPos);
+                    if (nListPos == pos.second)
+                    {
+                        m_pTempIter.reset(new sw::WrongListIterator(*pSmartTags->SubList(nPos)));
+                        static_cast<SwTextPaintInfo*>(pInf)->SetSmartTags(m_pTempIter.get());
+                    }
+                    else if (!m_pTempList && nPos < pSmartTags->Count()
+                                && nListPos < pos.second && !aText.isEmpty())
+                    {
+                        m_pTempList.reset(new SwWrongList( WRONGLIST_SMARTTAG ));
+                        m_pTempList->Insert( OUString(), nullptr, 0, aText.getLength(), 0 );
+                        m_pTempIter.reset(new sw::WrongListIterator(*m_pTempList));
+                        static_cast<SwTextPaintInfo*>(pInf)->SetSmartTags(m_pTempIter.get());
+                    }
+                    else
+                        static_cast<SwTextPaintInfo*>(pInf)->SetSmartTags(nullptr);
                 }
                 else
-                    static_cast<SwTextPaintInfo*>(pInf)->SetSmartTags( nullptr);
+                    static_cast<SwTextPaintInfo*>(pInf)->SetSmartTags(nullptr);
             }
-            pOldGrammarCheckList = static_cast<SwTextPaintInfo*>(pInf)->GetGrammarCheckList();
-            if ( pOldGrammarCheckList )
+            m_pOldGrammarCheckList = static_cast<SwTextPaintInfo*>(pInf)->GetGrammarCheckList();
+            if (m_pOldGrammarCheckList)
             {
-                const sal_uInt16 nPos = pOldGrammarCheckList->GetWrongPos(nIdx);
-                const sal_Int32 nListPos = pOldGrammarCheckList->Pos(nPos);
-                if( nListPos == nIdx )
-                    static_cast<SwTextPaintInfo*>(pInf)->SetGrammarCheckList( pOldGrammarCheckList->SubList( nPos ) );
-                else if( !pTempList && nPos < pOldGrammarCheckList->Count() && nListPos < nIdx && !aText.isEmpty() )
+                std::pair<SwTextNode const*, sal_Int32> pos(pNew->GetTextFrame()->MapViewToModel(nIdx));
+                SwWrongList const*const pGrammar(pos.first->GetGrammarCheck());
+                assert(m_pOldGrammarCheckList->MergedOrSame(pGrammar));
+                if (pGrammar)
                 {
-                    pTempList = new SwWrongList( WRONGLIST_GRAMMAR );
-                    pTempList->Insert( OUString(), nullptr, 0, aText.getLength(), 0 );
-                    static_cast<SwTextPaintInfo*>(pInf)->SetGrammarCheckList( pTempList );
+                    const sal_uInt16 nPos = pGrammar->GetWrongPos(pos.second);
+                    const sal_Int32 nListPos = pGrammar->Pos(nPos);
+                    if (nListPos == pos.second)
+                    {
+                        m_pTempIter.reset(new sw::WrongListIterator(*pGrammar->SubList(nPos)));
+                        static_cast<SwTextPaintInfo*>(pInf)->SetGrammarCheckList(m_pTempIter.get());
+                    }
+                    else if (!m_pTempList && nPos < pGrammar->Count()
+                                && nListPos < pos.second && !aText.isEmpty())
+                    {
+                        m_pTempList.reset(new SwWrongList( WRONGLIST_GRAMMAR ));
+                        m_pTempList->Insert( OUString(), nullptr, 0, aText.getLength(), 0 );
+                        m_pTempIter.reset(new sw::WrongListIterator(*m_pTempList));
+                        static_cast<SwTextPaintInfo*>(pInf)->SetGrammarCheckList(m_pTempIter.get());
+                    }
+                    else
+                        static_cast<SwTextPaintInfo*>(pInf)->SetGrammarCheckList(nullptr);
                 }
                 else
-                    static_cast<SwTextPaintInfo*>(pInf)->SetGrammarCheckList( nullptr);
+                    static_cast<SwTextPaintInfo*>(pInf)->SetGrammarCheckList(nullptr);
             }
         }
     }
@@ -1798,11 +1823,10 @@ SwTextSlot::~SwTextSlot()
 
         // ST2
         // Restore old smart tag list
-        if ( pOldSmartTagList )
-            static_cast<SwTextPaintInfo*>(pInf)->SetSmartTags( pOldSmartTagList );
-        if ( pOldGrammarCheckList )
-            static_cast<SwTextPaintInfo*>(pInf)->SetGrammarCheckList( pOldGrammarCheckList );
-        delete pTempList;
+        if (m_pOldSmartTagList)
+            static_cast<SwTextPaintInfo*>(pInf)->SetSmartTags(m_pOldSmartTagList);
+        if (m_pOldGrammarCheckList)
+            static_cast<SwTextPaintInfo*>(pInf)->SetGrammarCheckList(m_pOldGrammarCheckList);
     }
 }
 
diff --git a/sw/source/core/text/inftxt.hxx b/sw/source/core/text/inftxt.hxx
index 40bf57ebcebb..1156e1197c14 100644
--- a/sw/source/core/text/inftxt.hxx
+++ b/sw/source/core/text/inftxt.hxx
@@ -55,7 +55,7 @@ class SwViewShell;
 class SwAttrIter;
 struct SwMultiCreator;
 class SwMultiPortion;
-class SwWrongList;
+namespace sw { class WrongListIterator; }
 
 #define ARROW_WIDTH 200
 #define DIR_LEFT2RIGHT 0
@@ -351,9 +351,9 @@ public:
 
 class SwTextPaintInfo : public SwTextSizeInfo
 {
-    const SwWrongList *pWrongList;
-    const SwWrongList *pGrammarCheckList;
-    const SwWrongList *pSmartTags;
+    sw::WrongListIterator *m_pWrongList;
+    sw::WrongListIterator *m_pGrammarCheckList;
+    sw::WrongListIterator *m_pSmartTags;
     std::vector<long>* pSpaceAdd;
     const SvxBrushItem *pBrushItem; // For the background
     SwTextFly    aTextFly;    // Calculate the FlyFrame
@@ -371,9 +371,9 @@ class SwTextPaintInfo : public SwTextSizeInfo
 
 protected:
     SwTextPaintInfo()
-        : pWrongList(nullptr)
-        , pGrammarCheckList(nullptr)
-        , pSmartTags(nullptr)
+        : m_pWrongList(nullptr)
+        , m_pGrammarCheckList(nullptr)
+        , m_pSmartTags(nullptr)
         , pSpaceAdd(nullptr)
         , pBrushItem(nullptr)
         , nSpaceIdx(0)
@@ -458,14 +458,14 @@ public:
     void SetpSpaceAdd( std::vector<long>* pNew ){ pSpaceAdd = pNew; }
     std::vector<long>* GetpSpaceAdd() const { return pSpaceAdd; }
 
-    void SetWrongList( const SwWrongList *pNew ){ pWrongList = pNew; }
-    const SwWrongList* GetpWrongList() const { return pWrongList; }
+    void SetWrongList(sw::WrongListIterator *const pNew) { m_pWrongList = pNew; }
+    sw::WrongListIterator* GetpWrongList() const { return m_pWrongList; }
 
-    void SetGrammarCheckList( const SwWrongList *pNew ){ pGrammarCheckList = pNew; }
-    const SwWrongList* GetGrammarCheckList() const { return pGrammarCheckList; }
+    void SetGrammarCheckList(sw::WrongListIterator *const pNew) { m_pGrammarCheckList = pNew; }
+    sw::WrongListIterator* GetGrammarCheckList() const { return m_pGrammarCheckList; }
 
-    void SetSmartTags( const SwWrongList *pNew ){ pSmartTags = pNew; }
-    const SwWrongList* GetSmartTags() const { return pSmartTags; }
+    void SetSmartTags(sw::WrongListIterator *const pNew) { m_pSmartTags = pNew; }
+    sw::WrongListIterator* GetSmartTags() const { return m_pSmartTags; }
 };
 
 class SwTextFormatInfo : public SwTextPaintInfo
@@ -683,9 +683,10 @@ class SwTextSlot final
     OUString aText;
     std::shared_ptr<vcl::TextLayoutCache> m_pOldCachedVclData;
     const OUString *pOldText;
-    const SwWrongList* pOldSmartTagList;
-    const SwWrongList* pOldGrammarCheckList;
-    SwWrongList* pTempList;
+    sw::WrongListIterator * m_pOldSmartTagList;
+    sw::WrongListIterator * m_pOldGrammarCheckList;
+    std::unique_ptr<SwWrongList> m_pTempList;
+    std::unique_ptr<sw::WrongListIterator> m_pTempIter;
     TextFrameIndex nIdx;
     TextFrameIndex nLen;
     bool bOn;
diff --git a/sw/source/core/text/portxt.cxx b/sw/source/core/text/portxt.cxx
index 8256d458357e..69593f8d157c 100644
--- a/sw/source/core/text/portxt.cxx
+++ b/sw/source/core/text/portxt.cxx
@@ -550,9 +550,9 @@ void SwTextPortion::Paint( const SwTextPaintInfo &rInf ) const
         if( rInf.OnWin() && pPortion && !pPortion->Width() )
             pPortion->PrePaint( rInf, this );
 
-        const SwWrongList *pWrongList = rInf.GetpWrongList();
-        const SwWrongList *pGrammarCheckList = rInf.GetGrammarCheckList();
-        const SwWrongList *pSmarttags = rInf.GetSmartTags();
+        auto const* pWrongList = rInf.GetpWrongList();
+        auto const* pGrammarCheckList = rInf.GetGrammarCheckList();
+        auto const* pSmarttags = rInf.GetSmartTags();
 
         const bool bWrong = nullptr != pWrongList;
         const bool bGrammarCheck = nullptr != pGrammarCheckList;
diff --git a/sw/source/core/txtnode/fntcache.cxx b/sw/source/core/txtnode/fntcache.cxx
index c45b14086a2a..ed1b86f36218 100644
--- a/sw/source/core/txtnode/fntcache.cxx
+++ b/sw/source/core/txtnode/fntcache.cxx
@@ -644,7 +644,7 @@ typedef std::vector< std::pair< sal_Int32, sal_Int32 > > SwForbidden;
 static void lcl_DrawLineForWrongListData(
     SwForbidden &rForbidden,
     const SwDrawTextInfo    &rInf,
-    const SwWrongList       *pWList,
+    sw::WrongListIterator *pWList,
     const CalcLinePosData   &rCalcLinePosData,
     const Size              &rPrtFontSize )
 {
@@ -715,10 +715,7 @@ static void lcl_DrawLineForWrongListData(
             Point aEnd;
             lcl_calcLinePos( rCalcLinePosData, aStart, aEnd, nNextStart, nNextEnd - nNextStart );
 
-            const sal_uInt16 wrongPos = pWList->GetWrongPos(nNextStart + rInf.GetIdx());
-
-            const SwWrongArea* wrongArea = pWList->GetElement(wrongPos);
-
+            SwWrongArea const*const wrongArea = pWList->GetWrongElement(nNextStart + rInf.GetIdx());
             if (wrongArea != nullptr)
             {
                 if (WRONGAREA_DASHED == wrongArea->mLineType)
commit 6feeb066375e6b330e2ce9b3fdbfff6ef3cfdc15
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Thu Jun 7 17:37:52 2018 +0200

    sw_redlinehide: Add sw::WrongListIterator
    
    The simplest way to deal with the problem that wrong-lists are on the
    SwTextNode is to just take them as-is and iterate over them in a merged
    SwTextFrame.  This may give results that users may disapprove of, but
    i'm not sure how likely it is in practice to e.g. start a delete redline
    in the middle of a word and end it in another paragraph.
    
    Perhaps it would be better to move the SwWrongLists to the SwTextFrame,
    but that is probably more work.
    
    Also add missing SwTextNode function overloads for "const", so we don't
    need mutable SwTextNodes.
    
    Change-Id: I9742e3793abe090cf58ad3f27b51e89be86a1964

diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx
index 894f8c078635..d1a8801eb9c7 100644
--- a/sw/inc/ndtxt.hxx
+++ b/sw/inc/ndtxt.hxx
@@ -194,8 +194,11 @@ public:
     const SwWrongList* GetWrong() const;
     void SetGrammarCheck( SwGrammarMarkUp* pNew, bool bDelete = true );
     SwGrammarMarkUp* GetGrammarCheck();
+    // return SwWrongList because *function pointer* return values aren't covariant
+    SwWrongList const* GetGrammarCheck() const;
     void SetSmartTags( SwWrongList* pNew, bool bDelete = true );
     SwWrongList* GetSmartTags();
+    SwWrongList const* GetSmartTags() const;
     void TryCharSetExpandToNum(const SfxItemSet& pCharSet);
 
     /// End: Data collected during idle time
diff --git a/sw/source/core/inc/wrong.hxx b/sw/source/core/inc/wrong.hxx
index 0aa575434483..831c5bb7f99a 100644
--- a/sw/source/core/inc/wrong.hxx
+++ b/sw/source/core/inc/wrong.hxx
@@ -32,6 +32,7 @@
 #include <tools/color.hxx>
 #include <swtypes.hxx>
 #include <viewopt.hxx>
+#include "TextFrameIndex.hxx"
 
 class SwWrongList;
 
@@ -331,6 +332,41 @@ public:
     bool LookForEntry( sal_Int32 nBegin, sal_Int32 nEnd );
 };
 
+class SwTextNode;
+class SwTextFrame;
+
+namespace sw {
+
+struct MergedPara;
+
+class WrongListIterator
+{
+private:
+    SwWrongList const* (SwTextNode::*const m_pGetWrongList)() const;
+    sw::MergedPara const*const m_pMergedPara;
+    size_t m_CurrentExtent;
+    TextFrameIndex m_CurrentIndex;
+    TextFrameIndex m_CurrentNodeIndex;
+    SwWrongList const*const m_pWrongList;
+
+public:
+    /// for the text frame
+    WrongListIterator(SwTextFrame const& rFrame,
+        SwWrongList const* (SwTextNode::*pGetWrongList)() const);
+    /// for SwTextSlot
+    WrongListIterator(SwWrongList const& rWrongList);
+
+    bool Check(TextFrameIndex &rStart, TextFrameIndex &rLen);
+    const SwWrongArea* GetWrongElement(TextFrameIndex nStart);
+
+    bool LooksUseful() { return m_pMergedPara || m_pWrongList; }
+    bool MergedOrSame(SwWrongList const*const pList) const {
+        return m_pMergedPara || m_pWrongList == pList;
+    }
+};
+
+} // namespace sw
+
 #endif
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/text/wrong.cxx b/sw/source/core/text/wrong.cxx
index 20fdac821985..bdad843a43f8 100644
--- a/sw/source/core/text/wrong.cxx
+++ b/sw/source/core/text/wrong.cxx
@@ -20,6 +20,9 @@
 #include <swtypes.hxx>
 
 #include <SwGrammarMarkUp.hxx>
+#include <ndtxt.hxx>
+#include <txtfrm.hxx>
+
 #include <osl/diagnose.h>
 
 SwWrongArea::SwWrongArea( const OUString& rType, WrongListType listType,
@@ -659,4 +662,196 @@ void SwWrongList::Insert( const OUString& rType,
     maList.insert(aIter, SwWrongArea( rType, meType, xPropertyBag, nNewPos, nNewLen) );
 }
 
+namespace sw {
+
+WrongListIterator::WrongListIterator(SwTextFrame const& rFrame,
+        SwWrongList const* (SwTextNode::*pGetWrongList)() const)
+    : m_pGetWrongList(pGetWrongList)
+    , m_pMergedPara(rFrame.GetMergedPara())
+    , m_CurrentExtent(0)
+    , m_CurrentIndex(0)
+    , m_CurrentNodeIndex(0)
+    , m_pWrongList(m_pMergedPara
+                    ? nullptr
+                    : (rFrame.GetTextNodeFirst()->*pGetWrongList)())
+{
+}
+
+WrongListIterator::WrongListIterator(SwWrongList const& rWrongList)
+    : m_pGetWrongList(nullptr)
+    , m_pMergedPara(nullptr)
+    , m_CurrentExtent(0)
+    , m_CurrentIndex(0)
+    , m_CurrentNodeIndex(0)
+    , m_pWrongList(&rWrongList)
+{
+}
+
+bool WrongListIterator::Check(TextFrameIndex & rStart, TextFrameIndex & rLen)
+{
+    if (m_pMergedPara)
+    {
+        if (rStart < m_CurrentIndex)
+        {   // rewind
+            m_CurrentExtent = 0;
+            m_CurrentIndex = TextFrameIndex(0);
+            m_CurrentNodeIndex = TextFrameIndex(0);
+        }
+        while (m_CurrentExtent < m_pMergedPara->extents.size())
+        {
+            sw::Extent const& rExtent(m_pMergedPara->extents[m_CurrentExtent]);
+            if (rStart + rLen <= m_CurrentIndex)
+            {
+                return false;
+            }
+            else if (rStart < m_CurrentIndex)
+            {
+                rLen -= (m_CurrentIndex - rStart);
+                assert(0 < sal_Int32(rLen));
+                rStart = m_CurrentIndex;
+            }
+            if (m_CurrentIndex <= rStart &&
+                rStart < m_CurrentIndex + TextFrameIndex(rExtent.nEnd - rExtent.nStart))
+            {
+                SwWrongList const*const pWrongList((rExtent.pNode->*m_pGetWrongList)());
+                // found the extent containing start - first, call Check
+                sal_Int32 nStart(rExtent.nStart + sal_Int32(rStart - m_CurrentIndex)); // (m_CurrentIndex - m_CurrentNodeIndex));
+                sal_Int32 nLen;
+                if (sal_Int32(rLen) < rExtent.nEnd - nStart)
+                {
+                    nLen = sal_Int32(rLen);
+                }
+                else
+                {
+                    sal_Int32 nInLen(rLen);
+                    nLen = rExtent.nEnd - nStart;
+                    nInLen -= nLen;
+                    for (size_t i = m_CurrentExtent + 1;
+                         i < m_pMergedPara->extents.size(); ++i)
+                    {
+                        sw::Extent const& rExtentEnd(m_pMergedPara->extents[i]);
+                        if (rExtentEnd.pNode != rExtent.pNode)
+                        {
+                            nInLen = 0;
+                            break;
+                        }
+                        // add gap too
+                        nLen += rExtentEnd.nStart - m_pMergedPara->extents[i-1].nEnd;
+                        if (nInLen <= rExtentEnd.nEnd - rExtentEnd.nStart)
+                        {
+                            nLen += nInLen;
+                            nInLen = 0;
+                            break;
+                        }
+                        nLen += rExtentEnd.nEnd - rExtentEnd.nStart;
+                        nInLen -= rExtentEnd.nEnd - rExtentEnd.nStart;
+                    }
+                }
+                if (pWrongList && pWrongList->Check(nStart, nLen))
+                {
+                    // check if there's overlap with this extent
+                    if (rExtent.nStart <= nStart && nStart < rExtent.nEnd)
+                    {
+                        // yes - now compute end position / length
+                        sal_Int32 const nEnd(nStart + nLen);
+                        rStart = m_CurrentIndex + TextFrameIndex(nStart - rExtent.nStart);
+                        TextFrameIndex const nOrigLen(rLen);
+                        if (nEnd <= rExtent.nEnd)
+                        {
+                            rLen = TextFrameIndex(nEnd - nStart);
+                        }
+                        else // have to search other extents for the end...
+                        {
+                            rLen = TextFrameIndex(rExtent.nEnd - nStart);
+                            for (size_t i = m_CurrentExtent + 1;
+                                 i < m_pMergedPara->extents.size(); ++i)
+                            {
+                                sw::Extent const& rExtentEnd(m_pMergedPara->extents[i]);
+                                if (rExtentEnd.pNode != rExtent.pNode
+                                    || nEnd <= rExtentEnd.nStart)
+                                {
+                                    break;
+                                }
+                                if (nEnd <= rExtentEnd.nEnd)
+                                {
+                                    rLen += TextFrameIndex(nEnd - rExtentEnd.nStart);
+                                    break;
+                                }
+                                rLen += TextFrameIndex(rExtentEnd.nEnd - rExtentEnd.nStart);
+                            }
+                        }
+                        assert(rLen <= nOrigLen); (void) nOrigLen;
+                        return true;
+                    }
+                }
+            }
+            m_CurrentIndex += TextFrameIndex(rExtent.nEnd - rExtent.nStart);
+            ++m_CurrentExtent;
+            if (m_CurrentExtent < m_pMergedPara->extents.size() &&
+                rExtent.pNode != m_pMergedPara->extents[m_CurrentExtent].pNode)
+            {
+                m_CurrentNodeIndex = m_CurrentIndex; // reset
+            }
+        }
+        return false;
+    }
+    else if (m_pWrongList)
+    {
+        sal_Int32 nStart(rStart);
+        sal_Int32 nLen(rLen);
+        bool const bRet(m_pWrongList->Check(nStart, nLen));
+        rStart = TextFrameIndex(nStart);
+        rLen = TextFrameIndex(nLen);
+        return bRet;
+    }
+    return false;
+}
+
+const SwWrongArea*
+WrongListIterator::GetWrongElement(TextFrameIndex const nStart)
+{
+    if (m_pMergedPara)
+    {
+        if (nStart < m_CurrentIndex)
+        {   // rewind
+            m_CurrentExtent = 0;
+            m_CurrentIndex = TextFrameIndex(0);
+            m_CurrentNodeIndex = TextFrameIndex(0);
+        }
+        while (m_CurrentExtent < m_pMergedPara->extents.size())
+        {
+            sw::Extent const& rExtent(m_pMergedPara->extents[m_CurrentExtent]);
+            if (m_CurrentIndex <= nStart &&
+                nStart <= m_CurrentIndex + TextFrameIndex(rExtent.nEnd - rExtent.nStart))
+            {
+                // note: the returned object isn't wrapped because fntcache.cxx
+                // does not look at its positions, only its formatting props
+                SwWrongList const*const pWrongList((rExtent.pNode->*m_pGetWrongList)());
+                if (pWrongList)
+                {
+                    sal_Int32 const nNStart(rExtent.nStart + sal_Int32(nStart - m_CurrentIndex)); // (m_CurrentIndex - m_CurrentNodeIndex));
+                    sal_Int16 const nPos(pWrongList->GetWrongPos(nNStart));
+                    return pWrongList->GetElement(nPos);
+                }
+            }
+            m_CurrentIndex += TextFrameIndex(rExtent.nEnd - rExtent.nStart);
+            ++m_CurrentExtent;
+            if (m_CurrentExtent < m_pMergedPara->extents.size() &&
+                rExtent.pNode != m_pMergedPara->extents[m_CurrentExtent].pNode)
+            {
+                m_CurrentNodeIndex = m_CurrentIndex; // reset
+            }
+        }
+        return nullptr;
+    }
+    else if (m_pWrongList)
+    {
+        sal_Int16 const nPos(m_pWrongList->GetWrongPos(sal_Int32(nStart)));
+        return m_pWrongList->GetElement(nPos);
+    }
+    return nullptr;
+}
+
+} // namespace sw
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/txtnode/txtedt.cxx b/sw/source/core/txtnode/txtedt.cxx
index 1f1468b1429d..7a646fc2b8ed 100644
--- a/sw/source/core/txtnode/txtedt.cxx
+++ b/sw/source/core/txtnode/txtedt.cxx
@@ -2216,6 +2216,11 @@ SwGrammarMarkUp* SwTextNode::GetGrammarCheck()
     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pGrammarCheck : nullptr;
 }
 
+SwWrongList const* SwTextNode::GetGrammarCheck() const
+{
+    return static_cast<SwWrongList const*>(const_cast<SwTextNode*>(this)->GetGrammarCheck());
+}
+
 void SwTextNode::SetSmartTags( SwWrongList* pNew, bool bDelete )
 {
     OSL_ENSURE( !pNew || SwSmartTagMgr::Get().IsSmartTagsEnabled(),
@@ -2236,6 +2241,11 @@ SwWrongList* SwTextNode::GetSmartTags()
     return m_pParaIdleData_Impl ? m_pParaIdleData_Impl->pSmartTags : nullptr;
 }
 
+SwWrongList const* SwTextNode::GetSmartTags() const
+{
+    return const_cast<SwWrongList const*>(const_cast<SwTextNode*>(this)->GetSmartTags());
+}
+
 void SwTextNode::SetWordCountDirty( bool bNew ) const
 {
     if ( m_pParaIdleData_Impl )
commit 162fb509aee3c30b5b7bd15daf602c4f38e94242
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Tue Jun 5 13:41:58 2018 +0200

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

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

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

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

    sw_redlinehide: convert spelling SwTextFrame funcs called by DoIdleJob_
    
    These currently get passed the current shell cursor position, which
    seems quite pointless as the caller DoIdleJob_ can handle that case
    in one place.
    
    Instead, pass in the actual node that should be checked, since the
    SwTextFrame can have multiple nodes now.
    
    Change-Id: Id7a8a7a2a5a3eaeb700963eff5147d37b194a953

diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx
index f6fbb686903e..98a18f7ed8ad 100644
--- a/sw/source/core/inc/txtfrm.hxx
+++ b/sw/source/core/inc/txtfrm.hxx
@@ -280,14 +280,14 @@ public:
      */
     void Init();
 
-    /// Is called by FormatSpelling()
-    SwRect AutoSpell_( const SwContentNode*, sal_Int32 );
+    /// Is called by DoIdleJob_() and ExecSpellPopup()
+    SwRect AutoSpell_(SwTextNode &, sal_Int32);
 
-    /// Is called by FormatSpelling()
-    SwRect SmartTagScan();
+    /// Is called by DoIdleJob_()
+    SwRect SmartTagScan(SwTextNode &);
 
-    /// Is called by CollectAutoCmplWords()
-    void CollectAutoCmplWrds( SwContentNode const * , sal_Int32 );
+    /// Is called by DoIdleJob_()
+    void CollectAutoCmplWrds(SwTextNode &, sal_Int32);
 
     /**
      * Returns the screen position of rPos. The values are relative to the upper
diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx
index e98f19ccb771..761a85c51741 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -1849,7 +1849,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
 
     SwTextFrame const*const pTextFrame(static_cast<SwTextFrame const*>(pCnt));
     // sw_redlinehide: spell check only the nodes with visible content?
-    const SwTextNode* pTextNode = pTextFrame->GetTextNodeForParaProps();
+    SwTextNode* pTextNode = const_cast<SwTextNode*>(pTextFrame->GetTextNodeForParaProps());
 
     bool bProcess = false;
     for (size_t i = 0; pTextNode; )
@@ -1895,6 +1895,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
 
     if( bProcess )
     {
+        assert(pTextNode);
         SwViewShell *pSh = pImp->GetShell();
         if( COMPLETE_STRING == nTextPos )
         {
@@ -1909,12 +1910,15 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
                 }
             }
         }
+        sal_Int32 const nPos((pContentNode && pTextNode == pContentNode)
+                ? nTextPos
+                : COMPLETE_STRING);
 
         switch ( eJob )
         {
             case ONLINE_SPELLING :
             {
-                SwRect aRepaint( const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pCnt))->AutoSpell_( pContentNode, nTextPos ) );
+                SwRect aRepaint( const_cast<SwTextFrame*>(pTextFrame)->AutoSpell_(*pTextNode, nPos) );
                 // PENDING should stop idle spell checking
                 bPageValid = bPageValid && (SwTextNode::WrongState::TODO != pTextNode->GetWrongDirty());
                 if ( aRepaint.HasArea() )
@@ -1924,7 +1928,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
                 break;
             }
             case AUTOCOMPLETE_WORDS :
-                const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pCnt))->CollectAutoCmplWrds( pContentNode, nTextPos );
+                const_cast<SwTextFrame*>(pTextFrame)->CollectAutoCmplWrds(*pTextNode, nPos);
                 // note: bPageValid remains true here even if the cursor
                 // position is skipped, so no PENDING state needed currently
                 if (Application::AnyInput(VCL_INPUT_ANY & VclInputFlags(~VclInputFlags::TIMER)))
@@ -1942,7 +1946,7 @@ bool SwLayIdle::DoIdleJob_( const SwContentFrame *pCnt, IdleJobType eJob )
             case SMART_TAGS :
             {
                 try {
-                    const SwRect aRepaint( const_cast<SwTextFrame*>(static_cast<const SwTextFrame*>(pCnt))->SmartTagScan() );
+                    const SwRect aRepaint( const_cast<SwTextFrame*>(pTextFrame)->SmartTagScan(*pTextNode) );
                     bPageValid = bPageValid && !pTextNode->IsSmartTagDirty();
                     if ( aRepaint.HasArea() )
                         pImp->GetShell()->InvalidateWindows( aRepaint );
diff --git a/sw/source/core/txtnode/txtedt.cxx b/sw/source/core/txtnode/txtedt.cxx
index 7523293b45ea..1f1468b1429d 100644
--- a/sw/source/core/txtnode/txtedt.cxx
+++ b/sw/source/core/txtnode/txtedt.cxx
@@ -200,14 +200,16 @@ lcl_MaskRedlinesAndHiddenText( const SwTextNode& rNode, OUStringBuffer& rText,
 /**
  * Used for spell checking. Calculates a rectangle for repaint.
  */
-static SwRect lcl_CalculateRepaintRect( SwTextFrame& rTextFrame, sal_Int32 nChgStart, sal_Int32 nChgEnd )
+static SwRect lcl_CalculateRepaintRect(
+        SwTextFrame & rTextFrame, SwTextNode & rNode,
+        sal_Int32 const nChgStart, sal_Int32 const nChgEnd)
 {
     SwRect aRect;
 
-    SwTextNode *pNode = rTextFrame.GetTextNode();
+    TextFrameIndex const iChgStart(rTextFrame.MapModelToView(&rNode, nChgStart));
+    TextFrameIndex const iChgEnd(rTextFrame.MapModelToView(&rNode, nChgEnd));
 
-    SwNodeIndex aNdIdx( *pNode );
-    SwPosition aPos( aNdIdx, SwIndex( pNode, nChgEnd ) );
+    SwPosition aPos( rNode, nChgEnd );
     SwCursorMoveState aTmpState( MV_NONE );
     aTmpState.m_b2Lines = true;
     rTextFrame.GetCharRect( aRect, aPos, &aTmpState );
@@ -217,7 +219,7 @@ static SwRect lcl_CalculateRepaintRect( SwTextFrame& rTextFrame, sal_Int32 nChgS
     const SwTextFrame *pEndFrame = &rTextFrame;
 
     while( pEndFrame->HasFollow() &&
-           nChgEnd >= pEndFrame->GetFollow()->GetOfst() )
+           iChgEnd >= pEndFrame->GetFollow()->GetOfst())
         pEndFrame = pEndFrame->GetFollow();
 
     if ( pEnd2Pos )
@@ -236,7 +238,7 @@ static SwRect lcl_CalculateRepaintRect( SwTextFrame& rTextFrame, sal_Int32 nChgS
 
     aTmpState.m_p2Lines = nullptr;
     SwRect aTmp;
-    aPos = SwPosition( aNdIdx, SwIndex( pNode, nChgStart ) );
+    aPos = SwPosition( rNode, nChgStart );
     rTextFrame.GetCharRect( aTmp, aPos, &aTmpState );
 
     // i63141: GetCharRect(..) could cause a formatting,
@@ -244,11 +246,11 @@ static SwRect lcl_CalculateRepaintRect( SwTextFrame& rTextFrame, sal_Int32 nChgS
     // => we have to reinit pStartFrame and pEndFrame after the formatting
     const SwTextFrame* pStartFrame = &rTextFrame;
     while( pStartFrame->HasFollow() &&
-           nChgStart >= pStartFrame->GetFollow()->GetOfst() )
+           iChgStart >= pStartFrame->GetFollow()->GetOfst())
         pStartFrame = pStartFrame->GetFollow();
     pEndFrame = pStartFrame;
     while( pEndFrame->HasFollow() &&
-           nChgEnd >= pEndFrame->GetFollow()->GetOfst() )
+           iChgEnd >= pEndFrame->GetFollow()->GetOfst())
         pEndFrame = pEndFrame->GetFollow();
 
     // information about start of repaint area
@@ -1266,11 +1268,12 @@ bool SwTextNode::Convert( SwConversionArgs &rArgs )
 }
 
 // Note: this is a clone of SwTextNode::Spell, so keep them in sync when fixing things!
-SwRect SwTextFrame::AutoSpell_( const SwContentNode* pActNode, sal_Int32 nActPos )
+SwRect SwTextFrame::AutoSpell_(SwTextNode & rNode, sal_Int32 nActPos)
 {
     SwRect aRect;
-    SwTextNode *pNode = GetTextNode();
-    if( pNode != pActNode || !nActPos )
+    assert(sw::FrameContainsNode(*this, rNode.GetIndex()));
+    SwTextNode *const pNode(&rNode);
+    if (!nActPos)
         nActPos = COMPLETE_STRING;
 
     SwAutoCompleteWord& rACW = SwDoc::GetAutoCompleteWords();
@@ -1281,7 +1284,7 @@ SwRect SwTextFrame::AutoSpell_( const SwContentNode* pActNode, sal_Int32 nActPos
     const bool bRestoreString =
         lcl_MaskRedlinesAndHiddenText(*pNode, buf, 0, pNode->GetText().getLength());
     if (bRestoreString)
-    {   // ??? UGLY: is it really necessary to modify m_Text here?
+    {   // ??? UGLY: is it really necessary to modify m_Text here? just for GetLang()?
         pNode->m_Text = buf.makeStringAndClear();
     }
 
@@ -1415,7 +1418,7 @@ SwRect SwTextFrame::AutoSpell_( const SwContentNode* pActNode, sal_Int32 nActPos
 
         if( nChgStart < nChgEnd )
         {
-            aRect = lcl_CalculateRepaintRect( *this, nChgStart, nChgEnd );
+            aRect = lcl_CalculateRepaintRect(*this, rNode, nChgStart, nChgEnd);
 
             // fdo#71558 notify misspelled word to accessibility
             SwViewShell* pViewSh = getRootFrame() ? getRootFrame()->GetCurrShell() : nullptr;
@@ -1451,10 +1454,12 @@ SwRect SwTextFrame::AutoSpell_( const SwContentNode* pActNode, sal_Int32 nActPos
 
     @return SwRect Repaint area
 */
-SwRect SwTextFrame::SmartTagScan()
+SwRect SwTextFrame::SmartTagScan(SwTextNode & rNode)
 {
     SwRect aRet;
-    SwTextNode *pNode = GetTextNode();
+
+    assert(sw::FrameContainsNode(*this, rNode.GetIndex()));
+    SwTextNode *const pNode = &rNode;
     const OUString& rText = pNode->GetText();
 
     // Iterate over language portions
@@ -1556,7 +1561,7 @@ SwRect SwTextFrame::SmartTagScan()
         if ( nBegin < nEnd && ( 0 != nNumberOfRemovedEntries ||
                                 0 != nNumberOfInsertedEntries ) )
         {
-            aRet = lcl_CalculateRepaintRect( *this, nBegin, nEnd );
+            aRet = lcl_CalculateRepaintRect(*this, rNode, nBegin, nEnd);
         }
     }
     else
@@ -1565,10 +1570,11 @@ SwRect SwTextFrame::SmartTagScan()
     return aRet;
 }
 
-void SwTextFrame::CollectAutoCmplWrds( SwContentNode const * pActNode, sal_Int32 nActPos )
+void SwTextFrame::CollectAutoCmplWrds(SwTextNode & rNode, sal_Int32 nActPos)
 {
-    SwTextNode *pNode = GetTextNode();
-    if( pNode != pActNode || !nActPos )
+    assert(sw::FrameContainsNode(*this, rNode.GetIndex()));
+    SwTextNode *const pNode(&rNode);
+    if (!nActPos)
         nActPos = COMPLETE_STRING;
 
     SwDoc* pDoc = pNode->GetDoc();
diff --git a/sw/source/uibase/uiview/viewling.cxx b/sw/source/uibase/uiview/viewling.cxx
index 0f646e637c5e..1e0b389aefb0 100644
--- a/sw/source/uibase/uiview/viewling.cxx
+++ b/sw/source/uibase/uiview/viewling.cxx
@@ -656,7 +656,8 @@ bool SwView::ExecSpellPopup(const Point& rPt)
                                         &rPt, &aPoint, false);
                 if (pContentFrame)
                 {
-                    SwRect aRepaint(static_cast<SwTextFrame*>(pContentFrame)->AutoSpell_(nullptr, 0));
+                    SwRect aRepaint(static_cast<SwTextFrame*>(pContentFrame)->AutoSpell_(
+                        *pCursor->GetContentNode()->GetTextNode(), 0));
                     if (aRepaint.HasArea())
                         m_pWrtShell->InvalidateWindows(aRepaint);
                 }
commit 90cb0c4c43e744e058241c736b322337de5f0bc6
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Wed Jun 6 17:23:49 2018 +0200

    sw_redlinehide: SwAttrIter direct ctor gets a SwTextFrame arg
    
    ... and use it in SwTextPainter::CheckSpecialUnderline()
    
    Change-Id: I904cb955f0bc8dc1f92612b47dc129922865c198

diff --git a/sw/source/core/text/itratr.hxx b/sw/source/core/text/itratr.hxx
index 016f97c333bc..c47be02230d8 100644
--- a/sw/source/core/text/itratr.hxx
+++ b/sw/source/core/text/itratr.hxx
@@ -71,7 +71,7 @@ private:
 protected:
     void Chg( SwTextAttr const *pHt );
     void Rst( SwTextAttr const *pHt );
-    void CtorInitAttrIter(SwTextNode& rTextNode, SwScriptInfo& rScrInf, SwTextFrame * pFrame = nullptr);
+    void CtorInitAttrIter(SwTextNode& rTextNode, SwScriptInfo& rScrInf, SwTextFrame const* pFrame = nullptr);
     explicit SwAttrIter(SwTextNode const * pTextNode)
         : m_pViewShell(nullptr)
         , m_pFont(nullptr)
@@ -93,7 +93,7 @@ public:
     /// All subclasses of this always have a SwTextFrame passed to the
     /// constructor, but SwAttrIter itself may be created without a
     /// SwTextFrame in certain special cases via this ctor here
-    SwAttrIter( SwTextNode& rTextNode, SwScriptInfo& rScrInf )
+    SwAttrIter(SwTextNode& rTextNode, SwScriptInfo& rScrInf, SwTextFrame const*const pFrame = nullptr)
         : m_pViewShell(nullptr)
         , m_pFont(nullptr)
         , m_pScriptInfo(nullptr)
@@ -103,7 +103,9 @@ public:
         , m_nPropFont(0)
         , m_pTextNode(&rTextNode)
         , m_pMergedPara(nullptr)
-        { CtorInitAttrIter( rTextNode, rScrInf ); }
+    {
+        CtorInitAttrIter(rTextNode, rScrInf, pFrame);
+    }
 
     virtual ~SwAttrIter();
 
diff --git a/sw/source/core/text/itrpaint.cxx b/sw/source/core/text/itrpaint.cxx
index 295765d7f809..7e2458fcb2b9 100644
--- a/sw/source/core/text/itrpaint.cxx
+++ b/sw/source/core/text/itrpaint.cxx
@@ -596,8 +596,8 @@ void SwTextPainter::CheckSpecialUnderline( const SwLinePortion* pPor,
     {
         // here starts the algorithm for calculating the underline font
         SwScriptInfo& rScriptInfo = GetInfo().GetParaPortion()->GetScriptInfo();
-        SwAttrIter aIter( *GetInfo().GetTextFrame()->GetTextNode(),
-                          rScriptInfo );
+        SwAttrIter aIter(*GetInfo().GetTextFrame()->GetTextNodeFirst(),
+                         rScriptInfo, GetTextFrame());
 
         TextFrameIndex nTmpIdx = nIndx;
         sal_uLong nSumWidth = 0;
diff --git a/sw/source/core/text/redlnitr.cxx b/sw/source/core/text/redlnitr.cxx
index 0640001dddb0..b7ded98a503b 100644
--- a/sw/source/core/text/redlnitr.cxx
+++ b/sw/source/core/text/redlnitr.cxx
@@ -189,7 +189,7 @@ void SwAttrIter::InitFontAndAttrHandler(SwTextNode const& rTextNode,
 }
 
 void SwAttrIter::CtorInitAttrIter(SwTextNode & rTextNode,
-        SwScriptInfo & rScriptInfo, SwTextFrame *const pFrame)
+        SwScriptInfo & rScriptInfo, SwTextFrame const*const pFrame)
 {
     // during HTML-Import it can happen, that no layout exists
     SwRootFrame* pRootFrame = rTextNode.getIDocumentLayoutAccess().GetCurrentLayout();
commit 42c775b2b0f5cf0014a65b38927d5951886b199f
Author: Michael Stahl <Michael.Stahl at cib.de>
Date:   Wed Jun 6 13:29:04 2018 +0200

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

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

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

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

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

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

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

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

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

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

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

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

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list